Compare commits
370 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e99a99eb6e | ||
|
|
df9712f1c8 | ||
|
|
5c56b597a9 | ||
|
|
f712e10cb2 | ||
|
|
8a851af5e6 | ||
|
|
3b89d13aaf | ||
|
|
16225c473f | ||
|
|
dd2f0d89bf | ||
|
|
0b57e4483a | ||
|
|
f2dc49292f | ||
|
|
a7ace535c3 | ||
|
|
c99e8de5a4 | ||
|
|
c06aa62bda | ||
|
|
9ba998312d | ||
|
|
7d68afb2d2 | ||
|
|
bfdf1839e0 | ||
|
|
5dc86d7bca | ||
|
|
f35491190a | ||
|
|
10e37198aa | ||
|
|
950d0312dc | ||
|
|
c8ec36d1b9 | ||
|
|
97a2dc96f2 | ||
|
|
88b6ea993d | ||
|
|
d4f7039793 | ||
|
|
4399f65fb8 | ||
|
|
2d85a20c71 | ||
|
|
c01d17d77d | ||
|
|
ed0ba04da6 | ||
|
|
b15cfd3530 | ||
|
|
a438d505ba | ||
|
|
5eb590e79d | ||
|
|
bdc79ac8b2 | ||
|
|
a97d858b2a | ||
|
|
e592f1b298 | ||
|
|
513a567483 | ||
|
|
faf103e6ec | ||
|
|
e608296bc6 | ||
|
|
4ebe2cf348 | ||
|
|
422378cb85 | ||
|
|
594c818d85 | ||
|
|
d86898b014 | ||
|
|
be087c9c82 | ||
|
|
9cc8b72a38 | ||
|
|
3425c1b84c | ||
|
|
1c509f4350 | ||
|
|
48833c7b07 | ||
|
|
f385f1860b | ||
|
|
7df6c4b9ad | ||
|
|
8f6b6d5784 | ||
|
|
0fc11699ab | ||
|
|
9332c00ca5 | ||
|
|
fd9ad1a194 | ||
|
|
6ae3305040 | ||
|
|
cc0e091a6b | ||
|
|
dfc076a123 | ||
|
|
f6e1055727 | ||
|
|
6057e6ad70 | ||
|
|
ca39f15fa3 | ||
|
|
7953d1becb | ||
|
|
f4b41e1a6c | ||
|
|
4bc3328e80 | ||
|
|
ebe17f57ff | ||
|
|
ee05f97c9a | ||
|
|
78c02d038f | ||
|
|
bc823acc25 | ||
|
|
c21c5afe00 | ||
|
|
1ae54707a0 | ||
|
|
ede1e6d475 | ||
|
|
e701dce339 | ||
|
|
a93a87f64a | ||
|
|
7aba68cd54 | ||
|
|
dfc64d157a | ||
|
|
a41384ad73 | ||
|
|
ed7a4236b3 | ||
|
|
040c3b50d0 | ||
|
|
8b3519c5f7 | ||
|
|
ec559c02b8 | ||
|
|
2e4d4c9f60 | ||
|
|
b8d52ec266 | ||
|
|
b5da816487 | ||
|
|
3bae188b8d | ||
|
|
8165e51ecc | ||
|
|
9a15db21a6 | ||
|
|
58a1c5720a | ||
|
|
bc172e5e5f | ||
|
|
6745bdd0b3 | ||
|
|
5714f0a74e | ||
|
|
ce43f4af1c | ||
|
|
5d1609f5a2 | ||
|
|
4714f102d7 | ||
|
|
a675da65e9 | ||
|
|
e39755666b | ||
|
|
9adba5e2e6 | ||
|
|
5c1af383eb | ||
|
|
c81662eae4 | ||
|
|
8ea9ccf3a7 | ||
|
|
74a2b13687 | ||
|
|
4e7f2b757e | ||
|
|
2bba279cf1 | ||
|
|
56da77a548 | ||
|
|
494b575213 | ||
|
|
c383d59880 | ||
|
|
416fdaa3d5 | ||
|
|
2b0ebf5d32 | ||
|
|
f236e62d9d | ||
|
|
964e826a9b | ||
|
|
49673fc45c | ||
|
|
3342bdb331 | ||
|
|
1d02a7ffb6 | ||
|
|
788935175e | ||
|
|
32663bf431 | ||
|
|
e3be2e959b | ||
|
|
67f1e3f5ed | ||
|
|
23ea9b8968 | ||
|
|
921c6994b1 | ||
|
|
ea12588524 | ||
|
|
e8ad82f9ba | ||
|
|
6e2e4cad73 | ||
|
|
2e0e455fa6 | ||
|
|
d93742fe9a | ||
|
|
2e3b660dd0 | ||
|
|
0bd534adcf | ||
|
|
e59dd2c62c | ||
|
|
25be79208a | ||
|
|
2a3b91e3b6 | ||
|
|
221ee504aa | ||
|
|
64e74cefb7 | ||
|
|
eb4a0271fb | ||
|
|
cfec1c3e1b | ||
|
|
2b5386f039 | ||
|
|
a0eec14c7d | ||
|
|
54f9cdb0c3 | ||
|
|
d6fb313220 | ||
|
|
0aa2470c76 | ||
|
|
edc68f84f3 | ||
|
|
0089dd05e9 | ||
|
|
51f6c4a737 | ||
|
|
cd209f406e | ||
|
|
f4eaec3e1e | ||
|
|
b083418257 | ||
|
|
5794857f7a | ||
|
|
e7f3f6fa5a | ||
|
|
1b0fd7ead3 | ||
|
|
a926cd4d88 | ||
|
|
aa5671411b | ||
|
|
f8dfd0aa5e | ||
|
|
3dbf9c6560 | ||
|
|
de563a3ea3 | ||
|
|
9cf2b41c05 | ||
|
|
f310b875f8 | ||
|
|
ac14c463d5 | ||
|
|
578e888915 | ||
|
|
5231bf3653 | ||
|
|
8af945f353 | ||
|
|
d0e8ca1257 | ||
|
|
5a934fc923 | ||
|
|
c766d064ac | ||
|
|
0356081c0a | ||
|
|
6e8bfc8d12 | ||
|
|
18e91d5f85 | ||
|
|
1004d57b85 | ||
|
|
f9e4ef5eb0 | ||
|
|
eefbadd230 | ||
|
|
bc21b3ebf0 | ||
|
|
608fb2a21e | ||
|
|
92cbb7cc80 | ||
|
|
45050d9887 | ||
|
|
75a0052e64 | ||
|
|
c8efd08384 | ||
|
|
454cd147fb | ||
|
|
e41507bde2 | ||
|
|
599f85d4e4 | ||
|
|
5756ba9bc4 | ||
|
|
193a7e1dc1 | ||
|
|
0900d3b7a6 | ||
|
|
24dd50490a | ||
|
|
5ae8c7a985 | ||
|
|
9b57f9187b | ||
|
|
50e45b485f | ||
|
|
2051ebc0eb | ||
|
|
080243f040 | ||
|
|
933b9d44e1 | ||
|
|
44b3e8d51b | ||
|
|
9bf8ad741f | ||
|
|
9913ebbe21 | ||
|
|
c7a48e91d8 | ||
|
|
2cbf2200ac | ||
|
|
bac5772312 | ||
|
|
a6e5a397bd | ||
|
|
364f48d6c7 | ||
|
|
4174e7aa7a | ||
|
|
eb38750d99 | ||
|
|
cd0fef633c | ||
|
|
d0c73c28df | ||
|
|
8e6c249e48 | ||
|
|
752f99e8a1 | ||
|
|
a909223ee2 | ||
|
|
8ff271fc74 | ||
|
|
9dfac1dd65 | ||
|
|
a8a6848ce0 | ||
|
|
9232d1ef62 | ||
|
|
90483dc912 | ||
|
|
6bdb6f226b | ||
|
|
2ac1141980 | ||
|
|
1104d443cc | ||
|
|
49044a9608 | ||
|
|
71d2ff4946 | ||
|
|
474191dd7b | ||
|
|
637eceb6a7 | ||
|
|
976428f505 | ||
|
|
affe7caf78 | ||
|
|
941e3e2ef0 | ||
|
|
b7937e268f | ||
|
|
5a411fa38e | ||
|
|
bf26ae03cf | ||
|
|
3363cd5cd0 | ||
|
|
5c49a61353 | ||
|
|
f83c31e188 | ||
|
|
8f36467107 | ||
|
|
73e79a3310 | ||
|
|
34cf976866 | ||
|
|
e832b01349 | ||
|
|
26c8eae6fe | ||
|
|
d40efc4648 | ||
|
|
5705a49308 | ||
|
|
65185a565b | ||
|
|
1bb8f60d5a | ||
|
|
1d01189f04 | ||
|
|
8e49cb453f | ||
|
|
40f1e4edbe | ||
|
|
1267e15b0f | ||
|
|
eb9fef2c42 | ||
|
|
43b346d93b | ||
|
|
d918c7d9de | ||
|
|
e962e9edcf | ||
|
|
b7a62f1f1b | ||
|
|
2e5d1a2d48 | ||
|
|
fac0d87d00 | ||
|
|
a839b36e55 | ||
|
|
316c8328aa | ||
|
|
e8db031112 | ||
|
|
59b785a282 | ||
|
|
1a1daca621 | ||
|
|
837be914ca | ||
|
|
f44eac49fa | ||
|
|
0acdef4549 | ||
|
|
7d8ef90ccb | ||
|
|
91520838fc | ||
|
|
ada0e1fb08 | ||
|
|
33d97e81eb | ||
|
|
019324015b | ||
|
|
72d278fdac | ||
|
|
05d7f85af9 | ||
|
|
7fba358ae2 | ||
|
|
9f1fc40a64 | ||
|
|
3be7bc38e0 | ||
|
|
31c66d5a00 | ||
|
|
e7d36c9590 | ||
|
|
3e8626c4a1 | ||
|
|
e14dd4d33e | ||
|
|
87a69e6753 | ||
|
|
f64dbdbe3a | ||
|
|
2b5553144a | ||
|
|
e43ef364cb | ||
|
|
08a87d4b3b | ||
|
|
90f372af5c | ||
|
|
3ec29eb5da | ||
|
|
3a20e4e15d | ||
|
|
fd97190ee7 | ||
|
|
70480ce7bc | ||
|
|
bf7d6cbb4a | ||
|
|
c059785ffb | ||
|
|
a0f5fb7394 | ||
|
|
ad33e9f388 | ||
|
|
1d1d81b0bc | ||
|
|
f3d2969560 | ||
|
|
758ea61b77 | ||
|
|
4388bef996 | ||
|
|
e2b8ee2723 | ||
|
|
07dc0a5120 | ||
|
|
d3125d8570 | ||
|
|
283ebf3ff9 | ||
|
|
4c174e0bfb | ||
|
|
57a6c83547 | ||
|
|
cfc7684b7d | ||
|
|
be49f0a118 | ||
|
|
66a9d06d9f | ||
|
|
6940cf1ecd | ||
|
|
4e0cdc016a | ||
|
|
8a8109648a | ||
|
|
dc8b359319 | ||
|
|
dea29e7c99 | ||
|
|
ab6379b3e0 | ||
|
|
f7fed2ea5f | ||
|
|
35e87ee571 | ||
|
|
ab3893ff4d | ||
|
|
1277dca335 | ||
|
|
ba9aef6f2c | ||
|
|
dd619d2bd6 | ||
|
|
1e2ef274cd | ||
|
|
bcb5e36dd9 | ||
|
|
19121c16d9 | ||
|
|
27ee261e60 | ||
|
|
da3962266a | ||
|
|
e93afcdd2b | ||
|
|
dd1b9e38e9 | ||
|
|
96bc9ea7c1 | ||
|
|
16c8a10ef9 | ||
|
|
5dcd11be16 | ||
|
|
dc91a7b641 | ||
|
|
11998ae7d6 | ||
|
|
1cf9c80e97 | ||
|
|
6dbcdd3ed5 | ||
|
|
9632cf09bf | ||
|
|
96ab3c540d | ||
|
|
ff964d327d | ||
|
|
4b8688f1e5 | ||
|
|
55b5889a0f | ||
|
|
dd4c6f6a09 | ||
|
|
6058261a26 | ||
|
|
b461e4607d | ||
|
|
d399f72098 | ||
|
|
c9e1c65c64 | ||
|
|
3042f11666 | ||
|
|
e5e47c9862 | ||
|
|
1c5083315d | ||
|
|
27a137ccab | ||
|
|
7cc294e777 | ||
|
|
a20dcfb049 | ||
|
|
06b53e3fc7 | ||
|
|
8f9dd86146 | ||
|
|
ebba0a6024 | ||
|
|
c9236d99d2 | ||
|
|
f03c1b8eeb | ||
|
|
6f23e39e6b | ||
|
|
fe0378e9b3 | ||
|
|
96a1d7c645 | ||
|
|
79ee8b46f4 | ||
|
|
55a7a8b8c9 | ||
|
|
b47873c5ac | ||
|
|
adf75d402a | ||
|
|
cb1fdb2f03 | ||
|
|
d1d66b9c5f | ||
|
|
6dacbb451f | ||
|
|
ead9cefadb | ||
|
|
185a2fc55e | ||
|
|
fb8fac6c60 | ||
|
|
b6f288a1ce | ||
|
|
aa9bec96b1 | ||
|
|
11e28842ac | ||
|
|
b16ff9f859 | ||
|
|
348c5c4838 | ||
|
|
8dcc6a0280 | ||
|
|
3b5ad44647 | ||
|
|
5e029f7600 | ||
|
|
52cebe19e5 | ||
|
|
d8d33e8b8b | ||
|
|
b37f7d49d8 | ||
|
|
54da339b2c | ||
|
|
648c4f198b | ||
|
|
8589fd6db8 | ||
|
|
2e79719622 | ||
|
|
9bfec5a538 | ||
|
|
800d900688 | ||
|
|
bd144a64f6 | ||
|
|
2a20e85203 | ||
|
|
27d6777376 | ||
|
|
41cdd9b27f | ||
|
|
ec6b35240e | ||
|
|
42bcfcc927 |
1
.gitignore
vendored
@@ -15,3 +15,4 @@ docs/_build
|
||||
docs/_static
|
||||
docs/_templates
|
||||
.gopath/
|
||||
.dotcloud
|
||||
|
||||
2
.mailmap
@@ -23,3 +23,5 @@ Thatcher Peskens <thatcher@dotcloud.com>
|
||||
Walter Stanish <walter@pratyeka.org>
|
||||
<daniel@gasienica.ch> <dgasienica@zynga.com>
|
||||
Roberto Hashioka <roberto_hashioka@hotmail.com>
|
||||
Konstantin Pelykh <kpelykh@zettaset.com>
|
||||
David Sissitka <me@dsissitka.com>
|
||||
|
||||
26
AUTHORS
@@ -4,12 +4,15 @@
|
||||
# For a list of active project maintainers, see the MAINTAINERS file.
|
||||
#
|
||||
Al Tobey <al@ooyala.com>
|
||||
Alex Gaynor <alex.gaynor@gmail.com>
|
||||
Alexey Shamrin <shamrin@gmail.com>
|
||||
Andrea Luzzardi <aluzzardi@gmail.com>
|
||||
Andreas Tiefenthaler <at@an-ti.eu>
|
||||
Andrew Munsell <andrew@wizardapps.net>
|
||||
Andrews Medina <andrewsmedina@gmail.com>
|
||||
Andy Rothfusz <github@metaliveblog.com>
|
||||
Andy Smith <github@anarkystic.com>
|
||||
Anthony Bishopric <git@anthonybishopric.com>
|
||||
Antony Messerli <amesserl@rackspace.com>
|
||||
Barry Allard <barry.allard@gmail.com>
|
||||
Brandon Liu <bdon@bdon.org>
|
||||
@@ -23,17 +26,23 @@ Daniel Gasienica <daniel@gasienica.ch>
|
||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com>
|
||||
Daniel Robinson <gottagetmac@gmail.com>
|
||||
Daniel Von Fange <daniel@leancoder.com>
|
||||
Daniel YC Lin <dlin.tw@gmail.com>
|
||||
David Calavera <david.calavera@gmail.com>
|
||||
David Sissitka <me@dsissitka.com>
|
||||
Dominik Honnef <dominik@honnef.co>
|
||||
Don Spaulding <donspauldingii@gmail.com>
|
||||
Dr Nic Williams <drnicwilliams@gmail.com>
|
||||
Elias Probst <mail@eliasprobst.eu>
|
||||
Eric Hanchrow <ehanchrow@ine.com>
|
||||
Evan Wies <evan@neomantra.net>
|
||||
Eric Myhre <hash@exultant.us>
|
||||
Erno Hopearuoho <erno.hopearuoho@gmail.com>
|
||||
Evan Wies <evan@neomantra.net>
|
||||
ezbercih <cem.ezberci@gmail.com>
|
||||
Fabrizio Regini <freegenie@gmail.com>
|
||||
Flavio Castelli <fcastelli@suse.com>
|
||||
Francisco Souza <f@souza.cc>
|
||||
Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
|
||||
Gabriel Monroy <gabriel@opdemand.com>
|
||||
Gareth Rushgrove <gareth@morethanseven.net>
|
||||
Guillaume J. Charmes <guillaume.charmes@dotcloud.com>
|
||||
Harley Laue <losinggeneration@gmail.com>
|
||||
@@ -41,6 +50,7 @@ Hunter Blanks <hunter@twilio.com>
|
||||
Jeff Lindsay <progrium@gmail.com>
|
||||
Jeremy Grosser <jeremy@synack.me>
|
||||
Joffrey F <joffrey@dotcloud.com>
|
||||
Johan Euphrosine <proppy@google.com>
|
||||
John Costa <john.costa@gmail.com>
|
||||
Jon Wedaman <jweede@gmail.com>
|
||||
Jonas Pfenniger <jonas@pfenniger.name>
|
||||
@@ -48,40 +58,54 @@ Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
|
||||
Julien Barbier <write0@gmail.com>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com>
|
||||
Karan Lyons <karan@karanlyons.com>
|
||||
Keli Hu <dev@keli.hu>
|
||||
Ken Cochrane <kencochrane@gmail.com>
|
||||
Kevin J. Lynagh <kevin@keminglabs.com>
|
||||
kim0 <email.ahmedkamal@googlemail.com>
|
||||
Kimbro Staken <kstaken@kstaken.com>
|
||||
Kiran Gangadharan <kiran.daredevil@gmail.com>
|
||||
Konstantin Pelykh <kpelykh@zettaset.com>
|
||||
Louis Opter <kalessin@kalessin.fr>
|
||||
Marco Hennings <marco.hennings@freiheit.com>
|
||||
Marcus Farkas <toothlessgear@finitebox.com>
|
||||
Mark McGranaghan <mmcgrana@gmail.com>
|
||||
Maxim Treskin <zerthurd@gmail.com>
|
||||
meejah <meejah@meejah.ca>
|
||||
Michael Crosby <crosby.michael@gmail.com>
|
||||
Mike Gaffney <mike@uberu.com>
|
||||
Mikhail Sobolev <mss@mawhrin.net>
|
||||
Nan Monnand Deng <monnand@gmail.com>
|
||||
Nate Jones <nate@endot.org>
|
||||
Nelson Chen <crazysim@gmail.com>
|
||||
Niall O'Higgins <niallo@unworkable.org>
|
||||
Nick Stenning <nick.stenning@digital.cabinet-office.gov.uk>
|
||||
Nick Stinemates <nick@stinemates.org>
|
||||
odk- <github@odkurzacz.org>
|
||||
Paul Bowsher <pbowsher@globalpersonals.co.uk>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Phil Spitler <pspitler@gmail.com>
|
||||
Piotr Bogdan <ppbogdan@gmail.com>
|
||||
Renato Riccieri Santos Zannon <renato.riccieri@gmail.com>
|
||||
Rhys Hiltner <rhys@twitch.tv>
|
||||
Robert Obryk <robryk@gmail.com>
|
||||
Roberto Hashioka <roberto_hashioka@hotmail.com>
|
||||
Ryan Fowler <rwfowler@gmail.com>
|
||||
Sam Alba <sam.alba@gmail.com>
|
||||
Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
|
||||
Shawn Siefkas <shawn.siefkas@meredith.com>
|
||||
Silas Sewell <silas@sewell.org>
|
||||
Solomon Hykes <solomon@dotcloud.com>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com>
|
||||
Stefan Praszalowicz <stefan@greplin.com>
|
||||
Thatcher Peskens <thatcher@dotcloud.com>
|
||||
Thomas Bikeev <thomas.bikeev@mac.com>
|
||||
Thomas Hansen <thomas.hansen@gmail.com>
|
||||
Tianon Gravi <admwiggin@gmail.com>
|
||||
Tim Terhorst <mynamewastaken+git@gmail.com>
|
||||
Tobias Bieniek <Tobias.Bieniek@gmx.de>
|
||||
Tobias Schwab <tobias.schwab@dynport.de>
|
||||
Tom Hulihan <hulihan.tom159@gmail.com>
|
||||
unclejack <unclejacksons@gmail.com>
|
||||
Victor Vieux <victor.vieux@dotcloud.com>
|
||||
Vivek Agarwal <me@vivek.im>
|
||||
|
||||
42
CHANGELOG.md
@@ -1,5 +1,47 @@
|
||||
# Changelog
|
||||
|
||||
## 0.5.2 (2013-08-08)
|
||||
* Builder: Forbid certain paths within docker build ADD
|
||||
- Runtime: Change network range to avoid conflict with EC2 DNS
|
||||
* API: Change daemon to listen on unix socket by default
|
||||
|
||||
## 0.5.1 (2013-07-30)
|
||||
+ API: Docker client now sets useragent (RFC 2616)
|
||||
+ Runtime: Add `ps` args to `docker top`
|
||||
+ Runtime: Add support for container ID files (pidfile like)
|
||||
+ Runtime: Add container=lxc in default env
|
||||
+ Runtime: Support networkless containers with `docker run -n` and `docker -d -b=none`
|
||||
+ API: Add /events endpoint
|
||||
+ Builder: ADD command now understands URLs
|
||||
+ Builder: CmdAdd and CmdEnv now respect Dockerfile-set ENV variables
|
||||
* Hack: Simplify unit tests with helpers
|
||||
* Hack: Improve docker.upstart event
|
||||
* Hack: Add coverage testing into docker-ci
|
||||
* Runtime: Stdout/stderr logs are now stored in the same file as JSON
|
||||
* Runtime: Allocate a /16 IP range by default, with fallback to /24. Try 12 ranges instead of 3.
|
||||
* Runtime: Change .dockercfg format to json and support multiple auth remote
|
||||
- Runtime: Do not override volumes from config
|
||||
- Runtime: Fix issue with EXPOSE override
|
||||
- Builder: Create directories with 755 instead of 700 within ADD instruction
|
||||
|
||||
## 0.5.0 (2013-07-17)
|
||||
+ Runtime: List all processes running inside a container with 'docker top'
|
||||
+ Runtime: Host directories can be mounted as volumes with 'docker run -v'
|
||||
+ Runtime: Containers can expose public UDP ports (eg, '-p 123/udp')
|
||||
+ Runtime: Optionally specify an exact public port (eg. '-p 80:4500')
|
||||
+ Registry: New image naming scheme inspired by Go packaging convention allows arbitrary combinations of registries
|
||||
+ Builder: ENTRYPOINT instruction sets a default binary entry point to a container
|
||||
+ Builder: VOLUME instruction marks a part of the container as persistent data
|
||||
* Builder: 'docker build' displays the full output of a build by default
|
||||
* Runtime: 'docker login' supports additional options
|
||||
- Runtime: Dont save a container's hostname when committing an image.
|
||||
- Registry: Fix issues when uploading images to a private registry
|
||||
|
||||
## 0.4.8 (2013-07-01)
|
||||
+ Builder: New build operation ENTRYPOINT adds an executable entry point to the container.
|
||||
- Runtime: Fix a bug which caused 'docker run -d' to no longer print the container ID.
|
||||
- Tests: Fix issues in the test suite
|
||||
|
||||
## 0.4.7 (2013-06-28)
|
||||
* Registry: easier push/pull to a custom registry
|
||||
* Remote API: the progress bar updates faster when downloading and uploading large files
|
||||
|
||||
30
Dockerfile
Normal file
@@ -0,0 +1,30 @@
|
||||
# This file describes the standard way to build Docker, using docker
|
||||
docker-version 0.4.2
|
||||
from ubuntu:12.04
|
||||
maintainer Solomon Hykes <solomon@dotcloud.com>
|
||||
# Build dependencies
|
||||
run apt-get install -y -q curl
|
||||
run apt-get install -y -q git
|
||||
# Install Go
|
||||
run curl -s https://go.googlecode.com/files/go1.1.1.linux-amd64.tar.gz | tar -v -C /usr/local -xz
|
||||
env PATH /usr/local/go/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
|
||||
env GOPATH /go
|
||||
env CGO_ENABLED 0
|
||||
run cd /tmp && echo 'package main' > t.go && go test -a -i -v
|
||||
# Download dependencies
|
||||
run PKG=github.com/kr/pty REV=27435c699; git clone http://$PKG /go/src/$PKG && cd /go/src/$PKG && git checkout -f $REV
|
||||
run PKG=github.com/gorilla/context/ REV=708054d61e5; git clone http://$PKG /go/src/$PKG && cd /go/src/$PKG && git checkout -f $REV
|
||||
run PKG=github.com/gorilla/mux/ REV=9b36453141c; git clone http://$PKG /go/src/$PKG && cd /go/src/$PKG && git checkout -f $REV
|
||||
# Run dependencies
|
||||
run apt-get install -y iptables
|
||||
# lxc requires updating ubuntu sources
|
||||
run echo 'deb http://archive.ubuntu.com/ubuntu precise main universe' > /etc/apt/sources.list
|
||||
run apt-get update
|
||||
run apt-get install -y lxc
|
||||
run apt-get install -y aufs-tools
|
||||
# Upload docker source
|
||||
add . /go/src/github.com/dotcloud/docker
|
||||
# Build the binary
|
||||
run cd /go/src/github.com/dotcloud/docker/docker && go install -ldflags "-X main.GITCOMMIT '??' -d -w"
|
||||
env PATH /usr/local/go/bin:/go/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
|
||||
cmd ["docker"]
|
||||
7
Makefile
@@ -11,7 +11,7 @@ BUILD_DIR := $(CURDIR)/.gopath
|
||||
GOPATH ?= $(BUILD_DIR)
|
||||
export GOPATH
|
||||
|
||||
GO_OPTIONS ?=
|
||||
GO_OPTIONS ?= -a -ldflags='-w -d'
|
||||
ifeq ($(VERBOSE), 1)
|
||||
GO_OPTIONS += -v
|
||||
endif
|
||||
@@ -49,6 +49,7 @@ whichrelease:
|
||||
release: $(BINRELEASE)
|
||||
s3cmd -P put $(BINRELEASE) s3://get.docker.io/builds/`uname -s`/`uname -m`/docker-$(RELEASE_VERSION).tgz
|
||||
s3cmd -P put docker-latest.tgz s3://get.docker.io/builds/`uname -s`/`uname -m`/docker-latest.tgz
|
||||
s3cmd -P put $(SRCRELEASE)/bin/docker s3://get.docker.io/builds/`uname -s`/`uname -m`/docker
|
||||
|
||||
srcrelease: $(SRCRELEASE)
|
||||
deps: $(DOCKER_DIR)
|
||||
@@ -79,10 +80,10 @@ test:
|
||||
tar --exclude=${BUILD_SRC} -cz . | tar -xz -C ${BUILD_PATH}
|
||||
GOPATH=${CURDIR}/${BUILD_SRC} go get -d
|
||||
# Do the test
|
||||
sudo -E GOPATH=${CURDIR}/${BUILD_SRC} go test ${GO_OPTIONS}
|
||||
sudo -E GOPATH=${CURDIR}/${BUILD_SRC} CGO_ENABLED=0 go test ${GO_OPTIONS}
|
||||
|
||||
testall: all
|
||||
@(cd $(DOCKER_DIR); sudo -E go test ./... $(GO_OPTIONS))
|
||||
@(cd $(DOCKER_DIR); CGO_ENABLED=0 sudo -E go test ./... $(GO_OPTIONS))
|
||||
|
||||
fmt:
|
||||
@gofmt -s -l -w .
|
||||
|
||||
334
README.md
@@ -1,80 +1,129 @@
|
||||
Docker: the Linux container engine
|
||||
==================================
|
||||
|
||||
Docker is an open-source engine which automates the deployment of applications as highly portable, self-sufficient containers.
|
||||
Docker is an open-source engine which automates the deployment of
|
||||
applications as highly portable, self-sufficient containers.
|
||||
|
||||
Docker containers are both *hardware-agnostic* and *platform-agnostic*. This means that they can run anywhere, from your
|
||||
laptop to the largest EC2 compute instance and everything in between - and they don't require that you use a particular
|
||||
language, framework or packaging system. That makes them great building blocks for deploying and scaling web apps, databases
|
||||
and backend services without depending on a particular stack or provider.
|
||||
Docker containers are both *hardware-agnostic* and
|
||||
*platform-agnostic*. This means that they can run anywhere, from your
|
||||
laptop to the largest EC2 compute instance and everything in between -
|
||||
and they don't require that you use a particular language, framework
|
||||
or packaging system. That makes them great building blocks for
|
||||
deploying and scaling web apps, databases and backend services without
|
||||
depending on a particular stack or provider.
|
||||
|
||||
Docker is an open-source implementation of the deployment engine which powers [dotCloud](http://dotcloud.com), a popular Platform-as-a-Service.
|
||||
It benefits directly from the experience accumulated over several years of large-scale operation and support of hundreds of thousands
|
||||
of applications and databases.
|
||||
Docker is an open-source implementation of the deployment engine which
|
||||
powers [dotCloud](http://dotcloud.com), a popular
|
||||
Platform-as-a-Service. It benefits directly from the experience
|
||||
accumulated over several years of large-scale operation and support of
|
||||
hundreds of thousands of applications and databases.
|
||||
|
||||

|
||||

|
||||
|
||||
## Better than VMs
|
||||
|
||||
A common method for distributing applications and sandbox their execution is to use virtual machines, or VMs. Typical VM formats
|
||||
are VMWare's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In theory these formats should allow every developer to
|
||||
automatically package their application into a "machine" for easy distribution and deployment. In practice, that almost never
|
||||
happens, for a few reasons:
|
||||
A common method for distributing applications and sandbox their
|
||||
execution is to use virtual machines, or VMs. Typical VM formats are
|
||||
VMWare's vmdk, Oracle Virtualbox's vdi, and Amazon EC2's ami. In
|
||||
theory these formats should allow every developer to automatically
|
||||
package their application into a "machine" for easy distribution and
|
||||
deployment. In practice, that almost never happens, for a few reasons:
|
||||
|
||||
* *Size*: VMs are very large which makes them impractical to store and transfer.
|
||||
* *Performance*: running VMs consumes significant CPU and memory, which makes them impractical in many scenarios, for example local development of multi-tier applications, and
|
||||
large-scale deployment of cpu and memory-intensive applications on large numbers of machines.
|
||||
* *Portability*: competing VM environments don't play well with each other. Although conversion tools do exist, they are limited and add even more overhead.
|
||||
* *Hardware-centric*: VMs were designed with machine operators in mind, not software developers. As a result, they offer very limited tooling for what developers need most:
|
||||
building, testing and running their software. For example, VMs offer no facilities for application versioning, monitoring, configuration, logging or service discovery.
|
||||
* *Size*: VMs are very large which makes them impractical to store
|
||||
and transfer.
|
||||
* *Performance*: running VMs consumes significant CPU and memory,
|
||||
which makes them impractical in many scenarios, for example local
|
||||
development of multi-tier applications, and large-scale deployment
|
||||
of cpu and memory-intensive applications on large numbers of
|
||||
machines.
|
||||
* *Portability*: competing VM environments don't play well with each
|
||||
other. Although conversion tools do exist, they are limited and
|
||||
add even more overhead.
|
||||
* *Hardware-centric*: VMs were designed with machine operators in
|
||||
mind, not software developers. As a result, they offer very
|
||||
limited tooling for what developers need most: building, testing
|
||||
and running their software. For example, VMs offer no facilities
|
||||
for application versioning, monitoring, configuration, logging or
|
||||
service discovery.
|
||||
|
||||
By contrast, Docker relies on a different sandboxing method known as *containerization*. Unlike traditional virtualization,
|
||||
containerization takes place at the kernel level. Most modern operating system kernels now support the primitives necessary
|
||||
for containerization, including Linux with [openvz](http://openvz.org), [vserver](http://linux-vserver.org) and more recently [lxc](http://lxc.sourceforge.net),
|
||||
Solaris with [zones](http://docs.oracle.com/cd/E26502_01/html/E29024/preface-1.html#scrolltoc) and FreeBSD with [Jails](http://www.freebsd.org/doc/handbook/jails.html).
|
||||
By contrast, Docker relies on a different sandboxing method known as
|
||||
*containerization*. Unlike traditional virtualization,
|
||||
containerization takes place at the kernel level. Most modern
|
||||
operating system kernels now support the primitives necessary for
|
||||
containerization, including Linux with [openvz](http://openvz.org),
|
||||
[vserver](http://linux-vserver.org) and more recently
|
||||
[lxc](http://lxc.sourceforge.net), Solaris with
|
||||
[zones](http://docs.oracle.com/cd/E26502_01/html/E29024/preface-1.html#scrolltoc)
|
||||
and FreeBSD with
|
||||
[Jails](http://www.freebsd.org/doc/handbook/jails.html).
|
||||
|
||||
Docker builds on top of these low-level primitives to offer developers a portable format and runtime environment that solves
|
||||
all 4 problems. Docker containers are small (and their transfer can be optimized with layers), they have basically zero memory and cpu overhead,
|
||||
they are completely portable and are designed from the ground up with an application-centric design.
|
||||
Docker builds on top of these low-level primitives to offer developers
|
||||
a portable format and runtime environment that solves all 4
|
||||
problems. Docker containers are small (and their transfer can be
|
||||
optimized with layers), they have basically zero memory and cpu
|
||||
overhead, they are completely portable and are designed from the
|
||||
ground up with an application-centric design.
|
||||
|
||||
The best part: because docker operates at the OS level, it can still be run inside a VM!
|
||||
The best part: because ``docker`` operates at the OS level, it can
|
||||
still be run inside a VM!
|
||||
|
||||
## Plays well with others
|
||||
|
||||
Docker does not require that you buy into a particular programming language, framework, packaging system or configuration language.
|
||||
Docker does not require that you buy into a particular programming
|
||||
language, framework, packaging system or configuration language.
|
||||
|
||||
Is your application a unix process? Does it use files, tcp connections, environment variables, standard unix streams and command-line
|
||||
arguments as inputs and outputs? Then docker can run it.
|
||||
Is your application a Unix process? Does it use files, tcp
|
||||
connections, environment variables, standard Unix streams and
|
||||
command-line arguments as inputs and outputs? Then ``docker`` can run
|
||||
it.
|
||||
|
||||
Can your application's build be expressed as a sequence of such commands? Then docker can build it.
|
||||
Can your application's build be expressed as a sequence of such
|
||||
commands? Then ``docker`` can build it.
|
||||
|
||||
|
||||
## Escape dependency hell
|
||||
|
||||
A common problem for developers is the difficulty of managing all their application's dependencies in a simple and automated way.
|
||||
A common problem for developers is the difficulty of managing all
|
||||
their application's dependencies in a simple and automated way.
|
||||
|
||||
This is usually difficult for several reasons:
|
||||
|
||||
* *Cross-platform dependencies*. Modern applications often depend on a combination of system libraries and binaries, language-specific packages, framework-specific modules,
|
||||
internal components developed for another project, etc. These dependencies live in different "worlds" and require different tools - these tools typically don't work
|
||||
well with each other, requiring awkward custom integrations.
|
||||
* *Cross-platform dependencies*. Modern applications often depend on
|
||||
a combination of system libraries and binaries, language-specific
|
||||
packages, framework-specific modules, internal components
|
||||
developed for another project, etc. These dependencies live in
|
||||
different "worlds" and require different tools - these tools
|
||||
typically don't work well with each other, requiring awkward
|
||||
custom integrations.
|
||||
|
||||
* Conflicting dependencies. Different applications may depend on different versions of the same dependency. Packaging tools handle these situations with various degrees of ease -
|
||||
but they all handle them in different and incompatible ways, which again forces the developer to do extra work.
|
||||
* Conflicting dependencies. Different applications may depend on
|
||||
different versions of the same dependency. Packaging tools handle
|
||||
these situations with various degrees of ease - but they all
|
||||
handle them in different and incompatible ways, which again forces
|
||||
the developer to do extra work.
|
||||
|
||||
* Custom dependencies. A developer may need to prepare a custom version of his application's dependency. Some packaging systems can handle custom versions of a dependency,
|
||||
others can't - and all of them handle it differently.
|
||||
* Custom dependencies. A developer may need to prepare a custom
|
||||
version of their application's dependency. Some packaging systems
|
||||
can handle custom versions of a dependency, others can't - and all
|
||||
of them handle it differently.
|
||||
|
||||
|
||||
Docker solves dependency hell by giving the developer a simple way to express *all* his application's dependencies in one place,
|
||||
and streamline the process of assembling them. If this makes you think of [XKCD 927](http://xkcd.com/927/), don't worry. Docker doesn't
|
||||
*replace* your favorite packaging systems. It simply orchestrates their use in a simple and repeatable way. How does it do that? With layers.
|
||||
Docker solves dependency hell by giving the developer a simple way to
|
||||
express *all* their application's dependencies in one place, and
|
||||
streamline the process of assembling them. If this makes you think of
|
||||
[XKCD 927](http://xkcd.com/927/), don't worry. Docker doesn't
|
||||
*replace* your favorite packaging systems. It simply orchestrates
|
||||
their use in a simple and repeatable way. How does it do that? With
|
||||
layers.
|
||||
|
||||
Docker defines a build as running a sequence of unix commands, one after the other, in the same container. Build commands modify the contents of the container
|
||||
(usually by installing new files on the filesystem), the next command modifies it some more, etc. Since each build command inherits the result of the previous
|
||||
commands, the *order* in which the commands are executed expresses *dependencies*.
|
||||
Docker defines a build as running a sequence of Unix commands, one
|
||||
after the other, in the same container. Build commands modify the
|
||||
contents of the container (usually by installing new files on the
|
||||
filesystem), the next command modifies it some more, etc. Since each
|
||||
build command inherits the result of the previous commands, the
|
||||
*order* in which the commands are executed expresses *dependencies*.
|
||||
|
||||
Here's a typical docker build process:
|
||||
Here's a typical Docker build process:
|
||||
|
||||
```bash
|
||||
from ubuntu:12.10
|
||||
@@ -87,7 +136,8 @@ run curl -L https://github.com/shykes/helloflask/archive/master.tar.gz | tar -xz
|
||||
run cd helloflask-master && pip install -r requirements.txt
|
||||
```
|
||||
|
||||
Note that Docker doesn't care *how* dependencies are built - as long as they can be built by running a unix command in a container.
|
||||
Note that Docker doesn't care *how* dependencies are built - as long
|
||||
as they can be built by running a Unix command in a container.
|
||||
|
||||
|
||||
Install instructions
|
||||
@@ -103,8 +153,9 @@ curl get.docker.io | sudo sh -x
|
||||
Binary installs
|
||||
----------------
|
||||
|
||||
Docker supports the following binary installation methods.
|
||||
Note that some methods are community contributions and not yet officially supported.
|
||||
Docker supports the following binary installation methods. Note that
|
||||
some methods are community contributions and not yet officially
|
||||
supported.
|
||||
|
||||
* [Ubuntu 12.04 and 12.10 (officially supported)](http://docs.docker.io/en/latest/installation/ubuntulinux/)
|
||||
* [Arch Linux](http://docs.docker.io/en/latest/installation/archlinux/)
|
||||
@@ -115,15 +166,15 @@ Note that some methods are community contributions and not yet officially suppor
|
||||
Installing from source
|
||||
----------------------
|
||||
|
||||
1. Make sure you have a [Go language](http://golang.org/doc/install) compiler and [git](http://git-scm.com) installed.
|
||||
|
||||
1. Make sure you have a [Go language](http://golang.org/doc/install)
|
||||
compiler >= 1.1 and [git](http://git-scm.com) installed.
|
||||
2. Checkout the source code
|
||||
|
||||
```bash
|
||||
git clone http://github.com/dotcloud/docker
|
||||
```
|
||||
|
||||
3. Build the docker binary
|
||||
3. Build the ``docker`` binary
|
||||
|
||||
```bash
|
||||
cd docker
|
||||
@@ -134,17 +185,20 @@ Installing from source
|
||||
Usage examples
|
||||
==============
|
||||
|
||||
First run the docker daemon
|
||||
---------------------------
|
||||
First run the ``docker`` daemon
|
||||
-------------------------------
|
||||
|
||||
All the examples assume your machine is running the docker daemon. To run the docker daemon in the background, simply type:
|
||||
All the examples assume your machine is running the ``docker``
|
||||
daemon. To run the ``docker`` daemon in the background, simply type:
|
||||
|
||||
```bash
|
||||
# On a production system you want this running in an init script
|
||||
sudo docker -d &
|
||||
```
|
||||
|
||||
Now you can run docker in client mode: all commands will be forwarded to the docker daemon, so the client can run from any account.
|
||||
Now you can run ``docker`` in client mode: all commands will be
|
||||
forwarded to the ``docker`` daemon, so the client can run from any
|
||||
account.
|
||||
|
||||
```bash
|
||||
# Now you can run docker commands from any account.
|
||||
@@ -152,7 +206,7 @@ docker help
|
||||
```
|
||||
|
||||
|
||||
Throwaway shell in a base ubuntu image
|
||||
Throwaway shell in a base Ubuntu image
|
||||
--------------------------------------
|
||||
|
||||
```bash
|
||||
@@ -202,7 +256,8 @@ docker commit -m "Installed curl" $CONTAINER $USER/betterbase
|
||||
docker push $USER/betterbase
|
||||
```
|
||||
|
||||
A list of publicly available images is [available here](https://github.com/dotcloud/docker/wiki/Public-docker-images).
|
||||
A list of publicly available images is [available
|
||||
here](https://github.com/dotcloud/docker/wiki/Public-docker-images).
|
||||
|
||||
Expose a service on a TCP port
|
||||
------------------------------
|
||||
@@ -229,32 +284,40 @@ Under the hood
|
||||
|
||||
Under the hood, Docker is built on the following components:
|
||||
|
||||
|
||||
* The [cgroup](http://blog.dotcloud.com/kernel-secrets-from-the-paas-garage-part-24-c) and [namespacing](http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part) capabilities of the Linux kernel;
|
||||
|
||||
* [AUFS](http://aufs.sourceforge.net/aufs.html), a powerful union filesystem with copy-on-write capabilities;
|
||||
|
||||
* The
|
||||
[cgroup](http://blog.dotcloud.com/kernel-secrets-from-the-paas-garage-part-24-c)
|
||||
and
|
||||
[namespacing](http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part)
|
||||
capabilities of the Linux kernel;
|
||||
* [AUFS](http://aufs.sourceforge.net/aufs.html), a powerful union
|
||||
filesystem with copy-on-write capabilities;
|
||||
* The [Go](http://golang.org) programming language;
|
||||
|
||||
* [lxc](http://lxc.sourceforge.net/), a set of convenience scripts to simplify the creation of linux containers.
|
||||
* [lxc](http://lxc.sourceforge.net/), a set of convenience scripts to
|
||||
simplify the creation of Linux containers.
|
||||
|
||||
|
||||
|
||||
Contributing to Docker
|
||||
======================
|
||||
|
||||
Want to hack on Docker? Awesome! There are instructions to get you started on the website: http://docs.docker.io/en/latest/contributing/contributing/
|
||||
Want to hack on Docker? Awesome! There are instructions to get you
|
||||
started on the website:
|
||||
http://docs.docker.io/en/latest/contributing/contributing/
|
||||
|
||||
They are probably not perfect, please let us know if anything feels wrong or incomplete.
|
||||
They are probably not perfect, please let us know if anything feels
|
||||
wrong or incomplete.
|
||||
|
||||
|
||||
Note
|
||||
----
|
||||
|
||||
We also keep the documentation in this repository. The website documentation is generated using sphinx using these sources.
|
||||
Please find it under docs/sources/ and read more about it https://github.com/dotcloud/docker/tree/master/docs/README.md
|
||||
We also keep the documentation in this repository. The website
|
||||
documentation is generated using Sphinx using these sources. Please
|
||||
find it under docs/sources/ and read more about it
|
||||
https://github.com/dotcloud/docker/tree/master/docs/README.md
|
||||
|
||||
Please feel free to fix / update the documentation and send us pull requests. More tutorials are also welcome.
|
||||
Please feel free to fix / update the documentation and send us pull
|
||||
requests. More tutorials are also welcome.
|
||||
|
||||
|
||||
Setting up a dev environment
|
||||
@@ -289,93 +352,104 @@ Run the `go install` command (above) to recompile docker.
|
||||
What is a Standard Container?
|
||||
=============================
|
||||
|
||||
Docker defines a unit of software delivery called a Standard Container. The goal of a Standard Container is to encapsulate a software component and all its dependencies in
|
||||
a format that is self-describing and portable, so that any compliant runtime can run it without extra dependencies, regardless of the underlying machine and the contents of the container.
|
||||
Docker defines a unit of software delivery called a Standard
|
||||
Container. The goal of a Standard Container is to encapsulate a
|
||||
software component and all its dependencies in a format that is
|
||||
self-describing and portable, so that any compliant runtime can run it
|
||||
without extra dependencies, regardless of the underlying machine and
|
||||
the contents of the container.
|
||||
|
||||
The spec for Standard Containers is currently a work in progress, but it is very straightforward. It mostly defines 1) an image format, 2) a set of standard operations, and 3) an execution environment.
|
||||
The spec for Standard Containers is currently a work in progress, but
|
||||
it is very straightforward. It mostly defines 1) an image format, 2) a
|
||||
set of standard operations, and 3) an execution environment.
|
||||
|
||||
A great analogy for this is the shipping container. Just like how Standard Containers are a fundamental unit of software delivery, shipping containers (http://bricks.argz.com/ins/7823-1/12) are a fundamental unit of physical delivery.
|
||||
A great analogy for this is the shipping container. Just like how
|
||||
Standard Containers are a fundamental unit of software delivery,
|
||||
shipping containers are a fundamental unit of physical delivery.
|
||||
|
||||
### 1. STANDARD OPERATIONS
|
||||
|
||||
Just like shipping containers, Standard Containers define a set of STANDARD OPERATIONS. Shipping containers can be lifted, stacked, locked, loaded, unloaded and labelled. Similarly, standard containers can be started, stopped, copied, snapshotted, downloaded, uploaded and tagged.
|
||||
Just like shipping containers, Standard Containers define a set of
|
||||
STANDARD OPERATIONS. Shipping containers can be lifted, stacked,
|
||||
locked, loaded, unloaded and labelled. Similarly, Standard Containers
|
||||
can be started, stopped, copied, snapshotted, downloaded, uploaded and
|
||||
tagged.
|
||||
|
||||
|
||||
### 2. CONTENT-AGNOSTIC
|
||||
|
||||
Just like shipping containers, Standard Containers are CONTENT-AGNOSTIC: all standard operations have the same effect regardless of the contents. A shipping container will be stacked in exactly the same way whether it contains Vietnamese powder coffee or spare Maserati parts. Similarly, Standard Containers are started or uploaded in the same way whether they contain a postgres database, a php application with its dependencies and application server, or Java build artifacts.
|
||||
Just like shipping containers, Standard Containers are
|
||||
CONTENT-AGNOSTIC: all standard operations have the same effect
|
||||
regardless of the contents. A shipping container will be stacked in
|
||||
exactly the same way whether it contains Vietnamese powder coffee or
|
||||
spare Maserati parts. Similarly, Standard Containers are started or
|
||||
uploaded in the same way whether they contain a postgres database, a
|
||||
php application with its dependencies and application server, or Java
|
||||
build artifacts.
|
||||
|
||||
|
||||
### 3. INFRASTRUCTURE-AGNOSTIC
|
||||
|
||||
Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be transported to thousands of facilities around the world, and manipulated by a wide variety of equipment. A shipping container can be packed in a factory in Ukraine, transported by truck to the nearest routing center, stacked onto a train, loaded into a German boat by an Australian-built crane, stored in a warehouse at a US facility, etc. Similarly, a standard container can be bundled on my laptop, uploaded to S3, downloaded, run and snapshotted by a build server at Equinix in Virginia, uploaded to 10 staging servers in a home-made Openstack cluster, then sent to 30 production instances across 3 EC2 regions.
|
||||
Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be
|
||||
transported to thousands of facilities around the world, and
|
||||
manipulated by a wide variety of equipment. A shipping container can
|
||||
be packed in a factory in Ukraine, transported by truck to the nearest
|
||||
routing center, stacked onto a train, loaded into a German boat by an
|
||||
Australian-built crane, stored in a warehouse at a US facility,
|
||||
etc. Similarly, a standard container can be bundled on my laptop,
|
||||
uploaded to S3, downloaded, run and snapshotted by a build server at
|
||||
Equinix in Virginia, uploaded to 10 staging servers in a home-made
|
||||
Openstack cluster, then sent to 30 production instances across 3 EC2
|
||||
regions.
|
||||
|
||||
|
||||
### 4. DESIGNED FOR AUTOMATION
|
||||
|
||||
Because they offer the same standard operations regardless of content and infrastructure, Standard Containers, just like their physical counterpart, are extremely well-suited for automation. In fact, you could say automation is their secret weapon.
|
||||
Because they offer the same standard operations regardless of content
|
||||
and infrastructure, Standard Containers, just like their physical
|
||||
counterparts, are extremely well-suited for automation. In fact, you
|
||||
could say automation is their secret weapon.
|
||||
|
||||
Many things that once required time-consuming and error-prone human effort can now be programmed. Before shipping containers, a bag of powder coffee was hauled, dragged, dropped, rolled and stacked by 10 different people in 10 different locations by the time it reached its destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The process was slow, inefficient and cost a fortune - and was entirely different depending on the facility and the type of goods.
|
||||
Many things that once required time-consuming and error-prone human
|
||||
effort can now be programmed. Before shipping containers, a bag of
|
||||
powder coffee was hauled, dragged, dropped, rolled and stacked by 10
|
||||
different people in 10 different locations by the time it reached its
|
||||
destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The
|
||||
process was slow, inefficient and cost a fortune - and was entirely
|
||||
different depending on the facility and the type of goods.
|
||||
|
||||
Similarly, before Standard Containers, by the time a software component ran in production, it had been individually built, configured, bundled, documented, patched, vendored, templated, tweaked and instrumented by 10 different people on 10 different computers. Builds failed, libraries conflicted, mirrors crashed, post-it notes were lost, logs were misplaced, cluster updates were half-broken. The process was slow, inefficient and cost a fortune - and was entirely different depending on the language and infrastructure provider.
|
||||
Similarly, before Standard Containers, by the time a software
|
||||
component ran in production, it had been individually built,
|
||||
configured, bundled, documented, patched, vendored, templated, tweaked
|
||||
and instrumented by 10 different people on 10 different
|
||||
computers. Builds failed, libraries conflicted, mirrors crashed,
|
||||
post-it notes were lost, logs were misplaced, cluster updates were
|
||||
half-broken. The process was slow, inefficient and cost a fortune -
|
||||
and was entirely different depending on the language and
|
||||
infrastructure provider.
|
||||
|
||||
|
||||
### 5. INDUSTRIAL-GRADE DELIVERY
|
||||
|
||||
There are 17 million shipping containers in existence, packed with every physical good imaginable. Every single one of them can be loaded onto the same boats, by the same cranes, in the same facilities, and sent anywhere in the World with incredible efficiency. It is embarrassing to think that a 30 ton shipment of coffee can safely travel half-way across the World in *less time* than it takes a software team to deliver its code from one datacenter to another sitting 10 miles away.
|
||||
There are 17 million shipping containers in existence, packed with
|
||||
every physical good imaginable. Every single one of them can be loaded
|
||||
onto the same boats, by the same cranes, in the same facilities, and
|
||||
sent anywhere in the World with incredible efficiency. It is
|
||||
embarrassing to think that a 30 ton shipment of coffee can safely
|
||||
travel half-way across the World in *less time* than it takes a
|
||||
software team to deliver its code from one datacenter to another
|
||||
sitting 10 miles away.
|
||||
|
||||
With Standard Containers we can put an end to that embarrassment, by making INDUSTRIAL-GRADE DELIVERY of software a reality.
|
||||
With Standard Containers we can put an end to that embarrassment, by
|
||||
making INDUSTRIAL-GRADE DELIVERY of software a reality.
|
||||
|
||||
|
||||
|
||||
|
||||
Standard Container Specification
|
||||
--------------------------------
|
||||
|
||||
(TODO)
|
||||
|
||||
### Image format
|
||||
|
||||
|
||||
### Standard operations
|
||||
|
||||
* Copy
|
||||
* Run
|
||||
* Stop
|
||||
* Wait
|
||||
* Commit
|
||||
* Attach standard streams
|
||||
* List filesystem changes
|
||||
* ...
|
||||
|
||||
### Execution environment
|
||||
|
||||
#### Root filesystem
|
||||
|
||||
#### Environment variables
|
||||
|
||||
#### Process arguments
|
||||
|
||||
#### Networking
|
||||
|
||||
#### Process namespacing
|
||||
|
||||
#### Resource limits
|
||||
|
||||
#### Process monitoring
|
||||
|
||||
#### Logging
|
||||
|
||||
#### Signals
|
||||
|
||||
#### Pseudo-terminal allocation
|
||||
|
||||
#### Security
|
||||
|
||||
### Legal
|
||||
|
||||
Transfers of Docker shall be in accordance with applicable export controls of any country and all other applicable
|
||||
legal requirements. Docker shall not be distributed or downloaded to or in Cuba, Iran, North Korea, Sudan or Syria
|
||||
and shall not be distributed or downloaded to any person on the Denied Persons List administered by the U.S.
|
||||
Transfers of Docker shall be in accordance with applicable export
|
||||
controls of any country and all other applicable legal requirements.
|
||||
Docker shall not be distributed or downloaded to or in Cuba, Iran,
|
||||
North Korea, Sudan or Syria and shall not be distributed or downloaded
|
||||
to any person on the Denied Persons List administered by the U.S.
|
||||
Department of Commerce.
|
||||
|
||||
|
||||
2
Vagrantfile
vendored
@@ -20,6 +20,8 @@ Vagrant::Config.run do |config|
|
||||
pkg_cmd = "apt-get update -qq; apt-get install -q -y python-software-properties; " \
|
||||
"add-apt-repository -y ppa:dotcloud/lxc-docker; apt-get update -qq; " \
|
||||
"apt-get install -q -y lxc-docker; "
|
||||
# Listen on all interfaces so that the daemon is accessible from the host
|
||||
pkg_cmd << "sed -i -E 's| /usr/bin/docker -d| /usr/bin/docker -d -H 0.0.0.0|' /etc/init/docker.conf;"
|
||||
# Add X.org Ubuntu backported 3.8 kernel
|
||||
pkg_cmd << "add-apt-repository -y ppa:ubuntu-x-swat/r-lts-backport; " \
|
||||
"apt-get update -qq; apt-get install -q -y linux-image-3.8.0-19-generic; "
|
||||
|
||||
200
api.go
@@ -17,9 +17,10 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const APIVERSION = 1.3
|
||||
const DEFAULTHTTPHOST string = "127.0.0.1"
|
||||
const DEFAULTHTTPPORT int = 4243
|
||||
const APIVERSION = 1.4
|
||||
const DEFAULTHTTPHOST = "127.0.0.1"
|
||||
const DEFAULTHTTPPORT = 4243
|
||||
const DEFAULTUNIXSOCKET = "/var/run/docker.sock"
|
||||
|
||||
func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
|
||||
conn, _, err := w.(http.Hijacker).Hijack()
|
||||
@@ -47,21 +48,22 @@ func parseMultipartForm(r *http.Request) error {
|
||||
}
|
||||
|
||||
func httpError(w http.ResponseWriter, err error) {
|
||||
statusCode := http.StatusInternalServerError
|
||||
if strings.HasPrefix(err.Error(), "No such") {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
statusCode = http.StatusNotFound
|
||||
} else if strings.HasPrefix(err.Error(), "Bad parameter") {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
statusCode = http.StatusBadRequest
|
||||
} else if strings.HasPrefix(err.Error(), "Conflict") {
|
||||
http.Error(w, err.Error(), http.StatusConflict)
|
||||
statusCode = http.StatusConflict
|
||||
} else if strings.HasPrefix(err.Error(), "Impossible") {
|
||||
http.Error(w, err.Error(), http.StatusNotAcceptable)
|
||||
statusCode = http.StatusNotAcceptable
|
||||
} else if strings.HasPrefix(err.Error(), "Wrong login/password") {
|
||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||
statusCode = http.StatusUnauthorized
|
||||
} else if strings.Contains(err.Error(), "hasn't been activated") {
|
||||
http.Error(w, err.Error(), http.StatusForbidden)
|
||||
} else {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
statusCode = http.StatusForbidden
|
||||
}
|
||||
utils.Debugf("[error %d] %s", statusCode, err)
|
||||
http.Error(w, err.Error(), statusCode)
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, b []byte) {
|
||||
@@ -80,54 +82,15 @@ func getBoolParam(value string) (bool, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if version > 1.1 {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return nil
|
||||
}
|
||||
authConfig, err := auth.LoadConfig(srv.runtime.root)
|
||||
if err != nil {
|
||||
if err != auth.ErrConfigFileMissing {
|
||||
return err
|
||||
}
|
||||
authConfig = &auth.AuthConfig{}
|
||||
}
|
||||
b, err := json.Marshal(&auth.AuthConfig{Username: authConfig.Username, Email: authConfig.Email})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writeJSON(w, b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
authConfig := &auth.AuthConfig{}
|
||||
err := json.NewDecoder(r.Body).Decode(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
status := ""
|
||||
if version > 1.1 {
|
||||
status, err = auth.Login(authConfig, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
localAuthConfig, err := auth.LoadConfig(srv.runtime.root)
|
||||
if err != nil {
|
||||
if err != auth.ErrConfigFileMissing {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if authConfig.Username == localAuthConfig.Username {
|
||||
authConfig.Password = localAuthConfig.Password
|
||||
}
|
||||
|
||||
newAuthConfig := auth.NewAuthConfig(authConfig.Username, authConfig.Password, authConfig.Email, srv.runtime.root)
|
||||
status, err = auth.Login(newAuthConfig, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
status, err := auth.Login(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status != "" {
|
||||
b, err := json.Marshal(&APIAuth{Status: status})
|
||||
@@ -170,7 +133,7 @@ func getContainersExport(srv *Server, version float64, w http.ResponseWriter, r
|
||||
name := vars["name"]
|
||||
|
||||
if err := srv.ContainerExport(name, w); err != nil {
|
||||
utils.Debugf("%s", err.Error())
|
||||
utils.Debugf("%s", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -216,6 +179,64 @@ func getInfo(srv *Server, version float64, w http.ResponseWriter, r *http.Reques
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEvents(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
sendEvent := func(wf *utils.WriteFlusher, event *utils.JSONMessage) error {
|
||||
b, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
return fmt.Errorf("JSON error")
|
||||
}
|
||||
_, err = wf.Write(b)
|
||||
if err != nil {
|
||||
// On error, evict the listener
|
||||
utils.Debugf("%s", err)
|
||||
srv.Lock()
|
||||
delete(srv.listeners, r.RemoteAddr)
|
||||
srv.Unlock()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := parseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
listener := make(chan utils.JSONMessage)
|
||||
srv.Lock()
|
||||
srv.listeners[r.RemoteAddr] = listener
|
||||
srv.Unlock()
|
||||
since, err := strconv.ParseInt(r.Form.Get("since"), 10, 0)
|
||||
if err != nil {
|
||||
since = 0
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
wf := utils.NewWriteFlusher(w)
|
||||
if since != 0 {
|
||||
// If since, send previous events that happened after the timestamp
|
||||
for _, event := range srv.events {
|
||||
if event.Time >= since {
|
||||
err := sendEvent(wf, &event)
|
||||
if err != nil && err.Error() == "JSON error" {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for {
|
||||
event := <-listener
|
||||
err := sendEvent(wf, &event)
|
||||
if err != nil && err.Error() == "JSON error" {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getImagesHistory(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
@@ -250,6 +271,30 @@ func getContainersChanges(srv *Server, version float64, w http.ResponseWriter, r
|
||||
return nil
|
||||
}
|
||||
|
||||
func getContainersTop(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if version < 1.4 {
|
||||
return fmt.Errorf("top was improved a lot since 1.3, Please upgrade your docker client.")
|
||||
}
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
if err := parseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
name := vars["name"]
|
||||
ps_args := r.Form.Get("ps_args")
|
||||
procsStr, err := srv.ContainerTop(name, ps_args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(procsStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writeJSON(w, b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := parseForm(r); err != nil {
|
||||
return err
|
||||
@@ -306,7 +351,7 @@ func postCommit(srv *Server, version float64, w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
config := &Config{}
|
||||
if err := json.NewDecoder(r.Body).Decode(config); err != nil {
|
||||
utils.Debugf("%s", err.Error())
|
||||
utils.Debugf("%s", err)
|
||||
}
|
||||
repo := r.Form.Get("repo")
|
||||
tag := r.Form.Get("tag")
|
||||
@@ -342,8 +387,7 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht
|
||||
}
|
||||
sf := utils.NewStreamFormatter(version > 1.0)
|
||||
if image != "" { //pull
|
||||
registry := r.Form.Get("registry")
|
||||
if err := srv.ImagePull(image, tag, registry, w, sf, &auth.AuthConfig{}); err != nil {
|
||||
if err := srv.ImagePull(image, tag, w, sf, &auth.AuthConfig{}); err != nil {
|
||||
if sf.Used() {
|
||||
w.Write(sf.FormatError(err))
|
||||
return nil
|
||||
@@ -412,21 +456,12 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht
|
||||
|
||||
func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
authConfig := &auth.AuthConfig{}
|
||||
if version > 1.1 {
|
||||
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
localAuthConfig, err := auth.LoadConfig(srv.runtime.root)
|
||||
if err != nil && err != auth.ErrConfigFileMissing {
|
||||
return err
|
||||
}
|
||||
authConfig = localAuthConfig
|
||||
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := parseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
registry := r.Form.Get("registry")
|
||||
|
||||
if vars == nil {
|
||||
return fmt.Errorf("Missing parameter")
|
||||
@@ -436,7 +471,7 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
}
|
||||
sf := utils.NewStreamFormatter(version > 1.0)
|
||||
if err := srv.ImagePush(name, registry, w, sf, authConfig); err != nil {
|
||||
if err := srv.ImagePush(name, w, sf, authConfig); err != nil {
|
||||
if sf.Used() {
|
||||
w.Write(sf.FormatError(err))
|
||||
return nil
|
||||
@@ -535,7 +570,7 @@ func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.R
|
||||
return err
|
||||
}
|
||||
if imgs != nil {
|
||||
if len(*imgs) != 0 {
|
||||
if len(imgs) != 0 {
|
||||
b, err := json.Marshal(imgs)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -555,8 +590,10 @@ func postContainersStart(srv *Server, version float64, w http.ResponseWriter, r
|
||||
|
||||
// allow a nil body for backwards compatibility
|
||||
if r.Body != nil {
|
||||
if err := json.NewDecoder(r.Body).Decode(hostConfig); err != nil {
|
||||
return err
|
||||
if r.Header.Get("Content-Type") == "application/json" {
|
||||
if err := json.NewDecoder(r.Body).Decode(hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,6 +793,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
remoteURL := r.FormValue("remote")
|
||||
repoName := r.FormValue("t")
|
||||
rawSuppressOutput := r.FormValue("q")
|
||||
tag := ""
|
||||
if strings.Contains(repoName, ":") {
|
||||
remoteParts := strings.Split(repoName, ":")
|
||||
@@ -802,7 +840,13 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
context = c
|
||||
}
|
||||
b := NewBuildFile(srv, utils.NewWriteFlusher(w))
|
||||
|
||||
suppressOutput, err := getBoolParam(rawSuppressOutput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput)
|
||||
id, err := b.Build(context)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "Error build: %s\n", err)
|
||||
@@ -829,9 +873,9 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
||||
|
||||
m := map[string]map[string]func(*Server, float64, http.ResponseWriter, *http.Request, map[string]string) error{
|
||||
"GET": {
|
||||
"/auth": getAuth,
|
||||
"/version": getVersion,
|
||||
"/events": getEvents,
|
||||
"/info": getInfo,
|
||||
"/version": getVersion,
|
||||
"/images/json": getImagesJSON,
|
||||
"/images/viz": getImagesViz,
|
||||
"/images/search": getImagesSearch,
|
||||
@@ -842,6 +886,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
||||
"/containers/{name:.*}/export": getContainersExport,
|
||||
"/containers/{name:.*}/changes": getContainersChanges,
|
||||
"/containers/{name:.*}/json": getContainersByName,
|
||||
"/containers/{name:.*}/top": getContainersTop,
|
||||
},
|
||||
"POST": {
|
||||
"/auth": postAuth,
|
||||
@@ -878,7 +923,7 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
|
||||
localMethod := method
|
||||
localFct := fct
|
||||
f := func(w http.ResponseWriter, r *http.Request) {
|
||||
utils.Debugf("Calling %s %s", localMethod, localRoute)
|
||||
utils.Debugf("Calling %s %s from %s", localMethod, localRoute, r.RemoteAddr)
|
||||
|
||||
if logging {
|
||||
log.Println(r.Method, r.RequestURI)
|
||||
@@ -928,9 +973,8 @@ func ListenAndServe(proto, addr string, srv *Server, logging bool) error {
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
//as the daemon is launched as root, change to permission of the socket to allow non-root to connect
|
||||
if proto == "unix" {
|
||||
os.Chmod(addr, 0777)
|
||||
os.Chmod(addr, 0700)
|
||||
}
|
||||
httpSrv := http.Server{Addr: addr, Handler: r}
|
||||
return httpSrv.Serve(l)
|
||||
|
||||
@@ -17,13 +17,21 @@ type APIImages struct {
|
||||
}
|
||||
|
||||
type APIInfo struct {
|
||||
Debug bool
|
||||
Containers int
|
||||
Images int
|
||||
NFd int `json:",omitempty"`
|
||||
NGoroutines int `json:",omitempty"`
|
||||
MemoryLimit bool `json:",omitempty"`
|
||||
SwapLimit bool `json:",omitempty"`
|
||||
Debug bool
|
||||
Containers int
|
||||
Images int
|
||||
NFd int `json:",omitempty"`
|
||||
NGoroutines int `json:",omitempty"`
|
||||
MemoryLimit bool `json:",omitempty"`
|
||||
SwapLimit bool `json:",omitempty"`
|
||||
LXCVersion string `json:",omitempty"`
|
||||
NEventsListener int `json:",omitempty"`
|
||||
KernelVersion string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type APITop struct {
|
||||
Titles []string
|
||||
Processes [][]string
|
||||
}
|
||||
|
||||
type APIRmi struct {
|
||||
|
||||
615
api_test.go
@@ -5,7 +5,6 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/dotcloud/docker/auth"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"net"
|
||||
@@ -41,49 +40,9 @@ func TestGetBoolParam(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostAuth(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{
|
||||
runtime: runtime,
|
||||
}
|
||||
|
||||
r := httptest.NewRecorder()
|
||||
|
||||
authConfig := &auth.AuthConfig{
|
||||
Username: "utest",
|
||||
Password: "utest",
|
||||
Email: "utest@yopmail.com",
|
||||
}
|
||||
|
||||
authConfigJSON, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", "/auth", bytes.NewReader(authConfigJSON))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := postAuth(srv, APIVERSION, r, req, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if r.Code != http.StatusOK && r.Code != 0 {
|
||||
t.Fatalf("%d OK or 0 expected, received %d\n", http.StatusOK, r.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetVersion(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var err error
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -99,19 +58,21 @@ func TestGetVersion(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v.Version != VERSION {
|
||||
t.Errorf("Excepted version %s, %s found", VERSION, v.Version)
|
||||
t.Errorf("Expected version %s, %s found", VERSION, v.Version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetInfo(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
initialImages, err := srv.runtime.graph.All()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := httptest.NewRecorder()
|
||||
|
||||
if err := getInfo(srv, APIVERSION, r, nil, nil); err != nil {
|
||||
@@ -123,21 +84,62 @@ func TestGetInfo(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if infos.Images != 1 {
|
||||
t.Errorf("Excepted images: %d, %d found", 1, infos.Images)
|
||||
if infos.Images != len(initialImages) {
|
||||
t.Errorf("Expected images: %d, %d found", len(initialImages), infos.Images)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetImagesJSON(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
func TestGetEvents(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
srv := &Server{
|
||||
runtime: runtime,
|
||||
events: make([]utils.JSONMessage, 0, 64),
|
||||
listeners: make(map[string]chan utils.JSONMessage),
|
||||
}
|
||||
|
||||
srv.LogEvent("fakeaction", "fakeid")
|
||||
srv.LogEvent("fakeaction2", "fakeid")
|
||||
|
||||
req, err := http.NewRequest("GET", "/events?since=1", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := httptest.NewRecorder()
|
||||
setTimeout(t, "", 500*time.Millisecond, func() {
|
||||
if err := getEvents(srv, APIVERSION, r, req, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
dec := json.NewDecoder(r.Body)
|
||||
for i := 0; i < 2; i++ {
|
||||
var jm utils.JSONMessage
|
||||
if err := dec.Decode(&jm); err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if jm != srv.events[i] {
|
||||
t.Fatalf("Event received it different than expected")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetImagesJSON(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
// all=0
|
||||
|
||||
initialImages, err := srv.Images(false, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", "/images/json?all=0", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -154,17 +156,30 @@ func TestGetImagesJSON(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(images) != 1 {
|
||||
t.Errorf("Excepted 1 image, %d found", len(images))
|
||||
if len(images) != len(initialImages) {
|
||||
t.Errorf("Expected %d image, %d found", len(initialImages), len(images))
|
||||
}
|
||||
|
||||
if images[0].Repository != unitTestImageName {
|
||||
t.Errorf("Excepted image %s, %s found", unitTestImageName, images[0].Repository)
|
||||
found := false
|
||||
for _, img := range images {
|
||||
if img.Repository == unitTestImageName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("Expected image %s, %+v found", unitTestImageName, images)
|
||||
}
|
||||
|
||||
r2 := httptest.NewRecorder()
|
||||
|
||||
// all=1
|
||||
|
||||
initialImages, err = srv.Images(true, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
req2, err := http.NewRequest("GET", "/images/json?all=true", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -179,18 +194,25 @@ func TestGetImagesJSON(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(images2) != 1 {
|
||||
t.Errorf("Excepted 1 image, %d found", len(images2))
|
||||
if len(images2) != len(initialImages) {
|
||||
t.Errorf("Expected %d image, %d found", len(initialImages), len(images2))
|
||||
}
|
||||
|
||||
if images2[0].ID != GetTestImage(runtime).ID {
|
||||
t.Errorf("Retrieved image Id differs, expected %s, received %s", GetTestImage(runtime).ID, images2[0].ID)
|
||||
found = false
|
||||
for _, img := range images2 {
|
||||
if img.ID == GetTestImage(runtime).ID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("Retrieved image Id differs, expected %s, received %+v", GetTestImage(runtime).ID, images2)
|
||||
}
|
||||
|
||||
r3 := httptest.NewRecorder()
|
||||
|
||||
// filter=a
|
||||
req3, err := http.NewRequest("GET", "/images/json?filter=a", nil)
|
||||
req3, err := http.NewRequest("GET", "/images/json?filter=aaaaaaaaaa", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -205,7 +227,7 @@ func TestGetImagesJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
if len(images3) != 0 {
|
||||
t.Errorf("Excepted 1 image, %d found", len(images3))
|
||||
t.Errorf("Expected 0 image, %d found", len(images3))
|
||||
}
|
||||
|
||||
r4 := httptest.NewRecorder()
|
||||
@@ -228,10 +250,7 @@ func TestGetImagesJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetImagesViz(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -251,46 +270,12 @@ func TestGetImagesViz(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if line != "digraph docker {\n" {
|
||||
t.Errorf("Excepted digraph docker {\n, %s found", line)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetImagesSearch(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{
|
||||
runtime: runtime,
|
||||
}
|
||||
|
||||
r := httptest.NewRecorder()
|
||||
|
||||
req, err := http.NewRequest("GET", "/images/search?term=redis", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := getImagesSearch(srv, APIVERSION, r, req, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
results := []APISearch{}
|
||||
if err := json.Unmarshal(r.Body.Bytes(), &results); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(results) < 2 {
|
||||
t.Errorf("Excepted at least 2 lines, %d found", len(results))
|
||||
t.Errorf("Expected digraph docker {\n, %s found", line)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetImagesHistory(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -306,15 +291,12 @@ func TestGetImagesHistory(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(history) != 1 {
|
||||
t.Errorf("Excepted 1 line, %d found", len(history))
|
||||
t.Errorf("Expected 1 line, %d found", len(history))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetImagesByName(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -328,16 +310,13 @@ func TestGetImagesByName(t *testing.T) {
|
||||
if err := json.Unmarshal(r.Body.Bytes(), img); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if img.ID != GetTestImage(runtime).ID || img.Comment != "Imported from http://get.docker.io/images/busybox" {
|
||||
if img.ID != unitTestImageID {
|
||||
t.Errorf("Error inspecting image")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetContainersJSON(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -365,7 +344,7 @@ func TestGetContainersJSON(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(containers) != 1 {
|
||||
t.Fatalf("Excepted %d container, %d found", 1, len(containers))
|
||||
t.Fatalf("Expected %d container, %d found", 1, len(containers))
|
||||
}
|
||||
if containers[0].ID != container.ID {
|
||||
t.Fatalf("Container ID mismatch. Expected: %s, received: %s\n", container.ID, containers[0].ID)
|
||||
@@ -373,10 +352,7 @@ func TestGetContainersJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetContainersExport(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -428,10 +404,7 @@ func TestGetContainersExport(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetContainersChanges(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -475,7 +448,7 @@ func TestGetContainersChanges(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetContainersByName(t *testing.T) {
|
||||
func TestGetContainersTop(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -486,6 +459,67 @@ func TestGetContainersByName(t *testing.T) {
|
||||
|
||||
builder := NewBuilder(runtime)
|
||||
|
||||
container, err := builder.Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/sh", "-c", "sleep 2"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Give some time to the process to start
|
||||
container.WaitTimeout(500 * time.Millisecond)
|
||||
|
||||
if !container.State.Running {
|
||||
t.Errorf("Container should be running")
|
||||
}
|
||||
|
||||
r := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/"+container.ID+"/top?ps_args=u", bytes.NewReader([]byte{}))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := getContainersTop(srv, APIVERSION, r, req, map[string]string{"name": container.ID}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
procs := APITop{}
|
||||
if err := json.Unmarshal(r.Body.Bytes(), &procs); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(procs.Titles) != 11 {
|
||||
t.Fatalf("Expected 11 titles, found %d.", len(procs.Titles))
|
||||
}
|
||||
if procs.Titles[0] != "USER" || procs.Titles[10] != "COMMAND" {
|
||||
t.Fatalf("Expected Titles[0] to be USER and Titles[10] to be COMMAND, found %s and %s.", procs.Titles[0], procs.Titles[10])
|
||||
}
|
||||
|
||||
if len(procs.Processes) != 2 {
|
||||
t.Fatalf("Expected 2 processes, found %d.", len(procs.Processes))
|
||||
}
|
||||
if procs.Processes[0][10] != "/bin/sh" && procs.Processes[0][10] != "sleep" {
|
||||
t.Fatalf("Expected `sleep` or `/bin/sh`, found %s.", procs.Processes[0][10])
|
||||
}
|
||||
if procs.Processes[1][10] != "/bin/sh" && procs.Processes[1][10] != "sleep" {
|
||||
t.Fatalf("Expected `sleep` or `/bin/sh`, found %s.", procs.Processes[1][10])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetContainersByName(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
builder := NewBuilder(runtime)
|
||||
|
||||
// Create a container and remove a file
|
||||
container, err := builder.Create(
|
||||
&Config{
|
||||
@@ -512,10 +546,7 @@ func TestGetContainersByName(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostCommit(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -560,249 +591,8 @@ func TestPostCommit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostImagesCreate(t *testing.T) {
|
||||
// FIXME: Use the staging in order to perform tests
|
||||
|
||||
// runtime, err := newTestRuntime()
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// defer nuke(runtime)
|
||||
|
||||
// srv := &Server{runtime: runtime}
|
||||
|
||||
// stdin, stdinPipe := io.Pipe()
|
||||
// stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
// c1 := make(chan struct{})
|
||||
// go func() {
|
||||
// defer close(c1)
|
||||
|
||||
// r := &hijackTester{
|
||||
// ResponseRecorder: httptest.NewRecorder(),
|
||||
// in: stdin,
|
||||
// out: stdoutPipe,
|
||||
// }
|
||||
|
||||
// req, err := http.NewRequest("POST", "/images/create?fromImage="+unitTestImageName, bytes.NewReader([]byte{}))
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
// body, err := postImagesCreate(srv, r, req, nil)
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// if body != nil {
|
||||
// t.Fatalf("No body expected, received: %s\n", body)
|
||||
// }
|
||||
// }()
|
||||
|
||||
// // Acknowledge hijack
|
||||
// setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
|
||||
// stdout.Read([]byte{})
|
||||
// stdout.Read(make([]byte, 4096))
|
||||
// })
|
||||
|
||||
// setTimeout(t, "Waiting for imagesCreate output", 5*time.Second, func() {
|
||||
// reader := bufio.NewReader(stdout)
|
||||
// line, err := reader.ReadString('\n')
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// if !strings.HasPrefix(line, "Pulling repository d from") {
|
||||
// t.Fatalf("Expected Pulling repository docker-ut from..., found %s", line)
|
||||
// }
|
||||
// })
|
||||
|
||||
// // Close pipes (client disconnects)
|
||||
// if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
// // Wait for imagesCreate to finish, the client disconnected, therefore, Create finished his job
|
||||
// setTimeout(t, "Waiting for imagesCreate timed out", 10*time.Second, func() {
|
||||
// <-c1
|
||||
// })
|
||||
}
|
||||
|
||||
func TestPostImagesInsert(t *testing.T) {
|
||||
// runtime, err := newTestRuntime()
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// defer nuke(runtime)
|
||||
|
||||
// srv := &Server{runtime: runtime}
|
||||
|
||||
// stdin, stdinPipe := io.Pipe()
|
||||
// stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
// // Attach to it
|
||||
// c1 := make(chan struct{})
|
||||
// go func() {
|
||||
// defer close(c1)
|
||||
// r := &hijackTester{
|
||||
// ResponseRecorder: httptest.NewRecorder(),
|
||||
// in: stdin,
|
||||
// out: stdoutPipe,
|
||||
// }
|
||||
|
||||
// req, err := http.NewRequest("POST", "/images/"+unitTestImageName+"/insert?path=%2Ftest&url=https%3A%2F%2Fraw.github.com%2Fdotcloud%2Fdocker%2Fmaster%2FREADME.md", bytes.NewReader([]byte{}))
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// if err := postContainersCreate(srv, r, req, nil); err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// }()
|
||||
|
||||
// // Acknowledge hijack
|
||||
// setTimeout(t, "hijack acknowledge timed out", 5*time.Second, func() {
|
||||
// stdout.Read([]byte{})
|
||||
// stdout.Read(make([]byte, 4096))
|
||||
// })
|
||||
|
||||
// id := ""
|
||||
// setTimeout(t, "Waiting for imagesInsert output", 10*time.Second, func() {
|
||||
// for {
|
||||
// reader := bufio.NewReader(stdout)
|
||||
// id, err = reader.ReadString('\n')
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
|
||||
// // Close pipes (client disconnects)
|
||||
// if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
// // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
|
||||
// setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
|
||||
// <-c1
|
||||
// })
|
||||
|
||||
// img, err := srv.runtime.repositories.LookupImage(id)
|
||||
// if err != nil {
|
||||
// t.Fatalf("New image %s expected but not found", id)
|
||||
// }
|
||||
|
||||
// layer, err := img.layer()
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
// if _, err := os.Stat(path.Join(layer, "test")); err != nil {
|
||||
// t.Fatalf("The test file has not been found")
|
||||
// }
|
||||
|
||||
// if err := srv.runtime.graph.Delete(img.ID); err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
}
|
||||
|
||||
func TestPostImagesPush(t *testing.T) {
|
||||
//FIXME: Use staging in order to perform tests
|
||||
// runtime, err := newTestRuntime()
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// defer nuke(runtime)
|
||||
|
||||
// srv := &Server{runtime: runtime}
|
||||
|
||||
// stdin, stdinPipe := io.Pipe()
|
||||
// stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
// c1 := make(chan struct{})
|
||||
// go func() {
|
||||
// r := &hijackTester{
|
||||
// ResponseRecorder: httptest.NewRecorder(),
|
||||
// in: stdin,
|
||||
// out: stdoutPipe,
|
||||
// }
|
||||
|
||||
// req, err := http.NewRequest("POST", "/images/docker-ut/push", bytes.NewReader([]byte{}))
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
// body, err := postImagesPush(srv, r, req, map[string]string{"name": "docker-ut"})
|
||||
// close(c1)
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// if body != nil {
|
||||
// t.Fatalf("No body expected, received: %s\n", body)
|
||||
// }
|
||||
// }()
|
||||
|
||||
// // Acknowledge hijack
|
||||
// setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
|
||||
// stdout.Read([]byte{})
|
||||
// stdout.Read(make([]byte, 4096))
|
||||
// })
|
||||
|
||||
// setTimeout(t, "Waiting for imagesCreate output", 5*time.Second, func() {
|
||||
// reader := bufio.NewReader(stdout)
|
||||
// line, err := reader.ReadString('\n')
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// if !strings.HasPrefix(line, "Processing checksum") {
|
||||
// t.Fatalf("Processing checksum..., found %s", line)
|
||||
// }
|
||||
// })
|
||||
|
||||
// // Close pipes (client disconnects)
|
||||
// if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
// // Wait for imagesPush to finish, the client disconnected, therefore, Push finished his job
|
||||
// setTimeout(t, "Waiting for imagesPush timed out", 10*time.Second, func() {
|
||||
// <-c1
|
||||
// })
|
||||
}
|
||||
|
||||
func TestPostImagesTag(t *testing.T) {
|
||||
// FIXME: Use staging in order to perform tests
|
||||
|
||||
// runtime, err := newTestRuntime()
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// defer nuke(runtime)
|
||||
|
||||
// srv := &Server{runtime: runtime}
|
||||
|
||||
// r := httptest.NewRecorder()
|
||||
|
||||
// req, err := http.NewRequest("POST", "/images/docker-ut/tag?repo=testrepo&tag=testtag", bytes.NewReader([]byte{}))
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
// body, err := postImagesTag(srv, r, req, map[string]string{"name": "docker-ut"})
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
// if body != nil {
|
||||
// t.Fatalf("No body expected, received: %s\n", body)
|
||||
// }
|
||||
// if r.Code != http.StatusCreated {
|
||||
// t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
|
||||
// }
|
||||
}
|
||||
|
||||
func TestPostContainersCreate(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -853,10 +643,7 @@ func TestPostContainersCreate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostContainersKill(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -898,10 +685,7 @@ func TestPostContainersKill(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostContainersRestart(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -955,10 +739,7 @@ func TestPostContainersRestart(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostContainersStart(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -1008,10 +789,7 @@ func TestPostContainersStart(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostContainersStop(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -1058,10 +836,7 @@ func TestPostContainersStop(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostContainersWait(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -1103,10 +878,7 @@ func TestPostContainersWait(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostContainersAttach(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -1132,6 +904,12 @@ func TestPostContainersAttach(t *testing.T) {
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
// Try to avoid the timeoout in destroy. Best effort, don't check error
|
||||
defer func() {
|
||||
closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
|
||||
container.Kill()
|
||||
}()
|
||||
|
||||
// Attach to it
|
||||
c1 := make(chan struct{})
|
||||
go func() {
|
||||
@@ -1171,7 +949,7 @@ func TestPostContainersAttach(t *testing.T) {
|
||||
}
|
||||
|
||||
// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
|
||||
setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
|
||||
setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
|
||||
<-c1
|
||||
})
|
||||
|
||||
@@ -1192,10 +970,7 @@ func TestPostContainersAttach(t *testing.T) {
|
||||
// FIXME: Test deleting container with volume
|
||||
// FIXME: Test deleting volume in use by other container
|
||||
func TestDeleteContainers(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -1235,10 +1010,7 @@ func TestDeleteContainers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOptionsRoute(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime, enableCors: true}
|
||||
@@ -1261,10 +1033,7 @@ func TestOptionsRoute(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetEnabledCors(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime, enableCors: true}
|
||||
@@ -1302,14 +1071,16 @@ func TestGetEnabledCors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDeleteImages(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
initialImages, err := srv.Images(false, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := srv.runtime.repositories.Set("test", "test", unitTestImageName, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1319,25 +1090,35 @@ func TestDeleteImages(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(images) != 2 {
|
||||
t.Errorf("Excepted 2 images, %d found", len(images))
|
||||
if len(images) != len(initialImages)+1 {
|
||||
t.Errorf("Expected %d images, %d found", len(initialImages)+1, len(images))
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("DELETE", "/images/test:test", nil)
|
||||
req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := httptest.NewRecorder()
|
||||
if err := deleteImages(srv, APIVERSION, r, req, map[string]string{"name": "test:test"}); err != nil {
|
||||
if err := deleteImages(srv, APIVERSION, r, req, map[string]string{"name": unitTestImageID}); err == nil {
|
||||
t.Fatalf("Expected conflict error, got none")
|
||||
}
|
||||
|
||||
req2, err := http.NewRequest("DELETE", "/images/test:test", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if r.Code != http.StatusOK {
|
||||
|
||||
r2 := httptest.NewRecorder()
|
||||
if err := deleteImages(srv, APIVERSION, r2, req2, map[string]string{"name": "test:test"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if r2.Code != http.StatusOK {
|
||||
t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
|
||||
}
|
||||
|
||||
var outs []APIRmi
|
||||
if err := json.Unmarshal(r.Body.Bytes(), &outs); err != nil {
|
||||
if err := json.Unmarshal(r2.Body.Bytes(), &outs); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(outs) != 1 {
|
||||
@@ -1348,8 +1129,8 @@ func TestDeleteImages(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(images) != 1 {
|
||||
t.Errorf("Excepted 1 image, %d found", len(images))
|
||||
if len(images) != len(initialImages) {
|
||||
t.Errorf("Expected %d image, %d found", len(initialImages), len(images))
|
||||
}
|
||||
|
||||
/* if c := runtime.Get(container.Id); c != nil {
|
||||
|
||||
27
archive.go
@@ -2,9 +2,7 @@ package docker
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
@@ -27,10 +25,6 @@ const (
|
||||
)
|
||||
|
||||
func DetectCompression(source []byte) Compression {
|
||||
for _, c := range source[:10] {
|
||||
utils.Debugf("%x", c)
|
||||
}
|
||||
|
||||
sourceLen := len(source)
|
||||
for compression, m := range map[Compression][]byte{
|
||||
Bzip2: {0x42, 0x5A, 0x68},
|
||||
@@ -111,17 +105,26 @@ func Untar(archive io.Reader, path string) error {
|
||||
if archive == nil {
|
||||
return fmt.Errorf("Empty archive")
|
||||
}
|
||||
bufferedArchive := bufio.NewReaderSize(archive, 10)
|
||||
buf, err := bufferedArchive.Peek(10)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
buf := make([]byte, 10)
|
||||
totalN := 0
|
||||
for totalN < 10 {
|
||||
if n, err := archive.Read(buf[totalN:]); err != nil {
|
||||
if err == io.EOF {
|
||||
return fmt.Errorf("Tarball too short")
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
totalN += n
|
||||
utils.Debugf("[tar autodetect] n: %d", n)
|
||||
}
|
||||
}
|
||||
compression := DetectCompression(buf)
|
||||
|
||||
utils.Debugf("Archive compression detected: %s", compression.Extension())
|
||||
|
||||
cmd := exec.Command("tar", "--numeric-owner", "-f", "-", "-C", path, "-x"+compression.Flag())
|
||||
cmd.Stdin = bufferedArchive
|
||||
cmd.Stdin = io.MultiReader(bytes.NewReader(buf), archive)
|
||||
// Hardcode locale environment for predictable outcome regardless of host configuration.
|
||||
// (see https://github.com/dotcloud/docker/issues/355)
|
||||
cmd.Env = []string{"LANG=en_US.utf-8", "LC_ALL=en_US.utf-8"}
|
||||
@@ -251,7 +254,7 @@ func CmdStream(cmd *exec.Cmd) (io.Reader, error) {
|
||||
}
|
||||
errText := <-errChan
|
||||
if err := cmd.Wait(); err != nil {
|
||||
pipeW.CloseWithError(errors.New(err.Error() + ": " + string(errText)))
|
||||
pipeW.CloseWithError(fmt.Errorf("%s: %s", err, errText))
|
||||
} else {
|
||||
pipeW.Close()
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ func TestCmdStreamLargeStderr(t *testing.T) {
|
||||
cmd := exec.Command("/bin/sh", "-c", "dd if=/dev/zero bs=1k count=1000 of=/dev/stderr; echo hello")
|
||||
out, err := CmdStream(cmd)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start command: " + err.Error())
|
||||
t.Fatalf("Failed to start command: %s", err)
|
||||
}
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
@@ -26,7 +26,7 @@ func TestCmdStreamLargeStderr(t *testing.T) {
|
||||
select {
|
||||
case err := <-errCh:
|
||||
if err != nil {
|
||||
t.Fatalf("Command should not have failed (err=%s...)", err.Error()[:100])
|
||||
t.Fatalf("Command should not have failed (err=%.100s...)", err)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("Command did not complete in 5 seconds; probable deadlock")
|
||||
@@ -37,12 +37,12 @@ func TestCmdStreamBad(t *testing.T) {
|
||||
badCmd := exec.Command("/bin/sh", "-c", "echo hello; echo >&2 error couldn\\'t reverse the phase pulser; exit 1")
|
||||
out, err := CmdStream(badCmd)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start command: " + err.Error())
|
||||
t.Fatalf("Failed to start command: %s", err)
|
||||
}
|
||||
if output, err := ioutil.ReadAll(out); err == nil {
|
||||
t.Fatalf("Command should have failed")
|
||||
} else if err.Error() != "exit status 1: error couldn't reverse the phase pulser\n" {
|
||||
t.Fatalf("Wrong error value (%s)", err.Error())
|
||||
t.Fatalf("Wrong error value (%s)", err)
|
||||
} else if s := string(output); s != "hello\n" {
|
||||
t.Fatalf("Command output should be '%s', not '%s'", "hello\\n", output)
|
||||
}
|
||||
|
||||
123
auth/auth.go
@@ -15,8 +15,8 @@ import (
|
||||
// Where we store the config file
|
||||
const CONFIGFILE = ".dockercfg"
|
||||
|
||||
// the registry server we want to login against
|
||||
const INDEXSERVER = "https://index.docker.io/v1"
|
||||
// Only used for user auth + account creation
|
||||
const INDEXSERVER = "https://index.docker.io/v1/"
|
||||
|
||||
//const INDEXSERVER = "http://indexstaging-docker.dotcloud.com/"
|
||||
|
||||
@@ -25,25 +25,18 @@ var (
|
||||
)
|
||||
|
||||
type AuthConfig struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Auth string `json:"auth"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
type ConfigFile struct {
|
||||
Configs map[string]AuthConfig `json:"configs,omitempty"`
|
||||
rootPath string
|
||||
}
|
||||
|
||||
func NewAuthConfig(username, password, email, rootPath string) *AuthConfig {
|
||||
return &AuthConfig{
|
||||
Username: username,
|
||||
Password: password,
|
||||
Email: email,
|
||||
rootPath: rootPath,
|
||||
}
|
||||
}
|
||||
|
||||
func IndexServerAddress() string {
|
||||
if os.Getenv("DOCKER_INDEX_URL") != "" {
|
||||
return os.Getenv("DOCKER_INDEX_URL") + "/v1"
|
||||
}
|
||||
return INDEXSERVER
|
||||
}
|
||||
|
||||
@@ -57,61 +50,89 @@ func encodeAuth(authConfig *AuthConfig) string {
|
||||
}
|
||||
|
||||
// decode the auth string
|
||||
func decodeAuth(authStr string) (*AuthConfig, error) {
|
||||
func decodeAuth(authStr string) (string, string, error) {
|
||||
decLen := base64.StdEncoding.DecodedLen(len(authStr))
|
||||
decoded := make([]byte, decLen)
|
||||
authByte := []byte(authStr)
|
||||
n, err := base64.StdEncoding.Decode(decoded, authByte)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", "", err
|
||||
}
|
||||
if n > decLen {
|
||||
return nil, fmt.Errorf("Something went wrong decoding auth config")
|
||||
return "", "", fmt.Errorf("Something went wrong decoding auth config")
|
||||
}
|
||||
arr := strings.Split(string(decoded), ":")
|
||||
if len(arr) != 2 {
|
||||
return nil, fmt.Errorf("Invalid auth configuration file")
|
||||
return "", "", fmt.Errorf("Invalid auth configuration file")
|
||||
}
|
||||
password := strings.Trim(arr[1], "\x00")
|
||||
return &AuthConfig{Username: arr[0], Password: password}, nil
|
||||
return arr[0], password, nil
|
||||
}
|
||||
|
||||
// load up the auth config information and return values
|
||||
// FIXME: use the internal golang config parser
|
||||
func LoadConfig(rootPath string) (*AuthConfig, error) {
|
||||
func LoadConfig(rootPath string) (*ConfigFile, error) {
|
||||
configFile := ConfigFile{Configs: make(map[string]AuthConfig), rootPath: rootPath}
|
||||
confFile := path.Join(rootPath, CONFIGFILE)
|
||||
if _, err := os.Stat(confFile); err != nil {
|
||||
return &AuthConfig{rootPath: rootPath}, ErrConfigFileMissing
|
||||
return &configFile, ErrConfigFileMissing
|
||||
}
|
||||
b, err := ioutil.ReadFile(confFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
arr := strings.Split(string(b), "\n")
|
||||
if len(arr) < 2 {
|
||||
return nil, fmt.Errorf("The Auth config file is empty")
|
||||
|
||||
if err := json.Unmarshal(b, &configFile.Configs); err != nil {
|
||||
arr := strings.Split(string(b), "\n")
|
||||
if len(arr) < 2 {
|
||||
return nil, fmt.Errorf("The Auth config file is empty")
|
||||
}
|
||||
authConfig := AuthConfig{}
|
||||
origAuth := strings.Split(arr[0], " = ")
|
||||
authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
origEmail := strings.Split(arr[1], " = ")
|
||||
authConfig.Email = origEmail[1]
|
||||
configFile.Configs[IndexServerAddress()] = authConfig
|
||||
} else {
|
||||
for k, authConfig := range configFile.Configs {
|
||||
authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authConfig.Auth = ""
|
||||
configFile.Configs[k] = authConfig
|
||||
}
|
||||
}
|
||||
origAuth := strings.Split(arr[0], " = ")
|
||||
origEmail := strings.Split(arr[1], " = ")
|
||||
authConfig, err := decodeAuth(origAuth[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authConfig.Email = origEmail[1]
|
||||
authConfig.rootPath = rootPath
|
||||
return authConfig, nil
|
||||
return &configFile, nil
|
||||
}
|
||||
|
||||
// save the auth config
|
||||
func SaveConfig(authConfig *AuthConfig) error {
|
||||
confFile := path.Join(authConfig.rootPath, CONFIGFILE)
|
||||
if len(authConfig.Email) == 0 {
|
||||
func SaveConfig(configFile *ConfigFile) error {
|
||||
confFile := path.Join(configFile.rootPath, CONFIGFILE)
|
||||
if len(configFile.Configs) == 0 {
|
||||
os.Remove(confFile)
|
||||
return nil
|
||||
}
|
||||
lines := "auth = " + encodeAuth(authConfig) + "\n" + "email = " + authConfig.Email + "\n"
|
||||
b := []byte(lines)
|
||||
err := ioutil.WriteFile(confFile, b, 0600)
|
||||
|
||||
configs := make(map[string]AuthConfig, len(configFile.Configs))
|
||||
for k, authConfig := range configFile.Configs {
|
||||
authCopy := authConfig
|
||||
|
||||
authCopy.Auth = encodeAuth(&authCopy)
|
||||
authCopy.Username = ""
|
||||
authCopy.Password = ""
|
||||
|
||||
configs[k] = authCopy
|
||||
}
|
||||
|
||||
b, err := json.Marshal(configs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(confFile, b, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -119,8 +140,7 @@ func SaveConfig(authConfig *AuthConfig) error {
|
||||
}
|
||||
|
||||
// try to register/login to the registry server
|
||||
func Login(authConfig *AuthConfig, store bool) (string, error) {
|
||||
storeConfig := false
|
||||
func Login(authConfig *AuthConfig) (string, error) {
|
||||
client := &http.Client{}
|
||||
reqStatusCode := 0
|
||||
var status string
|
||||
@@ -132,7 +152,7 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
|
||||
|
||||
// using `bytes.NewReader(jsonBody)` here causes the server to respond with a 411 status.
|
||||
b := strings.NewReader(string(jsonBody))
|
||||
req1, err := http.Post(IndexServerAddress()+"/users/", "application/json; charset=utf-8", b)
|
||||
req1, err := http.Post(IndexServerAddress()+"users/", "application/json; charset=utf-8", b)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Server Error: %s", err)
|
||||
}
|
||||
@@ -146,13 +166,12 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
|
||||
if reqStatusCode == 201 {
|
||||
status = "Account created. Please use the confirmation link we sent" +
|
||||
" to your e-mail to activate it."
|
||||
storeConfig = true
|
||||
} else if reqStatusCode == 403 {
|
||||
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
|
||||
"Please check your e-mail for a confirmation link.")
|
||||
} else if reqStatusCode == 400 {
|
||||
if string(reqBody) == "\"Username or email already exists\"" {
|
||||
req, err := http.NewRequest("GET", IndexServerAddress()+"/users/", nil)
|
||||
req, err := http.NewRequest("GET", IndexServerAddress()+"users/", nil)
|
||||
req.SetBasicAuth(authConfig.Username, authConfig.Password)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
@@ -165,14 +184,7 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
|
||||
}
|
||||
if resp.StatusCode == 200 {
|
||||
status = "Login Succeeded"
|
||||
storeConfig = true
|
||||
} else if resp.StatusCode == 401 {
|
||||
if store {
|
||||
authConfig.Email = ""
|
||||
if err := SaveConfig(authConfig); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("Wrong login/password, please try again")
|
||||
} else {
|
||||
return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body,
|
||||
@@ -184,10 +196,5 @@ func Login(authConfig *AuthConfig, store bool) (string, error) {
|
||||
} else {
|
||||
return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody)
|
||||
}
|
||||
if storeConfig && store {
|
||||
if err := SaveConfig(authConfig); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package auth
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -11,7 +12,9 @@ import (
|
||||
func TestEncodeAuth(t *testing.T) {
|
||||
newAuthConfig := &AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"}
|
||||
authStr := encodeAuth(newAuthConfig)
|
||||
decAuthConfig, err := decodeAuth(authStr)
|
||||
decAuthConfig := &AuthConfig{}
|
||||
var err error
|
||||
decAuthConfig.Username, decAuthConfig.Password, err = decodeAuth(authStr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -29,8 +32,8 @@ func TestEncodeAuth(t *testing.T) {
|
||||
func TestLogin(t *testing.T) {
|
||||
os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
|
||||
defer os.Setenv("DOCKER_INDEX_URL", "")
|
||||
authConfig := NewAuthConfig("unittester", "surlautrerivejetattendrai", "noise+unittester@dotcloud.com", "/tmp")
|
||||
status, err := Login(authConfig, false)
|
||||
authConfig := &AuthConfig{Username: "unittester", Password: "surlautrerivejetattendrai", Email: "noise+unittester@dotcloud.com"}
|
||||
status, err := Login(authConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -49,8 +52,8 @@ func TestCreateAccount(t *testing.T) {
|
||||
}
|
||||
token := hex.EncodeToString(tokenBuffer)[:12]
|
||||
username := "ut" + token
|
||||
authConfig := NewAuthConfig(username, "test42", "docker-ut+"+token+"@example.com", "/tmp")
|
||||
status, err := Login(authConfig, false)
|
||||
authConfig := &AuthConfig{Username: username, Password: "test42", Email: "docker-ut+" + token + "@example.com"}
|
||||
status, err := Login(authConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -60,7 +63,7 @@ func TestCreateAccount(t *testing.T) {
|
||||
t.Fatalf("Expected status: \"%s\", found \"%s\" instead.", expectedStatus, status)
|
||||
}
|
||||
|
||||
status, err = Login(authConfig, false)
|
||||
status, err = Login(authConfig)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected error but found nil instead")
|
||||
}
|
||||
@@ -68,6 +71,42 @@ func TestCreateAccount(t *testing.T) {
|
||||
expectedError := "Login: Account is not Active"
|
||||
|
||||
if !strings.Contains(err.Error(), expectedError) {
|
||||
t.Fatalf("Expected message \"%s\" but found \"%s\" instead", expectedError, err.Error())
|
||||
t.Fatalf("Expected message \"%s\" but found \"%s\" instead", expectedError, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSameAuthDataPostSave(t *testing.T) {
|
||||
root, err := ioutil.TempDir("", "docker-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
configFile := &ConfigFile{
|
||||
rootPath: root,
|
||||
Configs: make(map[string]AuthConfig, 1),
|
||||
}
|
||||
|
||||
configFile.Configs["testIndex"] = AuthConfig{
|
||||
Username: "docker-user",
|
||||
Password: "docker-pass",
|
||||
Email: "docker@docker.io",
|
||||
}
|
||||
|
||||
err = SaveConfig(configFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
authConfig := configFile.Configs["testIndex"]
|
||||
if authConfig.Username != "docker-user" {
|
||||
t.Fail()
|
||||
}
|
||||
if authConfig.Password != "docker-pass" {
|
||||
t.Fail()
|
||||
}
|
||||
if authConfig.Email != "docker@docker.io" {
|
||||
t.Fail()
|
||||
}
|
||||
if authConfig.Auth != "" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
19
builder.go
@@ -50,12 +50,23 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
|
||||
config.Hostname = id[:12]
|
||||
}
|
||||
|
||||
var args []string
|
||||
var entrypoint string
|
||||
|
||||
if len(config.Entrypoint) != 0 {
|
||||
entrypoint = config.Entrypoint[0]
|
||||
args = append(config.Entrypoint[1:], config.Cmd...)
|
||||
} else {
|
||||
entrypoint = config.Cmd[0]
|
||||
args = config.Cmd[1:]
|
||||
}
|
||||
|
||||
container := &Container{
|
||||
// FIXME: we should generate the ID here instead of receiving it as an argument
|
||||
ID: id,
|
||||
Created: time.Now(),
|
||||
Path: config.Cmd[0],
|
||||
Args: config.Cmd[1:], //FIXME: de-duplicate from config
|
||||
Path: entrypoint,
|
||||
Args: args, //FIXME: de-duplicate from config
|
||||
Config: config,
|
||||
Image: img.ID, // Always use the resolved image id
|
||||
NetworkSettings: &NetworkSettings{},
|
||||
@@ -113,6 +124,10 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
|
||||
func (builder *Builder) Commit(container *Container, repository, tag, comment, author string, config *Config) (*Image, error) {
|
||||
// FIXME: freeze the container before copying it to avoid data corruption?
|
||||
// FIXME: this shouldn't be in commands.
|
||||
if err := container.EnsureMounted(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rwTar, err := container.ExportRw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
164
buildfile.go
@@ -7,9 +7,11 @@ import (
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -28,6 +30,7 @@ type buildFile struct {
|
||||
maintainer string
|
||||
config *Config
|
||||
context string
|
||||
verbose bool
|
||||
|
||||
tmpContainers map[string]struct{}
|
||||
tmpImages map[string]struct{}
|
||||
@@ -51,20 +54,10 @@ func (b *buildFile) CmdFrom(name string) error {
|
||||
image, err := b.runtime.repositories.LookupImage(name)
|
||||
if err != nil {
|
||||
if b.runtime.graph.IsNotExist(err) {
|
||||
|
||||
var tag, remote string
|
||||
if strings.Contains(name, ":") {
|
||||
remoteParts := strings.Split(name, ":")
|
||||
tag = remoteParts[1]
|
||||
remote = remoteParts[0]
|
||||
} else {
|
||||
remote = name
|
||||
}
|
||||
|
||||
if err := b.srv.ImagePull(remote, tag, "", b.out, utils.NewStreamFormatter(false), nil); err != nil {
|
||||
remote, tag := utils.ParseRepositoryTag(name)
|
||||
if err := b.srv.ImagePull(remote, tag, b.out, utils.NewStreamFormatter(false), nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
image, err = b.runtime.repositories.LookupImage(name)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -75,6 +68,9 @@ func (b *buildFile) CmdFrom(name string) error {
|
||||
}
|
||||
b.image = image.ID
|
||||
b.config = &Config{}
|
||||
if b.config.Env == nil || len(b.config.Env) == 0 {
|
||||
b.config.Env = append(b.config.Env, "HOME=/", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -120,6 +116,40 @@ func (b *buildFile) CmdRun(args string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *buildFile) FindEnvKey(key string) int {
|
||||
for k, envVar := range b.config.Env {
|
||||
envParts := strings.SplitN(envVar, "=", 2)
|
||||
if key == envParts[0] {
|
||||
return k
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (b *buildFile) ReplaceEnvMatches(value string) (string, error) {
|
||||
exp, err := regexp.Compile("(\\\\\\\\+|[^\\\\]|\\b|\\A)\\$({?)([[:alnum:]_]+)(}?)")
|
||||
if err != nil {
|
||||
return value, err
|
||||
}
|
||||
matches := exp.FindAllString(value, -1)
|
||||
for _, match := range matches {
|
||||
match = match[strings.Index(match, "$"):]
|
||||
matchKey := strings.Trim(match, "${}")
|
||||
|
||||
for _, envVar := range b.config.Env {
|
||||
envParts := strings.SplitN(envVar, "=", 2)
|
||||
envKey := envParts[0]
|
||||
envValue := envParts[1]
|
||||
|
||||
if envKey == matchKey {
|
||||
value = strings.Replace(value, match, envValue, -1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (b *buildFile) CmdEnv(args string) error {
|
||||
tmp := strings.SplitN(args, " ", 2)
|
||||
if len(tmp) != 2 {
|
||||
@@ -128,20 +158,25 @@ func (b *buildFile) CmdEnv(args string) error {
|
||||
key := strings.Trim(tmp[0], " \t")
|
||||
value := strings.Trim(tmp[1], " \t")
|
||||
|
||||
for i, elem := range b.config.Env {
|
||||
if strings.HasPrefix(elem, key+"=") {
|
||||
b.config.Env[i] = key + "=" + value
|
||||
return nil
|
||||
}
|
||||
envKey := b.FindEnvKey(key)
|
||||
replacedValue, err := b.ReplaceEnvMatches(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.config.Env = append(b.config.Env, key+"="+value)
|
||||
return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s=%s", key, value))
|
||||
replacedVar := fmt.Sprintf("%s=%s", key, replacedValue)
|
||||
|
||||
if envKey >= 0 {
|
||||
b.config.Env[envKey] = replacedVar
|
||||
return nil
|
||||
}
|
||||
b.config.Env = append(b.config.Env, replacedVar)
|
||||
return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s", replacedVar))
|
||||
}
|
||||
|
||||
func (b *buildFile) CmdCmd(args string) error {
|
||||
var cmd []string
|
||||
if err := json.Unmarshal([]byte(args), &cmd); err != nil {
|
||||
utils.Debugf("Error unmarshalling: %s, using /bin/sh -c", err)
|
||||
utils.Debugf("Error unmarshalling: %s, setting cmd to /bin/sh -c", err)
|
||||
cmd = []string{"/bin/sh", "-c", args}
|
||||
}
|
||||
if err := b.commit("", cmd, fmt.Sprintf("CMD %v", cmd)); err != nil {
|
||||
@@ -165,6 +200,44 @@ func (b *buildFile) CmdCopy(args string) error {
|
||||
return fmt.Errorf("COPY has been deprecated. Please use ADD instead")
|
||||
}
|
||||
|
||||
func (b *buildFile) CmdEntrypoint(args string) error {
|
||||
if args == "" {
|
||||
return fmt.Errorf("Entrypoint cannot be empty")
|
||||
}
|
||||
|
||||
var entrypoint []string
|
||||
if err := json.Unmarshal([]byte(args), &entrypoint); err != nil {
|
||||
b.config.Entrypoint = []string{"/bin/sh", "-c", args}
|
||||
} else {
|
||||
b.config.Entrypoint = entrypoint
|
||||
}
|
||||
if err := b.commit("", b.config.Cmd, fmt.Sprintf("ENTRYPOINT %s", args)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *buildFile) CmdVolume(args string) error {
|
||||
if args == "" {
|
||||
return fmt.Errorf("Volume cannot be empty")
|
||||
}
|
||||
|
||||
var volume []string
|
||||
if err := json.Unmarshal([]byte(args), &volume); err != nil {
|
||||
volume = []string{args}
|
||||
}
|
||||
if b.config.Volumes == nil {
|
||||
b.config.Volumes = NewPathOpts()
|
||||
}
|
||||
for _, v := range volume {
|
||||
b.config.Volumes[v] = struct{}{}
|
||||
}
|
||||
if err := b.commit("", b.config.Cmd, fmt.Sprintf("VOLUME %s", args)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *buildFile) addRemote(container *Container, orig, dest string) error {
|
||||
file, err := utils.Download(orig, ioutil.Discard)
|
||||
if err != nil {
|
||||
@@ -172,6 +245,24 @@ func (b *buildFile) addRemote(container *Container, orig, dest string) error {
|
||||
}
|
||||
defer file.Body.Close()
|
||||
|
||||
// If the destination is a directory, figure out the filename.
|
||||
if strings.HasSuffix(dest, "/") {
|
||||
u, err := url.Parse(orig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := u.Path
|
||||
if strings.HasSuffix(path, "/") {
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
parts := strings.Split(path, "/")
|
||||
filename := parts[len(parts)-1]
|
||||
if filename == "" {
|
||||
return fmt.Errorf("cannot determine filename from url: %s", u)
|
||||
}
|
||||
dest = dest + filename
|
||||
}
|
||||
|
||||
return container.Inject(file.Body, dest)
|
||||
}
|
||||
|
||||
@@ -179,9 +270,12 @@ func (b *buildFile) addContext(container *Container, orig, dest string) error {
|
||||
origPath := path.Join(b.context, orig)
|
||||
destPath := path.Join(container.RootfsPath(), dest)
|
||||
// Preserve the trailing '/'
|
||||
if dest[len(dest)-1] == '/' {
|
||||
if strings.HasSuffix(dest, "/") {
|
||||
destPath = destPath + "/"
|
||||
}
|
||||
if !strings.HasPrefix(origPath, b.context) {
|
||||
return fmt.Errorf("Forbidden path: %s", origPath)
|
||||
}
|
||||
fi, err := os.Stat(origPath)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -194,7 +288,7 @@ func (b *buildFile) addContext(container *Container, orig, dest string) error {
|
||||
} else if err := UntarPath(origPath, destPath); err != nil {
|
||||
utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err)
|
||||
// If that fails, just copy it as a regular file
|
||||
if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil {
|
||||
if err := os.MkdirAll(path.Dir(destPath), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := CopyWithTar(origPath, destPath); err != nil {
|
||||
@@ -212,8 +306,16 @@ func (b *buildFile) CmdAdd(args string) error {
|
||||
if len(tmp) != 2 {
|
||||
return fmt.Errorf("Invalid ADD format")
|
||||
}
|
||||
orig := strings.Trim(tmp[0], " \t")
|
||||
dest := strings.Trim(tmp[1], " \t")
|
||||
|
||||
orig, err := b.ReplaceEnvMatches(strings.Trim(tmp[0], " \t"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dest, err := b.ReplaceEnvMatches(strings.Trim(tmp[1], " \t"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := b.config.Cmd
|
||||
b.config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) ADD %s in %s", orig, dest)}
|
||||
@@ -262,12 +364,23 @@ func (b *buildFile) run() (string, error) {
|
||||
b.tmpContainers[c.ID] = struct{}{}
|
||||
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID))
|
||||
|
||||
// override the entry point that may have been picked up from the base image
|
||||
c.Path = b.config.Cmd[0]
|
||||
c.Args = b.config.Cmd[1:]
|
||||
|
||||
//start the container
|
||||
hostConfig := &HostConfig{}
|
||||
if err := c.Start(hostConfig); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if b.verbose {
|
||||
err = <-c.Attach(nil, nil, b.out, b.out)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for it to finish
|
||||
if ret := c.Wait(); ret != 0 {
|
||||
return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret)
|
||||
@@ -390,7 +503,7 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
|
||||
return "", fmt.Errorf("An error occured during the build\n")
|
||||
}
|
||||
|
||||
func NewBuildFile(srv *Server, out io.Writer) BuildFile {
|
||||
func NewBuildFile(srv *Server, out io.Writer, verbose bool) BuildFile {
|
||||
return &buildFile{
|
||||
builder: NewBuilder(srv.runtime),
|
||||
runtime: srv.runtime,
|
||||
@@ -399,5 +512,6 @@ func NewBuildFile(srv *Server, out io.Writer) BuildFile {
|
||||
out: out,
|
||||
tmpContainers: make(map[string]struct{}),
|
||||
tmpImages: make(map[string]struct{}),
|
||||
verbose: verbose,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
"testing"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// mkTestContext generates a build context from the contents of the provided dockerfile.
|
||||
// This context is suitable for use as an argument to BuildFile.Build()
|
||||
func mkTestContext(dockerfile string, files [][2]string, t *testing.T) Archive {
|
||||
context, err := mkBuildContext(fmt.Sprintf(dockerfile, unitTestImageId), files)
|
||||
context, err := mkBuildContext(dockerfile, files)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -23,34 +26,40 @@ type testContextTemplate struct {
|
||||
dockerfile string
|
||||
// Additional files in the context, eg [][2]string{"./passwd", "gordon"}
|
||||
files [][2]string
|
||||
// Additional remote files to host on a local HTTP server.
|
||||
remoteFiles [][2]string
|
||||
}
|
||||
|
||||
// A table of all the contexts to build and test.
|
||||
// A new docker runtime will be created and torn down for each context.
|
||||
var testContexts []testContextTemplate = []testContextTemplate{
|
||||
var testContexts = []testContextTemplate{
|
||||
{
|
||||
`
|
||||
from %s
|
||||
from {IMAGE}
|
||||
run sh -c 'echo root:testpass > /tmp/passwd'
|
||||
run mkdir -p /var/run/sshd
|
||||
run [ "$(cat /tmp/passwd)" = "root:testpass" ]
|
||||
run [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
|
||||
`,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
`
|
||||
from %s
|
||||
from {IMAGE}
|
||||
add foo /usr/lib/bla/bar
|
||||
run [ "$(cat /usr/lib/bla/bar)" = 'hello world!' ]
|
||||
run [ "$(cat /usr/lib/bla/bar)" = 'hello' ]
|
||||
add http://{SERVERADDR}/baz /usr/lib/baz/quux
|
||||
run [ "$(cat /usr/lib/baz/quux)" = 'world!' ]
|
||||
`,
|
||||
[][2]string{{"foo", "hello world!"}},
|
||||
[][2]string{{"foo", "hello"}},
|
||||
[][2]string{{"/baz", "world!"}},
|
||||
},
|
||||
|
||||
{
|
||||
`
|
||||
from %s
|
||||
from {IMAGE}
|
||||
add f /
|
||||
run [ "$(cat /f)" = "hello" ]
|
||||
add f /abc
|
||||
@@ -72,38 +81,296 @@ run [ "$(cat /somewheeeere/over/the/rainbooow/ga)" = "bu" ]
|
||||
{"f", "hello"},
|
||||
{"d/ga", "bu"},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
`
|
||||
from %s
|
||||
from {IMAGE}
|
||||
add http://{SERVERADDR}/x /a/b/c
|
||||
run [ "$(cat /a/b/c)" = "hello" ]
|
||||
add http://{SERVERADDR}/x?foo=bar /
|
||||
run [ "$(cat /x)" = "hello" ]
|
||||
add http://{SERVERADDR}/x /d/
|
||||
run [ "$(cat /d/x)" = "hello" ]
|
||||
add http://{SERVERADDR} /e
|
||||
run [ "$(cat /e)" = "blah" ]
|
||||
`,
|
||||
nil,
|
||||
[][2]string{{"/x", "hello"}, {"/", "blah"}},
|
||||
},
|
||||
|
||||
{
|
||||
`
|
||||
from {IMAGE}
|
||||
env FOO BAR
|
||||
run [ "$FOO" = "BAR" ]
|
||||
`,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
`
|
||||
from {IMAGE}
|
||||
ENTRYPOINT /bin/echo
|
||||
CMD Hello world
|
||||
`,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
`
|
||||
from {IMAGE}
|
||||
VOLUME /test
|
||||
CMD Hello world
|
||||
`,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
`
|
||||
from {IMAGE}
|
||||
env FOO /foo/baz
|
||||
env BAR /bar
|
||||
env BAZ $BAR
|
||||
env FOOPATH $PATH:$FOO
|
||||
run [ "$BAR" = "$BAZ" ]
|
||||
run [ "$FOOPATH" = "$PATH:/foo/baz" ]
|
||||
`,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
`
|
||||
from {IMAGE}
|
||||
env FOO /bar
|
||||
env TEST testdir
|
||||
env BAZ /foobar
|
||||
add testfile $BAZ/
|
||||
add $TEST $FOO
|
||||
run [ "$(cat /foobar/testfile)" = "test1" ]
|
||||
run [ "$(cat /bar/withfile)" = "test2" ]
|
||||
`,
|
||||
[][2]string{
|
||||
{"testfile", "test1"},
|
||||
{"testdir/withfile", "test2"},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
// FIXME: test building with 2 successive overlapping ADD commands
|
||||
|
||||
func constructDockerfile(template string, ip net.IP, port string) string {
|
||||
serverAddr := fmt.Sprintf("%s:%s", ip, port)
|
||||
replacer := strings.NewReplacer("{IMAGE}", unitTestImageID, "{SERVERADDR}", serverAddr)
|
||||
return replacer.Replace(template)
|
||||
}
|
||||
|
||||
func mkTestingFileServer(files [][2]string) (*httptest.Server, error) {
|
||||
mux := http.NewServeMux()
|
||||
for _, file := range files {
|
||||
name, contents := file[0], file[1]
|
||||
mux.HandleFunc(name, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(contents))
|
||||
})
|
||||
}
|
||||
|
||||
// This is how httptest.NewServer sets up a net.Listener, except that our listener must accept remote
|
||||
// connections (from the container).
|
||||
listener, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := httptest.NewUnstartedServer(mux)
|
||||
s.Listener = listener
|
||||
s.Start()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
for _, ctx := range testContexts {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
buildImage(ctx, t)
|
||||
}
|
||||
}
|
||||
|
||||
srv := &Server{
|
||||
runtime: runtime,
|
||||
lock: &sync.Mutex{},
|
||||
pullingPool: make(map[string]struct{}),
|
||||
pushingPool: make(map[string]struct{}),
|
||||
}
|
||||
func buildImage(context testContextTemplate, t *testing.T) *Image {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
buildfile := NewBuildFile(srv, ioutil.Discard)
|
||||
if _, err := buildfile.Build(mkTestContext(ctx.dockerfile, ctx.files, t)); err != nil {
|
||||
t.Fatal(err)
|
||||
srv := &Server{
|
||||
runtime: runtime,
|
||||
pullingPool: make(map[string]struct{}),
|
||||
pushingPool: make(map[string]struct{}),
|
||||
}
|
||||
|
||||
httpServer, err := mkTestingFileServer(context.remoteFiles)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer httpServer.Close()
|
||||
|
||||
idx := strings.LastIndex(httpServer.URL, ":")
|
||||
if idx < 0 {
|
||||
t.Fatalf("could not get port from test http server address %s", httpServer.URL)
|
||||
}
|
||||
port := httpServer.URL[idx+1:]
|
||||
|
||||
ip := runtime.networkManager.bridgeNetwork.IP
|
||||
dockerfile := constructDockerfile(context.dockerfile, ip, port)
|
||||
|
||||
buildfile := NewBuildFile(srv, ioutil.Discard, false)
|
||||
id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
img, err := srv.ImageInspect(id)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return img
|
||||
}
|
||||
|
||||
func TestVolume(t *testing.T) {
|
||||
img := buildImage(testContextTemplate{`
|
||||
from {IMAGE}
|
||||
volume /test
|
||||
cmd Hello world
|
||||
`, nil, nil}, t)
|
||||
|
||||
if len(img.Config.Volumes) == 0 {
|
||||
t.Fail()
|
||||
}
|
||||
for key := range img.Config.Volumes {
|
||||
if key != "/test" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildMaintainer(t *testing.T) {
|
||||
img := buildImage(testContextTemplate{`
|
||||
from {IMAGE}
|
||||
maintainer dockerio
|
||||
`, nil, nil}, t)
|
||||
|
||||
if img.Author != "dockerio" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildEnv(t *testing.T) {
|
||||
img := buildImage(testContextTemplate{`
|
||||
from {IMAGE}
|
||||
env port 4243
|
||||
`,
|
||||
nil, nil}, t)
|
||||
hasEnv := false
|
||||
for _, envVar := range img.Config.Env {
|
||||
if envVar == "port=4243" {
|
||||
hasEnv = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasEnv {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildCmd(t *testing.T) {
|
||||
img := buildImage(testContextTemplate{`
|
||||
from {IMAGE}
|
||||
cmd ["/bin/echo", "Hello World"]
|
||||
`,
|
||||
nil, nil}, t)
|
||||
|
||||
if img.Config.Cmd[0] != "/bin/echo" {
|
||||
t.Log(img.Config.Cmd[0])
|
||||
t.Fail()
|
||||
}
|
||||
if img.Config.Cmd[1] != "Hello World" {
|
||||
t.Log(img.Config.Cmd[1])
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildExpose(t *testing.T) {
|
||||
img := buildImage(testContextTemplate{`
|
||||
from {IMAGE}
|
||||
expose 4243
|
||||
`,
|
||||
nil, nil}, t)
|
||||
|
||||
if img.Config.PortSpecs[0] != "4243" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildEntrypoint(t *testing.T) {
|
||||
img := buildImage(testContextTemplate{`
|
||||
from {IMAGE}
|
||||
entrypoint ["/bin/echo"]
|
||||
`,
|
||||
nil, nil}, t)
|
||||
|
||||
if img.Config.Entrypoint[0] != "/bin/echo" {
|
||||
}
|
||||
}
|
||||
|
||||
func TestForbiddenContextPath(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{
|
||||
runtime: runtime,
|
||||
pullingPool: make(map[string]struct{}),
|
||||
pushingPool: make(map[string]struct{}),
|
||||
}
|
||||
|
||||
context := testContextTemplate{`
|
||||
from {IMAGE}
|
||||
maintainer dockerio
|
||||
add ../../ test/
|
||||
`,
|
||||
[][2]string{{"test.txt", "test1"}, {"other.txt", "other"}}, nil}
|
||||
|
||||
httpServer, err := mkTestingFileServer(context.remoteFiles)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer httpServer.Close()
|
||||
|
||||
idx := strings.LastIndex(httpServer.URL, ":")
|
||||
if idx < 0 {
|
||||
t.Fatalf("could not get port from test http server address %s", httpServer.URL)
|
||||
}
|
||||
port := httpServer.URL[idx+1:]
|
||||
|
||||
ip := srv.runtime.networkManager.bridgeNetwork.IP
|
||||
dockerfile := constructDockerfile(context.dockerfile, ip, port)
|
||||
|
||||
buildfile := NewBuildFile(srv, ioutil.Discard, false)
|
||||
_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
|
||||
|
||||
if err == nil {
|
||||
t.Log("Error should not be nil")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if err.Error() != "Forbidden path: /" {
|
||||
t.Logf("Error message is not expected: %s", err.Error())
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
371
commands.go
@@ -19,7 +19,6 @@ import (
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -28,7 +27,7 @@ import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const VERSION = "0.4.7"
|
||||
const VERSION = "0.5.2"
|
||||
|
||||
var (
|
||||
GITCOMMIT string
|
||||
@@ -73,12 +72,13 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=[tcp://%s:%d]: tcp://host:port to bind/connect to or unix://path/to/socker to use\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", DEFAULTHTTPHOST, DEFAULTHTTPPORT)
|
||||
help := fmt.Sprintf("Usage: docker [OPTIONS] COMMAND [arg...]\n -H=[tcp://%s:%d]: tcp://host:port to bind/connect to or unix://path/to/socket to use\n\nA self-sufficient runtime for linux containers.\n\nCommands:\n", DEFAULTHTTPHOST, DEFAULTHTTPPORT)
|
||||
for _, command := range [][]string{
|
||||
{"attach", "Attach to a running container"},
|
||||
{"build", "Build a container from a Dockerfile"},
|
||||
{"commit", "Create a new image from a container's changes"},
|
||||
{"diff", "Inspect changes on a container's filesystem"},
|
||||
{"events", "Get real time events from the server"},
|
||||
{"export", "Stream the contents of a container as a tar archive"},
|
||||
{"history", "Show the history of an image"},
|
||||
{"images", "List images"},
|
||||
@@ -90,12 +90,13 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
|
||||
{"login", "Register or Login to the docker registry server"},
|
||||
{"logs", "Fetch the logs of a container"},
|
||||
{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
|
||||
{"top", "Lookup the running processes of a container"},
|
||||
{"ps", "List containers"},
|
||||
{"pull", "Pull an image or a repository from the docker registry server"},
|
||||
{"push", "Push an image or a repository to the docker registry server"},
|
||||
{"restart", "Restart a running container"},
|
||||
{"rm", "Remove a container"},
|
||||
{"rmi", "Remove an image"},
|
||||
{"rm", "Remove one or more containers"},
|
||||
{"rmi", "Remove one or more images"},
|
||||
{"run", "Run a command in a new container"},
|
||||
{"search", "Search for an image in the docker index"},
|
||||
{"start", "Start a stopped container"},
|
||||
@@ -158,6 +159,8 @@ func mkBuildContext(dockerfile string, files [][2]string) (Archive, error) {
|
||||
func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||
cmd := Subcmd("build", "[OPTIONS] PATH | URL | -", "Build a new container image from the source code at PATH")
|
||||
tag := cmd.String("t", "", "Tag to be applied to the resulting image in case of success")
|
||||
suppressOutput := cmd.Bool("q", false, "Suppress verbose build output")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -183,6 +186,9 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||
} else if utils.IsURL(cmd.Arg(0)) || utils.IsGIT(cmd.Arg(0)) {
|
||||
isRemote = true
|
||||
} else {
|
||||
if _, err := os.Stat(cmd.Arg(0)); err != nil {
|
||||
return err
|
||||
}
|
||||
context, err = Tar(cmd.Arg(0), Uncompressed)
|
||||
}
|
||||
var body io.Reader
|
||||
@@ -195,6 +201,10 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||
// Upload the build context
|
||||
v := &url.Values{}
|
||||
v.Set("t", *tag)
|
||||
|
||||
if *suppressOutput {
|
||||
v.Set("q", "1")
|
||||
}
|
||||
if isRemote {
|
||||
v.Set("remote", cmd.Arg(0))
|
||||
}
|
||||
@@ -280,57 +290,88 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
|
||||
return readStringOnRawTerminal(stdin, stdout, false)
|
||||
}
|
||||
|
||||
oldState, err := term.SetRawTerminal(cli.terminalFd)
|
||||
cmd := Subcmd("login", "[OPTIONS]", "Register or Login to the docker registry server")
|
||||
flUsername := cmd.String("u", "", "username")
|
||||
flPassword := cmd.String("p", "", "password")
|
||||
flEmail := cmd.String("e", "", "email")
|
||||
err := cmd.Parse(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer term.RestoreTerminal(cli.terminalFd, oldState)
|
||||
|
||||
cmd := Subcmd("login", "", "Register or Login to the docker registry server")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var oldState *term.State
|
||||
if *flUsername == "" || *flPassword == "" || *flEmail == "" {
|
||||
oldState, err = term.SetRawTerminal(cli.terminalFd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer term.RestoreTerminal(cli.terminalFd, oldState)
|
||||
}
|
||||
|
||||
var (
|
||||
username string
|
||||
password string
|
||||
email string
|
||||
)
|
||||
|
||||
fmt.Fprintf(cli.out, "Username (%s):", cli.authConfig.Username)
|
||||
username = readAndEchoString(cli.in, cli.out)
|
||||
if username == "" {
|
||||
username = cli.authConfig.Username
|
||||
}
|
||||
if username != cli.authConfig.Username {
|
||||
fmt.Fprintf(cli.out, "Password: ")
|
||||
password = readString(cli.in, cli.out)
|
||||
|
||||
if password == "" {
|
||||
return fmt.Errorf("Error : Password Required")
|
||||
var promptDefault = func(prompt string, configDefault string) {
|
||||
if configDefault == "" {
|
||||
fmt.Fprintf(cli.out, "%s: ", prompt)
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(cli.out, "Email (%s): ", cli.authConfig.Email)
|
||||
email = readAndEchoString(cli.in, cli.out)
|
||||
if email == "" {
|
||||
email = cli.authConfig.Email
|
||||
authconfig, ok := cli.configFile.Configs[auth.IndexServerAddress()]
|
||||
if !ok {
|
||||
authconfig = auth.AuthConfig{}
|
||||
}
|
||||
|
||||
if *flUsername == "" {
|
||||
promptDefault("Username", authconfig.Username)
|
||||
username = readAndEchoString(cli.in, cli.out)
|
||||
if username == "" {
|
||||
username = authconfig.Username
|
||||
}
|
||||
} else {
|
||||
password = cli.authConfig.Password
|
||||
email = cli.authConfig.Email
|
||||
username = *flUsername
|
||||
}
|
||||
term.RestoreTerminal(cli.terminalFd, oldState)
|
||||
if username != authconfig.Username {
|
||||
if *flPassword == "" {
|
||||
fmt.Fprintf(cli.out, "Password: ")
|
||||
password = readString(cli.in, cli.out)
|
||||
if password == "" {
|
||||
return fmt.Errorf("Error : Password Required")
|
||||
}
|
||||
} else {
|
||||
password = *flPassword
|
||||
}
|
||||
|
||||
cli.authConfig.Username = username
|
||||
cli.authConfig.Password = password
|
||||
cli.authConfig.Email = email
|
||||
if *flEmail == "" {
|
||||
promptDefault("Email", authconfig.Email)
|
||||
email = readAndEchoString(cli.in, cli.out)
|
||||
if email == "" {
|
||||
email = authconfig.Email
|
||||
}
|
||||
} else {
|
||||
email = *flEmail
|
||||
}
|
||||
} else {
|
||||
password = authconfig.Password
|
||||
email = authconfig.Email
|
||||
}
|
||||
if oldState != nil {
|
||||
term.RestoreTerminal(cli.terminalFd, oldState)
|
||||
}
|
||||
authconfig.Username = username
|
||||
authconfig.Password = password
|
||||
authconfig.Email = email
|
||||
cli.configFile.Configs[auth.IndexServerAddress()] = authconfig
|
||||
|
||||
body, statusCode, err := cli.call("POST", "/auth", cli.authConfig)
|
||||
body, statusCode, err := cli.call("POST", "/auth", cli.configFile.Configs[auth.IndexServerAddress()])
|
||||
if statusCode == 401 {
|
||||
cli.authConfig.Username = ""
|
||||
cli.authConfig.Password = ""
|
||||
cli.authConfig.Email = ""
|
||||
auth.SaveConfig(cli.authConfig)
|
||||
delete(cli.configFile.Configs, auth.IndexServerAddress())
|
||||
auth.SaveConfig(cli.configFile)
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
@@ -340,10 +381,10 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
|
||||
var out2 APIAuth
|
||||
err = json.Unmarshal(body, &out2)
|
||||
if err != nil {
|
||||
auth.LoadConfig(os.Getenv("HOME"))
|
||||
cli.configFile, _ = auth.LoadConfig(os.Getenv("HOME"))
|
||||
return err
|
||||
}
|
||||
auth.SaveConfig(cli.authConfig)
|
||||
auth.SaveConfig(cli.configFile)
|
||||
if out2.Status != "" {
|
||||
fmt.Fprintf(cli.out, "%s\n", out2.Status)
|
||||
}
|
||||
@@ -438,6 +479,9 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
||||
fmt.Fprintf(cli.out, "Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
|
||||
fmt.Fprintf(cli.out, "Fds: %d\n", out.NFd)
|
||||
fmt.Fprintf(cli.out, "Goroutines: %d\n", out.NGoroutines)
|
||||
fmt.Fprintf(cli.out, "LXC Version: %s\n", out.LXCVersion)
|
||||
fmt.Fprintf(cli.out, "EventsListeners: %d\n", out.NEventsListener)
|
||||
fmt.Fprintf(cli.out, "Kernel Version: %s\n", out.KernelVersion)
|
||||
}
|
||||
if !out.MemoryLimit {
|
||||
fmt.Fprintf(cli.err, "WARNING: No memory limit support\n")
|
||||
@@ -450,7 +494,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
||||
|
||||
func (cli *DockerCli) CmdStop(args ...string) error {
|
||||
cmd := Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container")
|
||||
nSeconds := cmd.Int("t", 10, "wait t seconds before killing the container")
|
||||
nSeconds := cmd.Int("t", 10, "Number of seconds to wait for the container to stop before killing it.")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -475,7 +519,7 @@ func (cli *DockerCli) CmdStop(args ...string) error {
|
||||
|
||||
func (cli *DockerCli) CmdRestart(args ...string) error {
|
||||
cmd := Subcmd("restart", "[OPTIONS] CONTAINER [CONTAINER...]", "Restart a running container")
|
||||
nSeconds := cmd.Int("t", 10, "wait t seconds before killing the container")
|
||||
nSeconds := cmd.Int("t", 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default=10")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -555,6 +599,38 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) CmdTop(args ...string) error {
|
||||
cmd := Subcmd("top", "CONTAINER", "Lookup the running processes of a container")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
if cmd.NArg() == 0 {
|
||||
cmd.Usage()
|
||||
return nil
|
||||
}
|
||||
val := url.Values{}
|
||||
if cmd.NArg() > 1 {
|
||||
val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
|
||||
}
|
||||
|
||||
body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/top?"+val.Encode(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
procs := APITop{}
|
||||
err = json.Unmarshal(body, &procs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintln(w, strings.Join(procs.Titles, "\t"))
|
||||
for _, proc := range procs.Processes {
|
||||
fmt.Fprintln(w, strings.Join(proc, "\t"))
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) CmdPort(args ...string) error {
|
||||
cmd := Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
@@ -565,6 +641,13 @@ func (cli *DockerCli) CmdPort(args ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
port := cmd.Arg(1)
|
||||
proto := "Tcp"
|
||||
parts := strings.SplitN(port, "/", 2)
|
||||
if len(parts) == 2 && len(parts[1]) != 0 {
|
||||
port = parts[0]
|
||||
proto = strings.ToUpper(parts[1][:1]) + strings.ToLower(parts[1][1:])
|
||||
}
|
||||
body, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -575,7 +658,7 @@ func (cli *DockerCli) CmdPort(args ...string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if frontend, exists := out.NetworkSettings.PortMapping[cmd.Arg(1)]; exists {
|
||||
if frontend, exists := out.NetworkSettings.PortMapping[proto][port]; exists {
|
||||
fmt.Fprintf(cli.out, "%s\n", frontend)
|
||||
} else {
|
||||
return fmt.Errorf("Error: No private port '%s' allocated on %s", cmd.Arg(1), cmd.Arg(0))
|
||||
@@ -585,7 +668,7 @@ func (cli *DockerCli) CmdPort(args ...string) error {
|
||||
|
||||
// 'docker rmi IMAGE' removes all images with the name IMAGE
|
||||
func (cli *DockerCli) CmdRmi(args ...string) error {
|
||||
cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove an image")
|
||||
cmd := Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -650,7 +733,7 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
|
||||
}
|
||||
|
||||
func (cli *DockerCli) CmdRm(args ...string) error {
|
||||
cmd := Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove a container")
|
||||
cmd := Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
|
||||
v := cmd.Bool("v", false, "Remove the volumes associated to the container")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
@@ -697,7 +780,7 @@ func (cli *DockerCli) CmdKill(args ...string) error {
|
||||
}
|
||||
|
||||
func (cli *DockerCli) CmdImport(args ...string) error {
|
||||
cmd := Subcmd("import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball")
|
||||
cmd := Subcmd("import", "URL|- [REPOSITORY [TAG]]", "Create a new filesystem image from the contents of a tarball(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz).")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
@@ -720,8 +803,7 @@ func (cli *DockerCli) CmdImport(args ...string) error {
|
||||
}
|
||||
|
||||
func (cli *DockerCli) CmdPush(args ...string) error {
|
||||
cmd := Subcmd("push", "[OPTION] NAME", "Push an image or a repository to the registry")
|
||||
registry := cmd.String("registry", "", "Registry host to push the image to")
|
||||
cmd := Subcmd("push", "NAME", "Push an image or a repository to the registry")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -732,37 +814,24 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := cli.checkIfLogged(*registry == "", "push"); err != nil {
|
||||
if err := cli.checkIfLogged("push"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if *registry == "" {
|
||||
// If we're not using a custom registry, we know the restrictions
|
||||
// applied to repository names and can warn the user in advance.
|
||||
// Custom repositories can have different rules, and we must also
|
||||
// allow pushing by image ID.
|
||||
if len(strings.SplitN(name, "/", 2)) == 1 {
|
||||
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.authConfig.Username, name)
|
||||
}
|
||||
|
||||
nameParts := strings.SplitN(name, "/", 2)
|
||||
validNamespace := regexp.MustCompile(`^([a-z0-9_]{4,30})$`)
|
||||
if !validNamespace.MatchString(nameParts[0]) {
|
||||
return fmt.Errorf("Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30", nameParts[0])
|
||||
}
|
||||
validRepo := regexp.MustCompile(`^([a-zA-Z0-9-_.]+)$`)
|
||||
if !validRepo.MatchString(nameParts[1]) {
|
||||
return fmt.Errorf("Invalid repository name (%s), only [a-zA-Z0-9-_.] are allowed", nameParts[1])
|
||||
}
|
||||
// If we're not using a custom registry, we know the restrictions
|
||||
// applied to repository names and can warn the user in advance.
|
||||
// Custom repositories can have different rules, and we must also
|
||||
// allow pushing by image ID.
|
||||
if len(strings.SplitN(name, "/", 2)) == 1 {
|
||||
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.configFile.Configs[auth.IndexServerAddress()].Username, name)
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(cli.authConfig)
|
||||
buf, err := json.Marshal(cli.configFile.Configs[auth.IndexServerAddress()])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("registry", *registry)
|
||||
if err := cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), bytes.NewBuffer(buf), cli.out); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -772,7 +841,6 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
||||
func (cli *DockerCli) CmdPull(args ...string) error {
|
||||
cmd := Subcmd("pull", "NAME", "Pull an image or a repository from the registry")
|
||||
tag := cmd.String("t", "", "Download tagged image in repository")
|
||||
registry := cmd.String("registry", "", "Registry to download from. Necessary if image is pulled by ID")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -782,17 +850,14 @@ func (cli *DockerCli) CmdPull(args ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
remote := cmd.Arg(0)
|
||||
if strings.Contains(remote, ":") {
|
||||
remoteParts := strings.Split(remote, ":")
|
||||
tag = &remoteParts[1]
|
||||
remote = remoteParts[0]
|
||||
remote, parsedTag := utils.ParseRepositoryTag(cmd.Arg(0))
|
||||
if *tag == "" {
|
||||
*tag = parsedTag
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("fromImage", remote)
|
||||
v.Set("tag", *tag)
|
||||
v.Set("registry", *registry)
|
||||
|
||||
if err := cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.out); err != nil {
|
||||
return err
|
||||
@@ -1011,6 +1076,29 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) CmdEvents(args ...string) error {
|
||||
cmd := Subcmd("events", "[OPTIONS]", "Get real time events from the server")
|
||||
since := cmd.String("since", "", "Show events previously created (used for polling).")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cmd.NArg() != 0 {
|
||||
cmd.Usage()
|
||||
return nil
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
if *since != "" {
|
||||
v.Set("since", *since)
|
||||
}
|
||||
|
||||
if err := cli.stream("GET", "/events?"+v.Encode(), nil, cli.out); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) CmdExport(args ...string) error {
|
||||
cmd := Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
@@ -1064,10 +1152,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stdout=1", false, nil, cli.out); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stderr=1", false, nil, cli.err); err != nil {
|
||||
if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?logs=1&stdout=1&stderr=1", false, nil, cli.out); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -1118,6 +1203,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
|
||||
|
||||
func (cli *DockerCli) CmdSearch(args ...string) error {
|
||||
cmd := Subcmd("search", "NAME", "Search the docker index for images")
|
||||
noTrunc := cmd.Bool("notrunc", false, "Don't truncate output")
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -1139,13 +1225,19 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "Found %d results matching your query (\"%s\")\n", len(outs), cmd.Arg(0))
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
w := tabwriter.NewWriter(cli.out, 33, 1, 3, ' ', 0)
|
||||
fmt.Fprintf(w, "NAME\tDESCRIPTION\n")
|
||||
_, width := cli.getTtySize()
|
||||
if width == 0 {
|
||||
width = 45
|
||||
} else {
|
||||
width = width - 33 //remote the first column
|
||||
}
|
||||
for _, out := range outs {
|
||||
desc := strings.Replace(out.Description, "\n", " ", -1)
|
||||
desc = strings.Replace(desc, "\r", " ", -1)
|
||||
if len(desc) > 45 {
|
||||
desc = utils.Trunc(desc, 42) + "..."
|
||||
if !*noTrunc && len(desc) > width {
|
||||
desc = utils.Trunc(desc, width-3) + "..."
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%s\n", out.Name, desc)
|
||||
}
|
||||
@@ -1207,10 +1299,22 @@ func (opts PathOpts) String() string {
|
||||
}
|
||||
|
||||
func (opts PathOpts) Set(val string) error {
|
||||
if !filepath.IsAbs(val) {
|
||||
return fmt.Errorf("%s is not an absolute path", val)
|
||||
var containerPath string
|
||||
|
||||
splited := strings.SplitN(val, ":", 2)
|
||||
if len(splited) == 1 {
|
||||
containerPath = splited[0]
|
||||
val = filepath.Clean(splited[0])
|
||||
} else {
|
||||
containerPath = splited[1]
|
||||
val = fmt.Sprintf("%s:%s", splited[0], filepath.Clean(splited[1]))
|
||||
}
|
||||
opts[filepath.Clean(val)] = struct{}{}
|
||||
|
||||
if !filepath.IsAbs(containerPath) {
|
||||
utils.Debugf("%s is not an absolute path", containerPath)
|
||||
return fmt.Errorf("%s is not an absolute path", containerPath)
|
||||
}
|
||||
opts[val] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1251,12 +1355,26 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var containerIDFile *os.File
|
||||
if len(hostConfig.ContainerIDFile) > 0 {
|
||||
if _, err := ioutil.ReadFile(hostConfig.ContainerIDFile); err == nil {
|
||||
return fmt.Errorf("cid file found, make sure the other container isn't running or delete %s", hostConfig.ContainerIDFile)
|
||||
}
|
||||
containerIDFile, err = os.Create(hostConfig.ContainerIDFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create the container ID file: %s", err)
|
||||
}
|
||||
defer containerIDFile.Close()
|
||||
}
|
||||
|
||||
//create the container
|
||||
body, statusCode, err := cli.call("POST", "/containers/create", config)
|
||||
//if image not found try to pull it
|
||||
if statusCode == 404 {
|
||||
v := url.Values{}
|
||||
v.Set("fromImage", config.Image)
|
||||
repos, tag := utils.ParseRepositoryTag(config.Image)
|
||||
v.Set("fromImage", repos)
|
||||
v.Set("tag", tag)
|
||||
err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1277,7 +1395,12 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
||||
}
|
||||
|
||||
for _, warning := range runResult.Warnings {
|
||||
fmt.Fprintln(cli.err, "WARNING: ", warning)
|
||||
fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
|
||||
}
|
||||
if len(hostConfig.ContainerIDFile) > 0 {
|
||||
if _, err = containerIDFile.WriteString(runResult.ID); err != nil {
|
||||
return fmt.Errorf("failed to write the container ID to the file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
//start the container
|
||||
@@ -1285,15 +1408,21 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var wait chan struct{}
|
||||
|
||||
if !config.AttachStdout && !config.AttachStderr {
|
||||
// Make this asynchrone in order to let the client write to stdin before having to read the ID
|
||||
go fmt.Fprintf(cli.out, "%s\n", runResult.ID)
|
||||
wait = make(chan struct{})
|
||||
go func() {
|
||||
defer close(wait)
|
||||
fmt.Fprintf(cli.out, "%s\n", runResult.ID)
|
||||
}()
|
||||
}
|
||||
|
||||
if config.AttachStdin || config.AttachStdout || config.AttachStderr {
|
||||
if config.Tty {
|
||||
if err := cli.monitorTtySize(runResult.ID); err != nil {
|
||||
return err
|
||||
utils.Debugf("Error monitoring TTY size: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1316,16 +1445,20 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !config.AttachStdout && !config.AttachStderr {
|
||||
<-wait
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) checkIfLogged(condition bool, action string) error {
|
||||
func (cli *DockerCli) checkIfLogged(action string) error {
|
||||
// If condition AND the login failed
|
||||
if condition && cli.authConfig.Username == "" {
|
||||
if cli.configFile.Configs[auth.IndexServerAddress()].Username == "" {
|
||||
if err := cli.CmdLogin(""); err != nil {
|
||||
return err
|
||||
}
|
||||
if cli.authConfig.Username == "" {
|
||||
if cli.configFile.Configs[auth.IndexServerAddress()].Username == "" {
|
||||
return fmt.Errorf("Please login prior to %s. ('docker login')", action)
|
||||
}
|
||||
}
|
||||
@@ -1420,19 +1553,13 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
|
||||
if resp.Header.Get("Content-Type") == "application/json" {
|
||||
dec := json.NewDecoder(resp.Body)
|
||||
for {
|
||||
var m utils.JSONMessage
|
||||
if err := dec.Decode(&m); err == io.EOF {
|
||||
var jm utils.JSONMessage
|
||||
if err := dec.Decode(&jm); err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
if m.Progress != "" {
|
||||
fmt.Fprintf(out, "%s %s\r", m.Status, m.Progress)
|
||||
} else if m.Error != "" {
|
||||
return fmt.Errorf(m.Error)
|
||||
} else {
|
||||
fmt.Fprintf(out, "%s\n", m.Status)
|
||||
}
|
||||
jm.Display(out)
|
||||
}
|
||||
} else {
|
||||
if _, err := io.Copy(out, resp.Body); err != nil {
|
||||
@@ -1466,6 +1593,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
|
||||
|
||||
receiveStdout := utils.Go(func() error {
|
||||
_, err := io.Copy(out, br)
|
||||
utils.Debugf("[hijack] End of stdout")
|
||||
return err
|
||||
})
|
||||
|
||||
@@ -1480,6 +1608,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
|
||||
sendStdin := utils.Go(func() error {
|
||||
if in != nil {
|
||||
io.Copy(rwc, in)
|
||||
utils.Debugf("[hijack] End of stdin")
|
||||
}
|
||||
if tcpc, ok := rwc.(*net.TCPConn); ok {
|
||||
if err := tcpc.CloseWrite(); err != nil {
|
||||
@@ -1509,17 +1638,28 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
|
||||
|
||||
}
|
||||
|
||||
func (cli *DockerCli) resizeTty(id string) {
|
||||
func (cli *DockerCli) getTtySize() (int, int) {
|
||||
if !cli.isTerminal {
|
||||
return
|
||||
return 0, 0
|
||||
}
|
||||
ws, err := term.GetWinsize(cli.terminalFd)
|
||||
if err != nil {
|
||||
utils.Debugf("Error getting size: %s", err)
|
||||
if ws == nil {
|
||||
return 0, 0
|
||||
}
|
||||
}
|
||||
return int(ws.Height), int(ws.Width)
|
||||
}
|
||||
|
||||
func (cli *DockerCli) resizeTty(id string) {
|
||||
height, width := cli.getTtySize()
|
||||
if height == 0 && width == 0 {
|
||||
return
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Set("h", strconv.Itoa(int(ws.Height)))
|
||||
v.Set("w", strconv.Itoa(int(ws.Width)))
|
||||
v.Set("h", strconv.Itoa(height))
|
||||
v.Set("w", strconv.Itoa(width))
|
||||
if _, _, err := cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil); err != nil {
|
||||
utils.Debugf("Error resize: %s", err)
|
||||
}
|
||||
@@ -1531,13 +1671,12 @@ func (cli *DockerCli) monitorTtySize(id string) error {
|
||||
}
|
||||
cli.resizeTty(id)
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGWINCH)
|
||||
sigchan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigchan, syscall.SIGWINCH)
|
||||
go func() {
|
||||
for sig := range c {
|
||||
if sig == syscall.SIGWINCH {
|
||||
cli.resizeTty(id)
|
||||
}
|
||||
for {
|
||||
<-sigchan
|
||||
cli.resizeTty(id)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
@@ -1555,7 +1694,7 @@ func Subcmd(name, signature, description string) *flag.FlagSet {
|
||||
|
||||
func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *DockerCli {
|
||||
var (
|
||||
isTerminal bool = false
|
||||
isTerminal = false
|
||||
terminalFd uintptr
|
||||
)
|
||||
|
||||
@@ -1570,11 +1709,11 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *Doc
|
||||
err = out
|
||||
}
|
||||
|
||||
authConfig, _ := auth.LoadConfig(os.Getenv("HOME"))
|
||||
configFile, _ := auth.LoadConfig(os.Getenv("HOME"))
|
||||
return &DockerCli{
|
||||
proto: proto,
|
||||
addr: addr,
|
||||
authConfig: authConfig,
|
||||
configFile: configFile,
|
||||
in: in,
|
||||
out: out,
|
||||
err: err,
|
||||
@@ -1586,7 +1725,7 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string) *Doc
|
||||
type DockerCli struct {
|
||||
proto string
|
||||
addr string
|
||||
authConfig *auth.AuthConfig
|
||||
configFile *auth.ConfigFile
|
||||
in io.ReadCloser
|
||||
out io.Writer
|
||||
err io.Writer
|
||||
|
||||
231
commands_test.go
@@ -38,7 +38,7 @@ func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
|
||||
f()
|
||||
c <- false
|
||||
}()
|
||||
if <-c {
|
||||
if <-c && msg != "" {
|
||||
t.Fatal(msg)
|
||||
}
|
||||
}
|
||||
@@ -59,94 +59,21 @@ func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error
|
||||
return nil
|
||||
}
|
||||
|
||||
/*TODO
|
||||
func cmdImages(srv *Server, args ...string) (string, error) {
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
go func() {
|
||||
if err := srv.CmdImages(nil, stdoutPipe, args...); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// force the pipe closed, so that the code below gets an EOF
|
||||
stdoutPipe.Close()
|
||||
}()
|
||||
|
||||
output, err := ioutil.ReadAll(stdout)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Cleanup pipes
|
||||
return string(output), closeWrap(stdout, stdoutPipe)
|
||||
}
|
||||
|
||||
// TestImages checks that 'docker images' displays information correctly
|
||||
func TestImages(t *testing.T) {
|
||||
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
output, err := cmdImages(srv)
|
||||
|
||||
if !strings.Contains(output, "REPOSITORY") {
|
||||
t.Fatal("'images' should have a header")
|
||||
}
|
||||
if !strings.Contains(output, "docker-ut") {
|
||||
t.Fatal("'images' should show the docker-ut image")
|
||||
}
|
||||
if !strings.Contains(output, "e9aa60c60128") {
|
||||
t.Fatal("'images' should show the docker-ut image id")
|
||||
}
|
||||
|
||||
output, err = cmdImages(srv, "-q")
|
||||
|
||||
if strings.Contains(output, "REPOSITORY") {
|
||||
t.Fatal("'images -q' should not have a header")
|
||||
}
|
||||
if strings.Contains(output, "docker-ut") {
|
||||
t.Fatal("'images' should not show the docker-ut image name")
|
||||
}
|
||||
if !strings.Contains(output, "e9aa60c60128") {
|
||||
t.Fatal("'images' should show the docker-ut image id")
|
||||
}
|
||||
|
||||
output, err = cmdImages(srv, "-viz")
|
||||
|
||||
if !strings.HasPrefix(output, "digraph docker {") {
|
||||
t.Fatal("'images -v' should start with the dot header")
|
||||
}
|
||||
if !strings.HasSuffix(output, "}\n") {
|
||||
t.Fatal("'images -v' should end with a '}'")
|
||||
}
|
||||
if !strings.Contains(output, "base -> \"e9aa60c60128\" [style=invis]") {
|
||||
t.Fatal("'images -v' should have the docker-ut image id node")
|
||||
}
|
||||
|
||||
// todo: add checks for -a
|
||||
}
|
||||
|
||||
*/
|
||||
// TestRunHostname checks that 'docker run -h' correctly sets a custom hostname
|
||||
func TestRunHostname(t *testing.T) {
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
cli := NewDockerCli(nil, stdoutPipe, nil, testDaemonProto, testDaemonAddr)
|
||||
cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
|
||||
defer cleanup(globalRuntime)
|
||||
|
||||
c := make(chan struct{})
|
||||
go func() {
|
||||
defer close(c)
|
||||
if err := cli.CmdRun("-h", "foobar", unitTestImageId, "hostname"); err != nil {
|
||||
if err := cli.CmdRun("-h", "foobar", unitTestImageID, "hostname"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
utils.Debugf("--")
|
||||
|
||||
setTimeout(t, "Reading command output time out", 2*time.Second, func() {
|
||||
cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
|
||||
if err != nil {
|
||||
@@ -163,21 +90,16 @@ func TestRunHostname(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
func TestRunExit(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
|
||||
defer cleanup(globalRuntime)
|
||||
|
||||
c1 := make(chan struct{})
|
||||
go func() {
|
||||
srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", GetTestImage(runtime).Id, "/bin/cat")
|
||||
cli.CmdRun("-i", unitTestImageID, "/bin/cat")
|
||||
close(c1)
|
||||
}()
|
||||
|
||||
@@ -187,21 +109,24 @@ func TestRunExit(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
container := runtime.List()[0]
|
||||
container := globalRuntime.List()[0]
|
||||
|
||||
// Closing /bin/cat stdin, expect it to exit
|
||||
p, err := container.StdinPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := p.Close(); err != nil {
|
||||
if err := stdin.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// as the process exited, CmdRun must finish and unblock. Wait for it
|
||||
setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
|
||||
setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
|
||||
<-c1
|
||||
cmdWait(srv, container)
|
||||
|
||||
go func() {
|
||||
cli.CmdWait(container.ID)
|
||||
}()
|
||||
|
||||
if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
// Make sure that the client has been disconnected
|
||||
@@ -218,21 +143,18 @@ func TestRunExit(t *testing.T) {
|
||||
|
||||
// Expected behaviour: the process dies when the client disconnects
|
||||
func TestRunDisconnect(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
|
||||
defer cleanup(globalRuntime)
|
||||
|
||||
c1 := make(chan struct{})
|
||||
go func() {
|
||||
// We're simulating a disconnect so the return value doesn't matter. What matters is the
|
||||
// fact that CmdRun returns.
|
||||
srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", GetTestImage(runtime).Id, "/bin/cat")
|
||||
cli.CmdRun("-i", unitTestImageID, "/bin/cat")
|
||||
close(c1)
|
||||
}()
|
||||
|
||||
@@ -256,7 +178,7 @@ func TestRunDisconnect(t *testing.T) {
|
||||
// Client disconnect after run -i should cause stdin to be closed, which should
|
||||
// cause /bin/cat to exit.
|
||||
setTimeout(t, "Waiting for /bin/cat to exit timed out", 2*time.Second, func() {
|
||||
container := runtime.List()[0]
|
||||
container := globalRuntime.List()[0]
|
||||
container.Wait()
|
||||
if container.State.Running {
|
||||
t.Fatalf("/bin/cat is still running after closing stdin")
|
||||
@@ -266,40 +188,39 @@ func TestRunDisconnect(t *testing.T) {
|
||||
|
||||
// Expected behaviour: the process dies when the client disconnects
|
||||
func TestRunDisconnectTty(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
|
||||
defer cleanup(globalRuntime)
|
||||
|
||||
c1 := make(chan struct{})
|
||||
go func() {
|
||||
// We're simulating a disconnect so the return value doesn't matter. What matters is the
|
||||
// fact that CmdRun returns.
|
||||
srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", "-t", GetTestImage(runtime).Id, "/bin/cat")
|
||||
if err := cli.CmdRun("-i", "-t", unitTestImageID, "/bin/cat"); err != nil {
|
||||
utils.Debugf("Error CmdRun: %s\n", err)
|
||||
}
|
||||
|
||||
close(c1)
|
||||
}()
|
||||
|
||||
setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
|
||||
setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
|
||||
for {
|
||||
// Client disconnect after run -i should keep stdin out in TTY mode
|
||||
l := runtime.List()
|
||||
l := globalRuntime.List()
|
||||
if len(l) == 1 && l[0].State.Running {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
})
|
||||
|
||||
// Client disconnect after run -i should keep stdin out in TTY mode
|
||||
container := runtime.List()[0]
|
||||
container := globalRuntime.List()[0]
|
||||
|
||||
setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
|
||||
setTimeout(t, "Read/Write assertion timed out", 2000*time.Second, func() {
|
||||
if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -319,7 +240,6 @@ func TestRunDisconnectTty(t *testing.T) {
|
||||
t.Fatalf("/bin/cat should still be running after closing stdin (tty mode)")
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// TestAttachStdin checks attaching to stdin without stdout and stderr.
|
||||
// 'docker run -i -a stdin' should sends the client's stdin to the command,
|
||||
@@ -329,13 +249,13 @@ func TestRunAttachStdin(t *testing.T) {
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
cli := NewDockerCli(stdin, stdoutPipe, nil, testDaemonProto, testDaemonAddr)
|
||||
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
|
||||
defer cleanup(globalRuntime)
|
||||
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
defer close(ch)
|
||||
cli.CmdRun("-i", "-a", "stdin", unitTestImageId, "sh", "-c", "echo hello && cat")
|
||||
cli.CmdRun("-i", "-a", "stdin", unitTestImageID, "sh", "-c", "echo hello && cat")
|
||||
}()
|
||||
|
||||
// Send input to the command, close stdin
|
||||
@@ -373,59 +293,61 @@ func TestRunAttachStdin(t *testing.T) {
|
||||
})
|
||||
|
||||
// Check logs
|
||||
if cmdLogs, err := container.ReadLog("stdout"); err != nil {
|
||||
if cmdLogs, err := container.ReadLog("json"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if output, err := ioutil.ReadAll(cmdLogs); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
expectedLog := "hello\nhi there\n"
|
||||
if string(output) != expectedLog {
|
||||
t.Fatalf("Unexpected logs: should be '%s', not '%s'\n", expectedLog, output)
|
||||
expectedLogs := []string{"{\"log\":\"hello\\n\",\"stream\":\"stdout\"", "{\"log\":\"hi there\\n\",\"stream\":\"stdout\""}
|
||||
for _, expectedLog := range expectedLogs {
|
||||
if !strings.Contains(string(output), expectedLog) {
|
||||
t.Fatalf("Unexpected logs: should contains '%s', it is not '%s'\n", expectedLog, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Expected behaviour, the process stays alive when the client disconnects
|
||||
func TestAttachDisconnect(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
container, err := NewBuilder(runtime).Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).Id,
|
||||
CpuShares: 1000,
|
||||
Memory: 33554432,
|
||||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
// Start the process
|
||||
if err := container.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stdin, stdinPipe := io.Pipe()
|
||||
stdout, stdoutPipe := io.Pipe()
|
||||
|
||||
cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
|
||||
defer cleanup(globalRuntime)
|
||||
|
||||
go func() {
|
||||
// Start a process in daemon mode
|
||||
if err := cli.CmdRun("-d", "-i", unitTestImageID, "/bin/cat"); err != nil {
|
||||
utils.Debugf("Error CmdRun: %s\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
|
||||
if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
|
||||
for {
|
||||
l := globalRuntime.List()
|
||||
if len(l) == 1 && l[0].State.Running {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
})
|
||||
|
||||
container := globalRuntime.List()[0]
|
||||
|
||||
// Attach to it
|
||||
c1 := make(chan struct{})
|
||||
go func() {
|
||||
// We're simulating a disconnect so the return value doesn't matter. What matters is the
|
||||
// fact that CmdAttach returns.
|
||||
srv.CmdAttach(stdin, rcli.NewDockerLocalConn(stdoutPipe), container.Id)
|
||||
cli.CmdAttach(container.ID)
|
||||
close(c1)
|
||||
}()
|
||||
|
||||
@@ -446,7 +368,7 @@ func TestAttachDisconnect(t *testing.T) {
|
||||
|
||||
// We closed stdin, expect /bin/cat to still be running
|
||||
// Wait a little bit to make sure container.monitor() did his thing
|
||||
err = container.WaitTimeout(500 * time.Millisecond)
|
||||
err := container.WaitTimeout(500 * time.Millisecond)
|
||||
if err == nil || !container.State.Running {
|
||||
t.Fatalf("/bin/cat is not running after closing stdin")
|
||||
}
|
||||
@@ -456,4 +378,3 @@ func TestAttachDisconnect(t *testing.T) {
|
||||
cStdin.Close()
|
||||
container.Wait()
|
||||
}
|
||||
*/
|
||||
|
||||
269
container.go
@@ -52,34 +52,37 @@ type Container struct {
|
||||
|
||||
waitLock chan struct{}
|
||||
Volumes map[string]string
|
||||
// Store rw/ro in a separate structure to preserve reserve-compatibility on-disk.
|
||||
// Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
|
||||
// Easier than migrating older container configs :)
|
||||
VolumesRW map[string]bool
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Hostname string
|
||||
User string
|
||||
Memory int64 // Memory limit (in bytes)
|
||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap
|
||||
CpuShares int64 // CPU shares (relative weight vs. other containers)
|
||||
AttachStdin bool
|
||||
AttachStdout bool
|
||||
AttachStderr bool
|
||||
PortSpecs []string
|
||||
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
||||
OpenStdin bool // Open stdin
|
||||
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
||||
Env []string
|
||||
Cmd []string
|
||||
Dns []string
|
||||
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
|
||||
Volumes map[string]struct{}
|
||||
VolumesFrom string
|
||||
Hostname string
|
||||
User string
|
||||
Memory int64 // Memory limit (in bytes)
|
||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap
|
||||
CpuShares int64 // CPU shares (relative weight vs. other containers)
|
||||
AttachStdin bool
|
||||
AttachStdout bool
|
||||
AttachStderr bool
|
||||
PortSpecs []string
|
||||
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
||||
OpenStdin bool // Open stdin
|
||||
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
||||
Env []string
|
||||
Cmd []string
|
||||
Dns []string
|
||||
Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
|
||||
Volumes map[string]struct{}
|
||||
VolumesFrom string
|
||||
Entrypoint []string
|
||||
NetworkDisabled bool
|
||||
}
|
||||
|
||||
type HostConfig struct {
|
||||
Binds []string
|
||||
Binds []string
|
||||
ContainerIDFile string
|
||||
}
|
||||
|
||||
type BindMap struct {
|
||||
@@ -92,16 +95,19 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
|
||||
cmd := Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container")
|
||||
if len(args) > 0 && args[0] != "--help" {
|
||||
cmd.SetOutput(ioutil.Discard)
|
||||
cmd.Usage = nil
|
||||
}
|
||||
|
||||
flHostname := cmd.String("h", "", "Container host name")
|
||||
flUser := cmd.String("u", "", "Username or UID")
|
||||
flDetach := cmd.Bool("d", false, "Detached mode: leave the container running in the background")
|
||||
flDetach := cmd.Bool("d", false, "Detached mode: Run container in the background, print new container id")
|
||||
flAttach := NewAttachOpts()
|
||||
cmd.Var(flAttach, "a", "Attach to stdin, stdout or stderr.")
|
||||
flStdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
|
||||
flTty := cmd.Bool("t", false, "Allocate a pseudo-tty")
|
||||
flMemory := cmd.Int64("m", 0, "Memory limit (in bytes)")
|
||||
flContainerIDFile := cmd.String("cidfile", "", "Write the container ID to the file")
|
||||
flNetwork := cmd.Bool("n", true, "Enable networking for this container")
|
||||
|
||||
if capabilities != nil && *flMemory > 0 && !capabilities.MemoryLimit {
|
||||
//fmt.Fprintf(stdout, "WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
|
||||
@@ -120,12 +126,10 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
|
||||
cmd.Var(&flDns, "dns", "Set custom dns servers")
|
||||
|
||||
flVolumes := NewPathOpts()
|
||||
cmd.Var(flVolumes, "v", "Attach a data volume")
|
||||
cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)")
|
||||
|
||||
flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container")
|
||||
|
||||
var flBinds ListOpts
|
||||
cmd.Var(&flBinds, "b", "Bind mount a volume from the host (e.g. -b /host:/container)")
|
||||
flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil, nil, cmd, err
|
||||
@@ -144,15 +148,22 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
|
||||
}
|
||||
}
|
||||
|
||||
var binds []string
|
||||
|
||||
// add any bind targets to the list of container volumes
|
||||
for _, bind := range flBinds {
|
||||
for bind := range flVolumes {
|
||||
arr := strings.Split(bind, ":")
|
||||
dstDir := arr[1]
|
||||
flVolumes[dstDir] = struct{}{}
|
||||
if len(arr) > 1 {
|
||||
dstDir := arr[1]
|
||||
flVolumes[dstDir] = struct{}{}
|
||||
binds = append(binds, bind)
|
||||
delete(flVolumes, bind)
|
||||
}
|
||||
}
|
||||
|
||||
parsedArgs := cmd.Args()
|
||||
runCmd := []string{}
|
||||
entrypoint := []string{}
|
||||
image := ""
|
||||
if len(parsedArgs) >= 1 {
|
||||
image = cmd.Arg(0)
|
||||
@@ -160,26 +171,33 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
|
||||
if len(parsedArgs) > 1 {
|
||||
runCmd = parsedArgs[1:]
|
||||
}
|
||||
if *flEntrypoint != "" {
|
||||
entrypoint = []string{*flEntrypoint}
|
||||
}
|
||||
|
||||
config := &Config{
|
||||
Hostname: *flHostname,
|
||||
PortSpecs: flPorts,
|
||||
User: *flUser,
|
||||
Tty: *flTty,
|
||||
OpenStdin: *flStdin,
|
||||
Memory: *flMemory,
|
||||
CpuShares: *flCpuShares,
|
||||
AttachStdin: flAttach.Get("stdin"),
|
||||
AttachStdout: flAttach.Get("stdout"),
|
||||
AttachStderr: flAttach.Get("stderr"),
|
||||
Env: flEnv,
|
||||
Cmd: runCmd,
|
||||
Dns: flDns,
|
||||
Image: image,
|
||||
Volumes: flVolumes,
|
||||
VolumesFrom: *flVolumesFrom,
|
||||
Hostname: *flHostname,
|
||||
PortSpecs: flPorts,
|
||||
User: *flUser,
|
||||
Tty: *flTty,
|
||||
NetworkDisabled: !*flNetwork,
|
||||
OpenStdin: *flStdin,
|
||||
Memory: *flMemory,
|
||||
CpuShares: *flCpuShares,
|
||||
AttachStdin: flAttach.Get("stdin"),
|
||||
AttachStdout: flAttach.Get("stdout"),
|
||||
AttachStderr: flAttach.Get("stderr"),
|
||||
Env: flEnv,
|
||||
Cmd: runCmd,
|
||||
Dns: flDns,
|
||||
Image: image,
|
||||
Volumes: flVolumes,
|
||||
VolumesFrom: *flVolumesFrom,
|
||||
Entrypoint: entrypoint,
|
||||
}
|
||||
hostConfig := &HostConfig{
|
||||
Binds: flBinds,
|
||||
Binds: binds,
|
||||
ContainerIDFile: *flContainerIDFile,
|
||||
}
|
||||
|
||||
if capabilities != nil && *flMemory > 0 && !capabilities.SwapLimit {
|
||||
@@ -194,20 +212,25 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
|
||||
return config, hostConfig, cmd, nil
|
||||
}
|
||||
|
||||
type PortMapping map[string]string
|
||||
|
||||
type NetworkSettings struct {
|
||||
IPAddress string
|
||||
IPPrefixLen int
|
||||
Gateway string
|
||||
Bridge string
|
||||
PortMapping map[string]string
|
||||
PortMapping map[string]PortMapping
|
||||
}
|
||||
|
||||
// String returns a human-readable description of the port mapping defined in the settings
|
||||
func (settings *NetworkSettings) PortMappingHuman() string {
|
||||
var mapping []string
|
||||
for private, public := range settings.PortMapping {
|
||||
for private, public := range settings.PortMapping["Tcp"] {
|
||||
mapping = append(mapping, fmt.Sprintf("%s->%s", public, private))
|
||||
}
|
||||
for private, public := range settings.PortMapping["Udp"] {
|
||||
mapping = append(mapping, fmt.Sprintf("%s->%s/udp", public, private))
|
||||
}
|
||||
sort.Strings(mapping)
|
||||
return strings.Join(mapping, ", ")
|
||||
}
|
||||
@@ -257,6 +280,26 @@ func (container *Container) ToDisk() (err error) {
|
||||
return ioutil.WriteFile(container.jsonPath(), data, 0666)
|
||||
}
|
||||
|
||||
func (container *Container) ReadHostConfig() (*HostConfig, error) {
|
||||
data, err := ioutil.ReadFile(container.hostConfigPath())
|
||||
if err != nil {
|
||||
return &HostConfig{}, err
|
||||
}
|
||||
hostConfig := &HostConfig{}
|
||||
if err := json.Unmarshal(data, hostConfig); err != nil {
|
||||
return &HostConfig{}, err
|
||||
}
|
||||
return hostConfig, nil
|
||||
}
|
||||
|
||||
func (container *Container) SaveHostConfig(hostConfig *HostConfig) (err error) {
|
||||
data, err := json.Marshal(hostConfig)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
|
||||
}
|
||||
|
||||
func (container *Container) generateLXCConfig() error {
|
||||
fo, err := os.Create(container.lxcConfigPath())
|
||||
if err != nil {
|
||||
@@ -336,14 +379,15 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||
utils.Debugf("[start] attach stdin\n")
|
||||
defer utils.Debugf("[end] attach stdin\n")
|
||||
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
|
||||
if cStdout != nil {
|
||||
defer cStdout.Close()
|
||||
}
|
||||
if cStderr != nil {
|
||||
defer cStderr.Close()
|
||||
}
|
||||
if container.Config.StdinOnce && !container.Config.Tty {
|
||||
defer cStdin.Close()
|
||||
} else {
|
||||
if cStdout != nil {
|
||||
defer cStdout.Close()
|
||||
}
|
||||
if cStderr != nil {
|
||||
defer cStderr.Close()
|
||||
}
|
||||
}
|
||||
if container.Config.Tty {
|
||||
_, err = utils.CopyEscapable(cStdin, stdin)
|
||||
@@ -458,8 +502,12 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
|
||||
}
|
||||
|
||||
func (container *Container) Start(hostConfig *HostConfig) error {
|
||||
container.State.lock()
|
||||
defer container.State.unlock()
|
||||
container.State.Lock()
|
||||
defer container.State.Unlock()
|
||||
|
||||
if len(hostConfig.Binds) == 0 {
|
||||
hostConfig, _ = container.ReadHostConfig()
|
||||
}
|
||||
|
||||
if container.State.Running {
|
||||
return fmt.Errorf("The container %s is already running.", container.ID)
|
||||
@@ -467,8 +515,12 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||
if err := container.EnsureMounted(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.allocateNetwork(); err != nil {
|
||||
return err
|
||||
if container.runtime.networkManager.disabled {
|
||||
container.Config.NetworkDisabled = true
|
||||
} else {
|
||||
if err := container.allocateNetwork(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the config is compatible with the current kernel
|
||||
@@ -480,13 +532,11 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||
log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
||||
container.Config.MemorySwap = -1
|
||||
}
|
||||
container.Volumes = make(map[string]string)
|
||||
container.VolumesRW = make(map[string]bool)
|
||||
|
||||
// Create the requested bind mounts
|
||||
binds := make(map[string]BindMap)
|
||||
// Define illegal container destinations
|
||||
illegal_dsts := []string{"/", "."}
|
||||
illegalDsts := []string{"/", "."}
|
||||
|
||||
for _, bind := range hostConfig.Binds {
|
||||
// FIXME: factorize bind parsing in parseBind
|
||||
@@ -505,7 +555,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||
}
|
||||
|
||||
// Bail if trying to mount to an illegal destination
|
||||
for _, illegal := range illegal_dsts {
|
||||
for _, illegal := range illegalDsts {
|
||||
if dst == illegal {
|
||||
return fmt.Errorf("Illegal bind destination: %s", dst)
|
||||
}
|
||||
@@ -521,30 +571,35 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||
|
||||
// FIXME: evaluate volumes-from before individual volumes, so that the latter can override the former.
|
||||
// Create the requested volumes volumes
|
||||
for volPath := range container.Config.Volumes {
|
||||
volPath = path.Clean(volPath)
|
||||
// If an external bind is defined for this volume, use that as a source
|
||||
if bindMap, exists := binds[volPath]; exists {
|
||||
container.Volumes[volPath] = bindMap.SrcPath
|
||||
if strings.ToLower(bindMap.Mode) == "rw" {
|
||||
container.VolumesRW[volPath] = true
|
||||
if container.Volumes == nil || len(container.Volumes) == 0 {
|
||||
container.Volumes = make(map[string]string)
|
||||
container.VolumesRW = make(map[string]bool)
|
||||
|
||||
for volPath := range container.Config.Volumes {
|
||||
volPath = path.Clean(volPath)
|
||||
// If an external bind is defined for this volume, use that as a source
|
||||
if bindMap, exists := binds[volPath]; exists {
|
||||
container.Volumes[volPath] = bindMap.SrcPath
|
||||
if strings.ToLower(bindMap.Mode) == "rw" {
|
||||
container.VolumesRW[volPath] = true
|
||||
}
|
||||
// Otherwise create an directory in $ROOT/volumes/ and use that
|
||||
} else {
|
||||
c, err := container.runtime.volumes.Create(nil, container, "", "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srcPath, err := c.layer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
container.Volumes[volPath] = srcPath
|
||||
container.VolumesRW[volPath] = true // RW by default
|
||||
}
|
||||
// Otherwise create an directory in $ROOT/volumes/ and use that
|
||||
} else {
|
||||
c, err := container.runtime.volumes.Create(nil, container, "", "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
// Create the mountpoint
|
||||
if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
|
||||
return nil
|
||||
}
|
||||
srcPath, err := c.layer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
container.Volumes[volPath] = srcPath
|
||||
container.VolumesRW[volPath] = true // RW by default
|
||||
}
|
||||
// Create the mountpoint
|
||||
if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,6 +616,9 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||
return nil
|
||||
}
|
||||
container.Volumes[volPath] = id
|
||||
if isRW, exists := c.VolumesRW[volPath]; exists {
|
||||
container.VolumesRW[volPath] = isRW
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,7 +634,9 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||
}
|
||||
|
||||
// Networking
|
||||
params = append(params, "-g", container.network.Gateway.String())
|
||||
if !container.Config.NetworkDisabled {
|
||||
params = append(params, "-g", container.network.Gateway.String())
|
||||
}
|
||||
|
||||
// User
|
||||
if container.Config.User != "" {
|
||||
@@ -591,6 +651,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||
params = append(params,
|
||||
"-e", "HOME=/",
|
||||
"-e", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"-e", "container=lxc",
|
||||
)
|
||||
|
||||
for _, elem := range container.Config.Env {
|
||||
@@ -604,10 +665,10 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||
container.cmd = exec.Command("lxc-start", params...)
|
||||
|
||||
// Setup logging of stdout and stderr to disk
|
||||
if err := container.runtime.LogToDisk(container.stdout, container.logPath("stdout")); err != nil {
|
||||
if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.runtime.LogToDisk(container.stderr, container.logPath("stderr")); err != nil {
|
||||
if err := container.runtime.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -628,6 +689,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
|
||||
container.waitLock = make(chan struct{})
|
||||
|
||||
container.ToDisk()
|
||||
container.SaveHostConfig(hostConfig)
|
||||
go container.monitor()
|
||||
return nil
|
||||
}
|
||||
@@ -665,29 +727,37 @@ func (container *Container) StdinPipe() (io.WriteCloser, error) {
|
||||
|
||||
func (container *Container) StdoutPipe() (io.ReadCloser, error) {
|
||||
reader, writer := io.Pipe()
|
||||
container.stdout.AddWriter(writer)
|
||||
container.stdout.AddWriter(writer, "")
|
||||
return utils.NewBufReader(reader), nil
|
||||
}
|
||||
|
||||
func (container *Container) StderrPipe() (io.ReadCloser, error) {
|
||||
reader, writer := io.Pipe()
|
||||
container.stderr.AddWriter(writer)
|
||||
container.stderr.AddWriter(writer, "")
|
||||
return utils.NewBufReader(reader), nil
|
||||
}
|
||||
|
||||
func (container *Container) allocateNetwork() error {
|
||||
if container.Config.NetworkDisabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
iface, err := container.runtime.networkManager.Allocate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
container.NetworkSettings.PortMapping = make(map[string]string)
|
||||
container.NetworkSettings.PortMapping = make(map[string]PortMapping)
|
||||
container.NetworkSettings.PortMapping["Tcp"] = make(PortMapping)
|
||||
container.NetworkSettings.PortMapping["Udp"] = make(PortMapping)
|
||||
for _, spec := range container.Config.PortSpecs {
|
||||
nat, err := iface.AllocatePort(spec)
|
||||
if err != nil {
|
||||
iface.Release()
|
||||
return err
|
||||
}
|
||||
container.NetworkSettings.PortMapping[strconv.Itoa(nat.Backend)] = strconv.Itoa(nat.Frontend)
|
||||
proto := strings.Title(nat.Proto)
|
||||
backend, frontend := strconv.Itoa(nat.Backend), strconv.Itoa(nat.Frontend)
|
||||
container.NetworkSettings.PortMapping[proto][backend] = frontend
|
||||
}
|
||||
container.network = iface
|
||||
container.NetworkSettings.Bridge = container.runtime.networkManager.bridgeIface
|
||||
@@ -698,6 +768,9 @@ func (container *Container) allocateNetwork() error {
|
||||
}
|
||||
|
||||
func (container *Container) releaseNetwork() {
|
||||
if container.Config.NetworkDisabled {
|
||||
return
|
||||
}
|
||||
container.network.Release()
|
||||
container.network = nil
|
||||
container.NetworkSettings = &NetworkSettings{}
|
||||
@@ -733,7 +806,9 @@ func (container *Container) monitor() {
|
||||
}
|
||||
}
|
||||
utils.Debugf("Process finished")
|
||||
|
||||
if container.runtime != nil && container.runtime.srv != nil {
|
||||
container.runtime.srv.LogEvent("die", container.ShortID())
|
||||
}
|
||||
exitCode := -1
|
||||
if container.cmd != nil {
|
||||
exitCode = container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
|
||||
@@ -813,8 +888,8 @@ func (container *Container) kill() error {
|
||||
}
|
||||
|
||||
func (container *Container) Kill() error {
|
||||
container.State.lock()
|
||||
defer container.State.unlock()
|
||||
container.State.Lock()
|
||||
defer container.State.Unlock()
|
||||
if !container.State.Running {
|
||||
return nil
|
||||
}
|
||||
@@ -822,8 +897,8 @@ func (container *Container) Kill() error {
|
||||
}
|
||||
|
||||
func (container *Container) Stop(seconds int) error {
|
||||
container.State.lock()
|
||||
defer container.State.unlock()
|
||||
container.State.Lock()
|
||||
defer container.State.Unlock()
|
||||
if !container.State.Running {
|
||||
return nil
|
||||
}
|
||||
@@ -962,6 +1037,10 @@ func (container *Container) ReadLog(name string) (io.Reader, error) {
|
||||
return os.Open(container.logPath(name))
|
||||
}
|
||||
|
||||
func (container *Container) hostConfigPath() string {
|
||||
return path.Join(container.root, "hostconfig.json")
|
||||
}
|
||||
|
||||
func (container *Container) jsonPath() string {
|
||||
return path.Join(container.root, "config.json")
|
||||
}
|
||||
|
||||
@@ -39,16 +39,11 @@ func TestIDFormat(t *testing.T) {
|
||||
func TestMultipleAttachRestart(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, err := NewBuilder(runtime).Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/sh", "-c",
|
||||
"i=1; while [ $i -le 5 ]; do i=`expr $i + 1`; echo hello; done"},
|
||||
},
|
||||
container, hostConfig, _ := mkContainer(
|
||||
runtime,
|
||||
[]string{"_", "/bin/sh", "-c", "i=1; while [ $i -le 5 ]; do i=`expr $i + 1`; echo hello; done"},
|
||||
t,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
// Simulate 3 client attaching to the container and stop/restart
|
||||
@@ -65,7 +60,6 @@ func TestMultipleAttachRestart(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -140,19 +134,8 @@ func TestMultipleAttachRestart(t *testing.T) {
|
||||
func TestDiff(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
builder := NewBuilder(runtime)
|
||||
|
||||
// Create a container and remove a file
|
||||
container1, err := builder.Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/rm", "/etc/passwd"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container1, _, _ := mkContainer(runtime, []string{"_", "/bin/rm", "/etc/passwd"}, t)
|
||||
defer runtime.Destroy(container1)
|
||||
|
||||
if err := container1.Run(); err != nil {
|
||||
@@ -185,15 +168,7 @@ func TestDiff(t *testing.T) {
|
||||
}
|
||||
|
||||
// Create a new container from the commited image
|
||||
container2, err := builder.Create(
|
||||
&Config{
|
||||
Image: img.ID,
|
||||
Cmd: []string{"cat", "/etc/passwd"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container2, _, _ := mkContainer(runtime, []string{img.ID, "cat", "/etc/passwd"}, t)
|
||||
defer runtime.Destroy(container2)
|
||||
|
||||
if err := container2.Run(); err != nil {
|
||||
@@ -212,15 +187,7 @@ func TestDiff(t *testing.T) {
|
||||
}
|
||||
|
||||
// Create a new containere
|
||||
container3, err := builder.Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"rm", "/bin/httpd"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container3, _, _ := mkContainer(runtime, []string{"_", "rm", "/bin/httpd"}, t)
|
||||
defer runtime.Destroy(container3)
|
||||
|
||||
if err := container3.Run(); err != nil {
|
||||
@@ -246,17 +213,7 @@ func TestDiff(t *testing.T) {
|
||||
func TestCommitAutoRun(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
builder := NewBuilder(runtime)
|
||||
container1, err := builder.Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/sh", "-c", "echo hello > /world"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container1, _, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
|
||||
defer runtime.Destroy(container1)
|
||||
|
||||
if container1.State.Running {
|
||||
@@ -279,14 +236,7 @@ func TestCommitAutoRun(t *testing.T) {
|
||||
}
|
||||
|
||||
// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
|
||||
container2, err := builder.Create(
|
||||
&Config{
|
||||
Image: img.ID,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container2, hostConfig, _ := mkContainer(runtime, []string{img.ID}, t)
|
||||
defer runtime.Destroy(container2)
|
||||
stdout, err := container2.StdoutPipe()
|
||||
if err != nil {
|
||||
@@ -296,7 +246,6 @@ func TestCommitAutoRun(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container2.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -324,17 +273,7 @@ func TestCommitRun(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
builder := NewBuilder(runtime)
|
||||
|
||||
container1, err := builder.Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/sh", "-c", "echo hello > /world"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container1, hostConfig, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
|
||||
defer runtime.Destroy(container1)
|
||||
|
||||
if container1.State.Running {
|
||||
@@ -357,16 +296,7 @@ func TestCommitRun(t *testing.T) {
|
||||
}
|
||||
|
||||
// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
|
||||
|
||||
container2, err := builder.Create(
|
||||
&Config{
|
||||
Image: img.ID,
|
||||
Cmd: []string{"cat", "/world"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container2, hostConfig, _ := mkContainer(runtime, []string{img.ID, "cat", "/world"}, t)
|
||||
defer runtime.Destroy(container2)
|
||||
stdout, err := container2.StdoutPipe()
|
||||
if err != nil {
|
||||
@@ -376,7 +306,6 @@ func TestCommitRun(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container2.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -403,18 +332,7 @@ func TestCommitRun(t *testing.T) {
|
||||
func TestStart(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, err := NewBuilder(runtime).Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Memory: 33554432,
|
||||
CpuShares: 1000,
|
||||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container, hostConfig, _ := mkContainer(runtime, []string{"-m", "33554432", "-c", "1000", "-i", "_", "/bin/cat"}, t)
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
cStdin, err := container.StdinPipe()
|
||||
@@ -422,7 +340,6 @@ func TestStart(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -445,15 +362,7 @@ func TestStart(t *testing.T) {
|
||||
func TestRun(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, err := NewBuilder(runtime).Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
if container.State.Running {
|
||||
@@ -511,12 +420,14 @@ func TestKillDifferentUser(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Give some time to lxc to spawn the process (setuid might take some time)
|
||||
container.WaitTimeout(500 * time.Millisecond)
|
||||
setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
|
||||
for !container.State.Running {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
})
|
||||
|
||||
if !container.State.Running {
|
||||
t.Errorf("Container should be running")
|
||||
}
|
||||
// Even if the state is running, lets give some time to lxc to spawn the process
|
||||
container.WaitTimeout(500 * time.Millisecond)
|
||||
|
||||
if err := container.Kill(); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -847,6 +758,23 @@ func TestUser(t *testing.T) {
|
||||
if !strings.Contains(string(output), "uid=1(daemon) gid=1(daemon)") {
|
||||
t.Error(string(output))
|
||||
}
|
||||
|
||||
// Test an wrong username
|
||||
container, err = builder.Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"id"},
|
||||
|
||||
User: "unkownuser",
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
output, err = container.Output()
|
||||
if container.State.ExitCode == 0 {
|
||||
t.Fatal("Starting container with wrong uid should fail but it passed.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleContainers(t *testing.T) {
|
||||
@@ -1001,7 +929,7 @@ func TestEnv(t *testing.T) {
|
||||
defer nuke(runtime)
|
||||
container, err := NewBuilder(runtime).Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/usr/bin/env"},
|
||||
Cmd: []string{"env"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
@@ -1031,6 +959,7 @@ func TestEnv(t *testing.T) {
|
||||
goodEnv := []string{
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"HOME=/",
|
||||
"container=lxc",
|
||||
}
|
||||
sort.Strings(goodEnv)
|
||||
if len(goodEnv) != len(actualEnv) {
|
||||
@@ -1043,6 +972,29 @@ func TestEnv(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEntrypoint(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, err := NewBuilder(runtime).Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Entrypoint: []string{"/bin/echo"},
|
||||
Cmd: []string{"-n", "foobar"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
output, err := container.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(output) != "foobar" {
|
||||
t.Error(string(output))
|
||||
}
|
||||
}
|
||||
|
||||
func grepFile(t *testing.T, path string, pattern string) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
@@ -1097,10 +1049,7 @@ func TestLXCConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
func BenchmarkRunSequencial(b *testing.B) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(b)
|
||||
defer nuke(runtime)
|
||||
for i := 0; i < b.N; i++ {
|
||||
container, err := NewBuilder(runtime).Create(&Config{
|
||||
@@ -1126,10 +1075,7 @@ func BenchmarkRunSequencial(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkRunParallel(b *testing.B) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(b)
|
||||
defer nuke(runtime)
|
||||
|
||||
var tasks []chan error
|
||||
@@ -1195,18 +1141,152 @@ func TestBindMounts(t *testing.T) {
|
||||
writeFile(path.Join(tmpDir, "touch-me"), "", t)
|
||||
|
||||
// Test reading from a read-only bind mount
|
||||
stdout, _ := runContainer(r, []string{"-b", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t)
|
||||
stdout, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t)
|
||||
if !strings.Contains(stdout, "touch-me") {
|
||||
t.Fatal("Container failed to read from bind mount")
|
||||
}
|
||||
|
||||
// test writing to bind mount
|
||||
runContainer(r, []string{"-b", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t)
|
||||
runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t)
|
||||
readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist
|
||||
|
||||
// test mounting to an illegal destination directory
|
||||
if _, err := runContainer(r, []string{"-b", fmt.Sprintf("%s:.", tmpDir), "ls", "."}, nil); err == nil {
|
||||
if _, err := runContainer(r, []string{"-v", fmt.Sprintf("%s:.", tmpDir), "ls", "."}, nil); err == nil {
|
||||
t.Fatal("Container bind mounted illegal directory")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Test that VolumesRW values are copied to the new container. Regression test for #1201
|
||||
func TestVolumesFromReadonlyMount(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, err := NewBuilder(runtime).Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/echo", "-n", "foobar"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
_, err = container.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !container.VolumesRW["/test"] {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
container2, err := NewBuilder(runtime).Create(
|
||||
&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"/bin/echo", "-n", "foobar"},
|
||||
VolumesFrom: container.ID,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container2)
|
||||
|
||||
_, err = container2.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if container.Volumes["/test"] != container2.Volumes["/test"] {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
actual, exists := container2.VolumesRW["/test"]
|
||||
if !exists {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if container.VolumesRW["/test"] != actual {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
// Test that restarting a container with a volume does not create a new volume on restart. Regression test for #819.
|
||||
func TestRestartWithVolumes(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
container, err := NewBuilder(runtime).Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"echo", "-n", "foobar"},
|
||||
Volumes: map[string]struct{}{"/test": {}},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Destroy(container)
|
||||
|
||||
for key := range container.Config.Volumes {
|
||||
if key != "/test" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
_, err = container.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := container.Volumes["/test"]
|
||||
if expected == "" {
|
||||
t.Fail()
|
||||
}
|
||||
// Run the container again to verify the volume path persists
|
||||
_, err = container.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
actual := container.Volumes["/test"]
|
||||
if expected != actual {
|
||||
t.Fatalf("Expected volume path: %s Actual path: %s", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
config, hc, _, err := ParseRun([]string{"-n=false", GetTestImage(runtime).ID, "ip", "addr", "show"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c, err := NewBuilder(runtime).Create(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stdout, err := c.StdoutPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer runtime.Destroy(c)
|
||||
if err := c.Start(hc); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.WaitTimeout(500 * time.Millisecond)
|
||||
c.Wait()
|
||||
output, err := ioutil.ReadAll(stdout)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
interfaces := regexp.MustCompile(`(?m)^[0-9]+: [a-zA-Z0-9]+`).FindAllString(string(output), -1)
|
||||
if len(interfaces) != 1 {
|
||||
t.Fatalf("Wrong interface count in test container: expected [1: lo], got [%s]", interfaces)
|
||||
}
|
||||
if interfaces[0] != "1: lo" {
|
||||
t.Fatalf("Wrong interface in test container: expected [1: lo], got [%s]", interfaces)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ mkdir bin etc dev dev/pts lib proc sys tmp
|
||||
touch etc/resolv.conf
|
||||
cp /etc/nsswitch.conf etc/nsswitch.conf
|
||||
echo root:x:0:0:root:/:/bin/sh > etc/passwd
|
||||
echo daemon:x:1:1:daemon:/usr/sbin:/bin/sh >> etc/passwd
|
||||
echo root:x:0: > etc/group
|
||||
echo daemon:x:1: >> etc/group
|
||||
ln -s lib lib64
|
||||
ln -s bin sbin
|
||||
cp $BUSYBOX $SOCAT bin
|
||||
@@ -41,6 +43,7 @@ do
|
||||
cp -a /dev/$X dev
|
||||
done
|
||||
|
||||
chmod 0755 $ROOTFS # See #486
|
||||
tar -cf- . | docker import - docker-ut
|
||||
docker run -i -u root docker-ut /bin/echo Success.
|
||||
rm -rf $ROOTFS
|
||||
|
||||
@@ -28,16 +28,16 @@ func main() {
|
||||
flDaemon := flag.Bool("d", false, "Daemon mode")
|
||||
flDebug := flag.Bool("D", false, "Debug mode")
|
||||
flAutoRestart := flag.Bool("r", false, "Restart previously running containers")
|
||||
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge")
|
||||
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge. Use 'none' to disable container networking")
|
||||
pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID")
|
||||
flGraphPath := flag.String("g", "/var/lib/docker", "Path to graph storage base dir.")
|
||||
flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.")
|
||||
flDns := flag.String("dns", "", "Set custom dns servers")
|
||||
flHosts := docker.ListOpts{fmt.Sprintf("tcp://%s:%d", docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT)}
|
||||
flHosts := docker.ListOpts{fmt.Sprintf("unix://%s", docker.DEFAULTUNIXSOCKET)}
|
||||
flag.Var(&flHosts, "H", "tcp://host:port to bind/connect to or unix://path/to/socket to use")
|
||||
flag.Parse()
|
||||
if len(flHosts) > 1 {
|
||||
flHosts = flHosts[1:len(flHosts)] //trick to display a nice defaul value in the usage
|
||||
flHosts = flHosts[1:] //trick to display a nice defaul value in the usage
|
||||
}
|
||||
for i, flHost := range flHosts {
|
||||
flHosts[i] = utils.ParseHost(docker.DEFAULTHTTPHOST, docker.DEFAULTHTTPPORT, flHost)
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
:description: API Documentation for Docker
|
||||
:keywords: API, Docker, rcli, REST, documentation
|
||||
|
||||
.. COMMENT use http://pythonhosted.org/sphinxcontrib-httpdomain/ to
|
||||
.. document the REST API.
|
||||
|
||||
=================
|
||||
Docker Remote API
|
||||
=================
|
||||
@@ -12,31 +15,62 @@ Docker Remote API
|
||||
=====================
|
||||
|
||||
- The Remote API is replacing rcli
|
||||
- Default port in the docker deamon is 4243
|
||||
- The API tends to be REST, but for some complex commands, like attach or pull, the HTTP connection is hijacked to transport stdout stdin and stderr
|
||||
- Since API version 1.2, the auth configuration is now handled client side, so the client has to send the authConfig as POST in /images/(name)/push
|
||||
- By default the Docker daemon listens on unix:///var/run/docker.sock and the client must have root access to interact with the daemon
|
||||
- The API tends to be REST, but for some complex commands, like attach
|
||||
or pull, the HTTP connection is hijacked to transport stdout stdin
|
||||
and stderr
|
||||
- Since API version 1.2, the auth configuration is now handled client
|
||||
side, so the client has to send the authConfig as POST in
|
||||
/images/(name)/push
|
||||
|
||||
2. Versions
|
||||
===========
|
||||
|
||||
The current verson of the API is 1.3
|
||||
Calling /images/<name>/insert is the same as calling /v1.3/images/<name>/insert
|
||||
You can still call an old version of the api using /v1.0/images/<name>/insert
|
||||
The current verson of the API is 1.4
|
||||
|
||||
:doc:`docker_remote_api_v1.3`
|
||||
Calling /images/<name>/insert is the same as calling
|
||||
/v1.4/images/<name>/insert
|
||||
|
||||
You can still call an old version of the api using
|
||||
/v1.0/images/<name>/insert
|
||||
|
||||
:doc:`docker_remote_api_v1.4`
|
||||
*****************************
|
||||
|
||||
What's new
|
||||
----------
|
||||
|
||||
.. http:get:: /containers/(id)/top
|
||||
|
||||
**New!** You can now use ps args with docker top, like `docker top <container_id> aux`
|
||||
|
||||
:doc:`docker_remote_api_v1.3`
|
||||
*****************************
|
||||
|
||||
docker v0.5.0 51f6c4a_
|
||||
|
||||
What's new
|
||||
----------
|
||||
|
||||
.. http:get:: /containers/(id)/top
|
||||
|
||||
List the processes running inside a container.
|
||||
|
||||
.. http:get:: /events:
|
||||
|
||||
**New!** Monitor docker's events via streaming or via polling
|
||||
|
||||
Builder (/build):
|
||||
|
||||
- Simplify the upload of the build context
|
||||
- Simply stream a tarball instead of multipart upload with 4 intermediary buffers
|
||||
- Simply stream a tarball instead of multipart upload with 4
|
||||
intermediary buffers
|
||||
- Simpler, less memory usage, less disk usage and faster
|
||||
|
||||
.. Note::
|
||||
The /build improvements are not reverse-compatible. Pre 1.3 clients will break on /build.
|
||||
.. Warning::
|
||||
|
||||
The /build improvements are not reverse-compatible. Pre 1.3 clients
|
||||
will break on /build.
|
||||
|
||||
List containers (/containers/json):
|
||||
|
||||
@@ -44,7 +78,8 @@ List containers (/containers/json):
|
||||
|
||||
Start containers (/containers/<id>/start):
|
||||
|
||||
- You can now pass host-specific configuration (e.g. bind mounts) in the POST body for start calls
|
||||
- You can now pass host-specific configuration (e.g. bind mounts) in
|
||||
the POST body for start calls
|
||||
|
||||
:doc:`docker_remote_api_v1.2`
|
||||
*****************************
|
||||
@@ -55,14 +90,25 @@ What's new
|
||||
----------
|
||||
|
||||
The auth configuration is now handled by the client.
|
||||
The client should send it's authConfig as POST on each call of /images/(name)/push
|
||||
|
||||
.. http:get:: /auth is now deprecated
|
||||
.. http:post:: /auth only checks the configuration but doesn't store it on the server
|
||||
The client should send it's authConfig as POST on each call of
|
||||
/images/(name)/push
|
||||
|
||||
Deleting an image is now improved, will only untag the image if it has chidrens and remove all the untagged parents if has any.
|
||||
.. http:get:: /auth
|
||||
|
||||
.. http:post:: /images/<name>/delete now returns a JSON with the list of images deleted/untagged
|
||||
**Deprecated.**
|
||||
|
||||
.. http:post:: /auth
|
||||
|
||||
Only checks the configuration but doesn't store it on the server
|
||||
|
||||
Deleting an image is now improved, will only untag the image if it
|
||||
has chidren and remove all the untagged parents if has any.
|
||||
|
||||
.. http:post:: /images/<name>/delete
|
||||
|
||||
Now returns a JSON structure with the list of images
|
||||
deleted/untagged.
|
||||
|
||||
|
||||
:doc:`docker_remote_api_v1.1`
|
||||
@@ -77,7 +123,7 @@ What's new
|
||||
.. http:post:: /images/(name)/insert
|
||||
.. http:post:: /images/(name)/push
|
||||
|
||||
Uses json stream instead of HTML hijack, it looks like this:
|
||||
Uses json stream instead of HTML hijack, it looks like this:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
@@ -104,6 +150,7 @@ Initial version
|
||||
.. _a8ae398: https://github.com/dotcloud/docker/commit/a8ae398bf52e97148ee7bd0d5868de2e15bd297f
|
||||
.. _8d73740: https://github.com/dotcloud/docker/commit/8d73740343778651c09160cde9661f5f387b36f4
|
||||
.. _2e7649b: https://github.com/dotcloud/docker/commit/2e7649beda7c820793bd46766cbc2cfeace7b168
|
||||
.. _51f6c4a: https://github.com/dotcloud/docker/commit/51f6c4a7372450d164c61e0054daf0223ddbd909
|
||||
|
||||
==================================
|
||||
Docker Remote API Client Libraries
|
||||
@@ -130,3 +177,6 @@ and we will add the libraries here.
|
||||
| Javascript (Angular) | dockerui | https://github.com/crosbymichael/dockerui |
|
||||
| **WebUI** | | |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
| Java | docker-java | https://github.com/kpelykh/docker-java |
|
||||
+----------------------+----------------+--------------------------------------------+
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
.. use orphan to suppress "WARNING: document isn't included in any toctree"
|
||||
.. per http://sphinx-doc.org/markup/misc.html#file-wide-metadata
|
||||
|
||||
:orphan:
|
||||
|
||||
:title: Remote API v1.0
|
||||
:description: API Documentation for Docker
|
||||
:keywords: API, Docker, rcli, REST, documentation
|
||||
@@ -300,8 +305,8 @@ Start a container
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
Stop a contaier
|
||||
***************
|
||||
Stop a container
|
||||
****************
|
||||
|
||||
.. http:post:: /containers/(id)/stop
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.. use orphan to suppress "WARNING: document isn't included in any toctree"
|
||||
.. per http://sphinx-doc.org/markup/misc.html#file-wide-metadata
|
||||
|
||||
:orphan:
|
||||
|
||||
:title: Remote API v1.1
|
||||
:description: API Documentation for Docker
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
.. use orphan to suppress "WARNING: document isn't included in any toctree"
|
||||
.. per http://sphinx-doc.org/markup/misc.html#file-wide-metadata
|
||||
|
||||
:orphan:
|
||||
|
||||
:title: Remote API v1.2
|
||||
:description: API Documentation for Docker
|
||||
:keywords: API, Docker, rcli, REST, documentation
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
.. use orphan to suppress "WARNING: document isn't included in any toctree"
|
||||
.. per http://sphinx-doc.org/markup/misc.html#file-wide-metadata
|
||||
|
||||
:orphan:
|
||||
|
||||
:title: Remote API v1.3
|
||||
:description: API Documentation for Docker
|
||||
:keywords: API, Docker, rcli, REST, documentation
|
||||
@@ -220,6 +225,46 @@ Inspect a container
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
List processes running inside a container
|
||||
*****************************************
|
||||
|
||||
.. http:get:: /containers/(id)/top
|
||||
|
||||
List processes running inside the container ``id``
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /containers/4fa6e0f0c678/top HTTP/1.1
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
[
|
||||
{
|
||||
"PID":"11935",
|
||||
"Tty":"pts/2",
|
||||
"Time":"00:00:00",
|
||||
"Cmd":"sh"
|
||||
},
|
||||
{
|
||||
"PID":"12140",
|
||||
"Tty":"pts/2",
|
||||
"Time":"00:00:00",
|
||||
"Cmd":"sleep"
|
||||
}
|
||||
]
|
||||
|
||||
:statuscode 200: no error
|
||||
:statuscode 404: no such container
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
Inspect changes on a container's filesystem
|
||||
*******************************************
|
||||
|
||||
@@ -800,7 +845,7 @@ Remove an image
|
||||
{"Deleted":"53b4f83ac9"}
|
||||
]
|
||||
|
||||
:statuscode 204: no error
|
||||
:statuscode 200: no error
|
||||
:statuscode 404: no such image
|
||||
:statuscode 409: conflict
|
||||
:statuscode 500: server error
|
||||
@@ -881,6 +926,7 @@ Build an image from Dockerfile via stdin
|
||||
The Content-type header should be set to "application/tar".
|
||||
|
||||
:query t: tag to be applied to the resulting image in case of success
|
||||
:query q: suppress verbose build output
|
||||
:statuscode 200: no error
|
||||
:statuscode 500: server error
|
||||
|
||||
@@ -943,7 +989,10 @@ Display system-wide information
|
||||
"NFd": 11,
|
||||
"NGoroutines":21,
|
||||
"MemoryLimit":true,
|
||||
"SwapLimit":false
|
||||
"SwapLimit":false,
|
||||
"EventsListeners":"0",
|
||||
"LXCVersion":"0.7.5",
|
||||
"KernelVersion":"3.8.0-19-generic"
|
||||
}
|
||||
|
||||
:statuscode 200: no error
|
||||
@@ -1013,6 +1062,36 @@ Create a new image from a container's changes
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
Monitor Docker's events
|
||||
***********************
|
||||
|
||||
.. http:get:: /events
|
||||
|
||||
Get events from docker, either in real time via streaming, or via polling (using `since`)
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /events?since=1374067924
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{"status":"create","id":"dfdf82bd3881","time":1374067924}
|
||||
{"status":"start","id":"dfdf82bd3881","time":1374067924}
|
||||
{"status":"stop","id":"dfdf82bd3881","time":1374067966}
|
||||
{"status":"destroy","id":"dfdf82bd3881","time":1374067970}
|
||||
|
||||
:query since: timestamp used for polling
|
||||
:statuscode 200: no error
|
||||
:statuscode 500: server error
|
||||
|
||||
|
||||
3. Going further
|
||||
================
|
||||
|
||||
|
||||
1093
docs/sources/api/docker_remote_api_v1.4.rst
Normal file
@@ -452,7 +452,7 @@ User Register
|
||||
"username": "foobar"'}
|
||||
|
||||
:jsonparameter email: valid email address, that needs to be confirmed
|
||||
:jsonparameter username: min 4 character, max 30 characters, must match the regular expression [a-z0-9_].
|
||||
:jsonparameter username: min 4 character, max 30 characters, must match the regular expression [a-z0-9\_].
|
||||
:jsonparameter password: min 5 characters
|
||||
|
||||
**Example Response**:
|
||||
|
||||
@@ -367,7 +367,8 @@ POST /v1/users
|
||||
{"email": "sam@dotcloud.com", "password": "toto42", "username": "foobar"'}
|
||||
|
||||
**Validation**:
|
||||
- **username** : min 4 character, max 30 characters, must match the regular expression [a-z0-9_].
|
||||
- **username**: min 4 character, max 30 characters, must match the regular
|
||||
expression [a-z0-9\_].
|
||||
- **password**: min 5 characters
|
||||
|
||||
**Valid**: return HTTP 200
|
||||
@@ -566,4 +567,4 @@ Next request::
|
||||
---------------------
|
||||
|
||||
- 1.0 : May 6th 2013 : initial release
|
||||
- 1.1 : June 1st 2013 : Added Delete Repository and way to handle new source namespace.
|
||||
- 1.1 : June 1st 2013 : Added Delete Repository and way to handle new source namespace.
|
||||
|
||||
@@ -52,5 +52,6 @@ Available Commands
|
||||
command/start
|
||||
command/stop
|
||||
command/tag
|
||||
command/top
|
||||
command/version
|
||||
command/wait
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
Usage: docker build [OPTIONS] PATH | URL | -
|
||||
Build a new container image from the source code at PATH
|
||||
-t="": Tag to be applied to the resulting image in case of success.
|
||||
-q=false: Suppress verbose build output.
|
||||
When a single Dockerfile is given as URL, then no context is set. When a git repository is set as URL, the repository is used as context
|
||||
|
||||
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
|
||||
Create a new filesystem image from the contents of a tarball
|
||||
|
||||
At this time, the URL must start with ``http`` and point to a single file archive (.tar, .tar.gz, .bzip)
|
||||
containing a root filesystem. If you would like to import from a local directory or archive,
|
||||
At this time, the URL must start with ``http`` and point to a single file archive
|
||||
(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz)
|
||||
containing a root filesystem. If you would like to import from a local directory or archive,
|
||||
you can use the ``-`` parameter to take the data from standard in.
|
||||
|
||||
Examples
|
||||
@@ -30,7 +31,7 @@ Import from a local file
|
||||
Import to docker via pipe and standard in
|
||||
|
||||
``$ cat exampleimage.tgz | docker import - exampleimagelocal``
|
||||
|
||||
|
||||
Import from a local directory
|
||||
.............................
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
::
|
||||
|
||||
Usage: docker login
|
||||
Usage: docker login [OPTIONS]
|
||||
|
||||
Register or Login to the docker registry server
|
||||
|
||||
-e="": email
|
||||
-p="": password
|
||||
-u="": username
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
|
||||
Usage: docker rm [OPTIONS] CONTAINER
|
||||
|
||||
Remove a container
|
||||
Remove one or more containers
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
|
||||
::
|
||||
|
||||
Usage: docker rmimage [OPTIONS] IMAGE
|
||||
Usage: docker rmi IMAGE [IMAGE...]
|
||||
|
||||
Remove an image
|
||||
Remove one or more images
|
||||
|
||||
@@ -14,15 +14,27 @@
|
||||
|
||||
-a=map[]: Attach to stdin, stdout or stderr.
|
||||
-c=0: CPU shares (relative weight)
|
||||
-d=false: Detached mode: leave the container running in the background
|
||||
-cidfile="": Write the container ID to the file
|
||||
-d=false: Detached mode: Run container in the background, print new container id
|
||||
-e=[]: Set environment variables
|
||||
-h="": Container host name
|
||||
-i=false: Keep stdin open even if not attached
|
||||
-m=0: Memory limit (in bytes)
|
||||
-n=true: Enable networking for this container
|
||||
-p=[]: Map a network port to the container
|
||||
-t=false: Allocate a pseudo-tty
|
||||
-u="": Username or UID
|
||||
-d=[]: Set custom dns servers for the container
|
||||
-v=[]: Creates a new volume and mounts it at the specified path.
|
||||
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "host-dir" is missing, then docker creates a new volume.
|
||||
-volumes-from="": Mount all volumes from the given container.
|
||||
-b=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]
|
||||
-entrypoint="": Overwrite the default entrypoint set by the image.
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -cidfile /tmp/docker_test.cid ubuntu echo "test"
|
||||
|
||||
| This will create a container and print "test" to the console. The cidfile flag makes docker attempt to create a new file and write the container ID to it. If the file exists already, docker will return an error. Docker will close this file when docker run exits.
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
::
|
||||
|
||||
Usage: docker stop [OPTIONS] NAME
|
||||
Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
|
||||
|
||||
Stop a running container
|
||||
|
||||
-t=10: Number of seconds to wait for the container to stop before killing it.
|
||||
|
||||
13
docs/sources/commandline/command/top.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
:title: Top Command
|
||||
:description: Lookup the running processes of a container
|
||||
:keywords: top, docker, container, documentation
|
||||
|
||||
=======================================================
|
||||
``top`` -- Lookup the running processes of a container
|
||||
=======================================================
|
||||
|
||||
::
|
||||
|
||||
Usage: docker top CONTAINER
|
||||
|
||||
Lookup the running processes of a container
|
||||
@@ -37,5 +37,6 @@ Contents:
|
||||
start <command/start>
|
||||
stop <command/stop>
|
||||
tag <command/tag>
|
||||
top <command/top>
|
||||
version <command/version>
|
||||
wait <command/wait>
|
||||
wait <command/wait>
|
||||
|
||||
BIN
docs/sources/concepts/images/dockerlogo-h.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/sources/concepts/images/dockerlogo-v.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
@@ -1,10 +1,10 @@
|
||||
:title: Concepts
|
||||
:description: -- todo: change me
|
||||
:title: Overview
|
||||
:description: Docker documentation summary
|
||||
:keywords: concepts, documentation, docker, containers
|
||||
|
||||
|
||||
|
||||
Concepts
|
||||
Overview
|
||||
========
|
||||
|
||||
Contents:
|
||||
@@ -13,4 +13,4 @@ Contents:
|
||||
:maxdepth: 1
|
||||
|
||||
../index
|
||||
|
||||
manifesto
|
||||
|
||||
129
docs/sources/concepts/manifesto.rst
Normal file
@@ -0,0 +1,129 @@
|
||||
:title: Manifesto
|
||||
:description: An overview of Docker and standard containers
|
||||
:keywords: containers, lxc, concepts, explanation
|
||||
|
||||
.. _dockermanifesto:
|
||||
|
||||
Docker Manifesto
|
||||
----------------
|
||||
|
||||
Docker complements LXC with a high-level API which operates at the
|
||||
process level. It runs unix processes with strong guarantees of
|
||||
isolation and repeatability across servers.
|
||||
|
||||
Docker is a great building block for automating distributed systems:
|
||||
large-scale web deployments, database clusters, continuous deployment
|
||||
systems, private PaaS, service-oriented architectures, etc.
|
||||
|
||||
- **Heterogeneous payloads** Any combination of binaries, libraries,
|
||||
configuration files, scripts, virtualenvs, jars, gems, tarballs, you
|
||||
name it. No more juggling between domain-specific tools. Docker can
|
||||
deploy and run them all.
|
||||
- **Any server** Docker can run on any x64 machine with a modern linux
|
||||
kernel - whether it's a laptop, a bare metal server or a VM. This
|
||||
makes it perfect for multi-cloud deployments.
|
||||
- **Isolation** docker isolates processes from each other and from the
|
||||
underlying host, using lightweight containers.
|
||||
- **Repeatability** Because containers are isolated in their own
|
||||
filesystem, they behave the same regardless of where, when, and
|
||||
alongside what they run.
|
||||
|
||||
.. image:: images/lego_docker.jpg
|
||||
:target: http://bricks.argz.com/ins/7823-1/12
|
||||
|
||||
What is a Standard Container?
|
||||
.............................
|
||||
|
||||
Docker defines a unit of software delivery called a Standard
|
||||
Container. The goal of a Standard Container is to encapsulate a
|
||||
software component and all its dependencies in a format that is
|
||||
self-describing and portable, so that any compliant runtime can run it
|
||||
without extra dependency, regardless of the underlying machine and the
|
||||
contents of the container.
|
||||
|
||||
The spec for Standard Containers is currently work in progress, but it
|
||||
is very straightforward. It mostly defines 1) an image format, 2) a
|
||||
set of standard operations, and 3) an execution environment.
|
||||
|
||||
A great analogy for this is the shipping container. Just like Standard
|
||||
Containers are a fundamental unit of software delivery, shipping
|
||||
containers are a fundamental unit of physical delivery.
|
||||
|
||||
Standard operations
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Just like shipping containers, Standard Containers define a set of
|
||||
STANDARD OPERATIONS. Shipping containers can be lifted, stacked,
|
||||
locked, loaded, unloaded and labelled. Similarly, standard containers
|
||||
can be started, stopped, copied, snapshotted, downloaded, uploaded and
|
||||
tagged.
|
||||
|
||||
|
||||
Content-agnostic
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Just like shipping containers, Standard Containers are
|
||||
CONTENT-AGNOSTIC: all standard operations have the same effect
|
||||
regardless of the contents. A shipping container will be stacked in
|
||||
exactly the same way whether it contains Vietnamese powder coffee or
|
||||
spare Maserati parts. Similarly, Standard Containers are started or
|
||||
uploaded in the same way whether they contain a postgres database, a
|
||||
php application with its dependencies and application server, or Java
|
||||
build artifacts.
|
||||
|
||||
Infrastructure-agnostic
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be
|
||||
transported to thousands of facilities around the world, and
|
||||
manipulated by a wide variety of equipment. A shipping container can
|
||||
be packed in a factory in Ukraine, transported by truck to the nearest
|
||||
routing center, stacked onto a train, loaded into a German boat by an
|
||||
Australian-built crane, stored in a warehouse at a US facility,
|
||||
etc. Similarly, a standard container can be bundled on my laptop,
|
||||
uploaded to S3, downloaded, run and snapshotted by a build server at
|
||||
Equinix in Virginia, uploaded to 10 staging servers in a home-made
|
||||
Openstack cluster, then sent to 30 production instances across 3 EC2
|
||||
regions.
|
||||
|
||||
|
||||
Designed for automation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Because they offer the same standard operations regardless of content
|
||||
and infrastructure, Standard Containers, just like their physical
|
||||
counterpart, are extremely well-suited for automation. In fact, you
|
||||
could say automation is their secret weapon.
|
||||
|
||||
Many things that once required time-consuming and error-prone human
|
||||
effort can now be programmed. Before shipping containers, a bag of
|
||||
powder coffee was hauled, dragged, dropped, rolled and stacked by 10
|
||||
different people in 10 different locations by the time it reached its
|
||||
destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The
|
||||
process was slow, inefficient and cost a fortune - and was entirely
|
||||
different depending on the facility and the type of goods.
|
||||
|
||||
Similarly, before Standard Containers, by the time a software
|
||||
component ran in production, it had been individually built,
|
||||
configured, bundled, documented, patched, vendored, templated, tweaked
|
||||
and instrumented by 10 different people on 10 different
|
||||
computers. Builds failed, libraries conflicted, mirrors crashed,
|
||||
post-it notes were lost, logs were misplaced, cluster updates were
|
||||
half-broken. The process was slow, inefficient and cost a fortune -
|
||||
and was entirely different depending on the language and
|
||||
infrastructure provider.
|
||||
|
||||
Industrial-grade delivery
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There are 17 million shipping containers in existence, packed with
|
||||
every physical good imaginable. Every single one of them can be loaded
|
||||
on the same boats, by the same cranes, in the same facilities, and
|
||||
sent anywhere in the World with incredible efficiency. It is
|
||||
embarrassing to think that a 30 ton shipment of coffee can safely
|
||||
travel half-way across the World in *less time* than it takes a
|
||||
software team to deliver its code from one datacenter to another
|
||||
sitting 10 miles away.
|
||||
|
||||
With Standard Containers we can put an end to that embarrassment, by
|
||||
making INDUSTRIAL-GRADE DELIVERY of software a reality.
|
||||
@@ -5,53 +5,54 @@
|
||||
Setting Up a Dev Environment
|
||||
============================
|
||||
|
||||
Instructions that have been verified to work on Ubuntu Precise 12.04 (LTS) (64-bit),
|
||||
To make it easier to contribute to Docker, we provide a standard development environment. It is important that
|
||||
the same environment be used for all tests, builds and releases. The standard development environment defines
|
||||
all build dependencies: system libraries and binaries, go environment, go dependencies, etc.
|
||||
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
Step 1: install docker
|
||||
----------------------
|
||||
|
||||
**Linux kernel 3.8**
|
||||
Docker's build environment itself is a docker container, so the first step is to install docker on your system.
|
||||
|
||||
Due to a bug in LXC docker works best on the 3.8 kernel. Precise comes with a 3.2 kernel, so we need to upgrade it. The kernel we install comes with AUFS built in.
|
||||
You can follow the `install instructions most relevant to your system <https://docs.docker.io/en/latest/installation/>`.
|
||||
Make sure you have a working, up-to-date docker installation, then continue to the next step.
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
Step 2: check out the source
|
||||
----------------------------
|
||||
|
||||
# install the backported kernel
|
||||
sudo apt-get update && sudo apt-get install linux-image-generic-lts-raring
|
||||
::
|
||||
|
||||
# reboot
|
||||
sudo reboot
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt-get install python-software-properties
|
||||
sudo add-apt-repository ppa:gophers/go
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install lxc xz-utils curl golang-stable git aufs-tools
|
||||
|
||||
export GOPATH=~/go/
|
||||
export PATH=$GOPATH/bin:$PATH
|
||||
|
||||
mkdir -p $GOPATH/src/github.com/dotcloud
|
||||
cd $GOPATH/src/github.com/dotcloud
|
||||
git clone git://github.com/dotcloud/docker.git
|
||||
git clone http://git@github.com/dotcloud/docker
|
||||
cd docker
|
||||
|
||||
go get -v github.com/dotcloud/docker/...
|
||||
go install -v github.com/dotcloud/docker/...
|
||||
|
||||
Step 3: build
|
||||
-------------
|
||||
|
||||
When you are ready to build docker, run this command:
|
||||
|
||||
::
|
||||
|
||||
docker build -t docker .
|
||||
|
||||
This will build the revision currently checked out in the repository. Feel free to check out the version
|
||||
of your choice.
|
||||
|
||||
If the build is successful, congratulations! You have produced a clean build of docker, neatly encapsulated
|
||||
in a standard build environment.
|
||||
|
||||
You can run an interactive session in the newly built container:
|
||||
|
||||
::
|
||||
|
||||
docker run -i -t docker bash
|
||||
|
||||
|
||||
Then run the docker daemon,
|
||||
To extract the binaries from the container:
|
||||
|
||||
.. code-block:: bash
|
||||
::
|
||||
|
||||
sudo $GOPATH/bin/docker -d
|
||||
docker run docker sh -c 'cat $(which docker)' > docker-build && chmod +x docker-build
|
||||
|
||||
|
||||
Run the ``go install`` command (above) to recompile docker.
|
||||
|
||||
@@ -39,7 +39,7 @@ This time, we're requesting shared access to $COUCH1's volumes.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
COUCH2=$(docker run -d -volumes-from $COUCH1) shykes/couchdb:2013-05-03)
|
||||
COUCH2=$(docker run -d -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
|
||||
|
||||
Browse data on the second database
|
||||
----------------------------------
|
||||
@@ -48,6 +48,6 @@ Browse data on the second database
|
||||
|
||||
HOST=localhost
|
||||
URL="http://$HOST:$(docker port $COUCH2 5984)/_utils/"
|
||||
echo "Navigate to $URL in your browser. You should see the same data as in the first database!"
|
||||
echo "Navigate to $URL in your browser. You should see the same data as in the first database"'!'
|
||||
|
||||
Congratulations, you are running 2 Couchdb containers, completely isolated from each other *except* for their data.
|
||||
|
||||
@@ -1,127 +1,36 @@
|
||||
:title: Introduction
|
||||
:description: An introduction to docker and standard containers?
|
||||
:title: Welcome to the Docker Documentation
|
||||
:description: An overview of the Docker Documentation
|
||||
:keywords: containers, lxc, concepts, explanation
|
||||
|
||||
.. _introduction:
|
||||
Welcome
|
||||
=======
|
||||
|
||||
Introduction
|
||||
============
|
||||
.. image:: concepts/images/dockerlogo-h.png
|
||||
|
||||
Docker -- The Linux container runtime
|
||||
-------------------------------------
|
||||
``docker``, the Linux Container Runtime, runs Unix processes with
|
||||
strong guarantees of isolation across servers. Your software runs
|
||||
repeatably everywhere because its :ref:`container_def` includes any
|
||||
dependencies.
|
||||
|
||||
Docker complements LXC with a high-level API which operates at the process level. It runs unix processes with strong guarantees of isolation and repeatability across servers.
|
||||
``docker`` runs three ways:
|
||||
|
||||
Docker is a great building block for automating distributed systems: large-scale web deployments, database clusters, continuous deployment systems, private PaaS, service-oriented architectures, etc.
|
||||
* as a daemon to manage LXC containers on your :ref:`Linux host
|
||||
<kernel>` (``sudo docker -d``)
|
||||
* as a :ref:`CLI <cli>` which talks to the daemon's `REST API
|
||||
<api/docker_remote_api>`_ (``docker run ...``)
|
||||
* as a client of :ref:`Repositories <working_with_the_repository>`
|
||||
that let you share what you've built (``docker pull, docker
|
||||
commit``).
|
||||
|
||||
Each use of ``docker`` is documented here. The features of Docker are
|
||||
currently in active development, so this documention will change
|
||||
frequently.
|
||||
|
||||
- **Heterogeneous payloads** Any combination of binaries, libraries, configuration files, scripts, virtualenvs, jars, gems, tarballs, you name it. No more juggling between domain-specific tools. Docker can deploy and run them all.
|
||||
- **Any server** Docker can run on any x64 machine with a modern linux kernel - whether it's a laptop, a bare metal server or a VM. This makes it perfect for multi-cloud deployments.
|
||||
- **Isolation** docker isolates processes from each other and from the underlying host, using lightweight containers.
|
||||
- **Repeatability** Because containers are isolated in their own filesystem, they behave the same regardless of where, when, and alongside what they run.
|
||||
|
||||
.. image:: concepts/images/lego_docker.jpg
|
||||
|
||||
|
||||
What is a Standard Container?
|
||||
-----------------------------
|
||||
|
||||
Docker defines a unit of software delivery called a Standard Container. The goal of a Standard Container is to encapsulate a software component and all its dependencies in
|
||||
a format that is self-describing and portable, so that any compliant runtime can run it without extra dependency, regardless of the underlying machine and the contents of the container.
|
||||
|
||||
The spec for Standard Containers is currently work in progress, but it is very straightforward. It mostly defines 1) an image format, 2) a set of standard operations, and 3) an execution environment.
|
||||
|
||||
A great analogy for this is the shipping container. Just like Standard Containers are a fundamental unit of software delivery, shipping containers (http://bricks.argz.com/ins/7823-1/12) are a fundamental unit of physical delivery.
|
||||
|
||||
Standard operations
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Just like shipping containers, Standard Containers define a set of STANDARD OPERATIONS. Shipping containers can be lifted, stacked, locked, loaded, unloaded and labelled. Similarly, standard containers can be started, stopped, copied, snapshotted, downloaded, uploaded and tagged.
|
||||
|
||||
|
||||
Content-agnostic
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Just like shipping containers, Standard Containers are CONTENT-AGNOSTIC: all standard operations have the same effect regardless of the contents. A shipping container will be stacked in exactly the same way whether it contains Vietnamese powder coffee or spare Maserati parts. Similarly, Standard Containers are started or uploaded in the same way whether they contain a postgres database, a php application with its dependencies and application server, or Java build artifacts.
|
||||
|
||||
|
||||
Infrastructure-agnostic
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Both types of containers are INFRASTRUCTURE-AGNOSTIC: they can be transported to thousands of facilities around the world, and manipulated by a wide variety of equipment. A shipping container can be packed in a factory in Ukraine, transported by truck to the nearest routing center, stacked onto a train, loaded into a German boat by an Australian-built crane, stored in a warehouse at a US facility, etc. Similarly, a standard container can be bundled on my laptop, uploaded to S3, downloaded, run and snapshotted by a build server at Equinix in Virginia, uploaded to 10 staging servers in a home-made Openstack cluster, then sent to 30 production instances across 3 EC2 regions.
|
||||
|
||||
|
||||
Designed for automation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Because they offer the same standard operations regardless of content and infrastructure, Standard Containers, just like their physical counterpart, are extremely well-suited for automation. In fact, you could say automation is their secret weapon.
|
||||
|
||||
Many things that once required time-consuming and error-prone human effort can now be programmed. Before shipping containers, a bag of powder coffee was hauled, dragged, dropped, rolled and stacked by 10 different people in 10 different locations by the time it reached its destination. 1 out of 50 disappeared. 1 out of 20 was damaged. The process was slow, inefficient and cost a fortune - and was entirely different depending on the facility and the type of goods.
|
||||
|
||||
Similarly, before Standard Containers, by the time a software component ran in production, it had been individually built, configured, bundled, documented, patched, vendored, templated, tweaked and instrumented by 10 different people on 10 different computers. Builds failed, libraries conflicted, mirrors crashed, post-it notes were lost, logs were misplaced, cluster updates were half-broken. The process was slow, inefficient and cost a fortune - and was entirely different depending on the language and infrastructure provider.
|
||||
|
||||
|
||||
Industrial-grade delivery
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There are 17 million shipping containers in existence, packed with every physical good imaginable. Every single one of them can be loaded on the same boats, by the same cranes, in the same facilities, and sent anywhere in the World with incredible efficiency. It is embarrassing to think that a 30 ton shipment of coffee can safely travel half-way across the World in *less time* than it takes a software team to deliver its code from one datacenter to another sitting 10 miles away.
|
||||
|
||||
With Standard Containers we can put an end to that embarrassment, by making INDUSTRIAL-GRADE DELIVERY of software a reality.
|
||||
|
||||
|
||||
Standard Container Specification
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
(TODO)
|
||||
|
||||
Image format
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Standard operations
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Copy
|
||||
- Run
|
||||
- Stop
|
||||
- Wait
|
||||
- Commit
|
||||
- Attach standard streams
|
||||
- List filesystem changes
|
||||
- ...
|
||||
|
||||
Execution environment
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Root filesystem
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Environment variables
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Process arguments
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Networking
|
||||
^^^^^^^^^^
|
||||
|
||||
Process namespacing
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Resource limits
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Process monitoring
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Logging
|
||||
^^^^^^^
|
||||
|
||||
Signals
|
||||
^^^^^^^
|
||||
|
||||
Pseudo-terminal allocation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Security
|
||||
^^^^^^^^
|
||||
For an overview of Docker, please see the `Introduction
|
||||
<http://www.docker.io>`_. When you're ready to start working with
|
||||
Docker, we have a `quick start <http://www.docker.io/gettingstarted>`_
|
||||
and a more in-depth guide to :ref:`ubuntu_linux` and other
|
||||
:ref:`installation_list` paths including prebuilt binaries,
|
||||
Vagrant-created VMs, Rackspace and Amazon instances.
|
||||
|
||||
Enough reading! :ref:`Try it out! <running_examples>`
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
:title: Documentation
|
||||
:description: -- todo: change me
|
||||
:keywords: todo, docker, documentation, installation, OS support
|
||||
|
||||
:title: Docker Installation
|
||||
:description: many ways to install Docker
|
||||
:keywords: docker, installation
|
||||
|
||||
.. _installation_list:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
There are a number of ways to install Docker, depending on where you
|
||||
want to run the daemon. The :ref:`ubuntu_linux` installation is the
|
||||
officially-tested version, and the community adds more techniques for
|
||||
installing Docker all the time.
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
|
||||
40
docs/sources/terms/container.rst
Normal file
@@ -0,0 +1,40 @@
|
||||
:title: Container
|
||||
:description: Definitions of a container
|
||||
:keywords: containers, lxc, concepts, explanation, image, container
|
||||
|
||||
.. _container_def:
|
||||
|
||||
Container
|
||||
=========
|
||||
|
||||
.. image:: images/docker-filesystems-busyboxrw.png
|
||||
|
||||
Once you start a process in Docker from an :ref:`image_def`, Docker
|
||||
fetches the image and its :ref:`parent_image_def`, and repeats the
|
||||
process until it reaches the :ref:`base_image_def`. Then the
|
||||
:ref:`ufs_def` adds a read-write layer on top. That read-write layer,
|
||||
plus the information about its :ref:`parent_image_def` and some
|
||||
additional information like its unique id, networking configuration,
|
||||
and resource limits is called a **container**.
|
||||
|
||||
.. _container_state_def:
|
||||
|
||||
Container State
|
||||
...............
|
||||
|
||||
Containers can change, and so they have state. A container may be
|
||||
**running** or **exited**.
|
||||
|
||||
When a container is running, the idea of a "container" also includes a
|
||||
tree of processes running on the CPU, isolated from the other
|
||||
processes running on the host.
|
||||
|
||||
When the container is exited, the state of the file system and
|
||||
its exit value is preserved. You can start, stop, and restart a
|
||||
container. The processes restart from scratch (their memory state is
|
||||
**not** preserved in a container), but the file system is just as it
|
||||
was when the container was stopped.
|
||||
|
||||
You can promote a container to an :ref:`image_def` with ``docker
|
||||
commit``. Once a container is an image, you can use it as a parent for
|
||||
new containers.
|
||||
38
docs/sources/terms/filesystem.rst
Normal file
@@ -0,0 +1,38 @@
|
||||
:title: File Systems
|
||||
:description: How Linux organizes its persistent storage
|
||||
:keywords: containers, files, linux
|
||||
|
||||
.. _filesystem_def:
|
||||
|
||||
File System
|
||||
===========
|
||||
|
||||
.. image:: images/docker-filesystems-generic.png
|
||||
|
||||
In order for a Linux system to run, it typically needs two `file
|
||||
systems <http://en.wikipedia.org/wiki/Filesystem>`_:
|
||||
|
||||
1. boot file system (bootfs)
|
||||
2. root file system (rootfs)
|
||||
|
||||
The **boot file system** contains the bootloader and the kernel. The
|
||||
user never makes any changes to the boot file system. In fact, soon
|
||||
after the boot process is complete, the entire kernel is in memory,
|
||||
and the boot file system is unmounted to free up the RAM associated
|
||||
with the initrd disk image.
|
||||
|
||||
|
||||
The **root file system** includes the typical directory structure we
|
||||
associate with Unix-like operating systems: ``/dev, /proc, /bin, /etc,
|
||||
/lib, /usr,`` and ``/tmp`` plus all the configuration files, binaries
|
||||
and libraries required to run user applications (like bash, ls, and so
|
||||
forth).
|
||||
|
||||
While there can be important kernel differences between different
|
||||
Linux distributions, the contents and organization of the root file
|
||||
system are usually what make your software packages dependent on one
|
||||
distribution versus another. Docker can help solve this problem by
|
||||
running multiple distributions at the same time.
|
||||
|
||||
.. image:: images/docker-filesystems-multiroot.png
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
:title: Image & Container
|
||||
:description: Definitions of an image and container
|
||||
:keywords: containers, lxc, concepts, explanation, image, container
|
||||
|
||||
File Systems
|
||||
============
|
||||
|
||||
.. image:: images/docker-filesystems-generic.png
|
||||
|
||||
In order for a Linux system to run, it typically needs two `file
|
||||
systems <http://en.wikipedia.org/wiki/Filesystem>`_:
|
||||
|
||||
1. boot file system (bootfs)
|
||||
2. root file system (rootfs)
|
||||
|
||||
The **boot file system** contains the bootloader and the kernel. The
|
||||
user never makes any changes to the boot file system. In fact, soon
|
||||
after the boot process is complete, the entire kernel is in memory,
|
||||
and the boot file system is unmounted to free up the RAM associated
|
||||
with the initrd disk image.
|
||||
|
||||
The **root file system** includes the typical directory structure we
|
||||
associate with Unix-like operating systems: ``/dev, /proc, /bin, /etc,
|
||||
/lib, /usr,`` and ``/tmp`` plus all the configuration files, binaries
|
||||
and libraries required to run user applications (like bash, ls, and so
|
||||
forth).
|
||||
|
||||
While there can be important kernal differences between different
|
||||
Linux distributions, the contents and organization of the root file
|
||||
system are usually what make your software packages dependent on one
|
||||
distribution versus another. Docker can help solve this problem by
|
||||
running multiple distributions at the same time.
|
||||
|
||||
.. image:: images/docker-filesystems-multiroot.png
|
||||
|
||||
Layers and Union Mounts
|
||||
=======================
|
||||
|
||||
In a traditional Linux boot, the kernel first mounts the root file
|
||||
system as read-only, checks its integrity, and then switches the whole
|
||||
rootfs volume to read-write mode. Docker does something similar,
|
||||
*except* that instead of changing the file system to read-write mode,
|
||||
it takes advantage of a `union mount
|
||||
<http://en.wikipedia.org/wiki/Union_mount>`_ to add a read-write file
|
||||
system *over* the read-only file system. In fact there may be multiple
|
||||
read-only file systems stacked on top of each other.
|
||||
|
||||
.. image:: images/docker-filesystems-multilayer.png
|
||||
|
||||
At first, the top layer has nothing in it, but any time a process
|
||||
creates a file, this happens in the top layer. And if something needs
|
||||
to update an existing file in a lower layer, then the file gets copied
|
||||
to the upper layer and changes go into the copy. The version of the
|
||||
file on the lower layer cannot be seen by the applications anymore,
|
||||
but it is there, unchanged.
|
||||
|
||||
We call the union of the read-write layer and all the read-only layers
|
||||
a **union file system**.
|
||||
|
||||
Image
|
||||
=====
|
||||
|
||||
In Docker terminology, a read-only layer is called an **image**. An
|
||||
image never changes. Because Docker uses a union file system, the
|
||||
applications think the whole file system is mounted read-write,
|
||||
because any file can be changed. But all the changes go to the
|
||||
top-most layer, and underneath, the image is unchanged. Since they
|
||||
don't change, images do not have state.
|
||||
|
||||
Each image may depend on one more image which forms the layer beneath
|
||||
it. We sometimes say that the lower image is the **parent** of the
|
||||
upper image.
|
||||
|
||||
Base Image
|
||||
==========
|
||||
|
||||
An image that has no parent is a **base image**.
|
||||
|
||||
Container
|
||||
=========
|
||||
|
||||
Once you start a process in Docker from an image, Docker fetches the
|
||||
image and its parent, and repeats the process until it reaches the
|
||||
base image. Then the union file system adds a read-write layer on
|
||||
top. That read-write layer, plus the information about its parent and
|
||||
some additional information like its unique id, is called a
|
||||
**container**.
|
||||
|
||||
Containers can change, and so they have state. A container may be
|
||||
running or exited. In either case, the state of the file system and
|
||||
its exit value is preserved. You can start, stop, and restart a
|
||||
container. The processes restart from scratch (their memory state is
|
||||
**not** preserved in a container), but the file system is just as it
|
||||
was when the container was stopped.
|
||||
|
||||
You can promote a container to an image with ``docker commit``. Once a
|
||||
container is an image, you can use it as a parent for new containers.
|
||||
38
docs/sources/terms/image.rst
Normal file
@@ -0,0 +1,38 @@
|
||||
:title: Images
|
||||
:description: Definition of an image
|
||||
:keywords: containers, lxc, concepts, explanation, image, container
|
||||
|
||||
.. _image_def:
|
||||
|
||||
Image
|
||||
=====
|
||||
|
||||
.. image:: images/docker-filesystems-debian.png
|
||||
|
||||
In Docker terminology, a read-only :ref:`layer_def` is called an
|
||||
**image**. An image never changes.
|
||||
|
||||
Since Docker uses a :ref:`ufs_def`, the processes think the whole file
|
||||
system is mounted read-write. But all the changes go to the top-most
|
||||
writeable layer, and underneath, the original file in the read-only
|
||||
image is unchanged. Since images don't change, images do not have state.
|
||||
|
||||
.. image:: images/docker-filesystems-debianrw.png
|
||||
|
||||
.. _parent_image_def:
|
||||
|
||||
Parent Image
|
||||
............
|
||||
|
||||
.. image:: images/docker-filesystems-multilayer.png
|
||||
|
||||
Each image may depend on one more image which forms the layer beneath
|
||||
it. We sometimes say that the lower image is the **parent** of the
|
||||
upper image.
|
||||
|
||||
.. _base_image_def:
|
||||
|
||||
Base Image
|
||||
..........
|
||||
|
||||
An image that has no parent is a **base image**.
|
||||
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 69 KiB |
@@ -9,15 +9,15 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
height="600"
|
||||
width="800"
|
||||
sodipodi:docname="docker-filesystems.svg"
|
||||
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multilayer.png"
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multiroot.png"
|
||||
sodipodi:docname="docker-filesystems.svg"
|
||||
width="800"
|
||||
height="600"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
@@ -26,10 +26,10 @@
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.82666667"
|
||||
inkscape:cx="361.59949"
|
||||
inkscape:cy="396.77419"
|
||||
inkscape:cx="382.45968"
|
||||
inkscape:cy="348.3871"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer8"
|
||||
inkscape:current-layer="layer4"
|
||||
showgrid="false"
|
||||
width="800px"
|
||||
inkscape:window-width="1327"
|
||||
@@ -84,12 +84,34 @@
|
||||
position="-404.80241,590.32258"
|
||||
id="guide4281" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="518.95161,347.17742"
|
||||
id="guide9339" />
|
||||
id="guide5235"
|
||||
position="400.40322,131.85484"
|
||||
orientation="1,0" />
|
||||
<sodipodi:guide
|
||||
id="guide5237"
|
||||
position="143.95161,295.16129"
|
||||
orientation="1,0" />
|
||||
<sodipodi:guide
|
||||
id="guide5239"
|
||||
position="281.85484,384.67742"
|
||||
orientation="1,0" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs4">
|
||||
<inkscape:perspective
|
||||
id="perspective11489"
|
||||
inkscape:persp3d-origin="403.62904 : 221.23862 : 1"
|
||||
inkscape:vp_z="1196.7644 : 521.45993 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="-406.34117 : 522.93291 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="-407.55086 : 591.21042 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="1200.3935 : 584.89873 : 1"
|
||||
inkscape:persp3d-origin="400 : 200 : 1"
|
||||
id="perspective5786" />
|
||||
<inkscape:perspective
|
||||
id="perspective4014"
|
||||
inkscape:persp3d-origin="406.04839 : 290.19023 : 1"
|
||||
@@ -132,6 +154,7 @@
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
sodipodi:insensitive="true"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer8"
|
||||
inkscape:label="Background"
|
||||
@@ -197,38 +220,6 @@
|
||||
inkscape:box3dsidetype="3"
|
||||
d="m 132.72634,765.18707 253.32517,142.55608 0,96.58025 -253.32517,-173.38536 z" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multiroot.png"
|
||||
id="text8376"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
|
||||
transform="matrix(0.58237543,0,0,0.58237543,219.84375,178.6359)">
|
||||
<path
|
||||
id="path8383"
|
||||
d="m 407.6752,504.83554 c 0,0 0,16.04632 0,16.04632 0,0 4.1431,-2.64344 4.1431,-2.64344 2.73806,-1.74697 4.66912,-2.30333 5.80495,-1.67953 1.16895,0.55219 1.75215,1.89552 1.75218,4.03129 -3e-5,2.08935 -0.58323,4.1876 -1.75218,6.29934 -1.13583,2.04747 -3.06689,3.96726 -5.80495,5.76429 0,0 -17.71025,11.62348 -17.71025,11.62348 -2.88271,1.89195 -4.96006,2.58018 -6.21946,2.05325 -1.22381,-0.60271 -1.83708,-2.01825 -1.83708,-4.24517 0,-2.17847 0.63304,-4.35207 1.8962,-6.51576 1.25921,-2.20514 3.31673,-4.21714 6.16034,-6.03146 0,0 1.8589,-1.18604 1.8589,-1.18604 0,0 0,-57.52956 0,-57.52956 0,0 -1.8589,1.05311 -1.8589,1.05311 -2.88271,1.63317 -4.96006,2.13486 -6.21946,1.49476 -1.22381,-0.71252 -1.83708,-2.1831 -1.83708,-4.41009 0,-2.22685 0.61327,-4.35683 1.83708,-6.38541 1.2594,-2.09209 3.33675,-3.93007 6.21946,-5.51029 0,0 17.71025,-9.63763 17.71025,-9.63763 2.73806,-1.50103 4.66912,-1.90729 5.80495,-1.22806 1.16895,0.65733 1.75215,2.05308 1.75218,4.18878 -3e-5,2.13588 -0.58323,4.20494 -1.75218,6.21164 -1.13583,1.94555 -3.06689,3.69194 -5.80495,5.24303 0,0 -4.1431,2.34713 -4.1431,2.34713 0,0 0,21.48932 0,21.48932 0,0 19.97055,-33.42313 19.97055,-33.42313 -1.14267,-0.41166 -1.9302,-0.95733 -2.36038,-1.63677 -0.43077,-0.67999 -0.64629,-1.68902 -0.64626,-3.02649 -3e-5,-2.16742 0.55652,-4.22734 1.66728,-6.17561 1.14317,-1.96205 3.0292,-3.66214 5.64725,-5.09729 0,0 10.89672,-5.90556 10.89672,-5.90556 2.52713,-1.3854 4.30988,-1.73587 5.35863,-1.05974 1.07944,0.65586 1.61801,2.00928 1.61806,4.0617 -5e-5,2.00797 -0.53862,3.96169 -1.61806,5.86527 -1.04875,1.89005 -2.71237,3.4818 -4.99901,4.77715 0,0 -19.38021,33.27709 -19.38021,33.27709 3.69112,0.51378 7.11765,2.57896 10.28615,6.17689 3.1772,3.54703 5.96596,8.60211 8.37448,15.15605 0,0 2.81906,-1.79866 2.81906,-1.79866 2.47696,-1.58038 4.23151,-2.05261 5.27367,-1.42578 1.07264,0.55918 1.60782,1.86117 1.60788,3.90719 -6e-5,2.00157 -0.5185,3.98542 -1.55753,5.95553 -1.042,1.93101 -2.81324,3.71837 -5.32402,5.36622 0,0 -9.61907,6.31312 -9.61907,6.31312 -2.24123,-5.50482 -4.70762,-10.58658 -7.40337,-15.2454 -2.2133,-3.8066 -4.33127,-6.27087 -6.35225,-7.38073 -1.99524,-1.18421 -4.40301,-1.64069 -7.23093,-1.36339 0,0 -7.02864,11.83882 -7.02864,11.83882"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path8385"
|
||||
d="m 504.33889,450.20724 c 0,0 -38.51263,24.07437 -38.51263,24.07437 1.02952,2.84505 2.84029,4.51025 5.42072,4.99903 2.59378,0.4652 6.06003,-0.69838 10.37364,-3.4633 3.4995,-2.24309 8.09778,-6.22556 13.75209,-11.8953 2.30731,-2.30433 3.8959,-3.73056 4.77538,-4.2889 1.19829,-0.76067 2.20348,-0.79709 3.01722,-0.11236 0.81174,0.68323 1.21692,1.93451 1.21697,3.75503 -5e-5,1.65511 -0.43419,3.34335 -1.30407,5.06802 -1.16332,2.29253 -4.01513,5.63253 -8.59699,10.05719 -4.6422,4.44071 -9.16261,8.11778 -13.55534,11.01372 -7.68449,5.06604 -13.95767,6.17145 -18.74216,3.20582 -4.81441,-3.02556 -7.24522,-9.05127 -7.24522,-18.04744 0,-9.57222 2.62856,-18.90863 7.83044,-27.91368 5.16157,-8.94171 11.00878,-15.25277 17.50729,-18.97607 3.84969,-2.20557 7.3401,-3.27314 10.4811,-3.22069 3.14318,0.0349 5.46016,0.68067 6.96696,1.93361 2.1162,1.8432 3.85544,4.61873 5.22325,8.32396 0.92815,2.58851 1.39131,5.94912 1.39135,10.087 0,0 0,5.39999 0,5.39999 m -9.99158,-6.66099 c -1.40179,-2.8503 -3.2444,-4.50369 -5.53473,-4.95378 -2.30521,-0.49538 -5.06978,0.20545 -8.3042,2.11763 -3.23259,1.91123 -6.05351,4.52841 -8.45282,7.85517 -2.41524,3.30543 -4.39745,7.34338 -5.93945,12.11231 0,0 28.2312,-17.13133 28.2312,-17.13133"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path8387"
|
||||
d="m 532.28648,399.49334 c 0,0 0,7.62581 0,7.62581 3.42049,-5.6818 6.08733,-9.67191 8.01819,-12.00361 1.94545,-2.33281 3.75091,-3.97369 5.41859,-4.92923 2.54908,-1.4604 5.00284,-1.43726 7.3632,0.0528 1.59719,0.99371 2.39286,2.48554 2.3929,4.47907 -4e-5,1.68701 -0.38521,3.35331 -1.15685,5.00185 -0.74861,1.59928 -1.66169,2.72207 -2.74065,3.36726 -0.95657,0.57205 -1.9665,0.4409 -3.03028,-0.39672 -1.06733,-0.84026 -2.02323,-1.01257 -2.86671,-0.51395 -1.10244,0.65184 -2.763,2.68889 -4.99017,6.12693 -2.21624,3.44588 -5.01411,8.32326 -8.40822,14.66299 0,0 0,18.4092 0,18.4092 0,0 11.47319,-7.32028 11.47319,-7.32028 1.89957,-1.21199 3.2406,-1.50439 4.02992,-0.88361 0.81268,0.56434 1.2183,1.73659 1.21834,3.51786 -4e-5,1.74257 -0.40566,3.43988 -1.21834,5.0949 -0.78932,1.60367 -2.13035,3.0276 -4.02992,4.27431 0,0 -24.80701,16.28117 -24.80701,16.28117 -2.05798,1.35069 -3.53958,1.75299 -4.43724,1.19972 -0.87187,-0.6139 -1.30863,-1.86107 -1.30863,-3.74027 0,-1.83831 0.43676,-3.60993 1.30863,-5.31162 0.89766,-1.75595 2.37926,-3.2917 4.43724,-4.60477 0,0 5.03647,-3.21343 5.03647,-3.21343 0,0 0,-30.03766 0,-30.03766 0,0 -3.04598,1.80817 -3.04598,1.80817 -2.04596,1.2146 -3.51888,1.52055 -4.41127,0.91117 -0.86675,-0.66806 -1.30094,-1.93958 -1.30094,-3.81328 0,-1.8329 0.43419,-3.57126 1.30094,-5.212 0.89239,-1.6931 2.36531,-3.12925 4.41127,-4.30644 0,0 11.34333,-6.52633 11.34333,-6.52633"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path8389"
|
||||
d="m 572.24194,376.50516 c 0,0 0,3.86493 0,3.86493 1.31657,-2.55421 2.75611,-4.72562 4.31689,-6.51554 1.57611,-1.79414 3.27078,-3.20898 5.08203,-4.24677 4.13268,-2.36771 7.36362,-2.16528 9.72036,0.56776 1.85468,2.16735 2.77779,5.877 2.77783,11.1389 0,0 0,20.59729 0,20.59729 1.42308,-0.90797 2.46973,-1.05531 3.1438,-0.44622 0.67249,0.572 1.00821,1.68074 1.00824,3.32725 -3e-5,1.61072 -0.34658,3.16111 -1.04082,4.65362 -0.67414,1.44584 -1.81921,2.6999 -3.44058,3.76403 0,0 -6.15847,4.04189 -6.15847,4.04189 -1.66347,1.09175 -2.8604,1.36497 -3.58533,0.81425 -0.70395,-0.6035 -1.0565,-1.74997 -1.05647,-3.4383 -3e-5,-1.65157 0.35252,-3.21764 1.05647,-4.6957 0.70228,-1.51122 1.78658,-2.73371 3.24886,-3.66669 0,0 0,-21.15717 0,-21.15717 -2e-5,-2.44186 -0.40426,-3.98655 -1.21429,-4.63538 -1.06085,-0.83225 -2.65895,-0.61904 -4.8027,0.64833 -1.62916,0.96324 -3.07036,2.33311 -4.32094,4.11119 -1.23237,1.73432 -2.80892,4.8321 -4.73488,9.30874 0,0 0,21.34125 0,21.34125 1.85569,-1.184 3.04789,-1.66582 3.58407,-1.45135 1.13919,0.38348 1.70724,1.64851 1.70726,3.79612 -2e-5,1.66625 -0.37088,3.27815 -1.11389,4.83837 -0.72152,1.51157 -1.94723,2.83594 -3.68307,3.97519 0,0 -8.33029,5.46728 -8.33029,5.46728 -1.79222,1.17626 -3.08205,1.49092 -3.86336,0.938 -0.75872,-0.60834 -1.13874,-1.78952 -1.13874,-3.54238 0,-2.1339 0.58824,-4.16867 1.76149,-6.09901 0.58501,-0.94353 1.83674,-2.02693 3.74738,-3.24598 0,0 0,-28.22034 0,-28.22034 -1.57121,0.93277 -2.73648,1.07437 -3.4913,0.42017 -0.75664,-0.65565 -1.13561,-1.84028 -1.13561,-3.55271 0,-1.71238 0.37897,-3.32097 1.13561,-4.82316 0.77916,-1.55048 2.06546,-2.84066 3.85278,-3.86905 0,0 6.96767,-4.00881 6.96767,-4.00881"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path8391"
|
||||
d="m 634.34141,368.94225 c 0,0 -25.20953,15.75856 -25.20953,15.75856 0.6672,2.39172 1.84157,3.9121 3.51707,4.56242 1.68646,0.63355 3.94388,0.0402 6.75893,-1.7642 2.28854,-1.46689 5.30217,-4.23703 9.01804,-8.27952 1.51956,-1.64558 2.56684,-2.64955 3.14705,-3.0179 0.79096,-0.50209 1.45484,-0.43448 1.99254,0.20091 0.53661,0.63426 0.80455,1.6912 0.8046,3.17172 -5e-5,1.34601 -0.28714,2.67618 -0.86216,3.99258 -0.7686,1.7482 -2.65074,4.17765 -5.66863,7.30949 -3.05013,3.13106 -6.01295,5.64891 -8.88527,7.54251 -5.00854,3.3019 -9.08208,3.5476 -12.17982,0.67175 -3.10916,-2.91974 -4.67598,-8.00122 -4.67598,-15.22147 0,-7.68257 1.69435,-14.92957 5.05447,-21.68353 3.34323,-6.72524 7.14168,-11.28617 11.37713,-13.71287 2.51598,-1.44145 4.80162,-1.99625 6.86211,-1.67548 2.06538,0.30724 3.59011,1.03724 4.58269,2.18866 1.39536,1.68649 2.54336,4.09846 3.44695,7.23454 0.6135,2.18975 0.91977,4.96536 0.91981,8.3304 0,0 0,4.39143 0,4.39143 m -6.5902,-6.34854 c -0.92175,-2.4412 -2.13235,-3.95102 -3.6354,-4.52578 -1.51099,-0.61206 -3.3206,-0.29783 -5.4344,0.95183 -2.10895,1.2469 -3.94636,3.09915 -5.50696,5.55983 -1.56898,2.43888 -2.85515,5.5053 -3.85476,9.19879 0,0 18.43152,-11.18467 18.43152,-11.18467"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path8393"
|
||||
d="m 656.82836,308.98356 c 0,0 0,52.93031 0,52.93031 0,0 6.4328,-4.10434 6.4328,-4.10434 1.27173,-0.81141 2.17036,-0.92363 2.69958,-0.34039 0.54515,0.53946 0.81731,1.53839 0.81734,2.99761 -3e-5,1.42751 -0.27219,2.77874 -0.81734,4.05558 -0.52922,1.23647 -1.42785,2.27149 -2.69958,3.10614 0,0 -18.63545,12.2307 -18.63545,12.2307 -1.36813,0.89792 -2.35216,1.07925 -2.94796,0.53978 -0.57842,-0.58603 -0.86806,-1.64466 -0.86806,-3.17491 0,-1.49696 0.28964,-2.89722 0.86806,-4.19875 0.5958,-1.34387 1.57983,-2.45281 2.94796,-3.32572 0,0 6.72309,-4.28956 6.72309,-4.28956 0,0 0,-43.42716 0,-43.42716 0,0 -4.49128,2.51035 -4.49128,2.51035 -1.33877,0.74834 -2.3056,0.82613 -2.89655,0.22966 -0.59221,-0.63072 -0.88879,-1.70864 -0.88879,-3.23275 0,-1.49086 0.28731,-2.85673 0.86106,-4.0957 0.59101,-1.27931 1.56713,-2.28621 2.92428,-3.02004 0,0 9.97084,-5.39081 9.97084,-5.39081"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<path
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
@@ -269,45 +260,99 @@
|
||||
d="m 574.61499,283.99905 c -3.31444,-0.15435 -6.08369,-0.11845 -8.31443,0.10735 -2.30321,0.20508 -4.07372,0.60048 -5.31424,1.18721 -2.46838,1.16767 -3.01224,2.51015 -1.61447,4.03327 0.60292,0.67291 1.64413,1.22527 3.12534,1.65615 1.70913,0.49721 3.82744,0.77332 6.35381,0.8271 1.87073,0.0245 4.53088,-0.36099 7.97382,-1.15539 6.3436,-1.44672 11.39483,-2.26881 15.17355,-2.47016 4.98619,-0.25925 10.88971,0.10784 17.75075,1.10837 6.92387,1.00975 13.65666,2.40914 20.21272,4.20821 9.03796,2.4802 15.73657,5.10339 20.02734,7.86932 6.35081,4.06357 7.3,7.36394 2.70673,9.84732 -1.85312,1.00191 -4.27563,1.73258 -7.2635,2.1895 -2.88132,0.47104 -6.28692,0.6849 -10.20845,0.64145 0.80272,0.49803 1.32719,0.93276 1.57202,1.30366 0.24495,0.37149 0.1769,0.66031 -0.20564,0.86576 -1.02151,0.54865 -3.18409,0.59244 -6.47634,0.13197 -3.34347,-0.49542 -8.15753,-1.67755 -14.39541,-3.53092 0,0 -8.59884,-2.55485 -8.59884,-2.55485 -6.05987,-1.80048 -10.01632,-3.2171 -11.91481,-4.26116 -1.94556,-1.07213 -2.42442,-1.85248 -1.44701,-2.34539 0.78497,-0.39581 2.2796,-0.48123 4.48868,-0.25629 2.13397,0.20198 5.36767,0.81735 9.72187,1.85154 4.26215,0.44403 7.96002,0.55921 11.08074,0.3439 3.04016,-0.23936 5.45895,-0.82613 7.25042,-1.75782 2.92404,-1.52066 3.35798,-3.20948 1.3294,-5.05875 -1.04765,-0.89657 -2.55062,-1.61718 -4.50718,-2.1636 -3.2445,-0.90604 -6.44882,-1.37387 -9.62339,-1.4077 -3.16808,-0.0337 -7.17813,0.6088 -12.04806,1.93106 -7.21679,1.99422 -14.62018,2.58337 -22.13286,1.76443 -7.37333,-0.78946 -15.08696,-2.38082 -23.08624,-4.74933 -8.08729,-2.39456 -13.72809,-4.81726 -16.98815,-7.27133 -4.41938,-3.29135 -4.47329,-5.88661 -0.24956,-7.8229 1.46281,-0.6705 3.34863,-1.17273 5.65981,-1.50788 2.26094,-0.36411 4.98687,-0.55216 8.18326,-0.56429 -0.60143,-0.45433 -0.98542,-0.82473 -1.153,-1.11182 -0.14687,-0.2959 -0.0782,-0.50905 0.20561,-0.63976 0.85095,-0.3916 2.68442,-0.40633 5.50914,-0.0436 2.76417,0.34452 6.79329,1.24528 12.1235,2.71337 0,0 5.46229,1.50449 5.46229,1.50449 4.9316,1.35835 8.14703,2.36621 9.61371,3.01537 2.80152,1.26506 3.65218,2.17198 2.53312,2.71381 -0.75407,0.36519 -2.28486,0.44438 -4.58735,0.23757 -2.2968,-0.20623 -4.94238,-0.66681 -7.9287,-1.37921"
|
||||
id="path9377" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 386.05151,551.96125 0,-96.58028 280.72657,-151.77679 0,63.28635 z"
|
||||
id="path4672"
|
||||
inkscape:connector-curvature="0" />
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multiroot.png"
|
||||
transform="matrix(0.79944175,0,0,0.79944175,52.022588,84.530657)"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Sans"
|
||||
id="text12064">
|
||||
id="text7447"
|
||||
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium Italic">
|
||||
<path
|
||||
id="path7454"
|
||||
d="m 147.58834,332.81239 c 0,0 -1.75619,37.90152 -1.75619,37.90152 0,0 -1.88054,-1.21673 -1.88054,-1.21673 0,0 1.76021,-37.74043 1.76021,-37.74043 0,0 1.87652,1.05564 1.87652,1.05564"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7456"
|
||||
d="m 155.5998,356.97158 c 0,0 -0.24054,5.14593 -0.24054,5.14593 -0.40443,-1.61247 -0.78977,-2.82699 -1.15617,-3.64502 -0.35987,-0.7974 -0.78335,-1.34369 -1.27013,-1.63943 -0.73705,-0.44773 -1.33999,-0.091 -1.81,1.06776 -0.46924,1.15688 -0.70259,2.86881 -0.7006,5.13825 0.002,2.13082 0.22404,3.97436 0.6673,5.53232 0.4501,1.58081 1.03211,2.60051 1.7469,3.05745 0.68755,0.43955 1.39964,0.10214 2.13626,-1.01548 0,0 -0.24938,5.3343 -0.24938,5.3343 -0.75516,0.32879 -1.47328,0.27142 -2.15455,-0.1704 -1.21082,-0.78524 -2.19272,-2.47392 -2.94825,-5.0617 -0.74689,-2.57425 -1.12029,-5.52395 -1.12234,-8.85412 -0.002,-3.41998 0.39606,-6.0285 1.19618,-7.83178 0.80817,-1.82041 1.81762,-2.37095 3.0313,-1.64489 0.99666,0.59627 1.95471,2.12313 2.87402,4.58681"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7458"
|
||||
d="m 162.12519,369.14836 c 0,0 3.15558,14.14905 3.15558,14.14905 0,0 -2.36428,-1.52972 -2.36428,-1.52972 0,0 -2.06013,-9.88013 -2.06013,-9.88013 0,0 -2.73436,6.77803 -2.73436,6.77803 0,0 -2.55294,-1.65178 -2.55294,-1.65178 0,0 4.27078,-9.71399 4.27078,-9.71399 0,0 -2.54931,-11.45318 -2.54931,-11.45318 0,0 2.27488,1.36446 2.27488,1.36446 0,0 1.52855,7.34113 1.52855,7.34113 0,0 2.03981,-5.20084 2.03981,-5.20084 0,0 2.60043,1.55972 2.60043,1.55972 0,0 -3.60901,8.23725 -3.60901,8.23725"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7460"
|
||||
d="m 169.92343,379.36559 c 0,0 -3.25195,12.16924 -3.25195,12.16924 0,0 -1.27259,-2.63135 -1.27259,-2.63135 0,0 2.90583,-12.86349 2.90583,-12.86349 0,0 1.61871,3.3256 1.61871,3.3256"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7462"
|
||||
d="m 189.30148,375.04665 c 0,0 -1.03888,23.12027 -1.03888,23.12027 0,0 -2.24228,-1.45077 -2.24228,-1.45077 0,0 0.11673,-2.49125 0.11673,-2.49125 -0.94298,1.47092 -1.92196,1.87493 -2.93613,1.21763 -1.24207,-0.80501 -2.25567,-2.51652 -3.04325,-5.13028 -0.78468,-2.60409 -1.18382,-5.57547 -1.1996,-8.91911 -0.0182,-3.85301 0.40809,-6.73894 1.2807,-8.66498 0.88831,-1.92374 2.04012,-2.46472 3.45951,-1.61503 0.6727,0.40274 1.24847,1.02201 1.72666,1.85828 0.48587,0.84208 0.98515,2.09412 1.498,3.75781 0,0 0.13357,-3.0291 0.13357,-3.0291 0,0 2.24497,1.34653 2.24497,1.34653 m -2.66567,9.53882 c -0.0121,-2.10019 -0.26427,-3.95362 -0.75572,-5.55842 -0.49044,-1.61785 -1.11651,-2.65716 -1.8773,-3.11967 -0.82492,-0.50144 -1.51048,-0.11404 -2.058,1.15924 -0.54646,1.28764 -0.81341,3.10968 -0.80158,5.46904 0.0103,2.06152 0.24981,3.89591 0.71924,5.50498 0.47047,1.61265 1.07146,2.65376 1.80379,3.12165 0.81474,0.52057 1.51683,0.14096 2.10513,-1.14196 0.58925,-1.31904 0.87768,-3.13164 0.86444,-5.43486"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7464"
|
||||
d="m 200.98417,382.05386 c 0,0 -0.60701,13.76386 -0.60701,13.76386 -0.0478,1.17529 -0.11093,2.18594 -0.18949,3.03183 -0.0786,0.8458 -0.16535,1.53989 -0.26032,2.08222 -0.1903,1.03239 -0.51634,1.84794 -0.97764,2.4463 -0.78121,1.00906 -1.81569,1.09476 -3.10016,0.26227 -1.21534,-0.78769 -2.18714,-2.17556 -2.91798,-4.16161 -0.72858,-1.99666 -1.10026,-4.27781 -1.1168,-6.84699 -0.003,-0.39117 10e-4,-0.84599 0.0118,-1.36445 0.0173,-0.51405 0.0409,-1.10033 0.0709,-1.75873 0,0 0.55615,-12.57127 0.55615,-12.57127 0,0 2.29365,1.37572 2.29365,1.37572 0,0 -0.58535,13.12163 -0.58535,13.12163 -0.0239,0.56331 -0.0413,1.06266 -0.0521,1.49808 -0.011,0.4184 -0.0156,0.77281 -0.0136,1.06329 0.0172,2.54701 0.63463,4.21014 1.85674,4.9909 0.66588,0.42543 1.15463,0.31796 1.46518,-0.3237 0.31086,-0.6423 0.51161,-1.98957 0.60201,-4.04108 0,0 0.62456,-13.97146 0.62456,-13.97146 0,0 2.33946,1.40319 2.33946,1.40319"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7466"
|
||||
d="m 206.63389,390.78613 c 0,0 -0.82079,18.73618 -0.82079,18.73618 0,0 -2.40115,-1.55357 -2.40115,-1.55357 0,0 0.82954,-18.64209 0.82954,-18.64209 0,0 -1.55408,-0.94806 -1.55408,-0.94806 0,0 0.22678,-5.16711 0.22678,-5.16711 0,0 1.55445,0.93235 1.55445,0.93235 0,0 0.47336,-10.6332 0.47336,-10.6332 0.12045,-2.83044 0.43153,-4.7841 0.93387,-5.86279 0.50314,-1.08033 1.23473,-1.3513 2.1968,-0.81014 0.58479,0.32902 1.27387,1.15978 2.06817,2.49496 0,0 -0.21954,4.94262 -0.21954,4.94262 -0.4636,-1.13664 -0.88579,-1.81328 -1.26683,-2.03137 -0.43899,-0.25118 -0.76101,-0.0798 -0.96652,0.51359 -0.19081,0.60146 -0.32899,1.83118 -0.41464,3.6896 0,0 -0.40076,9.13858 -0.40076,9.13858 0,0 2.19474,1.3164 2.19474,1.3164 0,0 -0.22825,5.2293 -0.22825,5.2293 0,0 -2.20515,-1.34525 -2.20515,-1.34525"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7468"
|
||||
d="m 217.52646,394.74253 c 0,0 -1.38661,2.48014 -1.38661,2.48014 -0.67725,-1.8109 -1.29703,-2.88559 -1.8599,-3.22743 -0.38208,-0.23202 -0.69765,-0.16825 -0.94697,0.19084 -0.24182,0.34568 -0.3592,0.89013 -0.3523,1.63368 0.007,0.72604 0.11693,1.40131 0.33073,2.02617 0.21414,0.64318 0.65861,1.60559 1.33464,2.88942 0.96807,1.85739 1.62118,3.41663 1.95681,4.67361 0.3587,1.2553 0.54644,2.71574 0.56281,4.38041 0.0236,2.39986 -0.31049,4.09968 -1.00105,5.09661 -0.70429,0.96703 -1.62822,1.07848 -2.76933,0.33845 -1.54613,-1.0027 -2.83506,-3.48418 -3.86988,-7.43484 0,0 1.58533,-1.65255 1.58533,-1.65255 0.67846,2.3152 1.39501,3.71619 2.14973,4.19878 0.42688,0.27296 0.76562,0.22407 1.01586,-0.14723 0.25795,-0.3668 0.38295,-0.97802 0.37484,-1.83329 -0.007,-0.74819 -0.12185,-1.42257 -0.34408,-2.02287 -0.10729,-0.29756 -0.29412,-0.7335 -0.56031,-1.30745 -0.26591,-0.57331 -0.6257,-1.28445 -1.07896,-2.13273 -0.79912,-1.53842 -1.35435,-2.89536 -1.66731,-4.07336 -0.31299,-1.22922 -0.47603,-2.59245 -0.48943,-4.09057 -0.0202,-2.25482 0.31059,-3.91075 0.99349,-4.97061 0.68445,-1.0622 1.56745,-1.27103 2.65118,-0.62272 1.20102,0.71853 2.32478,2.58513 3.37071,5.60754"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7470"
|
||||
d="m 230.10477,380.45134 c 0,0 -10.56007,50.00187 -10.56007,50.00187 0,0 -1.7864,-3.10109 -1.7864,-3.10109 0,0 10.48761,-49.78707 10.48761,-49.78707 0,0 1.85886,2.88629 1.85886,2.88629"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7472"
|
||||
d="m 235.60558,382.32627 c 0,0 -0.96703,22.30206 -0.96703,22.30206 0.68945,-0.7749 1.29198,-1.21024 1.8071,-1.30486 0.54025,-0.0986 1.12911,0.0426 1.76693,0.4244 1.5763,0.94367 2.90043,2.95835 3.96916,6.05018 1.07316,3.08672 1.63707,6.54247 1.68823,10.35998 0.0562,4.19815 -0.49112,7.31628 -1.63901,9.3455 -1.15172,2.0543 -2.57758,2.52687 -4.27282,1.42815 -1.57073,-1.01801 -2.95455,-3.2779 -4.15367,-6.7709 0,0 -0.15177,3.37409 -0.15177,3.37409 0,0 -2.66427,-1.72381 -2.66427,-1.72381 0,0 1.94788,-44.98639 1.94788,-44.98639 0,0 2.66927,1.5016 2.66927,1.5016 m 5.4938,36.24781 c -0.0307,-2.35775 -0.3661,-4.47468 -1.00488,-6.34826 -0.63711,-1.86861 -1.44772,-3.10059 -2.43047,-3.69802 -1.06071,-0.64478 -1.92383,-0.28834 -2.59137,1.06538 -0.66665,1.31409 -0.98282,3.34554 -0.94953,6.09789 0.028,2.31062 0.34566,4.35609 0.9543,6.13874 0.61062,1.82429 1.3932,3.04273 2.34903,3.65337 1.05772,0.67576 1.9389,0.3393 2.64164,-1.01349 0.72078,-1.34522 1.06493,-3.31161 1.03128,-5.89561"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7474"
|
||||
d="m 250.36366,417.46334 c 0,0 -0.86865,20.3217 -0.86865,20.3217 0,0 -2.82008,-1.82462 -2.82008,-1.82462 0,0 0.86643,-20.21881 0.86643,-20.21881 0,0 -1.58388,-0.96624 -1.58388,-0.96624 0,0 0.23648,-5.60491 0.23648,-5.60491 0,0 1.5842,0.9502 1.5842,0.9502 0,0 0.51345,-11.96899 0.51345,-11.96899 0,0 2.8242,1.63235 2.8242,1.63235 0,0 -0.51476,12.02979 -0.51476,12.02979 0,0 2.631,1.57806 2.631,1.57806 0,0 -0.23791,5.67619 -0.23791,5.67619 0,0 -2.63048,-1.60472 -2.63048,-1.60472"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7476"
|
||||
d="m 258.21202,416.37883 c 0,0 -0.096,2.26144 -0.096,2.26144 0.95454,-1.4502 1.93663,-1.87534 2.94687,-1.27069 0.8891,0.53219 1.71186,1.72674 2.46789,3.5865 0,0 -1.80434,4.16015 -1.80434,4.16015 -0.55854,-1.34027 -1.10799,-2.17406 -1.64849,-2.50309 -0.37157,-0.22615 -0.69596,-0.26088 -0.97335,-0.10449 -0.27744,0.13698 -0.51645,0.48836 -0.7171,1.05404 -0.19204,0.55148 -0.35012,1.32418 -0.47428,2.31814 -0.11535,0.99924 -0.20109,2.22694 -0.25723,3.68339 0,0 -0.55745,13.1404 -0.55745,13.1404 0,0 -2.89641,-1.87402 -2.89641,-1.87402 0,0 1.11066,-26.19071 1.11066,-26.19071 0,0 2.89923,1.73894 2.89923,1.73894"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7478"
|
||||
d="m 268.68987,428.64319 c 0,0 -0.86895,20.99894 -0.86895,20.99894 0,0 -3.0058,-1.94479 -3.0058,-1.94479 0,0 0.88041,-20.88084 0.88041,-20.88084 0,0 -1.94335,-1.18553 -1.94335,-1.18553 0,0 0.24005,-5.7852 0.24005,-5.7852 0,0 1.94372,1.16583 1.94372,1.16583 0,0 0.50232,-11.90806 0.50232,-11.90806 0.12679,-3.17002 0.49833,-5.34145 1.11549,-6.5165 0.61826,-1.17706 1.52819,-1.42867 2.73266,-0.75115 0.7324,0.41206 1.59932,1.39576 2.60215,2.95457 0,0 -0.233,5.54102 -0.233,5.54102 -0.58832,-1.31228 -1.12097,-2.10411 -1.59836,-2.37735 -0.54989,-0.31462 -0.95023,-0.14571 -1.2017,0.50598 -0.23303,0.66182 -0.39522,2.0335 -0.48667,4.11558 0,0 -0.42429,10.24046 -0.42429,10.24046 0,0 2.74973,1.64927 2.74973,1.64927 0,0 -0.24152,5.86326 -0.24152,5.86326 0,0 -2.76289,-1.68549 -2.76289,-1.68549"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7480"
|
||||
d="m 282.34177,433.95542 c 0,0 -1.71638,2.6839 -1.71638,2.6839 -0.86347,-2.09418 -1.64851,-3.35394 -2.35592,-3.78356 -0.48009,-0.29154 -0.8744,-0.24473 -1.1833,0.13981 -0.29959,0.37 -0.44186,0.97364 -0.42698,1.8113 0.0145,0.81794 0.15802,1.58703 0.43072,2.30771 0.27333,0.74144 0.83759,1.86101 1.69454,3.3616 1.22784,2.17108 2.05909,3.98138 2.49024,5.42552 0.46013,1.4444 0.70781,3.10618 0.74244,4.98411 0.0499,2.7075 -0.35443,4.59578 -1.21137,5.66132 -0.87414,1.03039 -2.03028,1.07769 -3.4649,0.14731 -1.94263,-1.25984 -3.57478,-4.16196 -4.90072,-8.69458 0,0 1.96723,-1.72943 1.96723,-1.72943 0.86759,2.66246 1.77547,4.29951 2.72371,4.90584 0.53649,0.34304 0.96004,0.31621 1.27016,-0.0812 0.31984,-0.39178 0.47119,-1.07004 0.45383,-2.03432 -0.0152,-0.84353 -0.16454,-1.61277 -0.44778,-2.30734 -0.1368,-0.34403 -0.37432,-0.85044 -0.71229,-1.51877 -0.33757,-0.66749 -0.7937,-1.49777 -1.36782,-2.48995 -1.01224,-1.79695 -1.71772,-3.36927 -2.11873,-4.7203 -0.4014,-1.40844 -0.6165,-2.95548 -0.64576,-4.64225 -0.044,-2.5386 0.35547,-4.37575 1.20006,-5.51489 0.84671,-1.14196 1.94916,-1.30825 3.31041,-0.49392 1.50935,0.90299 2.93246,3.09378 4.26861,6.58212"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(1.2096774,-17.209677)"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier New;-inkscape-font-specification:Sans"
|
||||
id="text6884">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 140.43945,317.16536 c 0,0 0,50.22095 0,50.22095 0,0 5.54852,3.63087 5.54852,3.63087 0.35121,0.22983 0.60073,0.56653 0.7483,1.01023 0.14762,0.41494 0.22147,0.89737 0.22148,1.44707 -1e-5,0.52077 -0.0739,0.90601 -0.22148,1.15574 -0.14757,0.24955 -0.39709,0.25809 -0.7483,0.026 0,0 -12.35403,-8.16552 -12.35403,-8.16552 -0.3245,-0.21448 -0.55681,-0.53722 -0.69718,-0.9684 -0.1403,-0.43091 -0.21043,-0.89998 -0.21042,-1.40739 -1e-5,-0.53558 0.0701,-0.91246 0.21042,-1.13062 0.14037,-0.2465 0.37268,-0.26371 0.69718,-0.0514 0,0 5.41088,3.54079 5.41088,3.54079 0,0 0,-46.45699 0,-46.45699 0,0 -3.97848,-2.26531 -3.97848,-2.26531 -0.32622,-0.1857 -0.56519,-0.49145 -0.71716,-0.91726 -0.14103,-0.41932 -0.21152,-0.89742 -0.21151,-1.43445 -1e-5,-0.50868 0.0705,-0.89287 0.21151,-1.1526 0.14111,-0.25979 0.38007,-0.295 0.71716,-0.10537 0,0 5.37311,3.02366 5.37311,3.02366"
|
||||
id="path12071" />
|
||||
d="m 405.68539,517.2315 c 0,0 -0.0193,16.2617 -0.0193,16.2617 0,0 3.17768,-2.015 3.17768,-2.015 0.42104,-0.26699 0.71912,-0.28408 0.89461,-0.0515 0.17538,0.20367 0.26245,0.57777 0.26128,1.12234 -0.001,0.51582 -0.0901,1.00179 -0.26671,1.45807 -0.1768,0.45653 -0.47536,0.81943 -0.89606,1.08884 0,0 -7.2615,4.65021 -7.2615,4.65021 -0.4181,0.26775 -0.71809,0.2856 -0.89962,0.053 -0.18168,-0.23276 -0.27256,-0.61101 -0.27256,-1.13472 0,-0.55292 0.0909,-1.0473 0.27272,-1.48298 0.18171,-0.4645 0.48198,-0.82951 0.90042,-1.09484 0,0 2.35294,-1.49203 2.35294,-1.49203 0,0 0.0349,-43.95921 0.0349,-43.95921 0,0 -2.3762,1.32682 -2.3762,1.32682 -0.4226,0.23601 -0.72583,0.24206 -0.90932,0.0178 -0.18363,-0.25407 -0.2755,-0.66358 -0.2755,-1.22844 0,-0.56489 0.0919,-1.06185 0.27567,-1.49066 0.18367,-0.45823 0.48718,-0.80413 0.91014,-1.03765 0,0 7.3447,-4.05398 7.3447,-4.05398 0.42546,-0.23477 0.72666,-0.22523 0.90398,0.0279 0.17721,0.22388 0.26518,0.61389 0.26399,1.17006 -0.001,0.55615 -0.0911,1.05925 -0.26963,1.50941 -0.1786,0.42125 -0.48025,0.7505 -0.90536,0.98782 0,0 -3.20861,1.79162 -3.20861,1.79162 0,0 -0.027,22.7262 -0.027,22.7262 0,0 11.85347,-29.32986 11.85347,-29.32986 0,0 -1.84356,1.0294 -1.84356,1.0294 -0.4158,0.23222 -0.71071,0.23758 -0.8844,0.0157 -0.17376,-0.25093 -0.25981,-0.65252 -0.25806,-1.20465 0.002,-0.55216 0.0906,-1.03662 0.2666,-1.4532 0.17596,-0.44532 0.4722,-0.78288 0.88832,-1.01263 0,0 4.9265,-2.71923 4.9265,-2.71923 0.39516,-0.21804 0.67722,-0.2015 0.84652,0.049 0.16926,0.22176 0.25255,0.60547 0.24997,1.15114 -0.003,0.54567 -0.0901,1.03822 -0.26231,1.47778 -0.17228,0.41121 -0.45565,0.72699 -0.8505,0.94742 0,0 -0.67254,0.37553 -0.67254,0.37553 0,0 -9.34163,23.22298 -9.34163,23.22298 1.39299,0.391 2.54214,1.22247 3.45037,2.49219 0.90456,1.26471 1.76961,3.30318 2.59512,6.10986 0.47018,1.56163 1.32542,5.36141 2.55962,11.3683 0,0 2.05678,-1.30423 2.05678,-1.30423 0.40304,-0.25557 0.68792,-0.26799 0.85497,-0.0375 0.16702,0.20219 0.24918,0.57016 0.24656,1.10393 -0.003,0.5056 -0.0889,0.98066 -0.25892,1.42533 -0.17022,0.44492 -0.45652,0.79627 -0.85925,1.05417 0,0 -3.17718,2.03464 -3.17718,2.03464 -1.70416,-9.14138 -3.15817,-14.85521 -4.35315,-17.0766 -1.2016,-2.2625 -2.71697,-3.45967 -4.55059,-3.58265 0,0 -3.48846,8.71251 -3.48846,8.71251"
|
||||
id="path6891" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 161.94121,365.01042 c 0,0 7.0063,21.03115 7.0063,21.03115 0.46705,0.30563 0.76243,0.55906 0.88562,0.76022 0.1232,0.17114 0.22797,0.45063 0.31431,0.83876 0.0987,0.39631 0.14801,0.7905 0.14803,1.18245 -2e-5,0.54268 -0.0803,0.94201 -0.24052,1.19797 -0.16024,0.25578 -0.43119,0.25745 -0.81253,0.005 0,0 -4.93644,-3.26279 -4.93644,-3.26279 -0.37439,-0.24745 -0.63978,-0.60162 -0.79646,-1.06272 -0.15663,-0.46083 -0.23491,-0.95918 -0.2349,-1.49528 -1e-5,-0.56586 0.0782,-0.9613 0.2349,-1.1863 0.15668,-0.25496 0.42207,-0.2601 0.79646,-0.0151 0,0 2.53075,1.65609 2.53075,1.65609 0,0 -5.91837,-17.79825 -5.91837,-17.79825 0,0 -5.76255,10.15443 -5.76255,10.15443 0,0 2.46795,1.61498 2.46795,1.61498 0.35431,0.23186 0.60853,0.57528 0.76236,1.03037 0.15389,0.42575 0.23088,0.91936 0.23089,1.48061 -1e-5,0.53172 -0.077,0.92408 -0.23089,1.17691 -0.15383,0.25271 -0.40805,0.26179 -0.76236,0.0276 0,0 -4.79262,-3.16772 -4.79262,-3.16772 -0.34791,-0.22996 -0.59698,-0.56977 -0.74747,-1.01963 -0.15042,-0.44957 -0.2256,-0.93694 -0.2256,-1.46232 0,-0.37944 0.0405,-0.7031 0.12145,-0.9711 0.0926,-0.26048 0.19095,-0.40043 0.29517,-0.41982 0.11584,-0.0411 0.39404,0.0826 0.83509,0.37127 0,0 6.7894,-11.94448 6.7894,-11.94448 0,0 -6.03916,-18.18905 -6.03916,-18.18905 -0.41899,-0.2513 -0.68634,-0.4701 -0.8025,-0.65681 -0.1045,-0.17967 -0.20317,-0.45801 -0.29599,-0.83523 -0.0812,-0.37005 -0.12179,-0.74507 -0.12179,-1.12508 0,-0.52607 0.0754,-0.91967 0.22622,-1.18084 0.15091,-0.26129 0.40649,-0.28516 0.76703,-0.0713 0,0 4.02618,2.38826 4.02618,2.38826 0.36619,0.21727 0.62043,0.54511 0.76245,0.98383 0.15392,0.44591 0.23091,0.94962 0.23092,1.51086 -10e-6,0.5318 -0.077,0.92889 -0.23092,1.19109 -0.14202,0.26926 -0.39626,0.29387 -0.76245,0.0742 0,0 -1.76525,-1.05886 -1.76525,-1.05886 0,0 5.02444,15.1596 5.02444,15.1596 0,0 5.15132,-9.05581 5.15132,-9.05581 0,0 -1.81808,-1.09055 -1.81808,-1.09055 -0.36224,-0.21727 -0.62759,-0.5552 -0.79631,-1.01393 -0.15659,-0.45115 -0.23486,-0.95956 -0.23484,-1.52543 -2e-5,-0.53601 0.0782,-0.93617 0.23484,-1.20056 0.15666,-0.2645 0.422,-0.2859 0.79631,-0.0639 0,0 4.18055,2.47983 4.18055,2.47983 0.368,0.21834 0.63204,0.55537 0.79183,1.01139 0.15983,0.45621 0.23979,0.97042 0.23981,1.54238 -2e-5,0.3613 -0.0492,0.67811 -0.14761,0.95034 -0.0861,0.27955 -0.19055,0.44264 -0.3134,0.48931 -0.11055,0.0541 -0.38669,-0.0515 -0.82796,-0.3162 0,0 -6.23361,10.87982 -6.23361,10.87982"
|
||||
id="path12073" />
|
||||
d="m 443.47158,496.16573 c 0,0 -15.92023,9.70195 -15.92023,9.70195 0.25261,4.3947 1.09424,7.53188 2.51855,9.41247 1.42789,1.83288 3.19316,2.07344 5.2907,0.7382 1.15976,-0.73828 2.37336,-1.93312 3.64044,-3.58163 1.2617,-1.64151 2.29067,-3.40363 3.08952,-5.2883 0.23317,-0.55259 0.43412,-0.88169 0.60291,-0.98752 0.19273,-0.12084 0.35959,-0.0498 0.50059,0.2133 0.14113,0.23564 0.20944,0.58439 0.20501,1.04631 -0.004,0.46186 -0.1049,0.97075 -0.30138,1.52697 -0.59063,1.72481 -1.63435,3.65941 -3.13604,5.80979 -1.49675,2.12595 -3.03903,3.70146 -4.62822,4.72308 -2.68176,1.72399 -4.92977,1.22514 -6.73564,-1.52638 -1.80812,-2.81062 -2.70176,-7.0448 -2.66946,-12.69552 0.0295,-5.15711 0.92218,-10.10229 2.67206,-14.81044 1.75462,-4.69402 3.89166,-7.75636 6.39992,-9.19327 2.55976,-1.46633 4.63179,-0.79081 6.22479,2.00024 1.58113,2.74246 2.3269,7.04454 2.24648,12.91075 m -1.50759,-2.55533 c -0.26805,-3.63428 -1.04266,-6.26807 -2.32893,-7.90085 -1.28159,-1.6495 -2.8345,-1.95112 -4.66221,-0.89235 -1.83997,1.06596 -3.44162,3.19609 -4.79954,6.39411 -1.36305,3.21016 -2.22473,6.90224 -2.58104,11.06526 0,0 14.37172,-8.66617 14.37172,-8.66617"
|
||||
id="path6893" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 190.66329,367.61999 c 0,0 0,-1.31091 0,-1.31091 -2e-5,-0.96754 0.0793,-1.60701 0.23812,-1.91848 0.15885,-0.31161 0.35754,-0.39675 0.59615,-0.25526 0.25205,0.14956 0.45784,0.47505 0.61728,0.97627 0.15948,0.50164 0.23926,1.23771 0.23929,2.20799 0,0 0,8.92054 0,8.92054 -0.0133,0.96219 -0.0998,1.59756 -0.25923,1.90613 -0.14614,0.31665 -0.34529,0.39709 -0.59734,0.24155 -0.22536,-0.13902 -0.41744,-0.4293 -0.57629,-0.87076 -0.14557,-0.46428 -0.23155,-1.12587 -0.25798,-1.98485 -0.0793,-2.26435 -0.70007,-4.74694 -1.8588,-7.44034 -1.14118,-2.67507 -2.67549,-4.58556 -4.59684,-5.73359 -2.40997,-1.43988 -4.22691,-0.73221 -5.46164,2.10531 -1.22955,2.82567 -1.84239,6.53635 -1.84239,11.1409 0,4.97054 0.67609,9.5068 2.03299,13.62309 1.3632,4.13542 3.13715,6.92641 5.32927,8.36657 1.2711,0.83507 2.56726,1.1284 3.88879,0.87642 1.34056,-0.24449 2.55488,-1.26285 3.64142,-3.05912 0.27887,-0.4458 0.52476,-0.60042 0.73762,-0.46347 0.22628,0.14563 0.41277,0.45355 0.55941,0.92409 0.16,0.44793 0.24005,0.93848 0.24007,1.47145 -2e-5,1.3481 -0.67306,2.61811 -2.01459,3.80604 -2.1525,1.92107 -4.53114,2.00839 -7.13036,0.2837 -2.61508,-1.73522 -4.74914,-5.12664 -6.41235,-10.16426 -1.64124,-5.03145 -2.45842,-10.56254 -2.45841,-16.61439 -1e-5,-6.17346 0.83605,-10.78915 2.51538,-13.86032 1.70176,-3.08124 3.85575,-3.86089 6.47185,-2.31525 2.50885,1.48237 4.63121,4.52585 6.35858,9.14095"
|
||||
id="path12075" />
|
||||
d="m 455.58667,470.66722 c 0,0 -0.10498,8.56019 -0.10498,8.56019 1.93651,-5.08183 3.37081,-8.44336 4.30858,-10.1013 0.94661,-1.68612 1.80908,-2.7511 2.58784,-3.19777 0.84383,-0.48395 1.61379,-0.25336 2.31017,0.68823 0.70553,0.90558 1.05243,1.70098 1.04247,2.38832 -0.007,0.50226 -0.0857,0.96734 -0.23511,1.3954 -0.13804,0.39541 -0.31278,0.65513 -0.52432,0.77918 -0.11142,0.0654 -0.20559,0.0813 -0.28249,0.0476 -0.0766,-0.0601 -0.21729,-0.27954 -0.42229,-0.65871 -0.37824,-0.6994 -0.71083,-1.13744 -0.99754,-1.31325 -0.2871,-0.17598 -0.57132,-0.18255 -0.85261,-0.0195 -0.61996,0.35957 -1.37941,1.38224 -2.27917,3.07105 -0.89096,1.68702 -2.45801,5.46216 -4.70984,11.34948 0,0 -0.22596,18.42612 -0.22596,18.42612 0,0 6.33459,-4.01684 6.33459,-4.01684 0.34746,-0.22033 0.59161,-0.21895 0.7327,0.004 0.14133,0.1965 0.2085,0.54399 0.2016,1.04251 -0.007,0.47221 -0.0847,0.91205 -0.23427,1.31965 -0.14973,0.40781 -0.39805,0.72284 -0.74529,0.94521 0,0 -11.32013,7.24932 -11.32013,7.24932 -0.35123,0.22493 -0.6016,0.23885 -0.75084,0.0414 -0.14907,-0.22443 -0.22099,-0.57831 -0.21571,-1.0616 0.005,-0.45652 0.0796,-0.87735 0.22375,-1.26235 0.15613,-0.41912 0.41594,-0.74392 0.77913,-0.97432 0,0 3.54132,-2.24639 3.54132,-2.24639 0,0 0.33638,-28.17047 0.33638,-28.17047 0,0 -2.71509,1.57907 -2.71509,1.57907 -0.35236,0.20495 -0.60335,0.18908 -0.75268,-0.0481 -0.14946,-0.2372 -0.22135,-0.61416 -0.2156,-1.13086 0.005,-0.48951 0.0807,-0.93834 0.22572,-1.34628 0.15673,-0.41449 0.41745,-0.72656 0.78182,-0.93616 0,0 4.17785,-2.40283 4.17785,-2.40283"
|
||||
id="path6895" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 205.10727,399.25125 c 0,0 5.73306,3.65382 5.73306,3.65382 0,0 -6.23199,22.47411 -6.23199,22.47411 -0.37367,1.34168 -0.82284,1.83225 -1.34718,1.47339 -0.34449,-0.2358 -0.64043,-0.72486 -0.88797,-1.46697 -0.23361,-0.70036 -0.35034,-1.44789 -0.35034,-2.243 0,-0.31805 0.0206,-0.65395 0.0618,-1.00763 0,0 3.02262,-22.88372 3.02262,-22.88372"
|
||||
id="path12077" />
|
||||
d="m 473.30415,460.47729 c 0,0 -0.0804,4.97133 -0.0804,4.97133 0.98569,-2.87136 1.86574,-4.96674 2.64065,-6.28932 0.77288,-1.31909 1.63191,-2.24853 2.57593,-2.78936 1.01432,-0.58102 1.92593,-0.57975 2.7356,4.3e-4 0.57165,0.43409 1.07517,1.41355 1.51085,2.93619 0.44533,1.487 0.6504,3.16172 0.61612,5.02597 0,0 -0.37098,20.16552 -0.37098,20.16552 0,0 1.09632,-0.69519 1.09632,-0.69519 0.30795,-0.19527 0.52558,-0.18379 0.65312,0.0343 0.1279,0.19274 0.18732,0.5284 0.17832,1.00704 -0.009,0.4534 -0.0822,0.87365 -0.22092,1.26091 -0.13883,0.38745 -0.362,0.67967 -0.66977,0.87676 0,0 -3.48879,2.2342 -3.48879,2.2342 -0.32291,0.20678 -0.54961,0.20133 -0.67985,-0.0168 -0.13035,-0.21825 -0.19152,-0.55628 -0.18341,-1.01409 0.009,-0.48331 0.0832,-0.90811 0.22395,-1.27426 0.14113,-0.39138 0.37338,-0.68956 0.69648,-0.89444 0,0 1.09126,-0.69198 1.09126,-0.69198 0,0 0.35635,-19.67714 0.35635,-19.67714 0.0412,-2.27809 -0.26274,-4.00074 -0.9136,-5.16921 -0.65266,-1.19813 -1.55322,-1.46656 -2.70395,-0.79997 -0.87978,0.50971 -1.6529,1.39411 -2.31814,2.65394 -0.66627,1.2367 -1.63439,3.93929 -2.90635,8.11592 0,0 -0.33083,20.46711 -0.33083,20.46711 0,0 1.52554,-0.96736 1.52554,-0.96736 0.32,-0.20291 0.54652,-0.19417 0.67982,0.026 0.13361,0.19441 0.19632,0.5352 0.1882,1.02244 -0.008,0.46152 -0.0833,0.89021 -0.22665,1.28621 -0.14347,0.39619 -0.37497,0.69664 -0.69477,0.90144 0,0 -4.42215,2.83191 -4.42215,2.83191 -0.3258,0.20863 -0.55714,0.20298 -0.6938,-0.0174 -0.13675,-0.22051 -0.20159,-0.56416 -0.19444,-1.03091 0.008,-0.49277 0.0843,-0.92686 0.23029,-1.30217 0.1463,-0.40101 0.38259,-0.70494 0.70859,-0.91166 0,0 1.54286,-0.97835 1.54286,-0.97835 0,0 0.43113,-27.17649 0.43113,-27.17649 0,0 -1.15824,0.67362 -1.15824,0.67362 -0.32722,0.19033 -0.55954,0.16948 -0.69672,-0.0629 -0.13729,-0.23247 -0.20212,-0.59828 -0.19443,-1.09741 0.007,-0.47286 0.0845,-0.90805 0.23156,-1.30535 0.14701,-0.39707 0.38436,-0.6898 0.71179,-0.87815 0,0 2.52342,-1.45131 2.52342,-1.45131"
|
||||
id="path6897" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 271.11411,457.35945 c 0,0 0,-6.42681 0,-6.42681 -3.10047,3.40822 -6.38155,3.94515 -9.83759,1.65192 -2.48679,-1.65009 -4.41727,-4.24834 -5.80096,-7.79282 -1.37793,-3.56428 -2.06474,-7.25483 -2.06474,-11.08277 0,-4.20723 0.90527,-7.30878 2.72332,-9.31282 1.82803,-2.01507 4.51481,-1.9316 8.08109,0.27619 0.96857,0.59969 2.02383,1.3936 3.16658,2.38297 1.1466,0.95764 2.39035,2.13516 3.7323,3.53459 0,0 0,-7.22352 0,-7.22352 -3e-5,-2.44323 -0.54423,-4.89656 -1.63001,-7.35412 -1.08235,-2.44961 -2.69936,-4.31509 -4.84337,-5.59616 -1.63234,-0.97525 -3.90928,-1.34198 -6.81764,-1.10525 -0.52311,0.032 -0.8578,0.004 -1.00462,-0.0848 -0.26088,-0.15719 -0.48896,-0.50248 -0.68433,-1.03576 -0.17902,-0.52313 -0.26847,-1.09611 -0.26847,-1.7192 0,-0.58839 0.0813,-1.00706 0.24405,-1.25606 0.22793,-0.3834 1.14942,-0.54477 2.77027,-0.48366 2.57013,0.061 4.52742,0.48442 5.86093,1.27225 2.66612,1.57529 4.76009,4.20783 6.27107,7.90057 1.51771,3.67383 2.27912,7.27529 2.27913,10.79204 0,0 0,29.62623 0,29.62623 0,0 2.88997,1.89115 2.88997,1.89115 0.53593,0.3507 0.91679,0.8142 1.14207,1.39054 0.22537,0.54089 0.33812,1.15113 0.33816,1.83041 -4e-5,0.64351 -0.11284,1.10539 -0.33816,1.38561 -0.22528,0.27997 -0.60614,0.24255 -1.14207,-0.11167 0,0 -5.06698,-3.34907 -5.06698,-3.34907 m 0,-22.20172 c -1.00273,-1.23099 -2.06169,-2.33664 -3.17634,-3.31716 -1.11102,-0.97729 -2.27699,-1.84752 -3.49734,-2.61108 -3.03992,-1.90193 -5.39629,-2.00244 -7.08327,-0.32077 -1.27186,1.23928 -1.90596,3.27543 -1.90596,6.11197 0,2.62903 0.47952,5.1547 1.44068,7.58233 0.98029,2.44541 2.40686,4.2853 4.28547,5.51948 1.80611,1.18656 3.48841,1.53771 5.04496,1.04694 1.58058,-0.51735 3.21096,-1.91034 4.8918,-4.18559 0,0 0,-9.82612 0,-9.82612"
|
||||
id="path12079" />
|
||||
d="m 502.73274,460.0514 c 0,0 -12.58078,7.66685 -12.58078,7.66685 0.13943,3.95275 0.75486,6.81973 1.84191,8.60127 1.09127,1.74028 2.46782,2.07625 4.12588,1.02077 0.91736,-0.58398 1.88324,-1.57454 2.89733,-2.9694 1.01026,-1.38958 1.83995,-2.9037 2.49094,-4.54374 0.19007,-0.48101 0.352,-0.76339 0.48584,-0.84731 0.15283,-0.0958 0.2829,-0.0209 0.39022,0.22483 0.10778,0.2211 0.15695,0.53905 0.14755,0.95388 -0.009,0.41479 -0.0948,0.86546 -0.25619,1.35225 -0.48577,1.51058 -1.32969,3.17888 -2.53523,5.00941 -1.20067,1.80791 -2.42926,3.11745 -3.68662,3.92576 -2.11999,1.36285 -3.86995,0.76072 -5.24366,-1.82965 -1.37343,-2.64104 -2.01438,-6.49315 -1.91501,-11.55003 0.0906,-4.61389 0.85108,-8.9821 2.27681,-13.08506 1.42996,-4.0921 3.13808,-6.70212 5.11668,-7.83561 2.02129,-1.15786 3.63504,-0.42605 4.84758,2.17494 1.20485,2.55883 1.735,6.46775 1.59675,11.73084 m -1.15024,-2.39108 c -0.1636,-3.27931 -0.73716,-5.69144 -1.72424,-7.23625 -0.98254,-1.55853 -2.19418,-1.92464 -3.63745,-1.08857 -1.45189,0.84113 -2.73048,2.64931 -3.83206,5.42777 -1.10528,2.78784 -1.82554,6.03803 -2.15785,9.74209 0,0 11.3516,-6.84504 11.3516,-6.84504"
|
||||
id="path6899" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 305.27676,479.93957 c 0,0 0,-6.86189 0,-6.86189 -3.21505,3.68169 -6.65929,4.28417 -10.32564,1.85139 -2.236,-1.48368 -3.92619,-3.82619 -5.07842,-7.02675 -1.48866,-4.17529 -2.23061,-8.37816 -2.2306,-12.62199 0,0 0,-29.48895 0,-29.48895 0,0 -3.01401,-1.80791 -3.01401,-1.80791 -0.53074,-0.31833 -0.9106,-0.76254 -1.14007,-1.33286 -0.22933,-0.56981 -0.34393,-1.19694 -0.34393,-1.88171 0,-0.64863 0.11456,-1.12104 0.34393,-1.41732 0.22947,-0.29643 0.60933,-0.2875 1.14007,0.0273 0,0 5.27157,3.127 5.27157,3.127 0,0 0,34.2244 0,34.2244 0,2.98398 0.46767,5.74427 1.40491,8.28605 0.93973,2.54862 2.11799,4.29026 3.53714,5.2226 3.75734,2.46845 7.2386,1.27516 10.43505,-3.63264 0,0 0,-30.23698 0,-30.23698 0,0 -4.33901,-2.6027 -4.33901,-2.6027 -0.55605,-0.33351 -0.954,-0.79367 -1.19439,-1.38071 -0.24026,-0.58652 -0.36032,-1.23005 -0.36029,-1.93091 -3e-5,-0.66389 0.12001,-1.14576 0.36029,-1.44571 0.24039,-0.30014 0.63834,-0.28557 1.19439,0.0442 0,0 6.71277,3.9819 6.71277,3.9819 0,0 0,43.77138 0,43.77138 0,0 2.01873,1.32102 2.01873,1.32102 0.5707,0.37346 0.98027,0.86624 1.22818,1.47843 0.24802,0.57501 0.3721,1.21898 0.37212,1.93157 -2e-5,0.67508 -0.12418,1.15577 -0.37212,1.4421 -0.24791,0.28605 -0.65748,0.24015 -1.22818,-0.13705 0,0 -4.39249,-2.90326 -4.39249,-2.90326"
|
||||
id="path12081" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 331.10608,451.86264 c 0,0 0,40.29309 0,40.29309 0,0 11.33093,7.41479 11.33093,7.41479 0.62404,0.40837 1.07195,0.93651 1.34306,1.58448 0.27124,0.60912 0.40696,1.28649 0.40699,2.03171 -3e-5,0.70599 -0.13581,1.20478 -0.40699,1.49638 -0.27111,0.2913 -0.71902,0.23036 -1.34306,-0.18211 0,0 -19.93946,-13.17917 -19.93946,-13.17917 -0.59038,-0.39022 -1.0129,-0.89763 -1.26813,-1.5226 -0.25505,-0.62448 -0.38252,-1.27858 -0.38251,-1.96267 -10e-6,-0.72207 0.12741,-1.20858 0.38251,-1.45953 0.25523,-0.28919 0.67775,-0.24091 1.26813,0.14542 0,0 6.04677,3.95692 6.04677,3.95692 0,0 0,-40.15334 0,-40.15334 0,0 -5.42587,-3.25463 -5.42587,-3.25463 -0.59138,-0.35471 -1.01459,-0.83694 -1.27026,-1.44699 -0.2555,-0.60948 -0.38317,-1.27541 -0.38317,-1.99818 0,-0.68461 0.12762,-1.17925 0.38317,-1.48397 0.25567,-0.30491 0.67888,-0.28227 1.27026,0.0685 0,0 5.42587,3.21853 5.42587,3.21853 0,0 0,-7.31632 0,-7.31632 -2e-5,-4.07098 0.86197,-7.11046 2.592,-9.12558 1.73815,-2.02447 4.05487,-2.22739 6.961,-0.59209 2.45295,1.38047 5.08868,3.29457 7.91092,5.74926 1.07167,0.91997 1.71405,1.65721 1.92494,2.20997 0.23203,0.56511 0.34813,1.20269 0.34816,1.91248 -3e-5,0.70989 -0.1266,1.22928 -0.37979,1.55791 -0.25304,0.28912 -0.59009,0.31325 -1.01094,0.0727 -0.16827,-0.0961 -0.45198,-0.31718 -0.85089,-0.66317 -3.15558,-2.70293 -5.79955,-4.65865 -7.9424,-5.87884 -2.2532,-1.28289 -3.985,-1.22414 -5.20258,0.16697 -1.19342,1.39829 -1.78867,3.42534 -1.78866,6.08452 0,0 0,7.34179 0,7.34179 0,0 12.07996,7.16563 12.07996,7.16563 0.62529,0.37097 1.07408,0.87241 1.34574,1.50461 0.27179,0.63256 0.40778,1.32201 0.40781,2.06791 -3e-5,0.70676 -0.13609,1.21428 -0.40781,1.52253 -0.27166,0.30808 -0.72045,0.27422 -1.34574,-0.10088 0,0 -12.07996,-7.246 -12.07996,-7.246"
|
||||
id="path12083" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 381.53904,480.26145 c -4e-5,-1.19393 0.13803,-1.97639 0.41437,-2.34753 0.27648,-0.37137 0.62238,-0.43403 1.03788,-0.18762 0.439,0.26047 0.79752,0.74165 1.07534,1.44329 0.27794,0.70231 0.41702,1.69419 0.41703,2.97521 0,0 0,8.92609 0,8.92609 -10e-6,1.23978 -0.13902,2.04325 -0.41703,2.41011 -0.27782,0.36667 -0.63634,0.41516 -1.07534,0.14588 -0.39243,-0.24064 -0.72682,-0.67235 -1.00333,-1.29503 -0.25333,-0.60811 -0.40294,-1.44075 -0.44892,-2.49818 -0.13799,-2.55388 -0.85046,-5.02174 -2.13409,-7.39831 -1.87213,-3.42059 -4.3356,-6.03941 -7.37923,-7.858 -3.15377,-1.88428 -5.58541,-2.18625 -7.30824,-0.92152 -1.29812,0.94833 -1.94553,2.48638 -1.94553,4.61649 0,2.41154 0.76823,4.89373 2.30933,7.4543 1.0603,1.78482 3.07849,3.90375 6.06957,6.36723 3.94113,3.22198 6.70097,5.81863 8.2541,7.77127 2.22609,2.8303 3.88664,5.87077 4.97442,9.11605 1.11394,3.26899 1.6721,6.39758 1.67214,9.37882 -4e-5,4.43046 -1.1968,7.60368 -3.5795,9.51102 -2.36847,1.85478 -5.81509,1.27327 -10.31153,-1.7103 -4.44518,-2.94957 -8.0486,-7.3738 -10.83305,-13.26579 -10e-6,1.36395 -0.0436,2.2178 -0.13101,2.56131 -0.0874,0.34347 -0.25106,0.57633 -0.49105,0.6985 -0.21804,0.13637 -0.46864,0.11113 -0.75172,-0.076 -0.39163,-0.25884 -0.71767,-0.73428 -0.97829,-1.42646 -0.26047,-0.69164 -0.39063,-1.63687 -0.39063,-2.83609 0,0 0,-10.37303 0,-10.37303 0,-1.19919 0.11929,-1.98223 0.35807,-2.34925 0.2606,-0.35334 0.59748,-0.39824 1.01085,-0.13424 0.39201,0.25036 0.71901,0.71962 0.9808,1.40824 0.28381,0.6629 0.42578,1.41575 0.4258,2.25821 -2e-5,1.84546 0.25131,3.55252 0.75448,5.12277 0.76692,2.42665 1.98618,4.83059 3.66211,7.21589 1.70538,2.36981 3.79751,4.37105 6.28262,6.00369 3.70087,2.43135 6.47684,3.00416 8.3079,1.69647 1.83952,-1.31379 2.76254,-3.37564 2.76258,-6.18089 -4e-5,-3.21781 -0.93458,-6.38939 -2.797,-9.50367 -1.87655,-3.11405 -4.59528,-6.11381 -8.13869,-8.9908 -3.48927,-2.83712 -5.9752,-5.24246 -7.47672,-7.22927 -1.49576,-1.97906 -2.65753,-4.26856 -3.48835,-6.87006 -0.82903,-2.59583 -1.24288,-5.09307 -1.24286,-7.49587 -2e-5,-4.32499 1.1555,-7.05664 3.47704,-8.20014 2.33556,-1.19067 5.14142,-0.82407 8.42768,1.11751 3.92599,2.31968 7.14794,5.96756 9.64805,10.94971"
|
||||
id="path12085" />
|
||||
d="m 514.91047,422.62215 c 0,0 -1.06434,42.27288 -1.06434,42.27288 0,0 4.45362,-2.8241 4.45362,-2.8241 0.2761,-0.17507 0.46813,-0.15759 0.57629,0.0523 0.10868,0.18619 0.15712,0.50328 0.14534,0.95133 -0.0112,0.42443 -0.0782,0.81493 -0.20113,1.17164 -0.12299,0.35687 -0.32235,0.62363 -0.59831,0.80035 0,0 -10.15763,6.50487 -10.15763,6.50487 -0.27917,0.17878 -0.476,0.16246 -0.5903,-0.0494 -0.11437,-0.21191 -0.16642,-0.53506 -0.15609,-0.96944 0.0109,-0.45857 0.0801,-0.85922 0.20776,-1.20182 0.12814,-0.36656 0.33197,-0.63844 0.61129,-0.81556 0,0 4.56188,-2.89274 4.56188,-2.89274 0,0 0.97884,-39.26779 0.97884,-39.26779 0,0 -3.35907,1.85407 -3.35907,1.85407 -0.27977,0.15447 -0.48159,0.1208 -0.60529,-0.10124 -0.11445,-0.22726 -0.16609,-0.57399 -0.15489,-1.04015 0.0106,-0.44163 0.0802,-0.843 0.20889,-1.204 0.12859,-0.36073 0.33761,-0.62003 0.62686,-0.77784 0,0 4.51628,-2.46343 4.51628,-2.46343"
|
||||
id="path6901" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
@@ -599,7 +644,7 @@
|
||||
<g
|
||||
inkscape:corner7="0.22235256 : 0.05733945 : 0.532878 : 1"
|
||||
inkscape:corner0="0.4922944 : 0.12449455 : 0 : 1"
|
||||
inkscape:perspectiveID="#perspective3054"
|
||||
inkscape:perspectiveID="#perspective5786"
|
||||
id="g3195"
|
||||
style="fill:#f0f0f0;fill-opacity:0.51111115;stroke:#253237;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;display:inline"
|
||||
sodipodi:type="inkscape:box3d">
|
||||
@@ -684,31 +729,6 @@
|
||||
id="path4004"
|
||||
sodipodi:type="inkscape:box3dside" />
|
||||
</g>
|
||||
<g
|
||||
id="text4031"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Sans"
|
||||
transform="matrix(0.5589128,0,0,0.5589128,174.77385,97.01703)">
|
||||
<path
|
||||
id="path4038"
|
||||
d="m 282.79778,223.1883 c 0,0 -0.6821,34.01888 -0.6821,34.01888 0,0 18.98585,-5.00566 18.98585,-5.00566 1.2893,-0.33993 2.20833,-0.45044 2.75935,-0.33226 0.55064,0.096 0.82138,0.35348 0.81277,0.77255 -0.008,0.39705 -0.29289,0.80178 -0.85387,1.21447 -0.56196,0.41327 -1.48645,0.79167 -2.77573,1.13557 0,0 -44.72801,11.93065 -44.72801,11.93065 -1.42497,0.3801 -2.44616,0.51347 -3.06094,0.39901 -0.61559,-0.11457 -0.91968,-0.38193 -0.91159,-0.80201 0.008,-0.44338 0.3259,-0.87559 0.95192,-1.29625 0.62554,-0.44339 1.65213,-0.85314 3.07713,-1.22885 0,0 20.05366,-5.28718 20.05366,-5.28718 0,0 0.68066,-34.22837 0.68066,-34.22837 0,0 -20.05925,4.54892 -20.05925,4.54892 -1.42544,0.32329 -2.44718,0.42713 -3.0626,0.31069 -0.6158,-0.1399 -0.91975,-0.43212 -0.91119,-0.87654 0.008,-0.44433 0.32603,-0.86491 0.95227,-1.26139 0.62576,-0.41923 1.6527,-0.78845 3.07817,-1.10733 0,0 44.74122,-10.00757 44.74122,-10.00757 1.28958,-0.28842 2.20881,-0.36188 2.75993,-0.22091 0.55075,0.1187 0.82154,0.38796 0.81291,0.80788 -0.009,0.42002 -0.29367,0.82541 -0.85477,1.21646 -0.56164,0.36954 -1.48611,0.70037 -2.77567,0.99277 0,0 -18.99012,4.30647 -18.99012,4.30647"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path4040"
|
||||
d="m 333.70439,218.67102 c 0,0 -0.0587,2.72754 -0.0587,2.72754 4.31507,-3.46248 8.58164,-5.67789 12.79965,-6.66399 2.51867,-0.58878 4.7071,-0.73536 6.57013,-0.44328 1.85514,0.26995 3.39018,0.98553 4.60856,2.14501 2.14625,-1.9575 4.2924,-3.53718 6.43822,-4.74174 2.17248,-1.22772 4.32584,-2.08967 6.46016,-2.58865 3.32651,-0.77764 5.94413,-0.79259 7.86586,-0.0522 2.51331,0.93636 3.74321,2.31125 3.70162,4.12895 0,0 -0.40751,17.77352 -0.40751,17.77352 0,0 3.78154,-0.99701 3.78154,-0.99701 1.0589,-0.27918 1.81331,-0.35863 2.265,-0.23889 0.45151,0.0996 0.67268,0.33943 0.66395,0.71958 -0.008,0.36017 -0.24358,0.72101 -0.70559,1.08272 -0.46279,0.36219 -1.22275,0.68437 -2.28164,0.96681 0,0 -8.30108,2.21421 -8.30108,2.21421 0,0 0.46012,-20.18321 0.46012,-20.18321 0.0296,-1.29965 -0.64981,-2.20744 -2.04182,-2.72464 -1.39694,-0.51893 -3.02752,-0.55871 -4.89435,-0.11645 -1.69116,0.40066 -3.48972,1.18482 -5.39699,2.35517 -1.91549,1.15505 -4.1177,3.07215 -6.61075,5.75887 0,0 -0.38593,17.34484 -0.38593,17.34484 0,0 3.94466,-1.04002 3.94466,-1.04002 1.12023,-0.29535 1.91848,-0.38295 2.39656,-0.26337 0.47792,0.0988 0.71231,0.34368 0.70356,0.73459 -0.008,0.37035 -0.25674,0.74319 -0.74514,1.11873 -0.48916,0.37602 -1.29295,0.71329 -2.41317,1.01209 0,0 -8.78473,2.34322 -8.78473,2.34322 0,0 0.45491,-20.57441 0.45491,-20.57441 0.0309,-1.39962 -0.70802,-2.36557 -2.22095,-2.89919 -1.47959,-0.56565 -3.16794,-0.62501 -5.06745,-0.17502 -1.752,0.41508 -3.49828,1.13407 -5.2386,2.15872 -2.4247,1.44429 -4.99579,3.55425 -7.71548,6.33646 0,0 -0.38442,17.85802 -0.38442,17.85802 0,0 4.24187,-1.11838 4.24187,-1.11838 1.1874,-0.31306 2.03362,-0.40968 2.54064,-0.2905 0.50681,0.0978 0.75565,0.3479 0.7469,0.75024 -0.008,0.38118 -0.27082,0.76681 -0.78834,1.15733 -0.51807,0.39097 -1.3698,0.74465 -2.55719,1.06137 0,0 -13.64864,3.64061 -13.64864,3.64061 -1.22865,0.32772 -2.10857,0.43336 -2.63763,0.31598 -0.52971,-0.11749 -0.7907,-0.37136 -0.78245,-0.76153 0.009,-0.41183 0.28334,-0.80778 0.82373,-1.18753 0.54007,-0.40091 1.42551,-0.76349 2.65418,-1.08743 0,0 4.33418,-1.14272 4.33418,-1.14272 0,0 0.4806,-22.47941 0.4806,-22.47941 0,0 -4.33464,1.0317 -4.33464,1.0317 -1.2288,0.29249 -2.10883,0.37258 -2.63794,0.23946 -0.52978,-0.1332 -0.79056,-0.4061 -0.78184,-0.81857 0.008,-0.39072 0.28294,-0.77944 0.82386,-1.16588 0.54015,-0.38591 1.4257,-0.72332 2.65452,-1.01198 0,0 9.40801,-2.20977 9.40801,-2.20977"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path4042"
|
||||
d="m 431.66157,220.15121 c 0,0 0.0838,-3.4392 0.0838,-3.4392 -5.86908,4.46079 -12.19603,7.61638 -19.00283,9.44026 -5.01634,1.34413 -8.9635,1.66058 -11.80893,0.93249 -2.86592,-0.75319 -4.28108,-2.23143 -4.2297,-4.43076 0.0565,-2.41757 2.02666,-5.0136 5.88321,-7.76824 3.82039,-2.72881 9.29321,-4.96718 16.3493,-6.71054 1.8819,-0.46494 3.91395,-0.89069 6.09374,-1.27732 2.16795,-0.40343 4.49584,-0.76226 6.98064,-1.07648 0,0 0.0943,-3.86881 0.0943,-3.86881 0.0318,-1.30873 -0.94792,-2.20502 -2.94729,-2.69073 -2.0101,-0.48823 -5.06896,-0.24773 -9.20127,0.73123 -3.1937,0.75663 -7.73215,2.3834 -13.66129,4.9035 -1.08129,0.45367 -1.77483,0.7173 -2.07866,0.79 -0.54077,0.12948 -1.01175,0.12481 -1.41272,-0.0143 -0.36747,-0.14728 -0.54717,-0.39832 -0.53881,-0.75307 0.008,-0.33499 0.1838,-0.64127 0.52757,-0.91864 0.48125,-0.40757 2.39918,-1.26142 5.73331,-2.55378 5.19823,-2.03472 9.08047,-3.34807 11.68433,-3.95682 5.12395,-1.19783 9.05529,-1.36876 11.82888,-0.5292 2.75357,0.81456 4.09994,2.15371 4.05425,4.02181 0,0 -0.38517,15.72953 -0.38517,15.72953 0,0 5.19262,-1.36904 5.19262,-1.36904 0.95041,-0.25058 1.62073,-0.31597 2.01241,-0.19663 0.39163,0.10055 0.58294,0.32805 0.57423,0.68255 -0.008,0.33588 -0.21359,0.66851 -0.61574,0.99809 -0.40275,0.32996 -1.0786,0.62159 -2.02902,0.8751 0,0 -9.18117,2.44897 -9.18117,2.44897 m 0.28963,-11.88378 c -1.85188,0.1444 -3.826,0.40309 -5.9241,0.77705 -2.10961,0.37603 -4.34564,0.85922 -6.71011,1.45071 -5.99108,1.49874 -10.75526,3.45758 -14.2458,5.87477 -2.66308,1.8282 -4.02015,3.55498 -4.05808,5.1712 -0.0352,1.49786 0.93743,2.49682 2.9103,2.99513 1.99648,0.48693 4.89613,0.22483 8.67932,-0.77721 3.58353,-0.94915 6.88503,-2.2348 9.91145,-3.85407 3.03569,-1.63439 6.13916,-3.76218 9.30881,-6.377 0,0 0.12821,-5.26058 0.12821,-5.26058"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path4044"
|
||||
d="m 487.68217,186.54679 c 0,0 0.10564,-4.06721 0.10564,-4.06721 0,0 7.90801,-1.85745 7.90801,-1.85745 0.79301,-0.18623 1.35751,-0.21524 1.69464,-0.0873 0.3367,0.12786 0.50061,0.35664 0.49198,0.68643 -0.008,0.31249 -0.18616,0.61347 -0.5337,0.90306 -0.34808,0.28997 -0.91806,0.52925 -1.71109,0.71799 0,0 -4.51455,1.07452 -4.51455,1.07452 0,0 -0.57459,22.03902 -0.57459,22.03902 -0.0384,1.47001 -0.55548,2.91413 -1.55336,4.33529 -0.6668,0.94954 -1.76798,2.04674 -3.30751,3.29427 -1.54611,1.25278 -2.95556,2.23384 -4.2268,2.94103 -1.27575,0.70968 -2.98068,1.36473 -5.1209,1.96595 0,0 -10.09114,2.83466 -10.09114,2.83466 -0.86083,0.2418 -1.47625,0.30679 -1.84501,0.1943 -0.36961,-0.0944 -0.5502,-0.31403 -0.54146,-0.65872 0.009,-0.3447 0.20323,-0.67811 0.58346,-1.00002 0.37979,-0.32158 1.0007,-0.60203 1.86152,-0.84114 0,0 10.21573,-2.81129 10.21573,-2.81129 2.05634,-0.57131 3.90303,-1.41898 5.54333,-2.54169 1.66023,-1.12521 3.03533,-2.47541 4.12856,-4.05097 0.61561,-0.90119 0.93791,-1.9227 0.96764,-3.06566 0,0 0.17268,-6.6482 0.17268,-6.6482 -3.75728,4.22258 -8.58953,7.13169 -14.54094,8.71456 -4.90653,1.30498 -9.17076,1.28431 -12.76987,-0.0855 -3.60562,-1.4096 -5.38035,-3.78477 -5.29699,-7.11539 0.0834,-3.33124 2.00056,-6.62133 5.72421,-9.84613 3.71648,-3.20034 8.039,-5.36811 12.94485,-6.51501 5.95052,-1.39107 10.69758,-0.88232 14.28567,1.49047 m -0.1735,6.67977 c 0.0676,-2.60468 -1.25813,-4.46865 -3.99335,-5.59822 -2.72937,-1.14506 -6.06018,-1.2571 -10.00838,-0.32175 -3.99164,0.94566 -7.47585,2.69973 -10.43699,5.26937 -2.98394,2.57159 -4.51858,5.21107 -4.58622,7.90293 -0.0681,2.70979 1.35151,4.62821 4.24133,5.74881 2.86713,1.09352 6.30461,1.10802 10.2967,0.0587 3.94868,-1.03788 7.32661,-2.82534 10.14966,-5.35628 2.82923,-2.53633 4.26956,-5.09924 4.33725,-7.70358"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path4046"
|
||||
d="m 540.11557,181.1992 c 0,0 -31.2176,7.85302 -31.2176,7.85302 0.48573,2.63928 2.15047,4.43554 4.97687,5.38625 2.82796,0.91931 6.31992,0.8233 10.45571,-0.27212 2.27866,-0.60354 4.65697,-1.48834 7.13282,-2.65107 2.45777,-1.15424 4.45604,-2.3471 6.00292,-3.58061 0.45083,-0.36101 0.83942,-0.58385 1.16596,-0.6688 0.37271,-0.097 0.69561,-0.0757 0.96883,0.0637 0.27337,0.12295 0.40619,0.32289 0.39861,0.5999 -0.008,0.27704 -0.20081,0.59468 -0.57975,0.95322 -1.14042,1.11074 -3.16231,2.40927 -6.08171,3.90253 -2.92062,1.48339 -5.94124,2.64545 -9.0645,3.48232 -5.2951,1.41883 -9.75204,1.42909 -13.33713,0.003 -3.59795,-1.46568 -5.36582,-3.92779 -5.27448,-7.37497 0.0832,-3.13906 1.88506,-6.25108 5.37983,-9.31298 3.48579,-3.03794 7.7012,-5.12678 12.61811,-6.27626 4.99076,-1.1667 9.012,-0.99979 12.09648,0.47721 3.05557,1.44667 4.50134,3.91533 4.35903,7.41612 m -2.91605,-1.34024 c -0.52374,-2.13318 -2.02526,-3.60994 -4.51812,-4.43193 -2.48827,-0.834 -5.50996,-0.83398 -9.07894,0.0115 -3.60706,0.85456 -6.76149,2.32359 -9.44972,4.41217 -2.70894,2.10468 -4.4334,4.44604 -5.1587,7.01535 0,0 28.20548,-7.00711 28.20548,-7.00711"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.80256968,0,0,0.80256968,38.124381,46.818937)"
|
||||
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium Italic"
|
||||
@@ -749,7 +769,7 @@
|
||||
<g
|
||||
id="text4949"
|
||||
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium Italic"
|
||||
transform="matrix(0.83804272,0,0,0.83804272,31.314311,25.788578)">
|
||||
transform="matrix(0.74694175,0,0,0.74694175,45.485062,44.593966)">
|
||||
<path
|
||||
id="path4956"
|
||||
d="m 142.69979,137.10297 c 0,0 -1.02955,33.67577 -1.02955,33.67577 0,0 -1.95085,-0.57539 -1.95085,-0.57539 0,0 0.11438,-3.62641 0.11438,-3.62641 -0.83178,2.72212 -1.69018,3.94864 -2.57494,3.68641 -1.08457,-0.32145 -1.96585,-2.08912 -2.6458,-5.29794 -0.67825,-3.20078 -1.01674,-7.18681 -1.01674,-11.96409 0,-5.51039 0.38729,-9.93148 1.16353,-13.27043 0.79003,-3.34576 1.80543,-4.8788 3.04874,-4.59076 0.58877,0.13642 1.0911,0.64686 1.50651,1.53207 0.42191,0.88799 0.85328,2.3539 1.29417,4.39917 0,0 0.13239,-4.42502 0.13239,-4.42502 0,0 1.95816,0.45662 1.95816,0.45662 m -2.38162,15.3911 c 0,-2.99293 -0.21149,-5.4766 -0.63396,-7.44868 -0.42183,-1.99292 -0.96573,-3.06948 -1.63097,-3.23169 -0.72176,-0.17595 -1.32564,0.83047 -1.81241,3.01599 -0.4859,2.20539 -0.72852,4.99168 -0.72852,8.36184 0,2.94297 0.20217,5.40768 0.60697,7.39634 0.40539,1.99165 0.92751,3.07935 1.56702,3.26122 0.71103,0.20221 1.32739,-0.80489 1.84844,-3.02486 0.52203,-2.27207 0.78343,-5.04988 0.78343,-8.33016"
|
||||
@@ -788,29 +808,54 @@
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.53155689,0,0,0.53155689,185.92425,73.057684)"
|
||||
transform="matrix(0.87020295,0,0,0.87020295,36.583926,33.755817)"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Sans"
|
||||
id="text5440">
|
||||
id="text5788">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 282.85502,131.91713 c 0,0 0,60.1855 0,60.1855 0,0 18.99047,-3.66344 18.99047,-3.66344 1.28959,-0.24877 2.21156,-0.19199 2.76814,0.16971 0.55582,0.32211 0.83347,0.85406 0.83354,1.59612 -7e-5,0.70307 -0.27789,1.34368 -0.83354,1.92233 -0.55658,0.57941 -1.47855,0.99706 -2.76814,1.25292 0,0 -44.74121,8.87701 -44.74121,8.87701 -1.42547,0.28283 -2.44971,0.23848 -3.07009,-0.13431 -0.62119,-0.37318 -0.93211,-0.93202 -0.93207,-1.6762 -4e-5,-0.78548 0.31077,-1.46595 0.93207,-2.04091 0.62038,-0.61545 1.64462,-1.0607 3.07009,-1.33569 0,0 20.05972,-3.8697 20.05972,-3.8697 0,0 0,-60.55879 0,-60.55879 0,0 -20.05972,2.55389 -20.05972,2.55389 -1.42547,0.18155 -2.44971,0.0849 -3.07009,-0.29062 -0.62119,-0.41721 -0.93211,-1.01884 -0.93207,-1.80439 -4e-5,-0.78544 0.31077,-1.44382 0.93207,-1.97467 0.62038,-0.57129 1.64462,-0.94369 3.07009,-1.11742 0,0 44.74121,-5.45018 44.74121,-5.45018 1.28959,-0.157 2.21156,-0.0348 2.76814,0.36651 0.55582,0.36168 0.83347,0.91337 0.83354,1.65541 -7e-5,0.74214 -0.27789,1.38258 -0.83354,1.92167 -0.55658,0.50085 -1.47855,0.83337 -2.76814,0.99749 0,0 -18.99047,2.41776 -18.99047,2.41776"
|
||||
id="path5447" />
|
||||
d="m 292.16734,221.79451 c 0,0 0.079,32.92107 0.079,32.92107 0,0 6.83396,-1.8594 6.83396,-1.8594 0.46993,-0.12786 0.80691,-0.0884 1.01132,0.11827 0.20419,0.18473 0.30715,0.48443 0.30895,0.89923 0.002,0.39306 -0.0986,0.7486 -0.30066,1.06669 -0.20232,0.31832 -0.53842,0.54236 -1.00864,0.67204 0,0 -15.85959,4.37404 -15.85959,4.37404 -0.49118,0.13546 -0.8436,0.0983 -1.05684,-0.11192 -0.21335,-0.21022 -0.32005,-0.51707 -0.32005,-0.92043 0,-0.42568 0.10663,-0.79078 0.31991,-1.09527 0.21307,-0.32663 0.56522,-0.55672 1.05608,-0.69027 0,0 6.99856,-1.90419 6.99856,-1.90419 0,0 -0.0639,-33.01316 -0.0639,-33.01316 0,0 -6.94528,1.58452 -6.94528,1.58452 -0.48709,0.11116 -0.83656,0.0697 -1.04802,-0.12452 -0.21157,-0.21626 -0.31738,-0.53384 -0.31738,-0.95255 0,-0.41857 0.10573,-0.77281 0.31723,-1.06267 0.2113,-0.3116 0.56052,-0.52201 1.04729,-0.63134 0,0 15.72034,-3.52906 15.72034,-3.52906 0.46618,-0.1046 0.80048,-0.0507 1.00326,0.16175 0.20255,0.1909 0.30468,0.4903 0.30646,0.89834 0.002,0.40818 -0.0977,0.76414 -0.29818,1.06788 -0.2008,0.28254 -0.53427,0.47704 -1.00074,0.58343 0,0 -6.78316,1.54752 -6.78316,1.54752"
|
||||
id="path5793" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 333.91441,137.89555 c 0,0 0,4.82145 0,4.82145 4.26231,-4.95507 8.50252,-7.71134 12.72066,-8.30086 2.51875,-0.35197 4.71531,-0.0105 6.59457,1.01943 1.8709,0.98856 3.43002,2.67958 4.6808,5.07092 2.11395,-2.88191 4.23612,-5.09366 6.36625,-6.64009 2.15634,-1.5801 4.30164,-2.51686 6.43596,-2.81516 3.32659,-0.46487 5.9579,0.22791 7.90698,2.06895 2.54851,2.35126 3.81689,5.1278 3.81694,8.34054 0,0 0,31.43173 0,31.43173 0,0 3.78169,-0.72952 3.78169,-0.72952 1.05891,-0.20428 1.81612,-0.1377 2.27337,0.19926 0.45658,0.30111 0.68473,0.78785 0.68478,1.46049 -5e-5,0.63729 -0.22831,1.21332 -0.68478,1.72849 -0.45725,0.51581 -1.21446,0.87878 -2.27337,1.08887 0,0 -8.30139,1.64706 -8.30139,1.64706 0,0 0,-35.69743 0,-35.69743 -5e-5,-2.29723 -0.70401,-4.09415 -2.11546,-5.39408 -1.41642,-1.30426 -3.05675,-1.82293 -4.92361,-1.5517 -1.6912,0.24582 -3.48172,1.14219 -5.37282,2.6937 -1.89982,1.52212 -4.07088,4.31725 -6.51735,8.39799 0,0 0,30.68038 0,30.68038 0,0 3.945,-0.76103 3.945,-0.76103 1.12031,-0.21612 1.92139,-0.15193 2.40505,0.19205 0.48304,0.30709 0.72435,0.80641 0.7244,1.49821 -5e-5,0.65545 -0.24151,1.24922 -0.7244,1.78172 -0.48366,0.53316 -1.28474,0.91091 -2.40505,1.13318 0,0 -8.78558,1.74313 -8.78558,1.74313 0,0 0,-36.39673 0,-36.39673 -6e-5,-2.4744 -0.76441,-4.39095 -2.29726,-5.75335 -1.49996,-1.40997 -3.19853,-1.9793 -5.09812,-1.70331 -1.75207,0.25466 -3.49172,1.04986 -5.21877,2.38888 -2.4059,1.89533 -4.94464,4.93136 -7.61849,9.11946 0,0 0,31.59463 0,31.59463 0,0 4.24249,-0.81841 4.24249,-0.81841 1.18757,-0.22909 2.03666,-0.16772 2.54928,0.18357 0.51194,0.31331 0.76772,0.82591 0.76772,1.53812 0,0.67475 -0.25565,1.28741 -0.76772,1.83856 -0.51262,0.5518 -1.36171,0.94553 -2.54928,1.18115 0,0 -13.65088,2.70845 -13.65088,2.70845 -1.22888,0.24381 -2.11171,0.18914 -2.64637,-0.1651 -0.53532,-0.35459 -0.80324,-0.87742 -0.80324,-1.56821 0,-0.72913 0.26779,-1.35677 0.80324,-1.8825 0.53466,-0.56337 1.41749,-0.9636 2.64637,-1.20066 0,0 4.33489,-0.83624 4.33489,-0.83624 0,0 0,-39.76731 0,-39.76731 0,0 -4.33489,0.63844 -4.33489,0.63844 -1.22888,0.18102 -2.11171,0.0812 -2.64637,-0.30039 -0.53532,-0.3819 -0.80324,-0.93762 -0.80324,-1.66681 0,-0.69073 0.26779,-1.3047 0.80324,-1.84141 0.53466,-0.53594 1.41749,-0.89098 2.64637,-1.06519 0,0 9.40839,-1.33332 9.40839,-1.33332"
|
||||
id="path5449" />
|
||||
d="m 310.82617,224.548 c 0,0 0.0183,2.71052 0.0183,2.71052 1.59486,-2.82856 3.1975,-4.42813 4.80917,-4.80918 0.96652,-0.22849 1.81505,-0.0602 2.54657,0.50362 0.73011,0.54196 1.34443,1.48928 1.84362,2.84195 0.81039,-1.66756 1.62919,-2.95534 2.45658,-3.86518 0.83957,-0.93171 1.68046,-1.49641 2.52294,-1.6956 1.31778,-0.31154 2.3707,0.0529 3.16143,1.09107 1.03734,1.32998 1.56558,2.9259 1.58639,4.79109 0,0 0.20434,18.33386 0.20434,18.33386 0,0 1.53013,-0.41632 1.53013,-0.41632 0.42981,-0.11694 0.739,-0.0757 0.92789,0.12381 0.18853,0.17852 0.2851,0.46568 0.2898,0.86158 0.004,0.37517 -0.0849,0.71339 -0.26782,1.01476 -0.18312,0.30159 -0.48957,0.51171 -0.91962,0.63032 0,0 -3.35086,0.92415 -3.35086,0.92415 0,0 -0.22279,-20.77656 -0.22279,-20.77656 -0.0143,-1.33018 -0.30714,-2.3628 -0.87909,-3.0991 -0.57267,-0.73709 -1.22837,-1.01732 -1.9678,-0.8398 -0.66827,0.16051 -1.37063,0.69532 -2.10748,1.60588 -0.73886,0.89188 -1.5757,2.51342 -2.51176,4.86946 0,0 0.15842,17.6379 0.15842,17.6379 0,0 1.54833,-0.42128 1.54833,-0.42128 0.44115,-0.12002 0.75819,-0.0792 0.95147,0.12232 0.19296,0.18032 0.29136,0.47108 0.29523,0.8724 0.004,0.38029 -0.0887,0.72347 -0.27704,1.02961 -0.18854,0.30636 -0.50335,0.52043 -0.94475,0.64217 0,0 -3.43946,0.94859 -3.43946,0.94859 0,0 -0.17831,-20.87173 -0.17831,-20.87173 -0.0121,-1.41164 -0.31784,-2.49778 -0.91785,-3.25983 -0.5861,-0.78757 -1.24345,-1.09429 -1.97265,-0.91922 -0.67099,0.16116 -1.3334,0.62756 -1.98734,1.40021 -0.90879,1.0908 -1.86103,2.82298 -2.85755,5.20088 0,0 0.12057,17.88402 0.12057,17.88402 0,0 1.61271,-0.43879 1.61271,-0.43879 0.45299,-0.12325 0.77823,-0.083 0.97608,0.1207 0.1976,0.18215 0.29787,0.47663 0.3009,0.88354 0.003,0.38558 -0.0926,0.73385 -0.28674,1.04496 -0.19419,0.31131 -0.51774,0.52949 -0.971,0.6545 0,0 -5.16143,1.42351 -5.16143,1.42351 -0.46029,0.12695 -0.79127,0.0881 -0.99256,-0.11674 -0.20137,-0.20491 -0.30318,-0.50235 -0.30537,-0.89222 -0.002,-0.41142 0.0958,-0.76345 0.29429,-1.05603 0.19822,-0.314 0.5275,-0.53357 0.98751,-0.65873 0,0 1.62837,-0.44305 1.62837,-0.44305 0,0 -0.14116,-22.4169 -0.14116,-22.4169 0,0 -1.62022,0.3912 -1.62022,0.3912 -0.4577,0.11052 -0.78681,0.0614 -0.98695,-0.14757 -0.20023,-0.209 -0.30151,-0.51693 -0.3038,-0.92368 -0.002,-0.38522 0.0954,-0.72992 0.29266,-1.034 0.19711,-0.30384 0.52454,-0.51011 0.98197,-0.61888 0,0 3.52575,-0.83819 3.52575,-0.83819"
|
||||
id="path5795" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 432.47276,167.4628 c 0,0 0,-6.0828 0,-6.0828 -5.7975,6.30445 -12.08843,10.16628 -18.89488,11.53144 -5.01615,1.00608 -8.98079,0.48151 -11.86134,-1.59461 -2.90152,-2.12615 -4.36018,-5.14012 -4.36018,-9.03027 0,-4.27566 1.92089,-8.34103 5.73528,-12.16858 3.77821,-3.79124 9.22987,-6.25766 16.28577,-7.41051 1.88182,-0.30744 3.91568,-0.50406 6.09908,-0.59067 2.1711,-0.11991 4.5042,-0.11625 6.99627,0.009 0,0 0,-6.83683 0,-6.83683 -5e-5,-2.31243 -1.00752,-4.17126 -3.03041,-5.58202 -2.03364,-1.41813 -5.10423,-1.83216 -9.23645,-1.23173 -3.19365,0.46414 -7.71884,2.10172 -13.62152,4.94147 -1.07664,0.50744 -1.76786,0.78436 -2.07171,0.82982 -0.54075,0.081 -1.01453,-0.0567 -1.42103,-0.41361 -0.37302,-0.36215 -0.55967,-0.85678 -0.55965,-1.4836 -2e-5,-0.59191 0.16967,-1.08669 0.50881,-1.48409 0.4743,-0.5905 2.38272,-1.57754 5.70477,-2.95304 5.17873,-2.17952 9.05121,-3.44151 11.655,-3.80542 5.12389,-0.71605 9.07344,0.061 11.88347,2.3116 2.78957,2.201 4.1768,4.94583 4.17684,8.24643 0,0 0,27.80543 0,27.80543 0,0 5.19212,-1.00161 5.19212,-1.00161 0.9503,-0.18332 1.62332,-0.11496 2.02049,0.20469 0.39666,0.28626 0.59487,0.74275 0.59492,1.36971 -5e-5,0.59401 -0.19835,1.12807 -0.59492,1.60254 -0.39717,0.475 -1.07019,0.8068 -2.02049,0.99534 0,0 -9.18024,1.82144 -9.18024,1.82144 m 0,-21.01324 c -1.85966,-0.253 -3.83943,-0.33685 -5.94113,-0.2503 -2.11321,0.0871 -4.351,0.32956 -6.71539,0.72884 -5.99089,1.01179 -10.73667,3.1774 -14.19058,6.50681 -2.63574,2.51203 -3.96016,5.20345 -3.96016,8.06185 0,2.64923 1.0022,4.69037 2.99914,6.11798 2.02049,1.41398 4.93209,1.74663 8.71515,1.00868 3.58337,-0.69901 6.87476,-2.07305 9.88112,-4.11507 3.01516,-2.0662 6.08631,-4.98942 9.21185,-8.75869 0,0 0,-9.3001 0,-9.3001"
|
||||
id="path5451" />
|
||||
d="m 350.89656,241.32467 c 0,0 -0.0589,-3.6804 -0.0589,-3.6804 -2.44263,3.80778 -5.10211,6.12062 -7.98027,6.91861 -2.10441,0.58347 -3.76815,0.25666 -4.98415,-0.98555 -1.21953,-1.26623 -1.84495,-3.04991 -1.87379,-5.34667 -0.0317,-2.52154 0.73085,-4.92487 2.28129,-7.20305 1.54219,-2.26605 3.8038,-3.77126 6.77195,-4.51991 0.7964,-0.20085 1.66062,-0.33746 2.59222,-0.41005 0.92884,-0.0925 1.93136,-0.11301 3.00698,-0.0616 0,0 -0.0657,-4.10694 -0.0657,-4.10694 -0.0222,-1.38732 -0.47413,-2.48748 -1.3571,-3.30238 -0.88479,-0.81652 -2.19971,-1.01605 -3.95,-0.59577 -1.34605,0.32326 -3.2353,1.35808 -5.67763,3.11343 -0.44361,0.31258 -0.72851,0.48429 -0.85424,0.51483 -0.22367,0.0544 -0.4211,-0.0207 -0.59224,-0.22543 -0.1572,-0.2081 -0.23822,-0.49632 -0.24303,-0.86451 -0.005,-0.34763 0.0618,-0.6405 0.19913,-0.87854 0.1918,-0.35344 0.97539,-0.96079 2.34657,-1.81956 2.14879,-1.36681 3.76798,-2.17692 4.86556,-2.43642 2.17117,-0.5133 3.8675,-0.11811 5.09661,1.18044 1.22539,1.27503 1.8531,2.9031 1.88568,4.88818 0,0 0.27554,16.79617 0.27554,16.79617 0,0 2.26031,-0.61499 2.26031,-0.61499 0.41544,-0.11304 0.71203,-0.0724 0.89013,0.12173 0.17763,0.17395 0.26972,0.45203 0.27631,0.83437 0.006,0.36231 -0.0756,0.68817 -0.24525,0.97765 -0.1699,0.28969 -0.46252,0.49188 -0.87818,0.60651 0,0 -3.98778,1.09982 -3.98778,1.09982 m -0.20304,-12.6875 c -0.80507,-0.13756 -1.65804,-0.17224 -2.55931,-0.10371 -0.90358,0.0688 -1.85617,0.23114 -2.85824,0.48756 -2.52482,0.64614 -4.49945,1.96292 -5.91531,3.95406 -1.07701,1.49735 -1.60605,3.09291 -1.58411,4.78359 0.0203,1.56816 0.45251,2.77768 1.29533,3.62647 0.85525,0.84341 2.07851,1.0467 3.66561,0.61257 1.51075,-0.41325 2.89832,-1.234 4.16372,-2.45986 1.27358,-1.2449 2.56786,-3.01121 3.88202,-5.29462 0,0 -0.0897,-5.60606 -0.0897,-5.60606"
|
||||
id="path5797" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 487.99642,123.24158 c 0,0 0,-7.18198 0,-7.18198 0,0 7.90751,-1.12062 7.90751,-1.12062 0.79296,-0.11233 1.36016,-0.009 1.70274,0.31079 0.34213,0.31914 0.51311,0.76977 0.51315,1.35205 -4e-5,0.55172 -0.1711,1.03642 -0.51315,1.45436 -0.34258,0.41847 -0.90978,0.68611 -1.70274,0.80287 0,0 -4.51418,0.66486 -4.51418,0.66486 0,0 0,38.94129 0,38.94129 -4e-5,2.59919 -0.48281,5.02085 -1.45031,7.2696 -0.64654,1.50257 -1.72664,3.14785 -3.24428,4.93949 -1.52421,1.79929 -2.91796,3.15367 -4.17969,4.05975 -1.26625,0.90926 -2.96613,1.60334 -5.1058,2.08195 0,0 -10.08857,2.25658 -10.08857,2.25658 -0.86063,0.19248 -1.47865,0.13846 -1.85284,-0.1629 -0.37458,-0.26951 -0.56202,-0.70931 -0.56199,-1.31915 -3e-5,-0.6099 0.18735,-1.14853 0.56199,-1.6156 0.37419,-0.46662 0.99221,-0.79375 1.85284,-0.98147 0,0 10.21398,-2.18055 10.21398,-2.18055 2.05581,-0.44853 3.89332,-1.44561 5.5158,-2.98788 1.64244,-1.5412 2.99182,-3.56029 4.05143,-6.05696 0.59628,-1.43064 0.89407,-3.15551 0.89411,-5.17643 0,0 0,-11.75228 0,-11.75228 -3.67199,6.46046 -8.46094,10.29476 -14.41118,11.46715 -4.90563,0.96658 -9.19852,-0.24333 -12.85592,-3.66485 -3.66449,-3.49351 -5.51038,-8.19646 -5.51038,-14.08282 0,-5.88631 1.84589,-11.19456 5.51038,-15.88982 3.6574,-4.65324 7.95029,-7.30895 12.85592,-7.99455 5.95024,-0.83153 10.73919,1.3743 14.41118,6.56705 m 0,11.79891 c -4e-5,-4.60139 -1.38279,-8.2714 -4.16442,-11.02605 -2.77587,-2.78019 -6.12983,-3.89388 -10.07779,-3.32022 -3.9914,0.58007 -7.45175,2.73284 -10.36533,6.4757 -2.93682,3.74047 -4.41401,8.00015 -4.41399,12.75663 -2e-5,4.7889 1.47717,8.58342 4.41399,11.36687 2.91358,2.72941 6.37393,3.70079 10.36533,2.93654 3.94796,-0.75589 7.30192,-2.99916 10.07779,-6.71425 2.78163,-3.72257 4.16438,-7.87377 4.16442,-12.47522"
|
||||
id="path5453" />
|
||||
d="m 375.34938,213.69585 c 0,0 -0.0974,-4.46393 -0.0974,-4.46393 0,0 3.68773,-0.87669 3.68773,-0.87669 0.37208,-0.0884 0.64113,-0.0368 0.8074,0.15502 0.16617,0.1917 0.25341,0.46963 0.26178,0.83387 0.008,0.34517 -0.066,0.6522 -0.22166,0.92112 -0.15581,0.26917 -0.41973,0.44869 -0.792,0.53856 0,0 -2.11132,0.50977 -2.11132,0.50977 0,0 0.54123,24.40071 0.54123,24.40071 0.0363,1.63856 -0.15744,3.16664 -0.58194,4.58541 -0.2835,0.94739 -0.76869,1.98351 -1.45663,3.10962 -0.68973,1.12896 -1.32331,1.97649 -1.90026,2.54121 -0.57809,0.56581 -1.35962,0.99328 -2.34591,1.28221 0,0 -4.61112,1.35073 -4.61112,1.35073 -0.39039,0.11434 -0.67276,0.0767 -0.84684,-0.11314 -0.17377,-0.16995 -0.26435,-0.44453 -0.27168,-0.82361 -0.007,-0.37906 0.0714,-0.71279 0.23628,-1.00117 0.16471,-0.28821 0.4423,-0.4887 0.83248,-0.60152 0,0 4.66707,-1.3197 4.66707,-1.3197 0.94729,-0.27395 1.78841,-0.89388 2.52391,-1.85846 0.74626,-0.96574 1.35024,-2.23429 1.81265,-3.80502 0.26003,-0.90063 0.37608,-1.98619 0.34838,-3.25697 0,0 -0.16086,-7.37517 -0.16086,-7.37517 -1.62758,4.07072 -3.80169,6.48925 -6.53059,7.23934 -2.23287,0.61374 -4.19888,-0.12311 -5.89159,-2.21938 -1.68617,-2.12737 -2.56457,-4.99526 -2.6305,-8.59335 -0.0658,-3.59204 0.69765,-6.85485 2.28324,-9.77979 1.5891,-2.91055 3.49618,-4.62319 5.71739,-5.14835 2.71476,-0.64182 4.95439,0.6184 6.73072,3.76863 m 0.16039,7.3538 c -0.0626,-2.87086 -0.7569,-5.1338 -2.0858,-6.79534 -1.32015,-1.66944 -2.87807,-2.29072 -4.67812,-1.8585 -1.80975,0.43462 -3.35087,1.81991 -4.62062,4.16259 -1.27628,2.33429 -1.88951,4.95932 -1.83504,7.86963 0.0549,2.93412 0.76232,5.25114 2.11916,6.94432 1.35246,1.66842 2.93958,2.25345 4.75697,1.76072 1.80761,-0.49005 3.33004,-1.90799 4.57015,-4.24741 1.2464,-2.3511 1.83598,-4.96126 1.7733,-7.83601"
|
||||
id="path5799" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 540.62477,128.16676 c 0,0 -31.21107,5.34869 -31.21107,5.34869 0.55959,4.81556 2.2836,8.46026 5.1546,10.92445 2.872,2.40913 6.38532,3.19917 10.51985,2.39265 2.27795,-0.44435 4.64854,-1.36045 7.10966,-2.74289 2.44306,-1.3723 4.42228,-2.9394 5.94583,-4.70274 0.44396,-0.51656 0.82908,-0.80507 1.15552,-0.86603 0.37259,-0.0695 0.6983,0.0569 0.97727,0.37934 0.27866,0.2933 0.41792,0.68457 0.41796,1.174 -4e-5,0.48947 -0.18573,0.99996 -0.55739,1.53196 -1.11764,1.65734 -3.11777,3.40564 -6.01644,5.2527 -2.90027,1.82933 -5.91022,3.06093 -9.03241,3.68714 -5.29338,1.06168 -9.78084,-0.14614 -13.42879,-3.66389 -3.66146,-3.59033 -5.50683,-8.44484 -5.50683,-14.53483 0,-5.54457 1.73031,-10.56796 5.16522,-15.03667 3.42605,-4.4281 7.61147,-6.97301 12.52802,-7.66014 4.99038,-0.69739 9.04168,0.70282 12.18653,4.16823 3.11531,3.40416 4.63885,8.17864 4.59247,14.34803 m -2.97258,-3.17835 c -0.58603,-3.92674 -2.13806,-6.95772 -4.66971,-9.09992 -2.52711,-2.16203 -5.56808,-2.99195 -9.13671,-2.47342 -3.60671,0.52417 -6.74137,2.26195 -9.39035,5.22633 -2.66963,2.9875 -4.34237,6.66553 -5.00354,11.02281 0,0 28.20031,-4.6758 28.20031,-4.6758"
|
||||
id="path5455" />
|
||||
d="m 400.95375,215.84309 c 0,0 -15.30351,3.94188 -15.30351,3.94188 0.34391,3.04783 1.23396,5.34503 2.66637,6.88627 1.43922,1.51372 3.17433,1.99038 5.19951,1.43641 1.12095,-0.30662 2.28367,-0.91984 3.48738,-1.83766 1.19883,-0.91409 2.16489,-1.95211 2.90025,-3.11439 0.2145,-0.34084 0.40349,-0.53306 0.56706,-0.57689 0.1868,-0.05 0.35355,0.0278 0.50028,0.23369 0.14614,0.18703 0.22361,0.43961 0.23247,0.75782 0.009,0.31828 -0.0759,0.65247 -0.25418,1.00277 -0.53474,1.08992 -1.51174,2.24633 -2.93533,3.4719 -1.41926,1.20943 -2.89777,2.0288 -4.43582,2.45524 -2.59183,0.71861 -4.80714,-0.0257 -6.63604,-2.24415 -1.8247,-2.25008 -2.7858,-5.3079 -2.87757,-9.16136 -0.0834,-3.50233 0.67052,-6.70553 2.2543,-9.60045 1.58612,-2.87997 3.57782,-4.59755 5.9692,-5.16295 2.44485,-0.578 4.47658,0.20903 6.10451,2.35191 1.62144,2.1165 2.47361,5.16594 2.56112,9.15996 m -1.55297,-1.99958 c -0.36339,-2.52164 -1.19348,-4.43925 -2.49343,-5.75652 -1.29227,-1.32421 -2.81005,-1.77891 -4.55736,-1.35935 -1.75678,0.42189 -3.25581,1.59979 -4.49431,3.53879 -1.24433,1.94813 -1.99432,4.30819 -2.24605,7.0779 0,0 13.79115,-3.50082 13.79115,-3.50082"
|
||||
id="path5801" />
|
||||
</g>
|
||||
<g
|
||||
id="text6335"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Sans"
|
||||
transform="translate(1.4477142e-8,-14.516129)">
|
||||
<path
|
||||
id="path6342"
|
||||
d="m 289.7812,172.74924 c 0,0 0,30.32096 0,30.32096 0,0 5.31622,-1.09403 5.31622,-1.09403 0.36864,-0.0759 0.6328,-0.009 0.79253,0.19948 0.15968,0.18869 0.23953,0.47439 0.23955,0.85707 -2e-5,0.36257 -0.0799,0.68117 -0.23955,0.95582 -0.15973,0.27468 -0.42389,0.45007 -0.79253,0.52616 0,0 -12.20372,2.51907 -12.20372,2.51907 -0.37097,0.0766 -0.63686,0.0102 -0.79765,-0.19916 -0.16081,-0.20937 -0.24121,-0.49598 -0.24121,-0.85983 0,-0.38404 0.0804,-0.7038 0.24121,-0.95925 0.16079,-0.27564 0.42668,-0.45161 0.79765,-0.52795 0,0 5.3343,-1.09775 5.3343,-1.09775 0,0 0,-30.33259 0,-30.33259 0,0 -5.3343,1.0578 -5.3343,1.0578 -0.37097,0.0736 -0.63686,0.0152 -0.79765,-0.17532 -0.16081,-0.21064 -0.24121,-0.50801 -0.24121,-0.89209 0,-0.38402 0.0804,-0.70312 0.24121,-0.9573 0.16079,-0.2743 0.42668,-0.44812 0.79765,-0.52149 0,0 12.20372,-2.41236 12.20372,-2.41236 0.36864,-0.0728 0.6328,-0.004 0.79253,0.20591 0.15968,0.19002 0.23953,0.47636 0.23955,0.85902 -2e-5,0.38273 -0.0799,0.71076 -0.23955,0.98409 -0.15973,0.25327 -0.42389,0.41645 -0.79253,0.48952 0,0 -5.31622,1.05422 -5.31622,1.05422"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path6344"
|
||||
d="m 304.56912,176.44974 c 0,0 0,2.56275 0,2.56275 1.30843,-2.57317 2.62214,-3.99091 3.94109,-4.25437 0.79339,-0.15843 1.48888,0.0539 2.08658,0.63694 0.5975,0.56281 1.09732,1.50612 1.49954,2.82986 0.68233,-1.5411 1.37053,-2.72191 2.0646,-3.54263 0.70597,-0.84286 1.41171,-1.33466 2.11721,-1.47559 1.10637,-0.22094 1.98741,0.19403 2.64338,1.24457 0.86213,1.3493 1.29307,2.9247 1.29309,4.72665 0,0 0,17.62938 0,17.62938 0,0 1.29225,-0.26593 1.29225,-0.26593 0.36384,-0.0749 0.62457,-0.008 0.78222,0.19923 0.1576,0.18768 0.23641,0.47161 0.23643,0.8518 -2e-5,0.3602 -0.0789,0.67662 -0.23643,0.94926 -0.15765,0.27268 -0.41838,0.44656 -0.78222,0.52167 0,0 -2.82218,0.58254 -2.82218,0.58254 0,0 0,-19.91946 0,-19.91946 -2e-5,-1.28187 -0.2369,-2.29585 -0.71072,-3.04209 -0.47398,-0.74635 -1.02099,-1.0575 -1.64109,-0.93328 -0.55951,0.11212 -1.14958,0.58117 -1.77024,1.40731 -0.62086,0.80639 -1.32718,2.30204 -2.11901,4.48741 0,0 0,16.76074 0,16.76074 0,0 1.27899,-0.26321 1.27899,-0.26321 0.36526,-0.0752 0.62699,-0.009 0.78525,0.19931 0.15823,0.18797 0.23733,0.47243 0.23735,0.85335 -2e-5,0.3609 -0.0792,0.67796 -0.23735,0.95119 -0.15826,0.27327 -0.41999,0.4476 -0.78525,0.52299 0,0 -2.83314,0.58481 -2.83314,0.58481 0,0 0,-19.77746 0,-19.77746 -1e-5,-1.34457 -0.2439,-2.39933 -0.73178,-3.16444 -0.47581,-0.78777 -1.01275,-1.12183 -1.61085,-1.00201 -0.54945,0.11011 -1.09295,0.51024 -1.63047,1.20051 -0.74545,0.97331 -1.52785,2.54716 -2.34725,4.72194 0,0 0,16.79351 0,16.79351 0,0 1.30233,-0.26801 1.30233,-0.26801 0.3667,-0.0755 0.62946,-0.009 0.78832,0.19938 0.15885,0.18827 0.23827,0.47325 0.23828,0.85492 -1e-5,0.3616 -0.0794,0.6793 -0.23828,0.95314 -0.15886,0.27387 -0.42162,0.44864 -0.78832,0.52433 0,0 -4.14836,0.8563 -4.14836,0.8563 -0.36753,0.0759 -0.63097,0.01 -0.79027,-0.199 -0.15931,-0.20855 -0.23897,-0.49391 -0.23897,-0.85606 0,-0.38226 0.0796,-0.70045 0.23897,-0.95457 0.1593,-0.2742 0.42274,-0.44911 0.79027,-0.52474 0,0 1.30416,-0.26839 1.30416,-0.26839 0,0 0,-21.02253 0,-21.02253 0,0 -1.30416,0.26159 -1.30416,0.26159 -0.36753,0.0737 -0.63097,0.006 -0.79027,-0.20361 -0.15931,-0.20947 -0.23897,-0.50535 -0.23897,-0.88764 0,-0.36212 0.0796,-0.67984 0.23897,-0.95317 0.1593,-0.27324 0.42274,-0.44662 0.79027,-0.52013 0,0 2.84603,-0.56906 2.84603,-0.56906"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path6346"
|
||||
d="m 338.26689,195.60376 c 0,0 0,-3.61767 0,-3.61767 -2.20252,3.52388 -4.55814,5.54631 -7.06742,6.06489 -1.82363,0.37688 -3.24985,-0.0877 -4.27786,-1.39461 -1.02852,-1.32754 -1.54299,-3.10136 -1.54298,-5.32096 -10e-6,-2.43953 0.67785,-4.70711 2.03287,-6.80168 1.35409,-2.09312 3.3292,-3.40199 5.92348,-3.92714 0.69926,-0.14153 1.45854,-0.21543 2.27777,-0.22172 0.81887,-0.0262 1.70362,0.0239 2.65414,0.15025 0,0 0,-4.06615 0,-4.06615 -2e-5,-1.37528 -0.38498,-2.49383 -1.15511,-3.35589 -0.77046,-0.86234 -1.92668,-1.1392 -3.46933,-0.83014 -1.18192,0.23683 -2.84139,1.13844 -4.97959,2.70598 -0.38682,0.2775 -0.63466,0.4272 -0.74347,0.44903 -0.19348,0.0389 -0.36277,-0.047 -0.50789,-0.25774 -0.13305,-0.2131 -0.19957,-0.49956 -0.19957,-0.85935 0,-0.33976 0.0605,-0.6217 0.18143,-0.84583 0.1693,-0.33368 0.85246,-0.88012 2.04895,-1.63902 1.8839,-1.21542 3.30773,-1.91909 4.27248,-2.1118 1.91602,-0.38264 3.40901,0.10672 4.47992,1.46726 1.07032,1.33994 1.60526,2.99588 1.60527,4.96838 0,0 0,16.61698 0,16.61698 0,0 2.01829,-0.41534 2.01829,-0.41534 0.37219,-0.0766 0.63629,-0.0115 0.79235,0.19532 0.15601,0.18689 0.23402,0.46947 0.23404,0.84774 -2e-5,0.35837 -0.0781,0.67311 -0.23404,0.9442 -0.15606,0.27114 -0.42016,0.44511 -0.79235,0.52194 0,0 -3.55138,0.73307 -3.55138,0.73307 m 0,-12.49741 c -0.70985,-0.19458 -1.46206,-0.29097 -2.25669,-0.2891 -0.79498,0.002 -1.63244,0.0922 -2.51243,0.27083 -2.20778,0.44829 -3.93465,1.58796 -5.17941,3.41949 -0.94315,1.37125 -1.41489,2.87666 -1.41489,4.51572 0,1.51915 0.35684,2.72513 1.07033,3.61771 0.72532,0.8898 1.77657,1.19268 3.15324,0.90903 1.31539,-0.27102 2.53349,-0.95103 3.65445,-2.03968 1.13235,-1.11048 2.29417,-2.73492 3.4854,-4.87285 0,0 0,-5.53115 0,-5.53115"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path6348"
|
||||
d="m 361.03362,169.73799 c 0,0 0,-4.57811 0,-4.57811 0,0 3.51111,-0.70203 3.51111,-0.70203 0.35609,-0.0712 0.61126,-0.003 0.76556,0.20328 0.15424,0.20673 0.23137,0.49814 0.23139,0.87424 -2e-5,0.35635 -0.0772,0.66876 -0.23139,0.93722 -0.1543,0.26853 -0.40947,0.4385 -0.76556,0.50991 0,0 -2.01322,0.40381 -2.01322,0.40381 0,0 0,24.93239 0,24.93239 -2e-5,1.66412 -0.21394,3.19438 -0.64182,4.59098 -0.28533,0.93124 -0.76094,1.93198 -1.42698,3.00242 -0.66629,1.07077 -1.27327,1.8618 -1.82089,2.37289 -0.5478,0.51123 -1.2804,0.8629 -2.198,1.05498 0,0 -4.25995,0.89161 -4.25995,0.89161 -0.3584,0.075 -0.61529,0.01 -0.77062,-0.19631 -0.15536,-0.18605 -0.23304,-0.46782 -0.23304,-0.8453 0,-0.37749 0.0777,-0.70165 0.23304,-0.9725 0.15533,-0.27081 0.41222,-0.44362 0.77062,-0.51839 0,0 4.31359,-0.87039 4.31359,-0.87039 0.88183,-0.18403 1.67398,-0.72615 2.37652,-1.6262 0.71418,-0.90221 1.3032,-2.12502 1.76716,-3.66839 0.26165,-0.88672 0.39248,-1.97415 0.39248,-3.26235 0,0 0,-7.49145 0,-7.49145 -1.60613,3.99699 -3.67816,6.25834 -6.21753,6.78211 -2.06489,0.42591 -3.85102,-0.4773 -5.35762,-2.71118 -1.49577,-2.25793 -2.24408,-5.18732 -2.24408,-8.78698 0,-3.59961 0.74831,-6.82288 2.24408,-9.66819 1.5066,-2.84552 3.29273,-4.47385 5.35762,-4.88629 2.53937,-0.50714 4.6114,0.90308 6.21753,4.22817 m 0,7.52118 c 0,-2.93314 -0.60662,-5.28816 -1.82036,-7.06588 -1.20261,-1.78115 -2.6443,-2.50382 -4.3256,-2.16698 -1.68272,0.33717 -3.12789,1.64976 -4.33499,3.9386 -1.20785,2.27039 -1.81204,4.86726 -1.81204,7.78958 0,2.94224 0.60419,5.31369 1.81204,7.11356 1.2071,1.77893 2.65227,2.49487 4.33499,2.14886 1.6813,-0.34572 3.12299,-1.65368 4.3256,-3.9231 1.21374,-2.29027 1.82036,-4.90147 1.82036,-7.83464"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path6350"
|
||||
d="m 385.85186,173.58032 c 0,0 -15.13765,3.07797 -15.13765,3.07797 0.26034,3.16944 1.06482,5.60432 2.41279,7.30409 1.35885,1.67644 3.03546,2.3087 5.02902,1.89796 1.10796,-0.22828 2.26831,-0.77304 3.48095,-1.634 1.21188,-0.86041 2.19967,-1.87147 2.96371,-3.03319 0.22326,-0.34131 0.41713,-0.52883 0.58164,-0.56257 0.18794,-0.0385 0.3524,0.0557 0.49337,0.2829 0.14092,0.20743 0.21138,0.47854 0.21141,0.81334 -3e-5,0.33482 -0.094,0.67909 -0.28188,1.03285 -0.56391,1.10093 -1.56872,2.23389 -3.01514,3.39933 -1.43573,1.14415 -2.91371,1.87353 -4.43406,2.18773 -2.54834,0.52665 -4.68036,-0.42556 -6.39472,-2.85877 -1.70402,-2.4575 -2.55658,-5.67472 -2.55657,-9.65009 -10e-6,-3.61935 0.79928,-6.88542 2.39688,-9.79647 1.60812,-2.91102 3.59284,-4.60156 5.95302,-5.07297 2.42802,-0.4849 4.42362,0.44725 5.9881,2.79462 1.5632,2.32586 2.3326,5.59781 2.30913,9.81727 m -1.49798,-2.20747 c -0.29388,-2.67927 -1.06987,-4.74949 -2.32855,-6.21109 -1.24773,-1.46483 -2.73778,-2.02412 -4.4707,-1.67694 -1.73447,0.34753 -3.22825,1.49618 -4.48082,3.44663 -1.25337,1.95173 -2.03418,4.35276 -2.34185,7.20251 0,0 13.62192,-2.76111 13.62192,-2.76111"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
<text
|
||||
@@ -844,7 +889,7 @@
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multiroot.png"
|
||||
transform="matrix(0.81677441,0,0,0.81677441,35.330746,48.494017)"
|
||||
transform="matrix(0.64605126,0,0,0.64605126,58.138831,104.45649)"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium"
|
||||
id="text10309">
|
||||
<path
|
||||
@@ -872,6 +917,134 @@
|
||||
d="m 233.61915,313.32443 c 0,0 4.86427,2.31094 4.86427,2.31094 0,0 -2.7e-4,5.00485 -2.7e-4,5.00485 1.71074,-3.52308 3.64965,-4.78093 5.82081,-3.75454 2.5118,1.18756 4.48297,4.13443 5.9036,8.84914 1.23117,4.03483 1.84851,9.9569 1.84853,17.75524 0,0 0,33.90579 0,33.90579 0,0 -5.07083,-2.83374 -5.07083,-2.83374 0,0 6.2e-4,-30.6586 6.2e-4,-30.6586 9e-5,-5.40954 -0.29652,-9.29502 -0.88902,-11.65343 -0.57668,-2.38426 -1.62396,-3.94697 -3.13732,-4.68877 -1.63768,-0.80262 -2.79522,0.005 -3.4777,2.41735 -0.6666,2.37712 -0.99957,6.93792 -0.99994,13.68633 0,0 -0.001,26.14439 -0.001,26.14439 0,0 -4.86529,-2.71887 -4.86529,-2.71887 0,0 0.004,-53.76608 0.004,-53.76608"
|
||||
id="path10326" />
|
||||
</g>
|
||||
<g
|
||||
style="display:none"
|
||||
inkscape:label="rwlayershort"
|
||||
id="layer3"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
inkscape:corner7="0.23104367 : -0.032927705 : 0.53664065 : 1"
|
||||
inkscape:corner0="0.51156871 : 0.026428054 : 0 : 1"
|
||||
inkscape:perspectiveID="#perspective4014"
|
||||
id="g11520"
|
||||
style="fill:#24b8eb;fill-opacity:0.64251206;stroke:#253237;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
sodipodi:type="inkscape:box3d">
|
||||
<path
|
||||
d="M 131.92561,229.48947 254.03226,279.93524 540.96513,197.86229 411.55236,171.87435 z"
|
||||
inkscape:box3dsidetype="13"
|
||||
style="fill:#24b8eb;fill-opacity:0.64251206;fill-rule:evenodd;stroke:none"
|
||||
id="path11530"
|
||||
sodipodi:type="inkscape:box3dside" />
|
||||
<path
|
||||
d="m 131.92561,190.22181 0,39.26766 279.62675,-57.61512 0,-28.97934 z"
|
||||
inkscape:box3dsidetype="6"
|
||||
style="fill:#24b8eb;fill-opacity:0.64251206;fill-rule:evenodd;stroke:none"
|
||||
id="path11522"
|
||||
sodipodi:type="inkscape:box3dside" />
|
||||
<path
|
||||
d="m 411.55236,142.89501 129.41277,21.38902 0,33.57826 -129.41277,-25.98794 z"
|
||||
inkscape:box3dsidetype="11"
|
||||
style="fill:#24b8eb;fill-opacity:0.64251206;fill-rule:evenodd;stroke:none"
|
||||
id="path11532"
|
||||
sodipodi:type="inkscape:box3dside" />
|
||||
<path
|
||||
d="M 131.92561,190.22181 254.03226,231.71944 540.96513,164.28403 411.55236,142.89501 z"
|
||||
inkscape:box3dsidetype="5"
|
||||
style="fill:#24b8eb;fill-opacity:0.64251206"
|
||||
id="path11524"
|
||||
sodipodi:type="inkscape:box3dside" />
|
||||
<path
|
||||
d="m 254.03226,231.71944 0,48.2158 286.93287,-82.07295 0,-33.57826 z"
|
||||
inkscape:box3dsidetype="14"
|
||||
style="fill:#24b8eb;fill-opacity:0.64251206"
|
||||
id="path11528"
|
||||
sodipodi:type="inkscape:box3dside" />
|
||||
<path
|
||||
d="m 131.92561,190.22181 122.10665,41.49763 0,48.2158 -122.10665,-50.44577 z"
|
||||
inkscape:box3dsidetype="3"
|
||||
style="fill:#24b8eb;fill-opacity:0.64251206"
|
||||
id="path11526"
|
||||
sodipodi:type="inkscape:box3dside" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.65426564,0,0,0.65426564,59.078784,80.39098)"
|
||||
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Italic"
|
||||
id="text12905">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 132.39162,196.56835 c 0,0 2.25832,0.79098 2.25832,0.79098 0,0 1.50732,28.61196 1.50732,28.61196 0,0 4.34598,-26.56183 4.34598,-26.56183 0,0 2.722,0.95339 2.722,0.95339 0,0 1.63516,29.08943 1.63516,29.08943 0,0 4.31997,-27.00363 4.31997,-27.00363 0,0 2.42221,0.84838 2.42221,0.84838 0,0 -5.66212,33.42382 -5.66212,33.42382 0,0 -2.73065,-1.12467 -2.73065,-1.12467 0,0 -1.5784,-29.68879 -1.5784,-29.68879 0,0 -4.4624,27.20079 -4.4624,27.20079 0,0 -2.67264,-1.10077 -2.67264,-1.10077 0,0 -2.10475,-35.43906 -2.10475,-35.43906"
|
||||
id="path12912" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 164.03604,213.26939 c -0.2639,-0.42447 -0.56258,-0.78434 -0.89592,-1.0796 -0.33304,-0.29492 -0.68661,-0.50929 -1.06059,-0.64322 -1.33705,-0.47863 -2.47231,0.33686 -3.4066,2.43656 -0.92991,2.06688 -1.50465,5.07325 -1.72714,9.01466 0,0 -1.04777,17.82424 -1.04777,17.82424 0,0 -2.42011,-0.99676 -2.42011,-0.99676 0,0 1.98378,-35.17658 1.98378,-35.17658 0,0 2.47527,0.86697 2.47527,0.86697 0,0 -0.33507,5.56959 -0.33507,5.56959 0.60533,-1.89455 1.35104,-3.25595 2.23803,-4.08114 0.89961,-0.82526 1.87507,-1.05633 2.92646,-0.68969 0.27488,0.0959 0.54641,0.23479 0.81455,0.4165 0.26786,0.15981 0.53715,0.37533 0.80786,0.64667 0,0 -0.35275,5.89174 -0.35275,5.89174"
|
||||
id="path12914" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 167.87077,194.36999 c 0,0 2.5978,0.8462 2.5978,0.8462 0,0 -0.48615,7.70745 -0.48615,7.70745 0,0 -2.58509,-0.87602 -2.58509,-0.87602 0,0 0.47344,-7.67763 0.47344,-7.67763 m -0.87992,14.31682 c 0,0 2.57415,0.9016 2.57415,0.9016 0,0 -2.30324,35.91396 -2.30324,35.91396 0,0 -2.5149,-1.0358 -2.5149,-1.0358 0,0 2.24399,-35.77976 2.24399,-35.77976"
|
||||
id="path12916" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 183.34977,214.41656 c 0,0 -0.34194,4.75863 -0.34194,4.75863 0,0 -5.33307,-1.91046 -5.33307,-1.91046 0,0 -1.36427,19.81122 -1.36427,19.81122 -0.0441,0.73284 -0.076,1.34864 -0.0958,1.84769 -0.0198,0.49879 -0.0272,0.89218 -0.0223,1.18025 0.024,1.41732 0.22117,2.51814 0.59164,3.30404 0.38018,0.79025 0.97369,1.34835 1.78193,1.67447 0,0 2.66812,1.07661 2.66812,1.07661 0,0 -0.36838,4.94638 -0.36838,4.94638 0,0 -2.51686,-1.03661 -2.51686,-1.03661 -1.55308,-0.63966 -2.72009,-1.81877 -3.50617,-3.53794 -0.77559,-1.71295 -1.18868,-3.99849 -1.24016,-6.86324 -0.009,-0.50749 -0.005,-1.05378 0.0125,-1.63897 0.0171,-0.60759 0.0472,-1.26529 0.0905,-1.97325 0,0 1.33026,-19.73599 1.33026,-19.73599 0,0 -2.21945,-0.79507 -2.21945,-0.79507 0,0 0.32464,-4.68341 0.32464,-4.68341 0,0 2.18338,0.76473 2.18338,0.76473 0,0 0.70719,-10.54703 0.70719,-10.54703 0,0 2.66503,0.88587 2.66503,0.88587 0,0 -0.71095,10.59328 -0.71095,10.59328 0,0 5.36413,1.8788 5.36413,1.8788"
|
||||
id="path12918" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 199.13849,236.70883 c 0,0 -1.72385,21.2125 -1.72385,21.2125 0,0 -2.77523,-1.14302 -2.77523,-1.14302 0,0 0.45537,-5.5694 0.45537,-5.5694 -0.79039,1.93977 -1.69787,3.25939 -2.72178,3.963 -1.00998,0.68226 -2.14049,0.76306 -3.39088,0.2461 -1.4019,-0.5796 -2.56171,-2.02483 -3.48324,-4.3353 -0.91085,-2.32565 -1.3871,-5.01869 -1.42975,-8.08698 -0.0612,-4.40249 0.65095,-7.60298 2.1444,-9.6005 1.51381,-2.0078 3.64053,-2.5073 6.39035,-1.48111 0,0 3.88091,1.44834 3.88091,1.44834 0,0 0.13737,-1.64241 0.13737,-1.64241 0.0187,-0.17753 0.0322,-0.36859 0.0405,-0.57316 0.008,-0.22771 0.0101,-0.57318 0.006,-1.03646 -0.0184,-2.06353 -0.40494,-3.80038 -1.15864,-5.20652 -0.74267,-1.42355 -1.7772,-2.37178 -3.10017,-2.84471 -0.90567,-0.32369 -1.83075,-0.39003 -2.77476,-0.20023 -0.93078,0.19278 -1.88487,0.63805 -2.86168,1.33418 0,0 0.40119,-5.68296 0.40119,-5.68296 1.0224,-0.5343 2.0267,-0.84843 3.0124,-0.94098 0.99899,-0.11252 1.96874,-0.005 2.90868,0.32235 2.01064,0.70123 3.55659,2.24252 4.62956,4.62368 1.08518,2.38922 1.64359,5.50025 1.67366,9.32128 0.006,0.76751 -0.0125,1.66447 -0.0556,2.69043 -0.0433,1.00181 -0.11156,2.06254 -0.20482,3.18188 m -3.01967,1.47698 c 0,0 -2.78542,-1.06163 -2.78542,-1.06163 -2.2624,-0.86226 -3.92041,-0.80292 -4.98268,0.16995 -1.04789,0.94964 -1.55167,2.85777 -1.51494,5.72282 0.0254,1.98149 0.31466,3.64088 0.8682,4.98133 0.56384,1.34561 1.32816,2.21415 2.29484,2.60564 1.48548,0.60158 2.77591,-0.0812 3.87044,-2.05855 1.10034,-2.01109 1.81516,-5.00707 2.14096,-8.99265 0,0 0.1086,-1.36691 0.1086,-1.36691"
|
||||
id="path12920" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 217.64994,242.08214 c -0.003,-3.45467 -0.36941,-6.29845 -1.09988,-8.52314 -0.71911,-2.21914 -1.712,-3.55453 -2.9753,-4.006 -0.9147,-0.32682 -1.77169,-0.13384 -2.57095,0.57649 -0.7861,0.6882 -1.46696,1.86026 -2.04305,3.51377 -0.60552,1.7306 -1.08098,3.81943 -1.42712,6.2652 -0.33468,2.41877 -0.49538,4.89667 -0.48288,7.43549 0.0158,3.20708 0.36798,5.85818 1.05704,7.96044 0.69992,2.08483 1.65443,3.37263 2.86659,3.86366 0.92007,0.37271 1.77251,0.25313 2.55721,-0.36105 0.78714,-0.63948 1.47963,-1.76427 2.07706,-3.37684 0.61006,-1.68425 1.10315,-3.73887 1.47858,-6.16534 0.37661,-2.43421 0.56447,-4.82931 0.5627,-7.18268 m -9.23169,-12.84717 c 0.71257,-1.9212 1.61108,-3.31025 2.69696,-4.16424 1.10132,-0.8778 2.25765,-1.10762 3.46876,-0.68529 1.8688,0.65177 3.36054,2.56955 4.46812,5.75349 1.11991,3.19191 1.67936,7.16826 1.67728,11.91278 -0.002,3.86886 -0.33149,7.48101 -0.9869,10.83305 -0.64142,3.34015 -1.55578,6.15428 -2.74017,8.44433 -0.7715,1.50955 -1.65836,2.54577 -2.65987,3.1114 -0.99765,0.5634 -2.04044,0.61881 -3.12849,0.16897 -1.14744,-0.4744 -2.14129,-1.46065 -2.98356,-2.95812 -0.84085,-1.4949 -1.52693,-3.4884 -2.05939,-5.98273 0,0 -0.48266,5.66038 -0.48266,5.66038 0,0 -2.84889,-1.17336 -2.84889,-1.17336 0,0 4.44431,-52.94734 4.44431,-52.94734 0,0 2.95322,0.96198 2.95322,0.96198 0,0 -1.81872,21.0647 -1.81872,21.0647"
|
||||
id="path12922" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 228.71944,214.19071 c 0,0 3.15615,1.02808 3.15615,1.02808 0,0 -5.33605,54.69811 -5.33605,54.69811 0,0 -3.03879,-1.25157 -3.03879,-1.25157 0,0 5.21869,-54.47462 5.21869,-54.47462"
|
||||
id="path12924" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 249.07211,254.74636 c 0.0404,-0.38368 0.0691,-0.78443 0.0859,-1.20226 0.0288,-0.41348 0.0457,-0.83161 0.0506,-1.25434 0.0353,-3.03778 -0.36798,-5.60275 -1.20915,-7.68768 -0.82831,-2.07819 -1.97429,-3.37815 -3.43389,-3.89992 -1.61834,-0.57843 -3.05045,-0.009 -4.29713,1.70059 -1.23987,1.67549 -2.18445,4.34652 -2.83626,8.00619 0,0 11.63988,4.33748 11.63988,4.33748 m 2.81056,6.45167 c 0,0 -15.09094,-5.79069 -15.09094,-5.79069 -0.0752,0.89703 -0.126,1.60789 -0.15253,2.13298 -0.0265,0.52486 -0.0411,0.98119 -0.0437,1.36905 -0.0225,3.36482 0.44677,6.15468 1.40888,8.37881 0.97504,2.23208 2.36307,3.71384 4.1703,4.44572 1.39681,0.56568 2.72662,0.77468 3.98908,0.62476 1.26781,-0.15056 2.45566,-0.64338 3.56302,-1.48066 0,0 -0.70189,6.42657 -0.70189,6.42657 -1.18125,0.49488 -2.39603,0.72794 -3.64426,0.70088 -1.23153,-0.0222 -2.4791,-0.29519 -3.74285,-0.81767 -2.68557,-1.11031 -4.73074,-3.28927 -6.14928,-6.53818 -1.40393,-3.26112 -2.09137,-7.34961 -2.06451,-12.28511 0.023,-4.22844 0.39788,-8.03395 1.12728,-11.41867 0.74471,-3.42191 1.82516,-6.33485 3.24539,-8.73744 0.92003,-1.50587 2.01004,-2.53659 3.27144,-3.08937 1.27888,-0.55109 2.63589,-0.57813 4.0712,-0.0776 2.26618,0.79035 4.06153,2.85633 5.37632,6.19826 1.32912,3.35217 1.96352,7.4395 1.9016,12.24399 -0.0148,1.14841 -0.0669,2.36942 -0.15622,3.66262 -0.0889,1.26675 -0.21507,2.6175 -0.37835,4.05176"
|
||||
id="path12926" />
|
||||
</g>
|
||||
<g
|
||||
id="text14746"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New"
|
||||
transform="matrix(1.1734694,0,0,1.1734694,-48.893189,-48.489991)">
|
||||
<path
|
||||
id="path14753"
|
||||
d="m 292.56742,237.4772 c 0,0 0,-1.59047 0,-1.59047 -1e-5,-0.5391 0.0453,-0.93633 0.13582,-1.19161 0.0987,-0.25714 0.22627,-0.40435 0.38255,-0.44167 0.1562,-0.0372 0.27949,0.0501 0.36989,0.26184 0.0986,0.20984 0.14786,0.58398 0.14787,1.12245 0,0 0,6.27362 0,6.27362 -10e-6,0.55648 -0.0493,0.96364 -0.14787,1.22152 -0.0904,0.25592 -0.21369,0.40336 -0.36989,0.44226 -0.13983,0.0349 -0.25912,-0.0432 -0.35786,-0.23424 -0.0906,-0.1931 -0.14406,-0.53022 -0.16051,-1.01139 -0.0412,-1.49945 -0.41597,-2.74678 -1.12524,-3.74312 -0.95853,-1.37023 -2.0518,-1.9091 -3.28082,-1.61375 -0.80737,0.19408 -1.57032,0.76646 -2.2886,1.71804 -0.5353,0.69109 -0.96233,1.48343 -1.28077,2.37687 -0.55364,1.55049 -0.99453,3.22917 -1.32232,5.0356 -0.2355,1.33038 -0.35329,2.79525 -0.35329,4.3941 0,0 0,4.00625 0,4.00625 0,3.41577 0.57185,6.23436 1.71333,8.4515 1.13855,2.19332 2.4576,3.08294 3.95555,2.67411 0.89633,-0.24464 1.69568,-0.88624 2.39858,-1.92393 0.71,-1.03826 1.39417,-2.49958 2.05261,-4.38314 0.13978,-0.41447 0.29596,-0.64466 0.46853,-0.69065 0.14784,-0.0394 0.26691,0.0276 0.35722,0.20089 0.0903,0.17329 0.13541,0.41244 0.13543,0.71743 -2e-5,0.41269 -0.17649,1.08812 -0.52962,2.02685 -0.67425,1.83488 -1.43607,3.29166 -2.28591,4.36978 -0.84324,1.0599 -1.70051,1.71048 -2.57191,1.95056 -0.75663,0.20846 -1.52704,0.10426 -2.31133,-0.31343 -0.60168,-0.3239 -1.09951,-0.75841 -1.49315,-1.30354 -0.394,-0.54561 -0.88069,-1.51132 -1.46037,-2.89811 -0.57203,-1.40902 -0.96363,-2.74066 -1.1743,-3.99402 -0.21078,-1.27211 -0.3162,-2.69969 -0.3162,-4.28229 0,0 0,-4.6659 0,-4.6659 0,-2.25562 0.27827,-4.62592 0.83428,-7.1086 0.56373,-2.49973 1.32824,-4.49134 2.29251,-5.97481 0.97053,-1.50028 2.01815,-2.3831 3.14231,-2.65042 1.72644,-0.41045 3.20678,0.51535 4.44348,2.77142"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path14755"
|
||||
d="m 308.66695,250.09217 c -10e-6,3.3873 -0.5478,6.4277 -1.64547,9.12638 -1.09249,2.70338 -2.41593,4.27147 -3.97244,4.7003 -1.57825,0.43483 -2.92347,-0.40609 -4.03348,-2.528 -1.11284,-2.14518 -1.67032,-4.92676 -1.67032,-8.34065 0,-3.43174 0.55748,-6.50462 1.67032,-9.21347 1.11001,-2.71971 2.45523,-4.27243 4.03348,-4.66229 1.55651,-0.38443 2.87995,0.49215 3.97244,2.62466 1.09767,2.12517 1.64546,4.88816 1.64547,8.29307 m -1.01277,0.2646 c -10e-6,-2.7907 -0.44957,-5.05158 -1.35007,-6.78534 -0.89442,-1.73935 -1.98297,-2.45048 -3.26712,-2.12996 -1.28798,0.32151 -2.38981,1.59368 -3.30406,3.8193 -0.90806,2.21042 -1.3628,4.71879 -1.36279,7.52165 -10e-6,2.78505 0.45473,5.0558 1.36279,6.80955 0.91425,1.7479 2.01608,2.44432 3.30406,2.09279 1.28415,-0.35048 2.3727,-1.63042 3.26712,-3.83716 0.9005,-2.22197 1.35006,-4.71775 1.35007,-7.49083"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path14757"
|
||||
d="m 314.42401,237.15342 c 0,0 0,3.33838 0,3.33838 0.68834,-1.73173 1.30925,-2.96305 1.86301,-3.69535 0.55304,-0.7313 1.17532,-1.18207 1.86656,-1.35283 0.74434,-0.18383 1.42164,0.006 2.03224,0.56853 0.43228,0.41464 0.82174,1.18719 1.16849,2.31729 0.35414,1.10991 0.53111,2.29857 0.53112,3.56668 0,0 0,13.7844 0,13.7844 0,0 0.81847,-0.22256 0.81847,-0.22256 0.23026,-0.0626 0.39521,-0.003 0.49492,0.17762 0.0997,0.16363 0.14951,0.41019 0.14952,0.73967 -1e-5,0.31216 -0.0499,0.58594 -0.14952,0.82137 -0.0997,0.23549 -0.26466,0.38485 -0.49492,0.44805 0,0 -2.59918,0.71347 -2.59918,0.71347 -0.23955,0.0658 -0.40963,0.008 -0.51015,-0.17349 -0.10057,-0.18148 -0.15085,-0.42903 -0.15085,-0.74263 0,-0.331 0.0503,-0.60603 0.15085,-0.82505 0.10052,-0.23636 0.2706,-0.3871 0.51015,-0.45224 0,0 0.81034,-0.22035 0.81034,-0.22035 0,0 0,-13.43494 0,-13.43494 -10e-6,-1.54782 -0.25067,-2.78882 -0.75241,-3.72384 -0.50236,-0.9535 -1.17565,-1.32537 -2.02071,-1.11445 -0.64462,0.16091 -1.20459,0.59773 -1.67958,1.31084 -0.47553,0.69646 -1.15466,2.32016 -2.03835,4.87447 0,0 0,13.85296 0,13.85296 0,0 1.1141,-0.30294 1.1141,-0.30294 0.23417,-0.0637 0.40192,-0.004 0.50332,0.17797 0.10137,0.16478 0.15204,0.4133 0.15205,0.74557 -1e-5,0.31479 -0.0507,0.59099 -0.15205,0.82865 -0.1014,0.23771 -0.26915,0.38871 -0.50332,0.45299 0,0 -3.22119,0.88421 -3.22119,0.88421 -0.23607,0.0648 -0.40534,0.006 -0.50771,-0.17703 -0.10241,-0.18288 -0.15362,-0.43257 -0.15362,-0.74903 0,-0.33403 0.0512,-0.61171 0.15362,-0.83298 0.10237,-0.23878 0.27164,-0.39025 0.50771,-0.45445 0,0 1.11958,-0.30443 1.11958,-0.30443 0,0 0,-18.34278 0,-18.34278 0,0 -0.83646,0.20956 -0.83646,0.20956 -0.23592,0.0591 -0.40507,-0.004 -0.50738,-0.18919 -0.10234,-0.18526 -0.15352,-0.4449 -0.15351,-0.77884 -10e-6,-0.31633 0.0512,-0.59268 0.15351,-0.829 0.10231,-0.23622 0.27146,-0.38357 0.50738,-0.44208 0,0 1.82397,-0.4522 1.82397,-0.4522"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path14759"
|
||||
d="m 329.72799,233.35924 c 0,0 5.13345,-1.27269 5.13345,-1.27269 0.22371,-0.0554 0.38397,0.007 0.48085,0.18852 0.0968,0.18111 0.14525,0.43402 0.14526,0.75877 -10e-6,0.30771 -0.0485,0.57622 -0.14526,0.80555 -0.0969,0.22944 -0.25714,0.37217 -0.48085,0.4282 0,0 -5.13345,1.28608 -5.13345,1.28608 0,0 0,14.43158 0,14.43158 -10e-6,1.25643 0.21891,2.24711 0.65643,2.97148 0.44458,0.72157 1.09178,0.96605 1.94066,0.73436 0.6374,-0.17396 1.32621,-0.5761 2.06616,-1.20576 0.73864,-0.64564 1.31224,-1.29704 1.72148,-1.95454 0.1487,-0.2622 0.27135,-0.40633 0.36797,-0.43241 0.11885,-0.0321 0.22284,0.0507 0.31196,0.24856 0.0891,0.18071 0.13361,0.41608 0.13362,0.70616 -10e-6,0.25597 -0.0483,0.50799 -0.14476,0.75609 -0.23768,0.62804 -0.81757,1.40124 -1.74108,2.32087 -0.91812,0.90249 -1.8008,1.47097 -2.64781,1.70434 -1.10446,0.30428 -1.98559,-0.0463 -2.64198,-1.05341 -0.65743,-1.00874 -0.98654,-2.52169 -0.98653,-4.53773 0,0 0,-14.44811 0,-14.44811 0,0 -1.76335,0.44177 -1.76335,0.44177 -0.22807,0.0572 -0.39159,-0.006 -0.4905,-0.18811 -0.0989,-0.18257 -0.1484,-0.43805 -0.14839,-0.7664 -1e-5,-0.31102 0.0494,-0.58251 0.14839,-0.81445 0.0989,-0.23183 0.26243,-0.37601 0.4905,-0.43258 0,0 1.76335,-0.43717 1.76335,-0.43717 0,0 0,-6.4099 0,-6.4099 -1e-5,-0.51689 0.0454,-0.89822 0.13621,-1.14394 0.0908,-0.24561 0.20423,-0.38466 0.34033,-0.41716 0.14361,-0.0342 0.26073,0.0498 0.35139,0.25184 0.0906,0.20213 0.13594,0.56133 0.13595,1.07763 0,0 0,6.40256 0,6.40256"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path14761"
|
||||
d="m 347.92414,250.72178 c 0,0 0,-3.05626 0,-3.05626 -1.32486,2.95612 -2.74493,4.64604 -4.26117,5.06378 -1.10424,0.30423 -1.9692,-0.10219 -2.59338,-1.22112 -0.62513,-1.1376 -0.93805,-2.65046 -0.93805,-4.53728 0,-2.07378 0.41226,-3.99242 1.23557,-5.75329 0.82167,-1.75736 2.01824,-2.83768 3.58648,-3.24242 0.42203,-0.10891 0.87997,-0.15956 1.37368,-0.15206 0.49311,-0.009 1.02545,0.0469 1.59687,0.16843 0,0 0,-3.43514 0,-3.43514 -1e-5,-1.16186 -0.23137,-2.11384 -0.69447,-2.85657 -0.46365,-0.7435 -1.16008,-0.99968 -2.09048,-0.76745 -0.71376,0.17817 -1.7173,0.9112 -3.01271,2.20186 -0.23464,0.22862 -0.38501,0.35128 -0.45105,0.36788 -0.11743,0.0296 -0.22021,-0.0464 -0.30832,-0.22792 -0.0808,-0.18338 -0.12119,-0.42787 -0.12118,-0.73345 -10e-6,-0.28856 0.0367,-0.52691 0.11017,-0.715 0.10279,-0.2802 0.51741,-0.73128 1.24291,-1.35247 1.14063,-0.994 2.00133,-1.56201 2.58384,-1.70592 1.1553,-0.28533 2.05404,0.15837 2.69792,1.32913 0.64285,1.15216 0.9639,2.56014 0.96391,4.22531 0,0 0,14.02795 0,14.02795 0,0 1.20981,-0.32897 1.20981,-0.32897 0.22283,-0.0606 0.38091,-0.003 0.4743,0.17316 0.0933,0.15921 0.14002,0.39824 0.14004,0.7171 -2e-5,0.3021 -0.0467,0.56663 -0.14004,0.79361 -0.0934,0.22705 -0.25147,0.37117 -0.4743,0.43233 0,0 -2.13035,0.58478 -2.13035,0.58478 m 0,-10.558 c -0.42669,-0.17475 -0.87915,-0.26722 -1.35749,-0.27728 -0.47891,-0.0101 -0.9838,0.054 -1.51479,0.19244 -1.33413,0.34776 -2.37964,1.28966 -3.13434,2.82696 -0.57244,1.15204 -0.85896,2.42481 -0.85896,3.81711 0,1.29044 0.21674,2.31854 0.64989,3.0837 0.44002,0.76238 1.07722,1.02935 1.9107,0.80187 0.79534,-0.21708 1.53095,-0.78111 2.20715,-1.69129 0.68232,-0.92751 1.38163,-2.28814 2.09784,-4.08071 0,0 0,-4.6728 0,-4.6728"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path14763"
|
||||
d="m 358.9208,215.38083 c 0,0 0,5.40783 0,5.40783 0,0 -1.31083,0.31638 -1.31083,0.31638 0,0 0,-5.41657 0,-5.41657 0,0 1.31083,-0.30764 1.31083,-0.30764 m 0.0317,10.73306 c 0,0 0,19.48737 0,19.48737 0,0 3.46775,-0.94294 3.46775,-0.94294 0.21618,-0.0588 0.36953,-0.001 0.46013,0.17246 0.0906,0.15719 0.13584,0.39281 0.13585,0.70687 -1e-5,0.29756 -0.0453,0.5579 -0.13585,0.7811 -0.0906,0.22326 -0.24395,0.36455 -0.46013,0.42389 0,0 -7.86049,2.15769 -7.86049,2.15769 -0.21341,0.0586 -0.36643,3.5e-4 -0.45897,-0.17483 -0.0926,-0.1752 -0.13887,-0.41325 -0.13887,-0.71413 0,-0.31759 0.0463,-0.58094 0.13887,-0.79001 0.0925,-0.22573 0.24556,-0.36759 0.45897,-0.42562 0,0 3.50529,-0.95316 3.50529,-0.95316 0,0 0,-17.38816 0,-17.38816 0,0 -2.59952,0.65125 -2.59952,0.65125 -0.21294,0.0534 -0.36917,-0.008 -0.46862,-0.1831 -0.0924,-0.17722 -0.13856,-0.41614 -0.13855,-0.71671 -1e-5,-0.31722 0.0462,-0.58749 0.13855,-0.81081 0.0924,-0.22321 0.24857,-0.36209 0.46862,-0.41667 0,0 3.48697,-0.86449 3.48697,-0.86449"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path14765"
|
||||
d="m 368.46442,223.75567 c 0,0 0,3.12776 0,3.12776 0.60425,-1.6123 1.14936,-2.75688 1.63557,-3.43494 0.4856,-0.67719 1.03206,-1.09054 1.63914,-1.24051 0.65376,-0.16146 1.24872,0.0263 1.78514,0.56245 0.37979,0.39496 0.72197,1.12482 1.02665,2.18925 0.31119,1.04566 0.4667,2.16256 0.46671,3.35132 0,0 0,12.92183 0,12.92183 0,0 0.71929,-0.19559 0.71929,-0.19559 0.20237,-0.055 0.34735,0.003 0.43499,0.17441 0.0876,0.155 0.13141,0.38695 0.13142,0.69584 -1e-5,0.29266 -0.0438,0.54854 -0.13142,0.76765 -0.0876,0.21918 -0.23262,0.35655 -0.43499,0.4121 0,0 -2.28391,0.62693 -2.28391,0.62693 -0.21044,0.0578 -0.35985,8.6e-4 -0.44816,-0.17084 -0.0883,-0.17172 -0.13252,-0.40454 -0.13251,-0.69846 -1e-5,-0.31023 0.0442,-0.56721 0.13251,-0.77087 0.0883,-0.21993 0.23772,-0.3585 0.44816,-0.41572 0,0 0.71195,-0.19359 0.71195,-0.19359 0,0 0,-12.59334 0,-12.59334 0,-1.45086 -0.22023,-2.61784 -0.66105,-3.50168 -0.44133,-0.90112 -1.03277,-1.25955 -1.77501,-1.0743 -0.56613,0.14133 -1.05787,0.54243 -1.47496,1.20365 -0.41753,0.64556 -1.01377,2.15684 -1.78952,4.5368 0,0 0,12.97896 0,12.97896 0,0 0.97803,-0.26595 0.97803,-0.26595 0.20559,-0.0559 0.35287,0.002 0.4419,0.17485 0.089,0.15603 0.1335,0.38972 0.1335,0.70106 0,0.29497 -0.0445,0.55297 -0.1335,0.77401 -0.089,0.2211 -0.23631,0.35987 -0.4419,0.41631 0,0 -2.82735,0.7761 -2.82735,0.7761 -0.20715,0.0569 -0.35568,-0.001 -0.44551,-0.17409 -0.0899,-0.17297 -0.13479,-0.40769 -0.13479,-0.70413 0,-0.31289 0.0449,-0.57216 0.13479,-0.77778 0.0898,-0.22202 0.23836,-0.36119 0.44551,-0.41752 0,0 0.98254,-0.26717 0.98254,-0.26717 0,0 0,-17.18426 0,-17.18426 0,0 -0.73409,0.18391 -0.73409,0.18391 -0.20703,0.0519 -0.35546,-0.01 -0.44524,-0.18475 -0.0898,-0.17506 -0.13471,-0.41902 -0.13471,-0.73184 0,-0.29632 0.0449,-0.55442 0.13471,-0.7743 0.0898,-0.21977 0.23821,-0.35532 0.44524,-0.40667 0,0 1.60087,-0.39689 1.60087,-0.39689"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path14767"
|
||||
d="m 388.11235,229.76789 c 0,0 -8.48758,2.22224 -8.48758,2.22224 0.14697,2.60006 0.60091,4.60711 1.36077,6.01981 0.76503,1.39207 1.70765,1.93407 2.82657,1.62868 0.62097,-0.16949 1.27063,-0.59601 1.94883,-1.27892 0.67702,-0.6817 1.22829,-1.48892 1.65434,-2.42175 0.12444,-0.27395 0.23249,-0.42323 0.32414,-0.44789 0.10471,-0.0282 0.19631,0.0513 0.27482,0.23843 0.0785,0.17107 0.11771,0.39273 0.11772,0.665 -10e-6,0.27228 -0.0523,0.55072 -0.15697,0.83539 -0.31413,0.88653 -0.87429,1.79282 -1.68153,2.71981 -0.80235,0.91103 -1.62941,1.48439 -2.48135,1.71911 -1.43066,0.39416 -2.63019,-0.41452 -3.59644,-2.43084 -0.96193,-2.03924 -1.44377,-4.68961 -1.44377,-7.94738 0,-2.96601 0.45175,-5.62524 1.35369,-7.97367 0.90655,-2.34471 2.02355,-3.67918 3.34919,-4.00664 1.36076,-0.33608 2.47689,0.47235 3.35047,2.42115 0.87162,1.92849 1.30016,4.60654 1.2871,8.03747 m -0.83466,-1.82578 c -0.16388,-2.18666 -0.59682,-3.88887 -1.29971,-5.10755 -0.69758,-1.2225 -1.5317,-1.71355 -2.5032,-1.47106 -0.97392,0.24311 -1.81394,1.14718 -2.51921,2.71386 -0.70654,1.5695 -1.1471,3.51858 -1.32078,5.8459 0,0 7.6429,-1.98115 7.6429,-1.98115"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path14769"
|
||||
d="m 394.65863,217.26158 c 0,0 0,5.05071 0,5.05071 1.05317,-2.61538 1.83796,-4.31797 2.35603,-5.11227 0.52374,-0.81061 1.00534,-1.26991 1.44497,-1.37865 0.47726,-0.11799 0.91902,0.17532 1.32537,0.87929 0.41225,0.68589 0.61821,1.23352 0.61822,1.64339 -10e-6,0.29956 -0.0412,0.56219 -0.12356,0.78788 -0.0761,0.20844 -0.17434,0.32787 -0.29482,0.35828 -0.0634,0.016 -0.11736,0.006 -0.16176,-0.0302 -0.0444,-0.0519 -0.12694,-0.21251 -0.24755,-0.48199 -0.2223,-0.49656 -0.41611,-0.82689 -0.58139,-0.99082 -0.16538,-0.16396 -0.32763,-0.22611 -0.48676,-0.18636 -0.35034,0.0875 -0.77435,0.54152 -1.27228,1.36266 -0.49218,0.82062 -1.35019,2.74163 -2.57647,5.76941 0,0 0,10.95911 0,10.95911 0,0 3.57169,-0.97122 3.57169,-0.97122 0.19745,-0.0537 0.33753,0.003 0.42029,0.17013 0.0827,0.15127 0.12408,0.37699 0.12409,0.67715 -10e-6,0.28439 -0.0414,0.53269 -0.12409,0.74496 -0.0828,0.21232 -0.22284,0.34558 -0.42029,0.39978 0,0 -6.34991,1.74303 -6.34991,1.74303 -0.19434,0.0533 -0.33368,0.004 -0.41796,-0.14841 -0.0843,-0.16829 -0.12645,-0.396 -0.12645,-0.68312 0,-0.27115 0.0389,-0.50507 0.11673,-0.70172 0.0843,-0.21431 0.22686,-0.34878 0.42768,-0.40341 0,0 1.96714,-0.53508 1.96714,-0.53508 0,0 0,-16.69431 0,-16.69431 0,0 -1.5011,0.37607 -1.5011,0.37607 -0.19412,0.0486 -0.33329,-0.0121 -0.41746,-0.18232 -0.0842,-0.17019 -0.1263,-0.40677 -0.1263,-0.70967 0,-0.28692 0.0389,-0.53569 0.11658,-0.7463 0.0842,-0.21212 0.22659,-0.34304 0.42718,-0.3928 0,0 2.31218,-0.57324 2.31218,-0.57324"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer6"
|
||||
@@ -922,64 +1095,7 @@
|
||||
d="m 133.59629,56.078359 119.50583,10.663536 0,64.052605 -119.50583,-22.31404 z" />
|
||||
</g>
|
||||
<g
|
||||
id="text5935"
|
||||
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;text-align:center;line-height:88.99999857%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium Italic"
|
||||
transform="matrix(0.82611672,0,0,0.82611672,33.620121,15.579543)">
|
||||
<path
|
||||
id="path5944"
|
||||
d="m 153.83888,67.902732 c 0,0 -8.49364,12.847003 -8.49364,12.847003 0,0 -2.61139,-8.338168 -2.61139,-8.338168 0,0 -4.57259,7.39592 -4.57259,7.39592 0,0 -4.56493,-14.065601 -4.56493,-14.065601 0,0 3.1018,0.33111 3.1018,0.33111 0,0 2.23127,7.74856 2.23127,7.74856 0,0 4.57156,-7.36476 4.57156,-7.36476 0,0 2.48012,8.212597 2.48012,8.212597 0,0 4.3089,-7.145498 4.3089,-7.145498 0,0 3.5489,0.378837 3.5489,0.378837"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5946"
|
||||
d="m 159.48544,68.50549 c 0,0 -0.14506,1.081269 -0.14506,1.081269 1.08487,-0.840755 2.18357,-1.203434 3.29625,-1.085323 0.97953,0.104001 1.8738,0.531365 2.68199,1.28339 0,0 -2.07994,2.256579 -2.07994,2.256579 -0.59715,-0.539033 -1.19307,-0.84117 -1.78775,-0.907144 -0.40876,-0.04533 -0.76837,-0.0083 -1.07903,0.110906 -0.31032,0.110074 -0.58159,0.314687 -0.81388,0.613752 -0.22246,0.290909 -0.41092,0.680177 -0.56546,1.167777 -0.14482,0.48847 -0.26061,1.079247 -0.34742,1.772359 0,0 -0.83785,6.248278 -0.83785,6.248278 0,0 -3.17048,-0.408479 -3.17048,-0.408479 0,0 1.65969,-12.473776 1.65969,-12.473776 0,0 3.18894,0.340412 3.18894,0.340412"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5948"
|
||||
d="m 172.11804,63.653761 c -1e-5,0.442892 -0.17671,0.808538 -0.52981,1.096682 -0.35269,0.287833 -0.77536,0.407208 -1.2677,0.358444 -0.49153,-0.04865 -0.91718,-0.256105 -1.27725,-0.622096 -0.34966,-0.382881 -0.52433,-0.798829 -0.52434,-1.248191 0,-0.449323 0.16967,-0.813819 0.50932,-1.093731 0.35004,-0.288441 0.76564,-0.410358 1.24707,-0.365433 0.49226,0.04598 0.9199,0.256324 1.28263,0.631329 0.37326,0.367241 0.56007,0.781688 0.56008,1.242996 m -1.04355,6.088833 c 0,0 -1.74605,12.789101 -1.74605,12.789101 0,0 -3.29826,-0.42494 -3.29826,-0.42494 0,0 1.72648,-12.718331 1.72648,-12.718331 0,0 3.31783,0.35417 3.31783,0.35417"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5950"
|
||||
d="m 179.01592,73.460646 c 0,0 -1.40778,10.137791 -1.40778,10.137791 0,0 -3.39162,-0.436971 -3.39162,-0.436971 0,0 1.39178,-10.080958 1.39178,-10.080958 0,0 -1.91023,-0.213095 -1.91023,-0.213095 0,0 0.38104,-2.804082 0.38104,-2.804082 0,0 1.91269,0.204175 1.91269,0.204175 0,0 0.83006,-6.00759 0.83006,-6.00759 0,0 3.4216,0.330185 3.4216,0.330185 0,0 -0.83963,6.041632 -0.83963,6.041632 0,0 3.18456,0.339944 3.18456,0.339944 0,0 -0.39206,2.843759 -0.39206,2.843759 0,0 -3.18041,-0.35479 -3.18041,-0.35479"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5952"
|
||||
d="m 200.09628,72.840604 c 0,0 -1.92201,13.407533 -1.92201,13.407533 0,0 -3.62916,-0.467574 -3.62916,-0.467574 0,0 0.21229,-1.438465 0.21229,-1.438465 -1.54259,0.989936 -3.13133,1.376921 -4.76545,1.165541 -1.99844,-0.258505 -3.61848,-1.068102 -4.86609,-2.425845 -1.24247,-1.352149 -1.8618,-2.975618 -1.86182,-4.874587 -2e-5,-2.19038 0.70861,-3.906541 2.1309,-5.152891 1.45025,-1.249951 3.31827,-1.756081 5.61179,-1.512503 1.08847,0.115618 2.01837,0.372012 2.78823,0.769622 0.78266,0.399806 1.58371,1.032558 2.40329,1.899222 0,0 0.24627,-1.759869 0.24627,-1.759869 0,0 3.65176,0.389816 3.65176,0.389816 m -4.43914,5.916099 c -2e-5,-1.199313 -0.393,-2.217808 -1.17742,-3.05388 -0.78244,-0.843484 -1.79012,-1.332653 -3.0208,-1.468712 -1.33304,-0.147352 -2.44657,0.189847 -3.34298,1.009297 -0.89377,0.826514 -1.33967,1.910207 -1.33965,3.252913 0,1.172514 0.37155,2.177587 1.11602,3.016769 0.74629,0.841254 1.7085,1.336241 2.8887,1.483838 1.3143,0.164372 2.45544,-0.165971 3.42144,-0.99352 0.96902,-0.84934 1.45469,-1.932246 1.45469,-3.246705"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5954"
|
||||
d="m 210.59369,62.948857 c 0,0 -1.76559,12.102809 -1.76559,12.102809 0.99306,-0.529993 1.85742,-0.864422 2.59199,-1.002271 0.77082,-0.144321 1.60707,-0.168814 2.50926,-0.07301 2.23174,0.237044 4.08602,1.090293 5.55608,2.56358 1.47683,1.470144 2.21784,3.222946 2.21788,5.253295 1e-5,2.230397 -0.8416,3.981762 -2.51819,5.249095 -1.67957,1.279068 -3.71714,1.760708 -6.10579,1.451727 -2.21017,-0.285894 -4.13141,-1.259787 -5.76887,-2.916662 0,0 -0.27205,1.812753 -0.27205,1.812753 0,0 -3.734,-0.481081 -3.734,-0.481081 0,0 3.51282,-24.297211 3.51282,-24.297211 0,0 3.77646,0.336974 3.77646,0.336974 m 7.18134,18.458814 c -3e-5,-1.252477 -0.4394,-2.326274 -1.31629,-3.219543 -0.8745,-0.890788 -2.00772,-1.412305 -3.39688,-1.565883 -1.49808,-0.165597 -2.73151,0.1696 -3.70334,1.003067 -0.96885,0.811323 -1.45213,1.945103 -1.45212,3.403219 2e-5,1.223263 0.41506,2.257404 1.24678,3.10411 0.83392,0.8686 1.92249,1.387638 3.26835,1.55592 1.49058,0.186383 2.74974,-0.136303 3.77469,-0.970743 1.05167,-0.834302 1.57881,-1.938376 1.57881,-3.310147"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5956"
|
||||
d="m 232.93555,64.942427 c 0,0 -3.79346,25.295545 -3.79346,25.295545 0,0 -4.00189,-0.515597 -4.00189,-0.515597 0,0 3.76476,-25.139598 3.76476,-25.139598 0,0 4.03059,0.35965 4.03059,0.35965"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5958"
|
||||
d="m 239.07676,85.477198 c 1e-5,1.068436 0.45116,2.002121 1.35531,2.802708 0.91923,0.804368 2.09404,1.296834 3.52714,1.476294 1.97588,0.247435 3.50087,-0.165051 4.56866,-1.241156 0,0 3.20459,1.821904 3.20459,1.821904 -1.11699,1.073416 -2.26255,1.773857 -3.43638,2.10314 -1.18258,0.336864 -2.65489,0.390514 -4.41308,0.162756 -2.77115,-0.358979 -4.96266,-1.305345 -6.58587,-2.835657 -1.61521,-1.522765 -2.41984,-3.383769 -2.41987,-5.588642 -3e-5,-2.306935 0.88512,-4.137105 2.66268,-5.496037 1.77472,-1.357381 4.03193,-1.893987 6.78151,-1.60249 2.68277,0.284445 4.81243,1.219511 6.37815,2.809048 1.59911,1.610417 2.40156,3.625163 2.40163,6.038461 -3e-5,0.251826 -0.0196,0.658706 -0.0588,1.220604 0,0 -13.9657,-1.670933 -13.9657,-1.670933 m 9.66373,-1.627103 c -0.45104,-2.323059 -1.99908,-3.629393 -4.62888,-3.919627 -2.4703,-0.272608 -4.06924,0.672373 -4.8094,2.829777 0,0 9.43828,1.08985 9.43828,1.08985"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5960"
|
||||
d="m 159.44201,83.06886 c 0,0 -2.98737,22.36088 -2.98737,22.36088 0,0 -3.15565,-0.54145 -3.15565,-0.54145 0,0 2.96891,-22.238329 2.96891,-22.238329 0,0 3.17411,0.418899 3.17411,0.418899"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5962"
|
||||
d="m 176.52978,95.739649 c 0,0 -1.77849,12.829461 -1.77849,12.829461 0,0 -3.35926,-0.57638 -3.35926,-0.57638 0,0 0.19654,-1.37669 0.19654,-1.37669 -1.4283,0.89866 -2.89961,1.2156 -4.41324,0.95511 -1.85149,-0.31864 -3.35276,-1.15466 -4.5091,-2.50553 -1.15176,-1.3455 -1.72593,-2.93049 -1.72594,-4.75897 -2e-5,-2.109076 0.65694,-3.736288 1.97537,-4.885562 1.3441,-1.151542 3.07504,-1.57194 5.19969,-1.255482 1.00813,0.150176 1.86927,0.430138 2.58214,0.840229 0.72466,0.412634 1.46626,1.050011 2.22494,1.913032 0,0 0.22797,-1.684407 0.22797,-1.684407 0,0 3.37938,0.505189 3.37938,0.505189 m -4.10825,5.533921 c -2e-5,-1.15392 -0.36381,-2.14778 -1.09003,-2.980058 -0.72446,-0.839417 -1.65756,-1.345968 -2.79733,-1.520697 -1.23475,-0.189261 -2.26634,0.09566 -3.09688,0.852554 -0.8282,0.763868 -1.24141,1.791281 -1.24139,3.083861 0,1.12875 0.34431,2.10939 1.03417,2.94341 0.69147,0.836 1.58293,1.34622 2.67619,1.52967 1.2173,0.20427 2.27406,-0.0736 3.16851,-0.83603 0.89715,-0.78318 1.34676,-1.80802 1.34676,-3.07271"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5964"
|
||||
d="m 195.82123,98.623555 c 0,0 -13.67153,18.801495 -13.67153,18.801495 0,0 -3.92324,-0.72275 -3.92324,-0.72275 0,0 5.91998,-8.17342 5.91998,-8.17342 0,0 -5.26986,-12.438405 -5.26986,-12.438405 0,0 3.68066,0.550227 3.68066,0.550227 0,0 3.67874,9.080848 3.67874,9.080848 0,0 5.46568,-7.713835 5.46568,-7.713835 0,0 4.11957,0.61584 4.11957,0.61584"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5966"
|
||||
d="m 200.49583,107.30031 c 10e-6,1.00571 0.39972,1.89861 1.20069,2.68021 0.8142,0.7855 1.85458,1.28526 3.1234,1.49839 1.74884,0.29375 3.09819,-0.0472 4.04278,-1.02632 0,0 2.83375,1.81217 2.83375,1.81217 -0.98755,0.97496 -2.00057,1.5985 -3.0388,1.87223 -1.04617,0.28064 -2.34899,0.28605 -3.9052,0.0179 -2.45382,-0.42276 -4.39522,-1.38083 -5.83367,-2.87148 -1.43178,-1.48374 -2.14519,-3.26113 -2.14521,-5.33734 -2e-5,-2.17231 0.78478,-3.86759 2.36043,-5.09052 1.57263,-1.221165 3.5721,-1.654065 6.00661,-1.29191 2.37422,0.353213 4.25813,1.30051 5.6427,2.84497 1.41372,1.56471 2.12298,3.48409 2.12303,5.75287 -2e-5,0.23675 -0.0173,0.61866 -0.0519,1.14569 0,0 -12.35857,-2.0069 -12.35857,-2.0069 m 8.55495,-1.22843 c -0.39896,-2.19902 -1.76849,-3.47665 -4.09592,-3.833 -2.18726,-0.33486 -3.60353,0.50381 -4.25927,2.51108 0,0 8.35519,1.32192 8.35519,1.32192"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path5968"
|
||||
d="m 222.18466,102.56466 c 0,0 -0.17825,1.18915 -0.17825,1.18915 1.3334,-0.86103 2.68436,-1.19131 4.05308,-0.98751 1.20542,0.1795 2.30628,0.71229 3.30152,1.59991 0,0 -2.56067,2.36656 -2.56067,2.36656 -0.7348,-0.63744 -1.46792,-1.01191 -2.19936,-1.12432 -0.50266,-0.0772 -0.94483,-0.0599 -1.32674,0.0518 -0.38147,0.10156 -0.71487,0.31051 -1.00037,0.62671 -0.27337,0.30779 -0.50495,0.72683 -0.69483,1.25708 -0.17792,0.53184 -0.32018,1.17898 -0.42683,1.94144 0,0 -1.02913,6.86861 -1.02913,6.86861 0,0 -3.89147,-0.66771 -3.89147,-0.66771 0,0 2.03647,-13.70721 2.03647,-13.70721 0,0 3.91658,0.58549 3.91658,0.58549"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.70185341,0,0,0.70185341,118.30543,27.168909)"
|
||||
transform="matrix(0.70185341,0,0,0.70185341,103.7893,28.378586)"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
|
||||
id="text6476">
|
||||
<path
|
||||
@@ -1000,7 +1116,7 @@
|
||||
id="path6489" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 426.78356,107.09258 c 0,0 0,-1.88162 0,-1.88162 -1.29426,1.23241 -2.72793,2.21052 -4.30255,2.93345 -1.58097,0.75218 -3.02296,1.21187 -4.32438,1.37727 -2.84033,0.36091 -5.16206,-0.50088 -6.95591,-2.59442 -1.80197,-2.1297 -2.706,-4.61561 -2.706,-7.450523 0,-3.449995 1.14945,-6.766286 3.43846,-9.93519 2.29325,-3.179053 5.43363,-4.95254 9.40099,-5.331327 1.57921,-0.150749 3.39679,-0.06225 5.44939,0.26374 0,0 0,-1.920817 0,-1.920817 -1e-5,-1.202127 -0.33577,-2.151503 -1.00813,-2.849026 -0.6567,-0.700183 -1.92263,-0.967515 -3.80372,-0.800477 -1.5489,0.137578 -3.56646,0.792207 -6.05983,1.968997 -0.9326,0.429384 -1.65947,0.668141 -2.17946,0.715577 -0.71179,0.06498 -1.32039,-0.265367 -1.82538,-0.991816 -0.48819,-0.755544 -0.7325,-1.746725 -0.7325,-2.972869 0,-0.693 0.0873,-1.300079 0.26176,-1.821128 0.17441,-0.520739 0.41846,-0.940499 0.73202,-1.259265 0.31331,-0.345082 0.96525,-0.770689 1.95416,-1.276103 1.31474,-0.663016 2.65095,-1.206818 4.00842,-1.631975 1.3528,-0.449995 2.5732,-0.717309 3.66242,-0.802899 3.23272,-0.253864 5.71949,0.634365 7.47424,2.656278 1.76343,1.985514 2.64219,4.831201 2.64221,8.543807 0,0 0,16.434219 0,16.434219 0,0 0.8685,-0.09997 0.8685,-0.09997 1.22086,-0.140526 2.0847,0.135063 2.5939,0.825754 0.52488,0.662055 0.78706,1.586611 0.78708,2.774351 -2e-5,1.16192 -0.2622,2.14952 -0.78708,2.96365 -0.5092,0.78731 -1.37304,1.2577 -2.5939,1.41076 0,0 -5.99471,0.75157 -5.99471,0.75157 m 0,-14.386544 c -2.06948,-0.40743 -3.98883,-0.518817 -5.75577,-0.331915 -2.13431,0.225806 -3.97905,1.227956 -5.53012,3.010736 -0.96819,1.140564 -1.45318,2.243056 -1.45316,3.305406 -2e-5,0.770223 0.23388,1.367567 0.70129,1.791657 0.86409,0.77522 2.04484,1.07465 3.53944,0.90007 1.26684,-0.14798 2.69144,-0.69613 4.27211,-1.641973 1.59121,-0.943971 2.9993,-2.138927 4.22621,-3.584347 0,0 0,-3.449634 0,-3.449634"
|
||||
d="m 426.78356,107.09258 c 0,0 0,-1.88162 0,-1.88162 -1.29426,1.23241 -2.72793,2.21052 -4.30255,2.93345 -1.58097,0.75218 -3.02296,1.21187 -4.32438,1.37727 -2.84033,0.36091 -5.16206,-0.50088 -6.95591,-2.59442 -1.80197,-2.1297 -2.706,-4.61561 -2.706,-7.450523 0,-3.449995 1.14945,-6.766286 3.43846,-9.93519 2.29325,-3.179053 5.43363,-4.95254 9.40099,-5.331327 1.57921,-0.150749 3.39679,-0.06225 5.44939,0.26374 0,0 0,-1.920817 0,-1.920817 -1e-5,-1.202127 -0.33577,-2.151503 -1.00813,-2.849026 -0.6567,-0.700183 -1.92263,-0.967515 -3.80372,-0.800477 -1.5489,0.137578 -3.56646,0.792207 -6.05983,1.968997 -0.9326,0.429384 -1.65947,0.668141 -2.17946,0.715577 -0.71179,0.06498 -1.32039,-0.265367 -1.82538,-0.991816 -0.48819,-0.755544 -0.7325,-1.746725 -0.7325,-2.972869 0,-0.693 0.0873,-1.300079 0.26176,-1.821128 0.17441,-0.520739 0.41846,-0.940499 0.73202,-1.259265 0.31331,-0.345082 0.96525,-0.770689 1.95416,-1.276103 1.31474,-0.663016 2.65095,-1.206818 4.00842,-1.631975 1.3528,-0.449995 2.5732,-0.717309 3.66242,-0.802899 3.23272,-0.253864 5.71949,0.634365 7.47424,2.656278 1.76343,1.985514 2.64219,4.831201 2.64221,8.543807 0,0 0,16.434219 0,16.434219 0,0 0.8685,-0.09997 0.8685,-0.09997 1.22086,-0.140526 2.0847,0.135063 2.5939,0.825754 0.52488,0.662055 0.78706,1.586613 0.78708,2.774353 -2e-5,1.16192 -0.2622,2.14952 -0.78708,2.96365 -0.5092,0.78731 -1.37304,1.2577 -2.5939,1.41076 0,0 -5.99471,0.75157 -5.99471,0.75157 m 0,-14.386546 c -2.06948,-0.40743 -3.98883,-0.518817 -5.75577,-0.331915 -2.13431,0.225806 -3.97905,1.227956 -5.53012,3.010736 -0.96819,1.140564 -1.45318,2.243056 -1.45316,3.305406 -2e-5,0.770223 0.23388,1.367569 0.70129,1.791659 0.86409,0.77522 2.04484,1.07465 3.53944,0.90007 1.26684,-0.14798 2.69144,-0.69613 4.27211,-1.641975 1.59121,-0.943971 2.9993,-2.138927 4.22621,-3.584347 0,0 0,-3.449634 0,-3.449634"
|
||||
id="path6491" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
@@ -1019,54 +1135,127 @@
|
||||
d="m 529.26714,63.310804 c 0,0 0,4.360627 0,4.360627 1.63097,-2.247844 2.90878,-3.756252 3.83736,-4.531717 0.93851,-0.774258 1.81212,-1.192426 2.62133,-1.256017 1.24109,-0.09744 2.44062,0.637677 3.59899,2.201052 0.78636,1.052813 1.17886,2.159045 1.17888,3.320496 -2e-5,0.982826 -0.19008,1.837577 -0.5705,2.564837 -0.36861,0.704643 -0.8176,1.081739 -1.34729,1.13078 -0.46884,0.04344 -0.96305,-0.337016 -1.48272,-1.142328 -0.52052,-0.806521 -0.98594,-1.192073 -1.39602,-1.155672 -0.53514,0.04754 -1.33941,0.727598 -2.41476,2.043211 -1.06624,1.318692 -2.40692,3.27905 -4.02527,5.887282 0,0 0,10.526834 0,10.526834 0,0 5.50612,-0.63378 5.50612,-0.63378 0.92146,-0.106064 1.57368,0.14475 1.95822,0.751703 0.39645,0.582377 0.59451,1.389478 0.59453,2.421834 -2e-5,1.009903 -0.19808,1.864635 -0.59453,2.564818 -0.38454,0.676972 -1.03676,1.073391 -1.95822,1.188916 0,0 -11.77989,1.476871 -11.77989,1.476871 -0.95657,0.119927 -1.64331,-0.115635 -2.05861,-0.707472 -0.40281,-0.617169 -0.60438,-1.455248 -0.60438,-2.513711 0,-1.035437 0.20157,-1.898985 0.60438,-2.590038 0.4153,-0.714702 1.10204,-1.126896 2.05861,-1.237002 0,0 2.35416,-0.270974 2.35416,-0.270974 0,0 0,-17.063345 0,-17.063345 0,0 -1.426,0.128571 -1.426,0.128571 -0.95398,0.08605 -1.63887,-0.173426 -2.05304,-0.779149 -0.40171,-0.630509 -0.60275,-1.474561 -0.60274,-2.531606 -10e-6,-1.034031 0.20103,-1.889297 0.60274,-2.565222 0.41417,-0.699049 1.09906,-1.086463 2.05304,-1.162716 0,0 5.34561,-0.427083 5.34561,-0.427083"
|
||||
id="path6499" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.86745158,0,0,0.86745158,24.966041,10.718461)"
|
||||
style="font-size:40px;font-style:italic;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium Italic"
|
||||
id="text10906">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 153.83888,80.580698 c 0,0 -8.49369,30.064162 -8.49369,30.064162 0,0 -2.61138,-18.595363 -2.61138,-18.595363 0,0 -4.57263,17.271913 -4.57263,17.271913 0,0 -4.56489,-31.350308 -4.56489,-31.350308 0,0 3.1018,0.399872 3.1018,0.399872 0,0 2.23125,17.302482 2.23125,17.302482 0,0 4.5716,-17.201161 4.5716,-17.201161 0,0 2.48011,18.325657 2.48011,18.325657 0,0 4.30892,-16.674766 4.30892,-16.674766 0,0 3.54891,0.457512 3.54891,0.457512"
|
||||
id="path10913" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 159.48545,81.308632 c 0,0 -0.14506,2.466001 -0.14506,2.466001 1.08487,-2.027243 2.18358,-2.972954 3.29626,-2.831021 0.97953,0.125009 1.8738,0.992223 2.68199,2.604674 0,0 -2.07993,5.347173 -2.07993,5.347173 -0.59716,-1.153753 -1.19308,-1.770955 -1.78777,-1.853275 -0.40876,-0.05653 -0.76837,0.06793 -1.07902,0.373103 -0.31033,0.284418 -0.58159,0.778602 -0.81389,1.482374 -0.22246,0.684173 -0.41092,1.58735 -0.56546,2.709458 -0.14482,1.12299 -0.26061,2.474469 -0.34742,4.054536 0,0 -0.83785,14.250185 -0.83785,14.250185 0,0 -3.1705,-0.5674 -3.1705,-0.5674 0,0 1.65971,-28.446914 1.65971,-28.446914 0,0 3.18894,0.411106 3.18894,0.411106"
|
||||
id="path10915" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 172.11805,68.890531 c 0,1.003379 -0.1767,1.8517 -0.5298,2.544356 -0.35269,0.691923 -0.77536,1.010087 -1.2677,0.955217 -0.49153,-0.05472 -0.91719,-0.476639 -1.27726,-1.265141 -0.34966,-0.827922 -0.52433,-1.750538 -0.52433,-2.768572 -1e-5,-1.017937 0.16966,-1.862856 0.50931,-2.535355 0.35004,-0.692993 0.76564,-1.016131 1.24707,-0.968719 0.49226,0.04858 0.9199,0.476836 1.28263,1.285447 0.37326,0.789837 0.56007,1.707665 0.56008,2.752767 m -1.04353,13.912119 c 0,0 -1.74602,29.17105 -1.74602,29.17105 0,0 -3.29827,-0.59027 -3.29827,-0.59027 0,0 1.72646,-29.008502 1.72646,-29.008502 0,0 3.31783,0.427722 3.31783,0.427722"
|
||||
id="path10917" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 179.01598,90.329159 c 0,0 -1.40773,23.126301 -1.40773,23.126301 0,0 -3.39164,-0.60698 -3.39164,-0.60698 0,0 1.39174,-22.995732 1.39174,-22.995732 0,0 -1.91023,-0.267064 -1.91023,-0.267064 0,0 0.38103,-6.395689 0.38103,-6.395689 0,0 1.91269,0.246577 1.91269,0.246577 0,0 0.83004,-13.70396 0.83004,-13.70396 0,0 3.4216,0.361663 3.4216,0.361663 0,0 -0.8396,13.782164 -0.8396,13.782164 0,0 3.18457,0.410542 3.18457,0.410542 0,0 -0.39205,6.486823 -0.39205,6.486823 0,0 -3.18042,-0.444645 -3.18042,-0.444645"
|
||||
id="path10919" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 200.09638,86.544035 c 0,0 -1.9219,30.592005 -1.9219,30.592005 0,0 -3.62917,-0.64949 -3.62917,-0.64949 0,0 0.21227,-3.28285 0.21227,-3.28285 -1.54259,2.41691 -3.13133,3.47304 -4.76546,3.17868 -1.99844,-0.35998 -3.6185,-2.0112 -4.86612,-4.94632 -1.24249,-2.92301 -1.86183,-6.53106 -1.86186,-10.83321 -3e-5,-4.962328 0.70859,-8.930336 2.13088,-11.914549 1.45024,-2.995545 3.31826,-4.353123 5.61178,-4.060287 1.08848,0.139025 2.01838,0.614876 2.78825,1.428732 0.78266,0.817394 1.58372,2.160431 2.4033,4.031318 0,0 0.24627,-4.0148 0.24627,-4.0148 0,0 3.65176,0.470771 3.65176,0.470771 m -4.43909,13.904255 c -4e-5,-2.717054 -0.39303,-4.980086 -1.17745,-6.785644 -0.78246,-1.822565 -1.79014,-2.81699 -3.02082,-2.98627 -1.33305,-0.183291 -2.44658,0.70638 -3.34298,2.664066 -0.89378,1.973413 -1.33967,4.478873 -1.33964,7.520788 1e-5,2.65635 0.37157,4.89141 1.11605,6.70853 0.74629,1.8216 1.70851,2.83435 2.88872,3.03545 1.31431,0.22398 2.45545,-0.65327 3.42144,-2.63719 0.96902,-2.03362 1.45468,-4.54179 1.45468,-7.51973"
|
||||
id="path10921" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 210.59369,62.948857 c 0,0 -1.76545,27.618349 -1.76545,27.618349 0.99306,-1.312846 1.85741,-2.168093 2.59198,-2.563345 0.77082,-0.414004 1.60707,-0.563925 2.50926,-0.448755 2.23175,0.285016 4.08604,2.008664 5.55612,5.180407 1.47685,3.163873 2.21788,7.051196 2.21795,11.650967 4e-5,5.05301 -0.84154,9.11579 -2.51812,12.17628 -1.67956,3.08741 -3.71714,4.40866 -6.1058,3.97839 -2.21018,-0.39812 -4.13144,-2.38754 -5.76892,-5.95632 0,0 -0.27204,4.13756 -0.27204,4.13756 0,0 -3.73402,-0.66825 -3.73402,-0.66825 0,0 3.51259,-55.442257 3.51259,-55.442257 0,0 3.77645,0.336974 3.77645,0.336974 m 7.18157,41.007653 c -5e-5,-2.83751 -0.43943,-5.220592 -1.31634,-7.145285 -0.87451,-1.919338 -2.00774,-2.97287 -3.3969,-3.163946 -1.49809,-0.205986 -2.73151,0.692689 -3.70333,2.690649 -0.96885,1.947466 -1.45212,4.570632 -1.45209,7.874012 3e-5,2.77133 0.41508,5.06732 1.24682,6.89164 0.83393,1.87364 1.9225,2.92662 3.26838,3.15588 1.49058,0.25395 2.74975,-0.61929 3.77469,-2.62548 1.05165,-2.00888 1.57878,-4.5697 1.57877,-7.67747"
|
||||
id="path10923" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 232.93555,64.942427 c 0,0 -3.79307,57.735703 -3.79307,57.735703 0,0 -4.00192,-0.71619 -4.00192,-0.71619 0,0 3.76441,-57.379163 3.76441,-57.379163 0,0 4.03058,0.35965 4.03058,0.35965"
|
||||
id="path10925" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 239.0771,110.77066 c 3e-5,2.42055 0.4512,4.48489 1.35536,6.19654 0.91925,1.71851 2.09407,2.70154 3.52717,2.94627 1.9759,0.33746 3.50088,-0.76924 4.56866,-3.32776 0,0 3.20464,3.76569 3.20464,3.76569 -1.11698,2.55798 -2.26253,4.27421 -3.43636,5.15274 -1.18257,0.89672 -2.65489,1.18453 -4.41309,0.86707 -2.77117,-0.50035 -4.9627,-2.39688 -6.58594,-5.68055 -1.61524,-3.26745 -2.41991,-7.39273 -2.41997,-12.38791 -7e-5,-5.2264 0.88505,-9.472622 2.6626,-12.752021 1.77469,-3.27557 4.03189,-4.746141 6.78148,-4.39624 2.68278,0.341472 4.81246,2.219379 6.37821,5.643695 1.59914,3.467846 2.40165,7.941666 2.40175,13.409026 -1e-5,0.57052 -0.0196,1.49453 -0.0587,2.77194 0,0 -13.96577,-2.20849 -13.96577,-2.20849 m 9.66372,-4.77749 c -0.45108,-5.21198 -1.99914,-7.996687 -4.62896,-8.357264 -2.4703,-0.338637 -4.06923,1.982786 -4.80935,6.953984 0,0 9.43831,1.40328 9.43831,1.40328"
|
||||
id="path10927" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="text7027"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
|
||||
transform="matrix(0.71864924,0,0,0.71864924,121.45753,79.73219)">
|
||||
<path
|
||||
id="path7034"
|
||||
d="m 257.77651,339.30723 c 0,0 -0.0126,-47.29911 -0.0126,-47.29911 0,0 -1.07548,0.31593 -1.07548,0.31593 -1.66284,0.48854 -2.85746,0.28792 -3.58019,-0.6041 -0.70114,-0.93919 -1.05207,-2.31685 -1.05207,-4.13168 0,-1.81444 0.35082,-3.37328 1.05164,-4.67526 0.72225,-1.34546 1.91609,-2.25144 3.57799,-2.71834 0,0 16.97387,-4.76807 16.97387,-4.76807 3.96095,-1.11259 7.12511,-0.0323 9.50921,3.22201 2.37256,3.20077 3.55893,7.47543 3.56767,12.83748 0.004,2.54895 -0.26558,5.03047 -0.80964,7.44667 -0.54488,2.41969 -1.37616,4.76094 -2.49546,7.02568 2.05523,1.5616 3.5872,3.66333 4.601,6.30634 1.03267,2.59309 1.55152,5.7504 1.5581,9.47676 0.005,2.96688 -0.35657,5.85099 -1.08626,8.65561 -0.5429,2.13369 -1.21349,3.9137 -2.01229,5.33981 -1.07439,1.98467 -2.39566,3.77328 -3.96594,5.36629 -1.57592,1.56019 -3.5546,2.76646 -5.94107,3.61797 0,0 -19.88366,7.09459 -19.88366,7.09459 -1.66745,0.59496 -2.8654,0.46776 -3.59015,-0.3841 -0.7031,-0.90081 -1.05501,-2.26426 -1.05501,-4.08924 0,-1.78498 0.36314,-3.35858 1.08856,-4.71936 0.72421,-1.39809 1.91002,-2.37974 3.55397,-2.94517 0,0 1.07785,-0.37071 1.07785,-0.37071 m 6.82963,-31.88447 c 0,0 7.39137,-2.30892 7.39137,-2.30892 2.62158,-0.8189 4.78642,-2.6695 6.50056,-5.5468 1.1532,-1.92898 1.72713,-4.06042 1.72408,-6.3978 -0.003,-2.06859 -0.54939,-3.7066 -1.64172,-4.9163 -1.09485,-1.25071 -2.83681,-1.52649 -5.23332,-0.82255 0,0 -8.7512,2.57075 -8.7512,2.57075 0,0 0.0102,17.42162 0.0102,17.42162 m 0.0173,29.5295 c 0,0 11.59226,-3.98707 11.59226,-3.98707 2.6872,-0.92424 4.5687,-2.28259 5.65417,-4.07576 0.82819,-1.3569 1.24028,-3.03056 1.23742,-5.02267 -0.003,-2.37465 -0.82491,-4.43936 -2.46842,-6.19896 -1.6491,-1.76544 -4.02284,-2.14729 -7.13269,-1.13597 0,0 -8.89303,2.89208 -8.89303,2.89208 0,0 0.0103,17.52835 0.0103,17.52835"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7036"
|
||||
d="m 315.63395,330.78832 c 0,0 -0.008,-2.66312 -0.008,-2.66312 -1.5205,2.05858 -3.20684,3.79158 -5.06081,5.19796 -1.86182,1.44967 -3.56117,2.45156 -5.09604,3.00252 -3.35058,1.20262 -6.09378,0.54663 -8.21773,-1.98311 -2.1334,-2.5787 -3.20755,-5.87974 -3.21543,-9.8935 -0.01,-4.88257 1.33706,-9.85215 4.02708,-14.88639 2.69328,-5.04641 6.38764,-8.30943 11.05913,-9.80146 1.85895,-0.5937 3.99917,-0.90711 6.4167,-0.94198 0,0 -0.008,-2.71047 -0.008,-2.71047 -0.005,-1.69597 -0.40413,-2.95433 -1.19822,-3.7763 -0.77565,-0.82947 -2.26653,-0.90179 -4.47994,-0.2133 -1.82287,0.56707 -4.19603,1.97667 -7.12852,4.23834 -1.09717,0.83095 -1.95272,1.34329 -2.56522,1.53566 -0.83846,0.26342 -1.55663,-0.0562 -2.15389,-0.96001 -0.57751,-0.94891 -0.86835,-2.28914 -0.872,-4.01969 -0.002,-0.97796 0.0989,-1.85561 0.30293,-2.6328 0.20389,-0.77667 0.49009,-1.42758 0.85846,-1.95271 0.36795,-0.56215 1.13444,-1.3193 2.29738,-2.26995 1.54584,-1.25105 3.11705,-2.33895 4.71339,-3.2645 1.59048,-0.95927 3.02556,-1.62913 4.30677,-2.01132 3.80176,-1.13384 6.73,-0.47944 8.80217,1.94792 2.08246,2.37423 3.12878,6.17396 3.14584,11.40899 0,0 0.0755,23.20429 0.0755,23.20429 0,0 1.02221,-0.35158 1.02221,-0.35158 1.43677,-0.49417 2.45508,-0.3138 3.05789,0.53908 0.62114,0.80865 0.93435,2.052 0.94024,3.73109 0.006,1.64284 -0.29817,3.103 -0.91229,4.38174 -0.5959,1.23719 -1.61113,2.11228 -3.0486,2.62518 0,0 -7.06105,2.51942 -7.06105,2.51942 m -0.0605,-20.34496 c -2.43905,-0.0753 -4.70041,0.23148 -6.78144,0.92294 -2.51422,0.83547 -4.68502,2.69856 -6.5076,5.59502 -1.13795,1.84779 -1.70634,3.52499 -1.70292,5.02807 0.002,1.0899 0.28029,1.87848 0.83301,2.36524 1.0218,0.88744 2.41549,1.02464 4.17755,0.41484 1.49329,-0.5168 3.1709,-1.63797 5.03058,-3.3593 1.87161,-1.72078 3.52592,-3.75158 4.9653,-6.09198 0,0 -0.0145,-4.87483 -0.0145,-4.87483"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7038"
|
||||
d="m 351.45961,282.46833 c -0.91452,-0.81047 -1.87521,-1.32503 -2.88241,-1.54283 -1.00973,-0.2537 -2.06646,-0.2094 -3.17058,0.13403 -2.19836,0.68386 -3.94926,1.92675 -5.24728,3.73026 -0.5762,0.79085 -0.86315,1.54528 -0.8602,2.26251 0.003,0.82494 0.39908,1.5073 1.18614,2.04629 0.59861,0.38285 1.93021,0.51244 3.98804,0.38963 3.75668,-0.20875 6.35384,-0.0517 7.81225,0.46829 1.90678,0.68882 3.37659,2.14965 4.41397,4.38104 1.03506,2.22658 1.55882,4.7606 1.57299,7.60629 0.0192,3.8658 -0.83398,7.40347 -2.56521,10.62256 -2.494,4.67157 -5.77005,7.74446 -9.84541,9.20702 -1.64484,0.59029 -3.1764,0.85271 -4.59341,0.78534 -1.40277,-0.0383 -2.69857,-0.38697 -3.88635,-1.04728 -0.28039,0.56921 -0.58022,1.03726 -0.89956,1.40403 -0.31959,0.36694 -0.64935,0.61132 -0.9893,0.73259 -0.90789,0.32388 -1.6396,0.0228 -2.1942,-0.90467 -0.5364,-0.97147 -0.80986,-2.79935 -0.81995,-5.48228 0,0 -0.0141,-3.75135 -0.0141,-3.75135 -0.0101,-2.68128 0.24884,-4.67325 0.77628,-5.97507 0.54553,-1.34257 1.25338,-2.15911 2.12282,-2.4506 0.69806,-0.23398 1.28355,-0.0514 1.75697,0.54708 0.47278,0.56188 0.84401,1.69794 1.114,3.40803 0.88673,1.1377 1.94787,1.87097 3.18209,2.20069 1.2306,0.29303 2.64142,0.16353 4.23059,-0.38634 2.59273,-0.89712 4.59185,-2.37089 6.00541,-4.42001 0.6686,-1.00942 1.00048,-1.93805 0.99651,-2.78707 -0.007,-1.41485 -0.49308,-2.41976 -1.46078,-3.01586 -0.96983,-0.59733 -2.9752,-0.70841 -6.03069,-0.33021 -4.58673,0.59585 -7.6827,-0.17688 -9.25518,-2.32843 -1.57769,-2.12264 -2.37589,-5.11935 -2.39063,-8.9837 -0.0152,-3.97117 0.8521,-7.54395 2.5961,-10.70925 2.35076,-4.30605 5.42069,-7.0163 9.19499,-8.14207 1.30582,-0.38941 2.55386,-0.51306 3.74464,-0.37241 1.20554,0.0997 2.35451,0.48017 3.44739,1.14045 0.34168,-0.59723 0.65654,-1.06254 0.94466,-1.39612 0.30594,-0.33858 0.58518,-0.54582 0.83779,-0.62164 0.75685,-0.22696 1.38927,0.14621 1.89787,1.11843 0.50782,0.93618 0.76793,2.70208 0.78072,5.29897 0,0 0.013,2.63267 0.013,2.63267 0.0115,2.35245 -0.12411,3.99567 -0.4071,4.9298 -0.56706,1.80018 -1.34596,2.85977 -2.33781,3.17733 -0.6686,0.21411 -1.25866,-0.004 -1.76979,-0.6537 -0.51177,-0.6508 -0.84365,-1.62508 -0.99522,-2.92244"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7040"
|
||||
d="m 391.08767,286.09973 c 0,0 -21.40037,7.16598 -21.40037,7.16598 0.57216,2.58305 1.56606,4.48187 2.97874,5.69565 1.42536,1.20392 3.33049,1.3912 5.70856,0.56836 1.94011,-0.6713 4.49918,-2.39426 7.66518,-5.15474 1.2993,-1.12534 2.19719,-1.77197 2.69637,-1.94256 0.68118,-0.23272 1.25664,0.0618 1.72693,0.88273 0.46973,0.82008 0.70926,1.97252 0.71896,3.45813 0.009,1.35076 -0.23184,2.58617 -0.72232,3.70718 -0.65513,1.48575 -2.26858,3.26333 -4.85199,5.34083 -2.60048,2.05693 -5.11941,3.52549 -7.55489,4.39953 -4.22378,1.51581 -7.65099,0.33127 -10.26023,-3.58227 -2.60677,-3.94222 -3.93431,-9.46384 -3.97137,-16.54436 -0.0394,-7.52874 1.32903,-14.07941 4.09047,-19.62629 2.75903,-5.5472 5.92505,-8.84107 9.48957,-9.90426 2.12737,-0.63445 4.07097,-0.46394 5.83355,0.50605 1.77201,0.96099 3.08675,2.17372 3.94852,3.63907 1.21416,2.13157 2.22166,4.91277 3.02403,8.34384 0.54592,2.39326 0.82964,5.27426 0.85162,8.64573 0,0 0.0287,4.4014 0.0287,4.4014 m -5.73214,-8.54412 c -0.80672,-2.7354 -1.85391,-4.63367 -3.14346,-5.69374 -1.29366,-1.0973 -2.833,-1.37003 -4.62091,-0.81389 -1.77862,0.55329 -3.31967,1.79032 -4.62063,3.71406 -1.30548,1.89566 -2.36785,4.49783 -3.18525,7.80742 0,0 15.57025,-5.01385 15.57025,-5.01385"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7042"
|
||||
d="m 438.50105,238.91477 c 0,0 0.33366,38.11886 0.33366,38.11886 0,0 4.5189,-1.55424 4.5189,-1.55424 1.06904,-0.36769 1.8298,-0.17153 2.28417,0.58709 0.46789,0.72139 0.70825,1.80481 0.72144,3.25104 0.0129,1.41496 -0.20635,2.65984 -0.65806,3.73554 -0.43823,1.04046 -1.19112,1.75156 -2.26052,2.13313 0,0 -13.68028,4.8812 -13.68028,4.8812 -1.1116,0.39663 -1.91344,0.23005 -2.40353,-0.50122 -0.47582,-0.76976 -0.72,-1.89742 -0.73214,-3.38218 -0.0119,-1.45226 0.21273,-2.71134 0.67337,-3.77635 0.47483,-1.10101 1.26883,-1.84247 2.38003,-2.22466 0,0 4.62789,-1.59173 4.62789,-1.59173 0,0 -0.3275,-38.34793 -0.3275,-38.34793 0,0 -4.6215,1.35761 -4.6215,1.35761 -1.10965,0.32602 -1.91007,0.11077 -2.39927,-0.64712 -0.47496,-0.79518 -0.71868,-1.93224 -0.73077,-3.41027 -0.0121,-1.47774 0.21202,-2.73263 0.67186,-3.76384 0.47403,-1.06604 1.26664,-1.75469 2.37589,-2.06634 0,0 13.65257,-3.78793 13.65257,-3.78793 1.06727,-0.29982 1.82661,-0.0734 2.27992,0.67815 0.4671,0.74675 0.70703,1.83959 0.72016,3.27935 0.0131,1.44004 -0.20565,2.68084 -0.65663,3.72319 -0.43753,1.00825 -1.18918,1.66931 -2.25681,1.98288 0,0 -4.51285,1.3257 -4.51285,1.3257"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7044"
|
||||
d="m 455.88348,238.41146 c 0,0 0.0257,2.69003 0.0257,2.69003 0.68312,-1.72546 1.29991,-2.94833 1.85075,-3.67036 0.56356,-0.75579 1.21217,-1.24275 1.94542,-1.46144 0.62141,-0.18526 1.23821,-0.0305 1.85047,0.46347 0.61126,0.49329 1.21121,1.3268 1.79992,2.49991 0.71137,-1.56555 1.43158,-2.77864 2.16064,-3.64047 0.7408,-0.89447 1.49699,-1.45627 2.26852,-1.68643 1.53816,-0.45872 2.79097,0.0945 3.76153,1.65542 1.28104,2.03781 1.94044,5.01712 1.98128,8.9439 0,0 0.21643,20.82129 0.21643,20.82129 0.85204,-0.29305 1.48772,-0.0721 1.90821,0.66181 0.42,0.73316 0.63698,1.77834 0.65128,3.13628 0.0143,1.35811 -0.17928,2.54755 -0.58098,3.56911 -0.40256,0.99258 -1.09593,1.66483 -2.08175,2.01658 0,0 -3.92315,1.3998 -3.92315,1.3998 0,0 -0.30125,-29.5317 -0.30125,-29.5317 -0.0146,-1.42806 -0.13917,-2.37963 -0.37387,-2.85506 -0.23487,-0.47561 -0.58859,-0.64006 -1.06152,-0.49297 -0.46004,0.14313 -0.88398,0.55012 -1.27173,1.2214 -0.49476,0.91973 -1.09234,2.54691 -1.79337,4.88434 0,0 0.1894,18.96164 0.1894,18.96164 0.8724,-0.30006 1.52302,-0.079 1.95307,0.662 0.42956,0.74027 0.65113,1.79714 0.66503,3.17137 0.0139,1.37439 -0.18487,2.57895 -0.59663,3.61451 -0.4126,1.00623 -1.12276,1.68951 -2.13218,2.04968 0,0 -4.01729,1.43339 -4.01729,1.43339 0,0 -0.29261,-29.88883 -0.29261,-29.88883 -0.0139,-1.41455 -0.14767,-2.35965 -0.40153,-2.83564 -0.24053,-0.51127 -0.60278,-0.69179 -1.08713,-0.54115 -0.49887,0.15521 -0.98803,0.66317 -1.46747,1.52462 -0.4804,0.8318 -1.05239,2.39108 -1.71646,4.68046 0,0 0.18368,19.19395 0.18368,19.19395 0.89368,-0.30737 1.55989,-0.0863 1.99991,0.66201 0.45342,0.74274 0.68669,1.80921 0.70018,3.2002 0.0135,1.39115 -0.19765,2.61376 -0.6338,3.6687 -0.42312,1.02036 -1.1508,1.7151 -2.18483,2.08405 0,0 -3.90344,1.39277 -3.90344,1.39277 -1.04783,0.37387 -1.79708,0.20173 -2.24591,-0.51779 -0.46384,-0.74661 -0.70262,-1.84073 -0.71594,-3.28161 -0.013,-1.40935 0.19719,-2.62896 0.63021,-3.65799 0.43218,-1.05897 1.10915,-1.74654 2.02961,-2.06313 0,0 -0.21801,-23.27593 -0.21801,-23.27593 -0.91971,0.2877 -1.60455,0.0483 -2.05317,-0.71937 -0.44909,-0.76843 -0.68033,-1.85564 -0.69331,-3.26087 -0.013,-1.40499 0.20412,-2.61343 0.65085,-3.62449 0.43169,-1.03656 1.17158,-1.71162 2.21788,-2.0255 0,0 4.10732,-1.23196 4.10732,-1.23196"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7046"
|
||||
d="m 490.87185,268.26248 c 0,0 -0.0238,-2.12947 -0.0238,-2.12947 -0.96684,1.56112 -2.04221,2.85176 -3.22705,3.87118 -1.18857,1.05267 -2.27482,1.75638 -3.25773,2.1092 -2.1433,0.7693 -3.90736,0.0916 -5.28616,-2.04226 -1.38398,-2.17145 -2.09463,-4.85752 -2.12832,-8.05178 -0.041,-3.88602 0.78508,-7.77051 2.47177,-11.63982 1.69085,-3.8838 4.03967,-6.29946 7.03403,-7.25585 1.19331,-0.3811 2.57099,-0.52435 4.13102,-0.43103 0,0 -0.0243,-2.16861 -0.0243,-2.16861 -0.0152,-1.35698 -0.28175,-2.38328 -0.80016,-3.07972 -0.50639,-0.70131 -1.46852,-0.83189 -2.89014,-0.3897 -1.16973,0.36389 -2.6864,1.37311 -4.5546,3.03337 -0.69844,0.60846 -1.2438,0.97457 -1.63533,1.09754 -0.5358,0.16833 -0.99846,-0.12206 -1.38767,-0.87192 -0.37678,-0.78462 -0.57264,-1.86678 -0.58731,-3.24582 -0.008,-0.77933 0.0501,-1.47376 0.17529,-2.08321 0.1251,-0.60911 0.30385,-1.1141 0.53618,-1.51496 0.23184,-0.43046 0.71786,-0.99743 1.45701,-1.70003 0.98321,-0.92446 1.98458,-1.71816 3.00395,-2.38162 1.01611,-0.69116 1.93495,-1.15887 2.7573,-1.40418 2.44294,-0.72858 4.33815,-0.0679 5.69456,1.97299 1.36388,2.00056 2.06787,5.09484 2.11563,9.28942 0,0 0.21151,18.5876 0.21151,18.5876 0,0 0.65945,-0.22681 0.65945,-0.22681 0.92741,-0.31897 1.58879,-0.11998 1.98565,0.5958 0.40854,0.68149 0.62043,1.69497 0.63598,3.04114 0.0152,1.31705 -0.17178,2.47066 -0.56118,3.4616 -0.37775,0.95836 -1.02971,1.60314 -1.95738,1.93413 0,0 -4.54817,1.62282 -4.54817,1.62282 m -0.18218,-16.27076 c -1.57456,-0.18741 -3.03025,-0.0602 -4.36568,0.38353 -1.61175,0.53558 -2.9938,1.90828 -4.14364,4.12194 -0.71713,1.41252 -1.06983,2.71889 -1.05695,3.91694 0.009,0.8687 0.19313,1.51219 0.55118,1.93012 0.66205,0.76298 1.55791,0.94835 2.68579,0.55802 0.95654,-0.33103 2.02809,-1.13477 3.2135,-2.40861 1.19412,-1.27383 2.24686,-2.80822 3.15946,-4.60277 0,0 -0.0437,-3.89917 -0.0437,-3.89917"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7048"
|
||||
d="m 513.83107,223.64708 c 0,0 -0.0321,-2.60694 -0.0321,-2.60694 0,0 4.24921,-1.27452 4.24921,-1.27452 0.86692,-0.25998 1.48579,-0.0345 1.85799,0.67552 0.38309,0.67764 0.58268,1.66515 0.59908,2.9632 0.016,1.27005 -0.15729,2.37215 -0.52017,3.30702 -0.35202,0.90414 -0.96092,1.49191 -1.82805,1.76307 0,0 -0.61656,0.19283 -0.61656,0.19283 0,0 0.3963,31.78092 0.3963,31.78092 0.0383,3.07233 -0.1991,5.84676 -0.71289,8.32595 -0.50258,2.50775 -1.30016,4.80111 -2.39487,6.88205 -1.09848,2.08802 -2.35446,3.40535 -3.76947,3.94832 0,0 -4.20721,1.61434 -4.20721,1.61434 -0.90127,0.34581 -1.55322,0.17312 -1.95437,-0.5193 -0.389,-0.66876 -0.59138,-1.65732 -0.60684,-2.96502 -0.0158,-1.33662 0.16113,-2.49707 0.53047,-3.48063 0.38146,-0.95795 1.02342,-1.60387 1.92446,-1.93799 0,0 4.09797,-1.51959 4.09797,-1.51959 1.12773,-0.41818 1.99206,-1.47339 2.59485,-3.16418 0.6016,-1.68753 0.88825,-3.64562 0.86083,-5.87641 0,0 -0.0527,-4.28868 -0.0527,-4.28868 -0.79402,1.54526 -1.61175,2.78547 -2.45334,3.71951 -0.83173,0.93214 -1.69344,1.55874 -2.58528,1.87869 -2.53138,0.90814 -4.68912,-0.3421 -6.46539,-3.76745 -1.78479,-3.47022 -2.71501,-8.19944 -2.78452,-14.17311 -0.0698,-5.99942 0.74291,-11.29294 2.43134,-15.86475 1.6791,-4.57629 3.78635,-7.2342 6.31459,-7.98783 0.93884,-0.27979 1.83117,-0.21544 2.67743,0.19177 0.8558,0.37421 1.67211,1.10227 2.44924,2.18321 m 0.18895,16.81679 c -0.0397,-3.22458 -0.57346,-5.86075 -1.60346,-7.91342 -1.02083,-2.06186 -2.23403,-2.87672 -3.64183,-2.43909 -1.41359,0.43948 -2.61815,2.01503 -3.61171,4.73172 -0.98452,2.72148 -1.4586,5.72173 -1.41993,8.9951 0.039,3.30339 0.58054,5.9872 1.62246,8.04652 1.05092,2.02074 2.28478,2.78371 3.69937,2.29449 1.4088,-0.48717 2.59406,-2.07774 3.55781,-4.76688 0.97229,-2.71336 1.4373,-5.6943 1.39729,-8.94844"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7050"
|
||||
d="m 540.11181,236.19855 c 0,0 -14.17571,4.74678 -14.17571,4.74678 0.39598,2.12039 1.06655,3.70874 2.0101,4.76439 0.95245,1.04897 2.21683,1.29937 3.78949,0.75521 1.28429,-0.44438 2.97443,-1.71113 5.06396,-3.7914 0.85848,-0.84849 1.45291,-1.3286 1.78475,-1.44201 0.45294,-0.15474 0.83898,0.11397 1.1584,0.80553 0.3191,0.69101 0.48673,1.64075 0.5031,2.84977 0.0149,1.09925 -0.1376,2.09168 -0.45762,2.9779 -0.4274,1.17397 -1.49195,2.53431 -3.19995,4.08586 -1.71744,1.53209 -3.38257,2.58934 -4.99438,3.16779 -2.79108,1.00165 -5.0682,-0.14146 -6.81995,-3.44725 -1.74841,-3.32527 -2.66198,-7.85839 -2.73457,-13.58545 -0.0772,-6.09039 0.78143,-11.32407 2.56808,-15.68474 1.78745,-4.3669 3.86227,-6.89434 6.21974,-7.59751 1.4088,-0.42014 2.70212,-0.19498 3.88143,0.67196 1.18643,0.86072 2.07063,1.90611 2.65495,3.13691 0.82406,1.78934 1.51493,4.09853 2.07343,6.92778 0.38048,1.97331 0.58916,4.3313 0.62629,7.07581 0,0 0.0485,3.58267 0.0485,3.58267 m -3.88051,-7.22718 c -0.55565,-2.26143 -1.2656,-3.85327 -2.13087,-4.7749 -0.86777,-0.95155 -1.89277,-1.24457 -3.07652,-0.87637 -1.17666,0.36604 -2.19027,1.29725 -3.03946,2.79568 -0.85185,1.47453 -1.5375,3.53206 -2.05595,6.17324 0,0 10.3028,-3.31765 10.3028,-3.31765"
|
||||
inkscape:connector-curvature="0" />
|
||||
style="display:none"
|
||||
inkscape:label="Base Image"
|
||||
id="layer10"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="text7027"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
|
||||
transform="matrix(0.71864924,0,0,0.71864924,102.10269,88.99025)">
|
||||
<path
|
||||
id="path7034"
|
||||
d="m 257.77651,339.30723 c 0,0 -0.0126,-47.29911 -0.0126,-47.29911 0,0 -1.07548,0.31593 -1.07548,0.31593 -1.66284,0.48854 -2.85746,0.28792 -3.58019,-0.6041 -0.70114,-0.93919 -1.05207,-2.31685 -1.05207,-4.13168 0,-1.81444 0.35082,-3.37328 1.05164,-4.67526 0.72225,-1.34546 1.91609,-2.25144 3.57799,-2.71834 0,0 16.97387,-4.76807 16.97387,-4.76807 3.96095,-1.11259 7.12511,-0.0323 9.50921,3.22201 2.37256,3.20077 3.55893,7.47543 3.56767,12.83748 0.004,2.54895 -0.26558,5.03047 -0.80964,7.44667 -0.54488,2.41969 -1.37616,4.76094 -2.49546,7.02568 2.05523,1.5616 3.5872,3.66333 4.601,6.30634 1.03267,2.59309 1.55152,5.7504 1.5581,9.47676 0.005,2.96688 -0.35657,5.85099 -1.08626,8.65561 -0.5429,2.13369 -1.21349,3.9137 -2.01229,5.33981 -1.07439,1.98467 -2.39566,3.77328 -3.96594,5.36629 -1.57592,1.56019 -3.5546,2.76646 -5.94107,3.61797 0,0 -19.88366,7.09459 -19.88366,7.09459 -1.66745,0.59496 -2.8654,0.46776 -3.59015,-0.3841 -0.7031,-0.90081 -1.05501,-2.26426 -1.05501,-4.08924 0,-1.78498 0.36314,-3.35858 1.08856,-4.71936 0.72421,-1.39809 1.91002,-2.37974 3.55397,-2.94517 0,0 1.07785,-0.37071 1.07785,-0.37071 m 6.82963,-31.88447 c 0,0 7.39137,-2.30892 7.39137,-2.30892 2.62158,-0.8189 4.78642,-2.6695 6.50056,-5.5468 1.1532,-1.92898 1.72713,-4.06042 1.72408,-6.3978 -0.003,-2.06859 -0.54939,-3.7066 -1.64172,-4.9163 -1.09485,-1.25071 -2.83681,-1.52649 -5.23332,-0.82255 0,0 -8.7512,2.57075 -8.7512,2.57075 0,0 0.0102,17.42162 0.0102,17.42162 m 0.0173,29.5295 c 0,0 11.59226,-3.98707 11.59226,-3.98707 2.6872,-0.92424 4.5687,-2.28259 5.65417,-4.07576 0.82819,-1.3569 1.24028,-3.03056 1.23742,-5.02267 -0.003,-2.37465 -0.82491,-4.43936 -2.46842,-6.19896 -1.6491,-1.76544 -4.02284,-2.14729 -7.13269,-1.13597 0,0 -8.89303,2.89208 -8.89303,2.89208 0,0 0.0103,17.52835 0.0103,17.52835"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7036"
|
||||
d="m 315.63395,330.78832 c 0,0 -0.008,-2.66312 -0.008,-2.66312 -1.5205,2.05858 -3.20684,3.79158 -5.06081,5.19796 -1.86182,1.44967 -3.56117,2.45156 -5.09604,3.00252 -3.35058,1.20262 -6.09378,0.54663 -8.21773,-1.98311 -2.1334,-2.5787 -3.20755,-5.87974 -3.21543,-9.8935 -0.01,-4.88257 1.33706,-9.85215 4.02708,-14.88639 2.69328,-5.04641 6.38764,-8.30943 11.05913,-9.80146 1.85895,-0.5937 3.99917,-0.90711 6.4167,-0.94198 0,0 -0.008,-2.71047 -0.008,-2.71047 -0.005,-1.69597 -0.40413,-2.95433 -1.19822,-3.7763 -0.77565,-0.82947 -2.26653,-0.90179 -4.47994,-0.2133 -1.82287,0.56707 -4.19603,1.97667 -7.12852,4.23834 -1.09717,0.83095 -1.95272,1.34329 -2.56522,1.53566 -0.83846,0.26342 -1.55663,-0.0562 -2.15389,-0.96001 -0.57751,-0.94891 -0.86835,-2.28914 -0.872,-4.01969 -0.002,-0.97796 0.0989,-1.85561 0.30293,-2.6328 0.20389,-0.77667 0.49009,-1.42758 0.85846,-1.95271 0.36795,-0.56215 1.13444,-1.3193 2.29738,-2.26995 1.54584,-1.25105 3.11705,-2.33895 4.71339,-3.2645 1.59048,-0.95927 3.02556,-1.62913 4.30677,-2.01132 3.80176,-1.13384 6.73,-0.47944 8.80217,1.94792 2.08246,2.37423 3.12878,6.17396 3.14584,11.40899 0,0 0.0755,23.20429 0.0755,23.20429 0,0 1.02221,-0.35158 1.02221,-0.35158 1.43677,-0.49417 2.45508,-0.3138 3.05789,0.53908 0.62114,0.80865 0.93435,2.052 0.94024,3.73109 0.006,1.64284 -0.29817,3.103 -0.91229,4.38174 -0.5959,1.23719 -1.61113,2.11228 -3.0486,2.62518 0,0 -7.06105,2.51942 -7.06105,2.51942 m -0.0605,-20.34496 c -2.43905,-0.0753 -4.70041,0.23148 -6.78144,0.92294 -2.51422,0.83547 -4.68502,2.69856 -6.5076,5.59502 -1.13795,1.84779 -1.70634,3.52499 -1.70292,5.02807 0.002,1.0899 0.28029,1.87848 0.83301,2.36524 1.0218,0.88744 2.41549,1.02464 4.17755,0.41484 1.49329,-0.5168 3.1709,-1.63797 5.03058,-3.3593 1.87161,-1.72078 3.52592,-3.75158 4.9653,-6.09198 0,0 -0.0145,-4.87483 -0.0145,-4.87483"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7038"
|
||||
d="m 351.45961,282.46833 c -0.91452,-0.81047 -1.87521,-1.32503 -2.88241,-1.54283 -1.00973,-0.2537 -2.06646,-0.2094 -3.17058,0.13403 -2.19836,0.68386 -3.94926,1.92675 -5.24728,3.73026 -0.5762,0.79085 -0.86315,1.54528 -0.8602,2.26251 0.003,0.82494 0.39908,1.5073 1.18614,2.04629 0.59861,0.38285 1.93021,0.51244 3.98804,0.38963 3.75668,-0.20875 6.35384,-0.0517 7.81225,0.46829 1.90678,0.68882 3.37659,2.14965 4.41397,4.38104 1.03506,2.22658 1.55882,4.7606 1.57299,7.60629 0.0192,3.8658 -0.83398,7.40347 -2.56521,10.62256 -2.494,4.67157 -5.77005,7.74446 -9.84541,9.20702 -1.64484,0.59029 -3.1764,0.85271 -4.59341,0.78534 -1.40277,-0.0383 -2.69857,-0.38697 -3.88635,-1.04728 -0.28039,0.56921 -0.58022,1.03726 -0.89956,1.40403 -0.31959,0.36694 -0.64935,0.61132 -0.9893,0.73259 -0.90789,0.32388 -1.6396,0.0228 -2.1942,-0.90467 -0.5364,-0.97147 -0.80986,-2.79935 -0.81995,-5.48228 0,0 -0.0141,-3.75135 -0.0141,-3.75135 -0.0101,-2.68128 0.24884,-4.67325 0.77628,-5.97507 0.54553,-1.34257 1.25338,-2.15911 2.12282,-2.4506 0.69806,-0.23398 1.28355,-0.0514 1.75697,0.54708 0.47278,0.56188 0.84401,1.69794 1.114,3.40803 0.88673,1.1377 1.94787,1.87097 3.18209,2.20069 1.2306,0.29303 2.64142,0.16353 4.23059,-0.38634 2.59273,-0.89712 4.59185,-2.37089 6.00541,-4.42001 0.6686,-1.00942 1.00048,-1.93805 0.99651,-2.78707 -0.007,-1.41485 -0.49308,-2.41976 -1.46078,-3.01586 -0.96983,-0.59733 -2.9752,-0.70841 -6.03069,-0.33021 -4.58673,0.59585 -7.6827,-0.17688 -9.25518,-2.32843 -1.57769,-2.12264 -2.37589,-5.11935 -2.39063,-8.9837 -0.0152,-3.97117 0.8521,-7.54395 2.5961,-10.70925 2.35076,-4.30605 5.42069,-7.0163 9.19499,-8.14207 1.30582,-0.38941 2.55386,-0.51306 3.74464,-0.37241 1.20554,0.0997 2.35451,0.48017 3.44739,1.14045 0.34168,-0.59723 0.65654,-1.06254 0.94466,-1.39612 0.30594,-0.33858 0.58518,-0.54582 0.83779,-0.62164 0.75685,-0.22696 1.38927,0.14621 1.89787,1.11843 0.50782,0.93618 0.76793,2.70208 0.78072,5.29897 0,0 0.013,2.63267 0.013,2.63267 0.0115,2.35245 -0.12411,3.99567 -0.4071,4.9298 -0.56706,1.80018 -1.34596,2.85977 -2.33781,3.17733 -0.6686,0.21411 -1.25866,-0.004 -1.76979,-0.6537 -0.51177,-0.6508 -0.84365,-1.62508 -0.99522,-2.92244"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7040"
|
||||
d="m 391.08767,286.09973 c 0,0 -21.40037,7.16598 -21.40037,7.16598 0.57216,2.58305 1.56606,4.48187 2.97874,5.69565 1.42536,1.20392 3.33049,1.3912 5.70856,0.56836 1.94011,-0.6713 4.49918,-2.39426 7.66518,-5.15474 1.2993,-1.12534 2.19719,-1.77197 2.69637,-1.94256 0.68118,-0.23272 1.25664,0.0618 1.72693,0.88273 0.46973,0.82008 0.70926,1.97252 0.71896,3.45813 0.009,1.35076 -0.23184,2.58617 -0.72232,3.70718 -0.65513,1.48575 -2.26858,3.26333 -4.85199,5.34083 -2.60048,2.05693 -5.11941,3.52549 -7.55489,4.39953 -4.22378,1.51581 -7.65099,0.33127 -10.26023,-3.58227 -2.60677,-3.94222 -3.93431,-9.46384 -3.97137,-16.54436 -0.0394,-7.52874 1.32903,-14.07941 4.09047,-19.62629 2.75903,-5.5472 5.92505,-8.84107 9.48957,-9.90426 2.12737,-0.63445 4.07097,-0.46394 5.83355,0.50605 1.77201,0.96099 3.08675,2.17372 3.94852,3.63907 1.21416,2.13157 2.22166,4.91277 3.02403,8.34384 0.54592,2.39326 0.82964,5.27426 0.85162,8.64573 0,0 0.0287,4.4014 0.0287,4.4014 m -5.73214,-8.54412 c -0.80672,-2.7354 -1.85391,-4.63367 -3.14346,-5.69374 -1.29366,-1.0973 -2.833,-1.37003 -4.62091,-0.81389 -1.77862,0.55329 -3.31967,1.79032 -4.62063,3.71406 -1.30548,1.89566 -2.36785,4.49783 -3.18525,7.80742 0,0 15.57025,-5.01385 15.57025,-5.01385"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7042"
|
||||
d="m 438.50105,238.91477 c 0,0 0.33366,38.11886 0.33366,38.11886 0,0 4.5189,-1.55424 4.5189,-1.55424 1.06904,-0.36769 1.8298,-0.17153 2.28417,0.58709 0.46789,0.72139 0.70825,1.80481 0.72144,3.25104 0.0129,1.41496 -0.20635,2.65984 -0.65806,3.73554 -0.43823,1.04046 -1.19112,1.75156 -2.26052,2.13313 0,0 -13.68028,4.8812 -13.68028,4.8812 -1.1116,0.39663 -1.91344,0.23005 -2.40353,-0.50122 -0.47582,-0.76976 -0.72,-1.89742 -0.73214,-3.38218 -0.0119,-1.45226 0.21273,-2.71134 0.67337,-3.77635 0.47483,-1.10101 1.26883,-1.84247 2.38003,-2.22466 0,0 4.62789,-1.59173 4.62789,-1.59173 0,0 -0.3275,-38.34793 -0.3275,-38.34793 0,0 -4.6215,1.35761 -4.6215,1.35761 -1.10965,0.32602 -1.91007,0.11077 -2.39927,-0.64712 -0.47496,-0.79518 -0.71868,-1.93224 -0.73077,-3.41027 -0.0121,-1.47774 0.21202,-2.73263 0.67186,-3.76384 0.47403,-1.06604 1.26664,-1.75469 2.37589,-2.06634 0,0 13.65257,-3.78793 13.65257,-3.78793 1.06727,-0.29982 1.82661,-0.0734 2.27992,0.67815 0.4671,0.74675 0.70703,1.83959 0.72016,3.27935 0.0131,1.44004 -0.20565,2.68084 -0.65663,3.72319 -0.43753,1.00825 -1.18918,1.66931 -2.25681,1.98288 0,0 -4.51285,1.3257 -4.51285,1.3257"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7044"
|
||||
d="m 455.88348,238.41146 c 0,0 0.0257,2.69003 0.0257,2.69003 0.68312,-1.72546 1.29991,-2.94833 1.85075,-3.67036 0.56356,-0.75579 1.21217,-1.24275 1.94542,-1.46144 0.62141,-0.18526 1.23821,-0.0305 1.85047,0.46347 0.61126,0.49329 1.21121,1.3268 1.79992,2.49991 0.71137,-1.56555 1.43158,-2.77864 2.16064,-3.64047 0.7408,-0.89447 1.49699,-1.45627 2.26852,-1.68643 1.53816,-0.45872 2.79097,0.0945 3.76153,1.65542 1.28104,2.03781 1.94044,5.01712 1.98128,8.9439 0,0 0.21643,20.82129 0.21643,20.82129 0.85204,-0.29305 1.48772,-0.0721 1.90821,0.66181 0.42,0.73316 0.63698,1.77834 0.65128,3.13628 0.0143,1.35811 -0.17928,2.54755 -0.58098,3.56911 -0.40256,0.99258 -1.09593,1.66483 -2.08175,2.01658 0,0 -3.92315,1.3998 -3.92315,1.3998 0,0 -0.30125,-29.5317 -0.30125,-29.5317 -0.0146,-1.42806 -0.13917,-2.37963 -0.37387,-2.85506 -0.23487,-0.47561 -0.58859,-0.64006 -1.06152,-0.49297 -0.46004,0.14313 -0.88398,0.55012 -1.27173,1.2214 -0.49476,0.91973 -1.09234,2.54691 -1.79337,4.88434 0,0 0.1894,18.96164 0.1894,18.96164 0.8724,-0.30006 1.52302,-0.079 1.95307,0.662 0.42956,0.74027 0.65113,1.79714 0.66503,3.17137 0.0139,1.37439 -0.18487,2.57895 -0.59663,3.61451 -0.4126,1.00623 -1.12276,1.68951 -2.13218,2.04968 0,0 -4.01729,1.43339 -4.01729,1.43339 0,0 -0.29261,-29.88883 -0.29261,-29.88883 -0.0139,-1.41455 -0.14767,-2.35965 -0.40153,-2.83564 -0.24053,-0.51127 -0.60278,-0.69179 -1.08713,-0.54115 -0.49887,0.15521 -0.98803,0.66317 -1.46747,1.52462 -0.4804,0.8318 -1.05239,2.39108 -1.71646,4.68046 0,0 0.18368,19.19395 0.18368,19.19395 0.89368,-0.30737 1.55989,-0.0863 1.99991,0.66201 0.45342,0.74274 0.68669,1.80921 0.70018,3.2002 0.0135,1.39115 -0.19765,2.61376 -0.6338,3.6687 -0.42312,1.02036 -1.1508,1.7151 -2.18483,2.08405 0,0 -3.90344,1.39277 -3.90344,1.39277 -1.04783,0.37387 -1.79708,0.20173 -2.24591,-0.51779 -0.46384,-0.74661 -0.70262,-1.84073 -0.71594,-3.28161 -0.013,-1.40935 0.19719,-2.62896 0.63021,-3.65799 0.43218,-1.05897 1.10915,-1.74654 2.02961,-2.06313 0,0 -0.21801,-23.27593 -0.21801,-23.27593 -0.91971,0.2877 -1.60455,0.0483 -2.05317,-0.71937 -0.44909,-0.76843 -0.68033,-1.85564 -0.69331,-3.26087 -0.013,-1.40499 0.20412,-2.61343 0.65085,-3.62449 0.43169,-1.03656 1.17158,-1.71162 2.21788,-2.0255 0,0 4.10732,-1.23196 4.10732,-1.23196"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7046"
|
||||
d="m 490.87185,268.26248 c 0,0 -0.0238,-2.12947 -0.0238,-2.12947 -0.96684,1.56112 -2.04221,2.85176 -3.22705,3.87118 -1.18857,1.05267 -2.27482,1.75638 -3.25773,2.1092 -2.1433,0.7693 -3.90736,0.0916 -5.28616,-2.04226 -1.38398,-2.17145 -2.09463,-4.85752 -2.12832,-8.05178 -0.041,-3.88602 0.78508,-7.77051 2.47177,-11.63982 1.69085,-3.8838 4.03967,-6.29946 7.03403,-7.25585 1.19331,-0.3811 2.57099,-0.52435 4.13102,-0.43103 0,0 -0.0243,-2.16861 -0.0243,-2.16861 -0.0152,-1.35698 -0.28175,-2.38328 -0.80016,-3.07972 -0.50639,-0.70131 -1.46852,-0.83189 -2.89014,-0.3897 -1.16973,0.36389 -2.6864,1.37311 -4.5546,3.03337 -0.69844,0.60846 -1.2438,0.97457 -1.63533,1.09754 -0.5358,0.16833 -0.99846,-0.12206 -1.38767,-0.87192 -0.37678,-0.78462 -0.57264,-1.86678 -0.58731,-3.24582 -0.008,-0.77933 0.0501,-1.47376 0.17529,-2.08321 0.1251,-0.60911 0.30385,-1.1141 0.53618,-1.51496 0.23184,-0.43046 0.71786,-0.99743 1.45701,-1.70003 0.98321,-0.92446 1.98458,-1.71816 3.00395,-2.38162 1.01611,-0.69116 1.93495,-1.15887 2.7573,-1.40418 2.44294,-0.72858 4.33815,-0.0679 5.69456,1.97299 1.36388,2.00056 2.06787,5.09484 2.11563,9.28942 0,0 0.21151,18.5876 0.21151,18.5876 0,0 0.65945,-0.22681 0.65945,-0.22681 0.92741,-0.31897 1.58879,-0.11998 1.98565,0.5958 0.40854,0.68149 0.62043,1.69497 0.63598,3.04114 0.0152,1.31705 -0.17178,2.47066 -0.56118,3.4616 -0.37775,0.95836 -1.02971,1.60314 -1.95738,1.93413 0,0 -4.54817,1.62282 -4.54817,1.62282 m -0.18218,-16.27076 c -1.57456,-0.18741 -3.03025,-0.0602 -4.36568,0.38353 -1.61175,0.53558 -2.9938,1.90828 -4.14364,4.12194 -0.71713,1.41252 -1.06983,2.71889 -1.05695,3.91694 0.009,0.8687 0.19313,1.51219 0.55118,1.93012 0.66205,0.76298 1.55791,0.94835 2.68579,0.55802 0.95654,-0.33103 2.02809,-1.13477 3.2135,-2.40861 1.19412,-1.27383 2.24686,-2.80822 3.15946,-4.60277 0,0 -0.0437,-3.89917 -0.0437,-3.89917"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7048"
|
||||
d="m 513.83107,223.64708 c 0,0 -0.0321,-2.60694 -0.0321,-2.60694 0,0 4.24921,-1.27452 4.24921,-1.27452 0.86692,-0.25998 1.48579,-0.0345 1.85799,0.67552 0.38309,0.67764 0.58268,1.66515 0.59908,2.9632 0.016,1.27005 -0.15729,2.37215 -0.52017,3.30702 -0.35202,0.90414 -0.96092,1.49191 -1.82805,1.76307 0,0 -0.61656,0.19283 -0.61656,0.19283 0,0 0.3963,31.78092 0.3963,31.78092 0.0383,3.07233 -0.1991,5.84676 -0.71289,8.32595 -0.50258,2.50775 -1.30016,4.80111 -2.39487,6.88205 -1.09848,2.08802 -2.35446,3.40535 -3.76947,3.94832 0,0 -4.20721,1.61434 -4.20721,1.61434 -0.90127,0.34581 -1.55322,0.17312 -1.95437,-0.5193 -0.389,-0.66876 -0.59138,-1.65732 -0.60684,-2.96502 -0.0158,-1.33662 0.16113,-2.49707 0.53047,-3.48063 0.38146,-0.95795 1.02342,-1.60387 1.92446,-1.93799 0,0 4.09797,-1.51959 4.09797,-1.51959 1.12773,-0.41818 1.99206,-1.47339 2.59485,-3.16418 0.6016,-1.68753 0.88825,-3.64562 0.86083,-5.87641 0,0 -0.0527,-4.28868 -0.0527,-4.28868 -0.79402,1.54526 -1.61175,2.78547 -2.45334,3.71951 -0.83173,0.93214 -1.69344,1.55874 -2.58528,1.87869 -2.53138,0.90814 -4.68912,-0.3421 -6.46539,-3.76745 -1.78479,-3.47022 -2.71501,-8.19944 -2.78452,-14.17311 -0.0698,-5.99942 0.74291,-11.29294 2.43134,-15.86475 1.6791,-4.57629 3.78635,-7.2342 6.31459,-7.98783 0.93884,-0.27979 1.83117,-0.21544 2.67743,0.19177 0.8558,0.37421 1.67211,1.10227 2.44924,2.18321 m 0.18895,16.81679 c -0.0397,-3.22458 -0.57346,-5.86075 -1.60346,-7.91342 -1.02083,-2.06186 -2.23403,-2.87672 -3.64183,-2.43909 -1.41359,0.43948 -2.61815,2.01503 -3.61171,4.73172 -0.98452,2.72148 -1.4586,5.72173 -1.41993,8.9951 0.039,3.30339 0.58054,5.9872 1.62246,8.04652 1.05092,2.02074 2.28478,2.78371 3.69937,2.29449 1.4088,-0.48717 2.59406,-2.07774 3.55781,-4.76688 0.97229,-2.71336 1.4373,-5.6943 1.39729,-8.94844"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7050"
|
||||
d="m 540.11181,236.19855 c 0,0 -14.17571,4.74678 -14.17571,4.74678 0.39598,2.12039 1.06655,3.70874 2.0101,4.76439 0.95245,1.04897 2.21683,1.29937 3.78949,0.75521 1.28429,-0.44438 2.97443,-1.71113 5.06396,-3.7914 0.85848,-0.84849 1.45291,-1.3286 1.78475,-1.44201 0.45294,-0.15474 0.83898,0.11397 1.1584,0.80553 0.3191,0.69101 0.48673,1.64075 0.5031,2.84977 0.0149,1.09925 -0.1376,2.09168 -0.45762,2.9779 -0.4274,1.17397 -1.49195,2.53431 -3.19995,4.08586 -1.71744,1.53209 -3.38257,2.58934 -4.99438,3.16779 -2.79108,1.00165 -5.0682,-0.14146 -6.81995,-3.44725 -1.74841,-3.32527 -2.66198,-7.85839 -2.73457,-13.58545 -0.0772,-6.09039 0.78143,-11.32407 2.56808,-15.68474 1.78745,-4.3669 3.86227,-6.89434 6.21974,-7.59751 1.4088,-0.42014 2.70212,-0.19498 3.88143,0.67196 1.18643,0.86072 2.07063,1.90611 2.65495,3.13691 0.82406,1.78934 1.51493,4.09853 2.07343,6.92778 0.38048,1.97331 0.58916,4.3313 0.62629,7.07581 0,0 0.0485,3.58267 0.0485,3.58267 m -3.88051,-7.22718 c -0.55565,-2.26143 -1.2656,-3.85327 -2.13087,-4.7749 -0.86777,-0.95155 -1.89277,-1.24457 -3.07652,-0.87637 -1.17666,0.36604 -2.19027,1.29725 -3.03946,2.79568 -0.85185,1.47453 -1.5375,3.53206 -2.05595,6.17324 0,0 10.3028,-3.31765 10.3028,-3.31765"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
style="display:none"
|
||||
inkscape:label="Image (name)"
|
||||
id="layer11"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New"
|
||||
id="text14133">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 290.77223,304.74825 c 0,0 0,32.31662 0,32.31662 0,0 5.87857,-2.13185 5.87857,-2.13185 0.40465,-0.14674 0.69438,-0.12402 0.86947,0.0681 0.17497,0.17071 0.26242,0.45829 0.26244,0.86282 -2e-5,0.38327 -0.0874,0.73459 -0.26244,1.05416 -0.17509,0.31972 -0.46482,0.5537 -0.86947,0.70197 0,0 -13.61665,4.98933 -13.61665,4.98933 -0.42075,0.15417 -0.72258,0.13428 -0.9052,-0.06 -0.18272,-0.19433 -0.27412,-0.48744 -0.27411,-0.87928 -1e-5,-0.41357 0.0914,-0.77331 0.27411,-1.07911 0.18262,-0.32736 0.48445,-0.56735 0.9052,-0.71994 0,0 6.0052,-2.17777 6.0052,-2.17777 0,0 0,-32.39447 0,-32.39447 0,0 -6.0052,1.90797 -6.0052,1.90797 -0.42075,0.13372 -0.72258,0.10996 -0.9052,-0.0714 -0.18272,-0.20317 -0.27412,-0.51163 -0.27411,-0.92526 -1e-5,-0.41355 0.0914,-0.76884 0.27411,-1.06575 0.18262,-0.31845 0.48445,-0.54373 0.9052,-0.67588 0,0 13.61665,-4.27499 13.61665,-4.27499 0.40465,-0.127 0.69438,-0.0902 0.86947,0.11043 0.17497,0.17924 0.26242,0.47109 0.26244,0.87558 -2e-5,0.40459 -0.0874,0.76232 -0.26244,1.07333 -0.17509,0.28993 -0.46482,0.49917 -0.86947,0.6277 0,0 -5.87857,1.86774 -5.87857,1.86774"
|
||||
id="path14140" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 306.92675,306.55175 c 0,0 0,2.67986 0,2.67986 1.40003,-2.87625 2.80101,-4.53947 4.20289,-4.99685 0.84101,-0.27434 1.57685,-0.14959 2.20819,0.37302 0.63018,0.50092 1.1566,1.40903 1.57974,2.72378 0.71685,-1.69138 1.43861,-3.00815 2.16526,-3.95142 0.7378,-0.96608 1.47405,-1.5684 2.20876,-1.80813 1.14953,-0.37499 2.06265,-0.0655 2.74123,0.9259 0.89011,1.26835 1.33432,2.825 1.33433,4.6724 0,0 0,18.0741 0,18.0741 0,0 1.32918,-0.48202 1.32918,-0.48202 0.37346,-0.13543 0.64087,-0.10964 0.80249,0.0773 0.16149,0.1664 0.24221,0.4439 0.24224,0.83254 -3e-5,0.36823 -0.0808,0.70459 -0.24224,1.00917 -0.16162,0.30475 -0.42903,0.52553 -0.80249,0.66237 0,0 -2.90839,1.06568 -2.90839,1.06568 0,0 0,-20.46113 0,-20.46113 -2e-5,-1.31673 -0.24507,-2.32553 -0.73568,-3.02713 -0.49135,-0.70254 -1.05913,-0.94797 -1.70374,-0.73524 -0.58247,0.19227 -1.19764,0.75726 -1.8457,1.69604 -0.6493,0.9199 -1.38919,2.56622 -2.22024,4.94195 0,0 0,17.3523 0,17.3523 0,0 1.3415,-0.48649 1.3415,-0.48649 0.38232,-0.13865 0.65607,-0.11371 0.8215,0.0747 0.16532,0.16767 0.24796,0.44807 0.24797,0.8413 -1e-5,0.37255 -0.0826,0.71319 -0.24797,1.02208 -0.16543,0.30904 -0.43918,0.53359 -0.8215,0.67367 0,0 -2.97744,1.09098 -2.97744,1.09098 0,0 0,-20.5158 0,-20.5158 -10e-6,-1.39476 -0.25733,-2.45395 -0.77253,-3.1784 -0.50307,-0.7506 -1.0715,-1.02182 -1.70561,-0.81257 -0.58338,0.19258 -1.16121,0.68673 -1.7335,1.4832 -0.79496,1.12309 -1.63094,2.88106 -2.50825,5.27652 0,0 0,17.56098 0,17.56098 0,0 1.39351,-0.50535 1.39351,-0.50535 0.39153,-0.14199 0.67186,-0.11795 0.84127,0.072 0.16931,0.16894 0.25394,0.45233 0.25395,0.85026 -10e-6,0.377 -0.0846,0.72208 -0.25395,1.0354 -0.16941,0.31346 -0.44974,0.54191 -0.84127,0.68538 0,0 -4.455,1.63237 -4.455,1.63237 -0.39697,0.14545 -0.68175,0.12306 -0.85404,-0.0675 -0.17239,-0.19062 -0.25861,-0.47625 -0.25861,-0.85683 0,-0.40172 0.0862,-0.75019 0.25861,-1.04538 0.17229,-0.31613 0.45707,-0.54619 0.85404,-0.69015 0,0 1.40566,-0.50976 1.40566,-0.50976 0,0 0,-22.02661 0,-22.02661 0,0 -1.40566,0.46583 -1.40566,0.46583 -0.39697,0.13157 -0.68175,0.0992 -0.85404,-0.0974 -0.17239,-0.19662 -0.25861,-0.49584 -0.25861,-0.8976 0,-0.38054 0.0862,-0.72601 0.25861,-1.03629 0.17229,-0.31008 0.45707,-0.53015 0.85404,-0.66022 0,0 3.06149,-1.00289 3.06149,-1.00289"
|
||||
id="path14142" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 341.55437,321.16678 c 0,0 0,-3.62699 0,-3.62699 -2.17583,3.87291 -4.51596,6.27757 -7.0237,7.20015 -1.83227,0.67408 -3.27105,0.43232 -4.31124,-0.73067 -1.0434,-1.1869 -1.56629,-2.91222 -1.56629,-5.17318 0,-2.48503 0.68882,-4.89489 2.06231,-7.22253 1.36795,-2.31825 3.35505,-3.9208 5.95041,-4.80953 0.69672,-0.23856 1.45188,-0.41679 2.26509,-0.53489 0.81121,-0.13772 1.68585,-0.20766 2.62342,-0.20985 0,0 0,-4.07662 0,-4.07662 -2e-5,-1.37882 -0.37947,-2.45115 -1.13965,-3.21827 -0.76194,-0.7688 -1.90808,-0.90154 -3.44237,-0.39518 -1.17945,0.38931 -2.84126,1.51364 -4.99257,3.38085 -0.3904,0.3327 -0.64074,0.51747 -0.7507,0.55406 -0.19558,0.0652 -0.3668,3.9e-4 -0.51363,-0.19445 -0.13465,-0.19895 -0.202,-0.48128 -0.20199,-0.84695 -1e-5,-0.3453 0.0612,-0.63975 0.18363,-0.88328 0.17131,-0.36105 0.86176,-1.00434 2.06822,-1.92757 1.89239,-1.46888 3.31682,-2.35756 4.27913,-2.67154 1.90441,-0.62126 3.38216,-0.31269 4.43882,0.92018 1.05329,1.20909 1.5787,2.79915 1.57872,4.773 0,0 0,16.62862 0,16.62862 0,0 1.97614,-0.71664 1.97614,-0.71664 0.36334,-0.13177 0.62098,-0.10607 0.77314,0.077 0.15205,0.16316 0.22807,0.43326 0.22809,0.81038 -2e-5,0.35731 -0.0761,0.68284 -0.22809,0.97668 -0.15216,0.294 -0.4098,0.50756 -0.77314,0.64069 0,0 -3.48375,1.2765 -3.48375,1.2765 m 0,-12.52962 c -0.69996,-0.0967 -1.44303,-0.0891 -2.22949,0.0233 -0.78834,0.11262 -1.62047,0.32041 -2.49673,0.62375 -2.20674,0.76397 -3.94122,2.16401 -5.19605,4.20202 -0.95337,1.53165 -1.43106,3.1323 -1.43105,4.79877 -1e-5,1.54453 0.36138,2.71501 1.08302,3.51015 0.73228,0.78902 1.7913,0.93038 3.17399,0.42691 1.31676,-0.47947 2.5323,-1.35466 3.64772,-2.62381 1.12362,-1.28931 2.27325,-3.09547 3.44859,-5.41563 0,0 0,-5.54541 0,-5.54541"
|
||||
id="path14144" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 363.37657,292.52517 c 0,0 0,-4.46549 0,-4.46549 0,0 3.26058,-1.06811 3.26058,-1.06811 0.32917,-0.10781 0.56487,-0.0698 0.70734,0.11412 0.14235,0.1838 0.21351,0.45813 0.21353,0.82302 -2e-5,0.34574 -0.0711,0.65733 -0.21353,0.93491 -0.14247,0.27777 -0.37817,0.47117 -0.70734,0.58025 0,0 -1.86625,0.61846 -1.86625,0.61846 0,0 0,24.27579 0,24.27579 -2e-5,1.62032 -0.19884,3.14134 -0.59683,4.56437 -0.26563,0.94969 -0.7088,1.99622 -1.33026,3.14072 -0.62268,1.14668 -1.19079,2.01258 -1.70405,2.59672 -0.51409,0.58507 -1.20267,1.04343 -2.06685,1.37504 0,0 -4.03689,1.54904 -4.03689,1.54904 -0.34152,0.13104 -0.58649,0.1075 -0.73469,-0.0709 -0.14829,-0.15886 -0.22246,-0.42461 -0.22245,-0.79717 -1e-5,-0.37258 0.0741,-0.70475 0.22245,-0.99644 0.1482,-0.29158 0.39317,-0.50222 0.73469,-0.63197 0,0 4.08746,-1.52372 4.08746,-1.52372 0.83042,-0.31553 1.57488,-0.96721 2.23397,-1.95413 0.66885,-0.98911 1.21963,-2.27103 1.65294,-3.84567 0.24415,-0.9032 0.36616,-1.98282 0.36618,-3.23934 0,0 0,-7.30717 0,-7.30717 -1.50064,4.12055 -3.44508,6.62347 -5.84129,7.49922 -1.95926,0.71605 -3.66187,0.0829 -5.10374,-1.90912 -1.43671,-2.02462 -2.15742,-4.82517 -2.15742,-8.39501 0,-3.56981 0.72071,-6.859 2.15742,-9.85774 1.44187,-2.98939 3.14448,-4.80022 5.10374,-5.43943 2.39621,-0.78171 4.34065,0.36653 5.84129,3.42973 m 0,7.33618 c -2e-5,-2.86099 -0.5661,-5.08622 -1.70124,-6.6799 -1.12797,-1.60294 -2.48445,-2.14543 -4.0723,-1.62139 -1.59565,0.52668 -2.97118,1.98968 -4.12378,4.39343 -1.15668,2.39261 -1.73656,5.03846 -1.73655,7.93123 -1e-5,2.91249 0.57987,5.17691 1.73655,6.78901 1.1526,1.58686 2.52813,2.0886 4.12378,1.51152 1.58785,-0.57426 2.94433,-2.05505 4.0723,-4.43824 1.13514,-2.39819 1.70122,-5.02464 1.70124,-7.88566"
|
||||
id="path14146" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 385.85611,293.37466 c 0,0 -13.55496,4.71571 -13.55496,4.71571 0.2372,3.02382 0.96927,5.26873 2.19279,6.73218 1.2295,1.435 2.74111,1.82321 4.53079,1.17154 0.99106,-0.36087 2.02623,-1.02925 3.10508,-2.00348 1.07513,-0.97087 1.94922,-2.05434 2.62395,-3.25093 0.19693,-0.351 0.36786,-0.55242 0.51284,-0.60437 0.16557,-0.0593 0.31039,0.01 0.43448,0.20823 0.12401,0.17941 0.18601,0.42768 0.18602,0.74485 -10e-6,0.31721 -0.0827,0.65493 -0.24805,1.01332 -0.49671,1.11372 -1.38342,2.31505 -2.66343,3.60658 -1.27482,1.27424 -2.59161,2.16252 -3.95089,2.66259 -2.28921,0.84219 -4.21494,0.2119 -5.77044,-1.90319 -1.55233,-2.14839 -2.33133,-5.14665 -2.33133,-8.98687 0,-3.4963 0.73037,-6.7413 2.18612,-9.72476 1.45984,-2.97335 3.25394,-4.80294 5.37664,-5.49548 2.17154,-0.70841 3.94716,-0.0213 5.33343,2.05084 1.38014,2.04439 2.0576,5.06314 2.03696,9.06324 m -1.32018,-1.9248 c -0.25953,-2.51086 -0.94567,-4.39376 -2.06125,-5.65048 -1.10911,-1.26462 -2.43784,-1.64358 -3.98896,-1.13166 -1.55879,0.51451 -2.90637,1.77483 -4.03999,3.78444 -1.13768,2.01684 -1.8481,4.41869 -2.1284,7.20193 0,0 12.2186,-4.20423 12.2186,-4.20423"
|
||||
id="path14148" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="busybox"
|
||||
style="display:none">
|
||||
style="display:inline">
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
@@ -1154,7 +1343,7 @@
|
||||
style="display:inline">
|
||||
<g
|
||||
sodipodi:type="inkscape:box3d"
|
||||
style="fill:#dc7000;fill-opacity:0.50666665;stroke:#000000;stroke-linejoin:round;stroke-opacity:1;display:inline"
|
||||
style="fill:#dc7000;fill-opacity:0.6956522;stroke:#000000;stroke-linejoin:round;stroke-opacity:1;display:inline"
|
||||
id="g4222"
|
||||
inkscape:perspectiveID="#perspective3054"
|
||||
inkscape:corner0="0.22429094 : 0.11834566 : 0 : 1"
|
||||
@@ -1162,81 +1351,40 @@
|
||||
<path
|
||||
sodipodi:type="inkscape:box3dside"
|
||||
id="path4232"
|
||||
style="fill:#dc7000;fill-opacity:0.50666665;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
style="fill:#dc7000;fill-opacity:0.6956522;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
inkscape:box3dsidetype="13"
|
||||
d="M 252.05613,280.2201 384.72319,334.81304 666.79274,224.25249 541.87079,199.19901 z" />
|
||||
<path
|
||||
sodipodi:type="inkscape:box3dside"
|
||||
id="path4224"
|
||||
style="fill:#dc7000;fill-opacity:0.50666665;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
style="fill:#dc7000;fill-opacity:0.6956522;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
inkscape:box3dsidetype="6"
|
||||
d="m 252.05613,231.66533 0,48.55477 289.81466,-81.02109 0,-33.71629 z" />
|
||||
<path
|
||||
sodipodi:type="inkscape:box3dside"
|
||||
id="path4234"
|
||||
style="fill:#dc7000;fill-opacity:0.50666665;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
style="fill:#dc7000;fill-opacity:0.6956522;fill-rule:evenodd;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
inkscape:box3dsidetype="11"
|
||||
d="m 541.87079,165.48272 124.92195,20.6172 0,38.15257 -124.92195,-25.05348 z" />
|
||||
<path
|
||||
sodipodi:type="inkscape:box3dside"
|
||||
id="path4226"
|
||||
style="fill:#dc7000;fill-opacity:0.50666665;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
style="fill:#dc7000;fill-opacity:0.6956522;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
inkscape:box3dsidetype="5"
|
||||
d="m 252.05613,231.66533 132.66706,44.8271 282.06955,-90.39251 -124.92195,-20.6172 z" />
|
||||
<path
|
||||
sodipodi:type="inkscape:box3dside"
|
||||
id="path4230"
|
||||
style="fill:#dc7000;fill-opacity:0.50666665;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
style="fill:#dc7000;fill-opacity:0.6956522;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
inkscape:box3dsidetype="14"
|
||||
d="m 384.72319,276.49243 0,58.32061 282.06955,-110.56055 0,-38.15257 z" />
|
||||
<path
|
||||
sodipodi:type="inkscape:box3dside"
|
||||
id="path4228"
|
||||
style="fill:#dc7000;fill-opacity:0.50666665;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
style="fill:#dc7000;fill-opacity:0.6956522;stroke:#000000;stroke-linejoin:round;stroke-opacity:1"
|
||||
inkscape:box3dsidetype="3"
|
||||
d="m 252.05613,231.66533 132.66706,44.8271 0,58.32061 -132.66706,-54.59294 z" />
|
||||
</g>
|
||||
<g
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
|
||||
id="text7405"
|
||||
transform="matrix(0.86928132,0,0,0.86928132,68.726388,34.325549)">
|
||||
<path
|
||||
d="m 417.72187,271.67771 c 0.45964,-0.87898 0.95501,-1.58682 1.48596,-2.12375 0.55424,-0.54392 1.14379,-0.91726 1.7685,-1.12036 1.07876,-0.35057 1.95161,-0.2027 2.61991,0.44206 0.69087,0.63597 1.03586,1.98145 1.03589,4.03727 0,0 0,7.25115 0,7.25115 -3e-5,2.05593 -0.34502,3.64783 -1.03589,4.77721 -0.6683,1.09532 -1.54115,1.83155 -2.61991,2.20805 -0.98557,0.34403 -1.78059,0.29979 -2.38395,-0.13385 -0.60435,-0.43424 -1.05214,-1.48442 -1.34284,-3.15097 -0.16979,-1.1199 -0.50935,-1.91599 -1.01928,-2.38829 -0.9976,-0.92643 -2.40092,-1.46608 -4.21428,-1.61771 -1.79715,-0.16049 -3.61486,0.0653 -5.45337,0.67999 -2.29773,0.76835 -4.41987,2.04969 -6.36352,3.84723 -1.95316,1.80642 -3.68595,4.26332 -5.19549,7.37284 -1.51522,3.12131 -2.27496,6.47967 -2.27496,10.06631 0,0 0,5.77048 0,5.77048 0,4.28088 1.37679,7.34109 4.11635,9.17127 2.74635,1.8082 6.51717,1.79213 11.2834,-0.0225 2.81766,-1.07278 5.1872,-2.41185 7.11649,-4.017 1.11898,-0.92957 2.30747,-2.37459 3.56482,-4.33233 0.77171,-1.18439 1.37356,-1.98235 1.80635,-2.39529 0.43226,-0.44034 0.924,-0.76308 1.47501,-0.96835 0.98018,-0.36512 1.83884,-0.25397 2.57676,0.33193 0.73643,0.58484 1.10414,1.4594 1.10418,2.62451 -4e-5,1.16516 -0.49832,2.60348 -1.49676,4.31825 -1.4548,2.5064 -3.33495,4.76638 -5.64662,6.78184 -3.12807,2.73423 -6.61268,4.85827 -10.46302,6.36663 -4.53994,1.7785 -8.67566,2.32306 -12.39372,1.61343 -3.03035,-0.56053 -5.62935,-2.30057 -7.78841,-5.22863 -2.17061,-2.97285 -3.26028,-6.69992 -3.26028,-11.16928 0,0 0,-6.09058 0,-6.09058 0,-4.6738 0.97164,-9.36038 2.90802,-14.04301 1.95316,-4.69804 4.63314,-8.68963 8.02553,-11.97092 3.36399,-3.25375 6.90127,-5.47379 10.60692,-6.67212 2.21183,-0.71517 4.26347,-1.08158 6.15737,-1.10215 1.9092,-0.0564 3.67553,0.23986 5.30084,0.88669"
|
||||
id="path7412"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 466.70409,284.11603 c -4e-5,3.10053 -0.70271,6.37256 -2.11204,9.826 -1.39335,3.43214 -3.49325,6.5661 -6.31177,9.40829 -2.81823,2.82872 -5.79051,4.86062 -8.92029,6.08721 -3.13367,1.22811 -6.1576,1.54546 -9.06886,0.9409 -2.93374,-0.63654 -5.18367,-2.17957 -6.73746,-4.63284 -1.56014,-2.46323 -2.3426,-5.36517 -2.34258,-8.69833 -2e-5,-3.3882 0.7941,-6.99172 2.37743,-10.79875 1.5768,-3.81873 3.82638,-7.15944 6.73687,-10.01746 2.91098,-2.84395 5.92341,-4.78983 9.0346,-5.84739 3.10768,-1.05629 6.06917,-1.12915 8.88765,-0.23026 2.81875,0.85825 4.92959,2.59617 6.34441,5.21111 1.40933,2.57869 2.112,5.4934 2.11204,8.75152 m -6.60014,2.45977 c -3e-5,-2.62464 -0.76966,-4.76021 -2.31368,-6.41189 -2.11994,-2.23039 -4.9249,-2.73963 -8.43028,-1.50955 -3.11119,1.09182 -5.72735,3.2159 -7.83793,6.37866 -2.1224,3.18051 -3.18806,6.37399 -3.18806,9.56707 0,2.61999 1.0771,4.674 3.22219,6.15574 2.13302,1.44634 4.73755,1.57892 7.8038,0.41099 3.06347,-1.16686 5.61932,-3.24823 7.67767,-6.23879 2.04698,-3.0006 3.06626,-5.78055 3.06629,-8.35223"
|
||||
id="path7414"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 481.95196,260.34743 c 0,0 0,2.66299 0,2.66299 1.14044,-1.62655 2.38873,-2.97832 3.74374,-4.05613 1.36996,-1.0805 2.84485,-1.88838 4.42335,-2.42497 3.60997,-1.22702 6.4403,-0.76492 8.50935,1.36751 1.63094,1.69239 2.44358,4.36389 2.44362,8.02036 0,0 0,14.31302 0,14.31302 1.25392,-0.47538 2.17704,-0.46334 2.77196,0.0342 0.59383,0.47182 0.89038,1.28043 0.89041,2.42644 -3e-5,1.12112 -0.30615,2.16157 -0.91919,3.12262 -0.59495,0.93031 -1.60482,1.67385 -3.0332,2.23111 0,0 -5.40899,2.11024 -5.40899,2.11024 -1.45658,0.56826 -2.50348,0.62196 -3.13706,0.15871 -0.6149,-0.49714 -0.92274,-1.3301 -0.92273,-2.49824 -10e-6,-1.14273 0.30783,-2.18711 0.92273,-3.13192 0.61379,-0.96849 1.56213,-1.69544 2.8423,-2.18079 0,0 0,-14.66303 0,-14.66303 -3e-5,-1.69234 -0.35406,-2.80465 -1.06319,-3.33774 -0.92799,-0.68555 -2.32454,-0.70208 -4.19518,-0.0457 -1.41952,0.49817 -2.67379,1.29592 -3.76103,2.39428 -1.07036,1.069 -2.43819,3.04122 -4.10689,5.92428 0,0 0,14.70435 0,14.70435 1.60779,-0.60954 2.64191,-0.80934 3.10733,-0.60165 0.98946,0.39156 1.48317,1.32831 1.48319,2.81107 -2e-5,1.15043 -0.32236,2.22127 -0.96792,3.21388 -0.62652,0.9609 -1.69006,1.73454 -3.1945,2.32147 0,0 -7.19176,2.80576 -7.19176,2.80576 -1.54125,0.6013 -2.64914,0.6686 -3.31968,0.19933 -0.65079,-0.50439 -0.97661,-1.35781 -0.97661,-2.55958 0,-1.46302 0.50438,-2.79167 1.51105,-3.98347 0.50229,-0.58163 1.57779,-1.18477 3.22143,-1.80792 0,0 0,-19.38913 0,-19.38913 -1.35182,0.47637 -2.35332,0.45169 -3.00159,-0.0761 -0.64944,-0.52865 -0.97458,-1.38057 -0.97458,-2.55503 0,-1.17439 0.32514,-2.2388 0.97458,-3.19197 0.66916,-0.98457 1.77475,-1.73955 3.31283,-2.26462 0,0 6.01623,-2.05369 6.01623,-2.05369"
|
||||
id="path7416"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 521.96757,254.15887 c 0,0 0,14.97869 0,14.97869 -2e-5,1.60357 0.24544,2.56759 0.73584,2.89169 0.76139,0.51136 2.1168,0.39509 4.05911,-0.34473 2.80364,-1.06789 5.37237,-2.84804 7.7113,-5.33397 0.89251,-0.95596 1.59086,-1.52809 2.09628,-1.71808 0.6958,-0.26155 1.29479,-0.1308 1.79747,0.39123 0.51917,0.51473 0.77845,1.28093 0.77848,2.2992 -3e-5,0.94726 -0.27662,1.87049 -0.83044,2.77083 -0.84992,1.44318 -2.53882,3.13186 -5.07954,5.07434 -2.54256,1.92649 -4.70294,3.24084 -6.47355,3.93476 -3.44262,1.34919 -6.0523,1.37395 -7.8094,0.0588 -1.74779,-1.35347 -2.62505,-3.50271 -2.62503,-6.44251 0,0 0,-16.5731 0,-16.5731 0,0 -2.05882,0.72547 -2.05882,0.72547 -1.37945,0.48611 -2.37084,0.49025 -2.97081,0.0103 -0.58222,-0.51196 -0.87369,-1.33661 -0.87369,-2.47329 0,-1.1119 0.29147,-2.11405 0.87369,-3.00531 0.59997,-0.92076 1.59136,-1.6167 2.97081,-2.08763 0,0 2.05882,-0.70279 2.05882,-0.70279 0,0 0,-6.79827 0,-6.79827 -2e-5,-1.81283 0.25877,-3.18359 0.77578,-4.11122 0.53464,-0.95657 1.22474,-1.57143 2.06939,-1.84519 0.82422,-0.26705 1.49131,-0.0937 2.00219,0.51875 0.52827,0.58142 0.7921,1.77073 0.79212,3.56862 0,0 0,6.74223 0,6.74223 0,0 10.18499,-3.47674 10.18499,-3.47674 1.30327,-0.44485 2.22483,-0.41358 2.76783,0.0919 0.55951,0.47491 0.83894,1.2595 0.83897,2.35437 -3e-5,1.07114 -0.27946,2.04959 -0.83897,2.93643 -0.543,0.8584 -1.46456,1.51706 -2.76783,1.97627 0,0 -10.18499,3.58889 -10.18499,3.58889"
|
||||
id="path7418"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 559.66457,265.0724 c 0,0 0,-1.65213 0,-1.65213 -1.25166,1.42773 -2.63904,2.6702 -4.16386,3.72696 -1.5321,1.08495 -2.93048,1.87615 -4.19336,2.37115 -2.75884,1.08136 -5.01666,0.94734 -6.76281,-0.41439 -1.75549,-1.39258 -2.63677,-3.34151 -2.63676,-5.84124 -10e-6,-3.04209 1.12043,-6.27245 3.34992,-9.67368 2.23124,-3.40766 5.28286,-5.79805 9.13173,-7.17622 1.53009,-0.54785 3.28974,-0.94775 5.27514,-1.20046 0,0 0,-1.68655 0,-1.68655 -10e-6,-1.0555 -0.32465,-1.80122 -0.97488,-2.23783 -0.63528,-0.44317 -1.86051,-0.34677 -3.6824,0.29254 -1.50137,0.52689 -3.45863,1.632 -5.87999,3.32289 -0.90638,0.62348 -1.61309,1.02515 -2.1188,1.20392 -0.69244,0.24484 -1.28471,0.11428 -1.77624,-0.39265 -0.47531,-0.53707 -0.71321,-1.34616 -0.71321,-2.42667 0,-0.61067 0.085,-1.16859 0.2549,-1.67355 0.16981,-0.50463 0.4074,-0.93853 0.71264,-1.30164 0.30494,-0.38615 0.93933,-0.93193 1.90127,-1.63603 1.27817,-0.92773 2.57642,-1.75559 3.89452,-2.4841 1.31272,-0.74868 2.49627,-1.30178 3.55203,-1.66067 3.1303,-1.06398 5.53509,-0.93017 7.23033,0.38846 1.70225,1.28338 2.54998,3.55047 2.55001,6.8064 0,0 0,14.41279 0,14.41279 0,0 0.83751,-0.31753 0.83751,-0.31753 1.17673,-0.44611 2.00896,-0.43296 2.49936,0.0377 0.50538,0.4413 0.75778,1.18199 0.7578,2.2226 -2e-5,1.01802 -0.25242,1.95288 -0.7578,2.80559 -0.4904,0.82527 -1.32263,1.46729 -2.49936,1.92637 0,0 -5.78769,2.25798 -5.78769,2.25798 m 0,-12.63193 c -2.00172,0.18907 -3.85997,0.59879 -5.57212,1.23078 -2.06997,0.76411 -3.86077,2.13531 -5.36767,4.11681 -0.94116,1.26201 -1.41277,2.36215 -1.41276,3.29768 -10e-6,0.67828 0.22746,1.14181 0.68191,1.39034 0.83991,0.45156 1.98707,0.39956 3.43827,-0.15328 1.22924,-0.46827 2.61072,-1.33019 4.14246,-2.5826 1.54083,-1.25266 2.9034,-2.67625 4.08991,-4.27082 0,0 0,-3.02891 0,-3.02891"
|
||||
id="path7420"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 585.74071,212.074 c 0,0 0,7.16504 0,7.16504 0,0 -5.51333,1.83108 -5.51333,1.83108 0,0 0,-7.22931 0,-7.22931 0,0 5.51333,-1.76681 5.51333,-1.76681 m 0.6264,12.63042 c 0,0 0,23.18845 0,23.18845 0,0 5.44909,-2.06588 5.44909,-2.06588 1.08113,-0.40987 1.84584,-0.38472 2.29649,0.0738 0.46445,0.43068 0.69642,1.14459 0.69644,2.14221 -2e-5,0.97595 -0.23199,1.86831 -0.69644,2.67799 -0.45065,0.78354 -1.21536,1.38608 -2.29649,1.80787 0,0 -15.69674,6.12386 -15.69674,6.12386 -1.14176,0.44544 -1.96206,0.45149 -2.45838,0.0164 -0.48157,-0.46425 -0.72262,-1.21347 -0.72262,-2.24714 0,-1.01118 0.24105,-1.92338 0.72262,-2.73565 0.49632,-0.83932 1.31662,-1.47551 2.45838,-1.90839 0,0 5.63166,-2.13509 5.63166,-2.13509 0,0 0,-16.55001 0,-16.55001 0,0 -3.76605,1.32704 -3.76605,1.32704 -1.11956,0.39453 -1.92723,0.3661 -2.42053,-0.0869 -0.4941,-0.47605 -0.74144,-1.22966 -0.74144,-2.26024 0,-1.00813 0.23961,-1.90826 0.71829,-2.69949 0.49335,-0.81758 1.30874,-1.42015 2.44368,-1.8076 0,0 8.38204,-2.86128 8.38204,-2.86128"
|
||||
id="path7422"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 606.24115,217.92025 c 0,0 0,2.2023 0,2.2023 0.7802,-1.28921 1.63467,-2.3465 2.56278,-3.17247 0.93895,-0.82801 1.95053,-1.42568 3.03396,-1.79398 2.48087,-0.84324 4.42899,-0.32348 5.85479,1.54706 1.12491,1.48534 1.68574,3.74481 1.68578,6.78271 0,0 0,11.89164 0,11.89164 0.86581,-0.32825 1.50354,-0.26909 1.91468,0.17625 0.41052,0.42401 0.61557,1.11228 0.61559,2.06526 -2e-5,0.93228 -0.21169,1.78086 -0.63547,2.54657 -0.41117,0.74092 -1.10881,1.30366 -2.09499,1.6884 0,0 -3.72827,1.45454 -3.72827,1.45454 -1.00232,0.39104 -1.7223,0.37778 -2.15784,-0.0412 -0.42258,-0.44595 -0.63409,-1.15329 -0.63408,-2.12152 -1e-5,-0.94718 0.2115,-1.79617 0.63408,-2.54619 0.42194,-0.76993 1.0741,-1.32183 1.95495,-1.65578 0,0 0,-12.1648 0,-12.1648 -2e-5,-1.40401 -0.24368,-2.34454 -0.73159,-2.82219 -0.63824,-0.61483 -1.5982,-0.69805 -2.88303,-0.2472 -0.97422,0.34189 -1.83446,0.93988 -2.57973,1.79473 -0.73331,0.83097 -1.66987,2.39371 -2.81161,4.6933 0,0 0,12.16052 0,12.16052 1.10005,-0.41704 1.80804,-0.52636 2.12679,-0.32927 0.6779,0.37779 1.01628,1.18016 1.01629,2.40776 -10e-6,0.95246 -0.22094,1.82122 -0.6633,2.60717 -0.42918,0.76053 -1.15744,1.34151 -2.18696,1.74316 0,0 -4.91118,1.91603 -4.91118,1.91603 -1.0503,0.40976 -1.80479,0.403 -2.26125,-0.0218 -0.44287,-0.45256 -0.66454,-1.17471 -0.66454,-2.16594 0,-1.2067 0.34317,-2.27482 1.02834,-3.20276 0.342,-0.45242 1.07456,-0.8914 2.19484,-1.31613 0,0 0,-16.01045 0,-16.01045 -0.92144,0.32472 -1.60371,0.25352 -2.04516,-0.21486 -0.44212,-0.46902 -0.66341,-1.18822 -0.66341,-2.1571 0,-0.96882 0.22129,-1.83077 0.66341,-2.58503 0.45568,-0.77943 1.20889,-1.34815 2.25739,-1.7061 0,0 4.10874,-1.40255 4.10874,-1.40255"
|
||||
id="path7424"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 644.42407,221.55153 c 0,0 -15.84858,5.88512 -15.84858,5.88512 0.41318,1.48367 1.14126,2.52944 2.18182,3.13726 1.04954,0.60078 2.45777,0.56327 4.21934,-0.10771 1.43657,-0.54718 3.33446,-1.76325 5.68431,-3.63848 0.96403,-0.76487 1.62951,-1.21599 1.99855,-1.3552 0.50353,-0.18992 0.92654,-0.0603 1.26941,0.38809 0.3424,0.44789 0.51345,1.10965 0.51347,1.98568 -2e-5,0.79642 -0.18329,1.54398 -0.55019,2.24339 -0.48998,0.92735 -1.68791,2.10137 -3.60292,3.52816 -1.92823,1.41649 -3.79437,2.47996 -5.59703,3.18644 -3.12825,1.22598 -5.65843,0.79547 -7.57412,-1.31227 -1.91553,-2.12687 -2.8781,-5.28997 -2.8781,-9.47861 0,-4.45685 1.04101,-8.44454 3.11177,-11.94407 2.06878,-3.49923 4.4295,-5.69213 7.07474,-6.5913 1.57787,-0.5363 3.01551,-0.58142 4.315,-0.13915 1.30587,0.43603 2.27203,1.05539 2.90198,1.85821 0.88687,1.17037 1.61767,2.74022 2.19361,4.70929 0.39141,1.37395 0.58692,3.05573 0.58694,5.04679 0,0 0,2.59836 0,2.59836 m -4.19058,-4.61262 c -0.58342,-1.55695 -1.34865,-2.60079 -2.29717,-3.13041 -0.95176,-0.55153 -2.0893,-0.59624 -3.41485,-0.13111 -1.31911,0.46293 -2.4656,1.31304 -3.43736,2.55189 -0.97511,1.22272 -1.77306,2.84546 -2.39235,4.86837 0,0 11.54173,-4.15874 11.54173,-4.15874"
|
||||
id="path7426"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 656.45255,200.78016 c 0,0 0,3.74016 0,3.74016 1.50412,-2.33039 2.68177,-3.93837 3.53714,-4.83147 0.86415,-0.89415 1.66822,-1.46695 2.41272,-1.72004 1.14134,-0.38792 2.24384,-0.0528 3.30795,1.00108 0.72205,0.70786 1.08236,1.5579 1.08238,2.55158 -2e-5,0.84085 -0.17449,1.61893 -0.52373,2.33493 -0.33846,0.69384 -0.7508,1.12733 -1.23737,1.30005 -0.43076,0.15294 -0.88492,-0.0507 -1.36261,-0.6119 -0.47857,-0.56214 -0.90658,-0.77747 -1.28377,-0.64513 -0.49233,0.17279 -1.23248,0.95394 -2.22251,2.34704 -0.98213,1.39417 -2.21771,3.40728 -3.7102,6.0464 0,0 0,9.029 0,9.029 0,0 5.07344,-1.92346 5.07344,-1.92346 0.84781,-0.32142 1.44769,-0.26977 1.8013,0.15376 0.36448,0.39943 0.54656,1.04086 0.54657,1.92471 -1e-5,0.86465 -0.18209,1.64615 -0.54657,2.3452 -0.35361,0.67633 -0.95349,1.17981 -1.8013,1.51057 0,0 -10.8696,4.24062 -10.8696,4.24062 -0.88519,0.34534 -1.52093,0.31698 -1.90547,-0.0864 -0.37306,-0.42833 -0.55977,-1.09756 -0.55977,-2.00725 0,-0.88991 0.18671,-1.683 0.55977,-2.37855 0.38454,-0.71891 1.02028,-1.24619 1.90547,-1.58179 0,0 2.17687,-0.82531 2.17687,-0.82531 0,0 0,-14.64841 0,-14.64841 0,0 -1.31833,0.46454 -1.31833,0.46454 -0.88243,0.31097 -1.51618,0.25832 -1.89952,-0.15911 -0.37188,-0.4419 -0.55801,-1.11722 -0.55801,-2.02551 0,-0.88849 0.18613,-1.67319 0.55801,-2.35341 0.38334,-0.70305 1.01709,-1.2052 1.89952,-1.50645 0,0 4.93762,-1.6855 4.93762,-1.6855"
|
||||
id="path7428"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 384.72319,334.81304 0,-58.32061 282.06955,-90.39251 0,38.15257 z"
|
||||
@@ -1280,36 +1428,83 @@
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
id="text7126"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Courier New;-inkscape-font-specification:Courier New Bold"
|
||||
transform="matrix(0.57476281,0,0,0.57476281,223.85115,141.75209)">
|
||||
id="text9181"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New"
|
||||
transform="translate(0,-6)">
|
||||
<path
|
||||
id="path7133"
|
||||
d="m 424.21557,335.98998 c 0,0 0,55.19399 0,55.19399 0,0 13.47722,-6.53014 13.47722,-6.53014 3.14312,-1.52293 5.35743,-1.94671 6.65892,-1.28244 1.33868,0.59704 2.00626,1.9199 2.00632,3.97014 -6e-5,2.00575 -0.66764,3.98769 -2.00632,5.95105 -1.30149,1.90451 -3.5158,3.6444 -6.65892,5.22447 0,0 -41.77049,20.99836 -41.77049,20.99836 -3.52678,1.77294 -6.07175,2.38156 -7.61614,1.81257 -1.50171,-0.64346 -2.25469,-2.0732 -2.25465,-4.28748 -4e-5,-2.1661 0.75294,-4.2911 2.25465,-6.36916 1.54439,-2.1417 4.08936,-4.06954 7.61614,-5.77839 0,0 14.46852,-7.01045 14.46852,-7.01045 0,0 0,-56.17707 0,-56.17707 0,0 -14.46852,5.9816 -14.46852,5.9816 -3.52678,1.45812 -6.07175,1.8395 -7.61614,1.13255 -1.50171,-0.77747 -2.25469,-2.27444 -2.25465,-4.4888 -4e-5,-2.21416 0.75294,-4.29593 2.25465,-6.23985 1.54439,-2.0036 4.08936,-3.70398 7.61614,-5.0977 0,0 41.77049,-16.43825 41.77049,-16.43825 3.14312,-1.24222 5.35743,-1.49068 6.65892,-0.75493 1.33868,0.71676 2.00626,2.09928 2.00632,4.14946 -6e-5,2.05039 -0.66764,3.99501 -2.00632,5.83877 -1.30149,1.78837 -3.5158,3.33055 -6.65892,4.62992 0,0 -13.47722,5.57177 -13.47722,5.57177"
|
||||
id="path9188"
|
||||
d="m 419.10683,281.89145 c 0,0 0,-2.03714 0,-2.03714 -3e-5,-0.69051 0.0779,-1.21057 0.23359,-1.56003 0.16977,-0.35378 0.38897,-0.57387 0.65748,-0.66032 0.26827,-0.0863 0.47992,-0.005 0.63507,0.24347 0.16913,0.24399 0.25367,0.71031 0.2537,1.39901 0,0 0,8.02408 0,8.02408 -3e-5,0.71176 -0.0846,1.24546 -0.2537,1.6012 -0.15515,0.3512 -0.3668,0.57235 -0.63507,0.66333 -0.24024,0.0815 -0.44526,0.0131 -0.61501,-0.20548 -0.15572,-0.22341 -0.24776,-0.64111 -0.27606,-1.25309 -0.0708,-1.90988 -0.71598,-3.41113 -1.93866,-4.50643 -1.6562,-1.51414 -3.55054,-1.92872 -5.68694,-1.23502 -1.40743,0.45705 -2.7403,1.39227 -3.99772,2.80806 -0.93873,1.03358 -1.68859,2.17121 -2.24836,3.41229 -0.97438,2.15669 -1.75138,4.45228 -2.32971,6.88527 -0.4158,1.79161 -0.62389,3.72591 -0.62389,5.80133 0,0 0,5.20043 0,5.20043 0,4.43391 1.00955,7.91984 3.01993,10.44682 1.99887,2.48909 4.30676,3.23169 6.91744,2.24404 1.55697,-0.58902 2.94224,-1.65714 4.15785,-3.20225 1.2255,-1.54498 2.40414,-3.62131 3.53637,-6.22666 0.24009,-0.57118 0.50825,-0.91111 0.80442,-1.02002 0.25361,-0.0933 0.45778,-0.0421 0.61262,0.1533 0.15472,0.19535 0.23206,0.48794 0.23209,0.87783 -3e-5,0.52756 -0.30247,1.44272 -0.90815,2.74722 -1.15807,2.54873 -2.46912,4.64404 -3.9349,6.28471 -1.45779,1.61908 -2.94333,2.71978 -4.45696,3.29882 -1.31723,0.50391 -2.6613,0.60967 -4.03252,0.31496 -1.05399,-0.23099 -1.9274,-0.63787 -2.61886,-1.22095 -0.69284,-0.58423 -1.54974,-1.68494 -2.57189,-3.30482 -1.01027,-1.65369 -1.7028,-3.26411 -2.07569,-4.82896 -0.37329,-1.59011 -0.56008,-3.4145 -0.56008,-5.47187 0,0 0,-6.06566 0,-6.06566 0,-2.93231 0.49291,-6.09055 1.47668,-9.46765 0.99585,-3.39605 2.34392,-6.18065 4.04011,-8.35311 1.70261,-2.18997 3.53533,-3.5965 5.49604,-4.22491 2.99933,-0.96119 5.55976,-0.14235 7.69078,2.4382"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7135"
|
||||
d="m 474.35548,321.63415 c 0,0 0,3.73374 0,3.73374 1.92733,-2.9209 3.65321,-5.08391 5.18045,-6.49616 1.55867,-1.46461 3.33722,-2.61502 5.33231,-3.45245 1.68521,-0.70725 3.34395,-0.94038 4.97648,-0.70268 1.62504,0.23673 3.20599,0.94782 4.74343,2.13018 1.93051,-2.65596 3.86859,-4.82797 5.81403,-6.51986 1.97032,-1.73866 3.96513,-3.02996 5.98397,-3.87753 4.00255,-1.68024 7.21652,-1.79129 9.66328,-0.35535 3.21252,1.855 4.80754,5.38685 4.80759,10.60859 0,0 0,27.6555 0,27.6555 2.1599,-1.04652 3.75414,-1.23977 4.79061,-0.58622 1.03318,0.65163 1.54863,1.87201 1.54868,3.66267 -5e-5,1.79071 -0.5155,3.52001 -1.54868,5.19171 -1.03647,1.63695 -2.79895,3.08221 -5.29884,4.33892 0,0 -10.06477,5.05964 -10.06477,5.05964 0,0 0,-39.58935 0,-39.58935 -6e-5,-1.91719 -0.297,-3.11211 -0.89158,-3.58537 -0.59574,-0.47394 -1.50874,-0.44198 -2.74155,0.0979 -1.20189,0.52645 -2.3191,1.38607 -3.35078,2.58013 -1.3208,1.61273 -2.93391,4.26901 -4.84334,7.97938 0,0 0,25.7042 0,25.7042 2.30443,-1.11656 4.00503,-1.34235 5.11047,-0.68443 1.10187,0.6559 1.65151,1.90764 1.65157,3.75675 -6e-5,1.84918 -0.5497,3.64359 -1.65157,5.38738 -1.10544,1.70812 -2.98552,3.23082 -5.65277,4.57166 0,0 -10.74506,5.40164 -10.74506,5.40164 0,0 0,-40.91537 0,-40.91537 -3e-5,-1.93926 -0.33584,-3.14035 -1.00844,-3.60389 -0.63643,-0.52301 -1.61196,-0.49718 -2.92936,0.0798 -1.36017,0.59578 -2.70648,1.67478 -4.03875,3.23966 -1.33726,1.52808 -2.94849,4.14396 -4.83738,7.8579 0,0 0,26.58677 0,26.58677 2.46515,-1.19443 4.28396,-1.45709 5.46607,-0.79567 1.21615,0.64074 1.82269,1.91622 1.82272,3.82806 -3e-5,1.91187 -0.60657,3.7862 -1.82272,5.62767 -1.18211,1.78589 -3.1929,3.39402 -6.04626,4.82843 0,0 -10.90353,5.48129 -10.90353,5.48129 -2.9631,1.48957 -5.07979,1.93911 -6.33531,1.33808 -1.30051,-0.6268 -1.95246,-1.95499 -1.95246,-3.98291 0,-1.98383 0.63159,-3.90163 1.8916,-5.74874 1.25573,-1.88473 3.19176,-3.45934 5.79746,-4.7219 0,0 0,-32.59212 0,-32.59212 -2.6057,1.14753 -4.54173,1.36358 -5.79746,0.64022 -1.26001,-0.7257 -1.8916,-2.08142 -1.8916,-4.06531 0,-1.98377 0.65195,-3.87089 1.95246,-5.65667 1.25552,-1.80622 3.37221,-3.33638 6.33531,-4.58745 0,0 11.48372,-4.84843 11.48372,-4.84843"
|
||||
id="path9190"
|
||||
d="m 446.20148,293.70621 c -2e-5,4.24459 -0.90262,8.20511 -2.71524,11.89678 -1.80943,3.70706 -4.00854,6.06196 -6.60502,7.05524 -2.64397,1.01145 -4.90651,0.34117 -6.7797,-2.02677 -1.88367,-2.40388 -2.82947,-5.7829 -2.82946,-10.12702 -1e-5,-4.36681 0.94579,-8.42515 2.82946,-12.15934 1.87319,-3.73593 4.13573,-6.04253 6.7797,-6.93007 2.59648,-0.87152 4.79559,-0.0961 6.60502,2.31138 1.81262,2.38984 2.71522,5.71315 2.71524,9.9798 m -1.66979,0.59968 c -1e-5,-3.50178 -0.74267,-6.22333 -2.23301,-8.17124 -1.48384,-1.96123 -3.2946,-2.58265 -5.43761,-1.85412 -2.1569,0.73328 -4.00807,2.62575 -5.54831,5.68434 -1.53361,3.04527 -2.30304,6.35392 -2.30304,9.91552 0,3.53895 0.76943,6.29496 2.30304,8.26131 1.54024,1.9523 3.39141,2.51514 5.54831,1.69916 2.14301,-0.81073 3.95377,-2.73277 5.43761,-5.75981 1.49034,-3.04055 2.233,-6.29551 2.23301,-9.77516"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7137"
|
||||
d="m 562.43254,335.80937 c 0,0 0,-2.71514 0,-2.71514 -2.30606,2.70118 -4.87114,5.1449 -7.70127,7.33086 -2.8552,2.24364 -5.47141,3.96922 -7.84251,5.16834 -5.20777,2.63369 -9.49858,3.09887 -12.83492,1.35082 -3.37011,-1.8053 -5.06796,-4.81824 -5.06796,-9.0251 0,-5.11964 2.15792,-10.86811 6.43245,-17.18435 4.25226,-6.28955 10.02684,-11.0544 17.24316,-14.30015 2.84824,-1.28103 6.10956,-2.36863 9.77105,-3.26347 0,0 0,-2.7717 0,-2.7717 -2e-5,-1.73462 -0.5974,-2.88455 -1.79549,-3.45139 -1.17251,-0.58209 -3.43943,-0.13856 -6.82404,1.3438 -2.80151,1.22705 -6.47056,3.52887 -11.03627,6.93278 -1.71671,1.26407 -3.05812,2.11073 -4.01962,2.53599 -1.3186,0.58329 -2.4484,0.51384 -3.38742,-0.21163 -0.9092,-0.78105 -1.36471,-2.07838 -1.36471,-3.89039 0,-1.02411 0.16274,-1.9804 0.48805,-2.86825 0.32494,-0.88687 0.77935,-1.67105 1.36269,-2.35229 0.5823,-0.71918 1.79217,-1.78262 3.62279,-3.18545 2.42508,-1.8453 4.8798,-3.52261 7.36327,-5.03345 2.46472,-1.53781 4.67946,-2.71773 6.6492,-3.54469 5.80784,-2.43811 10.23696,-2.73568 13.34237,-0.93866 3.10431,1.72985 4.6451,5.24645 4.64515,10.56249 0,0 0,23.53209 0,23.53209 0,0 1.51884,-0.73593 1.51884,-0.73593 2.12842,-1.03128 3.62972,-1.22407 4.51288,-0.58501 0.90892,0.5867 1.36241,1.72437 1.36247,3.4143 -6e-5,1.65327 -0.45355,3.23865 -1.36247,4.75951 -0.88316,1.47417 -2.38446,2.74508 -4.51288,3.81506 0,0 -10.56481,5.31101 -10.56481,5.31101 m 0,-20.75947 c -3.69168,0.82545 -7.13631,1.98253 -10.32525,3.47506 -3.87486,1.81361 -7.24447,4.57256 -10.09242,8.28457 -1.7846,2.36681 -2.68052,4.33654 -2.68052,5.89954 0,1.13321 0.43227,1.84245 1.29513,2.12718 1.59189,0.51241 3.7604,0.0971 6.49405,-1.2357 2.30727,-1.12489 4.89129,-2.94044 7.74527,-5.43602 2.85919,-2.48828 5.37788,-5.20012 7.56374,-8.13688 0,0 0,-4.97775 0,-4.97775"
|
||||
id="path9192"
|
||||
d="m 455.60751,276.10974 c 0,0 0,4.15113 0,4.15113 1.11495,-2.3191 2.11892,-3.99679 3.01293,-5.03692 0.89151,-1.03717 1.89309,-1.74157 3.00371,-2.11441 1.19364,-0.40064 2.27776,-0.32355 3.25343,0.22887 0.68978,0.41072 1.31055,1.27219 1.86271,2.58332 0.56341,1.28329 0.84476,2.70473 0.84478,4.26601 0,0 0,16.97118 0,16.97118 0,0 1.29949,-0.48945 1.29949,-0.48945 0.36507,-0.1375 0.62647,-0.10806 0.78443,0.0883 0.15785,0.17489 0.23676,0.46473 0.23678,0.86961 -2e-5,0.38358 -0.079,0.73322 -0.23678,1.04899 -0.15796,0.31594 -0.41936,0.54343 -0.78443,0.68248 0,0 -4.13649,1.57553 -4.13649,1.57553 -0.38266,0.14575 -0.6545,0.1203 -0.81523,-0.0767 -0.16083,-0.19703 -0.24127,-0.48927 -0.24126,-0.8766 -10e-6,-0.40886 0.0804,-0.76201 0.24126,-1.05937 0.16073,-0.31869 0.43257,-0.5501 0.81523,-0.69423 0,0 1.29268,-0.48689 1.29268,-0.48689 0,0 0,-16.56218 0,-16.56218 -2e-5,-1.9081 -0.39958,-3.37817 -1.20018,-4.41215 -0.80264,-1.05804 -1.88008,-1.35848 -3.23511,-0.89784 -1.03568,0.35211 -1.93681,1.02658 -2.70223,2.02432 -0.76727,0.97846 -1.86472,3.15928 -3.29572,6.55195 0,0 0,17.22555 0,17.22555 0,0 1.80355,-0.67931 1.80355,-0.67931 0.3784,-0.14252 0.64933,-0.11436 0.81305,0.0844 0.16361,0.17695 0.24539,0.47148 0.2454,0.88368 -1e-5,0.39049 -0.0818,0.74701 -0.2454,1.06957 -0.16372,0.32276 -0.43465,0.55619 -0.81305,0.70032 0,0 -5.22933,1.99177 -5.22933,1.99177 -0.38503,0.14665 -0.66124,0.12033 -0.82837,-0.0793 -0.16721,-0.19969 -0.25085,-0.49706 -0.25084,-0.89202 -1e-5,-0.4169 0.0836,-0.77761 0.25084,-1.08204 0.16713,-0.32618 0.44334,-0.56178 0.82837,-0.7068 0,0 1.82264,-0.68649 1.82264,-0.68649 0,0 0,-22.83855 0,-22.83855 0,0 -1.36122,0.46482 -1.36122,0.46482 -0.38448,0.13131 -0.6603,0.094 -0.82719,-0.11207 -0.16697,-0.20614 -0.2505,-0.51757 -0.25049,-0.93421 -1e-5,-0.39465 0.0835,-0.75178 0.25049,-1.07132 0.16689,-0.31929 0.44271,-0.54376 0.82719,-0.67343 0,0 2.96436,-0.99954 2.96436,-0.99954"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7139"
|
||||
d="m 614.59063,265.59533 c 0,0 0,-3.16839 0,-3.16839 0,0 8.92,-3.76602 8.92,-3.76602 1.79996,-0.75989 3.07019,-0.80436 3.81764,-0.13827 0.76945,0.6204 1.15341,1.70749 1.15345,3.26251 -4e-5,1.52133 -0.384,2.93962 -1.15345,4.25756 -0.74745,1.27705 -2.01768,2.31128 -3.81764,3.10391 0,0 -1.28387,0.56539 -1.28387,0.56539 0,0 0,38.24265 0,38.24265 -4e-5,3.691 -0.5643,7.19606 -1.6961,10.52494 -1.11156,3.36323 -2.83663,6.66786 -5.18616,9.92382 -2.36864,3.28232 -5.0627,5.74584 -8.09096,7.38311 0,0 -9.11465,4.9279 -9.11465,4.9279 -1.97442,1.06746 -3.39649,1.31721 -4.25833,0.74277 -0.83728,-0.55472 -1.2568,-1.64096 -1.25677,-3.2576 -3e-5,-1.65259 0.41949,-3.22074 1.25677,-4.70139 0.86184,-1.45486 2.28391,-2.69907 4.25833,-3.73065 0,0 8.88239,-4.64088 8.88239,-4.64088 2.41674,-1.26271 4.28005,-3.1242 5.60022,-5.58388 1.31418,-2.44866 1.96909,-5.01935 1.96913,-7.72028 0,0 0,-5.19407 0,-5.19407 -1.71598,2.38202 -3.4802,4.41407 -5.29344,6.09337 -1.79872,1.67668 -3.66026,3.00312 -5.58571,3.97635 -5.50613,2.78311 -10.19527,2.66011 -14.02683,-0.43675 -3.88027,-3.17252 -5.83896,-8.5095 -5.83896,-15.98064 0,-7.50753 1.95869,-14.65634 5.83896,-21.38216 3.83156,-6.6772 8.5207,-11.15558 14.02683,-13.46567 2.02917,-0.85127 3.94159,-1.25068 5.73937,-1.20278 1.81231,0.002 3.52501,0.45844 5.13978,1.36515 m -0.0377,20.43011 c -4e-5,-3.91307 -1.05883,-6.83031 -3.18794,-8.76215 -2.11904,-1.95711 -4.6924,-2.28085 -7.7318,-0.95049 -3.07071,1.34414 -5.7337,3.98774 -7.9777,7.94239 -2.23376,3.97214 -3.35686,8.0001 -3.35684,12.06182 -2e-5,4.09774 1.12308,7.10481 3.35684,9.01068 2.244,1.84339 4.90699,2.00617 7.9777,0.51014 3.0394,-1.48077 5.61276,-4.16715 7.7318,-8.04946 2.12911,-3.90122 3.1879,-7.81515 3.18794,-11.76293"
|
||||
id="path9194"
|
||||
d="m 479.92231,267.91115 c 0,0 7.93929,-2.67701 7.93929,-2.67701 0.34358,-0.11582 0.58957,-0.0747 0.73824,0.12332 0.14856,0.19796 0.22283,0.49327 0.22285,0.88604 -2e-5,0.37214 -0.0743,0.70755 -0.22285,1.00626 -0.14867,0.29894 -0.39466,0.50704 -0.73824,0.62435 0,0 -7.93929,2.71107 -7.93929,2.71107 0,0 0,17.5856 0,17.5856 -10e-6,1.53103 0.34075,2.68285 1.02117,3.45423 0.69061,0.76528 1.69453,0.8979 3.00873,0.40072 0.98487,-0.37258 2.04735,-1.03413 3.18661,-1.9829 1.13503,-0.96594 2.01495,-1.89616 2.64195,-2.79193 0.22765,-0.35338 0.41536,-0.55761 0.56319,-0.61282 0.1818,-0.0679 0.3408,0.007 0.47704,0.22365 0.13614,0.1963 0.20421,0.46949 0.20422,0.81966 -10e-6,0.30901 -0.0738,0.62518 -0.22124,0.94859 -0.36343,0.81742 -1.25108,1.8964 -2.66748,3.24084 -1.41148,1.32553 -2.77168,2.23999 -4.07986,2.74044 -1.71013,0.65421 -3.07802,0.45516 -4.09907,-0.60245 -1.02442,-1.06109 -1.53788,-2.82281 -1.53788,-5.28253 0,0 0,-17.628 0,-17.628 0,0 -2.75879,0.94206 -2.75879,0.94206 -0.35775,0.12218 -0.61439,0.083 -0.76967,-0.11774 -0.15535,-0.20078 -0.23305,-0.50216 -0.23305,-0.90403 0,-0.38067 0.0777,-0.72418 0.23305,-1.03047 0.15528,-0.30606 0.41192,-0.51941 0.76967,-0.64007 0,0 2.75879,-0.93022 2.75879,-0.93022 0,0 0,-7.82065 0,-7.82065 0,-0.63066 0.0709,-1.10555 0.21258,-1.42455 0.14162,-0.31879 0.31857,-0.51233 0.53079,-0.58066 0.22384,-0.072 0.40634,0.006 0.54755,0.23289 0.14114,0.22719 0.21169,0.65532 0.2117,1.28446 0,0 0,7.80185 0,7.80185"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path7141"
|
||||
d="m 666.74676,266.8091 c 0,0 -27.70776,13.06906 -27.70776,13.06906 0.73837,2.30281 2.03731,3.81645 3.88909,4.54184 1.86216,0.70963 4.35196,0.30059 7.45241,-1.21076 2.51697,-1.22691 5.82649,-3.62825 9.89955,-7.1722 1.66319,-1.44005 2.80865,-2.30969 3.44295,-2.61502 0.86438,-0.41605 1.5896,-0.30651 2.17677,0.32658 0.58582,0.63176 0.87828,1.64102 0.87831,3.02886 -3e-5,1.26171 -0.31339,2.48919 -0.94115,3.68452 -0.8394,1.58764 -2.89644,3.74108 -6.19931,6.48162 -3.34379,2.74229 -6.59732,4.91806 -9.75663,6.51552 -5.52112,2.79166 -10.02299,2.76518 -13.45335,-0.14815 -3.449,-2.96066 -5.18937,-7.86937 -5.18937,-14.69893 0,-7.26688 1.88196,-13.999 5.60883,-20.13533 3.70116,-6.09897 7.89786,-10.11107 12.56687,-12.0712 2.7683,-1.1621 5.27977,-1.50678 7.54111,-1.04568 2.26409,0.44825 3.93385,1.25121 5.02007,2.40819 1.526,1.68907 2.78058,4.0385 3.76749,7.04712 0.66979,2.09858 1.00409,4.72307 1.00412,7.87745 0,0 0,4.11651 0,4.11651 m -7.20565,-6.43207 c -1.00994,-2.36059 -2.33715,-3.86869 -3.98626,-4.52066 -1.65921,-0.68816 -3.64816,-0.52771 -5.974,0.49093 -2.32324,1.01757 -4.34961,2.62703 -6.07233,4.83214 -1.73349,2.1859 -3.15565,4.98628 -4.26166,8.401 0,0 20.29425,-9.20341 20.29425,-9.20341"
|
||||
id="path9196"
|
||||
d="m 507.59418,284.6149 c 0,0 0,-3.63759 0,-3.63759 -1.97126,3.83544 -4.09162,6.19491 -6.36413,7.06425 -1.66058,0.63526 -2.96464,0.36062 -3.90749,-0.82933 -0.94581,-1.21408 -1.41981,-2.9567 -1.41981,-5.22501 0,-2.49306 0.62441,-4.89516 1.86942,-7.19916 1.2399,-2.29455 3.04084,-3.85692 5.3928,-4.68926 0.63133,-0.22341 1.31558,-0.38496 2.05241,-0.48487 0.73499,-0.11963 1.52741,-0.16982 2.3768,-0.15063 0,0 0,-4.08853 0,-4.08853 -10e-6,-1.38285 -0.34377,-2.46702 -1.03247,-3.25387 -0.69032,-0.78861 -1.72878,-0.94811 -3.11901,-0.47551 -1.06879,0.36336 -2.57478,1.45299 -4.52455,3.2767 -0.35386,0.32479 -0.58075,0.50443 -0.68042,0.53862 -0.17727,0.0609 -0.33247,-0.008 -0.46556,-0.20685 -0.12205,-0.20267 -0.1831,-0.48744 -0.18309,-0.85428 -1e-5,-0.34641 0.0555,-0.64039 0.16645,-0.88189 0.15527,-0.35826 0.7811,-0.98775 1.87459,-1.88616 1.71506,-1.42987 3.00589,-2.28846 3.8779,-2.5812 1.72557,-0.5792 3.06445,-0.23562 4.02174,1.02522 0.95419,1.23685 1.43016,2.84357 1.43017,4.82313 0,0 0,16.67655 0,16.67655 0,0 1.79004,-0.67421 1.79004,-0.67421 0.32911,-0.12395 0.56246,-0.0924 0.70028,0.0947 0.13772,0.16703 0.20657,0.43961 0.20659,0.8178 -2e-5,0.35829 -0.0689,0.68305 -0.20659,0.9743 -0.13782,0.29141 -0.37117,0.49978 -0.70028,0.62513 0,0 -3.15579,1.202 -3.15579,1.202 m 0,-12.56621 c -0.63412,-0.11291 -1.30734,-0.12215 -2.01989,-0.0274 -0.71427,0.095 -1.46826,0.28452 -2.26226,0.56886 -1.99974,0.71618 -3.57168,2.08121 -4.70901,4.09722 -0.86414,1.51494 -1.29713,3.10995 -1.29712,4.78174 -1e-5,1.54949 0.32757,2.73182 0.98167,3.54568 0.66373,0.80794 1.62356,0.97347 2.87668,0.4994 1.19328,-0.45143 2.29477,-1.30203 3.30546,-2.54998 1.01808,-1.26789 2.05966,-3.05352 3.12447,-5.35395 0,0 0,-5.5616 0,-5.5616"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path9198"
|
||||
d="m 523.702,240.54258 c 0,0 0,6.34723 0,6.34723 0,0 -1.89662,0.61903 -1.89662,0.61903 0,0 0,-6.36799 0,-6.36799 0,0 1.89662,-0.59827 1.89662,-0.59827 m 0.0457,12.59128 c 0,0 0,22.8716 0,22.8716 0,0 4.98692,-1.8783 4.98692,-1.8783 0.30944,-0.11656 0.52886,-0.0834 0.65845,0.0995 0.1295,0.16349 0.19423,0.42857 0.19424,0.79531 -10e-6,0.34743 -0.0648,0.66158 -0.19424,0.94246 -0.12959,0.28103 -0.34901,0.48047 -0.65845,0.59834 0,0 -11.367,4.32951 -11.367,4.32951 -0.31177,0.11876 -0.53541,0.0856 -0.67072,-0.0998 -0.13538,-0.1854 -0.20308,-0.45583 -0.20308,-0.81118 0,-0.37512 0.0677,-0.69681 0.20308,-0.96503 0.13531,-0.28782 0.35895,-0.49043 0.67072,-0.60786 0,0 5.09683,-1.9197 5.09683,-1.9197 0,0 0,-20.43068 0,-20.43068 0,0 -3.77547,1.28922 -3.77547,1.28922 -0.31037,0.106 -0.53819,0.0657 -0.68325,-0.12114 -0.13477,-0.19038 -0.20218,-0.46292 -0.20217,-0.81751 -10e-6,-0.37425 0.0674,-0.70236 0.20217,-0.98427 0.1347,-0.28172 0.36252,-0.47665 0.68325,-0.58482 0,0 5.05872,-1.70573 5.05872,-1.70573"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path9200"
|
||||
d="m 537.32375,248.55623 c 0,0 0,3.62744 0,3.62744 0.85157,-1.98473 1.61868,-3.41372 2.30203,-4.28987 0.68168,-0.87397 1.4478,-1.45313 2.29768,-1.73844 0.91383,-0.30672 1.74417,-0.19946 2.49175,0.31998 0.5287,0.38502 1.00462,1.16228 1.42804,2.33096 0.43214,1.14498 0.64797,2.40056 0.64799,3.76807 0,0 0,14.86484 0,14.86484 0,0 0.99719,-0.37559 0.99719,-0.37559 0.28024,-0.10556 0.48092,-0.0691 0.6022,0.1094 0.1212,0.15971 0.18179,0.41693 0.18181,0.77172 -2e-5,0.33612 -0.0606,0.63926 -0.18181,0.90944 -0.12128,0.27032 -0.32196,0.45885 -0.6022,0.56559 0,0 -3.17247,1.20835 -3.17247,1.20835 -0.29322,0.11168 -0.5015,0.0781 -0.62464,-0.10097 -0.1232,-0.17913 -0.18482,-0.43824 -0.18481,-0.77724 -1e-5,-0.35784 0.0616,-0.66361 0.18481,-0.91724 0.12314,-0.27233 0.33142,-0.46371 0.62464,-0.57415 0,0 0.99087,-0.37321 0.99087,-0.37321 0,0 0,-14.50223 0,-14.50223 -2e-5,-1.67078 -0.30634,-2.97304 -0.91998,-3.90831 -0.61502,-0.95611 -1.44029,-1.25912 -2.47769,-0.90646 -0.79254,0.26945 -1.48185,0.82573 -2.06717,1.66956 -0.58655,0.82666 -1.42522,2.69155 -2.51824,5.6018 0,0 0,15.05244 0,15.05244 0,0 1.37768,-0.5189 1.37768,-0.5189 0.28918,-0.10892 0.49624,-0.0731 0.62138,0.10749 0.12507,0.16149 0.18759,0.4224 0.18759,0.7828 0,0.34142 -0.0626,0.64972 -0.18759,0.9249 -0.12514,0.27533 -0.3322,0.46807 -0.62138,0.57821 0,0 -3.99187,1.52045 -3.99187,1.52045 -0.2936,0.11182 -0.50419,0.0772 -0.6316,-0.10415 -0.12747,-0.18138 -0.19123,-0.44453 -0.19122,-0.78936 -1e-5,-0.36399 0.0637,-0.67542 0.19122,-0.93422 0.12741,-0.27783 0.338,-0.47202 0.6316,-0.5826 0,0 1.39041,-0.52369 1.39041,-0.52369 0,0 0,-19.9511 0,-19.9511 0,0 -1.03851,0.35462 -1.03851,0.35462 -0.29323,0.10015 -0.50356,0.0572 -0.63081,-0.1291 -0.12731,-0.18629 -0.19099,-0.46138 -0.19098,-0.82516 -1e-5,-0.3446 0.0636,-0.6533 0.19098,-0.92606 0.12725,-0.27258 0.33758,-0.4583 0.63081,-0.5572 0,0 2.26229,-0.76281 2.26229,-0.76281"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path9202"
|
||||
d="m 564.37221,251.7564 c 0,0 -11.52429,4.14925 -11.52429,4.14925 0.20161,2.94498 0.82381,5.14921 1.86378,6.61012 1.04511,1.43359 2.33011,1.85933 3.85161,1.28373 0.8426,-0.31877 1.72276,-0.93491 2.64009,-1.84687 0.91423,-0.90885 1.65753,-1.93361 2.23132,-3.07472 0.16748,-0.33476 0.31285,-0.525 0.43614,-0.57085 0.14082,-0.0524 0.26398,0.0197 0.36951,0.21624 0.10547,0.17832 0.15819,0.42155 0.1582,0.72977 -10e-6,0.30823 -0.0703,0.63376 -0.21096,0.97672 -0.42243,1.06628 -1.1765,2.20515 -2.26499,3.41901 -1.08401,1.1971 -2.20364,2.01781 -3.35931,2.45991 -1.94615,0.7445 -3.58314,0.0702 -4.90528,-2.03457 -1.31936,-2.13686 -1.98142,-5.07429 -1.98141,-8.80462 -10e-6,-3.39624 0.62072,-6.52518 1.85798,-9.37715 1.24083,-2.84225 2.7659,-4.56294 4.57045,-5.16871 1.84627,-0.61971 3.35606,0.10399 4.53489,2.16125 1.17368,2.03023 1.74983,4.98512 1.73227,8.87149 m -1.12272,-1.91239 c -0.22071,-2.44805 -0.8042,-4.29941 -1.75284,-5.55586 -0.94308,-1.26387 -2.07284,-1.67412 -3.3916,-1.2258 -1.32518,0.45052 -2.47072,1.63227 -3.43432,3.54863 -0.96701,1.92314 -1.57083,4.23377 -1.80906,6.92855 0,0 10.38782,-3.69552 10.38782,-3.69552"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path9204"
|
||||
d="m 573.09946,236.49319 c 0,0 0,5.67252 0,5.67252 1.39118,-3.11706 2.42557,-5.15863 3.10733,-6.13505 0.68836,-0.9944 1.32057,-1.58768 1.89705,-1.78148 0.62514,-0.2101 1.20313,0.0452 1.73426,0.76436 0.5383,0.69735 0.80705,1.27409 0.80706,1.73125 -1e-5,0.33412 -0.0538,0.63396 -0.16121,0.89952 -0.0993,0.24531 -0.22754,0.39508 -0.38483,0.4493 -0.0829,0.0286 -0.15328,0.0265 -0.21128,-0.006 -0.0581,-0.0505 -0.16584,-0.21587 -0.32347,-0.49644 -0.29063,-0.51722 -0.54416,-0.85379 -0.76045,-1.00936 -0.21651,-0.15563 -0.42901,-0.19806 -0.6375,-0.12711 -0.4593,0.15634 -1.01569,0.73516 -1.66979,1.73811 -0.64734,1.00259 -1.77765,3.30323 -3.39717,6.91661 0,0 0,12.30832 0,12.30832 0,0 4.70377,-1.77166 4.70377,-1.77166 0.25887,-0.0975 0.44243,-0.0607 0.55085,0.11042 0.10835,0.15336 0.16252,0.39774 0.16253,0.73321 -10e-6,0.3178 -0.0542,0.60323 -0.16253,0.85632 -0.10842,0.25321 -0.29198,0.42911 -0.55085,0.52771 0,0 -8.39069,3.19589 -8.39069,3.19589 -0.25883,0.0986 -0.44449,0.0704 -0.55681,-0.0846 -0.11237,-0.17308 -0.16857,-0.42152 -0.16857,-0.74529 0,-0.30576 0.0519,-0.57716 0.15561,-0.81415 0.11232,-0.25813 0.3023,-0.43758 0.56977,-0.53836 0,0 2.61311,-0.98462 2.61311,-0.98462 0,0 0,-18.76796 0,-18.76796 0,0 -1.99291,0.68053 -1.99291,0.68053 -0.25825,0.0882 -0.44347,0.0437 -0.55552,-0.13359 -0.11211,-0.17732 -0.16818,-0.43671 -0.16818,-0.77807 0,-0.32336 0.0517,-0.61034 0.15524,-0.8609 0.11207,-0.25331 0.3016,-0.42495 0.56846,-0.51496 0,0 3.06672,-1.03405 3.06672,-1.03405"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer12"
|
||||
inkscape:label="Image (name)#1"
|
||||
style="display:inline">
|
||||
<g
|
||||
transform="translate(-12.096774,4.8387096)"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Courier New;-inkscape-font-specification:Courier New"
|
||||
id="text8052">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 423.74041,363.69642 c 0,0 0,46.13338 0,46.13338 0,0 6.60461,-3.25288 6.60461,-3.25288 0.45439,-0.22379 0.77972,-0.20169 0.97632,0.0662 0.19645,0.2373 0.29465,0.64448 0.29467,1.22164 -2e-5,0.54682 -0.0983,1.05125 -0.29467,1.51342 -0.1966,0.46245 -0.52193,0.80673 -0.97632,1.03282 0,0 -15.30796,7.61688 -15.30796,7.61688 -0.47355,0.23563 -0.81328,0.21827 -1.01883,-0.0526 -0.20568,-0.27092 -0.30855,-0.68631 -0.30855,-1.24607 0,-0.59083 0.10283,-1.10805 0.30855,-1.55154 0.20555,-0.47431 0.54528,-0.8281 1.01883,-1.06133 0,0 6.75525,-3.32706 6.75525,-3.32706 0,0 0,-46.25099 0,-46.25099 0,0 -6.75525,2.91925 -6.75525,2.91925 -0.47355,0.20469 -0.81328,0.18057 -1.01883,-0.0726 -0.20568,-0.2843 -0.30855,-0.72199 -0.30855,-1.31286 0,-0.59081 0.10283,-1.1013 0.30855,-1.53138 0.20555,-0.46081 0.54528,-0.79235 1.01883,-0.99466 0,0 15.30796,-6.53778 15.30796,-6.53778 0.45439,-0.19399 0.77972,-0.15067 0.97632,0.13006 0.19645,0.25021 0.29465,0.66381 0.29467,1.24095 -2e-5,0.57722 -0.0983,1.09044 -0.29467,1.53969 -0.1966,0.41925 -0.52193,0.72704 -0.97632,0.92336 0,0 -6.60461,2.85414 -6.60461,2.85414"
|
||||
id="path8059" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 441.87507,365.74833 c 0,0 0,3.82064 0,3.82064 1.56942,-4.14583 3.13954,-6.56174 4.71033,-7.25855 0.94216,-0.41791 1.76641,-0.26368 2.47352,0.46081 0.70573,0.69355 1.29521,1.97053 1.76901,3.83012 0.80259,-2.43288 1.61058,-4.33197 2.42395,-5.69892 0.82577,-1.39965 1.64969,-2.28097 2.47179,-2.64567 1.28608,-0.57047 2.30749,-0.15871 3.06643,1.23159 0.99542,1.77766 1.49212,3.97984 1.49215,6.61017 0,0 0,25.73386 0,25.73386 0,0 1.48605,-0.73191 1.48605,-0.73191 0.41748,-0.20562 0.71641,-0.17807 0.89705,0.0826 0.18051,0.23133 0.27074,0.62358 0.27077,1.17682 -3e-5,0.52419 -0.0903,1.00579 -0.27077,1.44493 -0.18064,0.43941 -0.47957,0.76299 -0.89705,0.97072 0,0 -3.25208,1.61816 -3.25208,1.61816 0,0 0,-29.13622 0,-29.13622 -2e-5,-1.87499 -0.27409,-3.30363 -0.82284,-4.287 -0.54964,-0.98475 -1.18481,-1.31612 -1.90601,-0.99255 -0.65174,0.29248 -1.34015,1.11693 -2.06542,2.47501 -0.72674,1.33131 -1.55495,3.70059 -2.48533,7.11235 0,0 0,24.72225 0,24.72225 0,0 1.50177,-0.73965 1.50177,-0.73965 0.42794,-0.21077 0.73434,-0.18473 0.9195,0.078 0.18502,0.23308 0.27752,0.62963 0.27753,1.18976 -1e-5,0.53068 -0.0926,1.01883 -0.27753,1.46455 -0.18516,0.446 -0.49156,0.77547 -0.9195,0.9884 0,0 -3.33363,1.65874 -3.33363,1.65874 0,0 0,-29.23324 0,-29.23324 -2e-5,-1.9874 -0.2882,-3.4883 -0.86521,-4.50391 -0.56348,-1.05333 -1.20023,-1.42148 -1.91062,-1.10276 -0.65361,0.29333 -1.30108,1.01634 -1.94239,2.17018 -0.89094,1.6268 -1.82798,4.16023 -2.81147,7.60421 0,0 0,25.03641 0,25.03641 0,0 1.56211,-0.76936 1.56211,-0.76936 0.43885,-0.21614 0.75303,-0.1917 0.94289,0.0732 0.18975,0.23484 0.28458,0.63583 0.28459,1.20303 -1e-5,0.53738 -0.0948,1.03223 -0.28459,1.48482 -0.18986,0.45281 -0.50404,0.78839 -0.94289,1.00674 0,0 -4.99523,2.48551 -4.99523,2.48551 -0.44529,0.22157 -0.76474,0.19977 -0.95802,-0.0659 -0.19339,-0.26571 -0.29012,-0.67 -0.29011,-1.21278 -1e-5,-0.57291 0.0967,-1.07295 0.29011,-1.5 0.19328,-0.45695 0.51273,-0.7951 0.95802,-1.01441 0,0 1.5765,-0.77645 1.5765,-0.77645 0,0 0,-31.40719 0,-31.40719 0,0 -1.5765,0.71024 -1.5765,0.71024 -0.44529,0.20064 -0.76474,0.16379 -0.95802,-0.11096 -0.19339,-0.27476 -0.29012,-0.69868 -0.29011,-1.27164 -1e-5,-0.54273 0.0967,-1.03824 0.29011,-1.48635 0.19328,-0.44782 0.51273,-0.77089 0.95802,-0.96927 0,0 3.43312,-1.52911 3.43312,-1.52911"
|
||||
id="path8061" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 480.58851,385.41099 c 0,0 0,-5.15657 0,-5.15657 -2.4262,5.5798 -5.03657,9.079 -7.835,10.47699 -2.04539,1.02181 -3.65191,0.72721 -4.81363,-0.89204 -1.16547,-1.65345 -1.74963,-4.09108 -1.74963,-7.30887 0,-3.53667 0.76951,-6.98913 2.30362,-10.34663 1.52759,-3.34322 3.746,-5.68753 6.64239,-7.03536 0.77733,-0.36171 1.61976,-0.63945 2.52684,-0.83351 0.90473,-0.2221 1.88006,-0.34939 2.92541,-0.38255 0,0 0,-5.7958 0,-5.7958 -10e-6,-1.96032 -0.42307,-3.47297 -1.27068,-4.53986 -0.84967,-1.0694 -2.12799,-1.22244 -3.8396,-0.45447 -1.31604,0.59057 -3.17073,2.24198 -5.57246,4.96625 -0.43594,0.48573 -0.71549,0.75657 -0.83828,0.81214 -0.21842,0.0989 -0.40964,0.0122 -0.57362,-0.26044 -0.15038,-0.27883 -0.22559,-0.67845 -0.22559,-1.19879 0,-0.49136 0.0684,-0.91228 0.20509,-1.26267 0.19131,-0.51914 0.96238,-1.45616 2.30947,-2.80749 2.11245,-2.14861 3.70209,-3.45689 4.77581,-3.9332 2.12442,-0.94235 3.77243,-0.54918 4.95058,1.17099 1.17422,1.68619 1.75986,3.93017 1.75988,6.73612 0,0 0,23.63827 0,23.63827 0,0 2.20228,-1.08466 2.20228,-1.08466 0.40486,-0.19939 0.6919,-0.17146 0.86143,0.0837 0.1694,0.2268 0.25409,0.60813 0.25411,1.1441 -2e-5,0.5078 -0.0847,0.973 -0.25411,1.39571 -0.16953,0.42296 -0.45657,0.73515 -0.86143,0.9366 0,0 -3.88288,1.93203 -3.88288,1.93203 m 0,-17.81357 c -0.78041,-0.11482 -1.60899,-0.0799 -2.48605,0.10525 -0.87928,0.18568 -1.80752,0.50815 -2.78512,0.968 -2.46256,1.15841 -4.39871,3.20675 -5.7998,6.14762 -1.06467,2.21091 -1.5982,4.50451 -1.59819,6.87592 -1e-5,2.19789 0.40363,3.85127 1.20954,4.95824 0.81771,1.09778 2.0001,1.26287 3.54357,0.49962 1.46955,-0.72669 2.82587,-2.01263 4.07022,-3.85519 1.2533,-1.87118 2.53536,-4.47776 3.84583,-7.81547 0,0 0,-7.88399 0,-7.88399"
|
||||
id="path8063" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 504.87507,344.02572 c 0,0 0,-6.33756 0,-6.33756 0,0 3.62149,-1.61301 3.62149,-1.61301 0.3655,-0.16275 0.62721,-0.11582 0.78538,0.14085 0.15805,0.25653 0.23705,0.64362 0.23708,1.1613 -3e-5,0.49052 -0.0791,0.93476 -0.23708,1.33282 -0.15817,0.39836 -0.41988,0.67984 -0.78538,0.84448 0,0 -2.07259,0.93375 -2.07259,0.93375 0,0 0,34.44897 0,34.44897 -2e-5,2.29935 -0.22086,4.46439 -0.66296,6.49712 -0.29508,1.35662 -0.78741,2.85674 -1.47785,4.50202 -0.69188,1.64858 -1.32318,2.89693 -1.89359,3.74358 -0.57137,0.84805 -1.33675,1.52227 -2.29743,2.02265 0,0 -4.48946,2.33825 -4.48946,2.33825 -0.37994,0.19787 -0.65249,0.17289 -0.81737,-0.0754 -0.16499,-0.22051 -0.24751,-0.5954 -0.2475,-1.12453 -10e-6,-0.52918 0.0825,-1.0035 0.2475,-1.42286 0.16488,-0.41919 0.43743,-0.72673 0.81737,-0.92267 0,0 4.54567,-2.30289 4.54567,-2.30289 0.92315,-0.47614 1.75064,-1.42648 2.48315,-2.84967 0.74328,-1.42651 1.3553,-3.26448 1.83674,-5.51382 0.27125,-1.28999 0.40681,-2.82626 0.40683,-4.60956 0,0 0,-10.37051 0,-10.37051 -1.66739,5.89686 -3.82848,9.5134 -6.49259,10.83562 -2.17909,1.08151 -4.07329,0.23861 -5.67781,-2.54346 -1.59915,-2.82914 -2.40148,-6.78447 -2.40147,-11.85622 -1e-5,-5.07169 0.80232,-9.76707 2.40147,-14.07131 1.60452,-4.29012 3.49872,-6.9134 5.67781,-7.88005 2.66411,-1.18176 4.8252,0.38981 6.49259,4.69207 m 0,10.41166 c -2e-5,-4.06038 -0.62896,-7.20112 -1.89031,-9.42839 -1.2536,-2.24103 -2.76147,-2.97007 -4.52696,-2.17791 -1.77459,0.79633 -3.30477,2.91596 -4.5872,6.36538 -1.28721,3.43436 -1.9326,7.21098 -1.9326,11.32033 0,4.13734 0.64539,7.33529 1.9326,9.58763 1.28243,2.21618 2.81261,2.88369 4.5872,2.01202 1.76549,-0.86719 3.27336,-3.01347 4.52696,-6.43279 1.26135,-3.44025 1.89029,-7.18583 1.89031,-11.24627"
|
||||
id="path8065" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 529.8044,344.5465 c 0,0 -15.0214,7.10051 -15.0214,7.10051 0.26314,4.28098 1.07521,7.44153 2.43223,9.47797 1.36338,1.99553 3.03922,2.49762 5.02283,1.51672 1.09819,-0.54306 2.24508,-1.52324 3.44017,-2.93807 1.19075,-1.4097 2.1587,-2.97236 2.90578,-4.68889 0.21804,-0.50344 0.40728,-0.79413 0.56779,-0.87226 0.1833,-0.0892 0.34362,0.005 0.48099,0.28146 0.13728,0.25029 0.2059,0.60007 0.20592,1.0494 -2e-5,0.44938 -0.0915,0.9304 -0.27459,1.44334 -0.5499,1.59345 -1.53164,3.3235 -2.9491,5.19415 -1.412,1.84634 -2.87079,3.14741 -4.37696,3.89984 -2.53736,1.26758 -4.67257,0.436 -6.39774,-2.51332 -1.72209,-2.9974 -2.58645,-7.22532 -2.58645,-12.67216 0,-4.95904 0.81041,-9.58368 2.42538,-13.8585 1.61912,-4.25962 3.60849,-6.90642 5.96144,-7.9502 2.40629,-1.06738 4.37322,-0.14533 5.90848,2.75024 1.52811,2.85581 2.27809,7.11232 2.25523,12.77977 m -1.46157,-2.68694 c -0.28736,-3.54969 -1.04714,-6.19709 -2.28263,-7.94479 -1.22853,-1.7594 -2.70063,-2.2574 -4.41951,-1.48616 -1.72781,0.77534 -3.22184,2.60204 -4.47892,5.48524 -1.26182,2.8941 -2.04987,6.32176 -2.36082,10.27751 0,0 13.54188,-6.3318 13.54188,-6.3318"
|
||||
id="path8067" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="/Users/arothfusz/src/metalivedev/docker/docs/sources/terms/images/docker-filesystems-multiroot.png"
|
||||
transform="matrix(0.83545525,0,0,0.83545525,52.49863,66.133437)"
|
||||
transform="matrix(0.71809444,0,0,0.71809444,82.080142,116.02377)"
|
||||
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Futura;-inkscape-font-specification:Futura Medium"
|
||||
id="text10963">
|
||||
<path
|
||||
|
||||
|
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 272 KiB |
@@ -1,11 +1,11 @@
|
||||
:title: Terms
|
||||
:title: Glossary
|
||||
:description: Definitions of terms used in Docker documentation
|
||||
:keywords: concepts, documentation, docker, containers
|
||||
|
||||
|
||||
|
||||
Terms
|
||||
=====
|
||||
Glossary
|
||||
========
|
||||
|
||||
Definitions of terms used in Docker documentation.
|
||||
|
||||
@@ -14,5 +14,9 @@ Contents:
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
fundamentals
|
||||
filesystem
|
||||
layer
|
||||
image
|
||||
container
|
||||
|
||||
|
||||
|
||||
40
docs/sources/terms/layer.rst
Normal file
@@ -0,0 +1,40 @@
|
||||
:title: Layers
|
||||
:description: Organizing the Docker Root File System
|
||||
:keywords: containers, lxc, concepts, explanation, image, container
|
||||
|
||||
Layers
|
||||
======
|
||||
|
||||
In a traditional Linux boot, the kernel first mounts the root
|
||||
:ref:`filesystem_def` as read-only, checks its integrity, and then
|
||||
switches the whole rootfs volume to read-write mode.
|
||||
|
||||
.. _layer_def:
|
||||
|
||||
Layer
|
||||
.....
|
||||
|
||||
When Docker mounts the rootfs, it starts read-only, as in a tradtional
|
||||
Linux boot, but then, instead of changing the file system to
|
||||
read-write mode, it takes advantage of a `union mount
|
||||
<http://en.wikipedia.org/wiki/Union_mount>`_ to add a read-write file
|
||||
system *over* the read-only file system. In fact there may be multiple
|
||||
read-only file systems stacked on top of each other. We think of each
|
||||
one of these file systems as a **layer**.
|
||||
|
||||
.. image:: images/docker-filesystems-multilayer.png
|
||||
|
||||
At first, the top read-write layer has nothing in it, but any time a
|
||||
process creates a file, this happens in the top layer. And if
|
||||
something needs to update an existing file in a lower layer, then the
|
||||
file gets copied to the upper layer and changes go into the copy. The
|
||||
version of the file on the lower layer cannot be seen by the
|
||||
applications anymore, but it is there, unchanged.
|
||||
|
||||
.. _ufs_def:
|
||||
|
||||
Union File System
|
||||
.................
|
||||
|
||||
We call the union of the read-write layer and all the read-only layers
|
||||
a **union file system**.
|
||||
@@ -17,7 +17,8 @@ This documentation has the following resources:
|
||||
commandline/index
|
||||
contributing/index
|
||||
api/index
|
||||
faq
|
||||
terms/index
|
||||
faq
|
||||
|
||||
|
||||
|
||||
.. image:: concepts/images/lego_docker.jpg
|
||||
|
||||
@@ -51,7 +51,7 @@ For example:
|
||||
.. code-block:: bash
|
||||
|
||||
# Run docker in daemon mode
|
||||
sudo <path to>/docker -H 0.0.0.0:5555 &
|
||||
sudo <path to>/docker -H 0.0.0.0:5555 -d &
|
||||
# Download a base image
|
||||
docker -H :5555 pull base
|
||||
|
||||
@@ -61,7 +61,7 @@ on both tcp and a unix socket
|
||||
.. code-block:: bash
|
||||
|
||||
# Run docker in daemon mode
|
||||
sudo <path to>/docker -H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock
|
||||
sudo <path to>/docker -H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock -d &
|
||||
# Download a base image
|
||||
docker pull base
|
||||
# OR
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
:title: Docker Builder
|
||||
:description: Docker Builder specifes a simple DSL which allows you to automate the steps you would normally manually take to create an image.
|
||||
:keywords: builder, docker, Docker Builder, automation, image creation
|
||||
:title: Dockerfiles for Images
|
||||
:description: Dockerfiles use a simple DSL which allows you to automate the steps you would normally manually take to create an image.
|
||||
:keywords: builder, docker, Dockerfile, automation, image creation
|
||||
|
||||
==============
|
||||
Docker Builder
|
||||
==============
|
||||
==================
|
||||
Dockerfile Builder
|
||||
==================
|
||||
|
||||
**Docker can act as a builder** and read instructions from a text
|
||||
Dockerfile to automate the steps you would otherwise make manually to
|
||||
create an image. Executing ``docker build`` will run your steps and
|
||||
commit them along the way, giving you a final image.
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
Docker Builder specifes a simple DSL which allows you to automate the steps you
|
||||
would normally manually take to create an image. Docker Build will run your
|
||||
steps and commit them along the way, giving you a final image.
|
||||
|
||||
1. Usage
|
||||
========
|
||||
|
||||
To build an image from a source repository, create a description file called `Dockerfile`
|
||||
at the root of your repository. This file will describe the steps to assemble
|
||||
the image.
|
||||
To build an image from a source repository, create a description file
|
||||
called ``Dockerfile`` at the root of your repository. This file will
|
||||
describe the steps to assemble the image.
|
||||
|
||||
Then call `docker build` with the path of your source repository as argument:
|
||||
Then call ``docker build`` with the path of your source repository as
|
||||
argument:
|
||||
|
||||
``docker build .``
|
||||
|
||||
@@ -28,7 +30,7 @@ build succeeds:
|
||||
|
||||
``docker build -t shykes/myapp .``
|
||||
|
||||
Docker will run your steps one-by-one, committing the result if necessary,
|
||||
Docker will run your steps one-by-one, committing the result if necessary,
|
||||
before finally outputting the ID of your new image.
|
||||
|
||||
2. Format
|
||||
@@ -36,124 +38,172 @@ before finally outputting the ID of your new image.
|
||||
|
||||
The Dockerfile format is quite simple:
|
||||
|
||||
``instruction arguments``
|
||||
::
|
||||
|
||||
The Instruction is not case-sensitive, however convention is for them to be
|
||||
# Comment
|
||||
INSTRUCTION arguments
|
||||
|
||||
The Instruction is not case-sensitive, however convention is for them to be
|
||||
UPPERCASE in order to distinguish them from arguments more easily.
|
||||
|
||||
Dockerfiles are evaluated in order, therefore the first instruction must be
|
||||
`FROM` in order to specify the base image from which you are building.
|
||||
Docker evaluates the instructions in a Dockerfile in order. **The first
|
||||
instruction must be `FROM`** in order to specify the base image from
|
||||
which you are building.
|
||||
|
||||
Docker will ignore lines in Dockerfiles prefixed with "`#`", so you may add
|
||||
comment lines. A comment marker in the rest of the line will be treated as an
|
||||
argument.
|
||||
Docker will ignore **comment lines** *beginning* with ``#``. A comment
|
||||
marker anywhere in the rest of the line will be treated as an argument.
|
||||
|
||||
2. Instructions
|
||||
3. Instructions
|
||||
===============
|
||||
|
||||
Docker builder comes with a set of instructions, described below.
|
||||
Here is the set of instructions you can use in a ``Dockerfile`` for
|
||||
building images.
|
||||
|
||||
2.1 FROM
|
||||
3.1 FROM
|
||||
--------
|
||||
|
||||
``FROM <image>``
|
||||
|
||||
The `FROM` instruction sets the base image for subsequent instructions. As such,
|
||||
a valid Dockerfile must have it as its first instruction.
|
||||
The ``FROM`` instruction sets the :ref:`base_image_def` for subsequent
|
||||
instructions. As such, a valid Dockerfile must have ``FROM`` as its
|
||||
first instruction.
|
||||
|
||||
`FROM` can be included multiple times within a single Dockerfile in order to
|
||||
create multiple images. Simply make a note of the last image id output by the
|
||||
commit before each new `FROM` command.
|
||||
``FROM`` must be the first non-comment instruction in the
|
||||
``Dockerfile``.
|
||||
|
||||
2.2 MAINTAINER
|
||||
``FROM`` can appear multiple times within a single Dockerfile in order
|
||||
to create multiple images. Simply make a note of the last image id
|
||||
output by the commit before each new ``FROM`` command.
|
||||
|
||||
3.2 MAINTAINER
|
||||
--------------
|
||||
|
||||
``MAINTAINER <name>``
|
||||
|
||||
The `MAINTAINER` instruction allows you to set the Author field of the generated
|
||||
images.
|
||||
The ``MAINTAINER`` instruction allows you to set the *Author* field of
|
||||
the generated images.
|
||||
|
||||
2.3 RUN
|
||||
3.3 RUN
|
||||
-------
|
||||
|
||||
``RUN <command>``
|
||||
|
||||
The `RUN` instruction will execute any commands on the current image and commit
|
||||
the results. The resulting committed image will be used for the next step in the
|
||||
Dockerfile.
|
||||
The ``RUN`` instruction will execute any commands on the current image
|
||||
and commit the results. The resulting committed image will be used for
|
||||
the next step in the Dockerfile.
|
||||
|
||||
Layering `RUN` instructions and generating commits conforms to the
|
||||
core concepts of Docker where commits are cheap and containers can be created
|
||||
from any point in an image's history, much like source control.
|
||||
Layering ``RUN`` instructions and generating commits conforms to the
|
||||
core concepts of Docker where commits are cheap and containers can be
|
||||
created from any point in an image's history, much like source
|
||||
control.
|
||||
|
||||
2.4 CMD
|
||||
3.4 CMD
|
||||
-------
|
||||
|
||||
``CMD <command>``
|
||||
|
||||
The `CMD` instruction sets the command to be executed when running the image.
|
||||
This is functionally equivalent to running
|
||||
`docker commit -run '{"Cmd": <command>}'` outside the builder.
|
||||
The ``CMD`` instruction sets the command to be executed when running
|
||||
the image. This is functionally equivalent to running ``docker commit
|
||||
-run '{"Cmd": <command>}'`` outside the builder.
|
||||
|
||||
.. note::
|
||||
Don't confuse `RUN` with `CMD`. `RUN` actually runs a command and commits
|
||||
the result; `CMD` does not execute anything at build time, but specifies the
|
||||
intended command for the image.
|
||||
Don't confuse `RUN` with `CMD`. `RUN` actually runs a
|
||||
command and commits the result; `CMD` does not execute anything at
|
||||
build time, but specifies the intended command for the image.
|
||||
|
||||
2.5 EXPOSE
|
||||
3.5 EXPOSE
|
||||
----------
|
||||
|
||||
``EXPOSE <port> [<port>...]``
|
||||
|
||||
The `EXPOSE` instruction sets ports to be publicly exposed when running the
|
||||
image. This is functionally equivalent to running
|
||||
`docker commit -run '{"PortSpecs": ["<port>", "<port2>"]}'` outside the builder.
|
||||
The ``EXPOSE`` instruction sets ports to be publicly exposed when
|
||||
running the image. This is functionally equivalent to running ``docker
|
||||
commit -run '{"PortSpecs": ["<port>", "<port2>"]}'`` outside the
|
||||
builder.
|
||||
|
||||
2.6 ENV
|
||||
3.6 ENV
|
||||
-------
|
||||
|
||||
``ENV <key> <value>``
|
||||
|
||||
The `ENV` instruction sets the environment variable `<key>` to the value
|
||||
`<value>`. This value will be passed to all future ``RUN`` instructions. This is
|
||||
functionally equivalent to prefixing the command with `<key>=<value>`
|
||||
The ``ENV`` instruction sets the environment variable ``<key>`` to the
|
||||
value ``<value>``. This value will be passed to all future ``RUN``
|
||||
instructions. This is functionally equivalent to prefixing the command
|
||||
with ``<key>=<value>``
|
||||
|
||||
.. note::
|
||||
The environment variables will persist when a container is run from the resulting image.
|
||||
The environment variables will persist when a container is run
|
||||
from the resulting image.
|
||||
|
||||
2.7 ADD
|
||||
3.7 ADD
|
||||
-------
|
||||
|
||||
``ADD <src> <dest>``
|
||||
|
||||
The `ADD` instruction will copy new files from <src> and add them to the container's filesystem at path `<dest>`.
|
||||
The ``ADD`` instruction will copy new files from <src> and add them to
|
||||
the container's filesystem at path ``<dest>``.
|
||||
|
||||
`<src>` must be the path to a file or directory relative to the source directory being built (also called the
|
||||
context of the build) or a remote file URL.
|
||||
``<src>`` must be the path to a file or directory relative to the
|
||||
source directory being built (also called the *context* of the build) or
|
||||
a remote file URL.
|
||||
|
||||
`<dest>` is the path at which the source will be copied in the destination container.
|
||||
``<dest>`` is the path at which the source will be copied in the
|
||||
destination container.
|
||||
|
||||
The copy obeys the following rules:
|
||||
|
||||
If `<src>` is a directory, the entire directory is copied, including filesystem metadata.
|
||||
* If ``<src>`` is a URL and ``<dest>`` does not end with a trailing slash,
|
||||
then a file is downloaded from the URL and copied to ``<dest>``.
|
||||
* If ``<src>`` is a URL and ``<dest>`` does end with a trailing slash,
|
||||
then the filename is inferred from the URL and the file is downloaded to
|
||||
``<dest>/<filename>``. For instance, ``ADD http://example.com/foobar /``
|
||||
would create the file ``/foobar``. The URL must have a nontrivial path
|
||||
so that an appropriate filename can be discovered in this case
|
||||
(``http://example.com`` will not work).
|
||||
* If ``<src>`` is a directory, the entire directory is copied,
|
||||
including filesystem metadata.
|
||||
* If ``<src>``` is a tar archive in a recognized compression format
|
||||
(identity, gzip, bzip2 or xz), it is unpacked as a directory.
|
||||
|
||||
If `<src>` is a tar archive in a recognized compression format (identity, gzip, bzip2 or xz), it
|
||||
is unpacked as a directory.
|
||||
When a directory is copied or unpacked, it has the same behavior as
|
||||
``tar -x``: the result is the union of
|
||||
|
||||
When a directory is copied or unpacked, it has the same behavior as 'tar -x': the result is the union of
|
||||
a) whatever existed at the destination path and b) the contents of the source tree, with conflicts resolved
|
||||
in favor of b on a file-by-file basis.
|
||||
1. whatever existed at the destination path and
|
||||
2. the contents of the source tree,
|
||||
|
||||
If `<src>` is any other kind of file, it is copied individually along with its metadata. In this case,
|
||||
if `<dst>` ends with a trailing slash '/', it will be considered a directory and the contents of `<src>`
|
||||
will be written at `<dst>/base(<src>)`.
|
||||
If `<dst>` does not end with a trailing slash, it will be considered a regular file and the contents
|
||||
of `<src>` will be written at `<dst>`.
|
||||
with conflicts resolved in favor of 2) on a file-by-file basis.
|
||||
|
||||
If `<dest>` doesn't exist, it is created along with all missing directories in its path. All new
|
||||
files and directories are created with mode 0700, uid and gid 0.
|
||||
* If ``<src>`` is any other kind of file, it is copied individually
|
||||
along with its metadata. In this case, if ``<dst>`` ends with a
|
||||
trailing slash ``/``, it will be considered a directory and the
|
||||
contents of ``<src>`` will be written at ``<dst>/base(<src>)``.
|
||||
* If ``<dst>`` does not end with a trailing slash, it will be
|
||||
considered a regular file and the contents of ``<src>`` will be
|
||||
written at ``<dst>``.
|
||||
* If ``<dest>`` doesn't exist, it is created along with all missing
|
||||
directories in its path. All new files and directories are created
|
||||
with mode 0700, uid and gid 0.
|
||||
|
||||
3. Dockerfile Examples
|
||||
3.8 ENTRYPOINT
|
||||
--------------
|
||||
|
||||
``ENTRYPOINT ["/bin/echo"]``
|
||||
|
||||
The ``ENTRYPOINT`` instruction adds an entry command that will not be
|
||||
overwritten when arguments are passed to docker run, unlike the
|
||||
behavior of ``CMD``. This allows arguments to be passed to the
|
||||
entrypoint. i.e. ``docker run <image> -d`` will pass the "-d" argument
|
||||
to the entrypoint.
|
||||
|
||||
3.9 VOLUME
|
||||
----------
|
||||
|
||||
``VOLUME ["/data"]``
|
||||
|
||||
The ``VOLUME`` instruction will add one or more new volumes to any
|
||||
container created from the image.
|
||||
|
||||
4. Dockerfile Examples
|
||||
======================
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -161,14 +211,14 @@ files and directories are created with mode 0700, uid and gid 0.
|
||||
# Nginx
|
||||
#
|
||||
# VERSION 0.0.1
|
||||
|
||||
|
||||
FROM ubuntu
|
||||
MAINTAINER Guillaume J. Charmes "guillaume@dotcloud.com"
|
||||
|
||||
|
||||
# make sure the package repository is up to date
|
||||
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
|
||||
RUN apt-get update
|
||||
|
||||
|
||||
RUN apt-get install -y inotify-tools nginx apache2 openssh-server
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -176,12 +226,12 @@ files and directories are created with mode 0700, uid and gid 0.
|
||||
# Firefox over VNC
|
||||
#
|
||||
# VERSION 0.3
|
||||
|
||||
|
||||
FROM ubuntu
|
||||
# make sure the package repository is up to date
|
||||
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
|
||||
RUN apt-get update
|
||||
|
||||
|
||||
# Install vnc, xvfb in order to create a 'fake' display and firefox
|
||||
RUN apt-get install -y x11vnc xvfb firefox
|
||||
RUN mkdir /.vnc
|
||||
@@ -189,7 +239,7 @@ files and directories are created with mode 0700, uid and gid 0.
|
||||
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
|
||||
# Autostart firefox (might not be the best way, but it does the trick)
|
||||
RUN bash -c 'echo "firefox" >> /.bashrc'
|
||||
|
||||
|
||||
EXPOSE 5900
|
||||
CMD ["x11vnc", "-forever", "-usepw", "-create"]
|
||||
|
||||
|
||||
@@ -1,27 +1,75 @@
|
||||
:title: Working With Repositories
|
||||
:description: Generally, there are two types of repositories: Top-level repositories which are controlled by the people behind Docker, and user repositories.
|
||||
:description: Repositories allow users to share images.
|
||||
:keywords: repo, repositiores, usage, pull image, push image, image, documentation
|
||||
|
||||
.. _working_with_the_repository:
|
||||
|
||||
Working with the Repository
|
||||
===========================
|
||||
Working with Repositories
|
||||
=========================
|
||||
|
||||
A *repository* is a hosted collection of tagged :ref:`images
|
||||
<image_def>` that together create the file system for a container. The
|
||||
repository's name is a tag that indicates the provenance of the
|
||||
repository, i.e. who created it and where the original copy is
|
||||
located.
|
||||
|
||||
Top-level repositories and user repositories
|
||||
--------------------------------------------
|
||||
You can find one or more repositories hosted on a *registry*. There
|
||||
can be an implicit or explicit host name as part of the repository
|
||||
tag. The implicit registry is located at ``index.docker.io``, the home
|
||||
of "top-level" repositories and the Central Index. This registry may
|
||||
also include public "user" repositories.
|
||||
|
||||
Generally, there are two types of repositories: Top-level repositories which are controlled by the people behind
|
||||
Docker, and user repositories.
|
||||
So Docker is not only a tool for creating and managing your own
|
||||
:ref:`containers <container_def>` -- **Docker is also a tool for
|
||||
sharing**. The Docker project provides a Central Registry to host
|
||||
public repositories, namespaced by user, and a Central Index which
|
||||
provides user authentication and search over all the public
|
||||
repositories. You can host your own Registry too! Docker acts as a
|
||||
client for these services via ``docker search, pull, login`` and
|
||||
``push``.
|
||||
|
||||
* Top-level repositories can easily be recognized by not having a ``/`` (slash) in their name. These repositories can
|
||||
generally be trusted.
|
||||
* User repositories always come in the form of ``<username>/<repo_name>``. This is what your published images will look like.
|
||||
* User images are not checked, it is therefore up to you whether or not you trust the creator of this image.
|
||||
Top-level, User, and Your Own Repositories
|
||||
------------------------------------------
|
||||
|
||||
There are two types of public repositories: *top-level* repositories
|
||||
which are controlled by the Docker team, and *user* repositories
|
||||
created by individual contributors.
|
||||
|
||||
Find public images available on the index
|
||||
-----------------------------------------
|
||||
* Top-level repositories can easily be recognized by **not** having a
|
||||
``/`` (slash) in their name. These repositories can generally be
|
||||
trusted.
|
||||
* User repositories always come in the form of
|
||||
``<username>/<repo_name>``. This is what your published images will
|
||||
look like if you push to the public Central Registry.
|
||||
* Only the authenticated user can push to their *username* namespace
|
||||
on the Central Registry.
|
||||
* User images are not checked, it is therefore up to you whether or
|
||||
not you trust the creator of this image.
|
||||
|
||||
Right now (version 0.5), private repositories are only possible by
|
||||
hosting `your own registry
|
||||
<https://github.com/dotcloud/docker-registry>`_. To push or pull to a
|
||||
repository on your own registry, you must prefix the tag with the
|
||||
address of the registry's host, like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Tag to create a repository with the full registry location.
|
||||
# The location (e.g. localhost.localdomain:5000) becomes
|
||||
# a permanent part of the repository name
|
||||
docker tag 0u812deadbeef localhost.localdomain:5000/repo_name
|
||||
|
||||
# Push the new repository to its home location on localhost
|
||||
docker push localhost.localdomain:5000/repo_name
|
||||
|
||||
Once a repository has your registry's host name as part of the tag,
|
||||
you can push and pull it like any other repository, but it will
|
||||
**not** be searchable (or indexed at all) in the Central Index, and
|
||||
there will be no user name checking performed. Your registry will
|
||||
function completely independently from the Central Index.
|
||||
|
||||
Find public images available on the Central Index
|
||||
-------------------------------------------------
|
||||
|
||||
Seach by name, namespace or description
|
||||
|
||||
@@ -37,68 +85,48 @@ Download them simply by their name
|
||||
docker pull <value>
|
||||
|
||||
|
||||
Very similarly you can search for and browse the index online on https://index.docker.io
|
||||
Very similarly you can search for and browse the index online on
|
||||
https://index.docker.io
|
||||
|
||||
|
||||
Connecting to the repository
|
||||
----------------------------
|
||||
Connecting to the Central Registry
|
||||
----------------------------------
|
||||
|
||||
You can create a user on the central docker repository online, or by running
|
||||
You can create a user on the central Docker Index online, or by running
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker login
|
||||
|
||||
This will prompt you for a username, which will become a public
|
||||
namespace for your public repositories.
|
||||
|
||||
If your username does not exist it will prompt you to also enter a password and your e-mail address. It will then
|
||||
automatically log you in.
|
||||
If your username does not exist it will prompt you to also enter a
|
||||
password and your e-mail address. It will then automatically log you
|
||||
in.
|
||||
|
||||
|
||||
Committing a container to a named image
|
||||
---------------------------------------
|
||||
|
||||
In order to commit to the repository it is required to have committed your container to an image with your namespace.
|
||||
In order to commit to the repository it is required to have committed
|
||||
your container to an image within your username namespace.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# for example docker commit $CONTAINER_ID dhrp/kickassapp
|
||||
docker commit <container_id> <your username>/<some_name>
|
||||
docker commit <container_id> <username>/<repo_name>
|
||||
|
||||
|
||||
Pushing a container to the repository
|
||||
-----------------------------------------
|
||||
Pushing a container to its repository
|
||||
-------------------------------------
|
||||
|
||||
In order to push an image to the repository you need to have committed your container to a named image (see above)
|
||||
In order to push an image to its repository you need to have committed
|
||||
your container to a named image (see above)
|
||||
|
||||
Now you can commit this image to the repository
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# for example docker push dhrp/kickassapp
|
||||
docker push <image-name>
|
||||
|
||||
|
||||
Changing the server to connect to
|
||||
----------------------------------
|
||||
|
||||
When you are running your own index and/or registry, You can change the server the docker client will connect to.
|
||||
|
||||
Variable
|
||||
^^^^^^^^
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
DOCKER_INDEX_URL
|
||||
|
||||
Setting this environment variable on the docker server will change the URL docker index.
|
||||
This address is used in commands such as ``docker login``, ``docker push`` and ``docker pull``.
|
||||
The docker daemon doesn't need to be restarted for this parameter to take effect.
|
||||
|
||||
Example
|
||||
^^^^^^^
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
docker -d &
|
||||
export DOCKER_INDEX_URL="https://index.docker.io"
|
||||
|
||||
docker push <username>/<repo_name>
|
||||
|
||||
2
docs/theme/MAINTAINERS
vendored
@@ -1 +1 @@
|
||||
Thatcher Penskens <thatcher@dotcloud.com>
|
||||
Thatcher Peskens <thatcher@dotcloud.com>
|
||||
|
||||
15
docs/theme/docker/layout.html
vendored
@@ -68,19 +68,18 @@
|
||||
|
||||
<div style="float: right" class="pull-right">
|
||||
<ul class="nav">
|
||||
<li id="nav-introduction"><a href="http://www.docker.io/">Introduction</a></li>
|
||||
<li id="nav-introduction"><a href="http://www.docker.io/" title="Docker Homepage">Home</a></li>
|
||||
<li id="nav-about"><a href="http://www.docker.io/about/" title="About">About</a></li>
|
||||
<li id="nav-community"><a href="http://www.docker.io/community/" title="Community">Community</a></li>
|
||||
<li id="nav-gettingstarted"><a href="http://www.docker.io/gettingstarted/">Getting started</a></li>
|
||||
<li id="nav-documentation" class="active"><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
|
||||
<li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
|
||||
<li id="nav-blog"><a href="http://blog.docker.io/" title="Docker Blog">Blog</a></li>
|
||||
<li id="nav-index"><a href="http://index.docker.io/" title="Docker Image Index, find images here">INDEX <img class="inline-icon" src="{{ pathto('_static/img/external-link-icon.png', 1) }}" title="external link"> </a></li>
|
||||
</ul>
|
||||
<!--<div class="social links" style="float: right; margin-top: 14px; margin-left: 12px">-->
|
||||
<!--<a class="twitter" href="http://twitter.com/getdocker">Twitter</a>-->
|
||||
<!--<a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>-->
|
||||
<!--</div>-->
|
||||
</div>
|
||||
|
||||
<div style="margin-left: -12px; float: left;">
|
||||
<a href="http://www.docker.io"><img style="margin-top: 12px; height: 38px" src="{{ pathto('_static/img/docker-letters-logo.gif', 1) }}"></a>
|
||||
<a href="http://www.docker.io" title="Docker Homepage"><img style="margin-top: 0px; height: 60px; margin-left: 10px;" src="{{ pathto('_static/img/docker-top-logo.png', 1) }}"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -96,7 +95,7 @@
|
||||
<div class="pull-right" id="fork-us" style="margin-top: 16px; margin-right: 16px;">
|
||||
<a href="http://github.com/dotcloud/docker/"><img src="{{ pathto('_static/img/fork-us.png', 1) }}"> Fork us on Github</a>
|
||||
</div>
|
||||
<h1 class="pageheader">DOCUMENTATION</h1>
|
||||
<h1 class="pageheader"><a href="http://docs.docker.io/en/latest/" title="Documentation" style="color: white;">DOCUMENTATION</a></h1>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
10
docs/theme/docker/static/css/main.css
vendored
@@ -34,12 +34,12 @@ h4 {
|
||||
.navbar .nav li a {
|
||||
padding: 22px 15px 22px;
|
||||
}
|
||||
.navbar .brand {
|
||||
padding: 13px 10px 13px 28px ;
|
||||
}
|
||||
.navbar-dotcloud .container {
|
||||
border-bottom: 2px #000000 solid;
|
||||
}
|
||||
.inline-icon {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
/*
|
||||
* Responsive YouTube, Vimeo, Embed, and HTML5 Videos with CSS
|
||||
* http://www.jonsuh.com
|
||||
@@ -82,7 +82,7 @@ h4 {
|
||||
.btn-custom {
|
||||
background-color: #292929 !important;
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr="#515151", endColorstr="#282828");
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#515151", endColorstr="#282828");
|
||||
background-image: -khtml-gradient(linear, left top, left bottom, from(#515151), to(#282828));
|
||||
background-image: -moz-linear-gradient(top, #515151, #282828);
|
||||
background-image: -ms-linear-gradient(top, #515151, #282828);
|
||||
@@ -301,7 +301,7 @@ section.header {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
background-color: #43484c;
|
||||
filter: progid:dximagetransform.microsoft.gradient(gradientType=0, startColorstr='#FFFF6E56', endColorstr='#FFED4F35');
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#FFFF6E56', endColorstr='#FFED4F35');
|
||||
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #747474), color-stop(100%, #43484c));
|
||||
background-image: -webkit-linear-gradient(top, #747474 0%, #43484c 100%);
|
||||
background-image: -moz-linear-gradient(top, #747474 0%, #43484c 100%);
|
||||
|
||||
10
docs/theme/docker/static/css/main.less
vendored
@@ -53,13 +53,6 @@ h1, h2, h3, h4 {
|
||||
padding: 22px 15px 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.brand {
|
||||
padding: 13px 10px 13px 28px ;
|
||||
// padding-left: 30px;
|
||||
|
||||
}
|
||||
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@@ -67,6 +60,9 @@ h1, h2, h3, h4 {
|
||||
border-bottom: 2px @black solid;
|
||||
}
|
||||
|
||||
.inline-icon {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Responsive YouTube, Vimeo, Embed, and HTML5 Videos with CSS
|
||||
|
||||
BIN
docs/theme/docker/static/img/docker-top-logo.png
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
docs/theme/docker/static/img/external-link-icon.png
vendored
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
@@ -1 +0,0 @@
|
||||
Thatcher Penskens <thatcher@dotcloud.com>
|
||||
@@ -1,2 +0,0 @@
|
||||
www:
|
||||
type: static
|
||||
@@ -1,220 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
|
||||
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
|
||||
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
|
||||
<!--[if gt IE 8]><!-->
|
||||
<html class="no-js" xmlns="http://www.w3.org/1999/html" xmlns="http://www.w3.org/1999/html"> <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title>Docker - the Linux container runtime</title>
|
||||
|
||||
<meta name="description" content="Docker encapsulates heterogeneous payloads in standard containers">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<!-- twitter bootstrap -->
|
||||
<link rel="stylesheet" href="../static/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="../static/css/bootstrap-responsive.min.css">
|
||||
|
||||
<!-- main style file -->
|
||||
<link rel="stylesheet" href="../static/css/main.css">
|
||||
|
||||
<!-- vendor scripts -->
|
||||
<script src="../static/js/vendor/jquery-1.9.1.min.js" type="text/javascript" ></script>
|
||||
<script src="../static/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js" type="text/javascript" ></script>
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-dotcloud">
|
||||
<div class="container" style="text-align: center;">
|
||||
|
||||
<div style="float: right" class="pull-right">
|
||||
<ul class="nav">
|
||||
<li id="nav-introduction"><a href="../">Introduction</a></li>
|
||||
<li id="nav-gettingstarted" class="active"><a href="">Getting started</a></li>
|
||||
<li id="nav-documentation" class=""><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
|
||||
<li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="margin-left: -12px; float: left;">
|
||||
<a href="../index.html"><img style="margin-top: 12px; height: 38px" src="../static/img/docker-letters-logo.gif"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
|
||||
<div class="span12 titlebar">
|
||||
|
||||
<div class="pull-right" id="fork-us" style="margin-top: 16px; margin-right: 16px;">
|
||||
<a href="http://github.com/dotcloud/docker/"><img src="../static/img/fork-us.png"> Fork us on Github</a>
|
||||
</div>
|
||||
|
||||
<h1 class="pageheader"> GETTING STARTED</h1>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="alert alert-info" style="margin-bottom: 0;">
|
||||
<strong>Docker is still under heavy development.</strong> It should not yet be used in production. Check <a href="http://github.com/dotcloud/docker">the repo</a> for recent progress.
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
<section class="contentblock">
|
||||
<h2>
|
||||
<a name="installing-on-ubuntu-1204-and-1210" class="anchor" href="#installing-on-ubuntu-1204-and-1210"><span class="mini-icon mini-icon-link"></span>
|
||||
</a>Installing on Ubuntu</h2>
|
||||
|
||||
<p><strong>Requirements</strong></p>
|
||||
<ul>
|
||||
<li>Ubuntu 12.04 (LTS) (64-bit)</li>
|
||||
<li> or Ubuntu 12.10 (quantal) (64-bit)</li>
|
||||
<li>The 3.8 Linux Kernel</li>
|
||||
</ul>
|
||||
<ol>
|
||||
<li>
|
||||
<p><strong>Install dependencies</strong></p>
|
||||
The linux-image-extra package is only needed on standard Ubuntu EC2 AMIs in order to install the aufs kernel module.
|
||||
<pre>sudo apt-get install linux-image-extra-`uname -r`</pre>
|
||||
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Install Docker</strong></p>
|
||||
<p>Add the Ubuntu PPA (Personal Package Archive) sources to your apt sources list, update and install.</p>
|
||||
<p>This may import a new GPG key (key 63561DC6: public key "Launchpad PPA for dotcloud team" imported).</p>
|
||||
<div class="highlight">
|
||||
<pre>sudo apt-get install software-properties-common</pre>
|
||||
<pre>sudo add-apt-repository ppa:dotcloud/lxc-docker</pre>
|
||||
<pre>sudo apt-get update</pre>
|
||||
<pre>sudo apt-get install lxc-docker</pre>
|
||||
</div>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<p><strong>Run!</strong></p>
|
||||
|
||||
<div class="highlight">
|
||||
<pre>docker run -i -t ubuntu /bin/bash</pre>
|
||||
</div>
|
||||
</li>
|
||||
Continue with the <a href="http://docs.docker.io/en/latest/examples/hello_world/">Hello world</a> example.<br>
|
||||
Or check <a href="http://docs.docker.io/en/latest/installation/ubuntulinux/">more detailed installation instructions</a>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section class="contentblock">
|
||||
<h2>Contributing to Docker</h2>
|
||||
|
||||
<p>Want to hack on Docker? Awesome! We have some <a href="http://docs.docker.io/en/latest/contributing/contributing/">instructions to get you started</a>. They are probably not perfect, please let us know if anything feels wrong or incomplete.</p>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
<div class="span6">
|
||||
<section class="contentblock">
|
||||
<h2>Quick install on other operating systems</h2>
|
||||
<p><strong>For other operating systems we recommend and provide a streamlined install with virtualbox,
|
||||
vagrant and an Ubuntu virtual machine.</strong></p>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://docs.docker.io/en/latest/installation/vagrant/">Mac OS X and other linuxes</a></li>
|
||||
<li><a href="http://docs.docker.io/en/latest/installation/windows/">Windows</a></li>
|
||||
</ul>
|
||||
|
||||
</section>
|
||||
|
||||
<section class="contentblock">
|
||||
<h2>Questions? Want to get in touch?</h2>
|
||||
<p>There are several ways to get in touch:</p>
|
||||
<p><strong>Join the discussion on IRC.</strong> We can be found in the <a href="irc://chat.freenode.net#docker">#docker</a> channel on chat.freenode.net</p>
|
||||
<p><strong>Discussions</strong> happen on our google group: <a href="https://groups.google.com/d/forum/docker-club">docker-club at googlegroups.com</a></p>
|
||||
<p>All our <strong>development and decisions</strong> are made out in the open on Github <a href="http://www.github.com/dotcloud/docker">github.com/dotcloud/docker</a></p>
|
||||
<p><strong>Get help on using Docker</strong> by asking on <a href="http://stackoverflow.com/tags/docker/">Stackoverflow</a></p>
|
||||
<p>And of course, <strong>tweet</strong> your tweets to <a href="http://twitter.com/getdocker/">twitter.com/getdocker</a></p>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="contentblock">
|
||||
<div id="wufoo-z7x3p3">
|
||||
Fill out my <a href="http://dotclouddocker.wufoo.com/forms/z7x3p3">online form</a>.
|
||||
</div>
|
||||
<script type="text/javascript">var z7x3p3;(function(d, t) {
|
||||
var s = d.createElement(t), options = {
|
||||
'userName':'dotclouddocker',
|
||||
'formHash':'z7x3p3',
|
||||
'autoResize':true,
|
||||
'height':'577',
|
||||
'async':true,
|
||||
'header':'show'};
|
||||
s.src = ('https:' == d.location.protocol ? 'https://' : 'http://') + 'wufoo.com/scripts/embed/form.js';
|
||||
s.onload = s.onreadystatechange = function() {
|
||||
var rs = this.readyState; if (rs) if (rs != 'complete') if (rs != 'loaded') return;
|
||||
try { z7x3p3 = new WufooForm();z7x3p3.initialize(options);z7x3p3.display(); } catch (e) {}};
|
||||
var scr = d.getElementsByTagName(t)[0], par = scr.parentNode; par.insertBefore(s, scr);
|
||||
})(document, 'script');</script>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container">
|
||||
<footer id="footer" class="footer">
|
||||
<div class="row">
|
||||
<div class="span12 social">
|
||||
<div class="tbox textright forceleftmargin social links pull-right">
|
||||
<a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
|
||||
<a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
|
||||
</div>
|
||||
Docker is a project by <a href="http://www.dotcloud.com">dotCloud</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="emptyspace" style="height: 40px">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- bootstrap javascipts -->
|
||||
<script src="../static/js/vendor/bootstrap.min.js" type="text/javascript"></script>
|
||||
|
||||
<!-- Google analytics -->
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-6096819-11']);
|
||||
_gaq.push(['_setDomainName', 'docker.io']);
|
||||
_gaq.push(['_setAllowLinker', true]);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,359 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
|
||||
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
|
||||
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
|
||||
<!--[if gt IE 8]><!-->
|
||||
<html class="no-js" xmlns="http://www.w3.org/1999/html"> <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="google-site-verification" content="UxV66EKuPe87dgnH1sbrldrx6VsoWMrx5NjwkgUFxXI" />
|
||||
<title>Docker - the Linux container engine</title>
|
||||
|
||||
<meta name="description" content="Docker encapsulates heterogeneous payloads in standard containers">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<!-- twitter bootstrap -->
|
||||
<link rel="stylesheet" href="static/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="static/css/bootstrap-responsive.min.css">
|
||||
|
||||
<!-- main style file -->
|
||||
<link rel="stylesheet" href="static/css/main.css">
|
||||
|
||||
<!-- vendor scripts -->
|
||||
<script src="static/js/vendor/jquery-1.9.1.min.js" type="text/javascript" ></script>
|
||||
<script src="static/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js" type="text/javascript" ></script>
|
||||
|
||||
<style>
|
||||
.indexlabel {
|
||||
float: left;
|
||||
width: 150px;
|
||||
display: block;
|
||||
padding: 10px 20px 10px;
|
||||
font-size: 20px;
|
||||
font-weight: 200;
|
||||
background-color: #a30000;
|
||||
color: white;
|
||||
height: 22px;
|
||||
}
|
||||
.searchbutton {
|
||||
font-size: 20px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.debug {
|
||||
border: 1px red dotted;
|
||||
}
|
||||
.twitterblock {
|
||||
min-height: 75px;
|
||||
}
|
||||
|
||||
.twitterblock img {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-dotcloud">
|
||||
<div class="container" style="text-align: center;">
|
||||
|
||||
|
||||
<div class="pull-left" id="fork-us" style="margin-top: 16px;">
|
||||
<a href="http://github.com/dotcloud/docker/"><img src="static/img/fork-us.png" alt="fork-icon"> Fork us on Github</a>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" >
|
||||
<ul class="nav">
|
||||
<li id="nav-introduction" class="active"><a href="/">Introduction</a></li>
|
||||
<li id="nav-gettingstarted"><a href="gettingstarted">Getting started</a></li>
|
||||
<li id="nav-documentation" class=""><a href="http://docs.docker.io/en/latest/">Documentation</a></li>
|
||||
<li id="nav-blog"><a href="http://blog.docker.io/">Blog</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container" style="margin-top: 30px;">
|
||||
<div class="row">
|
||||
|
||||
<div class="span12">
|
||||
<section class="contentblock header">
|
||||
|
||||
<div class="span5" style="margin-bottom: 15px;">
|
||||
<div style="text-align: center;" >
|
||||
<img src="static/img/docker_letters_500px.png" alt="docker letters">
|
||||
|
||||
<h2>The Linux container engine</h2>
|
||||
</div>
|
||||
|
||||
<div style="display: block; text-align: center; margin-top: 20px;">
|
||||
|
||||
<h5>
|
||||
Docker is an open-source engine which automates the deployment of applications as highly portable, self-sufficient containers which are independent of hardware, language, framework, packaging system and hosting provider.
|
||||
</h5>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div style="display: block; text-align: center; margin-top: 30px;">
|
||||
<a class="btn btn-custom btn-large" href="gettingstarted/">Let's get started</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="span6" >
|
||||
<div class="js-video" >
|
||||
<iframe width="600" height="360" src="http://www.youtube.com/embed/wW9CAH9nSLs?feature=player_detailpage&rel=0&modestbranding=1&start=11" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br style="clear: both"/>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
|
||||
<div class="span6">
|
||||
<section class="contentblock">
|
||||
<h4>Heterogeneous payloads</h4>
|
||||
<p>Any combination of binaries, libraries, configuration files, scripts, virtualenvs, jars, gems, tarballs, you name it. No more juggling between domain-specific tools. Docker can deploy and run them all.</p>
|
||||
<h4>Any server</h4>
|
||||
<p>Docker can run on any x64 machine with a modern linux kernel - whether it's a laptop, a bare metal server or a VM. This makes it perfect for multi-cloud deployments.</p>
|
||||
<h4>Isolation</h4>
|
||||
<p>Docker isolates processes from each other and from the underlying host, using lightweight containers.</p>
|
||||
<h4>Repeatability</h4>
|
||||
<p>Because each container is isolated in its own filesystem, they behave the same regardless of where, when, and alongside what they run.</p>
|
||||
</section>
|
||||
<section class="contentblock">
|
||||
<div class="container">
|
||||
<div class="span2" style="margin-left: 0" >
|
||||
<a href="http://dotcloud.theresumator.com/apply/mWjkD4/Software-Engineer.html" title="Job description"><img src="static/img/hiring_graphic.png" alt="we're hiring" width="140" style="margin-top: 25px"></a>
|
||||
</div>
|
||||
<div class="span4" style="margin-left: 0">
|
||||
<h4>Do you think it is cool to hack on docker? Join us!</h4>
|
||||
<ul>
|
||||
<li>Work on open source</li>
|
||||
<li>Program in Go</li>
|
||||
</ul>
|
||||
<a href="http://dotcloud.theresumator.com/apply/mWjkD4/Software-Engineer.html" title="Job description">read more</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<section class="contentblock">
|
||||
<h1>New! Docker Index</h1>
|
||||
On the Docker Index you can find and explore pre-made container images. It allows you to share your images and download them.
|
||||
|
||||
<br><br>
|
||||
<a href="https://index.docker.io" target="_blank">
|
||||
<div class="indexlabel">
|
||||
DOCKER index
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<input type="button" class="searchbutton" value="Search images"
|
||||
onClick="window.open('https://index.docker.io')" />
|
||||
|
||||
</section>
|
||||
<section class="contentblock">
|
||||
<div id="wufoo-z7x3p3">
|
||||
Fill out my <a href="http://dotclouddocker.wufoo.com/forms/z7x3p3">online form</a>.
|
||||
</div>
|
||||
<script type="text/javascript">var z7x3p3;(function(d, t) {
|
||||
var s = d.createElement(t), options = {
|
||||
'userName':'dotclouddocker',
|
||||
'formHash':'z7x3p3',
|
||||
'autoResize':true,
|
||||
'height':'577',
|
||||
'async':true,
|
||||
'header':'show'};
|
||||
s.src = ('https:' == d.location.protocol ? 'https://' : 'http://') + 'wufoo.com/scripts/embed/form.js';
|
||||
s.onload = s.onreadystatechange = function() {
|
||||
var rs = this.readyState; if (rs) if (rs != 'complete') if (rs != 'loaded') return;
|
||||
try { z7x3p3 = new WufooForm();z7x3p3.initialize(options);z7x3p3.display(); } catch (e) {}};
|
||||
var scr = d.getElementsByTagName(t)[0], par = scr.parentNode; par.insertBefore(s, scr);
|
||||
})(document, 'script');</script>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
<section class="contentblock twitterblock">
|
||||
<img src="https://si0.twimg.com/profile_images/2707460527/252a64411a339184ff375a96fb68dcb0_bigger.png">
|
||||
<em>Mitchell Hashimoto @mitchellh:</em> Docker launched today. It is incredible. They’re also working RIGHT NOW on a Vagrant provider. LXC is COMING!!
|
||||
</section>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<section class="contentblock twitterblock">
|
||||
<img src="https://si0.twimg.com/profile_images/1108290260/Adam_Jacob-114x150_original_bigger.jpg">
|
||||
<em>Adam Jacob @adamhjk:</em> Docker is clearly the right idea. @solomonstre absolutely killed it. Containerized app deployment is the future, I think.
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
<section class="contentblock twitterblock">
|
||||
<img src="https://si0.twimg.com/profile_images/14872832/twitter_pic_bigger.jpg">
|
||||
<em>Matt Townsend @mtownsend:</em> I have a serious code crush on docker.io - it's Lego for PaaS. Motherfucking awesome Lego.
|
||||
</section>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<section class="contentblock twitterblock">
|
||||
<img src="https://si0.twimg.com/profile_images/1312352395/rupert-259x300_bigger.jpg">
|
||||
<em>Rob Harrop @robertharrop:</em> Impressed by @getdocker - it's all kinds of magic. Serious rethink of AWS architecture happening @skillsmatter.
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
<section class="contentblock twitterblock">
|
||||
<img src="https://twimg0-a.akamaihd.net/profile_images/2491994496/rbevyyq6ykp6bnoby2je_bigger.jpeg">
|
||||
<em>John Willis @botchagalupe:</em> IMHO docker is to paas what chef was to Iaas 4 years ago
|
||||
</section>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<section class="contentblock twitterblock">
|
||||
<img src="https://twimg0-a.akamaihd.net/profile_images/3348427561/9d7f08f1e103a16c8debd169301b9944_bigger.jpeg">
|
||||
<em>John Feminella @superninjarobot:</em> So, @getdocker is pure excellence. If you've ever wished for arbitrary, PaaS-agnostic, lxc/aufs Linux containers, this is your jam!
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
<section class="contentblock twitterblock">
|
||||
<img src="https://si0.twimg.com/profile_images/3408403010/4496ccdd14e9b7285eca04c31a740207_bigger.jpeg">
|
||||
<em>David Romulan @destructuring:</em> I haven't had this much fun since AWS
|
||||
</section>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<section class="contentblock twitterblock">
|
||||
<img src="https://si0.twimg.com/profile_images/780893320/My_Avatar_bigger.jpg">
|
||||
<em>Ricardo Gladwell @rgladwell:</em> wow @getdocker is either amazing or totally stupid
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
|
||||
<section class="contentblock">
|
||||
|
||||
<h2>Notable features</h2>
|
||||
|
||||
<ul>
|
||||
<li>Filesystem isolation: each process container runs in a completely separate root filesystem.</li>
|
||||
<li>Resource isolation: system resources like cpu and memory can be allocated differently to each process container, using cgroups.</li>
|
||||
<li>Network isolation: each process container runs in its own network namespace, with a virtual interface and IP address of its own.</li>
|
||||
<li>Copy-on-write: root filesystems are created using copy-on-write, which makes deployment extremely fast, memory-cheap and disk-cheap.</li>
|
||||
<li>Logging: the standard streams (stdout/stderr/stdin) of each process container is collected and logged for real-time or batch retrieval.</li>
|
||||
<li>Change management: changes to a container's filesystem can be committed into a new image and re-used to create more containers. No templating or manual configuration required.</li>
|
||||
<li>Interactive shell: docker can allocate a pseudo-tty and attach to the standard input of any container, for example to run a throwaway interactive shell.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Under the hood</h2>
|
||||
|
||||
<p>Under the hood, Docker is built on the following components:</p>
|
||||
|
||||
<ul>
|
||||
<li>The <a href="http://blog.dotcloud.com/kernel-secrets-from-the-paas-garage-part-24-c">cgroup</a> and <a href="http://blog.dotcloud.com/under-the-hood-linux-kernels-on-dotcloud-part">namespacing</a> capabilities of the Linux kernel;</li>
|
||||
<li><a href="http://aufs.sourceforge.net/aufs.html">AUFS</a>, a powerful union filesystem with copy-on-write capabilities;</li>
|
||||
<li>The <a href="http://golang.org">Go</a> programming language;</li>
|
||||
<li><a href="http://lxc.sourceforge.net/">lxc</a>, a set of convenience scripts to simplify the creation of linux containers.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Who started it</h2>
|
||||
<p>
|
||||
Docker is an open-source implementation of the deployment engine which powers <a href="http://dotcloud.com">dotCloud</a>, a popular Platform-as-a-Service.</p>
|
||||
|
||||
<p>It benefits directly from the experience accumulated over several years of large-scale operation and support of hundreds of thousands
|
||||
of applications and databases.
|
||||
</p>
|
||||
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="span6">
|
||||
|
||||
|
||||
<section class="contentblock">
|
||||
<h3 id="twitter">Twitter</h3>
|
||||
<a class="twitter-timeline" href="https://twitter.com/getdocker" data-widget-id="312730839718957056">Tweets by @getdocker</a>
|
||||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!-- end container -->
|
||||
|
||||
|
||||
<div class="container">
|
||||
<footer id="footer" class="footer">
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<div class="tbox textright forceleftmargin social links pull-right">
|
||||
<a class="twitter" href="http://twitter.com/getdocker">Twitter</a>
|
||||
<a class="github" href="https://github.com/dotcloud/docker/">GitHub</a>
|
||||
</div>
|
||||
Docker is a project by <a href="http://www.dotcloud.com">dotCloud</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="emptyspace" style="height: 40px">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- bootstrap javascipts -->
|
||||
<script src="static/js/vendor/bootstrap.min.js" type="text/javascript"></script>
|
||||
|
||||
<!-- Google analytics -->
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-6096819-11']);
|
||||
_gaq.push(['_setDomainName', 'docker.io']);
|
||||
_gaq.push(['_setAllowLinker', true]);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
# rule to redirect original links created when hosted on github pages
|
||||
rewrite ^/documentation/(.*).html http://docs.docker.io/en/latest/$1/ permanent;
|
||||
|
||||
# rewrite the stuff which was on the current page
|
||||
rewrite ^/gettingstarted.html$ /gettingstarted/ permanent;
|
||||
@@ -1 +0,0 @@
|
||||
../theme/docker/static
|
||||
3
graph.go
@@ -162,7 +162,7 @@ func (graph *Graph) Register(layerData Archive, store bool, img *Image) error {
|
||||
// The archive is stored on disk and will be automatically deleted as soon as has been read.
|
||||
// If output is not nil, a human-readable progress bar will be written to it.
|
||||
// FIXME: does this belong in Graph? How about MktempFile, let the caller use it for archives?
|
||||
func (graph *Graph) TempLayerArchive(id string, compression Compression, output io.Writer) (*TempArchive, error) {
|
||||
func (graph *Graph) TempLayerArchive(id string, compression Compression, sf *utils.StreamFormatter, output io.Writer) (*TempArchive, error) {
|
||||
image, err := graph.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -175,7 +175,6 @@ func (graph *Graph) TempLayerArchive(id string, compression Compression, output
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sf := utils.NewStreamFormatter(false)
|
||||
return NewTempArchive(utils.ProgressReader(ioutil.NopCloser(archive), 0, output, sf.FormatProgress("Buffering to disk", "%v/%v (%v)"), sf), tmp.Root)
|
||||
}
|
||||
|
||||
|
||||
133
hack/RELEASE.md
Normal file
@@ -0,0 +1,133 @@
|
||||
## A maintainer's guide to releasing Docker
|
||||
|
||||
So you're in charge of a docker release? Cool. Here's what to do.
|
||||
|
||||
If your experience deviates from this document, please document the changes to keep it
|
||||
up-to-date.
|
||||
|
||||
|
||||
### 1. Pull from master and create a release branch
|
||||
|
||||
```bash
|
||||
$ git checkout master
|
||||
$ git pull
|
||||
$ git checkout -b bump_$VERSION
|
||||
```
|
||||
|
||||
### 2. Update CHANGELOG.md
|
||||
|
||||
You can run this command for reference:
|
||||
|
||||
```bash
|
||||
LAST_VERSION=$(git tag | grep -E "v[0-9\.]+$" | sort -nr | head -n 1)
|
||||
git log $LAST_VERSION..HEAD
|
||||
```
|
||||
|
||||
Each change should be formatted as ```BULLET CATEGORY: DESCRIPTION```
|
||||
|
||||
* BULLET is either ```-```, ```+``` or ```*```, to indicate a bugfix,
|
||||
new feature or upgrade, respectively.
|
||||
|
||||
* CATEGORY should describe which part of the project is affected.
|
||||
Valid categories are:
|
||||
* Builder
|
||||
* Documentation
|
||||
* Hack
|
||||
* Packaging
|
||||
* Remote API
|
||||
* Runtime
|
||||
|
||||
* DESCRIPTION: a concise description of the change that is relevant to the end-user,
|
||||
using the present tense.
|
||||
Changes should be described in terms of how they affect the user, for example "new feature
|
||||
X which allows Y", "fixed bug which caused X", "increased performance of Y".
|
||||
|
||||
EXAMPLES:
|
||||
|
||||
```
|
||||
+ Builder: 'docker build -t FOO' applies the tag FOO to the newly built container.
|
||||
* Runtime: improve detection of kernel version
|
||||
- Remote API: fix a bug in the optional unix socket transport
|
||||
```
|
||||
|
||||
### 3. Change VERSION in commands.go
|
||||
|
||||
### 4. Run all tests
|
||||
|
||||
```bash
|
||||
$ make test
|
||||
```
|
||||
|
||||
### 5. Commit and create a pull request
|
||||
|
||||
```bash
|
||||
$ git add commands.go CHANGELOG.md
|
||||
$ git commit -m "Bump version to $VERSION"
|
||||
$ git push origin bump_$VERSION
|
||||
```
|
||||
|
||||
### 6. Get 2 other maintainers to validate the pull request
|
||||
|
||||
### 7. Merge the pull request and apply tags
|
||||
|
||||
```bash
|
||||
$ git checkout master
|
||||
$ git merge bump_$VERSION
|
||||
$ git tag -a v$VERSION # Don't forget the v!
|
||||
$ git tag -f -a latest
|
||||
$ git push
|
||||
$ git push --tags
|
||||
```
|
||||
|
||||
### 8. Publish binaries
|
||||
|
||||
To run this you will need access to the release credentials.
|
||||
Get them from [the infrastructure maintainers](https://github.com/dotcloud/docker/blob/master/hack/infrastructure/MAINTAINERS).
|
||||
|
||||
```bash
|
||||
$ RELEASE_IMAGE=image_provided_by_infrastructure_maintainers
|
||||
$ BUILD=$(docker run -d -e RELEASE_PPA=0 $RELEASE_IMAGE)
|
||||
```
|
||||
|
||||
This will do 2 things:
|
||||
|
||||
* It will build and upload the binaries on http://get.docker.io
|
||||
* It will *test* the release on our Ubuntu PPA (a PPA is a community repository for ubuntu packages)
|
||||
|
||||
Wait for the build to complete.
|
||||
|
||||
```bash
|
||||
$ docker wait $BUILD # This should print 0. If it doesn't, your build failed.
|
||||
```
|
||||
|
||||
Check that the output looks OK. Here's an example of a correct output:
|
||||
|
||||
```bash
|
||||
$ docker logs 2>&1 b4e7c8299d73 | grep -e 'Public URL' -e 'Successfully uploaded'
|
||||
Public URL of the object is: http://get.docker.io.s3.amazonaws.com/builds/Linux/x86_64/docker-v0.4.7.tgz
|
||||
Public URL of the object is: http://get.docker.io.s3.amazonaws.com/builds/Linux/x86_64/docker-latest.tgz
|
||||
Successfully uploaded packages.
|
||||
```
|
||||
|
||||
If you don't see 3 lines similar to this, something might be wrong. Check the full logs and try again.
|
||||
|
||||
|
||||
### 9. Publish Ubuntu packages
|
||||
|
||||
If everything went well in the previous step, you can finalize the release by submitting the Ubuntu
|
||||
packages.
|
||||
|
||||
```bash
|
||||
$ RELEASE_IMAGE=image_provided_by_infrastructure_maintainers
|
||||
$ docker run -e RELEASE_PPA=1 $RELEASE_IMAGE
|
||||
```
|
||||
|
||||
If that goes well, Ubuntu Precise package is in its way. It will take anywhere from 0.5 to 30 hours
|
||||
for the builders to complete their job depending on builder demand at this time. At this point, Quantal
|
||||
and Raring packages need to be created using the Launchpad interface:
|
||||
https://launchpad.net/~dotcloud/+archive/lxc-docker/+packages
|
||||
|
||||
Notify [the packager maintainers](https://github.com/dotcloud/docker/blob/master/packaging/MAINTAINERS)
|
||||
who will ensure PPA is ready.
|
||||
|
||||
Congratulations! You're done
|
||||
91
hack/bootcamp/README.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Docker maintainer bootcamp
|
||||
|
||||
## Introduction: we need more maintainers
|
||||
|
||||
Docker is growing incredibly fast. At the time of writing, it has received over 200 contributions from 90 people,
|
||||
and its API is used by dozens of 3rd-party tools. Over 1,000 issues have been opened. As the first production deployments
|
||||
start going live, the growth will only accelerate.
|
||||
|
||||
Also at the time of writing, Docker has 3 full-time maintainers, and 7 part-time subsystem maintainers. If docker
|
||||
is going to live up to the expectations, we need more than that.
|
||||
|
||||
This document describes a *bootcamp* to guide and train volunteers interested in helping the project, either with individual
|
||||
contributions, maintainer work, or both.
|
||||
|
||||
This bootcamp is an experiment. If you decide to go through it, consider yourself an alpha-tester. You should expect quirks,
|
||||
and report them to us as you encounter them to help us smooth out the process.
|
||||
|
||||
|
||||
## How it works
|
||||
|
||||
The maintainer bootcamp is a 12-step program - one step for each of the maintainer's responsibilities. The aspiring maintainer must
|
||||
validate all 12 steps by 1) studying it, 2) practicing it, and 3) getting endorsed for it.
|
||||
|
||||
Steps are all equally important and can be validated in any order. Validating all 12 steps is a pre-requisite for becoming a core
|
||||
maintainer, but even 1 step will make you a better contributor!
|
||||
|
||||
### List of steps
|
||||
|
||||
#### 1) Be a power user
|
||||
|
||||
Use docker daily, build cool things with it, know its quirks inside and out.
|
||||
|
||||
|
||||
#### 2) Help users
|
||||
|
||||
Answer questions on irc, twitter, email, in person.
|
||||
|
||||
|
||||
#### 3) Manage the bug tracker
|
||||
|
||||
Help triage tickets - ask the right questions, find duplicates, reference relevant resources, know when to close a ticket when necessary, take the time to go over older tickets.
|
||||
|
||||
|
||||
#### 4) Improve the documentation
|
||||
|
||||
Follow the documentation from scratch regularly and make sure it is still up-to-date. Find and fix inconsistencies. Remove stale information. Find a frequently asked question that is not documented. Simplify the content and the form.
|
||||
|
||||
|
||||
#### 5) Evangelize the principles of docker
|
||||
|
||||
Understand what the underlying goals and principle of docker are. Explain design decisions based on what docker is, and what it is not. When someone is not using docker, find how docker can be valuable to them. If they are using docker, find how they can use it better.
|
||||
|
||||
|
||||
#### 6) Fix bugs
|
||||
|
||||
Self-explanatory. Contribute improvements to docker which solve defects. Bugfixes should be well-tested, and prioritized by impact to the user.
|
||||
|
||||
|
||||
#### 7) Improve the testing infrastructure
|
||||
|
||||
Automated testing is complicated and should be perpetually improved. Invest time to improve the current tooling. Refactor existing tests, create new ones, make testing more accessible to developers, add new testing capabilities (integration tests, mocking, stress test...), improve integration between tests and documentation...
|
||||
|
||||
|
||||
#### 8) Contribute features
|
||||
|
||||
Improve docker to do more things, or get better at doing the same things. Features should be well-tested, not break existing APIs, respect the project goals. They should make the user's life measurably better. Features should be discussed ahead of time to avoid wasting time and duplicating effort.
|
||||
|
||||
|
||||
#### 9) Refactor internals
|
||||
|
||||
Improve docker to repay technical debt. Simplify code layout, improve performance, add missing comments, reduce the number of files and functions, rename functions and variables to be more readable, go over FIXMEs, etc.
|
||||
|
||||
#### 10) Review and merge contributions
|
||||
|
||||
Review pull requests in a timely manner, review code in detail and offer feedback. Keep a high bar without being pedantic. Share the load of testing and merging pull requests.
|
||||
|
||||
#### 11) Release
|
||||
|
||||
Manage a release of docker from beginning to end. Tests, final review, tags, builds, upload to mirrors, distro packaging, etc.
|
||||
|
||||
#### 12) Train other maintainers
|
||||
|
||||
Contribute to training other maintainers. Give advice, delegate work, help organize the bootcamp. This also means contribute to the maintainer's manual, look for ways to improve the project organization etc.
|
||||
|
||||
### How to study a step
|
||||
|
||||
### How to practice a step
|
||||
|
||||
### How to get endorsed for a step
|
||||
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
# AUTHOR Solomon Hykes <solomon@dotcloud.com>
|
||||
# Daniel Mizyrycki <daniel@dotcloud.net>
|
||||
# BUILD_CMD docker build -t dockerbuilder .
|
||||
# RUN_CMD docker run -e AWS_ID="$AWS_ID" -e AWS_KEY="$AWS_KEY" -e GPG_KEY="$GPG_KEY" dockerbuilder
|
||||
# RUN_CMD docker run -e AWS_ID="$AWS_ID" -e AWS_KEY="$AWS_KEY" -e GPG_KEY="$GPG_KEY" -e PUBLISH_PPA="$PUBLISH_PPA" dockerbuilder
|
||||
#
|
||||
# ENV_VARIABLES AWS_ID, AWS_KEY: S3 credentials for uploading Docker binary and tarball
|
||||
# GPG_KEY: Signing key for docker package
|
||||
# PUBLISH_PPA: 0 for staging release, 1 for production release
|
||||
#
|
||||
from ubuntu:12.04
|
||||
maintainer Solomon Hykes <solomon@dotcloud.com>
|
||||
|
||||
5
image.go
@@ -68,7 +68,7 @@ func StoreImage(img *Image, layerData Archive, root string, store bool) error {
|
||||
}
|
||||
// Store the layer
|
||||
layer := layerPath(root)
|
||||
if err := os.MkdirAll(layer, 0700); err != nil {
|
||||
if err := os.MkdirAll(layer, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -94,9 +94,12 @@ func StoreImage(img *Image, layerData Archive, root string, store bool) error {
|
||||
}
|
||||
// If layerData is not nil, unpack it into the new layer
|
||||
if layerData != nil {
|
||||
start := time.Now()
|
||||
utils.Debugf("Start untar layer")
|
||||
if err := Untar(layerData, layer); err != nil {
|
||||
return err
|
||||
}
|
||||
utils.Debugf("Untar time: %vs\n", time.Now().Sub(start).Seconds())
|
||||
}
|
||||
|
||||
return StoreSize(img, root)
|
||||
|
||||
@@ -13,6 +13,10 @@ lxc.utsname = {{.Id}}
|
||||
{{end}}
|
||||
#lxc.aa_profile = unconfined
|
||||
|
||||
{{if .Config.NetworkDisabled}}
|
||||
# network is disabled (-n=false)
|
||||
lxc.network.type = empty
|
||||
{{else}}
|
||||
# network configuration
|
||||
lxc.network.type = veth
|
||||
lxc.network.flags = up
|
||||
@@ -20,6 +24,7 @@ lxc.network.link = {{.NetworkSettings.Bridge}}
|
||||
lxc.network.name = eth0
|
||||
lxc.network.mtu = 1500
|
||||
lxc.network.ipv4 = {{.NetworkSettings.IPAddress}}/{{.NetworkSettings.IPPrefixLen}}
|
||||
{{end}}
|
||||
|
||||
# root filesystem
|
||||
{{$ROOTFS := .RootfsPath}}
|
||||
|
||||
287
network.go
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os/exec"
|
||||
@@ -18,6 +17,7 @@ var NetworkBridgeIface string
|
||||
|
||||
const (
|
||||
DefaultNetworkBridge = "docker0"
|
||||
DisableNetworkBridge = "none"
|
||||
portRangeStart = 49153
|
||||
portRangeEnd = 65535
|
||||
)
|
||||
@@ -112,10 +112,29 @@ func checkRouteOverlaps(dockerNetwork *net.IPNet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`,
|
||||
// and attempts to configure it with an address which doesn't conflict with any other interface on the host.
|
||||
// If it can't find an address which doesn't conflict, it will return an error.
|
||||
func CreateBridgeIface(ifaceName string) error {
|
||||
// FIXME: try more IP ranges
|
||||
// FIXME: try bigger ranges! /24 is too small.
|
||||
addrs := []string{"172.16.42.1/24", "10.0.42.1/24", "192.168.42.1/24"}
|
||||
addrs := []string{
|
||||
// Here we don't follow the convention of using the 1st IP of the range for the gateway.
|
||||
// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
|
||||
// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
|
||||
// on the internal addressing or other stupid things like that.
|
||||
// The shouldn't, but hey, let's not break them unless we really have to.
|
||||
"172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
|
||||
"10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive
|
||||
"10.1.42.1/16",
|
||||
"10.42.42.1/16",
|
||||
"172.16.42.1/24",
|
||||
"172.16.43.1/24",
|
||||
"172.16.44.1/24",
|
||||
"10.0.42.1/24",
|
||||
"10.0.43.1/24",
|
||||
"192.168.42.1/24",
|
||||
"192.168.43.1/24",
|
||||
"192.168.44.1/24",
|
||||
}
|
||||
|
||||
var ifaceAddr string
|
||||
for _, addr := range addrs {
|
||||
@@ -183,8 +202,10 @@ func getIfaceAddr(name string) (net.Addr, error) {
|
||||
// up iptables rules.
|
||||
// It keeps track of all mappings and is able to unmap at will
|
||||
type PortMapper struct {
|
||||
mapping map[int]net.TCPAddr
|
||||
proxies map[int]net.Listener
|
||||
tcpMapping map[int]*net.TCPAddr
|
||||
tcpProxies map[int]Proxy
|
||||
udpMapping map[int]*net.UDPAddr
|
||||
udpProxies map[int]Proxy
|
||||
}
|
||||
|
||||
func (mapper *PortMapper) cleanup() error {
|
||||
@@ -197,8 +218,10 @@ func (mapper *PortMapper) cleanup() error {
|
||||
iptables("-t", "nat", "-D", "OUTPUT", "-j", "DOCKER")
|
||||
iptables("-t", "nat", "-F", "DOCKER")
|
||||
iptables("-t", "nat", "-X", "DOCKER")
|
||||
mapper.mapping = make(map[int]net.TCPAddr)
|
||||
mapper.proxies = make(map[int]net.Listener)
|
||||
mapper.tcpMapping = make(map[int]*net.TCPAddr)
|
||||
mapper.tcpProxies = make(map[int]Proxy)
|
||||
mapper.udpMapping = make(map[int]*net.UDPAddr)
|
||||
mapper.udpProxies = make(map[int]Proxy)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -215,76 +238,72 @@ func (mapper *PortMapper) setup() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mapper *PortMapper) iptablesForward(rule string, port int, dest net.TCPAddr) error {
|
||||
return iptables("-t", "nat", rule, "DOCKER", "-p", "tcp", "--dport", strconv.Itoa(port),
|
||||
"-j", "DNAT", "--to-destination", net.JoinHostPort(dest.IP.String(), strconv.Itoa(dest.Port)))
|
||||
func (mapper *PortMapper) iptablesForward(rule string, port int, proto string, dest_addr string, dest_port int) error {
|
||||
return iptables("-t", "nat", rule, "DOCKER", "-p", proto, "--dport", strconv.Itoa(port),
|
||||
"-j", "DNAT", "--to-destination", net.JoinHostPort(dest_addr, strconv.Itoa(dest_port)))
|
||||
}
|
||||
|
||||
func (mapper *PortMapper) Map(port int, dest net.TCPAddr) error {
|
||||
if err := mapper.iptablesForward("-A", port, dest); err != nil {
|
||||
return err
|
||||
func (mapper *PortMapper) Map(port int, backendAddr net.Addr) error {
|
||||
if _, isTCP := backendAddr.(*net.TCPAddr); isTCP {
|
||||
backendPort := backendAddr.(*net.TCPAddr).Port
|
||||
backendIP := backendAddr.(*net.TCPAddr).IP
|
||||
if err := mapper.iptablesForward("-A", port, "tcp", backendIP.String(), backendPort); err != nil {
|
||||
return err
|
||||
}
|
||||
mapper.tcpMapping[port] = backendAddr.(*net.TCPAddr)
|
||||
proxy, err := NewProxy(&net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: port}, backendAddr)
|
||||
if err != nil {
|
||||
mapper.Unmap(port, "tcp")
|
||||
return err
|
||||
}
|
||||
mapper.tcpProxies[port] = proxy
|
||||
go proxy.Run()
|
||||
} else {
|
||||
backendPort := backendAddr.(*net.UDPAddr).Port
|
||||
backendIP := backendAddr.(*net.UDPAddr).IP
|
||||
if err := mapper.iptablesForward("-A", port, "udp", backendIP.String(), backendPort); err != nil {
|
||||
return err
|
||||
}
|
||||
mapper.udpMapping[port] = backendAddr.(*net.UDPAddr)
|
||||
proxy, err := NewProxy(&net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: port}, backendAddr)
|
||||
if err != nil {
|
||||
mapper.Unmap(port, "udp")
|
||||
return err
|
||||
}
|
||||
mapper.udpProxies[port] = proxy
|
||||
go proxy.Run()
|
||||
}
|
||||
|
||||
mapper.mapping[port] = dest
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
|
||||
if err != nil {
|
||||
mapper.Unmap(port)
|
||||
return err
|
||||
}
|
||||
mapper.proxies[port] = listener
|
||||
go proxy(listener, "tcp", dest.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
// proxy listens for socket connections on `listener`, and forwards them unmodified
|
||||
// to `proto:address`
|
||||
func proxy(listener net.Listener, proto, address string) error {
|
||||
utils.Debugf("proxying to %s:%s", proto, address)
|
||||
defer utils.Debugf("Done proxying to %s:%s", proto, address)
|
||||
for {
|
||||
utils.Debugf("Listening on %s", listener)
|
||||
src, err := listener.Accept()
|
||||
if err != nil {
|
||||
func (mapper *PortMapper) Unmap(port int, proto string) error {
|
||||
if proto == "tcp" {
|
||||
backendAddr, ok := mapper.tcpMapping[port]
|
||||
if !ok {
|
||||
return fmt.Errorf("Port tcp/%v is not mapped", port)
|
||||
}
|
||||
if proxy, exists := mapper.tcpProxies[port]; exists {
|
||||
proxy.Close()
|
||||
delete(mapper.tcpProxies, port)
|
||||
}
|
||||
if err := mapper.iptablesForward("-D", port, proto, backendAddr.IP.String(), backendAddr.Port); err != nil {
|
||||
return err
|
||||
}
|
||||
utils.Debugf("Connecting to %s:%s", proto, address)
|
||||
dst, err := net.Dial(proto, address)
|
||||
if err != nil {
|
||||
log.Printf("Error connecting to %s:%s: %s", proto, address, err)
|
||||
src.Close()
|
||||
continue
|
||||
delete(mapper.tcpMapping, port)
|
||||
} else {
|
||||
backendAddr, ok := mapper.udpMapping[port]
|
||||
if !ok {
|
||||
return fmt.Errorf("Port udp/%v is not mapped", port)
|
||||
}
|
||||
utils.Debugf("Connected to backend, splicing")
|
||||
splice(src, dst)
|
||||
if proxy, exists := mapper.udpProxies[port]; exists {
|
||||
proxy.Close()
|
||||
delete(mapper.udpProxies, port)
|
||||
}
|
||||
if err := mapper.iptablesForward("-D", port, proto, backendAddr.IP.String(), backendAddr.Port); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(mapper.udpMapping, port)
|
||||
}
|
||||
}
|
||||
|
||||
func halfSplice(dst, src net.Conn) error {
|
||||
_, err := io.Copy(dst, src)
|
||||
// FIXME: on EOF from a tcp connection, pass WriteClose()
|
||||
dst.Close()
|
||||
src.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
func splice(a, b net.Conn) {
|
||||
go halfSplice(a, b)
|
||||
go halfSplice(b, a)
|
||||
}
|
||||
|
||||
func (mapper *PortMapper) Unmap(port int) error {
|
||||
dest, ok := mapper.mapping[port]
|
||||
if !ok {
|
||||
return errors.New("Port is not mapped")
|
||||
}
|
||||
if proxy, exists := mapper.proxies[port]; exists {
|
||||
proxy.Close()
|
||||
delete(mapper.proxies, port)
|
||||
}
|
||||
if err := mapper.iptablesForward("-D", port, dest); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(mapper.mapping, port)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -301,9 +320,9 @@ func newPortMapper() (*PortMapper, error) {
|
||||
|
||||
// Port allocator: Atomatically allocate and release networking ports
|
||||
type PortAllocator struct {
|
||||
sync.Mutex
|
||||
inUse map[int]struct{}
|
||||
fountain chan (int)
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func (alloc *PortAllocator) runFountain() {
|
||||
@@ -317,9 +336,9 @@ func (alloc *PortAllocator) runFountain() {
|
||||
// FIXME: Release can no longer fail, change its prototype to reflect that.
|
||||
func (alloc *PortAllocator) Release(port int) error {
|
||||
utils.Debugf("Releasing %d", port)
|
||||
alloc.lock.Lock()
|
||||
alloc.Lock()
|
||||
delete(alloc.inUse, port)
|
||||
alloc.lock.Unlock()
|
||||
alloc.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -334,8 +353,8 @@ func (alloc *PortAllocator) Acquire(port int) (int, error) {
|
||||
}
|
||||
return -1, fmt.Errorf("Port generator ended unexpectedly")
|
||||
}
|
||||
alloc.lock.Lock()
|
||||
defer alloc.lock.Unlock()
|
||||
alloc.Lock()
|
||||
defer alloc.Unlock()
|
||||
if _, inUse := alloc.inUse[port]; inUse {
|
||||
return -1, fmt.Errorf("Port already in use: %d", port)
|
||||
}
|
||||
@@ -453,26 +472,47 @@ type NetworkInterface struct {
|
||||
Gateway net.IP
|
||||
|
||||
manager *NetworkManager
|
||||
extPorts []int
|
||||
extPorts []*Nat
|
||||
disabled bool
|
||||
}
|
||||
|
||||
// Allocate an external TCP port and map it to the interface
|
||||
func (iface *NetworkInterface) AllocatePort(spec string) (*Nat, error) {
|
||||
|
||||
if iface.disabled {
|
||||
return nil, fmt.Errorf("Trying to allocate port for interface %v, which is disabled", iface) // FIXME
|
||||
}
|
||||
|
||||
nat, err := parseNat(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Allocate a random port if Frontend==0
|
||||
extPort, err := iface.manager.portAllocator.Acquire(nat.Frontend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
if nat.Proto == "tcp" {
|
||||
extPort, err := iface.manager.tcpPortAllocator.Acquire(nat.Frontend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
backend := &net.TCPAddr{IP: iface.IPNet.IP, Port: nat.Backend}
|
||||
if err := iface.manager.portMapper.Map(extPort, backend); err != nil {
|
||||
iface.manager.tcpPortAllocator.Release(extPort)
|
||||
return nil, err
|
||||
}
|
||||
nat.Frontend = extPort
|
||||
} else {
|
||||
extPort, err := iface.manager.udpPortAllocator.Acquire(nat.Frontend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
backend := &net.UDPAddr{IP: iface.IPNet.IP, Port: nat.Backend}
|
||||
if err := iface.manager.portMapper.Map(extPort, backend); err != nil {
|
||||
iface.manager.udpPortAllocator.Release(extPort)
|
||||
return nil, err
|
||||
}
|
||||
nat.Frontend = extPort
|
||||
}
|
||||
nat.Frontend = extPort
|
||||
if err := iface.manager.portMapper.Map(nat.Frontend, net.TCPAddr{IP: iface.IPNet.IP, Port: nat.Backend}); err != nil {
|
||||
iface.manager.portAllocator.Release(nat.Frontend)
|
||||
return nil, err
|
||||
}
|
||||
iface.extPorts = append(iface.extPorts, nat.Frontend)
|
||||
iface.extPorts = append(iface.extPorts, nat)
|
||||
|
||||
return nat, nil
|
||||
}
|
||||
|
||||
@@ -485,6 +525,21 @@ type Nat struct {
|
||||
func parseNat(spec string) (*Nat, error) {
|
||||
var nat Nat
|
||||
|
||||
if strings.Contains(spec, "/") {
|
||||
specParts := strings.Split(spec, "/")
|
||||
if len(specParts) != 2 {
|
||||
return nil, fmt.Errorf("Invalid port format.")
|
||||
}
|
||||
proto := specParts[1]
|
||||
spec = specParts[0]
|
||||
if proto != "tcp" && proto != "udp" {
|
||||
return nil, fmt.Errorf("Invalid port format: unknown protocol %v.", proto)
|
||||
}
|
||||
nat.Proto = proto
|
||||
} else {
|
||||
nat.Proto = "tcp"
|
||||
}
|
||||
|
||||
if strings.Contains(spec, ":") {
|
||||
specParts := strings.Split(spec, ":")
|
||||
if len(specParts) != 2 {
|
||||
@@ -517,20 +572,29 @@ func parseNat(spec string) (*Nat, error) {
|
||||
}
|
||||
nat.Backend = int(port)
|
||||
}
|
||||
nat.Proto = "tcp"
|
||||
|
||||
return &nat, nil
|
||||
}
|
||||
|
||||
// Release: Network cleanup - release all resources
|
||||
func (iface *NetworkInterface) Release() {
|
||||
for _, port := range iface.extPorts {
|
||||
if err := iface.manager.portMapper.Unmap(port); err != nil {
|
||||
log.Printf("Unable to unmap port %v: %v", port, err)
|
||||
}
|
||||
if err := iface.manager.portAllocator.Release(port); err != nil {
|
||||
log.Printf("Unable to release port %v: %v", port, err)
|
||||
}
|
||||
|
||||
if iface.disabled {
|
||||
return
|
||||
}
|
||||
|
||||
for _, nat := range iface.extPorts {
|
||||
utils.Debugf("Unmaping %v/%v", nat.Proto, nat.Frontend)
|
||||
if err := iface.manager.portMapper.Unmap(nat.Frontend, nat.Proto); err != nil {
|
||||
log.Printf("Unable to unmap port %v/%v: %v", nat.Proto, nat.Frontend, err)
|
||||
}
|
||||
if nat.Proto == "tcp" {
|
||||
if err := iface.manager.tcpPortAllocator.Release(nat.Frontend); err != nil {
|
||||
log.Printf("Unable to release port tcp/%v: %v", nat.Frontend, err)
|
||||
}
|
||||
} else if err := iface.manager.udpPortAllocator.Release(nat.Frontend); err != nil {
|
||||
log.Printf("Unable to release port udp/%v: %v", nat.Frontend, err)
|
||||
}
|
||||
}
|
||||
|
||||
iface.manager.ipAllocator.Release(iface.IPNet.IP)
|
||||
@@ -542,13 +606,21 @@ type NetworkManager struct {
|
||||
bridgeIface string
|
||||
bridgeNetwork *net.IPNet
|
||||
|
||||
ipAllocator *IPAllocator
|
||||
portAllocator *PortAllocator
|
||||
portMapper *PortMapper
|
||||
ipAllocator *IPAllocator
|
||||
tcpPortAllocator *PortAllocator
|
||||
udpPortAllocator *PortAllocator
|
||||
portMapper *PortMapper
|
||||
|
||||
disabled bool
|
||||
}
|
||||
|
||||
// Allocate a network interface
|
||||
func (manager *NetworkManager) Allocate() (*NetworkInterface, error) {
|
||||
|
||||
if manager.disabled {
|
||||
return &NetworkInterface{disabled: true}, nil
|
||||
}
|
||||
|
||||
ip, err := manager.ipAllocator.Acquire()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -562,6 +634,14 @@ func (manager *NetworkManager) Allocate() (*NetworkInterface, error) {
|
||||
}
|
||||
|
||||
func newNetworkManager(bridgeIface string) (*NetworkManager, error) {
|
||||
|
||||
if bridgeIface == DisableNetworkBridge {
|
||||
manager := &NetworkManager{
|
||||
disabled: true,
|
||||
}
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
addr, err := getIfaceAddr(bridgeIface)
|
||||
if err != nil {
|
||||
// If the iface is not found, try to create it
|
||||
@@ -577,7 +657,11 @@ func newNetworkManager(bridgeIface string) (*NetworkManager, error) {
|
||||
|
||||
ipAllocator := newIPAllocator(network)
|
||||
|
||||
portAllocator, err := newPortAllocator()
|
||||
tcpPortAllocator, err := newPortAllocator()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udpPortAllocator, err := newPortAllocator()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -588,11 +672,12 @@ func newNetworkManager(bridgeIface string) (*NetworkManager, error) {
|
||||
}
|
||||
|
||||
manager := &NetworkManager{
|
||||
bridgeIface: bridgeIface,
|
||||
bridgeNetwork: network,
|
||||
ipAllocator: ipAllocator,
|
||||
portAllocator: portAllocator,
|
||||
portMapper: portMapper,
|
||||
bridgeIface: bridgeIface,
|
||||
bridgeNetwork: network,
|
||||
ipAllocator: ipAllocator,
|
||||
tcpPortAllocator: tcpPortAllocator,
|
||||
udpPortAllocator: udpPortAllocator,
|
||||
portMapper: portMapper,
|
||||
}
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
258
network_proxy.go
Normal file
@@ -0,0 +1,258 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
UDPConnTrackTimeout = 90 * time.Second
|
||||
UDPBufSize = 2048
|
||||
)
|
||||
|
||||
type Proxy interface {
|
||||
// Start forwarding traffic back and forth the front and back-end
|
||||
// addresses.
|
||||
Run()
|
||||
// Stop forwarding traffic and close both ends of the Proxy.
|
||||
Close()
|
||||
// Return the address on which the proxy is listening.
|
||||
FrontendAddr() net.Addr
|
||||
// Return the proxied address.
|
||||
BackendAddr() net.Addr
|
||||
}
|
||||
|
||||
type TCPProxy struct {
|
||||
listener *net.TCPListener
|
||||
frontendAddr *net.TCPAddr
|
||||
backendAddr *net.TCPAddr
|
||||
}
|
||||
|
||||
func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) {
|
||||
listener, err := net.ListenTCP("tcp", frontendAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// If the port in frontendAddr was 0 then ListenTCP will have a picked
|
||||
// a port to listen on, hence the call to Addr to get that actual port:
|
||||
return &TCPProxy{
|
||||
listener: listener,
|
||||
frontendAddr: listener.Addr().(*net.TCPAddr),
|
||||
backendAddr: backendAddr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) {
|
||||
backend, err := net.DialTCP("tcp", nil, proxy.backendAddr)
|
||||
if err != nil {
|
||||
log.Printf("Can't forward traffic to backend tcp/%v: %v\n", proxy.backendAddr, err.Error())
|
||||
client.Close()
|
||||
return
|
||||
}
|
||||
|
||||
event := make(chan int64)
|
||||
var broker = func(to, from *net.TCPConn) {
|
||||
written, err := io.Copy(to, from)
|
||||
if err != nil {
|
||||
err, ok := err.(*net.OpError)
|
||||
// If the socket we are writing to is shutdown with
|
||||
// SHUT_WR, forward it to the other end of the pipe:
|
||||
if ok && err.Err == syscall.EPIPE {
|
||||
from.CloseWrite()
|
||||
}
|
||||
}
|
||||
to.CloseRead()
|
||||
event <- written
|
||||
}
|
||||
utils.Debugf("Forwarding traffic between tcp/%v and tcp/%v", client.RemoteAddr(), backend.RemoteAddr())
|
||||
go broker(client, backend)
|
||||
go broker(backend, client)
|
||||
|
||||
var transferred int64 = 0
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case written := <-event:
|
||||
transferred += written
|
||||
case <-quit:
|
||||
// Interrupt the two brokers and "join" them.
|
||||
client.Close()
|
||||
backend.Close()
|
||||
for ; i < 2; i++ {
|
||||
transferred += <-event
|
||||
}
|
||||
goto done
|
||||
}
|
||||
}
|
||||
client.Close()
|
||||
backend.Close()
|
||||
done:
|
||||
utils.Debugf("%v bytes transferred between tcp/%v and tcp/%v", transferred, client.RemoteAddr(), backend.RemoteAddr())
|
||||
}
|
||||
|
||||
func (proxy *TCPProxy) Run() {
|
||||
quit := make(chan bool)
|
||||
defer close(quit)
|
||||
utils.Debugf("Starting proxy on tcp/%v for tcp/%v", proxy.frontendAddr, proxy.backendAddr)
|
||||
for {
|
||||
client, err := proxy.listener.Accept()
|
||||
if err != nil {
|
||||
utils.Debugf("Stopping proxy on tcp/%v for tcp/%v (%v)", proxy.frontendAddr, proxy.backendAddr, err.Error())
|
||||
return
|
||||
}
|
||||
go proxy.clientLoop(client.(*net.TCPConn), quit)
|
||||
}
|
||||
}
|
||||
|
||||
func (proxy *TCPProxy) Close() { proxy.listener.Close() }
|
||||
func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
|
||||
func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
|
||||
|
||||
// A net.Addr where the IP is split into two fields so you can use it as a key
|
||||
// in a map:
|
||||
type connTrackKey struct {
|
||||
IPHigh uint64
|
||||
IPLow uint64
|
||||
Port int
|
||||
}
|
||||
|
||||
func newConnTrackKey(addr *net.UDPAddr) *connTrackKey {
|
||||
if len(addr.IP) == net.IPv4len {
|
||||
return &connTrackKey{
|
||||
IPHigh: 0,
|
||||
IPLow: uint64(binary.BigEndian.Uint32(addr.IP)),
|
||||
Port: addr.Port,
|
||||
}
|
||||
}
|
||||
return &connTrackKey{
|
||||
IPHigh: binary.BigEndian.Uint64(addr.IP[:8]),
|
||||
IPLow: binary.BigEndian.Uint64(addr.IP[8:]),
|
||||
Port: addr.Port,
|
||||
}
|
||||
}
|
||||
|
||||
type connTrackMap map[connTrackKey]*net.UDPConn
|
||||
|
||||
type UDPProxy struct {
|
||||
listener *net.UDPConn
|
||||
frontendAddr *net.UDPAddr
|
||||
backendAddr *net.UDPAddr
|
||||
connTrackTable connTrackMap
|
||||
connTrackLock sync.Mutex
|
||||
}
|
||||
|
||||
func NewUDPProxy(frontendAddr, backendAddr *net.UDPAddr) (*UDPProxy, error) {
|
||||
listener, err := net.ListenUDP("udp", frontendAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &UDPProxy{
|
||||
listener: listener,
|
||||
frontendAddr: listener.LocalAddr().(*net.UDPAddr),
|
||||
backendAddr: backendAddr,
|
||||
connTrackTable: make(connTrackMap),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) {
|
||||
defer func() {
|
||||
proxy.connTrackLock.Lock()
|
||||
delete(proxy.connTrackTable, *clientKey)
|
||||
proxy.connTrackLock.Unlock()
|
||||
utils.Debugf("Done proxying between udp/%v and udp/%v", clientAddr.String(), proxy.backendAddr.String())
|
||||
proxyConn.Close()
|
||||
}()
|
||||
|
||||
readBuf := make([]byte, UDPBufSize)
|
||||
for {
|
||||
proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout))
|
||||
again:
|
||||
read, err := proxyConn.Read(readBuf)
|
||||
if err != nil {
|
||||
if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED {
|
||||
// This will happen if the last write failed
|
||||
// (e.g: nothing is actually listening on the
|
||||
// proxied port on the container), ignore it
|
||||
// and continue until UDPConnTrackTimeout
|
||||
// expires:
|
||||
goto again
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i != read; {
|
||||
written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
i += written
|
||||
utils.Debugf("Forwarded %v/%v bytes to udp/%v", i, read, clientAddr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (proxy *UDPProxy) Run() {
|
||||
readBuf := make([]byte, UDPBufSize)
|
||||
utils.Debugf("Starting proxy on udp/%v for udp/%v", proxy.frontendAddr, proxy.backendAddr)
|
||||
for {
|
||||
read, from, err := proxy.listener.ReadFromUDP(readBuf)
|
||||
if err != nil {
|
||||
// NOTE: Apparently ReadFrom doesn't return
|
||||
// ECONNREFUSED like Read do (see comment in
|
||||
// UDPProxy.replyLoop)
|
||||
utils.Debugf("Stopping proxy on udp/%v for udp/%v (%v)", proxy.frontendAddr, proxy.backendAddr, err.Error())
|
||||
break
|
||||
}
|
||||
|
||||
fromKey := newConnTrackKey(from)
|
||||
proxy.connTrackLock.Lock()
|
||||
proxyConn, hit := proxy.connTrackTable[*fromKey]
|
||||
if !hit {
|
||||
proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr)
|
||||
if err != nil {
|
||||
log.Printf("Can't proxy a datagram to udp/%s: %v\n", proxy.backendAddr.String(), err)
|
||||
continue
|
||||
}
|
||||
proxy.connTrackTable[*fromKey] = proxyConn
|
||||
go proxy.replyLoop(proxyConn, from, fromKey)
|
||||
}
|
||||
proxy.connTrackLock.Unlock()
|
||||
for i := 0; i != read; {
|
||||
written, err := proxyConn.Write(readBuf[i:read])
|
||||
if err != nil {
|
||||
log.Printf("Can't proxy a datagram to udp/%s: %v\n", proxy.backendAddr.String(), err)
|
||||
break
|
||||
}
|
||||
i += written
|
||||
utils.Debugf("Forwarded %v/%v bytes to udp/%v", i, read, proxy.backendAddr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (proxy *UDPProxy) Close() {
|
||||
proxy.listener.Close()
|
||||
proxy.connTrackLock.Lock()
|
||||
defer proxy.connTrackLock.Unlock()
|
||||
for _, conn := range proxy.connTrackTable {
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (proxy *UDPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
|
||||
func (proxy *UDPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
|
||||
|
||||
func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
|
||||
switch frontendAddr.(type) {
|
||||
case *net.UDPAddr:
|
||||
return NewUDPProxy(frontendAddr.(*net.UDPAddr), backendAddr.(*net.UDPAddr))
|
||||
case *net.TCPAddr:
|
||||
return NewTCPProxy(frontendAddr.(*net.TCPAddr), backendAddr.(*net.TCPAddr))
|
||||
default:
|
||||
panic(fmt.Errorf("Unsupported protocol"))
|
||||
}
|
||||
}
|
||||
221
network_proxy_test.go
Normal file
@@ -0,0 +1,221 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var testBuf = []byte("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
|
||||
var testBufSize = len(testBuf)
|
||||
|
||||
type EchoServer interface {
|
||||
Run()
|
||||
Close()
|
||||
LocalAddr() net.Addr
|
||||
}
|
||||
|
||||
type TCPEchoServer struct {
|
||||
listener net.Listener
|
||||
testCtx *testing.T
|
||||
}
|
||||
|
||||
type UDPEchoServer struct {
|
||||
conn net.PacketConn
|
||||
testCtx *testing.T
|
||||
}
|
||||
|
||||
func NewEchoServer(t *testing.T, proto, address string) EchoServer {
|
||||
var server EchoServer
|
||||
if strings.HasPrefix(proto, "tcp") {
|
||||
listener, err := net.Listen(proto, address)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
server = &TCPEchoServer{listener: listener, testCtx: t}
|
||||
} else {
|
||||
socket, err := net.ListenPacket(proto, address)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
server = &UDPEchoServer{conn: socket, testCtx: t}
|
||||
}
|
||||
t.Logf("EchoServer listening on %v/%v\n", proto, server.LocalAddr().String())
|
||||
return server
|
||||
}
|
||||
|
||||
func (server *TCPEchoServer) Run() {
|
||||
go func() {
|
||||
for {
|
||||
client, err := server.listener.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go func(client net.Conn) {
|
||||
server.testCtx.Logf("TCP client accepted on the EchoServer\n")
|
||||
written, err := io.Copy(client, client)
|
||||
server.testCtx.Logf("%v bytes echoed back to the client\n", written)
|
||||
if err != nil {
|
||||
server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
|
||||
}
|
||||
client.Close()
|
||||
}(client)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (server *TCPEchoServer) LocalAddr() net.Addr { return server.listener.Addr() }
|
||||
func (server *TCPEchoServer) Close() { server.listener.Addr() }
|
||||
|
||||
func (server *UDPEchoServer) Run() {
|
||||
go func() {
|
||||
readBuf := make([]byte, 1024)
|
||||
for {
|
||||
read, from, err := server.conn.ReadFrom(readBuf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
server.testCtx.Logf("Writing UDP datagram back")
|
||||
for i := 0; i != read; {
|
||||
written, err := server.conn.WriteTo(readBuf[i:read], from)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
i += written
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (server *UDPEchoServer) LocalAddr() net.Addr { return server.conn.LocalAddr() }
|
||||
func (server *UDPEchoServer) Close() { server.conn.Close() }
|
||||
|
||||
func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) {
|
||||
defer proxy.Close()
|
||||
go proxy.Run()
|
||||
client, err := net.Dial(proto, addr)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't connect to the proxy: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
client.SetDeadline(time.Now().Add(10 * time.Second))
|
||||
if _, err = client.Write(testBuf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
recvBuf := make([]byte, testBufSize)
|
||||
if _, err = client.Read(recvBuf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(testBuf, recvBuf) {
|
||||
t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
|
||||
}
|
||||
}
|
||||
|
||||
func testProxy(t *testing.T, proto string, proxy Proxy) {
|
||||
testProxyAt(t, proto, proxy, proxy.FrontendAddr().String())
|
||||
}
|
||||
|
||||
func TestTCP4Proxy(t *testing.T) {
|
||||
backend := NewEchoServer(t, "tcp", "127.0.0.1:0")
|
||||
defer backend.Close()
|
||||
backend.Run()
|
||||
frontendAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
|
||||
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testProxy(t, "tcp", proxy)
|
||||
}
|
||||
|
||||
func TestTCP6Proxy(t *testing.T) {
|
||||
backend := NewEchoServer(t, "tcp", "[::1]:0")
|
||||
defer backend.Close()
|
||||
backend.Run()
|
||||
frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
|
||||
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testProxy(t, "tcp", proxy)
|
||||
}
|
||||
|
||||
func TestTCPDualStackProxy(t *testing.T) {
|
||||
// If I understand `godoc -src net favoriteAddrFamily` (used by the
|
||||
// net.Listen* functions) correctly this should work, but it doesn't.
|
||||
t.Skip("No support for dual stack yet")
|
||||
backend := NewEchoServer(t, "tcp", "[::1]:0")
|
||||
defer backend.Close()
|
||||
backend.Run()
|
||||
frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
|
||||
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ipv4ProxyAddr := &net.TCPAddr{
|
||||
IP: net.IPv4(127, 0, 0, 1),
|
||||
Port: proxy.FrontendAddr().(*net.TCPAddr).Port,
|
||||
}
|
||||
testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String())
|
||||
}
|
||||
|
||||
func TestUDP4Proxy(t *testing.T) {
|
||||
backend := NewEchoServer(t, "udp", "127.0.0.1:0")
|
||||
defer backend.Close()
|
||||
backend.Run()
|
||||
frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
|
||||
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testProxy(t, "udp", proxy)
|
||||
}
|
||||
|
||||
func TestUDP6Proxy(t *testing.T) {
|
||||
backend := NewEchoServer(t, "udp", "[::1]:0")
|
||||
defer backend.Close()
|
||||
backend.Run()
|
||||
frontendAddr := &net.UDPAddr{IP: net.IPv6loopback, Port: 0}
|
||||
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testProxy(t, "udp", proxy)
|
||||
}
|
||||
|
||||
func TestUDPWriteError(t *testing.T) {
|
||||
frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
|
||||
// Hopefully, this port will be free: */
|
||||
backendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 25587}
|
||||
proxy, err := NewProxy(frontendAddr, backendAddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer proxy.Close()
|
||||
go proxy.Run()
|
||||
client, err := net.Dial("udp", "127.0.0.1:25587")
|
||||
if err != nil {
|
||||
t.Fatalf("Can't connect to the proxy: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
// Make sure the proxy doesn't stop when there is no actual backend:
|
||||
client.Write(testBuf)
|
||||
client.Write(testBuf)
|
||||
backend := NewEchoServer(t, "udp", "127.0.0.1:25587")
|
||||
defer backend.Close()
|
||||
backend.Run()
|
||||
client.SetDeadline(time.Now().Add(10 * time.Second))
|
||||
if _, err = client.Write(testBuf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
recvBuf := make([]byte, testBufSize)
|
||||
if _, err = client.Read(recvBuf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(testBuf, recvBuf) {
|
||||
t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
|
||||
}
|
||||
}
|
||||
@@ -20,28 +20,97 @@ func TestIptables(t *testing.T) {
|
||||
|
||||
func TestParseNat(t *testing.T) {
|
||||
if nat, err := parseNat("4500"); err == nil {
|
||||
if nat.Frontend != 0 || nat.Backend != 4500 {
|
||||
t.Errorf("-p 4500 should produce 0->4500, got %d->%d", nat.Frontend, nat.Backend)
|
||||
if nat.Frontend != 0 || nat.Backend != 4500 || nat.Proto != "tcp" {
|
||||
t.Errorf("-p 4500 should produce 0->4500/tcp, got %d->%d/%s",
|
||||
nat.Frontend, nat.Backend, nat.Proto)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nat, err := parseNat(":4501"); err == nil {
|
||||
if nat.Frontend != 4501 || nat.Backend != 4501 {
|
||||
t.Errorf("-p :4501 should produce 4501->4501, got %d->%d", nat.Frontend, nat.Backend)
|
||||
if nat.Frontend != 4501 || nat.Backend != 4501 || nat.Proto != "tcp" {
|
||||
t.Errorf("-p :4501 should produce 4501->4501/tcp, got %d->%d/%s",
|
||||
nat.Frontend, nat.Backend, nat.Proto)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nat, err := parseNat("4502:4503"); err == nil {
|
||||
if nat.Frontend != 4502 || nat.Backend != 4503 {
|
||||
t.Errorf("-p 4502:4503 should produce 4502->4503, got %d->%d", nat.Frontend, nat.Backend)
|
||||
if nat.Frontend != 4502 || nat.Backend != 4503 || nat.Proto != "tcp" {
|
||||
t.Errorf("-p 4502:4503 should produce 4502->4503/tcp, got %d->%d/%s",
|
||||
nat.Frontend, nat.Backend, nat.Proto)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nat, err := parseNat("4502:4503/tcp"); err == nil {
|
||||
if nat.Frontend != 4502 || nat.Backend != 4503 || nat.Proto != "tcp" {
|
||||
t.Errorf("-p 4502:4503/tcp should produce 4502->4503/tcp, got %d->%d/%s",
|
||||
nat.Frontend, nat.Backend, nat.Proto)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nat, err := parseNat("4502:4503/udp"); err == nil {
|
||||
if nat.Frontend != 4502 || nat.Backend != 4503 || nat.Proto != "udp" {
|
||||
t.Errorf("-p 4502:4503/udp should produce 4502->4503/udp, got %d->%d/%s",
|
||||
nat.Frontend, nat.Backend, nat.Proto)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nat, err := parseNat(":4503/udp"); err == nil {
|
||||
if nat.Frontend != 4503 || nat.Backend != 4503 || nat.Proto != "udp" {
|
||||
t.Errorf("-p :4503/udp should produce 4503->4503/udp, got %d->%d/%s",
|
||||
nat.Frontend, nat.Backend, nat.Proto)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nat, err := parseNat(":4503/tcp"); err == nil {
|
||||
if nat.Frontend != 4503 || nat.Backend != 4503 || nat.Proto != "tcp" {
|
||||
t.Errorf("-p :4503/tcp should produce 4503->4503/tcp, got %d->%d/%s",
|
||||
nat.Frontend, nat.Backend, nat.Proto)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nat, err := parseNat("4503/tcp"); err == nil {
|
||||
if nat.Frontend != 0 || nat.Backend != 4503 || nat.Proto != "tcp" {
|
||||
t.Errorf("-p 4503/tcp should produce 0->4503/tcp, got %d->%d/%s",
|
||||
nat.Frontend, nat.Backend, nat.Proto)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if nat, err := parseNat("4503/udp"); err == nil {
|
||||
if nat.Frontend != 0 || nat.Backend != 4503 || nat.Proto != "udp" {
|
||||
t.Errorf("-p 4503/udp should produce 0->4503/udp, got %d->%d/%s",
|
||||
nat.Frontend, nat.Backend, nat.Proto)
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := parseNat("4503/tcpgarbage"); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := parseNat("4503/tcp/udp"); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := parseNat("4503/"); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPortAllocation(t *testing.T) {
|
||||
|
||||
@@ -13,8 +13,8 @@ PKG_NAME=lxc-docker
|
||||
ROOT_PATH=$(shell git rev-parse --show-toplevel)
|
||||
GITHUB_PATH=github.com/dotcloud/docker
|
||||
BUILD_SRC=build_src
|
||||
VERSION_TAG?=v$(shell sed -E 's/.+\((.+)-.+\).+/\1/;q' changelog)
|
||||
VERSION=$(shell echo ${VERSION_TAG} | cut -c2-)
|
||||
VERSION=$(shell sed -En '0,/^\#\# /{s/^\#\# ([^ ]+).+/\1/p}' ../../CHANGELOG.md)
|
||||
VERSION_TAG?=v${VERSION}
|
||||
DOCKER_VERSION=${PKG_NAME}_${VERSION}
|
||||
|
||||
all:
|
||||
@@ -28,7 +28,6 @@ install:
|
||||
mkdir -p $(DESTDIR)/usr/share/doc/lxc-docker
|
||||
install -m 0755 src/${GITHUB_PATH}/docker/docker $(DESTDIR)/usr/bin/lxc-docker
|
||||
cp debian/lxc-docker.1 $(DESTDIR)/usr/share/man/man1
|
||||
cp debian/CHANGELOG.md $(DESTDIR)/usr/share/doc/lxc-docker/changelog
|
||||
|
||||
debian:
|
||||
# Prepare docker source from revision ${VERSION_TAG}
|
||||
@@ -41,6 +40,7 @@ debian:
|
||||
cp -r `ls | grep -v ${BUILD_SRC}` ${BUILD_SRC}/debian
|
||||
cp ${ROOT_PATH}/README.md ${BUILD_SRC}
|
||||
cp ${ROOT_PATH}/CHANGELOG.md ${BUILD_SRC}/debian
|
||||
./parse_changelog.py < ../../CHANGELOG.md > ${BUILD_SRC}/debian/changelog
|
||||
# Cleanup
|
||||
rm -rf `find . -name '.git*'`
|
||||
rm -f ${DOCKER_VERSION}*
|
||||
|
||||
3
packaging/debian/Vagrantfile
vendored
@@ -13,6 +13,9 @@ Vagrant::Config.run do |config|
|
||||
|
||||
# Install debian packaging dependencies and create debian packages
|
||||
pkg_cmd = "apt-get -qq update; DEBIAN_FRONTEND=noninteractive apt-get install -qq -y #{PKG_DEP}; " \
|
||||
"curl -s -o /go.tar.gz https://go.googlecode.com/files/go1.1.1.linux-amd64.tar.gz; " \
|
||||
"tar -C /usr/local -xzf /go.tar.gz; rm /usr/bin/go; " \
|
||||
"ln -s /usr/local/go/bin/go /usr/bin; "\
|
||||
"export GPG_KEY='#{ENV['GPG_KEY']}'; cd /data/docker/packaging/debian; make debian"
|
||||
config.vm.provision :shell, :inline => pkg_cmd
|
||||
end
|
||||
|
||||
@@ -923,6 +923,12 @@ List images
|
||||
Usage: docker import [OPTIONS] URL|\- [REPOSITORY [TAG]]
|
||||
.sp
|
||||
Create a new filesystem image from the contents of a tarball
|
||||
|
||||
At this time, the URL must start with ``http`` and point to a single file archive
|
||||
(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz)
|
||||
containing a root filesystem. If you would like to import from a local directory or archive,
|
||||
you can use the ``-`` parameter to take the data from standard in.
|
||||
|
||||
.SS info
|
||||
.sp
|
||||
.nf
|
||||
|
||||
23
packaging/debian/parse_changelog.py
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'Parse main CHANGELOG.md from stdin outputing on stdout the debian changelog'
|
||||
|
||||
import sys,re, datetime
|
||||
|
||||
on_block=False
|
||||
for line in sys.stdin.readlines():
|
||||
line = line.strip()
|
||||
if line.startswith('# ') or len(line) == 0:
|
||||
continue
|
||||
if line.startswith('## '):
|
||||
if on_block:
|
||||
print '\n -- dotCloud <ops@dotcloud.com> {0}\n'.format(date)
|
||||
version, date = line[3:].split()
|
||||
date = datetime.datetime.strptime(date, '(%Y-%m-%d)').strftime(
|
||||
'%a, %d %b %Y 00:00:00 -0700')
|
||||
on_block = True
|
||||
print 'lxc-docker ({0}-1) precise; urgency=low'.format(version)
|
||||
continue
|
||||
if on_block:
|
||||
print ' ' + line
|
||||
print '\n -- dotCloud <ops@dotcloud.com> {0}'.format(date)
|
||||
@@ -1,9 +1,8 @@
|
||||
description "Run docker"
|
||||
|
||||
start on runlevel [2345]
|
||||
stop on starting rc RUNLEVEL=[016]
|
||||
start on filesystem or runlevel [2345]
|
||||
stop on runlevel [!2345]
|
||||
|
||||
respawn
|
||||
|
||||
script
|
||||
/usr/bin/docker -d
|
||||
end script
|
||||
exec /usr/bin/docker -d
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Stop docker
|
||||
/sbin/stop docker
|
||||
if [ "`pgrep -f '/usr/bin/docker -d'`" != "" ]; then /sbin/stop docker; fi
|
||||
|
||||
@@ -12,39 +12,140 @@ import (
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var ErrAlreadyExists = errors.New("Image already exists")
|
||||
var ErrInvalidRepositoryName = errors.New("Invalid repository name (ex: \"registry.domain.tld/myrepos\")")
|
||||
|
||||
func UrlScheme() string {
|
||||
u, err := url.Parse(auth.IndexServerAddress())
|
||||
if err != nil {
|
||||
return "https"
|
||||
func pingRegistryEndpoint(endpoint string) error {
|
||||
if endpoint == auth.IndexServerAddress() {
|
||||
// Skip the check, we now this one is valid
|
||||
// (and we never want to fallback to http in case of error)
|
||||
return nil
|
||||
}
|
||||
return u.Scheme
|
||||
resp, err := http.Get(endpoint + "_ping")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Header.Get("X-Docker-Registry-Version") == "" {
|
||||
return errors.New("This does not look like a Registry server (\"X-Docker-Registry-Version\" header not found in the response)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateRepositoryName(repositoryName string) error {
|
||||
var (
|
||||
namespace string
|
||||
name string
|
||||
)
|
||||
nameParts := strings.SplitN(repositoryName, "/", 2)
|
||||
if len(nameParts) < 2 {
|
||||
namespace = "library"
|
||||
name = nameParts[0]
|
||||
} else {
|
||||
namespace = nameParts[0]
|
||||
name = nameParts[1]
|
||||
}
|
||||
validNamespace := regexp.MustCompile(`^([a-z0-9_]{4,30})$`)
|
||||
if !validNamespace.MatchString(namespace) {
|
||||
return fmt.Errorf("Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30", namespace)
|
||||
}
|
||||
validRepo := regexp.MustCompile(`^([a-zA-Z0-9-_.]+)$`)
|
||||
if !validRepo.MatchString(name) {
|
||||
return fmt.Errorf("Invalid repository name (%s), only [a-zA-Z0-9-_.] are allowed", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Resolves a repository name to a endpoint + name
|
||||
func ResolveRepositoryName(reposName string) (string, string, error) {
|
||||
if strings.Contains(reposName, "://") {
|
||||
// It cannot contain a scheme!
|
||||
return "", "", ErrInvalidRepositoryName
|
||||
}
|
||||
nameParts := strings.SplitN(reposName, "/", 2)
|
||||
if !strings.Contains(nameParts[0], ".") && !strings.Contains(nameParts[0], ":") {
|
||||
// This is a Docker Index repos (ex: samalba/hipache or ubuntu)
|
||||
err := validateRepositoryName(reposName)
|
||||
return auth.IndexServerAddress(), reposName, err
|
||||
}
|
||||
if len(nameParts) < 2 {
|
||||
// There is a dot in repos name (and no registry address)
|
||||
// Is it a Registry address without repos name?
|
||||
return "", "", ErrInvalidRepositoryName
|
||||
}
|
||||
hostname := nameParts[0]
|
||||
reposName = nameParts[1]
|
||||
if strings.Contains(hostname, "index.docker.io") {
|
||||
return "", "", fmt.Errorf("Invalid repository name, try \"%s\" instead", reposName)
|
||||
}
|
||||
if err := validateRepositoryName(reposName); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
endpoint := fmt.Sprintf("https://%s/v1/", hostname)
|
||||
if err := pingRegistryEndpoint(endpoint); err != nil {
|
||||
utils.Debugf("Registry %s does not work (%s), falling back to http", endpoint, err)
|
||||
endpoint = fmt.Sprintf("http://%s/v1/", hostname)
|
||||
if err = pingRegistryEndpoint(endpoint); err != nil {
|
||||
//TODO: triggering highland build can be done there without "failing"
|
||||
return "", "", errors.New("Invalid Registry endpoint: " + err.Error())
|
||||
}
|
||||
}
|
||||
err := validateRepositoryName(reposName)
|
||||
return endpoint, reposName, err
|
||||
}
|
||||
|
||||
// VersionInfo is used to model entities which has a version.
|
||||
// It is basically a tupple with name and version.
|
||||
type VersionInfo interface {
|
||||
Name() string
|
||||
Version() string
|
||||
}
|
||||
|
||||
func doWithCookies(c *http.Client, req *http.Request) (*http.Response, error) {
|
||||
for _, cookie := range c.Jar.Cookies(req.URL) {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
return c.Do(req)
|
||||
res, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(res.Cookies()) > 0 {
|
||||
c.Jar.SetCookies(req.URL, res.Cookies())
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Set the user agent field in the header based on the versions provided
|
||||
// in NewRegistry() and extra.
|
||||
func (r *Registry) setUserAgent(req *http.Request, extra ...VersionInfo) {
|
||||
if len(r.baseVersions)+len(extra) == 0 {
|
||||
return
|
||||
}
|
||||
if len(extra) == 0 {
|
||||
req.Header.Set("User-Agent", r.baseVersionsStr)
|
||||
} else {
|
||||
req.Header.Set("User-Agent", appendVersions(r.baseVersionsStr, extra...))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve the history of a given image from the Registry.
|
||||
// Return a list of the parent's json (requested image included)
|
||||
func (r *Registry) GetRemoteHistory(imgId, registry string, token []string) ([]string, error) {
|
||||
req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/ancestry", nil)
|
||||
func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]string, error) {
|
||||
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/ancestry", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
|
||||
res, err := r.client.Do(req)
|
||||
r.setUserAgent(req)
|
||||
res, err := doWithCookies(r.client, req)
|
||||
if err != nil || res.StatusCode != 200 {
|
||||
if res != nil {
|
||||
return nil, fmt.Errorf("Internal server error: %d trying to fetch remote history for %s", res.StatusCode, imgId)
|
||||
return nil, fmt.Errorf("Internal server error: %d trying to fetch remote history for %s", res.StatusCode, imgID)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@@ -64,10 +165,10 @@ func (r *Registry) GetRemoteHistory(imgId, registry string, token []string) ([]s
|
||||
}
|
||||
|
||||
// Check if an image exists in the Registry
|
||||
func (r *Registry) LookupRemoteImage(imgId, registry string, token []string) bool {
|
||||
func (r *Registry) LookupRemoteImage(imgID, registry string, token []string) bool {
|
||||
rt := &http.Transport{Proxy: http.ProxyFromEnvironment}
|
||||
|
||||
req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/json", nil)
|
||||
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/json", nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -79,49 +180,16 @@ func (r *Registry) LookupRemoteImage(imgId, registry string, token []string) boo
|
||||
return res.StatusCode == 200
|
||||
}
|
||||
|
||||
func (r *Registry) getImagesInRepository(repository string, authConfig *auth.AuthConfig) ([]map[string]string, error) {
|
||||
u := auth.IndexServerAddress() + "/repositories/" + repository + "/images"
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if authConfig != nil && len(authConfig.Username) > 0 {
|
||||
req.SetBasicAuth(authConfig.Username, authConfig.Password)
|
||||
}
|
||||
res, err := r.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
// Repository doesn't exist yet
|
||||
if res.StatusCode == 404 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
jsonData, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
imageList := []map[string]string{}
|
||||
if err := json.Unmarshal(jsonData, &imageList); err != nil {
|
||||
utils.Debugf("Body: %s (%s)\n", res.Body, u)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return imageList, nil
|
||||
}
|
||||
|
||||
// Retrieve an image from the Registry.
|
||||
func (r *Registry) GetRemoteImageJSON(imgId, registry string, token []string) ([]byte, int, error) {
|
||||
func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([]byte, int, error) {
|
||||
// Get the JSON
|
||||
req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/json", nil)
|
||||
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/json", nil)
|
||||
if err != nil {
|
||||
return nil, -1, fmt.Errorf("Failed to download json: %s", err)
|
||||
}
|
||||
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
|
||||
res, err := r.client.Do(req)
|
||||
r.setUserAgent(req)
|
||||
res, err := doWithCookies(r.client, req)
|
||||
if err != nil {
|
||||
return nil, -1, fmt.Errorf("Failed to download json: %s", err)
|
||||
}
|
||||
@@ -142,13 +210,14 @@ func (r *Registry) GetRemoteImageJSON(imgId, registry string, token []string) ([
|
||||
return jsonString, imageSize, nil
|
||||
}
|
||||
|
||||
func (r *Registry) GetRemoteImageLayer(imgId, registry string, token []string) (io.ReadCloser, error) {
|
||||
req, err := http.NewRequest("GET", registry+"/images/"+imgId+"/layer", nil)
|
||||
func (r *Registry) GetRemoteImageLayer(imgID, registry string, token []string) (io.ReadCloser, error) {
|
||||
req, err := http.NewRequest("GET", registry+"images/"+imgID+"/layer", nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error while getting from the server: %s\n", err)
|
||||
}
|
||||
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
|
||||
res, err := r.client.Do(req)
|
||||
r.setUserAgent(req)
|
||||
res, err := doWithCookies(r.client, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -162,16 +231,14 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [
|
||||
repository = "library/" + repository
|
||||
}
|
||||
for _, host := range registries {
|
||||
endpoint := fmt.Sprintf("%s/v1/repositories/%s/tags", host, repository)
|
||||
if !(strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://")) {
|
||||
endpoint = fmt.Sprintf("%s://%s", UrlScheme(), endpoint)
|
||||
}
|
||||
endpoint := fmt.Sprintf("%srepositories/%s/tags", host, repository)
|
||||
req, err := r.opaqueRequest("GET", endpoint, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
|
||||
res, err := r.client.Do(req)
|
||||
r.setUserAgent(req)
|
||||
res, err := doWithCookies(r.client, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -198,8 +265,8 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [
|
||||
return nil, fmt.Errorf("Could not reach any registry endpoint")
|
||||
}
|
||||
|
||||
func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
|
||||
repositoryTarget := auth.IndexServerAddress() + "/repositories/" + remote + "/images"
|
||||
func (r *Registry) GetRepositoryData(indexEp, remote string) (*RepositoryData, error) {
|
||||
repositoryTarget := fmt.Sprintf("%srepositories/%s/images", indexEp, remote)
|
||||
|
||||
req, err := r.opaqueRequest("GET", repositoryTarget, nil)
|
||||
if err != nil {
|
||||
@@ -209,6 +276,7 @@ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
|
||||
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
|
||||
}
|
||||
req.Header.Set("X-Docker-Token", "true")
|
||||
r.setUserAgent(req)
|
||||
|
||||
res, err := r.client.Do(req)
|
||||
if err != nil {
|
||||
@@ -230,8 +298,12 @@ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
|
||||
}
|
||||
|
||||
var endpoints []string
|
||||
var urlScheme = indexEp[:strings.Index(indexEp, ":")]
|
||||
if res.Header.Get("X-Docker-Endpoints") != "" {
|
||||
endpoints = res.Header["X-Docker-Endpoints"]
|
||||
// The Registry's URL scheme has to match the Index'
|
||||
for _, ep := range res.Header["X-Docker-Endpoints"] {
|
||||
endpoints = append(endpoints, fmt.Sprintf("%s://%s/v1/", urlScheme, ep))
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("Index response didn't contain any endpoints")
|
||||
}
|
||||
@@ -260,15 +332,15 @@ func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) {
|
||||
|
||||
// Push a local image to the registry
|
||||
func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, registry string, token []string) error {
|
||||
registry = registry + "/v1"
|
||||
// FIXME: try json with UTF8
|
||||
req, err := http.NewRequest("PUT", registry+"/images/"+imgData.ID+"/json", strings.NewReader(string(jsonRaw)))
|
||||
req, err := http.NewRequest("PUT", registry+"images/"+imgData.ID+"/json", bytes.NewReader(jsonRaw))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("Content-type", "application/json")
|
||||
req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
|
||||
req.Header.Set("X-Docker-Checksum", imgData.Checksum)
|
||||
r.setUserAgent(req)
|
||||
|
||||
utils.Debugf("Setting checksum for %s: %s", imgData.ID, imgData.Checksum)
|
||||
res, err := doWithCookies(r.client, req)
|
||||
@@ -276,9 +348,6 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis
|
||||
return fmt.Errorf("Failed to upload metadata: %s", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if len(res.Cookies()) > 0 {
|
||||
r.client.Jar.SetCookies(req.URL, res.Cookies())
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
errBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
@@ -295,15 +364,15 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Registry) PushImageLayerRegistry(imgId string, layer io.Reader, registry string, token []string) error {
|
||||
registry = registry + "/v1"
|
||||
req, err := http.NewRequest("PUT", registry+"/images/"+imgId+"/layer", layer)
|
||||
func (r *Registry) PushImageLayerRegistry(imgID string, layer io.Reader, registry string, token []string) error {
|
||||
req, err := http.NewRequest("PUT", registry+"images/"+imgID+"/layer", layer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.ContentLength = -1
|
||||
req.TransferEncoding = []string{"chunked"}
|
||||
req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
|
||||
r.setUserAgent(req)
|
||||
res, err := doWithCookies(r.client, req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to upload layer: %s", err)
|
||||
@@ -334,14 +403,14 @@ func (r *Registry) opaqueRequest(method, urlStr string, body io.Reader) (*http.R
|
||||
func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token []string) error {
|
||||
// "jsonify" the string
|
||||
revision = "\"" + revision + "\""
|
||||
registry = registry + "/v1"
|
||||
|
||||
req, err := r.opaqueRequest("PUT", registry+"/repositories/"+remote+"/tags/"+tag, strings.NewReader(revision))
|
||||
req, err := r.opaqueRequest("PUT", registry+"repositories/"+remote+"/tags/"+tag, strings.NewReader(revision))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("Content-type", "application/json")
|
||||
req.Header.Set("Authorization", "Token "+strings.Join(token, ","))
|
||||
r.setUserAgent(req)
|
||||
req.ContentLength = int64(len(revision))
|
||||
res, err := doWithCookies(r.client, req)
|
||||
if err != nil {
|
||||
@@ -354,7 +423,7 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validate bool, regs []string) (*RepositoryData, error) {
|
||||
func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData, validate bool, regs []string) (*RepositoryData, error) {
|
||||
imgListJSON, err := json.Marshal(imgList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -364,15 +433,17 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
|
||||
suffix = "images"
|
||||
}
|
||||
|
||||
u := fmt.Sprintf("%srepositories/%s/%s", indexEp, remote, suffix)
|
||||
utils.Debugf("PUT %s", u)
|
||||
utils.Debugf("Image list pushed to index:\n%s\n", imgListJSON)
|
||||
|
||||
req, err := r.opaqueRequest("PUT", auth.IndexServerAddress()+"/repositories/"+remote+"/"+suffix, bytes.NewReader(imgListJSON))
|
||||
req, err := r.opaqueRequest("PUT", u, bytes.NewReader(imgListJSON))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
|
||||
req.ContentLength = int64(len(imgListJSON))
|
||||
req.Header.Set("X-Docker-Token", "true")
|
||||
r.setUserAgent(req)
|
||||
if validate {
|
||||
req.Header["X-Docker-Endpoints"] = regs
|
||||
}
|
||||
@@ -393,6 +464,7 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
|
||||
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
|
||||
req.ContentLength = int64(len(imgListJSON))
|
||||
req.Header.Set("X-Docker-Token", "true")
|
||||
r.setUserAgent(req)
|
||||
if validate {
|
||||
req.Header["X-Docker-Endpoints"] = regs
|
||||
}
|
||||
@@ -404,6 +476,7 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
|
||||
}
|
||||
|
||||
var tokens, endpoints []string
|
||||
var urlScheme = indexEp[:strings.Index(indexEp, ":")]
|
||||
if !validate {
|
||||
if res.StatusCode != 200 && res.StatusCode != 201 {
|
||||
errBody, err := ioutil.ReadAll(res.Body)
|
||||
@@ -420,7 +493,10 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
|
||||
}
|
||||
|
||||
if res.Header.Get("X-Docker-Endpoints") != "" {
|
||||
endpoints = res.Header["X-Docker-Endpoints"]
|
||||
// The Registry's URL scheme has to match the Index'
|
||||
for _, ep := range res.Header["X-Docker-Endpoints"] {
|
||||
endpoints = append(endpoints, fmt.Sprintf("%s://%s/v1/", urlScheme, ep))
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("Index response didn't contain any endpoints")
|
||||
}
|
||||
@@ -442,7 +518,7 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
|
||||
}
|
||||
|
||||
func (r *Registry) SearchRepositories(term string) (*SearchResults, error) {
|
||||
u := auth.IndexServerAddress() + "/search?q=" + url.QueryEscape(term)
|
||||
u := auth.IndexServerAddress() + "search?q=" + url.QueryEscape(term)
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -495,11 +571,52 @@ type ImgData struct {
|
||||
}
|
||||
|
||||
type Registry struct {
|
||||
client *http.Client
|
||||
authConfig *auth.AuthConfig
|
||||
client *http.Client
|
||||
authConfig *auth.AuthConfig
|
||||
baseVersions []VersionInfo
|
||||
baseVersionsStr string
|
||||
}
|
||||
|
||||
func NewRegistry(root string, authConfig *auth.AuthConfig) (r *Registry, err error) {
|
||||
func validVersion(version VersionInfo) bool {
|
||||
stopChars := " \t\r\n/"
|
||||
if strings.ContainsAny(version.Name(), stopChars) {
|
||||
return false
|
||||
}
|
||||
if strings.ContainsAny(version.Version(), stopChars) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Convert versions to a string and append the string to the string base.
|
||||
//
|
||||
// Each VersionInfo will be converted to a string in the format of
|
||||
// "product/version", where the "product" is get from the Name() method, while
|
||||
// version is get from the Version() method. Several pieces of verson information
|
||||
// will be concatinated and separated by space.
|
||||
func appendVersions(base string, versions ...VersionInfo) string {
|
||||
if len(versions) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if len(base) > 0 {
|
||||
buf.Write([]byte(base))
|
||||
}
|
||||
|
||||
for _, v := range versions {
|
||||
if !validVersion(v) {
|
||||
continue
|
||||
}
|
||||
buf.Write([]byte(v.Name()))
|
||||
buf.Write([]byte("/"))
|
||||
buf.Write([]byte(v.Version()))
|
||||
buf.Write([]byte(" "))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func NewRegistry(root string, authConfig *auth.AuthConfig, baseVersions ...VersionInfo) (r *Registry, err error) {
|
||||
httpTransport := &http.Transport{
|
||||
DisableKeepAlives: true,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
@@ -512,5 +629,10 @@ func NewRegistry(root string, authConfig *auth.AuthConfig) (r *Registry, err err
|
||||
},
|
||||
}
|
||||
r.client.Jar, err = cookiejar.New(nil)
|
||||
return r, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.baseVersions = baseVersions
|
||||
r.baseVersionsStr = appendVersions("", baseVersions...)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
@@ -108,9 +108,6 @@ func (runtime *Runtime) Register(container *Container) error {
|
||||
// init the wait lock
|
||||
container.waitLock = make(chan struct{})
|
||||
|
||||
// Even if not running, we init the lock (prevents races in start/stop/kill)
|
||||
container.State.initLock()
|
||||
|
||||
container.runtime = runtime
|
||||
|
||||
// Attach to stdout and stderr
|
||||
@@ -144,7 +141,6 @@ func (runtime *Runtime) Register(container *Container) error {
|
||||
utils.Debugf("Restarting")
|
||||
container.State.Ghost = false
|
||||
container.State.setStopped(0)
|
||||
// assume empty host config
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
return err
|
||||
@@ -171,12 +167,12 @@ func (runtime *Runtime) Register(container *Container) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (runtime *Runtime) LogToDisk(src *utils.WriteBroadcaster, dst string) error {
|
||||
func (runtime *Runtime) LogToDisk(src *utils.WriteBroadcaster, dst, stream string) error {
|
||||
log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src.AddWriter(log)
|
||||
src.AddWriter(log, stream)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
322
runtime_test.go
@@ -1,13 +1,14 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -17,14 +18,19 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
unitTestImageName = "docker-unit-tests"
|
||||
unitTestImageId = "e9aa60c60128cad1"
|
||||
unitTestStoreBase = "/var/lib/docker/unit-tests"
|
||||
testDaemonAddr = "127.0.0.1:4270"
|
||||
testDaemonProto = "tcp"
|
||||
unitTestImageName = "docker-test-image"
|
||||
unitTestImageID = "83599e29c455eb719f77d799bc7c51521b9551972f5a850d7ad265bc1b5292f6" // 1.0
|
||||
unitTestNetworkBridge = "testdockbr0"
|
||||
unitTestStoreBase = "/var/lib/docker/unit-tests"
|
||||
testDaemonAddr = "127.0.0.1:4270"
|
||||
testDaemonProto = "tcp"
|
||||
)
|
||||
|
||||
var globalRuntime *Runtime
|
||||
var (
|
||||
globalRuntime *Runtime
|
||||
startFds int
|
||||
startGoroutines int
|
||||
)
|
||||
|
||||
func nuke(runtime *Runtime) error {
|
||||
var wg sync.WaitGroup
|
||||
@@ -49,7 +55,7 @@ func cleanup(runtime *Runtime) error {
|
||||
return err
|
||||
}
|
||||
for _, image := range images {
|
||||
if image.ID != unitTestImageId {
|
||||
if image.ID != unitTestImageID {
|
||||
runtime.graph.Delete(image.ID)
|
||||
}
|
||||
}
|
||||
@@ -73,31 +79,32 @@ func init() {
|
||||
}
|
||||
|
||||
if uid := syscall.Geteuid(); uid != 0 {
|
||||
log.Fatal("docker tests needs to be run as root")
|
||||
log.Fatal("docker tests need to be run as root")
|
||||
}
|
||||
|
||||
NetworkBridgeIface = "testdockbr0"
|
||||
NetworkBridgeIface = unitTestNetworkBridge
|
||||
|
||||
// Make it our Store root
|
||||
runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false)
|
||||
if err != nil {
|
||||
if runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
globalRuntime = runtime
|
||||
}
|
||||
globalRuntime = runtime
|
||||
|
||||
// Create the "Server"
|
||||
srv := &Server{
|
||||
runtime: runtime,
|
||||
runtime: globalRuntime,
|
||||
enableCors: false,
|
||||
lock: &sync.Mutex{},
|
||||
pullingPool: make(map[string]struct{}),
|
||||
pushingPool: make(map[string]struct{}),
|
||||
}
|
||||
// Retrieve the Image
|
||||
if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, utils.NewStreamFormatter(false), nil); err != nil {
|
||||
panic(err)
|
||||
// If the unit test is not found, try to download it.
|
||||
if img, err := globalRuntime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID {
|
||||
// Retrieve the Image
|
||||
if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn a Daemon
|
||||
go func() {
|
||||
if err := ListenAndServe(testDaemonProto, testDaemonAddr, srv, os.Getenv("DEBUG") != ""); err != nil {
|
||||
@@ -107,48 +114,27 @@ func init() {
|
||||
|
||||
// Give some time to ListenAndServer to actually start
|
||||
time.Sleep(time.Second)
|
||||
|
||||
startFds, startGoroutines = utils.GetTotalUsedFds(), runtime.NumGoroutine()
|
||||
}
|
||||
|
||||
// FIXME: test that ImagePull(json=true) send correct json output
|
||||
|
||||
func newTestRuntime() (*Runtime, error) {
|
||||
root, err := ioutil.TempDir("", "docker-test")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.Remove(root); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := utils.CopyDirectory(unitTestStoreBase, root); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
runtime, err := NewRuntimeFromDirectory(root, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
runtime.UpdateCapabilities(true)
|
||||
return runtime, nil
|
||||
}
|
||||
|
||||
func GetTestImage(runtime *Runtime) *Image {
|
||||
imgs, err := runtime.graph.All()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for i := range imgs {
|
||||
if imgs[i].ID == unitTestImageId {
|
||||
if imgs[i].ID == unitTestImageID {
|
||||
return imgs[i]
|
||||
}
|
||||
}
|
||||
panic(fmt.Errorf("Test image %v not found", unitTestImageId))
|
||||
panic(fmt.Errorf("Test image %v not found", unitTestImageID))
|
||||
}
|
||||
|
||||
func TestRuntimeCreate(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
// Make sure we start we 0 containers
|
||||
@@ -220,10 +206,7 @@ func TestRuntimeCreate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDestroy(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
container, err := NewBuilder(runtime).Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
@@ -267,42 +250,16 @@ func TestDestroy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
builder := NewBuilder(runtime)
|
||||
|
||||
container1, err := builder.Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container1, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
|
||||
defer runtime.Destroy(container1)
|
||||
|
||||
container2, err := builder.Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container2, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
|
||||
defer runtime.Destroy(container2)
|
||||
|
||||
container3, err := builder.Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container3, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
|
||||
defer runtime.Destroy(container3)
|
||||
|
||||
if runtime.Get(container1.ID) != container1 {
|
||||
@@ -319,125 +276,152 @@ func TestGet(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func findAvailalblePort(runtime *Runtime, port int) (*Container, error) {
|
||||
strPort := strconv.Itoa(port)
|
||||
container, err := NewBuilder(runtime).Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sh", "-c", "echo well hello there | nc -l -p " + strPort},
|
||||
PortSpecs: []string{strPort},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
if strings.Contains(err.Error(), "address already in use") {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return container, nil
|
||||
}
|
||||
|
||||
// Run a container with a TCP port allocated, and test that it can receive connections on localhost
|
||||
func TestAllocatePortLocalhost(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
func startEchoServerContainer(t *testing.T, proto string) (*Runtime, *Container, string) {
|
||||
var err error
|
||||
runtime := mkRuntime(t)
|
||||
port := 5554
|
||||
|
||||
var container *Container
|
||||
var strPort string
|
||||
for {
|
||||
port += 1
|
||||
log.Println("Trying port", port)
|
||||
t.Log("Trying port", port)
|
||||
container, err = findAvailalblePort(runtime, port)
|
||||
strPort = strconv.Itoa(port)
|
||||
var cmd string
|
||||
if proto == "tcp" {
|
||||
cmd = "socat TCP-LISTEN:" + strPort + ",reuseaddr,fork EXEC:/bin/cat"
|
||||
} else if proto == "udp" {
|
||||
cmd = "socat UDP-RECVFROM:" + strPort + ",fork EXEC:/bin/cat"
|
||||
} else {
|
||||
t.Fatal(fmt.Errorf("Unknown protocol %v", proto))
|
||||
}
|
||||
t.Log("Trying port", strPort)
|
||||
container, err = NewBuilder(runtime).Create(&Config{
|
||||
Image: GetTestImage(runtime).ID,
|
||||
Cmd: []string{"sh", "-c", cmd},
|
||||
PortSpecs: []string{fmt.Sprintf("%s/%s", strPort, proto)},
|
||||
})
|
||||
if container != nil {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
nuke(runtime)
|
||||
t.Fatal(err)
|
||||
}
|
||||
log.Println("Port", port, "already in use")
|
||||
t.Log("Port", port, "already in use")
|
||||
t.Logf("Port %v already in use", strPort)
|
||||
}
|
||||
|
||||
defer container.Kill()
|
||||
hostConfig := &HostConfig{}
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
nuke(runtime)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
|
||||
for {
|
||||
if container.State.Running {
|
||||
break
|
||||
}
|
||||
for !container.State.Running {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
})
|
||||
|
||||
conn, err := net.Dial("tcp",
|
||||
fmt.Sprintf(
|
||||
"localhost:%s", container.NetworkSettings.PortMapping[strconv.Itoa(port)],
|
||||
),
|
||||
)
|
||||
// Even if the state is running, lets give some time to lxc to spawn the process
|
||||
container.WaitTimeout(500 * time.Millisecond)
|
||||
|
||||
strPort = container.NetworkSettings.PortMapping[strings.Title(proto)][strPort]
|
||||
return runtime, container, strPort
|
||||
}
|
||||
|
||||
// Run a container with a TCP port allocated, and test that it can receive connections on localhost
|
||||
func TestAllocateTCPPortLocalhost(t *testing.T) {
|
||||
runtime, container, port := startEchoServerContainer(t, "tcp")
|
||||
defer nuke(runtime)
|
||||
defer container.Kill()
|
||||
|
||||
for i := 0; i != 10; i++ {
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%v", port))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
input := bytes.NewBufferString("well hello there\n")
|
||||
_, err = conn.Write(input.Bytes())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
buf := make([]byte, 16)
|
||||
read := 0
|
||||
conn.SetReadDeadline(time.Now().Add(3 * time.Second))
|
||||
read, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
if err, ok := err.(*net.OpError); ok {
|
||||
if err.Err == syscall.ECONNRESET {
|
||||
t.Logf("Connection reset by the proxy, socat is probably not listening yet, trying again in a sec")
|
||||
conn.Close()
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
if err.Timeout() {
|
||||
t.Log("Timeout, trying again")
|
||||
conn.Close()
|
||||
continue
|
||||
}
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
output := string(buf[:read])
|
||||
if !strings.Contains(output, "well hello there") {
|
||||
t.Fatal(fmt.Errorf("[%v] doesn't contain [well hello there]", output))
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
t.Fatal("No reply from the container")
|
||||
}
|
||||
|
||||
// Run a container with an UDP port allocated, and test that it can receive connections on localhost
|
||||
func TestAllocateUDPPortLocalhost(t *testing.T) {
|
||||
runtime, container, port := startEchoServerContainer(t, "udp")
|
||||
defer nuke(runtime)
|
||||
defer container.Kill()
|
||||
|
||||
conn, err := net.Dial("udp", fmt.Sprintf("localhost:%v", port))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
output, err := ioutil.ReadAll(conn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
input := bytes.NewBufferString("well hello there\n")
|
||||
buf := make([]byte, 16)
|
||||
// Try for a minute, for some reason the select in socat may take ages
|
||||
// to return even though everything on the path seems fine (i.e: the
|
||||
// UDPProxy forwards the traffic correctly and you can see the packets
|
||||
// on the interface from within the container).
|
||||
for i := 0; i != 120; i++ {
|
||||
_, err := conn.Write(input.Bytes())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
|
||||
read, err := conn.Read(buf)
|
||||
if err == nil {
|
||||
output := string(buf[:read])
|
||||
if strings.Contains(output, "well hello there") {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if string(output) != "well hello there\n" {
|
||||
t.Fatalf("Received wrong output from network connection: should be '%s', not '%s'",
|
||||
"well hello there\n",
|
||||
string(output),
|
||||
)
|
||||
}
|
||||
container.Wait()
|
||||
|
||||
t.Fatal("No reply from the container")
|
||||
}
|
||||
|
||||
func TestRestore(t *testing.T) {
|
||||
|
||||
root, err := ioutil.TempDir("", "docker-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Remove(root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := utils.CopyDirectory(unitTestStoreBase, root); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
runtime1, err := NewRuntimeFromDirectory(root, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
builder := NewBuilder(runtime1)
|
||||
|
||||
runtime1 := mkRuntime(t)
|
||||
defer nuke(runtime1)
|
||||
// Create a container with one instance of docker
|
||||
container1, err := builder.Create(&Config{
|
||||
Image: GetTestImage(runtime1).ID,
|
||||
Cmd: []string{"ls", "-al"},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container1, _, _ := mkContainer(runtime1, []string{"_", "ls", "-al"}, t)
|
||||
defer runtime1.Destroy(container1)
|
||||
|
||||
// Create a second container meant to be killed
|
||||
container2, err := builder.Create(&Config{
|
||||
Image: GetTestImage(runtime1).ID,
|
||||
Cmd: []string{"/bin/cat"},
|
||||
OpenStdin: true,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
container2, _, _ := mkContainer(runtime1, []string{"-i", "_", "/bin/cat"}, t)
|
||||
defer runtime1.Destroy(container2)
|
||||
|
||||
// Start the container non blocking
|
||||
@@ -472,7 +456,7 @@ func TestRestore(t *testing.T) {
|
||||
|
||||
// Here are are simulating a docker restart - that is, reloading all containers
|
||||
// from scratch
|
||||
runtime2, err := NewRuntimeFromDirectory(root, false)
|
||||
runtime2, err := NewRuntimeFromDirectory(runtime1.root, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
447
server.go
@@ -1,6 +1,8 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/auth"
|
||||
@@ -12,10 +14,12 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (srv *Server) DockerVersion() APIVersion {
|
||||
@@ -26,11 +30,53 @@ func (srv *Server) DockerVersion() APIVersion {
|
||||
}
|
||||
}
|
||||
|
||||
// simpleVersionInfo is a simple implementation of
|
||||
// the interface VersionInfo, which is used
|
||||
// to provide version information for some product,
|
||||
// component, etc. It stores the product name and the version
|
||||
// in string and returns them on calls to Name() and Version().
|
||||
type simpleVersionInfo struct {
|
||||
name string
|
||||
version string
|
||||
}
|
||||
|
||||
func (v *simpleVersionInfo) Name() string {
|
||||
return v.name
|
||||
}
|
||||
|
||||
func (v *simpleVersionInfo) Version() string {
|
||||
return v.version
|
||||
}
|
||||
|
||||
// versionCheckers() returns version informations of:
|
||||
// docker, go, git-commit (of the docker) and the host's kernel.
|
||||
//
|
||||
// Such information will be used on call to NewRegistry().
|
||||
func (srv *Server) versionInfos() []registry.VersionInfo {
|
||||
v := srv.DockerVersion()
|
||||
ret := make([]registry.VersionInfo, 0, 4)
|
||||
ret = append(ret, &simpleVersionInfo{"docker", v.Version})
|
||||
|
||||
if len(v.GoVersion) > 0 {
|
||||
ret = append(ret, &simpleVersionInfo{"go", v.GoVersion})
|
||||
}
|
||||
if len(v.GitCommit) > 0 {
|
||||
ret = append(ret, &simpleVersionInfo{"git-commit", v.GitCommit})
|
||||
}
|
||||
kernelVersion, err := utils.GetKernelVersion()
|
||||
if err == nil {
|
||||
ret = append(ret, &simpleVersionInfo{"kernel", kernelVersion.String()})
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (srv *Server) ContainerKill(name string) error {
|
||||
if container := srv.runtime.Get(name); container != nil {
|
||||
if err := container.Kill(); err != nil {
|
||||
return fmt.Errorf("Error restarting container %s: %s", name, err.Error())
|
||||
return fmt.Errorf("Error killing container %s: %s", name, err)
|
||||
}
|
||||
srv.LogEvent("kill", name)
|
||||
} else {
|
||||
return fmt.Errorf("No such container: %s", name)
|
||||
}
|
||||
@@ -49,13 +95,14 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error {
|
||||
if _, err := io.Copy(out, data); err != nil {
|
||||
return err
|
||||
}
|
||||
srv.LogEvent("export", name)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("No such container: %s", name)
|
||||
}
|
||||
|
||||
func (srv *Server) ImagesSearch(term string) ([]APISearch, error) {
|
||||
r, err := registry.NewRegistry(srv.runtime.root, nil)
|
||||
r, err := registry.NewRegistry(srv.runtime.root, nil, srv.versionInfos()...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -98,7 +145,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer, sf *utils.
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), path); err != nil {
|
||||
if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, sf.FormatProgress("Downloading", "%8v/%v (%v)"), sf), path); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// FIXME: Handle custom repo, tag comment, author
|
||||
@@ -205,14 +252,29 @@ func (srv *Server) DockerInfo() *APIInfo {
|
||||
} else {
|
||||
imgcount = len(images)
|
||||
}
|
||||
lxcVersion := ""
|
||||
if output, err := exec.Command("lxc-version").CombinedOutput(); err == nil {
|
||||
outputStr := string(output)
|
||||
if len(strings.SplitN(outputStr, ":", 2)) == 2 {
|
||||
lxcVersion = strings.TrimSpace(strings.SplitN(string(output), ":", 2)[1])
|
||||
}
|
||||
}
|
||||
kernelVersion := "<unknown>"
|
||||
if kv, err := utils.GetKernelVersion(); err == nil {
|
||||
kernelVersion = kv.String()
|
||||
}
|
||||
|
||||
return &APIInfo{
|
||||
Containers: len(srv.runtime.List()),
|
||||
Images: imgcount,
|
||||
MemoryLimit: srv.runtime.capabilities.MemoryLimit,
|
||||
SwapLimit: srv.runtime.capabilities.SwapLimit,
|
||||
Debug: os.Getenv("DEBUG") != "",
|
||||
NFd: utils.GetTotalUsedFds(),
|
||||
NGoroutines: runtime.NumGoroutine(),
|
||||
Containers: len(srv.runtime.List()),
|
||||
Images: imgcount,
|
||||
MemoryLimit: srv.runtime.capabilities.MemoryLimit,
|
||||
SwapLimit: srv.runtime.capabilities.SwapLimit,
|
||||
Debug: os.Getenv("DEBUG") != "",
|
||||
NFd: utils.GetTotalUsedFds(),
|
||||
NGoroutines: runtime.NumGoroutine(),
|
||||
LXCVersion: lxcVersion,
|
||||
NEventsListener: len(srv.events),
|
||||
KernelVersion: kernelVersion,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +309,39 @@ func (srv *Server) ImageHistory(name string) ([]APIHistory, error) {
|
||||
|
||||
}
|
||||
|
||||
func (srv *Server) ContainerTop(name, ps_args string) (*APITop, error) {
|
||||
if container := srv.runtime.Get(name); container != nil {
|
||||
output, err := exec.Command("lxc-ps", "--name", container.ID, "--", ps_args).CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error trying to use lxc-ps: %s (%s)", err, output)
|
||||
}
|
||||
procs := APITop{}
|
||||
for i, line := range strings.Split(string(output), "\n") {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
words := []string{}
|
||||
scanner := bufio.NewScanner(strings.NewReader(line))
|
||||
scanner.Split(bufio.ScanWords)
|
||||
if !scanner.Scan() {
|
||||
return nil, fmt.Errorf("Error trying to use lxc-ps")
|
||||
}
|
||||
// no scanner.Text because we skip container id
|
||||
for scanner.Scan() {
|
||||
words = append(words, scanner.Text())
|
||||
}
|
||||
if i == 0 {
|
||||
procs.Titles = words
|
||||
} else {
|
||||
procs.Processes = append(procs.Processes, words)
|
||||
}
|
||||
}
|
||||
return &procs, nil
|
||||
|
||||
}
|
||||
return nil, fmt.Errorf("No such container: %s", name)
|
||||
}
|
||||
|
||||
func (srv *Server) ContainerChanges(name string) ([]Change, error) {
|
||||
if container := srv.runtime.Get(name); container != nil {
|
||||
return container.Changes()
|
||||
@@ -315,8 +410,8 @@ func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoint string, token []string, sf *utils.StreamFormatter) error {
|
||||
history, err := r.GetRemoteHistory(imgId, endpoint, token)
|
||||
func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgID, endpoint string, token []string, sf *utils.StreamFormatter) error {
|
||||
history, err := r.GetRemoteHistory(imgID, endpoint, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -343,7 +438,7 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoin
|
||||
return err
|
||||
}
|
||||
defer layer.Close()
|
||||
if err := srv.runtime.graph.Register(utils.ProgressReader(layer, imgSize, out, sf.FormatProgress("Downloading", "%v/%v (%v)"), sf), false, img); err != nil {
|
||||
if err := srv.runtime.graph.Register(utils.ProgressReader(layer, imgSize, out, sf.FormatProgress("Downloading", "%8v/%v (%v)"), sf), false, img); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -351,44 +446,32 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgId, endpoin
|
||||
return nil
|
||||
}
|
||||
|
||||
func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, remote, askedTag, registryEp string, sf *utils.StreamFormatter) error {
|
||||
out.Write(sf.FormatStatus("Pulling repository %s from %s", local, auth.IndexServerAddress()))
|
||||
func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, localName, remoteName, askedTag, indexEp string, sf *utils.StreamFormatter) error {
|
||||
out.Write(sf.FormatStatus("Pulling repository %s", localName))
|
||||
|
||||
var repoData *registry.RepositoryData
|
||||
var err error
|
||||
if registryEp == "" {
|
||||
repoData, err = r.GetRepositoryData(remote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repoData, err := r.GetRepositoryData(indexEp, remoteName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
utils.Debugf("Updating checksums")
|
||||
// Reload the json file to make sure not to overwrite faster sums
|
||||
if err := srv.runtime.graph.UpdateChecksums(repoData.ImgList); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
repoData = ®istry.RepositoryData{
|
||||
Tokens: []string{},
|
||||
ImgList: make(map[string]*registry.ImgData),
|
||||
Endpoints: []string{registryEp},
|
||||
}
|
||||
utils.Debugf("Updating checksums")
|
||||
// Reload the json file to make sure not to overwrite faster sums
|
||||
if err := srv.runtime.graph.UpdateChecksums(repoData.ImgList); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
utils.Debugf("Retrieving the tag list")
|
||||
tagsList, err := r.GetRemoteTags(repoData.Endpoints, remote, repoData.Tokens)
|
||||
tagsList, err := r.GetRemoteTags(repoData.Endpoints, remoteName, repoData.Tokens)
|
||||
if err != nil {
|
||||
utils.Debugf("%v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if registryEp != "" {
|
||||
for tag, id := range tagsList {
|
||||
repoData.ImgList[id] = ®istry.ImgData{
|
||||
ID: id,
|
||||
Tag: tag,
|
||||
Checksum: "",
|
||||
}
|
||||
for tag, id := range tagsList {
|
||||
repoData.ImgList[id] = ®istry.ImgData{
|
||||
ID: id,
|
||||
Tag: tag,
|
||||
Checksum: "",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +485,7 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re
|
||||
// Otherwise, check that the tag exists and use only that one
|
||||
id, exists := tagsList[askedTag]
|
||||
if !exists {
|
||||
return fmt.Errorf("Tag %s not found in repositoy %s", askedTag, local)
|
||||
return fmt.Errorf("Tag %s not found in repository %s", askedTag, localName)
|
||||
}
|
||||
repoData.ImgList[id].Tag = askedTag
|
||||
}
|
||||
@@ -412,13 +495,15 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re
|
||||
utils.Debugf("(%s) does not match %s (id: %s), skipping", img.Tag, askedTag, img.ID)
|
||||
continue
|
||||
}
|
||||
out.Write(sf.FormatStatus("Pulling image %s (%s) from %s", img.ID, img.Tag, remote))
|
||||
|
||||
if img.Tag == "" {
|
||||
utils.Debugf("Image (id: %s) present in this repository but untagged, skipping", img.ID)
|
||||
continue
|
||||
}
|
||||
out.Write(sf.FormatStatus("Pulling image %s (%s) from %s", img.ID, img.Tag, localName))
|
||||
success := false
|
||||
for _, ep := range repoData.Endpoints {
|
||||
if !(strings.HasPrefix(ep, "http://") || strings.HasPrefix(ep, "https://")) {
|
||||
ep = fmt.Sprintf("%s://%s", registry.UrlScheme(), ep)
|
||||
}
|
||||
if err := srv.pullImage(r, out, img.ID, ep+"/v1", repoData.Tokens, sf); err != nil {
|
||||
if err := srv.pullImage(r, out, img.ID, ep, repoData.Tokens, sf); err != nil {
|
||||
out.Write(sf.FormatStatus("Error while retrieving image for tag: %s (%s); checking next endpoint", askedTag, err))
|
||||
continue
|
||||
}
|
||||
@@ -433,7 +518,7 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re
|
||||
if askedTag != "" && tag != askedTag {
|
||||
continue
|
||||
}
|
||||
if err := srv.runtime.repositories.Set(local, tag, id, true); err != nil {
|
||||
if err := srv.runtime.repositories.Set(localName, tag, id, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -445,8 +530,8 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, local, re
|
||||
}
|
||||
|
||||
func (srv *Server) poolAdd(kind, key string) error {
|
||||
srv.lock.Lock()
|
||||
defer srv.lock.Unlock()
|
||||
srv.Lock()
|
||||
defer srv.Unlock()
|
||||
|
||||
if _, exists := srv.pullingPool[key]; exists {
|
||||
return fmt.Errorf("%s %s is already in progress", key, kind)
|
||||
@@ -478,25 +563,32 @@ func (srv *Server) poolRemove(kind, key string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error {
|
||||
r, err := registry.NewRegistry(srv.runtime.root, authConfig)
|
||||
|
||||
func (srv *Server) ImagePull(localName string, tag string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error {
|
||||
r, err := registry.NewRegistry(srv.runtime.root, authConfig, srv.versionInfos()...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := srv.poolAdd("pull", name+":"+tag); err != nil {
|
||||
if err := srv.poolAdd("pull", localName+":"+tag); err != nil {
|
||||
return err
|
||||
}
|
||||
defer srv.poolRemove("pull", name+":"+tag)
|
||||
defer srv.poolRemove("pull", localName+":"+tag)
|
||||
|
||||
remote := name
|
||||
parts := strings.Split(name, "/")
|
||||
if len(parts) > 2 {
|
||||
remote = fmt.Sprintf("src/%s", url.QueryEscape(strings.Join(parts, "/")))
|
||||
// Resolve the Repository name from fqn to endpoint + name
|
||||
endpoint, remoteName, err := registry.ResolveRepositoryName(localName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if endpoint == auth.IndexServerAddress() {
|
||||
// If pull "index.docker.io/foo/bar", it's stored locally under "foo/bar"
|
||||
localName = remoteName
|
||||
}
|
||||
|
||||
out = utils.NewWriteFlusher(out)
|
||||
err = srv.pullRepository(r, out, name, remote, tag, endpoint, sf)
|
||||
if err != nil && endpoint != "" {
|
||||
if err := srv.pullImage(r, out, name, endpoint, nil, sf); err != nil {
|
||||
err = srv.pullRepository(r, out, localName, remoteName, tag, endpoint, sf)
|
||||
if err != nil {
|
||||
if err := srv.pullImage(r, out, remoteName, endpoint, nil, sf); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -511,20 +603,20 @@ func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, sf *util
|
||||
// - Check if the archive exists, if it does not, ask the registry
|
||||
// - If the archive does exists, process the checksum from it
|
||||
// - If the archive does not exists and not found on registry, process checksum from layer
|
||||
func (srv *Server) getChecksum(imageId string) (string, error) {
|
||||
func (srv *Server) getChecksum(imageID string) (string, error) {
|
||||
// FIXME: Use in-memory map instead of reading the file each time
|
||||
if sums, err := srv.runtime.graph.getStoredChecksums(); err != nil {
|
||||
return "", err
|
||||
} else if checksum, exists := sums[imageId]; exists {
|
||||
} else if checksum, exists := sums[imageID]; exists {
|
||||
return checksum, nil
|
||||
}
|
||||
|
||||
img, err := srv.runtime.graph.Get(imageId)
|
||||
img, err := srv.runtime.graph.Get(imageID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(layerArchivePath(srv.runtime.graph.imageRoot(imageId))); err != nil {
|
||||
if _, err := os.Stat(layerArchivePath(srv.runtime.graph.imageRoot(imageID))); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// TODO: Ask the registry for the checksum
|
||||
// As the archive is not there, it is supposed to come from a pull.
|
||||
@@ -571,7 +663,7 @@ func (srv *Server) getImageList(localRepo map[string]string) ([]*registry.ImgDat
|
||||
return imgList, nil
|
||||
}
|
||||
|
||||
func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name, registryEp string, localRepo map[string]string, sf *utils.StreamFormatter) error {
|
||||
func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, indexEp string, sf *utils.StreamFormatter) error {
|
||||
out = utils.NewWriteFlusher(out)
|
||||
out.Write(sf.FormatStatus("Processing checksums"))
|
||||
imgList, err := srv.getImageList(localRepo)
|
||||
@@ -579,94 +671,64 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name, reg
|
||||
return err
|
||||
}
|
||||
out.Write(sf.FormatStatus("Sending image list"))
|
||||
srvName := name
|
||||
parts := strings.Split(name, "/")
|
||||
if len(parts) > 2 {
|
||||
srvName = fmt.Sprintf("src/%s", url.QueryEscape(strings.Join(parts, "/")))
|
||||
}
|
||||
|
||||
var repoData *registry.RepositoryData
|
||||
if registryEp == "" {
|
||||
repoData, err = r.PushImageJSONIndex(name, imgList, false, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
repoData = ®istry.RepositoryData{
|
||||
ImgList: make(map[string]*registry.ImgData),
|
||||
Tokens: []string{},
|
||||
Endpoints: []string{registryEp},
|
||||
}
|
||||
tagsList, err := r.GetRemoteTags(repoData.Endpoints, name, repoData.Tokens)
|
||||
if err != nil && err.Error() != "Repository not found" {
|
||||
return err
|
||||
} else if err == nil {
|
||||
for tag, id := range tagsList {
|
||||
repoData.ImgList[id] = ®istry.ImgData{
|
||||
ID: id,
|
||||
Tag: tag,
|
||||
Checksum: "",
|
||||
}
|
||||
}
|
||||
}
|
||||
repoData, err = r.PushImageJSONIndex(indexEp, remoteName, imgList, false, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ep := range repoData.Endpoints {
|
||||
if !(strings.HasPrefix(ep, "http://") || strings.HasPrefix(ep, "https://")) {
|
||||
ep = fmt.Sprintf("%s://%s", registry.UrlScheme(), ep)
|
||||
}
|
||||
out.Write(sf.FormatStatus("Pushing repository %s to %s (%d tags)", name, ep, len(localRepo)))
|
||||
out.Write(sf.FormatStatus("Pushing repository %s (%d tags)", localName, len(localRepo)))
|
||||
// For each image within the repo, push them
|
||||
for _, elem := range imgList {
|
||||
if _, exists := repoData.ImgList[elem.ID]; exists {
|
||||
out.Write(sf.FormatStatus("Image %s already on registry, skipping", name))
|
||||
out.Write(sf.FormatStatus("Image %s already pushed, skipping", elem.ID))
|
||||
continue
|
||||
} else if registryEp != "" && r.LookupRemoteImage(elem.ID, registryEp, repoData.Tokens) {
|
||||
fmt.Fprintf(out, "Image %s already on registry, skipping\n", name)
|
||||
} else if r.LookupRemoteImage(elem.ID, ep, repoData.Tokens) {
|
||||
out.Write(sf.FormatStatus("Image %s already pushed, skipping", elem.ID))
|
||||
continue
|
||||
}
|
||||
if err := srv.pushImage(r, out, name, elem.ID, ep, repoData.Tokens, sf); err != nil {
|
||||
if err := srv.pushImage(r, out, remoteName, elem.ID, ep, repoData.Tokens, sf); err != nil {
|
||||
// FIXME: Continue on error?
|
||||
return err
|
||||
}
|
||||
out.Write(sf.FormatStatus("Pushing tags for rev [%s] on {%s}", elem.ID, ep+"/repositories/"+srvName+"/tags/"+elem.Tag))
|
||||
if err := r.PushRegistryTag(srvName, elem.ID, elem.Tag, ep, repoData.Tokens); err != nil {
|
||||
out.Write(sf.FormatStatus("Pushing tags for rev [%s] on {%s}", elem.ID, ep+"repositories/"+remoteName+"/tags/"+elem.Tag))
|
||||
if err := r.PushRegistryTag(remoteName, elem.ID, elem.Tag, ep, repoData.Tokens); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if registryEp == "" {
|
||||
if _, err := r.PushImageJSONIndex(name, imgList, true, repoData.Endpoints); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := r.PushImageJSONIndex(indexEp, remoteName, imgList, true, repoData.Endpoints); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId, ep string, token []string, sf *utils.StreamFormatter) error {
|
||||
func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgID, ep string, token []string, sf *utils.StreamFormatter) error {
|
||||
out = utils.NewWriteFlusher(out)
|
||||
jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.graph.Root, imgId, "json"))
|
||||
jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.graph.Root, imgID, "json"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error while retreiving the path for {%s}: %s", imgId, err)
|
||||
return fmt.Errorf("Error while retreiving the path for {%s}: %s", imgID, err)
|
||||
}
|
||||
out.Write(sf.FormatStatus("Pushing %s", imgId))
|
||||
out.Write(sf.FormatStatus("Pushing %s", imgID))
|
||||
|
||||
// Make sure we have the image's checksum
|
||||
checksum, err := srv.getChecksum(imgId)
|
||||
checksum, err := srv.getChecksum(imgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imgData := ®istry.ImgData{
|
||||
ID: imgId,
|
||||
ID: imgID,
|
||||
Checksum: checksum,
|
||||
}
|
||||
|
||||
// Send the json
|
||||
if err := r.PushImageJSONRegistry(imgData, jsonRaw, ep, token); err != nil {
|
||||
if err == registry.ErrAlreadyExists {
|
||||
out.Write(sf.FormatStatus("Image %s already uploaded ; skipping", imgData.ID))
|
||||
out.Write(sf.FormatStatus("Image %s already pushed, skipping", imgData.ID))
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -675,11 +737,11 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId,
|
||||
// Retrieve the tarball to be sent
|
||||
var layerData *TempArchive
|
||||
// If the archive exists, use it
|
||||
file, err := os.Open(layerArchivePath(srv.runtime.graph.imageRoot(imgId)))
|
||||
file, err := os.Open(layerArchivePath(srv.runtime.graph.imageRoot(imgID)))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// If the archive does not exist, create one from the layer
|
||||
layerData, err = srv.runtime.graph.TempLayerArchive(imgId, Xz, out)
|
||||
layerData, err = srv.runtime.graph.TempLayerArchive(imgID, Xz, sf, out)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to generate layer archive: %s", err)
|
||||
}
|
||||
@@ -699,40 +761,48 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId,
|
||||
}
|
||||
|
||||
// Send the layer
|
||||
if err := r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("Pushing", "%v/%v (%v)"), sf), ep, token); err != nil {
|
||||
if err := r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("Pushing", "%8v/%v (%v)"), sf), ep, token); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME: Allow to interupt current push when new push of same image is done.
|
||||
func (srv *Server) ImagePush(name, endpoint string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error {
|
||||
if err := srv.poolAdd("push", name); err != nil {
|
||||
func (srv *Server) ImagePush(localName string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig) error {
|
||||
if err := srv.poolAdd("push", localName); err != nil {
|
||||
return err
|
||||
}
|
||||
defer srv.poolRemove("push", localName)
|
||||
|
||||
// Resolve the Repository name from fqn to endpoint + name
|
||||
endpoint, remoteName, err := registry.ResolveRepositoryName(localName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srv.poolRemove("push", name)
|
||||
|
||||
out = utils.NewWriteFlusher(out)
|
||||
img, err := srv.runtime.graph.Get(name)
|
||||
r, err2 := registry.NewRegistry(srv.runtime.root, authConfig)
|
||||
img, err := srv.runtime.graph.Get(localName)
|
||||
r, err2 := registry.NewRegistry(srv.runtime.root, authConfig, srv.versionInfos()...)
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
out.Write(sf.FormatStatus("The push refers to a repository [%s] (len: %d)", name, len(srv.runtime.repositories.Repositories[name])))
|
||||
reposLen := len(srv.runtime.repositories.Repositories[localName])
|
||||
out.Write(sf.FormatStatus("The push refers to a repository [%s] (len: %d)", localName, reposLen))
|
||||
// If it fails, try to get the repository
|
||||
if localRepo, exists := srv.runtime.repositories.Repositories[name]; exists {
|
||||
if err := srv.pushRepository(r, out, name, endpoint, localRepo, sf); err != nil {
|
||||
if localRepo, exists := srv.runtime.repositories.Repositories[localName]; exists {
|
||||
if err := srv.pushRepository(r, out, localName, remoteName, localRepo, endpoint, sf); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
out.Write(sf.FormatStatus("The push refers to an image: [%s]", name))
|
||||
if err := srv.pushImage(r, out, name, img.ID, endpoint, nil, sf); err != nil {
|
||||
|
||||
var token []string
|
||||
out.Write(sf.FormatStatus("The push refers to an image: [%s]", localName))
|
||||
if err := srv.pushImage(r, out, remoteName, img.ID, endpoint, token, sf); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -761,7 +831,7 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, sf.FormatProgress("Importing", "%v/%v (%v)"), sf)
|
||||
archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, sf.FormatProgress("Importing", "%8v/%v (%v)"), sf)
|
||||
}
|
||||
img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil)
|
||||
if err != nil {
|
||||
@@ -798,14 +868,16 @@ func (srv *Server) ContainerCreate(config *Config) (string, error) {
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
srv.LogEvent("create", container.ShortID())
|
||||
return container.ShortID(), nil
|
||||
}
|
||||
|
||||
func (srv *Server) ContainerRestart(name string, t int) error {
|
||||
if container := srv.runtime.Get(name); container != nil {
|
||||
if err := container.Restart(t); err != nil {
|
||||
return fmt.Errorf("Error restarting container %s: %s", name, err.Error())
|
||||
return fmt.Errorf("Error restarting container %s: %s", name, err)
|
||||
}
|
||||
srv.LogEvent("restart", name)
|
||||
} else {
|
||||
return fmt.Errorf("No such container: %s", name)
|
||||
}
|
||||
@@ -823,8 +895,9 @@ func (srv *Server) ContainerDestroy(name string, removeVolume bool) error {
|
||||
volumes[volumeId] = struct{}{}
|
||||
}
|
||||
if err := srv.runtime.Destroy(container); err != nil {
|
||||
return fmt.Errorf("Error destroying container %s: %s", name, err.Error())
|
||||
return fmt.Errorf("Error destroying container %s: %s", name, err)
|
||||
}
|
||||
srv.LogEvent("destroy", name)
|
||||
|
||||
if removeVolume {
|
||||
// Retrieve all volumes from all remaining containers
|
||||
@@ -859,7 +932,6 @@ func (srv *Server) deleteImageAndChildren(id string, imgs *[]APIRmi) error {
|
||||
if len(srv.runtime.repositories.ByID()[id]) != 0 {
|
||||
return ErrImageReferenced
|
||||
}
|
||||
|
||||
// If the image is not referenced but has children, go recursive
|
||||
referenced := false
|
||||
byParents, err := srv.runtime.graph.ByParent()
|
||||
@@ -892,6 +964,7 @@ func (srv *Server) deleteImageAndChildren(id string, imgs *[]APIRmi) error {
|
||||
return err
|
||||
}
|
||||
*imgs = append(*imgs, APIRmi{Deleted: utils.TruncateID(id)})
|
||||
srv.LogEvent("delete", utils.TruncateID(id))
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
@@ -912,38 +985,56 @@ func (srv *Server) deleteImageParents(img *Image, imgs *[]APIRmi) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (srv *Server) deleteImage(img *Image, repoName, tag string) (*[]APIRmi, error) {
|
||||
func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, error) {
|
||||
imgs := []APIRmi{}
|
||||
|
||||
//If delete by id, see if the id belong only to one repository
|
||||
if strings.Contains(img.ID, repoName) && tag == "" {
|
||||
for _, repoAndTag := range srv.runtime.repositories.ByID()[img.ID] {
|
||||
parsedRepo := strings.Split(repoAndTag, ":")[0]
|
||||
if strings.Contains(img.ID, repoName) {
|
||||
repoName = parsedRepo
|
||||
if len(srv.runtime.repositories.ByID()[img.ID]) == 1 && len(strings.Split(repoAndTag, ":")) > 1 {
|
||||
tag = strings.Split(repoAndTag, ":")[1]
|
||||
}
|
||||
} else if repoName != parsedRepo {
|
||||
// the id belongs to multiple repos, like base:latest and user:test,
|
||||
// in that case return conflict
|
||||
return imgs, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
//Untag the current image
|
||||
var imgs []APIRmi
|
||||
tagDeleted, err := srv.runtime.repositories.Delete(repoName, tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tagDeleted {
|
||||
imgs = append(imgs, APIRmi{Untagged: img.ShortID()})
|
||||
srv.LogEvent("untag", img.ShortID())
|
||||
}
|
||||
if len(srv.runtime.repositories.ByID()[img.ID]) == 0 {
|
||||
if err := srv.deleteImageAndChildren(img.ID, &imgs); err != nil {
|
||||
if err != ErrImageReferenced {
|
||||
return &imgs, err
|
||||
return imgs, err
|
||||
}
|
||||
} else if err := srv.deleteImageParents(img, &imgs); err != nil {
|
||||
if err != ErrImageReferenced {
|
||||
return &imgs, err
|
||||
return imgs, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return &imgs, nil
|
||||
return imgs, nil
|
||||
}
|
||||
|
||||
func (srv *Server) ImageDelete(name string, autoPrune bool) (*[]APIRmi, error) {
|
||||
func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
|
||||
img, err := srv.runtime.repositories.LookupImage(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("No such image: %s", name)
|
||||
}
|
||||
if !autoPrune {
|
||||
if err := srv.runtime.graph.Delete(img.ID); err != nil {
|
||||
return nil, fmt.Errorf("Error deleting image %s: %s", name, err.Error())
|
||||
return nil, fmt.Errorf("Error deleting image %s: %s", name, err)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -958,7 +1049,7 @@ func (srv *Server) ImageDelete(name string, autoPrune bool) (*[]APIRmi, error) {
|
||||
return srv.deleteImage(img, name, tag)
|
||||
}
|
||||
|
||||
func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error) {
|
||||
func (srv *Server) ImageGetCached(imgID string, config *Config) (*Image, error) {
|
||||
|
||||
// Retrieve all images
|
||||
images, err := srv.runtime.graph.All()
|
||||
@@ -976,7 +1067,7 @@ func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error)
|
||||
}
|
||||
|
||||
// Loop on the children of the given image and check the config
|
||||
for elem := range imageMap[imgId] {
|
||||
for elem := range imageMap[imgID] {
|
||||
img, err := srv.runtime.graph.Get(elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -991,8 +1082,9 @@ func (srv *Server) ImageGetCached(imgId string, config *Config) (*Image, error)
|
||||
func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
|
||||
if container := srv.runtime.Get(name); container != nil {
|
||||
if err := container.Start(hostConfig); err != nil {
|
||||
return fmt.Errorf("Error starting container %s: %s", name, err.Error())
|
||||
return fmt.Errorf("Error starting container %s: %s", name, err)
|
||||
}
|
||||
srv.LogEvent("start", name)
|
||||
} else {
|
||||
return fmt.Errorf("No such container: %s", name)
|
||||
}
|
||||
@@ -1002,8 +1094,9 @@ func (srv *Server) ContainerStart(name string, hostConfig *HostConfig) error {
|
||||
func (srv *Server) ContainerStop(name string, t int) error {
|
||||
if container := srv.runtime.Get(name); container != nil {
|
||||
if err := container.Stop(t); err != nil {
|
||||
return fmt.Errorf("Error stopping container %s: %s", name, err.Error())
|
||||
return fmt.Errorf("Error stopping container %s: %s", name, err)
|
||||
}
|
||||
srv.LogEvent("stop", name)
|
||||
} else {
|
||||
return fmt.Errorf("No such container: %s", name)
|
||||
}
|
||||
@@ -1031,20 +1124,41 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std
|
||||
}
|
||||
//logs
|
||||
if logs {
|
||||
if stdout {
|
||||
cLog, err := container.ReadLog("stdout")
|
||||
if err != nil {
|
||||
utils.Debugf("Error reading logs (stdout): %s", err)
|
||||
} else if _, err := io.Copy(out, cLog); err != nil {
|
||||
utils.Debugf("Error streaming logs (stdout): %s", err)
|
||||
cLog, err := container.ReadLog("json")
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
// Legacy logs
|
||||
utils.Debugf("Old logs format")
|
||||
if stdout {
|
||||
cLog, err := container.ReadLog("stdout")
|
||||
if err != nil {
|
||||
utils.Debugf("Error reading logs (stdout): %s", err)
|
||||
} else if _, err := io.Copy(out, cLog); err != nil {
|
||||
utils.Debugf("Error streaming logs (stdout): %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if stderr {
|
||||
cLog, err := container.ReadLog("stderr")
|
||||
if err != nil {
|
||||
utils.Debugf("Error reading logs (stderr): %s", err)
|
||||
} else if _, err := io.Copy(out, cLog); err != nil {
|
||||
utils.Debugf("Error streaming logs (stderr): %s", err)
|
||||
if stderr {
|
||||
cLog, err := container.ReadLog("stderr")
|
||||
if err != nil {
|
||||
utils.Debugf("Error reading logs (stderr): %s", err)
|
||||
} else if _, err := io.Copy(out, cLog); err != nil {
|
||||
utils.Debugf("Error streaming logs (stderr): %s", err)
|
||||
}
|
||||
}
|
||||
} else if err != nil {
|
||||
utils.Debugf("Error reading logs (json): %s", err)
|
||||
} else {
|
||||
dec := json.NewDecoder(cLog)
|
||||
for {
|
||||
var l utils.JSONLog
|
||||
if err := dec.Decode(&l); err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
utils.Debugf("Error streaming logs: %s", err)
|
||||
break
|
||||
}
|
||||
if (l.Stream == "stdout" && stdout) || (l.Stream == "stderr" && stderr) {
|
||||
fmt.Fprintf(out, "%s", l.Log)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1114,18 +1228,33 @@ func NewServer(flGraphPath string, autoRestart, enableCors bool, dns ListOpts) (
|
||||
srv := &Server{
|
||||
runtime: runtime,
|
||||
enableCors: enableCors,
|
||||
lock: &sync.Mutex{},
|
||||
pullingPool: make(map[string]struct{}),
|
||||
pushingPool: make(map[string]struct{}),
|
||||
events: make([]utils.JSONMessage, 0, 64), //only keeps the 64 last events
|
||||
listeners: make(map[string]chan utils.JSONMessage),
|
||||
}
|
||||
runtime.srv = srv
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
func (srv *Server) LogEvent(action, id string) {
|
||||
now := time.Now().Unix()
|
||||
jm := utils.JSONMessage{Status: action, ID: id, Time: now}
|
||||
srv.events = append(srv.events, jm)
|
||||
for _, c := range srv.listeners {
|
||||
select { // non blocking channel
|
||||
case c <- jm:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
sync.Mutex
|
||||
runtime *Runtime
|
||||
enableCors bool
|
||||
lock *sync.Mutex
|
||||
pullingPool map[string]struct{}
|
||||
pushingPool map[string]struct{}
|
||||
events []utils.JSONMessage
|
||||
listeners map[string]chan utils.JSONMessage
|
||||
}
|
||||
|
||||
181
server_test.go
@@ -1,18 +1,23 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestContainerTagImageDelete(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
initialImages, err := srv.Images(false, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := srv.runtime.repositories.Set("utest", "tag1", unitTestImageName, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -25,8 +30,8 @@ func TestContainerTagImageDelete(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(images) != 3 {
|
||||
t.Errorf("Excepted 3 images, %d found", len(images))
|
||||
if len(images) != len(initialImages)+2 {
|
||||
t.Errorf("Expected %d images, %d found", len(initialImages)+2, len(images))
|
||||
}
|
||||
|
||||
if _, err := srv.ImageDelete("utest/docker:tag2", true); err != nil {
|
||||
@@ -38,8 +43,8 @@ func TestContainerTagImageDelete(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(images) != 2 {
|
||||
t.Errorf("Excepted 2 images, %d found", len(images))
|
||||
if len(images) != len(initialImages)+1 {
|
||||
t.Errorf("Expected %d images, %d found", len(initialImages)+1, len(images))
|
||||
}
|
||||
|
||||
if _, err := srv.ImageDelete("utest:tag1", true); err != nil {
|
||||
@@ -51,16 +56,13 @@ func TestContainerTagImageDelete(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(images) != 1 {
|
||||
t.Errorf("Excepted 1 image, %d found", len(images))
|
||||
if len(images) != len(initialImages) {
|
||||
t.Errorf("Expected %d image, %d found", len(initialImages), len(images))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateRm(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -89,11 +91,29 @@ func TestCreateRm(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
func TestCommit(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
config, _, _, err := ParseRun([]string{GetTestImage(runtime).ID, "/bin/cat"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id, err := srv.ContainerCreate(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := srv.ContainerCommit(id, "testrepo", "testtag", "", "", config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
|
||||
srv := &Server{runtime: runtime}
|
||||
@@ -149,11 +169,9 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRunWithTooLowMemoryLimit(t *testing.T) {
|
||||
runtime, err := newTestRuntime()
|
||||
var err error
|
||||
runtime := mkRuntime(t)
|
||||
srv := &Server{runtime: runtime}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer nuke(runtime)
|
||||
// Try to create a container with a memory limit of 1 byte less than the minimum allowed limit.
|
||||
_, err = srv.ContainerCreate(
|
||||
@@ -169,3 +187,126 @@ func TestRunWithTooLowMemoryLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLogEvent(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
srv := &Server{
|
||||
runtime: runtime,
|
||||
events: make([]utils.JSONMessage, 0, 64),
|
||||
listeners: make(map[string]chan utils.JSONMessage),
|
||||
}
|
||||
|
||||
srv.LogEvent("fakeaction", "fakeid")
|
||||
|
||||
listener := make(chan utils.JSONMessage)
|
||||
srv.Lock()
|
||||
srv.listeners["test"] = listener
|
||||
srv.Unlock()
|
||||
|
||||
srv.LogEvent("fakeaction2", "fakeid")
|
||||
|
||||
if len(srv.events) != 2 {
|
||||
t.Fatalf("Expected 2 events, found %d", len(srv.events))
|
||||
}
|
||||
go func() {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
srv.LogEvent("fakeaction3", "fakeid")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
srv.LogEvent("fakeaction4", "fakeid")
|
||||
}()
|
||||
|
||||
setTimeout(t, "Listening for events timed out", 2*time.Second, func() {
|
||||
for i := 2; i < 4; i++ {
|
||||
event := <-listener
|
||||
if event != srv.events[i] {
|
||||
t.Fatalf("Event received it different than expected")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestRmi(t *testing.T) {
|
||||
runtime := mkRuntime(t)
|
||||
defer nuke(runtime)
|
||||
srv := &Server{runtime: runtime}
|
||||
|
||||
initialImages, err := srv.Images(false, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
config, hostConfig, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
containerID, err := srv.ContainerCreate(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
//To remove
|
||||
err = srv.ContainerStart(containerID, hostConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
imageID, err := srv.ContainerCommit(containerID, "test", "", "", "", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = srv.ContainerTag(imageID, "test", "0.1", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
containerID, err = srv.ContainerCreate(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
//To remove
|
||||
err = srv.ContainerStart(containerID, hostConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = srv.ContainerCommit(containerID, "test", "", "", "", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
images, err := srv.Images(false, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(images)-len(initialImages) != 2 {
|
||||
t.Fatalf("Expected 2 new images, found %d.", len(images)-len(initialImages))
|
||||
}
|
||||
|
||||
_, err = srv.ImageDelete(imageID, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
images, err = srv.Images(false, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(images)-len(initialImages) != 1 {
|
||||
t.Fatalf("Expected 1 new image, found %d.", len(images)-len(initialImages))
|
||||
}
|
||||
|
||||
for _, image := range images {
|
||||
if strings.Contains(unitTestImageID, image.ID) {
|
||||
continue
|
||||
}
|
||||
if image.Repository == "" {
|
||||
t.Fatalf("Expected tagged image, got untagged one.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||