mirror of
https://github.com/clearlinux/docker.git
synced 2026-09-06 21:51:33 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa7b24f2c3 | ||
|
|
380129d0d7 | ||
|
|
b1d20c483a | ||
|
|
997336fd95 | ||
|
|
624b944896 | ||
|
|
2eb26991f4 | ||
|
|
94fbcea7a3 | ||
|
|
494bea9fba | ||
|
|
0d26b7cc6d | ||
|
|
9faf0254ef | ||
|
|
4d0b88c52f | ||
|
|
98dd982586 | ||
|
|
8c7915fcde | ||
|
|
05a09675c3 | ||
|
|
b63c10558e | ||
|
|
d4c2d0c57f | ||
|
|
487af281bf | ||
|
|
7db55a1807 | ||
|
|
abc1346777 | ||
|
|
39bcc3a3e5 | ||
|
|
26feb09fac | ||
|
|
fc39f9c78d | ||
|
|
f3b2c93b9f | ||
|
|
dad2fcb199 | ||
|
|
366fe67946 | ||
|
|
7cb6871355 | ||
|
|
99082de9ad | ||
|
|
37db53bf7a | ||
|
|
075e1bc1c3 | ||
|
|
018e75a6e4 | ||
|
|
55533693be | ||
|
|
c1ee94a343 | ||
|
|
676308b853 | ||
|
|
3231033a80 | ||
|
|
a67d06fd43 | ||
|
|
7afb98ad5d | ||
|
|
57564d91a4 | ||
|
|
101c749b65 | ||
|
|
a20f4ce291 | ||
|
|
3a70ca3c67 | ||
|
|
d1fc32e265 | ||
|
|
31bd4a19c9 | ||
|
|
4bcc7e283f | ||
|
|
2a39635d30 | ||
|
|
5a1e4a1092 | ||
|
|
0d4d7e4a28 | ||
|
|
f1975cbc7c | ||
|
|
93d6adf8a1 | ||
|
|
1480168e9f | ||
|
|
17112704b9 | ||
|
|
5073554ca6 | ||
|
|
a7d116f1b0 | ||
|
|
31a9c97d7d | ||
|
|
f945edb3e0 | ||
|
|
a0392324f1 | ||
|
|
fcf37be2b1 | ||
|
|
d939fe758a | ||
|
|
b95f6c183b | ||
|
|
25c519e829 | ||
|
|
73ced63680 | ||
|
|
2ec1b697c1 | ||
|
|
ebf5d4657d | ||
|
|
972c894931 | ||
|
|
c4a00d549d | ||
|
|
a2afb2b1e3 | ||
|
|
be22d7ac2d | ||
|
|
6ae05936e1 | ||
|
|
b7550cd456 | ||
|
|
feda8fbb21 | ||
|
|
41870a42be | ||
|
|
617edd89f4 | ||
|
|
860c13b788 | ||
|
|
2b0776c883 | ||
|
|
d9753ba20d | ||
|
|
e0a076d486 | ||
|
|
bd8c9dc239 | ||
|
|
0d70706b4b | ||
|
|
6b363b81de | ||
|
|
ac63d925d2 | ||
|
|
a02f67be5b | ||
|
|
13eb477b62 | ||
|
|
6aecdb4f8e | ||
|
|
fd1b563b4f | ||
|
|
2837a36bd7 | ||
|
|
49c43004a7 | ||
|
|
0c6b137f06 | ||
|
|
e350df5b2c | ||
|
|
7bfc78b038 | ||
|
|
a30fd7a962 | ||
|
|
1d10c55aec | ||
|
|
1eba59eb24 | ||
|
|
ca11b77471 | ||
|
|
353b7c8ec7 | ||
|
|
6200002669 | ||
|
|
33fa175abf | ||
|
|
cdf8a55670 | ||
|
|
6d59a56675 | ||
|
|
a4befff533 | ||
|
|
b4e2f5ed96 | ||
|
|
c9c271858a | ||
|
|
c071cd7c7c | ||
|
|
283ee10886 | ||
|
|
1c5a4e0900 | ||
|
|
ad7279e480 | ||
|
|
3cc79e7818 | ||
|
|
c9e359cf97 | ||
|
|
8c38a3d732 | ||
|
|
752dd707ac | ||
|
|
6cbb8e070d | ||
|
|
84146719d8 | ||
|
|
57f6b3e1ec | ||
|
|
7d1b2ebde8 | ||
|
|
da63a93e89 | ||
|
|
391c35c822 | ||
|
|
63503cafe4 | ||
|
|
c6595b3ee8 | ||
|
|
99423e7e1e | ||
|
|
491deae9b8 | ||
|
|
64579f51fc | ||
|
|
b06311a72e | ||
|
|
136631df46 | ||
|
|
bcfd6a653b | ||
|
|
10ec205b77 | ||
|
|
3de3719290 | ||
|
|
e608312677 | ||
|
|
af5ced62ca | ||
|
|
631fadc0b9 | ||
|
|
91a2f22aca | ||
|
|
e4a09cd79d | ||
|
|
8830653977 | ||
|
|
18a0eba72d | ||
|
|
c58c70b8bd | ||
|
|
0771eb32dc | ||
|
|
d42326d927 | ||
|
|
96b52545ab | ||
|
|
7df5493071 | ||
|
|
c19e0fe7e2 | ||
|
|
a44f065f17 | ||
|
|
fcddecc828 | ||
|
|
01995ebebb | ||
|
|
1a249a5feb | ||
|
|
2c882a482e | ||
|
|
b94f2c4c6d | ||
|
|
1e2ce72ffe | ||
|
|
df9650eebb | ||
|
|
58ef92f89e | ||
|
|
8a4d2d6f7f | ||
|
|
8595a4ff7a | ||
|
|
2e5d35c1f1 | ||
|
|
57e0cbb991 | ||
|
|
9694209241 | ||
|
|
29af9c14e4 | ||
|
|
7321067176 | ||
|
|
e033425f0b | ||
|
|
5ffbc8dc82 | ||
|
|
e94d772910 | ||
|
|
a9ff2fdfac | ||
|
|
f4f1e4db70 | ||
|
|
44842ea3d8 | ||
|
|
17ab516fde | ||
|
|
b74e507245 | ||
|
|
9fa4bea03b | ||
|
|
dfd6fcb548 | ||
|
|
7b13212076 | ||
|
|
aa3bc6559b | ||
|
|
d613f11217 | ||
|
|
ea59aa8cb5 | ||
|
|
e9aa6489a6 | ||
|
|
a110ce2f28 | ||
|
|
5e9b3727b8 | ||
|
|
93f6cf0351 | ||
|
|
6ba1949e6a | ||
|
|
7afc49b40b | ||
|
|
55dc4f2b94 | ||
|
|
8b3f2381d0 | ||
|
|
cc3e94b9ba | ||
|
|
2c90fde982 | ||
|
|
93da07a8dc | ||
|
|
983b4fc3bf | ||
|
|
c74e8b544d | ||
|
|
99a864431d | ||
|
|
3c49cb17fb | ||
|
|
2dc21af70b | ||
|
|
fb650d1e6d | ||
|
|
7dbab337dd | ||
|
|
a34dd21611 | ||
|
|
90e97960fa | ||
|
|
6856a6b110 | ||
|
|
33d6b20c13 | ||
|
|
94715e8e64 | ||
|
|
0ca010695c | ||
|
|
09ad385f64 | ||
|
|
2767509894 | ||
|
|
414ccee23a | ||
|
|
5d9cfde0df | ||
|
|
478fdaf933 | ||
|
|
860ab469cc | ||
|
|
b36f630817 | ||
|
|
95f86da641 | ||
|
|
01022a305d | ||
|
|
bc9f5cdeb5 | ||
|
|
e907df8d93 | ||
|
|
b386bce1f1 | ||
|
|
7a34f13433 | ||
|
|
f8f36ff320 | ||
|
|
d687c5b339 | ||
|
|
7d78dc33b1 | ||
|
|
b87daf6d69 | ||
|
|
ab3e34e187 | ||
|
|
45a239c168 | ||
|
|
140e6abb17 | ||
|
|
abbfc7e828 | ||
|
|
dc296903f0 | ||
|
|
3f136dc0e0 | ||
|
|
6e0f072e36 | ||
|
|
8891bb52de | ||
|
|
7e12911f62 | ||
|
|
bd373712d0 | ||
|
|
5cdb9c8aca | ||
|
|
5ab09f2f71 | ||
|
|
89ec17d113 | ||
|
|
bc684fae64 | ||
|
|
e86d87e1ce | ||
|
|
8733cd7c0b | ||
|
|
f34679d0a9 | ||
|
|
c9ca37dfe9 | ||
|
|
90da088491 | ||
|
|
872db07119 | ||
|
|
fba37a038d | ||
|
|
5101173e1f | ||
|
|
5e20b0027c | ||
|
|
eb79dc14fe | ||
|
|
92105ea0fa | ||
|
|
20b0841c1b | ||
|
|
61eab75939 | ||
|
|
78f0a914ee | ||
|
|
b4efcd53e0 | ||
|
|
c9f3fd3fc7 | ||
|
|
d55e3fea72 | ||
|
|
d745067487 | ||
|
|
66c8f87e89 | ||
|
|
231e07ded4 | ||
|
|
5240e5f713 | ||
|
|
1c11d7f93e | ||
|
|
8d056423f8 | ||
|
|
af0781974d | ||
|
|
69f9d488dc | ||
|
|
d787937957 | ||
|
|
7a5e3df162 | ||
|
|
fa27580cff | ||
|
|
f2029f7be1 | ||
|
|
77781440f1 | ||
|
|
51dd68d659 | ||
|
|
55235e121e | ||
|
|
6e28d11d1f | ||
|
|
bd30746e07 | ||
|
|
4d0527856c | ||
|
|
6215422286 | ||
|
|
07099b6256 | ||
|
|
042b642d40 | ||
|
|
0ea5160d2a | ||
|
|
b4813f2841 | ||
|
|
8f4b477c32 | ||
|
|
047ce47d92 | ||
|
|
e47415d5f5 | ||
|
|
a49de2c467 | ||
|
|
3c1212ca30 | ||
|
|
6b94f2d9be | ||
|
|
ba663eac3a | ||
|
|
1b95590d06 | ||
|
|
74212a1565 | ||
|
|
0af135e906 | ||
|
|
07fce305f7 | ||
|
|
cd6b903825 | ||
|
|
22f373aeda | ||
|
|
bafad8cdc4 | ||
|
|
825ca10dfd | ||
|
|
aa2d6dbc0c | ||
|
|
1b6546b840 | ||
|
|
7dba5024e8 | ||
|
|
d48492a12e | ||
|
|
41a553ca35 | ||
|
|
5514afcd88 | ||
|
|
60341f80d7 | ||
|
|
bec676e2de | ||
|
|
6b04d597ee | ||
|
|
4909a70204 | ||
|
|
e9b4cafd8d | ||
|
|
8266c381d6 | ||
|
|
a5c5dc121c | ||
|
|
78ac75fe00 | ||
|
|
ca602cd1e5 | ||
|
|
69aa07af1e | ||
|
|
867ffca84f | ||
|
|
f46de04af6 | ||
|
|
d037007658 | ||
|
|
aa49632fef | ||
|
|
49e61f62ce | ||
|
|
06229a4b76 | ||
|
|
cc39d579f5 | ||
|
|
066330fc96 | ||
|
|
fdad41f5b9 | ||
|
|
e0fd96f850 | ||
|
|
c4ce396f46 | ||
|
|
bd54a73c42 | ||
|
|
4180b87514 | ||
|
|
03c07617cc | ||
|
|
80f3272ee9 | ||
|
|
8031c23b0f | ||
|
|
8652830661 | ||
|
|
4cb2cfed9f | ||
|
|
5d2a62d8de | ||
|
|
e6a084f4f8 | ||
|
|
58588009c0 | ||
|
|
503d124677 | ||
|
|
3490042836 | ||
|
|
63a4ba229c | ||
|
|
103ae23504 | ||
|
|
0fc304ce32 | ||
|
|
631ea726e4 | ||
|
|
5395cecc48 | ||
|
|
90dadea84d | ||
|
|
b1496effe3 | ||
|
|
c5cdbc376f | ||
|
|
8891e912b4 | ||
|
|
27cca4c70c | ||
|
|
4c282b979b | ||
|
|
ceffc9ea1d | ||
|
|
eccc44fad6 | ||
|
|
f77ae9b4f3 | ||
|
|
531f5907d6 | ||
|
|
1f2d75774a | ||
|
|
54b287bbc8 | ||
|
|
32fdcaa419 | ||
|
|
52db7b8cb7 | ||
|
|
8ea7242250 | ||
|
|
f34d0e55f3 | ||
|
|
57b9467f45 | ||
|
|
f4db3985d9 | ||
|
|
b5ef212ec1 | ||
|
|
bfacdfdccf | ||
|
|
294f33b37a | ||
|
|
bbca4867f8 | ||
|
|
970ebaa887 | ||
|
|
65d316e50d | ||
|
|
6bc483fa59 | ||
|
|
5ebe86ccf9 | ||
|
|
2970ba4877 | ||
|
|
3a14eb066c | ||
|
|
e13b1fc05f | ||
|
|
19c8e74fd3 | ||
|
|
3100afa0e1 | ||
|
|
a713413293 | ||
|
|
8162c6eedd | ||
|
|
a0338ff04b | ||
|
|
74fdadc86c | ||
|
|
ef6b78f7db | ||
|
|
c3045f563d | ||
|
|
ff02bea883 | ||
|
|
ba57d3d9e6 | ||
|
|
711fb3e19d | ||
|
|
c18b38f912 | ||
|
|
b0fb0055d2 | ||
|
|
63bd4ad9d6 | ||
|
|
42a77de3d3 | ||
|
|
4184cccb0f | ||
|
|
1219e458d1 | ||
|
|
fae72c83be | ||
|
|
0af7b5f83d | ||
|
|
c2496d97cc | ||
|
|
4949e070fb | ||
|
|
e92a9e0b53 | ||
|
|
a7d8c732b1 | ||
|
|
419b9fe164 | ||
|
|
3e1c1567ea | ||
|
|
d82bb603af | ||
|
|
2b9d8248d6 | ||
|
|
403df1765a | ||
|
|
4398108433 | ||
|
|
335e82f3f7 | ||
|
|
1063b438eb | ||
|
|
3bae02cbe3 | ||
|
|
38bce17904 | ||
|
|
3a177ccd3a | ||
|
|
475131cd4a | ||
|
|
4749b884fe | ||
|
|
900d54b48b | ||
|
|
c0517857f6 | ||
|
|
372f9bb58b | ||
|
|
f60c8e9e61 | ||
|
|
3369b4f6f0 | ||
|
|
5931669343 | ||
|
|
fc637b5275 | ||
|
|
ac3eecf3db | ||
|
|
331200cbaa | ||
|
|
a0dad3dfb2 | ||
|
|
f906f31877 | ||
|
|
704b97d1c4 | ||
|
|
2519872d77 | ||
|
|
5ef1126669 | ||
|
|
d09e682c46 | ||
|
|
380153f0d7 | ||
|
|
77237be0e2 | ||
|
|
030676444a | ||
|
|
da40d9b7a5 | ||
|
|
7978b32127 | ||
|
|
2095e22121 | ||
|
|
533916fa6b | ||
|
|
0f26195a8d | ||
|
|
fe68df36fc | ||
|
|
81c7d28b84 | ||
|
|
c7a2e86b51 | ||
|
|
d0a0e91f1f | ||
|
|
4cfe806db2 | ||
|
|
0a7cd70924 | ||
|
|
81e78db507 | ||
|
|
a6085fd430 | ||
|
|
3a1385702c | ||
|
|
158e3068bd | ||
|
|
2d84b877bd | ||
|
|
96f1a99034 | ||
|
|
487a417d9f | ||
|
|
1d21f75fa4 | ||
|
|
caa5769928 | ||
|
|
dacf909870 | ||
|
|
d082381a93 | ||
|
|
ec5b97ce9b | ||
|
|
7a5db6df99 | ||
|
|
7dde97640f | ||
|
|
7756bcc7ab | ||
|
|
c028bb239f | ||
|
|
2fb63aba0b | ||
|
|
32bc865879 | ||
|
|
3fb913ab77 | ||
|
|
9503afbc91 | ||
|
|
ff28b0b919 | ||
|
|
5b293f1596 | ||
|
|
228c6a374b | ||
|
|
4fbc47e801 | ||
|
|
771ed23915 | ||
|
|
1082246262 | ||
|
|
5a0ef08c94 | ||
|
|
b3ee9ac74e | ||
|
|
c765134ac9 | ||
|
|
2481e08e41 | ||
|
|
97283fa985 | ||
|
|
7365225957 | ||
|
|
2ed10eae5b | ||
|
|
be326b0ece | ||
|
|
0758acfb03 | ||
|
|
2819d9b406 | ||
|
|
5b0d4cf296 | ||
|
|
386d300a6e | ||
|
|
e4ab996b9d | ||
|
|
d512294382 | ||
|
|
a4d57d8a85 | ||
|
|
0fd37bd7ac | ||
|
|
9380e8cbe7 | ||
|
|
03697f0a93 | ||
|
|
bb6217c055 | ||
|
|
6b65e8817c | ||
|
|
1403372963 | ||
|
|
683038bf57 | ||
|
|
9fbae59244 | ||
|
|
92cba0845c | ||
|
|
c71edef8d5 | ||
|
|
56bb7ce780 | ||
|
|
604a975303 | ||
|
|
1df87acb33 | ||
|
|
b9024174be | ||
|
|
be3aa1eba0 | ||
|
|
455e837e20 | ||
|
|
0a4b39b6a4 | ||
|
|
29ecc95c31 | ||
|
|
5743cc3423 | ||
|
|
d84a070e47 | ||
|
|
4e12484ea1 | ||
|
|
2c185e25c2 | ||
|
|
21341e9e13 | ||
|
|
699bc47137 | ||
|
|
885cda1ae2 | ||
|
|
9e1a9a7d98 | ||
|
|
2f23e204d9 | ||
|
|
ea7b8ea03f | ||
|
|
d0cbc54f23 | ||
|
|
a491d204a0 | ||
|
|
314bf61889 | ||
|
|
0d118ffbf8 | ||
|
|
4002b4623c | ||
|
|
7407664c66 | ||
|
|
588090c49b | ||
|
|
c838a4be29 | ||
|
|
ceddf4c0e8 | ||
|
|
a1c5f268e5 | ||
|
|
c47ab1425f | ||
|
|
75ba7a9b32 | ||
|
|
f1e072c8d5 | ||
|
|
29f1ed833c | ||
|
|
4d109f6158 | ||
|
|
3472c006c4 | ||
|
|
3853a9c612 | ||
|
|
ddb2086ca9 | ||
|
|
1b31a80eb7 | ||
|
|
a091d949ac | ||
|
|
9dc82e6102 | ||
|
|
1cc55fda3d | ||
|
|
324010ad66 | ||
|
|
8f75de2d4e | ||
|
|
1473374a2a | ||
|
|
b7ff33f73c | ||
|
|
ebc05cbbea | ||
|
|
5d8e80ba8d | ||
|
|
d0e2d9ec39 | ||
|
|
61b675d3bb | ||
|
|
76429cc11f | ||
|
|
a377844998 | ||
|
|
24c00c8508 | ||
|
|
d8a76a02dc | ||
|
|
319a8a241e | ||
|
|
b752e7402a | ||
|
|
86f20e561f | ||
|
|
30519330c7 | ||
|
|
6dd8eb9520 | ||
|
|
e4c79736bf | ||
|
|
e1bb99d925 | ||
|
|
ed92c3f964 | ||
|
|
12ee68aabe | ||
|
|
c47ebe7a35 | ||
|
|
f033ce3ee9 | ||
|
|
9ff7bbe0ac | ||
|
|
8365abb200 | ||
|
|
5cd0f0824d | ||
|
|
c550ad5900 | ||
|
|
8a4b79ca50 | ||
|
|
4ac6375790 | ||
|
|
e60543400d | ||
|
|
3cff015169 | ||
|
|
f39e0567b6 | ||
|
|
e88487b321 | ||
|
|
9a7c5be7d1 | ||
|
|
ac6ec9df1d | ||
|
|
a781de0c10 | ||
|
|
7aed2130f9 | ||
|
|
b82778b293 | ||
|
|
ccbaf4bc6e | ||
|
|
93a7c84b6f | ||
|
|
c7bc929e01 | ||
|
|
82675ee359 | ||
|
|
1b9b11db4f | ||
|
|
7ee8fd5ecf | ||
|
|
e52382292f | ||
|
|
95caf8c485 | ||
|
|
9b3c0e65da | ||
|
|
9870a2bcae | ||
|
|
1646e5d69a | ||
|
|
615f211084 | ||
|
|
56a39ca5d3 | ||
|
|
4162309d11 | ||
|
|
4b5b3b4321 | ||
|
|
06bc4e0752 | ||
|
|
8273cb4b9b | ||
|
|
36608696e1 | ||
|
|
31351d08a3 | ||
|
|
261dc5e2f6 | ||
|
|
204e080932 | ||
|
|
7d97a5f476 | ||
|
|
c11660169a | ||
|
|
5948b105e7 | ||
|
|
7a5ddd5df8 | ||
|
|
9f036fc6ee | ||
|
|
c92e13f678 | ||
|
|
68bb56a4a5 | ||
|
|
e5e8669c72 | ||
|
|
8130768014 | ||
|
|
ae37f2b88f | ||
|
|
ca015b8885 | ||
|
|
ee7313472c | ||
|
|
67e3f7482f | ||
|
|
1476f295ac | ||
|
|
dca52c47a4 | ||
|
|
f9b3147e2c | ||
|
|
ffe885ec0e | ||
|
|
4ae27be2cd | ||
|
|
f565862abc | ||
|
|
ff08357c9b | ||
|
|
07f9d48696 | ||
|
|
ade6d780d6 | ||
|
|
6ae07e2410 | ||
|
|
7a8ea91392 | ||
|
|
0d67b420b5 | ||
|
|
1501c342d8 | ||
|
|
9fc6058aa1 | ||
|
|
41d6ab6318 | ||
|
|
6cd1061a5b | ||
|
|
6d238c6fba | ||
|
|
b0e9d370c2 | ||
|
|
f84bcc6bd0 | ||
|
|
352909dd54 | ||
|
|
be8cea9856 | ||
|
|
2e61e8267e | ||
|
|
50b580cfec | ||
|
|
dae6af1d1c | ||
|
|
47917135da | ||
|
|
7c19499c63 | ||
|
|
905ae7bb28 | ||
|
|
5702029a0f | ||
|
|
1583e7af41 | ||
|
|
f861bfd9ff | ||
|
|
c5f55a233d | ||
|
|
3b3f0fa085 | ||
|
|
8175c666a3 | ||
|
|
fa5bce2859 | ||
|
|
4eaacb6b88 | ||
|
|
ed8b017ee0 | ||
|
|
c6197058a8 | ||
|
|
b45e8fa945 | ||
|
|
58955a30ff | ||
|
|
3957d72f9c | ||
|
|
5b8a6eb05f | ||
|
|
01d1615001 | ||
|
|
d736754a47 | ||
|
|
c0471ee35a | ||
|
|
9c8b59c1b0 | ||
|
|
5bdf2cf459 | ||
|
|
b6e1cfc075 | ||
|
|
4fc8edd0df | ||
|
|
fb51a330bb | ||
|
|
2a230729da | ||
|
|
d91d381856 | ||
|
|
37309f37fa | ||
|
|
88c6017644 | ||
|
|
b3b6e05f26 | ||
|
|
47de2e3269 | ||
|
|
f976014410 | ||
|
|
781a47e3f3 | ||
|
|
0bde827c3f | ||
|
|
076ac1d7d2 | ||
|
|
5105981431 | ||
|
|
9d6f295d5d | ||
|
|
12d58a2688 | ||
|
|
f77cde6a93 | ||
|
|
f00e643576 | ||
|
|
3b4a1c54d8 | ||
|
|
4f0fbb885e | ||
|
|
7ebd49c49a | ||
|
|
b39fb160c6 | ||
|
|
dfbb291c40 | ||
|
|
97a3807901 | ||
|
|
804f028862 | ||
|
|
32740543da | ||
|
|
66ccd55ed4 | ||
|
|
8a4f1ad837 | ||
|
|
b93787e6e0 | ||
|
|
b1677f9d09 | ||
|
|
e20a95f24c | ||
|
|
07d93c6e34 | ||
|
|
b5a69da5b6 | ||
|
|
214ab777f4 | ||
|
|
848e837698 | ||
|
|
1a1ee73e38 | ||
|
|
88326e9b91 | ||
|
|
b2ba1a9ce5 | ||
|
|
6bb27f18d1 | ||
|
|
e7d9854414 | ||
|
|
c04230c42b | ||
|
|
064b5f870d | ||
|
|
222a6f4401 | ||
|
|
f3ff323fb3 | ||
|
|
8344b6d736 | ||
|
|
21059af3ac | ||
|
|
94e6dc9781 | ||
|
|
319f551614 | ||
|
|
fe5ab5b058 | ||
|
|
5ba11e6890 | ||
|
|
d689a5e1e2 | ||
|
|
7810070630 | ||
|
|
d53db040c8 | ||
|
|
00c1668011 | ||
|
|
cdfdbe9bc6 | ||
|
|
c3f247860a | ||
|
|
eae5cf1e20 | ||
|
|
358758e99f | ||
|
|
2944d8ca3e | ||
|
|
c3d91263a8 | ||
|
|
1a99f36580 | ||
|
|
7c4f7780a1 | ||
|
|
9216ced003 | ||
|
|
e8762bfe39 | ||
|
|
e80d075633 | ||
|
|
e855c4b921 | ||
|
|
840ed5ace2 | ||
|
|
0c67dcb0df | ||
|
|
85761b7fdb | ||
|
|
d9265007a0 | ||
|
|
98e099e3a0 | ||
|
|
1c50f3797c | ||
|
|
439d7ea701 | ||
|
|
1df4049e17 | ||
|
|
680e27d6ec | ||
|
|
9319b7aef1 | ||
|
|
e72f8161b9 | ||
|
|
de5f3020d9 | ||
|
|
ce9d48e896 | ||
|
|
b68111713d | ||
|
|
0abdea9094 | ||
|
|
899e9e7416 | ||
|
|
519319b989 | ||
|
|
a1ddf57216 | ||
|
|
457166295c | ||
|
|
d715803d45 | ||
|
|
31f0cc04ec | ||
|
|
b95fbe2d3f | ||
|
|
3afb89da48 | ||
|
|
ecd20a96df | ||
|
|
aa0eca03e6 | ||
|
|
aec8d90462 | ||
|
|
65a5dde38b | ||
|
|
fc2631b499 | ||
|
|
2d34a08c48 | ||
|
|
463435827b | ||
|
|
e479cae7cf | ||
|
|
a52441b114 | ||
|
|
9176911736 | ||
|
|
e1166861d2 | ||
|
|
903c2af04e | ||
|
|
dc62f3cdcc | ||
|
|
f91a97256b | ||
|
|
037a869919 | ||
|
|
4898267988 | ||
|
|
ca9d57245c | ||
|
|
2c9d055253 | ||
|
|
2112c5e948 | ||
|
|
bdf7224941 | ||
|
|
a613ac1907 | ||
|
|
560eb07009 | ||
|
|
46747963b6 | ||
|
|
5d4986c755 | ||
|
|
27c34f3eb9 | ||
|
|
f021cd64ed | ||
|
|
751c7e0f00 | ||
|
|
f0aba1aad4 | ||
|
|
699556e661 | ||
|
|
94c27842d8 | ||
|
|
44456ba065 | ||
|
|
50c33ee877 | ||
|
|
f2a5b1fc37 | ||
|
|
cfa4999d69 | ||
|
|
e1ec91fc58 | ||
|
|
4b1a464ac1 | ||
|
|
10d066c9cb | ||
|
|
446ceee51e | ||
|
|
f014236791 | ||
|
|
0327b0f4af | ||
|
|
a247b63aa1 | ||
|
|
14ffde2d8c | ||
|
|
55915b8e00 | ||
|
|
6a9c6d3bf1 | ||
|
|
42a28f79dc | ||
|
|
fbafa8038d | ||
|
|
0284e5dfea | ||
|
|
d20367c216 | ||
|
|
a6f1995550 | ||
|
|
714b63d1be | ||
|
|
fd66e77465 | ||
|
|
77ed01c8da | ||
|
|
170609e369 | ||
|
|
52c58b9ea0 | ||
|
|
f34510b123 | ||
|
|
e7db0d4f44 | ||
|
|
627805f5f8 | ||
|
|
ea583fda97 | ||
|
|
3993f9d581 | ||
|
|
bade039bda | ||
|
|
600f65b247 | ||
|
|
578513095c | ||
|
|
35b511b6d0 | ||
|
|
219a3345de | ||
|
|
2e4f99d99c | ||
|
|
880c98d2d3 | ||
|
|
860c664ccb | ||
|
|
bcec0f30e8 | ||
|
|
dd89904ad3 | ||
|
|
4a20c9b005 | ||
|
|
c2653b0a9e | ||
|
|
9f61e233c6 | ||
|
|
de07654c60 | ||
|
|
3e2ad6ffee | ||
|
|
09927fdbae | ||
|
|
bbbf642427 | ||
|
|
e2c575c5a6 | ||
|
|
cafb1bfd76 | ||
|
|
2ffd13bc31 | ||
|
|
07be572f8e | ||
|
|
e895817ad7 | ||
|
|
3589f5b9c2 | ||
|
|
963ee6ce79 | ||
|
|
2f13d3a8e5 | ||
|
|
ebbfdf0a0f | ||
|
|
323e6a3cf2 | ||
|
|
cf01997ebe | ||
|
|
2f649301e5 | ||
|
|
95870ef334 | ||
|
|
1d4862b7a2 | ||
|
|
29a20672c2 | ||
|
|
ac392bc0d7 | ||
|
|
87df57810d | ||
|
|
cfbe062eb2 | ||
|
|
20a77aeeb8 | ||
|
|
02ef9437d3 | ||
|
|
6ad5fe8659 | ||
|
|
eceacb8334 | ||
|
|
649b50c0b7 | ||
|
|
3f5ab612c8 | ||
|
|
804b00cd7d | ||
|
|
44d737707c | ||
|
|
0cdda85df2 | ||
|
|
0a3abe33f0 | ||
|
|
8f97a1778e | ||
|
|
6e4b37fffd | ||
|
|
5c246c931e | ||
|
|
700880ca16 | ||
|
|
d55cafb72e | ||
|
|
b3191bf042 | ||
|
|
4c52272a2d | ||
|
|
4318802f64 | ||
|
|
e11a714f7a | ||
|
|
7bdd23bfee | ||
|
|
a8d95b7c57 | ||
|
|
b885f61a61 | ||
|
|
873241790f | ||
|
|
d013b76e10 | ||
|
|
79812e3646 | ||
|
|
6eda9f3207 | ||
|
|
f8d9ecfb2c | ||
|
|
9fe95f1c5b | ||
|
|
c3f4972f6d | ||
|
|
65e4b57fda | ||
|
|
f746a48fe6 | ||
|
|
fa29b1f062 | ||
|
|
2c32c195d9 | ||
|
|
b07f193822 | ||
|
|
b59754bcb3 | ||
|
|
f337a52a6e | ||
|
|
d946cae364 | ||
|
|
9da6c80533 | ||
|
|
2b3959c414 | ||
|
|
a4a80b64a7 | ||
|
|
9d4e802221 | ||
|
|
170ba7f8fe | ||
|
|
8ea3589287 | ||
|
|
f357b18ee3 | ||
|
|
deb57c5144 | ||
|
|
292483531f | ||
|
|
dad4768037 | ||
|
|
bae79c3e72 | ||
|
|
7abe70c0b1 | ||
|
|
d403936818 | ||
|
|
cccb64e863 | ||
|
|
5ff18b8155 | ||
|
|
b0824edc7c | ||
|
|
96e2bfe28a | ||
|
|
a52d90a100 | ||
|
|
a09f99b8b0 | ||
|
|
3091d9a31e | ||
|
|
91c4fbb7bf | ||
|
|
84990731f7 | ||
|
|
fc4c0d9de4 | ||
|
|
49d49ac98f | ||
|
|
e06d533cc2 | ||
|
|
5c344dca4b | ||
|
|
1822bf730e | ||
|
|
1dc0caf9c0 | ||
|
|
c21c55e0b6 | ||
|
|
f387cc1205 | ||
|
|
cdc62c778f | ||
|
|
957c510d72 | ||
|
|
c41c00cab4 | ||
|
|
6ac20416c8 | ||
|
|
ae1ff4dea3 | ||
|
|
bc33ce0d8f | ||
|
|
17d870bed5 | ||
|
|
3f18afc94c | ||
|
|
fde10cf87b | ||
|
|
b44e13ae02 | ||
|
|
e6d9c097b2 | ||
|
|
262d45e0fe | ||
|
|
ff45a3cbac | ||
|
|
75b3b382ca | ||
|
|
63e28cc363 | ||
|
|
eb1e8e884d | ||
|
|
36c78c9172 | ||
|
|
fef1e0a708 | ||
|
|
7128353be5 | ||
|
|
8d1cc68673 | ||
|
|
753ff36cc3 | ||
|
|
c2699d8d89 | ||
|
|
da853e98c9 | ||
|
|
26332fe339 | ||
|
|
b4df555d27 | ||
|
|
8c765ae68a | ||
|
|
24bf8faa99 | ||
|
|
0757a5663a | ||
|
|
860d8e9271 | ||
|
|
9a2771eac2 | ||
|
|
3be683a0bb | ||
|
|
dda0ce6459 | ||
|
|
2075ef029e | ||
|
|
86f06b6deb | ||
|
|
5c0819a046 | ||
|
|
e4742dbb94 | ||
|
|
7362a09cd9 | ||
|
|
525d41118e | ||
|
|
0d2656ce6e | ||
|
|
4a5f09387e | ||
|
|
ea464ea212 | ||
|
|
095cb7a818 | ||
|
|
2edfb1e696 | ||
|
|
4a9dc8d73d | ||
|
|
1960da1dd0 | ||
|
|
a0b2290713 | ||
|
|
2cdcfc0c57 | ||
|
|
ff20637499 | ||
|
|
018f887fe1 | ||
|
|
74a34bb1fe | ||
|
|
e5d3aa2765 | ||
|
|
5a3d774e56 | ||
|
|
680adb98e1 | ||
|
|
3aa75210c4 | ||
|
|
0acec44374 | ||
|
|
08182da5d8 | ||
|
|
3a50675a68 | ||
|
|
ade6bd7785 | ||
|
|
e77729c2e0 | ||
|
|
ffd68badc0 | ||
|
|
dafddf461e | ||
|
|
38b005ec69 | ||
|
|
a1b6f350e8 | ||
|
|
510f1ba438 | ||
|
|
815279c240 | ||
|
|
4361366783 | ||
|
|
9b9d698081 | ||
|
|
2fcbfb5a66 | ||
|
|
287e604a8f | ||
|
|
57d86a5619 | ||
|
|
47065b9045 | ||
|
|
a7722d752d | ||
|
|
0bfa14a70a | ||
|
|
bc8d618cde | ||
|
|
b074e9b01d | ||
|
|
debbb26291 | ||
|
|
15ea1ca1f0 | ||
|
|
d14cfc8d43 | ||
|
|
748aaf3530 | ||
|
|
425ab3da5e | ||
|
|
5cabfd1526 | ||
|
|
67f6b0fd43 | ||
|
|
e817681581 | ||
|
|
6e3fe93148 | ||
|
|
e35a9a7def | ||
|
|
f7eaeae43c | ||
|
|
012091a28f | ||
|
|
c9fdb08bda | ||
|
|
41e7523291 | ||
|
|
cab7894808 | ||
|
|
250b0d070c | ||
|
|
aecdbf3471 | ||
|
|
8162dc0312 | ||
|
|
0098360726 | ||
|
|
42ca8a064b | ||
|
|
9189db3aff | ||
|
|
111ab125b9 | ||
|
|
af025f2a95 | ||
|
|
69ec5824c3 | ||
|
|
55691e5fdc | ||
|
|
fa3ac2d370 | ||
|
|
363b49948a | ||
|
|
56a0f49dcc | ||
|
|
e39b8eade1 | ||
|
|
7606412d53 | ||
|
|
a2f3ce2294 | ||
|
|
79f217e350 | ||
|
|
9aa840c50d | ||
|
|
e0dad30579 | ||
|
|
714c1bd8ca | ||
|
|
6bb6e422b5 | ||
|
|
5e256799dd | ||
|
|
87c5ecdd69 | ||
|
|
3051ffe0fa | ||
|
|
c42b5575e5 | ||
|
|
389916bf9a | ||
|
|
3fcb0d880a | ||
|
|
917b7436af | ||
|
|
fe31ea7d0f | ||
|
|
c9e647e42f | ||
|
|
8eb34b2a0e | ||
|
|
6b6e915b85 | ||
|
|
5ef0fe4b53 | ||
|
|
5f6a725332 | ||
|
|
d3fde633bd | ||
|
|
02a0c7aca9 | ||
|
|
5743151118 | ||
|
|
d15bc4a342 | ||
|
|
f6e6cf9071 | ||
|
|
d91b8bcf0b | ||
|
|
94370add05 | ||
|
|
17f6535482 | ||
|
|
7be83a0857 | ||
|
|
f87afda123 | ||
|
|
b85f20cf13 | ||
|
|
03c5c1930d | ||
|
|
f3ea94a797 | ||
|
|
0b2b3221e2 | ||
|
|
04a9fe1e62 | ||
|
|
baacc7006b | ||
|
|
385c9b1a08 | ||
|
|
1c8d3106df | ||
|
|
be4f4599a6 | ||
|
|
6b29019541 | ||
|
|
9026888b10 | ||
|
|
7c8445826f | ||
|
|
01d4fd76dd | ||
|
|
b18c721555 | ||
|
|
11902d4ccb | ||
|
|
c72cfa8d45 | ||
|
|
1d3d1c5d2b | ||
|
|
e899700254 | ||
|
|
05f293e65e | ||
|
|
901a47daff | ||
|
|
7b1dd54d5d | ||
|
|
4f5e91e3b4 | ||
|
|
11ef08402a | ||
|
|
6d8e95557c | ||
|
|
dd258553b1 | ||
|
|
408963ed4d | ||
|
|
1059e166fd | ||
|
|
c4dbd4f7c0 | ||
|
|
f6d11c8d50 | ||
|
|
53b036032d | ||
|
|
1dc8e2ffab | ||
|
|
cee6f4506c | ||
|
|
423a8f91d7 | ||
|
|
01b424028e | ||
|
|
7eb425ccd1 | ||
|
|
e23e3a1600 | ||
|
|
ed032ddfd6 | ||
|
|
f9c078ef38 | ||
|
|
09ee269d99 | ||
|
|
2470a5ed99 | ||
|
|
1c291ccbbe | ||
|
|
d420134fa2 | ||
|
|
733711481e | ||
|
|
a51dc92379 | ||
|
|
6e74754a50 | ||
|
|
f1ac8962f9 | ||
|
|
21e258d732 | ||
|
|
87d522a557 | ||
|
|
c7a1bdf6c0 | ||
|
|
42be6f2957 | ||
|
|
cf513185b0 | ||
|
|
f54823bf05 | ||
|
|
664ba0c031 | ||
|
|
67ba305841 | ||
|
|
d7587aa976 | ||
|
|
6a762e8594 | ||
|
|
28c22cb7f9 | ||
|
|
c5f1cb1121 | ||
|
|
431a6736d2 | ||
|
|
b49cfaffa8 | ||
|
|
2d195fb6f8 | ||
|
|
14ee021885 | ||
|
|
edcb41451a | ||
|
|
3f600c831b | ||
|
|
cf6834d797 | ||
|
|
edf16383c6 | ||
|
|
386d1ecc6e | ||
|
|
62b2b1bac3 | ||
|
|
8228d0e2bb | ||
|
|
c32036fa9b | ||
|
|
549e34b3d7 | ||
|
|
3ce5fde7ab | ||
|
|
fa8f89c521 | ||
|
|
10b8d6b8b0 | ||
|
|
09e694aa7d | ||
|
|
4d7e28a7d7 | ||
|
|
9559f57463 | ||
|
|
ad19e5e133 | ||
|
|
875b0698e8 | ||
|
|
22cf1586cf | ||
|
|
1e847bff7a | ||
|
|
e876067e34 | ||
|
|
51d032737c | ||
|
|
ba7245f072 | ||
|
|
00469957ad | ||
|
|
ab0fc77ebe | ||
|
|
c70fbae3ed | ||
|
|
ad19f1beb7 | ||
|
|
506ad22743 | ||
|
|
d6f7725e58 | ||
|
|
5266d6fa7b | ||
|
|
1bcc37caec | ||
|
|
6d14e9f1ac | ||
|
|
a5f5d5e8d7 | ||
|
|
8ee1f2a9e9 | ||
|
|
189967a12a | ||
|
|
d3bc787bca | ||
|
|
f55fa8211b | ||
|
|
a206186f84 | ||
|
|
ff1ea0064b | ||
|
|
b2eb79b7da | ||
|
|
ed833bb62d | ||
|
|
0d63d68e33 | ||
|
|
a32f3b4b50 | ||
|
|
66bccf3064 | ||
|
|
c60cde1499 | ||
|
|
cbdce9912d | ||
|
|
db9bf744ab | ||
|
|
4efe02b3df | ||
|
|
4e286a9094 | ||
|
|
8554841c6a | ||
|
|
49376ec448 | ||
|
|
7030cdce59 | ||
|
|
990021ac2b | ||
|
|
41d405fa53 | ||
|
|
8d06bfc12e | ||
|
|
98ea12ac38 | ||
|
|
7ba8788919 | ||
|
|
bf69b773ec | ||
|
|
986a151b8a | ||
|
|
abda245ddc | ||
|
|
4ad5af81c8 | ||
|
|
3f7909e996 | ||
|
|
707ef9618b | ||
|
|
d31ae5aed8 | ||
|
|
b4857dffa8 | ||
|
|
2eac1c4bc5 | ||
|
|
d17c929659 | ||
|
|
bdf4b74b52 | ||
|
|
346a350df4 | ||
|
|
181e54bff3 | ||
|
|
d7e5fdfb58 | ||
|
|
10eae16fa7 | ||
|
|
874698cb4a | ||
|
|
40966fa096 | ||
|
|
a57298791c | ||
|
|
7303467c77 | ||
|
|
7b1f34d626 | ||
|
|
80bc06f1cf | ||
|
|
cf331cdd6a | ||
|
|
b1c114c3a7 | ||
|
|
b13cdb01bd | ||
|
|
f619243099 | ||
|
|
a841152069 | ||
|
|
30313cacce | ||
|
|
8646bf4a40 | ||
|
|
421707f638 | ||
|
|
a790d3309c | ||
|
|
df217f5377 | ||
|
|
c60d178ad0 | ||
|
|
b132e7b36d | ||
|
|
1ca7964cdd | ||
|
|
3e2a9f667f | ||
|
|
7a0e599142 | ||
|
|
381050b1ee | ||
|
|
f3db32c035 | ||
|
|
d803523cdc | ||
|
|
443d923f08 | ||
|
|
586e72218c | ||
|
|
98041d26bb | ||
|
|
48907d57ed | ||
|
|
5c069940db | ||
|
|
65d4047cb6 | ||
|
|
def86d0cf4 | ||
|
|
c4c92e66cd | ||
|
|
216b4c9cf6 | ||
|
|
3303789b4f | ||
|
|
7c52ab7f83 | ||
|
|
40b55a4174 | ||
|
|
f53b922f40 | ||
|
|
f08cd445b0 | ||
|
|
962e1186f9 | ||
|
|
d9d08c5ef5 | ||
|
|
331ae9c0f8 | ||
|
|
06cd125e64 | ||
|
|
4195fc0494 | ||
|
|
ffe3ae7bfb | ||
|
|
2294294e19 | ||
|
|
cc96d31252 | ||
|
|
0c5d9626b8 | ||
|
|
438d26b405 | ||
|
|
42fe9327b9 | ||
|
|
6b352d1cfe | ||
|
|
f0ec901819 | ||
|
|
04bfa8e91f | ||
|
|
d0fe1147ea | ||
|
|
ec0fb311ed | ||
|
|
4dcf4e9bd0 | ||
|
|
3336bdf5b5 | ||
|
|
ba4ae2c46d | ||
|
|
092826152c | ||
|
|
c7fdd51eb6 | ||
|
|
661a1e9026 | ||
|
|
3807f8b708 | ||
|
|
9e2cc4fcd9 | ||
|
|
698ded75b9 | ||
|
|
4902f047d3 | ||
|
|
d0c4e44863 | ||
|
|
cc42eeac21 | ||
|
|
52edbe6a23 | ||
|
|
d4ec4d6e9b | ||
|
|
207d7807af | ||
|
|
bf9482987f | ||
|
|
0ba7f934ee | ||
|
|
087acccf0c | ||
|
|
cac97b6bd8 | ||
|
|
e278082c21 | ||
|
|
690711b584 | ||
|
|
1c8ec01c55 | ||
|
|
2ed8b22099 | ||
|
|
1e0e86360f | ||
|
|
2629e2ec23 | ||
|
|
08a10f936b | ||
|
|
d3023f25f5 | ||
|
|
f1d7ed35bd | ||
|
|
62d97afaf8 | ||
|
|
686786f107 | ||
|
|
c5b82f5e8d | ||
|
|
c44c98edec | ||
|
|
da327c8fa3 | ||
|
|
6228761f67 | ||
|
|
614c57c521 | ||
|
|
21849f1a21 | ||
|
|
5e8402568e | ||
|
|
7e9fbbba1c | ||
|
|
2c5405f699 | ||
|
|
b3e80c6935 | ||
|
|
742d8bf922 | ||
|
|
3e4e8636c1 | ||
|
|
8f6162f17b | ||
|
|
d5f7b4df1b | ||
|
|
95ca361df6 | ||
|
|
4e2cf53f4f | ||
|
|
d671768b52 | ||
|
|
06248d745a | ||
|
|
69a1f53e70 | ||
|
|
8ae966de75 | ||
|
|
ed5054389a | ||
|
|
7a7bb43db5 | ||
|
|
03ae463c8d | ||
|
|
a6ce867e48 | ||
|
|
aab9078ff9 | ||
|
|
4e20407d82 | ||
|
|
1c05ddd645 | ||
|
|
f83c873d8b | ||
|
|
41d437117d | ||
|
|
7085ec875f | ||
|
|
2b468dc283 | ||
|
|
8df0b12d82 | ||
|
|
50d49d0db8 | ||
|
|
50fde602a1 | ||
|
|
8ca34e4b5e | ||
|
|
520163a00e | ||
|
|
0b97725340 | ||
|
|
4adab34dfa | ||
|
|
be9dcbbef5 | ||
|
|
c4327f7146 | ||
|
|
c0c58b6b46 | ||
|
|
947405a909 | ||
|
|
93bf556f13 | ||
|
|
e9f1f760f2 | ||
|
|
e02cf69789 | ||
|
|
cb92c47144 | ||
|
|
d561fe6d2d | ||
|
|
c40602b254 | ||
|
|
1a441d9aea | ||
|
|
821d3aab65 | ||
|
|
073382a9c6 | ||
|
|
77b09a6a19 | ||
|
|
65567e125d | ||
|
|
27b2d7ff72 | ||
|
|
eb97163348 | ||
|
|
7b366b1f01 | ||
|
|
52e88d92f0 | ||
|
|
05243104fc | ||
|
|
51b188c510 | ||
|
|
8091157038 | ||
|
|
d871725cf2 | ||
|
|
f9f6379a53 | ||
|
|
15243cdbde | ||
|
|
f5979b9d0d | ||
|
|
9494643bf1 | ||
|
|
a8d6d28be4 | ||
|
|
fbf7815b25 | ||
|
|
784a008346 | ||
|
|
0bdadfe4e7 | ||
|
|
dbee7dd69e | ||
|
|
338e87f6b3 | ||
|
|
3b9e8679db | ||
|
|
cb47ddd968 | ||
|
|
4ccd91f0d8 | ||
|
|
a084f4bc61 | ||
|
|
c99ee556d4 | ||
|
|
6cb16f1c31 | ||
|
|
f411f8bfc5 | ||
|
|
37115ffb00 | ||
|
|
384b60b940 | ||
|
|
9ac293e1a8 | ||
|
|
6c953a3059 | ||
|
|
8f909221f5 | ||
|
|
96c03d6d92 | ||
|
|
a092f979d4 | ||
|
|
a1b7a35c90 | ||
|
|
fa7c8d523e | ||
|
|
0b3fe55442 | ||
|
|
db00e224c2 | ||
|
|
b1bae92534 | ||
|
|
a247af9c97 | ||
|
|
d1757c005f | ||
|
|
8194556337 | ||
|
|
8a8b6d7964 | ||
|
|
4cf40c968f | ||
|
|
cb40e3302e | ||
|
|
9a7bd6d95b | ||
|
|
9254a62cd6 | ||
|
|
b83a171f9e | ||
|
|
5ff3a28cb4 | ||
|
|
a7b60b21de | ||
|
|
53802d54d6 | ||
|
|
7ab1a90e59 | ||
|
|
fb2ac5bedb | ||
|
|
bae6a5a616 | ||
|
|
6158ccad97 | ||
|
|
052ad32a7b | ||
|
|
cacb5c0dde | ||
|
|
e827c8ff61 | ||
|
|
fd32fc8062 | ||
|
|
faf5ef6f80 | ||
|
|
07e9ac9ffe | ||
|
|
d9939758e6 | ||
|
|
5dc6339e33 | ||
|
|
875d0b776d | ||
|
|
e2fce7d612 | ||
|
|
135ced208c | ||
|
|
871299de0d | ||
|
|
11fee48c2d | ||
|
|
3b0ae3ec68 | ||
|
|
9e2e8188ae | ||
|
|
9bc75d008e | ||
|
|
a43cebf088 | ||
|
|
83b446492c | ||
|
|
4fd9cc9980 | ||
|
|
63fe64c471 | ||
|
|
9722c66dad | ||
|
|
b0a46d1cb9 | ||
|
|
e570987c4f | ||
|
|
c740c76017 | ||
|
|
744d39a466 | ||
|
|
23cc3e5c63 | ||
|
|
e975687b9a | ||
|
|
c37b4828dd | ||
|
|
23bdb3b3a6 | ||
|
|
bb7baf1835 | ||
|
|
4dc5315e3b | ||
|
|
7842630480 | ||
|
|
d87fdaa1e3 | ||
|
|
ef364f7e1f | ||
|
|
c9f216d2fa | ||
|
|
b737837882 | ||
|
|
3cb59c5140 | ||
|
|
55d645246a | ||
|
|
90251a488d | ||
|
|
f72a31ae31 | ||
|
|
8e851aaa27 | ||
|
|
fa7946a510 | ||
|
|
faeede0200 | ||
|
|
862d3eb284 | ||
|
|
8ac4261263 | ||
|
|
8349e282a9 | ||
|
|
2337f52999 | ||
|
|
1ecb170352 | ||
|
|
d6c494671f | ||
|
|
5b85dc3584 | ||
|
|
752c3e9208 | ||
|
|
7992fb5911 | ||
|
|
38daa47ee2 | ||
|
|
5f9a673025 | ||
|
|
4a3b36f443 | ||
|
|
1151f9ef9e | ||
|
|
31e8993d57 | ||
|
|
259d714b93 | ||
|
|
8f99875d03 | ||
|
|
cfd209fd6e | ||
|
|
8baafacf40 | ||
|
|
a2c08792f0 | ||
|
|
fa72eb3a58 | ||
|
|
39320f9393 | ||
|
|
94dc07c044 | ||
|
|
daa89c420c | ||
|
|
f7e4546af0 | ||
|
|
a59e1949b5 | ||
|
|
0c611d9b15 | ||
|
|
e2119f3050 | ||
|
|
92f46d233e | ||
|
|
5d07362a84 | ||
|
|
c95f77866c | ||
|
|
c624caa949 | ||
|
|
c11fadb282 | ||
|
|
d9885abdc4 | ||
|
|
b611198d28 | ||
|
|
05e9574cf3 | ||
|
|
249524ec49 | ||
|
|
6854e2997e | ||
|
|
3754fdd7ca | ||
|
|
ca7a0e6d6e | ||
|
|
a7e181c857 |
@@ -0,0 +1,2 @@
|
|||||||
|
bundles
|
||||||
|
.gopath
|
||||||
@@ -26,3 +26,4 @@ Vagrantfile
|
|||||||
docs/AWS_S3_BUCKET
|
docs/AWS_S3_BUCKET
|
||||||
docs/GIT_BRANCH
|
docs/GIT_BRANCH
|
||||||
docs/VERSION
|
docs/VERSION
|
||||||
|
docs/GITCOMMIT
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
# Generate AUTHORS: git log --format='%aN <%aE>' | sort -uf
|
# Generate AUTHORS: hack/generate-authors.sh
|
||||||
|
|
||||||
|
# Tip for finding duplicates (besides scanning the output of AUTHORS for name
|
||||||
|
# duplicates that aren't also email duplicates): scan the output of:
|
||||||
|
# git log --format='%aE - %aN' | sort -uf
|
||||||
|
|
||||||
<charles.hooper@dotcloud.com> <chooper@plumata.com>
|
<charles.hooper@dotcloud.com> <chooper@plumata.com>
|
||||||
<daniel.mizyrycki@dotcloud.com> <daniel@dotcloud.com>
|
<daniel.mizyrycki@dotcloud.com> <daniel@dotcloud.com>
|
||||||
<daniel.mizyrycki@dotcloud.com> <mzdaniel@glidelink.net>
|
<daniel.mizyrycki@dotcloud.com> <mzdaniel@glidelink.net>
|
||||||
@@ -47,8 +52,9 @@ Shih-Yuan Lee <fourdollars@gmail.com>
|
|||||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> root <root@vagrant-ubuntu-12.10.vagrantup.com>
|
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> root <root@vagrant-ubuntu-12.10.vagrantup.com>
|
||||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||||
<proppy@google.com> <proppy@aminche.com>
|
<proppy@google.com> <proppy@aminche.com>
|
||||||
<michael@crosbymichael.com> <crosby.michael@gmail.com>
|
<michael@docker.com> <michael@crosbymichael.com>
|
||||||
<github@metaliveblog.com> <github@developersupport.net>
|
<michael@docker.com> <crosby.michael@gmail.com>
|
||||||
|
<github@developersupport.net> <github@metaliveblog.com>
|
||||||
<brandon@ifup.org> <brandon@ifup.co>
|
<brandon@ifup.org> <brandon@ifup.co>
|
||||||
<dano@spotify.com> <daniel.norberg@gmail.com>
|
<dano@spotify.com> <daniel.norberg@gmail.com>
|
||||||
<danny@codeaholics.org> <Danny.Yates@mailonline.co.uk>
|
<danny@codeaholics.org> <Danny.Yates@mailonline.co.uk>
|
||||||
@@ -78,3 +84,16 @@ Sridhar Ratnakumar <sridharr@activestate.com> <github@srid.name>
|
|||||||
Liang-Chi Hsieh <viirya@gmail.com>
|
Liang-Chi Hsieh <viirya@gmail.com>
|
||||||
Aleksa Sarai <cyphar@cyphar.com>
|
Aleksa Sarai <cyphar@cyphar.com>
|
||||||
Will Weaver <monkey@buildingbananas.com>
|
Will Weaver <monkey@buildingbananas.com>
|
||||||
|
Timothy Hobbs <timothyhobbs@seznam.cz>
|
||||||
|
Nathan LeClaire <nathan.leclaire@docker.com> <nathan.leclaire@gmail.com>
|
||||||
|
Nathan LeClaire <nathan.leclaire@docker.com> <nathanleclaire@gmail.com>
|
||||||
|
<github@hollensbe.org> <erik+github@hollensbe.org>
|
||||||
|
<github@albersweb.de> <albers@users.noreply.github.com>
|
||||||
|
<lsm5@fedoraproject.org> <lsm5@redhat.com>
|
||||||
|
<marc@marc-abramowitz.com> <msabramo@gmail.com>
|
||||||
|
Matthew Heon <mheon@redhat.com> <mheon@mheonlaptop.redhat.com>
|
||||||
|
<bernat@luffy.cx> <vincent@bernat.im>
|
||||||
|
<p@pwaller.net> <peter@scraperwiki.com>
|
||||||
|
<andrew.weiss@outlook.com> <andrew.weiss@microsoft.com>
|
||||||
|
Francisco Carriedo <fcarriedo@gmail.com>
|
||||||
|
<julienbordellier@gmail.com> <git@julienbordellier.com>
|
||||||
|
|||||||
+14
-2
@@ -3,10 +3,20 @@
|
|||||||
|
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
go: 1.2
|
go:
|
||||||
|
# This should match the version in the Dockerfile.
|
||||||
|
- 1.3.1
|
||||||
|
# Test against older versions too, just for a little extra retrocompat.
|
||||||
|
- 1.2
|
||||||
|
|
||||||
|
# Let us have pretty experimental Docker-based Travis workers.
|
||||||
|
# (These spin up much faster than the VM-based ones.)
|
||||||
|
sudo: false
|
||||||
|
|
||||||
# Disable the normal go build.
|
# Disable the normal go build.
|
||||||
install: true
|
install:
|
||||||
|
- export DOCKER_BUILDTAGS='exclude_graphdriver_btrfs exclude_graphdriver_devicemapper' # btrfs and devicemapper fail to compile thanks to a couple missing headers (which we can't install thanks to "sudo: false")
|
||||||
|
- export AUTO_GOPATH=1
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- env | sort
|
- env | sort
|
||||||
@@ -14,5 +24,7 @@ before_script:
|
|||||||
script:
|
script:
|
||||||
- hack/make.sh validate-dco
|
- hack/make.sh validate-dco
|
||||||
- hack/make.sh validate-gofmt
|
- hack/make.sh validate-gofmt
|
||||||
|
- ./hack/make.sh dynbinary
|
||||||
|
- DOCKER_CLIENTONLY=1 ./hack/make.sh dynbinary
|
||||||
|
|
||||||
# vim:set sw=2 ts=2:
|
# vim:set sw=2 ts=2:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# This file lists all individuals having contributed content to the repository.
|
# This file lists all individuals having contributed content to the repository.
|
||||||
# For how it is generated, see `.mailmap`.
|
# For how it is generated, see `hack/generate-authors.sh`.
|
||||||
|
|
||||||
Aanand Prasad <aanand.prasad@gmail.com>
|
Aanand Prasad <aanand.prasad@gmail.com>
|
||||||
Aaron Feng <aaron.feng@gmail.com>
|
Aaron Feng <aaron.feng@gmail.com>
|
||||||
@@ -9,33 +9,43 @@ Adam Miller <admiller@redhat.com>
|
|||||||
Adam Singer <financeCoding@gmail.com>
|
Adam Singer <financeCoding@gmail.com>
|
||||||
Aditya <aditya@netroy.in>
|
Aditya <aditya@netroy.in>
|
||||||
Adrian Mouat <adrian.mouat@gmail.com>
|
Adrian Mouat <adrian.mouat@gmail.com>
|
||||||
|
Adrien Folie <folie.adrien@gmail.com>
|
||||||
|
AJ Bowen <aj@gandi.net>
|
||||||
|
Al Tobey <al@ooyala.com>
|
||||||
alambike <alambike@gmail.com>
|
alambike <alambike@gmail.com>
|
||||||
|
Albert Zhang <zhgwenming@gmail.com>
|
||||||
Aleksa Sarai <cyphar@cyphar.com>
|
Aleksa Sarai <cyphar@cyphar.com>
|
||||||
|
Alex Gaynor <alex.gaynor@gmail.com>
|
||||||
|
Alex Warhawk <ax.warhawk@gmail.com>
|
||||||
Alexander Larsson <alexl@redhat.com>
|
Alexander Larsson <alexl@redhat.com>
|
||||||
|
Alexander Shopov <ash@kambanaria.org>
|
||||||
Alexandr Morozov <lk4d4math@gmail.com>
|
Alexandr Morozov <lk4d4math@gmail.com>
|
||||||
Alexey Kotlyarov <alexey@infoxchange.net.au>
|
Alexey Kotlyarov <alexey@infoxchange.net.au>
|
||||||
Alexey Shamrin <shamrin@gmail.com>
|
Alexey Shamrin <shamrin@gmail.com>
|
||||||
Alex Gaynor <alex.gaynor@gmail.com>
|
|
||||||
Alexis THOMAS <fr.alexisthomas@gmail.com>
|
Alexis THOMAS <fr.alexisthomas@gmail.com>
|
||||||
almoehi <almoehi@users.noreply.github.com>
|
almoehi <almoehi@users.noreply.github.com>
|
||||||
Al Tobey <al@ooyala.com>
|
|
||||||
amangoel <amangoel@gmail.com>
|
amangoel <amangoel@gmail.com>
|
||||||
|
AnandkumarPatel <anandkumarpatel@gmail.com>
|
||||||
|
Andre Dublin <81dublin@gmail.com>
|
||||||
Andrea Luzzardi <aluzzardi@gmail.com>
|
Andrea Luzzardi <aluzzardi@gmail.com>
|
||||||
|
Andrea Turli <andrea.turli@gmail.com>
|
||||||
Andreas Savvides <andreas@editd.com>
|
Andreas Savvides <andreas@editd.com>
|
||||||
Andreas Tiefenthaler <at@an-ti.eu>
|
Andreas Tiefenthaler <at@an-ti.eu>
|
||||||
Andrea Turli <andrea.turli@gmail.com>
|
|
||||||
Andrew Duckworth <grillopress@gmail.com>
|
Andrew Duckworth <grillopress@gmail.com>
|
||||||
|
Andrew France <andrew@avito.co.uk>
|
||||||
Andrew Macgregor <andrew.macgregor@agworld.com.au>
|
Andrew Macgregor <andrew.macgregor@agworld.com.au>
|
||||||
Andrew Munsell <andrew@wizardapps.net>
|
Andrew Munsell <andrew@wizardapps.net>
|
||||||
Andrews Medina <andrewsmedina@gmail.com>
|
Andrew Weiss <andrew.weiss@outlook.com>
|
||||||
Andrew Williams <williams.andrew@gmail.com>
|
Andrew Williams <williams.andrew@gmail.com>
|
||||||
|
Andrews Medina <andrewsmedina@gmail.com>
|
||||||
Andy Chambers <anchambers@paypal.com>
|
Andy Chambers <anchambers@paypal.com>
|
||||||
andy diller <dillera@gmail.com>
|
andy diller <dillera@gmail.com>
|
||||||
Andy Goldstein <agoldste@redhat.com>
|
Andy Goldstein <agoldste@redhat.com>
|
||||||
Andy Kipp <andy@rstudio.com>
|
Andy Kipp <andy@rstudio.com>
|
||||||
Andy Rothfusz <github@metaliveblog.com>
|
Andy Rothfusz <github@developersupport.net>
|
||||||
Andy Smith <github@anarkystic.com>
|
Andy Smith <github@anarkystic.com>
|
||||||
Anthony Bishopric <git@anthonybishopric.com>
|
Anthony Bishopric <git@anthonybishopric.com>
|
||||||
|
Anton Löfgren <anton.lofgren@gmail.com>
|
||||||
Anton Nikitin <anton.k.nikitin@gmail.com>
|
Anton Nikitin <anton.k.nikitin@gmail.com>
|
||||||
Antony Messerli <amesserl@rackspace.com>
|
Antony Messerli <amesserl@rackspace.com>
|
||||||
apocas <petermdias@gmail.com>
|
apocas <petermdias@gmail.com>
|
||||||
@@ -44,25 +54,34 @@ Asbjørn Enge <asbjorn@hanafjedle.net>
|
|||||||
Barnaby Gray <barnaby@pickle.me.uk>
|
Barnaby Gray <barnaby@pickle.me.uk>
|
||||||
Barry Allard <barry.allard@gmail.com>
|
Barry Allard <barry.allard@gmail.com>
|
||||||
Bartłomiej Piotrowski <b@bpiotrowski.pl>
|
Bartłomiej Piotrowski <b@bpiotrowski.pl>
|
||||||
Benjamin Atkin <ben@benatkin.com>
|
bdevloed <boris.de.vloed@gmail.com>
|
||||||
Benoit Chesneau <bchesneau@gmail.com>
|
Ben Firshman <ben@firshman.co.uk>
|
||||||
Ben Sargent <ben@brokendigits.com>
|
Ben Sargent <ben@brokendigits.com>
|
||||||
Ben Toews <mastahyeti@gmail.com>
|
Ben Toews <mastahyeti@gmail.com>
|
||||||
Ben Wiklund <ben@daisyowl.com>
|
Ben Wiklund <ben@daisyowl.com>
|
||||||
|
Benjamin Atkin <ben@benatkin.com>
|
||||||
|
Benoit Chesneau <bchesneau@gmail.com>
|
||||||
Bernerd Schaefer <bj.schaefer@gmail.com>
|
Bernerd Schaefer <bj.schaefer@gmail.com>
|
||||||
Bhiraj Butala <abhiraj.butala@gmail.com>
|
Bhiraj Butala <abhiraj.butala@gmail.com>
|
||||||
bin liu <liubin0329@users.noreply.github.com>
|
bin liu <liubin0329@users.noreply.github.com>
|
||||||
Bouke Haarsma <bouke@webatoom.nl>
|
Bouke Haarsma <bouke@webatoom.nl>
|
||||||
|
Boyd Hemphill <boyd@feedmagnet.com>
|
||||||
Brandon Liu <bdon@bdon.org>
|
Brandon Liu <bdon@bdon.org>
|
||||||
Brandon Philips <brandon@ifup.org>
|
Brandon Philips <brandon@ifup.org>
|
||||||
|
Brandon Rhodes <brandon@rhodesmill.org>
|
||||||
|
Brett Kochendorfer <brett.kochendorfer@gmail.com>
|
||||||
|
Brian (bex) Exelbierd <bexelbie@redhat.com>
|
||||||
Brian Dorsey <brian@dorseys.org>
|
Brian Dorsey <brian@dorseys.org>
|
||||||
Brian Flad <bflad417@gmail.com>
|
Brian Flad <bflad417@gmail.com>
|
||||||
Brian Goff <cpuguy83@gmail.com>
|
Brian Goff <cpuguy83@gmail.com>
|
||||||
Brian McCallister <brianm@skife.org>
|
Brian McCallister <brianm@skife.org>
|
||||||
Brian Olsen <brian@maven-group.org>
|
Brian Olsen <brian@maven-group.org>
|
||||||
Brian Shumate <brian@couchbase.com>
|
Brian Shumate <brian@couchbase.com>
|
||||||
|
Brice Jaglin <bjaglin@teads.tv>
|
||||||
Briehan Lombaard <briehan.lombaard@gmail.com>
|
Briehan Lombaard <briehan.lombaard@gmail.com>
|
||||||
Bruno Bigras <bigras.bruno@gmail.com>
|
Bruno Bigras <bigras.bruno@gmail.com>
|
||||||
|
Bruno Renié <brutasse@gmail.com>
|
||||||
|
Bryan Bess <squarejaw@bsbess.com>
|
||||||
Bryan Matsuo <bryan.matsuo@gmail.com>
|
Bryan Matsuo <bryan.matsuo@gmail.com>
|
||||||
Bryan Murphy <bmurphy1976@gmail.com>
|
Bryan Murphy <bmurphy1976@gmail.com>
|
||||||
Caleb Spare <cespare@gmail.com>
|
Caleb Spare <cespare@gmail.com>
|
||||||
@@ -73,19 +92,35 @@ Charles Hooper <charles.hooper@dotcloud.com>
|
|||||||
Charles Lindsay <chaz@chazomatic.us>
|
Charles Lindsay <chaz@chazomatic.us>
|
||||||
Charles Merriam <charles.merriam@gmail.com>
|
Charles Merriam <charles.merriam@gmail.com>
|
||||||
Charlie Lewis <charliel@lab41.org>
|
Charlie Lewis <charliel@lab41.org>
|
||||||
|
Chewey <prosto-chewey@users.noreply.github.com>
|
||||||
Chia-liang Kao <clkao@clkao.org>
|
Chia-liang Kao <clkao@clkao.org>
|
||||||
|
Chris Alfonso <calfonso@redhat.com>
|
||||||
|
Chris Snow <chsnow123@gmail.com>
|
||||||
Chris St. Pierre <chris.a.st.pierre@gmail.com>
|
Chris St. Pierre <chris.a.st.pierre@gmail.com>
|
||||||
|
chrismckinnel <chris.mckinnel@tangentlabs.co.uk>
|
||||||
|
Christian Berendt <berendt@b1-systems.de>
|
||||||
|
ChristoperBiscardi <biscarch@sketcht.com>
|
||||||
|
Christophe Troestler <christophe.Troestler@umons.ac.be>
|
||||||
Christopher Currie <codemonkey+github@gmail.com>
|
Christopher Currie <codemonkey+github@gmail.com>
|
||||||
Christopher Rigor <crigor@gmail.com>
|
Christopher Rigor <crigor@gmail.com>
|
||||||
Christophe Troestler <christophe.Troestler@umons.ac.be>
|
Ciro S. Costa <ciro.costa@usp.br>
|
||||||
Clayton Coleman <ccoleman@redhat.com>
|
Clayton Coleman <ccoleman@redhat.com>
|
||||||
Colin Dunklau <colin.dunklau@gmail.com>
|
Colin Dunklau <colin.dunklau@gmail.com>
|
||||||
Colin Rice <colin@daedrum.net>
|
Colin Rice <colin@daedrum.net>
|
||||||
|
Colin Walters <walters@verbum.org>
|
||||||
Cory Forsyth <cory.forsyth@gmail.com>
|
Cory Forsyth <cory.forsyth@gmail.com>
|
||||||
|
cpuguy83 <cpuguy83@gmail.com>
|
||||||
cressie176 <github@stephen-cresswell.net>
|
cressie176 <github@stephen-cresswell.net>
|
||||||
|
Cruceru Calin-Cristian <crucerucalincristian@gmail.com>
|
||||||
|
Daan van Berkel <daan.v.berkel.1980@gmail.com>
|
||||||
Dafydd Crosby <dtcrsby@gmail.com>
|
Dafydd Crosby <dtcrsby@gmail.com>
|
||||||
Dan Buch <d.buch@modcloth.com>
|
Dan Buch <d.buch@modcloth.com>
|
||||||
Dan Hirsch <thequux@upstandinghackers.com>
|
Dan Hirsch <thequux@upstandinghackers.com>
|
||||||
|
Dan Keder <dan.keder@gmail.com>
|
||||||
|
Dan McPherson <dmcphers@redhat.com>
|
||||||
|
Dan Stine <sw@stinemail.com>
|
||||||
|
Dan Walsh <dwalsh@redhat.com>
|
||||||
|
Dan Williams <me@deedubs.com>
|
||||||
Daniel Exner <dex@dragonslave.de>
|
Daniel Exner <dex@dragonslave.de>
|
||||||
Daniel Garcia <daniel@danielgarcia.info>
|
Daniel Garcia <daniel@danielgarcia.info>
|
||||||
Daniel Gasienica <daniel@gasienica.ch>
|
Daniel Gasienica <daniel@gasienica.ch>
|
||||||
@@ -95,22 +130,21 @@ Daniel Nordberg <dnordberg@gmail.com>
|
|||||||
Daniel Robinson <gottagetmac@gmail.com>
|
Daniel Robinson <gottagetmac@gmail.com>
|
||||||
Daniel Von Fange <daniel@leancoder.com>
|
Daniel Von Fange <daniel@leancoder.com>
|
||||||
Daniel YC Lin <dlin.tw@gmail.com>
|
Daniel YC Lin <dlin.tw@gmail.com>
|
||||||
Dan Keder <dan.keder@gmail.com>
|
Daniel, Dao Quang Minh <dqminh89@gmail.com>
|
||||||
Dan McPherson <dmcphers@redhat.com>
|
|
||||||
Danny Berger <dpb587@gmail.com>
|
Danny Berger <dpb587@gmail.com>
|
||||||
Danny Yates <danny@codeaholics.org>
|
Danny Yates <danny@codeaholics.org>
|
||||||
Dan Stine <sw@stinemail.com>
|
|
||||||
Dan Walsh <dwalsh@redhat.com>
|
|
||||||
Dan Williams <me@deedubs.com>
|
|
||||||
Darren Coxall <darren@darrencoxall.com>
|
Darren Coxall <darren@darrencoxall.com>
|
||||||
Darren Shepherd <darren.s.shepherd@gmail.com>
|
Darren Shepherd <darren.s.shepherd@gmail.com>
|
||||||
David Anderson <dave@natulte.net>
|
David Anderson <dave@natulte.net>
|
||||||
David Calavera <david.calavera@gmail.com>
|
David Calavera <david.calavera@gmail.com>
|
||||||
|
David Corking <dmc-source@dcorking.com>
|
||||||
David Gageot <david@gageot.net>
|
David Gageot <david@gageot.net>
|
||||||
David Mcanulty <github@hellspark.com>
|
David Mcanulty <github@hellspark.com>
|
||||||
David Röthlisberger <david@rothlis.net>
|
David Röthlisberger <david@rothlis.net>
|
||||||
David Sissitka <me@dsissitka.com>
|
David Sissitka <me@dsissitka.com>
|
||||||
Deni Bertovic <deni@kset.org>
|
Deni Bertovic <deni@kset.org>
|
||||||
|
Derek <crq@kernel.org>
|
||||||
|
Deric Crago <deric.crago@gmail.com>
|
||||||
Dinesh Subhraveti <dineshs@altiscale.com>
|
Dinesh Subhraveti <dineshs@altiscale.com>
|
||||||
Djibril Koné <kone.djibril@gmail.com>
|
Djibril Koné <kone.djibril@gmail.com>
|
||||||
dkumor <daniel@dkumor.com>
|
dkumor <daniel@dkumor.com>
|
||||||
@@ -118,8 +152,10 @@ Dmitry Demeshchuk <demeshchuk@gmail.com>
|
|||||||
Dolph Mathews <dolph.mathews@gmail.com>
|
Dolph Mathews <dolph.mathews@gmail.com>
|
||||||
Dominik Honnef <dominik@honnef.co>
|
Dominik Honnef <dominik@honnef.co>
|
||||||
Don Spaulding <donspauldingii@gmail.com>
|
Don Spaulding <donspauldingii@gmail.com>
|
||||||
Dražen Lučanin <kermit666@gmail.com>
|
Doug Davis <dug@us.ibm.com>
|
||||||
|
doug tangren <d.tangren@gmail.com>
|
||||||
Dr Nic Williams <drnicwilliams@gmail.com>
|
Dr Nic Williams <drnicwilliams@gmail.com>
|
||||||
|
Dražen Lučanin <kermit666@gmail.com>
|
||||||
Dustin Sallings <dustin@spy.net>
|
Dustin Sallings <dustin@spy.net>
|
||||||
Edmund Wagner <edmund-wagner@web.de>
|
Edmund Wagner <edmund-wagner@web.de>
|
||||||
Eiichi Tsukata <devel@etsukata.com>
|
Eiichi Tsukata <devel@etsukata.com>
|
||||||
@@ -130,13 +166,17 @@ Emily Rose <emily@contactvibe.com>
|
|||||||
Eric Hanchrow <ehanchrow@ine.com>
|
Eric Hanchrow <ehanchrow@ine.com>
|
||||||
Eric Lee <thenorthsecedes@gmail.com>
|
Eric Lee <thenorthsecedes@gmail.com>
|
||||||
Eric Myhre <hash@exultant.us>
|
Eric Myhre <hash@exultant.us>
|
||||||
Erik Hollensbe <erik+github@hollensbe.org>
|
Eric Windisch <eric@windisch.us>
|
||||||
|
Eric Windisch <ewindisch@docker.com>
|
||||||
|
Erik Hollensbe <github@hollensbe.org>
|
||||||
|
Erik Inge Bolsø <knan@redpill-linpro.com>
|
||||||
Erno Hopearuoho <erno.hopearuoho@gmail.com>
|
Erno Hopearuoho <erno.hopearuoho@gmail.com>
|
||||||
eugenkrizo <eugen.krizo@gmail.com>
|
eugenkrizo <eugen.krizo@gmail.com>
|
||||||
Evan Hazlett <ejhazlett@gmail.com>
|
Evan Hazlett <ejhazlett@gmail.com>
|
||||||
Evan Krall <krall@yelp.com>
|
Evan Krall <krall@yelp.com>
|
||||||
Evan Phoenix <evan@fallingsnow.net>
|
Evan Phoenix <evan@fallingsnow.net>
|
||||||
Evan Wies <evan@neomantra.net>
|
Evan Wies <evan@neomantra.net>
|
||||||
|
evanderkoogh <info@erronis.nl>
|
||||||
Eystein Måløy Stenberg <eystein.maloy.stenberg@cfengine.com>
|
Eystein Måløy Stenberg <eystein.maloy.stenberg@cfengine.com>
|
||||||
ezbercih <cem.ezberci@gmail.com>
|
ezbercih <cem.ezberci@gmail.com>
|
||||||
Fabio Falci <fabiofalci@gmail.com>
|
Fabio Falci <fabiofalci@gmail.com>
|
||||||
@@ -147,12 +187,16 @@ Fareed Dudhia <fareeddudhia@googlemail.com>
|
|||||||
Felix Rabe <felix@rabe.io>
|
Felix Rabe <felix@rabe.io>
|
||||||
Fernando <fermayo@gmail.com>
|
Fernando <fermayo@gmail.com>
|
||||||
Flavio Castelli <fcastelli@suse.com>
|
Flavio Castelli <fcastelli@suse.com>
|
||||||
|
FLGMwt <ryan.stelly@live.com>
|
||||||
|
Francisco Carriedo <fcarriedo@gmail.com>
|
||||||
Francisco Souza <f@souza.cc>
|
Francisco Souza <f@souza.cc>
|
||||||
Frank Macreery <frank@macreery.com>
|
Frank Macreery <frank@macreery.com>
|
||||||
|
Fred Lifton <fred.lifton@docker.com>
|
||||||
Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
|
Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
|
||||||
Frederik Loeffert <frederik@zitrusmedia.de>
|
Frederik Loeffert <frederik@zitrusmedia.de>
|
||||||
Freek Kalter <freek@kalteronline.org>
|
Freek Kalter <freek@kalteronline.org>
|
||||||
Gabe Rosenhouse <gabe@missionst.com>
|
Gabe Rosenhouse <gabe@missionst.com>
|
||||||
|
Gabor Nagy <mail@aigeruth.hu>
|
||||||
Gabriel Monroy <gabriel@opdemand.com>
|
Gabriel Monroy <gabriel@opdemand.com>
|
||||||
Galen Sampson <galen.sampson@gmail.com>
|
Galen Sampson <galen.sampson@gmail.com>
|
||||||
Gareth Rushgrove <gareth@morethanseven.net>
|
Gareth Rushgrove <gareth@morethanseven.net>
|
||||||
@@ -160,75 +204,106 @@ Geoffrey Bachelet <grosfrais@gmail.com>
|
|||||||
Gereon Frey <gereon.frey@dynport.de>
|
Gereon Frey <gereon.frey@dynport.de>
|
||||||
German DZ <germ@ndz.com.ar>
|
German DZ <germ@ndz.com.ar>
|
||||||
Gert van Valkenhoef <g.h.m.van.valkenhoef@rug.nl>
|
Gert van Valkenhoef <g.h.m.van.valkenhoef@rug.nl>
|
||||||
|
Giuseppe Mazzotta <gdm85@users.noreply.github.com>
|
||||||
|
Gleb Fotengauer-Malinovskiy <glebfm@altlinux.org>
|
||||||
|
Glyn Normington <gnormington@gopivotal.com>
|
||||||
Goffert van Gool <goffert@phusion.nl>
|
Goffert van Gool <goffert@phusion.nl>
|
||||||
Graydon Hoare <graydon@pobox.com>
|
Graydon Hoare <graydon@pobox.com>
|
||||||
Greg Thornton <xdissent@me.com>
|
Greg Thornton <xdissent@me.com>
|
||||||
grunny <mwgrunny@gmail.com>
|
grunny <mwgrunny@gmail.com>
|
||||||
|
Guilherme Salgado <gsalgado@gmail.com>
|
||||||
Guillaume J. Charmes <guillaume.charmes@docker.com>
|
Guillaume J. Charmes <guillaume.charmes@docker.com>
|
||||||
Gurjeet Singh <gurjeet@singh.im>
|
Gurjeet Singh <gurjeet@singh.im>
|
||||||
Guruprasad <lgp171188@gmail.com>
|
Guruprasad <lgp171188@gmail.com>
|
||||||
|
Harald Albers <github@albersweb.de>
|
||||||
Harley Laue <losinggeneration@gmail.com>
|
Harley Laue <losinggeneration@gmail.com>
|
||||||
Hector Castro <hectcastro@gmail.com>
|
Hector Castro <hectcastro@gmail.com>
|
||||||
|
Henning Sprang <henning.sprang@gmail.com>
|
||||||
Hobofan <goisser94@gmail.com>
|
Hobofan <goisser94@gmail.com>
|
||||||
|
Hollie Teal <hollie.teal@docker.com>
|
||||||
|
Hollie Teal <hollietealok@users.noreply.github.com>
|
||||||
|
hollietealok <hollie@docker.com>
|
||||||
Hunter Blanks <hunter@twilio.com>
|
Hunter Blanks <hunter@twilio.com>
|
||||||
|
hyeongkyu.lee <hyeongkyu.lee@navercorp.com>
|
||||||
|
Ian Babrou <ibobrik@gmail.com>
|
||||||
|
Ian Bull <irbull@gmail.com>
|
||||||
|
Ian Main <imain@redhat.com>
|
||||||
Ian Truslove <ian.truslove@gmail.com>
|
Ian Truslove <ian.truslove@gmail.com>
|
||||||
ILYA Khlopotov <ilya.khlopotov@gmail.com>
|
ILYA Khlopotov <ilya.khlopotov@gmail.com>
|
||||||
inglesp <peter.inglesby@gmail.com>
|
inglesp <peter.inglesby@gmail.com>
|
||||||
Isaac Dupree <antispam@idupree.com>
|
Isaac Dupree <antispam@idupree.com>
|
||||||
Isabel Jimenez <contact.isabeljimenez@gmail.com>
|
Isabel Jimenez <contact.isabeljimenez@gmail.com>
|
||||||
Isao Jonas <isao.jonas@gmail.com>
|
Isao Jonas <isao.jonas@gmail.com>
|
||||||
|
Ivan Fraixedes <ifcdev@gmail.com>
|
||||||
Jack Danger Canty <jackdanger@squareup.com>
|
Jack Danger Canty <jackdanger@squareup.com>
|
||||||
jakedt <jake@devtable.com>
|
|
||||||
Jake Moshenko <jake@devtable.com>
|
Jake Moshenko <jake@devtable.com>
|
||||||
|
jakedt <jake@devtable.com>
|
||||||
James Allen <jamesallen0108@gmail.com>
|
James Allen <jamesallen0108@gmail.com>
|
||||||
James Carr <james.r.carr@gmail.com>
|
James Carr <james.r.carr@gmail.com>
|
||||||
James DeFelice <james.defelice@ishisystems.com>
|
James DeFelice <james.defelice@ishisystems.com>
|
||||||
James Harrison Fisher <jameshfisher@gmail.com>
|
James Harrison Fisher <jameshfisher@gmail.com>
|
||||||
|
James Kyle <james@jameskyle.org>
|
||||||
James Mills <prologic@shortcircuit.net.au>
|
James Mills <prologic@shortcircuit.net.au>
|
||||||
James Turnbull <james@lovedthanlost.net>
|
James Turnbull <james@lovedthanlost.net>
|
||||||
|
Jan Pazdziora <jpazdziora@redhat.com>
|
||||||
|
Jan Toebes <jan@toebes.info>
|
||||||
|
Jaroslaw Zabiello <hipertracker@gmail.com>
|
||||||
jaseg <jaseg@jaseg.net>
|
jaseg <jaseg@jaseg.net>
|
||||||
|
Jason Giedymin <jasong@apache.org>
|
||||||
|
Jason Hall <imjasonh@gmail.com>
|
||||||
|
Jason Livesay <ithkuil@gmail.com>
|
||||||
Jason McVetta <jason.mcvetta@gmail.com>
|
Jason McVetta <jason.mcvetta@gmail.com>
|
||||||
Jason Plum <jplum@devonit.com>
|
Jason Plum <jplum@devonit.com>
|
||||||
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
||||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||||
Jeff Lindsay <progrium@gmail.com>
|
Jeff Lindsay <progrium@gmail.com>
|
||||||
|
Jeff Welch <whatthejeff@gmail.com>
|
||||||
|
Jeffrey Bolle <jeffreybolle@gmail.com>
|
||||||
Jeremy Grosser <jeremy@synack.me>
|
Jeremy Grosser <jeremy@synack.me>
|
||||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com>
|
|
||||||
Jesse Dubay <jesse@thefortytwo.net>
|
Jesse Dubay <jesse@thefortytwo.net>
|
||||||
|
Jezeniel Zapanta <jpzapanta22@gmail.com>
|
||||||
Jilles Oldenbeuving <ojilles@gmail.com>
|
Jilles Oldenbeuving <ojilles@gmail.com>
|
||||||
Jim Alateras <jima@comware.com.au>
|
Jim Alateras <jima@comware.com.au>
|
||||||
|
Jim Perrin <jperrin@centos.org>
|
||||||
Jimmy Cuadra <jimmy@jimmycuadra.com>
|
Jimmy Cuadra <jimmy@jimmycuadra.com>
|
||||||
|
Jiří Župka <jzupka@redhat.com>
|
||||||
Joe Beda <joe.github@bedafamily.com>
|
Joe Beda <joe.github@bedafamily.com>
|
||||||
Joel Handwell <joelhandwell@gmail.com>
|
|
||||||
Joe Shaw <joe@joeshaw.org>
|
Joe Shaw <joe@joeshaw.org>
|
||||||
Joe Van Dyk <joe@tanga.com>
|
Joe Van Dyk <joe@tanga.com>
|
||||||
|
Joel Handwell <joelhandwell@gmail.com>
|
||||||
Joffrey F <joffrey@docker.com>
|
Joffrey F <joffrey@docker.com>
|
||||||
Johan Euphrosine <proppy@google.com>
|
Johan Euphrosine <proppy@google.com>
|
||||||
Johannes 'fish' Ziemke <github@freigeist.org>
|
|
||||||
Johan Rydberg <johan.rydberg@gmail.com>
|
Johan Rydberg <johan.rydberg@gmail.com>
|
||||||
|
Johannes 'fish' Ziemke <github@freigeist.org>
|
||||||
John Costa <john.costa@gmail.com>
|
John Costa <john.costa@gmail.com>
|
||||||
John Feminella <jxf@jxf.me>
|
John Feminella <jxf@jxf.me>
|
||||||
John Gardiner Myers <jgmyers@proofpoint.com>
|
John Gardiner Myers <jgmyers@proofpoint.com>
|
||||||
|
John OBrien III <jobrieniii@yahoo.com>
|
||||||
John Warwick <jwarwick@gmail.com>
|
John Warwick <jwarwick@gmail.com>
|
||||||
|
Jon Wedaman <jweede@gmail.com>
|
||||||
Jonas Pfenniger <jonas@pfenniger.name>
|
Jonas Pfenniger <jonas@pfenniger.name>
|
||||||
|
Jonathan Boulle <jonathanboulle@gmail.com>
|
||||||
|
Jonathan Camp <jonathan@irondojo.com>
|
||||||
Jonathan McCrohan <jmccrohan@gmail.com>
|
Jonathan McCrohan <jmccrohan@gmail.com>
|
||||||
Jonathan Mueller <j.mueller@apoveda.ch>
|
Jonathan Mueller <j.mueller@apoveda.ch>
|
||||||
Jonathan Pares <jonathanpa@users.noreply.github.com>
|
Jonathan Pares <jonathanpa@users.noreply.github.com>
|
||||||
Jonathan Rudenberg <jonathan@titanous.com>
|
Jonathan Rudenberg <jonathan@titanous.com>
|
||||||
Jon Wedaman <jweede@gmail.com>
|
|
||||||
Joost Cassee <joost@cassee.net>
|
Joost Cassee <joost@cassee.net>
|
||||||
Jordan Arentsen <blissdev@gmail.com>
|
Jordan Arentsen <blissdev@gmail.com>
|
||||||
Jordan Sissel <jls@semicomplete.com>
|
Jordan Sissel <jls@semicomplete.com>
|
||||||
Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
|
Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
|
||||||
Joseph Hager <ajhager@gmail.com>
|
Joseph Hager <ajhager@gmail.com>
|
||||||
|
Josh <jokajak@gmail.com>
|
||||||
Josh Hawn <josh.hawn@docker.com>
|
Josh Hawn <josh.hawn@docker.com>
|
||||||
Josh Poimboeuf <jpoimboe@redhat.com>
|
Josh Poimboeuf <jpoimboe@redhat.com>
|
||||||
JP <jpellerin@leapfrogonline.com>
|
JP <jpellerin@leapfrogonline.com>
|
||||||
Julien Barbier <write0@gmail.com>
|
Julien Barbier <write0@gmail.com>
|
||||||
|
Julien Bordellier <julienbordellier@gmail.com>
|
||||||
Julien Dubois <julien.dubois@gmail.com>
|
Julien Dubois <julien.dubois@gmail.com>
|
||||||
Justin Force <justin.force@gmail.com>
|
Justin Force <justin.force@gmail.com>
|
||||||
Justin Plock <jplock@users.noreply.github.com>
|
Justin Plock <jplock@users.noreply.github.com>
|
||||||
Justin Simonelis <justin.p.simonelis@gmail.com>
|
Justin Simonelis <justin.p.simonelis@gmail.com>
|
||||||
|
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com>
|
||||||
Karan Lyons <karan@karanlyons.com>
|
Karan Lyons <karan@karanlyons.com>
|
||||||
Karl Grzeszczak <karlgrz@gmail.com>
|
Karl Grzeszczak <karlgrz@gmail.com>
|
||||||
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
|
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
|
||||||
@@ -236,36 +311,49 @@ Kawsar Saiyeed <kawsar.saiyeed@projiris.com>
|
|||||||
Keli Hu <dev@keli.hu>
|
Keli Hu <dev@keli.hu>
|
||||||
Ken Cochrane <kencochrane@gmail.com>
|
Ken Cochrane <kencochrane@gmail.com>
|
||||||
Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com>
|
Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com>
|
||||||
|
Kevin "qwazerty" Houdebert <kevin.houdebert@gmail.com>
|
||||||
Kevin Clark <kevin.clark@gmail.com>
|
Kevin Clark <kevin.clark@gmail.com>
|
||||||
Kevin J. Lynagh <kevin@keminglabs.com>
|
Kevin J. Lynagh <kevin@keminglabs.com>
|
||||||
Kevin Menard <kevin@nirvdrum.com>
|
Kevin Menard <kevin@nirvdrum.com>
|
||||||
Kevin Wallace <kevin@pentabarf.net>
|
Kevin Wallace <kevin@pentabarf.net>
|
||||||
Keyvan Fatehi <keyvanfatehi@gmail.com>
|
Keyvan Fatehi <keyvanfatehi@gmail.com>
|
||||||
kim0 <email.ahmedkamal@googlemail.com>
|
kies <lleelm@gmail.com>
|
||||||
Kim BKC Carlbacker <kim.carlbacker@gmail.com>
|
Kim BKC Carlbacker <kim.carlbacker@gmail.com>
|
||||||
|
kim0 <email.ahmedkamal@googlemail.com>
|
||||||
Kimbro Staken <kstaken@kstaken.com>
|
Kimbro Staken <kstaken@kstaken.com>
|
||||||
Kiran Gangadharan <kiran.daredevil@gmail.com>
|
Kiran Gangadharan <kiran.daredevil@gmail.com>
|
||||||
|
knappe <tyler.knappe@gmail.com>
|
||||||
|
Kohei Tsuruta <coheyxyz@gmail.com>
|
||||||
Konstantin Pelykh <kpelykh@zettaset.com>
|
Konstantin Pelykh <kpelykh@zettaset.com>
|
||||||
Kyle Conroy <kyle.j.conroy@gmail.com>
|
Kyle Conroy <kyle.j.conroy@gmail.com>
|
||||||
|
kyu <leehk1227@gmail.com>
|
||||||
|
Lachlan Coote <lcoote@vmware.com>
|
||||||
lalyos <lalyos@yahoo.com>
|
lalyos <lalyos@yahoo.com>
|
||||||
Lance Chen <cyen0312@gmail.com>
|
Lance Chen <cyen0312@gmail.com>
|
||||||
Lars R. Damerow <lars@pixar.com>
|
Lars R. Damerow <lars@pixar.com>
|
||||||
Laurie Voss <github@seldo.com>
|
Laurie Voss <github@seldo.com>
|
||||||
|
leeplay <hyeongkyu.lee@navercorp.com>
|
||||||
|
Len Weincier <len@cloudafrica.net>
|
||||||
|
Levi Gross <levi@levigross.com>
|
||||||
Lewis Peckover <lew+github@lew.io>
|
Lewis Peckover <lew+github@lew.io>
|
||||||
Liang-Chi Hsieh <viirya@gmail.com>
|
Liang-Chi Hsieh <viirya@gmail.com>
|
||||||
Lokesh Mandvekar <lsm5@redhat.com>
|
Lokesh Mandvekar <lsm5@fedoraproject.org>
|
||||||
Louis Opter <kalessin@kalessin.fr>
|
Louis Opter <kalessin@kalessin.fr>
|
||||||
lukaspustina <lukas.pustina@centerdevice.com>
|
lukaspustina <lukas.pustina@centerdevice.com>
|
||||||
lukemarsden <luke@digital-crocus.com>
|
lukemarsden <luke@digital-crocus.com>
|
||||||
Mahesh Tiyyagura <tmahesh@gmail.com>
|
Mahesh Tiyyagura <tmahesh@gmail.com>
|
||||||
|
Manfred Zabarauskas <manfredas@zabarauskas.com>
|
||||||
Manuel Meurer <manuel@krautcomputing.com>
|
Manuel Meurer <manuel@krautcomputing.com>
|
||||||
Manuel Woelker <github@manuel.woelker.org>
|
Manuel Woelker <github@manuel.woelker.org>
|
||||||
Marc Abramowitz <marc@marc-abramowitz.com>
|
Marc Abramowitz <marc@marc-abramowitz.com>
|
||||||
Marc Kuo <kuomarc2@gmail.com>
|
Marc Kuo <kuomarc2@gmail.com>
|
||||||
|
Marc Tamsky <mtamsky@gmail.com>
|
||||||
Marco Hennings <marco.hennings@freiheit.com>
|
Marco Hennings <marco.hennings@freiheit.com>
|
||||||
Marcus Farkas <toothlessgear@finitebox.com>
|
Marcus Farkas <toothlessgear@finitebox.com>
|
||||||
Marcus Ramberg <marcus@nordaaker.com>
|
Marcus Ramberg <marcus@nordaaker.com>
|
||||||
|
marcuslinke <marcus.linke@gmx.de>
|
||||||
Marek Goldmann <marek.goldmann@gmail.com>
|
Marek Goldmann <marek.goldmann@gmail.com>
|
||||||
|
Marius Voila <marius.voila@gmail.com>
|
||||||
Mark Allen <mrallen1@yahoo.com>
|
Mark Allen <mrallen1@yahoo.com>
|
||||||
Mark McGranaghan <mmcgrana@gmail.com>
|
Mark McGranaghan <mmcgrana@gmail.com>
|
||||||
Marko Mikulicic <mmikulicic@gmail.com>
|
Marko Mikulicic <mmikulicic@gmail.com>
|
||||||
@@ -278,30 +366,40 @@ Mathieu Le Marec - Pasquet <kiorky@cryptelium.net>
|
|||||||
Matt Apperson <me@mattapperson.com>
|
Matt Apperson <me@mattapperson.com>
|
||||||
Matt Bachmann <bachmann.matt@gmail.com>
|
Matt Bachmann <bachmann.matt@gmail.com>
|
||||||
Matt Haggard <haggardii@gmail.com>
|
Matt Haggard <haggardii@gmail.com>
|
||||||
|
Matthew Heon <mheon@redhat.com>
|
||||||
Matthew Mueller <mattmuelle@gmail.com>
|
Matthew Mueller <mattmuelle@gmail.com>
|
||||||
Matthias Klumpp <matthias@tenstral.net>
|
Matthias Klumpp <matthias@tenstral.net>
|
||||||
Matthias Kühnle <git.nivoc@neverbox.com>
|
Matthias Kühnle <git.nivoc@neverbox.com>
|
||||||
mattymo <raytrac3r@gmail.com>
|
mattymo <raytrac3r@gmail.com>
|
||||||
Maxime Petazzoni <max@signalfuse.com>
|
mattyw <mattyw@me.com>
|
||||||
Maxim Treskin <zerthurd@gmail.com>
|
|
||||||
Max Shytikov <mshytikov@gmail.com>
|
Max Shytikov <mshytikov@gmail.com>
|
||||||
|
Maxim Treskin <zerthurd@gmail.com>
|
||||||
|
Maxime Petazzoni <max@signalfuse.com>
|
||||||
meejah <meejah@meejah.ca>
|
meejah <meejah@meejah.ca>
|
||||||
Michael Brown <michael@netdirect.ca>
|
Michael Brown <michael@netdirect.ca>
|
||||||
Michael Crosby <michael@crosbymichael.com>
|
Michael Crosby <michael@docker.com>
|
||||||
Michael Gorsuch <gorsuch@github.com>
|
Michael Gorsuch <gorsuch@github.com>
|
||||||
Michael Neale <michael.neale@gmail.com>
|
Michael Neale <michael.neale@gmail.com>
|
||||||
|
Michael Prokop <github@michael-prokop.at>
|
||||||
Michael Stapelberg <michael+gh@stapelberg.de>
|
Michael Stapelberg <michael+gh@stapelberg.de>
|
||||||
|
Michaël Pailloncy <mpapo.dev@gmail.com>
|
||||||
|
Michiel@unhosted <michiel@unhosted.org>
|
||||||
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
||||||
|
Mike Chelen <michael.chelen@gmail.com>
|
||||||
Mike Gaffney <mike@uberu.com>
|
Mike Gaffney <mike@uberu.com>
|
||||||
Mike MacCana <mike.maccana@gmail.com>
|
Mike MacCana <mike.maccana@gmail.com>
|
||||||
Mike Naberezny <mike@naberezny.com>
|
Mike Naberezny <mike@naberezny.com>
|
||||||
|
Mike Snitzer <snitzer@redhat.com>
|
||||||
Mikhail Sobolev <mss@mawhrin.net>
|
Mikhail Sobolev <mss@mawhrin.net>
|
||||||
Mohit Soni <mosoni@ebay.com>
|
Mohit Soni <mosoni@ebay.com>
|
||||||
Morgante Pell <morgante.pell@morgante.net>
|
Morgante Pell <morgante.pell@morgante.net>
|
||||||
Morten Siebuhr <sbhr@sbhr.dk>
|
Morten Siebuhr <sbhr@sbhr.dk>
|
||||||
|
Mrunal Patel <mrunalp@gmail.com>
|
||||||
Nan Monnand Deng <monnand@gmail.com>
|
Nan Monnand Deng <monnand@gmail.com>
|
||||||
|
Naoki Orii <norii@cs.cmu.edu>
|
||||||
Nate Jones <nate@endot.org>
|
Nate Jones <nate@endot.org>
|
||||||
Nathan Kleyn <nathan@nathankleyn.com>
|
Nathan Kleyn <nathan@nathankleyn.com>
|
||||||
|
Nathan LeClaire <nathan.leclaire@docker.com>
|
||||||
Nelson Chen <crazysim@gmail.com>
|
Nelson Chen <crazysim@gmail.com>
|
||||||
Niall O'Higgins <niallo@unworkable.org>
|
Niall O'Higgins <niallo@unworkable.org>
|
||||||
Nick Payne <nick@kurai.co.uk>
|
Nick Payne <nick@kurai.co.uk>
|
||||||
@@ -309,15 +407,20 @@ Nick Stenning <nick.stenning@digital.cabinet-office.gov.uk>
|
|||||||
Nick Stinemates <nick@stinemates.org>
|
Nick Stinemates <nick@stinemates.org>
|
||||||
Nicolas Dudebout <nicolas.dudebout@gatech.edu>
|
Nicolas Dudebout <nicolas.dudebout@gatech.edu>
|
||||||
Nicolas Kaiser <nikai@nikai.net>
|
Nicolas Kaiser <nikai@nikai.net>
|
||||||
|
NikolaMandic <mn080202@gmail.com>
|
||||||
noducks <onemannoducks@gmail.com>
|
noducks <onemannoducks@gmail.com>
|
||||||
Nolan Darilek <nolan@thewordnerd.info>
|
Nolan Darilek <nolan@thewordnerd.info>
|
||||||
|
O.S. Tezer <ostezer@gmail.com>
|
||||||
|
OddBloke <daniel@daniel-watkins.co.uk>
|
||||||
odk- <github@odkurzacz.org>
|
odk- <github@odkurzacz.org>
|
||||||
Oguz Bilgic <fisyonet@gmail.com>
|
Oguz Bilgic <fisyonet@gmail.com>
|
||||||
Ole Reifschneider <mail@ole-reifschneider.de>
|
Ole Reifschneider <mail@ole-reifschneider.de>
|
||||||
O.S. Tezer <ostezer@gmail.com>
|
Olivier Gambier <dmp42@users.noreply.github.com>
|
||||||
pandrew <letters@paulnotcom.se>
|
pandrew <letters@paulnotcom.se>
|
||||||
Pascal Borreli <pascal@borreli.com>
|
Pascal Borreli <pascal@borreli.com>
|
||||||
|
Patrick Hemmer <patrick.hemmer@gmail.com>
|
||||||
pattichen <craftsbear@gmail.com>
|
pattichen <craftsbear@gmail.com>
|
||||||
|
Paul <paul9869@gmail.com>
|
||||||
Paul Annesley <paul@annesley.cc>
|
Paul Annesley <paul@annesley.cc>
|
||||||
Paul Bowsher <pbowsher@globalpersonals.co.uk>
|
Paul Bowsher <pbowsher@globalpersonals.co.uk>
|
||||||
Paul Hammond <paul@paulhammond.org>
|
Paul Hammond <paul@paulhammond.org>
|
||||||
@@ -325,49 +428,71 @@ Paul Jimenez <pj@place.org>
|
|||||||
Paul Lietar <paul@lietar.net>
|
Paul Lietar <paul@lietar.net>
|
||||||
Paul Morie <pmorie@gmail.com>
|
Paul Morie <pmorie@gmail.com>
|
||||||
Paul Nasrat <pnasrat@gmail.com>
|
Paul Nasrat <pnasrat@gmail.com>
|
||||||
Paul <paul9869@gmail.com>
|
Paul Weaver <pauweave@cisco.com>
|
||||||
|
Peter Bourgon <peter@bourgon.org>
|
||||||
Peter Braden <peterbraden@peterbraden.co.uk>
|
Peter Braden <peterbraden@peterbraden.co.uk>
|
||||||
Peter Waller <peter@scraperwiki.com>
|
Peter Waller <p@pwaller.net>
|
||||||
Phillip Alexander <git@phillipalexander.io>
|
Phil <underscorephil@gmail.com>
|
||||||
Phil Spitler <pspitler@gmail.com>
|
Phil Spitler <pspitler@gmail.com>
|
||||||
|
Phillip Alexander <git@phillipalexander.io>
|
||||||
Piergiuliano Bossi <pgbossi@gmail.com>
|
Piergiuliano Bossi <pgbossi@gmail.com>
|
||||||
Pierre-Alain RIVIERE <pariviere@ippon.fr>
|
Pierre-Alain RIVIERE <pariviere@ippon.fr>
|
||||||
Piotr Bogdan <ppbogdan@gmail.com>
|
Piotr Bogdan <ppbogdan@gmail.com>
|
||||||
pysqz <randomq@126.com>
|
pysqz <randomq@126.com>
|
||||||
Quentin Brossard <qbrossard@gmail.com>
|
Quentin Brossard <qbrossard@gmail.com>
|
||||||
|
r0n22 <cameron.regan@gmail.com>
|
||||||
Rafal Jeczalik <rjeczalik@gmail.com>
|
Rafal Jeczalik <rjeczalik@gmail.com>
|
||||||
Rajat Pandit <rp@rajatpandit.com>
|
Rajat Pandit <rp@rajatpandit.com>
|
||||||
|
Rajdeep Dua <dua_rajdeep@yahoo.com>
|
||||||
Ralph Bean <rbean@redhat.com>
|
Ralph Bean <rbean@redhat.com>
|
||||||
Ramkumar Ramachandra <artagnon@gmail.com>
|
Ramkumar Ramachandra <artagnon@gmail.com>
|
||||||
Ramon van Alteren <ramon@vanalteren.nl>
|
Ramon van Alteren <ramon@vanalteren.nl>
|
||||||
Renato Riccieri Santos Zannon <renato.riccieri@gmail.com>
|
Renato Riccieri Santos Zannon <renato.riccieri@gmail.com>
|
||||||
rgstephens <greg@udon.org>
|
rgstephens <greg@udon.org>
|
||||||
Rhys Hiltner <rhys@twitch.tv>
|
Rhys Hiltner <rhys@twitch.tv>
|
||||||
|
Richard Harvey <richard@squarecows.com>
|
||||||
Richo Healey <richo@psych0tik.net>
|
Richo Healey <richo@psych0tik.net>
|
||||||
Rick Bradley <rick@users.noreply.github.com>
|
Rick Bradley <rick@users.noreply.github.com>
|
||||||
|
Rick van de Loo <rickvandeloo@gmail.com>
|
||||||
|
Robert Bachmann <rb@robertbachmann.at>
|
||||||
Robert Obryk <robryk@gmail.com>
|
Robert Obryk <robryk@gmail.com>
|
||||||
Roberto G. Hashioka <roberto.hashioka@docker.com>
|
Roberto G. Hashioka <roberto.hashioka@docker.com>
|
||||||
|
Robin Speekenbrink <robin@kingsquare.nl>
|
||||||
robpc <rpcann@gmail.com>
|
robpc <rpcann@gmail.com>
|
||||||
Rodrigo Vaz <rodrigo.vaz@gmail.com>
|
Rodrigo Vaz <rodrigo.vaz@gmail.com>
|
||||||
Roel Van Nyen <roel.vannyen@gmail.com>
|
Roel Van Nyen <roel.vannyen@gmail.com>
|
||||||
Roger Peppe <rogpeppe@gmail.com>
|
Roger Peppe <rogpeppe@gmail.com>
|
||||||
Rohit Jnagal <jnagal@google.com>
|
Rohit Jnagal <jnagal@google.com>
|
||||||
|
Roland Huß <roland@jolokia.org>
|
||||||
Roland Moriz <rmoriz@users.noreply.github.com>
|
Roland Moriz <rmoriz@users.noreply.github.com>
|
||||||
|
Ron Smits <ron.smits@gmail.com>
|
||||||
Rovanion Luckey <rovanion.luckey@gmail.com>
|
Rovanion Luckey <rovanion.luckey@gmail.com>
|
||||||
|
Rudolph Gottesheim <r.gottesheim@loot.at>
|
||||||
|
Ryan Anderson <anderson.ryanc@gmail.com>
|
||||||
Ryan Aslett <github@mixologic.com>
|
Ryan Aslett <github@mixologic.com>
|
||||||
Ryan Fowler <rwfowler@gmail.com>
|
Ryan Fowler <rwfowler@gmail.com>
|
||||||
Ryan O'Donnell <odonnellryanc@gmail.com>
|
Ryan O'Donnell <odonnellryanc@gmail.com>
|
||||||
Ryan Seto <ryanseto@yak.net>
|
Ryan Seto <ryanseto@yak.net>
|
||||||
Ryan Thomas <rthomas@atlassian.com>
|
Ryan Thomas <rthomas@atlassian.com>
|
||||||
|
s-ko <aleks@s-ko.net>
|
||||||
Sam Alba <sam.alba@gmail.com>
|
Sam Alba <sam.alba@gmail.com>
|
||||||
|
Sam Bailey <cyprix@cyprix.com.au>
|
||||||
Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
|
Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
|
||||||
|
Sam Reis <sreis@atlassian.com>
|
||||||
Sam Rijs <srijs@airpost.net>
|
Sam Rijs <srijs@airpost.net>
|
||||||
Samuel Andaya <samuel@andaya.net>
|
Samuel Andaya <samuel@andaya.net>
|
||||||
|
satoru <satorulogic@gmail.com>
|
||||||
|
Satoshi Amemiya <satoshi_amemiya@voyagegroup.com>
|
||||||
Scott Bessler <scottbessler@gmail.com>
|
Scott Bessler <scottbessler@gmail.com>
|
||||||
Scott Collier <emailscottcollier@gmail.com>
|
Scott Collier <emailscottcollier@gmail.com>
|
||||||
Sean Cronin <seancron@gmail.com>
|
Sean Cronin <seancron@gmail.com>
|
||||||
Sean P. Kane <skane@newrelic.com>
|
Sean P. Kane <skane@newrelic.com>
|
||||||
Sébastien Stormacq <sebsto@users.noreply.github.com>
|
Sebastiaan van Stijn <github@gone.nl>
|
||||||
|
Sebastiaan van Stijn <thaJeztah@users.noreply.github.com>
|
||||||
|
Senthil Kumar Selvaraj <senthil.thecoder@gmail.com>
|
||||||
|
SeongJae Park <sj38.park@gmail.com>
|
||||||
|
Shane Canon <scanon@lbl.gov>
|
||||||
|
shaunol <shaunol@gmail.com>
|
||||||
Shawn Landden <shawn@churchofgit.com>
|
Shawn Landden <shawn@churchofgit.com>
|
||||||
Shawn Siefkas <shawn.siefkas@meredith.com>
|
Shawn Siefkas <shawn.siefkas@meredith.com>
|
||||||
Shih-Yuan Lee <fourdollars@gmail.com>
|
Shih-Yuan Lee <fourdollars@gmail.com>
|
||||||
@@ -378,14 +503,19 @@ Sjoerd Langkemper <sjoerd-github@linuxonly.nl>
|
|||||||
Solomon Hykes <solomon@docker.com>
|
Solomon Hykes <solomon@docker.com>
|
||||||
Song Gao <song@gao.io>
|
Song Gao <song@gao.io>
|
||||||
Soulou <leo@unbekandt.eu>
|
Soulou <leo@unbekandt.eu>
|
||||||
|
soulshake <amy@gandi.net>
|
||||||
Sridatta Thatipamala <sthatipamala@gmail.com>
|
Sridatta Thatipamala <sthatipamala@gmail.com>
|
||||||
Sridhar Ratnakumar <sridharr@activestate.com>
|
Sridhar Ratnakumar <sridharr@activestate.com>
|
||||||
Steeve Morin <steeve.morin@gmail.com>
|
Steeve Morin <steeve.morin@gmail.com>
|
||||||
Stefan Praszalowicz <stefan@greplin.com>
|
Stefan Praszalowicz <stefan@greplin.com>
|
||||||
|
Stephen Crosby <stevecrozz@gmail.com>
|
||||||
Steven Burgess <steven.a.burgess@hotmail.com>
|
Steven Burgess <steven.a.burgess@hotmail.com>
|
||||||
sudosurootdev <sudosurootdev@gmail.com>
|
sudosurootdev <sudosurootdev@gmail.com>
|
||||||
Sven Dowideit <SvenDowideit@home.org.au>
|
Sven Dowideit <svendowideit@home.org.au>
|
||||||
Sylvain Bellemare <sylvain.bellemare@ezeep.com>
|
Sylvain Bellemare <sylvain.bellemare@ezeep.com>
|
||||||
|
Sébastien <sebastien@yoozio.com>
|
||||||
|
Sébastien Luttringer <seblu@seblu.net>
|
||||||
|
Sébastien Stormacq <sebsto@users.noreply.github.com>
|
||||||
tang0th <tang0th@gmx.com>
|
tang0th <tang0th@gmx.com>
|
||||||
Tatsuki Sugiura <sugi@nemui.org>
|
Tatsuki Sugiura <sugi@nemui.org>
|
||||||
Tehmasp Chaudhri <tehmasp@gmail.com>
|
Tehmasp Chaudhri <tehmasp@gmail.com>
|
||||||
@@ -400,19 +530,24 @@ Thomas Schroeter <thomas@cliqz.com>
|
|||||||
Tianon Gravi <admwiggin@gmail.com>
|
Tianon Gravi <admwiggin@gmail.com>
|
||||||
Tibor Vass <teabee89@gmail.com>
|
Tibor Vass <teabee89@gmail.com>
|
||||||
Tim Bosse <taim@bosboot.org>
|
Tim Bosse <taim@bosboot.org>
|
||||||
Timothy Hobbs <timothyhobbs@seznam.cz>
|
|
||||||
Tim Ruffles <oi@truffles.me.uk>
|
Tim Ruffles <oi@truffles.me.uk>
|
||||||
|
Tim Ruffles <timruffles@googlemail.com>
|
||||||
Tim Terhorst <mynamewastaken+git@gmail.com>
|
Tim Terhorst <mynamewastaken+git@gmail.com>
|
||||||
|
Timothy Hobbs <timothyhobbs@seznam.cz>
|
||||||
tjmehta <tj@init.me>
|
tjmehta <tj@init.me>
|
||||||
Tobias Bieniek <Tobias.Bieniek@gmx.de>
|
Tobias Bieniek <Tobias.Bieniek@gmx.de>
|
||||||
|
Tobias Gesellchen <tobias@gesellix.de>
|
||||||
Tobias Schmidt <ts@soundcloud.com>
|
Tobias Schmidt <ts@soundcloud.com>
|
||||||
Tobias Schwab <tobias.schwab@dynport.de>
|
Tobias Schwab <tobias.schwab@dynport.de>
|
||||||
Todd Lunter <tlunter@gmail.com>
|
Todd Lunter <tlunter@gmail.com>
|
||||||
Tom Fotherby <tom+github@peopleperhour.com>
|
Tom Fotherby <tom+github@peopleperhour.com>
|
||||||
Tom Hulihan <hulihan.tom159@gmail.com>
|
Tom Hulihan <hulihan.tom159@gmail.com>
|
||||||
|
Tom Maaswinkel <tom.maaswinkel@12wiki.eu>
|
||||||
Tommaso Visconti <tommaso.visconti@gmail.com>
|
Tommaso Visconti <tommaso.visconti@gmail.com>
|
||||||
Tony Daws <tony@daws.ca>
|
Tony Daws <tony@daws.ca>
|
||||||
|
tpng <benny.tpng@gmail.com>
|
||||||
Travis Cline <travis.cline@gmail.com>
|
Travis Cline <travis.cline@gmail.com>
|
||||||
|
Trent Ogren <tedwardo2@gmail.com>
|
||||||
Tyler Brock <tyler.brock@gmail.com>
|
Tyler Brock <tyler.brock@gmail.com>
|
||||||
Tzu-Jung Lee <roylee17@gmail.com>
|
Tzu-Jung Lee <roylee17@gmail.com>
|
||||||
Ulysse Carion <ulyssecarion@gmail.com>
|
Ulysse Carion <ulyssecarion@gmail.com>
|
||||||
@@ -434,21 +569,29 @@ Vivek Agarwal <me@vivek.im>
|
|||||||
Vladimir Bulyga <xx@ccxx.cc>
|
Vladimir Bulyga <xx@ccxx.cc>
|
||||||
Vladimir Kirillov <proger@wilab.org.ua>
|
Vladimir Kirillov <proger@wilab.org.ua>
|
||||||
Vladimir Rutsky <altsysrq@gmail.com>
|
Vladimir Rutsky <altsysrq@gmail.com>
|
||||||
|
waitingkuo <waitingkuo0527@gmail.com>
|
||||||
Walter Leibbrandt <github@wrl.co.za>
|
Walter Leibbrandt <github@wrl.co.za>
|
||||||
Walter Stanish <walter@pratyeka.org>
|
Walter Stanish <walter@pratyeka.org>
|
||||||
WarheadsSE <max@warheads.net>
|
WarheadsSE <max@warheads.net>
|
||||||
Wes Morgan <cap10morgan@gmail.com>
|
Wes Morgan <cap10morgan@gmail.com>
|
||||||
Will Dietz <w@wdtz.org>
|
Will Dietz <w@wdtz.org>
|
||||||
William Delanoue <william.delanoue@gmail.com>
|
|
||||||
William Henry <whenry@redhat.com>
|
|
||||||
Will Rouesnel <w.rouesnel@gmail.com>
|
Will Rouesnel <w.rouesnel@gmail.com>
|
||||||
Will Weaver <monkey@buildingbananas.com>
|
Will Weaver <monkey@buildingbananas.com>
|
||||||
|
William Delanoue <william.delanoue@gmail.com>
|
||||||
|
William Henry <whenry@redhat.com>
|
||||||
|
William Riancho <wr.wllm@gmail.com>
|
||||||
|
William Thurston <thurstw@amazon.com>
|
||||||
|
wyc <wayne@neverfear.org>
|
||||||
Xiuming Chen <cc@cxm.cc>
|
Xiuming Chen <cc@cxm.cc>
|
||||||
Yang Bai <hamo.by@gmail.com>
|
Yang Bai <hamo.by@gmail.com>
|
||||||
Yasunori Mahata <nori@mahata.net>
|
Yasunori Mahata <nori@mahata.net>
|
||||||
Yurii Rashkovskii <yrashk@gmail.com>
|
Yurii Rashkovskii <yrashk@gmail.com>
|
||||||
|
Zac Dover <zdover@redhat.com>
|
||||||
Zain Memon <zain@inzain.net>
|
Zain Memon <zain@inzain.net>
|
||||||
Zaiste! <oh@zaiste.net>
|
Zaiste! <oh@zaiste.net>
|
||||||
|
Zane DeGraffenried <zane.deg@gmail.com>
|
||||||
Zilin Du <zilin.du@gmail.com>
|
Zilin Du <zilin.du@gmail.com>
|
||||||
zimbatm <zimbatm@zimbatm.com>
|
zimbatm <zimbatm@zimbatm.com>
|
||||||
|
Zoltan Tombol <zoltan.tombol@gmail.com>
|
||||||
zqh <zqhxuyuan@gmail.com>
|
zqh <zqhxuyuan@gmail.com>
|
||||||
|
Álvaro Lázaro <alvaro.lazaro.g@gmail.com>
|
||||||
|
|||||||
+94
-8
@@ -1,8 +1,94 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 1.2.0 (2014-08-20)
|
||||||
|
|
||||||
|
#### Runtime
|
||||||
|
+ Make /etc/hosts /etc/resolv.conf and /etc/hostname editable at runtime
|
||||||
|
+ Auto-restart containers using policies
|
||||||
|
+ Use /var/lib/docker/tmp for large temporary files
|
||||||
|
+ `--cap-add` and `--cap-drop` to tweak what linux capability you want
|
||||||
|
+ `--device` to use devices in containers
|
||||||
|
|
||||||
|
#### Client
|
||||||
|
+ `docker search` on private registries
|
||||||
|
+ Add `exited` filter to `docker ps --filter`
|
||||||
|
* `docker rm -f` now kills instead of stop
|
||||||
|
+ Support for IPv6 addresses in `--dns` flag
|
||||||
|
|
||||||
|
#### Proxy
|
||||||
|
+ Proxy instances in separate processes
|
||||||
|
* Small bug fix on UDP proxy
|
||||||
|
|
||||||
|
## 1.1.2 (2014-07-23)
|
||||||
|
|
||||||
|
#### Runtime
|
||||||
|
+ Fix port allocation for existing containers
|
||||||
|
+ Fix containers restart on daemon restart
|
||||||
|
|
||||||
|
#### Packaging
|
||||||
|
+ Fix /etc/init.d/docker issue on Debian
|
||||||
|
|
||||||
|
## 1.1.1 (2014-07-09)
|
||||||
|
|
||||||
|
#### Builder
|
||||||
|
* Fix issue with ADD
|
||||||
|
|
||||||
|
## 1.1.0 (2014-07-03)
|
||||||
|
|
||||||
|
#### Notable features since 1.0.1
|
||||||
|
+ Add `.dockerignore` support
|
||||||
|
+ Pause containers during `docker commit`
|
||||||
|
+ Add `--tail` to `docker logs`
|
||||||
|
|
||||||
|
#### Builder
|
||||||
|
+ Allow a tar file as context for `docker build`
|
||||||
|
* Fix issue with white-spaces and multi-lines in `Dockerfiles`
|
||||||
|
|
||||||
|
#### Runtime
|
||||||
|
* Overall performance improvements
|
||||||
|
* Allow `/` as source of `docker run -v`
|
||||||
|
* Fix port allocation
|
||||||
|
* Fix bug in `docker save`
|
||||||
|
* Add links information to `docker inspect`
|
||||||
|
|
||||||
|
#### Client
|
||||||
|
* Improve command line parsing for `docker commit`
|
||||||
|
|
||||||
|
#### Remote API
|
||||||
|
* Improve status code for the `start` and `stop` endpoints
|
||||||
|
|
||||||
|
## 1.0.1 (2014-06-19)
|
||||||
|
|
||||||
|
#### Notable features since 1.0.0
|
||||||
|
* Enhance security for the LXC driver
|
||||||
|
|
||||||
|
#### Builder
|
||||||
|
* Fix `ONBUILD` instruction passed to grandchildren
|
||||||
|
|
||||||
|
#### Runtime
|
||||||
|
* Fix events subscription
|
||||||
|
* Fix /etc/hostname file with host networking
|
||||||
|
* Allow `-h` and `--net=none`
|
||||||
|
* Fix issue with hotplug devices in `--privileged`
|
||||||
|
|
||||||
|
#### Client
|
||||||
|
* Fix artifacts with events
|
||||||
|
* Fix a panic with empty flags
|
||||||
|
* Fix `docker cp` on Mac OS X
|
||||||
|
|
||||||
|
#### Miscellaneous
|
||||||
|
* Fix compilation on Mac OS X
|
||||||
|
* Fix several races
|
||||||
|
|
||||||
|
## 1.0.0 (2014-06-09)
|
||||||
|
|
||||||
|
#### Notable features since 0.12.0
|
||||||
|
* Production support
|
||||||
|
|
||||||
## 0.12.0 (2014-06-05)
|
## 0.12.0 (2014-06-05)
|
||||||
|
|
||||||
#### Notable features since 0.11.0
|
#### Notable features since 0.11.0
|
||||||
|
* 40+ various improvements to stability, performance and usability
|
||||||
* New `COPY` Dockerfile instruction to allow copying a local file from the context into the container without ever extracting if the file is a tar file
|
* New `COPY` Dockerfile instruction to allow copying a local file from the context into the container without ever extracting if the file is a tar file
|
||||||
* Inherit file permissions from the host on `ADD`
|
* Inherit file permissions from the host on `ADD`
|
||||||
* New `pause` and `unpause` commands to allow pausing and unpausing of containers using cgroup freezer
|
* New `pause` and `unpause` commands to allow pausing and unpausing of containers using cgroup freezer
|
||||||
@@ -246,7 +332,7 @@
|
|||||||
- Add newlines to the JSON stream functions.
|
- Add newlines to the JSON stream functions.
|
||||||
|
|
||||||
#### Runtime
|
#### Runtime
|
||||||
* Do not ping the registry from the CLI. All requests to registres flow through the daemon.
|
* Do not ping the registry from the CLI. All requests to registries flow through the daemon.
|
||||||
- Check for nil information return in the lxc driver. This fixes panics with older lxc versions.
|
- Check for nil information return in the lxc driver. This fixes panics with older lxc versions.
|
||||||
- Devicemapper: cleanups and fix for unmount. Fixes two problems which were causing unmount to fail intermittently.
|
- Devicemapper: cleanups and fix for unmount. Fixes two problems which were causing unmount to fail intermittently.
|
||||||
- Devicemapper: remove directory when removing device. Directories don't get left behind when removing the device.
|
- Devicemapper: remove directory when removing device. Directories don't get left behind when removing the device.
|
||||||
@@ -838,7 +924,7 @@ With the ongoing changes to the networking and execution subsystems of docker te
|
|||||||
|
|
||||||
+ Add domainname support
|
+ Add domainname support
|
||||||
+ Implement image filtering with path.Match
|
+ Implement image filtering with path.Match
|
||||||
* Remove unnecesasry warnings
|
* Remove unnecessary warnings
|
||||||
* Remove os/user dependency
|
* Remove os/user dependency
|
||||||
* Only mount the hostname file when the config exists
|
* Only mount the hostname file when the config exists
|
||||||
* Handle signals within the `docker login` command
|
* Handle signals within the `docker login` command
|
||||||
@@ -861,7 +947,7 @@ With the ongoing changes to the networking and execution subsystems of docker te
|
|||||||
+ Hack: Vendor all dependencies
|
+ Hack: Vendor all dependencies
|
||||||
* Remote API: Bump to v1.5
|
* Remote API: Bump to v1.5
|
||||||
* Packaging: Break down hack/make.sh into small scripts, one per 'bundle': test, binary, ubuntu etc.
|
* Packaging: Break down hack/make.sh into small scripts, one per 'bundle': test, binary, ubuntu etc.
|
||||||
* Documentation: General improvments
|
* Documentation: General improvements
|
||||||
|
|
||||||
## 0.6.1 (2013-08-23)
|
## 0.6.1 (2013-08-23)
|
||||||
|
|
||||||
@@ -1131,7 +1217,7 @@ With the ongoing changes to the networking and execution subsystems of docker te
|
|||||||
* Prevent rm of running containers
|
* Prevent rm of running containers
|
||||||
* Use go1.1 cookiejar
|
* Use go1.1 cookiejar
|
||||||
- Fix issue detaching from running TTY container
|
- Fix issue detaching from running TTY container
|
||||||
- Forbid parralel push/pull for a single image/repo. Fixes #311
|
- Forbid parallel push/pull for a single image/repo. Fixes #311
|
||||||
- Fix race condition within Run command when attaching.
|
- Fix race condition within Run command when attaching.
|
||||||
|
|
||||||
#### Client
|
#### Client
|
||||||
@@ -1247,7 +1333,7 @@ With the ongoing changes to the networking and execution subsystems of docker te
|
|||||||
+ Add caching to docker builder
|
+ Add caching to docker builder
|
||||||
+ Add support for docker builder with native API as top level command
|
+ Add support for docker builder with native API as top level command
|
||||||
+ Implement ENV within docker builder
|
+ Implement ENV within docker builder
|
||||||
- Check the command existance prior create and add Unit tests for the case
|
- Check the command existence prior create and add Unit tests for the case
|
||||||
* use any whitespaces instead of tabs
|
* use any whitespaces instead of tabs
|
||||||
|
|
||||||
#### Runtime
|
#### Runtime
|
||||||
@@ -1286,13 +1372,13 @@ With the ongoing changes to the networking and execution subsystems of docker te
|
|||||||
|
|
||||||
#### Runtime
|
#### Runtime
|
||||||
|
|
||||||
- Fix the command existance check
|
- Fix the command existence check
|
||||||
- strings.Split may return an empty string on no match
|
- strings.Split may return an empty string on no match
|
||||||
- Fix an index out of range crash if cgroup memory is not
|
- Fix an index out of range crash if cgroup memory is not
|
||||||
|
|
||||||
#### Documentation
|
#### Documentation
|
||||||
|
|
||||||
* Various improvments
|
* Various improvements
|
||||||
+ New example: sharing data between 2 couchdb databases
|
+ New example: sharing data between 2 couchdb databases
|
||||||
|
|
||||||
#### Other
|
#### Other
|
||||||
@@ -1322,7 +1408,7 @@ With the ongoing changes to the networking and execution subsystems of docker te
|
|||||||
## 0.2.0 (2013-04-23)
|
## 0.2.0 (2013-04-23)
|
||||||
|
|
||||||
- Runtime: ghost containers can be killed and waited for
|
- Runtime: ghost containers can be killed and waited for
|
||||||
* Documentation: update install intructions
|
* Documentation: update install instructions
|
||||||
- Packaging: fix Vagrantfile
|
- Packaging: fix Vagrantfile
|
||||||
- Development: automate releasing binaries and ubuntu packages
|
- Development: automate releasing binaries and ubuntu packages
|
||||||
+ Add a changelog
|
+ Add a changelog
|
||||||
|
|||||||
+155
-43
@@ -4,20 +4,58 @@ Want to hack on Docker? Awesome! Here are instructions to get you
|
|||||||
started. They are probably not perfect, please let us know if anything
|
started. They are probably not perfect, please let us know if anything
|
||||||
feels wrong or incomplete.
|
feels wrong or incomplete.
|
||||||
|
|
||||||
|
## Topics
|
||||||
|
|
||||||
|
* [Security Reports](#security-reports)
|
||||||
|
* [Design and Cleanup Proposals](#design-and-cleanup-proposals)
|
||||||
|
* [Reporting Issues](#reporting-issues)
|
||||||
|
* [Build Environment](#build-environment)
|
||||||
|
* [Contribution Guidelines](#contribution-guidelines)
|
||||||
|
* [Community Guidelines](#docker-community-guidelines)
|
||||||
|
|
||||||
|
## Security Reports
|
||||||
|
|
||||||
|
Please **DO NOT** file an issue for security related issues. Please send your
|
||||||
|
reports to [security@docker.com](mailto:security@docker.com) instead.
|
||||||
|
|
||||||
|
## Design and Cleanup Proposals
|
||||||
|
|
||||||
|
When considering a design proposal, we are looking for:
|
||||||
|
|
||||||
|
* A description of the problem this design proposal solves
|
||||||
|
* An issue -- not a pull request -- that describes what you will take action on
|
||||||
|
* Please prefix your issue with `Proposal:` in the title
|
||||||
|
* Please review [the existing Proposals](https://github.com/dotcloud/docker/issues?direction=asc&labels=Proposal&page=1&sort=created&state=open)
|
||||||
|
before reporting a new issue. You can always pair with someone if you both
|
||||||
|
have the same idea.
|
||||||
|
|
||||||
|
When considering a cleanup task, we are looking for:
|
||||||
|
|
||||||
|
* A description of the refactors made
|
||||||
|
* Please note any logic changes if necessary
|
||||||
|
* A pull request with the code
|
||||||
|
* Please prefix your PR's title with `Cleanup:` so we can quickly address it.
|
||||||
|
* Your pull request must remain up to date with master, so rebase as necessary.
|
||||||
|
|
||||||
## Reporting Issues
|
## Reporting Issues
|
||||||
|
|
||||||
When reporting [issues](https://github.com/dotcloud/docker/issues)
|
When reporting [issues](https://github.com/docker/docker/issues) on
|
||||||
on GitHub please include your host OS (Ubuntu 12.04, Fedora 19, etc),
|
GitHub please include your host OS (Ubuntu 12.04, Fedora 19, etc).
|
||||||
the output of `uname -a` and the output of `docker version` along with
|
Please include:
|
||||||
the output of `docker info`. Please include the steps required to reproduce
|
|
||||||
the problem if possible and applicable.
|
* The output of `uname -a`.
|
||||||
This information will help us review and fix your issue faster.
|
* The output of `docker version`.
|
||||||
|
* The output of `docker -D info`.
|
||||||
|
|
||||||
|
Please also include the steps required to reproduce the problem if
|
||||||
|
possible and applicable. This information will help us review and fix
|
||||||
|
your issue faster.
|
||||||
|
|
||||||
## Build Environment
|
## Build Environment
|
||||||
|
|
||||||
For instructions on setting up your development environment, please
|
For instructions on setting up your development environment, please
|
||||||
see our dedicated [dev environment setup
|
see our dedicated [dev environment setup
|
||||||
docs](http://docs.docker.io/en/latest/contributing/devenvironment/).
|
docs](http://docs.docker.com/contributing/devenvironment/).
|
||||||
|
|
||||||
## Contribution guidelines
|
## Contribution guidelines
|
||||||
|
|
||||||
@@ -34,7 +72,7 @@ received feedback on what to improve.
|
|||||||
We're trying very hard to keep Docker lean and focused. We don't want it
|
We're trying very hard to keep Docker lean and focused. We don't want it
|
||||||
to do everything for everybody. This means that we might decide against
|
to do everything for everybody. This means that we might decide against
|
||||||
incorporating a new feature. However, there might be a way to implement
|
incorporating a new feature. However, there might be a way to implement
|
||||||
that feature *on top of* docker.
|
that feature *on top of* Docker.
|
||||||
|
|
||||||
### Discuss your design on the mailing list
|
### Discuss your design on the mailing list
|
||||||
|
|
||||||
@@ -48,7 +86,7 @@ else is working on the same thing.
|
|||||||
### Create issues...
|
### Create issues...
|
||||||
|
|
||||||
Any significant improvement should be documented as [a GitHub
|
Any significant improvement should be documented as [a GitHub
|
||||||
issue](https://github.com/dotcloud/docker/issues) before anybody
|
issue](https://github.com/docker/docker/issues) before anybody
|
||||||
starts working on it.
|
starts working on it.
|
||||||
|
|
||||||
### ...but check for existing issues first!
|
### ...but check for existing issues first!
|
||||||
@@ -60,12 +98,12 @@ help prioritize the most common problems and requests.
|
|||||||
|
|
||||||
### Conventions
|
### Conventions
|
||||||
|
|
||||||
Fork the repo and make changes on your fork in a feature branch:
|
Fork the repository and make changes on your fork in a feature branch:
|
||||||
|
|
||||||
- If it's a bugfix branch, name it XXX-something where XXX is the number of the
|
- If it's a bug fix branch, name it XXXX-something where XXXX is the number of the
|
||||||
issue
|
issue.
|
||||||
- If it's a feature branch, create an enhancement issue to announce your
|
- If it's a feature branch, create an enhancement issue to announce your
|
||||||
intentions, and name it XXX-something where XXX is the number of the issue.
|
intentions, and name it XXXX-something where XXXX is the number of the issue.
|
||||||
|
|
||||||
Submit unit tests for your changes. Go has a great test framework built in; use
|
Submit unit tests for your changes. Go has a great test framework built in; use
|
||||||
it! Take a look at existing tests for inspiration. Run the full test suite on
|
it! Take a look at existing tests for inspiration. Run the full test suite on
|
||||||
@@ -73,18 +111,16 @@ your branch before submitting a pull request.
|
|||||||
|
|
||||||
Update the documentation when creating or modifying features. Test
|
Update the documentation when creating or modifying features. Test
|
||||||
your documentation changes for clarity, concision, and correctness, as
|
your documentation changes for clarity, concision, and correctness, as
|
||||||
well as a clean documentation build. See ``docs/README.md`` for more
|
well as a clean documentation build. See `docs/README.md` for more
|
||||||
information on building the docs and how docs get released.
|
information on building the docs and how they get released.
|
||||||
|
|
||||||
Write clean code. Universally formatted code promotes ease of writing, reading,
|
Write clean code. Universally formatted code promotes ease of writing, reading,
|
||||||
and maintenance. Always run `gofmt -s -w file.go` on each changed file before
|
and maintenance. Always run `gofmt -s -w file.go` on each changed file before
|
||||||
committing your changes. Most editors have plugins that do this automatically.
|
committing your changes. Most editors have plug-ins that do this automatically.
|
||||||
|
|
||||||
Pull requests descriptions should be as clear as possible and include a
|
Pull requests descriptions should be as clear as possible and include a
|
||||||
reference to all the issues that they address.
|
reference to all the issues that they address.
|
||||||
|
|
||||||
Pull requests must not contain commits from other users or branches.
|
|
||||||
|
|
||||||
Commit messages must start with a capitalized and short summary (max. 50
|
Commit messages must start with a capitalized and short summary (max. 50
|
||||||
chars) written in the imperative, followed by an optional, more detailed
|
chars) written in the imperative, followed by an optional, more detailed
|
||||||
explanatory text which is separated from the summary by an empty line.
|
explanatory text which is separated from the summary by an empty line.
|
||||||
@@ -95,26 +131,33 @@ sure to post a comment after pushing. The new commits will show up in the pull
|
|||||||
request automatically, but the reviewers will not be notified unless you
|
request automatically, but the reviewers will not be notified unless you
|
||||||
comment.
|
comment.
|
||||||
|
|
||||||
|
Pull requests must be cleanly rebased ontop of master without multiple branches
|
||||||
|
mixed into the PR.
|
||||||
|
|
||||||
|
**Git tip**: If your PR no longer merges cleanly, use `rebase master` in your
|
||||||
|
feature branch to update your pull request rather than `merge master`.
|
||||||
|
|
||||||
Before the pull request is merged, make sure that you squash your commits into
|
Before the pull request is merged, make sure that you squash your commits into
|
||||||
logical units of work using `git rebase -i` and `git push -f`. After every
|
logical units of work using `git rebase -i` and `git push -f`. After every
|
||||||
commit the test suite should be passing. Include documentation changes in the
|
commit the test suite should be passing. Include documentation changes in the
|
||||||
same commit so that a revert would remove all traces of the feature or fix.
|
same commit so that a revert would remove all traces of the feature or fix.
|
||||||
|
|
||||||
Commits that fix or close an issue should include a reference like `Closes #XXX`
|
Commits that fix or close an issue should include a reference like
|
||||||
or `Fixes #XXX`, which will automatically close the issue when merged.
|
`Closes #XXXX` or `Fixes #XXXX`, which will automatically close the
|
||||||
|
issue when merged.
|
||||||
|
|
||||||
Please do not add yourself to the AUTHORS file, as it is regenerated
|
Please do not add yourself to the `AUTHORS` file, as it is regenerated
|
||||||
regularly from the Git history.
|
regularly from the Git history.
|
||||||
|
|
||||||
### Merge approval
|
### Merge approval
|
||||||
|
|
||||||
Docker maintainers use LGTM (looks good to me) in comments on the code review
|
Docker maintainers use LGTM (Looks Good To Me) in comments on the code review
|
||||||
to indicate acceptance.
|
to indicate acceptance.
|
||||||
|
|
||||||
A change requires LGTMs from an absolute majority of the maintainers of each
|
A change requires LGTMs from an absolute majority of the maintainers of each
|
||||||
component affected. For example, if a change affects docs/ and registry/, it
|
component affected. For example, if a change affects `docs/` and `registry/`, it
|
||||||
needs an absolute majority from the maintainers of docs/ AND, separately, an
|
needs an absolute majority from the maintainers of `docs/` AND, separately, an
|
||||||
absolute majority of the maintainers of registry.
|
absolute majority of the maintainers of `registry/`.
|
||||||
|
|
||||||
For more details see [MAINTAINERS.md](hack/MAINTAINERS.md)
|
For more details see [MAINTAINERS.md](hack/MAINTAINERS.md)
|
||||||
|
|
||||||
@@ -137,7 +180,6 @@ San Francisco, CA 94110 USA
|
|||||||
Everyone is permitted to copy and distribute verbatim copies of this
|
Everyone is permitted to copy and distribute verbatim copies of this
|
||||||
license document, but changing it is not allowed.
|
license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
Developer's Certificate of Origin 1.1
|
Developer's Certificate of Origin 1.1
|
||||||
|
|
||||||
By making a contribution to this project, I certify that:
|
By making a contribution to this project, I certify that:
|
||||||
@@ -165,20 +207,18 @@ By making a contribution to this project, I certify that:
|
|||||||
this project or the open source license(s) involved.
|
this project or the open source license(s) involved.
|
||||||
```
|
```
|
||||||
|
|
||||||
then you just add a line to every git commit message:
|
Then you just add a line to every git commit message:
|
||||||
|
|
||||||
Docker-DCO-1.1-Signed-off-by: Joe Smith <joe.smith@email.com> (github: github_handle)
|
Signed-off-by: Joe Smith <joe.smith@email.com>
|
||||||
|
|
||||||
using your real name (sorry, no pseudonyms or anonymous contributions.)
|
Using your real name (sorry, no pseudonyms or anonymous contributions.)
|
||||||
|
|
||||||
One way to automate this, is customise your get ``commit.template`` by adding
|
If you set your `user.name` and `user.email` git configs, you can sign your
|
||||||
a ``prepare-commit-msg`` hook to your docker checkout:
|
commit automatically with `git commit -s`.
|
||||||
|
|
||||||
```
|
Note that the old-style `Docker-DCO-1.1-Signed-off-by: ...` format is still
|
||||||
curl -o .git/hooks/prepare-commit-msg https://raw.githubusercontent.com/dotcloud/docker/master/contrib/prepare-commit-msg.hook && chmod +x .git/hooks/prepare-commit-msg
|
accepted, so there is no need to update outstanding pull requests to the new
|
||||||
```
|
format right away, but please do adjust your processes for future contributions.
|
||||||
|
|
||||||
* Note: the above script expects to find your GitHub user name in ``git config --get github.user``
|
|
||||||
|
|
||||||
#### Small patch exception
|
#### Small patch exception
|
||||||
|
|
||||||
@@ -190,15 +230,87 @@ There are several exceptions to the signing requirement. Currently these are:
|
|||||||
* Your patch fixes Markdown formatting or syntax errors in the
|
* Your patch fixes Markdown formatting or syntax errors in the
|
||||||
documentation contained in the `docs` directory.
|
documentation contained in the `docs` directory.
|
||||||
|
|
||||||
If you have any questions, please refer to the FAQ in the [docs](http://docs.docker.io)
|
If you have any questions, please refer to the FAQ in the [docs](http://docs.docker.com)
|
||||||
|
|
||||||
### How can I become a maintainer?
|
### How can I become a maintainer?
|
||||||
|
|
||||||
* Step 1: learn the component inside out
|
* Step 1: Learn the component inside out
|
||||||
* Step 2: make yourself useful by contributing code, bugfixes, support etc.
|
* Step 2: Make yourself useful by contributing code, bug fixes, support etc.
|
||||||
* Step 3: volunteer on the irc channel (#docker@freenode)
|
* Step 3: Volunteer on the IRC channel (#docker at Freenode)
|
||||||
* Step 4: propose yourself at a scheduled docker meeting in #docker-dev
|
* Step 4: Propose yourself at a scheduled docker meeting in #docker-dev
|
||||||
|
|
||||||
Don't forget: being a maintainer is a time investment. Make sure you will have time to make yourself available.
|
Don't forget: being a maintainer is a time investment. Make sure you
|
||||||
You don't have to be a maintainer to make a difference on the project!
|
will have time to make yourself available. You don't have to be a
|
||||||
|
maintainer to make a difference on the project!
|
||||||
|
|
||||||
|
### IRC Meetings
|
||||||
|
|
||||||
|
There are two monthly meetings taking place on #docker-dev IRC to accomodate all timezones.
|
||||||
|
Anybody can ask for a topic to be discussed prior to the meeting.
|
||||||
|
|
||||||
|
If you feel the conversation is going off-topic, feel free to point it out.
|
||||||
|
|
||||||
|
For the exact dates and times, have a look at [the irc-minutes repo](https://github.com/docker/irc-minutes).
|
||||||
|
They also contain all the notes from previous meetings.
|
||||||
|
|
||||||
|
## Docker Community Guidelines
|
||||||
|
|
||||||
|
We want to keep the Docker community awesome, growing and collaborative. We
|
||||||
|
need your help to keep it that way. To help with this we've come up with some
|
||||||
|
general guidelines for the community as a whole:
|
||||||
|
|
||||||
|
* Be nice: Be courteous, respectful and polite to fellow community members: no
|
||||||
|
regional, racial, gender, or other abuse will be tolerated. We like nice people
|
||||||
|
way better than mean ones!
|
||||||
|
|
||||||
|
* Encourage diversity and participation: Make everyone in our community
|
||||||
|
feel welcome, regardless of their background and the extent of their
|
||||||
|
contributions, and do everything possible to encourage participation in
|
||||||
|
our community.
|
||||||
|
|
||||||
|
* Keep it legal: Basically, don't get us in trouble. Share only content that
|
||||||
|
you own, do not share private or sensitive information, and don't break the
|
||||||
|
law.
|
||||||
|
|
||||||
|
* Stay on topic: Make sure that you are posting to the correct channel
|
||||||
|
and avoid off-topic discussions. Remember when you update an issue or
|
||||||
|
respond to an email you are potentially sending to a large number of
|
||||||
|
people. Please consider this before you update. Also remember that
|
||||||
|
nobody likes spam.
|
||||||
|
|
||||||
|
### Guideline Violations — 3 Strikes Method
|
||||||
|
|
||||||
|
The point of this section is not to find opportunities to punish people, but we
|
||||||
|
do need a fair way to deal with people who are making our community suck.
|
||||||
|
|
||||||
|
1. First occurrence: We'll give you a friendly, but public reminder that the
|
||||||
|
behavior is inappropriate according to our guidelines.
|
||||||
|
|
||||||
|
2. Second occurrence: We will send you a private message with a warning that
|
||||||
|
any additional violations will result in removal from the community.
|
||||||
|
|
||||||
|
3. Third occurrence: Depending on the violation, we may need to delete or ban
|
||||||
|
your account.
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
|
||||||
|
* Obvious spammers are banned on first occurrence. If we don't do this, we'll
|
||||||
|
have spam all over the place.
|
||||||
|
|
||||||
|
* Violations are forgiven after 6 months of good behavior, and we won't
|
||||||
|
hold a grudge.
|
||||||
|
|
||||||
|
* People who commit minor infractions will get some education,
|
||||||
|
rather than hammering them in the 3 strikes process.
|
||||||
|
|
||||||
|
* The rules apply equally to everyone in the community, no matter how
|
||||||
|
much you've contributed.
|
||||||
|
|
||||||
|
* Extreme violations of a threatening, abusive, destructive or illegal nature
|
||||||
|
will be addressed immediately and are not subject to 3 strikes or
|
||||||
|
forgiveness.
|
||||||
|
|
||||||
|
* Contact james@docker.com to report abuse or appeal violations. In the case of
|
||||||
|
appeals, we know that mistakes happen, and we'll work with you to come up with
|
||||||
|
a fair solution if there has been a misunderstanding.
|
||||||
|
|
||||||
|
|||||||
+14
-8
@@ -6,7 +6,7 @@
|
|||||||
# docker build -t docker .
|
# docker build -t docker .
|
||||||
#
|
#
|
||||||
# # Mount your source in an interactive container for quick testing:
|
# # Mount your source in an interactive container for quick testing:
|
||||||
# docker run -v `pwd`:/go/src/github.com/dotcloud/docker --privileged -i -t docker bash
|
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||||
#
|
#
|
||||||
# # Run the test suite:
|
# # Run the test suite:
|
||||||
# docker run --privileged docker hack/make.sh test
|
# docker run --privileged docker hack/make.sh test
|
||||||
@@ -28,8 +28,7 @@ FROM ubuntu:14.04
|
|||||||
MAINTAINER Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
MAINTAINER Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||||
|
|
||||||
# Packaged dependencies
|
# Packaged dependencies
|
||||||
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
RUN apt-get update && apt-get install -y \
|
||||||
apt-utils \
|
|
||||||
aufs-tools \
|
aufs-tools \
|
||||||
automake \
|
automake \
|
||||||
btrfs-tools \
|
btrfs-tools \
|
||||||
@@ -43,7 +42,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
|||||||
libsqlite3-dev \
|
libsqlite3-dev \
|
||||||
lxc=1.0* \
|
lxc=1.0* \
|
||||||
mercurial \
|
mercurial \
|
||||||
pandoc \
|
parallel \
|
||||||
reprepro \
|
reprepro \
|
||||||
ruby1.9.1 \
|
ruby1.9.1 \
|
||||||
ruby1.9.1-dev \
|
ruby1.9.1-dev \
|
||||||
@@ -60,9 +59,10 @@ RUN cd /usr/local/lvm2 && ./configure --enable-static_link && make device-mapper
|
|||||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||||
|
|
||||||
# Install Go
|
# Install Go
|
||||||
RUN curl -s https://go.googlecode.com/files/go1.2.1.src.tar.gz | tar -v -C /usr/local -xz
|
RUN curl -sSL https://golang.org/dl/go1.3.1.src.tar.gz | tar -v -C /usr/local -xz
|
||||||
ENV PATH /usr/local/go/bin:$PATH
|
ENV PATH /usr/local/go/bin:$PATH
|
||||||
ENV GOPATH /go:/go/src/github.com/dotcloud/docker/vendor
|
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
|
||||||
|
ENV PATH /go/bin:$PATH
|
||||||
RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1
|
RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1
|
||||||
|
|
||||||
# Compile Go for cross compilation
|
# Compile Go for cross compilation
|
||||||
@@ -80,6 +80,12 @@ RUN go get code.google.com/p/go.tools/cmd/cover
|
|||||||
# TODO replace FPM with some very minimal debhelper stuff
|
# TODO replace FPM with some very minimal debhelper stuff
|
||||||
RUN gem install --no-rdoc --no-ri fpm --version 1.0.2
|
RUN gem install --no-rdoc --no-ri fpm --version 1.0.2
|
||||||
|
|
||||||
|
# Install man page generator
|
||||||
|
RUN mkdir -p /go/src/github.com/cpuguy83 \
|
||||||
|
&& git clone -b v1 https://github.com/cpuguy83/go-md2man.git /go/src/github.com/cpuguy83/go-md2man \
|
||||||
|
&& cd /go/src/github.com/cpuguy83/go-md2man \
|
||||||
|
&& go get -v ./...
|
||||||
|
|
||||||
# Get the "busybox" image source so we can build locally instead of pulling
|
# Get the "busybox" image source so we can build locally instead of pulling
|
||||||
RUN git clone -b buildroot-2014.02 https://github.com/jpetazzo/docker-busybox.git /docker-busybox
|
RUN git clone -b buildroot-2014.02 https://github.com/jpetazzo/docker-busybox.git /docker-busybox
|
||||||
|
|
||||||
@@ -94,11 +100,11 @@ RUN groupadd -r docker
|
|||||||
RUN useradd --create-home --gid docker unprivilegeduser
|
RUN useradd --create-home --gid docker unprivilegeduser
|
||||||
|
|
||||||
VOLUME /var/lib/docker
|
VOLUME /var/lib/docker
|
||||||
WORKDIR /go/src/github.com/dotcloud/docker
|
WORKDIR /go/src/github.com/docker/docker
|
||||||
ENV DOCKER_BUILDTAGS apparmor selinux
|
ENV DOCKER_BUILDTAGS apparmor selinux
|
||||||
|
|
||||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||||
ENTRYPOINT ["hack/dind"]
|
ENTRYPOINT ["hack/dind"]
|
||||||
|
|
||||||
# Upload docker source
|
# Upload docker source
|
||||||
ADD . /go/src/github.com/dotcloud/docker
|
COPY . /go/src/github.com/docker/docker
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
|
|
||||||
## FIXME
|
|
||||||
|
|
||||||
This file is a loose collection of things to improve in the codebase, for the internal
|
|
||||||
use of the maintainers.
|
|
||||||
|
|
||||||
They are not big enough to be in the roadmap, not user-facing enough to be github issues,
|
|
||||||
and not important enough to be discussed in the mailing list.
|
|
||||||
|
|
||||||
They are just like FIXME comments in the source code, except we're not sure where in the source
|
|
||||||
to put them - so we put them here :)
|
|
||||||
|
|
||||||
|
|
||||||
* Run linter on codebase
|
|
||||||
* Unify build commands and regular commands
|
|
||||||
* Move source code into src/ subdir for clarity
|
|
||||||
* docker build: on non-existent local path for ADD, don't show full absolute path on the host
|
|
||||||
* use size header for progress bar in pull
|
|
||||||
* Clean up context upload in build!!!
|
|
||||||
* Parallel pull
|
|
||||||
* Upgrade dockerd without stopping containers
|
|
||||||
* Simple command to remove all untagged images (`docker rmi $(docker images | awk '/^<none>/ { print $3 }')`)
|
|
||||||
* Simple command to clean up containers for disk space
|
|
||||||
* Clean up the ProgressReader api, it's a PITA to use
|
|
||||||
+1
-1
@@ -1,5 +1,4 @@
|
|||||||
Solomon Hykes <solomon@docker.com> (@shykes)
|
Solomon Hykes <solomon@docker.com> (@shykes)
|
||||||
Guillaume J. Charmes <guillaume@docker.com> (@creack)
|
|
||||||
Victor Vieux <vieux@docker.com> (@vieux)
|
Victor Vieux <vieux@docker.com> (@vieux)
|
||||||
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
||||||
.mailmap: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
.mailmap: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||||
@@ -7,3 +6,4 @@ Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
|||||||
AUTHORS: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
AUTHORS: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||||
Dockerfile: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
Dockerfile: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||||
Makefile: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
Makefile: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||||
|
.dockerignore: Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
.PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration test-integration-cli validate
|
.PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration test-integration-cli validate
|
||||||
|
|
||||||
# to allow `make BINDDIR=. shell` or `make BINDDIR= test`
|
# to allow `make BINDDIR=. shell` or `make BINDDIR= test`
|
||||||
BINDDIR := bundles
|
# (default to no bind mount if DOCKER_HOST is set)
|
||||||
|
BINDDIR := $(if $(DOCKER_HOST),,bundles)
|
||||||
# to allow `make DOCSPORT=9000 docs`
|
# to allow `make DOCSPORT=9000 docs`
|
||||||
DOCSPORT := 8000
|
DOCSPORT := 8000
|
||||||
|
|
||||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||||
|
GITCOMMIT := $(shell git rev-parse --short HEAD 2>/dev/null)
|
||||||
DOCKER_IMAGE := docker$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
DOCKER_IMAGE := docker$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
||||||
DOCKER_DOCS_IMAGE := docker-docs$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
DOCKER_DOCS_IMAGE := docker-docs$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
||||||
DOCKER_MOUNT := $(if $(BINDDIR),-v "$(CURDIR)/$(BINDDIR):/go/src/github.com/dotcloud/docker/$(BINDDIR)")
|
DOCKER_MOUNT := $(if $(BINDDIR),-v "$(CURDIR)/$(BINDDIR):/go/src/github.com/docker/docker/$(BINDDIR)")
|
||||||
|
|
||||||
DOCKER_RUN_DOCKER := docker run --rm -it --privileged -e TESTFLAGS -e TESTDIRS -e DOCKER_GRAPHDRIVER -e DOCKER_EXECDRIVER $(DOCKER_MOUNT) "$(DOCKER_IMAGE)"
|
DOCKER_RUN_DOCKER := docker run --rm -it --privileged -e TESTFLAGS -e TESTDIRS -e DOCKER_GRAPHDRIVER -e DOCKER_EXECDRIVER $(DOCKER_MOUNT) "$(DOCKER_IMAGE)"
|
||||||
# to allow `make DOCSDIR=docs docs-shell`
|
# to allow `make DOCSDIR=docs docs-shell`
|
||||||
@@ -32,7 +34,7 @@ docs-shell: docs-build
|
|||||||
$(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" bash
|
$(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" bash
|
||||||
|
|
||||||
docs-release: docs-build
|
docs-release: docs-build
|
||||||
$(DOCKER_RUN_DOCS) "$(DOCKER_DOCS_IMAGE)" ./release.sh
|
$(DOCKER_RUN_DOCS) -e BUILD_ROOT "$(DOCKER_DOCS_IMAGE)" ./release.sh
|
||||||
|
|
||||||
test: build
|
test: build
|
||||||
$(DOCKER_RUN_DOCKER) hack/make.sh binary cross test-unit test-integration test-integration-cli
|
$(DOCKER_RUN_DOCKER) hack/make.sh binary cross test-unit test-integration test-integration-cli
|
||||||
@@ -59,6 +61,7 @@ docs-build:
|
|||||||
cp ./VERSION docs/VERSION
|
cp ./VERSION docs/VERSION
|
||||||
echo "$(GIT_BRANCH)" > docs/GIT_BRANCH
|
echo "$(GIT_BRANCH)" > docs/GIT_BRANCH
|
||||||
echo "$(AWS_S3_BUCKET)" > docs/AWS_S3_BUCKET
|
echo "$(AWS_S3_BUCKET)" > docs/AWS_S3_BUCKET
|
||||||
|
echo "$(GITCOMMIT)" > docs/GITCOMMIT
|
||||||
docker build -t "$(DOCKER_DOCS_IMAGE)" docs
|
docker build -t "$(DOCKER_DOCS_IMAGE)" docs
|
||||||
|
|
||||||
bundles:
|
bundles:
|
||||||
|
|||||||
@@ -18,7 +18,13 @@ It benefits directly from the experience accumulated over several years
|
|||||||
of large-scale operation and support of hundreds of thousands of
|
of large-scale operation and support of hundreds of thousands of
|
||||||
applications and databases.
|
applications and databases.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Security Disclosure
|
||||||
|
|
||||||
|
Security is very important to us. If you have any issue regarding security,
|
||||||
|
please disclose the information responsibly by sending an email to
|
||||||
|
security@docker.com and not by creating a github issue.
|
||||||
|
|
||||||
## Better than VMs
|
## Better than VMs
|
||||||
|
|
||||||
@@ -125,9 +131,8 @@ Here's a typical Docker build process:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
FROM ubuntu:12.04
|
FROM ubuntu:12.04
|
||||||
RUN apt-get update
|
RUN apt-get update && apt-get install -y python python-pip curl
|
||||||
RUN apt-get install -q -y python python-pip curl
|
RUN curl -sSL https://github.com/shykes/helloflask/archive/master.tar.gz | tar -xzv
|
||||||
RUN curl -L https://github.com/shykes/helloflask/archive/master.tar.gz | tar -xzv
|
|
||||||
RUN cd helloflask-master && pip install -r requirements.txt
|
RUN cd helloflask-master && pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -142,11 +147,10 @@ Docker can be installed on your local machine as well as servers - both
|
|||||||
bare metal and virtualized. It is available as a binary on most modern
|
bare metal and virtualized. It is available as a binary on most modern
|
||||||
Linux systems, or as a VM on Windows, Mac and other systems.
|
Linux systems, or as a VM on Windows, Mac and other systems.
|
||||||
|
|
||||||
We also offer an interactive tutorial for quickly learning the basics of
|
We also offer an [interactive tutorial](http://www.docker.com/tryit/)
|
||||||
using Docker.
|
for quickly learning the basics of using Docker.
|
||||||
|
|
||||||
For up-to-date install instructions and online tutorials, see the
|
For up-to-date install instructions, see the [Docs](http://docs.docker.com).
|
||||||
[Getting Started page](http://www.docker.io/gettingstarted/).
|
|
||||||
|
|
||||||
Usage examples
|
Usage examples
|
||||||
==============
|
==============
|
||||||
@@ -155,7 +159,7 @@ Docker can be used to run short-lived commands, long-running daemons
|
|||||||
(app servers, databases etc.), interactive shell sessions, etc.
|
(app servers, databases etc.), interactive shell sessions, etc.
|
||||||
|
|
||||||
You can find a [list of real-world
|
You can find a [list of real-world
|
||||||
examples](http://docs.docker.io/en/latest/examples/) in the
|
examples](http://docs.docker.com/examples/) in the
|
||||||
documentation.
|
documentation.
|
||||||
|
|
||||||
Under the hood
|
Under the hood
|
||||||
@@ -173,6 +177,9 @@ Under the hood, Docker is built on the following components:
|
|||||||
Contributing to Docker
|
Contributing to Docker
|
||||||
======================
|
======================
|
||||||
|
|
||||||
|
[](https://godoc.org/github.com/docker/docker)
|
||||||
|
[](https://travis-ci.org/docker/docker)
|
||||||
|
|
||||||
Want to hack on Docker? Awesome! There are instructions to get you
|
Want to hack on Docker? Awesome! There are instructions to get you
|
||||||
started [here](CONTRIBUTING.md).
|
started [here](CONTRIBUTING.md).
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
This directory contains code pertaining to the Docker API:
|
This directory contains code pertaining to the Docker API:
|
||||||
|
|
||||||
- Used by the docker client when comunicating with the docker deamon
|
- Used by the docker client when communicating with the docker daemon
|
||||||
|
|
||||||
- Used by third party tools wishing to interface with the docker deamon
|
- Used by third party tools wishing to interface with the docker daemon
|
||||||
|
|||||||
+18
-17
@@ -10,11 +10,24 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
flag "github.com/dotcloud/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
"github.com/dotcloud/docker/pkg/term"
|
"github.com/docker/docker/pkg/term"
|
||||||
"github.com/dotcloud/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DockerCli struct {
|
||||||
|
proto string
|
||||||
|
addr string
|
||||||
|
configFile *registry.ConfigFile
|
||||||
|
in io.ReadCloser
|
||||||
|
out io.Writer
|
||||||
|
err io.Writer
|
||||||
|
isTerminal bool
|
||||||
|
terminalFd uintptr
|
||||||
|
tlsConfig *tls.Config
|
||||||
|
scheme string
|
||||||
|
}
|
||||||
|
|
||||||
var funcMap = template.FuncMap{
|
var funcMap = template.FuncMap{
|
||||||
"json": func(v interface{}) string {
|
"json": func(v interface{}) string {
|
||||||
a, _ := json.Marshal(v)
|
a, _ := json.Marshal(v)
|
||||||
@@ -34,7 +47,8 @@ func (cli *DockerCli) getMethod(name string) (func(...string) error, bool) {
|
|||||||
return method.Interface().(func(...string) error), true
|
return method.Interface().(func(...string) error), true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *DockerCli) ParseCommands(args ...string) error {
|
// Cmd executes the specified command
|
||||||
|
func (cli *DockerCli) Cmd(args ...string) error {
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
method, exists := cli.getMethod(args[0])
|
method, exists := cli.getMethod(args[0])
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -97,16 +111,3 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string, tlsC
|
|||||||
scheme: scheme,
|
scheme: scheme,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type DockerCli struct {
|
|
||||||
proto string
|
|
||||||
addr string
|
|
||||||
configFile *registry.ConfigFile
|
|
||||||
in io.ReadCloser
|
|
||||||
out io.Writer
|
|
||||||
err io.Writer
|
|
||||||
isTerminal bool
|
|
||||||
terminalFd uintptr
|
|
||||||
tlsConfig *tls.Config
|
|
||||||
scheme string
|
|
||||||
}
|
|
||||||
|
|||||||
+233
-154
@@ -13,6 +13,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -21,19 +22,25 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/api"
|
"github.com/docker/docker/api"
|
||||||
"github.com/dotcloud/docker/archive"
|
"github.com/docker/docker/archive"
|
||||||
"github.com/dotcloud/docker/dockerversion"
|
"github.com/docker/docker/dockerversion"
|
||||||
"github.com/dotcloud/docker/engine"
|
"github.com/docker/docker/engine"
|
||||||
"github.com/dotcloud/docker/nat"
|
"github.com/docker/docker/nat"
|
||||||
"github.com/dotcloud/docker/opts"
|
"github.com/docker/docker/opts"
|
||||||
"github.com/dotcloud/docker/pkg/signal"
|
"github.com/docker/docker/pkg/log"
|
||||||
"github.com/dotcloud/docker/pkg/term"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/dotcloud/docker/pkg/units"
|
"github.com/docker/docker/pkg/parsers/filters"
|
||||||
"github.com/dotcloud/docker/registry"
|
"github.com/docker/docker/pkg/signal"
|
||||||
"github.com/dotcloud/docker/runconfig"
|
"github.com/docker/docker/pkg/term"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/docker/docker/pkg/units"
|
||||||
"github.com/dotcloud/docker/utils/filters"
|
"github.com/docker/docker/registry"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tarHeaderSize = 512
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cli *DockerCli) CmdHelp(args ...string) error {
|
func (cli *DockerCli) CmdHelp(args ...string) error {
|
||||||
@@ -51,7 +58,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
|
|||||||
{"attach", "Attach to a running container"},
|
{"attach", "Attach to a running container"},
|
||||||
{"build", "Build an image from a Dockerfile"},
|
{"build", "Build an image from a Dockerfile"},
|
||||||
{"commit", "Create a new image from a container's changes"},
|
{"commit", "Create a new image from a container's changes"},
|
||||||
{"cp", "Copy files/folders from the containers filesystem to the host path"},
|
{"cp", "Copy files/folders from a container's filesystem to the host path"},
|
||||||
{"diff", "Inspect changes on a container's filesystem"},
|
{"diff", "Inspect changes on a container's filesystem"},
|
||||||
{"events", "Get real time events from the server"},
|
{"events", "Get real time events from the server"},
|
||||||
{"export", "Stream the contents of a container as a tar archive"},
|
{"export", "Stream the contents of a container as a tar archive"},
|
||||||
@@ -62,25 +69,26 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
|
|||||||
{"inspect", "Return low-level information on a container"},
|
{"inspect", "Return low-level information on a container"},
|
||||||
{"kill", "Kill a running container"},
|
{"kill", "Kill a running container"},
|
||||||
{"load", "Load an image from a tar archive"},
|
{"load", "Load an image from a tar archive"},
|
||||||
{"login", "Register or Login to the docker registry server"},
|
{"login", "Register or log in to a Docker registry server"},
|
||||||
|
{"logout", "Log out from a Docker registry server"},
|
||||||
{"logs", "Fetch the logs of a container"},
|
{"logs", "Fetch the logs of a container"},
|
||||||
{"port", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT"},
|
{"port", "Lookup the public-facing port that is NAT-ed to PRIVATE_PORT"},
|
||||||
{"pause", "Pause all processes within a container"},
|
{"pause", "Pause all processes within a container"},
|
||||||
{"ps", "List containers"},
|
{"ps", "List containers"},
|
||||||
{"pull", "Pull an image or a repository from the docker registry server"},
|
{"pull", "Pull an image or a repository from a Docker registry server"},
|
||||||
{"push", "Push an image or a repository to the docker registry server"},
|
{"push", "Push an image or a repository to a Docker registry server"},
|
||||||
{"restart", "Restart a running container"},
|
{"restart", "Restart a running container"},
|
||||||
{"rm", "Remove one or more containers"},
|
{"rm", "Remove one or more containers"},
|
||||||
{"rmi", "Remove one or more images"},
|
{"rmi", "Remove one or more images"},
|
||||||
{"run", "Run a command in a new container"},
|
{"run", "Run a command in a new container"},
|
||||||
{"save", "Save an image to a tar archive"},
|
{"save", "Save an image to a tar archive"},
|
||||||
{"search", "Search for an image in the docker index"},
|
{"search", "Search for an image on the Docker Hub"},
|
||||||
{"start", "Start a stopped container"},
|
{"start", "Start a stopped container"},
|
||||||
{"stop", "Stop a running container"},
|
{"stop", "Stop a running container"},
|
||||||
{"tag", "Tag an image into a repository"},
|
{"tag", "Tag an image into a repository"},
|
||||||
{"top", "Lookup the running processes of a container"},
|
{"top", "Lookup the running processes of a container"},
|
||||||
{"unpause", "Unpause a paused container"},
|
{"unpause", "Unpause a paused container"},
|
||||||
{"version", "Show the docker version information"},
|
{"version", "Show the Docker version information"},
|
||||||
{"wait", "Block until a container stops, then print its exit code"},
|
{"wait", "Block until a container stops, then print its exit code"},
|
||||||
} {
|
} {
|
||||||
help += fmt.Sprintf(" %-10.10s%s\n", command[0], command[1])
|
help += fmt.Sprintf(" %-10.10s%s\n", command[0], command[1])
|
||||||
@@ -89,25 +97,6 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: 'insert' is deprecated.
|
|
||||||
func (cli *DockerCli) CmdInsert(args ...string) error {
|
|
||||||
fmt.Fprintf(os.Stderr, "Warning: '%s' is deprecated and will be removed in a future version. Please use 'docker build' and 'ADD' instead.\n")
|
|
||||||
cmd := cli.Subcmd("insert", "IMAGE URL PATH", "Insert a file from URL in the IMAGE at PATH")
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if cmd.NArg() != 3 {
|
|
||||||
cmd.Usage()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
v := url.Values{}
|
|
||||||
v.Set("url", cmd.Arg(1))
|
|
||||||
v.Set("path", cmd.Arg(2))
|
|
||||||
|
|
||||||
return cli.stream("POST", "/images/"+cmd.Arg(0)+"/insert?"+v.Encode(), nil, cli.out, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cli *DockerCli) CmdBuild(args ...string) error {
|
func (cli *DockerCli) CmdBuild(args ...string) error {
|
||||||
cmd := cli.Subcmd("build", "[OPTIONS] PATH | URL | -", "Build a new image from the source code at PATH")
|
cmd := cli.Subcmd("build", "[OPTIONS] PATH | URL | -", "Build a new image from the source code at PATH")
|
||||||
tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
|
tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
|
||||||
@@ -132,13 +121,22 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||||||
_, err = exec.LookPath("git")
|
_, err = exec.LookPath("git")
|
||||||
hasGit := err == nil
|
hasGit := err == nil
|
||||||
if cmd.Arg(0) == "-" {
|
if cmd.Arg(0) == "-" {
|
||||||
// As a special case, 'docker build -' will build from an empty context with the
|
// As a special case, 'docker build -' will build from either an empty context with the
|
||||||
// contents of stdin as a Dockerfile
|
// contents of stdin as a Dockerfile, or a tar-ed context from stdin.
|
||||||
dockerfile, err := ioutil.ReadAll(cli.in)
|
buf := bufio.NewReader(cli.in)
|
||||||
if err != nil {
|
magic, err := buf.Peek(tarHeaderSize)
|
||||||
return err
|
if err != nil && err != io.EOF {
|
||||||
|
return fmt.Errorf("failed to peek context header from STDIN: %v", err)
|
||||||
|
}
|
||||||
|
if !archive.IsArchive(magic) {
|
||||||
|
dockerfile, err := ioutil.ReadAll(buf)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read Dockerfile from STDIN: %v", err)
|
||||||
|
}
|
||||||
|
context, err = archive.Generate("Dockerfile", string(dockerfile))
|
||||||
|
} else {
|
||||||
|
context = ioutil.NopCloser(buf)
|
||||||
}
|
}
|
||||||
context, err = archive.Generate("Dockerfile", string(dockerfile))
|
|
||||||
} else if utils.IsURL(cmd.Arg(0)) && (!utils.IsGIT(cmd.Arg(0)) || !hasGit) {
|
} else if utils.IsURL(cmd.Arg(0)) && (!utils.IsGIT(cmd.Arg(0)) || !hasGit) {
|
||||||
isRemote = true
|
isRemote = true
|
||||||
} else {
|
} else {
|
||||||
@@ -166,10 +164,32 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||||||
if _, err = os.Stat(filename); os.IsNotExist(err) {
|
if _, err = os.Stat(filename); os.IsNotExist(err) {
|
||||||
return fmt.Errorf("no Dockerfile found in %s", cmd.Arg(0))
|
return fmt.Errorf("no Dockerfile found in %s", cmd.Arg(0))
|
||||||
}
|
}
|
||||||
if err = utils.ValidateContextDirectory(root); err != nil {
|
var excludes []string
|
||||||
|
ignore, err := ioutil.ReadFile(path.Join(root, ".dockerignore"))
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("Error reading .dockerignore: '%s'", err)
|
||||||
|
}
|
||||||
|
for _, pattern := range strings.Split(string(ignore), "\n") {
|
||||||
|
ok, err := filepath.Match(pattern, "Dockerfile")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Bad .dockerignore pattern: '%s', error: %s", pattern, err)
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
return fmt.Errorf("Dockerfile was excluded by .dockerignore pattern '%s'", pattern)
|
||||||
|
}
|
||||||
|
excludes = append(excludes, pattern)
|
||||||
|
}
|
||||||
|
if err = utils.ValidateContextDirectory(root, excludes); err != nil {
|
||||||
return fmt.Errorf("Error checking context is accessible: '%s'. Please check permissions and try again.", err)
|
return fmt.Errorf("Error checking context is accessible: '%s'. Please check permissions and try again.", err)
|
||||||
}
|
}
|
||||||
context, err = archive.Tar(root, archive.Uncompressed)
|
options := &archive.TarOptions{
|
||||||
|
Compression: archive.Uncompressed,
|
||||||
|
Excludes: excludes,
|
||||||
|
}
|
||||||
|
context, err = archive.TarWithOptions(root, options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var body io.Reader
|
var body io.Reader
|
||||||
// Setup an upload progress bar
|
// Setup an upload progress bar
|
||||||
@@ -183,7 +203,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||||||
|
|
||||||
//Check if the given image name can be resolved
|
//Check if the given image name can be resolved
|
||||||
if *tag != "" {
|
if *tag != "" {
|
||||||
repository, _ := utils.ParseRepositoryTag(*tag)
|
repository, _ := parsers.ParseRepositoryTag(*tag)
|
||||||
if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
|
if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -235,7 +255,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||||||
|
|
||||||
// 'docker login': login / register a user to registry service.
|
// 'docker login': login / register a user to registry service.
|
||||||
func (cli *DockerCli) CmdLogin(args ...string) error {
|
func (cli *DockerCli) CmdLogin(args ...string) error {
|
||||||
cmd := cli.Subcmd("login", "[OPTIONS] [SERVER]", "Register or Login to a docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
|
cmd := cli.Subcmd("login", "[OPTIONS] [SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
|
||||||
|
|
||||||
var username, password, email string
|
var username, password, email string
|
||||||
|
|
||||||
@@ -336,6 +356,32 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// log out from a Docker registry
|
||||||
|
func (cli *DockerCli) CmdLogout(args ...string) error {
|
||||||
|
cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
|
||||||
|
|
||||||
|
if err := cmd.Parse(args); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
serverAddress := registry.IndexServerAddress()
|
||||||
|
if len(cmd.Args()) > 0 {
|
||||||
|
serverAddress = cmd.Arg(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
cli.LoadConfigFile()
|
||||||
|
if _, ok := cli.configFile.Configs[serverAddress]; !ok {
|
||||||
|
fmt.Fprintf(cli.out, "Not logged in to %s\n", serverAddress)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
|
||||||
|
delete(cli.configFile.Configs, serverAddress)
|
||||||
|
|
||||||
|
if err := registry.SaveConfig(cli.configFile); err != nil {
|
||||||
|
return fmt.Errorf("Failed to save docker config: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// 'docker wait': block until a container stops
|
// 'docker wait': block until a container stops
|
||||||
func (cli *DockerCli) CmdWait(args ...string) error {
|
func (cli *DockerCli) CmdWait(args ...string) error {
|
||||||
cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
|
cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
|
||||||
@@ -361,7 +407,7 @@ func (cli *DockerCli) CmdWait(args ...string) error {
|
|||||||
|
|
||||||
// 'docker version': show version information
|
// 'docker version': show version information
|
||||||
func (cli *DockerCli) CmdVersion(args ...string) error {
|
func (cli *DockerCli) CmdVersion(args ...string) error {
|
||||||
cmd := cli.Subcmd("version", "", "Show the docker version information.")
|
cmd := cli.Subcmd("version", "", "Show the Docker version information.")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -378,6 +424,7 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
|
|||||||
if dockerversion.GITCOMMIT != "" {
|
if dockerversion.GITCOMMIT != "" {
|
||||||
fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
|
fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(cli.out, "OS/Arch (client): %s/%s\n", runtime.GOOS, runtime.GOARCH)
|
||||||
|
|
||||||
body, _, err := readBody(cli.call("GET", "/version", nil, false))
|
body, _, err := readBody(cli.call("GET", "/version", nil, false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -387,11 +434,11 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
|
|||||||
out := engine.NewOutput()
|
out := engine.NewOutput()
|
||||||
remoteVersion, err := out.AddEnv()
|
remoteVersion, err := out.AddEnv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("Error reading remote version: %s\n", err)
|
log.Errorf("Error reading remote version: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := out.Write(body); err != nil {
|
if _, err := out.Write(body); err != nil {
|
||||||
utils.Errorf("Error reading remote version: %s\n", err)
|
log.Errorf("Error reading remote version: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.Close()
|
out.Close()
|
||||||
@@ -427,7 +474,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, err := out.Write(body); err != nil {
|
if _, err := out.Write(body); err != nil {
|
||||||
utils.Errorf("Error reading remote info: %s\n", err)
|
log.Errorf("Error reading remote info: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.Close()
|
out.Close()
|
||||||
@@ -444,6 +491,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
|||||||
}
|
}
|
||||||
fmt.Fprintf(cli.out, "Execution Driver: %s\n", remoteInfo.Get("ExecutionDriver"))
|
fmt.Fprintf(cli.out, "Execution Driver: %s\n", remoteInfo.Get("ExecutionDriver"))
|
||||||
fmt.Fprintf(cli.out, "Kernel Version: %s\n", remoteInfo.Get("KernelVersion"))
|
fmt.Fprintf(cli.out, "Kernel Version: %s\n", remoteInfo.Get("KernelVersion"))
|
||||||
|
fmt.Fprintf(cli.out, "Operating System: %s\n", remoteInfo.Get("OperatingSystem"))
|
||||||
|
|
||||||
if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
|
if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
|
||||||
fmt.Fprintf(cli.out, "Debug mode (server): %v\n", remoteInfo.GetBool("Debug"))
|
fmt.Fprintf(cli.out, "Debug mode (server): %v\n", remoteInfo.GetBool("Debug"))
|
||||||
@@ -481,8 +529,8 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cli *DockerCli) CmdStop(args ...string) error {
|
func (cli *DockerCli) CmdStop(args ...string) error {
|
||||||
cmd := cli.Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container (Send SIGTERM, and then SIGKILL after grace period)")
|
cmd := cli.Subcmd("stop", "[OPTIONS] CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period")
|
||||||
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it.")
|
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -509,7 +557,7 @@ func (cli *DockerCli) CmdStop(args ...string) error {
|
|||||||
|
|
||||||
func (cli *DockerCli) CmdRestart(args ...string) error {
|
func (cli *DockerCli) CmdRestart(args ...string) error {
|
||||||
cmd := cli.Subcmd("restart", "[OPTIONS] CONTAINER [CONTAINER...]", "Restart a running container")
|
cmd := cli.Subcmd("restart", "[OPTIONS] CONTAINER [CONTAINER...]", "Restart a running container")
|
||||||
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default=10")
|
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -535,7 +583,7 @@ func (cli *DockerCli) CmdRestart(args ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
|
func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
|
||||||
sigc := make(chan os.Signal, 1)
|
sigc := make(chan os.Signal, 128)
|
||||||
signal.CatchAll(sigc)
|
signal.CatchAll(sigc)
|
||||||
go func() {
|
go func() {
|
||||||
for s := range sigc {
|
for s := range sigc {
|
||||||
@@ -550,10 +598,10 @@ func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sig == "" {
|
if sig == "" {
|
||||||
utils.Errorf("Unsupported signal: %d. Discarding.", s)
|
log.Errorf("Unsupported signal: %d. Discarding.", s)
|
||||||
}
|
}
|
||||||
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, false)); err != nil {
|
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, false)); err != nil {
|
||||||
utils.Debugf("Error sending signal: %s", err)
|
log.Debugf("Error sending signal: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -566,8 +614,8 @@ func (cli *DockerCli) CmdStart(args ...string) error {
|
|||||||
tty bool
|
tty bool
|
||||||
|
|
||||||
cmd = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
|
cmd = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
|
||||||
attach = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's stdout/stderr and forward all signals to the process")
|
attach = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process")
|
||||||
openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's stdin")
|
openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
@@ -643,7 +691,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
|
|||||||
if *openStdin || *attach {
|
if *openStdin || *attach {
|
||||||
if tty && cli.isTerminal {
|
if tty && cli.isTerminal {
|
||||||
if err := cli.monitorTtySize(cmd.Arg(0)); err != nil {
|
if err := cli.monitorTtySize(cmd.Arg(0)); err != nil {
|
||||||
utils.Errorf("Error monitoring TTY size: %s\n", err)
|
log.Errorf("Error monitoring TTY size: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return <-cErr
|
return <-cErr
|
||||||
@@ -698,7 +746,7 @@ func (cli *DockerCli) CmdPause(args ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cli *DockerCli) CmdInspect(args ...string) error {
|
func (cli *DockerCli) CmdInspect(args ...string) error {
|
||||||
cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container/image")
|
cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image")
|
||||||
tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
|
tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -778,7 +826,7 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cli *DockerCli) CmdTop(args ...string) error {
|
func (cli *DockerCli) CmdTop(args ...string) error {
|
||||||
cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Lookup the running processes of a container")
|
cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -813,7 +861,7 @@ func (cli *DockerCli) CmdTop(args ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cli *DockerCli) CmdPort(args ...string) error {
|
func (cli *DockerCli) CmdPort(args ...string) error {
|
||||||
cmd := cli.Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port which is NAT-ed to PRIVATE_PORT")
|
cmd := cli.Subcmd("port", "CONTAINER PRIVATE_PORT", "Lookup the public-facing port that is NAT-ed to PRIVATE_PORT")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -861,7 +909,7 @@ func (cli *DockerCli) CmdPort(args ...string) error {
|
|||||||
func (cli *DockerCli) CmdRmi(args ...string) error {
|
func (cli *DockerCli) CmdRmi(args ...string) error {
|
||||||
var (
|
var (
|
||||||
cmd = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
|
cmd = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
|
||||||
force = cmd.Bool([]string{"f", "-force"}, false, "Force")
|
force = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
|
||||||
noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
|
noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
|
||||||
)
|
)
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
@@ -964,9 +1012,9 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
|
|||||||
|
|
||||||
func (cli *DockerCli) CmdRm(args ...string) error {
|
func (cli *DockerCli) CmdRm(args ...string) error {
|
||||||
cmd := cli.Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
|
cmd := cli.Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
|
||||||
v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated to the container")
|
v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
|
||||||
link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
|
link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
|
||||||
force := cmd.Bool([]string{"f", "-force"}, false, "Force removal of running container")
|
force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
|
||||||
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -975,6 +1023,7 @@ func (cli *DockerCli) CmdRm(args ...string) error {
|
|||||||
cmd.Usage()
|
cmd.Usage()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
val := url.Values{}
|
val := url.Values{}
|
||||||
if *v {
|
if *v {
|
||||||
val.Set("v", "1")
|
val.Set("v", "1")
|
||||||
@@ -982,6 +1031,7 @@ func (cli *DockerCli) CmdRm(args ...string) error {
|
|||||||
if *link {
|
if *link {
|
||||||
val.Set("link", "1")
|
val.Set("link", "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *force {
|
if *force {
|
||||||
val.Set("force", "1")
|
val.Set("force", "1")
|
||||||
}
|
}
|
||||||
@@ -1001,7 +1051,7 @@ func (cli *DockerCli) CmdRm(args ...string) error {
|
|||||||
|
|
||||||
// 'docker kill NAME' kills a running container
|
// 'docker kill NAME' kills a running container
|
||||||
func (cli *DockerCli) CmdKill(args ...string) error {
|
func (cli *DockerCli) CmdKill(args ...string) error {
|
||||||
cmd := cli.Subcmd("kill", "[OPTIONS] CONTAINER [CONTAINER...]", "Kill a running container (send SIGKILL, or specified signal)")
|
cmd := cli.Subcmd("kill", "[OPTIONS] CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal")
|
||||||
signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
|
signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
|
||||||
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
@@ -1035,16 +1085,19 @@ func (cli *DockerCli) CmdImport(args ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var src, repository, tag string
|
var (
|
||||||
|
v = url.Values{}
|
||||||
|
src = cmd.Arg(0)
|
||||||
|
repository = cmd.Arg(1)
|
||||||
|
)
|
||||||
|
|
||||||
|
v.Set("fromSrc", src)
|
||||||
|
v.Set("repo", repository)
|
||||||
|
|
||||||
if cmd.NArg() == 3 {
|
if cmd.NArg() == 3 {
|
||||||
fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' as been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n")
|
fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' as been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n")
|
||||||
src, repository, tag = cmd.Arg(0), cmd.Arg(1), cmd.Arg(2)
|
v.Set("tag", cmd.Arg(2))
|
||||||
} else {
|
|
||||||
src = cmd.Arg(0)
|
|
||||||
repository, tag = utils.ParseRepositoryTag(cmd.Arg(1))
|
|
||||||
}
|
}
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if repository != "" {
|
if repository != "" {
|
||||||
//Check if the given image name can be resolved
|
//Check if the given image name can be resolved
|
||||||
@@ -1053,10 +1106,6 @@ func (cli *DockerCli) CmdImport(args ...string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v.Set("repo", repository)
|
|
||||||
v.Set("tag", tag)
|
|
||||||
v.Set("fromSrc", src)
|
|
||||||
|
|
||||||
var in io.Reader
|
var in io.Reader
|
||||||
|
|
||||||
if src == "-" {
|
if src == "-" {
|
||||||
@@ -1080,7 +1129,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
|||||||
|
|
||||||
cli.LoadConfigFile()
|
cli.LoadConfigFile()
|
||||||
|
|
||||||
remote, tag := utils.ParseRepositoryTag(name)
|
remote, tag := parsers.ParseRepositoryTag(name)
|
||||||
|
|
||||||
// Resolve the Repository name from fqn to hostname + name
|
// Resolve the Repository name from fqn to hostname + name
|
||||||
hostname, _, err := registry.ResolveRepositoryName(remote)
|
hostname, _, err := registry.ResolveRepositoryName(remote)
|
||||||
@@ -1133,7 +1182,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
|||||||
|
|
||||||
func (cli *DockerCli) CmdPull(args ...string) error {
|
func (cli *DockerCli) CmdPull(args ...string) error {
|
||||||
cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry")
|
cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry")
|
||||||
tag := cmd.String([]string{"#t", "#-tag"}, "", "Download tagged image in repository")
|
tag := cmd.String([]string{"#t", "#-tag"}, "", "Download tagged image in a repository")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1142,12 +1191,18 @@ func (cli *DockerCli) CmdPull(args ...string) error {
|
|||||||
cmd.Usage()
|
cmd.Usage()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
var (
|
||||||
|
v = url.Values{}
|
||||||
|
remote = cmd.Arg(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
v.Set("fromImage", remote)
|
||||||
|
|
||||||
remote, parsedTag := utils.ParseRepositoryTag(cmd.Arg(0))
|
|
||||||
if *tag == "" {
|
if *tag == "" {
|
||||||
*tag = parsedTag
|
v.Set("tag", *tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remote, _ = parsers.ParseRepositoryTag(remote)
|
||||||
// Resolve the Repository name from fqn to hostname + name
|
// Resolve the Repository name from fqn to hostname + name
|
||||||
hostname, _, err := registry.ResolveRepositoryName(remote)
|
hostname, _, err := registry.ResolveRepositoryName(remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1158,9 +1213,6 @@ func (cli *DockerCli) CmdPull(args ...string) error {
|
|||||||
|
|
||||||
// Resolve the Auth config relevant for this server
|
// Resolve the Auth config relevant for this server
|
||||||
authConfig := cli.configFile.ResolveAuthConfig(hostname)
|
authConfig := cli.configFile.ResolveAuthConfig(hostname)
|
||||||
v := url.Values{}
|
|
||||||
v.Set("fromImage", remote)
|
|
||||||
v.Set("tag", *tag)
|
|
||||||
|
|
||||||
pull := func(authConfig registry.AuthConfig) error {
|
pull := func(authConfig registry.AuthConfig) error {
|
||||||
buf, err := json.Marshal(authConfig)
|
buf, err := json.Marshal(authConfig)
|
||||||
@@ -1200,7 +1252,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
|
|||||||
flViz := cmd.Bool([]string{"#v", "#viz", "#-viz"}, false, "Output graph in graphviz format")
|
flViz := cmd.Bool([]string{"#v", "#viz", "#-viz"}, false, "Output graph in graphviz format")
|
||||||
flTree := cmd.Bool([]string{"#t", "#tree", "#-tree"}, false, "Output graph in tree format")
|
flTree := cmd.Bool([]string{"#t", "#tree", "#-tree"}, false, "Output graph in tree format")
|
||||||
|
|
||||||
var flFilter opts.ListOpts
|
flFilter := opts.NewListOpts(nil)
|
||||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
|
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
|
||||||
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
@@ -1333,7 +1385,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
|
|||||||
for _, out := range outs.Data {
|
for _, out := range outs.Data {
|
||||||
for _, repotag := range out.GetList("RepoTags") {
|
for _, repotag := range out.GetList("RepoTags") {
|
||||||
|
|
||||||
repo, tag := utils.ParseRepositoryTag(repotag)
|
repo, tag := parsers.ParseRepositoryTag(repotag)
|
||||||
outID := out.Get("Id")
|
outID := out.Get("Id")
|
||||||
if !*noTrunc {
|
if !*noTrunc {
|
||||||
outID = utils.TruncateID(outID)
|
outID = utils.TruncateID(outID)
|
||||||
@@ -1433,6 +1485,9 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
|||||||
before := cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name, include non-running ones.")
|
before := cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name, include non-running ones.")
|
||||||
last := cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
|
last := cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
|
||||||
|
|
||||||
|
flFilter := opts.NewListOpts(nil)
|
||||||
|
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>")
|
||||||
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1456,6 +1511,24 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
|||||||
v.Set("size", "1")
|
v.Set("size", "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Consolidate all filter flags, and sanity check them.
|
||||||
|
// They'll get processed in the daemon/server.
|
||||||
|
psFilterArgs := filters.Args{}
|
||||||
|
for _, f := range flFilter.GetAll() {
|
||||||
|
var err error
|
||||||
|
psFilterArgs, err = filters.ParseFlag(f, psFilterArgs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(psFilterArgs) > 0 {
|
||||||
|
filterJson, err := filters.ToParam(psFilterArgs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Set("filters", filterJson)
|
||||||
|
}
|
||||||
|
|
||||||
body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false))
|
body, _, err := readBody(cli.call("GET", "/containers/json?"+v.Encode(), nil, false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1495,6 +1568,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
|||||||
outCommand = out.Get("Command")
|
outCommand = out.Get("Command")
|
||||||
ports = engine.NewTable("", 0)
|
ports = engine.NewTable("", 0)
|
||||||
)
|
)
|
||||||
|
outCommand = strconv.Quote(outCommand)
|
||||||
if !*noTrunc {
|
if !*noTrunc {
|
||||||
outCommand = utils.Trunc(outCommand, 20)
|
outCommand = utils.Trunc(outCommand, 20)
|
||||||
}
|
}
|
||||||
@@ -1522,25 +1596,21 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
|||||||
|
|
||||||
func (cli *DockerCli) CmdCommit(args ...string) error {
|
func (cli *DockerCli) CmdCommit(args ...string) error {
|
||||||
cmd := cli.Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes")
|
cmd := cli.Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes")
|
||||||
|
flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
|
||||||
flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
|
flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
|
||||||
flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\"")
|
flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
|
||||||
// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
|
// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
|
||||||
flConfig := cmd.String([]string{"#run", "#-run"}, "", "this option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands")
|
flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var name, repository, tag string
|
var (
|
||||||
|
name = cmd.Arg(0)
|
||||||
|
repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
|
||||||
|
)
|
||||||
|
|
||||||
if cmd.NArg() == 3 {
|
if name == "" || len(cmd.Args()) > 2 {
|
||||||
fmt.Fprintf(cli.err, "[DEPRECATED] The format 'CONTAINER [REPOSITORY [TAG]]' as been deprecated. Please use CONTAINER [REPOSITORY[:TAG]]\n")
|
|
||||||
name, repository, tag = cmd.Arg(0), cmd.Arg(1), cmd.Arg(2)
|
|
||||||
} else {
|
|
||||||
name = cmd.Arg(0)
|
|
||||||
repository, tag = utils.ParseRepositoryTag(cmd.Arg(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == "" {
|
|
||||||
cmd.Usage()
|
cmd.Usage()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1558,6 +1628,11 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
|
|||||||
v.Set("tag", tag)
|
v.Set("tag", tag)
|
||||||
v.Set("comment", *flComment)
|
v.Set("comment", *flComment)
|
||||||
v.Set("author", *flAuthor)
|
v.Set("author", *flAuthor)
|
||||||
|
|
||||||
|
if *flPause != true {
|
||||||
|
v.Set("pause", "0")
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
config *runconfig.Config
|
config *runconfig.Config
|
||||||
env engine.Env
|
env engine.Env
|
||||||
@@ -1597,7 +1672,7 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
|
|||||||
loc = time.FixedZone(time.Now().Zone())
|
loc = time.FixedZone(time.Now().Zone())
|
||||||
)
|
)
|
||||||
var setTime = func(key, value string) {
|
var setTime = func(key, value string) {
|
||||||
format := "2006-01-02 15:04:05 -0700 MST"
|
format := time.RFC3339Nano
|
||||||
if len(value) < len(format) {
|
if len(value) < len(format) {
|
||||||
format = format[:len(value)]
|
format = format[:len(value)]
|
||||||
}
|
}
|
||||||
@@ -1676,6 +1751,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
|
|||||||
cmd = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container")
|
cmd = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container")
|
||||||
follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
|
follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
|
||||||
times = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
|
times = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
|
||||||
|
tail = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)")
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
@@ -1709,6 +1785,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
|
|||||||
if *follow {
|
if *follow {
|
||||||
v.Set("follow", "1")
|
v.Set("follow", "1")
|
||||||
}
|
}
|
||||||
|
v.Set("tail", *tail)
|
||||||
|
|
||||||
return cli.streamHelper("GET", "/containers/"+name+"/logs?"+v.Encode(), env.GetSubEnv("Config").GetBool("Tty"), nil, cli.out, cli.err, nil)
|
return cli.streamHelper("GET", "/containers/"+name+"/logs?"+v.Encode(), env.GetSubEnv("Config").GetBool("Tty"), nil, cli.out, cli.err, nil)
|
||||||
}
|
}
|
||||||
@@ -1716,8 +1793,8 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
|
|||||||
func (cli *DockerCli) CmdAttach(args ...string) error {
|
func (cli *DockerCli) CmdAttach(args ...string) error {
|
||||||
var (
|
var (
|
||||||
cmd = cli.Subcmd("attach", "[OPTIONS] CONTAINER", "Attach to a running container")
|
cmd = cli.Subcmd("attach", "[OPTIONS] CONTAINER", "Attach to a running container")
|
||||||
noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach stdin")
|
noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
|
||||||
proxy = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)")
|
proxy = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process (even in non-TTY mode). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.")
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
@@ -1751,7 +1828,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
|
|||||||
|
|
||||||
if tty && cli.isTerminal {
|
if tty && cli.isTerminal {
|
||||||
if err := cli.monitorTtySize(cmd.Arg(0)); err != nil {
|
if err := cli.monitorTtySize(cmd.Arg(0)); err != nil {
|
||||||
utils.Debugf("Error monitoring TTY size: %s", err)
|
log.Debugf("Error monitoring TTY size: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1788,11 +1865,11 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cli *DockerCli) CmdSearch(args ...string) error {
|
func (cli *DockerCli) CmdSearch(args ...string) error {
|
||||||
cmd := cli.Subcmd("search", "TERM", "Search the docker index for images")
|
cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images")
|
||||||
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
|
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
|
||||||
trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
|
trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
|
||||||
automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
|
automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
|
||||||
stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least xxx stars")
|
stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1843,26 +1920,20 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
|
|||||||
type ports []int
|
type ports []int
|
||||||
|
|
||||||
func (cli *DockerCli) CmdTag(args ...string) error {
|
func (cli *DockerCli) CmdTag(args ...string) error {
|
||||||
cmd := cli.Subcmd("tag", "[OPTIONS] IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository")
|
cmd := cli.Subcmd("tag", "[OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository")
|
||||||
force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
|
force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if cmd.NArg() != 2 && cmd.NArg() != 3 {
|
if cmd.NArg() != 2 {
|
||||||
cmd.Usage()
|
cmd.Usage()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var repository, tag string
|
var (
|
||||||
|
repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
|
||||||
if cmd.NArg() == 3 {
|
v = url.Values{}
|
||||||
fmt.Fprintf(cli.err, "[DEPRECATED] The format 'IMAGE [REPOSITORY [TAG]]' as been deprecated. Please use IMAGE [REGISTRYHOST/][USERNAME/]NAME[:TAG]]\n")
|
)
|
||||||
repository, tag = cmd.Arg(1), cmd.Arg(2)
|
|
||||||
} else {
|
|
||||||
repository, tag = utils.ParseRepositoryTag(cmd.Arg(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
//Check if the given image name can be resolved
|
//Check if the given image name can be resolved
|
||||||
if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
|
if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
|
||||||
@@ -1881,6 +1952,41 @@ func (cli *DockerCli) CmdTag(args ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cli *DockerCli) pullImage(image string) error {
|
||||||
|
v := url.Values{}
|
||||||
|
repos, tag := parsers.ParseRepositoryTag(image)
|
||||||
|
// pull only the image tagged 'latest' if no tag was specified
|
||||||
|
if tag == "" {
|
||||||
|
tag = "latest"
|
||||||
|
}
|
||||||
|
v.Set("fromImage", repos)
|
||||||
|
v.Set("tag", tag)
|
||||||
|
|
||||||
|
// Resolve the Repository name from fqn to hostname + name
|
||||||
|
hostname, _, err := registry.ResolveRepositoryName(repos)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the auth config file, to be able to pull the image
|
||||||
|
cli.LoadConfigFile()
|
||||||
|
|
||||||
|
// Resolve the Auth config relevant for this server
|
||||||
|
authConfig := cli.configFile.ResolveAuthConfig(hostname)
|
||||||
|
buf, err := json.Marshal(authConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
registryAuthHeader := []string{
|
||||||
|
base64.URLEncoding.EncodeToString(buf),
|
||||||
|
}
|
||||||
|
if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err, map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (cli *DockerCli) CmdRun(args ...string) error {
|
func (cli *DockerCli) CmdRun(args ...string) error {
|
||||||
// FIXME: just use runconfig.Parse already
|
// FIXME: just use runconfig.Parse already
|
||||||
config, hostConfig, cmd, err := runconfig.ParseSubcommand(cli.Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container"), args, nil)
|
config, hostConfig, cmd, err := runconfig.ParseSubcommand(cli.Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container"), args, nil)
|
||||||
@@ -1925,7 +2031,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||||||
}
|
}
|
||||||
if cidFileInfo.Size() == 0 {
|
if cidFileInfo.Size() == 0 {
|
||||||
if err := os.Remove(hostConfig.ContainerIDFile); err != nil {
|
if err := os.Remove(hostConfig.ContainerIDFile); err != nil {
|
||||||
fmt.Printf("failed to remove CID file '%s': %s \n", hostConfig.ContainerIDFile, err)
|
fmt.Printf("failed to remove Container ID file '%s': %s \n", hostConfig.ContainerIDFile, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -1942,37 +2048,10 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||||||
if statusCode == 404 {
|
if statusCode == 404 {
|
||||||
fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", config.Image)
|
fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", config.Image)
|
||||||
|
|
||||||
v := url.Values{}
|
if err = cli.pullImage(config.Image); err != nil {
|
||||||
repos, tag := utils.ParseRepositoryTag(config.Image)
|
|
||||||
// pull only the image tagged 'latest' if no tag was specified
|
|
||||||
if tag == "" {
|
|
||||||
tag = "latest"
|
|
||||||
}
|
|
||||||
v.Set("fromImage", repos)
|
|
||||||
v.Set("tag", tag)
|
|
||||||
|
|
||||||
// Resolve the Repository name from fqn to hostname + name
|
|
||||||
hostname, _, err := registry.ResolveRepositoryName(repos)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the auth config file, to be able to pull the image
|
|
||||||
cli.LoadConfigFile()
|
|
||||||
|
|
||||||
// Resolve the Auth config relevant for this server
|
|
||||||
authConfig := cli.configFile.ResolveAuthConfig(hostname)
|
|
||||||
buf, err := json.Marshal(authConfig)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
registryAuthHeader := []string{
|
|
||||||
base64.URLEncoding.EncodeToString(buf),
|
|
||||||
}
|
|
||||||
if err = cli.stream("POST", "/images/create?"+v.Encode(), nil, cli.err, map[string][]string{"X-Registry-Auth": registryAuthHeader}); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Retry
|
||||||
if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false); err != nil {
|
if stream, _, err = cli.call("POST", "/containers/create?"+containerValues.Encode(), config, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -2020,9 +2099,9 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||||||
|
|
||||||
// Block the return until the chan gets closed
|
// Block the return until the chan gets closed
|
||||||
defer func() {
|
defer func() {
|
||||||
utils.Debugf("End of CmdRun(), Waiting for hijack to finish.")
|
log.Debugf("End of CmdRun(), Waiting for hijack to finish.")
|
||||||
if _, ok := <-hijacked; ok {
|
if _, ok := <-hijacked; ok {
|
||||||
utils.Errorf("Hijack did not finish (chan still open)")
|
log.Errorf("Hijack did not finish (chan still open)")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -2068,7 +2147,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||||||
}
|
}
|
||||||
case err := <-errCh:
|
case err := <-errCh:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Debugf("Error hijack: %s", err)
|
log.Debugf("Error hijack: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2080,13 +2159,13 @@ func (cli *DockerCli) CmdRun(args ...string) error {
|
|||||||
|
|
||||||
if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminal {
|
if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminal {
|
||||||
if err := cli.monitorTtySize(runResult.Get("Id")); err != nil {
|
if err := cli.monitorTtySize(runResult.Get("Id")); err != nil {
|
||||||
utils.Errorf("Error monitoring TTY size: %s\n", err)
|
log.Errorf("Error monitoring TTY size: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if errCh != nil {
|
if errCh != nil {
|
||||||
if err := <-errCh; err != nil {
|
if err := <-errCh; err != nil {
|
||||||
utils.Debugf("Error hijack: %s", err)
|
log.Debugf("Error hijack: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2175,7 +2254,7 @@ func (cli *DockerCli) CmdCp(args ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cli *DockerCli) CmdSave(args ...string) error {
|
func (cli *DockerCli) CmdSave(args ...string) error {
|
||||||
cmd := cli.Subcmd("save", "IMAGE", "Save an image to a tar archive (streamed to stdout by default)")
|
cmd := cli.Subcmd("save", "IMAGE", "Save an image to a tar archive (streamed to STDOUT by default)")
|
||||||
outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
|
outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
|
||||||
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
|
|||||||
+12
-11
@@ -11,10 +11,11 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/api"
|
"github.com/docker/docker/api"
|
||||||
"github.com/dotcloud/docker/dockerversion"
|
"github.com/docker/docker/dockerversion"
|
||||||
"github.com/dotcloud/docker/pkg/term"
|
"github.com/docker/docker/pkg/log"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/docker/docker/pkg/term"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cli *DockerCli) dial() (net.Conn, error) {
|
func (cli *DockerCli) dial() (net.Conn, error) {
|
||||||
@@ -88,12 +89,12 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// When TTY is ON, use regular copy
|
// When TTY is ON, use regular copy
|
||||||
if setRawTerminal {
|
if setRawTerminal && stdout != nil {
|
||||||
_, err = io.Copy(stdout, br)
|
_, err = io.Copy(stdout, br)
|
||||||
} else {
|
} else {
|
||||||
_, err = utils.StdCopy(stdout, stderr, br)
|
_, err = utils.StdCopy(stdout, stderr, br)
|
||||||
}
|
}
|
||||||
utils.Debugf("[hijack] End of stdout")
|
log.Debugf("[hijack] End of stdout")
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -101,15 +102,15 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
|
|||||||
sendStdin := utils.Go(func() error {
|
sendStdin := utils.Go(func() error {
|
||||||
if in != nil {
|
if in != nil {
|
||||||
io.Copy(rwc, in)
|
io.Copy(rwc, in)
|
||||||
utils.Debugf("[hijack] End of stdin")
|
log.Debugf("[hijack] End of stdin")
|
||||||
}
|
}
|
||||||
if tcpc, ok := rwc.(*net.TCPConn); ok {
|
if tcpc, ok := rwc.(*net.TCPConn); ok {
|
||||||
if err := tcpc.CloseWrite(); err != nil {
|
if err := tcpc.CloseWrite(); err != nil {
|
||||||
utils.Debugf("Couldn't send EOF: %s\n", err)
|
log.Debugf("Couldn't send EOF: %s", err)
|
||||||
}
|
}
|
||||||
} else if unixc, ok := rwc.(*net.UnixConn); ok {
|
} else if unixc, ok := rwc.(*net.UnixConn); ok {
|
||||||
if err := unixc.CloseWrite(); err != nil {
|
if err := unixc.CloseWrite(); err != nil {
|
||||||
utils.Debugf("Couldn't send EOF: %s\n", err)
|
log.Debugf("Couldn't send EOF: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Discard errors due to pipe interruption
|
// Discard errors due to pipe interruption
|
||||||
@@ -118,14 +119,14 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
|
|||||||
|
|
||||||
if stdout != nil || stderr != nil {
|
if stdout != nil || stderr != nil {
|
||||||
if err := <-receiveStdout; err != nil {
|
if err := <-receiveStdout; err != nil {
|
||||||
utils.Debugf("Error receiveStdout: %s", err)
|
log.Debugf("Error receiveStdout: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cli.isTerminal {
|
if !cli.isTerminal {
|
||||||
if err := <-sendStdin; err != nil {
|
if err := <-sendStdin; err != nil {
|
||||||
utils.Debugf("Error sendStdin: %s", err)
|
log.Debugf("Error sendStdin: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-10
@@ -17,12 +17,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/api"
|
"github.com/docker/docker/api"
|
||||||
"github.com/dotcloud/docker/dockerversion"
|
"github.com/docker/docker/dockerversion"
|
||||||
"github.com/dotcloud/docker/engine"
|
"github.com/docker/docker/engine"
|
||||||
"github.com/dotcloud/docker/pkg/term"
|
"github.com/docker/docker/pkg/log"
|
||||||
"github.com/dotcloud/docker/registry"
|
"github.com/docker/docker/pkg/term"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/docker/docker/registry"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -105,7 +106,7 @@ func (cli *DockerCli) call(method, path string, data interface{}, passAuthInfo b
|
|||||||
if len(body) == 0 {
|
if len(body) == 0 {
|
||||||
return nil, resp.StatusCode, fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(resp.StatusCode), req.URL)
|
return nil, resp.StatusCode, fmt.Errorf("Error: request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(resp.StatusCode), req.URL)
|
||||||
}
|
}
|
||||||
return nil, resp.StatusCode, fmt.Errorf("Error: %s", bytes.TrimSpace(body))
|
return nil, resp.StatusCode, fmt.Errorf("Error response from daemon: %s", bytes.TrimSpace(body))
|
||||||
}
|
}
|
||||||
return resp.Body, resp.StatusCode, nil
|
return resp.Body, resp.StatusCode, nil
|
||||||
}
|
}
|
||||||
@@ -165,7 +166,7 @@ func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in
|
|||||||
} else {
|
} else {
|
||||||
_, err = utils.StdCopy(stdout, stderr, resp.Body)
|
_, err = utils.StdCopy(stdout, stderr, resp.Body)
|
||||||
}
|
}
|
||||||
utils.Debugf("[stream] End of stdout")
|
log.Debugf("[stream] End of stdout")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -180,7 +181,7 @@ func (cli *DockerCli) resizeTty(id string) {
|
|||||||
v.Set("h", strconv.Itoa(height))
|
v.Set("h", strconv.Itoa(height))
|
||||||
v.Set("w", strconv.Itoa(width))
|
v.Set("w", strconv.Itoa(width))
|
||||||
if _, _, err := readBody(cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil, false)); err != nil {
|
if _, _, err := readBody(cli.call("POST", "/containers/"+id+"/resize?"+v.Encode(), nil, false)); err != nil {
|
||||||
utils.Debugf("Error resize: %s", err)
|
log.Debugf("Error resize: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +238,7 @@ func (cli *DockerCli) getTtySize() (int, int) {
|
|||||||
}
|
}
|
||||||
ws, err := term.GetWinsize(cli.terminalFd)
|
ws, err := term.GetWinsize(cli.terminalFd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Debugf("Error getting size: %s", err)
|
log.Debugf("Error getting size: %s", err)
|
||||||
if ws == nil {
|
if ws == nil {
|
||||||
return 0, 0
|
return 0, 0
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-6
@@ -5,19 +5,20 @@ import (
|
|||||||
"mime"
|
"mime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/engine"
|
"github.com/docker/docker/engine"
|
||||||
"github.com/dotcloud/docker/pkg/version"
|
"github.com/docker/docker/pkg/log"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
|
"github.com/docker/docker/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
APIVERSION version.Version = "1.12"
|
APIVERSION version.Version = "1.14"
|
||||||
DEFAULTHTTPHOST = "127.0.0.1"
|
DEFAULTHTTPHOST = "127.0.0.1"
|
||||||
DEFAULTUNIXSOCKET = "/var/run/docker.sock"
|
DEFAULTUNIXSOCKET = "/var/run/docker.sock"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidateHost(val string) (string, error) {
|
func ValidateHost(val string) (string, error) {
|
||||||
host, err := utils.ParseHost(DEFAULTHTTPHOST, DEFAULTUNIXSOCKET, val)
|
host, err := parsers.ParseHost(DEFAULTHTTPHOST, DEFAULTUNIXSOCKET, val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return val, err
|
return val, err
|
||||||
}
|
}
|
||||||
@@ -42,7 +43,7 @@ func DisplayablePorts(ports *engine.Table) string {
|
|||||||
func MatchesContentType(contentType, expectedType string) bool {
|
func MatchesContentType(contentType, expectedType string) bool {
|
||||||
mimetype, _, err := mime.ParseMediaType(contentType)
|
mimetype, _, err := mime.ParseMediaType(contentType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("Error parsing media type: %s error: %s", contentType, err.Error())
|
log.Errorf("Error parsing media type: %s error: %s", contentType, err.Error())
|
||||||
}
|
}
|
||||||
return err == nil && mimetype == expectedType
|
return err == nil && mimetype == expectedType
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Victor Vieux <vieux@docker.com> (@vieux)
|
||||||
|
# off the grid until september
|
||||||
|
# Johan Euphrosine <proppy@google.com> (@proppy)
|
||||||
+91
-54
@@ -11,7 +11,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/pprof"
|
"net/http/pprof"
|
||||||
@@ -21,16 +20,18 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"code.google.com/p/go.net/websocket"
|
"code.google.com/p/go.net/websocket"
|
||||||
|
"github.com/docker/libcontainer/user"
|
||||||
"github.com/dotcloud/docker/api"
|
|
||||||
"github.com/dotcloud/docker/engine"
|
|
||||||
"github.com/dotcloud/docker/pkg/listenbuffer"
|
|
||||||
"github.com/dotcloud/docker/pkg/systemd"
|
|
||||||
"github.com/dotcloud/docker/pkg/user"
|
|
||||||
"github.com/dotcloud/docker/pkg/version"
|
|
||||||
"github.com/dotcloud/docker/registry"
|
|
||||||
"github.com/dotcloud/docker/utils"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api"
|
||||||
|
"github.com/docker/docker/engine"
|
||||||
|
"github.com/docker/docker/pkg/listenbuffer"
|
||||||
|
"github.com/docker/docker/pkg/log"
|
||||||
|
"github.com/docker/docker/pkg/parsers"
|
||||||
|
"github.com/docker/docker/pkg/systemd"
|
||||||
|
"github.com/docker/docker/pkg/version"
|
||||||
|
"github.com/docker/docker/registry"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -87,7 +88,7 @@ func httpError(w http.ResponseWriter, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("HTTP Error: statusCode=%d %s", statusCode, err.Error())
|
log.Errorf("HTTP Error: statusCode=%d %s", statusCode, err.Error())
|
||||||
http.Error(w, err.Error(), statusCode)
|
http.Error(w, err.Error(), statusCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -237,10 +238,10 @@ func getImagesJSON(eng *engine.Engine, version version.Version, w http.ResponseW
|
|||||||
outsLegacy := engine.NewTable("Created", 0)
|
outsLegacy := engine.NewTable("Created", 0)
|
||||||
for _, out := range outs.Data {
|
for _, out := range outs.Data {
|
||||||
for _, repoTag := range out.GetList("RepoTags") {
|
for _, repoTag := range out.GetList("RepoTags") {
|
||||||
parts := strings.Split(repoTag, ":")
|
repo, tag := parsers.ParseRepositoryTag(repoTag)
|
||||||
outLegacy := &engine.Env{}
|
outLegacy := &engine.Env{}
|
||||||
outLegacy.Set("Repository", parts[0])
|
outLegacy.Set("Repository", repo)
|
||||||
outLegacy.Set("Tag", parts[1])
|
outLegacy.SetJson("Tag", tag)
|
||||||
outLegacy.Set("Id", out.Get("Id"))
|
outLegacy.Set("Id", out.Get("Id"))
|
||||||
outLegacy.SetInt64("Created", out.GetInt64("Created"))
|
outLegacy.SetInt64("Created", out.GetInt64("Created"))
|
||||||
outLegacy.SetInt64("Size", out.GetInt64("Size"))
|
outLegacy.SetInt64("Size", out.GetInt64("Size"))
|
||||||
@@ -301,7 +302,7 @@ func getContainersChanges(eng *engine.Engine, version version.Version, w http.Re
|
|||||||
if vars == nil {
|
if vars == nil {
|
||||||
return fmt.Errorf("Missing parameter")
|
return fmt.Errorf("Missing parameter")
|
||||||
}
|
}
|
||||||
var job = eng.Job("changes", vars["name"])
|
var job = eng.Job("container_changes", vars["name"])
|
||||||
streamJSON(job, w, false)
|
streamJSON(job, w, false)
|
||||||
|
|
||||||
return job.Run()
|
return job.Run()
|
||||||
@@ -338,6 +339,7 @@ func getContainersJSON(eng *engine.Engine, version version.Version, w http.Respo
|
|||||||
job.Setenv("since", r.Form.Get("since"))
|
job.Setenv("since", r.Form.Get("since"))
|
||||||
job.Setenv("before", r.Form.Get("before"))
|
job.Setenv("before", r.Form.Get("before"))
|
||||||
job.Setenv("limit", r.Form.Get("limit"))
|
job.Setenv("limit", r.Form.Get("limit"))
|
||||||
|
job.Setenv("filters", r.Form.Get("filters"))
|
||||||
|
|
||||||
if version.GreaterThanOrEqualTo("1.5") {
|
if version.GreaterThanOrEqualTo("1.5") {
|
||||||
streamJSON(job, w, false)
|
streamJSON(job, w, false)
|
||||||
@@ -370,13 +372,24 @@ func getContainersLogs(eng *engine.Engine, version version.Version, w http.Respo
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
job = eng.Job("container_inspect", vars["name"])
|
inspectJob = eng.Job("container_inspect", vars["name"])
|
||||||
c, err = job.Stdout.AddEnv()
|
logsJob = eng.Job("logs", vars["name"])
|
||||||
|
c, err = inspectJob.Stdout.AddEnv()
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = job.Run(); err != nil {
|
logsJob.Setenv("follow", r.Form.Get("follow"))
|
||||||
|
logsJob.Setenv("tail", r.Form.Get("tail"))
|
||||||
|
logsJob.Setenv("stdout", r.Form.Get("stdout"))
|
||||||
|
logsJob.Setenv("stderr", r.Form.Get("stderr"))
|
||||||
|
logsJob.Setenv("timestamps", r.Form.Get("timestamps"))
|
||||||
|
// Validate args here, because we can't return not StatusOK after job.Run() call
|
||||||
|
stdout, stderr := logsJob.GetenvBool("stdout"), logsJob.GetenvBool("stderr")
|
||||||
|
if !(stdout || stderr) {
|
||||||
|
return fmt.Errorf("Bad parameters: you must choose at least one stream")
|
||||||
|
}
|
||||||
|
if err = inspectJob.Run(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,15 +403,10 @@ func getContainersLogs(eng *engine.Engine, version version.Version, w http.Respo
|
|||||||
errStream = outStream
|
errStream = outStream
|
||||||
}
|
}
|
||||||
|
|
||||||
job = eng.Job("logs", vars["name"])
|
logsJob.Stdout.Add(outStream)
|
||||||
job.Setenv("follow", r.Form.Get("follow"))
|
logsJob.Stderr.Set(errStream)
|
||||||
job.Setenv("stdout", r.Form.Get("stdout"))
|
if err := logsJob.Run(); err != nil {
|
||||||
job.Setenv("stderr", r.Form.Get("stderr"))
|
fmt.Fprintf(outStream, "Error running logs job: %s\n", err)
|
||||||
job.Setenv("timestamps", r.Form.Get("timestamps"))
|
|
||||||
job.Stdout.Add(outStream)
|
|
||||||
job.Stderr.Set(errStream)
|
|
||||||
if err := job.Run(); err != nil {
|
|
||||||
fmt.Fprintf(outStream, "Error: %s\n", err)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -431,7 +439,13 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit
|
|||||||
stdoutBuffer = bytes.NewBuffer(nil)
|
stdoutBuffer = bytes.NewBuffer(nil)
|
||||||
)
|
)
|
||||||
if err := config.Decode(r.Body); err != nil {
|
if err := config.Decode(r.Body); err != nil {
|
||||||
utils.Errorf("%s", err)
|
log.Errorf("%s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
|
||||||
|
job.Setenv("pause", "1")
|
||||||
|
} else {
|
||||||
|
job.Setenv("pause", r.FormValue("pause"))
|
||||||
}
|
}
|
||||||
|
|
||||||
job.Setenv("repo", r.Form.Get("repo"))
|
job.Setenv("repo", r.Form.Get("repo"))
|
||||||
@@ -456,6 +470,7 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
image = r.Form.Get("fromImage")
|
image = r.Form.Get("fromImage")
|
||||||
|
repo = r.Form.Get("repo")
|
||||||
tag = r.Form.Get("tag")
|
tag = r.Form.Get("tag")
|
||||||
job *engine.Job
|
job *engine.Job
|
||||||
)
|
)
|
||||||
@@ -470,18 +485,24 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if image != "" { //pull
|
if image != "" { //pull
|
||||||
|
if tag == "" {
|
||||||
|
image, tag = parsers.ParseRepositoryTag(image)
|
||||||
|
}
|
||||||
metaHeaders := map[string][]string{}
|
metaHeaders := map[string][]string{}
|
||||||
for k, v := range r.Header {
|
for k, v := range r.Header {
|
||||||
if strings.HasPrefix(k, "X-Meta-") {
|
if strings.HasPrefix(k, "X-Meta-") {
|
||||||
metaHeaders[k] = v
|
metaHeaders[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
job = eng.Job("pull", r.Form.Get("fromImage"), tag)
|
job = eng.Job("pull", image, tag)
|
||||||
job.SetenvBool("parallel", version.GreaterThan("1.3"))
|
job.SetenvBool("parallel", version.GreaterThan("1.3"))
|
||||||
job.SetenvJson("metaHeaders", metaHeaders)
|
job.SetenvJson("metaHeaders", metaHeaders)
|
||||||
job.SetenvJson("authConfig", authConfig)
|
job.SetenvJson("authConfig", authConfig)
|
||||||
} else { //import
|
} else { //import
|
||||||
job = eng.Job("import", r.Form.Get("fromSrc"), r.Form.Get("repo"), tag)
|
if tag == "" {
|
||||||
|
repo, tag = parsers.ParseRepositoryTag(repo)
|
||||||
|
}
|
||||||
|
job = eng.Job("import", r.Form.Get("fromSrc"), repo, tag)
|
||||||
job.Stdin.Add(r.Body)
|
job.Stdin.Add(r.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,10 +679,12 @@ func deleteContainers(eng *engine.Engine, version version.Version, w http.Respon
|
|||||||
if vars == nil {
|
if vars == nil {
|
||||||
return fmt.Errorf("Missing parameter")
|
return fmt.Errorf("Missing parameter")
|
||||||
}
|
}
|
||||||
job := eng.Job("container_delete", vars["name"])
|
job := eng.Job("delete", vars["name"])
|
||||||
|
|
||||||
|
job.Setenv("forceRemove", r.Form.Get("force"))
|
||||||
|
|
||||||
job.Setenv("removeVolume", r.Form.Get("v"))
|
job.Setenv("removeVolume", r.Form.Get("v"))
|
||||||
job.Setenv("removeLink", r.Form.Get("link"))
|
job.Setenv("removeLink", r.Form.Get("link"))
|
||||||
job.Setenv("forceRemove", r.Form.Get("force"))
|
|
||||||
if err := job.Run(); err != nil {
|
if err := job.Run(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -688,17 +711,27 @@ func postContainersStart(eng *engine.Engine, version version.Version, w http.Res
|
|||||||
if vars == nil {
|
if vars == nil {
|
||||||
return fmt.Errorf("Missing parameter")
|
return fmt.Errorf("Missing parameter")
|
||||||
}
|
}
|
||||||
name := vars["name"]
|
var (
|
||||||
job := eng.Job("start", name)
|
name = vars["name"]
|
||||||
|
job = eng.Job("start", name)
|
||||||
|
)
|
||||||
|
|
||||||
// allow a nil body for backwards compatibility
|
// allow a nil body for backwards compatibility
|
||||||
if r.Body != nil {
|
if r.Body != nil && r.ContentLength > 0 {
|
||||||
if api.MatchesContentType(r.Header.Get("Content-Type"), "application/json") {
|
if !api.MatchesContentType(r.Header.Get("Content-Type"), "application/json") {
|
||||||
if err := job.DecodeEnv(r.Body); err != nil {
|
return fmt.Errorf("Content-Type of application/json is required")
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
if err := job.DecodeEnv(r.Body); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := job.Run(); err != nil {
|
if err := job.Run(); err != nil {
|
||||||
|
if err.Error() == "Container already started" {
|
||||||
|
w.WriteHeader(http.StatusNotModified)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
@@ -715,6 +748,10 @@ func postContainersStop(eng *engine.Engine, version version.Version, w http.Resp
|
|||||||
job := eng.Job("stop", vars["name"])
|
job := eng.Job("stop", vars["name"])
|
||||||
job.Setenv("t", r.Form.Get("t"))
|
job.Setenv("t", r.Form.Get("t"))
|
||||||
if err := job.Run(); err != nil {
|
if err := job.Run(); err != nil {
|
||||||
|
if err.Error() == "Container already stopped" {
|
||||||
|
w.WriteHeader(http.StatusNotModified)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
@@ -811,7 +848,7 @@ func postContainersAttach(eng *engine.Engine, version version.Version, w http.Re
|
|||||||
job.Stdout.Add(outStream)
|
job.Stdout.Add(outStream)
|
||||||
job.Stderr.Set(errStream)
|
job.Stderr.Set(errStream)
|
||||||
if err := job.Run(); err != nil {
|
if err := job.Run(); err != nil {
|
||||||
fmt.Fprintf(outStream, "Error: %s\n", err)
|
fmt.Fprintf(outStream, "Error attaching: %s\n", err)
|
||||||
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -841,7 +878,7 @@ func wsContainersAttach(eng *engine.Engine, version version.Version, w http.Resp
|
|||||||
job.Stdout.Add(ws)
|
job.Stdout.Add(ws)
|
||||||
job.Stderr.Set(ws)
|
job.Stderr.Set(ws)
|
||||||
if err := job.Run(); err != nil {
|
if err := job.Run(); err != nil {
|
||||||
utils.Errorf("Error: %s", err)
|
log.Errorf("Error attaching websocket: %s", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
h.ServeHTTP(w, r)
|
h.ServeHTTP(w, r)
|
||||||
@@ -855,7 +892,7 @@ func getContainersByName(eng *engine.Engine, version version.Version, w http.Res
|
|||||||
}
|
}
|
||||||
var job = eng.Job("container_inspect", vars["name"])
|
var job = eng.Job("container_inspect", vars["name"])
|
||||||
if version.LessThan("1.12") {
|
if version.LessThan("1.12") {
|
||||||
job.SetenvBool("dirty", true)
|
job.SetenvBool("raw", true)
|
||||||
}
|
}
|
||||||
streamJSON(job, w, false)
|
streamJSON(job, w, false)
|
||||||
return job.Run()
|
return job.Run()
|
||||||
@@ -867,7 +904,7 @@ func getImagesByName(eng *engine.Engine, version version.Version, w http.Respons
|
|||||||
}
|
}
|
||||||
var job = eng.Job("image_inspect", vars["name"])
|
var job = eng.Job("image_inspect", vars["name"])
|
||||||
if version.LessThan("1.12") {
|
if version.LessThan("1.12") {
|
||||||
job.SetenvBool("dirty", true)
|
job.SetenvBool("raw", true)
|
||||||
}
|
}
|
||||||
streamJSON(job, w, false)
|
streamJSON(job, w, false)
|
||||||
return job.Run()
|
return job.Run()
|
||||||
@@ -968,7 +1005,7 @@ func postContainersCopy(eng *engine.Engine, version version.Version, w http.Resp
|
|||||||
job := eng.Job("container_copy", vars["name"], copyData.Get("Resource"))
|
job := eng.Job("container_copy", vars["name"], copyData.Get("Resource"))
|
||||||
job.Stdout.Add(w)
|
job.Stdout.Add(w)
|
||||||
if err := job.Run(); err != nil {
|
if err := job.Run(); err != nil {
|
||||||
utils.Errorf("%s", err.Error())
|
log.Errorf("%s", err.Error())
|
||||||
if strings.Contains(err.Error(), "No such container") {
|
if strings.Contains(err.Error(), "No such container") {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
} else if strings.Contains(err.Error(), "no such file or directory") {
|
} else if strings.Contains(err.Error(), "no such file or directory") {
|
||||||
@@ -996,16 +1033,16 @@ func ping(eng *engine.Engine, version version.Version, w http.ResponseWriter, r
|
|||||||
func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion version.Version) http.HandlerFunc {
|
func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, localRoute string, handlerFunc HttpApiFunc, enableCors bool, dockerVersion version.Version) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
// log the request
|
// log the request
|
||||||
utils.Debugf("Calling %s %s", localMethod, localRoute)
|
log.Debugf("Calling %s %s", localMethod, localRoute)
|
||||||
|
|
||||||
if logging {
|
if logging {
|
||||||
log.Println(r.Method, r.RequestURI)
|
log.Infof("%s %s", r.Method, r.RequestURI)
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
|
if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
|
||||||
userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
|
userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
|
||||||
if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) {
|
if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) {
|
||||||
utils.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion)
|
log.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
version := version.Version(mux.Vars(r)["version"])
|
version := version.Version(mux.Vars(r)["version"])
|
||||||
@@ -1022,7 +1059,7 @@ func makeHttpHandler(eng *engine.Engine, logging bool, localMethod string, local
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := handlerFunc(eng, version, w, r, mux.Vars(r)); err != nil {
|
if err := handlerFunc(eng, version, w, r, mux.Vars(r)); err != nil {
|
||||||
utils.Errorf("Error: %s", err)
|
log.Errorf("Handler for %s %s returned error: %s", localMethod, localRoute, err)
|
||||||
httpError(w, err)
|
httpError(w, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1111,7 +1148,7 @@ func createRouter(eng *engine.Engine, logging, enableCors bool, dockerVersion st
|
|||||||
|
|
||||||
for method, routes := range m {
|
for method, routes := range m {
|
||||||
for route, fct := range routes {
|
for route, fct := range routes {
|
||||||
utils.Debugf("Registering %s, %s", method, route)
|
log.Debugf("Registering %s, %s", method, route)
|
||||||
// NOTE: scope issue, make sure the variables are local and won't be changed
|
// NOTE: scope issue, make sure the variables are local and won't be changed
|
||||||
localRoute := route
|
localRoute := route
|
||||||
localFct := fct
|
localFct := fct
|
||||||
@@ -1158,7 +1195,7 @@ func ServeFd(addr string, handle http.Handler) error {
|
|||||||
chErrors := make(chan error, len(ls))
|
chErrors := make(chan error, len(ls))
|
||||||
|
|
||||||
// We don't want to start serving on these sockets until the
|
// We don't want to start serving on these sockets until the
|
||||||
// "initserver" job has completed. Otherwise required handlers
|
// daemon is initialized and installed. Otherwise required handlers
|
||||||
// won't be ready.
|
// won't be ready.
|
||||||
<-activationLock
|
<-activationLock
|
||||||
|
|
||||||
@@ -1201,7 +1238,7 @@ func changeGroup(addr string, nameOrGid string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.Debugf("%s group found. gid: %d", nameOrGid, gid)
|
log.Debugf("%s group found. gid: %d", nameOrGid, gid)
|
||||||
return os.Chown(addr, 0, gid)
|
return os.Chown(addr, 0, gid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1272,7 +1309,7 @@ func ListenAndServe(proto, addr string, job *engine.Job) error {
|
|||||||
switch proto {
|
switch proto {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
if !strings.HasPrefix(addr, "127.0.0.1") && !job.GetenvBool("TlsVerify") {
|
if !strings.HasPrefix(addr, "127.0.0.1") && !job.GetenvBool("TlsVerify") {
|
||||||
log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
|
log.Infof("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
|
||||||
}
|
}
|
||||||
case "unix":
|
case "unix":
|
||||||
socketGroup := job.Getenv("SocketGroup")
|
socketGroup := job.Getenv("SocketGroup")
|
||||||
@@ -1280,7 +1317,7 @@ func ListenAndServe(proto, addr string, job *engine.Job) error {
|
|||||||
if err := changeGroup(addr, socketGroup); err != nil {
|
if err := changeGroup(addr, socketGroup); err != nil {
|
||||||
if socketGroup == "docker" {
|
if socketGroup == "docker" {
|
||||||
// if the user hasn't explicitly specified the group ownership, don't fail on errors.
|
// if the user hasn't explicitly specified the group ownership, don't fail on errors.
|
||||||
utils.Debugf("Warning: could not chgrp %s to docker: %s", addr, err.Error())
|
log.Debugf("Warning: could not chgrp %s to docker: %s", addr, err.Error())
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1315,7 +1352,7 @@ func ServeApi(job *engine.Job) engine.Status {
|
|||||||
return job.Errorf("usage: %s PROTO://ADDR [PROTO://ADDR ...]", job.Name)
|
return job.Errorf("usage: %s PROTO://ADDR [PROTO://ADDR ...]", job.Name)
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
log.Printf("Listening for HTTP on %s (%s)\n", protoAddrParts[0], protoAddrParts[1])
|
log.Infof("Listening for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1])
|
||||||
chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], job)
|
chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], job)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker/api"
|
|
||||||
"github.com/dotcloud/docker/engine"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api"
|
||||||
|
"github.com/docker/docker/engine"
|
||||||
|
"github.com/docker/docker/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetBoolParam(t *testing.T) {
|
func TestGetBoolParam(t *testing.T) {
|
||||||
@@ -109,18 +113,378 @@ func TestGetInfo(t *testing.T) {
|
|||||||
if v.GetInt("Containers") != 1 {
|
if v.GetInt("Containers") != 1 {
|
||||||
t.Fatalf("%#v\n", v)
|
t.Fatalf("%#v\n", v)
|
||||||
}
|
}
|
||||||
|
assertContentType(r, "application/json", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetImagesJSON(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
var called bool
|
||||||
|
eng.Register("images", func(job *engine.Job) engine.Status {
|
||||||
|
called = true
|
||||||
|
v := createEnvFromGetImagesJSONStruct(sampleImage)
|
||||||
|
if _, err := v.WriteTo(job.Stdout); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
r := serveRequest("GET", "/images/json", nil, eng, t)
|
||||||
|
if !called {
|
||||||
|
t.Fatal("handler was not called")
|
||||||
|
}
|
||||||
|
assertHttpNotError(r, t)
|
||||||
|
assertContentType(r, "application/json", t)
|
||||||
|
var observed getImagesJSONStruct
|
||||||
|
if err := json.Unmarshal(r.Body.Bytes(), &observed); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(observed, sampleImage) {
|
||||||
|
t.Errorf("Expected %#v but got %#v", sampleImage, observed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetImagesJSONFilter(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
filter := "nothing"
|
||||||
|
eng.Register("images", func(job *engine.Job) engine.Status {
|
||||||
|
filter = job.Getenv("filter")
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
serveRequest("GET", "/images/json?filter=aaaa", nil, eng, t)
|
||||||
|
if filter != "aaaa" {
|
||||||
|
t.Errorf("%#v", filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetImagesJSONFilters(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
filter := "nothing"
|
||||||
|
eng.Register("images", func(job *engine.Job) engine.Status {
|
||||||
|
filter = job.Getenv("filters")
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
serveRequest("GET", "/images/json?filters=nnnn", nil, eng, t)
|
||||||
|
if filter != "nnnn" {
|
||||||
|
t.Errorf("%#v", filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetImagesJSONAll(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
allFilter := "-1"
|
||||||
|
eng.Register("images", func(job *engine.Job) engine.Status {
|
||||||
|
allFilter = job.Getenv("all")
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
serveRequest("GET", "/images/json?all=1", nil, eng, t)
|
||||||
|
if allFilter != "1" {
|
||||||
|
t.Errorf("%#v", allFilter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetImagesJSONLegacyFormat(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
var called bool
|
||||||
|
eng.Register("images", func(job *engine.Job) engine.Status {
|
||||||
|
called = true
|
||||||
|
outsLegacy := engine.NewTable("Created", 0)
|
||||||
|
outsLegacy.Add(createEnvFromGetImagesJSONStruct(sampleImage))
|
||||||
|
if _, err := outsLegacy.WriteListTo(job.Stdout); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
r := serveRequestUsingVersion("GET", "/images/json", "1.6", nil, eng, t)
|
||||||
|
if !called {
|
||||||
|
t.Fatal("handler was not called")
|
||||||
|
}
|
||||||
|
assertHttpNotError(r, t)
|
||||||
|
assertContentType(r, "application/json", t)
|
||||||
|
images := engine.NewTable("Created", 0)
|
||||||
|
if _, err := images.ReadListFrom(r.Body.Bytes()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if images.Len() != 1 {
|
||||||
|
t.Fatalf("Expected 1 image, %d found", images.Len())
|
||||||
|
}
|
||||||
|
image := images.Data[0]
|
||||||
|
if image.Get("Tag") != "test-tag" {
|
||||||
|
t.Errorf("Expected tag 'test-tag', found '%s'", image.Get("Tag"))
|
||||||
|
}
|
||||||
|
if image.Get("Repository") != "test-name" {
|
||||||
|
t.Errorf("Expected repository 'test-name', found '%s'", image.Get("Repository"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetContainersByName(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
name := "container_name"
|
||||||
|
var called bool
|
||||||
|
eng.Register("container_inspect", func(job *engine.Job) engine.Status {
|
||||||
|
called = true
|
||||||
|
if job.Args[0] != name {
|
||||||
|
t.Errorf("name != '%s': %#v", name, job.Args[0])
|
||||||
|
}
|
||||||
|
if api.APIVERSION.LessThan("1.12") && !job.GetenvBool("dirty") {
|
||||||
|
t.Errorf("dirty env variable not set")
|
||||||
|
} else if api.APIVERSION.GreaterThanOrEqualTo("1.12") && job.GetenvBool("dirty") {
|
||||||
|
t.Errorf("dirty env variable set when it shouldn't")
|
||||||
|
}
|
||||||
|
v := &engine.Env{}
|
||||||
|
v.SetBool("dirty", true)
|
||||||
|
if _, err := v.WriteTo(job.Stdout); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
r := serveRequest("GET", "/containers/"+name+"/json", nil, eng, t)
|
||||||
|
if !called {
|
||||||
|
t.Fatal("handler was not called")
|
||||||
|
}
|
||||||
|
assertContentType(r, "application/json", t)
|
||||||
|
var stdoutJson interface{}
|
||||||
|
if err := json.Unmarshal(r.Body.Bytes(), &stdoutJson); err != nil {
|
||||||
|
t.Fatalf("%#v", err)
|
||||||
|
}
|
||||||
|
if stdoutJson.(map[string]interface{})["dirty"].(float64) != 1 {
|
||||||
|
t.Fatalf("%#v", stdoutJson)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetEvents(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
var called bool
|
||||||
|
eng.Register("events", func(job *engine.Job) engine.Status {
|
||||||
|
called = true
|
||||||
|
since := job.Getenv("since")
|
||||||
|
if since != "1" {
|
||||||
|
t.Fatalf("'since' should be 1, found %#v instead", since)
|
||||||
|
}
|
||||||
|
until := job.Getenv("until")
|
||||||
|
if until != "0" {
|
||||||
|
t.Fatalf("'until' should be 0, found %#v instead", until)
|
||||||
|
}
|
||||||
|
v := &engine.Env{}
|
||||||
|
v.Set("since", since)
|
||||||
|
v.Set("until", until)
|
||||||
|
if _, err := v.WriteTo(job.Stdout); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
r := serveRequest("GET", "/events?since=1&until=0", nil, eng, t)
|
||||||
|
if !called {
|
||||||
|
t.Fatal("handler was not called")
|
||||||
|
}
|
||||||
|
assertContentType(r, "application/json", t)
|
||||||
|
var stdout_json struct {
|
||||||
|
Since int
|
||||||
|
Until int
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(r.Body.Bytes(), &stdout_json); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if stdout_json.Since != 1 {
|
||||||
|
t.Errorf("since != 1: %#v", stdout_json.Since)
|
||||||
|
}
|
||||||
|
if stdout_json.Until != 0 {
|
||||||
|
t.Errorf("until != 0: %#v", stdout_json.Until)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogs(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
var inspect bool
|
||||||
|
var logs bool
|
||||||
|
eng.Register("container_inspect", func(job *engine.Job) engine.Status {
|
||||||
|
inspect = true
|
||||||
|
if len(job.Args) == 0 {
|
||||||
|
t.Fatal("Job arguments is empty")
|
||||||
|
}
|
||||||
|
if job.Args[0] != "test" {
|
||||||
|
t.Fatalf("Container name %s, must be test", job.Args[0])
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
expected := "logs"
|
||||||
|
eng.Register("logs", func(job *engine.Job) engine.Status {
|
||||||
|
logs = true
|
||||||
|
if len(job.Args) == 0 {
|
||||||
|
t.Fatal("Job arguments is empty")
|
||||||
|
}
|
||||||
|
if job.Args[0] != "test" {
|
||||||
|
t.Fatalf("Container name %s, must be test", job.Args[0])
|
||||||
|
}
|
||||||
|
follow := job.Getenv("follow")
|
||||||
|
if follow != "1" {
|
||||||
|
t.Fatalf("follow: %s, must be 1", follow)
|
||||||
|
}
|
||||||
|
stdout := job.Getenv("stdout")
|
||||||
|
if stdout != "1" {
|
||||||
|
t.Fatalf("stdout %s, must be 1", stdout)
|
||||||
|
}
|
||||||
|
stderr := job.Getenv("stderr")
|
||||||
|
if stderr != "" {
|
||||||
|
t.Fatalf("stderr %s, must be empty", stderr)
|
||||||
|
}
|
||||||
|
timestamps := job.Getenv("timestamps")
|
||||||
|
if timestamps != "1" {
|
||||||
|
t.Fatalf("timestamps %s, must be 1", timestamps)
|
||||||
|
}
|
||||||
|
job.Stdout.Write([]byte(expected))
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
r := serveRequest("GET", "/containers/test/logs?follow=1&stdout=1×tamps=1", nil, eng, t)
|
||||||
|
if r.Code != http.StatusOK {
|
||||||
|
t.Fatalf("Got status %d, expected %d", r.Code, http.StatusOK)
|
||||||
|
}
|
||||||
|
if !inspect {
|
||||||
|
t.Fatal("container_inspect job was not called")
|
||||||
|
}
|
||||||
|
if !logs {
|
||||||
|
t.Fatal("logs job was not called")
|
||||||
|
}
|
||||||
|
res := r.Body.String()
|
||||||
|
if res != expected {
|
||||||
|
t.Fatalf("Output %s, expected %s", res, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogsNoStreams(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
var inspect bool
|
||||||
|
var logs bool
|
||||||
|
eng.Register("container_inspect", func(job *engine.Job) engine.Status {
|
||||||
|
inspect = true
|
||||||
|
if len(job.Args) == 0 {
|
||||||
|
t.Fatal("Job arguments is empty")
|
||||||
|
}
|
||||||
|
if job.Args[0] != "test" {
|
||||||
|
t.Fatalf("Container name %s, must be test", job.Args[0])
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
eng.Register("logs", func(job *engine.Job) engine.Status {
|
||||||
|
logs = true
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
r := serveRequest("GET", "/containers/test/logs", nil, eng, t)
|
||||||
|
if r.Code != http.StatusBadRequest {
|
||||||
|
t.Fatalf("Got status %d, expected %d", r.Code, http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
if inspect {
|
||||||
|
t.Fatal("container_inspect job was called, but it shouldn't")
|
||||||
|
}
|
||||||
|
if logs {
|
||||||
|
t.Fatal("logs job was called, but it shouldn't")
|
||||||
|
}
|
||||||
|
res := strings.TrimSpace(r.Body.String())
|
||||||
|
expected := "Bad parameters: you must choose at least one stream"
|
||||||
|
if !strings.Contains(res, expected) {
|
||||||
|
t.Fatalf("Output %s, expected %s in it", res, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetImagesHistory(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
imageName := "docker-test-image"
|
||||||
|
var called bool
|
||||||
|
eng.Register("history", func(job *engine.Job) engine.Status {
|
||||||
|
called = true
|
||||||
|
if len(job.Args) == 0 {
|
||||||
|
t.Fatal("Job arguments is empty")
|
||||||
|
}
|
||||||
|
if job.Args[0] != imageName {
|
||||||
|
t.Fatalf("name != '%s': %#v", imageName, job.Args[0])
|
||||||
|
}
|
||||||
|
v := &engine.Env{}
|
||||||
|
if _, err := v.WriteTo(job.Stdout); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
r := serveRequest("GET", "/images/"+imageName+"/history", nil, eng, t)
|
||||||
|
if !called {
|
||||||
|
t.Fatalf("handler was not called")
|
||||||
|
}
|
||||||
|
if r.Code != http.StatusOK {
|
||||||
|
t.Fatalf("Got status %d, expected %d", r.Code, http.StatusOK)
|
||||||
|
}
|
||||||
if r.HeaderMap.Get("Content-Type") != "application/json" {
|
if r.HeaderMap.Get("Content-Type") != "application/json" {
|
||||||
t.Fatalf("%#v\n", r)
|
t.Fatalf("%#v\n", r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetImagesByName(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
name := "image_name"
|
||||||
|
var called bool
|
||||||
|
eng.Register("image_inspect", func(job *engine.Job) engine.Status {
|
||||||
|
called = true
|
||||||
|
if job.Args[0] != name {
|
||||||
|
t.Fatalf("name != '%s': %#v", name, job.Args[0])
|
||||||
|
}
|
||||||
|
if api.APIVERSION.LessThan("1.12") && !job.GetenvBool("dirty") {
|
||||||
|
t.Fatal("dirty env variable not set")
|
||||||
|
} else if api.APIVERSION.GreaterThanOrEqualTo("1.12") && job.GetenvBool("dirty") {
|
||||||
|
t.Fatal("dirty env variable set when it shouldn't")
|
||||||
|
}
|
||||||
|
v := &engine.Env{}
|
||||||
|
v.SetBool("dirty", true)
|
||||||
|
if _, err := v.WriteTo(job.Stdout); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
r := serveRequest("GET", "/images/"+name+"/json", nil, eng, t)
|
||||||
|
if !called {
|
||||||
|
t.Fatal("handler was not called")
|
||||||
|
}
|
||||||
|
if r.HeaderMap.Get("Content-Type") != "application/json" {
|
||||||
|
t.Fatalf("%#v\n", r)
|
||||||
|
}
|
||||||
|
var stdoutJson interface{}
|
||||||
|
if err := json.Unmarshal(r.Body.Bytes(), &stdoutJson); err != nil {
|
||||||
|
t.Fatalf("%#v", err)
|
||||||
|
}
|
||||||
|
if stdoutJson.(map[string]interface{})["dirty"].(float64) != 1 {
|
||||||
|
t.Fatalf("%#v", stdoutJson)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteContainers(t *testing.T) {
|
||||||
|
eng := engine.New()
|
||||||
|
name := "foo"
|
||||||
|
var called bool
|
||||||
|
eng.Register("delete", func(job *engine.Job) engine.Status {
|
||||||
|
called = true
|
||||||
|
if len(job.Args) == 0 {
|
||||||
|
t.Fatalf("Job arguments is empty")
|
||||||
|
}
|
||||||
|
if job.Args[0] != name {
|
||||||
|
t.Fatalf("name != '%s': %#v", name, job.Args[0])
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
})
|
||||||
|
r := serveRequest("DELETE", "/containers/"+name, nil, eng, t)
|
||||||
|
if !called {
|
||||||
|
t.Fatalf("handler was not called")
|
||||||
|
}
|
||||||
|
if r.Code != http.StatusNoContent {
|
||||||
|
t.Fatalf("Got status %d, expected %d", r.Code, http.StatusNoContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func serveRequest(method, target string, body io.Reader, eng *engine.Engine, t *testing.T) *httptest.ResponseRecorder {
|
func serveRequest(method, target string, body io.Reader, eng *engine.Engine, t *testing.T) *httptest.ResponseRecorder {
|
||||||
|
return serveRequestUsingVersion(method, target, api.APIVERSION, body, eng, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveRequestUsingVersion(method, target string, version version.Version, body io.Reader, eng *engine.Engine, t *testing.T) *httptest.ResponseRecorder {
|
||||||
r := httptest.NewRecorder()
|
r := httptest.NewRecorder()
|
||||||
req, err := http.NewRequest(method, target, body)
|
req, err := http.NewRequest(method, target, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := ServeRequest(eng, api.APIVERSION, r, req); err != nil {
|
if err := ServeRequest(eng, version, r, req); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
@@ -146,3 +510,46 @@ func toJson(data interface{}, t *testing.T) io.Reader {
|
|||||||
}
|
}
|
||||||
return &buf
|
return &buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertContentType(recorder *httptest.ResponseRecorder, content_type string, t *testing.T) {
|
||||||
|
if recorder.HeaderMap.Get("Content-Type") != content_type {
|
||||||
|
t.Fatalf("%#v\n", recorder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: Duplicated from integration/utils_test.go, but maybe that's OK as that
|
||||||
|
// should die as soon as we converted all integration tests?
|
||||||
|
// assertHttpNotError expect the given response to not have an error.
|
||||||
|
// Otherwise the it causes the test to fail.
|
||||||
|
func assertHttpNotError(r *httptest.ResponseRecorder, t *testing.T) {
|
||||||
|
// Non-error http status are [200, 400)
|
||||||
|
if r.Code < http.StatusOK || r.Code >= http.StatusBadRequest {
|
||||||
|
t.Fatal(fmt.Errorf("Unexpected http error: %v", r.Code))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createEnvFromGetImagesJSONStruct(data getImagesJSONStruct) *engine.Env {
|
||||||
|
v := &engine.Env{}
|
||||||
|
v.SetList("RepoTags", data.RepoTags)
|
||||||
|
v.Set("Id", data.Id)
|
||||||
|
v.SetInt64("Created", data.Created)
|
||||||
|
v.SetInt64("Size", data.Size)
|
||||||
|
v.SetInt64("VirtualSize", data.VirtualSize)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
type getImagesJSONStruct struct {
|
||||||
|
RepoTags []string
|
||||||
|
Id string
|
||||||
|
Created int64
|
||||||
|
Size int64
|
||||||
|
VirtualSize int64
|
||||||
|
}
|
||||||
|
|
||||||
|
var sampleImage getImagesJSONStruct = getImagesJSONStruct{
|
||||||
|
RepoTags: []string{"test-name:test-tag"},
|
||||||
|
Id: "ID",
|
||||||
|
Created: 999,
|
||||||
|
Size: 777,
|
||||||
|
VirtualSize: 666,
|
||||||
|
}
|
||||||
|
|||||||
+2
-1
@@ -1 +1,2 @@
|
|||||||
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
Cristian Staretu <cristian.staretu@gmail.com> (@unclejack)
|
||||||
|
Tibor Vass <teabee89@gmail.com> (@tiborvass)
|
||||||
|
|||||||
+86
-37
@@ -16,9 +16,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
||||||
"github.com/dotcloud/docker/utils"
|
|
||||||
"github.com/dotcloud/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
"github.com/docker/docker/pkg/log"
|
||||||
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -27,6 +29,7 @@ type (
|
|||||||
Compression int
|
Compression int
|
||||||
TarOptions struct {
|
TarOptions struct {
|
||||||
Includes []string
|
Includes []string
|
||||||
|
Excludes []string
|
||||||
Compression Compression
|
Compression Compression
|
||||||
NoLchown bool
|
NoLchown bool
|
||||||
}
|
}
|
||||||
@@ -43,6 +46,16 @@ const (
|
|||||||
Xz
|
Xz
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func IsArchive(header []byte) bool {
|
||||||
|
compression := DetectCompression(header)
|
||||||
|
if compression != Uncompressed {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
r := tar.NewReader(bytes.NewBuffer(header))
|
||||||
|
_, err := r.Next()
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
func DetectCompression(source []byte) Compression {
|
func DetectCompression(source []byte) Compression {
|
||||||
for compression, m := range map[Compression][]byte{
|
for compression, m := range map[Compression][]byte{
|
||||||
Bzip2: {0x42, 0x5A, 0x68},
|
Bzip2: {0x42, 0x5A, 0x68},
|
||||||
@@ -50,7 +63,7 @@ func DetectCompression(source []byte) Compression {
|
|||||||
Xz: {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00},
|
Xz: {0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00},
|
||||||
} {
|
} {
|
||||||
if len(source) < len(m) {
|
if len(source) < len(m) {
|
||||||
utils.Debugf("Len too short")
|
log.Debugf("Len too short")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if bytes.Compare(m, source[:len(m)]) == 0 {
|
if bytes.Compare(m, source[:len(m)]) == 0 {
|
||||||
@@ -72,7 +85,7 @@ func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
utils.Debugf("[tar autodetect] n: %v", bs)
|
log.Debugf("[tar autodetect] n: %v", bs)
|
||||||
|
|
||||||
compression := DetectCompression(bs)
|
compression := DetectCompression(bs)
|
||||||
|
|
||||||
@@ -120,7 +133,7 @@ func (compression *Compression) Extension() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func addTarFile(path, name string, tw *tar.Writer) error {
|
func addTarFile(path, name string, tw *tar.Writer, twBuf *bufio.Writer) error {
|
||||||
fi, err := os.Lstat(path)
|
fi, err := os.Lstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -166,15 +179,22 @@ func addTarFile(path, name string, tw *tar.Writer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if hdr.Typeflag == tar.TypeReg {
|
if hdr.Typeflag == tar.TypeReg {
|
||||||
if file, err := os.Open(path); err != nil {
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
|
||||||
_, err := io.Copy(tw, file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
file.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
twBuf.Reset(tw)
|
||||||
|
_, err = io.Copy(twBuf, file)
|
||||||
|
file.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = twBuf.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
twBuf.Reset(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -234,7 +254,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
|||||||
}
|
}
|
||||||
|
|
||||||
case tar.TypeXGlobalHeader:
|
case tar.TypeXGlobalHeader:
|
||||||
utils.Debugf("PAX Global Extended Headers found and ignored")
|
log.Debugf("PAX Global Extended Headers found and ignored")
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -262,11 +282,11 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
|||||||
ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
|
ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
|
||||||
// syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and
|
// syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and
|
||||||
if hdr.Typeflag != tar.TypeSymlink {
|
if hdr.Typeflag != tar.TypeSymlink {
|
||||||
if err := system.UtimesNano(path, ts); err != nil {
|
if err := system.UtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := system.LUtimesNano(path, ts); err != nil {
|
if err := system.LUtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,7 +296,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
|||||||
// Tar creates an archive from the directory at `path`, and returns it as a
|
// Tar creates an archive from the directory at `path`, and returns it as a
|
||||||
// stream of bytes.
|
// stream of bytes.
|
||||||
func Tar(path string, compression Compression) (io.ReadCloser, error) {
|
func Tar(path string, compression Compression) (io.ReadCloser, error) {
|
||||||
return TarFilter(path, &TarOptions{Compression: compression})
|
return TarWithOptions(path, &TarOptions{Compression: compression})
|
||||||
}
|
}
|
||||||
|
|
||||||
func escapeName(name string) string {
|
func escapeName(name string) string {
|
||||||
@@ -295,12 +315,9 @@ func escapeName(name string) string {
|
|||||||
return string(escaped)
|
return string(escaped)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TarFilter creates an archive from the directory at `srcPath` with `options`, and returns it as a
|
// TarWithOptions creates an archive from the directory at `path`, only including files whose relative
|
||||||
// stream of bytes.
|
// paths are included in `options.Includes` (if non-nil) or not in `options.Excludes`.
|
||||||
//
|
func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) {
|
||||||
// Files are included according to `options.Includes`, default to including all files.
|
|
||||||
// Stream is compressed according to `options.Compression', default to Uncompressed.
|
|
||||||
func TarFilter(srcPath string, options *TarOptions) (io.ReadCloser, error) {
|
|
||||||
pipeReader, pipeWriter := io.Pipe()
|
pipeReader, pipeWriter := io.Pipe()
|
||||||
|
|
||||||
compressWriter, err := CompressStream(pipeWriter, options.Compression)
|
compressWriter, err := CompressStream(pipeWriter, options.Compression)
|
||||||
@@ -320,10 +337,12 @@ func TarFilter(srcPath string, options *TarOptions) (io.ReadCloser, error) {
|
|||||||
options.Includes = []string{"."}
|
options.Includes = []string{"."}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
twBuf := bufio.NewWriterSize(nil, twBufSize)
|
||||||
|
|
||||||
for _, include := range options.Includes {
|
for _, include := range options.Includes {
|
||||||
filepath.Walk(filepath.Join(srcPath, include), func(filePath string, f os.FileInfo, err error) error {
|
filepath.Walk(filepath.Join(srcPath, include), func(filePath string, f os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Debugf("Tar: Can't stat file %s to tar: %s\n", srcPath, err)
|
log.Debugf("Tar: Can't stat file %s to tar: %s", srcPath, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,8 +351,21 @@ func TarFilter(srcPath string, options *TarOptions) (io.ReadCloser, error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := addTarFile(filePath, relFilePath, tw); err != nil {
|
skip, err := utils.Matches(relFilePath, options.Excludes)
|
||||||
utils.Debugf("Can't add file %s to tar: %s\n", srcPath, err)
|
if err != nil {
|
||||||
|
log.Debugf("Error matching %s", relFilePath, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if skip {
|
||||||
|
if f.IsDir() {
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := addTarFile(filePath, relFilePath, tw, twBuf); err != nil {
|
||||||
|
log.Debugf("Can't add file %s to tar: %s", srcPath, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -341,13 +373,13 @@ func TarFilter(srcPath string, options *TarOptions) (io.ReadCloser, error) {
|
|||||||
|
|
||||||
// Make sure to check the error on Close.
|
// Make sure to check the error on Close.
|
||||||
if err := tw.Close(); err != nil {
|
if err := tw.Close(); err != nil {
|
||||||
utils.Debugf("Can't close tar writer: %s\n", err)
|
log.Debugf("Can't close tar writer: %s", err)
|
||||||
}
|
}
|
||||||
if err := compressWriter.Close(); err != nil {
|
if err := compressWriter.Close(); err != nil {
|
||||||
utils.Debugf("Can't close compress writer: %s\n", err)
|
log.Debugf("Can't close compress writer: %s", err)
|
||||||
}
|
}
|
||||||
if err := pipeWriter.Close(); err != nil {
|
if err := pipeWriter.Close(); err != nil {
|
||||||
utils.Debugf("Can't close pipe writer: %s\n", err)
|
log.Debugf("Can't close pipe writer: %s", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -360,10 +392,18 @@ func TarFilter(srcPath string, options *TarOptions) (io.ReadCloser, error) {
|
|||||||
// identity (uncompressed), gzip, bzip2, xz.
|
// identity (uncompressed), gzip, bzip2, xz.
|
||||||
// FIXME: specify behavior when target path exists vs. doesn't exist.
|
// FIXME: specify behavior when target path exists vs. doesn't exist.
|
||||||
func Untar(archive io.Reader, dest string, options *TarOptions) error {
|
func Untar(archive io.Reader, dest string, options *TarOptions) error {
|
||||||
|
if options == nil {
|
||||||
|
options = &TarOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
if archive == nil {
|
if archive == nil {
|
||||||
return fmt.Errorf("Empty archive")
|
return fmt.Errorf("Empty archive")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.Excludes == nil {
|
||||||
|
options.Excludes = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
decompressedArchive, err := DecompressStream(archive)
|
decompressedArchive, err := DecompressStream(archive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -371,10 +411,12 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error {
|
|||||||
defer decompressedArchive.Close()
|
defer decompressedArchive.Close()
|
||||||
|
|
||||||
tr := tar.NewReader(decompressedArchive)
|
tr := tar.NewReader(decompressedArchive)
|
||||||
|
trBuf := bufio.NewReaderSize(nil, trBufSize)
|
||||||
|
|
||||||
var dirs []*tar.Header
|
var dirs []*tar.Header
|
||||||
|
|
||||||
// Iterate through the files in the archive.
|
// Iterate through the files in the archive.
|
||||||
|
loop:
|
||||||
for {
|
for {
|
||||||
hdr, err := tr.Next()
|
hdr, err := tr.Next()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@@ -388,6 +430,12 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error {
|
|||||||
// Normalize name, for safety and for a simple is-root check
|
// Normalize name, for safety and for a simple is-root check
|
||||||
hdr.Name = filepath.Clean(hdr.Name)
|
hdr.Name = filepath.Clean(hdr.Name)
|
||||||
|
|
||||||
|
for _, exclude := range options.Excludes {
|
||||||
|
if strings.HasPrefix(hdr.Name, exclude) {
|
||||||
|
continue loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !strings.HasSuffix(hdr.Name, "/") {
|
if !strings.HasSuffix(hdr.Name, "/") {
|
||||||
// Not the root directory, ensure that the parent directory exists
|
// Not the root directory, ensure that the parent directory exists
|
||||||
parent := filepath.Dir(hdr.Name)
|
parent := filepath.Dir(hdr.Name)
|
||||||
@@ -416,7 +464,8 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := createTarFile(path, dest, hdr, tr, options == nil || !options.NoLchown); err != nil {
|
trBuf.Reset(tr)
|
||||||
|
if err := createTarFile(path, dest, hdr, trBuf, !options.NoLchown); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,8 +491,8 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error {
|
|||||||
// the output of one piped into the other. If either Tar or Untar fails,
|
// the output of one piped into the other. If either Tar or Untar fails,
|
||||||
// TarUntar aborts and returns the error.
|
// TarUntar aborts and returns the error.
|
||||||
func TarUntar(src string, dst string) error {
|
func TarUntar(src string, dst string) error {
|
||||||
utils.Debugf("TarUntar(%s %s)", src, dst)
|
log.Debugf("TarUntar(%s %s)", src, dst)
|
||||||
archive, err := TarFilter(src, &TarOptions{Compression: Uncompressed})
|
archive, err := TarWithOptions(src, &TarOptions{Compression: Uncompressed})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -479,11 +528,11 @@ func CopyWithTar(src, dst string) error {
|
|||||||
return CopyFileWithTar(src, dst)
|
return CopyFileWithTar(src, dst)
|
||||||
}
|
}
|
||||||
// Create dst, copy src's content into it
|
// Create dst, copy src's content into it
|
||||||
utils.Debugf("Creating dest directory: %s", dst)
|
log.Debugf("Creating dest directory: %s", dst)
|
||||||
if err := os.MkdirAll(dst, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(dst, 0755); err != nil && !os.IsExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
utils.Debugf("Calling TarUntar(%s, %s)", src, dst)
|
log.Debugf("Calling TarUntar(%s, %s)", src, dst)
|
||||||
return TarUntar(src, dst)
|
return TarUntar(src, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +543,7 @@ func CopyWithTar(src, dst string) error {
|
|||||||
// If `dst` ends with a trailing slash '/', the final destination path
|
// If `dst` ends with a trailing slash '/', the final destination path
|
||||||
// will be `dst/base(src)`.
|
// will be `dst/base(src)`.
|
||||||
func CopyFileWithTar(src, dst string) (err error) {
|
func CopyFileWithTar(src, dst string) (err error) {
|
||||||
utils.Debugf("CopyFileWithTar(%s, %s)", src, dst)
|
log.Debugf("CopyFileWithTar(%s, %s)", src, dst)
|
||||||
srcSt, err := os.Stat(src)
|
srcSt, err := os.Stat(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -521,19 +570,19 @@ func CopyFileWithTar(src, dst string) (err error) {
|
|||||||
}
|
}
|
||||||
defer srcF.Close()
|
defer srcF.Close()
|
||||||
|
|
||||||
tw := tar.NewWriter(w)
|
|
||||||
hdr, err := tar.FileInfoHeader(srcSt, "")
|
hdr, err := tar.FileInfoHeader(srcSt, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hdr.Name = filepath.Base(dst)
|
hdr.Name = filepath.Base(dst)
|
||||||
|
tw := tar.NewWriter(w)
|
||||||
|
defer tw.Close()
|
||||||
if err := tw.WriteHeader(hdr); err != nil {
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(tw, srcF); err != nil {
|
if _, err := io.Copy(tw, srcF); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tw.Close()
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
+95
-20
@@ -11,7 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCmdStreamLargeStderr(t *testing.T) {
|
func TestCmdStreamLargeStderr(t *testing.T) {
|
||||||
@@ -63,8 +63,8 @@ func TestCmdStreamGood(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tarUntar(t *testing.T, origin string, compression Compression) error {
|
func tarUntar(t *testing.T, origin string, options *TarOptions) ([]Change, error) {
|
||||||
archive, err := Tar(origin, compression)
|
archive, err := TarWithOptions(origin, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -72,37 +72,29 @@ func tarUntar(t *testing.T, origin string, compression Compression) error {
|
|||||||
|
|
||||||
buf := make([]byte, 10)
|
buf := make([]byte, 10)
|
||||||
if _, err := archive.Read(buf); err != nil {
|
if _, err := archive.Read(buf); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
wrap := io.MultiReader(bytes.NewReader(buf), archive)
|
wrap := io.MultiReader(bytes.NewReader(buf), archive)
|
||||||
|
|
||||||
detectedCompression := DetectCompression(buf)
|
detectedCompression := DetectCompression(buf)
|
||||||
|
compression := options.Compression
|
||||||
if detectedCompression.Extension() != compression.Extension() {
|
if detectedCompression.Extension() != compression.Extension() {
|
||||||
return fmt.Errorf("Wrong compression detected. Actual compression: %s, found %s", compression.Extension(), detectedCompression.Extension())
|
return nil, fmt.Errorf("Wrong compression detected. Actual compression: %s, found %s", compression.Extension(), detectedCompression.Extension())
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp, err := ioutil.TempDir("", "docker-test-untar")
|
tmp, err := ioutil.TempDir("", "docker-test-untar")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tmp)
|
defer os.RemoveAll(tmp)
|
||||||
if err := Untar(wrap, tmp, nil); err != nil {
|
if err := Untar(wrap, tmp, nil); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(tmp); err != nil {
|
if _, err := os.Stat(tmp); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
changes, err := ChangesDirs(origin, tmp)
|
return ChangesDirs(origin, tmp)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(changes) != 0 {
|
|
||||||
t.Fatalf("Unexpected differences after tarUntar: %v", changes)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTarUntar(t *testing.T) {
|
func TestTarUntar(t *testing.T) {
|
||||||
@@ -117,14 +109,58 @@ func TestTarUntar(t *testing.T) {
|
|||||||
if err := ioutil.WriteFile(path.Join(origin, "2"), []byte("welcome!"), 0700); err != nil {
|
if err := ioutil.WriteFile(path.Join(origin, "2"), []byte("welcome!"), 0700); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if err := ioutil.WriteFile(path.Join(origin, "3"), []byte("will be ignored"), 0700); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
for _, c := range []Compression{
|
for _, c := range []Compression{
|
||||||
Uncompressed,
|
Uncompressed,
|
||||||
Gzip,
|
Gzip,
|
||||||
} {
|
} {
|
||||||
if err := tarUntar(t, origin, c); err != nil {
|
changes, err := tarUntar(t, origin, &TarOptions{
|
||||||
|
Compression: c,
|
||||||
|
Excludes: []string{"3"},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
t.Fatalf("Error tar/untar for compression %s: %s", c.Extension(), err)
|
t.Fatalf("Error tar/untar for compression %s: %s", c.Extension(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(changes) != 1 || changes[0].Path != "/3" {
|
||||||
|
t.Fatalf("Unexpected differences after tarUntar: %v", changes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTarWithOptions(t *testing.T) {
|
||||||
|
origin, err := ioutil.TempDir("", "docker-test-untar-origin")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(origin)
|
||||||
|
if err := ioutil.WriteFile(path.Join(origin, "1"), []byte("hello world"), 0700); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(path.Join(origin, "2"), []byte("welcome!"), 0700); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
opts *TarOptions
|
||||||
|
numChanges int
|
||||||
|
}{
|
||||||
|
{&TarOptions{Includes: []string{"1"}}, 1},
|
||||||
|
{&TarOptions{Excludes: []string{"2"}}, 1},
|
||||||
|
}
|
||||||
|
for _, testCase := range cases {
|
||||||
|
changes, err := tarUntar(t, origin, testCase.opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error tar/untar when testing inclusion/exclusion: %s", err)
|
||||||
|
}
|
||||||
|
if len(changes) != testCase.numChanges {
|
||||||
|
t.Errorf("Expected %d changes, got %d for %+v:",
|
||||||
|
testCase.numChanges, len(changes), testCase.opts)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,6 +200,45 @@ func TestUntarUstarGnuConflict(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
t.Fatal("%s not found in the archive", "root/.cpanm/work/1395823785.24209/Plack-1.0030/blib/man3/Plack::Middleware::LighttpdScriptNameFix.3pm")
|
t.Fatalf("%s not found in the archive", "root/.cpanm/work/1395823785.24209/Plack-1.0030/blib/man3/Plack::Middleware::LighttpdScriptNameFix.3pm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareUntarSourceDirectory(numberOfFiles int, targetPath string) (int, error) {
|
||||||
|
fileData := []byte("fooo")
|
||||||
|
for n := 0; n < numberOfFiles; n++ {
|
||||||
|
fileName := fmt.Sprintf("file-%d", n)
|
||||||
|
if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalSize := numberOfFiles * len(fileData)
|
||||||
|
return totalSize, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkTarUntar(b *testing.B) {
|
||||||
|
origin, err := ioutil.TempDir("", "docker-test-untar-origin")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
tempDir, err := ioutil.TempDir("", "docker-test-untar-destination")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
target := path.Join(tempDir, "dest")
|
||||||
|
n, err := prepareUntarSourceDirectory(100, origin)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
b.SetBytes(int64(n))
|
||||||
|
defer os.RemoveAll(origin)
|
||||||
|
defer os.RemoveAll(tempDir)
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
err := TarUntar(origin, target)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
os.RemoveAll(target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-7
@@ -1,6 +1,7 @@
|
|||||||
package archive
|
package archive
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -10,9 +11,10 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
||||||
"github.com/dotcloud/docker/utils"
|
|
||||||
"github.com/dotcloud/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
"github.com/docker/docker/pkg/log"
|
||||||
|
"github.com/docker/docker/pkg/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ChangeType int
|
type ChangeType int
|
||||||
@@ -343,6 +345,7 @@ func ExportChanges(dir string, changes []Change) (Archive, error) {
|
|||||||
tw := tar.NewWriter(writer)
|
tw := tar.NewWriter(writer)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
twBuf := bufio.NewWriterSize(nil, twBufSize)
|
||||||
// In general we log errors here but ignore them because
|
// In general we log errors here but ignore them because
|
||||||
// during e.g. a diff operation the container can continue
|
// during e.g. a diff operation the container can continue
|
||||||
// mutating the filesystem and we can see transient errors
|
// mutating the filesystem and we can see transient errors
|
||||||
@@ -361,19 +364,19 @@ func ExportChanges(dir string, changes []Change) (Archive, error) {
|
|||||||
ChangeTime: timestamp,
|
ChangeTime: timestamp,
|
||||||
}
|
}
|
||||||
if err := tw.WriteHeader(hdr); err != nil {
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
utils.Debugf("Can't write whiteout header: %s\n", err)
|
log.Debugf("Can't write whiteout header: %s", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
path := filepath.Join(dir, change.Path)
|
path := filepath.Join(dir, change.Path)
|
||||||
if err := addTarFile(path, change.Path[1:], tw); err != nil {
|
if err := addTarFile(path, change.Path[1:], tw, twBuf); err != nil {
|
||||||
utils.Debugf("Can't add file %s to tar: %s\n", path, err)
|
log.Debugf("Can't add file %s to tar: %s", path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure to check the error on Close.
|
// Make sure to check the error on Close.
|
||||||
if err := tw.Close(); err != nil {
|
if err := tw.Close(); err != nil {
|
||||||
utils.Debugf("Can't close layer: %s\n", err)
|
log.Debugf("Can't close layer: %s", err)
|
||||||
}
|
}
|
||||||
writer.Close()
|
writer.Close()
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package archive
|
||||||
|
|
||||||
|
const twBufSize = 32 * 1024
|
||||||
|
const trBufSize = 32 * 1024
|
||||||
+5
-2
@@ -1,6 +1,7 @@
|
|||||||
package archive
|
package archive
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -9,7 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes.
|
// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes.
|
||||||
@@ -32,6 +33,7 @@ func ApplyLayer(dest string, layer ArchiveReader) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tr := tar.NewReader(layer)
|
tr := tar.NewReader(layer)
|
||||||
|
trBuf := bufio.NewReaderSize(nil, trBufSize)
|
||||||
|
|
||||||
var dirs []*tar.Header
|
var dirs []*tar.Header
|
||||||
|
|
||||||
@@ -108,7 +110,8 @@ func ApplyLayer(dest string, layer ArchiveReader) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
srcData := io.Reader(tr)
|
trBuf.Reset(tr)
|
||||||
|
srcData := io.Reader(trBuf)
|
||||||
srcHdr := hdr
|
srcHdr := hdr
|
||||||
|
|
||||||
// Hard links into /.wh..wh.plnk don't work, as we don't extract that directory, so
|
// Hard links into /.wh..wh.plnk don't work, as we don't extract that directory, so
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ package archive
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"github.com/dotcloud/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -3,14 +3,14 @@ package builtins
|
|||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/api"
|
"github.com/docker/docker/api"
|
||||||
apiserver "github.com/dotcloud/docker/api/server"
|
apiserver "github.com/docker/docker/api/server"
|
||||||
"github.com/dotcloud/docker/daemon/networkdriver/bridge"
|
"github.com/docker/docker/daemon/networkdriver/bridge"
|
||||||
"github.com/dotcloud/docker/dockerversion"
|
"github.com/docker/docker/dockerversion"
|
||||||
"github.com/dotcloud/docker/engine"
|
"github.com/docker/docker/engine"
|
||||||
"github.com/dotcloud/docker/registry"
|
"github.com/docker/docker/events"
|
||||||
"github.com/dotcloud/docker/server"
|
"github.com/docker/docker/pkg/parsers/kernel"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/docker/docker/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Register(eng *engine.Engine) error {
|
func Register(eng *engine.Engine) error {
|
||||||
@@ -20,6 +20,9 @@ func Register(eng *engine.Engine) error {
|
|||||||
if err := remote(eng); err != nil {
|
if err := remote(eng); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := events.New().Install(eng); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := eng.Register("version", dockerVersion); err != nil {
|
if err := eng.Register("version", dockerVersion); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -50,22 +53,19 @@ func remote(eng *engine.Engine) error {
|
|||||||
// These components should be broken off into plugins of their own.
|
// These components should be broken off into plugins of their own.
|
||||||
//
|
//
|
||||||
func daemon(eng *engine.Engine) error {
|
func daemon(eng *engine.Engine) error {
|
||||||
if err := eng.Register("initserver", server.InitServer); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return eng.Register("init_networkdriver", bridge.InitDriver)
|
return eng.Register("init_networkdriver", bridge.InitDriver)
|
||||||
}
|
}
|
||||||
|
|
||||||
// builtins jobs independent of any subsystem
|
// builtins jobs independent of any subsystem
|
||||||
func dockerVersion(job *engine.Job) engine.Status {
|
func dockerVersion(job *engine.Job) engine.Status {
|
||||||
v := &engine.Env{}
|
v := &engine.Env{}
|
||||||
v.Set("Version", dockerversion.VERSION)
|
v.SetJson("Version", dockerversion.VERSION)
|
||||||
v.SetJson("ApiVersion", api.APIVERSION)
|
v.SetJson("ApiVersion", api.APIVERSION)
|
||||||
v.Set("GitCommit", dockerversion.GITCOMMIT)
|
v.Set("GitCommit", dockerversion.GITCOMMIT)
|
||||||
v.Set("GoVersion", runtime.Version())
|
v.Set("GoVersion", runtime.Version())
|
||||||
v.Set("Os", runtime.GOOS)
|
v.Set("Os", runtime.GOOS)
|
||||||
v.Set("Arch", runtime.GOARCH)
|
v.Set("Arch", runtime.GOARCH)
|
||||||
if kernelVersion, err := utils.GetKernelVersion(); err == nil {
|
if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
|
||||||
v.Set("KernelVersion", kernelVersion.String())
|
v.Set("KernelVersion", kernelVersion.String())
|
||||||
}
|
}
|
||||||
if _, err := v.WriteTo(job.Stdout); err != nil {
|
if _, err := v.WriteTo(job.Stdout); err != nil {
|
||||||
|
|||||||
+19
-2
@@ -100,7 +100,7 @@ echo
|
|||||||
echo 'Generally Necessary:'
|
echo 'Generally Necessary:'
|
||||||
|
|
||||||
echo -n '- '
|
echo -n '- '
|
||||||
cgroupSubsystemDir="$(awk '/[, ](cpu|cpuacct|cpuset|devices|freezer|memory)([, ]|$)/ && $8 == "cgroup" { print $5 }' /proc/$$/mountinfo | head -n1)"
|
cgroupSubsystemDir="$(awk '/[, ](cpu|cpuacct|cpuset|devices|freezer|memory)[, ]/ && $3 == "cgroup" { print $2 }' /proc/mounts | head -n1)"
|
||||||
cgroupDir="$(dirname "$cgroupSubsystemDir")"
|
cgroupDir="$(dirname "$cgroupSubsystemDir")"
|
||||||
if [ -d "$cgroupDir/cpu" -o -d "$cgroupDir/cpuacct" -o -d "$cgroupDir/cpuset" -o -d "$cgroupDir/devices" -o -d "$cgroupDir/freezer" -o -d "$cgroupDir/memory" ]; then
|
if [ -d "$cgroupDir/cpu" -o -d "$cgroupDir/cpuacct" -o -d "$cgroupDir/cpuset" -o -d "$cgroupDir/devices" -o -d "$cgroupDir/freezer" -o -d "$cgroupDir/memory" ]; then
|
||||||
echo "$(wrap_good 'cgroup hierarchy' 'properly mounted') [$cgroupDir]"
|
echo "$(wrap_good 'cgroup hierarchy' 'properly mounted') [$cgroupDir]"
|
||||||
@@ -113,10 +113,27 @@ else
|
|||||||
echo " $(wrap_color '(see https://github.com/tianon/cgroupfs-mount)' yellow)"
|
echo " $(wrap_color '(see https://github.com/tianon/cgroupfs-mount)' yellow)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = 'Y' ]; then
|
||||||
|
echo -n '- '
|
||||||
|
if command -v apparmor_parser &> /dev/null; then
|
||||||
|
echo "$(wrap_good 'apparmor' 'enabled and tools installed')"
|
||||||
|
else
|
||||||
|
echo "$(wrap_bad 'apparmor' 'enabled, but apparmor_parser missing')"
|
||||||
|
echo -n ' '
|
||||||
|
if command -v apt-get &> /dev/null; then
|
||||||
|
echo "$(wrap_color '(use "apt-get install apparmor" to fix this)')"
|
||||||
|
elif command -v yum &> /dev/null; then
|
||||||
|
echo "$(wrap_color '(your best bet is "yum install apparmor-parser")')"
|
||||||
|
else
|
||||||
|
echo "$(wrap_color '(look for an "apparmor" package for your distribution)')"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
flags=(
|
flags=(
|
||||||
NAMESPACES {NET,PID,IPC,UTS}_NS
|
NAMESPACES {NET,PID,IPC,UTS}_NS
|
||||||
DEVPTS_MULTIPLE_INSTANCES
|
DEVPTS_MULTIPLE_INSTANCES
|
||||||
CGROUPS CGROUP_CPUACCT CGROUP_DEVICE CGROUP_SCHED
|
CGROUPS CGROUP_CPUACCT CGROUP_DEVICE CGROUP_FREEZER CGROUP_SCHED
|
||||||
MACVLAN VETH BRIDGE
|
MACVLAN VETH BRIDGE
|
||||||
NF_NAT_IPV4 IP_NF_TARGET_MASQUERADE
|
NF_NAT_IPV4 IP_NF_TARGET_MASQUERADE
|
||||||
NETFILTER_XT_MATCH_{ADDRTYPE,CONNTRACK}
|
NETFILTER_XT_MATCH_{ADDRTYPE,CONNTRACK}
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ _docker_build()
|
|||||||
*)
|
*)
|
||||||
local counter="$(__docker_pos_first_nonflag '-t|--tag')"
|
local counter="$(__docker_pos_first_nonflag '-t|--tag')"
|
||||||
if [ $cword -eq $counter ]; then
|
if [ $cword -eq $counter ]; then
|
||||||
_filedir
|
_filedir -d
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -309,14 +309,6 @@ _docker_info()
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_docker_insert()
|
|
||||||
{
|
|
||||||
local counter=$(__docker_pos_first_nonflag)
|
|
||||||
if [ $cword -eq $counter ]; then
|
|
||||||
__docker_image_repos_and_tags_and_ids
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_docker_inspect()
|
_docker_inspect()
|
||||||
{
|
{
|
||||||
case "$prev" in
|
case "$prev" in
|
||||||
@@ -393,7 +385,7 @@ _docker_ps()
|
|||||||
{
|
{
|
||||||
case "$prev" in
|
case "$prev" in
|
||||||
--since|--before)
|
--since|--before)
|
||||||
__docker_containers_all
|
__docker_containers_all
|
||||||
;;
|
;;
|
||||||
-n)
|
-n)
|
||||||
return
|
return
|
||||||
@@ -438,9 +430,7 @@ _docker_push()
|
|||||||
{
|
{
|
||||||
local counter=$(__docker_pos_first_nonflag)
|
local counter=$(__docker_pos_first_nonflag)
|
||||||
if [ $cword -eq $counter ]; then
|
if [ $cword -eq $counter ]; then
|
||||||
__docker_image_repos
|
__docker_image_repos_and_tags
|
||||||
# TODO replace this with __docker_image_repos_and_tags
|
|
||||||
# see https://github.com/dotcloud/docker/issues/3411
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,10 +458,21 @@ _docker_rm()
|
|||||||
{
|
{
|
||||||
case "$cur" in
|
case "$cur" in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W "-v --volumes -l --link" -- "$cur" ) )
|
COMPREPLY=( $( compgen -W "-f --force -l --link -v --volumes" -- "$cur" ) )
|
||||||
|
return
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
local force=
|
||||||
|
for arg in "${COMP_WORDS[@]}"; do
|
||||||
|
case "$arg" in
|
||||||
|
-f|--force)
|
||||||
|
__docker_containers_all
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
__docker_containers_stopped
|
__docker_containers_stopped
|
||||||
|
return
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -484,21 +485,52 @@ _docker_rmi()
|
|||||||
_docker_run()
|
_docker_run()
|
||||||
{
|
{
|
||||||
case "$prev" in
|
case "$prev" in
|
||||||
--cidfile)
|
-a|--attach)
|
||||||
|
COMPREPLY=( $( compgen -W 'stdin stdout stderr' -- "$cur" ) )
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
--cidfile|--env-file)
|
||||||
_filedir
|
_filedir
|
||||||
|
return
|
||||||
;;
|
;;
|
||||||
--volumes-from)
|
--volumes-from)
|
||||||
__docker_containers_all
|
__docker_containers_all
|
||||||
|
return
|
||||||
;;
|
;;
|
||||||
-v|--volume)
|
-v|--volume)
|
||||||
# TODO something magical with colons and _filedir ?
|
case "$cur" in
|
||||||
|
*:*)
|
||||||
|
# TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine)
|
||||||
|
;;
|
||||||
|
'')
|
||||||
|
COMPREPLY=( $( compgen -W '/' -- "$cur" ) )
|
||||||
|
compopt -o nospace
|
||||||
|
;;
|
||||||
|
/*)
|
||||||
|
_filedir
|
||||||
|
compopt -o nospace
|
||||||
|
;;
|
||||||
|
esac
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
-e|--env)
|
-e|--env)
|
||||||
COMPREPLY=( $( compgen -e -- "$cur" ) )
|
COMPREPLY=( $( compgen -e -- "$cur" ) )
|
||||||
|
compopt -o nospace
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
--entrypoint|-h|--hostname|-m|--memory|-u|--user|-w|--workdir|-c|--cpu-shares|-n|--name|-a|--attach|--link|-p|--publish|--expose|--dns|--lxc-conf)
|
--link)
|
||||||
|
case "$cur" in
|
||||||
|
*:*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
__docker_containers_running
|
||||||
|
COMPREPLY=( $( compgen -W "${COMPREPLY[*]}" -S ':' ) )
|
||||||
|
compopt -o nospace
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
--entrypoint|-h|--hostname|-m|--memory|-u|--user|-w|--workdir|-c|--cpu-shares|-n|--name|-p|--publish|--expose|--dns|--lxc-conf)
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
|||||||
@@ -79,13 +79,13 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from build' -s t -l tag -d '
|
|||||||
|
|
||||||
# commit
|
# commit
|
||||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a commit -d "Create a new image from a container's changes"
|
complete -c docker -f -n '__fish_docker_no_subcommand' -a commit -d "Create a new image from a container's changes"
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s a -l author -d 'Author (eg. "John Hannibal Smith <hannibal@a-team.com>"'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s a -l author -d 'Author (e.g., "John Hannibal Smith <hannibal@a-team.com>"'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s m -l message -d 'Commit message'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -s m -l message -d 'Commit message'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -l run -d 'Config automatically applied when the image is run. (ex: -run=\'{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}\')'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -l run -d 'Config automatically applied when the image is run. (ex: -run=\'{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}\')'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -a '(__fish_print_docker_containers all)' -d "Container"
|
complete -c docker -A -f -n '__fish_seen_subcommand_from commit' -a '(__fish_print_docker_containers all)' -d "Container"
|
||||||
|
|
||||||
# cp
|
# cp
|
||||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a cp -d 'Copy files/folders from the containers filesystem to the host path'
|
complete -c docker -f -n '__fish_docker_no_subcommand' -a cp -d "Copy files/folders from a container's filesystem to the host path"
|
||||||
|
|
||||||
# diff
|
# diff
|
||||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a diff -d "Inspect changes on a container's filesystem"
|
complete -c docker -f -n '__fish_docker_no_subcommand' -a diff -d "Inspect changes on a container's filesystem"
|
||||||
@@ -120,10 +120,6 @@ complete -c docker -f -n '__fish_docker_no_subcommand' -a import -d 'Create a ne
|
|||||||
# info
|
# info
|
||||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a info -d 'Display system-wide information'
|
complete -c docker -f -n '__fish_docker_no_subcommand' -a info -d 'Display system-wide information'
|
||||||
|
|
||||||
# insert
|
|
||||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a insert -d 'Insert a file in an image'
|
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from insert' -a '(__fish_print_docker_images)' -d "Image"
|
|
||||||
|
|
||||||
# inspect
|
# inspect
|
||||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a inspect -d 'Return low-level information on a container'
|
complete -c docker -f -n '__fish_docker_no_subcommand' -a inspect -d 'Return low-level information on a container'
|
||||||
complete -c docker -A -f -n '__fish_seen_subcommand_from inspect' -s f -l format -d 'Format the output using the given go template.'
|
complete -c docker -A -f -n '__fish_seen_subcommand_from inspect' -s f -l format -d 'Format the output using the given go template.'
|
||||||
|
|||||||
Executable → Regular
+230
-62
@@ -1,58 +1,118 @@
|
|||||||
#compdef docker
|
#compdef docker
|
||||||
#
|
#
|
||||||
# zsh completion for docker (http://docker.io)
|
# zsh completion for docker (http://docker.com)
|
||||||
#
|
#
|
||||||
# version: 0.2.2
|
# version: 0.3.0
|
||||||
# author: Felix Riedel
|
|
||||||
# license: BSD License
|
|
||||||
# github: https://github.com/felixr/docker-zsh-completion
|
# github: https://github.com/felixr/docker-zsh-completion
|
||||||
#
|
#
|
||||||
|
# contributers:
|
||||||
|
# - Felix Riedel
|
||||||
|
# - Vincent Bernat
|
||||||
|
#
|
||||||
|
# license:
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013, Felix Riedel
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of the <organization> nor the
|
||||||
|
# names of its contributors may be used to endorse or promote products
|
||||||
|
# derived from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||||
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
__parse_docker_list() {
|
__parse_docker_list() {
|
||||||
sed -e '/^ID/d' -e 's/[ ]\{2,\}/|/g' -e 's/ \([hdwm]\)\(inutes\|ays\|ours\|eeks\)/\1/' | awk ' BEGIN {FS="|"} { printf("%s:%7s, %s\n", $1, $4, $2)}'
|
awk '
|
||||||
|
NR == 1 {
|
||||||
|
idx=1;i=0;f[i]=0
|
||||||
|
header=$0
|
||||||
|
while ( match(header, / ([A-Z]+|[A-Z]+ [A-Z]+)/) ) {
|
||||||
|
idx += RSTART+1
|
||||||
|
f[++i]=idx
|
||||||
|
header = substr($0,idx)
|
||||||
|
}
|
||||||
|
f[++i]=999
|
||||||
|
}
|
||||||
|
|
||||||
|
NR > 1 '"$1"' {
|
||||||
|
for(j=0;j<i;j++) {
|
||||||
|
x[j] = substr($0, f[j], f[j+1]-f[j]-1)
|
||||||
|
gsub(/[ ]+$/, "", x[j])
|
||||||
|
}
|
||||||
|
printf("%s:%7s, %s\n", x[0], x[3], x[1])
|
||||||
|
if (x[6] != "") {
|
||||||
|
split(x[6], names, /,/)
|
||||||
|
for (name in names) printf("%s:%7s, %s\n", names[name], x[3], x[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'| sed -e 's/ \([hdwm]\)\(inutes\|ays\|ours\|eeks\)/\1/'
|
||||||
}
|
}
|
||||||
|
|
||||||
__docker_stoppedcontainers() {
|
__docker_stoppedcontainers() {
|
||||||
local expl
|
local expl
|
||||||
declare -a stoppedcontainers
|
declare -a stoppedcontainers
|
||||||
stoppedcontainers=(${(f)"$(docker ps -a | grep --color=never 'Exit' | __parse_docker_list )"})
|
stoppedcontainers=(${(f)"$(_call_program commands docker ps -a | __parse_docker_list '&& / Exit/')"})
|
||||||
_describe -t containers-stopped "Stopped Containers" stoppedcontainers
|
_describe -t containers-stopped "Stopped Containers" stoppedcontainers "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
__docker_runningcontainers() {
|
__docker_runningcontainers() {
|
||||||
local expl
|
local expl
|
||||||
declare -a containers
|
declare -a containers
|
||||||
|
|
||||||
containers=(${(f)"$(docker ps | __parse_docker_list)"})
|
containers=(${(f)"$(_call_program commands docker ps | __parse_docker_list)"})
|
||||||
_describe -t containers-active "Running Containers" containers
|
_describe -t containers-active "Running Containers" containers "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
__docker_containers () {
|
__docker_containers () {
|
||||||
__docker_stoppedcontainers
|
__docker_stoppedcontainers "$@"
|
||||||
__docker_runningcontainers
|
__docker_runningcontainers "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
__docker_images () {
|
__docker_images () {
|
||||||
local expl
|
local expl
|
||||||
declare -a images
|
declare -a images
|
||||||
images=(${(f)"$(docker images | awk '(NR > 1){printf("%s\\:%s\n", $1,$2)}')"})
|
images=(${(f)"$(_call_program commands docker images | awk '(NR > 1 && $1 != "<none>"){printf("%s", $1);if ($2 != "<none>") printf("\\:%s", $2); printf("\n")}')"})
|
||||||
images=($images ${(f)"$(docker images | awk '(NR > 1){printf("%s:%-15s in %s\n", $3,$2,$1)}')"})
|
images=($images ${(f)"$(_call_program commands docker images | awk '(NR > 1){printf("%s:%-15s in %s\n", $3,$2,$1)}')"})
|
||||||
_describe -t docker-images "Images" images
|
_describe -t docker-images "Images" images
|
||||||
}
|
}
|
||||||
|
|
||||||
__docker_tags() {
|
__docker_tags() {
|
||||||
local expl
|
local expl
|
||||||
declare -a tags
|
declare -a tags
|
||||||
tags=(${(f)"$(docker images | awk '(NR>1){print $2}'| sort | uniq)"})
|
tags=(${(f)"$(_call_program commands docker images | awk '(NR>1){print $2}'| sort | uniq)"})
|
||||||
_describe -t docker-tags "tags" tags
|
_describe -t docker-tags "tags" tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__docker_repositories_with_tags() {
|
||||||
|
if compset -P '*:'; then
|
||||||
|
__docker_tags
|
||||||
|
else
|
||||||
|
__docker_repositories -qS ":"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
__docker_search() {
|
__docker_search() {
|
||||||
# declare -a dockersearch
|
# declare -a dockersearch
|
||||||
local cache_policy
|
local cache_policy
|
||||||
zstyle -s ":completion:${curcontext}:" cache-policy cache_policy
|
zstyle -s ":completion:${curcontext}:" cache-policy cache_policy
|
||||||
if [[ -z "$cache_policy" ]]; then
|
if [[ -z "$cache_policy" ]]; then
|
||||||
zstyle ":completion:${curcontext}:" cache-policy __docker_caching_policy
|
zstyle ":completion:${curcontext}:" cache-policy __docker_caching_policy
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local searchterm cachename
|
local searchterm cachename
|
||||||
@@ -60,14 +120,14 @@ __docker_search() {
|
|||||||
cachename=_docker-search-$searchterm
|
cachename=_docker-search-$searchterm
|
||||||
|
|
||||||
local expl
|
local expl
|
||||||
local -a result
|
local -a result
|
||||||
if ( [[ ${(P)+cachename} -eq 0 ]] || _cache_invalid ${cachename#_} ) \
|
if ( [[ ${(P)+cachename} -eq 0 ]] || _cache_invalid ${cachename#_} ) \
|
||||||
&& ! _retrieve_cache ${cachename#_}; then
|
&& ! _retrieve_cache ${cachename#_}; then
|
||||||
_message "Searching for ${searchterm}..."
|
_message "Searching for ${searchterm}..."
|
||||||
result=(${(f)"$(docker search ${searchterm} | awk '(NR>2){print $1}')"})
|
result=(${(f)"$(_call_program commands docker search ${searchterm} | awk '(NR>2){print $1}')"})
|
||||||
_store_cache ${cachename#_} result
|
_store_cache ${cachename#_} result
|
||||||
fi
|
fi
|
||||||
_wanted dockersearch expl 'Available images' compadd -a result
|
_wanted dockersearch expl 'Available images' compadd -a result
|
||||||
}
|
}
|
||||||
|
|
||||||
__docker_caching_policy()
|
__docker_caching_policy()
|
||||||
@@ -81,8 +141,8 @@ __docker_caching_policy()
|
|||||||
__docker_repositories () {
|
__docker_repositories () {
|
||||||
local expl
|
local expl
|
||||||
declare -a repos
|
declare -a repos
|
||||||
repos=(${(f)"$(docker images | sed -e '1d' -e 's/[ ].*//' | sort | uniq)"})
|
repos=(${(f)"$(_call_program commands docker images | sed -e '1d' -e 's/[ ].*//' | sort | uniq)"})
|
||||||
_describe -t docker-repos "Repositories" repos
|
_describe -t docker-repos "Repositories" repos "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
__docker_commands () {
|
__docker_commands () {
|
||||||
@@ -91,15 +151,15 @@ __docker_commands () {
|
|||||||
|
|
||||||
zstyle -s ":completion:${curcontext}:" cache-policy cache_policy
|
zstyle -s ":completion:${curcontext}:" cache-policy cache_policy
|
||||||
if [[ -z "$cache_policy" ]]; then
|
if [[ -z "$cache_policy" ]]; then
|
||||||
zstyle ":completion:${curcontext}:" cache-policy __docker_caching_policy
|
zstyle ":completion:${curcontext}:" cache-policy __docker_caching_policy
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ( [[ ${+_docker_subcommands} -eq 0 ]] || _cache_invalid docker_subcommands) \
|
if ( [[ ${+_docker_subcommands} -eq 0 ]] || _cache_invalid docker_subcommands) \
|
||||||
&& ! _retrieve_cache docker_subcommands;
|
&& ! _retrieve_cache docker_subcommands;
|
||||||
then
|
then
|
||||||
_docker_subcommands=(${${(f)"$(_call_program commands
|
_docker_subcommands=(${${(f)"$(_call_program commands
|
||||||
docker 2>&1 | sed -e '1,6d' -e '/^[ ]*$/d' -e 's/[ ]*\([^ ]\+\)\s*\([^ ].*\)/\1:\2/' )"}})
|
docker 2>&1 | sed -e '1,6d' -e '/^[ ]*$/d' -e 's/[ ]*\([^ ]\+\)\s*\([^ ].*\)/\1:\2/' )"}})
|
||||||
_docker_subcommands=($_docker_subcommands 'help:Show help for a command')
|
_docker_subcommands=($_docker_subcommands 'help:Show help for a command')
|
||||||
_store_cache docker_subcommands _docker_subcommands
|
_store_cache docker_subcommands _docker_subcommands
|
||||||
fi
|
fi
|
||||||
_describe -t docker-commands "docker command" _docker_subcommands
|
_describe -t docker-commands "docker command" _docker_subcommands
|
||||||
@@ -108,36 +168,76 @@ __docker_commands () {
|
|||||||
__docker_subcommand () {
|
__docker_subcommand () {
|
||||||
local -a _command_args
|
local -a _command_args
|
||||||
case "$words[1]" in
|
case "$words[1]" in
|
||||||
(attach|wait)
|
(attach)
|
||||||
_arguments ':containers:__docker_runningcontainers'
|
_arguments \
|
||||||
|
'--no-stdin[Do not attach stdin]' \
|
||||||
|
'--sig-proxy[Proxify all received signal]' \
|
||||||
|
':containers:__docker_runningcontainers'
|
||||||
;;
|
;;
|
||||||
(build)
|
(build)
|
||||||
_arguments \
|
_arguments \
|
||||||
'-t=-:repository:__docker_repositories' \
|
'--no-cache[Do not use cache when building the image]' \
|
||||||
|
'-q[Suppress verbose build output]' \
|
||||||
|
'--rm[Remove intermediate containers after a successful build]' \
|
||||||
|
'-t=-:repository:__docker_repositories_with_tags' \
|
||||||
':path or URL:_directories'
|
':path or URL:_directories'
|
||||||
;;
|
;;
|
||||||
(commit)
|
(commit)
|
||||||
_arguments \
|
_arguments \
|
||||||
|
'--author=-[Author]:author: ' \
|
||||||
|
'-m=-[Commit message]:message: ' \
|
||||||
|
'--run=-[Configuration automatically applied when the image is run]:configuration: ' \
|
||||||
':container:__docker_containers' \
|
':container:__docker_containers' \
|
||||||
':repository:__docker_repositories' \
|
':repository:__docker_repositories_with_tags'
|
||||||
':tag: '
|
|
||||||
;;
|
;;
|
||||||
(diff|export|logs)
|
(cp)
|
||||||
|
_arguments \
|
||||||
|
':container:->container' \
|
||||||
|
':hostpath:_files'
|
||||||
|
case $state in
|
||||||
|
(container)
|
||||||
|
if compset -P '*:'; then
|
||||||
|
_files
|
||||||
|
else
|
||||||
|
__docker_containers -qS ":"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
(diff|export)
|
||||||
_arguments '*:containers:__docker_containers'
|
_arguments '*:containers:__docker_containers'
|
||||||
;;
|
;;
|
||||||
(history)
|
(history)
|
||||||
_arguments '*:images:__docker_images'
|
_arguments \
|
||||||
|
'--no-trunc[Do not truncate output]' \
|
||||||
|
'-q[Only show numeric IDs]' \
|
||||||
|
'*:images:__docker_images'
|
||||||
;;
|
;;
|
||||||
(images)
|
(images)
|
||||||
_arguments \
|
_arguments \
|
||||||
'-a[Show all images]' \
|
'-a[Show all images]' \
|
||||||
|
'--no-trunc[Do not truncate output]' \
|
||||||
|
'-q[Only show numeric IDs]' \
|
||||||
|
'--tree[Output graph in tree format]' \
|
||||||
|
'--viz[Output graph in graphviz format]' \
|
||||||
':repository:__docker_repositories'
|
':repository:__docker_repositories'
|
||||||
;;
|
;;
|
||||||
(inspect)
|
(inspect)
|
||||||
_arguments '*:containers:__docker_containers'
|
_arguments \
|
||||||
|
'--format=-[Format the output using the given go template]:template: ' \
|
||||||
|
'*:containers:__docker_containers'
|
||||||
;;
|
;;
|
||||||
(history)
|
(import)
|
||||||
_arguments ':images:__docker_images'
|
_arguments \
|
||||||
|
':URL:(- http:// file://)' \
|
||||||
|
':repository:__docker_repositories_with_tags'
|
||||||
|
;;
|
||||||
|
(info)
|
||||||
|
;;
|
||||||
|
(import)
|
||||||
|
_arguments \
|
||||||
|
':URL:(- http:// file://)' \
|
||||||
|
':repository:__docker_repositories_with_tags'
|
||||||
;;
|
;;
|
||||||
(insert)
|
(insert)
|
||||||
_arguments '1:containers:__docker_containers' \
|
_arguments '1:containers:__docker_containers' \
|
||||||
@@ -147,66 +247,127 @@ __docker_subcommand () {
|
|||||||
(kill)
|
(kill)
|
||||||
_arguments '*:containers:__docker_runningcontainers'
|
_arguments '*:containers:__docker_runningcontainers'
|
||||||
;;
|
;;
|
||||||
|
(load)
|
||||||
|
;;
|
||||||
|
(login)
|
||||||
|
_arguments \
|
||||||
|
'-e=-[Email]:email: ' \
|
||||||
|
'-p=-[Password]:password: ' \
|
||||||
|
'-u=-[Username]:username: ' \
|
||||||
|
':server: '
|
||||||
|
;;
|
||||||
|
(logs)
|
||||||
|
_arguments \
|
||||||
|
'-f[Follow log output]' \
|
||||||
|
'*:containers:__docker_containers'
|
||||||
|
;;
|
||||||
(port)
|
(port)
|
||||||
_arguments '1:containers:__docker_runningcontainers'
|
_arguments \
|
||||||
|
'1:containers:__docker_runningcontainers' \
|
||||||
|
'2:port:_ports'
|
||||||
;;
|
;;
|
||||||
(start)
|
(start)
|
||||||
_arguments '*:containers:__docker_stoppedcontainers'
|
_arguments \
|
||||||
|
'-a[Attach container'"'"'s stdout/stderr and forward all signals]' \
|
||||||
|
'-i[Attach container'"'"'s stding]' \
|
||||||
|
'*:containers:__docker_stoppedcontainers'
|
||||||
;;
|
;;
|
||||||
(rm)
|
(rm)
|
||||||
_arguments '-v[Remove the volumes associated to the container]' \
|
_arguments \
|
||||||
|
'--link[Remove the specified link and not the underlying container]' \
|
||||||
|
'-v[Remove the volumes associated to the container]' \
|
||||||
'*:containers:__docker_stoppedcontainers'
|
'*:containers:__docker_stoppedcontainers'
|
||||||
;;
|
;;
|
||||||
(rmi)
|
(rmi)
|
||||||
_arguments '-v[Remove the volumes associated to the container]' \
|
_arguments \
|
||||||
'*:images:__docker_images'
|
'*:images:__docker_images'
|
||||||
;;
|
;;
|
||||||
(top)
|
|
||||||
_arguments '1:containers:__docker_runningcontainers'
|
|
||||||
;;
|
|
||||||
(restart|stop)
|
(restart|stop)
|
||||||
_arguments '-t=-[Number of seconds to try to stop for before killing the container]:seconds to before killing:(1 5 10 30 60)' \
|
_arguments '-t=-[Number of seconds to try to stop for before killing the container]:seconds to before killing:(1 5 10 30 60)' \
|
||||||
'*:containers:__docker_runningcontainers'
|
'*:containers:__docker_runningcontainers'
|
||||||
;;
|
;;
|
||||||
(top)
|
(top)
|
||||||
_arguments ':containers:__docker_runningcontainers'
|
_arguments \
|
||||||
|
'1:containers:__docker_runningcontainers' \
|
||||||
|
'(-)*:: :->ps-arguments'
|
||||||
|
case $state in
|
||||||
|
(ps-arguments)
|
||||||
|
_ps
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
;;
|
;;
|
||||||
(ps)
|
(ps)
|
||||||
_arguments '-a[Show all containers. Only running containers are shown by default]' \
|
_arguments \
|
||||||
'-h[Show help]' \
|
'-a[Show all containers]' \
|
||||||
'--before-id=-[Show only container created before Id, include non-running one]:containers:__docker_containers' \
|
'--before=-[Show only container created before...]:containers:__docker_containers' \
|
||||||
'-n=-[Show n last created containers, include non-running one]:n:(1 5 10 25 50)'
|
'-l[Show only the latest created container]' \
|
||||||
|
'-n=-[Show n last created containers, include non-running one]:n:(1 5 10 25 50)' \
|
||||||
|
'--no-trunc[Do not truncate output]' \
|
||||||
|
'-q[Only show numeric IDs]' \
|
||||||
|
'-s[Display sizes]' \
|
||||||
|
'--since=-[Show only containers created since...]:containers:__docker_containers'
|
||||||
;;
|
;;
|
||||||
(tag)
|
(tag)
|
||||||
_arguments \
|
_arguments \
|
||||||
'-f[force]'\
|
'-f[force]'\
|
||||||
':image:__docker_images'\
|
':image:__docker_images'\
|
||||||
':repository:__docker_repositories' \
|
':repository:__docker_repositories_with_tags'
|
||||||
':tag:__docker_tags'
|
|
||||||
;;
|
;;
|
||||||
(run)
|
(run)
|
||||||
_arguments \
|
_arguments \
|
||||||
'-a=-[Attach to stdin, stdout or stderr]:toggle:(true false)' \
|
'-P[Publish all exposed ports to the host]' \
|
||||||
'-c=-[CPU shares (relative weight)]:CPU shares: ' \
|
'-a[Attach to stdin, stdout or stderr]' \
|
||||||
|
'-c=-[CPU shares (relative weight)]:CPU shares:(0 10 100 200 500 800 1000)' \
|
||||||
|
'--cidfile=-[Write the container ID to the file]:CID file:_files' \
|
||||||
'-d[Detached mode: leave the container running in the background]' \
|
'-d[Detached mode: leave the container running in the background]' \
|
||||||
'*--dns=[Set custom dns servers]:dns server: ' \
|
'*--dns=-[Set custom dns servers]:dns server: ' \
|
||||||
'*-e=[Set environment variables]:environment variable: ' \
|
'*-e=-[Set environment variables]:environment variable: ' \
|
||||||
'--entrypoint=-[Overwrite the default entrypoint of the image]:entry point: ' \
|
'--entrypoint=-[Overwrite the default entrypoint of the image]:entry point: ' \
|
||||||
|
'*--expose=-[Expose a port from the container without publishing it]: ' \
|
||||||
'-h=-[Container host name]:hostname:_hosts' \
|
'-h=-[Container host name]:hostname:_hosts' \
|
||||||
'-i[Keep stdin open even if not attached]' \
|
'-i[Keep stdin open even if not attached]' \
|
||||||
|
'--link=-[Add link to another container]:link:->link' \
|
||||||
|
'--lxc-conf=-[Add custom lxc options]:lxc options: ' \
|
||||||
'-m=-[Memory limit (in bytes)]:limit: ' \
|
'-m=-[Memory limit (in bytes)]:limit: ' \
|
||||||
'*-p=-[Expose a container''s port to the host]:port:_ports' \
|
'--name=-[Container name]:name: ' \
|
||||||
'-t=-[Allocate a pseudo-tty]:toggle:(true false)' \
|
'*-p=-[Expose a container'"'"'s port to the host]:port:_ports' \
|
||||||
|
'--privileged[Give extended privileges to this container]' \
|
||||||
|
'--rm[Remove intermediate containers when it exits]' \
|
||||||
|
'--sig-proxy[Proxify all received signal]' \
|
||||||
|
'-t[Allocate a pseudo-tty]' \
|
||||||
'-u=-[Username or UID]:user:_users' \
|
'-u=-[Username or UID]:user:_users' \
|
||||||
'*-v=-[Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)]:volume: '\
|
'*-v=-[Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)]:volume: '\
|
||||||
'--volumes-from=-[Mount volumes from the specified container]:volume: ' \
|
'--volumes-from=-[Mount volumes from the specified container]:volume: ' \
|
||||||
|
'-w=-[Working directory inside the container]:directory:_directories' \
|
||||||
'(-):images:__docker_images' \
|
'(-):images:__docker_images' \
|
||||||
'(-):command: _command_names -e' \
|
'(-):command: _command_names -e' \
|
||||||
'*::arguments: _normal'
|
'*::arguments: _normal'
|
||||||
;;
|
|
||||||
|
case $state in
|
||||||
|
(link)
|
||||||
|
if compset -P '*:'; then
|
||||||
|
_wanted alias expl 'Alias' compadd -E ""
|
||||||
|
else
|
||||||
|
__docker_runningcontainers -qS ":"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
;;
|
||||||
(pull|search)
|
(pull|search)
|
||||||
_arguments ':name:__docker_search'
|
_arguments ':name:__docker_search'
|
||||||
;;
|
;;
|
||||||
|
(push)
|
||||||
|
_arguments ':repository:__docker_repositories_with_tags'
|
||||||
|
;;
|
||||||
|
(save)
|
||||||
|
_arguments \
|
||||||
|
':images:__docker_images'
|
||||||
|
;;
|
||||||
|
(wait)
|
||||||
|
_arguments ':containers:__docker_runningcontainers'
|
||||||
|
;;
|
||||||
(help)
|
(help)
|
||||||
_arguments ':subcommand:__docker_commands'
|
_arguments ':subcommand:__docker_commands'
|
||||||
;;
|
;;
|
||||||
@@ -217,24 +378,31 @@ __docker_subcommand () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_docker () {
|
_docker () {
|
||||||
|
# Support for subservices, which allows for `compdef _docker docker-shell=_docker_containers`.
|
||||||
|
# Based on /usr/share/zsh/functions/Completion/Unix/_git without support for `ret`.
|
||||||
|
if [[ $service != docker ]]; then
|
||||||
|
_call_function - _$service
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
local curcontext="$curcontext" state line
|
local curcontext="$curcontext" state line
|
||||||
typeset -A opt_args
|
typeset -A opt_args
|
||||||
|
|
||||||
_arguments -C \
|
_arguments -C \
|
||||||
'-H=-[tcp://host:port to bind/connect to]:socket: ' \
|
'-H=-[tcp://host:port to bind/connect to]:socket: ' \
|
||||||
'(-): :->command' \
|
'(-): :->command' \
|
||||||
'(-)*:: :->option-or-argument'
|
'(-)*:: :->option-or-argument'
|
||||||
|
|
||||||
if (( CURRENT == 1 )); then
|
if (( CURRENT == 1 )); then
|
||||||
|
|
||||||
fi
|
fi
|
||||||
case $state in
|
case $state in
|
||||||
(command)
|
(command)
|
||||||
__docker_commands
|
__docker_commands
|
||||||
;;
|
;;
|
||||||
(option-or-argument)
|
(option-or-argument)
|
||||||
curcontext=${curcontext%:*:*}:docker-$words[1]:
|
curcontext=${curcontext%:*:*}:docker-$words[1]:
|
||||||
__docker_subcommand
|
__docker_subcommand
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,125 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var DOCKERPATH = path.Join(os.Getenv("DOCKERPATH"), "docker")
|
|
||||||
|
|
||||||
// WARNING: this crashTest will 1) crash your host, 2) remove all containers
|
|
||||||
func runDaemon() (*exec.Cmd, error) {
|
|
||||||
os.Remove("/var/run/docker.pid")
|
|
||||||
exec.Command("rm", "-rf", "/var/lib/docker/containers").Run()
|
|
||||||
cmd := exec.Command(DOCKERPATH, "-d")
|
|
||||||
outPipe, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
errPipe, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
io.Copy(os.Stdout, outPipe)
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
io.Copy(os.Stderr, errPipe)
|
|
||||||
}()
|
|
||||||
return cmd, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func crashTest() error {
|
|
||||||
if err := exec.Command("/bin/bash", "-c", "while true; do true; done").Start(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var endpoint string
|
|
||||||
if ep := os.Getenv("TEST_ENDPOINT"); ep == "" {
|
|
||||||
endpoint = "192.168.56.1:7979"
|
|
||||||
} else {
|
|
||||||
endpoint = ep
|
|
||||||
}
|
|
||||||
|
|
||||||
c := make(chan bool)
|
|
||||||
var conn io.Writer
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
conn, _ = net.Dial("tcp", endpoint)
|
|
||||||
c <- false
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
c <- true
|
|
||||||
}()
|
|
||||||
<-c
|
|
||||||
|
|
||||||
restartCount := 0
|
|
||||||
totalTestCount := 1
|
|
||||||
for {
|
|
||||||
daemon, err := runDaemon()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
restartCount++
|
|
||||||
// time.Sleep(5000 * time.Millisecond)
|
|
||||||
var stop bool
|
|
||||||
go func() error {
|
|
||||||
stop = false
|
|
||||||
for i := 0; i < 100 && !stop; {
|
|
||||||
func() error {
|
|
||||||
cmd := exec.Command(DOCKERPATH, "run", "ubuntu", "echo", fmt.Sprintf("%d", totalTestCount))
|
|
||||||
i++
|
|
||||||
totalTestCount++
|
|
||||||
outPipe, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
inPipe, err := cmd.StdinPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if conn != nil {
|
|
||||||
go io.Copy(conn, outPipe)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expecting error, do not check
|
|
||||||
inPipe.Write([]byte("hello world!!!!!\n"))
|
|
||||||
go inPipe.Write([]byte("hello world!!!!!\n"))
|
|
||||||
go inPipe.Write([]byte("hello world!!!!!\n"))
|
|
||||||
inPipe.Close()
|
|
||||||
|
|
||||||
if err := cmd.Wait(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
outPipe.Close()
|
|
||||||
return nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}()
|
|
||||||
time.Sleep(20 * time.Second)
|
|
||||||
stop = true
|
|
||||||
if err := daemon.Process.Kill(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if err := crashTest(); err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,7 +29,7 @@ FROM debian:wheezy
|
|||||||
MAINTAINER Daniel Mizyrycki <daniel@docker.com>
|
MAINTAINER Daniel Mizyrycki <daniel@docker.com>
|
||||||
|
|
||||||
# Install Iceweasel and "sudo"
|
# Install Iceweasel and "sudo"
|
||||||
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -yq iceweasel sudo
|
RUN apt-get update && apt-get install -y iceweasel sudo
|
||||||
|
|
||||||
# create sysadmin account
|
# create sysadmin account
|
||||||
RUN useradd -m -d /data -p saIVpsc0EVTwA sysadmin
|
RUN useradd -m -d /data -p saIVpsc0EVTwA sysadmin
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker/daemon/graphdriver/devmapper"
|
"github.com/docker/docker/daemon/graphdriver/devmapper"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ ENV GOROOT /goroot
|
|||||||
ENV GOPATH /go
|
ENV GOPATH /go
|
||||||
ENV PATH $GOROOT/bin:$PATH
|
ENV PATH $GOROOT/bin:$PATH
|
||||||
|
|
||||||
RUN go get github.com/dotcloud/docker && cd /go/src/github.com/dotcloud/docker && git checkout v0.6.3
|
RUN go get github.com/docker/docker && cd /go/src/github.com/docker/docker && git checkout v0.6.3
|
||||||
ADD manager.go /manager/
|
ADD manager.go /manager/
|
||||||
RUN cd /manager && go build -o /usr/bin/manager
|
RUN cd /manager && go build -o /usr/bin/manager
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker"
|
"github.com/docker/docker"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ if [ ! -e "manager/$script" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# TODO https://github.com/dotcloud/docker/issues/734 (docker inspect formatting)
|
# TODO https://github.com/docker/docker/issues/734 (docker inspect formatting)
|
||||||
#if command -v docker > /dev/null 2>&1; then
|
#if command -v docker > /dev/null 2>&1; then
|
||||||
# image="$(docker inspect -f '{{.Image}}' "$cid")"
|
# image="$(docker inspect -f '{{.Image}}' "$cid")"
|
||||||
# if [ "$image" ]; then
|
# if [ "$image" ]; then
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ DOCKER_OPTS=${DOCKER_OPTS:-}
|
|||||||
start() {
|
start() {
|
||||||
checkpath -f -m 0644 -o root:docker "$DOCKER_LOGFILE"
|
checkpath -f -m 0644 -o root:docker "$DOCKER_LOGFILE"
|
||||||
|
|
||||||
|
ulimit -n 1048576
|
||||||
|
ulimit -u 1048576
|
||||||
|
|
||||||
ebegin "Starting docker daemon"
|
ebegin "Starting docker daemon"
|
||||||
start-stop-daemon --start --background \
|
start-stop-daemon --start --background \
|
||||||
--exec "$DOCKER_BINARY" \
|
--exec "$DOCKER_BINARY" \
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Lokesh Mandvekar <lsm5@fedoraproject.org> (@lsm5)
|
||||||
|
Brandon Philips <brandon.philips@coreos.com> (@philips)
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Docker Application Container Engine
|
Description=Docker Application Container Engine
|
||||||
Documentation=http://docs.docker.io
|
Documentation=http://docs.docker.com
|
||||||
After=network.target
|
After=network.target docker.socket
|
||||||
|
Requires=docker.socket
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/usr/bin/docker -d
|
ExecStart=/usr/bin/docker -d -H fd://
|
||||||
Restart=on-failure
|
|
||||||
LimitNOFILE=1048576
|
LimitNOFILE=1048576
|
||||||
LimitNPROC=1048576
|
LimitNPROC=1048576
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
Also=docker.socket
|
||||||
|
|||||||
+3
@@ -3,6 +3,9 @@ Description=Docker Socket for the API
|
|||||||
|
|
||||||
[Socket]
|
[Socket]
|
||||||
ListenStream=/var/run/docker.sock
|
ListenStream=/var/run/docker.sock
|
||||||
|
SocketMode=0660
|
||||||
|
SocketUser=root
|
||||||
|
SocketGroup=docker
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=sockets.target
|
WantedBy=sockets.target
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Docker Application Container Engine
|
|
||||||
Documentation=http://docs.docker.io
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
ExecStart=/usr/bin/docker -d -H fd://
|
|
||||||
Restart=on-failure
|
|
||||||
LimitNOFILE=1048576
|
|
||||||
LimitNPROC=1048576
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
### BEGIN INIT INFO
|
### BEGIN INIT INFO
|
||||||
# Provides: docker
|
# Provides: docker
|
||||||
@@ -22,7 +23,10 @@ BASE=$(basename $0)
|
|||||||
|
|
||||||
# modify these in /etc/default/$BASE (/etc/default/docker)
|
# modify these in /etc/default/$BASE (/etc/default/docker)
|
||||||
DOCKER=/usr/bin/$BASE
|
DOCKER=/usr/bin/$BASE
|
||||||
|
# This is the pid file managed by docker itself
|
||||||
DOCKER_PIDFILE=/var/run/$BASE.pid
|
DOCKER_PIDFILE=/var/run/$BASE.pid
|
||||||
|
# This is the pid file created/managed by start-stop-daemon
|
||||||
|
DOCKER_SSD_PIDFILE=/var/run/$BASE-ssd.pid
|
||||||
DOCKER_LOGFILE=/var/log/$BASE.log
|
DOCKER_LOGFILE=/var/log/$BASE.log
|
||||||
DOCKER_OPTS=
|
DOCKER_OPTS=
|
||||||
DOCKER_DESC="Docker"
|
DOCKER_DESC="Docker"
|
||||||
@@ -85,11 +89,19 @@ case "$1" in
|
|||||||
touch "$DOCKER_LOGFILE"
|
touch "$DOCKER_LOGFILE"
|
||||||
chgrp docker "$DOCKER_LOGFILE"
|
chgrp docker "$DOCKER_LOGFILE"
|
||||||
|
|
||||||
|
ulimit -n 1048576
|
||||||
|
if [ "$BASH" ]; then
|
||||||
|
ulimit -u 1048576
|
||||||
|
else
|
||||||
|
ulimit -p 1048576
|
||||||
|
fi
|
||||||
|
|
||||||
log_begin_msg "Starting $DOCKER_DESC: $BASE"
|
log_begin_msg "Starting $DOCKER_DESC: $BASE"
|
||||||
start-stop-daemon --start --background \
|
start-stop-daemon --start --background \
|
||||||
--no-close \
|
--no-close \
|
||||||
--exec "$DOCKER" \
|
--exec "$DOCKER" \
|
||||||
--pidfile "$DOCKER_PIDFILE" \
|
--pidfile "$DOCKER_SSD_PIDFILE" \
|
||||||
|
--make-pidfile \
|
||||||
-- \
|
-- \
|
||||||
-d -p "$DOCKER_PIDFILE" \
|
-d -p "$DOCKER_PIDFILE" \
|
||||||
$DOCKER_OPTS \
|
$DOCKER_OPTS \
|
||||||
@@ -100,13 +112,13 @@ case "$1" in
|
|||||||
stop)
|
stop)
|
||||||
fail_unless_root
|
fail_unless_root
|
||||||
log_begin_msg "Stopping $DOCKER_DESC: $BASE"
|
log_begin_msg "Stopping $DOCKER_DESC: $BASE"
|
||||||
start-stop-daemon --stop --pidfile "$DOCKER_PIDFILE"
|
start-stop-daemon --stop --pidfile "$DOCKER_SSD_PIDFILE"
|
||||||
log_end_msg $?
|
log_end_msg $?
|
||||||
;;
|
;;
|
||||||
|
|
||||||
restart)
|
restart)
|
||||||
fail_unless_root
|
fail_unless_root
|
||||||
docker_pid=`cat "$DOCKER_PIDFILE" 2>/dev/null`
|
docker_pid=`cat "$DOCKER_SSD_PIDFILE" 2>/dev/null`
|
||||||
[ -n "$docker_pid" ] \
|
[ -n "$docker_pid" ] \
|
||||||
&& ps -p $docker_pid > /dev/null 2>&1 \
|
&& ps -p $docker_pid > /dev/null 2>&1 \
|
||||||
&& $0 stop
|
&& $0 stop
|
||||||
@@ -119,7 +131,7 @@ case "$1" in
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
status)
|
status)
|
||||||
status_of_proc -p "$DOCKER_PIDFILE" "$DOCKER" docker
|
status_of_proc -p "$DOCKER_SSD_PIDFILE" "$DOCKER" "$DOCKER_DESC"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
@@ -127,5 +139,3 @@ case "$1" in
|
|||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
exit 0
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
#
|
#
|
||||||
# /etc/rc.d/init.d/docker
|
# /etc/rc.d/init.d/docker
|
||||||
#
|
#
|
||||||
# Daemon for docker.io
|
# Daemon for docker.com
|
||||||
#
|
#
|
||||||
# chkconfig: 2345 95 95
|
# chkconfig: 2345 95 95
|
||||||
# description: Daemon for docker.io
|
# description: Daemon for docker.com
|
||||||
|
|
||||||
### BEGIN INIT INFO
|
### BEGIN INIT INFO
|
||||||
# Provides: docker
|
# Provides: docker
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
# Default-Start: 2 3 4 5
|
# Default-Start: 2 3 4 5
|
||||||
# Default-Stop: 0 1 6
|
# Default-Stop: 0 1 6
|
||||||
# Short-Description: start and stop docker
|
# Short-Description: start and stop docker
|
||||||
# Description: Daemon for docker.io
|
# Description: Daemon for docker.com
|
||||||
### END INIT INFO
|
### END INIT INFO
|
||||||
|
|
||||||
# Source function library.
|
# Source function library.
|
||||||
@@ -50,7 +50,7 @@ start() {
|
|||||||
pid=$!
|
pid=$!
|
||||||
touch $lockfile
|
touch $lockfile
|
||||||
# wait up to 10 seconds for the pidfile to exist. see
|
# wait up to 10 seconds for the pidfile to exist. see
|
||||||
# https://github.com/dotcloud/docker/issues/5359
|
# https://github.com/docker/docker/issues/5359
|
||||||
tries=0
|
tries=0
|
||||||
while [ ! -f $pidfile -a $tries -lt 10 ]; do
|
while [ ! -f $pidfile -a $tries -lt 10 ]; do
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# these are generated by the md/md2man-all.sh script
|
|
||||||
man*
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
FROM fedora:20
|
|
||||||
MAINTAINER ipbabble <emailwhenry@redhat.com>
|
|
||||||
# Update and install pandoc
|
|
||||||
RUN yum -y update; yum clean all;
|
|
||||||
RUN yum -y install pandoc;
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
% DOCKER(1) Docker User Manuals
|
|
||||||
% William Henry
|
|
||||||
% APRIL 2014
|
|
||||||
# NAME
|
|
||||||
docker-commit - Create a new image from the changes to an existing
|
|
||||||
container
|
|
||||||
|
|
||||||
# SYNOPSIS
|
|
||||||
**docker commit** **-a**|**--author**[=""] **-m**|**--message**[=""]
|
|
||||||
CONTAINER [REPOSITORY[:TAG]]
|
|
||||||
|
|
||||||
# DESCRIPTION
|
|
||||||
Using an existing container's name or ID you can create a new image.
|
|
||||||
|
|
||||||
# OPTIONS
|
|
||||||
**-a, --author**=""
|
|
||||||
Author name. (eg. "John Hannibal Smith <hannibal@a-team.com>"
|
|
||||||
|
|
||||||
**-m, --message**=""
|
|
||||||
Commit message
|
|
||||||
|
|
||||||
# EXAMPLES
|
|
||||||
|
|
||||||
## Creating a new image from an existing container
|
|
||||||
An existing Fedora based container has had Apache installed while running
|
|
||||||
in interactive mode with the bash shell. Apache is also running. To
|
|
||||||
create a new image run docker ps to find the container's ID and then run:
|
|
||||||
|
|
||||||
# docker commit -me= "Added Apache to Fedora base image" \
|
|
||||||
--a="A D Ministrator" 98bd7fc99854 fedora/fedora_httpd:20
|
|
||||||
|
|
||||||
# HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
|
|
||||||
based on docker.io source material and in
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
% DOCKER(1) Docker User Manuals
|
|
||||||
% William Henry
|
|
||||||
% APRIL 2014
|
|
||||||
# NAME
|
|
||||||
docker-kill - Kill a running container (send SIGKILL, or specified signal)
|
|
||||||
|
|
||||||
# SYNOPSIS
|
|
||||||
**docker kill** **--signal**[=*"KILL"*] CONTAINER [CONTAINER...]
|
|
||||||
|
|
||||||
# DESCRIPTION
|
|
||||||
|
|
||||||
The main process inside each container specified will be sent SIGKILL,
|
|
||||||
or any signal specified with option --signal.
|
|
||||||
|
|
||||||
# OPTIONS
|
|
||||||
**-s**, **--signal**=*"KILL"*
|
|
||||||
Signal to send to the container
|
|
||||||
|
|
||||||
# HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
|
|
||||||
based on docker.io source material and internal work.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
% DOCKER(1) Docker User Manuals
|
|
||||||
% William Henry
|
|
||||||
% APRIL 2014
|
|
||||||
# NAME
|
|
||||||
docker-port - Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
|
|
||||||
|
|
||||||
# SYNOPSIS
|
|
||||||
**docker port** CONTAINER PRIVATE_PORT
|
|
||||||
|
|
||||||
# DESCRIPTION
|
|
||||||
Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
|
|
||||||
|
|
||||||
# HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
|
|
||||||
based on docker.io source material and internal work.
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
% DOCKER(1) Docker User Manuals
|
|
||||||
% William Henry
|
|
||||||
% APRIL 2014
|
|
||||||
# NAME
|
|
||||||
docker-restart - Restart a running container
|
|
||||||
|
|
||||||
# SYNOPSIS
|
|
||||||
**docker restart** [**-t**|**--time**[=*10*]] CONTAINER [CONTAINER...]
|
|
||||||
|
|
||||||
# DESCRIPTION
|
|
||||||
Restart each container listed.
|
|
||||||
|
|
||||||
# OPTIONS
|
|
||||||
**-t**, **--time**=NUM
|
|
||||||
Number of seconds to try to stop for before killing the container. Once
|
|
||||||
killed it will then be restarted. Default=10
|
|
||||||
|
|
||||||
# HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
|
|
||||||
based on docker.io source material and internal work.
|
|
||||||
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
% DOCKER(1) Docker User Manuals
|
|
||||||
% William Henry
|
|
||||||
% APRIL 2014
|
|
||||||
# NAME
|
|
||||||
docker-start - Restart a stopped container
|
|
||||||
|
|
||||||
# SYNOPSIS
|
|
||||||
**docker start** [**a**|**--attach**[=*false*]] [**-i**|**--interactive**
|
|
||||||
[=*true*] CONTAINER [CONTAINER...]
|
|
||||||
|
|
||||||
# DESCRIPTION
|
|
||||||
|
|
||||||
Start a stopped container.
|
|
||||||
|
|
||||||
# OPTION
|
|
||||||
**-a**, **--attach**=*true*|*false*
|
|
||||||
When true attach to container's stdout/stderr and forward all signals to
|
|
||||||
the process
|
|
||||||
|
|
||||||
**-i**, **--interactive**=*true*|*false*
|
|
||||||
When true attach to container's stdin
|
|
||||||
|
|
||||||
# NOTES
|
|
||||||
If run on a started container, start takes no action and succeeds
|
|
||||||
unconditionally.
|
|
||||||
|
|
||||||
# HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
|
|
||||||
based on docker.io source material and internal work.
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
% DOCKER(1) Docker User Manuals
|
|
||||||
% William Henry
|
|
||||||
% APRIL 2014
|
|
||||||
# NAME
|
|
||||||
docker-stop - Stop a running container
|
|
||||||
grace period)
|
|
||||||
|
|
||||||
# SYNOPSIS
|
|
||||||
**docker stop** [**-t**|**--time**[=*10*]] CONTAINER [CONTAINER...]
|
|
||||||
|
|
||||||
# DESCRIPTION
|
|
||||||
Stop a running container (Send SIGTERM, and then SIGKILL after
|
|
||||||
grace period)
|
|
||||||
|
|
||||||
# OPTIONS
|
|
||||||
**-t**, **--time**=NUM
|
|
||||||
Wait NUM number of seconds for the container to stop before killing it.
|
|
||||||
The default is 10 seconds.
|
|
||||||
|
|
||||||
# HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com)
|
|
||||||
based on docker.io source material and internal work.
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
.\" Process this file with
|
|
||||||
.\" nroff -man -Tascii docker-attach.1
|
|
||||||
.\"
|
|
||||||
.TH "DOCKER" "1" "APRIL 2014" "0.1" "Docker"
|
|
||||||
.SH NAME
|
|
||||||
docker-attach \- Attach to a running container
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B docker attach
|
|
||||||
\fB--no-stdin\fR[=\fIfalse\fR]
|
|
||||||
\fB--sig-proxy\fR[=\fItrue\fR]
|
|
||||||
container
|
|
||||||
.SH DESCRIPTION
|
|
||||||
If you \fBdocker run\fR a container in detached mode (\fB-d\fR), you can reattach to the detached container with \fBdocker attach\fR using the container's ID or name.
|
|
||||||
.sp
|
|
||||||
You can detach from the container again (and leave it running) with CTRL-c (for a quiet exit) or CTRL-\ to get a stacktrace of the Docker client when it quits. When you detach from the container the exit code will be returned to the client.
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.TP
|
|
||||||
.B --no-stdin=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, do not attach to stdin. The default is \fIfalse\fR.
|
|
||||||
.TP
|
|
||||||
.B --sig-proxy=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, proxify all received signal to the process (even in non-tty mode). The default is \fItrue\fR.
|
|
||||||
.sp
|
|
||||||
.SH EXAMPLES
|
|
||||||
.sp
|
|
||||||
.PP
|
|
||||||
.B Attaching to a container
|
|
||||||
.TP
|
|
||||||
In this example the top command is run inside a container, from an image called fedora, in detached mode. The ID from the container is passed into the \fBdocker attach\fR command:
|
|
||||||
.sp
|
|
||||||
.nf
|
|
||||||
.RS
|
|
||||||
# ID=$(sudo docker run -d fedora /usr/bin/top -b)
|
|
||||||
# sudo docker attach $ID
|
|
||||||
top - 02:05:52 up 3:05, 0 users, load average: 0.01, 0.02, 0.05
|
|
||||||
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
|
|
||||||
Cpu(s): 0.1%us, 0.2%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
|
|
||||||
Mem: 373572k total, 355560k used, 18012k free, 27872k buffers
|
|
||||||
Swap: 786428k total, 0k used, 786428k free, 221740k cached
|
|
||||||
|
|
||||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
|
||||||
1 root 20 0 17200 1116 912 R 0 0.3 0:00.03 top
|
|
||||||
|
|
||||||
top - 02:05:55 up 3:05, 0 users, load average: 0.01, 0.02, 0.05
|
|
||||||
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
|
|
||||||
Cpu(s): 0.0%us, 0.2%sy, 0.0%ni, 99.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
|
|
||||||
Mem: 373572k total, 355244k used, 18328k free, 27872k buffers
|
|
||||||
Swap: 786428k total, 0k used, 786428k free, 221776k cached
|
|
||||||
|
|
||||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
|
||||||
1 root 20 0 17208 1144 932 R 0 0.3 0:00.03 top
|
|
||||||
.RE
|
|
||||||
.fi
|
|
||||||
.sp
|
|
||||||
.SH HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
.\" Process this file with
|
|
||||||
.\" nroff -man -Tascii docker-build.1
|
|
||||||
.\"
|
|
||||||
.TH "DOCKER" "1" "MARCH 2014" "0.1" "Docker"
|
|
||||||
.SH NAME
|
|
||||||
docker-build \- Build an image from a Dockerfile source at PATH
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B docker build
|
|
||||||
[\fB--no-cache\fR[=\fIfalse\fR]
|
|
||||||
[\fB-q\fR|\fB--quiet\fR[=\fIfalse\fR]
|
|
||||||
[\fB--rm\fR[=\fitrue\fR]]
|
|
||||||
[\fB-t\fR|\fB--tag\fR=\fItag\fR]
|
|
||||||
PATH | URL | -
|
|
||||||
.SH DESCRIPTION
|
|
||||||
This will read the Dockerfile from the directory specified in \fBPATH\fR. It also sends any other files and directories found in the current directory to the Docker daemon. The contents of this directory would be used by ADD command found within the Dockerfile.
|
|
||||||
Warning, this will send a lot of data to the Docker daemon if the current directory contains a lot of data.
|
|
||||||
If the absolute path is provided instead of ‘.’, only the files and directories required by the ADD commands from the Dockerfile will be added to the context and transferred to the Docker daemon.
|
|
||||||
.sp
|
|
||||||
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.
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.TP
|
|
||||||
.B -q, --quiet=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, suppress verbose build output. Default is \fIfalse\fR.
|
|
||||||
.TP
|
|
||||||
.B --rm=\fItrue\fr|\fIfalse\fR:
|
|
||||||
When true, remove intermediate containers that are created during the build process. The default is true.
|
|
||||||
.TP
|
|
||||||
.B -t, --tag=\fItag\fR:
|
|
||||||
Tag to be applied to the resulting image on successful completion of the build.
|
|
||||||
.TP
|
|
||||||
.B --no-cache=\fItrue\fR|\fIfalse\fR
|
|
||||||
When set to true, do not use a cache when building the image. The default is \fIfalse\fR.
|
|
||||||
.sp
|
|
||||||
.SH EXAMPLES
|
|
||||||
.sp
|
|
||||||
.sp
|
|
||||||
.B Building an image from current directory
|
|
||||||
.TP
|
|
||||||
USing a Dockerfile, Docker images are built using the build command:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker build .
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
If, for some reasone, you do not what to remove the intermediate containers created during the build you must set--rm=false.
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker build --rm=false .
|
|
||||||
.sp
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
A good practice is to make a subdirectory with a related name and create the Dockerfile in that directory. E.g. a directory called mongo may contain a Dockerfile for a MongoDB image, or a directory called httpd may contain an Dockerfile for an Apache web server.
|
|
||||||
.sp
|
|
||||||
It is also good practice to add the files required for the image to the subdirectory. These files will be then specified with the `ADD` instruction in the Dockerfile. Note: if you include a tar file, which is good practice, then Docker will automatically extract the contents of the tar file specified in the `ADD` instruction into the specified target.
|
|
||||||
.sp
|
|
||||||
.B Building an image container using a URL
|
|
||||||
.TP
|
|
||||||
This will clone the Github repository and use it as context. The Dockerfile at the root of the repository is used as Dockerfile. This only works if the Github repository is a dedicated repository. Note that you can specify an arbitrary Git repository by using the ‘git://’ schema.
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker build github.com/scollier/Fedora-Dockerfiles/tree/master/apache
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.SH HISTORY
|
|
||||||
March 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
.\" Process this file with
|
|
||||||
.\" nroff -man -Tascii docker-images.1
|
|
||||||
.\"
|
|
||||||
.TH "DOCKER" "1" "April 2014" "0.1" "Docker"
|
|
||||||
.SH NAME
|
|
||||||
docker-images \- List the images in the local repository
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B docker images
|
|
||||||
[\fB-a\fR|\fB--all\fR=\fIfalse\fR]
|
|
||||||
[\fB--no-trunc\fR[=\fIfalse\fR]
|
|
||||||
[\fB-q\fR|\fB--quiet\fR[=\fIfalse\fR]
|
|
||||||
[\fB-t\fR|\fB--tree\fR=\fIfalse\fR]
|
|
||||||
[\fB-v\fR|\fB--viz\fR=\fIfalse\fR]
|
|
||||||
[NAME]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
This command lists the images stored in the local Docker repository.
|
|
||||||
.sp
|
|
||||||
By default, intermediate images, used during builds, are not listed. Some of the output, e.g. image ID, is truncated, for space reasons. However the truncated image ID, and often the first few characters, are enough to be used in other Docker commands that use the image ID. The output includes repository, tag, image ID, date created and the virtual size.
|
|
||||||
.sp
|
|
||||||
The title REPOSITORY for the first title may seem confusing. It is essentially the image name. However, because you can tag a specific image, and multiple tags (image instances) can be associated with a single name, the name is really a repository for all tagged images of the same name.
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.TP
|
|
||||||
.B -a, --all=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, also include all intermediate images in the list. The default is false.
|
|
||||||
.TP
|
|
||||||
.B --no-trunc=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, list the full image ID and not the truncated ID. The default is false.
|
|
||||||
.TP
|
|
||||||
.B -q, --quiet=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, list the complete image ID as part of the output. The default is false.
|
|
||||||
.TP
|
|
||||||
.B -t, --tree=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, list the images in a tree dependency tree (hierarchy) format. The default is false.
|
|
||||||
.TP
|
|
||||||
.B -v, --viz=\fItrue\fR|\fIfalse\fR
|
|
||||||
When set to true, list the graph in graphviz format. The default is \fIfalse\fR.
|
|
||||||
.sp
|
|
||||||
.SH EXAMPLES
|
|
||||||
.sp
|
|
||||||
.B Listing the images
|
|
||||||
.TP
|
|
||||||
To list the images in a local repository (not the registry) run:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker images
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
The list will contain the image repository name, a tag for the image, and an image ID, when it was created and its virtual size. Columns: REPOSITORY, TAG, IMAGE ID, CREATED, and VIRTUAL SIZE.
|
|
||||||
.sp
|
|
||||||
To get a verbose list of images which contains all the intermediate images used in builds use \fB-a\fR:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker images -a
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.B List images dependency tree hierarchy
|
|
||||||
.TP
|
|
||||||
To list the images in the local repository (not the registry) in a dependency tree format then use the \fB-t\fR|\fB--tree=true\fR option.
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker images -t
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
This displays a staggered hierarchy tree where the less indented image is the oldest with dependent image layers branching inward (to the right) on subsequent lines. The newest or top level image layer is listed last in any tree branch.
|
|
||||||
.sp
|
|
||||||
.B List images in GraphViz format
|
|
||||||
.TP
|
|
||||||
To display the list in a format consumable by a GraphViz tools run with \fB-v\fR|\fB--viz=true\fR. For example to produce a .png graph file of the hierarchy use:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker images --viz | dot -Tpng -o docker.png
|
|
||||||
.sp
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.B Listing only the shortened image IDs
|
|
||||||
.TP
|
|
||||||
Listing just the shortened image IDs. This can be useful for some automated tools.
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker images -q
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.SH HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
.\" Process this file with
|
|
||||||
.\" nroff -man -Tascii docker-info.1
|
|
||||||
.\"
|
|
||||||
.TH "DOCKER" "1" "APRIL 2014" "0.1" "Docker"
|
|
||||||
.SH NAME
|
|
||||||
docker-info \- Display system wide information
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B docker info
|
|
||||||
.SH DESCRIPTION
|
|
||||||
This command displays system wide information regarding the Docker installation. Information displayed includes the number of containers and images, pool name, data file, metadata file, data space used, total data space, metadata space used, total metadata space, execution driver, and the kernel version.
|
|
||||||
.sp
|
|
||||||
The data file is where the images are stored and the metadata file is where the meta data regarding those images are stored. When run for the first time Docker allocates a certain amount of data space and meta data space from the space available on the volume where /var/lib/docker is mounted.
|
|
||||||
.SH "OPTIONS"
|
|
||||||
There are no available options.
|
|
||||||
.sp
|
|
||||||
.SH EXAMPLES
|
|
||||||
.sp
|
|
||||||
.B Display Docker system information
|
|
||||||
.TP
|
|
||||||
Here is a sample output:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
# docker info
|
|
||||||
Containers: 18
|
|
||||||
Images: 95
|
|
||||||
Storage Driver: devicemapper
|
|
||||||
Pool Name: docker-8:1-170408448-pool
|
|
||||||
Data file: /var/lib/docker/devicemapper/devicemapper/data
|
|
||||||
Metadata file: /var/lib/docker/devicemapper/devicemapper/metadata
|
|
||||||
Data Space Used: 9946.3 Mb
|
|
||||||
Data Space Total: 102400.0 Mb
|
|
||||||
Metadata Space Used: 9.9 Mb
|
|
||||||
Metadata Space Total: 2048.0 Mb
|
|
||||||
Execution Driver: native-0.1
|
|
||||||
Kernel Version: 3.10.0-116.el7.x86_64
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.SH HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
.\" Process this file with
|
|
||||||
.\" nroff -man -Tascii docker-inspect.1
|
|
||||||
.\"
|
|
||||||
.TH "DOCKER" "1" "APRIL 2014" "0.1" "Docker"
|
|
||||||
.SH NAME
|
|
||||||
docker-inspect \- Return low-level information on a container/image
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B docker inspect
|
|
||||||
[\fB-f\fR|\fB--format\fR=""
|
|
||||||
CONTAINER|IMAGE [CONTAINER|IMAGE...]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
This displays all the information available in Docker for a given container or image. By default, this will render all results in a JSON array. If a format is specified, the given template will be executed for each result.
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.TP
|
|
||||||
.B -f, --format="":
|
|
||||||
The text/template package of Go describes all the details of the format. See examples section
|
|
||||||
.SH EXAMPLES
|
|
||||||
.sp
|
|
||||||
.PP
|
|
||||||
.B Getting information on a container
|
|
||||||
.TP
|
|
||||||
To get information on a container use it's ID or instance name
|
|
||||||
.sp
|
|
||||||
.fi
|
|
||||||
.RS
|
|
||||||
#docker inspect 1eb5fabf5a03
|
|
||||||
|
|
||||||
[{
|
|
||||||
"ID": "1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b",
|
|
||||||
"Created": "2014-04-04T21:33:52.02361335Z",
|
|
||||||
"Path": "/usr/sbin/nginx",
|
|
||||||
"Args": [],
|
|
||||||
"Config": {
|
|
||||||
"Hostname": "1eb5fabf5a03",
|
|
||||||
"Domainname": "",
|
|
||||||
"User": "",
|
|
||||||
"Memory": 0,
|
|
||||||
"MemorySwap": 0,
|
|
||||||
"CpuShares": 0,
|
|
||||||
"AttachStdin": false,
|
|
||||||
"AttachStdout": false,
|
|
||||||
"AttachStderr": false,
|
|
||||||
"PortSpecs": null,
|
|
||||||
"ExposedPorts": {
|
|
||||||
"80/tcp": {}
|
|
||||||
},
|
|
||||||
"Tty": true,
|
|
||||||
"OpenStdin": false,
|
|
||||||
"StdinOnce": false,
|
|
||||||
"Env": [
|
|
||||||
"HOME=/",
|
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
||||||
],
|
|
||||||
"Cmd": [
|
|
||||||
"/usr/sbin/nginx"
|
|
||||||
],
|
|
||||||
"Dns": null,
|
|
||||||
"DnsSearch": null,
|
|
||||||
"Image": "summit/nginx",
|
|
||||||
"Volumes": null,
|
|
||||||
"VolumesFrom": "",
|
|
||||||
"WorkingDir": "",
|
|
||||||
"Entrypoint": null,
|
|
||||||
"NetworkDisabled": false,
|
|
||||||
"OnBuild": null,
|
|
||||||
"Context": {
|
|
||||||
"mount_label": "system_u:object_r:svirt_sandbox_file_t:s0:c0,c650",
|
|
||||||
"process_label": "system_u:system_r:svirt_lxc_net_t:s0:c0,c650"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"State": {
|
|
||||||
"Running": true,
|
|
||||||
"Pid": 858,
|
|
||||||
"ExitCode": 0,
|
|
||||||
"StartedAt": "2014-04-04T21:33:54.16259207Z",
|
|
||||||
"FinishedAt": "0001-01-01T00:00:00Z",
|
|
||||||
"Ghost": false
|
|
||||||
},
|
|
||||||
"Image": "df53773a4390e25936f9fd3739e0c0e60a62d024ea7b669282b27e65ae8458e6",
|
|
||||||
"NetworkSettings": {
|
|
||||||
"IPAddress": "172.17.0.2",
|
|
||||||
"IPPrefixLen": 16,
|
|
||||||
"Gateway": "172.17.42.1",
|
|
||||||
"Bridge": "docker0",
|
|
||||||
"PortMapping": null,
|
|
||||||
"Ports": {
|
|
||||||
"80/tcp": [
|
|
||||||
{
|
|
||||||
"HostIp": "0.0.0.0",
|
|
||||||
"HostPort": "80"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ResolvConfPath": "/etc/resolv.conf",
|
|
||||||
"HostnamePath": "/var/lib/docker/containers/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b/hostname",
|
|
||||||
"HostsPath": "/var/lib/docker/containers/1eb5fabf5a03807136561b3c00adcd2992b535d624d5e18b6cdc6a6844d9767b/hosts",
|
|
||||||
"Name": "/ecstatic_ptolemy",
|
|
||||||
"Driver": "devicemapper",
|
|
||||||
"ExecDriver": "native-0.1",
|
|
||||||
"Volumes": {},
|
|
||||||
"VolumesRW": {},
|
|
||||||
"HostConfig": {
|
|
||||||
"Binds": null,
|
|
||||||
"ContainerIDFile": "",
|
|
||||||
"LxcConf": [],
|
|
||||||
"Privileged": false,
|
|
||||||
"PortBindings": {
|
|
||||||
"80/tcp": [
|
|
||||||
{
|
|
||||||
"HostIp": "0.0.0.0",
|
|
||||||
"HostPort": "80"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Links": null,
|
|
||||||
"PublishAllPorts": false,
|
|
||||||
"DriverOptions": {
|
|
||||||
"lxc": null
|
|
||||||
},
|
|
||||||
"CliAddress": ""
|
|
||||||
}
|
|
||||||
.RE
|
|
||||||
.nf
|
|
||||||
.sp
|
|
||||||
.B Getting the IP address of a container instance
|
|
||||||
.TP
|
|
||||||
To get the IP address of a container use:
|
|
||||||
.sp
|
|
||||||
.fi
|
|
||||||
.RS
|
|
||||||
# docker inspect --format='{{.NetworkSettings.IPAddress}}' 1eb5fabf5a03
|
|
||||||
|
|
||||||
172.17.0.2
|
|
||||||
.RE
|
|
||||||
.nf
|
|
||||||
.sp
|
|
||||||
.B Listing all port bindings
|
|
||||||
.TP
|
|
||||||
One can loop over arrays and maps in the results to produce simple text output:
|
|
||||||
.sp
|
|
||||||
.fi
|
|
||||||
.RS
|
|
||||||
# docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' 1eb5fabf5a03
|
|
||||||
|
|
||||||
80/tcp -> 80
|
|
||||||
.RE
|
|
||||||
.nf
|
|
||||||
.sp
|
|
||||||
.B Getting information on an image
|
|
||||||
.TP
|
|
||||||
Use an image's ID or name (e.g. repository/name[:tag]) to get information on it.
|
|
||||||
.sp
|
|
||||||
.fi
|
|
||||||
.RS
|
|
||||||
docker inspect 58394af37342
|
|
||||||
[{
|
|
||||||
"id": "58394af373423902a1b97f209a31e3777932d9321ef10e64feaaa7b4df609cf9",
|
|
||||||
"parent": "8abc22fbb04266308ff408ca61cb8f6f4244a59308f7efc64e54b08b496c58db",
|
|
||||||
"created": "2014-02-03T16:10:40.500814677Z",
|
|
||||||
"container": "f718f19a28a5147da49313c54620306243734bafa63c76942ef6f8c4b4113bc5",
|
|
||||||
"container_config": {
|
|
||||||
"Hostname": "88807319f25e",
|
|
||||||
"Domainname": "",
|
|
||||||
"User": "",
|
|
||||||
"Memory": 0,
|
|
||||||
"MemorySwap": 0,
|
|
||||||
"CpuShares": 0,
|
|
||||||
"AttachStdin": false,
|
|
||||||
"AttachStdout": false,
|
|
||||||
"AttachStderr": false,
|
|
||||||
"PortSpecs": null,
|
|
||||||
"ExposedPorts": null,
|
|
||||||
"Tty": false,
|
|
||||||
"OpenStdin": false,
|
|
||||||
"StdinOnce": false,
|
|
||||||
"Env": [
|
|
||||||
"HOME=/",
|
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
||||||
],
|
|
||||||
"Cmd": [
|
|
||||||
"/bin/sh",
|
|
||||||
"-c",
|
|
||||||
"#(nop) ADD fedora-20-medium.tar.xz in /"
|
|
||||||
],
|
|
||||||
"Dns": null,
|
|
||||||
"DnsSearch": null,
|
|
||||||
"Image": "8abc22fbb04266308ff408ca61cb8f6f4244a59308f7efc64e54b08b496c58db",
|
|
||||||
"Volumes": null,
|
|
||||||
"VolumesFrom": "",
|
|
||||||
"WorkingDir": "",
|
|
||||||
"Entrypoint": null,
|
|
||||||
"NetworkDisabled": false,
|
|
||||||
"OnBuild": null,
|
|
||||||
"Context": null
|
|
||||||
},
|
|
||||||
"docker_version": "0.6.3",
|
|
||||||
"author": "Lokesh Mandvekar \u003clsm5@redhat.com\u003e - ./buildcontainers.sh",
|
|
||||||
"config": {
|
|
||||||
"Hostname": "88807319f25e",
|
|
||||||
"Domainname": "",
|
|
||||||
"User": "",
|
|
||||||
"Memory": 0,
|
|
||||||
"MemorySwap": 0,
|
|
||||||
"CpuShares": 0,
|
|
||||||
"AttachStdin": false,
|
|
||||||
"AttachStdout": false,
|
|
||||||
"AttachStderr": false,
|
|
||||||
"PortSpecs": null,
|
|
||||||
"ExposedPorts": null,
|
|
||||||
"Tty": false,
|
|
||||||
"OpenStdin": false,
|
|
||||||
"StdinOnce": false,
|
|
||||||
"Env": [
|
|
||||||
"HOME=/",
|
|
||||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
||||||
],
|
|
||||||
"Cmd": null,
|
|
||||||
"Dns": null,
|
|
||||||
"DnsSearch": null,
|
|
||||||
"Image": "8abc22fbb04266308ff408ca61cb8f6f4244a59308f7efc64e54b08b496c58db",
|
|
||||||
"Volumes": null,
|
|
||||||
"VolumesFrom": "",
|
|
||||||
"WorkingDir": "",
|
|
||||||
"Entrypoint": null,
|
|
||||||
"NetworkDisabled": false,
|
|
||||||
"OnBuild": null,
|
|
||||||
"Context": null
|
|
||||||
},
|
|
||||||
"architecture": "x86_64",
|
|
||||||
"Size": 385520098
|
|
||||||
}]
|
|
||||||
.RE
|
|
||||||
.nf
|
|
||||||
.sp
|
|
||||||
.SH HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
.\" Process this file with
|
|
||||||
.\" nroff -man -Tascii docker-rm.1
|
|
||||||
.\"
|
|
||||||
.TH "DOCKER" "1" "MARCH 2014" "0.1" "Docker"
|
|
||||||
.SH NAME
|
|
||||||
docker-rm \- Remove one or more containers.
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B docker rm
|
|
||||||
[\fB-f\fR|\fB--force\fR[=\fIfalse\fR]
|
|
||||||
[\fB-l\fR|\fB--link\fR[=\fIfalse\fR]
|
|
||||||
[\fB-v\fR|\fB--volumes\fR[=\fIfalse\fR]
|
|
||||||
CONTAINER [CONTAINER...]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
This will remove one or more containers from the host node. The container name or ID can be used. This does not remove images. You cannot remove a running container unless you use the \fB-f\fR option. To see all containers on a host use the \fBdocker ps -a\fR command.
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.TP
|
|
||||||
.B -f, --force=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, force the removal of the container. The default is \fIfalse\fR.
|
|
||||||
.TP
|
|
||||||
.B -l, --link=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, remove the specified link and not the underlying container. The default is \fIfalse\fR.
|
|
||||||
.TP
|
|
||||||
.B -v, --volumes=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, remove the volumes associated to the container. The default is \fIfalse\fR.
|
|
||||||
.SH EXAMPLES
|
|
||||||
.sp
|
|
||||||
.PP
|
|
||||||
.B Removing a container using its ID
|
|
||||||
.TP
|
|
||||||
To remove a container using its ID, find either from a \fBdocker ps -a\fR command, or use the ID returned from the \fBdocker run\fR command, or retrieve it from a file used to store it using the \fBdocker run --cidfile\fR:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker rm abebf7571666
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.B Removing a container using the container name:
|
|
||||||
.TP
|
|
||||||
The name of the container can be found using the \fBdocker ps -a\fR command. The use that name as follows:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker rm hopeful_morse
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.SH HISTORY
|
|
||||||
March 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
DOCKER "1" "APRIL 2014" "0.1" "Docker"
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
NAME
|
|
||||||
----
|
|
||||||
|
|
||||||
docker-rm - Remove one or more containers.
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
--------
|
|
||||||
|
|
||||||
`docker rm` [`-f`|`--force`[=*false*] [`-l`|`--link`[=*false*] [`-v`|`--volumes`[=*false*]
|
|
||||||
CONTAINER [CONTAINER...]
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
-----------
|
|
||||||
|
|
||||||
`docker rm` will remove one or more containers from the host node. The container name or ID can be used. This does not remove images. You cannot remove a running container unless you use the \fB-f\fR option. To see all containers on a host use the `docker ps -a` command.
|
|
||||||
|
|
||||||
OPTIONS
|
|
||||||
-------
|
|
||||||
|
|
||||||
`-f`, `--force`=*true*|*false*:
|
|
||||||
When set to true, force the removal of the container. The default is *false*.
|
|
||||||
|
|
||||||
`-l`, `--link`=*true*|*false*:
|
|
||||||
When set to true, remove the specified link and not the underlying container. The default is *false*.
|
|
||||||
|
|
||||||
`-v`, `--volumes`=*true*|*false*:
|
|
||||||
When set to true, remove the volumes associated to the container. The default is *false*.
|
|
||||||
|
|
||||||
EXAMPLES
|
|
||||||
--------
|
|
||||||
|
|
||||||
##Removing a container using its ID##
|
|
||||||
|
|
||||||
To remove a container using its ID, find either from a `docker ps -a` command, or use the ID returned from the `docker run` command, or retrieve it from a file used to store it using the `docker run --cidfile`:
|
|
||||||
|
|
||||||
docker rm abebf7571666
|
|
||||||
|
|
||||||
##Removing a container using the container name##
|
|
||||||
|
|
||||||
The name of the container can be found using the \fBdocker ps -a\fR command. The use that name as follows:
|
|
||||||
|
|
||||||
docker rm hopeful_morse
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
-------
|
|
||||||
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
.\" Process this file with
|
|
||||||
.\" nroff -man -Tascii docker-run.1
|
|
||||||
.\"
|
|
||||||
.TH "DOCKER" "1" "MARCH 2014" "0.1" "Docker"
|
|
||||||
.SH NAME
|
|
||||||
docker-rmi \- Remove one or more images.
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B docker rmi
|
|
||||||
[\fB-f\fR|\fB--force\fR[=\fIfalse\fR]
|
|
||||||
IMAGE [IMAGE...]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
This will remove one or more images from the host node. This does not remove images from a registry. You cannot remove an image of a running container unless you use the \fB-f\fR option. To see all images on a host use the \fBdocker images\fR command.
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.TP
|
|
||||||
.B -f, --force=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, force the removal of the image. The default is \fIfalse\fR.
|
|
||||||
.SH EXAMPLES
|
|
||||||
.sp
|
|
||||||
.PP
|
|
||||||
.B Removing an image
|
|
||||||
.TP
|
|
||||||
Here is an example of removing and image:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker rmi fedora/httpd
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.SH HISTORY
|
|
||||||
March 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
.\" Process this file with
|
|
||||||
.\" nroff -man -Tascii docker-run.1
|
|
||||||
.\"
|
|
||||||
.TH "DOCKER" "1" "MARCH 2014" "0.1" "Docker"
|
|
||||||
.SH NAME
|
|
||||||
docker-run \- Run a process in an isolated container
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B docker run
|
|
||||||
[\fB-a\fR|\fB--attach\fR[=]] [\fB-c\fR|\fB--cpu-shares\fR[=0] [\fB-m\fR|\fB--memory\fR=\fImemory-limit\fR]
|
|
||||||
[\fB--cidfile\fR=\fIfile\fR] [\fB-d\fR|\fB--detach\fR[=\fIfalse\fR]] [\fB--dns\fR=\fIIP-address\fR]
|
|
||||||
[\fB--name\fR=\fIname\fR] [\fB-u\fR|\fB--user\fR=\fIusername\fR|\fIuid\fR]
|
|
||||||
[\fB--link\fR=\fIname\fR:\fIalias\fR]
|
|
||||||
[\fB-e\fR|\fB--env\fR=\fIenvironment\fR] [\fB--entrypoint\fR=\fIcommand\fR]
|
|
||||||
[\fB--expose\fR=\fIport\fR] [\fB-P\fR|\fB--publish-all\fR[=\fIfalse\fR]]
|
|
||||||
[\fB-p\fR|\fB--publish\fR=\fIport-mappping\fR] [\fB-h\fR|\fB--hostname\fR=\fIhostname\fR]
|
|
||||||
[\fB--rm\fR[=\fIfalse\fR]] [\fB--priviledged\fR[=\fIfalse\fR]
|
|
||||||
[\fB-i\fR|\fB--interactive\fR[=\fIfalse\fR]
|
|
||||||
[\fB-t\fR|\fB--tty\fR[=\fIfalse\fR]] [\fB--lxc-conf\fR=\fIoptions\fR]
|
|
||||||
[\fB-n\fR|\fB--networking\fR[=\fItrue\fR]]
|
|
||||||
[\fB-v\fR|\fB--volume\fR=\fIvolume\fR] [\fB--volumes-from\fR=\fIcontainer-id\fR]
|
|
||||||
[\fB-w\fR|\fB--workdir\fR=\fIdirectory\fR] [\fB--sig-proxy\fR[=\fItrue\fR]]
|
|
||||||
IMAGE [COMMAND] [ARG...]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
.PP
|
|
||||||
Run a process in a new container. \fBdocker run\fR starts a process with its own file system, its own networking, and its own isolated process tree. The \fIIMAGE\fR which starts the process may define defaults related to the process that will be run in the container, the networking to expose, and more, but \fBdocker run\fR gives final control to the operator or administrator who starts the container from the image. For that reason \fBdocker run\fR has more options than any other docker command.
|
|
||||||
|
|
||||||
If the \fIIMAGE\fR is not already loaded then \fBdocker run\fR will pull the \fIIMAGE\fR, and all image dependencies, from the repository in the same way running \fBdocker pull\fR \fIIMAGE\fR, before it starts the container from that image.
|
|
||||||
|
|
||||||
|
|
||||||
.SH "OPTIONS"
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -a, --attach=\fIstdin\fR|\fIstdout\fR|\fIstderr\fR:
|
|
||||||
Attach to stdin, stdout or stderr. In foreground mode (the default when -d is not specified), \fBdocker run\fR can start the process in the container and attach the console to the process’s standard input, output, and standard error. It can even pretend to be a TTY (this is what most commandline executables expect) and pass along signals. The \fB-a\fR option can be set for each of stdin, stdout, and stderr.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -c, --cpu-shares=0:
|
|
||||||
CPU shares in relative weight. You can increase the priority of a container with the -c option. By default, all containers run at the same priority and get the same proportion of CPU cycles, but you can tell the kernel to give more shares of CPU time to one or more containers when you start them via \fBdocker run\fR.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -m, --memory=\fImemory-limit\fR:
|
|
||||||
Allows you to constrain the memory available to a container. If the host supports swap memory, then the -m memory setting can be larger than physical RAM. If a limit of 0 is specified, the container's memory is not limited. The memory limit format: <number><optional unit>, where unit = b, k, m or g.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B --cidfile=\fIfile\fR:
|
|
||||||
Write the container ID to the file specified.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -d, --detach=\fItrue\fR|\fIfalse\fR:
|
|
||||||
Detached mode. This runs the container in the background. It outputs the new container's id and and error messages. At any time you can run \fBdocker ps\fR in the other shell to view a list of the running containers. You can reattach to a detached container with \fBdocker attach\fR. If you choose to run a container in the detached mode, then you cannot use the -rm option.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B --dns=\fIIP-address\fR:
|
|
||||||
Set custom DNS servers. This option can be used to override the DNS configuration passed to the container. Typically this is necessary when the host DNS configuration is invalid for the container (eg. 127.0.0.1). When this is the case the \fB-dns\fR flags is necessary for every run.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -e, --env=\fIenvironment\fR:
|
|
||||||
Set environment variables. This option allows you to specify arbitrary environment variables that are available for the process that will be launched inside of the container.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B --entrypoint=\ficommand\fR:
|
|
||||||
This option allows you to overwrite the default entrypoint of the image that is set in the Dockerfile. The ENTRYPOINT of an image is similar to a COMMAND because it specifies what executable to run when the container starts, but it is (purposely) more difficult to override. The ENTRYPOINT gives a container its default nature or behavior, so that when you set an ENTRYPOINT you can run the container as if it were that binary, complete with default options, and you can pass in more options via the COMMAND. But, sometimes an operator may want to run something else inside the container, so you can override the default ENTRYPOINT at runtime by using a \fB--entrypoint\fR and a string to specify the new ENTRYPOINT.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B --expose=\fIport\fR:
|
|
||||||
Expose a port from the container without publishing it to your host. A containers port can be exposed to other containers in three ways: 1) The developer can expose the port using the EXPOSE parameter of the Dockerfile, 2) the operator can use the \fB--expose\fR option with \fBdocker run\fR, or 3) the container can be started with the \fB--link\fR.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -P, --publish-all=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true publish all exposed ports to the host interfaces. The default is false. If the operator uses -P (or -p) then Docker will make the exposed port accessible on the host and the ports will be available to any client that can reach the host. To find the map between the host ports and the exposed ports, use \fBdocker port\fR.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -p, --publish=[]:
|
|
||||||
Publish a container's port to the host (format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort) (use 'docker port' to see the actual mapping)
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -h , --hostname=\fIhostname\fR:
|
|
||||||
Sets the container host name that is available inside the container.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -i , --interactive=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, keep stdin open even if not attached. The default is false.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B --link=\fIname\fR:\fIalias\fR:
|
|
||||||
Add link to another container. The format is name:alias. If the operator uses \fB--link\fR when starting the new client container, then the client container can access the exposed port via a private networking interface. Docker will set some environment variables in the client container to help indicate which interface and port to use.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -n, --networking=\fItrue\fR|\fIfalse\fR:
|
|
||||||
By default, all containers have networking enabled (true) and can make outgoing connections. The operator can disable networking with \fB--networking\fR to false. This disables all incoming and outgoing networking. In cases like this, I/O can only be performed through files or by using STDIN/STDOUT.
|
|
||||||
|
|
||||||
Also by default, the container will use the same DNS servers as the host. but you canThe operator may override this with \fB-dns\fR.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B --name=\fIname\fR:
|
|
||||||
Assign a name to the container. The operator can identify a container in three ways:
|
|
||||||
.sp
|
|
||||||
.nf
|
|
||||||
UUID long identifier (“f78375b1c487e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778”)
|
|
||||||
UUID short identifier (“f78375b1c487”)
|
|
||||||
Name (“jonah”)
|
|
||||||
.fi
|
|
||||||
.sp
|
|
||||||
The UUID identifiers come from the Docker daemon, and if a name is not assigned to the container with \fB--name\fR then the daemon will also generate a random string name. The name is useful when defining links (see \fB--link\fR) (or any other place you need to identify a container). This works for both background and foreground Docker containers.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B --privileged=\fItrue\fR|\fIfalse\fR:
|
|
||||||
Give extended privileges to this container. By default, Docker containers are “unprivileged” (=false) and cannot, for example, run a Docker daemon inside the Docker container. This is because by default a container is not allowed to access any devices. A “privileged” container is given access to all devices.
|
|
||||||
|
|
||||||
When the operator executes \fBdocker run -privileged\fR, Docker will enable access to all devices on the host as well as set some configuration in AppArmor (\fB???\fR) to allow the container nearly all the same access to the host as processes running outside of a container on the host.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B --rm=\fItrue\fR|\fIfalse\fR:
|
|
||||||
If set to \fItrue\fR the container is automatically removed when it exits. The default is \fIfalse\fR. This option is incompatible with \fB-d\fR.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B --sig-proxy=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, proxify all received signals to the process (even in non-tty mode). The default is true.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -t, --tty=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true Docker can allocate a pseudo-tty and attach to the standard input of any container. This can be used, for example, to run a throwaway interactive shell. The default is value is false.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -u, --user=\fIusername\fR,\fRuid\fR:
|
|
||||||
Set a username or UID for the container.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -v, --volume=\fIvolume\fR:
|
|
||||||
Bind mount a volume to the container. The \fB-v\fR option can be used one or more times to add one or more mounts to a container. These mounts can then be used in other containers using the \fB--volumes-from\fR option. See examples.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B --volumes-from=\fIcontainer-id\fR:
|
|
||||||
Will mount volumes from the specified container identified by container-id. Once a volume is mounted in a one container it can be shared with other containers using the \fB--volumes-from\fR option when running those other containers. The volumes can be shared even if the original container with the mount is not running.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B -w, --workdir=\fIdirectory\fR:
|
|
||||||
Working directory inside the container. The default working directory for running binaries within a container is the root directory (/). The developer can set a different default with the Dockerfile WORKDIR instruction. The operator can override the working directory by using the \fB-w\fR option.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B IMAGE:
|
|
||||||
The image name or ID.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B COMMAND:
|
|
||||||
The command or program to run inside the image.
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B ARG:
|
|
||||||
The arguments for the command to be run in the container.
|
|
||||||
|
|
||||||
.SH EXAMPLES
|
|
||||||
.sp
|
|
||||||
.sp
|
|
||||||
.B Exposing log messages from the container to the host's log
|
|
||||||
.TP
|
|
||||||
If you want messages that are logged in your container to show up in the host's syslog/journal then you should bind mount the /var/log directory as follows.
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker run -v /dev/log:/dev/log -i -t fedora /bin/bash
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
From inside the container you can test this by sending a message to the log.
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
logger "Hello from my container"
|
|
||||||
.sp
|
|
||||||
.RE
|
|
||||||
Then exit and check the journal.
|
|
||||||
.RS
|
|
||||||
.sp
|
|
||||||
exit
|
|
||||||
.sp
|
|
||||||
journalctl -b | grep hello
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
This should list the message sent to logger.
|
|
||||||
.sp
|
|
||||||
.B Attaching to one or more from STDIN, STDOUT, STDERR
|
|
||||||
.TP
|
|
||||||
If you do not specify -a then Docker will attach everything (stdin,stdout,stderr). You can specify to which of the three standard streams (stdin, stdout, stderr) you’d like to connect instead, as in:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker run -a stdin -a stdout -i -t fedora /bin/bash
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.B Linking Containers
|
|
||||||
.TP
|
|
||||||
The link feature allows multiple containers to communicate with each other. For example, a container whose Dockerfile has exposed port 80 can be run and named as follows:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker run --name=link-test -d -i -t fedora/httpd
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.TP
|
|
||||||
A second container, in this case called linker, can communicate with the httpd container, named link-test, by running with the \fB--link=<name>:<alias>\fR
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker run -t -i --link=link-test:lt --name=linker fedora /bin/bash
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.TP
|
|
||||||
Now the container linker is linked to container link-test with the alias lt. Running the \fBenv\fR command in the linker container shows environment variables with the LT (alias) context (\fBLT_\fR)
|
|
||||||
.sp
|
|
||||||
.nf
|
|
||||||
.RS
|
|
||||||
# env
|
|
||||||
HOSTNAME=668231cb0978
|
|
||||||
TERM=xterm
|
|
||||||
LT_PORT_80_TCP=tcp://172.17.0.3:80
|
|
||||||
LT_PORT_80_TCP_PORT=80
|
|
||||||
LT_PORT_80_TCP_PROTO=tcp
|
|
||||||
LT_PORT=tcp://172.17.0.3:80
|
|
||||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
|
||||||
PWD=/
|
|
||||||
LT_NAME=/linker/lt
|
|
||||||
SHLVL=1
|
|
||||||
HOME=/
|
|
||||||
LT_PORT_80_TCP_ADDR=172.17.0.3
|
|
||||||
_=/usr/bin/env
|
|
||||||
.RE
|
|
||||||
.fi
|
|
||||||
.sp
|
|
||||||
.TP
|
|
||||||
When linking two containers Docker will use the exposed ports of the container to create a secure tunnel for the parent to access.
|
|
||||||
.TP
|
|
||||||
.sp
|
|
||||||
.B Mapping Ports for External Usage
|
|
||||||
.TP
|
|
||||||
The exposed port of an application can be mapped to a host port using the \fB-p\fR flag. For example a httpd port 80 can be mapped to the host port 8080 using the following:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker run -p 8080:80 -d -i -t fedora/httpd
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.TP
|
|
||||||
.B Creating and Mounting a Data Volume Container
|
|
||||||
.TP
|
|
||||||
Many applications require the sharing of persistent data across several containers. Docker allows you to create a Data Volume Container that other containers can mount from. For example, create a named container that contains directories /var/volume1 and /tmp/volume2. The image will need to contain these directories so a couple of RUN mkdir instructions might be required for you fedora-data image:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker run --name=data -v /var/volume1 -v /tmp/volume2 -i -t fedora-data true
|
|
||||||
.sp
|
|
||||||
docker run --volumes-from=data --name=fedora-container1 -i -t fedora bash
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.TP
|
|
||||||
Multiple --volumes-from parameters will bring together multiple data volumes from multiple containers. And it's possible to mount the volumes that came from the DATA container in yet another container via the fedora-container1 intermidiery container, allowing to abstract the actual data source from users of that data:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker run --volumes-from=fedora-container1 --name=fedora-container2 -i -t fedora bash
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.sp
|
|
||||||
.B Mounting External Volumes
|
|
||||||
.TP
|
|
||||||
To mount a host directory as a container volume, specify the absolute path to the directory and the absolute path for the container directory separated by a colon:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker run -v /var/db:/data1 -i -t fedora bash
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.TP
|
|
||||||
When using SELinux, be aware that the host has no knowledge of container SELinux policy. Therefore, in the above example, if SELinux policy is enforced, the /var/db directory is not writable to the container. A "Permission Denied" message will occur and an avc: message in the host's syslog.
|
|
||||||
.sp
|
|
||||||
.TP
|
|
||||||
To work around this, at time of writing this man page, the following command needs to be run in order for the proper SELinux policy type label to be attached to the host directory:
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
chcon -Rt svirt_sandbox_file_t /var/db
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.TP
|
|
||||||
Now, writing to the /data1 volume in the container will be allowed and the changes will also be reflected on the host in /var/db.
|
|
||||||
.sp
|
|
||||||
.SH HISTORY
|
|
||||||
March 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
.\" Process this file with
|
|
||||||
.\" nroff -man -Tascii docker-tag.1
|
|
||||||
.\"
|
|
||||||
.TH "DOCKER" "1" "APRIL 2014" "0.1" "Docker"
|
|
||||||
.SH NAME
|
|
||||||
docker-tag \- Tag an image in the repository
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B docker tag
|
|
||||||
[\fB-f\fR|\fB--force\fR[=\fIfalse\fR]
|
|
||||||
\fBIMAGE\fR [REGISTRYHOST/][USERNAME/]NAME[:TAG]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
This will tag an image in the repository.
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.TP
|
|
||||||
.B -f, --force=\fItrue\fR|\fIfalse\fR:
|
|
||||||
When set to true, force the tag name. The default is \fIfalse\fR.
|
|
||||||
.TP
|
|
||||||
.B REGISTRYHOST:
|
|
||||||
The hostname of the registry if required. This may also include the port separated by a ':'
|
|
||||||
.TP
|
|
||||||
.B USERNAME:
|
|
||||||
The username or other qualifying identifier for the image.
|
|
||||||
.TP
|
|
||||||
.B NAME:
|
|
||||||
The image name.
|
|
||||||
.TP
|
|
||||||
.B TAG:
|
|
||||||
The tag you are assigning to the image.
|
|
||||||
.SH EXAMPLES
|
|
||||||
.sp
|
|
||||||
.PP
|
|
||||||
.B Tagging an image
|
|
||||||
.TP
|
|
||||||
Here is an example where an image is tagged with the tag 'Version-1.0' :
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker tag 0e5574283393 fedora/httpd:Version-1.0
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.B Tagging an image for an internal repository
|
|
||||||
.TP
|
|
||||||
To push an image to an internal Registry and not the default docker.io based registry you must tag it with the registry hostname and port (if needed).
|
|
||||||
.sp
|
|
||||||
.RS
|
|
||||||
docker tag 0e5574283393 myregistryhost:5000/fedora/httpd:version1.0
|
|
||||||
.RE
|
|
||||||
.sp
|
|
||||||
.SH HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
.\" Process this file with
|
|
||||||
.\" nroff -man -Tascii docker.1
|
|
||||||
.\"
|
|
||||||
.TH "DOCKER" "1" "APRIL 2014" "0.1" "Docker"
|
|
||||||
.SH NAME
|
|
||||||
docker \- Docker image and container command line interface
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B docker [OPTIONS] [COMMAND] [arg...]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
\fBdocker\fR has two distinct functions. It is used for starting the Docker daemon and to run the CLI (i.e., to command the daemon to manage images, containers etc.) So \fBdocker\fR is both a server as deamon and a client to the daemon through the CLI.
|
|
||||||
.sp
|
|
||||||
To run the Docker deamon you do not specify any of the commands listed below but must specify the \fB-d\fR option. The other options listed below are for the daemon only.
|
|
||||||
.sp
|
|
||||||
The Docker CLI has over 30 commands. The commands are listed below and each has its own man page which explain usage and arguements.
|
|
||||||
.sp
|
|
||||||
To see the man page for a command run \fBman docker <command>\fR.
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.B \-D=false:
|
|
||||||
Enable debug mode
|
|
||||||
.TP
|
|
||||||
.B\-H=[unix:///var/run/docker.sock]: tcp://[host[:port]] to bind or unix://[/path/to/socket] to use.
|
|
||||||
When host=[0.0.0.0], port=[2375] or path
|
|
||||||
=[/var/run/docker.sock] is omitted, default values are used.
|
|
||||||
.TP
|
|
||||||
.B \-\-api-enable-cors=false
|
|
||||||
Enable CORS headers in the remote API
|
|
||||||
.TP
|
|
||||||
.B \-b=""
|
|
||||||
Attach containers to a pre\-existing network bridge; use 'none' to disable container networking
|
|
||||||
.TP
|
|
||||||
.B \-\-bip=""
|
|
||||||
Use the provided CIDR notation address for the dynamically created bridge (docker0); Mutually exclusive of \-b
|
|
||||||
.TP
|
|
||||||
.B \-d=false
|
|
||||||
Enable daemon mode
|
|
||||||
.TP
|
|
||||||
.B \-\-dns=""
|
|
||||||
Force Docker to use specific DNS servers
|
|
||||||
.TP
|
|
||||||
.B \-g="/var/lib/docker"
|
|
||||||
Path to use as the root of the Docker runtime
|
|
||||||
.TP
|
|
||||||
.B \-\-icc=true
|
|
||||||
Enable inter\-container communication
|
|
||||||
.TP
|
|
||||||
.B \-\-ip="0.0.0.0"
|
|
||||||
Default IP address to use when binding container ports
|
|
||||||
.TP
|
|
||||||
.B \-\-iptables=true
|
|
||||||
Disable Docker's addition of iptables rules
|
|
||||||
.TP
|
|
||||||
.B \-\-mtu=1500
|
|
||||||
Set the containers network mtu
|
|
||||||
.TP
|
|
||||||
.B \-p="/var/run/docker.pid"
|
|
||||||
Path to use for daemon PID file
|
|
||||||
.TP
|
|
||||||
.B \-r=true
|
|
||||||
Restart previously running containers
|
|
||||||
.TP
|
|
||||||
.B \-s=""
|
|
||||||
Force the Docker runtime to use a specific storage driver
|
|
||||||
.TP
|
|
||||||
.B \-v=false
|
|
||||||
Print version information and quit
|
|
||||||
.SH "COMMANDS"
|
|
||||||
.TP
|
|
||||||
.B attach
|
|
||||||
Attach to a running container
|
|
||||||
.TP
|
|
||||||
.B build
|
|
||||||
Build an image from a Dockerfile
|
|
||||||
.TP
|
|
||||||
.B commit
|
|
||||||
Create a new image from a container's changes
|
|
||||||
.TP
|
|
||||||
.B cp
|
|
||||||
Copy files/folders from the containers filesystem to the host at path
|
|
||||||
.TP
|
|
||||||
.B diff
|
|
||||||
Inspect changes on a container's filesystem
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B events
|
|
||||||
Get real time events from the server
|
|
||||||
.TP
|
|
||||||
.B export
|
|
||||||
Stream the contents of a container as a tar archive
|
|
||||||
.TP
|
|
||||||
.B history
|
|
||||||
Show the history of an image
|
|
||||||
.TP
|
|
||||||
.B images
|
|
||||||
List images
|
|
||||||
.TP
|
|
||||||
.B import
|
|
||||||
Create a new filesystem image from the contents of a tarball
|
|
||||||
.TP
|
|
||||||
.B info
|
|
||||||
Display system-wide information
|
|
||||||
.TP
|
|
||||||
.B insert
|
|
||||||
Insert a file in an image
|
|
||||||
.TP
|
|
||||||
.B inspect
|
|
||||||
Return low-level information on a container
|
|
||||||
.TP
|
|
||||||
.B kill
|
|
||||||
Kill a running container (which includes the wrapper process and everything inside it)
|
|
||||||
.TP
|
|
||||||
.B load
|
|
||||||
Load an image from a tar archive
|
|
||||||
.TP
|
|
||||||
.B login
|
|
||||||
Register or Login to a Docker registry server
|
|
||||||
.TP
|
|
||||||
.B logs
|
|
||||||
Fetch the logs of a container
|
|
||||||
.TP
|
|
||||||
.B port
|
|
||||||
Lookup the public-facing port which is NAT-ed to PRIVATE_PORT
|
|
||||||
.TP
|
|
||||||
.B ps
|
|
||||||
List containers
|
|
||||||
.TP
|
|
||||||
.B pull
|
|
||||||
Pull an image or a repository from a Docker registry server
|
|
||||||
.TP
|
|
||||||
.B push
|
|
||||||
Push an image or a repository to a Docker registry server
|
|
||||||
.TP
|
|
||||||
.B restart
|
|
||||||
Restart a running container
|
|
||||||
.TP
|
|
||||||
.B rm
|
|
||||||
Remove one or more containers
|
|
||||||
.TP
|
|
||||||
.B rmi
|
|
||||||
Remove one or more images
|
|
||||||
.TP
|
|
||||||
.B run
|
|
||||||
Run a command in a new container
|
|
||||||
.TP
|
|
||||||
.B save
|
|
||||||
Save an image to a tar archive
|
|
||||||
.TP
|
|
||||||
.B search
|
|
||||||
Search for an image in the Docker index
|
|
||||||
.TP
|
|
||||||
.B start
|
|
||||||
Start a stopped container
|
|
||||||
.TP
|
|
||||||
.B stop
|
|
||||||
Stop a running container
|
|
||||||
.TP
|
|
||||||
.B tag
|
|
||||||
Tag an image into a repository
|
|
||||||
.TP
|
|
||||||
.B top
|
|
||||||
Lookup the running processes of a container
|
|
||||||
.TP
|
|
||||||
.B version
|
|
||||||
Show the Docker version information
|
|
||||||
.TP
|
|
||||||
.B wait
|
|
||||||
Block until a container stops, then print its exit code
|
|
||||||
.SH EXAMPLES
|
|
||||||
.sp
|
|
||||||
For specific examples please see the man page for the specific Docker command.
|
|
||||||
.sp
|
|
||||||
.SH HISTORY
|
|
||||||
April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on dockier.io source material and internal work.
|
|
||||||
@@ -13,18 +13,18 @@ usage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tmp() {
|
tmp() {
|
||||||
TMP=$(mktemp -d /tmp/alpine-docker-XXXXXXXXXX)
|
TMP=$(mktemp -d ${TMPDIR:-/var/tmp}/alpine-docker-XXXXXXXXXX)
|
||||||
ROOTFS=$(mktemp -d /tmp/alpine-docker-rootfs-XXXXXXXXXX)
|
ROOTFS=$(mktemp -d ${TMPDIR:-/var/tmp}/alpine-docker-rootfs-XXXXXXXXXX)
|
||||||
trap "rm -rf $TMP $ROOTFS" EXIT TERM INT
|
trap "rm -rf $TMP $ROOTFS" EXIT TERM INT
|
||||||
}
|
}
|
||||||
|
|
||||||
apkv() {
|
apkv() {
|
||||||
curl -s $REPO/$ARCH/APKINDEX.tar.gz | tar -Oxz |
|
curl -sSL $REPO/$ARCH/APKINDEX.tar.gz | tar -Oxz |
|
||||||
grep '^P:apk-tools-static$' -A1 | tail -n1 | cut -d: -f2
|
grep '^P:apk-tools-static$' -A1 | tail -n1 | cut -d: -f2
|
||||||
}
|
}
|
||||||
|
|
||||||
getapk() {
|
getapk() {
|
||||||
curl -s $REPO/$ARCH/apk-tools-static-$(apkv).apk |
|
curl -sSL $REPO/$ARCH/apk-tools-static-$(apkv).apk |
|
||||||
tar -xz -C $TMP sbin/apk.static
|
tar -xz -C $TMP sbin/apk.static
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-17
@@ -5,34 +5,35 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
hash pacstrap &>/dev/null || {
|
hash pacstrap &>/dev/null || {
|
||||||
echo "Could not find pacstrap. Run pacman -S arch-install-scripts"
|
echo "Could not find pacstrap. Run pacman -S arch-install-scripts"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
hash expect &>/dev/null || {
|
hash expect &>/dev/null || {
|
||||||
echo "Could not find expect. Run pacman -S expect"
|
echo "Could not find expect. Run pacman -S expect"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
ROOTFS=$(mktemp -d /tmp/rootfs-archlinux-XXXXXXXXXX)
|
ROOTFS=$(mktemp -d ${TMPDIR:-/var/tmp}/rootfs-archlinux-XXXXXXXXXX)
|
||||||
chmod 755 $ROOTFS
|
chmod 755 $ROOTFS
|
||||||
|
|
||||||
# packages to ignore for space savings
|
# packages to ignore for space savings
|
||||||
PKGIGNORE=linux,jfsutils,lvm2,cryptsetup,groff,man-db,man-pages,mdadm,pciutils,pcmciautils,reiserfsprogs,s-nail,xfsprogs
|
PKGIGNORE=linux,jfsutils,lvm2,cryptsetup,groff,man-db,man-pages,mdadm,pciutils,pcmciautils,reiserfsprogs,s-nail,xfsprogs
|
||||||
|
|
||||||
expect <<EOF
|
expect <<EOF
|
||||||
set timeout 60
|
set send_slow {1 .1}
|
||||||
set send_slow {1 1}
|
proc send {ignore arg} {
|
||||||
spawn pacstrap -C ./mkimage-arch-pacman.conf -c -d -G -i $ROOTFS base haveged --ignore $PKGIGNORE
|
sleep .1
|
||||||
expect {
|
exp_send -s -- \$arg
|
||||||
"Install anyway?" { send n\r; exp_continue }
|
}
|
||||||
"(default=all)" { send \r; exp_continue }
|
set timeout 60
|
||||||
"Proceed with installation?" { send "\r"; exp_continue }
|
|
||||||
"skip the above package" {send "y\r"; exp_continue }
|
spawn pacstrap -C ./mkimage-arch-pacman.conf -c -d -G -i $ROOTFS base haveged --ignore $PKGIGNORE
|
||||||
"checking" { exp_continue }
|
expect {
|
||||||
"loading" { exp_continue }
|
-exact "anyway? \[Y/n\] " { send -- "n\r"; exp_continue }
|
||||||
"installing" { exp_continue }
|
-exact "(default=all): " { send -- "\r"; exp_continue }
|
||||||
}
|
-exact "installation? \[Y/n\]" { send -- "y\r"; exp_continue }
|
||||||
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
arch-chroot $ROOTFS /bin/sh -c "haveged -w 1024; pacman-key --init; pkill haveged; pacman -Rs --noconfirm haveged; pacman-key --populate archlinux"
|
arch-chroot $ROOTFS /bin/sh -c "haveged -w 1024; pacman-key --init; pkill haveged; pacman -Rs --noconfirm haveged; pacman-key --populate archlinux"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ BUSYBOX=$(which busybox)
|
|||||||
}
|
}
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
ROOTFS=/tmp/rootfs-busybox-$$-$RANDOM
|
ROOTFS=${TMPDIR:-/var/tmp}/rootfs-busybox-$$-$RANDOM
|
||||||
mkdir $ROOTFS
|
mkdir $ROOTFS
|
||||||
cd $ROOTFS
|
cd $ROOTFS
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ die () {
|
|||||||
|
|
||||||
ISO=${1}
|
ISO=${1}
|
||||||
|
|
||||||
ROOTFS=$(mktemp -d /tmp/rootfs-crux-XXXXXXXXXX)
|
ROOTFS=$(mktemp -d ${TMPDIR:-/var/tmp}/rootfs-crux-XXXXXXXXXX)
|
||||||
CRUX=$(mktemp -d /tmp/crux-XXXXXXXXXX)
|
CRUX=$(mktemp -d ${TMPDIR:-/var/tmp}/crux-XXXXXXXXXX)
|
||||||
TMP=$(mktemp -d /tmp/XXXXXXXXXX)
|
TMP=$(mktemp -d ${TMPDIR:-/var/tmp}/XXXXXXXXXX)
|
||||||
|
|
||||||
VERSION=$(basename --suffix=.iso $ISO | sed 's/[^0-9.]*\([0-9.]*\).*/\1/')
|
VERSION=$(basename --suffix=.iso $ISO | sed 's/[^0-9.]*\([0-9.]*\).*/\1/')
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ fi
|
|||||||
# will be filled in later, if [ -z "$skipDetection" ]
|
# will be filled in later, if [ -z "$skipDetection" ]
|
||||||
lsbDist=''
|
lsbDist=''
|
||||||
|
|
||||||
target="/tmp/docker-rootfs-debootstrap-$suite-$$-$RANDOM"
|
target="${TMPDIR:-/var/tmp}/docker-rootfs-debootstrap-$suite-$$-$RANDOM"
|
||||||
|
|
||||||
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
||||||
returnTo="$(pwd -P)"
|
returnTo="$(pwd -P)"
|
||||||
@@ -144,7 +144,7 @@ if [ -z "$strictDebootstrap" ]; then
|
|||||||
# initctl (for some pesky upstart scripts)
|
# initctl (for some pesky upstart scripts)
|
||||||
sudo chroot . dpkg-divert --local --rename --add /sbin/initctl
|
sudo chroot . dpkg-divert --local --rename --add /sbin/initctl
|
||||||
sudo ln -sf /bin/true sbin/initctl
|
sudo ln -sf /bin/true sbin/initctl
|
||||||
# see https://github.com/dotcloud/docker/issues/446#issuecomment-16953173
|
# see https://github.com/docker/docker/issues/446#issuecomment-16953173
|
||||||
|
|
||||||
# shrink the image, since apt makes us fat (wheezy: ~157.5MB vs ~120MB)
|
# shrink the image, since apt makes us fat (wheezy: ~157.5MB vs ~120MB)
|
||||||
sudo chroot . apt-get clean
|
sudo chroot . apt-get clean
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ if [ ! "$repo" ] || [ ! "$distro" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
target="/tmp/docker-rootfs-rinse-$distro-$$-$RANDOM"
|
target="${TMPDIR:-/var/tmp}/docker-rootfs-rinse-$distro-$$-$RANDOM"
|
||||||
|
|
||||||
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
|
||||||
returnTo="$(pwd -P)"
|
returnTo="$(pwd -P)"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ SOCAT=$(which socat)
|
|||||||
|
|
||||||
shopt -s extglob
|
shopt -s extglob
|
||||||
set -ex
|
set -ex
|
||||||
ROOTFS=`mktemp -d /tmp/rootfs-busybox.XXXXXXXXXX`
|
ROOTFS=`mktemp -d ${TMPDIR:-/var/tmp}/rootfs-busybox.XXXXXXXXXX`
|
||||||
trap "rm -rf $ROOTFS" INT QUIT TERM
|
trap "rm -rf $ROOTFS" INT QUIT TERM
|
||||||
cd $ROOTFS
|
cd $ROOTFS
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -6,9 +6,11 @@ mkimg="$(basename "$0")"
|
|||||||
usage() {
|
usage() {
|
||||||
echo >&2 "usage: $mkimg [-d dir] [-t tag] script [script-args]"
|
echo >&2 "usage: $mkimg [-d dir] [-t tag] script [script-args]"
|
||||||
echo >&2 " ie: $mkimg -t someuser/debian debootstrap --variant=minbase jessie"
|
echo >&2 " ie: $mkimg -t someuser/debian debootstrap --variant=minbase jessie"
|
||||||
echo >&2 " $mkimg -t someuser/ubuntu debootstrap --include=ubuntu-minimal trusty"
|
echo >&2 " $mkimg -t someuser/ubuntu debootstrap --include=ubuntu-minimal --components main,universe trusty"
|
||||||
echo >&2 " $mkimg -t someuser/busybox busybox-static"
|
echo >&2 " $mkimg -t someuser/busybox busybox-static"
|
||||||
echo >&2 " $mkimg -t someuser/centos:5 rinse --distribution centos-5"
|
echo >&2 " $mkimg -t someuser/centos:5 rinse --distribution centos-5"
|
||||||
|
echo >&2 " $mkimg -t someuser/mageia:4 mageia-urpmi --version=4"
|
||||||
|
echo >&2 " $mkimg -t someuser/mageia:4 mageia-urpmi --version=4 --mirror=http://somemirror/"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +50,7 @@ fi
|
|||||||
|
|
||||||
delDir=
|
delDir=
|
||||||
if [ -z "$dir" ]; then
|
if [ -z "$dir" ]; then
|
||||||
dir="$(mktemp -d ${TMPDIR:-/tmp}/docker-mkimage.XXXXXXXXXX)"
|
dir="$(mktemp -d ${TMPDIR:-/var/tmp}/docker-mkimage.XXXXXXXXXX)"
|
||||||
delDir=1
|
delDir=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ shift
|
|||||||
# docs
|
# docs
|
||||||
rm -rf usr/share/{man,doc,info,gnome/help}
|
rm -rf usr/share/{man,doc,info,gnome/help}
|
||||||
# cracklib
|
# cracklib
|
||||||
#rm -rf usr/share/cracklib
|
rm -rf usr/share/cracklib
|
||||||
# i18n
|
# i18n
|
||||||
rm -rf usr/share/i18n
|
rm -rf usr/share/i18n
|
||||||
# yum cache
|
# yum cache
|
||||||
|
|||||||
+88
-20
@@ -23,9 +23,14 @@ shift
|
|||||||
# now for some Docker-specific tweaks
|
# now for some Docker-specific tweaks
|
||||||
|
|
||||||
# prevent init scripts from running during install/update
|
# prevent init scripts from running during install/update
|
||||||
echo >&2 "+ cat > '$rootfsDir/usr/sbin/policy-rc.d'"
|
echo >&2 "+ echo exit 101 > '$rootfsDir/usr/sbin/policy-rc.d'"
|
||||||
cat > "$rootfsDir/usr/sbin/policy-rc.d" <<'EOF'
|
cat > "$rootfsDir/usr/sbin/policy-rc.d" <<'EOF'
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
# For most Docker users, "apt-get install" only happens during "docker build",
|
||||||
|
# where starting services doesn't work and often fails in humorous ways. This
|
||||||
|
# prevents those failures by stopping the services from attempting to start.
|
||||||
|
|
||||||
exit 101
|
exit 101
|
||||||
EOF
|
EOF
|
||||||
chmod +x "$rootfsDir/usr/sbin/policy-rc.d"
|
chmod +x "$rootfsDir/usr/sbin/policy-rc.d"
|
||||||
@@ -34,17 +39,25 @@ chmod +x "$rootfsDir/usr/sbin/policy-rc.d"
|
|||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
chroot "$rootfsDir" dpkg-divert --local --rename --add /sbin/initctl
|
chroot "$rootfsDir" dpkg-divert --local --rename --add /sbin/initctl
|
||||||
ln -sf /bin/true "$rootfsDir/sbin/initctl"
|
cp -a "$rootfsDir/usr/sbin/policy-rc.d" "$rootfsDir/sbin/initctl"
|
||||||
|
sed -i 's/^exit.*/exit 0/' "$rootfsDir/sbin/initctl"
|
||||||
)
|
)
|
||||||
|
|
||||||
# shrink the image, since apt makes us fat (wheezy: ~157.5MB vs ~120MB)
|
# shrink a little, since apt makes us cache-fat (wheezy: ~157.5MB vs ~120MB)
|
||||||
( set -x; chroot "$rootfsDir" apt-get clean )
|
( set -x; chroot "$rootfsDir" apt-get clean )
|
||||||
|
|
||||||
# Ubuntu 10.04 sucks... :)
|
# Ubuntu 10.04 sucks... :)
|
||||||
if strings "$rootfsDir/usr/bin/dpkg" | grep -q unsafe-io; then
|
if strings "$rootfsDir/usr/bin/dpkg" | grep -q unsafe-io; then
|
||||||
# force dpkg not to call sync() after package extraction (speeding up installs)
|
# force dpkg not to call sync() after package extraction (speeding up installs)
|
||||||
echo >&2 "+ echo force-unsafe-io > '$rootfsDir/etc/dpkg/dpkg.cfg.d/docker-apt-speedup'"
|
echo >&2 "+ echo force-unsafe-io > '$rootfsDir/etc/dpkg/dpkg.cfg.d/docker-apt-speedup'"
|
||||||
echo 'force-unsafe-io' > "$rootfsDir/etc/dpkg/dpkg.cfg.d/docker-apt-speedup"
|
cat > "$rootfsDir/etc/dpkg/dpkg.cfg.d/docker-apt-speedup" <<-'EOF'
|
||||||
|
# For most Docker users, package installs happen during "docker build", which
|
||||||
|
# doesn't survive power loss and gets restarted clean afterwards anyhow, so
|
||||||
|
# this minor tweak gives us a nice speedup (much nicer on spinning disks,
|
||||||
|
# obviously).
|
||||||
|
|
||||||
|
force-unsafe-io
|
||||||
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -d "$rootfsDir/etc/apt/apt.conf.d" ]; then
|
if [ -d "$rootfsDir/etc/apt/apt.conf.d" ]; then
|
||||||
@@ -52,16 +65,51 @@ if [ -d "$rootfsDir/etc/apt/apt.conf.d" ]; then
|
|||||||
aptGetClean='"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true";'
|
aptGetClean='"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true";'
|
||||||
echo >&2 "+ cat > '$rootfsDir/etc/apt/apt.conf.d/docker-clean'"
|
echo >&2 "+ cat > '$rootfsDir/etc/apt/apt.conf.d/docker-clean'"
|
||||||
cat > "$rootfsDir/etc/apt/apt.conf.d/docker-clean" <<-EOF
|
cat > "$rootfsDir/etc/apt/apt.conf.d/docker-clean" <<-EOF
|
||||||
|
# Since for most Docker users, package installs happen in "docker build" steps,
|
||||||
|
# they essentially become individual layers due to the way Docker handles
|
||||||
|
# layering, especially using CoW filesystems. What this means for us is that
|
||||||
|
# the caches that APT keeps end up just wasting space in those layers, making
|
||||||
|
# our layers unnecessarily large (especially since we'll normally never use
|
||||||
|
# these caches again and will instead just "docker build" again and make a brand
|
||||||
|
# new image).
|
||||||
|
|
||||||
|
# Ideally, these would just be invoking "apt-get clean", but in our testing,
|
||||||
|
# that ended up being cyclic and we got stuck on APT's lock, so we get this fun
|
||||||
|
# creation that's essentially just "apt-get clean".
|
||||||
DPkg::Post-Invoke { ${aptGetClean} };
|
DPkg::Post-Invoke { ${aptGetClean} };
|
||||||
APT::Update::Post-Invoke { ${aptGetClean} };
|
APT::Update::Post-Invoke { ${aptGetClean} };
|
||||||
|
|
||||||
Dir::Cache::pkgcache "";
|
Dir::Cache::pkgcache "";
|
||||||
Dir::Cache::srcpkgcache "";
|
Dir::Cache::srcpkgcache "";
|
||||||
|
|
||||||
|
# Note that we do realize this isn't the ideal way to do this, and are always
|
||||||
|
# open to better suggestions (https://github.com/docker/docker/issues).
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# remove apt-cache translations for fast "apt-get update"
|
# remove apt-cache translations for fast "apt-get update"
|
||||||
echo >&2 "+ cat > '$rootfsDir/etc/apt/apt.conf.d/docker-no-languages'"
|
echo >&2 "+ echo Acquire::Languages 'none' > '$rootfsDir/etc/apt/apt.conf.d/docker-no-languages'"
|
||||||
echo 'Acquire::Languages "none";' > "$rootfsDir/etc/apt/apt.conf.d/docker-no-languages"
|
cat > "$rootfsDir/etc/apt/apt.conf.d/docker-no-languages" <<-'EOF'
|
||||||
|
# In Docker, we don't often need the "Translations" files, so we're just wasting
|
||||||
|
# time and space by downloading them, and this inhibits that. For users that do
|
||||||
|
# need them, it's a simple matter to delete this file and "apt-get update". :)
|
||||||
|
|
||||||
|
Acquire::Languages "none";
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo >&2 "+ echo Acquire::GzipIndexes 'true' > '$rootfsDir/etc/apt/apt.conf.d/docker-gzip-indexes'"
|
||||||
|
cat > "$rootfsDir/etc/apt/apt.conf.d/docker-gzip-indexes" <<-'EOF'
|
||||||
|
# Since Docker users using "RUN apt-get update && apt-get install -y ..." in
|
||||||
|
# their Dockerfiles don't go delete the lists files afterwards, we want them to
|
||||||
|
# be as small as possible on-disk, so we explicitly request "gz" versions and
|
||||||
|
# tell Apt to keep them gzipped on-disk.
|
||||||
|
|
||||||
|
# For comparison, an "apt-get update" layer without this on a pristine
|
||||||
|
# "debian:wheezy" base image was "29.88 MB", where with this it was only
|
||||||
|
# "8.273 MB".
|
||||||
|
|
||||||
|
Acquire::GzipIndexes "true";
|
||||||
|
Acquire::CompressionTypes::Order:: "gz";
|
||||||
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$DONT_TOUCH_SOURCES_LIST" ]; then
|
if [ -z "$DONT_TOUCH_SOURCES_LIST" ]; then
|
||||||
@@ -76,39 +124,53 @@ if [ -z "$DONT_TOUCH_SOURCES_LIST" ]; then
|
|||||||
if [ -z "$lsbDist" -a -r "$rootfsDir/etc/debian_version" ]; then
|
if [ -z "$lsbDist" -a -r "$rootfsDir/etc/debian_version" ]; then
|
||||||
lsbDist='Debian'
|
lsbDist='Debian'
|
||||||
fi
|
fi
|
||||||
|
# normalize to lowercase for easier matching
|
||||||
|
lsbDist="$(echo "$lsbDist" | tr '[:upper:]' '[:lower:]')"
|
||||||
case "$lsbDist" in
|
case "$lsbDist" in
|
||||||
debian|Debian)
|
debian)
|
||||||
# updates and security!
|
# updates and security!
|
||||||
if [ "$suite" != 'sid' -a "$suite" != 'unstable' ]; then
|
if [ "$suite" != 'sid' -a "$suite" != 'unstable' ]; then
|
||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
sed -i "p; s/ $suite main$/ ${suite}-updates main/" "$rootfsDir/etc/apt/sources.list"
|
sed -i "
|
||||||
|
p;
|
||||||
|
s/ $suite / ${suite}-updates /
|
||||||
|
" "$rootfsDir/etc/apt/sources.list"
|
||||||
echo "deb http://security.debian.org $suite/updates main" >> "$rootfsDir/etc/apt/sources.list"
|
echo "deb http://security.debian.org $suite/updates main" >> "$rootfsDir/etc/apt/sources.list"
|
||||||
|
# LTS
|
||||||
|
if [ "$suite" = 'squeeze' -o "$suite" = 'oldstable' ]; then
|
||||||
|
head -1 "$rootfsDir/etc/apt/sources.list" \
|
||||||
|
| sed "s/ $suite / squeeze-lts /" \
|
||||||
|
>> "$rootfsDir/etc/apt/sources.list"
|
||||||
|
fi
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
ubuntu|Ubuntu)
|
ubuntu)
|
||||||
# add the universe, updates, and security repositories
|
# add the updates and security repositories
|
||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
sed -i "
|
sed -i "
|
||||||
s/ $suite main$/ $suite main universe/; p;
|
p;
|
||||||
s/ $suite main/ ${suite}-updates main/; p;
|
s/ $suite / ${suite}-updates /; p;
|
||||||
s/ $suite-updates main/ ${suite}-security main/
|
s/ $suite-updates / ${suite}-security /
|
||||||
" "$rootfsDir/etc/apt/sources.list"
|
" "$rootfsDir/etc/apt/sources.list"
|
||||||
)
|
)
|
||||||
;;
|
;;
|
||||||
tanglu|Tanglu)
|
tanglu)
|
||||||
# add the updates repository
|
# add the updates repository
|
||||||
if [ "$suite" != 'devel' ]; then
|
if [ "$suite" != 'devel' ]; then
|
||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
sed -i "p; s/ $suite main$/ ${suite}-updates main/" "$rootfsDir/etc/apt/sources.list"
|
sed -i "
|
||||||
|
p;
|
||||||
|
s/ $suite / ${suite}-updates /
|
||||||
|
" "$rootfsDir/etc/apt/sources.list"
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
steamos|SteamOS)
|
steamos)
|
||||||
# add contrib and non-free
|
# add contrib and non-free if "main" is the only component
|
||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
sed -i "s/ $suite main$/ $suite main contrib non-free/" "$rootfsDir/etc/apt/sources.list"
|
sed -i "s/ $suite main$/ $suite main contrib non-free/" "$rootfsDir/etc/apt/sources.list"
|
||||||
@@ -117,9 +179,15 @@ if [ -z "$DONT_TOUCH_SOURCES_LIST" ]; then
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# make sure we're fully up-to-date, too
|
|
||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
chroot "$rootfsDir" apt-get update
|
|
||||||
chroot "$rootfsDir" apt-get dist-upgrade -y
|
# make sure we're fully up-to-date
|
||||||
|
chroot "$rootfsDir" bash -c 'apt-get update && apt-get dist-upgrade -y'
|
||||||
|
|
||||||
|
# delete all the apt list files since they're big and get stale quickly
|
||||||
|
rm -rf "$rootfsDir/var/lib/apt/lists"/*
|
||||||
|
# this forces "apt-get update" in dependent images, which is also good
|
||||||
|
|
||||||
|
mkdir "$rootfsDir/var/lib/apt/lists/partial" # Lucid... "E: Lists directory /var/lib/apt/lists/partial is missing."
|
||||||
)
|
)
|
||||||
|
|||||||
Executable
+61
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Needs to be run from Mageia 4 or greater for kernel support for docker.
|
||||||
|
#
|
||||||
|
# Mageia 4 does not have docker available in official repos, so please
|
||||||
|
# install and run the docker binary manually.
|
||||||
|
#
|
||||||
|
# Tested working versions are for Mageia 2 onwards (inc. cauldron).
|
||||||
|
#
|
||||||
|
set -e
|
||||||
|
|
||||||
|
rootfsDir="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
optTemp=$(getopt --options '+v:,m:' --longoptions 'version:,mirror:' --name mageia-urpmi -- "$@")
|
||||||
|
eval set -- "$optTemp"
|
||||||
|
unset optTemp
|
||||||
|
|
||||||
|
installversion=
|
||||||
|
mirror=
|
||||||
|
while true; do
|
||||||
|
case "$1" in
|
||||||
|
-v|--version) installversion="$2" ; shift 2 ;;
|
||||||
|
-m|--mirror) mirror="$2" ; shift 2 ;;
|
||||||
|
--) shift ; break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z $installversion ]; then
|
||||||
|
# Attempt to match host version
|
||||||
|
if [ -r /etc/mageia-release ]; then
|
||||||
|
installversion="$(sed 's/^[^0-9\]*\([0-9.]\+\).*$/\1/' /etc/mageia-release)"
|
||||||
|
else
|
||||||
|
echo "Error: no version supplied and unable to detect host mageia version"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z $mirror ]; then
|
||||||
|
# No mirror provided, default to mirrorlist
|
||||||
|
mirror="--mirrorlist https://mirrors.mageia.org/api/mageia.$installversion.x86_64.list"
|
||||||
|
fi
|
||||||
|
|
||||||
|
(
|
||||||
|
set -x
|
||||||
|
urpmi.addmedia --distrib \
|
||||||
|
$mirror \
|
||||||
|
--urpmi-root "$rootfsDir"
|
||||||
|
urpmi basesystem-minimal urpmi \
|
||||||
|
--auto \
|
||||||
|
--no-suggests \
|
||||||
|
--urpmi-root "$rootfsDir" \
|
||||||
|
--root "$rootfsDir"
|
||||||
|
)
|
||||||
|
|
||||||
|
"$(dirname "$BASH_SOURCE")/.febootstrap-minimize" "$rootfsDir"
|
||||||
|
|
||||||
|
if [ -d "$rootfsDir/etc/sysconfig" ]; then
|
||||||
|
# allow networking init scripts inside the container to work without extra steps
|
||||||
|
echo 'NETWORKING=yes' > "$rootfsDir/etc/sysconfig/network"
|
||||||
|
fi
|
||||||
Executable
+64
@@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
dir="$1"
|
||||||
|
|
||||||
|
if [ -z "$dir" ]; then
|
||||||
|
{
|
||||||
|
echo 'This script is for destroying old /var/lib/docker directories more safely than'
|
||||||
|
echo ' "rm -rf", which can cause data loss or other serious issues.'
|
||||||
|
echo
|
||||||
|
echo "usage: $0 directory"
|
||||||
|
echo " ie: $0 /var/lib/docker"
|
||||||
|
} >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(id -u)" != 0 ]; then
|
||||||
|
echo >&2 "error: $0 must be run as root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$dir" ]; then
|
||||||
|
echo >&2 "error: $dir is not a directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
dir="$(readlink -f "$dir")"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Nuking $dir ..."
|
||||||
|
echo ' (if this is wrong, press Ctrl+C NOW!)'
|
||||||
|
echo
|
||||||
|
|
||||||
|
( set -x; sleep 10 )
|
||||||
|
echo
|
||||||
|
|
||||||
|
dir_in_dir() {
|
||||||
|
inner="$1"
|
||||||
|
outer="$2"
|
||||||
|
[ "${inner#$outer}" != "$inner" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# let's start by unmounting any submounts in $dir
|
||||||
|
# (like -v /home:... for example - DON'T DELETE MY HOME DIRECTORY BRU!)
|
||||||
|
for mount in $(awk '{ print $5 }' /proc/self/mountinfo); do
|
||||||
|
mount="$(readlink -f "$mount" || true)"
|
||||||
|
if dir_in_dir "$mount" "$dir"; then
|
||||||
|
( set -x; umount -f "$mount" )
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# now, let's go destroy individual btrfs subvolumes, if any exist
|
||||||
|
if command -v btrfs &> /dev/null; then
|
||||||
|
root="$(df "$dir" | awk 'NR>1 { print $NF }')"
|
||||||
|
for subvol in $(btrfs subvolume list -o "$root" 2>/dev/null | awk -F' path ' '{ print $2 }'); do
|
||||||
|
subvolDir="$root/$subvol"
|
||||||
|
if dir_in_dir "$subvolDir" "$dir"; then
|
||||||
|
( set -x; btrfs subvolume delete "$subvolDir" )
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# finally, DESTROY ALL THINGS
|
||||||
|
( set -x; rm -rf "$dir" )
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Auto sign all commits to allow them to be used by the Docker project.
|
|
||||||
# see https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md#sign-your-work
|
|
||||||
#
|
|
||||||
GH_USER=$(git config --get github.user)
|
|
||||||
SOB=$(git var GIT_AUTHOR_IDENT | sed -n "s/^\(.*>\).*$/Docker-DCO-1.1-Signed-off-by: \1 \(github: $GH_USER\)/p")
|
|
||||||
grep -qs "^$SOB" "$1" || {
|
|
||||||
echo
|
|
||||||
echo "$SOB"
|
|
||||||
} >> "$1"
|
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
<key>match</key>
|
<key>match</key>
|
||||||
<string>^\s*(ONBUILD\s+)?(FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|USER|WORKDIR)\s</string>
|
<string>^\s*(ONBUILD\s+)?(FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|USER|WORKDIR|COPY)\s</string>
|
||||||
<key>captures</key>
|
<key>captures</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>0</key>
|
<key>0</key>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ let b:current_syntax = "dockerfile"
|
|||||||
|
|
||||||
syntax case ignore
|
syntax case ignore
|
||||||
|
|
||||||
syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|VOLUME|WORKDIR)\s/
|
syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|VOLUME|WORKDIR|COPY)\s/
|
||||||
highlight link dockerfileKeyword Keyword
|
highlight link dockerfileKeyword Keyword
|
||||||
|
|
||||||
syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/
|
syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
Solomon Hykes <solomon@docker.com> (@shykes)
|
||||||
|
Victor Vieux <vieux@docker.com> (@vieux)
|
||||||
|
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
||||||
|
Cristian Staretu <cristian.staretu@gmail.com> (@unclejack)
|
||||||
|
Tibor Vass <teabee89@gmail.com> (@tiborvass)
|
||||||
|
volumes.go: Brian Goff <cpuguy83@gmail.com> (@cpuguy83)
|
||||||
+129
-16
@@ -1,11 +1,124 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/docker/docker/engine"
|
||||||
|
"github.com/docker/docker/pkg/jsonlog"
|
||||||
|
"github.com/docker/docker/pkg/log"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (daemon *Daemon) ContainerAttach(job *engine.Job) engine.Status {
|
||||||
|
if len(job.Args) != 1 {
|
||||||
|
return job.Errorf("Usage: %s CONTAINER\n", job.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
name = job.Args[0]
|
||||||
|
logs = job.GetenvBool("logs")
|
||||||
|
stream = job.GetenvBool("stream")
|
||||||
|
stdin = job.GetenvBool("stdin")
|
||||||
|
stdout = job.GetenvBool("stdout")
|
||||||
|
stderr = job.GetenvBool("stderr")
|
||||||
|
)
|
||||||
|
|
||||||
|
container := daemon.Get(name)
|
||||||
|
if container == nil {
|
||||||
|
return job.Errorf("No such container: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
//logs
|
||||||
|
if logs {
|
||||||
|
cLog, err := container.ReadLog("json")
|
||||||
|
if err != nil && os.IsNotExist(err) {
|
||||||
|
// Legacy logs
|
||||||
|
log.Debugf("Old logs format")
|
||||||
|
if stdout {
|
||||||
|
cLog, err := container.ReadLog("stdout")
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error reading logs (stdout): %s", err)
|
||||||
|
} else if _, err := io.Copy(job.Stdout, cLog); err != nil {
|
||||||
|
log.Errorf("Error streaming logs (stdout): %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if stderr {
|
||||||
|
cLog, err := container.ReadLog("stderr")
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error reading logs (stderr): %s", err)
|
||||||
|
} else if _, err := io.Copy(job.Stderr, cLog); err != nil {
|
||||||
|
log.Errorf("Error streaming logs (stderr): %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
log.Errorf("Error reading logs (json): %s", err)
|
||||||
|
} else {
|
||||||
|
dec := json.NewDecoder(cLog)
|
||||||
|
for {
|
||||||
|
l := &jsonlog.JSONLog{}
|
||||||
|
|
||||||
|
if err := dec.Decode(l); err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
log.Errorf("Error streaming logs: %s", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if l.Stream == "stdout" && stdout {
|
||||||
|
fmt.Fprintf(job.Stdout, "%s", l.Log)
|
||||||
|
}
|
||||||
|
if l.Stream == "stderr" && stderr {
|
||||||
|
fmt.Fprintf(job.Stderr, "%s", l.Log)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//stream
|
||||||
|
if stream {
|
||||||
|
var (
|
||||||
|
cStdin io.ReadCloser
|
||||||
|
cStdout, cStderr io.Writer
|
||||||
|
cStdinCloser io.Closer
|
||||||
|
)
|
||||||
|
|
||||||
|
if stdin {
|
||||||
|
r, w := io.Pipe()
|
||||||
|
go func() {
|
||||||
|
defer w.Close()
|
||||||
|
defer log.Debugf("Closing buffered stdin pipe")
|
||||||
|
io.Copy(w, job.Stdin)
|
||||||
|
}()
|
||||||
|
cStdin = r
|
||||||
|
cStdinCloser = job.Stdin
|
||||||
|
}
|
||||||
|
if stdout {
|
||||||
|
cStdout = job.Stdout
|
||||||
|
}
|
||||||
|
if stderr {
|
||||||
|
cStderr = job.Stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
<-daemon.Attach(container, cStdin, cStdinCloser, cStdout, cStderr)
|
||||||
|
|
||||||
|
// If we are in stdinonce mode, wait for the process to end
|
||||||
|
// otherwise, simply return
|
||||||
|
if container.Config.StdinOnce && !container.Config.Tty {
|
||||||
|
container.State.WaitStop(-1 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: this should be private, and every outside subsystem
|
||||||
|
// should go through the "container_attach" job. But that would require
|
||||||
|
// that job to be properly documented, as well as the relationship betweem
|
||||||
|
// Attach and ContainerAttach.
|
||||||
|
//
|
||||||
|
// This method is in use by builder/builder.go.
|
||||||
func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
|
func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
|
||||||
var (
|
var (
|
||||||
cStdout, cStderr io.ReadCloser
|
cStdout, cStderr io.ReadCloser
|
||||||
@@ -19,8 +132,8 @@ func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinClo
|
|||||||
errors <- err
|
errors <- err
|
||||||
} else {
|
} else {
|
||||||
go func() {
|
go func() {
|
||||||
utils.Debugf("attach: stdin: begin")
|
log.Debugf("attach: stdin: begin")
|
||||||
defer utils.Debugf("attach: stdin: end")
|
defer log.Debugf("attach: stdin: end")
|
||||||
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
|
// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
|
||||||
if container.Config.StdinOnce && !container.Config.Tty {
|
if container.Config.StdinOnce && !container.Config.Tty {
|
||||||
defer cStdin.Close()
|
defer cStdin.Close()
|
||||||
@@ -43,7 +156,7 @@ func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinClo
|
|||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("attach: stdin: %s", err)
|
log.Errorf("attach: stdin: %s", err)
|
||||||
}
|
}
|
||||||
errors <- err
|
errors <- err
|
||||||
}()
|
}()
|
||||||
@@ -56,8 +169,8 @@ func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinClo
|
|||||||
} else {
|
} else {
|
||||||
cStdout = p
|
cStdout = p
|
||||||
go func() {
|
go func() {
|
||||||
utils.Debugf("attach: stdout: begin")
|
log.Debugf("attach: stdout: begin")
|
||||||
defer utils.Debugf("attach: stdout: end")
|
defer log.Debugf("attach: stdout: end")
|
||||||
// If we are in StdinOnce mode, then close stdin
|
// If we are in StdinOnce mode, then close stdin
|
||||||
if container.Config.StdinOnce && stdin != nil {
|
if container.Config.StdinOnce && stdin != nil {
|
||||||
defer stdin.Close()
|
defer stdin.Close()
|
||||||
@@ -70,7 +183,7 @@ func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinClo
|
|||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("attach: stdout: %s", err)
|
log.Errorf("attach: stdout: %s", err)
|
||||||
}
|
}
|
||||||
errors <- err
|
errors <- err
|
||||||
}()
|
}()
|
||||||
@@ -81,7 +194,7 @@ func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinClo
|
|||||||
defer stdinCloser.Close()
|
defer stdinCloser.Close()
|
||||||
}
|
}
|
||||||
if cStdout, err := container.StdoutPipe(); err != nil {
|
if cStdout, err := container.StdoutPipe(); err != nil {
|
||||||
utils.Errorf("attach: stdout pipe: %s", err)
|
log.Errorf("attach: stdout pipe: %s", err)
|
||||||
} else {
|
} else {
|
||||||
io.Copy(&utils.NopWriter{}, cStdout)
|
io.Copy(&utils.NopWriter{}, cStdout)
|
||||||
}
|
}
|
||||||
@@ -94,8 +207,8 @@ func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinClo
|
|||||||
} else {
|
} else {
|
||||||
cStderr = p
|
cStderr = p
|
||||||
go func() {
|
go func() {
|
||||||
utils.Debugf("attach: stderr: begin")
|
log.Debugf("attach: stderr: begin")
|
||||||
defer utils.Debugf("attach: stderr: end")
|
defer log.Debugf("attach: stderr: end")
|
||||||
// If we are in StdinOnce mode, then close stdin
|
// If we are in StdinOnce mode, then close stdin
|
||||||
if container.Config.StdinOnce && stdin != nil {
|
if container.Config.StdinOnce && stdin != nil {
|
||||||
defer stdin.Close()
|
defer stdin.Close()
|
||||||
@@ -108,7 +221,7 @@ func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinClo
|
|||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("attach: stderr: %s", err)
|
log.Errorf("attach: stderr: %s", err)
|
||||||
}
|
}
|
||||||
errors <- err
|
errors <- err
|
||||||
}()
|
}()
|
||||||
@@ -120,7 +233,7 @@ func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinClo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cStderr, err := container.StderrPipe(); err != nil {
|
if cStderr, err := container.StderrPipe(); err != nil {
|
||||||
utils.Errorf("attach: stdout pipe: %s", err)
|
log.Errorf("attach: stdout pipe: %s", err)
|
||||||
} else {
|
} else {
|
||||||
io.Copy(&utils.NopWriter{}, cStderr)
|
io.Copy(&utils.NopWriter{}, cStderr)
|
||||||
}
|
}
|
||||||
@@ -140,14 +253,14 @@ func (daemon *Daemon) Attach(container *Container, stdin io.ReadCloser, stdinClo
|
|||||||
// FIXME: how to clean up the stdin goroutine without the unwanted side effect
|
// FIXME: how to clean up the stdin goroutine without the unwanted side effect
|
||||||
// of closing the passed stdin? Add an intermediary io.Pipe?
|
// of closing the passed stdin? Add an intermediary io.Pipe?
|
||||||
for i := 0; i < nJobs; i += 1 {
|
for i := 0; i < nJobs; i += 1 {
|
||||||
utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
|
log.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
|
||||||
if err := <-errors; err != nil {
|
if err := <-errors; err != nil {
|
||||||
utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
|
log.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
utils.Debugf("attach: job %d completed successfully", i+1)
|
log.Debugf("attach: job %d completed successfully", i+1)
|
||||||
}
|
}
|
||||||
utils.Debugf("attach: all jobs completed successfully")
|
log.Debugf("attach: all jobs completed successfully")
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package server
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -17,17 +18,101 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/archive"
|
"github.com/docker/docker/archive"
|
||||||
"github.com/dotcloud/docker/daemon"
|
"github.com/docker/docker/engine"
|
||||||
"github.com/dotcloud/docker/nat"
|
"github.com/docker/docker/nat"
|
||||||
"github.com/dotcloud/docker/pkg/symlink"
|
"github.com/docker/docker/pkg/log"
|
||||||
"github.com/dotcloud/docker/pkg/system"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/dotcloud/docker/registry"
|
"github.com/docker/docker/pkg/symlink"
|
||||||
"github.com/dotcloud/docker/runconfig"
|
"github.com/docker/docker/pkg/system"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/docker/docker/pkg/tarsum"
|
||||||
|
"github.com/docker/docker/registry"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (daemon *Daemon) CmdBuild(job *engine.Job) engine.Status {
|
||||||
|
if len(job.Args) != 0 {
|
||||||
|
return job.Errorf("Usage: %s\n", job.Name)
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
remoteURL = job.Getenv("remote")
|
||||||
|
repoName = job.Getenv("t")
|
||||||
|
suppressOutput = job.GetenvBool("q")
|
||||||
|
noCache = job.GetenvBool("nocache")
|
||||||
|
rm = job.GetenvBool("rm")
|
||||||
|
forceRm = job.GetenvBool("forcerm")
|
||||||
|
authConfig = ®istry.AuthConfig{}
|
||||||
|
configFile = ®istry.ConfigFile{}
|
||||||
|
tag string
|
||||||
|
context io.ReadCloser
|
||||||
|
)
|
||||||
|
job.GetenvJson("authConfig", authConfig)
|
||||||
|
job.GetenvJson("configFile", configFile)
|
||||||
|
repoName, tag = parsers.ParseRepositoryTag(repoName)
|
||||||
|
|
||||||
|
if remoteURL == "" {
|
||||||
|
context = ioutil.NopCloser(job.Stdin)
|
||||||
|
} else if utils.IsGIT(remoteURL) {
|
||||||
|
if !strings.HasPrefix(remoteURL, "git://") {
|
||||||
|
remoteURL = "https://" + remoteURL
|
||||||
|
}
|
||||||
|
root, err := ioutil.TempDir("", "docker-build-git")
|
||||||
|
if err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(root)
|
||||||
|
|
||||||
|
if output, err := exec.Command("git", "clone", "--recursive", remoteURL, root).CombinedOutput(); err != nil {
|
||||||
|
return job.Errorf("Error trying to use git: %s (%s)", err, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := archive.Tar(root, archive.Uncompressed)
|
||||||
|
if err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
context = c
|
||||||
|
} else if utils.IsURL(remoteURL) {
|
||||||
|
f, err := utils.Download(remoteURL)
|
||||||
|
if err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
defer f.Body.Close()
|
||||||
|
dockerFile, err := ioutil.ReadAll(f.Body)
|
||||||
|
if err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
c, err := archive.Generate("Dockerfile", string(dockerFile))
|
||||||
|
if err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
context = c
|
||||||
|
}
|
||||||
|
defer context.Close()
|
||||||
|
|
||||||
|
sf := utils.NewStreamFormatter(job.GetenvBool("json"))
|
||||||
|
b := NewBuildFile(daemon, daemon.eng,
|
||||||
|
&utils.StdoutFormater{
|
||||||
|
Writer: job.Stdout,
|
||||||
|
StreamFormatter: sf,
|
||||||
|
},
|
||||||
|
&utils.StderrFormater{
|
||||||
|
Writer: job.Stdout,
|
||||||
|
StreamFormatter: sf,
|
||||||
|
},
|
||||||
|
!suppressOutput, !noCache, rm, forceRm, job.Stdout, sf, authConfig, configFile)
|
||||||
|
id, err := b.Build(context)
|
||||||
|
if err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
if repoName != "" {
|
||||||
|
daemon.Repositories().Set(repoName, tag, id, false)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrDockerfileEmpty = errors.New("Dockerfile cannot be empty")
|
ErrDockerfileEmpty = errors.New("Dockerfile cannot be empty")
|
||||||
)
|
)
|
||||||
@@ -39,15 +124,15 @@ type BuildFile interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type buildFile struct {
|
type buildFile struct {
|
||||||
daemon *daemon.Daemon
|
daemon *Daemon
|
||||||
srv *Server
|
eng *engine.Engine
|
||||||
|
|
||||||
image string
|
image string
|
||||||
maintainer string
|
maintainer string
|
||||||
config *runconfig.Config
|
config *runconfig.Config
|
||||||
|
|
||||||
contextPath string
|
contextPath string
|
||||||
context *utils.TarSum
|
context *tarsum.TarSum
|
||||||
|
|
||||||
verbose bool
|
verbose bool
|
||||||
utilizeCache bool
|
utilizeCache bool
|
||||||
@@ -66,6 +151,9 @@ type buildFile struct {
|
|||||||
// Deprecated, original writer used for ImagePull. To be removed.
|
// Deprecated, original writer used for ImagePull. To be removed.
|
||||||
outOld io.Writer
|
outOld io.Writer
|
||||||
sf *utils.StreamFormatter
|
sf *utils.StreamFormatter
|
||||||
|
|
||||||
|
// cmdSet indicates is CMD was set in current Dockerfile
|
||||||
|
cmdSet bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *buildFile) clearTmp(containers map[string]struct{}) {
|
func (b *buildFile) clearTmp(containers map[string]struct{}) {
|
||||||
@@ -84,7 +172,7 @@ func (b *buildFile) CmdFrom(name string) error {
|
|||||||
image, err := b.daemon.Repositories().LookupImage(name)
|
image, err := b.daemon.Repositories().LookupImage(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if b.daemon.Graph().IsNotExist(err) {
|
if b.daemon.Graph().IsNotExist(err) {
|
||||||
remote, tag := utils.ParseRepositoryTag(name)
|
remote, tag := parsers.ParseRepositoryTag(name)
|
||||||
pullRegistryAuth := b.authConfig
|
pullRegistryAuth := b.authConfig
|
||||||
if len(b.configFile.Configs) > 0 {
|
if len(b.configFile.Configs) > 0 {
|
||||||
// The request came with a full auth config file, we prefer to use that
|
// The request came with a full auth config file, we prefer to use that
|
||||||
@@ -95,7 +183,7 @@ func (b *buildFile) CmdFrom(name string) error {
|
|||||||
resolvedAuth := b.configFile.ResolveAuthConfig(endpoint)
|
resolvedAuth := b.configFile.ResolveAuthConfig(endpoint)
|
||||||
pullRegistryAuth = &resolvedAuth
|
pullRegistryAuth = &resolvedAuth
|
||||||
}
|
}
|
||||||
job := b.srv.Eng.Job("pull", remote, tag)
|
job := b.eng.Job("pull", remote, tag)
|
||||||
job.SetenvBool("json", b.sf.Json())
|
job.SetenvBool("json", b.sf.Json())
|
||||||
job.SetenvBool("parallel", true)
|
job.SetenvBool("parallel", true)
|
||||||
job.SetenvJson("authConfig", pullRegistryAuth)
|
job.SetenvJson("authConfig", pullRegistryAuth)
|
||||||
@@ -117,13 +205,18 @@ func (b *buildFile) CmdFrom(name string) error {
|
|||||||
b.config = image.Config
|
b.config = image.Config
|
||||||
}
|
}
|
||||||
if b.config.Env == nil || len(b.config.Env) == 0 {
|
if b.config.Env == nil || len(b.config.Env) == 0 {
|
||||||
b.config.Env = append(b.config.Env, "HOME=/", "PATH="+daemon.DefaultPathEnv)
|
b.config.Env = append(b.config.Env, "PATH="+DefaultPathEnv)
|
||||||
}
|
}
|
||||||
// Process ONBUILD triggers if they exist
|
// Process ONBUILD triggers if they exist
|
||||||
if nTriggers := len(b.config.OnBuild); nTriggers != 0 {
|
if nTriggers := len(b.config.OnBuild); nTriggers != 0 {
|
||||||
fmt.Fprintf(b.errStream, "# Executing %d build triggers\n", nTriggers)
|
fmt.Fprintf(b.errStream, "# Executing %d build triggers\n", nTriggers)
|
||||||
}
|
}
|
||||||
for n, step := range b.config.OnBuild {
|
|
||||||
|
// Copy the ONBUILD triggers, and remove them from the config, since the config will be commited.
|
||||||
|
onBuildTriggers := b.config.OnBuild
|
||||||
|
b.config.OnBuild = []string{}
|
||||||
|
|
||||||
|
for n, step := range onBuildTriggers {
|
||||||
splitStep := strings.Split(step, " ")
|
splitStep := strings.Split(step, " ")
|
||||||
stepInstruction := strings.ToUpper(strings.Trim(splitStep[0], " "))
|
stepInstruction := strings.ToUpper(strings.Trim(splitStep[0], " "))
|
||||||
switch stepInstruction {
|
switch stepInstruction {
|
||||||
@@ -136,7 +229,6 @@ func (b *buildFile) CmdFrom(name string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.config.OnBuild = []string{}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,20 +254,20 @@ func (b *buildFile) CmdMaintainer(name string) error {
|
|||||||
|
|
||||||
// probeCache checks to see if image-caching is enabled (`b.utilizeCache`)
|
// probeCache checks to see if image-caching is enabled (`b.utilizeCache`)
|
||||||
// and if so attempts to look up the current `b.image` and `b.config` pair
|
// and if so attempts to look up the current `b.image` and `b.config` pair
|
||||||
// in the current server `b.srv`. If an image is found, probeCache returns
|
// in the current server `b.daemon`. If an image is found, probeCache returns
|
||||||
// `(true, nil)`. If no image is found, it returns `(false, nil)`. If there
|
// `(true, nil)`. If no image is found, it returns `(false, nil)`. If there
|
||||||
// is any error, it returns `(false, err)`.
|
// is any error, it returns `(false, err)`.
|
||||||
func (b *buildFile) probeCache() (bool, error) {
|
func (b *buildFile) probeCache() (bool, error) {
|
||||||
if b.utilizeCache {
|
if b.utilizeCache {
|
||||||
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
|
if cache, err := b.daemon.ImageGetCached(b.image, b.config); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
} else if cache != nil {
|
} else if cache != nil {
|
||||||
fmt.Fprintf(b.outStream, " ---> Using cache\n")
|
fmt.Fprintf(b.outStream, " ---> Using cache\n")
|
||||||
utils.Debugf("[BUILDER] Use cached version")
|
log.Debugf("[BUILDER] Use cached version")
|
||||||
b.image = cache.ID
|
b.image = cache.ID
|
||||||
return true, nil
|
return true, nil
|
||||||
} else {
|
} else {
|
||||||
utils.Debugf("[BUILDER] Cache miss")
|
log.Debugf("[BUILDER] Cache miss")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
@@ -191,12 +283,13 @@ func (b *buildFile) CmdRun(args string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd := b.config.Cmd
|
cmd := b.config.Cmd
|
||||||
b.config.Cmd = nil
|
// set Cmd manually, this is special case only for Dockerfiles
|
||||||
|
b.config.Cmd = config.Cmd
|
||||||
runconfig.Merge(b.config, config)
|
runconfig.Merge(b.config, config)
|
||||||
|
|
||||||
defer func(cmd []string) { b.config.Cmd = cmd }(cmd)
|
defer func(cmd []string) { b.config.Cmd = cmd }(cmd)
|
||||||
|
|
||||||
utils.Debugf("Command to be executed: %v", b.config.Cmd)
|
log.Debugf("Command to be executed: %v", b.config.Cmd)
|
||||||
|
|
||||||
hit, err := b.probeCache()
|
hit, err := b.probeCache()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -286,7 +379,7 @@ func (b *buildFile) CmdEnv(args string) error {
|
|||||||
func (b *buildFile) buildCmdFromJson(args string) []string {
|
func (b *buildFile) buildCmdFromJson(args string) []string {
|
||||||
var cmd []string
|
var cmd []string
|
||||||
if err := json.Unmarshal([]byte(args), &cmd); err != nil {
|
if err := json.Unmarshal([]byte(args), &cmd); err != nil {
|
||||||
utils.Debugf("Error unmarshalling: %s, setting to /bin/sh -c", err)
|
log.Debugf("Error unmarshalling: %s, setting to /bin/sh -c", err)
|
||||||
cmd = []string{"/bin/sh", "-c", args}
|
cmd = []string{"/bin/sh", "-c", args}
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
@@ -298,12 +391,17 @@ func (b *buildFile) CmdCmd(args string) error {
|
|||||||
if err := b.commit("", b.config.Cmd, fmt.Sprintf("CMD %v", cmd)); err != nil {
|
if err := b.commit("", b.config.Cmd, fmt.Sprintf("CMD %v", cmd)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
b.cmdSet = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *buildFile) CmdEntrypoint(args string) error {
|
func (b *buildFile) CmdEntrypoint(args string) error {
|
||||||
entrypoint := b.buildCmdFromJson(args)
|
entrypoint := b.buildCmdFromJson(args)
|
||||||
b.config.Entrypoint = entrypoint
|
b.config.Entrypoint = entrypoint
|
||||||
|
// if there is no cmd in current Dockerfile - cleanup cmd
|
||||||
|
if !b.cmdSet {
|
||||||
|
b.config.Cmd = nil
|
||||||
|
}
|
||||||
if err := b.commit("", b.config.Cmd, fmt.Sprintf("ENTRYPOINT %v", entrypoint)); err != nil {
|
if err := b.commit("", b.config.Cmd, fmt.Sprintf("ENTRYPOINT %v", entrypoint)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -399,7 +497,7 @@ func (b *buildFile) checkPathForAddition(orig string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *buildFile) addContext(container *daemon.Container, orig, dest string, decompress bool) error {
|
func (b *buildFile) addContext(container *Container, orig, dest string, decompress bool) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
destExists = true
|
destExists = true
|
||||||
@@ -454,7 +552,7 @@ func (b *buildFile) addContext(container *daemon.Container, orig, dest string, d
|
|||||||
if err := archive.UntarPath(origPath, tarDest); err == nil {
|
if err := archive.UntarPath(origPath, tarDest); err == nil {
|
||||||
return nil
|
return nil
|
||||||
} else if err != io.EOF {
|
} else if err != io.EOF {
|
||||||
utils.Debugf("Couldn't untar %s to %s: %s", origPath, tarDest, err)
|
log.Debugf("Couldn't untar %s to %s: %s", origPath, tarDest, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,7 +646,7 @@ func (b *buildFile) runContextCommand(args string, allowRemote bool, allowDecomp
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tarSum := &utils.TarSum{Reader: r, DisableCompression: true}
|
tarSum := &tarsum.TarSum{Reader: r, DisableCompression: true}
|
||||||
if _, err := io.Copy(ioutil.Discard, tarSum); err != nil {
|
if _, err := io.Copy(ioutil.Discard, tarSum); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -651,7 +749,7 @@ func (b *buildFile) CmdAdd(args string) error {
|
|||||||
return b.runContextCommand(args, true, true, "ADD")
|
return b.runContextCommand(args, true, true, "ADD")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *buildFile) create() (*daemon.Container, error) {
|
func (b *buildFile) create() (*Container, error) {
|
||||||
if b.image == "" {
|
if b.image == "" {
|
||||||
return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
|
return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
|
||||||
}
|
}
|
||||||
@@ -672,10 +770,15 @@ func (b *buildFile) create() (*daemon.Container, error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *buildFile) run(c *daemon.Container) error {
|
func (b *buildFile) run(c *Container) error {
|
||||||
var errCh chan error
|
var errCh chan error
|
||||||
if b.verbose {
|
if b.verbose {
|
||||||
errCh = utils.Go(func() error {
|
errCh = utils.Go(func() error {
|
||||||
|
// FIXME: call the 'attach' job so that daemon.Attach can be made private
|
||||||
|
//
|
||||||
|
// FIXME (LK4D4): Also, maybe makes sense to call "logs" job, it is like attach
|
||||||
|
// but without hijacking for stdin. Also, with attach there can be race
|
||||||
|
// condition because of some output already was printed before it.
|
||||||
return <-b.daemon.Attach(c, nil, nil, b.outStream, b.errStream)
|
return <-b.daemon.Attach(c, nil, nil, b.outStream, b.errStream)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -692,7 +795,7 @@ func (b *buildFile) run(c *daemon.Container) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for it to finish
|
// Wait for it to finish
|
||||||
if ret := c.Wait(); ret != 0 {
|
if ret, _ := c.State.WaitStop(-1 * time.Second); ret != 0 {
|
||||||
err := &utils.JSONError{
|
err := &utils.JSONError{
|
||||||
Message: fmt.Sprintf("The command %v returned a non-zero code: %d", b.config.Cmd, ret),
|
Message: fmt.Sprintf("The command %v returned a non-zero code: %d", b.config.Cmd, ret),
|
||||||
Code: ret,
|
Code: ret,
|
||||||
@@ -747,7 +850,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
|
|||||||
autoConfig := *b.config
|
autoConfig := *b.config
|
||||||
autoConfig.Cmd = autoCmd
|
autoConfig.Cmd = autoCmd
|
||||||
// Commit the container
|
// Commit the container
|
||||||
image, err := b.daemon.Commit(container, "", "", "", b.maintainer, &autoConfig)
|
image, err := b.daemon.Commit(container, "", "", "", b.maintainer, true, &autoConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -757,7 +860,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Long lines can be split with a backslash
|
// Long lines can be split with a backslash
|
||||||
var lineContinuation = regexp.MustCompile(`\s*\\\s*\n`)
|
var lineContinuation = regexp.MustCompile(`\\\s*\n`)
|
||||||
|
|
||||||
func (b *buildFile) Build(context io.Reader) (string, error) {
|
func (b *buildFile) Build(context io.Reader) (string, error) {
|
||||||
tmpdirPath, err := ioutil.TempDir("", "docker-build")
|
tmpdirPath, err := ioutil.TempDir("", "docker-build")
|
||||||
@@ -770,7 +873,7 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
b.context = &utils.TarSum{Reader: decompressedStream, DisableCompression: true}
|
b.context = &tarsum.TarSum{Reader: decompressedStream, DisableCompression: true}
|
||||||
if err := archive.Untar(b.context, tmpdirPath, nil); err != nil {
|
if err := archive.Untar(b.context, tmpdirPath, nil); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -884,10 +987,10 @@ func fixPermissions(destination string, uid, gid int) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeCache, rm bool, forceRm bool, outOld io.Writer, sf *utils.StreamFormatter, auth *registry.AuthConfig, authConfigFile *registry.ConfigFile) BuildFile {
|
func NewBuildFile(d *Daemon, eng *engine.Engine, outStream, errStream io.Writer, verbose, utilizeCache, rm bool, forceRm bool, outOld io.Writer, sf *utils.StreamFormatter, auth *registry.AuthConfig, authConfigFile *registry.ConfigFile) BuildFile {
|
||||||
return &buildFile{
|
return &buildFile{
|
||||||
daemon: srv.daemon,
|
daemon: d,
|
||||||
srv: srv,
|
eng: eng,
|
||||||
config: &runconfig.Config{},
|
config: &runconfig.Config{},
|
||||||
outStream: outStream,
|
outStream: outStream,
|
||||||
errStream: errStream,
|
errStream: errStream,
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/docker/docker/engine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (daemon *Daemon) ContainerChanges(job *engine.Job) engine.Status {
|
||||||
|
if n := len(job.Args); n != 1 {
|
||||||
|
return job.Errorf("Usage: %s CONTAINER", job.Name)
|
||||||
|
}
|
||||||
|
name := job.Args[0]
|
||||||
|
if container := daemon.Get(name); container != nil {
|
||||||
|
outs := engine.NewTable("", 0)
|
||||||
|
changes, err := container.Changes()
|
||||||
|
if err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
for _, change := range changes {
|
||||||
|
out := &engine.Env{}
|
||||||
|
if err := out.Import(change); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
outs.Add(out)
|
||||||
|
}
|
||||||
|
if _, err := outs.WriteListTo(job.Stdout); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return job.Errorf("No such container: %s", name)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/docker/docker/engine"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (daemon *Daemon) ContainerCommit(job *engine.Job) engine.Status {
|
||||||
|
if len(job.Args) != 1 {
|
||||||
|
return job.Errorf("Not enough arguments. Usage: %s CONTAINER\n", job.Name)
|
||||||
|
}
|
||||||
|
name := job.Args[0]
|
||||||
|
|
||||||
|
container := daemon.Get(name)
|
||||||
|
if container == nil {
|
||||||
|
return job.Errorf("No such container: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
config = container.Config
|
||||||
|
newConfig runconfig.Config
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := job.GetenvJson("config", &newConfig); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runconfig.Merge(&newConfig, config); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
img, err := daemon.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), job.GetenvBool("pause"), &newConfig)
|
||||||
|
if err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
job.Printf("%s\n", img.ID)
|
||||||
|
return engine.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit creates a new filesystem image from the current state of a container.
|
||||||
|
// The image can optionally be tagged into a repository
|
||||||
|
func (daemon *Daemon) Commit(container *Container, repository, tag, comment, author string, pause bool, config *runconfig.Config) (*image.Image, error) {
|
||||||
|
if pause {
|
||||||
|
container.Pause()
|
||||||
|
defer container.Unpause()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := container.Mount(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer container.Unmount()
|
||||||
|
|
||||||
|
rwTar, err := container.ExportRw()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rwTar.Close()
|
||||||
|
|
||||||
|
// Create a new image from the container's base layers + a new layer from container changes
|
||||||
|
var (
|
||||||
|
containerID, containerImage string
|
||||||
|
containerConfig *runconfig.Config
|
||||||
|
)
|
||||||
|
|
||||||
|
if container != nil {
|
||||||
|
containerID = container.ID
|
||||||
|
containerImage = container.Image
|
||||||
|
containerConfig = container.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
img, err := daemon.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the image if needed
|
||||||
|
if repository != "" {
|
||||||
|
if err := daemon.repositories.Set(repository, tag, img.ID, true); err != nil {
|
||||||
|
return img, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return img, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/docker/docker/daemon/networkdriver"
|
||||||
|
"github.com/docker/docker/opts"
|
||||||
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultNetworkMtu = 1500
|
||||||
|
DisableNetworkBridge = "none"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config define the configuration of a docker daemon
|
||||||
|
// These are the configuration settings that you pass
|
||||||
|
// to the docker daemon when you launch it with say: `docker -d -e lxc`
|
||||||
|
// FIXME: separate runtime configuration from http api configuration
|
||||||
|
type Config struct {
|
||||||
|
Pidfile string
|
||||||
|
Root string
|
||||||
|
AutoRestart bool
|
||||||
|
Dns []string
|
||||||
|
DnsSearch []string
|
||||||
|
EnableIptables bool
|
||||||
|
EnableIpForward bool
|
||||||
|
DefaultIp net.IP
|
||||||
|
BridgeIface string
|
||||||
|
BridgeIP string
|
||||||
|
InterContainerCommunication bool
|
||||||
|
GraphDriver string
|
||||||
|
GraphOptions []string
|
||||||
|
ExecDriver string
|
||||||
|
Mtu int
|
||||||
|
DisableNetwork bool
|
||||||
|
EnableSelinuxSupport bool
|
||||||
|
Context map[string][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstallFlags adds command-line options to the top-level flag parser for
|
||||||
|
// the current process.
|
||||||
|
// Subsequent calls to `flag.Parse` will populate config with values parsed
|
||||||
|
// from the command-line.
|
||||||
|
func (config *Config) InstallFlags() {
|
||||||
|
flag.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file")
|
||||||
|
flag.StringVar(&config.Root, []string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the Docker runtime")
|
||||||
|
flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated infavor of --restart policies on docker run")
|
||||||
|
flag.BoolVar(&config.EnableIptables, []string{"#iptables", "-iptables"}, true, "Enable Docker's addition of iptables rules")
|
||||||
|
flag.BoolVar(&config.EnableIpForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
|
||||||
|
flag.StringVar(&config.BridgeIP, []string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b")
|
||||||
|
flag.StringVar(&config.BridgeIface, []string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking")
|
||||||
|
flag.BoolVar(&config.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
|
||||||
|
flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Force the Docker runtime to use a specific storage driver")
|
||||||
|
flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, "native", "Force the Docker runtime to use a specific exec driver")
|
||||||
|
flag.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, "Enable selinux support. SELinux does not presently support the BTRFS storage driver")
|
||||||
|
flag.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, "Set the containers network MTU\nif no value is provided: default to the default route MTU or 1500 if no default route is available")
|
||||||
|
opts.IPVar(&config.DefaultIp, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP address to use when binding container ports")
|
||||||
|
opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options")
|
||||||
|
// FIXME: why the inconsistency between "hosts" and "sockets"?
|
||||||
|
opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "Force Docker to use specific DNS servers")
|
||||||
|
opts.DnsSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "Force Docker to use specific DNS search domains")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDefaultNetworkMtu() int {
|
||||||
|
if iface, err := networkdriver.GetDefaultRouteIface(); err == nil {
|
||||||
|
return iface.MTU
|
||||||
|
}
|
||||||
|
return defaultNetworkMtu
|
||||||
|
}
|
||||||
+208
-192
@@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -15,20 +14,23 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/archive"
|
"github.com/docker/libcontainer/devices"
|
||||||
"github.com/dotcloud/docker/daemon/execdriver"
|
"github.com/docker/libcontainer/label"
|
||||||
"github.com/dotcloud/docker/daemon/graphdriver"
|
|
||||||
"github.com/dotcloud/docker/engine"
|
"github.com/docker/docker/archive"
|
||||||
"github.com/dotcloud/docker/image"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
"github.com/dotcloud/docker/links"
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
"github.com/dotcloud/docker/nat"
|
"github.com/docker/docker/engine"
|
||||||
"github.com/dotcloud/docker/pkg/label"
|
"github.com/docker/docker/image"
|
||||||
"github.com/dotcloud/docker/pkg/libcontainer/devices"
|
"github.com/docker/docker/links"
|
||||||
"github.com/dotcloud/docker/pkg/networkfs/etchosts"
|
"github.com/docker/docker/nat"
|
||||||
"github.com/dotcloud/docker/pkg/networkfs/resolvconf"
|
"github.com/docker/docker/pkg/broadcastwriter"
|
||||||
"github.com/dotcloud/docker/pkg/symlink"
|
"github.com/docker/docker/pkg/log"
|
||||||
"github.com/dotcloud/docker/runconfig"
|
"github.com/docker/docker/pkg/networkfs/etchosts"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/docker/docker/pkg/networkfs/resolvconf"
|
||||||
|
"github.com/docker/docker/pkg/symlink"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
@@ -53,7 +55,7 @@ type Container struct {
|
|||||||
Args []string
|
Args []string
|
||||||
|
|
||||||
Config *runconfig.Config
|
Config *runconfig.Config
|
||||||
State State
|
State *State
|
||||||
Image string
|
Image string
|
||||||
|
|
||||||
NetworkSettings *NetworkSettings
|
NetworkSettings *NetworkSettings
|
||||||
@@ -66,26 +68,32 @@ type Container struct {
|
|||||||
ExecDriver string
|
ExecDriver string
|
||||||
|
|
||||||
command *execdriver.Command
|
command *execdriver.Command
|
||||||
stdout *utils.WriteBroadcaster
|
stdout *broadcastwriter.BroadcastWriter
|
||||||
stderr *utils.WriteBroadcaster
|
stderr *broadcastwriter.BroadcastWriter
|
||||||
stdin io.ReadCloser
|
stdin io.ReadCloser
|
||||||
stdinPipe io.WriteCloser
|
stdinPipe io.WriteCloser
|
||||||
|
|
||||||
daemon *Daemon
|
daemon *Daemon
|
||||||
MountLabel, ProcessLabel string
|
MountLabel, ProcessLabel string
|
||||||
|
RestartCount int
|
||||||
|
|
||||||
waitLock chan struct{}
|
Volumes map[string]string
|
||||||
Volumes map[string]string
|
|
||||||
// Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
|
// Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
|
||||||
// Easier than migrating older container configs :)
|
// Easier than migrating older container configs :)
|
||||||
VolumesRW map[string]bool
|
VolumesRW map[string]bool
|
||||||
hostConfig *runconfig.HostConfig
|
hostConfig *runconfig.HostConfig
|
||||||
|
|
||||||
activeLinks map[string]*links.Link
|
activeLinks map[string]*links.Link
|
||||||
|
monitor *containerMonitor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) FromDisk() error {
|
func (container *Container) FromDisk() error {
|
||||||
data, err := ioutil.ReadFile(container.jsonPath())
|
pth, err := container.jsonPath()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(pth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -101,50 +109,83 @@ func (container *Container) FromDisk() error {
|
|||||||
return container.readHostConfig()
|
return container.readHostConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) ToDisk() (err error) {
|
func (container *Container) toDisk() error {
|
||||||
data, err := json.Marshal(container)
|
data, err := json.Marshal(container)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(container.jsonPath(), data, 0666)
|
|
||||||
|
pth, err := container.jsonPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(pth, data, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return container.WriteHostConfig()
|
return container.WriteHostConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (container *Container) ToDisk() error {
|
||||||
|
container.Lock()
|
||||||
|
err := container.toDisk()
|
||||||
|
container.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (container *Container) readHostConfig() error {
|
func (container *Container) readHostConfig() error {
|
||||||
container.hostConfig = &runconfig.HostConfig{}
|
container.hostConfig = &runconfig.HostConfig{}
|
||||||
// If the hostconfig file does not exist, do not read it.
|
// If the hostconfig file does not exist, do not read it.
|
||||||
// (We still have to initialize container.hostConfig,
|
// (We still have to initialize container.hostConfig,
|
||||||
// but that's OK, since we just did that above.)
|
// but that's OK, since we just did that above.)
|
||||||
_, err := os.Stat(container.hostConfigPath())
|
pth, err := container.hostConfigPath()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = os.Stat(pth)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadFile(container.hostConfigPath())
|
|
||||||
|
data, err := ioutil.ReadFile(pth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return json.Unmarshal(data, container.hostConfig)
|
return json.Unmarshal(data, container.hostConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) WriteHostConfig() (err error) {
|
func (container *Container) WriteHostConfig() error {
|
||||||
data, err := json.Marshal(container.hostConfig)
|
data, err := json.Marshal(container.hostConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
|
|
||||||
|
pth, err := container.hostConfigPath()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioutil.WriteFile(pth, data, 0666)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) getResourcePath(path string) string {
|
func (container *Container) LogEvent(action string) {
|
||||||
cleanPath := filepath.Join("/", path)
|
d := container.daemon
|
||||||
return filepath.Join(container.basefs, cleanPath)
|
if err := d.eng.Job("log", action, container.ID, d.Repositories().ImageName(container.Image)).Run(); err != nil {
|
||||||
|
log.Errorf("Error logging event %s for %s: %s", action, container.ID, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) getRootResourcePath(path string) string {
|
func (container *Container) getResourcePath(path string) (string, error) {
|
||||||
cleanPath := filepath.Join("/", path)
|
cleanPath := filepath.Join("/", path)
|
||||||
return filepath.Join(container.root, cleanPath)
|
return symlink.FollowSymlinkInScope(filepath.Join(container.basefs, cleanPath), container.basefs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (container *Container) getRootResourcePath(path string) (string, error) {
|
||||||
|
cleanPath := filepath.Join("/", path)
|
||||||
|
return symlink.FollowSymlinkInScope(filepath.Join(container.root, cleanPath), container.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
func populateCommand(c *Container, env []string) error {
|
func populateCommand(c *Container, env []string) error {
|
||||||
@@ -185,6 +226,20 @@ func populateCommand(c *Container, env []string) error {
|
|||||||
return fmt.Errorf("invalid network mode: %s", c.hostConfig.NetworkMode)
|
return fmt.Errorf("invalid network mode: %s", c.hostConfig.NetworkMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build lists of devices allowed and created within the container.
|
||||||
|
userSpecifiedDevices := make([]*devices.Device, len(c.hostConfig.Devices))
|
||||||
|
for i, deviceMapping := range c.hostConfig.Devices {
|
||||||
|
device, err := devices.GetDevice(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions)
|
||||||
|
device.Path = deviceMapping.PathInContainer
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error gathering device information while adding custom device %s", err)
|
||||||
|
}
|
||||||
|
userSpecifiedDevices[i] = device
|
||||||
|
}
|
||||||
|
allowedDevices := append(devices.DefaultAllowedDevices, userSpecifiedDevices...)
|
||||||
|
|
||||||
|
autoCreatedDevices := append(devices.DefaultAutoCreatedDevices, userSpecifiedDevices...)
|
||||||
|
|
||||||
// TODO: this can be removed after lxc-conf is fully deprecated
|
// TODO: this can be removed after lxc-conf is fully deprecated
|
||||||
mergeLxcConfIntoOptions(c.hostConfig, context)
|
mergeLxcConfIntoOptions(c.hostConfig, context)
|
||||||
|
|
||||||
@@ -207,8 +262,10 @@ func populateCommand(c *Container, env []string) error {
|
|||||||
User: c.Config.User,
|
User: c.Config.User,
|
||||||
Config: context,
|
Config: context,
|
||||||
Resources: resources,
|
Resources: resources,
|
||||||
AllowedDevices: devices.DefaultAllowedDevices,
|
AllowedDevices: allowedDevices,
|
||||||
AutoCreatedDevices: devices.DefaultAutoCreatedDevices,
|
AutoCreatedDevices: autoCreatedDevices,
|
||||||
|
CapAdd: c.hostConfig.CapAdd,
|
||||||
|
CapDrop: c.hostConfig.CapDrop,
|
||||||
}
|
}
|
||||||
c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
||||||
c.command.Env = env
|
c.command.Env = env
|
||||||
@@ -222,6 +279,7 @@ func (container *Container) Start() (err error) {
|
|||||||
if container.State.IsRunning() {
|
if container.State.IsRunning() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we encounter and error during start we need to ensure that any other
|
// if we encounter and error during start we need to ensure that any other
|
||||||
// setup has been cleaned up properly
|
// setup has been cleaned up properly
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -257,10 +315,6 @@ func (container *Container) Start() (err error) {
|
|||||||
if err := setupMountsForContainer(container); err != nil {
|
if err := setupMountsForContainer(container); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := container.startLoggingToDisk(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
container.waitLock = make(chan struct{})
|
|
||||||
|
|
||||||
return container.waitForStart()
|
return container.waitForStart()
|
||||||
}
|
}
|
||||||
@@ -269,7 +323,7 @@ func (container *Container) Run() error {
|
|||||||
if err := container.Start(); err != nil {
|
if err := container.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
container.Wait()
|
container.State.WaitStop(-1 * time.Second)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +337,7 @@ func (container *Container) Output() (output []byte, err error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
output, err = ioutil.ReadAll(pipe)
|
output, err = ioutil.ReadAll(pipe)
|
||||||
container.Wait()
|
container.State.WaitStop(-1 * time.Second)
|
||||||
return output, err
|
return output, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,7 +378,12 @@ func (container *Container) StderrLogPipe() io.ReadCloser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) buildHostnameFile() error {
|
func (container *Container) buildHostnameFile() error {
|
||||||
container.HostnamePath = container.getRootResourcePath("hostname")
|
hostnamePath, err := container.getRootResourcePath("hostname")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
container.HostnamePath = hostnamePath
|
||||||
|
|
||||||
if container.Config.Domainname != "" {
|
if container.Config.Domainname != "" {
|
||||||
return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
|
return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
|
||||||
}
|
}
|
||||||
@@ -336,7 +395,11 @@ func (container *Container) buildHostnameAndHostsFiles(IP string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
container.HostsPath = container.getRootResourcePath("hosts")
|
hostsPath, err := container.getRootResourcePath("hosts")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
container.HostsPath = hostsPath
|
||||||
|
|
||||||
extraContent := make(map[string]string)
|
extraContent := make(map[string]string)
|
||||||
|
|
||||||
@@ -391,8 +454,17 @@ func (container *Container) allocateNetwork() error {
|
|||||||
if container.Config.ExposedPorts != nil {
|
if container.Config.ExposedPorts != nil {
|
||||||
portSpecs = container.Config.ExposedPorts
|
portSpecs = container.Config.ExposedPorts
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.hostConfig.PortBindings != nil {
|
if container.hostConfig.PortBindings != nil {
|
||||||
bindings = container.hostConfig.PortBindings
|
for p, b := range container.hostConfig.PortBindings {
|
||||||
|
bindings[p] = []nat.PortBinding{}
|
||||||
|
for _, bb := range b {
|
||||||
|
bindings[p] = append(bindings[p], nat.PortBinding{
|
||||||
|
HostIp: bb.HostIp,
|
||||||
|
HostPort: bb.HostPort,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
container.NetworkSettings.PortMapping = nil
|
container.NetworkSettings.PortMapping = nil
|
||||||
@@ -423,50 +495,8 @@ func (container *Container) releaseNetwork() {
|
|||||||
container.NetworkSettings = &NetworkSettings{}
|
container.NetworkSettings = &NetworkSettings{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) monitor(callback execdriver.StartCallback) error {
|
// cleanup releases any network resources allocated to the container along with any rules
|
||||||
var (
|
// around how containers are linked together. It also unmounts the container's root filesystem.
|
||||||
err error
|
|
||||||
exitCode int
|
|
||||||
)
|
|
||||||
|
|
||||||
pipes := execdriver.NewPipes(container.stdin, container.stdout, container.stderr, container.Config.OpenStdin)
|
|
||||||
exitCode, err = container.daemon.Run(container, pipes, callback)
|
|
||||||
if err != nil {
|
|
||||||
utils.Errorf("Error running container: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
container.cleanup()
|
|
||||||
|
|
||||||
// Re-create a brand new stdin pipe once the container exited
|
|
||||||
if container.Config.OpenStdin {
|
|
||||||
container.stdin, container.stdinPipe = io.Pipe()
|
|
||||||
}
|
|
||||||
|
|
||||||
if container.daemon != nil && container.daemon.srv != nil {
|
|
||||||
container.daemon.srv.LogEvent("die", container.ID, container.daemon.repositories.ImageName(container.Image))
|
|
||||||
}
|
|
||||||
|
|
||||||
close(container.waitLock)
|
|
||||||
|
|
||||||
if container.daemon != nil && container.daemon.srv != nil && container.daemon.srv.IsRunning() {
|
|
||||||
container.State.SetStopped(exitCode)
|
|
||||||
|
|
||||||
// FIXME: there is a race condition here which causes this to fail during the unit tests.
|
|
||||||
// If another goroutine was waiting for Wait() to return before removing the container's root
|
|
||||||
// from the filesystem... At this point it may already have done so.
|
|
||||||
// This is because State.setStopped() has already been called, and has caused Wait()
|
|
||||||
// to return.
|
|
||||||
// FIXME: why are we serializing running state to disk in the first place?
|
|
||||||
//log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err)
|
|
||||||
if err := container.ToDisk(); err != nil {
|
|
||||||
utils.Errorf("Error dumping container state to disk: %s\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (container *Container) cleanup() {
|
func (container *Container) cleanup() {
|
||||||
container.releaseNetwork()
|
container.releaseNetwork()
|
||||||
|
|
||||||
@@ -476,29 +506,14 @@ func (container *Container) cleanup() {
|
|||||||
link.Disable()
|
link.Disable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if container.Config.OpenStdin {
|
|
||||||
if err := container.stdin.Close(); err != nil {
|
|
||||||
utils.Errorf("%s: Error close stdin: %s", container.ID, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := container.stdout.CloseWriters(); err != nil {
|
|
||||||
utils.Errorf("%s: Error close stdout: %s", container.ID, err)
|
|
||||||
}
|
|
||||||
if err := container.stderr.CloseWriters(); err != nil {
|
|
||||||
utils.Errorf("%s: Error close stderr: %s", container.ID, err)
|
|
||||||
}
|
|
||||||
if container.command != nil && container.command.Terminal != nil {
|
|
||||||
if err := container.command.Terminal.Close(); err != nil {
|
|
||||||
utils.Errorf("%s: Error closing terminal: %s", container.ID, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := container.Unmount(); err != nil {
|
if err := container.Unmount(); err != nil {
|
||||||
log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
|
log.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) KillSig(sig int) error {
|
func (container *Container) KillSig(sig int) error {
|
||||||
|
log.Debugf("Sending %d to %s", sig, container.ID)
|
||||||
container.Lock()
|
container.Lock()
|
||||||
defer container.Unlock()
|
defer container.Unlock()
|
||||||
|
|
||||||
@@ -510,6 +525,18 @@ func (container *Container) KillSig(sig int) error {
|
|||||||
if !container.State.IsRunning() {
|
if !container.State.IsRunning() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// signal to the monitor that it should not restart the container
|
||||||
|
// after we send the kill signal
|
||||||
|
container.monitor.ExitOnNext()
|
||||||
|
|
||||||
|
// if the container is currently restarting we do not need to send the signal
|
||||||
|
// to the process. Telling the monitor that it should exit on it's next event
|
||||||
|
// loop is enough
|
||||||
|
if container.State.IsRestarting() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return container.daemon.Kill(container, sig)
|
return container.daemon.Kill(container, sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,17 +571,17 @@ func (container *Container) Kill() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. Wait for the process to die, in last resort, try to kill the process directly
|
// 2. Wait for the process to die, in last resort, try to kill the process directly
|
||||||
if err := container.WaitTimeout(10 * time.Second); err != nil {
|
if _, err := container.State.WaitStop(10 * time.Second); err != nil {
|
||||||
// Ensure that we don't kill ourselves
|
// Ensure that we don't kill ourselves
|
||||||
if pid := container.State.Pid; pid != 0 {
|
if pid := container.State.GetPid(); pid != 0 {
|
||||||
log.Printf("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", utils.TruncateID(container.ID))
|
log.Infof("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", utils.TruncateID(container.ID))
|
||||||
if err := syscall.Kill(pid, 9); err != nil {
|
if err := syscall.Kill(pid, 9); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
container.Wait()
|
container.State.WaitStop(-1 * time.Second)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,18 +592,18 @@ func (container *Container) Stop(seconds int) error {
|
|||||||
|
|
||||||
// 1. Send a SIGTERM
|
// 1. Send a SIGTERM
|
||||||
if err := container.KillSig(15); err != nil {
|
if err := container.KillSig(15); err != nil {
|
||||||
log.Print("Failed to send SIGTERM to the process, force killing")
|
log.Infof("Failed to send SIGTERM to the process, force killing")
|
||||||
if err := container.KillSig(9); err != nil {
|
if err := container.KillSig(9); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Wait for the process to exit on its own
|
// 2. Wait for the process to exit on its own
|
||||||
if err := container.WaitTimeout(time.Duration(seconds) * time.Second); err != nil {
|
if _, err := container.State.WaitStop(time.Duration(seconds) * time.Second); err != nil {
|
||||||
log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds)
|
log.Infof("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds)
|
||||||
// 3. If it doesn't, then send SIGKILL
|
// 3. If it doesn't, then send SIGKILL
|
||||||
if err := container.Kill(); err != nil {
|
if err := container.Kill(); err != nil {
|
||||||
container.Wait()
|
container.State.WaitStop(-1 * time.Second)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -597,12 +624,6 @@ func (container *Container) Restart(seconds int) error {
|
|||||||
return container.Start()
|
return container.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait blocks until the container stops running, then returns its exit code.
|
|
||||||
func (container *Container) Wait() int {
|
|
||||||
<-container.waitLock
|
|
||||||
return container.State.GetExitCode()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (container *Container) Resize(h, w int) error {
|
func (container *Container) Resize(h, w int) error {
|
||||||
return container.command.Terminal.Resize(h, w)
|
return container.command.Terminal.Resize(h, w)
|
||||||
}
|
}
|
||||||
@@ -645,21 +666,6 @@ func (container *Container) Export() (archive.Archive, error) {
|
|||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) WaitTimeout(timeout time.Duration) error {
|
|
||||||
done := make(chan bool, 1)
|
|
||||||
go func() {
|
|
||||||
container.Wait()
|
|
||||||
done <- true
|
|
||||||
}()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-time.After(timeout):
|
|
||||||
return fmt.Errorf("Timed Out")
|
|
||||||
case <-done:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (container *Container) Mount() error {
|
func (container *Container) Mount() error {
|
||||||
return container.daemon.Mount(container)
|
return container.daemon.Mount(container)
|
||||||
}
|
}
|
||||||
@@ -681,19 +687,23 @@ func (container *Container) Unmount() error {
|
|||||||
return container.daemon.Unmount(container)
|
return container.daemon.Unmount(container)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) logPath(name string) string {
|
func (container *Container) logPath(name string) (string, error) {
|
||||||
return container.getRootResourcePath(fmt.Sprintf("%s-%s.log", container.ID, name))
|
return container.getRootResourcePath(fmt.Sprintf("%s-%s.log", container.ID, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) ReadLog(name string) (io.Reader, error) {
|
func (container *Container) ReadLog(name string) (io.Reader, error) {
|
||||||
return os.Open(container.logPath(name))
|
pth, err := container.logPath(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return os.Open(pth)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) hostConfigPath() string {
|
func (container *Container) hostConfigPath() (string, error) {
|
||||||
return container.getRootResourcePath("hostconfig.json")
|
return container.getRootResourcePath("hostconfig.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) jsonPath() string {
|
func (container *Container) jsonPath() (string, error) {
|
||||||
return container.getRootResourcePath("config.json")
|
return container.getRootResourcePath("config.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,7 +729,7 @@ func (container *Container) GetSize() (int64, int64) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if err := container.Mount(); err != nil {
|
if err := container.Mount(); err != nil {
|
||||||
utils.Errorf("Warning: failed to compute size of container rootfs %s: %s", container.ID, err)
|
log.Errorf("Warning: failed to compute size of container rootfs %s: %s", container.ID, err)
|
||||||
return sizeRw, sizeRootfs
|
return sizeRw, sizeRootfs
|
||||||
}
|
}
|
||||||
defer container.Unmount()
|
defer container.Unmount()
|
||||||
@@ -727,7 +737,7 @@ func (container *Container) GetSize() (int64, int64) {
|
|||||||
if differ, ok := container.daemon.driver.(graphdriver.Differ); ok {
|
if differ, ok := container.daemon.driver.(graphdriver.Differ); ok {
|
||||||
sizeRw, err = differ.DiffSize(container.ID)
|
sizeRw, err = differ.DiffSize(container.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
|
log.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
|
||||||
// FIXME: GetSize should return an error. Not changing it now in case
|
// FIXME: GetSize should return an error. Not changing it now in case
|
||||||
// there is a side-effect.
|
// there is a side-effect.
|
||||||
sizeRw = -1
|
sizeRw = -1
|
||||||
@@ -756,8 +766,7 @@ func (container *Container) Copy(resource string) (io.ReadCloser, error) {
|
|||||||
|
|
||||||
var filter []string
|
var filter []string
|
||||||
|
|
||||||
resPath := container.getResourcePath(resource)
|
basePath, err := container.getResourcePath(resource)
|
||||||
basePath, err := symlink.FollowSymlinkInScope(resPath, container.basefs)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
container.Unmount()
|
container.Unmount()
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -777,7 +786,7 @@ func (container *Container) Copy(resource string) (io.ReadCloser, error) {
|
|||||||
basePath = path.Dir(basePath)
|
basePath = path.Dir(basePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
archive, err := archive.TarFilter(basePath, &archive.TarOptions{
|
archive, err := archive.TarWithOptions(basePath, &archive.TarOptions{
|
||||||
Compression: archive.Uncompressed,
|
Compression: archive.Uncompressed,
|
||||||
Includes: filter,
|
Includes: filter,
|
||||||
})
|
})
|
||||||
@@ -808,11 +817,16 @@ func (container *Container) GetPtyMaster() (*os.File, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) HostConfig() *runconfig.HostConfig {
|
func (container *Container) HostConfig() *runconfig.HostConfig {
|
||||||
return container.hostConfig
|
container.Lock()
|
||||||
|
res := container.hostConfig
|
||||||
|
container.Unlock()
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) SetHostConfig(hostConfig *runconfig.HostConfig) {
|
func (container *Container) SetHostConfig(hostConfig *runconfig.HostConfig) {
|
||||||
|
container.Lock()
|
||||||
container.hostConfig = hostConfig
|
container.hostConfig = hostConfig
|
||||||
|
container.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) DisableLink(name string) {
|
func (container *Container) DisableLink(name string) {
|
||||||
@@ -820,7 +834,7 @@ func (container *Container) DisableLink(name string) {
|
|||||||
if link, exists := container.activeLinks[name]; exists {
|
if link, exists := container.activeLinks[name]; exists {
|
||||||
link.Disable()
|
link.Disable()
|
||||||
} else {
|
} else {
|
||||||
utils.Debugf("Could not find active link for %s", name)
|
log.Debugf("Could not find active link for %s", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -835,18 +849,16 @@ func (container *Container) setupContainerDns() error {
|
|||||||
daemon = container.daemon
|
daemon = container.daemon
|
||||||
)
|
)
|
||||||
|
|
||||||
if config.NetworkMode == "host" {
|
|
||||||
container.ResolvConfPath = "/etc/resolv.conf"
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvConf, err := resolvconf.Get()
|
resolvConf, err := resolvconf.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
container.ResolvConfPath, err = container.getRootResourcePath("resolv.conf")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// If custom dns exists, then create a resolv.conf for the container
|
if config.NetworkMode != "host" && (len(config.Dns) > 0 || len(daemon.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(daemon.config.DnsSearch) > 0) {
|
||||||
if len(config.Dns) > 0 || len(daemon.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(daemon.config.DnsSearch) > 0 {
|
|
||||||
var (
|
var (
|
||||||
dns = resolvconf.GetNameservers(resolvConf)
|
dns = resolvconf.GetNameservers(resolvConf)
|
||||||
dnsSearch = resolvconf.GetSearchDomains(resolvConf)
|
dnsSearch = resolvconf.GetSearchDomains(resolvConf)
|
||||||
@@ -861,12 +873,9 @@ func (container *Container) setupContainerDns() error {
|
|||||||
} else if len(daemon.config.DnsSearch) > 0 {
|
} else if len(daemon.config.DnsSearch) > 0 {
|
||||||
dnsSearch = daemon.config.DnsSearch
|
dnsSearch = daemon.config.DnsSearch
|
||||||
}
|
}
|
||||||
container.ResolvConfPath = container.getRootResourcePath("resolv.conf")
|
|
||||||
return resolvconf.Build(container.ResolvConfPath, dns, dnsSearch)
|
return resolvconf.Build(container.ResolvConfPath, dns, dnsSearch)
|
||||||
} else {
|
|
||||||
container.ResolvConfPath = "/etc/resolv.conf"
|
|
||||||
}
|
}
|
||||||
return nil
|
return ioutil.WriteFile(container.ResolvConfPath, resolvConf, 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) initializeNetworking() error {
|
func (container *Container) initializeNetworking() error {
|
||||||
@@ -886,12 +895,20 @@ func (container *Container) initializeNetworking() error {
|
|||||||
content, err := ioutil.ReadFile("/etc/hosts")
|
content, err := ioutil.ReadFile("/etc/hosts")
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return container.buildHostnameAndHostsFiles("")
|
return container.buildHostnameAndHostsFiles("")
|
||||||
}
|
} else if err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
container.HostsPath = container.getRootResourcePath("hosts")
|
if err := container.buildHostnameFile(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hostsPath, err := container.getRootResourcePath("hosts")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
container.HostsPath = hostsPath
|
||||||
|
|
||||||
return ioutil.WriteFile(container.HostsPath, content, 0644)
|
return ioutil.WriteFile(container.HostsPath, content, 0644)
|
||||||
} else if container.hostConfig.NetworkMode.IsContainer() {
|
} else if container.hostConfig.NetworkMode.IsContainer() {
|
||||||
// we need to get the hosts files from the container to join
|
// we need to get the hosts files from the container to join
|
||||||
@@ -918,15 +935,15 @@ func (container *Container) initializeNetworking() error {
|
|||||||
// Make sure the config is compatible with the current kernel
|
// Make sure the config is compatible with the current kernel
|
||||||
func (container *Container) verifyDaemonSettings() {
|
func (container *Container) verifyDaemonSettings() {
|
||||||
if container.Config.Memory > 0 && !container.daemon.sysInfo.MemoryLimit {
|
if container.Config.Memory > 0 && !container.daemon.sysInfo.MemoryLimit {
|
||||||
log.Printf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
|
log.Infof("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.")
|
||||||
container.Config.Memory = 0
|
container.Config.Memory = 0
|
||||||
}
|
}
|
||||||
if container.Config.Memory > 0 && !container.daemon.sysInfo.SwapLimit {
|
if container.Config.Memory > 0 && !container.daemon.sysInfo.SwapLimit {
|
||||||
log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
log.Infof("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.")
|
||||||
container.Config.MemorySwap = -1
|
container.Config.MemorySwap = -1
|
||||||
}
|
}
|
||||||
if container.daemon.sysInfo.IPv4ForwardingDisabled {
|
if container.daemon.sysInfo.IPv4ForwardingDisabled {
|
||||||
log.Printf("WARNING: IPv4 forwarding is disabled. Networking will not work")
|
log.Infof("WARNING: IPv4 forwarding is disabled. Networking will not work")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -987,9 +1004,12 @@ func (container *Container) setupLinkedContainers() ([]string, error) {
|
|||||||
func (container *Container) createDaemonEnvironment(linkedEnv []string) []string {
|
func (container *Container) createDaemonEnvironment(linkedEnv []string) []string {
|
||||||
// Setup environment
|
// Setup environment
|
||||||
env := []string{
|
env := []string{
|
||||||
"HOME=/",
|
|
||||||
"PATH=" + DefaultPathEnv,
|
"PATH=" + DefaultPathEnv,
|
||||||
"HOSTNAME=" + container.Config.Hostname,
|
"HOSTNAME=" + container.Config.Hostname,
|
||||||
|
// Note: we don't set HOME here because it'll get autoset intelligently
|
||||||
|
// based on the value of USER inside dockerinit, but only if it isn't
|
||||||
|
// set already (ie, that can be overridden by setting HOME via -e or ENV
|
||||||
|
// in a Dockerfile).
|
||||||
}
|
}
|
||||||
if container.Config.Tty {
|
if container.Config.Tty {
|
||||||
env = append(env, "TERM=xterm")
|
env = append(env, "TERM=xterm")
|
||||||
@@ -1007,12 +1027,18 @@ func (container *Container) setupWorkingDirectory() error {
|
|||||||
if container.Config.WorkingDir != "" {
|
if container.Config.WorkingDir != "" {
|
||||||
container.Config.WorkingDir = path.Clean(container.Config.WorkingDir)
|
container.Config.WorkingDir = path.Clean(container.Config.WorkingDir)
|
||||||
|
|
||||||
pthInfo, err := os.Stat(container.getResourcePath(container.Config.WorkingDir))
|
pth, err := container.getResourcePath(container.Config.WorkingDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pthInfo, err := os.Stat(pth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !os.IsNotExist(err) {
|
if !os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(container.getResourcePath(container.Config.WorkingDir), 0755); err != nil {
|
|
||||||
|
if err := os.MkdirAll(pth, 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1025,43 +1051,33 @@ func (container *Container) setupWorkingDirectory() error {
|
|||||||
|
|
||||||
func (container *Container) startLoggingToDisk() error {
|
func (container *Container) startLoggingToDisk() error {
|
||||||
// Setup logging of stdout and stderr to disk
|
// Setup logging of stdout and stderr to disk
|
||||||
if err := container.daemon.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
|
pth, err := container.logPath("json")
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := container.daemon.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
|
|
||||||
|
if err := container.daemon.LogToDisk(container.stdout, pth, "stdout"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := container.daemon.LogToDisk(container.stderr, pth, "stderr"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *Container) waitForStart() error {
|
func (container *Container) waitForStart() error {
|
||||||
callbackLock := make(chan struct{})
|
container.monitor = newContainerMonitor(container, container.hostConfig.RestartPolicy)
|
||||||
callback := func(command *execdriver.Command) {
|
|
||||||
container.State.SetRunning(command.Pid())
|
|
||||||
if command.Tty {
|
|
||||||
// The callback is called after the process Start()
|
|
||||||
// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlace
|
|
||||||
// which we close here.
|
|
||||||
if c, ok := command.Stdout.(io.Closer); ok {
|
|
||||||
c.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := container.ToDisk(); err != nil {
|
|
||||||
utils.Debugf("%s", err)
|
|
||||||
}
|
|
||||||
close(callbackLock)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use a callback here instead of a goroutine and an chan for
|
// block until we either receive an error from the initial start of the container's
|
||||||
// syncronization purposes
|
// process or until the process is running in the container
|
||||||
cErr := utils.Go(func() error { return container.monitor(callback) })
|
|
||||||
|
|
||||||
// Start should not return until the process is actually running
|
|
||||||
select {
|
select {
|
||||||
case <-callbackLock:
|
case <-container.monitor.startSignal:
|
||||||
case err := <-cErr:
|
case err := <-utils.Go(container.monitor.Start):
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/dotcloud/docker/nat"
|
"github.com/docker/docker/nat"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -89,6 +89,41 @@ func TestParseNetworkOptsPublic(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseNetworkOptsPublicNoPort(t *testing.T) {
|
||||||
|
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100"})
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Logf("Expected error Invalid containerPort")
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if ports != nil {
|
||||||
|
t.Logf("Expected nil got %s", ports)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if bindings != nil {
|
||||||
|
t.Logf("Expected nil got %s", bindings)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseNetworkOptsNegativePorts(t *testing.T) {
|
||||||
|
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100:-1:-1"})
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
t.Logf("%v", len(ports))
|
||||||
|
t.Logf("%v", bindings)
|
||||||
|
if len(ports) != 0 {
|
||||||
|
t.Logf("Expected nil got %s", len(ports))
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if len(bindings) != 0 {
|
||||||
|
t.Logf("Expected 0 got %s", len(bindings))
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseNetworkOptsUdp(t *testing.T) {
|
func TestParseNetworkOptsUdp(t *testing.T) {
|
||||||
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100::6000/udp"})
|
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100::6000/udp"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/docker/docker/engine"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (daemon *Daemon) ContainerCopy(job *engine.Job) engine.Status {
|
||||||
|
if len(job.Args) != 2 {
|
||||||
|
return job.Errorf("Usage: %s CONTAINER RESOURCE\n", job.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
name = job.Args[0]
|
||||||
|
resource = job.Args[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
if container := daemon.Get(name); container != nil {
|
||||||
|
|
||||||
|
data, err := container.Copy(resource)
|
||||||
|
if err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
defer data.Close()
|
||||||
|
|
||||||
|
if _, err := io.Copy(job.Stdout, data); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
}
|
||||||
|
return job.Errorf("No such container: %s", name)
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/docker/docker/engine"
|
||||||
|
"github.com/docker/docker/graph"
|
||||||
|
"github.com/docker/docker/pkg/parsers"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (daemon *Daemon) ContainerCreate(job *engine.Job) engine.Status {
|
||||||
|
var name string
|
||||||
|
if len(job.Args) == 1 {
|
||||||
|
name = job.Args[0]
|
||||||
|
} else if len(job.Args) > 1 {
|
||||||
|
return job.Errorf("Usage: %s", job.Name)
|
||||||
|
}
|
||||||
|
config := runconfig.ContainerConfigFromJob(job)
|
||||||
|
if config.Memory != 0 && config.Memory < 524288 {
|
||||||
|
return job.Errorf("Minimum memory limit allowed is 512k")
|
||||||
|
}
|
||||||
|
if config.Memory > 0 && !daemon.SystemConfig().MemoryLimit {
|
||||||
|
job.Errorf("Your kernel does not support memory limit capabilities. Limitation discarded.\n")
|
||||||
|
config.Memory = 0
|
||||||
|
}
|
||||||
|
if config.Memory > 0 && !daemon.SystemConfig().SwapLimit {
|
||||||
|
job.Errorf("Your kernel does not support swap limit capabilities. Limitation discarded.\n")
|
||||||
|
config.MemorySwap = -1
|
||||||
|
}
|
||||||
|
container, buildWarnings, err := daemon.Create(config, name)
|
||||||
|
if err != nil {
|
||||||
|
if daemon.Graph().IsNotExist(err) {
|
||||||
|
_, tag := parsers.ParseRepositoryTag(config.Image)
|
||||||
|
if tag == "" {
|
||||||
|
tag = graph.DEFAULTTAG
|
||||||
|
}
|
||||||
|
return job.Errorf("No such image: %s (tag: %s)", config.Image, tag)
|
||||||
|
}
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
if !container.Config.NetworkDisabled && daemon.SystemConfig().IPv4ForwardingDisabled {
|
||||||
|
job.Errorf("IPv4 forwarding is disabled.\n")
|
||||||
|
}
|
||||||
|
container.LogEvent("create")
|
||||||
|
// FIXME: this is necessary because daemon.Create might return a nil container
|
||||||
|
// with a non-nil error. This should not happen! Once it's fixed we
|
||||||
|
// can remove this workaround.
|
||||||
|
if container != nil {
|
||||||
|
job.Printf("%s\n", container.ID)
|
||||||
|
}
|
||||||
|
for _, warning := range buildWarnings {
|
||||||
|
job.Errorf("%s\n", warning)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a new container from the given configuration with a given name.
|
||||||
|
func (daemon *Daemon) Create(config *runconfig.Config, name string) (*Container, []string, error) {
|
||||||
|
var (
|
||||||
|
container *Container
|
||||||
|
warnings []string
|
||||||
|
)
|
||||||
|
|
||||||
|
img, err := daemon.repositories.LookupImage(config.Image)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if err := img.CheckDepth(); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if warnings, err = daemon.mergeAndVerifyConfig(config, img); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if container, err = daemon.newContainer(name, config, img); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if err := daemon.createRootfs(container, img); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if err := container.ToDisk(); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if err := daemon.Register(container); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return container, warnings, nil
|
||||||
|
}
|
||||||
+296
-274
@@ -4,41 +4,40 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/archive"
|
"github.com/docker/libcontainer/label"
|
||||||
"github.com/dotcloud/docker/daemon/execdriver"
|
|
||||||
"github.com/dotcloud/docker/daemon/execdriver/execdrivers"
|
|
||||||
"github.com/dotcloud/docker/daemon/execdriver/lxc"
|
|
||||||
"github.com/dotcloud/docker/daemon/graphdriver"
|
|
||||||
_ "github.com/dotcloud/docker/daemon/graphdriver/vfs"
|
|
||||||
_ "github.com/dotcloud/docker/daemon/networkdriver/bridge"
|
|
||||||
"github.com/dotcloud/docker/daemon/networkdriver/portallocator"
|
|
||||||
"github.com/dotcloud/docker/daemonconfig"
|
|
||||||
"github.com/dotcloud/docker/dockerversion"
|
|
||||||
"github.com/dotcloud/docker/engine"
|
|
||||||
"github.com/dotcloud/docker/graph"
|
|
||||||
"github.com/dotcloud/docker/image"
|
|
||||||
"github.com/dotcloud/docker/pkg/graphdb"
|
|
||||||
"github.com/dotcloud/docker/pkg/label"
|
|
||||||
"github.com/dotcloud/docker/pkg/namesgenerator"
|
|
||||||
"github.com/dotcloud/docker/pkg/networkfs/resolvconf"
|
|
||||||
"github.com/dotcloud/docker/pkg/selinux"
|
|
||||||
"github.com/dotcloud/docker/pkg/sysinfo"
|
|
||||||
"github.com/dotcloud/docker/runconfig"
|
|
||||||
"github.com/dotcloud/docker/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set the max depth to the aufs default that most
|
"github.com/docker/docker/archive"
|
||||||
// kernels are compiled with
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
// For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk
|
"github.com/docker/docker/daemon/execdriver/execdrivers"
|
||||||
const MaxImageDepth = 127
|
"github.com/docker/docker/daemon/execdriver/lxc"
|
||||||
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
|
_ "github.com/docker/docker/daemon/graphdriver/vfs"
|
||||||
|
_ "github.com/docker/docker/daemon/networkdriver/bridge"
|
||||||
|
"github.com/docker/docker/daemon/networkdriver/portallocator"
|
||||||
|
"github.com/docker/docker/dockerversion"
|
||||||
|
"github.com/docker/docker/engine"
|
||||||
|
"github.com/docker/docker/graph"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
|
"github.com/docker/docker/pkg/broadcastwriter"
|
||||||
|
"github.com/docker/docker/pkg/graphdb"
|
||||||
|
"github.com/docker/docker/pkg/log"
|
||||||
|
"github.com/docker/docker/pkg/namesgenerator"
|
||||||
|
"github.com/docker/docker/pkg/networkfs/resolvconf"
|
||||||
|
"github.com/docker/docker/pkg/parsers"
|
||||||
|
"github.com/docker/docker/pkg/parsers/kernel"
|
||||||
|
"github.com/docker/docker/pkg/sysinfo"
|
||||||
|
"github.com/docker/docker/pkg/truncindex"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultDns = []string{"8.8.8.8", "8.8.4.4"}
|
DefaultDns = []string{"8.8.8.8", "8.8.4.4"}
|
||||||
@@ -72,9 +71,11 @@ func (c *contStore) Delete(id string) {
|
|||||||
|
|
||||||
func (c *contStore) List() []*Container {
|
func (c *contStore) List() []*Container {
|
||||||
containers := new(History)
|
containers := new(History)
|
||||||
|
c.Lock()
|
||||||
for _, cont := range c.s {
|
for _, cont := range c.s {
|
||||||
containers.Add(cont)
|
containers.Add(cont)
|
||||||
}
|
}
|
||||||
|
c.Unlock()
|
||||||
containers.Sort()
|
containers.Sort()
|
||||||
return *containers
|
return *containers
|
||||||
}
|
}
|
||||||
@@ -85,12 +86,11 @@ type Daemon struct {
|
|||||||
containers *contStore
|
containers *contStore
|
||||||
graph *graph.Graph
|
graph *graph.Graph
|
||||||
repositories *graph.TagStore
|
repositories *graph.TagStore
|
||||||
idIndex *utils.TruncIndex
|
idIndex *truncindex.TruncIndex
|
||||||
sysInfo *sysinfo.SysInfo
|
sysInfo *sysinfo.SysInfo
|
||||||
volumes *graph.Graph
|
volumes *graph.Graph
|
||||||
srv Server
|
|
||||||
eng *engine.Engine
|
eng *engine.Engine
|
||||||
config *daemonconfig.Config
|
config *Config
|
||||||
containerGraph *graphdb.Database
|
containerGraph *graphdb.Database
|
||||||
driver graphdriver.Driver
|
driver graphdriver.Driver
|
||||||
execDriver execdriver.Driver
|
execDriver execdriver.Driver
|
||||||
@@ -98,27 +98,56 @@ type Daemon struct {
|
|||||||
|
|
||||||
// Install installs daemon capabilities to eng.
|
// Install installs daemon capabilities to eng.
|
||||||
func (daemon *Daemon) Install(eng *engine.Engine) error {
|
func (daemon *Daemon) Install(eng *engine.Engine) error {
|
||||||
return eng.Register("container_inspect", daemon.ContainerInspect)
|
// FIXME: rename "delete" to "rm" for consistency with the CLI command
|
||||||
}
|
// FIXME: rename ContainerDestroy to ContainerRm for consistency with the CLI command
|
||||||
|
// FIXME: remove ImageDelete's dependency on Daemon, then move to graph/
|
||||||
// List returns an array of all containers registered in the daemon.
|
for name, method := range map[string]engine.Handler{
|
||||||
func (daemon *Daemon) List() []*Container {
|
"attach": daemon.ContainerAttach,
|
||||||
return daemon.containers.List()
|
"build": daemon.CmdBuild,
|
||||||
|
"commit": daemon.ContainerCommit,
|
||||||
|
"container_changes": daemon.ContainerChanges,
|
||||||
|
"container_copy": daemon.ContainerCopy,
|
||||||
|
"container_inspect": daemon.ContainerInspect,
|
||||||
|
"containers": daemon.Containers,
|
||||||
|
"create": daemon.ContainerCreate,
|
||||||
|
"delete": daemon.ContainerDestroy,
|
||||||
|
"export": daemon.ContainerExport,
|
||||||
|
"info": daemon.CmdInfo,
|
||||||
|
"kill": daemon.ContainerKill,
|
||||||
|
"logs": daemon.ContainerLogs,
|
||||||
|
"pause": daemon.ContainerPause,
|
||||||
|
"resize": daemon.ContainerResize,
|
||||||
|
"restart": daemon.ContainerRestart,
|
||||||
|
"start": daemon.ContainerStart,
|
||||||
|
"stop": daemon.ContainerStop,
|
||||||
|
"top": daemon.ContainerTop,
|
||||||
|
"unpause": daemon.ContainerUnpause,
|
||||||
|
"wait": daemon.ContainerWait,
|
||||||
|
"image_delete": daemon.ImageDelete, // FIXME: see above
|
||||||
|
} {
|
||||||
|
if err := eng.Register(name, method); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := daemon.Repositories().Install(eng); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// FIXME: this hack is necessary for legacy integration tests to access
|
||||||
|
// the daemon object.
|
||||||
|
eng.Hack_SetGlobalVar("httpapi.daemon", daemon)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get looks for a container by the specified ID or name, and returns it.
|
// Get looks for a container by the specified ID or name, and returns it.
|
||||||
// If the container is not found, or if an error occurs, nil is returned.
|
// If the container is not found, or if an error occurs, nil is returned.
|
||||||
func (daemon *Daemon) Get(name string) *Container {
|
func (daemon *Daemon) Get(name string) *Container {
|
||||||
|
if id, err := daemon.idIndex.Get(name); err == nil {
|
||||||
|
return daemon.containers.Get(id)
|
||||||
|
}
|
||||||
if c, _ := daemon.GetByName(name); c != nil {
|
if c, _ := daemon.GetByName(name); c != nil {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
id, err := daemon.idIndex.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return daemon.containers.Get(id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists returns a true if a container of the specified ID or name exists,
|
// Exists returns a true if a container of the specified ID or name exists,
|
||||||
@@ -134,24 +163,28 @@ func (daemon *Daemon) containerRoot(id string) string {
|
|||||||
// Load reads the contents of a container from disk
|
// Load reads the contents of a container from disk
|
||||||
// This is typically done at startup.
|
// This is typically done at startup.
|
||||||
func (daemon *Daemon) load(id string) (*Container, error) {
|
func (daemon *Daemon) load(id string) (*Container, error) {
|
||||||
container := &Container{root: daemon.containerRoot(id)}
|
container := &Container{root: daemon.containerRoot(id), State: NewState()}
|
||||||
if err := container.FromDisk(); err != nil {
|
if err := container.FromDisk(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.ID != id {
|
if container.ID != id {
|
||||||
return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
|
return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
container.readHostConfig()
|
||||||
|
|
||||||
return container, nil
|
return container, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register makes a container object usable by the daemon as <container.ID>
|
// Register makes a container object usable by the daemon as <container.ID>
|
||||||
// This is a wrapper for register
|
// This is a wrapper for register
|
||||||
func (daemon *Daemon) Register(container *Container) error {
|
func (daemon *Daemon) Register(container *Container) error {
|
||||||
return daemon.register(container, true, nil)
|
return daemon.register(container, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// register makes a container object usable by the daemon as <container.ID>
|
// register makes a container object usable by the daemon as <container.ID>
|
||||||
func (daemon *Daemon) register(container *Container, updateSuffixarray bool, containersToStart *[]*Container) error {
|
func (daemon *Daemon) register(container *Container, updateSuffixarray bool) error {
|
||||||
if container.daemon != nil || daemon.Exists(container.ID) {
|
if container.daemon != nil || daemon.Exists(container.ID) {
|
||||||
return fmt.Errorf("Container is already loaded")
|
return fmt.Errorf("Container is already loaded")
|
||||||
}
|
}
|
||||||
@@ -165,8 +198,8 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool, con
|
|||||||
container.daemon = daemon
|
container.daemon = daemon
|
||||||
|
|
||||||
// Attach to stdout and stderr
|
// Attach to stdout and stderr
|
||||||
container.stderr = utils.NewWriteBroadcaster()
|
container.stderr = broadcastwriter.New()
|
||||||
container.stdout = utils.NewWriteBroadcaster()
|
container.stdout = broadcastwriter.New()
|
||||||
// Attach to stdin
|
// Attach to stdin
|
||||||
if container.Config.OpenStdin {
|
if container.Config.OpenStdin {
|
||||||
container.stdin, container.stdinPipe = io.Pipe()
|
container.stdin, container.stdinPipe = io.Pipe()
|
||||||
@@ -178,17 +211,13 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool, con
|
|||||||
|
|
||||||
// don't update the Suffixarray if we're starting up
|
// don't update the Suffixarray if we're starting up
|
||||||
// we'll waste time if we update it for every container
|
// we'll waste time if we update it for every container
|
||||||
if updateSuffixarray {
|
daemon.idIndex.Add(container.ID)
|
||||||
daemon.idIndex.Add(container.ID)
|
|
||||||
} else {
|
|
||||||
daemon.idIndex.AddWithoutSuffixarrayUpdate(container.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: if the container is supposed to be running but is not, auto restart it?
|
// FIXME: if the container is supposed to be running but is not, auto restart it?
|
||||||
// if so, then we need to restart monitor and init a new lock
|
// if so, then we need to restart monitor and init a new lock
|
||||||
// If the container is supposed to be running, make sure of it
|
// If the container is supposed to be running, make sure of it
|
||||||
if container.State.IsRunning() {
|
if container.State.IsRunning() {
|
||||||
utils.Debugf("killing old running container %s", container.ID)
|
log.Debugf("killing old running container %s", container.ID)
|
||||||
|
|
||||||
existingPid := container.State.Pid
|
existingPid := container.State.Pid
|
||||||
container.State.SetStopped(0)
|
container.State.SetStopped(0)
|
||||||
@@ -205,43 +234,29 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool, con
|
|||||||
var err error
|
var err error
|
||||||
cmd.Process, err = os.FindProcess(existingPid)
|
cmd.Process, err = os.FindProcess(existingPid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Debugf("cannot find existing process for %d", existingPid)
|
log.Debugf("cannot find existing process for %d", existingPid)
|
||||||
}
|
}
|
||||||
daemon.execDriver.Terminate(cmd)
|
daemon.execDriver.Terminate(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := container.Unmount(); err != nil {
|
if err := container.Unmount(); err != nil {
|
||||||
utils.Debugf("unmount error %s", err)
|
log.Debugf("unmount error %s", err)
|
||||||
}
|
}
|
||||||
if err := container.ToDisk(); err != nil {
|
if err := container.ToDisk(); err != nil {
|
||||||
utils.Debugf("saving stopped state to disk %s", err)
|
log.Debugf("saving stopped state to disk %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
info := daemon.execDriver.Info(container.ID)
|
info := daemon.execDriver.Info(container.ID)
|
||||||
if !info.IsRunning() {
|
if !info.IsRunning() {
|
||||||
utils.Debugf("Container %s was supposed to be running but is not.", container.ID)
|
log.Debugf("Container %s was supposed to be running but is not.", container.ID)
|
||||||
if daemon.config.AutoRestart {
|
|
||||||
utils.Debugf("Marking as restarting")
|
|
||||||
if err := container.Unmount(); err != nil {
|
|
||||||
utils.Debugf("restart unmount error %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if containersToStart != nil {
|
log.Debugf("Marking as stopped")
|
||||||
*containersToStart = append(*containersToStart, container)
|
|
||||||
}
|
container.State.SetStopped(-127)
|
||||||
} else {
|
if err := container.ToDisk(); err != nil {
|
||||||
utils.Debugf("Marking as stopped")
|
return err
|
||||||
container.State.SetStopped(-127)
|
|
||||||
if err := container.ToDisk(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// When the container is not running, we still initialize the waitLock
|
|
||||||
// chan and close it. Receiving on nil chan blocks whereas receiving on a
|
|
||||||
// closed chan does not. In this case we do not want to block.
|
|
||||||
container.waitLock = make(chan struct{})
|
|
||||||
close(container.waitLock)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -255,13 +270,13 @@ func (daemon *Daemon) ensureName(container *Container) error {
|
|||||||
container.Name = name
|
container.Name = name
|
||||||
|
|
||||||
if err := container.ToDisk(); err != nil {
|
if err := container.ToDisk(); err != nil {
|
||||||
utils.Debugf("Error saving container name %s", err)
|
log.Debugf("Error saving container name %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) LogToDisk(src *utils.WriteBroadcaster, dst, stream string) error {
|
func (daemon *Daemon) LogToDisk(src *broadcastwriter.BroadcastWriter, dst, stream string) error {
|
||||||
log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
|
log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -270,56 +285,15 @@ func (daemon *Daemon) LogToDisk(src *utils.WriteBroadcaster, dst, stream string)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
|
|
||||||
func (daemon *Daemon) Destroy(container *Container) error {
|
|
||||||
if container == nil {
|
|
||||||
return fmt.Errorf("The given container is <nil>")
|
|
||||||
}
|
|
||||||
|
|
||||||
element := daemon.containers.Get(container.ID)
|
|
||||||
if element == nil {
|
|
||||||
return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := container.Stop(3); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deregister the container before removing its directory, to avoid race conditions
|
|
||||||
daemon.idIndex.Delete(container.ID)
|
|
||||||
daemon.containers.Delete(container.ID)
|
|
||||||
|
|
||||||
if _, err := daemon.containerGraph.Purge(container.ID); err != nil {
|
|
||||||
utils.Debugf("Unable to remove container from link graph: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := daemon.driver.Remove(container.ID); err != nil {
|
|
||||||
return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.driver, container.ID, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
initID := fmt.Sprintf("%s-init", container.ID)
|
|
||||||
if err := daemon.driver.Remove(initID); err != nil {
|
|
||||||
return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", daemon.driver, initID, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.RemoveAll(container.root); err != nil {
|
|
||||||
return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
|
|
||||||
}
|
|
||||||
selinux.FreeLxcContexts(container.ProcessLabel)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (daemon *Daemon) restore() error {
|
func (daemon *Daemon) restore() error {
|
||||||
var (
|
var (
|
||||||
debug = (os.Getenv("DEBUG") != "" || os.Getenv("TEST") != "")
|
debug = (os.Getenv("DEBUG") != "" || os.Getenv("TEST") != "")
|
||||||
containers = make(map[string]*Container)
|
containers = make(map[string]*Container)
|
||||||
currentDriver = daemon.driver.String()
|
currentDriver = daemon.driver.String()
|
||||||
containersToStart = []*Container{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if !debug {
|
if !debug {
|
||||||
fmt.Printf("Loading containers: ")
|
log.Infof("Loading containers: ")
|
||||||
}
|
}
|
||||||
dir, err := ioutil.ReadDir(daemon.repository)
|
dir, err := ioutil.ReadDir(daemon.repository)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -333,29 +307,38 @@ func (daemon *Daemon) restore() error {
|
|||||||
fmt.Print(".")
|
fmt.Print(".")
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Errorf("Failed to load container %v: %v", id, err)
|
log.Errorf("Failed to load container %v: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore the container if it does not support the current driver being used by the graph
|
// Ignore the container if it does not support the current driver being used by the graph
|
||||||
if container.Driver == "" && currentDriver == "aufs" || container.Driver == currentDriver {
|
if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver {
|
||||||
utils.Debugf("Loaded container %v", container.ID)
|
log.Debugf("Loaded container %v", container.ID)
|
||||||
|
|
||||||
containers[container.ID] = container
|
containers[container.ID] = container
|
||||||
} else {
|
} else {
|
||||||
utils.Debugf("Cannot load container %s because it was created with another graph driver.", container.ID)
|
log.Debugf("Cannot load container %s because it was created with another graph driver.", container.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registeredContainers := []*Container{}
|
||||||
|
|
||||||
if entities := daemon.containerGraph.List("/", -1); entities != nil {
|
if entities := daemon.containerGraph.List("/", -1); entities != nil {
|
||||||
for _, p := range entities.Paths() {
|
for _, p := range entities.Paths() {
|
||||||
if !debug {
|
if !debug {
|
||||||
fmt.Print(".")
|
fmt.Print(".")
|
||||||
}
|
}
|
||||||
|
|
||||||
e := entities[p]
|
e := entities[p]
|
||||||
|
|
||||||
if container, ok := containers[e.ID()]; ok {
|
if container, ok := containers[e.ID()]; ok {
|
||||||
if err := daemon.register(container, false, &containersToStart); err != nil {
|
if err := daemon.register(container, false); err != nil {
|
||||||
utils.Debugf("Failed to register container %s: %s", container.ID, err)
|
log.Debugf("Failed to register container %s: %s", container.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registeredContainers = append(registeredContainers, container)
|
||||||
|
|
||||||
|
// delete from the map so that a new name is not automatically generated
|
||||||
delete(containers, e.ID())
|
delete(containers, e.ID())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,74 +349,40 @@ func (daemon *Daemon) restore() error {
|
|||||||
// Try to set the default name for a container if it exists prior to links
|
// Try to set the default name for a container if it exists prior to links
|
||||||
container.Name, err = daemon.generateNewName(container.ID)
|
container.Name, err = daemon.generateNewName(container.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Debugf("Setting default id - %s", err)
|
log.Debugf("Setting default id - %s", err)
|
||||||
}
|
}
|
||||||
if err := daemon.register(container, false, &containersToStart); err != nil {
|
|
||||||
utils.Debugf("Failed to register container %s: %s", container.ID, err)
|
if err := daemon.register(container, false); err != nil {
|
||||||
|
log.Debugf("Failed to register container %s: %s", container.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registeredContainers = append(registeredContainers, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
daemon.idIndex.UpdateSuffixarray()
|
// check the restart policy on the containers and restart any container with
|
||||||
|
// the restart policy of "always"
|
||||||
|
if daemon.config.AutoRestart {
|
||||||
|
log.Debugf("Restarting containers...")
|
||||||
|
|
||||||
for _, container := range containersToStart {
|
for _, container := range registeredContainers {
|
||||||
utils.Debugf("Starting container %d", container.ID)
|
if container.hostConfig.RestartPolicy.Name == "always" ||
|
||||||
if err := container.Start(); err != nil {
|
(container.hostConfig.RestartPolicy.Name == "on-failure" && container.State.ExitCode != 0) {
|
||||||
utils.Debugf("Failed to start container %s: %s", container.ID, err)
|
log.Debugf("Starting container %s", container.ID)
|
||||||
|
|
||||||
|
if err := container.Start(); err != nil {
|
||||||
|
log.Debugf("Failed to start container %s: %s", container.ID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !debug {
|
if !debug {
|
||||||
fmt.Printf(": done.\n")
|
log.Infof(": done.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new container from the given configuration with a given name.
|
|
||||||
func (daemon *Daemon) Create(config *runconfig.Config, name string) (*Container, []string, error) {
|
|
||||||
var (
|
|
||||||
container *Container
|
|
||||||
warnings []string
|
|
||||||
)
|
|
||||||
|
|
||||||
img, err := daemon.repositories.LookupImage(config.Image)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if err := daemon.checkImageDepth(img); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if warnings, err = daemon.mergeAndVerifyConfig(config, img); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if container, err = daemon.newContainer(name, config, img); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if err := daemon.createRootfs(container, img); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if err := container.ToDisk(); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if err := daemon.Register(container); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return container, warnings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (daemon *Daemon) checkImageDepth(img *image.Image) error {
|
|
||||||
// We add 2 layers to the depth because the container's rw and
|
|
||||||
// init layer add to the restriction
|
|
||||||
depth, err := img.Depth()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if depth+2 >= MaxImageDepth {
|
|
||||||
return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool {
|
func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool {
|
||||||
if config != nil {
|
if config != nil {
|
||||||
if config.PortSpecs != nil {
|
if config.PortSpecs != nil {
|
||||||
@@ -590,6 +539,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, img *i
|
|||||||
Name: name,
|
Name: name,
|
||||||
Driver: daemon.driver.String(),
|
Driver: daemon.driver.String(),
|
||||||
ExecDriver: daemon.execDriver.Name(),
|
ExecDriver: daemon.execDriver.Name(),
|
||||||
|
State: NewState(),
|
||||||
}
|
}
|
||||||
container.root = daemon.containerRoot(container.ID)
|
container.root = daemon.containerRoot(container.ID)
|
||||||
|
|
||||||
@@ -625,47 +575,6 @@ func (daemon *Daemon) createRootfs(container *Container, img *image.Image) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit creates a new filesystem image from the current state of a container.
|
|
||||||
// The image can optionally be tagged into a repository
|
|
||||||
func (daemon *Daemon) Commit(container *Container, repository, tag, comment, author string, config *runconfig.Config) (*image.Image, error) {
|
|
||||||
// FIXME: freeze the container before copying it to avoid data corruption?
|
|
||||||
if err := container.Mount(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer container.Unmount()
|
|
||||||
|
|
||||||
rwTar, err := container.ExportRw()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rwTar.Close()
|
|
||||||
|
|
||||||
// Create a new image from the container's base layers + a new layer from container changes
|
|
||||||
var (
|
|
||||||
containerID, containerImage string
|
|
||||||
containerConfig *runconfig.Config
|
|
||||||
)
|
|
||||||
|
|
||||||
if container != nil {
|
|
||||||
containerID = container.ID
|
|
||||||
containerImage = container.Image
|
|
||||||
containerConfig = container.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
img, err := daemon.graph.Create(rwTar, containerID, containerImage, comment, author, containerConfig, config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the image if needed
|
|
||||||
if repository != "" {
|
|
||||||
if err := daemon.repositories.Set(repository, tag, img.ID, true); err != nil {
|
|
||||||
return img, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return img, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetFullContainerName(name string) (string, error) {
|
func GetFullContainerName(name string) (string, error) {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return "", fmt.Errorf("Container name cannot be empty")
|
return "", fmt.Errorf("Container name cannot be empty")
|
||||||
@@ -726,7 +635,7 @@ func (daemon *Daemon) RegisterLink(parent, child *Container, alias string) error
|
|||||||
func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.HostConfig) error {
|
func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.HostConfig) error {
|
||||||
if hostConfig != nil && hostConfig.Links != nil {
|
if hostConfig != nil && hostConfig.Links != nil {
|
||||||
for _, l := range hostConfig.Links {
|
for _, l := range hostConfig.Links {
|
||||||
parts, err := utils.PartParser("name:alias", l)
|
parts, err := parsers.PartParser("name:alias", l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -753,7 +662,7 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: harmonize with NewGraph()
|
// FIXME: harmonize with NewGraph()
|
||||||
func NewDaemon(config *daemonconfig.Config, eng *engine.Engine) (*Daemon, error) {
|
func NewDaemon(config *Config, eng *engine.Engine) (*Daemon, error) {
|
||||||
daemon, err := NewDaemonFromDirectory(config, eng)
|
daemon, err := NewDaemonFromDirectory(config, eng)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -761,11 +670,71 @@ func NewDaemon(config *daemonconfig.Config, eng *engine.Engine) (*Daemon, error)
|
|||||||
return daemon, nil
|
return daemon, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*Daemon, error) {
|
func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error) {
|
||||||
if !config.EnableSelinuxSupport {
|
// Apply configuration defaults
|
||||||
selinux.SetDisabled()
|
if config.Mtu == 0 {
|
||||||
|
// FIXME: GetDefaultNetwork Mtu doesn't need to be public anymore
|
||||||
|
config.Mtu = GetDefaultNetworkMtu()
|
||||||
|
}
|
||||||
|
// Check for mutually incompatible config options
|
||||||
|
if config.BridgeIface != "" && config.BridgeIP != "" {
|
||||||
|
return nil, fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.")
|
||||||
|
}
|
||||||
|
if !config.EnableIptables && !config.InterContainerCommunication {
|
||||||
|
return nil, fmt.Errorf("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.")
|
||||||
|
}
|
||||||
|
// FIXME: DisableNetworkBidge doesn't need to be public anymore
|
||||||
|
config.DisableNetwork = config.BridgeIface == DisableNetworkBridge
|
||||||
|
|
||||||
|
// Claim the pidfile first, to avoid any and all unexpected race conditions.
|
||||||
|
// Some of the init doesn't need a pidfile lock - but let's not try to be smart.
|
||||||
|
if config.Pidfile != "" {
|
||||||
|
if err := utils.CreatePidFile(config.Pidfile); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
eng.OnShutdown(func() {
|
||||||
|
// Always release the pidfile last, just in case
|
||||||
|
utils.RemovePidFile(config.Pidfile)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that the system is supported and we have sufficient privileges
|
||||||
|
// FIXME: return errors instead of calling Fatal
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
log.Fatalf("The Docker daemon is only supported on linux")
|
||||||
|
}
|
||||||
|
if os.Geteuid() != 0 {
|
||||||
|
log.Fatalf("The Docker daemon needs to be run as root")
|
||||||
|
}
|
||||||
|
if err := checkKernelAndArch(); err != nil {
|
||||||
|
log.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up the TempDir to use a canonical path
|
||||||
|
tmp, err := utils.TempDir(config.Root)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to get the TempDir under %s: %s", config.Root, err)
|
||||||
|
}
|
||||||
|
realTmp, err := utils.ReadSymlinkedDirectory(tmp)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to get the full path to the TempDir (%s): %s", tmp, err)
|
||||||
|
}
|
||||||
|
os.Setenv("TMPDIR", realTmp)
|
||||||
|
if !config.EnableSelinuxSupport {
|
||||||
|
selinuxSetDisabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the canonical path to the Docker root directory
|
||||||
|
var realRoot string
|
||||||
|
if _, err := os.Stat(config.Root); err != nil && os.IsNotExist(err) {
|
||||||
|
realRoot = config.Root
|
||||||
|
} else {
|
||||||
|
realRoot, err = utils.ReadSymlinkedDirectory(config.Root)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to get the full path to root (%s): %s", config.Root, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.Root = realRoot
|
||||||
// Create the root directory if it doesn't exists
|
// Create the root directory if it doesn't exists
|
||||||
if err := os.MkdirAll(config.Root, 0700); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(config.Root, 0700); err != nil && !os.IsExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -779,7 +748,12 @@ func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*D
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
utils.Debugf("Using graph driver %s", driver)
|
log.Debugf("Using graph driver %s", driver)
|
||||||
|
|
||||||
|
// As Docker on btrfs and SELinux are incompatible at present, error on both being enabled
|
||||||
|
if config.EnableSelinuxSupport && driver.String() == "btrfs" {
|
||||||
|
return nil, fmt.Errorf("SELinux is not supported with the BTRFS graph driver!")
|
||||||
|
}
|
||||||
|
|
||||||
daemonRepo := path.Join(config.Root, "containers")
|
daemonRepo := path.Join(config.Root, "containers")
|
||||||
|
|
||||||
@@ -792,7 +766,7 @@ func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*D
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.Debugf("Creating images graph")
|
log.Debugf("Creating images graph")
|
||||||
g, err := graph.NewGraph(path.Join(config.Root, "graph"), driver)
|
g, err := graph.NewGraph(path.Join(config.Root, "graph"), driver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -804,12 +778,12 @@ func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*D
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
utils.Debugf("Creating volumes graph")
|
log.Debugf("Creating volumes graph")
|
||||||
volumes, err := graph.NewGraph(path.Join(config.Root, "volumes"), volumesDriver)
|
volumes, err := graph.NewGraph(path.Join(config.Root, "volumes"), volumesDriver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
utils.Debugf("Creating repository list")
|
log.Debugf("Creating repository list")
|
||||||
repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), g)
|
repositories, err := graph.NewTagStore(path.Join(config.Root, "repositories-"+driver.String()), g)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
|
return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
|
||||||
@@ -839,7 +813,7 @@ func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*D
|
|||||||
localCopy := path.Join(config.Root, "init", fmt.Sprintf("dockerinit-%s", dockerversion.VERSION))
|
localCopy := path.Join(config.Root, "init", fmt.Sprintf("dockerinit-%s", dockerversion.VERSION))
|
||||||
sysInitPath := utils.DockerInitPath(localCopy)
|
sysInitPath := utils.DockerInitPath(localCopy)
|
||||||
if sysInitPath == "" {
|
if sysInitPath == "" {
|
||||||
return nil, fmt.Errorf("Could not locate dockerinit: This usually means docker was built incorrectly. See http://docs.docker.io/en/latest/contributing/devenvironment for official build instructions.")
|
return nil, fmt.Errorf("Could not locate dockerinit: This usually means docker was built incorrectly. See http://docs.docker.com/contributing/devenvironment for official build instructions.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if sysInitPath != localCopy {
|
if sysInitPath != localCopy {
|
||||||
@@ -867,7 +841,7 @@ func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*D
|
|||||||
containers: &contStore{s: make(map[string]*Container)},
|
containers: &contStore{s: make(map[string]*Container)},
|
||||||
graph: g,
|
graph: g,
|
||||||
repositories: repositories,
|
repositories: repositories,
|
||||||
idIndex: utils.NewTruncIndex([]string{}),
|
idIndex: truncindex.NewTruncIndex([]string{}),
|
||||||
sysInfo: sysInfo,
|
sysInfo: sysInfo,
|
||||||
volumes: volumes,
|
volumes: volumes,
|
||||||
config: config,
|
config: config,
|
||||||
@@ -877,32 +851,51 @@ func NewDaemonFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (*D
|
|||||||
execDriver: ed,
|
execDriver: ed,
|
||||||
eng: eng,
|
eng: eng,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := daemon.checkLocaldns(); err != nil {
|
if err := daemon.checkLocaldns(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := daemon.restore(); err != nil {
|
if err := daemon.restore(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// Setup shutdown handlers
|
||||||
|
// FIXME: can these shutdown handlers be registered closer to their source?
|
||||||
|
eng.OnShutdown(func() {
|
||||||
|
// FIXME: if these cleanup steps can be called concurrently, register
|
||||||
|
// them as separate handlers to speed up total shutdown time
|
||||||
|
// FIXME: use engine logging instead of log.Errorf
|
||||||
|
if err := daemon.shutdown(); err != nil {
|
||||||
|
log.Errorf("daemon.shutdown(): %s", err)
|
||||||
|
}
|
||||||
|
if err := portallocator.ReleaseAll(); err != nil {
|
||||||
|
log.Errorf("portallocator.ReleaseAll(): %s", err)
|
||||||
|
}
|
||||||
|
if err := daemon.driver.Cleanup(); err != nil {
|
||||||
|
log.Errorf("daemon.driver.Cleanup(): %s", err.Error())
|
||||||
|
}
|
||||||
|
if err := daemon.containerGraph.Close(); err != nil {
|
||||||
|
log.Errorf("daemon.containerGraph.Close(): %s", err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return daemon, nil
|
return daemon, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) shutdown() error {
|
func (daemon *Daemon) shutdown() error {
|
||||||
group := sync.WaitGroup{}
|
group := sync.WaitGroup{}
|
||||||
utils.Debugf("starting clean shutdown of all containers...")
|
log.Debugf("starting clean shutdown of all containers...")
|
||||||
for _, container := range daemon.List() {
|
for _, container := range daemon.List() {
|
||||||
c := container
|
c := container
|
||||||
if c.State.IsRunning() {
|
if c.State.IsRunning() {
|
||||||
utils.Debugf("stopping %s", c.ID)
|
log.Debugf("stopping %s", c.ID)
|
||||||
group.Add(1)
|
group.Add(1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer group.Done()
|
defer group.Done()
|
||||||
if err := c.KillSig(15); err != nil {
|
if err := c.KillSig(15); err != nil {
|
||||||
utils.Debugf("kill 15 error for %s - %s", c.ID, err)
|
log.Debugf("kill 15 error for %s - %s", c.ID, err)
|
||||||
}
|
}
|
||||||
c.Wait()
|
c.State.WaitStop(-1 * time.Second)
|
||||||
utils.Debugf("container stopped %s", c.ID)
|
log.Debugf("container stopped %s", c.ID)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -911,30 +904,6 @@ func (daemon *Daemon) shutdown() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) Close() error {
|
|
||||||
errorsStrings := []string{}
|
|
||||||
if err := daemon.shutdown(); err != nil {
|
|
||||||
utils.Errorf("daemon.shutdown(): %s", err)
|
|
||||||
errorsStrings = append(errorsStrings, err.Error())
|
|
||||||
}
|
|
||||||
if err := portallocator.ReleaseAll(); err != nil {
|
|
||||||
utils.Errorf("portallocator.ReleaseAll(): %s", err)
|
|
||||||
errorsStrings = append(errorsStrings, err.Error())
|
|
||||||
}
|
|
||||||
if err := daemon.driver.Cleanup(); err != nil {
|
|
||||||
utils.Errorf("daemon.driver.Cleanup(): %s", err.Error())
|
|
||||||
errorsStrings = append(errorsStrings, err.Error())
|
|
||||||
}
|
|
||||||
if err := daemon.containerGraph.Close(); err != nil {
|
|
||||||
utils.Errorf("daemon.containerGraph.Close(): %s", err.Error())
|
|
||||||
errorsStrings = append(errorsStrings, err.Error())
|
|
||||||
}
|
|
||||||
if len(errorsStrings) > 0 {
|
|
||||||
return fmt.Errorf("%s", strings.Join(errorsStrings, ", "))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (daemon *Daemon) Mount(container *Container) error {
|
func (daemon *Daemon) Mount(container *Container) error {
|
||||||
dir, err := daemon.driver.Get(container.ID, container.GetMountLabel())
|
dir, err := daemon.driver.Get(container.ID, container.GetMountLabel())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1025,6 +994,8 @@ func (daemon *Daemon) Kill(c *Container, sig int) error {
|
|||||||
// from the content root, including images, volumes and
|
// from the content root, including images, volumes and
|
||||||
// container filesystems.
|
// container filesystems.
|
||||||
// Again: this will remove your entire docker daemon!
|
// Again: this will remove your entire docker daemon!
|
||||||
|
// FIXME: this is deprecated, and only used in legacy
|
||||||
|
// tests. Please remove.
|
||||||
func (daemon *Daemon) Nuke() error {
|
func (daemon *Daemon) Nuke() error {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
for _, container := range daemon.List() {
|
for _, container := range daemon.List() {
|
||||||
@@ -1035,7 +1006,6 @@ func (daemon *Daemon) Nuke() error {
|
|||||||
}(container)
|
}(container)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
daemon.Close()
|
|
||||||
|
|
||||||
return os.RemoveAll(daemon.config.Root)
|
return os.RemoveAll(daemon.config.Root)
|
||||||
}
|
}
|
||||||
@@ -1052,7 +1022,7 @@ func (daemon *Daemon) Repositories() *graph.TagStore {
|
|||||||
return daemon.repositories
|
return daemon.repositories
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) Config() *daemonconfig.Config {
|
func (daemon *Daemon) Config() *Config {
|
||||||
return daemon.config
|
return daemon.config
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1080,18 +1050,70 @@ func (daemon *Daemon) ContainerGraph() *graphdb.Database {
|
|||||||
return daemon.containerGraph
|
return daemon.containerGraph
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) SetServer(server Server) {
|
|
||||||
daemon.srv = server
|
|
||||||
}
|
|
||||||
|
|
||||||
func (daemon *Daemon) checkLocaldns() error {
|
func (daemon *Daemon) checkLocaldns() error {
|
||||||
resolvConf, err := resolvconf.Get()
|
resolvConf, err := resolvconf.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(daemon.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
|
if len(daemon.config.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
|
||||||
log.Printf("Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : %v\n", DefaultDns)
|
log.Infof("Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : %v", DefaultDns)
|
||||||
daemon.config.Dns = DefaultDns
|
daemon.config.Dns = DefaultDns
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*image.Image, error) {
|
||||||
|
// Retrieve all images
|
||||||
|
images, err := daemon.Graph().Map()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the tree in a map of map (map[parentId][childId])
|
||||||
|
imageMap := make(map[string]map[string]struct{})
|
||||||
|
for _, img := range images {
|
||||||
|
if _, exists := imageMap[img.Parent]; !exists {
|
||||||
|
imageMap[img.Parent] = make(map[string]struct{})
|
||||||
|
}
|
||||||
|
imageMap[img.Parent][img.ID] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop on the children of the given image and check the config
|
||||||
|
var match *image.Image
|
||||||
|
for elem := range imageMap[imgID] {
|
||||||
|
img, err := daemon.Graph().Get(elem)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if runconfig.Compare(&img.ContainerConfig, config) {
|
||||||
|
if match == nil || match.Created.Before(img.Created) {
|
||||||
|
match = img
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkKernelAndArch() error {
|
||||||
|
// Check for unsupported architectures
|
||||||
|
if runtime.GOARCH != "amd64" {
|
||||||
|
return fmt.Errorf("The Docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
|
||||||
|
}
|
||||||
|
// Check for unsupported kernel versions
|
||||||
|
// FIXME: it would be cleaner to not test for specific versions, but rather
|
||||||
|
// test for specific functionalities.
|
||||||
|
// Unfortunately we can't test for the feature "does not cause a kernel panic"
|
||||||
|
// without actually causing a kernel panic, so we need this workaround until
|
||||||
|
// the circumstances of pre-3.8 crashes are clearer.
|
||||||
|
// For details see http://github.com/docker/docker/issues/407
|
||||||
|
if k, err := kernel.GetKernelVersion(); err != nil {
|
||||||
|
log.Infof("WARNING: %s", err)
|
||||||
|
} else {
|
||||||
|
if kernel.CompareKernelVersion(k, &kernel.KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
|
||||||
|
if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
|
||||||
|
log.Infof("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,17 +3,17 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/dotcloud/docker/daemon/graphdriver"
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
"github.com/dotcloud/docker/daemon/graphdriver/aufs"
|
"github.com/docker/docker/daemon/graphdriver/aufs"
|
||||||
"github.com/dotcloud/docker/graph"
|
"github.com/docker/docker/graph"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/docker/docker/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Given the graphdriver ad, if it is aufs, then migrate it.
|
// Given the graphdriver ad, if it is aufs, then migrate it.
|
||||||
// If aufs driver is not built, this func is a noop.
|
// If aufs driver is not built, this func is a noop.
|
||||||
func migrateIfAufs(driver graphdriver.Driver, root string) error {
|
func migrateIfAufs(driver graphdriver.Driver, root string) error {
|
||||||
if ad, ok := driver.(*aufs.Driver); ok {
|
if ad, ok := driver.(*aufs.Driver); ok {
|
||||||
utils.Debugf("Migrating existing containers")
|
log.Debugf("Migrating existing containers")
|
||||||
if err := ad.Migrate(root, graph.SetupInitLayer); err != nil {
|
if err := ad.Migrate(root, graph.SetupInitLayer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "github.com/dotcloud/docker/daemon/graphdriver/btrfs"
|
_ "github.com/docker/docker/daemon/graphdriver/btrfs"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "github.com/dotcloud/docker/daemon/graphdriver/devmapper"
|
_ "github.com/docker/docker/daemon/graphdriver/devmapper"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/dotcloud/docker/daemon/graphdriver"
|
"github.com/docker/docker/daemon/graphdriver"
|
||||||
)
|
)
|
||||||
|
|
||||||
func migrateIfAufs(driver graphdriver.Driver, root string) error {
|
func migrateIfAufs(driver graphdriver.Driver, root string) error {
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/docker/engine"
|
||||||
|
"github.com/docker/docker/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FIXME: rename to ContainerRemove for consistency with the CLI command.
|
||||||
|
func (daemon *Daemon) ContainerDestroy(job *engine.Job) engine.Status {
|
||||||
|
if len(job.Args) != 1 {
|
||||||
|
return job.Errorf("Not enough arguments. Usage: %s CONTAINER\n", job.Name)
|
||||||
|
}
|
||||||
|
name := job.Args[0]
|
||||||
|
removeVolume := job.GetenvBool("removeVolume")
|
||||||
|
removeLink := job.GetenvBool("removeLink")
|
||||||
|
forceRemove := job.GetenvBool("forceRemove")
|
||||||
|
container := daemon.Get(name)
|
||||||
|
|
||||||
|
if removeLink {
|
||||||
|
if container == nil {
|
||||||
|
return job.Errorf("No such link: %s", name)
|
||||||
|
}
|
||||||
|
name, err := GetFullContainerName(name)
|
||||||
|
if err != nil {
|
||||||
|
job.Error(err)
|
||||||
|
}
|
||||||
|
parent, n := path.Split(name)
|
||||||
|
if parent == "/" {
|
||||||
|
return job.Errorf("Conflict, cannot remove the default name of the container")
|
||||||
|
}
|
||||||
|
pe := daemon.ContainerGraph().Get(parent)
|
||||||
|
if pe == nil {
|
||||||
|
return job.Errorf("Cannot get parent %s for name %s", parent, name)
|
||||||
|
}
|
||||||
|
parentContainer := daemon.Get(pe.ID())
|
||||||
|
|
||||||
|
if parentContainer != nil {
|
||||||
|
parentContainer.DisableLink(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := daemon.ContainerGraph().Delete(name); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
if container != nil {
|
||||||
|
if container.State.IsRunning() {
|
||||||
|
if forceRemove {
|
||||||
|
if err := container.Kill(); err != nil {
|
||||||
|
return job.Errorf("Could not kill running container, cannot remove - %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return job.Errorf("You cannot remove a running container. Stop the container before attempting removal or use -f")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := daemon.Destroy(container); err != nil {
|
||||||
|
return job.Errorf("Cannot destroy container %s: %s", name, err)
|
||||||
|
}
|
||||||
|
container.LogEvent("destroy")
|
||||||
|
|
||||||
|
if removeVolume {
|
||||||
|
var (
|
||||||
|
volumes = make(map[string]struct{})
|
||||||
|
binds = make(map[string]struct{})
|
||||||
|
usedVolumes = make(map[string]*Container)
|
||||||
|
)
|
||||||
|
|
||||||
|
// the volume id is always the base of the path
|
||||||
|
getVolumeId := func(p string) string {
|
||||||
|
return filepath.Base(strings.TrimSuffix(p, "/layer"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate bind map so that they can be skipped and not removed
|
||||||
|
for _, bind := range container.HostConfig().Binds {
|
||||||
|
source := strings.Split(bind, ":")[0]
|
||||||
|
// TODO: refactor all volume stuff, all of it
|
||||||
|
// it is very important that we eval the link or comparing the keys to container.Volumes will not work
|
||||||
|
//
|
||||||
|
// eval symlink can fail, ref #5244 if we receive an is not exist error we can ignore it
|
||||||
|
p, err := filepath.EvalSymlinks(source)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
if p != "" {
|
||||||
|
source = p
|
||||||
|
}
|
||||||
|
binds[source] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store all the deleted containers volumes
|
||||||
|
for _, volumeId := range container.Volumes {
|
||||||
|
// Skip the volumes mounted from external
|
||||||
|
// bind mounts here will will be evaluated for a symlink
|
||||||
|
if _, exists := binds[volumeId]; exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
volumeId = getVolumeId(volumeId)
|
||||||
|
volumes[volumeId] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve all volumes from all remaining containers
|
||||||
|
for _, container := range daemon.List() {
|
||||||
|
for _, containerVolumeId := range container.Volumes {
|
||||||
|
containerVolumeId = getVolumeId(containerVolumeId)
|
||||||
|
usedVolumes[containerVolumeId] = container
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for volumeId := range volumes {
|
||||||
|
// If the requested volu
|
||||||
|
if c, exists := usedVolumes[volumeId]; exists {
|
||||||
|
log.Infof("The volume %s is used by the container %s. Impossible to remove it. Skipping.", volumeId, c.ID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := daemon.Volumes().Delete(volumeId); err != nil {
|
||||||
|
return job.Errorf("Error calling volumes.Delete(%q): %v", volumeId, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return job.Errorf("No such container: %s", name)
|
||||||
|
}
|
||||||
|
return engine.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
|
||||||
|
// FIXME: rename to Rm for consistency with the CLI command
|
||||||
|
func (daemon *Daemon) Destroy(container *Container) error {
|
||||||
|
if container == nil {
|
||||||
|
return fmt.Errorf("The given container is <nil>")
|
||||||
|
}
|
||||||
|
|
||||||
|
element := daemon.containers.Get(container.ID)
|
||||||
|
if element == nil {
|
||||||
|
return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := container.Stop(3); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deregister the container before removing its directory, to avoid race conditions
|
||||||
|
daemon.idIndex.Delete(container.ID)
|
||||||
|
daemon.containers.Delete(container.ID)
|
||||||
|
|
||||||
|
if _, err := daemon.containerGraph.Purge(container.ID); err != nil {
|
||||||
|
log.Debugf("Unable to remove container from link graph: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := daemon.driver.Remove(container.ID); err != nil {
|
||||||
|
return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.driver, container.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
initID := fmt.Sprintf("%s-init", container.ID)
|
||||||
|
if err := daemon.driver.Remove(initID); err != nil {
|
||||||
|
return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", daemon.driver, initID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.RemoveAll(container.root); err != nil {
|
||||||
|
return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selinuxFreeLxcContexts(container.ProcessLabel)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
||||||
Guillaume J. Charmes <guillaume@docker.com> (@creack)
|
Victor Vieux <vieux@docker.com> (@vieux)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/pkg/libcontainer/devices"
|
"github.com/docker/libcontainer/devices"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Context is a generic key value pair that allows
|
// Context is a generic key value pair that allows
|
||||||
@@ -20,47 +20,7 @@ var (
|
|||||||
ErrDriverNotFound = errors.New("The requested docker init has not been found")
|
ErrDriverNotFound = errors.New("The requested docker init has not been found")
|
||||||
)
|
)
|
||||||
|
|
||||||
var dockerInitFcts map[string]InitFunc
|
type StartCallback func(*Command)
|
||||||
|
|
||||||
type (
|
|
||||||
StartCallback func(*Command)
|
|
||||||
InitFunc func(i *InitArgs) error
|
|
||||||
)
|
|
||||||
|
|
||||||
func RegisterInitFunc(name string, fct InitFunc) error {
|
|
||||||
if dockerInitFcts == nil {
|
|
||||||
dockerInitFcts = make(map[string]InitFunc)
|
|
||||||
}
|
|
||||||
if _, ok := dockerInitFcts[name]; ok {
|
|
||||||
return ErrDriverAlreadyRegistered
|
|
||||||
}
|
|
||||||
dockerInitFcts[name] = fct
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetInitFunc(name string) (InitFunc, error) {
|
|
||||||
fct, ok := dockerInitFcts[name]
|
|
||||||
if !ok {
|
|
||||||
return nil, ErrDriverNotFound
|
|
||||||
}
|
|
||||||
return fct, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Args provided to the init function for a driver
|
|
||||||
type InitArgs struct {
|
|
||||||
User string
|
|
||||||
Gateway string
|
|
||||||
Ip string
|
|
||||||
WorkDir string
|
|
||||||
Privileged bool
|
|
||||||
Env []string
|
|
||||||
Args []string
|
|
||||||
Mtu int
|
|
||||||
Driver string
|
|
||||||
Console string
|
|
||||||
Pipe int
|
|
||||||
Root string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Driver specific information based on
|
// Driver specific information based on
|
||||||
// processes registered with the driver
|
// processes registered with the driver
|
||||||
@@ -140,6 +100,8 @@ type Command struct {
|
|||||||
Mounts []Mount `json:"mounts"`
|
Mounts []Mount `json:"mounts"`
|
||||||
AllowedDevices []*devices.Device `json:"allowed_devices"`
|
AllowedDevices []*devices.Device `json:"allowed_devices"`
|
||||||
AutoCreatedDevices []*devices.Device `json:"autocreated_devices"`
|
AutoCreatedDevices []*devices.Device `json:"autocreated_devices"`
|
||||||
|
CapAdd []string `json:"cap_add"`
|
||||||
|
CapDrop []string `json:"cap_drop"`
|
||||||
|
|
||||||
Terminal Terminal `json:"-"` // standard or tty terminal
|
Terminal Terminal `json:"-"` // standard or tty terminal
|
||||||
Console string `json:"-"` // dev/console path
|
Console string `json:"-"` // dev/console path
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package execdrivers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker/daemon/execdriver"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
"github.com/dotcloud/docker/daemon/execdriver/lxc"
|
"github.com/docker/docker/daemon/execdriver/lxc"
|
||||||
"github.com/dotcloud/docker/daemon/execdriver/native"
|
"github.com/docker/docker/daemon/execdriver/native"
|
||||||
"github.com/dotcloud/docker/pkg/sysinfo"
|
"github.com/docker/docker/pkg/sysinfo"
|
||||||
"path"
|
"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ func NewDriver(name, root, initPath string, sysInfo *sysinfo.SysInfo) (execdrive
|
|||||||
// we want to give the lxc driver the full docker root because it needs
|
// we want to give the lxc driver the full docker root because it needs
|
||||||
// to access and write config and template files in /var/lib/docker/containers/*
|
// to access and write config and template files in /var/lib/docker/containers/*
|
||||||
// to be backwards compatible
|
// to be backwards compatible
|
||||||
return lxc.NewDriver(root, sysInfo.AppArmor)
|
return lxc.NewDriver(root, initPath, sysInfo.AppArmor)
|
||||||
case "native":
|
case "native":
|
||||||
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath)
|
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath)
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user