mirror of
https://github.com/moby/moby.git
synced 2026-01-15 18:02:03 +00:00
Compare commits
681 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
473c5701cb | ||
|
|
71e6babfa2 | ||
|
|
979cb4fd1e | ||
|
|
5f730ed857 | ||
|
|
68e914ce62 | ||
|
|
ce07fb6b0f | ||
|
|
1c44f35eb1 | ||
|
|
d1c1b391bc | ||
|
|
8b1112be3b | ||
|
|
855eb121aa | ||
|
|
eb04072245 | ||
|
|
c9e1a9e16d | ||
|
|
c9ae02ec59 | ||
|
|
19460e43f4 | ||
|
|
2a46799a87 | ||
|
|
aedc0ca2fd | ||
|
|
05516452d6 | ||
|
|
b53cef8425 | ||
|
|
b975e02386 | ||
|
|
aaff3d513e | ||
|
|
d4897c746f | ||
|
|
9287b8f99e | ||
|
|
7a02f05068 | ||
|
|
d4e2280b0f | ||
|
|
ecfddcf227 | ||
|
|
b0e4cf1ad2 | ||
|
|
dffbf0bc73 | ||
|
|
671a4aa4a4 | ||
|
|
46af6a6a41 | ||
|
|
87a53468b2 | ||
|
|
fe375a64db | ||
|
|
2e440580bc | ||
|
|
4122443aa7 | ||
|
|
e301d956b7 | ||
|
|
1c47c89d76 | ||
|
|
7e11df6273 | ||
|
|
b326920b3e | ||
|
|
56e99a8791 | ||
|
|
9e74ea8594 | ||
|
|
740fbef836 | ||
|
|
9dcb36dfa2 | ||
|
|
9f46122c94 | ||
|
|
951ffc056b | ||
|
|
ed6e849a1c | ||
|
|
e7e23df3f6 | ||
|
|
890f4c7aa5 | ||
|
|
30a5e20cc0 | ||
|
|
b3b30b0dcd | ||
|
|
2b0d7d2d86 | ||
|
|
2e544b1513 | ||
|
|
e5a90d46e3 | ||
|
|
018981111c | ||
|
|
092cba3727 | ||
|
|
f26487b568 | ||
|
|
fc0b5dbedb | ||
|
|
19d67e6e4a | ||
|
|
e29c142293 | ||
|
|
54f71fd84a | ||
|
|
516792001a | ||
|
|
14deb7d32c | ||
|
|
26ec0e71d1 | ||
|
|
5f696e6d48 | ||
|
|
0406faf887 | ||
|
|
f6bf85f99c | ||
|
|
0220459168 | ||
|
|
b47fa5a5d1 | ||
|
|
1a17bc6bc4 | ||
|
|
96b0320d5c | ||
|
|
905cf26b43 | ||
|
|
202df64a3b | ||
|
|
f709fd4e5b | ||
|
|
17e6f81948 | ||
|
|
778f9a86c4 | ||
|
|
fbc84e24aa | ||
|
|
553d56d456 | ||
|
|
6e2e808146 | ||
|
|
2556b7a70a | ||
|
|
14153795ba | ||
|
|
ec0e3fe4e2 | ||
|
|
d00e249c26 | ||
|
|
68f9fb9fd7 | ||
|
|
7b15b4a9b2 | ||
|
|
5e859cf3c1 | ||
|
|
96b87362e6 | ||
|
|
baf9288b78 | ||
|
|
0311ed7b1c | ||
|
|
c74f17e91e | ||
|
|
64856b7a24 | ||
|
|
c7f27f8c07 | ||
|
|
171745b261 | ||
|
|
73b9bdc6cb | ||
|
|
10d999d7ab | ||
|
|
ee1b5c5944 | ||
|
|
c4d731c24c | ||
|
|
1e0179589d | ||
|
|
c1c5d30ee4 | ||
|
|
2527cfcc49 | ||
|
|
de6c83de28 | ||
|
|
e84317c735 | ||
|
|
e25c046488 | ||
|
|
749f8bfee8 | ||
|
|
bdc5b347f5 | ||
|
|
370e8f25d2 | ||
|
|
e0c79df37d | ||
|
|
e3441eb64c | ||
|
|
8d0198c59d | ||
|
|
ed7aea3533 | ||
|
|
1b05e7aee7 | ||
|
|
c5147e6ab5 | ||
|
|
692c98895f | ||
|
|
4dc1b6221d | ||
|
|
1afa22733c | ||
|
|
c19f50acef | ||
|
|
6b70c68a7c | ||
|
|
909014d324 | ||
|
|
1fed3349fb | ||
|
|
2f445705f9 | ||
|
|
118e55df62 | ||
|
|
e6f89d1af5 | ||
|
|
819bcf8182 | ||
|
|
3fc246ded2 | ||
|
|
426c4cb747 | ||
|
|
017381aea4 | ||
|
|
214f42d541 | ||
|
|
a64c9357ca | ||
|
|
e7077f7d26 | ||
|
|
328775ea4f | ||
|
|
bf43d2a58d | ||
|
|
6a9670b044 | ||
|
|
53576a5bf9 | ||
|
|
6b4a835431 | ||
|
|
92155e37b3 | ||
|
|
7f396e8ea3 | ||
|
|
d9bda3080a | ||
|
|
007e492eac | ||
|
|
6bc7bc19df | ||
|
|
cbe6781501 | ||
|
|
5bf7901f5d | ||
|
|
06dae4eae5 | ||
|
|
a757b9bea9 | ||
|
|
f147d9b0d1 | ||
|
|
5537dbde84 | ||
|
|
732e19892d | ||
|
|
c9ffd3586c | ||
|
|
0b27583f82 | ||
|
|
3fdce9676b | ||
|
|
f0f020a579 | ||
|
|
3048e50434 | ||
|
|
b194252d80 | ||
|
|
e9751047e9 | ||
|
|
b875349fef | ||
|
|
b0970b629b | ||
|
|
e9779fd7df | ||
|
|
2dd2ac2c14 | ||
|
|
b60f411292 | ||
|
|
482534ff5f | ||
|
|
25810f3f47 | ||
|
|
37be2d4e9b | ||
|
|
880c12df7d | ||
|
|
ecd95a41d2 | ||
|
|
b9ee1c6880 | ||
|
|
0c16980468 | ||
|
|
1ec7869443 | ||
|
|
0fa35e2073 | ||
|
|
0be8ebd2a1 | ||
|
|
b4fd48ce32 | ||
|
|
9da299954f | ||
|
|
d4e6422212 | ||
|
|
954520f0ef | ||
|
|
23e9d30cea | ||
|
|
7bb3740386 | ||
|
|
ba79dde9d2 | ||
|
|
d621d74f64 | ||
|
|
78e4fa2caa | ||
|
|
f6d70d08a8 | ||
|
|
660a186e92 | ||
|
|
bd6c3ebed9 | ||
|
|
49bf474f9e | ||
|
|
d4f36676f0 | ||
|
|
197977d7fd | ||
|
|
8324f11b5a | ||
|
|
48a9e53d70 | ||
|
|
bca3b05950 | ||
|
|
4f914489e3 | ||
|
|
e62d984138 | ||
|
|
f6bc09c380 | ||
|
|
2f2d055013 | ||
|
|
fc82c4b391 | ||
|
|
e0c07ab799 | ||
|
|
acbad31dcd | ||
|
|
7e792d6ca9 | ||
|
|
c8083e8735 | ||
|
|
18fd3885c6 | ||
|
|
83b2782ea9 | ||
|
|
ece7e8ba27 | ||
|
|
4b2b0eb608 | ||
|
|
3fc1510dff | ||
|
|
340f288211 | ||
|
|
0b2a029e56 | ||
|
|
b7f412ef44 | ||
|
|
57c17882a3 | ||
|
|
25879cfa54 | ||
|
|
6c2fdb64d1 | ||
|
|
3fc150171f | ||
|
|
53ac375422 | ||
|
|
831eeb38f1 | ||
|
|
f27a297595 | ||
|
|
46af2edec2 | ||
|
|
f2260228a7 | ||
|
|
b2219f1bb5 | ||
|
|
7c8511236c | ||
|
|
b2e12626c7 | ||
|
|
57a63f1ed2 | ||
|
|
d3bffd978a | ||
|
|
40736b1848 | ||
|
|
462cd90f74 | ||
|
|
19cf2b3d5f | ||
|
|
1dded0dee4 | ||
|
|
9f0e745152 | ||
|
|
464b205956 | ||
|
|
3b2982a2bb | ||
|
|
d2e99882b9 | ||
|
|
25b967e149 | ||
|
|
eb5273edd4 | ||
|
|
46afc8f148 | ||
|
|
1afd41e4f7 | ||
|
|
43cc971d76 | ||
|
|
7f20c11c47 | ||
|
|
69240476d4 | ||
|
|
a46dbbded9 | ||
|
|
4e9dd0e51c | ||
|
|
84f25c7cb8 | ||
|
|
6841887132 | ||
|
|
aa5ac38f41 | ||
|
|
d01138c162 | ||
|
|
def75b2c2c | ||
|
|
ff7934faf2 | ||
|
|
045e9834a5 | ||
|
|
a2dc349c74 | ||
|
|
7cbc4cb7f2 | ||
|
|
e2b04a7818 | ||
|
|
ea00b14170 | ||
|
|
5903ead08e | ||
|
|
428ae70759 | ||
|
|
eefb2220c0 | ||
|
|
8b155a9109 | ||
|
|
c809c40647 | ||
|
|
994b3928f6 | ||
|
|
39b3e39c40 | ||
|
|
e7960584f2 | ||
|
|
c25a4762ef | ||
|
|
2c53989b4b | ||
|
|
1c5cb46649 | ||
|
|
97b0bb730e | ||
|
|
6d6c11dceb | ||
|
|
cf93b2b1c2 | ||
|
|
7a89c43a5e | ||
|
|
8afa73d280 | ||
|
|
d2a4a53f11 | ||
|
|
7d58f5fb88 | ||
|
|
73be1c098a | ||
|
|
c18f592150 | ||
|
|
f335200410 | ||
|
|
c5b5b4ea45 | ||
|
|
627bc91727 | ||
|
|
15293063ba | ||
|
|
b219698e75 | ||
|
|
1ca25a2e5e | ||
|
|
36c0b59149 | ||
|
|
3e0df05ec4 | ||
|
|
f02d46f050 | ||
|
|
25bbf8ab7c | ||
|
|
38d914cc96 | ||
|
|
bb37c67a90 | ||
|
|
a55a9b14d1 | ||
|
|
2039ea6adc | ||
|
|
05426c80d9 | ||
|
|
fed1b91bb4 | ||
|
|
88862e707a | ||
|
|
f3749c5a9c | ||
|
|
7d4318c83c | ||
|
|
05fba4af5f | ||
|
|
501083e82a | ||
|
|
4e5129c511 | ||
|
|
e460a5f45c | ||
|
|
c9a557765e | ||
|
|
1a865dd303 | ||
|
|
0c19045523 | ||
|
|
ecf7a631a6 | ||
|
|
f573d8b621 | ||
|
|
51020f7074 | ||
|
|
5391ce8ffa | ||
|
|
29f42b4036 | ||
|
|
caaee2ebab | ||
|
|
315c34953d | ||
|
|
b5d4f87612 | ||
|
|
dc05dfd30e | ||
|
|
f68d703a8c | ||
|
|
ce5ea47cb0 | ||
|
|
a260417927 | ||
|
|
a80251e8cd | ||
|
|
8f724a277a | ||
|
|
61dc897a30 | ||
|
|
5e7d2ab3b8 | ||
|
|
261f9b6243 | ||
|
|
45b441f4f9 | ||
|
|
61ce93a6f5 | ||
|
|
162ef5d158 | ||
|
|
37ea8104b0 | ||
|
|
1b521547f0 | ||
|
|
4d2be03b68 | ||
|
|
fa9618550a | ||
|
|
29861173e1 | ||
|
|
b7316e85c0 | ||
|
|
efdf7ae8f3 | ||
|
|
a4af72fc87 | ||
|
|
20dc482b10 | ||
|
|
8b31f217ff | ||
|
|
39c9f1c024 | ||
|
|
4e08d8ef03 | ||
|
|
47b838db40 | ||
|
|
1dd2e2f545 | ||
|
|
e65660da3d | ||
|
|
004ec96608 | ||
|
|
54e52b97f4 | ||
|
|
4aa72cb5a9 | ||
|
|
f59aa96e3d | ||
|
|
89c27499da | ||
|
|
4c65bf9a10 | ||
|
|
1149997787 | ||
|
|
1a86cbb031 | ||
|
|
80c3ed1c0c | ||
|
|
20d6f23b55 | ||
|
|
20a7e39728 | ||
|
|
09296e053d | ||
|
|
1f4dc1158c | ||
|
|
99eb943186 | ||
|
|
d8e435ab6c | ||
|
|
09cd31b128 | ||
|
|
85ae13f6d0 | ||
|
|
fcb58702bc | ||
|
|
cc855179cf | ||
|
|
9a6c5e14be | ||
|
|
0d575d1304 | ||
|
|
508d06752d | ||
|
|
159f4f14d7 | ||
|
|
de5fba3833 | ||
|
|
4b7bef26c5 | ||
|
|
cd7fea22f4 | ||
|
|
30b458a28c | ||
|
|
870beb70fb | ||
|
|
64aac182d6 | ||
|
|
4fba52a2f7 | ||
|
|
b18516e6ac | ||
|
|
6e08e2edcf | ||
|
|
c027e4a861 | ||
|
|
1c858abc96 | ||
|
|
3a571b72fd | ||
|
|
aa22b96457 | ||
|
|
d842cf6db6 | ||
|
|
213ee20706 | ||
|
|
f081b22a4a | ||
|
|
c84f43d63f | ||
|
|
be7d576f5d | ||
|
|
cca0132fcf | ||
|
|
9ecbaa77ae | ||
|
|
edd9c522b7 | ||
|
|
aca0bdab13 | ||
|
|
674cf8233d | ||
|
|
90a24f7bfd | ||
|
|
6c8bd56007 | ||
|
|
78f2dc90bf | ||
|
|
52b88ccc23 | ||
|
|
c9ec321e56 | ||
|
|
bec385cff0 | ||
|
|
0383913b65 | ||
|
|
51b83ae8fb | ||
|
|
ad794bba5b | ||
|
|
540758ee99 | ||
|
|
0f2364f73c | ||
|
|
6ce7fb23f5 | ||
|
|
fd7aee8fe0 | ||
|
|
e0d8cfaa7d | ||
|
|
62fdac59bd | ||
|
|
487fad2a2c | ||
|
|
e26de82e54 | ||
|
|
8bed67c368 | ||
|
|
728296b9ea | ||
|
|
696130c949 | ||
|
|
d1d6357beb | ||
|
|
4d92237de1 | ||
|
|
c0522e349a | ||
|
|
3ac2991ff8 | ||
|
|
69f3cb179e | ||
|
|
1b195847f4 | ||
|
|
877c2b5ac0 | ||
|
|
1b310cd47c | ||
|
|
3891c1f376 | ||
|
|
c015a2a1a6 | ||
|
|
2aed732d3a | ||
|
|
e509501437 | ||
|
|
e81d02e4cd | ||
|
|
8f961397f4 | ||
|
|
7ec079dbfd | ||
|
|
c49078c78d | ||
|
|
94f3ccc31e | ||
|
|
f1ea64fa07 | ||
|
|
64b41aa52a | ||
|
|
6df19c209f | ||
|
|
ecf889816c | ||
|
|
018f19f8c9 | ||
|
|
3477da0cdb | ||
|
|
90c3c389c4 | ||
|
|
6ad8328cb8 | ||
|
|
df71cee489 | ||
|
|
12aa5ea8b1 | ||
|
|
32e0ea346b | ||
|
|
68b88c8749 | ||
|
|
c31df2f3de | ||
|
|
f687616995 | ||
|
|
766e6ab07f | ||
|
|
fba707ee1f | ||
|
|
76f4793290 | ||
|
|
0e1721f09f | ||
|
|
2d0a198eb8 | ||
|
|
783e1a94b5 | ||
|
|
bb55c05ec1 | ||
|
|
6c466eadb7 | ||
|
|
f5c429bea2 | ||
|
|
1638b8f5c5 | ||
|
|
7c081219ac | ||
|
|
d55b0802cf | ||
|
|
d9329742d0 | ||
|
|
375e970991 | ||
|
|
30e5e0a781 | ||
|
|
50bcdc9de2 | ||
|
|
f8b981574c | ||
|
|
4609c728e3 | ||
|
|
5764fbb878 | ||
|
|
ee7d498364 | ||
|
|
79f153f49e | ||
|
|
bf711ea00e | ||
|
|
f5df634db7 | ||
|
|
5e5d02b9f5 | ||
|
|
51f1980e30 | ||
|
|
68cfaf216d | ||
|
|
0dd3ae8ed0 | ||
|
|
1f289dc411 | ||
|
|
005a5428ee | ||
|
|
b4567db876 | ||
|
|
1b187660c2 | ||
|
|
0669e372d2 | ||
|
|
a40ae77529 | ||
|
|
7c030bbd76 | ||
|
|
98132f7db9 | ||
|
|
a8c2248e6f | ||
|
|
97b0fd9fe3 | ||
|
|
936499e1ff | ||
|
|
8c56588d04 | ||
|
|
e3d03adc25 | ||
|
|
90dab0778c | ||
|
|
b998f95014 | ||
|
|
7c74809fe9 | ||
|
|
0f5d85371a | ||
|
|
bee66467cd | ||
|
|
d0fb24d853 | ||
|
|
4a0b7b215e | ||
|
|
bdde4d3be5 | ||
|
|
568a0a83a9 | ||
|
|
a903471bfc | ||
|
|
76d2619406 | ||
|
|
e0654b40b7 | ||
|
|
555f65587e | ||
|
|
25cb6a829b | ||
|
|
877207946a | ||
|
|
0e386515c8 | ||
|
|
7d7af6ad14 | ||
|
|
6622465645 | ||
|
|
bfbb2fdee9 | ||
|
|
663ca540ea | ||
|
|
4b230af83f | ||
|
|
99e1814731 | ||
|
|
3d27cb3d6f | ||
|
|
05a75a567a | ||
|
|
a2c9e625e6 | ||
|
|
edbe73670a | ||
|
|
234a8b9496 | ||
|
|
86ae5d2895 | ||
|
|
46cfeaf8ef | ||
|
|
d981bbc288 | ||
|
|
bc4219bd0c | ||
|
|
f70e7f840b | ||
|
|
35a87689e4 | ||
|
|
07fa269eee | ||
|
|
46b8a5fb57 | ||
|
|
fcc38c048c | ||
|
|
c75eeb4b7c | ||
|
|
10d2d8aefd | ||
|
|
d4d4edec2e | ||
|
|
833f3b3cf0 | ||
|
|
bbfd3a518b | ||
|
|
3decd08d7a | ||
|
|
1f9b3ef9e9 | ||
|
|
dba611d0f1 | ||
|
|
2a80a863ca | ||
|
|
01807b785f | ||
|
|
b82be871ab | ||
|
|
00fd466e00 | ||
|
|
f9f8a94f42 | ||
|
|
f531a8f06b | ||
|
|
44fe761b35 | ||
|
|
38b0c93954 | ||
|
|
aa6211e153 | ||
|
|
fad605e8c5 | ||
|
|
8738566853 | ||
|
|
f67b380325 | ||
|
|
520e601dc2 | ||
|
|
2ac34851ec | ||
|
|
a4aabe7286 | ||
|
|
e8b27e7dc7 | ||
|
|
54518a214d | ||
|
|
1053fdf27e | ||
|
|
43e6479fd4 | ||
|
|
af08f44640 | ||
|
|
faab09c1aa | ||
|
|
561f2b27cb | ||
|
|
63277b0aff | ||
|
|
8f66c5e731 | ||
|
|
a275ca2093 | ||
|
|
c28c63472a | ||
|
|
fb3c3d7eea | ||
|
|
40a56f29e2 | ||
|
|
9e35dea991 | ||
|
|
a65a2936ac | ||
|
|
24628fd7a0 | ||
|
|
9302b0f59c | ||
|
|
3168635120 | ||
|
|
f46b2fd604 | ||
|
|
702b03b6fc | ||
|
|
3f0aa9bceb | ||
|
|
3ab3f953d7 | ||
|
|
bab6bf1d5e | ||
|
|
8ebbeda5a8 | ||
|
|
ca51b2bf2c | ||
|
|
0403addc5f | ||
|
|
abc0eea899 | ||
|
|
b4c0b07d89 | ||
|
|
2d5f5287c3 | ||
|
|
41b92e6f36 | ||
|
|
8079cc8147 | ||
|
|
309662d03f | ||
|
|
e285a304db | ||
|
|
6f03b32968 | ||
|
|
2fb6810841 | ||
|
|
7e2522ec9f | ||
|
|
95398c33cc | ||
|
|
fcb64b6e08 | ||
|
|
2ecc8cd4bd | ||
|
|
bdc378e781 | ||
|
|
01aab8baa3 | ||
|
|
0a5732d1cf | ||
|
|
2737519f9a | ||
|
|
5c684ba099 | ||
|
|
ba9726350d | ||
|
|
05eb544ae2 | ||
|
|
040d4ebd58 | ||
|
|
db8991c957 | ||
|
|
20f3c552e0 | ||
|
|
a20820b05c | ||
|
|
68e99239d3 | ||
|
|
a47957d6f6 | ||
|
|
5b81d7e8b5 | ||
|
|
4acf6aa456 | ||
|
|
c707468415 | ||
|
|
a6e1ed7a51 | ||
|
|
2c832d7d66 | ||
|
|
f44e2dca56 | ||
|
|
c8e2552827 | ||
|
|
a0df810219 | ||
|
|
c050ee1917 | ||
|
|
cbff9474d2 | ||
|
|
f7ae8204cb | ||
|
|
2d632c34ce | ||
|
|
4edaaeb671 | ||
|
|
d63582c131 | ||
|
|
e773e0e654 | ||
|
|
fe8e347741 | ||
|
|
0d94260458 | ||
|
|
cdfde9ecc1 | ||
|
|
8e21480106 | ||
|
|
fd75cc462f | ||
|
|
c4fd597ab3 | ||
|
|
47ccfcc09f | ||
|
|
e3c24caf7a | ||
|
|
d4392659f7 | ||
|
|
649445a206 | ||
|
|
df8a5e48de | ||
|
|
c0ea2c8498 | ||
|
|
ce22bc39dc | ||
|
|
3e9dd55695 | ||
|
|
19d2e68fb8 | ||
|
|
530b7cb4a0 | ||
|
|
902774c871 | ||
|
|
1af49192e4 | ||
|
|
0be7359265 | ||
|
|
e013d7c543 | ||
|
|
5e7e260bac | ||
|
|
20dd2d1e4e | ||
|
|
3d43caf6f6 | ||
|
|
3f6e6b3f2d | ||
|
|
48c2da3cd5 | ||
|
|
7ef4feaf38 | ||
|
|
8b9b8bd930 | ||
|
|
cd587419d0 | ||
|
|
10ce88227d | ||
|
|
9f3c9209d0 | ||
|
|
f02e4e1900 | ||
|
|
411e0bdc8e | ||
|
|
51dc584445 | ||
|
|
78fe91c31c | ||
|
|
0b8f8876b9 | ||
|
|
c125c131d7 | ||
|
|
0a9521d321 | ||
|
|
88a45c4a1b | ||
|
|
22f0055e18 | ||
|
|
73bf1ec999 | ||
|
|
0269ac0494 | ||
|
|
f2eeaed8a3 | ||
|
|
43f1682cef | ||
|
|
94c4cfc209 | ||
|
|
dc71b1425e | ||
|
|
a51fe6b056 | ||
|
|
1841986d17 | ||
|
|
0d815d9bb7 | ||
|
|
3b93497fdb | ||
|
|
44bb0bb7f2 | ||
|
|
896e4f2d75 | ||
|
|
7154093e59 | ||
|
|
dbf1900e8c | ||
|
|
d1b1dea80f | ||
|
|
2dfa08bc50 | ||
|
|
f5afe63eb6 | ||
|
|
7a457451f6 | ||
|
|
5c69e4fa94 | ||
|
|
c102ab8711 | ||
|
|
44b5bcd744 | ||
|
|
0f254ab8b9 | ||
|
|
4d850bd49a | ||
|
|
7346a6aebd | ||
|
|
846b198dd7 | ||
|
|
6c3744f4fc | ||
|
|
6e10c4c8b2 | ||
|
|
a9bbf92b3f | ||
|
|
02c7b6ffad | ||
|
|
d3ae1d7bd6 | ||
|
|
b1c96a73a3 | ||
|
|
d114b7dc48 | ||
|
|
fd04a2db51 | ||
|
|
2c61e9c3bd | ||
|
|
9ed0bb2d0a | ||
|
|
ba5d2331d5 | ||
|
|
6ec7c7a89c | ||
|
|
a2575eb741 | ||
|
|
4b003634bc | ||
|
|
580343247e | ||
|
|
261958bfa8 | ||
|
|
2da971cf06 | ||
|
|
285915755c | ||
|
|
9798cdd632 | ||
|
|
5060ff0d8d | ||
|
|
4bfd3643da | ||
|
|
f3d628129e | ||
|
|
19c16fd95e | ||
|
|
89c4410799 | ||
|
|
70e7fcc595 | ||
|
|
03c8f0cda1 | ||
|
|
22c09cf902 | ||
|
|
8ac6b97189 | ||
|
|
a7a8fa0e6b | ||
|
|
16d4e6395e | ||
|
|
75fd88ba89 |
17
.DEREK.yml
17
.DEREK.yml
@@ -1,17 +0,0 @@
|
||||
curators:
|
||||
- aboch
|
||||
- alexellis
|
||||
- andrewhsu
|
||||
- anonymuse
|
||||
- chanwit
|
||||
- ehazlett
|
||||
- fntlnz
|
||||
- gianarb
|
||||
- mgoelzer
|
||||
- programmerq
|
||||
- rheinwein
|
||||
- ripcurld0
|
||||
- thajeztah
|
||||
|
||||
features:
|
||||
- comments
|
||||
@@ -2,6 +2,3 @@ bundles
|
||||
.gopath
|
||||
vendor/pkg
|
||||
.go-pkg-cache
|
||||
.git
|
||||
hack/integration-cli-on-swarm/integration-cli-on-swarm
|
||||
|
||||
|
||||
20
.github/CODEOWNERS
vendored
20
.github/CODEOWNERS
vendored
@@ -1,20 +0,0 @@
|
||||
# GitHub code owners
|
||||
# See https://help.github.com/articles/about-codeowners/
|
||||
#
|
||||
# KEEP THIS FILE SORTED. Order is important. Last match takes precedence.
|
||||
|
||||
builder/** @tonistiigi
|
||||
client/** @dnephin
|
||||
contrib/mkimage/** @tianon
|
||||
daemon/graphdriver/devmapper/** @rhvgoyal
|
||||
daemon/graphdriver/lcow/** @johnstep @jhowardmsft
|
||||
daemon/graphdriver/overlay/** @dmcgowan
|
||||
daemon/graphdriver/overlay2/** @dmcgowan
|
||||
daemon/graphdriver/windows/** @johnstep @jhowardmsft
|
||||
daemon/logger/awslogs/** @samuelkarp
|
||||
hack/** @tianon
|
||||
hack/integration-cli-on-swarm/** @AkihiroSuda
|
||||
integration-cli/** @vdemeester
|
||||
integration/** @vdemeester
|
||||
plugin/** @cpuguy83
|
||||
project/** @thaJeztah
|
||||
12
.github/ISSUE_TEMPLATE.md
vendored
12
.github/ISSUE_TEMPLATE.md
vendored
@@ -10,25 +10,19 @@ information within 7 days, we cannot debug your issue and will close it. We
|
||||
will, however, reopen it if you later provide the information.
|
||||
|
||||
For more information about reporting issues, see
|
||||
https://github.com/moby/moby/blob/master/CONTRIBUTING.md#reporting-other-issues
|
||||
https://github.com/docker/docker/blob/master/CONTRIBUTING.md#reporting-other-issues
|
||||
|
||||
---------------------------------------------------
|
||||
GENERAL SUPPORT INFORMATION
|
||||
---------------------------------------------------
|
||||
|
||||
The GitHub issue tracker is for bug reports and feature requests.
|
||||
General support for **docker** can be found at the following locations:
|
||||
General support can be found at the following locations:
|
||||
|
||||
- Docker Support Forums - https://forums.docker.com
|
||||
- Slack - community.docker.com #general channel
|
||||
- IRC - irc.freenode.net #docker channel
|
||||
- Post a question on StackOverflow, using the Docker tag
|
||||
|
||||
General support for **moby** can be found at the following locations:
|
||||
|
||||
- Moby Project Forums - https://forums.mobyproject.org
|
||||
- Slack - community.docker.com #moby-project channel
|
||||
- Post a question on StackOverflow, using the Moby tag
|
||||
|
||||
---------------------------------------------------
|
||||
BUG REPORT INFORMATION
|
||||
---------------------------------------------------
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,6 +1,6 @@
|
||||
<!--
|
||||
Please make sure you've read and understood our contributing guidelines;
|
||||
https://github.com/moby/moby/blob/master/CONTRIBUTING.md
|
||||
https://github.com/docker/docker/blob/master/CONTRIBUTING.md
|
||||
|
||||
** Make sure all your commits include a signature generated with `git commit -s` **
|
||||
|
||||
|
||||
19
.gitignore
vendored
19
.gitignore
vendored
@@ -4,7 +4,7 @@
|
||||
*.exe
|
||||
*.exe~
|
||||
*.orig
|
||||
test.main
|
||||
*.test
|
||||
.*.swp
|
||||
.DS_Store
|
||||
# a .bashrc may be added to customize the build environment
|
||||
@@ -15,10 +15,19 @@ test.main
|
||||
autogen/
|
||||
bundles/
|
||||
cmd/dockerd/dockerd
|
||||
contrib/builder/rpm/*/changelog
|
||||
cmd/docker/docker
|
||||
dockerversion/version_autogen.go
|
||||
dockerversion/version_autogen_unix.go
|
||||
docs/AWS_S3_BUCKET
|
||||
docs/GITCOMMIT
|
||||
docs/GIT_BRANCH
|
||||
docs/VERSION
|
||||
docs/_build
|
||||
docs/_static
|
||||
docs/_templates
|
||||
docs/changed-files
|
||||
# generated by man/md2man-all.sh
|
||||
man/man1
|
||||
man/man5
|
||||
man/man8
|
||||
vendor/pkg/
|
||||
hack/integration-cli-on-swarm/integration-cli-on-swarm
|
||||
coverage.txt
|
||||
profile.out
|
||||
|
||||
732
.mailmap
732
.mailmap
@@ -6,486 +6,270 @@
|
||||
#
|
||||
# For explanation on this file format: man git-shortlog
|
||||
|
||||
<21551195@zju.edu.cn> <hsinko@users.noreply.github.com>
|
||||
<mr.wrfly@gmail.com> <wrfly@users.noreply.github.com>
|
||||
Aaron L. Xu <liker.xu@foxmail.com>
|
||||
Abhinandan Prativadi <abhi@docker.com>
|
||||
Adrien Gallouët <adrien@gallouet.fr> <angt@users.noreply.github.com>
|
||||
Patrick Stapleton <github@gdi2290.com>
|
||||
Shishir Mahajan <shishir.mahajan@redhat.com> <smahajan@redhat.com>
|
||||
Erwin van der Koogh <info@erronis.nl>
|
||||
Ahmed Kamal <email.ahmedkamal@googlemail.com>
|
||||
Ahmet Alp Balkan <ahmetb@microsoft.com> <ahmetalpbalkan@gmail.com>
|
||||
AJ Bowen <aj@soulshake.net>
|
||||
AJ Bowen <aj@soulshake.net> <aj@gandi.net>
|
||||
AJ Bowen <aj@soulshake.net> <amy@gandi.net>
|
||||
Akihiro Matsushima <amatsusbit@gmail.com> <amatsus@users.noreply.github.com>
|
||||
Akihiro Suda <suda.akihiro@lab.ntt.co.jp> <suda.kyoto@gmail.com>
|
||||
Tejesh Mehta <tejesh.mehta@gmail.com> <tj@init.me>
|
||||
Cristian Staretu <cristian.staretu@gmail.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com> <unclejacksons@gmail.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com> <unclejack@users.noreply.github.com>
|
||||
Marcus Linke <marcus.linke@gmx.de>
|
||||
Aleksandrs Fadins <aleks@s-ko.net>
|
||||
Christopher Latham <sudosurootdev@gmail.com>
|
||||
Hu Keping <hukeping@huawei.com>
|
||||
Wayne Chang <wayne@neverfear.org>
|
||||
Chen Chao <cc272309126@gmail.com>
|
||||
Daehyeok Mun <daehyeok@gmail.com>
|
||||
<daehyeok@gmail.com> <daehyeok@daehyeokui-MacBook-Air.local>
|
||||
<jt@yadutaf.fr> <admin@jtlebi.fr>
|
||||
<jeff@docker.com> <jefferya@programmerq.net>
|
||||
<charles.hooper@dotcloud.com> <chooper@plumata.com>
|
||||
<daniel.mizyrycki@dotcloud.com> <daniel@dotcloud.com>
|
||||
<daniel.mizyrycki@dotcloud.com> <mzdaniel@glidelink.net>
|
||||
Guillaume J. Charmes <guillaume.charmes@docker.com> <charmes.guillaume@gmail.com>
|
||||
<guillaume.charmes@docker.com> <guillaume@dotcloud.com>
|
||||
<guillaume.charmes@docker.com> <guillaume@docker.com>
|
||||
<guillaume.charmes@docker.com> <guillaume.charmes@dotcloud.com>
|
||||
<guillaume.charmes@docker.com> <guillaume@charmes.net>
|
||||
<kencochrane@gmail.com> <KenCochrane@gmail.com>
|
||||
Thatcher Peskens <thatcher@docker.com>
|
||||
Thatcher Peskens <thatcher@docker.com> <thatcher@dotcloud.com>
|
||||
Thatcher Peskens <thatcher@docker.com> dhrp <thatcher@gmx.net>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com> jpetazzo <jerome.petazzoni@dotcloud.com>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com> <jp@enix.org>
|
||||
Joffrey F <joffrey@docker.com>
|
||||
Joffrey F <joffrey@docker.com> <joffrey@dotcloud.com>
|
||||
Joffrey F <joffrey@docker.com> <f.joffrey@gmail.com>
|
||||
Tim Terhorst <mynamewastaken+git@gmail.com>
|
||||
Andy Smith <github@anarkystic.com>
|
||||
<kalessin@kalessin.fr> <louis@dotcloud.com>
|
||||
<victor.vieux@docker.com> <victor.vieux@dotcloud.com>
|
||||
<victor.vieux@docker.com> <victor@dotcloud.com>
|
||||
<victor.vieux@docker.com> <dev@vvieux.com>
|
||||
<victor.vieux@docker.com> <victor@docker.com>
|
||||
<victor.vieux@docker.com> <vieux@docker.com>
|
||||
<victor.vieux@docker.com> <victorvieux@gmail.com>
|
||||
<dominik@honnef.co> <dominikh@fork-bomb.org>
|
||||
<ehanchrow@ine.com> <eric.hanchrow@gmail.com>
|
||||
Walter Stanish <walter@pratyeka.org>
|
||||
<daniel@gasienica.ch> <dgasienica@zynga.com>
|
||||
Roberto Hashioka <roberto_hashioka@hotmail.com>
|
||||
Konstantin Pelykh <kpelykh@zettaset.com>
|
||||
David Sissitka <me@dsissitka.com>
|
||||
Nolan Darilek <nolan@thewordnerd.info>
|
||||
<mastahyeti@gmail.com> <mastahyeti@users.noreply.github.com>
|
||||
Benoit Chesneau <bchesneau@gmail.com>
|
||||
Jordan Arentsen <blissdev@gmail.com>
|
||||
Daniel Garcia <daniel@danielgarcia.info>
|
||||
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
||||
Bhiraj Butala <abhiraj.butala@gmail.com>
|
||||
Faiz Khan <faizkhan00@gmail.com>
|
||||
Victor Lyuboslavsky <victor@victoreda.com>
|
||||
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
||||
Matthew Mueller <mattmuelle@gmail.com>
|
||||
<mosoni@ebay.com> <mohitsoni1989@gmail.com>
|
||||
Shih-Yuan Lee <fourdollars@gmail.com>
|
||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> root <root@vagrant-ubuntu-12.10.vagrantup.com>
|
||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||
<proppy@google.com> <proppy@aminche.com>
|
||||
<michael@docker.com> <michael@crosbymichael.com>
|
||||
<michael@docker.com> <crosby.michael@gmail.com>
|
||||
<michael@docker.com> <crosbymichael@gmail.com>
|
||||
<github@developersupport.net> <github@metaliveblog.com>
|
||||
<brandon@ifup.org> <brandon@ifup.co>
|
||||
<dano@spotify.com> <daniel.norberg@gmail.com>
|
||||
<danny@codeaholics.org> <Danny.Yates@mailonline.co.uk>
|
||||
<gurjeet@singh.im> <singh.gurjeet@gmail.com>
|
||||
<shawn@churchofgit.com> <shawnlandden@gmail.com>
|
||||
<sjoerd-github@linuxonly.nl> <sjoerd@byte.nl>
|
||||
<solomon@docker.com> <solomon.hykes@dotcloud.com>
|
||||
<solomon@docker.com> <solomon@dotcloud.com>
|
||||
<solomon@docker.com> <s@docker.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@fosiki.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@docker.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <¨SvenDowideit@home.org.au¨>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@home.org.au>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@users.noreply.github.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <sven@t440s.home.gateway>
|
||||
<alexl@redhat.com> <alexander.larsson@gmail.com>
|
||||
Alexander Morozov <lk4d4@docker.com> <lk4d4math@gmail.com>
|
||||
Alexander Morozov <lk4d4@docker.com>
|
||||
<git.nivoc@neverbox.com> <kuehnle@online.de>
|
||||
O.S. Tezer <ostezer@gmail.com>
|
||||
<ostezer@gmail.com> <ostezer@users.noreply.github.com>
|
||||
Roberto G. Hashioka <roberto.hashioka@docker.com> <roberto_hashioka@hotmail.com>
|
||||
<justin.p.simonelis@gmail.com> <justin.simonelis@PTS-JSIMON2.toronto.exclamation.com>
|
||||
<taim@bosboot.org> <maztaim@users.noreply.github.com>
|
||||
<viktor.vojnovski@amadeus.com> <vojnovski@gmail.com>
|
||||
<vbatts@redhat.com> <vbatts@hashbangbash.com>
|
||||
<altsysrq@gmail.com> <iamironbob@gmail.com>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com> <github@srid.name>
|
||||
Liang-Chi Hsieh <viirya@gmail.com>
|
||||
Aleksa Sarai <asarai@suse.de>
|
||||
Aleksa Sarai <asarai@suse.de> <asarai@suse.com>
|
||||
Aleksa Sarai <asarai@suse.de> <cyphar@cyphar.com>
|
||||
Aleksandrs Fadins <aleks@s-ko.net>
|
||||
Alessandro Boch <aboch@tetrationanalytics.com> <aboch@docker.com>
|
||||
Alex Chen <alexchenunix@gmail.com> <root@localhost.localdomain>
|
||||
Alex Ellis <alexellis2@gmail.com>
|
||||
Alex Goodman <wagoodman@gmail.com> <wagoodman@users.noreply.github.com>
|
||||
Alexander Larsson <alexl@redhat.com> <alexander.larsson@gmail.com>
|
||||
Alexander Morozov <lk4d4@docker.com>
|
||||
Alexander Morozov <lk4d4@docker.com> <lk4d4math@gmail.com>
|
||||
Alexandre Beslic <alexandre.beslic@gmail.com> <abronan@docker.com>
|
||||
Alicia Lauerman <alicia@eta.im> <allydevour@me.com>
|
||||
Allen Sun <allensun.shl@alibaba-inc.com> <allen.sun@daocloud.io>
|
||||
Allen Sun <allensun.shl@alibaba-inc.com> <shlallen1990@gmail.com>
|
||||
Andrew Weiss <andrew.weiss@docker.com> <andrew.weiss@microsoft.com>
|
||||
Andrew Weiss <andrew.weiss@docker.com> <andrew.weiss@outlook.com>
|
||||
André Martins <aanm90@gmail.com> <martins@noironetworks.com>
|
||||
Andy Rothfusz <github@developersupport.net> <github@metaliveblog.com>
|
||||
Andy Smith <github@anarkystic.com>
|
||||
Ankush Agarwal <ankushagarwal11@gmail.com> <ankushagarwal@users.noreply.github.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <amurdaca@redhat.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <me@runcom.ninja>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@linux.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@redhat.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@users.noreply.github.com>
|
||||
Anuj Bahuguna <anujbahuguna.dev@gmail.com>
|
||||
Anuj Bahuguna <anujbahuguna.dev@gmail.com> <abahuguna@fiberlink.com>
|
||||
Anusha Ragunathan <anusha.ragunathan@docker.com> <anusha@docker.com>
|
||||
Arnaud Porterie <arnaud.porterie@docker.com>
|
||||
Arnaud Porterie <arnaud.porterie@docker.com> <icecrime@gmail.com>
|
||||
Arthur Gautier <baloo@gandi.net> <superbaloo+registrations.github@superbaloo.net>
|
||||
Avi Miller <avi.miller@oracle.com> <avi.miller@gmail.com>
|
||||
Ben Bonnefoy <frenchben@docker.com>
|
||||
Ben Golub <ben.golub@dotcloud.com>
|
||||
Ben Toews <mastahyeti@gmail.com> <mastahyeti@users.noreply.github.com>
|
||||
Benoit Chesneau <bchesneau@gmail.com>
|
||||
Bhiraj Butala <abhiraj.butala@gmail.com>
|
||||
Bhumika Bayani <bhumikabayani@gmail.com>
|
||||
Bilal Amarni <bilal.amarni@gmail.com> <bamarni@users.noreply.github.com>
|
||||
Bill Wang <ozbillwang@gmail.com> <SydOps@users.noreply.github.com>
|
||||
Bin Liu <liubin0329@gmail.com>
|
||||
Bin Liu <liubin0329@gmail.com> <liubin0329@users.noreply.github.com>
|
||||
Bingshen Wang <bingshen.wbs@alibaba-inc.com>
|
||||
Boaz Shuster <ripcurld.github@gmail.com>
|
||||
Brandon Philips <brandon.philips@coreos.com> <brandon@ifup.co>
|
||||
Brandon Philips <brandon.philips@coreos.com> <brandon@ifup.org>
|
||||
Brent Salisbury <brent.salisbury@docker.com> <brent@docker.com>
|
||||
Brian Goff <cpuguy83@gmail.com>
|
||||
Brian Goff <cpuguy83@gmail.com> <bgoff@cpuguy83-mbp.home>
|
||||
Brian Goff <cpuguy83@gmail.com> <bgoff@cpuguy83-mbp.local>
|
||||
Chander Govindarajan <chandergovind@gmail.com>
|
||||
Chao Wang <wangchao.fnst@cn.fujitsu.com> <chaowang@localhost.localdomain>
|
||||
Charles Hooper <charles.hooper@dotcloud.com> <chooper@plumata.com>
|
||||
Chen Chao <cc272309126@gmail.com>
|
||||
Chen Chuanliang <chen.chuanliang@zte.com.cn>
|
||||
Chen Mingjie <chenmingjie0828@163.com>
|
||||
Chen Qiu <cheney-90@hotmail.com>
|
||||
Chen Qiu <cheney-90@hotmail.com> <21321229@zju.edu.cn>
|
||||
Chris Dias <cdias@microsoft.com>
|
||||
Chris McKinnel <chris.mckinnel@tangentlabs.co.uk>
|
||||
Christopher Biscardi <biscarch@sketcht.com>
|
||||
Christopher Latham <sudosurootdev@gmail.com>
|
||||
Chun Chen <ramichen@tencent.com> <chenchun.feed@gmail.com>
|
||||
Corbin Coleman <corbin.coleman@docker.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com> <unclejack@users.noreply.github.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com> <unclejacksons@gmail.com>
|
||||
CUI Wei <ghostplant@qq.com> cuiwei13 <cuiwei13@pku.edu.cn>
|
||||
Daehyeok Mun <daehyeok@gmail.com>
|
||||
Daehyeok Mun <daehyeok@gmail.com> <daehyeok@daehyeok-ui-MacBook-Air.local>
|
||||
Daehyeok Mun <daehyeok@gmail.com> <daehyeok@daehyeokui-MacBook-Air.local>
|
||||
Dan Feldman <danf@jfrog.com>
|
||||
Daniel Dao <dqminh@cloudflare.com>
|
||||
Daniel Dao <dqminh@cloudflare.com> <dqminh89@gmail.com>
|
||||
Daniel Garcia <daniel@danielgarcia.info>
|
||||
Daniel Gasienica <daniel@gasienica.ch> <dgasienica@zynga.com>
|
||||
Daniel Goosen <daniel.goosen@surveysampling.com> <djgoosen@users.noreply.github.com>
|
||||
Daniel Grunwell <mwgrunny@gmail.com>
|
||||
Daniel J Walsh <dwalsh@redhat.com>
|
||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> <daniel@dotcloud.com>
|
||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> <mzdaniel@glidelink.net>
|
||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> <root@vagrant-ubuntu-12.10.vagrantup.com>
|
||||
Daniel Nephin <dnephin@docker.com> <dnephin@gmail.com>
|
||||
Daniel Norberg <dano@spotify.com> <daniel.norberg@gmail.com>
|
||||
Daniel Watkins <daniel@daniel-watkins.co.uk>
|
||||
Danny Yates <danny@codeaholics.org> <Danny.Yates@mailonline.co.uk>
|
||||
Darren Shepherd <darren.s.shepherd@gmail.com> <darren@rancher.com>
|
||||
Dattatraya Kumbhar <dattatraya.kumbhar@gslab.com>
|
||||
Dave Goodchild <buddhamagnet@gmail.com>
|
||||
Dave Henderson <dhenderson@gmail.com> <Dave.Henderson@ca.ibm.com>
|
||||
Dave Tucker <dt@docker.com> <dave@dtucker.co.uk>
|
||||
David M. Karr <davidmichaelkarr@gmail.com>
|
||||
David Sheets <dsheets@docker.com> <sheets@alum.mit.edu>
|
||||
David Sissitka <me@dsissitka.com>
|
||||
David Williamson <david.williamson@docker.com> <davidwilliamson@users.noreply.github.com>
|
||||
Deshi Xiao <dxiao@redhat.com> <dsxiao@dataman-inc.com>
|
||||
Deshi Xiao <dxiao@redhat.com> <xiaods@gmail.com>
|
||||
Diego Siqueira <dieg0@live.com>
|
||||
Diogo Monica <diogo@docker.com> <diogo.monica@gmail.com>
|
||||
Dominik Honnef <dominik@honnef.co> <dominikh@fork-bomb.org>
|
||||
Doug Davis <dug@us.ibm.com> <duglin@users.noreply.github.com>
|
||||
Doug Tangren <d.tangren@gmail.com>
|
||||
Elan Ruusamäe <glen@pld-linux.org>
|
||||
Elan Ruusamäe <glen@pld-linux.org> <glen@delfi.ee>
|
||||
Elango Sivanandam <elango.siva@docker.com>
|
||||
Eric G. Noriega <enoriega@vizuri.com> <egnoriega@users.noreply.github.com>
|
||||
Eric Hanchrow <ehanchrow@ine.com> <eric.hanchrow@gmail.com>
|
||||
Eric Rosenberg <ehaydenr@gmail.com> <ehaydenr@users.noreply.github.com>
|
||||
Erica Windisch <erica@windisch.us> <eric@windisch.us>
|
||||
Erica Windisch <erica@windisch.us> <ewindisch@docker.com>
|
||||
Erik Hollensbe <github@hollensbe.org> <erik+github@hollensbe.org>
|
||||
Erwin van der Koogh <info@erronis.nl>
|
||||
Ethan Bell <ebgamer29@gmail.com>
|
||||
Euan Kemp <euan.kemp@coreos.com> <euank@amazon.com>
|
||||
Eugen Krizo <eugen.krizo@gmail.com>
|
||||
Evan Hazlett <ejhazlett@gmail.com> <ehazlett@users.noreply.github.com>
|
||||
Evelyn Xu <evelynhsu21@gmail.com>
|
||||
Evgeny Shmarnev <shmarnev@gmail.com>
|
||||
Faiz Khan <faizkhan00@gmail.com>
|
||||
Fangming Fang <fangming.fang@arm.com>
|
||||
Felix Hupfeld <felix@quobyte.com> <quofelix@users.noreply.github.com>
|
||||
Felix Ruess <felix.ruess@gmail.com> <felix.ruess@roboception.de>
|
||||
Feng Yan <fy2462@gmail.com>
|
||||
Fengtu Wang <wangfengtu@huawei.com> <wangfengtu@huawei.com>
|
||||
Francisco Carriedo <fcarriedo@gmail.com>
|
||||
Frank Rosquin <frank.rosquin+github@gmail.com> <frank.rosquin@gmail.com>
|
||||
Frederick F. Kautz IV <fkautz@redhat.com> <fkautz@alumni.cmu.edu>
|
||||
Gabriel Nicolas Avellaneda <avellaneda.gabriel@gmail.com>
|
||||
Gaetan de Villele <gdevillele@gmail.com>
|
||||
Gang Qiao <qiaohai8866@gmail.com> <1373319223@qq.com>
|
||||
George Kontridze <george@bugsnag.com>
|
||||
Gerwim Feiken <g.feiken@tfe.nl> <gerwim@gmail.com>
|
||||
Giampaolo Mancini <giampaolo@trampolineup.com>
|
||||
Gopikannan Venugopalsamy <gopikannan.venugopalsamy@gmail.com>
|
||||
Gou Rao <gou@portworx.com> <gourao@users.noreply.github.com>
|
||||
Greg Stephens <greg@udon.org>
|
||||
Guillaume J. Charmes <guillaume.charmes@docker.com> <charmes.guillaume@gmail.com>
|
||||
Guillaume J. Charmes <guillaume.charmes@docker.com> <guillaume.charmes@dotcloud.com>
|
||||
Guillaume J. Charmes <guillaume.charmes@docker.com> <guillaume@charmes.net>
|
||||
Guillaume J. Charmes <guillaume.charmes@docker.com> <guillaume@docker.com>
|
||||
Guillaume J. Charmes <guillaume.charmes@docker.com> <guillaume@dotcloud.com>
|
||||
Guri <odg0318@gmail.com>
|
||||
Gurjeet Singh <gurjeet@singh.im> <singh.gurjeet@gmail.com>
|
||||
Gustav Sinder <gustav.sinder@gmail.com>
|
||||
Günther Jungbluth <gunther@gameslabs.net>
|
||||
Hakan Özler <hakan.ozler@kodcu.com>
|
||||
Hao Shu Wei <haosw@cn.ibm.com>
|
||||
Hao Shu Wei <haosw@cn.ibm.com> <haoshuwei1989@163.com>
|
||||
Harald Albers <github@albersweb.de> <albers@users.noreply.github.com>
|
||||
Harold Cooper <hrldcpr@gmail.com>
|
||||
Harry Zhang <harryz@hyper.sh> <harryzhang@zju.edu.cn>
|
||||
Harry Zhang <harryz@hyper.sh> <resouer@163.com>
|
||||
Harry Zhang <harryz@hyper.sh> <resouer@gmail.com>
|
||||
Harry Zhang <resouer@163.com>
|
||||
Harshal Patil <harshal.patil@in.ibm.com> <harche@users.noreply.github.com>
|
||||
Helen Xie <chenjg@harmonycloud.cn>
|
||||
Hollie Teal <hollie@docker.com>
|
||||
Hollie Teal <hollie@docker.com> <hollie.teal@docker.com>
|
||||
Hollie Teal <hollie@docker.com> <hollietealok@users.noreply.github.com>
|
||||
Hu Keping <hukeping@huawei.com>
|
||||
Huu Nguyen <huu@prismskylabs.com> <whoshuu@gmail.com>
|
||||
Hyzhou Zhy <hyzhou.zhy@alibaba-inc.com>
|
||||
Hyzhou Zhy <hyzhou.zhy@alibaba-inc.com> <1187766782@qq.com>
|
||||
Ilya Khlopotov <ilya.khlopotov@gmail.com>
|
||||
Ivan Markin <sw@nogoegst.net> <twim@riseup.net>
|
||||
Jack Laxson <jackjrabbit@gmail.com>
|
||||
Jacob Atzen <jacob@jacobatzen.dk> <jatzen@gmail.com>
|
||||
Jacob Tomlinson <jacob@tom.linson.uk> <jacobtomlinson@users.noreply.github.com>
|
||||
Jaivish Kothari <janonymous.codevulture@gmail.com>
|
||||
Jamie Hannaford <jamie@limetree.org> <jamie.hannaford@rackspace.com>
|
||||
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||
Jean-Tiare Le Bigot <jt@yadutaf.fr> <admin@jtlebi.fr>
|
||||
Jeff Anderson <jeff@docker.com> <jefferya@programmerq.net>
|
||||
Jeff Nickoloff <jeff.nickoloff@gmail.com> <jeff@allingeek.com>
|
||||
Jeroen Franse <jeroenfranse@gmail.com>
|
||||
Jessica Frazelle <jessfraz@google.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <acidburn@docker.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <acidburn@google.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <jess@docker.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <jess@mesosphere.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <jfrazelle@users.noreply.github.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <me@jessfraz.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <princess@docker.com>
|
||||
Jim Galasyn <jim.galasyn@docker.com>
|
||||
Jiuyue Ma <majiuyue@huawei.com>
|
||||
Joey Geiger <jgeiger@gmail.com>
|
||||
Joffrey F <joffrey@docker.com>
|
||||
Joffrey F <joffrey@docker.com> <f.joffrey@gmail.com>
|
||||
Joffrey F <joffrey@docker.com> <joffrey@dotcloud.com>
|
||||
Johan Euphrosine <proppy@google.com> <proppy@aminche.com>
|
||||
John Harris <john@johnharris.io>
|
||||
John Howard (VM) <John.Howard@microsoft.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> <jhoward@microsoft.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> <jhoward@ntdev.microsoft.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> <jhowardmsft@users.noreply.github.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> <john.howard@microsoft.com>
|
||||
John Stephens <johnstep@docker.com> <johnstep@users.noreply.github.com>
|
||||
Jonathan Choy <jonathan.j.choy@gmail.com>
|
||||
Jonathan Choy <jonathan.j.choy@gmail.com> <oni@tetsujinlabs.com>
|
||||
Jon Surrell <jon.surrell@gmail.com> <jon.surrell@automattic.com>
|
||||
Jordan Arentsen <blissdev@gmail.com>
|
||||
Jordan Jennings <jjn2009@gmail.com> <jjn2009@users.noreply.github.com>
|
||||
Jorit Kleine-Möllhoff <joppich@bricknet.de> <joppich@users.noreply.github.com>
|
||||
Jose Diaz-Gonzalez <jose@seatgeek.com> <josegonzalez@users.noreply.github.com>
|
||||
Josh Bonczkowski <josh.bonczkowski@gmail.com>
|
||||
Josh Eveleth <joshe@opendns.com> <jeveleth@users.noreply.github.com>
|
||||
Josh Hawn <josh.hawn@docker.com> <jlhawn@berkeley.edu>
|
||||
Josh Horwitz <horwitz@addthis.com> <horwitzja@gmail.com>
|
||||
Josh Soref <jsoref@gmail.com> <jsoref@users.noreply.github.com>
|
||||
Josh Wilson <josh.wilson@fivestars.com> <jcwilson@users.noreply.github.com>
|
||||
Joyce Jang <mail@joycejang.com>
|
||||
Julien Bordellier <julienbordellier@gmail.com> <git@julienbordellier.com>
|
||||
Julien Bordellier <julienbordellier@gmail.com> <me@julienbordellier.com>
|
||||
Justin Cormack <justin.cormack@docker.com>
|
||||
Justin Cormack <justin.cormack@docker.com> <justin.cormack@unikernel.com>
|
||||
Justin Cormack <justin.cormack@docker.com> <justin@specialbusservice.com>
|
||||
Justin Simonelis <justin.p.simonelis@gmail.com> <justin.simonelis@PTS-JSIMON2.toronto.exclamation.com>
|
||||
Jérôme Petazzoni <jerome.petazzoni@docker.com> <jerome.petazzoni@dotcloud.com>
|
||||
Jérôme Petazzoni <jerome.petazzoni@docker.com> <jerome.petazzoni@gmail.com>
|
||||
Jérôme Petazzoni <jerome.petazzoni@docker.com> <jp@enix.org>
|
||||
K. Heller <pestophagous@gmail.com> <pestophagous@users.noreply.github.com>
|
||||
Kai Qiang Wu (Kennan) <wkq5325@gmail.com>
|
||||
Kai Qiang Wu (Kennan) <wkq5325@gmail.com> <wkqwu@cn.ibm.com>
|
||||
Kamil Domański <kamil@domanski.co>
|
||||
Kamjar Gerami <kami.gerami@gmail.com>
|
||||
Ken Cochrane <kencochrane@gmail.com> <KenCochrane@gmail.com>
|
||||
Ken Herner <kherner@progress.com> <chosenken@gmail.com>
|
||||
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
||||
Kevin Feyrer <kevin.feyrer@btinternet.com> <kevinfeyrer@users.noreply.github.com>
|
||||
Kevin Kern <kaiwentan@harmonycloud.cn>
|
||||
Kevin Meredith <kevin.m.meredith@gmail.com>
|
||||
Kir Kolyshkin <kolyshkin@gmail.com>
|
||||
Kir Kolyshkin <kolyshkin@gmail.com> <kir@openvz.org>
|
||||
Kir Kolyshkin <kolyshkin@gmail.com> <kolyshkin@users.noreply.github.com>
|
||||
Konrad Kleine <konrad.wilhelm.kleine@gmail.com> <kwk@users.noreply.github.com>
|
||||
Konstantin Gribov <grossws@gmail.com>
|
||||
Konstantin Pelykh <kpelykh@zettaset.com>
|
||||
Kotaro Yoshimatsu <kotaro.yoshimatsu@gmail.com>
|
||||
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp> <kunal.kushwaha@gmail.com>
|
||||
Lajos Papp <lajos.papp@sequenceiq.com> <lalyos@yahoo.com>
|
||||
Lei Jitang <leijitang@huawei.com>
|
||||
Lei Jitang <leijitang@huawei.com> <leijitang@gmail.com>
|
||||
Liang Mingqiang <mqliang.zju@gmail.com>
|
||||
Liang-Chi Hsieh <viirya@gmail.com>
|
||||
Liao Qingwei <liaoqingwei@huawei.com>
|
||||
Linus Heckemann <lheckemann@twig-world.com>
|
||||
Linus Heckemann <lheckemann@twig-world.com> <anonymouse2048@gmail.com>
|
||||
Lokesh Mandvekar <lsm5@fedoraproject.org> <lsm5@redhat.com>
|
||||
Lorenzo Fontana <lo@linux.com> <fontanalorenzo@me.com>
|
||||
Louis Opter <kalessin@kalessin.fr>
|
||||
Louis Opter <kalessin@kalessin.fr> <louis@dotcloud.com>
|
||||
Luca Favatella <luca.favatella@erlang-solutions.com> <lucafavatella@users.noreply.github.com>
|
||||
Luke Marsden <me@lukemarsden.net> <luke@digital-crocus.com>
|
||||
Lyn <energylyn@zju.edu.cn>
|
||||
Lynda O'Leary <lyndaoleary29@gmail.com>
|
||||
Lynda O'Leary <lyndaoleary29@gmail.com> <lyndaoleary@hotmail.com>
|
||||
Ma Müller <mueller-ma@users.noreply.github.com>
|
||||
Madhan Raj Mookkandy <MadhanRaj.Mookkandy@microsoft.com> <madhanm@microsoft.com>
|
||||
Madhu Venugopal <madhu@socketplane.io> <madhu@docker.com>
|
||||
Mageee <fangpuyi@foxmail.com> <21521230.zju.edu.cn>
|
||||
Mansi Nahar <mmn4185@rit.edu> <mansi.nahar@macbookpro-mansinahar.local>
|
||||
Mansi Nahar <mmn4185@rit.edu> <mansinahar@users.noreply.github.com>
|
||||
Marc Abramowitz <marc@marc-abramowitz.com> <msabramo@gmail.com>
|
||||
Marcelo Horacio Fortino <info@fortinux.com> <fortinux@users.noreply.github.com>
|
||||
Marcus Linke <marcus.linke@gmx.de>
|
||||
Marianna Tessel <mtesselh@gmail.com>
|
||||
Mark Oates <fl0yd@me.com>
|
||||
Markan Patel <mpatel678@gmail.com>
|
||||
Markus Kortlang <hyp3rdino@googlemail.com> <markus.kortlang@lhsystems.com>
|
||||
Martin Redmond <redmond.martin@gmail.com> <martin@tinychat.com>
|
||||
Martin Redmond <redmond.martin@gmail.com> <xgithub@redmond5.com>
|
||||
Mary Anthony <mary.anthony@docker.com> <mary@docker.com>
|
||||
Mary Anthony <mary.anthony@docker.com> <moxieandmore@gmail.com>
|
||||
Mary Anthony <mary.anthony@docker.com> moxiegirl <mary@docker.com>
|
||||
Masato Ohba <over.rye@gmail.com>
|
||||
Matt Bentley <matt.bentley@docker.com> <mbentley@mbentley.net>
|
||||
Matt Schurenko <matt.schurenko@gmail.com>
|
||||
Matt Williams <mattyw@me.com>
|
||||
Matt Williams <mattyw@me.com> <gh@mattyw.net>
|
||||
Matthew Heon <mheon@redhat.com> <mheon@mheonlaptop.redhat.com>
|
||||
Matthew Mosesohn <raytrac3r@gmail.com>
|
||||
Matthew Mueller <mattmuelle@gmail.com>
|
||||
Matthias Kühnle <git.nivoc@neverbox.com> <kuehnle@online.de>
|
||||
Mauricio Garavaglia <mauricio@medallia.com> <mauriciogaravaglia@gmail.com>
|
||||
Michael Crosby <michael@docker.com> <crosby.michael@gmail.com>
|
||||
Michael Crosby <michael@docker.com> <crosbymichael@gmail.com>
|
||||
Michael Crosby <michael@docker.com> <michael@crosbymichael.com>
|
||||
Michał Gryko <github@odkurzacz.org>
|
||||
Michael Hudson-Doyle <michael.hudson@canonical.com> <michael.hudson@linaro.org>
|
||||
Michael Huettermann <michael@huettermann.net>
|
||||
Michael Käufl <docker@c.michael-kaeufl.de> <michael-k@users.noreply.github.com>
|
||||
Michael Nussbaum <michael.nussbaum@getbraintree.com>
|
||||
Michael Nussbaum <michael.nussbaum@getbraintree.com> <code@getbraintree.com>
|
||||
Michael Spetsiotis <michael_spets@hotmail.com>
|
||||
Michal Minář <miminar@redhat.com>
|
||||
Miguel Angel Alvarez Cabrerizo <doncicuto@gmail.com> <30386061+doncicuto@users.noreply.github.com>
|
||||
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
||||
Mihai Borobocea <MihaiBorob@gmail.com> <MihaiBorobocea@gmail.com>
|
||||
Mike Casas <mkcsas0@gmail.com> <mikecasas@users.noreply.github.com>
|
||||
Mike Goelzer <mike.goelzer@docker.com> <mgoelzer@docker.com>
|
||||
Milind Chawre <milindchawre@gmail.com>
|
||||
Misty Stanley-Jones <misty@docker.com> <misty@apache.org>
|
||||
Mohit Soni <mosoni@ebay.com> <mohitsoni1989@gmail.com>
|
||||
Moorthy RS <rsmoorthy@gmail.com> <rsmoorthy@users.noreply.github.com>
|
||||
Moysés Borges <moysesb@gmail.com>
|
||||
Moysés Borges <moysesb@gmail.com> <moyses.furtado@wplex.com.br>
|
||||
Nace Oroz <orkica@gmail.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>
|
||||
Neil Horman <nhorman@tuxdriver.com> <nhorman@hmswarspite.think-freely.org>
|
||||
Nick Russo <nicholasjamesrusso@gmail.com> <nicholasrusso@icloud.com>
|
||||
Nicolas Borboën <ponsfrilus@gmail.com> <ponsfrilus@users.noreply.github.com>
|
||||
Nigel Poulton <nigelpoulton@hotmail.com>
|
||||
Nik Nyby <nikolas@gnu.org> <nnyby@columbia.edu>
|
||||
Nolan Darilek <nolan@thewordnerd.info>
|
||||
O.S. Tezer <ostezer@gmail.com>
|
||||
O.S. Tezer <ostezer@gmail.com> <ostezer@users.noreply.github.com>
|
||||
Oh Jinkyun <tintypemolly@gmail.com> <tintypemolly@Ohui-MacBook-Pro.local>
|
||||
Ouyang Liduo <oyld0210@163.com>
|
||||
Patrick Stapleton <github@gdi2290.com>
|
||||
Paul Liljenberg <liljenberg.paul@gmail.com> <letters@paulnotcom.se>
|
||||
Pavel Tikhomirov <ptikhomirov@virtuozzo.com> <ptikhomirov@parallels.com>
|
||||
Pawel Konczalski <mail@konczalski.de>
|
||||
Peter Choi <phkchoi89@gmail.com> <reikani@Peters-MacBook-Pro.local>
|
||||
Peter Dave Hello <hsu@peterdavehello.org> <PeterDaveHello@users.noreply.github.com>
|
||||
Peter Jaffe <pjaffe@nevo.com>
|
||||
Peter Nagy <xificurC@gmail.com> <pnagy@gratex.com>
|
||||
Peter Waller <p@pwaller.net> <peter@scraperwiki.com>
|
||||
Phil Estes <estesp@linux.vnet.ibm.com> <estesp@gmail.com>
|
||||
Philip Alexander Etling <paetling@gmail.com>
|
||||
Philipp Gillé <philipp.gille@gmail.com> <philippgille@users.noreply.github.com>
|
||||
Qiang Huang <h.huangqiang@huawei.com>
|
||||
Qiang Huang <h.huangqiang@huawei.com> <qhuang@10.0.2.15>
|
||||
Ray Tsang <rayt@google.com> <saturnism@users.noreply.github.com>
|
||||
Renaud Gaubert <rgaubert@nvidia.com> <renaud.gaubert@gmail.com>
|
||||
Robert Terhaar <rterhaar@atlanticdynamic.com> <robbyt@users.noreply.github.com>
|
||||
Roberto G. Hashioka <roberto.hashioka@docker.com> <roberto_hashioka@hotmail.com>
|
||||
Roberto Muñoz Fernández <robertomf@gmail.com> <roberto.munoz.fernandez.contractor@bbva.com>
|
||||
Roman Dudin <katrmr@gmail.com> <decadent@users.noreply.github.com>
|
||||
Ross Boucher <rboucher@gmail.com>
|
||||
Runshen Zhu <runshen.zhu@gmail.com>
|
||||
Ryan Stelly <ryan.stelly@live.com>
|
||||
Sakeven Jiang <jc5930@sina.cn>
|
||||
Sandeep Bansal <sabansal@microsoft.com>
|
||||
Sandeep Bansal <sabansal@microsoft.com> <msabansal@microsoft.com>
|
||||
Sargun Dhillon <sargun@netflix.com> <sargun@sargun.me>
|
||||
Sean Lee <seanlee@tw.ibm.com> <scaleoutsean@users.noreply.github.com>
|
||||
Sebastiaan van Stijn <github@gone.nl> <sebastiaan@ws-key-sebas3.dpi1.dpi>
|
||||
Sebastiaan van Stijn <github@gone.nl> <thaJeztah@users.noreply.github.com>
|
||||
Shaun Kaasten <shaunk@gmail.com>
|
||||
Shawn Landden <shawn@churchofgit.com> <shawnlandden@gmail.com>
|
||||
Shengbo Song <thomassong@tencent.com>
|
||||
Shengbo Song <thomassong@tencent.com> <mymneo@163.com>
|
||||
Shih-Yuan Lee <fourdollars@gmail.com>
|
||||
Shishir Mahajan <shishir.mahajan@redhat.com> <smahajan@redhat.com>
|
||||
Shukui Yang <yangshukui@huawei.com>
|
||||
Shuwei Hao <haosw@cn.ibm.com>
|
||||
Shuwei Hao <haosw@cn.ibm.com> <haoshuwei24@gmail.com>
|
||||
Sidhartha Mani <sidharthamn@gmail.com>
|
||||
Sjoerd Langkemper <sjoerd-github@linuxonly.nl> <sjoerd@byte.nl>
|
||||
Solomon Hykes <solomon@docker.com> <s@docker.com>
|
||||
Solomon Hykes <solomon@docker.com> <solomon.hykes@dotcloud.com>
|
||||
Solomon Hykes <solomon@docker.com> <solomon@dotcloud.com>
|
||||
Soshi Katsuta <soshi.katsuta@gmail.com>
|
||||
Soshi Katsuta <soshi.katsuta@gmail.com> <katsuta_soshi@cyberagent.co.jp>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com> <github@srid.name>
|
||||
Srini Brahmaroutu <srbrahma@us.ibm.com> <sbrahma@us.ibm.com>
|
||||
Srinivasan Srivatsan <srinivasan.srivatsan@hpe.com> <srinsriv@users.noreply.github.com>
|
||||
Stefan Berger <stefanb@linux.vnet.ibm.com>
|
||||
Stefan Berger <stefanb@linux.vnet.ibm.com> <stefanb@us.ibm.com>
|
||||
Stefan J. Wernli <swernli@microsoft.com> <swernli@ntdev.microsoft.com>
|
||||
Stefan S. <tronicum@user.github.com>
|
||||
Stephan Spindler <shutefan@gmail.com> <shutefan@users.noreply.github.com>
|
||||
Stephen Day <stephen.day@docker.com>
|
||||
Stephen Day <stephen.day@docker.com> <stevvooe@users.noreply.github.com>
|
||||
Steve Desmond <steve@vtsv.ca> <stevedesmond-ca@users.noreply.github.com>
|
||||
Sun Gengze <690388648@qq.com>
|
||||
Sun Jianbo <wonderflow.sun@gmail.com>
|
||||
Sun Jianbo <wonderflow.sun@gmail.com> <wonderflow@zju.edu.cn>
|
||||
Sven Dowideit <SvenDowideit@home.org.au>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <sven@t440s.home.gateway>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@docker.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@fosiki.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@home.org.au>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@users.noreply.github.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <¨SvenDowideit@home.org.au¨>
|
||||
Sylvain Bellemare <sylvain@ascribe.io>
|
||||
Sylvain Bellemare <sylvain@ascribe.io> <sylvain.bellemare@ezeep.com>
|
||||
Tangi Colin <tangicolin@gmail.com>
|
||||
Tejesh Mehta <tejesh.mehta@gmail.com> <tj@init.me>
|
||||
Thatcher Peskens <thatcher@docker.com>
|
||||
Thatcher Peskens <thatcher@docker.com> <thatcher@dotcloud.com>
|
||||
Thatcher Peskens <thatcher@docker.com> <thatcher@gmx.net>
|
||||
Thomas Gazagnaire <thomas@gazagnaire.org> <thomas@gazagnaire.com>
|
||||
Thomas Léveil <thomasleveil@gmail.com>
|
||||
Thomas Léveil <thomasleveil@gmail.com> <thomasleveil@users.noreply.github.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>
|
||||
<bernat@luffy.cx> <Vincent.Bernat@exoscale.ch>
|
||||
<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>
|
||||
<ahmetb@microsoft.com> <ahmetalpbalkan@gmail.com>
|
||||
<arnaud.porterie@docker.com> <icecrime@gmail.com>
|
||||
<baloo@gandi.net> <superbaloo+registrations.github@superbaloo.net>
|
||||
Brian Goff <cpuguy83@gmail.com>
|
||||
<cpuguy83@gmail.com> <bgoff@cpuguy83-mbp.home>
|
||||
<eric@windisch.us> <ewindisch@docker.com>
|
||||
<frank.rosquin+github@gmail.com> <frank.rosquin@gmail.com>
|
||||
Hollie Teal <hollie@docker.com>
|
||||
<hollie@docker.com> <hollie.teal@docker.com>
|
||||
<hollie@docker.com> <hollietealok@users.noreply.github.com>
|
||||
<huu@prismskylabs.com> <whoshuu@gmail.com>
|
||||
Jessica Frazelle <jessfraz@google.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <me@jessfraz.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <jess@mesosphere.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <jfrazelle@users.noreply.github.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <acidburn@docker.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <jess@docker.com>
|
||||
Jessica Frazelle <jessfraz@google.com> <princess@docker.com>
|
||||
<konrad.wilhelm.kleine@gmail.com> <kwk@users.noreply.github.com>
|
||||
<tintypemolly@gmail.com> <tintypemolly@Ohui-MacBook-Pro.local>
|
||||
<estesp@linux.vnet.ibm.com> <estesp@gmail.com>
|
||||
<github@gone.nl> <thaJeztah@users.noreply.github.com>
|
||||
Thomas LEVEIL <thomasleveil@gmail.com> Thomas LÉVEIL <thomasleveil@users.noreply.github.com>
|
||||
<oi@truffles.me.uk> <timruffles@googlemail.com>
|
||||
<Vincent.Bernat@exoscale.ch> <bernat@luffy.cx>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <amurdaca@redhat.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@redhat.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <me@runcom.ninja>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@linux.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@users.noreply.github.com>
|
||||
Darren Shepherd <darren.s.shepherd@gmail.com> <darren@rancher.com>
|
||||
Deshi Xiao <dxiao@redhat.com> <dsxiao@dataman-inc.com>
|
||||
Deshi Xiao <dxiao@redhat.com> <xiaods@gmail.com>
|
||||
Doug Davis <dug@us.ibm.com> <duglin@users.noreply.github.com>
|
||||
Jacob Atzen <jacob@jacobatzen.dk> <jatzen@gmail.com>
|
||||
Jeff Nickoloff <jeff.nickoloff@gmail.com> <jeff@allingeek.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> <jhowardmsft@users.noreply.github.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> <john.howard@microsoft.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> <jhoward@microsoft.com>
|
||||
Madhu Venugopal <madhu@socketplane.io> <madhu@docker.com>
|
||||
Mary Anthony <mary.anthony@docker.com> <mary@docker.com>
|
||||
Mary Anthony <mary.anthony@docker.com> moxiegirl <mary@docker.com>
|
||||
Mary Anthony <mary.anthony@docker.com> <moxieandmore@gmail.com>
|
||||
mattyw <mattyw@me.com> <gh@mattyw.net>
|
||||
resouer <resouer@163.com> <resouer@gmail.com>
|
||||
AJ Bowen <aj@gandi.net> soulshake <amy@gandi.net>
|
||||
AJ Bowen <aj@gandi.net> soulshake <aj@gandi.net>
|
||||
Tibor Vass <teabee89@gmail.com> <tibor@docker.com>
|
||||
Tibor Vass <teabee89@gmail.com> <tiborvass@users.noreply.github.com>
|
||||
Tim Bart <tim@fewagainstmany.com>
|
||||
Tim Bosse <taim@bosboot.org> <maztaim@users.noreply.github.com>
|
||||
Tim Ruffles <oi@truffles.me.uk> <timruffles@googlemail.com>
|
||||
Tim Terhorst <mynamewastaken+git@gmail.com>
|
||||
Tim Zju <21651152@zju.edu.cn>
|
||||
Timothy Hobbs <timothyhobbs@seznam.cz>
|
||||
Toli Kuznets <toli@docker.com>
|
||||
Tom Barlow <tomwbarlow@gmail.com>
|
||||
Tom Sweeney <tsweeney@redhat.com>
|
||||
Tõnis Tiigi <tonistiigi@gmail.com>
|
||||
Trishna Guha <trishnaguha17@gmail.com>
|
||||
Tristan Carel <tristan@cogniteev.com>
|
||||
Tristan Carel <tristan@cogniteev.com> <tristan.carel@gmail.com>
|
||||
Umesh Yadav <umesh4257@gmail.com>
|
||||
Umesh Yadav <umesh4257@gmail.com> <dungeonmaster18@users.noreply.github.com>
|
||||
Victor Lyuboslavsky <victor@victoreda.com>
|
||||
Victor Vieux <victor.vieux@docker.com> <dev@vvieux.com>
|
||||
Victor Vieux <victor.vieux@docker.com> <victor.vieux@dotcloud.com>
|
||||
Victor Vieux <victor.vieux@docker.com> <victor@docker.com>
|
||||
Victor Vieux <victor.vieux@docker.com> <victor@dotcloud.com>
|
||||
Victor Vieux <victor.vieux@docker.com> <victorvieux@gmail.com>
|
||||
Victor Vieux <victor.vieux@docker.com> <vieux@docker.com>
|
||||
Viktor Vojnovski <viktor.vojnovski@amadeus.com> <vojnovski@gmail.com>
|
||||
Vincent Batts <vbatts@redhat.com> <vbatts@hashbangbash.com>
|
||||
Vincent Bernat <Vincent.Bernat@exoscale.ch> <bernat@luffy.cx>
|
||||
Vincent Bernat <Vincent.Bernat@exoscale.ch> <vincent@bernat.im>
|
||||
Vincent Demeester <vincent.demeester@docker.com> <vincent+github@demeester.fr>
|
||||
Vincent Demeester <vincent.demeester@docker.com> <vincent@demeester.fr>
|
||||
Vincent Demeester <vincent.demeester@docker.com> <vincent@sbr.pm>
|
||||
Vishnu Kannan <vishnuk@google.com>
|
||||
Vladimir Rutsky <altsysrq@gmail.com> <iamironbob@gmail.com>
|
||||
Walter Stanish <walter@pratyeka.org>
|
||||
Wang Chao <chao.wang@ucloud.cn>
|
||||
Wang Chao <chao.wang@ucloud.cn> <wcwxyz@gmail.com>
|
||||
Wang Guoliang <liangcszzu@163.com>
|
||||
Wang Jie <wangjie5@chinaskycloud.com>
|
||||
Wang Ping <present.wp@icloud.com>
|
||||
Wang Xing <hzwangxing@corp.netease.com> <root@localhost>
|
||||
Wang Yuexiao <wang.yuexiao@zte.com.cn>
|
||||
Wayne Chang <wayne@neverfear.org>
|
||||
Wayne Song <wsong@docker.com> <wsong@users.noreply.github.com>
|
||||
Wei Wu <wuwei4455@gmail.com> cizixs <cizixs@163.com>
|
||||
Wenjun Tang <tangwj2@lenovo.com> <dodia@163.com>
|
||||
Wewang Xiaorenfine <wang.xiaoren@zte.com.cn>
|
||||
Will Weaver <monkey@buildingbananas.com>
|
||||
Xianglin Gao <xlgao@zju.edu.cn>
|
||||
Xianlu Bird <xianlubird@gmail.com>
|
||||
Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
|
||||
Xuecong Liao <satorulogic@gmail.com>
|
||||
Yamasaki Masahide <masahide.y@gmail.com>
|
||||
Yao Zaiyong <yaozaiyong@hotmail.com>
|
||||
Yassine Tijani <yasstij11@gmail.com>
|
||||
Yazhong Liu <yorkiefixer@gmail.com>
|
||||
Vincent Bernat <bernat@luffy.cx> <Vincent.Bernat@exoscale.ch>
|
||||
Yestin Sun <sunyi0804@gmail.com> <yestin.sun@polyera.com>
|
||||
Yi EungJun <eungjun.yi@navercorp.com> <semtlenori@gmail.com>
|
||||
Ying Li <ying.li@docker.com>
|
||||
Ying Li <ying.li@docker.com> <cyli@twistedmatrix.com>
|
||||
Yong Tang <yong.tang.github@outlook.com> <yongtang@users.noreply.github.com>
|
||||
Yosef Fertel <yfertel@gmail.com> <frosforever@users.noreply.github.com>
|
||||
Yu Changchun <yuchangchun1@huawei.com>
|
||||
Yu Chengxia <yuchengxia@huawei.com>
|
||||
Yu Peng <yu.peng36@zte.com.cn>
|
||||
Yu Peng <yu.peng36@zte.com.cn> <yupeng36@zte.com.cn>
|
||||
Zachary Jaffee <zjaffee@us.ibm.com> <zij@case.edu>
|
||||
Zachary Jaffee <zjaffee@us.ibm.com> <zjaffee@apache.org>
|
||||
ZhangHang <stevezhang2014@gmail.com>
|
||||
Zhenkun Bi <bi.zhenkun@zte.com.cn>
|
||||
Zhou Hao <zhouhao@cn.fujitsu.com>
|
||||
Zhu Kunjia <zhu.kunjia@zte.com.cn>
|
||||
Zou Yu <zouyu7@huawei.com>
|
||||
bin liu <liubin0329@users.noreply.github.com> <liubin0329@gmail.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> jhowardmsft <jhoward@microsoft.com>
|
||||
Ankush Agarwal <ankushagarwal11@gmail.com> <ankushagarwal@users.noreply.github.com>
|
||||
Tangi COLIN <tangicolin@gmail.com> tangicolin <tangicolin@gmail.com>
|
||||
Allen Sun <allen.sun@daocloud.io>
|
||||
Adrien Gallouët <adrien@gallouet.fr> <angt@users.noreply.github.com>
|
||||
<aanm90@gmail.com> <martins@noironetworks.com>
|
||||
Anuj Bahuguna <anujbahuguna.dev@gmail.com>
|
||||
Anusha Ragunathan <anusha.ragunathan@docker.com> <anusha@docker.com>
|
||||
Avi Miller <avi.miller@oracle.com> <avi.miller@gmail.com>
|
||||
Brent Salisbury <brent.salisbury@docker.com> <brent@docker.com>
|
||||
Chander G <chandergovind@gmail.com>
|
||||
Chun Chen <ramichen@tencent.com> <chenchun.feed@gmail.com>
|
||||
Ying Li <cyli@twistedmatrix.com>
|
||||
Daehyeok Mun <daehyeok@gmail.com> <daehyeok@daehyeok-ui-MacBook-Air.local>
|
||||
<dqminh@cloudflare.com> <dqminh89@gmail.com>
|
||||
Daniel, Dao Quang Minh <dqminh@cloudflare.com>
|
||||
Daniel Nephin <dnephin@docker.com> <dnephin@gmail.com>
|
||||
Dave Tucker <dt@docker.com> <dave@dtucker.co.uk>
|
||||
Doug Tangren <d.tangren@gmail.com>
|
||||
Frederick F. Kautz IV <fkautz@redhat.com> <fkautz@alumni.cmu.edu>
|
||||
Ben Golub <ben.golub@dotcloud.com>
|
||||
Harold Cooper <hrldcpr@gmail.com>
|
||||
hsinko <21551195@zju.edu.cn> <hsinko@users.noreply.github.com>
|
||||
Josh Hawn <josh.hawn@docker.com> <jlhawn@berkeley.edu>
|
||||
Justin Cormack <justin.cormack@docker.com>
|
||||
<justin.cormack@docker.com> <justin.cormack@unikernel.com>
|
||||
<justin.cormack@docker.com> <justin@specialbusservice.com>
|
||||
Kamil Domański <kamil@domanski.co>
|
||||
Lei Jitang <leijitang@huawei.com>
|
||||
<leijitang@huawei.com> <leijitang@gmail.com>
|
||||
Linus Heckemann <lheckemann@twig-world.com>
|
||||
<lheckemann@twig-world.com> <anonymouse2048@gmail.com>
|
||||
Lynda O'Leary <lyndaoleary29@gmail.com>
|
||||
<lyndaoleary29@gmail.com> <lyndaoleary@hotmail.com>
|
||||
Marianna Tessel <mtesselh@gmail.com>
|
||||
Michael Huettermann <michael@huettermann.net>
|
||||
Moysés Borges <moysesb@gmail.com>
|
||||
<moysesb@gmail.com> <moyses.furtado@wplex.com.br>
|
||||
Nigel Poulton <nigelpoulton@hotmail.com>
|
||||
Qiang Huang <h.huangqiang@huawei.com>
|
||||
<h.huangqiang@huawei.com> <qhuang@10.0.2.15>
|
||||
Boaz Shuster <ripcurld.github@gmail.com>
|
||||
Shuwei Hao <haosw@cn.ibm.com>
|
||||
<haosw@cn.ibm.com> <haoshuwei24@gmail.com>
|
||||
Soshi Katsuta <soshi.katsuta@gmail.com>
|
||||
<soshi.katsuta@gmail.com> <katsuta_soshi@cyberagent.co.jp>
|
||||
Stefan Berger <stefanb@linux.vnet.ibm.com>
|
||||
<stefanb@linux.vnet.ibm.com> <stefanb@us.ibm.com>
|
||||
Stephen Day <stephen.day@docker.com>
|
||||
<stephen.day@docker.com> <stevvooe@users.noreply.github.com>
|
||||
Toli Kuznets <toli@docker.com>
|
||||
Tristan Carel <tristan@cogniteev.com>
|
||||
<tristan@cogniteev.com> <tristan.carel@gmail.com>
|
||||
Vincent Demeester <vincent@sbr.pm>
|
||||
<vincent@sbr.pm> <vincent+github@demeester.fr>
|
||||
Vishnu Kannan <vishnuk@google.com>
|
||||
xlgao-zju <xlgao@zju.edu.cn> xlgao <xlgao@zju.edu.cn>
|
||||
yuchangchun <yuchangchun1@huawei.com> y00277921 <yuchangchun1@huawei.com>
|
||||
<zij@case.edu> <zjaffee@us.ibm.com>
|
||||
<anujbahuguna.dev@gmail.com> <abahuguna@fiberlink.com>
|
||||
<eungjun.yi@navercorp.com> <semtlenori@gmail.com>
|
||||
<haosw@cn.ibm.com> <haoshuwei1989@163.com>
|
||||
Hao Shu Wei <haosw@cn.ibm.com>
|
||||
<matt.bentley@docker.com> <mbentley@mbentley.net>
|
||||
<MihaiBorob@gmail.com> <MihaiBorobocea@gmail.com>
|
||||
<redmond.martin@gmail.com> <xgithub@redmond5.com>
|
||||
<redmond.martin@gmail.com> <martin@tinychat.com>
|
||||
<srbrahma@us.ibm.com> <sbrahma@us.ibm.com>
|
||||
<suda.akihiro@lab.ntt.co.jp> <suda.kyoto@gmail.com>
|
||||
<thomas@gazagnaire.org> <thomas@gazagnaire.com>
|
||||
Shengbo Song <thomassong@tencent.com> mYmNeo <mymneo@163.com>
|
||||
Shengbo Song <thomassong@tencent.com>
|
||||
<sylvain@ascribe.io> <sylvain.bellemare@ezeep.com>
|
||||
Sylvain Bellemare <sylvain@ascribe.io>
|
||||
<alexandre.beslic@gmail.com> <abronan@docker.com>
|
||||
<bilal.amarni@gmail.com> <bamarni@users.noreply.github.com>
|
||||
<misty@docker.com> <misty@apache.org>
|
||||
Arnaud Porterie <arnaud.porterie@docker.com>
|
||||
<cpuguy83@gmail.com> <bgoff@cpuguy83-mbp.local>
|
||||
David M. Karr <davidmichaelkarr@gmail.com>
|
||||
<diogo@docker.com> <diogo.monica@gmail.com>
|
||||
<horwitz@addthis.com> <horwitzja@gmail.com>
|
||||
<kherner@progress.com> <chosenken@gmail.com>
|
||||
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
||||
<mauricio@medallia.com> <mauriciogaravaglia@gmail.com>
|
||||
<dhenderson@gmail.com> <Dave.Henderson@ca.ibm.com>
|
||||
<wkq5325@gmail.com> <wkqwu@cn.ibm.com>
|
||||
<mike.goelzer@docker.com> <mgoelzer@docker.com>
|
||||
<nicholasjamesrusso@gmail.com> <nicholasrusso@icloud.com>
|
||||
Runshen Zhu <runshen.zhu@gmail.com>
|
||||
Tom Barlow <tomwbarlow@gmail.com>
|
||||
Xianlu Bird <xianlubird@gmail.com>
|
||||
Dan Feldman <danf@jfrog.com>
|
||||
Harry Zhang <harryz@hyper.sh> <harryzhang@zju.edu.cn>
|
||||
|
||||
272
CHANGELOG.md
272
CHANGELOG.md
@@ -5,276 +5,25 @@ information on the list of deprecated flags and APIs please have a look at
|
||||
https://docs.docker.com/engine/deprecated/ where target removal dates can also
|
||||
be found.
|
||||
|
||||
## 17.03.2-ce (2017-05-29)
|
||||
|
||||
### Networking
|
||||
|
||||
- Fix a concurrency issue preventing network creation [#33273](https://github.com/moby/moby/pull/33273)
|
||||
|
||||
### Runtime
|
||||
|
||||
- Relabel secrets path to avoid a Permission Denied on selinux enabled systems [#33236](https://github.com/moby/moby/pull/33236) (ref [#32529](https://github.com/moby/moby/pull/32529)
|
||||
- Fix cases where local volume were not properly relabeled if needed [#33236](https://github.com/moby/moby/pull/33236) (ref [#29428](https://github.com/moby/moby/pull/29428))
|
||||
- Fix an issue while upgrading if a plugin rootfs was still mounted [#33236](https://github.com/moby/moby/pull/33236) (ref [#32525](https://github.com/moby/moby/pull/32525))
|
||||
- Fix an issue where volume wouldn't default to the `rprivate` propagation mode [#33236](https://github.com/moby/moby/pull/33236) (ref [#32851](https://github.com/moby/moby/pull/32851))
|
||||
- Fix a panic that could occur when a volume driver could not be retrieved [#33236](https://github.com/moby/moby/pull/33236) (ref [#32347](https://github.com/moby/moby/pull/32347))
|
||||
+ Add a warning in `docker info` when the `overlay` or `overlay2` graphdriver is used on a filesystem without `d_type` support [#33236](https://github.com/moby/moby/pull/33236) (ref [#31290](https://github.com/moby/moby/pull/31290))
|
||||
- Fix an issue with backporting mount spec to older volumes [#33207](https://github.com/moby/moby/pull/33207)
|
||||
- Fix issue where a failed unmount can lead to data loss on local volume remove [#33120](https://github.com/moby/moby/pull/33120)
|
||||
|
||||
### Swarm Mode
|
||||
|
||||
- Fix a case where tasks could get killed unexpectedly [#33118](https://github.com/moby/moby/pull/33118)
|
||||
- Fix an issue preventing to deploy services if the registry cannot be reached despite the needed images being locally present [#33117](https://github.com/moby/moby/pull/33117)
|
||||
|
||||
## 17.05.0-ce (2017-05-04)
|
||||
|
||||
### Builder
|
||||
|
||||
+ Add multi-stage build support [#31257](https://github.com/docker/docker/pull/31257) [#32063](https://github.com/docker/docker/pull/32063)
|
||||
+ Allow using build-time args (`ARG`) in `FROM` [#31352](https://github.com/docker/docker/pull/31352)
|
||||
+ Add an option for specifying build target [#32496](https://github.com/docker/docker/pull/32496)
|
||||
* Accept `-f -` to read Dockerfile from `stdin`, but use local context for building [#31236](https://github.com/docker/docker/pull/31236)
|
||||
* The values of default build time arguments (e.g `HTTP_PROXY`) are no longer displayed in docker image history unless a corresponding `ARG` instruction is written in the Dockerfile. [#31584](https://github.com/docker/docker/pull/31584)
|
||||
- Fix setting command if a custom shell is used in a parent image [#32236](https://github.com/docker/docker/pull/32236)
|
||||
- Fix `docker build --label` when the label includes single quotes and a space [#31750](https://github.com/docker/docker/pull/31750)
|
||||
|
||||
### Client
|
||||
|
||||
* Add `--mount` flag to `docker run` and `docker create` [#32251](https://github.com/docker/docker/pull/32251)
|
||||
* Add `--type=secret` to `docker inspect` [#32124](https://github.com/docker/docker/pull/32124)
|
||||
* Add `--format` option to `docker secret ls` [#31552](https://github.com/docker/docker/pull/31552)
|
||||
* Add `--filter` option to `docker secret ls` [#30810](https://github.com/docker/docker/pull/30810)
|
||||
* Add `--filter scope=<swarm|local>` to `docker network ls` [#31529](https://github.com/docker/docker/pull/31529)
|
||||
* Add `--cpus` support to `docker update` [#31148](https://github.com/docker/docker/pull/31148)
|
||||
* Add label filter to `docker system prune` and other `prune` commands [#30740](https://github.com/docker/docker/pull/30740)
|
||||
* `docker stack rm` now accepts multiple stacks as input [#32110](https://github.com/docker/docker/pull/32110)
|
||||
* Improve `docker version --format` option when the client has downgraded the API version [#31022](https://github.com/docker/docker/pull/31022)
|
||||
* Prompt when using an encrypted client certificate to connect to a docker daemon [#31364](https://github.com/docker/docker/pull/31364)
|
||||
* Display created tags on successful `docker build` [#32077](https://github.com/docker/docker/pull/32077)
|
||||
* Cleanup compose convert error messages [#32087](https://github.com/moby/moby/pull/32087)
|
||||
|
||||
### Contrib
|
||||
|
||||
+ Add support for building docker debs for Ubuntu 17.04 Zesty on amd64 [#32435](https://github.com/docker/docker/pull/32435)
|
||||
|
||||
### Daemon
|
||||
|
||||
- Fix `--api-cors-header` being ignored if `--api-enable-cors` is not set [#32174](https://github.com/docker/docker/pull/32174)
|
||||
- Cleanup docker tmp dir on start [#31741](https://github.com/docker/docker/pull/31741)
|
||||
- Deprecate `--graph` flag in favor or `--data-root` [#28696](https://github.com/docker/docker/pull/28696)
|
||||
|
||||
### Logging
|
||||
|
||||
+ Add support for logging driver plugins [#28403](https://github.com/docker/docker/pull/28403)
|
||||
* Add support for showing logs of individual tasks to `docker service logs`, and add `/task/{id}/logs` REST endpoint [#32015](https://github.com/docker/docker/pull/32015)
|
||||
* Add `--log-opt env-regex` option to match environment variables using a regular expression [#27565](https://github.com/docker/docker/pull/27565)
|
||||
|
||||
### Networking
|
||||
|
||||
+ Allow user to replace, and customize the ingress network [#31714](https://github.com/docker/docker/pull/31714)
|
||||
- Fix UDP traffic in containers not working after the container is restarted [#32505](https://github.com/docker/docker/pull/32505)
|
||||
- Fix files being written to `/var/lib/docker` if a different data-root is set [#32505](https://github.com/docker/docker/pull/32505)
|
||||
|
||||
### Runtime
|
||||
|
||||
- Ensure health probe is stopped when a container exits [#32274](https://github.com/docker/docker/pull/32274)
|
||||
|
||||
### Swarm Mode
|
||||
|
||||
+ Add update/rollback order for services (`--update-order` / `--rollback-order`) [#30261](https://github.com/docker/docker/pull/30261)
|
||||
+ Add support for synchronous `service create` and `service update` [#31144](https://github.com/docker/docker/pull/31144)
|
||||
+ Add support for "grace periods" on healthchecks through the `HEALTHCHECK --start-period` and `--health-start-period` flag to
|
||||
`docker service create`, `docker service update`, `docker create`, and `docker run` to support containers with an initial startup
|
||||
time [#28938](https://github.com/docker/docker/pull/28938)
|
||||
* `docker service create` now omits fields that are not specified by the user, when possible. This will allow defaults to be applied inside the manager [#32284](https://github.com/docker/docker/pull/32284)
|
||||
* `docker service inspect` now shows default values for fields that are not specified by the user [#32284](https://github.com/docker/docker/pull/32284)
|
||||
* Move `docker service logs` out of experimental [#32462](https://github.com/docker/docker/pull/32462)
|
||||
* Add support for Credential Spec and SELinux to services to the API [#32339](https://github.com/docker/docker/pull/32339)
|
||||
* Add `--entrypoint` flag to `docker service create` and `docker service update` [#29228](https://github.com/docker/docker/pull/29228)
|
||||
* Add `--network-add` and `--network-rm` to `docker service update` [#32062](https://github.com/docker/docker/pull/32062)
|
||||
* Add `--credential-spec` flag to `docker service create` and `docker service update` [#32339](https://github.com/docker/docker/pull/32339)
|
||||
* Add `--filter mode=<global|replicated>` to `docker service ls` [#31538](https://github.com/docker/docker/pull/31538)
|
||||
* Resolve network IDs on the client side, instead of in the daemon when creating services [#32062](https://github.com/docker/docker/pull/32062)
|
||||
* Add `--format` option to `docker node ls` [#30424](https://github.com/docker/docker/pull/30424)
|
||||
* Add `--prune` option to `docker stack deploy` to remove services that are no longer defined in the docker-compose file [#31302](https://github.com/docker/docker/pull/31302)
|
||||
* Add `PORTS` column for `docker service ls` when using `ingress` mode [#30813](https://github.com/docker/docker/pull/30813)
|
||||
- Fix unnescessary re-deploying of tasks when environment-variables are used [#32364](https://github.com/docker/docker/pull/32364)
|
||||
- Fix `docker stack deploy` not supporting `endpoint_mode` when deploying from a docker compose file [#32333](https://github.com/docker/docker/pull/32333)
|
||||
- Proceed with startup if cluster component cannot be created to allow recovering from a broken swarm setup [#31631](https://github.com/docker/docker/pull/31631)
|
||||
|
||||
### Security
|
||||
|
||||
* Allow setting SELinux type or MCS labels when using `--ipc=container:` or `--ipc=host` [#30652](https://github.com/docker/docker/pull/30652)
|
||||
|
||||
|
||||
### Deprecation
|
||||
|
||||
- Deprecate `--api-enable-cors` daemon flag. This flag was marked deprecated in Docker 1.6.0 but not listed in deprecated features [#32352](https://github.com/docker/docker/pull/32352)
|
||||
- Remove Ubuntu 12.04 (Precise Pangolin) as supported platform. Ubuntu 12.04 is EOL, and no longer receives updates [#32520](https://github.com/docker/docker/pull/32520)
|
||||
|
||||
## 17.04.0-ce (2017-04-05)
|
||||
|
||||
### Builder
|
||||
|
||||
* Disable container logging for build containers [#29552](https://github.com/docker/docker/pull/29552)
|
||||
* Fix use of `**/` in `.dockerignore` [#29043](https://github.com/docker/docker/pull/29043)
|
||||
|
||||
### Client
|
||||
|
||||
+ Sort `docker stack ls` by name [#31085](https://github.com/docker/docker/pull/31085)
|
||||
+ Flags for specifying bind mount consistency [#31047](https://github.com/docker/docker/pull/31047)
|
||||
* Output of docker CLI --help is now wrapped to the terminal width [#28751](https://github.com/docker/docker/pull/28751)
|
||||
* Suppress image digest in docker ps [#30848](https://github.com/docker/docker/pull/30848)
|
||||
* Hide command options that are related to Windows [#30788](https://github.com/docker/docker/pull/30788)
|
||||
* Fix `docker plugin install` prompt to accept "enter" for the "N" default [#30769](https://github.com/docker/docker/pull/30769)
|
||||
+ Add `truncate` function for Go templates [#30484](https://github.com/docker/docker/pull/30484)
|
||||
* Support expanded syntax of ports in `stack deploy` [#30476](https://github.com/docker/docker/pull/30476)
|
||||
* Support expanded syntax of mounts in `stack deploy` [#30597](https://github.com/docker/docker/pull/30597) [#31795](https://github.com/docker/docker/pull/31795)
|
||||
+ Add `--add-host` for docker build [#30383](https://github.com/docker/docker/pull/30383)
|
||||
+ Add `.CreatedAt` placeholder for `docker network ls --format` [#29900](https://github.com/docker/docker/pull/29900)
|
||||
* Update order of `--secret-rm` and `--secret-add` [#29802](https://github.com/docker/docker/pull/29802)
|
||||
+ Add `--filter enabled=true` for `docker plugin ls` [#28627](https://github.com/docker/docker/pull/28627)
|
||||
+ Add `--format` to `docker service ls` [#28199](https://github.com/docker/docker/pull/28199)
|
||||
+ Add `publish` and `expose` filter for `docker ps --filter` [#27557](https://github.com/docker/docker/pull/27557)
|
||||
* Support multiple service IDs on `docker service ps` [#25234](https://github.com/docker/docker/pull/25234)
|
||||
+ Allow swarm join with `--availability=drain` [#24993](https://github.com/docker/docker/pull/24993)
|
||||
* Docker inspect now shows "docker-default" when AppArmor is enabled and no other profile was defined [#27083](https://github.com/docker/docker/pull/27083)
|
||||
|
||||
### Logging
|
||||
|
||||
+ Implement optional ring buffer for container logs [#28762](https://github.com/docker/docker/pull/28762)
|
||||
+ Add `--log-opt awslogs-create-group=<true|false>` for awslogs (CloudWatch) to support creation of log groups as needed [#29504](https://github.com/docker/docker/pull/29504)
|
||||
- Fix segfault when using the gcplogs logging driver with a "static" binary [#29478](https://github.com/docker/docker/pull/29478)
|
||||
|
||||
|
||||
### Networking
|
||||
|
||||
* Check parameter `--ip`, `--ip6` and `--link-local-ip` in `docker network connect` [#30807](https://github.com/docker/docker/pull/30807)
|
||||
+ Added support for `dns-search` [#30117](https://github.com/docker/docker/pull/30117)
|
||||
+ Added --verbose option for docker network inspect to show task details from all swarm nodes [#31710](https://github.com/docker/docker/pull/31710)
|
||||
* Clear stale datapath encryption states when joining the cluster [docker/libnetwork#1354](https://github.com/docker/libnetwork/pull/1354)
|
||||
+ Ensure iptables initialization only happens once [docker/libnetwork#1676](https://github.com/docker/libnetwork/pull/1676)
|
||||
* Fix bad order of iptables filter rules [docker/libnetwork#961](https://github.com/docker/libnetwork/pull/961)
|
||||
+ Add anonymous container alias to service record on attachable network [docker/libnetwork#1651](https://github.com/docker/libnetwork/pull/1651)
|
||||
+ Support for `com.docker.network.container_interface_prefix` driver label [docker/libnetwork#1667](https://github.com/docker/libnetwork/pull/1667)
|
||||
+ Improve network list performance by omitting network details that are not used [#30673](https://github.com/docker/docker/pull/30673)
|
||||
|
||||
### Runtime
|
||||
|
||||
* Handle paused container when restoring without live-restore set [#31704](https://github.com/docker/docker/pull/31704)
|
||||
- Do not allow sub second in healthcheck options in Dockerfile [#31177](https://github.com/docker/docker/pull/31177)
|
||||
* Support name and id prefix in `secret update` [#30856](https://github.com/docker/docker/pull/30856)
|
||||
* Use binary frame for websocket attach endpoint [#30460](https://github.com/docker/docker/pull/30460)
|
||||
* Fix linux mount calls not applying propagation type changes [#30416](https://github.com/docker/docker/pull/30416)
|
||||
* Fix ExecIds leak on failed `exec -i` [#30340](https://github.com/docker/docker/pull/30340)
|
||||
* Prune named but untagged images if `danglingOnly=true` [#30330](https://github.com/docker/docker/pull/30330)
|
||||
+ Add daemon flag to set `no_new_priv` as default for unprivileged containers [#29984](https://github.com/docker/docker/pull/29984)
|
||||
+ Add daemon option `--default-shm-size` [#29692](https://github.com/docker/docker/pull/29692)
|
||||
+ Support registry mirror config reload [#29650](https://github.com/docker/docker/pull/29650)
|
||||
- Ignore the daemon log config when building images [#29552](https://github.com/docker/docker/pull/29552)
|
||||
* Move secret name or ID prefix resolving from client to daemon [#29218](https://github.com/docker/docker/pull/29218)
|
||||
+ Allow adding rules to `cgroup devices.allow` on container create/run [#22563](https://github.com/docker/docker/pull/22563)
|
||||
- Fix `cpu.cfs_quota_us` being reset when running `systemd daemon-reload` [#31736](https://github.com/docker/docker/pull/31736)
|
||||
|
||||
### Swarm Mode
|
||||
|
||||
+ Topology-aware scheduling [#30725](https://github.com/docker/docker/pull/30725)
|
||||
+ Automatic service rollback on failure [#31108](https://github.com/docker/docker/pull/31108)
|
||||
+ Worker and manager on the same node are now connected through a UNIX socket [docker/swarmkit#1828](https://github.com/docker/swarmkit/pull/1828), [docker/swarmkit#1850](https://github.com/docker/swarmkit/pull/1850), [docker/swarmkit#1851](https://github.com/docker/swarmkit/pull/1851)
|
||||
* Improve raft transport package [docker/swarmkit#1748](https://github.com/docker/swarmkit/pull/1748)
|
||||
* No automatic manager shutdown on demotion/removal [docker/swarmkit#1829](https://github.com/docker/swarmkit/pull/1829)
|
||||
* Use TransferLeadership to make leader demotion safer [docker/swarmkit#1939](https://github.com/docker/swarmkit/pull/1939)
|
||||
* Decrease default monitoring period [docker/swarmkit#1967](https://github.com/docker/swarmkit/pull/1967)
|
||||
+ Add Service logs formatting [#31672](https://github.com/docker/docker/pull/31672)
|
||||
* Fix service logs API to be able to specify stream [#31313](https://github.com/docker/docker/pull/31313)
|
||||
+ Add `--stop-signal` for `service create` and `service update` [#30754](https://github.com/docker/docker/pull/30754)
|
||||
+ Add `--read-only` for `service create` and `service update` [#30162](https://github.com/docker/docker/pull/30162)
|
||||
+ Renew the context after communicating with the registry [#31586](https://github.com/docker/docker/pull/31586)
|
||||
+ (experimental) Add `--tail` and `--since` options to `docker service logs` [#31500](https://github.com/docker/docker/pull/31500)
|
||||
+ (experimental) Add `--no-task-ids` and `--no-trunc` options to `docker service logs` [#31672](https://github.com/docker/docker/pull/31672)
|
||||
|
||||
### Windows
|
||||
|
||||
* Block pulling Windows images on non-Windows daemons [#29001](https://github.com/docker/docker/pull/29001)
|
||||
|
||||
## 17.03.1-ce (2017-03-27)
|
||||
|
||||
### Remote API (v1.27) & Client
|
||||
|
||||
* Fix autoremove on older api [#31692](https://github.com/docker/docker/pull/31692)
|
||||
* Fix default network customization for a stack [#31258](https://github.com/docker/docker/pull/31258/)
|
||||
* Correct CPU usage calculation in presence of offline CPUs and newer Linux [#31802](https://github.com/docker/docker/pull/31802)
|
||||
* Fix issue where service healthcheck is `{}` in remote API [#30197](https://github.com/docker/docker/pull/30197)
|
||||
|
||||
### Runtime
|
||||
|
||||
* Update runc to 54296cf40ad8143b62dbcaa1d90e520a2136ddfe [#31666](https://github.com/docker/docker/pull/31666)
|
||||
* Ignore cgroup2 mountpoints [opencontainers/runc#1266](https://github.com/opencontainers/runc/pull/1266)
|
||||
* Update containerd to 4ab9917febca54791c5f071a9d1f404867857fcc [#31662](https://github.com/docker/docker/pull/31662) [#31852](https://github.com/docker/docker/pull/31852)
|
||||
* Register healthcheck service before calling restore() [docker/containerd#609](https://github.com/docker/containerd/pull/609)
|
||||
* Fix `docker exec` not working after unattended upgrades that reload apparmor profiles [#31773](https://github.com/docker/docker/pull/31773)
|
||||
* Fix unmounting layer without merge dir with Overlay2 [#31069](https://github.com/docker/docker/pull/31069)
|
||||
* Do not ignore "volume in use" errors when force-delete [#31450](https://github.com/docker/docker/pull/31450)
|
||||
|
||||
### Swarm Mode
|
||||
|
||||
* Update swarmkit to 17756457ad6dc4d8a639a1f0b7a85d1b65a617bb [#31807](https://github.com/docker/docker/pull/31807)
|
||||
* Scheduler now correctly considers tasks which have been assigned to a node but aren't yet running [docker/swarmkit#1980](https://github.com/docker/swarmkit/pull/1980)
|
||||
* Allow removal of a network when only dead tasks reference it [docker/swarmkit#2018](https://github.com/docker/swarmkit/pull/2018)
|
||||
* Retry failed network allocations less aggressively [docker/swarmkit#2021](https://github.com/docker/swarmkit/pull/2021)
|
||||
* Avoid network allocation for tasks that are no longer running [docker/swarmkit#2017](https://github.com/docker/swarmkit/pull/2017)
|
||||
* Bookkeeping fixes inside network allocator allocator [docker/swarmkit#2019](https://github.com/docker/swarmkit/pull/2019) [docker/swarmkit#2020](https://github.com/docker/swarmkit/pull/2020)
|
||||
|
||||
### Windows
|
||||
|
||||
* Cleanup HCS on restore [#31503](https://github.com/docker/docker/pull/31503)
|
||||
|
||||
## 17.03.0-ce (2017-03-01)
|
||||
|
||||
**IMPORTANT**: Starting with this release, Docker is on a monthly release cycle and uses a
|
||||
new YY.MM versioning scheme to reflect this. Two channels are available: monthly and quarterly.
|
||||
Any given monthly release will only receive security and bugfixes until the next monthly
|
||||
release is available. Quarterly releases receive security and bugfixes for 4 months after
|
||||
initial release. This release includes bugfixes for 1.13.1 but
|
||||
there are no major feature additions and the API version stays the same.
|
||||
Upgrading from Docker 1.13.1 to 17.03.0 is expected to be simple and low-risk.
|
||||
|
||||
### Client
|
||||
|
||||
* Fix panic in `docker stats --format` [#30776](https://github.com/docker/docker/pull/30776)
|
||||
* Fix panic in `docker stats --format`
|
||||
|
||||
### Contrib
|
||||
|
||||
* Update various `bash` and `zsh` completion scripts [#30823](https://github.com/docker/docker/pull/30823), [#30945](https://github.com/docker/docker/pull/30945) and more...
|
||||
* Block obsolete socket families in default seccomp profile - mitigates unpatched kernels' CVE-2017-6074 [#29076](https://github.com/docker/docker/pull/29076)
|
||||
|
||||
### Networking
|
||||
|
||||
* Fix bug on overlay encryption keys rotation in cross-datacenter swarm [#30727](https://github.com/docker/docker/pull/30727)
|
||||
* Fix side effect panic in overlay encryption and network control plane communication failure ("No installed keys could decrypt the message") on frequent swarm leader re-election [#25608](https://github.com/docker/docker/pull/25608)
|
||||
* Several fixes around system responsiveness and datapath programming when using overlay network with external kv-store [docker/libnetwork#1639](https://github.com/docker/libnetwork/pull/1639), [docker/libnetwork#1632](https://github.com/docker/libnetwork/pull/1632) and more...
|
||||
* Discard incoming plain vxlan packets for encrypted overlay network [#31170](https://github.com/docker/docker/pull/31170)
|
||||
* Release the network attachment on allocation failure [#31073](https://github.com/docker/docker/pull/31073)
|
||||
* Fix port allocation when multiple published ports map to the same target port [docker/swarmkit#1835](https://github.com/docker/swarmkit/pull/1835)
|
||||
|
||||
### Runtime
|
||||
|
||||
* Fix a deadlock in docker logs [#30223](https://github.com/docker/docker/pull/30223)
|
||||
* Fix cpu spin waiting for log write events [#31070](https://github.com/docker/docker/pull/31070)
|
||||
* Fix a possible crash when using journald [#31231](https://github.com/docker/docker/pull/31231) [#31263](https://github.com/docker/docker/pull/31263)
|
||||
* Fix a panic on close of nil channel [#31274](https://github.com/docker/docker/pull/31274)
|
||||
* Fix duplicate mount point for `--volumes-from` in `docker run` [#29563](https://github.com/docker/docker/pull/29563)
|
||||
* Fix `--cache-from` does not cache last step [#31189](https://github.com/docker/docker/pull/31189)
|
||||
|
||||
### Swarm Mode
|
||||
|
||||
* Shutdown leaks an error when the container was never started [#31279](https://github.com/docker/docker/pull/31279)
|
||||
* Fix possibility of tasks getting stuck in the "NEW" state during a leader failover [docker/swarmkit#1938](https://github.com/docker/swarmkit/pull/1938)
|
||||
* Fix extraneous task creations for global services that led to confusing replica counts in `docker service ls` [docker/swarmkit#1957](https://github.com/docker/swarmkit/pull/1957)
|
||||
* Fix problem that made rolling updates slow when `task-history-limit` was set to 1 [docker/swarmkit#1948](https://github.com/docker/swarmkit/pull/1948)
|
||||
* Restart tasks elsewhere, if appropriate, when they are shut down as a result of nodes no longer satisfying constraints [docker/swarmkit#1958](https://github.com/docker/swarmkit/pull/1958)
|
||||
* (experimental)
|
||||
|
||||
## 1.13.1 (2017-02-08)
|
||||
|
||||
@@ -545,7 +294,7 @@ To manually remove all plugins and resolve this problem, take the following step
|
||||
- Fix selinux labeling of volumes shared in a container [#23024](https://github.com/docker/docker/pull/23024)
|
||||
- Prohibit `/sys/firmware/**` from being accessed with apparmor [#26618](https://github.com/docker/docker/pull/26618)
|
||||
|
||||
### Deprecation
|
||||
### DEPRECATION
|
||||
|
||||
- Marked the `docker daemon` command as deprecated. The daemon is moved to a separate binary (`dockerd`), and should be used instead [#26834](https://github.com/docker/docker/pull/26834)
|
||||
- Deprecate unversioned API endpoints [#28208](https://github.com/docker/docker/pull/28208)
|
||||
@@ -1109,12 +858,12 @@ installing docker, please make sure to update them accordingly.
|
||||
+ Add security options to `docker info` output [#21172](https://github.com/docker/docker/pull/21172) [#23520](https://github.com/docker/docker/pull/23520)
|
||||
+ Add insecure registries to `docker info` output [#20410](https://github.com/docker/docker/pull/20410)
|
||||
+ Extend Docker authorization with TLS user information [#21556](https://github.com/docker/docker/pull/21556)
|
||||
+ devicemapper: expose Minimum Thin Pool Free Space through `docker info` [#21945](https://github.com/docker/docker/pull/21945)
|
||||
+ devicemapper: expose Mininum Thin Pool Free Space through `docker info` [#21945](https://github.com/docker/docker/pull/21945)
|
||||
* API now returns a JSON object when an error occurs making it more consistent [#22880](https://github.com/docker/docker/pull/22880)
|
||||
- Prevent `docker run -i --restart` from hanging on exit [#22777](https://github.com/docker/docker/pull/22777)
|
||||
- Fix API/CLI discrepancy on hostname validation [#21641](https://github.com/docker/docker/pull/21641)
|
||||
- Fix discrepancy in the format of sizes in `stats` from HumanSize to BytesSize [#21773](https://github.com/docker/docker/pull/21773)
|
||||
- authz: when request is denied return forbidden exit code (403) [#22448](https://github.com/docker/docker/pull/22448)
|
||||
- authz: when request is denied return forbbiden exit code (403) [#22448](https://github.com/docker/docker/pull/22448)
|
||||
- Windows: fix tty-related displaying issues [#23878](https://github.com/docker/docker/pull/23878)
|
||||
|
||||
### Runtime
|
||||
@@ -1168,8 +917,7 @@ installing docker, please make sure to update them accordingly.
|
||||
- Windows: Enable auto-creation of host-path to match Linux [#22094](https://github.com/docker/docker/pull/22094)
|
||||
|
||||
|
||||
### Deprecation
|
||||
|
||||
### DEPRECATION
|
||||
* Environment variables `DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE` and `DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE` have been renamed
|
||||
to `DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE` and `DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE` respectively [#22574](https://github.com/docker/docker/pull/22574)
|
||||
* Remove deprecated `syslog-tag`, `gelf-tag`, `fluentd-tag` log option in favor of the more generic `tag` one [#22620](https://github.com/docker/docker/pull/22620)
|
||||
@@ -1706,7 +1454,7 @@ that allows to add build-time environment variables (#15182)
|
||||
|
||||
- devicemapper: Implement deferred deletion capability (#16381)
|
||||
|
||||
### Networking
|
||||
## Networking
|
||||
|
||||
+ `docker network` exits experimental and is part of standard release (#16645)
|
||||
+ New network top-level concept, with associated subcommands and API (#16645)
|
||||
@@ -1909,7 +1657,7 @@ by another client (#15489)
|
||||
|
||||
#### Remote API
|
||||
|
||||
- Fix unmarshaling of Command and Entrypoint
|
||||
- Fix unmarshalling of Command and Entrypoint
|
||||
- Set limit for minimum client version supported
|
||||
- Validate port specification
|
||||
- Return proper errors when attach/reattach fail
|
||||
@@ -2306,7 +2054,7 @@ by another client (#15489)
|
||||
- Use mock for search tests.
|
||||
- Update to double-dash everywhere.
|
||||
- Move .dockerenv parsing to lxc driver.
|
||||
- Move all bind mounts in the container inside the namespace.
|
||||
- Move all bind-mounts in the container inside the namespace.
|
||||
- Don't use separate bind mount for container.
|
||||
- Always symlink /dev/ptmx for libcontainer.
|
||||
- Don't kill by pid for other drivers.
|
||||
@@ -2594,7 +2342,7 @@ With the ongoing changes to the networking and execution subsystems of docker te
|
||||
- Fix ADD caching issue with . prefixed path
|
||||
- Fix docker build on devicemapper by reverting sparse file tar option
|
||||
- Fix issue with file caching and prevent wrong cache hit
|
||||
* Use same error handling while unmarshaling CMD and ENTRYPOINT
|
||||
* Use same error handling while unmarshalling CMD and ENTRYPOINT
|
||||
|
||||
#### Documentation
|
||||
|
||||
@@ -2741,7 +2489,7 @@ With the ongoing changes to the networking and execution subsystems of docker te
|
||||
+ Implement `docker log -f` to stream logs
|
||||
+ Add env variable to disable kernel version warning
|
||||
+ Add -format to `docker inspect`
|
||||
+ Support bind mount for files
|
||||
+ Support bind-mount for files
|
||||
- Fix bridge creation on RHEL
|
||||
- Fix image size calculation
|
||||
- Make sure iptables are called even if the bridge already exists
|
||||
|
||||
191
CONTRIBUTING.md
191
CONTRIBUTING.md
@@ -1,14 +1,14 @@
|
||||
# Contribute to the Moby Project
|
||||
# Contributing to Docker
|
||||
|
||||
Want to hack on the Moby Project? Awesome! We have a contributor's guide that explains
|
||||
[setting up a development environment and the contribution
|
||||
process](docs/contributing/).
|
||||
Want to hack on Docker? Awesome! We have a contributor's guide that explains
|
||||
[setting up a Docker development environment and the contribution
|
||||
process](https://docs.docker.com/opensource/project/who-written-for/).
|
||||
|
||||
[](https://docs.docker.com/opensource/project/who-written-for/)
|
||||
|
||||
This page contains information about reporting issues as well as some tips and
|
||||
guidelines useful to experienced open source contributors. Finally, make sure
|
||||
you read our [community guidelines](#moby-community-guidelines) before you
|
||||
you read our [community guidelines](#docker-community-guidelines) before you
|
||||
start participating.
|
||||
|
||||
## Topics
|
||||
@@ -17,18 +17,18 @@ start participating.
|
||||
* [Design and Cleanup Proposals](#design-and-cleanup-proposals)
|
||||
* [Reporting Issues](#reporting-other-issues)
|
||||
* [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines)
|
||||
* [Community Guidelines](#moby-community-guidelines)
|
||||
* [Community Guidelines](#docker-community-guidelines)
|
||||
|
||||
## Reporting security issues
|
||||
|
||||
The Moby maintainers take security seriously. If you discover a security
|
||||
The Docker maintainers take security seriously. If you discover a security
|
||||
issue, please bring it to their attention right away!
|
||||
|
||||
Please **DO NOT** file a public issue, instead send your report privately to
|
||||
[security@docker.com](mailto:security@docker.com).
|
||||
|
||||
Security reports are greatly appreciated and we will publicly thank you for it.
|
||||
We also like to send gifts—if you're into schwag, make sure to let
|
||||
We also like to send gifts—if you're into Docker schwag, make sure to let
|
||||
us know. We currently do not offer a paid security bounty program, but are not
|
||||
ruling it out in the future.
|
||||
|
||||
@@ -39,7 +39,7 @@ A great way to contribute to the project is to send a detailed report when you
|
||||
encounter an issue. We always appreciate a well-written, thorough bug report,
|
||||
and will thank you for it!
|
||||
|
||||
Check that [our issue database](https://github.com/moby/moby/issues)
|
||||
Check that [our issue database](https://github.com/docker/docker/issues)
|
||||
doesn't already include that problem or suggestion before submitting an issue.
|
||||
If you find a match, you can use the "subscribe" button to get notified on
|
||||
updates. Do *not* leave random "+1" or "I have this too" comments, as they
|
||||
@@ -66,7 +66,7 @@ This section gives the experienced contributor some tips and guidelines.
|
||||
|
||||
Not sure if that typo is worth a pull request? Found a bug and know how to fix
|
||||
it? Do it! We will appreciate it. Any significant improvement should be
|
||||
documented as [a GitHub issue](https://github.com/moby/moby/issues) before
|
||||
documented as [a GitHub issue](https://github.com/docker/docker/issues) before
|
||||
anybody starts working on it.
|
||||
|
||||
We are always thrilled to receive pull requests. We do our best to process them
|
||||
@@ -83,7 +83,11 @@ contributions, see [the advanced contribution
|
||||
section](https://docs.docker.com/opensource/workflow/advanced-contributing/) in
|
||||
the contributors guide.
|
||||
|
||||
### Connect with other Moby Project contributors
|
||||
We try hard to keep Docker lean and focused. Docker can't do everything for
|
||||
everybody. This means that we might decide against incorporating a new feature.
|
||||
However, there might be a way to implement that feature *on top of* Docker.
|
||||
|
||||
### Talking to other Docker users and contributors
|
||||
|
||||
<table class="tg">
|
||||
<col width="45%">
|
||||
@@ -92,29 +96,52 @@ the contributors guide.
|
||||
<td>Forums</td>
|
||||
<td>
|
||||
A public forum for users to discuss questions and explore current design patterns and
|
||||
best practices about all the Moby projects. To participate, log in with your Github
|
||||
account or create an account at <a href="https://forums.mobyproject.org" target="_blank">https://forums.mobyproject.org</a>.
|
||||
best practices about Docker and related projects in the Docker Ecosystem. To participate,
|
||||
just log in with your Docker Hub account on <a href="https://forums.docker.com" target="_blank">https://forums.docker.com</a>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Slack</td>
|
||||
<td>Internet Relay Chat (IRC)</td>
|
||||
<td>
|
||||
<p>
|
||||
Register for the Docker Community Slack at
|
||||
<a href="https://community.docker.com/registrations/groups/4316" target="_blank">https://community.docker.com/registrations/groups/4316</a>.
|
||||
We use the #moby-project channel for general discussion, and there are separate channels for other Moby projects such as #containerd.
|
||||
Archives are available at <a href="https://dockercommunity.slackarchive.io/" target="_blank">https://dockercommunity.slackarchive.io/</a>.
|
||||
IRC a direct line to our most knowledgeable Docker users; we have
|
||||
both the <code>#docker</code> and <code>#docker-dev</code> group on
|
||||
<strong>irc.freenode.net</strong>.
|
||||
IRC is a rich chat protocol but it can overwhelm new users. You can search
|
||||
<a href="https://botbot.me/freenode/docker/#" target="_blank">our chat archives</a>.
|
||||
</p>
|
||||
<p>
|
||||
Read our <a href="https://docs.docker.com/opensource/get-help/#irc-quickstart" target="_blank">IRC quickstart guide</a>
|
||||
for an easy way to get started.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Google Group</td>
|
||||
<td>
|
||||
The <a href="https://groups.google.com/forum/#!forum/docker-dev" target="_blank">docker-dev</a>
|
||||
group is for contributors and other people contributing to the Docker project.
|
||||
You can join them without a google account by sending an email to
|
||||
<a href="mailto:docker-dev+subscribe@googlegroups.com">docker-dev+subscribe@googlegroups.com</a>.
|
||||
After receiving the join-request message, you can simply reply to that to confirm the subscription.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Twitter</td>
|
||||
<td>
|
||||
You can follow <a href="https://twitter.com/moby/" target="_blank">Moby Project Twitter feed</a>
|
||||
You can follow <a href="https://twitter.com/docker/" target="_blank">Docker's Twitter feed</a>
|
||||
to get updates on our products. You can also tweet us questions or just
|
||||
share blogs or stories.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stack Overflow</td>
|
||||
<td>
|
||||
Stack Overflow has over 17000 Docker questions listed. We regularly
|
||||
monitor <a href="https://stackoverflow.com/search?tab=newest&q=docker" target="_blank">Docker questions</a>
|
||||
and so do many other knowledgeable Docker users.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -128,11 +155,10 @@ Fork the repository and make changes on your fork in a feature branch:
|
||||
your intentions, and name it XXXX-something where XXXX is the number of the
|
||||
issue.
|
||||
|
||||
Submit tests for your changes. See [TESTING.md](./TESTING.md) for details.
|
||||
|
||||
If your changes need integration tests, write them against the API. The `cli`
|
||||
integration tests are slowly either migrated to API tests or moved away as unit
|
||||
tests in `docker/cli` and end-to-end tests for Docker.
|
||||
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](https://docs.docker.com/opensource/project/test-and-docs/) on your branch before
|
||||
submitting a pull request.
|
||||
|
||||
Update the documentation when creating or modifying features. Test your
|
||||
documentation changes for clarity, concision, and correctness, as well as a
|
||||
@@ -147,64 +173,10 @@ committing your changes. Most editors have plug-ins that do this automatically.
|
||||
Pull request descriptions should be as clear as possible and include a reference
|
||||
to all the issues that they address.
|
||||
|
||||
### Successful Changes
|
||||
|
||||
Before contributing large or high impact changes, make the effort to coordinate
|
||||
with the maintainers of the project before submitting a pull request. This
|
||||
prevents you from doing extra work that may or may not be merged.
|
||||
|
||||
Large PRs that are just submitted without any prior communication are unlikely
|
||||
to be successful.
|
||||
|
||||
While pull requests are the methodology for submitting changes to code, changes
|
||||
are much more likely to be accepted if they are accompanied by additional
|
||||
engineering work. While we don't define this explicitly, most of these goals
|
||||
are accomplished through communication of the design goals and subsequent
|
||||
solutions. Often times, it helps to first state the problem before presenting
|
||||
solutions.
|
||||
|
||||
Typically, the best methods of accomplishing this are to submit an issue,
|
||||
stating the problem. This issue can include a problem statement and a
|
||||
checklist with requirements. If solutions are proposed, alternatives should be
|
||||
listed and eliminated. Even if the criteria for elimination of a solution is
|
||||
frivolous, say so.
|
||||
|
||||
Larger changes typically work best with design documents. These are focused on
|
||||
providing context to the design at the time the feature was conceived and can
|
||||
inform future documentation contributions.
|
||||
|
||||
### Commit Messages
|
||||
|
||||
Commit messages must start with a capitalized and short summary (max. 50 chars)
|
||||
written in the imperative, followed by an optional, more detailed explanatory
|
||||
text which is separated from the summary by an empty line.
|
||||
|
||||
Commit messages should follow best practices, including explaining the context
|
||||
of the problem and how it was solved, including in caveats or follow up changes
|
||||
required. They should tell the story of the change and provide readers
|
||||
understanding of what led to it.
|
||||
|
||||
If you're lost about what this even means, please see [How to Write a Git
|
||||
Commit Message](http://chris.beams.io/posts/git-commit/) for a start.
|
||||
|
||||
In practice, the best approach to maintaining a nice commit message is to
|
||||
leverage a `git add -p` and `git commit --amend` to formulate a solid
|
||||
changeset. This allows one to piece together a change, as information becomes
|
||||
available.
|
||||
|
||||
If you squash a series of commits, don't just submit that. Re-write the commit
|
||||
message, as if the series of commits was a single stroke of brilliance.
|
||||
|
||||
That said, there is no requirement to have a single commit for a PR, as long as
|
||||
each commit tells the story. For example, if there is a feature that requires a
|
||||
package, it might make sense to have the package in a separate commit then have
|
||||
a subsequent commit that uses it.
|
||||
|
||||
Remember, you're telling part of the story with the commit message. Don't make
|
||||
your chapter weird.
|
||||
|
||||
### Review
|
||||
|
||||
Code review comments may be added to your pull request. Discuss, then make the
|
||||
suggested modifications and push additional commits to your feature branch. Post
|
||||
a comment after pushing. New commits show up in the pull request automatically,
|
||||
@@ -225,9 +197,10 @@ calling it in another file constitute a single logical unit of work. The very
|
||||
high majority of submissions should have a single commit, so if in doubt: squash
|
||||
down to one.
|
||||
|
||||
After every commit, [make sure the test suite passes](./TESTING.md). Include
|
||||
documentation changes in the same pull request so that a revert would remove
|
||||
all traces of the feature or fix.
|
||||
After every commit, [make sure the test suite passes]
|
||||
(https://docs.docker.com/opensource/project/test-and-docs/). Include documentation
|
||||
changes in the same pull request so that a revert would remove all traces of
|
||||
the feature or fix.
|
||||
|
||||
Include an issue reference like `Closes #XXXX` or `Fixes #XXXX` in commits that
|
||||
close an issue. Including references automatically closes the issue on a merge.
|
||||
@@ -239,11 +212,15 @@ Please see the [Coding Style](#coding-style) for further guidelines.
|
||||
|
||||
### Merge approval
|
||||
|
||||
Moby maintainers use LGTM (Looks Good To Me) in comments on the code review to
|
||||
indicate acceptance, or use the Github review approval feature.
|
||||
Docker maintainers use LGTM (Looks Good To Me) in comments on the code review to
|
||||
indicate acceptance.
|
||||
|
||||
For an explanation of the review and approval process see the
|
||||
[REVIEWING](project/REVIEWING.md) page.
|
||||
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
|
||||
needs an absolute majority from the maintainers of `docs/` AND, separately, an
|
||||
absolute majority of the maintainers of `registry/`.
|
||||
|
||||
For more details, see the [MAINTAINERS](MAINTAINERS) page.
|
||||
|
||||
### Sign your work
|
||||
|
||||
@@ -303,46 +280,17 @@ commit automatically with `git commit -s`.
|
||||
### How can I become a maintainer?
|
||||
|
||||
The procedures for adding new maintainers are explained in the
|
||||
[/project/GOVERNANCE.md](/project/GOVERNANCE.md)
|
||||
file in this repository.
|
||||
global [MAINTAINERS](https://github.com/docker/opensource/blob/master/MAINTAINERS)
|
||||
file in the [https://github.com/docker/opensource/](https://github.com/docker/opensource/)
|
||||
repository.
|
||||
|
||||
Don't forget: being a maintainer is a time investment. Make sure you
|
||||
will have time to make yourself available. You don't have to be a
|
||||
maintainer to make a difference on the project!
|
||||
|
||||
### Manage issues and pull requests using the Derek bot
|
||||
## Docker community guidelines
|
||||
|
||||
If you want to help label, assign, close or reopen issues or pull requests
|
||||
without commit rights, ask a maintainer to add your Github handle to the
|
||||
`.DEREK.yml` file. [Derek](https://github.com/alexellis/derek) is a bot that extends
|
||||
Github's user permissions to help non-committers to manage issues and pull requests simply by commenting.
|
||||
|
||||
For example:
|
||||
|
||||
* Labels
|
||||
|
||||
```
|
||||
Derek add label: kind/question
|
||||
Derek remove label: status/claimed
|
||||
```
|
||||
|
||||
* Assign work
|
||||
|
||||
```
|
||||
Derek assign: username
|
||||
Derek unassign: me
|
||||
```
|
||||
|
||||
* Manage issues and PRs
|
||||
|
||||
```
|
||||
Derek close
|
||||
Derek reopen
|
||||
```
|
||||
|
||||
## Moby community guidelines
|
||||
|
||||
We want to keep the Moby community awesome, growing and collaborative. We need
|
||||
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:
|
||||
|
||||
@@ -370,11 +318,6 @@ guidelines for the community as a whole:
|
||||
used to ping maintainers to review a pull request, a proposal or an
|
||||
issue.
|
||||
|
||||
The open source governance for this repository is handled via the [Moby Technical Steering Committee (TSC)](https://github.com/moby/tsc)
|
||||
charter. For any concerns with the community process regarding technical contributions,
|
||||
please contact the TSC. More information on project governance is available in
|
||||
our [project/GOVERNANCE.md](/project/GOVERNANCE.md) document.
|
||||
|
||||
### Guideline violations — 3 strikes method
|
||||
|
||||
The point of this section is not to find opportunities to punish people, but we
|
||||
|
||||
393
Dockerfile
393
Dockerfile
@@ -2,56 +2,164 @@
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Use make to build a development environment image and run it in a container.
|
||||
# # This is slow the first time.
|
||||
# make BIND_DIR=. shell
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker .
|
||||
#
|
||||
# The following commands are executed inside the running container.
|
||||
|
||||
# # Make a dockerd binary.
|
||||
# # hack/make.sh binary
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Install dockerd to /usr/local/bin
|
||||
# # make install
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
|
||||
#
|
||||
# # Run unit tests
|
||||
# # hack/test/unit
|
||||
#
|
||||
# # Run tests e.g. integration, py
|
||||
# # hack/make.sh binary test-integration test-docker-py
|
||||
# # Publish a release:
|
||||
# docker run --privileged \
|
||||
# -e AWS_S3_BUCKET=baz \
|
||||
# -e AWS_ACCESS_KEY=foo \
|
||||
# -e AWS_SECRET_KEY=bar \
|
||||
# -e GPG_PASSPHRASE=gloubiboulga \
|
||||
# docker hack/release.sh
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM golang:1.10.6 AS base
|
||||
# FIXME(vdemeester) this is kept for other script depending on it to not fail right away
|
||||
# Remove this once the other scripts uses something else to detect the version
|
||||
ENV GO_VERSION 1.10.6
|
||||
FROM debian:jessie
|
||||
|
||||
# allow replacing httpredir or deb mirror
|
||||
ARG APT_MIRROR=deb.debian.org
|
||||
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
FROM base AS criu
|
||||
# Install CRIU for checkpoint/restore support
|
||||
ENV CRIU_VERSION 3.6
|
||||
# Install dependency packages specific to criu
|
||||
# Add zfs ppa
|
||||
RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys E871F18B51E0147C77796AC81196BA81F6B0FC61 \
|
||||
|| apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys E871F18B51E0147C77796AC81196BA81F6B0FC61
|
||||
RUN echo deb http://ppa.launchpad.net/zfs-native/stable/ubuntu trusty main > /etc/apt/sources.list.d/zfs.list
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libnet-dev \
|
||||
apparmor \
|
||||
apt-utils \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
binutils-mingw-w64 \
|
||||
bsdmainutils \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
clang \
|
||||
cmake \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
gcc-mingw-w64 \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libnl-3-dev \
|
||||
libprotobuf-c0-dev \
|
||||
libprotobuf-dev \
|
||||
libnl-3-dev \
|
||||
libcap-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
net-tools \
|
||||
pkg-config \
|
||||
protobuf-compiler \
|
||||
protobuf-c-compiler \
|
||||
python-protobuf \
|
||||
&& mkdir -p /usr/src/criu \
|
||||
&& curl -sSL https://github.com/checkpoint-restore/criu/archive/v${CRIU_VERSION}.tar.gz | tar -C /usr/src/criu/ -xz --strip-components=1 \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
ubuntu-zfs \
|
||||
xfsprogs \
|
||||
vim-common \
|
||||
libzfs-dev \
|
||||
tar \
|
||||
zip \
|
||||
--no-install-recommends \
|
||||
&& pip install awscli==1.10.15
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Configure the container for OSX cross compilation
|
||||
ENV OSX_SDK MacOSX10.11.sdk
|
||||
ENV OSX_CROSS_COMMIT a9317c18a3a457ca0a657f08cc4d0d43c6cf8953
|
||||
RUN set -x \
|
||||
&& export OSXCROSS_PATH="/osxcross" \
|
||||
&& git clone https://github.com/tpoechtrager/osxcross.git $OSXCROSS_PATH \
|
||||
&& ( cd $OSXCROSS_PATH && git checkout -q $OSX_CROSS_COMMIT) \
|
||||
&& curl -sSL https://s3.dockerproject.org/darwin/v2/${OSX_SDK}.tar.xz -o "${OSXCROSS_PATH}/tarballs/${OSX_SDK}.tar.xz" \
|
||||
&& UNATTENDED=yes OSX_VERSION_MIN=10.6 ${OSXCROSS_PATH}/build.sh
|
||||
ENV PATH /osxcross/target/bin:$PATH
|
||||
|
||||
# Install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install Go
|
||||
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
|
||||
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
|
||||
# with a heads-up.
|
||||
ENV GO_VERSION 1.7.5
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# Compile Go for cross compilation
|
||||
ENV DOCKER_CROSSPLATFORMS \
|
||||
linux/386 linux/arm \
|
||||
darwin/amd64 \
|
||||
freebsd/amd64 freebsd/386 freebsd/arm \
|
||||
windows/amd64 windows/386 \
|
||||
solaris/amd64
|
||||
|
||||
# Dependency for golint
|
||||
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT)
|
||||
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# Install CRIU for checkpoint/restore support
|
||||
ENV CRIU_VERSION 2.2
|
||||
RUN mkdir -p /usr/src/criu \
|
||||
&& curl -sSL https://github.com/xemul/criu/archive/v${CRIU_VERSION}.tar.gz | tar -v -C /usr/src/criu/ -xz --strip-components=1 \
|
||||
&& cd /usr/src/criu \
|
||||
&& make \
|
||||
&& make PREFIX=/build/ install-criu
|
||||
&& make install-criu
|
||||
|
||||
FROM base AS registry
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
@@ -63,181 +171,76 @@ RUN set -x \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -buildmode=pie -o /build/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& case $(dpkg --print-architecture) in \
|
||||
amd64|ppc64*|s390x) \
|
||||
(cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1"); \
|
||||
GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH"; \
|
||||
go build -buildmode=pie -o /build/registry-v2-schema1 github.com/docker/distribution/cmd/registry; \
|
||||
;; \
|
||||
esac \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
|
||||
|
||||
FROM base AS docker-py
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
|
||||
RUN git clone https://github.com/docker/docker-py.git /build \
|
||||
&& cd /build \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT
|
||||
|
||||
|
||||
|
||||
FROM base AS swagger
|
||||
# Install go-swagger for validating swagger.yaml
|
||||
ENV GO_SWAGGER_COMMIT c28258affb0b6251755d92489ef685af8d4ff3eb
|
||||
# Install notary and notary-server
|
||||
ENV NOTARY_VERSION v0.4.2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/go-swagger/go-swagger.git "$GOPATH/src/github.com/go-swagger/go-swagger" \
|
||||
&& (cd "$GOPATH/src/github.com/go-swagger/go-swagger" && git checkout -q "$GO_SWAGGER_COMMIT") \
|
||||
&& go build -o /build/swagger github.com/go-swagger/go-swagger/cmd/swagger \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
|
||||
FROM base AS frozen-images
|
||||
RUN apt-get update && apt-get install -y jq ca-certificates --no-install-recommends
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /
|
||||
RUN /download-frozen-image-v2.sh /build \
|
||||
buildpack-deps:jessie@sha256:dd86dced7c9cd2a724e779730f0a53f93b7ef42228d4344b25ce9a42a1486251 \
|
||||
busybox:latest@sha256:bbc3a03235220b170ba48a157dd097dd1379299370e1ed99ce976df0355d24f0 \
|
||||
busybox:glibc@sha256:0b55a30394294ab23b9afd58fab94e61a923f5834fba7ddbae7f8e0c11ba85e6 \
|
||||
debian:jessie@sha256:287a20c5f73087ab406e6b364833e3fb7b3ae63ca0eb3486555dc27ed32c6e60 \
|
||||
hello-world:latest@sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
|
||||
# See also ensureFrozenImagesLinux() in "integration-cli/fixtures_linux_daemon_test.go" (which needs to be updated when adding images to this list)
|
||||
|
||||
# Just a little hack so we don't have to install these deps twice, once for runc and once for dockerd
|
||||
FROM base AS runtime-dev
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libapparmor-dev \
|
||||
libseccomp-dev
|
||||
|
||||
|
||||
FROM base AS tomlv
|
||||
ENV INSTALL_BINARY_NAME=tomlv
|
||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
||||
|
||||
FROM base AS vndr
|
||||
ENV INSTALL_BINARY_NAME=vndr
|
||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
||||
|
||||
FROM base AS containerd
|
||||
RUN apt-get update && apt-get install -y btrfs-tools
|
||||
ENV INSTALL_BINARY_NAME=containerd
|
||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
||||
|
||||
FROM base AS proxy
|
||||
ENV INSTALL_BINARY_NAME=proxy
|
||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
||||
|
||||
FROM base AS gometalinter
|
||||
ENV INSTALL_BINARY_NAME=gometalinter
|
||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
||||
|
||||
FROM base AS dockercli
|
||||
ENV INSTALL_BINARY_NAME=dockercli
|
||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
||||
|
||||
FROM runtime-dev AS runc
|
||||
ENV INSTALL_BINARY_NAME=runc
|
||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||
COPY git-bundles /go/src/github.com/docker/docker/git-bundles
|
||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
||||
|
||||
FROM base AS tini
|
||||
RUN apt-get update && apt-get install -y cmake vim-common
|
||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||
ENV INSTALL_BINARY_NAME=tini
|
||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
||||
|
||||
|
||||
|
||||
# TODO: Some of this is only really needed for testing, it would be nice to split this up
|
||||
FROM runtime-dev AS dev
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv /go/src/github.com/docker/docker/.bashrc ~/.bashrc
|
||||
# Activate bash completion and include Docker's completion if mounted with DOCKER_BASH_COMPLETION_PATH
|
||||
RUN echo "source /usr/share/bash-completion/bash_completion" >> /etc/bash.bashrc
|
||||
RUN ln -s /usr/local/completion/bash/docker /etc/bash_completion.d/docker
|
||||
RUN ldconfig
|
||||
# This should only install packages that are specifically needed for the dev environment and nothing else
|
||||
# Do you really need to add another package here? Can it be done in a different build stage?
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
iptables \
|
||||
jq \
|
||||
libdevmapper-dev \
|
||||
libudev-dev \
|
||||
libsystemd-dev \
|
||||
binutils-mingw-w64 \
|
||||
g++-mingw-w64-x86-64 \
|
||||
net-tools \
|
||||
pigz \
|
||||
python-backports.ssl-match-hostname \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-requests \
|
||||
python-setuptools \
|
||||
python-websocket \
|
||||
python-wheel \
|
||||
thin-provisioning-tools \
|
||||
vim \
|
||||
vim-common \
|
||||
xfsprogs \
|
||||
zip \
|
||||
bzip2 \
|
||||
xz-utils \
|
||||
--no-install-recommends
|
||||
COPY --from=swagger /build/swagger* /usr/local/bin/
|
||||
COPY --from=frozen-images /build/ /docker-frozen-images
|
||||
COPY --from=gometalinter /build/ /usr/local/bin/
|
||||
COPY --from=tomlv /build/ /usr/local/bin/
|
||||
COPY --from=vndr /build/ /usr/local/bin/
|
||||
COPY --from=tini /build/ /usr/local/bin/
|
||||
COPY --from=runc /build/ /usr/local/bin/
|
||||
COPY --from=containerd /build/ /usr/local/bin/
|
||||
COPY --from=proxy /build/ /usr/local/bin/
|
||||
COPY --from=dockercli /build/ /usr/local/cli
|
||||
COPY --from=registry /build/registry* /usr/local/bin/
|
||||
COPY --from=criu /build/ /usr/local/
|
||||
COPY --from=docker-py /build/ /docker-py
|
||||
# TODO: This is for the docker-py tests, which shouldn't really be needed for
|
||||
# this image, but currently CI is expecting to run this image. This should be
|
||||
# split out into a separate image, including all the `python-*` deps installed
|
||||
# above.
|
||||
RUN cd /docker-py \
|
||||
&& pip install docker-pycreds==0.2.1 \
|
||||
&& pip install yamllint==1.5.0 \
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
ENV PATH=/usr/local/cli:$PATH
|
||||
ENV DOCKER_BUILDTAGS apparmor seccomp selinux
|
||||
# Options for hack/validate/gometalinter
|
||||
ENV GOMETALINTER_OPTS="--deadline=2m"
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
# Install yamllint for validating swagger.yaml
|
||||
RUN pip install yamllint==1.5.0
|
||||
|
||||
# Install go-swagger for validating swagger.yaml
|
||||
ENV GO_SWAGGER_COMMIT c28258affb0b6251755d92489ef685af8d4ff3eb
|
||||
RUN git clone https://github.com/go-swagger/go-swagger.git /go/src/github.com/go-swagger/go-swagger \
|
||||
&& (cd /go/src/github.com/go-swagger/go-swagger && git checkout -q $GO_SWAGGER_COMMIT) \
|
||||
&& go install -v github.com/go-swagger/go-swagger/cmd/swagger
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
# Add integration helps to bashrc
|
||||
RUN echo "source $PWD/hack/make/.integration-test-helpers" >> /etc/bash.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
buildpack-deps:jessie@sha256:25785f89240fbcdd8a74bdaf30dd5599a9523882c6dfc567f2e9ef7cf6f79db6 \
|
||||
busybox:latest@sha256:e4f93f6ed15a0cdd342f5aae387886fba0ab98af0a102da6276eaf24d6e6ade0 \
|
||||
debian:jessie@sha256:f968f10b4b523737e253a97eac59b0d1420b5c19b69928d35801a6373ffe330e \
|
||||
hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
|
||||
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Install tomlv, vndr, runc, containerd, tini, docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy bindata
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
|
||||
175
Dockerfile.aarch64
Normal file
175
Dockerfile.aarch64
Normal file
@@ -0,0 +1,175 @@
|
||||
# This file describes the standard way to build Docker on aarch64, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.aarch64 .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM aarch64/ubuntu:wily
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
cmake \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
g++ \
|
||||
gcc \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
libapparmor-dev \
|
||||
libc6-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-dev \
|
||||
mercurial \
|
||||
net-tools \
|
||||
parallel \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
gccgo \
|
||||
iproute2 \
|
||||
iputils-ping \
|
||||
vim-common \
|
||||
--no-install-recommends
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Fix platform enablement in lvm2 to support aarch64 properly
|
||||
RUN set -e \
|
||||
&& for f in config.guess config.sub; do \
|
||||
curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \
|
||||
done
|
||||
# "arch.c:78:2: error: #error the arch code needs to know about your machine type"
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install Go
|
||||
# We don't have official binary tarballs for ARM64, eigher for Go or bootstrap,
|
||||
# so we use gccgo as bootstrap to build Go from source code.
|
||||
# We don't use the official ARMv6 released binaries as a GOROOT_BOOTSTRAP, because
|
||||
# not all ARM64 platforms support 32-bit mode. 32-bit mode is optional for ARMv8.
|
||||
ENV GO_VERSION 1.7.5
|
||||
RUN mkdir /usr/src/go && curl -fsSL https://golang.org/dl/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/src/go -xz --strip-components=1 \
|
||||
&& cd /usr/src/go/src \
|
||||
&& GOOS=linux GOARCH=arm64 GOROOT_BOOTSTRAP="$(go env GOROOT)" ./make.bash
|
||||
|
||||
ENV PATH /usr/src/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# Only install one version of the registry, because old version which support
|
||||
# schema1 manifests is not working on ARM64, we should skip integration-cli
|
||||
# tests for schema1 manifests on ARM64.
|
||||
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary and notary-server
|
||||
ENV NOTARY_VERSION v0.4.2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
aarch64/buildpack-deps:jessie@sha256:6aa1d6910791b7ac78265fd0798e5abd6cb3f27ae992f6f960f6c303ec9535f2 \
|
||||
aarch64/busybox:latest@sha256:b23a6a37cf269dff6e46d2473b6e227afa42b037e6d23435f1d2bc40fc8c2828 \
|
||||
aarch64/debian:jessie@sha256:4be74a41a7c70ebe887b634b11ffe516cf4fcd56864a54941e56bb49883c3170 \
|
||||
aarch64/hello-world:latest@sha256:65a4a158587b307bb02db4de41b836addb0c35175bdc801367b1ac1ddeb9afda
|
||||
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Install tomlv, vndr, runc, containerd, tini, docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
182
Dockerfile.armhf
Normal file
182
Dockerfile.armhf
Normal file
@@ -0,0 +1,182 @@
|
||||
# This file describes the standard way to build Docker on ARMv7, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.armhf .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM armhf/debian:jessie
|
||||
|
||||
# allow replacing httpredir or deb mirror
|
||||
ARG APT_MIRROR=deb.debian.org
|
||||
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
createrepo \
|
||||
curl \
|
||||
cmake \
|
||||
dpkg-sig \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
net-tools \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
xfsprogs \
|
||||
tar \
|
||||
vim-common \
|
||||
--no-install-recommends \
|
||||
&& pip install awscli==1.10.15
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Install Go
|
||||
ENV GO_VERSION 1.7.5
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# We're building for armhf, which is ARMv7, so let's be explicit about that
|
||||
ENV GOARCH arm
|
||||
ENV GOARM 7
|
||||
|
||||
# Dependency for golint
|
||||
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT)
|
||||
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# Install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
# and schema2 manifests.
|
||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT cb08de17d74bef86ce6c5abe8b240e282f5750be
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary and notary-server
|
||||
ENV NOTARY_VERSION v0.4.2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
armhf/buildpack-deps:jessie@sha256:ca6cce8e5bf5c952129889b5cc15cd6aa8d995d77e55e3749bbaadae50e476cb \
|
||||
armhf/busybox:latest@sha256:d98a7343ac750ffe387e3d514f8521ba69846c216778919b01414b8617cfb3d4 \
|
||||
armhf/debian:jessie@sha256:4a2187483f04a84f9830910fe3581d69b3c985cc045d9f01d8e2f3795b28107b \
|
||||
armhf/hello-world:latest@sha256:161dcecea0225975b2ad5f768058212c1e0d39e8211098666ffa1ac74cfb7791
|
||||
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Install tomlv, vndr, runc, containerd, tini, docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy
|
||||
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
@@ -1,74 +0,0 @@
|
||||
## Step 1: Build tests
|
||||
FROM golang:1.10.6-alpine3.7 as builder
|
||||
|
||||
RUN apk add --update \
|
||||
bash \
|
||||
btrfs-progs-dev \
|
||||
build-base \
|
||||
curl \
|
||||
lvm2-dev \
|
||||
jq \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
RUN mkdir -p /go/src/github.com/docker/docker/
|
||||
WORKDIR /go/src/github.com/docker/docker/
|
||||
|
||||
# Generate frozen images
|
||||
COPY contrib/download-frozen-image-v2.sh contrib/download-frozen-image-v2.sh
|
||||
RUN contrib/download-frozen-image-v2.sh /output/docker-frozen-images \
|
||||
buildpack-deps:jessie@sha256:dd86dced7c9cd2a724e779730f0a53f93b7ef42228d4344b25ce9a42a1486251 \
|
||||
busybox:latest@sha256:bbc3a03235220b170ba48a157dd097dd1379299370e1ed99ce976df0355d24f0 \
|
||||
busybox:glibc@sha256:0b55a30394294ab23b9afd58fab94e61a923f5834fba7ddbae7f8e0c11ba85e6 \
|
||||
debian:jessie@sha256:287a20c5f73087ab406e6b364833e3fb7b3ae63ca0eb3486555dc27ed32c6e60 \
|
||||
hello-world:latest@sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
|
||||
|
||||
# Install dockercli
|
||||
# Please edit hack/dockerfile/install/<name>.installer to update them.
|
||||
COPY hack/dockerfile/install hack/dockerfile/install
|
||||
RUN ./hack/dockerfile/install/install.sh dockercli
|
||||
|
||||
# Set tag and add sources
|
||||
ARG DOCKER_GITCOMMIT
|
||||
ENV DOCKER_GITCOMMIT=${DOCKER_GITCOMMIT:-undefined}
|
||||
ADD . .
|
||||
|
||||
# Build DockerSuite.TestBuild* dependency
|
||||
RUN CGO_ENABLED=0 go build -buildmode=pie -o /output/httpserver github.com/docker/docker/contrib/httpserver
|
||||
|
||||
# Build the integration tests and copy the resulting binaries to /output/tests
|
||||
RUN hack/make.sh build-integration-test-binary
|
||||
RUN mkdir -p /output/tests && find . -name test.main -exec cp --parents '{}' /output/tests \;
|
||||
|
||||
## Step 2: Generate testing image
|
||||
FROM alpine:3.7 as runner
|
||||
|
||||
# GNU tar is used for generating the emptyfs image
|
||||
RUN apk add --update \
|
||||
bash \
|
||||
ca-certificates \
|
||||
g++ \
|
||||
git \
|
||||
iptables \
|
||||
pigz \
|
||||
tar \
|
||||
xz \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN addgroup docker && adduser -D -G docker unprivilegeduser -s /bin/ash
|
||||
|
||||
COPY contrib/httpserver/Dockerfile /tests/contrib/httpserver/Dockerfile
|
||||
COPY contrib/syscall-test /tests/contrib/syscall-test
|
||||
COPY integration-cli/fixtures /tests/integration-cli/fixtures
|
||||
|
||||
COPY hack/test/e2e-run.sh /scripts/run.sh
|
||||
COPY hack/make/.ensure-emptyfs /scripts/ensure-emptyfs.sh
|
||||
|
||||
COPY --from=builder /output/docker-frozen-images /docker-frozen-images
|
||||
COPY --from=builder /output/httpserver /tests/contrib/httpserver/httpserver
|
||||
COPY --from=builder /output/tests /tests
|
||||
COPY --from=builder /usr/local/bin/docker /usr/bin/docker
|
||||
|
||||
ENV DOCKER_REMOTE_DAEMON=1 DOCKER_INTEGRATION_DAEMON_DEST=/
|
||||
|
||||
ENTRYPOINT ["/scripts/run.sh"]
|
||||
188
Dockerfile.ppc64le
Normal file
188
Dockerfile.ppc64le
Normal file
@@ -0,0 +1,188 @@
|
||||
# This file describes the standard way to build Docker on ppc64le, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.ppc64le .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM ppc64le/debian:jessie
|
||||
|
||||
# allow replacing httpredir or deb mirror
|
||||
ARG APT_MIRROR=deb.debian.org
|
||||
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
cmake \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
net-tools \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
xfsprogs \
|
||||
tar \
|
||||
vim-common \
|
||||
--no-install-recommends
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Fix platform enablement in lvm2 to support ppc64le properly
|
||||
RUN set -e \
|
||||
&& for f in config.guess config.sub; do \
|
||||
curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \
|
||||
done
|
||||
# "arch.c:78:2: error: #error the arch code needs to know about your machine type"
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Install seccomp: the version shipped in jessie is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
|
||||
# Install Go
|
||||
# NOTE: official ppc64le go binaries weren't available until go 1.6.4 and 1.7.4
|
||||
ENV GO_VERSION 1.7.5
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# Dependency for golint
|
||||
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT)
|
||||
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
# and schema2 manifests.
|
||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary and notary-server
|
||||
ENV NOTARY_VERSION v0.4.2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
ppc64le/buildpack-deps:jessie@sha256:902bfe4ef1389f94d143d64516dd50a2de75bca2e66d4a44b1d73f63ddf05dda \
|
||||
ppc64le/busybox:latest@sha256:38bb82085248d5a3c24bd7a5dc146f2f2c191e189da0441f1c2ca560e3fc6f1b \
|
||||
ppc64le/debian:jessie@sha256:412845f51b6ab662afba71bc7a716e20fdb9b84f185d180d4c7504f8a75c4f91 \
|
||||
ppc64le/hello-world:latest@sha256:186a40a9a02ca26df0b6c8acdfb8ac2f3ae6678996a838f977e57fac9d963974
|
||||
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Install tomlv, vndr, runc, containerd, tini, docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
190
Dockerfile.s390x
Normal file
190
Dockerfile.s390x
Normal file
@@ -0,0 +1,190 @@
|
||||
# This file describes the standard way to build Docker on s390x, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.s390x .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM s390x/gcc:6.1
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
cmake \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
net-tools \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
xfsprogs \
|
||||
tar \
|
||||
vim-common \
|
||||
--no-install-recommends
|
||||
|
||||
# glibc in Debian has a bug specific to s390x that won't be fixed until Debian 8.6 is released
|
||||
# - https://github.com/docker/docker/issues/24748
|
||||
# - https://sourceware.org/git/?p=glibc.git;a=commit;h=890b7a4b33d482b5c768ab47d70758b80227e9bc
|
||||
# - https://sourceware.org/git/?p=glibc.git;a=commit;h=2e807f29595eb5b1e5d0decc6e356a3562ecc58e
|
||||
RUN echo 'deb http://httpredir.debian.org/debian jessie-proposed-updates main' >> /etc/apt/sources.list.d/pu.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y libc6 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install seccomp: the version shipped in jessie is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Fix platform enablement in lvm2 to support s390x properly
|
||||
RUN set -e \
|
||||
&& for f in config.guess config.sub; do \
|
||||
curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \
|
||||
done
|
||||
# "arch.c:78:2: error: #error the arch code needs to know about your machine type"
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
ENV GO_VERSION 1.7.5
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-s390x.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go
|
||||
|
||||
# Dependency for golint
|
||||
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT)
|
||||
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
# and schema2 manifests.
|
||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary and notary-server
|
||||
ENV NOTARY_VERSION v0.4.2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor selinux seccomp
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
s390x/buildpack-deps:jessie@sha256:4d1381224acaca6c4bfe3604de3af6972083a8558a99672cb6989c7541780099 \
|
||||
s390x/busybox:latest@sha256:dd61522c983884a66ed72d60301925889028c6d2d5e0220a8fe1d9b4c6a4f01b \
|
||||
s390x/debian:jessie@sha256:b74c863400909eff3c5e196cac9bfd1f6333ce47aae6a38398d87d5875da170a \
|
||||
s390x/hello-world:latest@sha256:780d80b3a7677c3788c0d5cd9168281320c8d4a6d9183892d8ee5cdd610f5699
|
||||
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Install tomlv, vndr, runc, containerd, tini, docker-proxy
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
@@ -1,11 +1,11 @@
|
||||
# docker build -t docker:simple -f Dockerfile.simple .
|
||||
# docker run --rm docker:simple hack/make.sh dynbinary
|
||||
# docker run --rm --privileged docker:simple hack/dind hack/make.sh test-unit
|
||||
# docker run --rm --privileged -v /var/lib/docker docker:simple hack/dind hack/make.sh dynbinary test-integration
|
||||
# docker run --rm --privileged -v /var/lib/docker docker:simple hack/dind hack/make.sh dynbinary test-integration-cli
|
||||
|
||||
# This represents the bare minimum required to build and test Docker.
|
||||
|
||||
FROM debian:stretch
|
||||
FROM debian:jessie
|
||||
|
||||
# allow replacing httpredir or deb mirror
|
||||
ARG APT_MIRROR=deb.debian.org
|
||||
@@ -23,12 +23,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
libapparmor-dev \
|
||||
libdevmapper-dev \
|
||||
libseccomp-dev \
|
||||
libsqlite3-dev \
|
||||
\
|
||||
ca-certificates \
|
||||
e2fsprogs \
|
||||
iptables \
|
||||
pkg-config \
|
||||
pigz \
|
||||
procps \
|
||||
xfsprogs \
|
||||
xz-utils \
|
||||
@@ -37,12 +36,26 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
vim-common \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.3.1
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install Go
|
||||
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
|
||||
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
|
||||
# with a heads-up.
|
||||
# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
|
||||
ENV GO_VERSION 1.10.6
|
||||
ENV GO_VERSION 1.7.5
|
||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
@@ -50,12 +63,10 @@ ENV GOPATH /go
|
||||
ENV CGO_LDFLAGS -L/lib
|
||||
|
||||
# Install runc, containerd, tini and docker-proxy
|
||||
# Please edit hack/dockerfile/install/<name>.installer to update them.
|
||||
COPY hack/dockerfile/install hack/dockerfile/install
|
||||
RUN for i in runc containerd tini proxy dockercli; \
|
||||
do hack/dockerfile/install/install.sh $i; \
|
||||
done
|
||||
ENV PATH=/usr/local/cli:$PATH
|
||||
# Please edit hack/dockerfile/install-binaries.sh to update them.
|
||||
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
|
||||
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
|
||||
RUN /tmp/install-binaries.sh runc containerd tini proxy
|
||||
|
||||
ENV AUTO_GOPATH 1
|
||||
WORKDIR /usr/src/docker
|
||||
|
||||
20
Dockerfile.solaris
Normal file
20
Dockerfile.solaris
Normal file
@@ -0,0 +1,20 @@
|
||||
# Defines an image that hosts a native Docker build environment for Solaris
|
||||
# TODO: Improve stub
|
||||
|
||||
FROM solaris:latest
|
||||
|
||||
# compile and runtime deps
|
||||
RUN pkg install --accept \
|
||||
git \
|
||||
gnu-coreutils \
|
||||
gnu-make \
|
||||
gnu-tar \
|
||||
diagnostic/top \
|
||||
golang \
|
||||
library/golang/* \
|
||||
developer/gcc-*
|
||||
|
||||
ENV GOPATH /go/:/usr/lib/gocode/1.5/
|
||||
ENV DOCKER_CROSSPLATFORMS solaris/amd64
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
@@ -71,9 +71,8 @@
|
||||
#
|
||||
# 4. Build the docker executable binaries by running one of the following:
|
||||
#
|
||||
# >> $DOCKER_GITCOMMIT=(git rev-parse --short HEAD)
|
||||
# >> docker run --name binaries -e DOCKER_GITCOMMIT=$DOCKER_GITCOMMIT nativebuildimage hack\make.ps1 -Binary
|
||||
# >> docker run --name binaries -e DOCKER_GITCOMMIT=$DOCKER_GITCOMMIT -m 2GB nativebuildimage hack\make.ps1 -Binary (if using Hyper-V containers)
|
||||
# >> docker run --name binaries nativebuildimage hack\make.ps1 -Binary
|
||||
# >> docker run --name binaries -m 2GB nativebuildimage hack\make.ps1 -Binary (if using Hyper-V containers)
|
||||
#
|
||||
#
|
||||
# 5. Copy the binaries out of the container, replacing HostPath with an appropriate destination
|
||||
@@ -99,14 +98,19 @@
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# The validation tests can only run directly on the host. This is because they calculate
|
||||
# information from the git repo, but the .git directory is not passed into the image as
|
||||
# it is excluded via .dockerignore. Run the following from a Windows PowerShell prompt
|
||||
# (elevation is not required): (Note Go must be installed to run these tests)
|
||||
# The validation tests can either run in a container, or directly on the host. To run in a
|
||||
# container, ensure you have created the nativebuildimage above. Then run one of the
|
||||
# following from an (elevated) Windows PowerShell prompt:
|
||||
#
|
||||
# >> docker run --rm nativebuildimage hack\make.ps1 -DCO -PkgImports -GoFormat
|
||||
# >> docker run --rm -m 2GB nativebuildimage hack\make.ps1 -DCO -PkgImports -GoFormat (if using Hyper-V containers)
|
||||
|
||||
# To run the validation tests on the host, from the root of the repository, run the
|
||||
# following from a Windows PowerShell prompt (elevation is not required): (Note Go
|
||||
# must be installed to run these tests)
|
||||
#
|
||||
# >> hack\make.ps1 -DCO -PkgImports -GoFormat
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -120,7 +124,7 @@
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# To run unit tests and binary build, ensure you have created the nativebuildimage above. Then
|
||||
# To run all tests and binary build, ensure you have created the nativebuildimage above. Then
|
||||
# run one of the following from an (elevated) Windows PowerShell prompt:
|
||||
#
|
||||
# >> docker run nativebuildimage hack\make.ps1 -All
|
||||
@@ -132,8 +136,8 @@
|
||||
# Important notes:
|
||||
# ---------------
|
||||
#
|
||||
# Don't attempt to use a bind mount to pass a local directory as the bundles target
|
||||
# directory. It does not work (golang attempts for follow a mapped folder incorrectly).
|
||||
# Don't attempt to use a bind-mount to pass a local directory as the bundles target
|
||||
# directory. It does not work (golang attempts for follow a mapped folder incorrectly).
|
||||
# Instead, use docker cp as per the example.
|
||||
#
|
||||
# go.zip is not removed from the image as it is used by the Windows CI servers
|
||||
@@ -156,17 +160,20 @@
|
||||
FROM microsoft/windowsservercore
|
||||
|
||||
# Use PowerShell as the default shell
|
||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||
SHELL ["powershell", "-command"]
|
||||
|
||||
# Environment variable notes:
|
||||
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
|
||||
# - FROM_DOCKERFILE is used for detection of building within a container.
|
||||
ENV GO_VERSION=1.10.6 `
|
||||
GIT_VERSION=2.11.1 `
|
||||
ENV GO_VERSION=1.7.5 `
|
||||
GIT_VERSION=2.11.0 `
|
||||
GOPATH=C:\go `
|
||||
FROM_DOCKERFILE=1
|
||||
|
||||
RUN `
|
||||
$ErrorActionPreference = 'Stop'; `
|
||||
$ProgressPreference = 'SilentlyContinue'; `
|
||||
`
|
||||
Function Test-Nano() { `
|
||||
$EditionId = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'EditionID').EditionId; `
|
||||
return (($EditionId -eq 'ServerStandardNano') -or ($EditionId -eq 'ServerDataCenterNano') -or ($EditionId -eq 'NanoServer')); `
|
||||
@@ -198,11 +205,11 @@ RUN `
|
||||
} `
|
||||
} `
|
||||
`
|
||||
setx /M PATH $('C:\git\cmd;C:\git\usr\bin;'+$Env:PATH+';C:\gcc\bin;C:\go\bin'); `
|
||||
setx /M PATH $('C:\git\bin;C:\git\usr\bin;'+$Env:PATH+';C:\gcc\bin;C:\go\bin'); `
|
||||
`
|
||||
Write-Host INFO: Downloading git...; `
|
||||
$location='https://www.nuget.org/api/v2/package/GitForWindows/'+$Env:GIT_VERSION; `
|
||||
Download-File $location C:\gitsetup.zip; `
|
||||
$location='https://github.com/git-for-windows/git/releases/download/v'+$env:GIT_VERSION+'.windows.1/PortableGit-'+$env:GIT_VERSION+'-64-bit.7z.exe'; `
|
||||
Download-File $location C:\gitsetup.7z.exe; `
|
||||
`
|
||||
Write-Host INFO: Downloading go...; `
|
||||
Download-File $('https://golang.org/dl/go'+$Env:GO_VERSION+'.windows-amd64.zip') C:\go.zip; `
|
||||
@@ -216,11 +223,15 @@ RUN `
|
||||
Write-Host INFO: Downloading compiler 3 of 3...; `
|
||||
Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/binutils.zip C:\binutils.zip; `
|
||||
`
|
||||
Write-Host INFO: Installing PS7Zip package...; `
|
||||
Install-Package PS7Zip -Force | Out-Null; `
|
||||
Write-Host INFO: Importing PS7Zip...; `
|
||||
Import-Module PS7Zip -Force; `
|
||||
New-Item C:\git -ItemType Directory | Out-Null ; `
|
||||
cd C:\git; `
|
||||
Write-Host INFO: Extracting git...; `
|
||||
Expand-Archive C:\gitsetup.zip C:\git-tmp; `
|
||||
New-Item -Type Directory C:\git | Out-Null; `
|
||||
Move-Item C:\git-tmp\tools\* C:\git\.; `
|
||||
Remove-Item -Recurse -Force C:\git-tmp; `
|
||||
Expand-7Zip C:\gitsetup.7z.exe | Out-Null; `
|
||||
cd C:\; `
|
||||
`
|
||||
Write-Host INFO: Expanding go...; `
|
||||
Expand-Archive C:\go.zip -DestinationPath C:\; `
|
||||
@@ -236,13 +247,13 @@ RUN `
|
||||
Remove-Item C:\gcc.zip; `
|
||||
Remove-Item C:\runtime.zip; `
|
||||
Remove-Item C:\binutils.zip; `
|
||||
Remove-Item C:\gitsetup.zip; `
|
||||
Remove-Item C:\gitsetup.7z.exe; `
|
||||
`
|
||||
Write-Host INFO: Creating source directory...; `
|
||||
New-Item -ItemType Directory -Path C:\go\src\github.com\docker\docker | Out-Null; `
|
||||
`
|
||||
Write-Host INFO: Configuring git core.autocrlf...; `
|
||||
C:\git\cmd\git config --global core.autocrlf true; `
|
||||
C:\git\bin\git config --global core.autocrlf true; `
|
||||
`
|
||||
Write-Host INFO: Completed
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -176,7 +176,7 @@
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2013-2017 Docker, Inc.
|
||||
Copyright 2013-2016 Docker, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
176
MAINTAINERS
176
MAINTAINERS
@@ -1,14 +1,12 @@
|
||||
# Moby maintainers file
|
||||
# Docker maintainers file
|
||||
#
|
||||
# This file describes the maintainer groups within the moby/moby project.
|
||||
# More detail on Moby project governance is available in the
|
||||
# project/GOVERNANCE.md file found in this repository.
|
||||
# This file describes who runs the docker/docker project and how.
|
||||
# This is a living document - if you see something out of date or missing, speak up!
|
||||
#
|
||||
# It is structured to be consumable by both humans and programs.
|
||||
# To extract its contents programmatically, use any TOML-compliant
|
||||
# parser.
|
||||
#
|
||||
# TODO(estesp): This file should not necessarily depend on docker/opensource
|
||||
# This file is compiled into the MAINTAINERS file in docker/opensource.
|
||||
#
|
||||
[Org]
|
||||
@@ -23,9 +21,14 @@
|
||||
# a subsystem, they are responsible for doing so and holding the
|
||||
# subsystem maintainers accountable. If ownership is unclear, they are the de facto owners.
|
||||
|
||||
# For each release (including minor releases), a "release captain" is assigned from the
|
||||
# pool of core maintainers. Rotation is encouraged across all maintainers, to ensure
|
||||
# the release process is clear and up-to-date.
|
||||
|
||||
people = [
|
||||
"aaronlehmann",
|
||||
"akihirosuda",
|
||||
"aluzzardi",
|
||||
"anusha",
|
||||
"coolljt0725",
|
||||
"cpuguy83",
|
||||
@@ -33,21 +36,22 @@
|
||||
"dnephin",
|
||||
"duglin",
|
||||
"estesp",
|
||||
"icecrime",
|
||||
"jhowardmsft",
|
||||
"johnstep",
|
||||
"justincormack",
|
||||
"lk4d4",
|
||||
"mavenugo",
|
||||
"mhbauer",
|
||||
"mlaventure",
|
||||
"mrjana",
|
||||
"runcom",
|
||||
"stevvooe",
|
||||
"thajeztah",
|
||||
"tianon",
|
||||
"tibor",
|
||||
"tonistiigi",
|
||||
"unclejack",
|
||||
"vdemeester",
|
||||
"vieux",
|
||||
"yongtang"
|
||||
"vieux"
|
||||
]
|
||||
|
||||
[Org."Docs maintainers"]
|
||||
@@ -55,7 +59,9 @@
|
||||
# TODO Describe the docs maintainers role.
|
||||
|
||||
people = [
|
||||
"jamtur01",
|
||||
"misty",
|
||||
"sven",
|
||||
"thajeztah"
|
||||
]
|
||||
|
||||
@@ -72,15 +78,11 @@
|
||||
# - close an issue or pull request when it's inappropriate or off-topic
|
||||
|
||||
people = [
|
||||
"alexellis",
|
||||
"aboch",
|
||||
"andrewhsu",
|
||||
"anonymuse",
|
||||
"chanwit",
|
||||
"fntlnz",
|
||||
"gianarb",
|
||||
"ehazlett",
|
||||
"mgoelzer",
|
||||
"programmerq",
|
||||
"rheinwein",
|
||||
"ripcurld",
|
||||
"thajeztah"
|
||||
]
|
||||
|
||||
@@ -91,16 +93,6 @@
|
||||
# Thank you!
|
||||
|
||||
people = [
|
||||
# Harald Albers is the mastermind behind the bash completion scripts for the
|
||||
# Docker CLI. The completion scripts moved to the Docker CLI repository, so
|
||||
# you can now find him perform his magic in the https://github.com/docker/cli repository.
|
||||
"albers",
|
||||
|
||||
# Andrea Luzzardi started contributing to the Docker codebase in the "dotCloud"
|
||||
# era, even before it was called "Docker". He is one of the architects of both
|
||||
# Swarm and SwarmKit, and its integration into the Docker engine.
|
||||
"aluzzardi",
|
||||
|
||||
# David Calavera contributed many features to Docker, such as an improved
|
||||
# event system, dynamic configuration reloading, volume plugins, fancy
|
||||
# new templating options, and an external client credential store. As a
|
||||
@@ -118,33 +110,6 @@
|
||||
# still stumble into him in our issue tracker, or on IRC.
|
||||
"erikh",
|
||||
|
||||
# Evan Hazlett is the creator of of the Shipyard and Interlock open source projects,
|
||||
# and the author of "Orca", which became the foundation of Docker Universal Control
|
||||
# Plane (UCP). As a maintainer, Evan helped integrating SwarmKit (secrets, tasks)
|
||||
# into the Docker engine.
|
||||
"ehazlett",
|
||||
|
||||
# Arnaud Porterie (AKA "icecrime") was in charge of maintaining the maintainers.
|
||||
# As a maintainer, he made life easier for contributors to the Docker open-source
|
||||
# projects, bringing order in the chaos by designing a triage- and review workflow
|
||||
# using labels (see https://icecrime.net/technology/a-structured-approach-to-labeling/),
|
||||
# and automating the hell out of things with his buddies GordonTheTurtle and Poule
|
||||
# (a chicken!).
|
||||
#
|
||||
# A lesser-known fact is that he created the first commit in the libnetwork repository
|
||||
# even though he didn't know anything about it. Some say, he's now selling stuff on
|
||||
# the internet ;-)
|
||||
"icecrime",
|
||||
|
||||
# After a false start with his first PR being rejected, James Turnbull became a frequent
|
||||
# contributor to the documentation, and became a docs maintainer on December 5, 2013. As
|
||||
# a maintainer, James lifted the docs to a higher standard, and introduced the community
|
||||
# guidelines ("three strikes"). James is currently changing the world as CTO of https://www.empatico.org,
|
||||
# meanwhile authoring various books that are worth checking out. You can find him on Twitter,
|
||||
# rambling as @kartar, and although no longer active as a maintainer, he's always "game" to
|
||||
# help out reviewing docs PRs, so you may still see him around in the repository.
|
||||
"jamtur01",
|
||||
|
||||
# Jessica Frazelle, also known as the "Keyser Söze of containers",
|
||||
# runs *everything* in containers. She started contributing to
|
||||
# Docker with a (fun fun) change involving both iptables and regular
|
||||
@@ -155,24 +120,13 @@
|
||||
# containers a lot more secure). Besides being a maintainer, she
|
||||
# set up the CI infrastructure for the project, giving everyone
|
||||
# something to shout at if a PR failed ("noooo Janky!").
|
||||
# Jess is currently working on the DCOS security team at Mesosphere,
|
||||
# and contributing to various open source projects.
|
||||
# Be sure you don't miss her talks at a conference near you (a must-see),
|
||||
# read her blog at https://blog.jessfraz.com (a must-read), and
|
||||
# check out her open source projects on GitHub https://github.com/jessfraz (a must-try).
|
||||
"jessfraz",
|
||||
|
||||
# Alexander Morozov contributed many features to Docker, worked on the premise of
|
||||
# what later became containerd (and worked on that too), and made a "stupid" Go
|
||||
# vendor tool specifically for docker/docker needs: vndr (https://github.com/LK4D4/vndr).
|
||||
# Not many know that Alexander is a master negotiator, being able to change course
|
||||
# of action with a single "Nope, we're not gonna do that".
|
||||
"lk4d4",
|
||||
|
||||
# Madhu Venugopal was part of the SocketPlane team that joined Docker.
|
||||
# As a maintainer, he was working with Jana for the Container Network
|
||||
# Model (CNM) implemented through libnetwork, and the "routing mesh" powering
|
||||
# Swarm mode networking.
|
||||
"mavenugo",
|
||||
|
||||
# As a docs maintainer, Mary Anthony contributed greatly to the Docker
|
||||
# docs. She wrote the Docker Contributor Guide and Getting Started
|
||||
# Guides. She helped create a doc build system independent of
|
||||
@@ -182,30 +136,6 @@
|
||||
# maryatdocker/docker-whale back in May 2015.
|
||||
"moxiegirl",
|
||||
|
||||
# Jana Radhakrishnan was part of the SocketPlane team that joined Docker.
|
||||
# As a maintainer, he was the lead architect for the Container Network
|
||||
# Model (CNM) implemented through libnetwork, and the "routing mesh" powering
|
||||
# Swarm mode networking.
|
||||
#
|
||||
# Jana started new adventures in networking, but you can find him tweeting as @mrjana,
|
||||
# coding on GitHub https://github.com/mrjana, and he may be hiding on the Docker Community
|
||||
# slack channel :-)
|
||||
"mrjana",
|
||||
|
||||
# Sven Dowideit became a well known person in the Docker ecosphere, building
|
||||
# boot2docker, and became a regular contributor to the project, starting as
|
||||
# early as October 2013 (https://github.com/docker/docker/pull/2119), to become
|
||||
# a maintainer less than two months later (https://github.com/docker/docker/pull/3061).
|
||||
#
|
||||
# As a maintainer, Sven took on the task to convert the documentation from
|
||||
# ReStructuredText to Markdown, migrate to Hugo for generating the docs, and
|
||||
# writing tooling for building, testing, and publishing them.
|
||||
#
|
||||
# If you're not in the occasion to visit "the Australian office", you
|
||||
# can keep up with Sven on Twitter (@SvenDowideit), his blog http://fosiki.com,
|
||||
# and of course on GitHub.
|
||||
"sven",
|
||||
|
||||
# Vincent "vbatts!" Batts made his first contribution to the project
|
||||
# in November 2013, to become a maintainer a few months later, on
|
||||
# May 10, 2014 (https://github.com/docker/docker/commit/d6e666a87a01a5634c250358a94c814bf26cb778).
|
||||
@@ -240,10 +170,10 @@
|
||||
Email = "aaron.lehmann@docker.com"
|
||||
GitHub = "aaronlehmann"
|
||||
|
||||
[people.alexellis]
|
||||
Name = "Alex Ellis"
|
||||
Email = "alexellis2@gmail.com"
|
||||
GitHub = "alexellis"
|
||||
[people.aboch]
|
||||
Name = "Alessandro Boch"
|
||||
Email = "aboch@docker.com"
|
||||
GitHub = "aboch"
|
||||
|
||||
[people.akihirosuda]
|
||||
Name = "Akihiro Suda"
|
||||
@@ -255,21 +185,11 @@
|
||||
Email = "al@docker.com"
|
||||
GitHub = "aluzzardi"
|
||||
|
||||
[people.albers]
|
||||
Name = "Harald Albers"
|
||||
Email = "github@albersweb.de"
|
||||
GitHub = "albers"
|
||||
|
||||
[people.andrewhsu]
|
||||
Name = "Andrew Hsu"
|
||||
Email = "andrewhsu@docker.com"
|
||||
GitHub = "andrewhsu"
|
||||
|
||||
[people.anonymuse]
|
||||
Name = "Jesse White"
|
||||
Email = "anonymuse@gmail.com"
|
||||
GitHub = "anonymuse"
|
||||
|
||||
[people.anusha]
|
||||
Name = "Anusha Ragunathan"
|
||||
Email = "anusha@docker.com"
|
||||
@@ -288,12 +208,7 @@
|
||||
[people.cpuguy83]
|
||||
Name = "Brian Goff"
|
||||
Email = "cpuguy83@gmail.com"
|
||||
GitHub = "cpuguy83"
|
||||
|
||||
[people.chanwit]
|
||||
Name = "Chanwit Kaewkasi"
|
||||
Email = "chanwit@gmail.com"
|
||||
GitHub = "chanwit"
|
||||
Github = "cpuguy83"
|
||||
|
||||
[people.crosbymichael]
|
||||
Name = "Michael Crosby"
|
||||
@@ -325,19 +240,9 @@
|
||||
Email = "estesp@linux.vnet.ibm.com"
|
||||
GitHub = "estesp"
|
||||
|
||||
[people.fntlnz]
|
||||
Name = "Lorenzo Fontana"
|
||||
Email = "fontanalorenz@gmail.com"
|
||||
GitHub = "fntlnz"
|
||||
|
||||
[people.gianarb]
|
||||
Name = "Gianluca Arbezzano"
|
||||
Email = "ga@thumpflow.com"
|
||||
GitHub = "gianarb"
|
||||
|
||||
[people.icecrime]
|
||||
Name = "Arnaud Porterie"
|
||||
Email = "icecrime@gmail.com"
|
||||
Email = "arnaud@docker.com"
|
||||
GitHub = "icecrime"
|
||||
|
||||
[people.jamtur01]
|
||||
@@ -355,11 +260,6 @@
|
||||
Email = "jess@linux.com"
|
||||
GitHub = "jessfraz"
|
||||
|
||||
[people.johnstep]
|
||||
Name = "John Stephens"
|
||||
Email = "johnstep@docker.com"
|
||||
GitHub = "johnstep"
|
||||
|
||||
[people.justincormack]
|
||||
Name = "Justin Cormack"
|
||||
Email = "justin.cormack@docker.com"
|
||||
@@ -375,6 +275,11 @@
|
||||
Email = "madhu@docker.com"
|
||||
GitHub = "mavenugo"
|
||||
|
||||
[people.mgoelzer]
|
||||
Name = "Mike Goelzer"
|
||||
Email = "mike.goelzer@docker.com"
|
||||
GitHub = "mgoelzer"
|
||||
|
||||
[people.mhbauer]
|
||||
Name = "Morgan Bauer"
|
||||
Email = "mbauer@us.ibm.com"
|
||||
@@ -383,11 +288,11 @@
|
||||
[people.misty]
|
||||
Name = "Misty Stanley-Jones"
|
||||
Email = "misty@docker.com"
|
||||
GitHub = "mistyhacks"
|
||||
GitHub = "mstanleyjones"
|
||||
|
||||
[people.mlaventure]
|
||||
Name = "Kenfe-Mickaël Laventure"
|
||||
Email = "mickael.laventure@gmail.com"
|
||||
Email = "mickael.laventure@docker.com"
|
||||
GitHub = "mlaventure"
|
||||
|
||||
[people.moxiegirl]
|
||||
@@ -405,16 +310,6 @@
|
||||
Email = "jeff@docker.com"
|
||||
GitHub = "programmerq"
|
||||
|
||||
[people.rheinwein]
|
||||
Name = "Laura Frank"
|
||||
Email = "laura@codeship.com"
|
||||
GitHub = "rheinwein"
|
||||
|
||||
[people.ripcurld]
|
||||
Name = "Boaz Shuster"
|
||||
Email = "ripcurld.github@gmail.com"
|
||||
GitHub = "ripcurld"
|
||||
|
||||
[people.runcom]
|
||||
Name = "Antonio Murdaca"
|
||||
Email = "runcom@redhat.com"
|
||||
@@ -479,8 +374,3 @@
|
||||
Name = "Vishnu Kannan"
|
||||
Email = "vishnuk@google.com"
|
||||
GitHub = "vishh"
|
||||
|
||||
[people.yongtang]
|
||||
Name = "Yong Tang"
|
||||
Email = "yong.tang.github@outlook.com"
|
||||
GitHub = "yongtang"
|
||||
|
||||
129
Makefile
129
Makefile
@@ -1,51 +1,31 @@
|
||||
.PHONY: all binary dynbinary build cross help init-go-pkg-cache install manpages run shell test test-docker-py test-integration test-unit validate win
|
||||
.PHONY: all binary build cross deb help init-go-pkg-cache install manpages rpm run shell test test-docker-py test-integration-cli test-unit tgz validate win
|
||||
|
||||
# set the graph driver as the current graphdriver if not set
|
||||
DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info 2>&1 | grep "Storage Driver" | sed 's/.*: //'))
|
||||
export DOCKER_GRAPHDRIVER
|
||||
DOCKER_INCREMENTAL_BINARY := $(if $(DOCKER_INCREMENTAL_BINARY),$(DOCKER_INCREMENTAL_BINARY),1)
|
||||
export DOCKER_INCREMENTAL_BINARY
|
||||
|
||||
# get OS/Arch of docker engine
|
||||
DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKER_ENGINE_OSARCH}')
|
||||
DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKER_ENGINE_OSARCH:-$$DOCKER_CLIENT_OSARCH}')
|
||||
DOCKERFILE := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKERFILE}')
|
||||
|
||||
DOCKER_GITCOMMIT := $(shell git rev-parse --short HEAD || echo unsupported)
|
||||
export DOCKER_GITCOMMIT
|
||||
|
||||
# env vars passed through directly to Docker's build scripts
|
||||
# to allow things like `make KEEPBUNDLE=1 binary` easily
|
||||
# `project/PACKAGERS.md` have some limited documentation of some of these
|
||||
#
|
||||
# DOCKER_LDFLAGS can be used to pass additional parameters to -ldflags
|
||||
# option of "go build". For example, a built-in graphdriver priority list
|
||||
# can be changed during build time like this:
|
||||
#
|
||||
# make DOCKER_LDFLAGS="-X github.com/docker/docker/daemon/graphdriver.priority=overlay2,devicemapper" dynbinary
|
||||
#
|
||||
DOCKER_ENVS := \
|
||||
-e DOCKER_CROSSPLATFORMS \
|
||||
-e BUILD_APT_MIRROR \
|
||||
-e BUILDFLAGS \
|
||||
-e KEEPBUNDLE \
|
||||
-e DOCKER_BUILD_ARGS \
|
||||
-e DOCKER_BUILD_GOGC \
|
||||
-e DOCKER_BUILD_PKGS \
|
||||
-e DOCKER_BUILDKIT \
|
||||
-e DOCKER_BASH_COMPLETION_PATH \
|
||||
-e DOCKER_CLI_PATH \
|
||||
-e DOCKER_DEBUG \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e DOCKER_GRAPHDRIVER=$(DOCKER_GRAPHDRIVER) \
|
||||
-e DOCKER_INCREMENTAL_BINARY \
|
||||
-e DOCKER_LDFLAGS \
|
||||
-e DOCKER_PORT \
|
||||
-e DOCKER_REMAP_ROOT \
|
||||
-e DOCKER_STORAGE_OPTS \
|
||||
-e DOCKER_USERLANDPROXY \
|
||||
-e DOCKERD_ARGS \
|
||||
-e TEST_INTEGRATION_DIR \
|
||||
-e TESTDIRS \
|
||||
-e TESTFLAGS \
|
||||
-e TIMEOUT \
|
||||
@@ -54,11 +34,7 @@ DOCKER_ENVS := \
|
||||
-e NO_PROXY \
|
||||
-e http_proxy \
|
||||
-e https_proxy \
|
||||
-e no_proxy \
|
||||
-e VERSION \
|
||||
-e PLATFORM \
|
||||
-e DEFAULT_PRODUCT_LICENSE \
|
||||
-e PRODUCT
|
||||
-e no_proxy
|
||||
# note: we _cannot_ add "-e DOCKER_BUILDTAGS" here because even if it's unset in the shell, that would shadow the "ENV DOCKER_BUILDTAGS" set in our Dockerfile, which is very important for our official builds
|
||||
|
||||
# to allow `make BIND_DIR=. shell` or `make BIND_DIR= test`
|
||||
@@ -70,39 +46,22 @@ DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/do
|
||||
# This allows the test suite to be able to run without worrying about the underlying fs used by the container running the daemon (e.g. aufs-on-aufs), so long as the host running the container is running a supported fs.
|
||||
# The volume will be cleaned up when the container is removed due to `--rm`.
|
||||
# Note that `BIND_DIR` will already be set to `bundles` if `DOCKER_HOST` is not set (see above BIND_DIR line), in such case this will do nothing since `DOCKER_MOUNT` will already be set.
|
||||
DOCKER_MOUNT := $(if $(DOCKER_MOUNT),$(DOCKER_MOUNT),-v /go/src/github.com/docker/docker/bundles) -v "$(CURDIR)/.git:/go/src/github.com/docker/docker/.git"
|
||||
DOCKER_MOUNT := $(if $(DOCKER_MOUNT),$(DOCKER_MOUNT),-v /go/src/github.com/docker/docker/bundles)
|
||||
|
||||
# This allows to set the docker-dev container name
|
||||
DOCKER_CONTAINER_NAME := $(if $(CONTAINER_NAME),--name $(CONTAINER_NAME),)
|
||||
|
||||
# enable package cache if DOCKER_INCREMENTAL_BINARY and DOCKER_MOUNT (i.e.DOCKER_HOST) are set
|
||||
PKGCACHE_MAP := gopath:/go/pkg goroot-linux_amd64:/usr/local/go/pkg/linux_amd64 goroot-linux_amd64_netgo:/usr/local/go/pkg/linux_amd64_netgo
|
||||
PKGCACHE_VOLROOT := dockerdev-go-pkg-cache
|
||||
PKGCACHE_VOL := $(if $(PKGCACHE_DIR),$(CURDIR)/$(PKGCACHE_DIR)/,$(PKGCACHE_VOLROOT)-)
|
||||
DOCKER_MOUNT_PKGCACHE := $(if $(DOCKER_INCREMENTAL_BINARY),$(shell echo $(PKGCACHE_MAP) | sed -E 's@([^ ]*)@-v "$(PKGCACHE_VOL)\1"@g'),)
|
||||
DOCKER_MOUNT_CLI := $(if $(DOCKER_CLI_PATH),-v $(shell dirname $(DOCKER_CLI_PATH)):/usr/local/cli,)
|
||||
DOCKER_MOUNT_BASH_COMPLETION := $(if $(DOCKER_BASH_COMPLETION_PATH),-v $(shell dirname $(DOCKER_BASH_COMPLETION_PATH)):/usr/local/completion/bash,)
|
||||
DOCKER_MOUNT := $(DOCKER_MOUNT) $(DOCKER_MOUNT_PKGCACHE) $(DOCKER_MOUNT_CLI) $(DOCKER_MOUNT_BASH_COMPLETION)
|
||||
# enable .go-pkg-cache if DOCKER_INCREMENTAL_BINARY and DOCKER_MOUNT (i.e.DOCKER_HOST) are set
|
||||
PKGCACHE_DIR := $(if $(PKGCACHE_DIR),$(PKGCACHE_DIR),.go-pkg-cache)
|
||||
PKGCACHE_MAP := gopath:/go/pkg goroot-linux_amd64_netgo:/usr/local/go/pkg/linux_amd64_netgo
|
||||
DOCKER_MOUNT := $(if $(DOCKER_INCREMENTAL_BINARY),$(DOCKER_MOUNT) $(shell echo $(PKGCACHE_MAP) | sed -E 's@([^ ]*)@-v "$(CURDIR)/$(PKGCACHE_DIR)/\1"@g'),$(DOCKER_MOUNT))
|
||||
|
||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||
GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g")
|
||||
DOCKER_IMAGE := docker-dev$(if $(GIT_BRANCH_CLEAN),:$(GIT_BRANCH_CLEAN))
|
||||
DOCKER_PORT_FORWARD := $(if $(DOCKER_PORT),-p "$(DOCKER_PORT)",)
|
||||
|
||||
DOCKER_FLAGS := docker run --rm -i --privileged $(DOCKER_CONTAINER_NAME) $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD)
|
||||
DOCKER_FLAGS := docker run --rm -i --privileged $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD)
|
||||
BUILD_APT_MIRROR := $(if $(DOCKER_BUILD_APT_MIRROR),--build-arg APT_MIRROR=$(DOCKER_BUILD_APT_MIRROR))
|
||||
export BUILD_APT_MIRROR
|
||||
|
||||
SWAGGER_DOCS_PORT ?= 9000
|
||||
|
||||
INTEGRATION_CLI_MASTER_IMAGE := $(if $(INTEGRATION_CLI_MASTER_IMAGE), $(INTEGRATION_CLI_MASTER_IMAGE), integration-cli-master)
|
||||
INTEGRATION_CLI_WORKER_IMAGE := $(if $(INTEGRATION_CLI_WORKER_IMAGE), $(INTEGRATION_CLI_WORKER_IMAGE), integration-cli-worker)
|
||||
|
||||
define \n
|
||||
|
||||
|
||||
endef
|
||||
|
||||
# if this session isn't interactive, then we don't want to allocate a
|
||||
# TTY, which would fail, but if it is interactive, we do want to attach
|
||||
# so that the user can send e.g. ^C through.
|
||||
@@ -121,54 +80,60 @@ all: build ## validate all checks, build linux binaries, run all tests\ncross bu
|
||||
binary: build ## build the linux binaries
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh binary
|
||||
|
||||
dynbinary: build ## build the linux dynbinaries
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary
|
||||
|
||||
build: bundles init-go-pkg-cache
|
||||
$(warning The docker client CLI has moved to github.com/docker/cli. For a dev-test cycle involving the CLI, run:${\n} DOCKER_CLI_PATH=/host/path/to/cli/binary make shell ${\n} then change the cli and compile into a binary at the same location.${\n})
|
||||
docker build ${BUILD_APT_MIRROR} ${DOCKER_BUILD_ARGS} -t "$(DOCKER_IMAGE)" -f "$(DOCKERFILE)" .
|
||||
|
||||
bundles:
|
||||
mkdir bundles
|
||||
|
||||
clean: clean-pkg-cache-vol ## clean up cached resources
|
||||
|
||||
clean-pkg-cache-vol:
|
||||
@- $(foreach mapping,$(PKGCACHE_MAP), \
|
||||
$(shell docker volume rm $(PKGCACHE_VOLROOT)-$(shell echo $(mapping) | awk -F':/' '{ print $$1 }') > /dev/null 2>&1) \
|
||||
)
|
||||
|
||||
cross: build ## cross build the binaries for darwin, freebsd and\nwindows
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross
|
||||
|
||||
deb: build ## build the deb packages
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary build-deb
|
||||
|
||||
|
||||
help: ## this help
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
|
||||
init-go-pkg-cache:
|
||||
$(if $(PKGCACHE_DIR), mkdir -p $(shell echo $(PKGCACHE_MAP) | sed -E 's@([^: ]*):[^ ]*@$(PKGCACHE_DIR)/\1@g'))
|
||||
mkdir -p $(shell echo $(PKGCACHE_MAP) | sed -E 's@([^: ]*):[^ ]*@$(PKGCACHE_DIR)/\1@g')
|
||||
|
||||
install: ## install the linux binaries
|
||||
KEEPBUNDLE=1 hack/make.sh install-binary
|
||||
|
||||
manpages: ## Generate man pages from go source and markdown
|
||||
docker build -t docker-manpage-dev -f "man/$(DOCKERFILE)" ./man
|
||||
docker run --rm \
|
||||
-v $(PWD):/go/src/github.com/docker/docker/ \
|
||||
docker-manpage-dev
|
||||
|
||||
rpm: build ## build the rpm packages
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary build-rpm
|
||||
|
||||
run: build ## run the docker daemon in a container
|
||||
$(DOCKER_RUN_DOCKER) sh -c "KEEPBUNDLE=1 hack/make.sh install-binary run"
|
||||
|
||||
shell: build ## start a shell inside the build env
|
||||
$(DOCKER_RUN_DOCKER) bash
|
||||
|
||||
test: build test-unit ## run the unit, integration and docker-py tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary cross test-integration test-docker-py
|
||||
yaml-docs-gen: build ## generate documentation YAML files consumed by docs repo
|
||||
$(DOCKER_RUN_DOCKER) sh -c 'hack/make.sh yaml-docs-generator && ( root=$$(pwd); cd bundles/latest/yaml-docs-generator; mkdir docs; ./yaml-docs-generator --root $${root} --target $$(pwd)/docs )'
|
||||
|
||||
test: build ## run the unit, integration and docker-py tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary cross test-unit test-integration-cli test-docker-py
|
||||
|
||||
test-docker-py: build ## run the docker-py tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-docker-py
|
||||
|
||||
test-integration-cli: test-integration ## (DEPRECATED) use test-integration
|
||||
|
||||
test-integration: build ## run the integration tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-integration
|
||||
test-integration-cli: build ## run the integration tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh build-integration-test-binary dynbinary test-integration-cli
|
||||
|
||||
test-unit: build ## run the unit tests
|
||||
$(DOCKER_RUN_DOCKER) hack/test/unit
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh test-unit
|
||||
|
||||
tgz: build ## build the archives (.zip on windows and .tgz\notherwise) containing the binaries
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross tgz
|
||||
|
||||
validate: build ## validate DCO, Seccomp profile generation, gofmt,\n./pkg/ isolation, golint, tests, tomls, go vet and vendor
|
||||
$(DOCKER_RUN_DOCKER) hack/validate/all
|
||||
@@ -183,27 +148,3 @@ swagger-gen:
|
||||
--entrypoint hack/generate-swagger-api.sh \
|
||||
-e GOPATH=/go \
|
||||
quay.io/goswagger/swagger:0.7.4
|
||||
|
||||
.PHONY: swagger-docs
|
||||
swagger-docs: ## preview the API documentation
|
||||
@echo "API docs preview will be running at http://localhost:$(SWAGGER_DOCS_PORT)"
|
||||
@docker run --rm -v $(PWD)/api/swagger.yaml:/usr/share/nginx/html/swagger.yaml \
|
||||
-e 'REDOC_OPTIONS=hide-hostname="true" lazy-rendering' \
|
||||
-p $(SWAGGER_DOCS_PORT):80 \
|
||||
bfirsh/redoc:1.6.2
|
||||
|
||||
build-integration-cli-on-swarm: build ## build images and binary for running integration-cli on Swarm in parallel
|
||||
@echo "Building hack/integration-cli-on-swarm (if build fails, please refer to hack/integration-cli-on-swarm/README.md)"
|
||||
go build -buildmode=pie -o ./hack/integration-cli-on-swarm/integration-cli-on-swarm ./hack/integration-cli-on-swarm/host
|
||||
@echo "Building $(INTEGRATION_CLI_MASTER_IMAGE)"
|
||||
docker build -t $(INTEGRATION_CLI_MASTER_IMAGE) hack/integration-cli-on-swarm/agent
|
||||
# For worker, we don't use `docker build` so as to enable DOCKER_INCREMENTAL_BINARY and so on
|
||||
@echo "Building $(INTEGRATION_CLI_WORKER_IMAGE) from $(DOCKER_IMAGE)"
|
||||
$(eval tmp := integration-cli-worker-tmp)
|
||||
# We mount pkgcache, but not bundle (bundle needs to be baked into the image)
|
||||
# For avoiding bakings DOCKER_GRAPHDRIVER and so on to image, we cannot use $(DOCKER_ENVS) here
|
||||
docker run -t -d --name $(tmp) -e DOCKER_GITCOMMIT -e BUILDFLAGS -e DOCKER_INCREMENTAL_BINARY --privileged $(DOCKER_MOUNT_PKGCACHE) $(DOCKER_IMAGE) top
|
||||
docker exec $(tmp) hack/make.sh build-integration-test-binary dynbinary
|
||||
docker exec $(tmp) go build -buildmode=pie -o /worker github.com/docker/docker/hack/integration-cli-on-swarm/agent/worker
|
||||
docker commit -c 'ENTRYPOINT ["/worker"]' $(tmp) $(INTEGRATION_CLI_WORKER_IMAGE)
|
||||
docker rm -f $(tmp)
|
||||
|
||||
2
NOTICE
2
NOTICE
@@ -1,5 +1,5 @@
|
||||
Docker
|
||||
Copyright 2012-2017 Docker, Inc.
|
||||
Copyright 2012-2016 Docker, Inc.
|
||||
|
||||
This product includes software developed at Docker, Inc. (https://www.docker.com).
|
||||
|
||||
|
||||
309
README.md
309
README.md
@@ -1,48 +1,270 @@
|
||||
The Moby Project
|
||||
================
|
||||
Docker: the container engine [](https://github.com/docker/docker/releases/latest)
|
||||
============================
|
||||
|
||||

|
||||
Docker is an open source project to pack, ship and run any application
|
||||
as a lightweight container.
|
||||
|
||||
Moby is an open-source project created by Docker to enable and accelerate software containerization.
|
||||
Docker containers are both *hardware-agnostic* and *platform-agnostic*.
|
||||
This means they can run anywhere, from your laptop to the largest
|
||||
cloud compute instance and everything in between - and they don't require
|
||||
you to use a particular language, framework or packaging system. That
|
||||
makes them great building blocks for deploying and scaling web apps,
|
||||
databases, and backend services without depending on a particular stack
|
||||
or provider.
|
||||
|
||||
It provides a "Lego set" of toolkit components, the framework for assembling them into custom container-based systems, and a place for all container enthusiasts and professionals to experiment and exchange ideas.
|
||||
Components include container build tools, a container registry, orchestration tools, a runtime and more, and these can be used as building blocks in conjunction with other tools and projects.
|
||||
Docker began as an open-source implementation of the deployment engine which
|
||||
powered [dotCloud](http://web.archive.org/web/20130530031104/https://www.dotcloud.com/),
|
||||
a popular Platform-as-a-Service. It benefits directly from the experience
|
||||
accumulated over several years of large-scale operation and support of hundreds
|
||||
of thousands of applications and databases.
|
||||
|
||||
## Principles
|
||||

|
||||
|
||||
Moby is an open project guided by strong principles, aiming to be modular, flexible and without too strong an opinion on user experience.
|
||||
It is open to the community to help set its direction.
|
||||
## Security Disclosure
|
||||
|
||||
- Modular: the project includes lots of components that have well-defined functions and APIs that work together.
|
||||
- Batteries included but swappable: Moby includes enough components to build fully featured container system, but its modular architecture ensures that most of the components can be swapped by different implementations.
|
||||
- Usable security: Moby provides secure defaults without compromising usability.
|
||||
- Developer focused: The APIs are intended to be functional and useful to build powerful tools.
|
||||
They are not necessarily intended as end user tools but as components aimed at developers.
|
||||
Documentation and UX is aimed at developers not end users.
|
||||
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.
|
||||
|
||||
## Audience
|
||||
## Better than VMs
|
||||
|
||||
The Moby Project is intended for engineers, integrators and enthusiasts looking to modify, hack, fix, experiment, invent and build systems based on containers.
|
||||
It is not for people looking for a commercially supported system, but for people who want to work and learn with open source code.
|
||||
A common method for distributing applications and sandboxing their
|
||||
execution is to use virtual machines, or VMs. Typical VM formats are
|
||||
VMware's vmdk, Oracle VirtualBox's vdi, and Amazon EC2's ami. In theory
|
||||
these formats should allow every developer to automatically package
|
||||
their application into a "machine" for easy distribution and deployment.
|
||||
In practice, that almost never happens, for a few reasons:
|
||||
|
||||
## Relationship with Docker
|
||||
* *Size*: VMs are very large which makes them impractical to store
|
||||
and transfer.
|
||||
* *Performance*: running VMs consumes significant CPU and memory,
|
||||
which makes them impractical in many scenarios, for example local
|
||||
development of multi-tier applications, and large-scale deployment
|
||||
of cpu and memory-intensive applications on large numbers of
|
||||
machines.
|
||||
* *Portability*: competing VM environments don't play well with each
|
||||
other. Although conversion tools do exist, they are limited and
|
||||
add even more overhead.
|
||||
* *Hardware-centric*: VMs were designed with machine operators in
|
||||
mind, not software developers. As a result, they offer very
|
||||
limited tooling for what developers need most: building, testing
|
||||
and running their software. For example, VMs offer no facilities
|
||||
for application versioning, monitoring, configuration, logging or
|
||||
service discovery.
|
||||
|
||||
The components and tools in the Moby Project are initially the open source components that Docker and the community have built for the Docker Project.
|
||||
New projects can be added if they fit with the community goals. Docker is committed to using Moby as the upstream for the Docker Product.
|
||||
However, other projects are also encouraged to use Moby as an upstream, and to reuse the components in diverse ways, and all these uses will be treated in the same way. External maintainers and contributors are welcomed.
|
||||
By contrast, Docker relies on a different sandboxing method known as
|
||||
*containerization*. Unlike traditional virtualization, containerization
|
||||
takes place at the kernel level. Most modern operating system kernels
|
||||
now support the primitives necessary for containerization, including
|
||||
Linux with [openvz](https://openvz.org),
|
||||
[vserver](http://linux-vserver.org) and more recently
|
||||
[lxc](https://linuxcontainers.org/), Solaris with
|
||||
[zones](https://docs.oracle.com/cd/E26502_01/html/E29024/preface-1.html#scrolltoc),
|
||||
and FreeBSD with
|
||||
[Jails](https://www.freebsd.org/doc/handbook/jails.html).
|
||||
|
||||
The Moby project is not intended as a location for support or feature requests for Docker products, but as a place for contributors to work on open source code, fix bugs, and make the code more useful.
|
||||
The releases are supported by the maintainers, community and users, on a best efforts basis only, and are not intended for customers who want enterprise or commercial support; Docker EE is the appropriate product for these use cases.
|
||||
Docker builds on top of these low-level primitives to offer developers a
|
||||
portable format and runtime environment that solves all four problems.
|
||||
Docker containers are small (and their transfer can be optimized with
|
||||
layers), they have basically zero memory and cpu overhead, they are
|
||||
completely portable, and are designed from the ground up with an
|
||||
application-centric design.
|
||||
|
||||
-----
|
||||
Perhaps best of all, because Docker operates at the OS level, it can still be
|
||||
run inside a VM!
|
||||
|
||||
Legal
|
||||
=====
|
||||
## Plays well with others
|
||||
|
||||
Docker does not require you to buy into a particular programming
|
||||
language, framework, packaging system, or configuration language.
|
||||
|
||||
Is your application a Unix process? Does it use files, tcp connections,
|
||||
environment variables, standard Unix streams and command-line arguments
|
||||
as inputs and outputs? Then Docker can run it.
|
||||
|
||||
Can your application's build be expressed as a sequence of such
|
||||
commands? Then Docker can build it.
|
||||
|
||||
## Escape dependency hell
|
||||
|
||||
A common problem for developers is the difficulty of managing all
|
||||
their application's dependencies in a simple and automated way.
|
||||
|
||||
This is usually difficult for several reasons:
|
||||
|
||||
* *Cross-platform dependencies*. Modern applications often depend on
|
||||
a combination of system libraries and binaries, language-specific
|
||||
packages, framework-specific modules, internal components
|
||||
developed for another project, etc. These dependencies live in
|
||||
different "worlds" and require different tools - these tools
|
||||
typically don't work well with each other, requiring awkward
|
||||
custom integrations.
|
||||
|
||||
* *Conflicting dependencies*. Different applications may depend on
|
||||
different versions of the same dependency. Packaging tools handle
|
||||
these situations with various degrees of ease - but they all
|
||||
handle them in different and incompatible ways, which again forces
|
||||
the developer to do extra work.
|
||||
|
||||
* *Custom dependencies*. A developer may need to prepare a custom
|
||||
version of their application's dependency. Some packaging systems
|
||||
can handle custom versions of a dependency, others can't - and all
|
||||
of them handle it differently.
|
||||
|
||||
|
||||
Docker solves the problem of dependency hell by giving the developer a simple
|
||||
way to express *all* their application's dependencies in one place, while
|
||||
streamlining the process of assembling them. If this makes you think of
|
||||
[XKCD 927](https://xkcd.com/927/), don't worry. Docker doesn't
|
||||
*replace* your favorite packaging systems. It simply orchestrates
|
||||
their use in a simple and repeatable way. How does it do that? With
|
||||
layers.
|
||||
|
||||
Docker defines a build as running a sequence of Unix commands, one
|
||||
after the other, in the same container. Build commands modify the
|
||||
contents of the container (usually by installing new files on the
|
||||
filesystem), the next command modifies it some more, etc. Since each
|
||||
build command inherits the result of the previous commands, the
|
||||
*order* in which the commands are executed expresses *dependencies*.
|
||||
|
||||
Here's a typical Docker build process:
|
||||
|
||||
```bash
|
||||
FROM ubuntu:12.04
|
||||
RUN apt-get update && apt-get install -y python python-pip curl
|
||||
RUN curl -sSL https://github.com/shykes/helloflask/archive/master.tar.gz | tar -xzv
|
||||
RUN cd helloflask-master && pip install -r requirements.txt
|
||||
```
|
||||
|
||||
Note that Docker doesn't care *how* dependencies are built - as long
|
||||
as they can be built by running a Unix command in a container.
|
||||
|
||||
|
||||
Getting started
|
||||
===============
|
||||
|
||||
Docker can be installed either on your computer for building applications or
|
||||
on servers for running them. To get started, [check out the installation
|
||||
instructions in the
|
||||
documentation](https://docs.docker.com/engine/installation/).
|
||||
|
||||
Usage examples
|
||||
==============
|
||||
|
||||
Docker can be used to run short-lived commands, long-running daemons
|
||||
(app servers, databases, etc.), interactive shell sessions, etc.
|
||||
|
||||
You can find a [list of real-world
|
||||
examples](https://docs.docker.com/engine/examples/) in the
|
||||
documentation.
|
||||
|
||||
Under the hood
|
||||
--------------
|
||||
|
||||
Under the hood, Docker is built on the following components:
|
||||
|
||||
* The
|
||||
[cgroups](https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt)
|
||||
and
|
||||
[namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html)
|
||||
capabilities of the Linux kernel
|
||||
* The [Go](https://golang.org) programming language
|
||||
* The [Docker Image Specification](https://github.com/docker/docker/blob/master/image/spec/v1.md)
|
||||
* The [Libcontainer Specification](https://github.com/opencontainers/runc/blob/master/libcontainer/SPEC.md)
|
||||
|
||||
Contributing to Docker [](https://godoc.org/github.com/docker/docker)
|
||||
======================
|
||||
|
||||
| **Master** (Linux) | **Experimental** (Linux) | **Windows** | **FreeBSD** |
|
||||
|------------------|----------------------|---------|---------|
|
||||
| [](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master/) | [](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master%20%28experimental%29/) | [/badge/icon)](http://jenkins.dockerproject.org/job/Docker%20Master%20(windows)/) | [/badge/icon)](http://jenkins.dockerproject.org/job/Docker%20Master%20(freebsd)/) |
|
||||
|
||||
Want to hack on Docker? Awesome! We have [instructions to help you get
|
||||
started contributing code or documentation](https://docs.docker.com/opensource/project/who-written-for/).
|
||||
|
||||
These instructions are probably not perfect, please let us know if anything
|
||||
feels wrong or incomplete. Better yet, submit a PR and improve them yourself.
|
||||
|
||||
Getting the development builds
|
||||
==============================
|
||||
|
||||
Want to run Docker from a master build? You can download
|
||||
master builds at [master.dockerproject.org](https://master.dockerproject.org).
|
||||
They are updated with each commit merged into the master branch.
|
||||
|
||||
Don't know how to use that super cool new feature in the master build? Check
|
||||
out the master docs at
|
||||
[docs.master.dockerproject.org](http://docs.master.dockerproject.org).
|
||||
|
||||
How the project is run
|
||||
======================
|
||||
|
||||
Docker is a very, very active project. If you want to learn more about how it is run,
|
||||
or want to get more involved, the best place to start is [the project directory](https://github.com/docker/docker/tree/master/project).
|
||||
|
||||
We are always open to suggestions on process improvements, and are always looking for more maintainers.
|
||||
|
||||
### Talking to other Docker users and contributors
|
||||
|
||||
<table class="tg">
|
||||
<col width="45%">
|
||||
<col width="65%">
|
||||
<tr>
|
||||
<td>Internet Relay Chat (IRC)</td>
|
||||
<td>
|
||||
<p>
|
||||
IRC is a direct line to our most knowledgeable Docker users; we have
|
||||
both the <code>#docker</code> and <code>#docker-dev</code> group on
|
||||
<strong>irc.freenode.net</strong>.
|
||||
IRC is a rich chat protocol but it can overwhelm new users. You can search
|
||||
<a href="https://botbot.me/freenode/docker/#" target="_blank">our chat archives</a>.
|
||||
</p>
|
||||
Read our <a href="https://docs.docker.com/opensource/get-help/#/irc-quickstart" target="_blank">IRC quickstart guide</a> for an easy way to get started.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Docker Community Forums</td>
|
||||
<td>
|
||||
The <a href="https://forums.docker.com/c/open-source-projects/de" target="_blank">Docker Engine</a>
|
||||
group is for users of the Docker Engine project.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Google Groups</td>
|
||||
<td>
|
||||
The <a href="https://groups.google.com/forum/#!forum/docker-dev"
|
||||
target="_blank">docker-dev</a> group is for contributors and other people
|
||||
contributing to the Docker project. You can join this group without a
|
||||
Google account by sending an email to <a
|
||||
href="mailto:docker-dev+subscribe@googlegroups.com">docker-dev+subscribe@googlegroups.com</a>.
|
||||
You'll receive a join-request message; simply reply to the message to
|
||||
confirm your subscription.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Twitter</td>
|
||||
<td>
|
||||
You can follow <a href="https://twitter.com/docker/" target="_blank">Docker's Twitter feed</a>
|
||||
to get updates on our products. You can also tweet us questions or just
|
||||
share blogs or stories.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stack Overflow</td>
|
||||
<td>
|
||||
Stack Overflow has over 7000 Docker questions listed. We regularly
|
||||
monitor <a href="https://stackoverflow.com/search?tab=newest&q=docker" target="_blank">Docker questions</a>
|
||||
and so do many other knowledgeable Docker users.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Legal
|
||||
|
||||
*Brought to you courtesy of our legal counsel. For more context,
|
||||
please see the [NOTICE](https://github.com/moby/moby/blob/master/NOTICE) document in this repo.*
|
||||
please see the [NOTICE](https://github.com/docker/docker/blob/master/NOTICE) document in this repo.*
|
||||
|
||||
Use and transfer of Moby may be subject to certain restrictions by the
|
||||
Use and transfer of Docker may be subject to certain restrictions by the
|
||||
United States and other governments.
|
||||
|
||||
It is your responsibility to ensure that your use and/or transfer does not
|
||||
@@ -50,8 +272,33 @@ violate applicable laws.
|
||||
|
||||
For more information, please see https://www.bis.doc.gov
|
||||
|
||||
|
||||
Licensing
|
||||
=========
|
||||
Moby is licensed under the Apache License, Version 2.0. See
|
||||
[LICENSE](https://github.com/moby/moby/blob/master/LICENSE) for the full
|
||||
Docker is licensed under the Apache License, Version 2.0. See
|
||||
[LICENSE](https://github.com/docker/docker/blob/master/LICENSE) for the full
|
||||
license text.
|
||||
|
||||
Other Docker Related Projects
|
||||
=============================
|
||||
There are a number of projects under development that are based on Docker's
|
||||
core technology. These projects expand the tooling built around the
|
||||
Docker platform to broaden its application and utility.
|
||||
|
||||
* [Docker Registry](https://github.com/docker/distribution): Registry
|
||||
server for Docker (hosting/delivery of repositories and images)
|
||||
* [Docker Machine](https://github.com/docker/machine): Machine management
|
||||
for a container-centric world
|
||||
* [Docker Swarm](https://github.com/docker/swarm): A Docker-native clustering
|
||||
system
|
||||
* [Docker Compose](https://github.com/docker/compose) (formerly Fig):
|
||||
Define and run multi-container apps
|
||||
* [Kitematic](https://github.com/docker/kitematic): The easiest way to use
|
||||
Docker on Mac and Windows
|
||||
|
||||
If you know of another project underway that should be listed here, please help
|
||||
us keep this list up-to-date by submitting a PR.
|
||||
|
||||
Awesome-Docker
|
||||
==============
|
||||
You can find more projects, tools and articles related to Docker on the [awesome-docker list](https://github.com/veggiemonk/awesome-docker). Add your project there.
|
||||
|
||||
122
ROADMAP.md
122
ROADMAP.md
@@ -1,68 +1,118 @@
|
||||
Moby Project Roadmap
|
||||
====================
|
||||
Docker Engine Roadmap
|
||||
=====================
|
||||
|
||||
### How should I use this document?
|
||||
|
||||
This document provides description of items that the project decided to prioritize. This should
|
||||
serve as a reference point for Moby contributors to understand where the project is going, and
|
||||
help determine if a contribution could be conflicting with some longer term plans.
|
||||
serve as a reference point for Docker contributors to understand where the project is going, and
|
||||
help determine if a contribution could be conflicting with some longer terms plans.
|
||||
|
||||
The fact that a feature isn't listed here doesn't mean that a patch for it will automatically be
|
||||
refused! We are always happy to receive patches for new cool features we haven't thought about,
|
||||
or didn't judge to be a priority. Please however understand that such patches might take longer
|
||||
for us to review.
|
||||
refused (except for those mentioned as "frozen features" below)! We are always happy to receive
|
||||
patches for new cool features we haven't thought about, or didn't judge priority. Please however
|
||||
understand that such patches might take longer for us to review.
|
||||
|
||||
### How can I help?
|
||||
|
||||
Short term objectives are listed in
|
||||
[Issues](https://github.com/moby/moby/issues?q=is%3Aopen+is%3Aissue+label%3Aroadmap). Our
|
||||
Short term objectives are listed in the [wiki](https://github.com/docker/docker/wiki) and described
|
||||
in [Issues](https://github.com/docker/docker/issues?q=is%3Aopen+is%3Aissue+label%3Aroadmap). Our
|
||||
goal is to split down the workload in such way that anybody can jump in and help. Please comment on
|
||||
issues if you want to work on it to avoid duplicating effort! Similarly, if a maintainer is already
|
||||
assigned on an issue you'd like to participate in, pinging him on GitHub to offer your help is
|
||||
issues if you want to take it to avoid duplicating effort! Similarly, if a maintainer is already
|
||||
assigned on an issue you'd like to participate in, pinging him on IRC or GitHub to offer your help is
|
||||
the best way to go.
|
||||
|
||||
### How can I add something to the roadmap?
|
||||
|
||||
The roadmap process is new to the Moby Project: we are only beginning to structure and document the
|
||||
The roadmap process is new to the Docker Engine: we are only beginning to structure and document the
|
||||
project objectives. Our immediate goal is to be more transparent, and work with our community to
|
||||
focus our efforts on fewer prioritized topics.
|
||||
|
||||
We hope to offer in the near future a process allowing anyone to propose a topic to the roadmap, but
|
||||
we are not quite there yet. For the time being, it is best to discuss with the maintainers on an
|
||||
issue, in the Slack channel, or in person at the Moby Summits that happen every few months.
|
||||
we are not quite there yet. For the time being, the BDFL remains the keeper of the roadmap, and we
|
||||
won't be accepting pull requests adding or removing items from this file.
|
||||
|
||||
# 1. Features and refactoring
|
||||
|
||||
## 1.1 Runtime improvements
|
||||
|
||||
We introduced [`runC`](https://runc.io) as a standalone low-level tool for container
|
||||
execution in 2015, the first stage in spinning out parts of the Engine into standalone tools.
|
||||
We recently introduced [`runC`](https://runc.io) as a standalone low-level tool for container
|
||||
execution. The initial goal was to integrate runC as a replacement in the Engine for the traditional
|
||||
default libcontainer `execdriver`, but the Engine internals were not ready for this.
|
||||
|
||||
As runC continued evolving, and the OCI specification along with it, we created
|
||||
[`containerd`](https://github.com/containerd/containerd), a daemon to control and monitor `runC`.
|
||||
In late 2016 this was relaunched as the `containerd` 1.0 track, aiming to provide a common runtime
|
||||
for the whole spectrum of container systems, including Kubernetes, with wide community support.
|
||||
This change meant that there was an increased scope for `containerd`, including image management
|
||||
and storage drivers.
|
||||
[`containerd`](https://containerd.tools/), a daemon to control and monitor multiple `runC`. This is
|
||||
the new target for Engine integration, as it can entirely replace the whole `execdriver`
|
||||
architecture, and container monitoring along with it.
|
||||
|
||||
Moby will rely on a long-running `containerd` companion daemon for all container execution
|
||||
Docker Engine will rely on a long-running `containerd` companion daemon for all container execution
|
||||
related operations. This could open the door in the future for Engine restarts without interrupting
|
||||
running containers. The switch over to containerd 1.0 is an important goal for the project, and
|
||||
will result in a significant simplification of the functions implemented in this repository.
|
||||
running containers.
|
||||
|
||||
## 1.2 Internal decoupling
|
||||
## 1.2 Plugins improvements
|
||||
|
||||
A lot of work has been done in trying to decouple Moby internals. This process of creating
|
||||
standalone projects with a well defined function that attract a dedicated community should continue.
|
||||
As well as integrating `containerd` we would like to integrate [BuildKit](https://github.com/moby/buildkit)
|
||||
as the next standalone component.
|
||||
Docker Engine 1.7.0 introduced plugin support, initially for the use cases of volumes and networks
|
||||
extensions. The plugin infrastructure was kept minimal as we were collecting use cases and real
|
||||
world feedback before optimizing for any particular workflow.
|
||||
|
||||
We see gRPC as the natural communication layer between decoupled components.
|
||||
In the future, we'd like plugins to become first class citizens, and encourage an ecosystem of
|
||||
plugins. This implies in particular making it trivially easy to distribute plugins as containers
|
||||
through any Registry instance, as well as solving the commonly heard pain points of plugins needing
|
||||
to be treated as somewhat special (being active at all time, started before any other user
|
||||
containers, and not as easily dismissed).
|
||||
|
||||
## 1.3 Custom assembly tooling
|
||||
## 1.3 Internal decoupling
|
||||
|
||||
We have been prototyping the Moby [assembly tool](https://github.com/moby/tool) which was originally
|
||||
developed for LinuxKit and intend to turn it into a more generic packaging and assembly mechanism
|
||||
that can build not only the default version of Moby, as distribution packages or other useful forms,
|
||||
but can also build very different container systems, themselves built of cooperating daemons built in
|
||||
and running in containers. We intend to merge this functionality into this repo.
|
||||
A lot of work has been done in trying to decouple the Docker Engine's internals. In particular, the
|
||||
API implementation has been refactored, and the Builder side of the daemon is now
|
||||
[fully independent](https://github.com/docker/docker/tree/master/builder) while still residing in
|
||||
the same repository.
|
||||
|
||||
We are exploring ways to go further with that decoupling, capitalizing on the work introduced by the
|
||||
runtime renovation and plugins improvement efforts. Indeed, the combination of `containerd` support
|
||||
with the concept of "special" containers opens the door for bootstrapping more Engine internals
|
||||
using the same facilities.
|
||||
|
||||
## 1.4 Cluster capable Engine
|
||||
|
||||
The community has been pushing for a more cluster capable Docker Engine, and a huge effort was spent
|
||||
adding features such as multihost networking, and node discovery down at the Engine level. Yet, the
|
||||
Engine is currently incapable of taking scheduling decisions alone, and continues relying on Swarm
|
||||
for that.
|
||||
|
||||
We plan to complete this effort and make Engine fully cluster capable. Multiple instances of the
|
||||
Docker Engine being already capable of discovering each other and establish overlay networking for
|
||||
their container to communicate, the next step is for a given Engine to gain ability to dispatch work
|
||||
to another node in the cluster. This will be introduced in a backward compatible way, such that a
|
||||
`docker run` invocation on a particular node remains fully deterministic.
|
||||
|
||||
# 2 Frozen features
|
||||
|
||||
## 2.1 Docker exec
|
||||
|
||||
We won't accept patches expanding the surface of `docker exec`, which we intend to keep as a
|
||||
*debugging* feature, as well as being strongly dependent on the Runtime ingredient effort.
|
||||
|
||||
## 2.2 Remote Registry Operations
|
||||
|
||||
A large amount of work is ongoing in the area of image distribution and provenance. This includes
|
||||
moving to the V2 Registry API and heavily refactoring the code that powers these features. The
|
||||
desired result is more secure, reliable and easier to use image distribution.
|
||||
|
||||
Part of the problem with this part of the code base is the lack of a stable and flexible interface.
|
||||
If new features are added that access the registry without solidifying these interfaces, achieving
|
||||
feature parity will continue to be elusive. While we get a handle on this situation, we are imposing
|
||||
a moratorium on new code that accesses the Registry API in commands that don't already make remote
|
||||
calls.
|
||||
|
||||
Currently, only the following commands cause interaction with a remote registry:
|
||||
|
||||
- push
|
||||
- pull
|
||||
- run
|
||||
- build
|
||||
- search
|
||||
- login
|
||||
|
||||
In the interest of stabilizing the registry access model during this ongoing work, we are not
|
||||
accepting additions to other commands that will cause remote interaction with the Registry API. This
|
||||
moratorium will lift when the goals of the distribution project have been met.
|
||||
|
||||
89
TESTING.md
89
TESTING.md
@@ -1,89 +0,0 @@
|
||||
# Testing
|
||||
|
||||
This document contains the Moby code testing guidelines. It should answer any
|
||||
questions you may have as an aspiring Moby contributor.
|
||||
|
||||
## Test suites
|
||||
|
||||
Moby has two test suites (and one legacy test suite):
|
||||
|
||||
* Unit tests - use standard `go test` and
|
||||
[gotest.tools/assert](https://godoc.org/gotest.tools/assert) assertions. They are located in
|
||||
the package they test. Unit tests should be fast and test only their own
|
||||
package.
|
||||
* API integration tests - use standard `go test` and
|
||||
[gotest.tools/assert](https://godoc.org/gotest.tools/assert) assertions. They are located in
|
||||
`./integration/<component>` directories, where `component` is: container,
|
||||
image, volume, etc. These tests perform HTTP requests to an API endpoint and
|
||||
check the HTTP response and daemon state after the call.
|
||||
|
||||
The legacy test suite `integration-cli/` is deprecated. No new tests will be
|
||||
added to this suite. Any tests in this suite which require updates should be
|
||||
ported to either the unit test suite or the new API integration test suite.
|
||||
|
||||
## Writing new tests
|
||||
|
||||
Most code changes will fall into one of the following categories.
|
||||
|
||||
### Writing tests for new features
|
||||
|
||||
New code should be covered by unit tests. If the code is difficult to test with
|
||||
a unit tests then that is a good sign that it should be refactored to make it
|
||||
easier to reuse and maintain. Consider accepting unexported interfaces instead
|
||||
of structs so that fakes can be provided for dependencies.
|
||||
|
||||
If the new feature includes a completely new API endpoint then a new API
|
||||
integration test should be added to cover the success case of that endpoint.
|
||||
|
||||
If the new feature does not include a completely new API endpoint consider
|
||||
adding the new API fields to the existing test for that endpoint. A new
|
||||
integration test should **not** be added for every new API field or API error
|
||||
case. Error cases should be handled by unit tests.
|
||||
|
||||
### Writing tests for bug fixes
|
||||
|
||||
Bugs fixes should include a unit test case which exercises the bug.
|
||||
|
||||
A bug fix may also include new assertions in an existing integration tests for the
|
||||
API endpoint.
|
||||
|
||||
### Integration tests environment considerations
|
||||
|
||||
When adding new tests or modifying existing test under `integration/`, testing
|
||||
environment should be properly considered. `skip.If` from
|
||||
[gotest.tools/skip](https://godoc.org/gotest.tools/skip) can be used to make the
|
||||
test run conditionally. Full testing environment conditions can be found at
|
||||
[environment.go](https://github.com/moby/moby/blob/cb37987ee11655ed6bbef663d245e55922354c68/internal/test/environment/environment.go)
|
||||
|
||||
Here is a quick example. If the test needs to interact with a docker daemon on
|
||||
the same host, the following condition should be checked within the test code
|
||||
|
||||
```go
|
||||
skip.If(t, testEnv.IsRemoteDaemon())
|
||||
// your integration test code
|
||||
```
|
||||
|
||||
If a remote daemon is detected, the test will be skipped.
|
||||
|
||||
## Running tests
|
||||
|
||||
To run the unit test suite:
|
||||
|
||||
```
|
||||
make test-unit
|
||||
```
|
||||
|
||||
or `hack/test/unit` from inside a `BINDDIR=. make shell` container or properly
|
||||
configured environment.
|
||||
|
||||
The following environment variables may be used to run a subset of tests:
|
||||
|
||||
* `TESTDIRS` - paths to directories to be tested, defaults to `./...`
|
||||
* `TESTFLAGS` - flags passed to `go test`, to run tests which match a pattern
|
||||
use `TESTFLAGS="-test.run TestNameOrPrefix"`
|
||||
|
||||
To run the integration test suite:
|
||||
|
||||
```
|
||||
make test-integration
|
||||
```
|
||||
11
VENDORING.md
11
VENDORING.md
@@ -26,14 +26,13 @@ dependency on a package of a specific version or greater up to the next major
|
||||
release, without encountering breaking changes.
|
||||
|
||||
## Semantic Versioning
|
||||
Annotated version tags should follow [Semantic Versioning](http://semver.org) policies:
|
||||
Annotated version tags should follow Schema Versioning policies.
|
||||
According to http://semver.org:
|
||||
|
||||
"Given a version number MAJOR.MINOR.PATCH, increment the:
|
||||
|
||||
1. MAJOR version when you make incompatible API changes,
|
||||
2. MINOR version when you add functionality in a backwards-compatible manner, and
|
||||
3. PATCH version when you make backwards-compatible bug fixes.
|
||||
|
||||
MAJOR version when you make incompatible API changes,
|
||||
MINOR version when you add functionality in a backwards-compatible manner, and
|
||||
PATCH version when you make backwards-compatible bug fixes.
|
||||
Additional labels for pre-release and build metadata are available as extensions
|
||||
to the MAJOR.MINOR.PATCH format."
|
||||
|
||||
|
||||
@@ -10,17 +10,17 @@ It consists of various components in this repository:
|
||||
- `client/` The Go client used by the command-line client. It can also be used by third-party Go programs.
|
||||
- `daemon/` The daemon, which serves the API.
|
||||
|
||||
## Swagger definition
|
||||
## Swagger definition
|
||||
|
||||
The API is defined by the [Swagger](http://swagger.io/specification/) definition in `api/swagger.yaml`. This definition can be used to:
|
||||
|
||||
1. Automatically generate documentation.
|
||||
2. Automatically generate the Go server and client. (A work-in-progress.)
|
||||
1. To automatically generate documentation.
|
||||
2. To automatically generate the Go server and client. (A work-in-progress.)
|
||||
3. Provide a machine readable version of the API for introspecting what it can do, automatically generating clients for other languages, etc.
|
||||
|
||||
## Updating the API documentation
|
||||
|
||||
The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, edit this file to represent the change in the documentation.
|
||||
The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, you'll need to edit this file to represent the change in the documentation.
|
||||
|
||||
The file is split into two main sections:
|
||||
|
||||
@@ -29,14 +29,14 @@ The file is split into two main sections:
|
||||
|
||||
To make an edit, first look for the endpoint you want to edit under `paths`, then make the required edits. Endpoints may reference reusable objects with `$ref`, which can be found in the `definitions` section.
|
||||
|
||||
There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919).
|
||||
There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919)
|
||||
|
||||
`swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful when making edits to ensure you are doing the right thing.
|
||||
`swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful for when you are making edits to ensure you are doing the right thing.
|
||||
|
||||
## Viewing the API documentation
|
||||
|
||||
When you make edits to `swagger.yaml`, you may want to check the generated API documentation to ensure it renders correctly.
|
||||
|
||||
Run `make swagger-docs` and a preview will be running at `http://localhost`. Some of the styling may be incorrect, but you'll be able to ensure that it is generating the correct documentation.
|
||||
All the documentation generation is done in the documentation repository, [docker/docker.github.io](https://github.com/docker/docker.github.io). The Swagger definition is vendored periodically into this repository, but you can manually copy over the Swagger definition to test changes.
|
||||
|
||||
The production documentation is generated by vendoring `swagger.yaml` into [docker/docker.github.io](https://github.com/docker/docker.github.io).
|
||||
Copy `api/swagger.yaml` in this repository to `engine/api/[VERSION_NUMBER]/swagger.yaml` in the documentation repository, overwriting what is already there. Then, run `docker-compose up` in the documentation repository and browse to [http://localhost:4000/engine/api/](http://localhost:4000/engine/api/) when it finishes rendering.
|
||||
|
||||
161
api/common.go
161
api/common.go
@@ -1,11 +1,166 @@
|
||||
package api // import "github.com/docker/docker/api"
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"mime"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/libtrust"
|
||||
)
|
||||
|
||||
// Common constants for daemon and client.
|
||||
const (
|
||||
// DefaultVersion of Current REST API
|
||||
DefaultVersion = "1.39"
|
||||
DefaultVersion string = "1.26"
|
||||
|
||||
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||
// command to specify that no base image is to be used.
|
||||
NoBaseImageSpecifier = "scratch"
|
||||
NoBaseImageSpecifier string = "scratch"
|
||||
)
|
||||
|
||||
// byPortInfo is a temporary type used to sort types.Port by its fields
|
||||
type byPortInfo []types.Port
|
||||
|
||||
func (r byPortInfo) Len() int { return len(r) }
|
||||
func (r byPortInfo) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
func (r byPortInfo) Less(i, j int) bool {
|
||||
if r[i].PrivatePort != r[j].PrivatePort {
|
||||
return r[i].PrivatePort < r[j].PrivatePort
|
||||
}
|
||||
|
||||
if r[i].IP != r[j].IP {
|
||||
return r[i].IP < r[j].IP
|
||||
}
|
||||
|
||||
if r[i].PublicPort != r[j].PublicPort {
|
||||
return r[i].PublicPort < r[j].PublicPort
|
||||
}
|
||||
|
||||
return r[i].Type < r[j].Type
|
||||
}
|
||||
|
||||
// DisplayablePorts returns formatted string representing open ports of container
|
||||
// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
|
||||
// it's used by command 'docker ps'
|
||||
func DisplayablePorts(ports []types.Port) string {
|
||||
type portGroup struct {
|
||||
first uint16
|
||||
last uint16
|
||||
}
|
||||
groupMap := make(map[string]*portGroup)
|
||||
var result []string
|
||||
var hostMappings []string
|
||||
var groupMapKeys []string
|
||||
sort.Sort(byPortInfo(ports))
|
||||
for _, port := range ports {
|
||||
current := port.PrivatePort
|
||||
portKey := port.Type
|
||||
if port.IP != "" {
|
||||
if port.PublicPort != current {
|
||||
hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
|
||||
continue
|
||||
}
|
||||
portKey = fmt.Sprintf("%s/%s", port.IP, port.Type)
|
||||
}
|
||||
group := groupMap[portKey]
|
||||
|
||||
if group == nil {
|
||||
groupMap[portKey] = &portGroup{first: current, last: current}
|
||||
// record order that groupMap keys are created
|
||||
groupMapKeys = append(groupMapKeys, portKey)
|
||||
continue
|
||||
}
|
||||
if current == (group.last + 1) {
|
||||
group.last = current
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, formGroup(portKey, group.first, group.last))
|
||||
groupMap[portKey] = &portGroup{first: current, last: current}
|
||||
}
|
||||
for _, portKey := range groupMapKeys {
|
||||
g := groupMap[portKey]
|
||||
result = append(result, formGroup(portKey, g.first, g.last))
|
||||
}
|
||||
result = append(result, hostMappings...)
|
||||
return strings.Join(result, ", ")
|
||||
}
|
||||
|
||||
func formGroup(key string, start, last uint16) string {
|
||||
parts := strings.Split(key, "/")
|
||||
groupType := parts[0]
|
||||
var ip string
|
||||
if len(parts) > 1 {
|
||||
ip = parts[0]
|
||||
groupType = parts[1]
|
||||
}
|
||||
group := strconv.Itoa(int(start))
|
||||
if start != last {
|
||||
group = fmt.Sprintf("%s-%d", group, last)
|
||||
}
|
||||
if ip != "" {
|
||||
group = fmt.Sprintf("%s:%s->%s", ip, group, group)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", group, groupType)
|
||||
}
|
||||
|
||||
// MatchesContentType validates the content type against the expected one
|
||||
func MatchesContentType(contentType, expectedType string) bool {
|
||||
mimetype, _, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error parsing media type: %s error: %v", contentType, err)
|
||||
}
|
||||
return err == nil && mimetype == expectedType
|
||||
}
|
||||
|
||||
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
|
||||
// otherwise generates a new one
|
||||
func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
|
||||
err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
trustKey, err := libtrust.LoadKeyFile(trustKeyPath)
|
||||
if err == libtrust.ErrKeyFileDoesNotExist {
|
||||
trustKey, err = libtrust.GenerateECP256PrivateKey()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error generating key: %s", err)
|
||||
}
|
||||
encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error serializing key: %s", err)
|
||||
}
|
||||
if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil {
|
||||
return nil, fmt.Errorf("Error saving key file: %s", err)
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err)
|
||||
}
|
||||
return trustKey, nil
|
||||
}
|
||||
|
||||
func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) {
|
||||
if ext == ".json" || ext == ".jwk" {
|
||||
encoded, err = json.Marshal(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to encode private key JWK: %s", err)
|
||||
}
|
||||
} else {
|
||||
pemBlock, err := key.PEMBlock()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to encode private key PEM: %s", err)
|
||||
}
|
||||
encoded = pem.EncodeToMemory(pemBlock)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
341
api/common_test.go
Normal file
341
api/common_test.go
Normal file
@@ -0,0 +1,341 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
type ports struct {
|
||||
ports []types.Port
|
||||
expected string
|
||||
}
|
||||
|
||||
// DisplayablePorts
|
||||
func TestDisplayablePorts(t *testing.T) {
|
||||
cases := []ports{
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"9988/tcp"},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9988/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "0.0.0.0",
|
||||
PrivatePort: 9988,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"0.0.0.0:0->9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"4.3.2.1:8899->9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 9988,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"4.3.2.1:9988->9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
Type: "udp",
|
||||
}, {
|
||||
PrivatePort: 9988,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9988/udp, 9988/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 9998,
|
||||
PrivatePort: 9998,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 9999,
|
||||
PrivatePort: 9999,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"1.2.3.4:9998-9999->9998-9999/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 8887,
|
||||
PrivatePort: 9998,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 8888,
|
||||
PrivatePort: 9999,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"1.2.3.4:8887->9998/udp, 1.2.3.4:8888->9999/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9998,
|
||||
Type: "udp",
|
||||
}, {
|
||||
PrivatePort: 9999,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9998-9999/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 6677,
|
||||
PublicPort: 7766,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9988/udp, 1.2.3.4:7766->6677/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 2233,
|
||||
PublicPort: 3322,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"4.3.2.1:3322->2233/tcp, 1.2.3.4:8899->9988/tcp, 1.2.3.4:8899->9988/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 6677,
|
||||
PublicPort: 7766,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 2233,
|
||||
PublicPort: 3322,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"9988/udp, 4.3.2.1:3322->2233/tcp, 1.2.3.4:7766->6677/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 80,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
PrivatePort: 1024,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
PrivatePort: 80,
|
||||
Type: "udp",
|
||||
}, {
|
||||
PrivatePort: 1024,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"80/tcp, 80/udp, 1024/tcp, 1024/udp, 1.1.1.1:1024->80/tcp, 1.1.1.1:1024->80/udp, 2.1.1.1:1024->80/tcp, 2.1.1.1:1024->80/udp, 1.1.1.1:80->1024/tcp, 1.1.1.1:80->1024/udp, 2.1.1.1:80->1024/tcp, 2.1.1.1:80->1024/udp",
|
||||
},
|
||||
}
|
||||
|
||||
for _, port := range cases {
|
||||
actual := DisplayablePorts(port.ports)
|
||||
if port.expected != actual {
|
||||
t.Fatalf("Expected %s, got %s.", port.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MatchesContentType
|
||||
func TestJsonContentType(t *testing.T) {
|
||||
if !MatchesContentType("application/json", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if !MatchesContentType("application/json; charset=utf-8", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if MatchesContentType("dockerapplication/json", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
// LoadOrCreateTrustKey
|
||||
func TestLoadOrCreateTrustKeyInvalidKeyFile(t *testing.T) {
|
||||
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpKeyFolderPath)
|
||||
|
||||
tmpKeyFile, err := ioutil.TempFile(tmpKeyFolderPath, "keyfile")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := LoadOrCreateTrustKey(tmpKeyFile.Name()); err == nil {
|
||||
t.Fatalf("expected an error, got nothing.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLoadOrCreateTrustKeyCreateKey(t *testing.T) {
|
||||
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpKeyFolderPath)
|
||||
|
||||
// Without the need to create the folder hierarchy
|
||||
tmpKeyFile := filepath.Join(tmpKeyFolderPath, "keyfile")
|
||||
|
||||
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
|
||||
t.Fatalf("expected a new key file, got : %v and %v", err, key)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(tmpKeyFile); err != nil {
|
||||
t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err)
|
||||
}
|
||||
|
||||
// With the need to create the folder hierarchy as tmpKeyFie is in a path
|
||||
// where some folders do not exist.
|
||||
tmpKeyFile = filepath.Join(tmpKeyFolderPath, "folder/hierarchy/keyfile")
|
||||
|
||||
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
|
||||
t.Fatalf("expected a new key file, got : %v and %v", err, key)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(tmpKeyFile); err != nil {
|
||||
t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err)
|
||||
}
|
||||
|
||||
// With no path at all
|
||||
defer os.Remove("keyfile")
|
||||
if key, err := LoadOrCreateTrustKey("keyfile"); err != nil || key == nil {
|
||||
t.Fatalf("expected a new key file, got : %v and %v", err, key)
|
||||
}
|
||||
|
||||
if _, err := os.Stat("keyfile"); err != nil {
|
||||
t.Fatalf("Expected to find a file keyfile, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadOrCreateTrustKeyLoadValidKey(t *testing.T) {
|
||||
tmpKeyFile := filepath.Join("fixtures", "keyfile")
|
||||
|
||||
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
|
||||
t.Fatalf("expected a key file, got : %v and %v", err, key)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// +build !windows
|
||||
|
||||
package api // import "github.com/docker/docker/api"
|
||||
package api
|
||||
|
||||
// MinVersion represents Minimum REST API version supported
|
||||
const MinVersion = "1.12"
|
||||
const MinVersion string = "1.12"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package api // import "github.com/docker/docker/api"
|
||||
package api
|
||||
|
||||
// MinVersion represents Minimum REST API version supported
|
||||
// Technically the first daemon API version released on Windows is v1.25 in
|
||||
// engine version 1.13. However, some clients are explicitly using downlevel
|
||||
// APIs (e.g. docker-compose v2.1 file format) and that is just too restrictive.
|
||||
// APIs (eg docker-compose v2.1 file format) and that is just too restrictive.
|
||||
// Hence also allowing 1.24 on Windows.
|
||||
const MinVersion string = "1.24"
|
||||
|
||||
47
api/errors/errors.go
Normal file
47
api/errors/errors.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package errors
|
||||
|
||||
import "net/http"
|
||||
|
||||
// apiError is an error wrapper that also
|
||||
// holds information about response status codes.
|
||||
type apiError struct {
|
||||
error
|
||||
statusCode int
|
||||
}
|
||||
|
||||
// HTTPErrorStatusCode returns a status code.
|
||||
func (e apiError) HTTPErrorStatusCode() int {
|
||||
return e.statusCode
|
||||
}
|
||||
|
||||
// NewErrorWithStatusCode allows you to associate
|
||||
// a specific HTTP Status Code to an error.
|
||||
// The Server will take that code and set
|
||||
// it as the response status.
|
||||
func NewErrorWithStatusCode(err error, code int) error {
|
||||
return apiError{err, code}
|
||||
}
|
||||
|
||||
// NewBadRequestError creates a new API error
|
||||
// that has the 400 HTTP status code associated to it.
|
||||
func NewBadRequestError(err error) error {
|
||||
return NewErrorWithStatusCode(err, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// NewRequestForbiddenError creates a new API error
|
||||
// that has the 403 HTTP status code associated to it.
|
||||
func NewRequestForbiddenError(err error) error {
|
||||
return NewErrorWithStatusCode(err, http.StatusForbidden)
|
||||
}
|
||||
|
||||
// NewRequestNotFoundError creates a new API error
|
||||
// that has the 404 HTTP status code associated to it.
|
||||
func NewRequestNotFoundError(err error) error {
|
||||
return NewErrorWithStatusCode(err, http.StatusNotFound)
|
||||
}
|
||||
|
||||
// NewRequestConflictError creates a new API error
|
||||
// that has the 409 HTTP status code associated to it.
|
||||
func NewRequestConflictError(err error) error {
|
||||
return NewErrorWithStatusCode(err, http.StatusConflict)
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package build // import "github.com/docker/docker/api/server/backend/build"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/builder"
|
||||
buildkit "github.com/docker/docker/builder/builder-next"
|
||||
"github.com/docker/docker/builder/fscache"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// ImageComponent provides an interface for working with images
|
||||
type ImageComponent interface {
|
||||
SquashImage(from string, to string) (string, error)
|
||||
TagImageWithReference(image.ID, reference.Named) error
|
||||
}
|
||||
|
||||
// Builder defines interface for running a build
|
||||
type Builder interface {
|
||||
Build(context.Context, backend.BuildConfig) (*builder.Result, error)
|
||||
}
|
||||
|
||||
// Backend provides build functionality to the API router
|
||||
type Backend struct {
|
||||
builder Builder
|
||||
fsCache *fscache.FSCache
|
||||
imageComponent ImageComponent
|
||||
buildkit *buildkit.Builder
|
||||
}
|
||||
|
||||
// NewBackend creates a new build backend from components
|
||||
func NewBackend(components ImageComponent, builder Builder, fsCache *fscache.FSCache, buildkit *buildkit.Builder) (*Backend, error) {
|
||||
return &Backend{imageComponent: components, builder: builder, fsCache: fsCache, buildkit: buildkit}, nil
|
||||
}
|
||||
|
||||
// Build builds an image from a Source
|
||||
func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string, error) {
|
||||
options := config.Options
|
||||
useBuildKit := options.Version == types.BuilderBuildKit
|
||||
|
||||
tagger, err := NewTagger(b.imageComponent, config.ProgressWriter.StdoutFormatter, options.Tags)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var build *builder.Result
|
||||
if useBuildKit {
|
||||
build, err = b.buildkit.Build(ctx, config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
build, err = b.builder.Build(ctx, config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if build == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
var imageID = build.ImageID
|
||||
if options.Squash {
|
||||
if imageID, err = squashBuild(build, b.imageComponent); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if config.ProgressWriter.AuxFormatter != nil {
|
||||
if err = config.ProgressWriter.AuxFormatter.Emit("moby.image.id", types.BuildResult{ID: imageID}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !useBuildKit {
|
||||
stdout := config.ProgressWriter.StdoutFormatter
|
||||
fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
|
||||
err = tagger.TagImages(image.ID(imageID))
|
||||
}
|
||||
return imageID, err
|
||||
}
|
||||
|
||||
// PruneCache removes all cached build sources
|
||||
func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
var fsCacheSize uint64
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
fsCacheSize, err = b.fsCache.Prune(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to prune fscache")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
var buildCacheSize int64
|
||||
var cacheIDs []string
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
buildCacheSize, cacheIDs, err = b.buildkit.Prune(ctx, opts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to prune build cache")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.BuildCachePruneReport{SpaceReclaimed: fsCacheSize + uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
|
||||
}
|
||||
|
||||
// Cancel cancels the build by ID
|
||||
func (b *Backend) Cancel(ctx context.Context, id string) error {
|
||||
return b.buildkit.Cancel(ctx, id)
|
||||
}
|
||||
|
||||
func squashBuild(build *builder.Result, imageComponent ImageComponent) (string, error) {
|
||||
var fromID string
|
||||
if build.FromImage != nil {
|
||||
fromID = build.FromImage.ImageID()
|
||||
}
|
||||
imageID, err := imageComponent.SquashImage(build.ImageID, fromID)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error squashing image")
|
||||
}
|
||||
return imageID, nil
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package build // import "github.com/docker/docker/api/server/backend/build"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Tagger is responsible for tagging an image created by a builder
|
||||
type Tagger struct {
|
||||
imageComponent ImageComponent
|
||||
stdout io.Writer
|
||||
repoAndTags []reference.Named
|
||||
}
|
||||
|
||||
// NewTagger returns a new Tagger for tagging the images of a build.
|
||||
// If any of the names are invalid tags an error is returned.
|
||||
func NewTagger(backend ImageComponent, stdout io.Writer, names []string) (*Tagger, error) {
|
||||
reposAndTags, err := sanitizeRepoAndTags(names)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Tagger{
|
||||
imageComponent: backend,
|
||||
stdout: stdout,
|
||||
repoAndTags: reposAndTags,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TagImages creates image tags for the imageID
|
||||
func (bt *Tagger) TagImages(imageID image.ID) error {
|
||||
for _, rt := range bt.repoAndTags {
|
||||
if err := bt.imageComponent.TagImageWithReference(imageID, rt); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(bt.stdout, "Successfully tagged %s\n", reference.FamiliarString(rt))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// sanitizeRepoAndTags parses the raw "t" parameter received from the client
|
||||
// to a slice of repoAndTag.
|
||||
// It also validates each repoName and tag.
|
||||
func sanitizeRepoAndTags(names []string) ([]reference.Named, error) {
|
||||
var (
|
||||
repoAndTags []reference.Named
|
||||
// This map is used for deduplicating the "-t" parameter.
|
||||
uniqNames = make(map[string]struct{})
|
||||
)
|
||||
for _, repo := range names {
|
||||
if repo == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
ref, err := reference.ParseNormalizedNamed(repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return nil, errors.New("build tag cannot contain a digest")
|
||||
}
|
||||
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
nameWithTag := ref.String()
|
||||
|
||||
if _, exists := uniqNames[nameWithTag]; !exists {
|
||||
uniqNames[nameWithTag] = struct{}{}
|
||||
repoAndTags = append(repoAndTags, ref)
|
||||
}
|
||||
}
|
||||
return repoAndTags, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
@@ -1,23 +1,34 @@
|
||||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
type causer interface {
|
||||
Cause() error
|
||||
// httpStatusError is an interface
|
||||
// that errors with custom status codes
|
||||
// implement to tell the api layer
|
||||
// which response status to set.
|
||||
type httpStatusError interface {
|
||||
HTTPErrorStatusCode() int
|
||||
}
|
||||
|
||||
// GetHTTPErrorStatusCode retrieves status code from error message.
|
||||
// inputValidationError is an interface
|
||||
// that errors generated by invalid
|
||||
// inputs can implement to tell the
|
||||
// api layer to set a 400 status code
|
||||
// in the response.
|
||||
type inputValidationError interface {
|
||||
IsValidationError() bool
|
||||
}
|
||||
|
||||
// GetHTTPErrorStatusCode retrieves status code from error message
|
||||
func GetHTTPErrorStatusCode(err error) int {
|
||||
if err == nil {
|
||||
logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling")
|
||||
@@ -25,44 +36,41 @@ func GetHTTPErrorStatusCode(err error) int {
|
||||
}
|
||||
|
||||
var statusCode int
|
||||
errMsg := err.Error()
|
||||
|
||||
// Stop right there
|
||||
// Are you sure you should be adding a new error class here? Do one of the existing ones work?
|
||||
|
||||
// Note that the below functions are already checking the error causal chain for matches.
|
||||
switch {
|
||||
case errdefs.IsNotFound(err):
|
||||
statusCode = http.StatusNotFound
|
||||
case errdefs.IsInvalidParameter(err):
|
||||
switch e := err.(type) {
|
||||
case httpStatusError:
|
||||
statusCode = e.HTTPErrorStatusCode()
|
||||
case inputValidationError:
|
||||
statusCode = http.StatusBadRequest
|
||||
case errdefs.IsConflict(err) || errdefs.IsAlreadyExists(err):
|
||||
statusCode = http.StatusConflict
|
||||
case errdefs.IsUnauthorized(err):
|
||||
statusCode = http.StatusUnauthorized
|
||||
case errdefs.IsUnavailable(err):
|
||||
statusCode = http.StatusServiceUnavailable
|
||||
case errdefs.IsForbidden(err):
|
||||
statusCode = http.StatusForbidden
|
||||
case errdefs.IsNotModified(err):
|
||||
statusCode = http.StatusNotModified
|
||||
case errdefs.IsNotImplemented(err):
|
||||
statusCode = http.StatusNotImplemented
|
||||
case errdefs.IsSystem(err) || errdefs.IsUnknown(err) || errdefs.IsDataLoss(err) || errdefs.IsDeadline(err) || errdefs.IsCancelled(err):
|
||||
statusCode = http.StatusInternalServerError
|
||||
default:
|
||||
statusCode = statusCodeFromGRPCError(err)
|
||||
if statusCode != http.StatusInternalServerError {
|
||||
return statusCode
|
||||
// FIXME: this is brittle and should not be necessary, but we still need to identify if
|
||||
// there are errors falling back into this logic.
|
||||
// If we need to differentiate between different possible error types,
|
||||
// we should create appropriate error types that implement the httpStatusError interface.
|
||||
errStr := strings.ToLower(errMsg)
|
||||
for _, status := range []struct {
|
||||
keyword string
|
||||
code int
|
||||
}{
|
||||
{"not found", http.StatusNotFound},
|
||||
{"no such", http.StatusNotFound},
|
||||
{"bad parameter", http.StatusBadRequest},
|
||||
{"no command", http.StatusBadRequest},
|
||||
{"conflict", http.StatusConflict},
|
||||
{"impossible", http.StatusNotAcceptable},
|
||||
{"wrong login/password", http.StatusUnauthorized},
|
||||
{"unauthorized", http.StatusUnauthorized},
|
||||
{"hasn't been activated", http.StatusForbidden},
|
||||
{"this node", http.StatusServiceUnavailable},
|
||||
{"needs to be unlocked", http.StatusServiceUnavailable},
|
||||
{"certificates have expired", http.StatusServiceUnavailable},
|
||||
} {
|
||||
if strings.Contains(errStr, status.keyword) {
|
||||
statusCode = status.code
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if e, ok := err.(causer); ok {
|
||||
return GetHTTPErrorStatusCode(e.Cause())
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"module": "api",
|
||||
"error_type": fmt.Sprintf("%T", err),
|
||||
}).Debugf("FIXME: Got an API for which error does not match any expected type!!!: %+v", err)
|
||||
}
|
||||
|
||||
if statusCode == 0 {
|
||||
@@ -93,39 +101,3 @@ func MakeErrorHandler(err error) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// statusCodeFromGRPCError returns status code according to gRPC error
|
||||
func statusCodeFromGRPCError(err error) int {
|
||||
switch grpc.Code(err) {
|
||||
case codes.InvalidArgument: // code 3
|
||||
return http.StatusBadRequest
|
||||
case codes.NotFound: // code 5
|
||||
return http.StatusNotFound
|
||||
case codes.AlreadyExists: // code 6
|
||||
return http.StatusConflict
|
||||
case codes.PermissionDenied: // code 7
|
||||
return http.StatusForbidden
|
||||
case codes.FailedPrecondition: // code 9
|
||||
return http.StatusBadRequest
|
||||
case codes.Unauthenticated: // code 16
|
||||
return http.StatusUnauthorized
|
||||
case codes.OutOfRange: // code 11
|
||||
return http.StatusBadRequest
|
||||
case codes.Unimplemented: // code 12
|
||||
return http.StatusNotImplemented
|
||||
case codes.Unavailable: // code 14
|
||||
return http.StatusServiceUnavailable
|
||||
default:
|
||||
if e, ok := err.(causer); ok {
|
||||
return statusCodeFromGRPCError(e.Cause())
|
||||
}
|
||||
// codes.Canceled(1)
|
||||
// codes.Unknown(2)
|
||||
// codes.DeadlineExceeded(4)
|
||||
// codes.ResourceExhausted(8)
|
||||
// codes.Aborted(10)
|
||||
// codes.Internal(13)
|
||||
// codes.DataLoss(15)
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -13,7 +15,7 @@ func BoolValue(r *http.Request, k string) bool {
|
||||
}
|
||||
|
||||
// BoolValueOrDefault returns the default bool passed if the query param is
|
||||
// missing, otherwise it's just a proxy to boolValue above.
|
||||
// missing, otherwise it's just a proxy to boolValue above
|
||||
func BoolValueOrDefault(r *http.Request, k string, d bool) bool {
|
||||
if _, ok := r.Form[k]; !ok {
|
||||
return d
|
||||
@@ -36,7 +38,10 @@ func Int64ValueOrZero(r *http.Request, k string) int64 {
|
||||
func Int64ValueOrDefault(r *http.Request, field string, def int64) (int64, error) {
|
||||
if r.Form.Get(field) != "" {
|
||||
value, err := strconv.ParseInt(r.Form.Get(field), 10, 64)
|
||||
return value, err
|
||||
if err != nil {
|
||||
return value, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
return def, nil
|
||||
}
|
||||
@@ -47,16 +52,6 @@ type ArchiveOptions struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
type badParameterError struct {
|
||||
param string
|
||||
}
|
||||
|
||||
func (e badParameterError) Error() string {
|
||||
return "bad parameter: " + e.param + "cannot be empty"
|
||||
}
|
||||
|
||||
func (e badParameterError) InvalidParameter() {}
|
||||
|
||||
// ArchiveFormValues parses form values and turns them into ArchiveOptions.
|
||||
// It fails if the archive name and path are not in the request.
|
||||
func ArchiveFormValues(r *http.Request, vars map[string]string) (ArchiveOptions, error) {
|
||||
@@ -65,12 +60,14 @@ func ArchiveFormValues(r *http.Request, vars map[string]string) (ArchiveOptions,
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
if name == "" {
|
||||
return ArchiveOptions{}, badParameterError{"name"}
|
||||
}
|
||||
path := r.Form.Get("path")
|
||||
if path == "" {
|
||||
return ArchiveOptions{}, badParameterError{"path"}
|
||||
path := filepath.FromSlash(r.Form.Get("path"))
|
||||
|
||||
switch {
|
||||
case name == "":
|
||||
return ArchiveOptions{}, fmt.Errorf("bad parameter: 'name' cannot be empty")
|
||||
case path == "":
|
||||
return ArchiveOptions{}, fmt.Errorf("bad parameter: 'path' cannot be empty")
|
||||
}
|
||||
|
||||
return ArchiveOptions{name, path}, nil
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
@@ -100,6 +100,6 @@ func TestInt64ValueOrDefaultWithError(t *testing.T) {
|
||||
|
||||
_, err := Int64ValueOrDefault(r, "test", -1)
|
||||
if err == nil {
|
||||
t.Fatal("Expected an error.")
|
||||
t.Fatalf("Expected an error.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
// APIVersionKey is the client's requested API version.
|
||||
const APIVersionKey contextKey = "api-version"
|
||||
const APIVersionKey = "api-version"
|
||||
|
||||
// UAStringKey is used as key type for user-agent string in net/context struct
|
||||
const UAStringKey = "upstream-user-agent"
|
||||
|
||||
// APIFunc is an adapter to allow the use of ordinary functions as Docker API endpoints.
|
||||
// Any function that has the appropriate signature can be registered as an API endpoint (e.g. getVersion).
|
||||
@@ -58,10 +58,10 @@ func CheckForJSON(r *http.Request) error {
|
||||
}
|
||||
|
||||
// Otherwise it better be json
|
||||
if matchesContentType(ct, "application/json") {
|
||||
if api.MatchesContentType(ct, "application/json") {
|
||||
return nil
|
||||
}
|
||||
return errdefs.InvalidParameter(errors.Errorf("Content-Type specified (%s) must be 'application/json'", ct))
|
||||
return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
|
||||
}
|
||||
|
||||
// ParseForm ensures the request form is parsed even with invalid content types.
|
||||
@@ -71,30 +71,20 @@ func ParseForm(r *http.Request) error {
|
||||
return nil
|
||||
}
|
||||
if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VersionFromContext returns an API version from the context using APIVersionKey.
|
||||
// It panics if the context value does not have version.Version type.
|
||||
func VersionFromContext(ctx context.Context) string {
|
||||
func VersionFromContext(ctx context.Context) (ver string) {
|
||||
if ctx == nil {
|
||||
return ""
|
||||
return
|
||||
}
|
||||
|
||||
if val := ctx.Value(APIVersionKey); val != nil {
|
||||
return val.(string)
|
||||
val := ctx.Value(APIVersionKey)
|
||||
if val == nil {
|
||||
return
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// matchesContentType validates the content type against the expected one
|
||||
func matchesContentType(contentType, expectedType string) bool {
|
||||
mimetype, _, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error parsing media type: %s error: %v", contentType, err)
|
||||
}
|
||||
return err == nil && mimetype == expectedType
|
||||
return val.(string)
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
|
||||
import "testing"
|
||||
|
||||
// matchesContentType
|
||||
func TestJsonContentType(t *testing.T) {
|
||||
if !matchesContentType("application/json", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if !matchesContentType("application/json; charset=utf-8", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if matchesContentType("dockerapplication/json", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
// +build go1.7
|
||||
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
16
api/server/httputils/httputils_write_json_go16.go
Normal file
16
api/server/httputils/httputils_write_json_go16.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// +build go1.6,!go1.7
|
||||
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// WriteJSON writes the value v to the http response stream as json with standard json encoding.
|
||||
func WriteJSON(w http.ResponseWriter, code int, v interface{}) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(v)
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
)
|
||||
|
||||
// WriteLogStream writes an encoded byte stream of log messages from the
|
||||
// messages channel, multiplexing them with a stdcopy.Writer if mux is true
|
||||
func WriteLogStream(_ context.Context, w io.Writer, msgs <-chan *backend.LogMessage, config *types.ContainerLogsOptions, mux bool) {
|
||||
wf := ioutils.NewWriteFlusher(w)
|
||||
defer wf.Close()
|
||||
|
||||
wf.Flush()
|
||||
|
||||
outStream := io.Writer(wf)
|
||||
errStream := outStream
|
||||
sysErrStream := errStream
|
||||
if mux {
|
||||
sysErrStream = stdcopy.NewStdWriter(outStream, stdcopy.Systemerr)
|
||||
errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
|
||||
outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
|
||||
}
|
||||
|
||||
for {
|
||||
msg, ok := <-msgs
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// check if the message contains an error. if so, write that error
|
||||
// and exit
|
||||
if msg.Err != nil {
|
||||
fmt.Fprintf(sysErrStream, "Error grabbing logs: %v\n", msg.Err)
|
||||
continue
|
||||
}
|
||||
logLine := msg.Line
|
||||
if config.Details {
|
||||
logLine = append(attrsByteSlice(msg.Attrs), ' ')
|
||||
logLine = append(logLine, msg.Line...)
|
||||
}
|
||||
if config.Timestamps {
|
||||
logLine = append([]byte(msg.Timestamp.Format(jsonmessage.RFC3339NanoFixed)+" "), logLine...)
|
||||
}
|
||||
if msg.Source == "stdout" && config.ShowStdout {
|
||||
outStream.Write(logLine)
|
||||
}
|
||||
if msg.Source == "stderr" && config.ShowStderr {
|
||||
errStream.Write(logLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type byKey []backend.LogAttr
|
||||
|
||||
func (b byKey) Len() int { return len(b) }
|
||||
func (b byKey) Less(i, j int) bool { return b[i].Key < b[j].Key }
|
||||
func (b byKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||
|
||||
func attrsByteSlice(a []backend.LogAttr) []byte {
|
||||
// Note this sorts "a" in-place. That is fine here - nothing else is
|
||||
// going to use Attrs or care about the order.
|
||||
sort.Sort(byKey(a))
|
||||
|
||||
var ret []byte
|
||||
for i, pair := range a {
|
||||
k, v := url.QueryEscape(pair.Key), url.QueryEscape(pair.Value)
|
||||
ret = append(ret, []byte(k)...)
|
||||
ret = append(ret, '=')
|
||||
ret = append(ret, []byte(v)...)
|
||||
if i != len(a)-1 {
|
||||
ret = append(ret, ',')
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package server // import "github.com/docker/docker/api/server"
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/middleware"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// handlerWithGlobalMiddlewares wraps the handler function for a request with
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package middleware // import "github.com/docker/docker/api/server/middleware"
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CORSMiddleware injects CORS headers to each request
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package middleware // import "github.com/docker/docker/api/server/middleware"
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// DebugRequestMiddleware dumps the request to logger
|
||||
@@ -41,7 +41,7 @@ func DebugRequestMiddleware(handler func(ctx context.Context, w http.ResponseWri
|
||||
|
||||
var postForm map[string]interface{}
|
||||
if err := json.Unmarshal(b, &postForm); err == nil {
|
||||
maskSecretKeys(postForm, r.RequestURI)
|
||||
maskSecretKeys(postForm)
|
||||
formStr, errMarshal := json.Marshal(postForm)
|
||||
if errMarshal == nil {
|
||||
logrus.Debugf("form data: %s", string(formStr))
|
||||
@@ -54,41 +54,23 @@ func DebugRequestMiddleware(handler func(ctx context.Context, w http.ResponseWri
|
||||
}
|
||||
}
|
||||
|
||||
func maskSecretKeys(inp interface{}, path string) {
|
||||
// Remove any query string from the path
|
||||
idx := strings.Index(path, "?")
|
||||
if idx != -1 {
|
||||
path = path[:idx]
|
||||
}
|
||||
// Remove trailing / characters
|
||||
path = strings.TrimRight(path, "/")
|
||||
|
||||
func maskSecretKeys(inp interface{}) {
|
||||
if arr, ok := inp.([]interface{}); ok {
|
||||
for _, f := range arr {
|
||||
maskSecretKeys(f, path)
|
||||
maskSecretKeys(f)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if form, ok := inp.(map[string]interface{}); ok {
|
||||
loop0:
|
||||
for k, v := range form {
|
||||
for _, m := range []string{"password", "secret", "jointoken", "unlockkey", "signingcakey"} {
|
||||
for _, m := range []string{"password", "secret", "jointoken", "unlockkey"} {
|
||||
if strings.EqualFold(m, k) {
|
||||
form[k] = "*****"
|
||||
continue loop0
|
||||
}
|
||||
}
|
||||
maskSecretKeys(v, path)
|
||||
}
|
||||
|
||||
// Route-specific redactions
|
||||
if strings.HasSuffix(path, "/secrets/create") {
|
||||
for k := range form {
|
||||
if k == "Data" {
|
||||
form[k] = "*****"
|
||||
}
|
||||
}
|
||||
maskSecretKeys(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
package middleware // import "github.com/docker/docker/api/server/middleware"
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
)
|
||||
|
||||
func TestMaskSecretKeys(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
input map[string]interface{}
|
||||
expected map[string]interface{}
|
||||
}{
|
||||
{
|
||||
path: "/v1.30/secrets/create",
|
||||
input: map[string]interface{}{"Data": "foo", "Name": "name", "Labels": map[string]interface{}{}},
|
||||
expected: map[string]interface{}{"Data": "*****", "Name": "name", "Labels": map[string]interface{}{}},
|
||||
},
|
||||
{
|
||||
path: "/v1.30/secrets/create//",
|
||||
input: map[string]interface{}{"Data": "foo", "Name": "name", "Labels": map[string]interface{}{}},
|
||||
expected: map[string]interface{}{"Data": "*****", "Name": "name", "Labels": map[string]interface{}{}},
|
||||
},
|
||||
|
||||
{
|
||||
path: "/secrets/create?key=val",
|
||||
input: map[string]interface{}{"Data": "foo", "Name": "name", "Labels": map[string]interface{}{}},
|
||||
expected: map[string]interface{}{"Data": "*****", "Name": "name", "Labels": map[string]interface{}{}},
|
||||
},
|
||||
{
|
||||
path: "/v1.30/some/other/path",
|
||||
input: map[string]interface{}{
|
||||
"password": "pass",
|
||||
"other": map[string]interface{}{
|
||||
"secret": "secret",
|
||||
"jointoken": "jointoken",
|
||||
"unlockkey": "unlockkey",
|
||||
"signingcakey": "signingcakey",
|
||||
},
|
||||
},
|
||||
expected: map[string]interface{}{
|
||||
"password": "*****",
|
||||
"other": map[string]interface{}{
|
||||
"secret": "*****",
|
||||
"jointoken": "*****",
|
||||
"unlockkey": "*****",
|
||||
"signingcakey": "*****",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testcase := range tests {
|
||||
maskSecretKeys(testcase.input, testcase.path)
|
||||
assert.Check(t, is.DeepEqual(testcase.expected, testcase.input))
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package middleware // import "github.com/docker/docker/api/server/middleware"
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// ExperimentalMiddleware is a the middleware in charge of adding the
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package middleware // import "github.com/docker/docker/api/server/middleware"
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Middleware is an interface to allow the use of ordinary functions as Docker API filters.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package middleware // import "github.com/docker/docker/api/server/middleware"
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// VersionMiddleware is a middleware that
|
||||
@@ -28,37 +28,22 @@ func NewVersionMiddleware(s, d, m string) VersionMiddleware {
|
||||
}
|
||||
}
|
||||
|
||||
type versionUnsupportedError struct {
|
||||
version, minVersion, maxVersion string
|
||||
}
|
||||
|
||||
func (e versionUnsupportedError) Error() string {
|
||||
if e.minVersion != "" {
|
||||
return fmt.Sprintf("client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", e.version, e.minVersion)
|
||||
}
|
||||
return fmt.Sprintf("client version %s is too new. Maximum supported API version is %s", e.version, e.maxVersion)
|
||||
}
|
||||
|
||||
func (e versionUnsupportedError) InvalidParameter() {}
|
||||
|
||||
// WrapHandler returns a new handler function wrapping the previous one in the request chain.
|
||||
func (v VersionMiddleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
w.Header().Set("Server", fmt.Sprintf("Docker/%s (%s)", v.serverVersion, runtime.GOOS))
|
||||
w.Header().Set("API-Version", v.defaultVersion)
|
||||
w.Header().Set("OSType", runtime.GOOS)
|
||||
|
||||
apiVersion := vars["version"]
|
||||
if apiVersion == "" {
|
||||
apiVersion = v.defaultVersion
|
||||
}
|
||||
|
||||
if versions.LessThan(apiVersion, v.minVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, minVersion: v.minVersion}
|
||||
return errors.NewBadRequestError(fmt.Errorf("client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", apiVersion, v.minVersion))
|
||||
}
|
||||
if versions.GreaterThan(apiVersion, v.defaultVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultVersion}
|
||||
}
|
||||
ctx = context.WithValue(ctx, httputils.APIVersionKey, apiVersion)
|
||||
|
||||
header := fmt.Sprintf("Docker/%s (%s)", v.serverVersion, runtime.GOOS)
|
||||
w.Header().Set("Server", header)
|
||||
w.Header().Set("API-Version", v.defaultVersion)
|
||||
ctx = context.WithValue(ctx, "api-version", apiVersion)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,73 +1,41 @@
|
||||
package middleware // import "github.com/docker/docker/api/server/middleware"
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestVersionMiddlewareVersion(t *testing.T) {
|
||||
defaultVersion := "1.10.0"
|
||||
minVersion := "1.2.0"
|
||||
expectedVersion := defaultVersion
|
||||
func TestVersionMiddleware(t *testing.T) {
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v := httputils.VersionFromContext(ctx)
|
||||
assert.Check(t, is.Equal(expectedVersion, v))
|
||||
if httputils.VersionFromContext(ctx) == "" {
|
||||
t.Fatalf("Expected version, got empty string")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultVersion := "1.10.0"
|
||||
minVersion := "1.2.0"
|
||||
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
|
||||
h := m.WrapHandler(handler)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/containers/json", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
ctx := context.Background()
|
||||
|
||||
tests := []struct {
|
||||
reqVersion string
|
||||
expectedVersion string
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
expectedVersion: "1.10.0",
|
||||
},
|
||||
{
|
||||
reqVersion: "1.9.0",
|
||||
expectedVersion: "1.9.0",
|
||||
},
|
||||
{
|
||||
reqVersion: "0.1",
|
||||
errString: "client version 0.1 is too old. Minimum supported API version is 1.2.0, please upgrade your client to a newer version",
|
||||
},
|
||||
{
|
||||
reqVersion: "9999.9999",
|
||||
errString: "client version 9999.9999 is too new. Maximum supported API version is 1.10.0",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
expectedVersion = test.expectedVersion
|
||||
|
||||
err := h(ctx, resp, req, map[string]string{"version": test.reqVersion})
|
||||
|
||||
if test.errString != "" {
|
||||
assert.Check(t, is.Error(err, test.errString))
|
||||
} else {
|
||||
assert.Check(t, err)
|
||||
}
|
||||
if err := h(ctx, resp, req, map[string]string{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
|
||||
func TestVersionMiddlewareWithErrors(t *testing.T) {
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v := httputils.VersionFromContext(ctx)
|
||||
assert.Check(t, len(v) != 0)
|
||||
if httputils.VersionFromContext(ctx) == "" {
|
||||
t.Fatalf("Expected version, got empty string")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -82,11 +50,8 @@ func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
|
||||
|
||||
vars := map[string]string{"version": "0.1"}
|
||||
err := h(ctx, resp, req, vars)
|
||||
assert.Check(t, is.ErrorContains(err, ""))
|
||||
|
||||
hdr := resp.Result().Header
|
||||
assert.Check(t, is.Contains(hdr.Get("Server"), "Docker/"+defaultVersion))
|
||||
assert.Check(t, is.Contains(hdr.Get("Server"), runtime.GOOS))
|
||||
assert.Check(t, is.Equal(hdr.Get("API-Version"), defaultVersion))
|
||||
assert.Check(t, is.Equal(hdr.Get("OSType"), runtime.GOOS))
|
||||
if !strings.Contains(err.Error(), "client version 0.1 is too old. Minimum supported API version is 1.2.0") {
|
||||
t.Fatalf("Expected too old client error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
41
api/server/profiler.go
Normal file
41
api/server/profiler.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
const debugPathPrefix = "/debug/"
|
||||
|
||||
func profilerSetup(mainRouter *mux.Router) {
|
||||
var r = mainRouter.PathPrefix(debugPathPrefix).Subrouter()
|
||||
r.HandleFunc("/vars", expVars)
|
||||
r.HandleFunc("/pprof/", pprof.Index)
|
||||
r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
|
||||
r.HandleFunc("/pprof/profile", pprof.Profile)
|
||||
r.HandleFunc("/pprof/symbol", pprof.Symbol)
|
||||
r.HandleFunc("/pprof/trace", pprof.Trace)
|
||||
r.HandleFunc("/pprof/block", pprof.Handler("block").ServeHTTP)
|
||||
r.HandleFunc("/pprof/heap", pprof.Handler("heap").ServeHTTP)
|
||||
r.HandleFunc("/pprof/goroutine", pprof.Handler("goroutine").ServeHTTP)
|
||||
r.HandleFunc("/pprof/threadcreate", pprof.Handler("threadcreate").ServeHTTP)
|
||||
}
|
||||
|
||||
// Replicated from expvar.go as not public.
|
||||
func expVars(w http.ResponseWriter, r *http.Request) {
|
||||
first := true
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
fmt.Fprintf(w, "{\n")
|
||||
expvar.Do(func(kv expvar.KeyValue) {
|
||||
if !first {
|
||||
fmt.Fprintf(w, ",\n")
|
||||
}
|
||||
first = false
|
||||
fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
|
||||
})
|
||||
fmt.Fprintf(w, "\n}\n")
|
||||
}
|
||||
@@ -1,24 +1,20 @@
|
||||
package build // import "github.com/docker/docker/api/server/router/build"
|
||||
package build
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Backend abstracts an image builder whose only purpose is to build an image referenced by an imageID.
|
||||
type Backend interface {
|
||||
// Build a Docker image returning the id of the image
|
||||
// Build builds a Docker image referenced by an imageID string.
|
||||
//
|
||||
// Note: Tagging an image should not be done by a Builder, it should instead be done
|
||||
// by the caller.
|
||||
//
|
||||
// TODO: make this return a reference instead of string
|
||||
Build(context.Context, backend.BuildConfig) (string, error)
|
||||
|
||||
// Prune build cache
|
||||
PruneCache(context.Context, types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error)
|
||||
|
||||
Cancel(context.Context, string) error
|
||||
}
|
||||
|
||||
type experimentalProvider interface {
|
||||
HasExperimental() bool
|
||||
BuildFromContext(ctx context.Context, src io.ReadCloser, remote string, buildOptions *types.ImageBuildOptions, pg backend.ProgressWriter) (string, error)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,17 @@
|
||||
package build // import "github.com/docker/docker/api/server/router/build"
|
||||
package build
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
import "github.com/docker/docker/api/server/router"
|
||||
|
||||
// buildRouter is a router to talk with the build controller
|
||||
type buildRouter struct {
|
||||
backend Backend
|
||||
daemon experimentalProvider
|
||||
routes []router.Route
|
||||
features *map[string]bool
|
||||
backend Backend
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// NewRouter initializes a new build router
|
||||
func NewRouter(b Backend, d experimentalProvider, features *map[string]bool) router.Router {
|
||||
func NewRouter(b Backend) router.Router {
|
||||
r := &buildRouter{
|
||||
backend: b,
|
||||
daemon: d,
|
||||
features: features,
|
||||
backend: b,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
@@ -31,23 +24,6 @@ func (r *buildRouter) Routes() []router.Route {
|
||||
|
||||
func (r *buildRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.NewPostRoute("/build", r.postBuild, router.WithCancel),
|
||||
router.NewPostRoute("/build/prune", r.postPrune, router.WithCancel),
|
||||
router.NewPostRoute("/build/cancel", r.postCancel),
|
||||
router.Cancellable(router.NewPostRoute("/build", r.postBuild)),
|
||||
}
|
||||
}
|
||||
|
||||
// BuilderVersion derives the default docker builder version from the config
|
||||
// Note: it is valid to have BuilderVersion unset which means it is up to the
|
||||
// client to choose which builder to use.
|
||||
func BuilderVersion(features map[string]bool) types.BuilderVersion {
|
||||
var bv types.BuilderVersion
|
||||
if v, ok := features["buildkit"]; ok {
|
||||
if v {
|
||||
bv = types.BuilderBuildKit
|
||||
} else {
|
||||
bv = types.BuilderV1
|
||||
}
|
||||
}
|
||||
return bv
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package build // import "github.com/docker/docker/api/server/router/build"
|
||||
package build
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -14,29 +12,19 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/docker/go-units"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type invalidIsolationError string
|
||||
|
||||
func (e invalidIsolationError) Error() string {
|
||||
return fmt.Sprintf("Unsupported isolation: %q", string(e))
|
||||
}
|
||||
|
||||
func (e invalidIsolationError) InvalidParameter() {}
|
||||
|
||||
func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBuildOptions, error) {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
options := &types.ImageBuildOptions{}
|
||||
@@ -65,14 +53,8 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
||||
options.CgroupParent = r.FormValue("cgroupparent")
|
||||
options.NetworkMode = r.FormValue("networkmode")
|
||||
options.Tags = r.Form["t"]
|
||||
options.ExtraHosts = r.Form["extrahosts"]
|
||||
options.SecurityOpt = r.Form["securityopt"]
|
||||
options.Squash = httputils.BoolValue(r, "squash")
|
||||
options.Target = r.FormValue("target")
|
||||
options.RemoteContext = r.FormValue("remote")
|
||||
if versions.GreaterThanOrEqualTo(version, "1.32") {
|
||||
options.Platform = r.FormValue("platform")
|
||||
}
|
||||
|
||||
if r.Form.Get("shmsize") != "" {
|
||||
shmSize, err := strconv.ParseInt(r.Form.Get("shmsize"), 10, 64)
|
||||
@@ -84,24 +66,27 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
||||
|
||||
if i := container.Isolation(r.FormValue("isolation")); i != "" {
|
||||
if !container.Isolation.IsValid(i) {
|
||||
return nil, invalidIsolationError(i)
|
||||
return nil, fmt.Errorf("Unsupported isolation: %q", i)
|
||||
}
|
||||
options.Isolation = i
|
||||
}
|
||||
|
||||
if runtime.GOOS != "windows" && options.SecurityOpt != nil {
|
||||
return nil, errdefs.InvalidParameter(errors.New("The daemon on this platform does not support setting security options on build"))
|
||||
return nil, fmt.Errorf("the daemon on this platform does not support --security-opt to build")
|
||||
}
|
||||
|
||||
var buildUlimits = []*units.Ulimit{}
|
||||
ulimitsJSON := r.FormValue("ulimits")
|
||||
if ulimitsJSON != "" {
|
||||
if err := json.Unmarshal([]byte(ulimitsJSON), &buildUlimits); err != nil {
|
||||
return nil, errors.Wrap(errdefs.InvalidParameter(err), "error reading ulimit settings")
|
||||
return nil, err
|
||||
}
|
||||
options.Ulimits = buildUlimits
|
||||
}
|
||||
|
||||
var buildArgs = map[string]*string{}
|
||||
buildArgsJSON := r.FormValue("buildargs")
|
||||
|
||||
// Note that there are two ways a --build-arg might appear in the
|
||||
// json of the query param:
|
||||
// "foo":"bar"
|
||||
@@ -114,191 +99,34 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
||||
// the fact they mentioned it, we need to pass that along to the builder
|
||||
// so that it can print a warning about "foo" being unused if there is
|
||||
// no "ARG foo" in the Dockerfile.
|
||||
buildArgsJSON := r.FormValue("buildargs")
|
||||
if buildArgsJSON != "" {
|
||||
var buildArgs = map[string]*string{}
|
||||
if err := json.Unmarshal([]byte(buildArgsJSON), &buildArgs); err != nil {
|
||||
return nil, errors.Wrap(errdefs.InvalidParameter(err), "error reading build args")
|
||||
return nil, err
|
||||
}
|
||||
options.BuildArgs = buildArgs
|
||||
}
|
||||
|
||||
var labels = map[string]string{}
|
||||
labelsJSON := r.FormValue("labels")
|
||||
if labelsJSON != "" {
|
||||
var labels = map[string]string{}
|
||||
if err := json.Unmarshal([]byte(labelsJSON), &labels); err != nil {
|
||||
return nil, errors.Wrap(errdefs.InvalidParameter(err), "error reading labels")
|
||||
return nil, err
|
||||
}
|
||||
options.Labels = labels
|
||||
}
|
||||
|
||||
var cacheFrom = []string{}
|
||||
cacheFromJSON := r.FormValue("cachefrom")
|
||||
if cacheFromJSON != "" {
|
||||
var cacheFrom = []string{}
|
||||
if err := json.Unmarshal([]byte(cacheFromJSON), &cacheFrom); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options.CacheFrom = cacheFrom
|
||||
}
|
||||
options.SessionID = r.FormValue("session")
|
||||
options.BuildID = r.FormValue("buildid")
|
||||
builderVersion, err := parseVersion(r.FormValue("version"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options.Version = builderVersion
|
||||
|
||||
return options, nil
|
||||
}
|
||||
|
||||
func parseVersion(s string) (types.BuilderVersion, error) {
|
||||
if s == "" || s == string(types.BuilderV1) {
|
||||
return types.BuilderV1, nil
|
||||
}
|
||||
if s == string(types.BuilderBuildKit) {
|
||||
return types.BuilderBuildKit, nil
|
||||
}
|
||||
return "", errors.Errorf("invalid version %s", s)
|
||||
}
|
||||
|
||||
func (br *buildRouter) postPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not parse filters")
|
||||
}
|
||||
ksfv := r.FormValue("keep-storage")
|
||||
if ksfv == "" {
|
||||
ksfv = "0"
|
||||
}
|
||||
ks, err := strconv.Atoi(ksfv)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "keep-storage is in bytes and expects an integer, got %v", ksfv)
|
||||
}
|
||||
|
||||
opts := types.BuildCachePruneOptions{
|
||||
All: httputils.BoolValue(r, "all"),
|
||||
Filters: filters,
|
||||
KeepStorage: int64(ks),
|
||||
}
|
||||
|
||||
report, err := br.backend.PruneCache(ctx, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, report)
|
||||
}
|
||||
|
||||
func (br *buildRouter) postCancel(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
id := r.FormValue("id")
|
||||
if id == "" {
|
||||
return errors.Errorf("build ID not provided")
|
||||
}
|
||||
|
||||
return br.backend.Cancel(ctx, id)
|
||||
}
|
||||
|
||||
func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var (
|
||||
notVerboseBuffer = bytes.NewBuffer(nil)
|
||||
version = httputils.VersionFromContext(ctx)
|
||||
)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
body := r.Body
|
||||
var ww io.Writer = w
|
||||
if body != nil {
|
||||
// there is a possibility that output is written before request body
|
||||
// has been fully read so we need to protect against it.
|
||||
// this can be removed when
|
||||
// https://github.com/golang/go/issues/15527
|
||||
// https://github.com/golang/go/issues/22209
|
||||
// has been fixed
|
||||
body, ww = wrapOutputBufferedUntilRequestRead(body, ww)
|
||||
}
|
||||
|
||||
output := ioutils.NewWriteFlusher(ww)
|
||||
defer output.Close()
|
||||
|
||||
errf := func(err error) error {
|
||||
|
||||
if httputils.BoolValue(r, "q") && notVerboseBuffer.Len() > 0 {
|
||||
output.Write(notVerboseBuffer.Bytes())
|
||||
}
|
||||
|
||||
// Do not write the error in the http output if it's still empty.
|
||||
// This prevents from writing a 200(OK) when there is an internal error.
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
_, err = output.Write(streamformatter.FormatError(err))
|
||||
if err != nil {
|
||||
logrus.Warnf("could not write error response: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
buildOptions, err := newImageBuildOptions(ctx, r)
|
||||
if err != nil {
|
||||
return errf(err)
|
||||
}
|
||||
buildOptions.AuthConfigs = getAuthConfigs(r.Header)
|
||||
|
||||
if buildOptions.Squash && !br.daemon.HasExperimental() {
|
||||
return errdefs.InvalidParameter(errors.New("squash is only supported with experimental mode"))
|
||||
}
|
||||
|
||||
out := io.Writer(output)
|
||||
if buildOptions.SuppressOutput {
|
||||
out = notVerboseBuffer
|
||||
}
|
||||
|
||||
// Currently, only used if context is from a remote url.
|
||||
// Look at code in DetectContextFromRemoteURL for more information.
|
||||
createProgressReader := func(in io.ReadCloser) io.ReadCloser {
|
||||
progressOutput := streamformatter.NewJSONProgressOutput(out, true)
|
||||
return progress.NewProgressReader(in, progressOutput, r.ContentLength, "Downloading context", buildOptions.RemoteContext)
|
||||
}
|
||||
|
||||
wantAux := versions.GreaterThanOrEqualTo(version, "1.30")
|
||||
|
||||
imgID, err := br.backend.Build(ctx, backend.BuildConfig{
|
||||
Source: body,
|
||||
Options: buildOptions,
|
||||
ProgressWriter: buildProgressWriter(out, wantAux, createProgressReader),
|
||||
})
|
||||
if err != nil {
|
||||
return errf(err)
|
||||
}
|
||||
|
||||
// Everything worked so if -q was provided the output from the daemon
|
||||
// should be just the image ID and we'll print that to stdout.
|
||||
if buildOptions.SuppressOutput {
|
||||
fmt.Fprintln(streamformatter.NewStdoutWriter(output), imgID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAuthConfigs(header http.Header) map[string]types.AuthConfig {
|
||||
authConfigs := map[string]types.AuthConfig{}
|
||||
authConfigsEncoded := header.Get("X-Registry-Config")
|
||||
|
||||
if authConfigsEncoded == "" {
|
||||
return authConfigs
|
||||
}
|
||||
|
||||
authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authConfigsEncoded))
|
||||
// Pulling an image does not error when no auth is provided so to remain
|
||||
// consistent with the existing api decode errors are ignored
|
||||
json.NewDecoder(authConfigsJSON).Decode(&authConfigs)
|
||||
return authConfigs
|
||||
}
|
||||
|
||||
type syncWriter struct {
|
||||
w io.Writer
|
||||
mu sync.Mutex
|
||||
@@ -311,118 +139,87 @@ func (s *syncWriter) Write(b []byte) (count int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func buildProgressWriter(out io.Writer, wantAux bool, createProgressReader func(io.ReadCloser) io.ReadCloser) backend.ProgressWriter {
|
||||
out = &syncWriter{w: out}
|
||||
func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var (
|
||||
authConfigs = map[string]types.AuthConfig{}
|
||||
authConfigsEncoded = r.Header.Get("X-Registry-Config")
|
||||
notVerboseBuffer = bytes.NewBuffer(nil)
|
||||
)
|
||||
|
||||
var aux *streamformatter.AuxFormatter
|
||||
if wantAux {
|
||||
aux = &streamformatter.AuxFormatter{Writer: out}
|
||||
if authConfigsEncoded != "" {
|
||||
authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authConfigsEncoded))
|
||||
if err := json.NewDecoder(authConfigsJSON).Decode(&authConfigs); err != nil {
|
||||
// for a pull it is not an error if no auth was given
|
||||
// to increase compatibility with the existing api it is defaulting
|
||||
// to be empty.
|
||||
}
|
||||
}
|
||||
|
||||
return backend.ProgressWriter{
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
output := ioutils.NewWriteFlusher(w)
|
||||
defer output.Close()
|
||||
sf := streamformatter.NewJSONStreamFormatter()
|
||||
errf := func(err error) error {
|
||||
if httputils.BoolValue(r, "q") && notVerboseBuffer.Len() > 0 {
|
||||
output.Write(notVerboseBuffer.Bytes())
|
||||
}
|
||||
// Do not write the error in the http output if it's still empty.
|
||||
// This prevents from writing a 200(OK) when there is an internal error.
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(sf.FormatError(err))
|
||||
if err != nil {
|
||||
logrus.Warnf("could not write error response: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
buildOptions, err := newImageBuildOptions(ctx, r)
|
||||
if err != nil {
|
||||
return errf(err)
|
||||
}
|
||||
buildOptions.AuthConfigs = authConfigs
|
||||
|
||||
remoteURL := r.FormValue("remote")
|
||||
|
||||
// Currently, only used if context is from a remote url.
|
||||
// Look at code in DetectContextFromRemoteURL for more information.
|
||||
createProgressReader := func(in io.ReadCloser) io.ReadCloser {
|
||||
progressOutput := sf.NewProgressOutput(output, true)
|
||||
if buildOptions.SuppressOutput {
|
||||
progressOutput = sf.NewProgressOutput(notVerboseBuffer, true)
|
||||
}
|
||||
return progress.NewProgressReader(in, progressOutput, r.ContentLength, "Downloading context", remoteURL)
|
||||
}
|
||||
|
||||
out := io.Writer(output)
|
||||
if buildOptions.SuppressOutput {
|
||||
out = notVerboseBuffer
|
||||
}
|
||||
out = &syncWriter{w: out}
|
||||
stdout := &streamformatter.StdoutFormatter{Writer: out, StreamFormatter: sf}
|
||||
stderr := &streamformatter.StderrFormatter{Writer: out, StreamFormatter: sf}
|
||||
|
||||
pg := backend.ProgressWriter{
|
||||
Output: out,
|
||||
StdoutFormatter: streamformatter.NewStdoutWriter(out),
|
||||
StderrFormatter: streamformatter.NewStderrWriter(out),
|
||||
AuxFormatter: aux,
|
||||
StdoutFormatter: stdout,
|
||||
StderrFormatter: stderr,
|
||||
ProgressReaderFunc: createProgressReader,
|
||||
}
|
||||
}
|
||||
|
||||
type flusher interface {
|
||||
Flush()
|
||||
}
|
||||
|
||||
func wrapOutputBufferedUntilRequestRead(rc io.ReadCloser, out io.Writer) (io.ReadCloser, io.Writer) {
|
||||
var fl flusher = &ioutils.NopFlusher{}
|
||||
if f, ok := out.(flusher); ok {
|
||||
fl = f
|
||||
}
|
||||
|
||||
w := &wcf{
|
||||
buf: bytes.NewBuffer(nil),
|
||||
Writer: out,
|
||||
flusher: fl,
|
||||
}
|
||||
r := bufio.NewReader(rc)
|
||||
_, err := r.Peek(1)
|
||||
imgID, err := br.backend.BuildFromContext(ctx, r.Body, remoteURL, buildOptions, pg)
|
||||
if err != nil {
|
||||
return rc, out
|
||||
return errf(err)
|
||||
}
|
||||
rc = &rcNotifier{
|
||||
Reader: r,
|
||||
Closer: rc,
|
||||
notify: w.notify,
|
||||
|
||||
// Everything worked so if -q was provided the output from the daemon
|
||||
// should be just the image ID and we'll print that to stdout.
|
||||
if buildOptions.SuppressOutput {
|
||||
stdout := &streamformatter.StdoutFormatter{Writer: output, StreamFormatter: sf}
|
||||
fmt.Fprintf(stdout, "%s\n", string(imgID))
|
||||
}
|
||||
return rc, w
|
||||
}
|
||||
|
||||
type rcNotifier struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
notify func()
|
||||
}
|
||||
|
||||
func (r *rcNotifier) Read(b []byte) (int, error) {
|
||||
n, err := r.Reader.Read(b)
|
||||
if err != nil {
|
||||
r.notify()
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (r *rcNotifier) Close() error {
|
||||
r.notify()
|
||||
return r.Closer.Close()
|
||||
}
|
||||
|
||||
type wcf struct {
|
||||
io.Writer
|
||||
flusher
|
||||
mu sync.Mutex
|
||||
ready bool
|
||||
buf *bytes.Buffer
|
||||
flushed bool
|
||||
}
|
||||
|
||||
func (w *wcf) Flush() {
|
||||
w.mu.Lock()
|
||||
w.flushed = true
|
||||
if !w.ready {
|
||||
w.mu.Unlock()
|
||||
return
|
||||
}
|
||||
w.mu.Unlock()
|
||||
w.flusher.Flush()
|
||||
}
|
||||
|
||||
func (w *wcf) Flushed() bool {
|
||||
w.mu.Lock()
|
||||
b := w.flushed
|
||||
w.mu.Unlock()
|
||||
return b
|
||||
}
|
||||
|
||||
func (w *wcf) Write(b []byte) (int, error) {
|
||||
w.mu.Lock()
|
||||
if !w.ready {
|
||||
n, err := w.buf.Write(b)
|
||||
w.mu.Unlock()
|
||||
return n, err
|
||||
}
|
||||
w.mu.Unlock()
|
||||
return w.Writer.Write(b)
|
||||
}
|
||||
|
||||
func (w *wcf) notify() {
|
||||
w.mu.Lock()
|
||||
if !w.ready {
|
||||
if w.buf.Len() > 0 {
|
||||
io.Copy(w.Writer, w.buf)
|
||||
}
|
||||
if w.flushed {
|
||||
w.flusher.Flush()
|
||||
}
|
||||
w.ready = true
|
||||
}
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package checkpoint // import "github.com/docker/docker/api/server/router/checkpoint"
|
||||
package checkpoint
|
||||
|
||||
import "github.com/docker/docker/api/types"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package checkpoint // import "github.com/docker/docker/api/server/router/checkpoint"
|
||||
package checkpoint
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
@@ -29,8 +29,8 @@ func (r *checkpointRouter) Routes() []router.Route {
|
||||
|
||||
func (r *checkpointRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints, router.Experimental),
|
||||
router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint, router.Experimental),
|
||||
router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint, router.Experimental),
|
||||
router.Experimental(router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints)),
|
||||
router.Experimental(router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint)),
|
||||
router.Experimental(router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package checkpoint // import "github.com/docker/docker/api/server/router/checkpoint"
|
||||
package checkpoint
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (s *checkpointRouter) postContainerCheckpoint(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package container // import "github.com/docker/docker/api/server/router/container"
|
||||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
containerpkg "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
)
|
||||
|
||||
@@ -17,7 +18,7 @@ type execBackend interface {
|
||||
ContainerExecCreate(name string, config *types.ExecConfig) (string, error)
|
||||
ContainerExecInspect(id string) (*backend.ExecInspect, error)
|
||||
ContainerExecResize(name string, height, width int) error
|
||||
ContainerExecStart(ctx context.Context, name string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error
|
||||
ContainerExecStart(ctx context.Context, name string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error
|
||||
ExecExists(name string) (bool, error)
|
||||
}
|
||||
|
||||
@@ -26,7 +27,7 @@ type copyBackend interface {
|
||||
ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error)
|
||||
ContainerCopy(name string, res string) (io.ReadCloser, error)
|
||||
ContainerExport(name string, out io.Writer) error
|
||||
ContainerExtractToDir(name, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error
|
||||
ContainerExtractToDir(name, path string, noOverwriteDirNonDir bool, content io.Reader) error
|
||||
ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error)
|
||||
}
|
||||
|
||||
@@ -43,16 +44,16 @@ type stateBackend interface {
|
||||
ContainerStop(name string, seconds *int) error
|
||||
ContainerUnpause(name string) error
|
||||
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)
|
||||
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
|
||||
ContainerWait(name string, timeout time.Duration) (int, error)
|
||||
}
|
||||
|
||||
// monitorBackend includes functions to implement to provide containers monitoring functionality.
|
||||
type monitorBackend interface {
|
||||
ContainerChanges(name string) ([]archive.Change, error)
|
||||
ContainerInspect(name string, size bool, version string) (interface{}, error)
|
||||
ContainerLogs(ctx context.Context, name string, config *types.ContainerLogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
||||
ContainerLogs(ctx context.Context, name string, config *backend.ContainerLogsConfig, started chan struct{}) error
|
||||
ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
|
||||
ContainerTop(name string, psArgs string) (*container.ContainerTopOKBody, error)
|
||||
ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error)
|
||||
|
||||
Containers(config *types.ContainerListOptions) ([]*types.Container, error)
|
||||
}
|
||||
@@ -64,16 +65,11 @@ type attachBackend interface {
|
||||
|
||||
// systemBackend includes functions to implement to provide system wide containers functionality
|
||||
type systemBackend interface {
|
||||
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (*types.ContainersPruneReport, error)
|
||||
}
|
||||
|
||||
type commitBackend interface {
|
||||
CreateImageFromContainer(name string, config *backend.CreateImageConfig) (imageID string, err error)
|
||||
ContainersPrune(pruneFilters filters.Args) (*types.ContainersPruneReport, error)
|
||||
}
|
||||
|
||||
// Backend is all the methods that need to be implemented to provide container specific functionality.
|
||||
type Backend interface {
|
||||
commitBackend
|
||||
execBackend
|
||||
copyBackend
|
||||
stateBackend
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
package container // import "github.com/docker/docker/api/server/router/container"
|
||||
package container
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
)
|
||||
|
||||
type validationError struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (validationError) IsValidationError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// containerRouter is a router to talk with the container controller
|
||||
type containerRouter struct {
|
||||
backend Backend
|
||||
@@ -38,8 +46,8 @@ func (r *containerRouter) initRoutes() {
|
||||
router.NewGetRoute("/containers/{name:.*}/changes", r.getContainersChanges),
|
||||
router.NewGetRoute("/containers/{name:.*}/json", r.getContainersByName),
|
||||
router.NewGetRoute("/containers/{name:.*}/top", r.getContainersTop),
|
||||
router.NewGetRoute("/containers/{name:.*}/logs", r.getContainersLogs, router.WithCancel),
|
||||
router.NewGetRoute("/containers/{name:.*}/stats", r.getContainersStats, router.WithCancel),
|
||||
router.Cancellable(router.NewGetRoute("/containers/{name:.*}/logs", r.getContainersLogs)),
|
||||
router.Cancellable(router.NewGetRoute("/containers/{name:.*}/stats", r.getContainersStats)),
|
||||
router.NewGetRoute("/containers/{name:.*}/attach/ws", r.wsContainersAttach),
|
||||
router.NewGetRoute("/exec/{id:.*}/json", r.getExecByID),
|
||||
router.NewGetRoute("/containers/{name:.*}/archive", r.getContainersArchive),
|
||||
@@ -51,7 +59,7 @@ func (r *containerRouter) initRoutes() {
|
||||
router.NewPostRoute("/containers/{name:.*}/restart", r.postContainersRestart),
|
||||
router.NewPostRoute("/containers/{name:.*}/start", r.postContainersStart),
|
||||
router.NewPostRoute("/containers/{name:.*}/stop", r.postContainersStop),
|
||||
router.NewPostRoute("/containers/{name:.*}/wait", r.postContainersWait, router.WithCancel),
|
||||
router.NewPostRoute("/containers/{name:.*}/wait", r.postContainersWait),
|
||||
router.NewPostRoute("/containers/{name:.*}/resize", r.postContainersResize),
|
||||
router.NewPostRoute("/containers/{name:.*}/attach", r.postContainersAttach),
|
||||
router.NewPostRoute("/containers/{name:.*}/copy", r.postContainersCopy), // Deprecated since 1.8, Errors out since 1.12
|
||||
@@ -60,8 +68,7 @@ func (r *containerRouter) initRoutes() {
|
||||
router.NewPostRoute("/exec/{name:.*}/resize", r.postContainerExecResize),
|
||||
router.NewPostRoute("/containers/{name:.*}/rename", r.postContainerRename),
|
||||
router.NewPostRoute("/containers/{name:.*}/update", r.postContainerUpdate),
|
||||
router.NewPostRoute("/containers/prune", r.postContainersPrune, router.WithCancel),
|
||||
router.NewPostRoute("/commit", r.postCommit),
|
||||
router.NewPostRoute("/containers/prune", r.postContainersPrune),
|
||||
// PUT
|
||||
router.NewPutRoute("/containers/{name:.*}/archive", r.putContainersArchive),
|
||||
// DELETE
|
||||
|
||||
@@ -1,73 +1,32 @@
|
||||
package container // import "github.com/docker/docker/api/server/router/container"
|
||||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
containerpkg "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
func (s *containerRouter) postCommit(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: remove pause arg, and always pause in backend
|
||||
pause := httputils.BoolValue(r, "pause")
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if r.FormValue("pause") == "" && versions.GreaterThanOrEqualTo(version, "1.13") {
|
||||
pause = true
|
||||
}
|
||||
|
||||
config, _, _, err := s.decoder.DecodeConfig(r.Body)
|
||||
if err != nil && err != io.EOF { //Do not fail if body is empty.
|
||||
return err
|
||||
}
|
||||
|
||||
commitCfg := &backend.CreateImageConfig{
|
||||
Pause: pause,
|
||||
Repo: r.Form.Get("repo"),
|
||||
Tag: r.Form.Get("tag"),
|
||||
Author: r.Form.Get("author"),
|
||||
Comment: r.Form.Get("comment"),
|
||||
Config: config,
|
||||
Changes: r.Form["changes"],
|
||||
}
|
||||
|
||||
imgID, err := s.backend.CreateImageFromContainer(r.Form.Get("container"), commitCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &types.IDResponse{ID: imgID})
|
||||
}
|
||||
|
||||
func (s *containerRouter) getContainersJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filter, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
filter, err := filters.FromParam(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -109,7 +68,7 @@ func (s *containerRouter) getContainersStats(ctx context.Context, w http.Respons
|
||||
config := &backend.ContainerStatsConfig{
|
||||
Stream: stream,
|
||||
OutStream: w,
|
||||
Version: httputils.VersionFromContext(ctx),
|
||||
Version: string(httputils.VersionFromContext(ctx)),
|
||||
}
|
||||
|
||||
return s.backend.ContainerStats(ctx, vars["name"], config)
|
||||
@@ -127,31 +86,36 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response
|
||||
// with the appropriate status code.
|
||||
stdout, stderr := httputils.BoolValue(r, "stdout"), httputils.BoolValue(r, "stderr")
|
||||
if !(stdout || stderr) {
|
||||
return errdefs.InvalidParameter(errors.New("Bad parameters: you must choose at least one stream"))
|
||||
return fmt.Errorf("Bad parameters: you must choose at least one stream")
|
||||
}
|
||||
|
||||
containerName := vars["name"]
|
||||
logsConfig := &types.ContainerLogsOptions{
|
||||
Follow: httputils.BoolValue(r, "follow"),
|
||||
Timestamps: httputils.BoolValue(r, "timestamps"),
|
||||
Since: r.Form.Get("since"),
|
||||
Until: r.Form.Get("until"),
|
||||
Tail: r.Form.Get("tail"),
|
||||
ShowStdout: stdout,
|
||||
ShowStderr: stderr,
|
||||
Details: httputils.BoolValue(r, "details"),
|
||||
logsConfig := &backend.ContainerLogsConfig{
|
||||
ContainerLogsOptions: types.ContainerLogsOptions{
|
||||
Follow: httputils.BoolValue(r, "follow"),
|
||||
Timestamps: httputils.BoolValue(r, "timestamps"),
|
||||
Since: r.Form.Get("since"),
|
||||
Tail: r.Form.Get("tail"),
|
||||
ShowStdout: stdout,
|
||||
ShowStderr: stderr,
|
||||
Details: httputils.BoolValue(r, "details"),
|
||||
},
|
||||
OutStream: w,
|
||||
}
|
||||
|
||||
msgs, tty, err := s.backend.ContainerLogs(ctx, containerName, logsConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
chStarted := make(chan struct{})
|
||||
if err := s.backend.ContainerLogs(ctx, containerName, logsConfig, chStarted); err != nil {
|
||||
select {
|
||||
case <-chStarted:
|
||||
// The client may be expecting all of the data we're sending to
|
||||
// be multiplexed, so send it through OutStream, which will
|
||||
// have been set up to handle that if needed.
|
||||
fmt.Fprintf(logsConfig.OutStream, "Error running logs job: %v\n", err)
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// if has a tty, we're not muxing streams. if it doesn't, we are. simple.
|
||||
// this is the point of no return for writing a response. once we call
|
||||
// WriteLogStream, the response has been started and errors will be
|
||||
// returned in band by WriteLogStream
|
||||
httputils.WriteLogStream(ctx, w, msgs, logsConfig, !tty)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -159,14 +123,6 @@ func (s *containerRouter) getContainersExport(ctx context.Context, w http.Respon
|
||||
return s.backend.ContainerExport(vars["name"], w)
|
||||
}
|
||||
|
||||
type bodyOnStartError struct{}
|
||||
|
||||
func (bodyOnStartError) Error() string {
|
||||
return "starting container with non-empty request body was deprecated since API v1.22 and removed in v1.24"
|
||||
}
|
||||
|
||||
func (bodyOnStartError) InvalidParameter() {}
|
||||
|
||||
func (s *containerRouter) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
// If contentLength is -1, we can assumed chunked encoding
|
||||
// or more technically that the length is unknown
|
||||
@@ -180,7 +136,7 @@ func (s *containerRouter) postContainersStart(ctx context.Context, w http.Respon
|
||||
// A non-nil json object is at least 7 characters.
|
||||
if r.ContentLength > 7 || r.ContentLength == -1 {
|
||||
if versions.GreaterThanOrEqualTo(version, "1.24") {
|
||||
return bodyOnStartError{}
|
||||
return validationError{fmt.Errorf("starting container with non-empty request body was deprecated since v1.10 and removed in v1.12")}
|
||||
}
|
||||
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
@@ -230,6 +186,10 @@ func (s *containerRouter) postContainersStop(ctx context.Context, w http.Respons
|
||||
return nil
|
||||
}
|
||||
|
||||
type errContainerIsRunning interface {
|
||||
ContainerIsRunning() bool
|
||||
}
|
||||
|
||||
func (s *containerRouter) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
@@ -242,14 +202,14 @@ func (s *containerRouter) postContainersKill(ctx context.Context, w http.Respons
|
||||
if sigStr := r.Form.Get("signal"); sigStr != "" {
|
||||
var err error
|
||||
if sig, err = signal.ParseSignal(sigStr); err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.backend.ContainerKill(name, uint64(sig)); err != nil {
|
||||
var isStopped bool
|
||||
if errdefs.IsConflict(err) {
|
||||
isStopped = true
|
||||
if e, ok := err.(errContainerIsRunning); ok {
|
||||
isStopped = !e.ContainerIsRunning()
|
||||
}
|
||||
|
||||
// Return error that's not caused because the container is stopped.
|
||||
@@ -257,7 +217,7 @@ func (s *containerRouter) postContainersKill(ctx context.Context, w http.Respons
|
||||
// to keep backwards compatibility.
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.GreaterThanOrEqualTo(version, "1.20") || !isStopped {
|
||||
return errors.Wrapf(err, "Cannot kill container: %s", name)
|
||||
return fmt.Errorf("Cannot kill container %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,64 +277,13 @@ func (s *containerRouter) postContainersUnpause(ctx context.Context, w http.Resp
|
||||
}
|
||||
|
||||
func (s *containerRouter) postContainersWait(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
// Behavior changed in version 1.30 to handle wait condition and to
|
||||
// return headers immediately.
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
legacyBehaviorPre130 := versions.LessThan(version, "1.30")
|
||||
legacyRemovalWaitPre134 := false
|
||||
|
||||
// The wait condition defaults to "not-running".
|
||||
waitCondition := containerpkg.WaitConditionNotRunning
|
||||
if !legacyBehaviorPre130 {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
switch container.WaitCondition(r.Form.Get("condition")) {
|
||||
case container.WaitConditionNextExit:
|
||||
waitCondition = containerpkg.WaitConditionNextExit
|
||||
case container.WaitConditionRemoved:
|
||||
waitCondition = containerpkg.WaitConditionRemoved
|
||||
legacyRemovalWaitPre134 = versions.LessThan(version, "1.34")
|
||||
}
|
||||
}
|
||||
|
||||
// Note: the context should get canceled if the client closes the
|
||||
// connection since this handler has been wrapped by the
|
||||
// router.WithCancel() wrapper.
|
||||
waitC, err := s.backend.ContainerWait(ctx, vars["name"], waitCondition)
|
||||
status, err := s.backend.ContainerWait(vars["name"], -1*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if !legacyBehaviorPre130 {
|
||||
// Write response header immediately.
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if flusher, ok := w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
// Block on the result of the wait operation.
|
||||
status := <-waitC
|
||||
|
||||
// With API < 1.34, wait on WaitConditionRemoved did not return
|
||||
// in case container removal failed. The only way to report an
|
||||
// error back to the client is to not write anything (i.e. send
|
||||
// an empty response which will be treated as an error).
|
||||
if legacyRemovalWaitPre134 && status.Err() != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var waitError *container.ContainerWaitOKBodyError
|
||||
if status.Err() != nil {
|
||||
waitError = &container.ContainerWaitOKBodyError{Message: status.Err().Error()}
|
||||
}
|
||||
|
||||
return json.NewEncoder(w).Encode(&container.ContainerWaitOKBody{
|
||||
StatusCode: int64(status.ExitCode()),
|
||||
Error: waitError,
|
||||
return httputils.WriteJSON(w, http.StatusOK, &container.ContainerWaitOKBody{
|
||||
StatusCode: int64(status),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -507,11 +416,11 @@ func (s *containerRouter) postContainersResize(ctx context.Context, w http.Respo
|
||||
|
||||
height, err := strconv.Atoi(r.Form.Get("h"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
width, err := strconv.Atoi(r.Form.Get("w"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return s.backend.ContainerResize(vars["name"], height, width)
|
||||
@@ -529,7 +438,7 @@ func (s *containerRouter) postContainersAttach(ctx context.Context, w http.Respo
|
||||
|
||||
hijacker, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
return errdefs.InvalidParameter(errors.Errorf("error attaching to container %s, hijack connection missing", containerName))
|
||||
return fmt.Errorf("error attaching to container %s, hijack connection missing", containerName)
|
||||
}
|
||||
|
||||
setupStreams := func() (io.ReadCloser, io.Writer, io.Writer, error) {
|
||||
@@ -593,8 +502,6 @@ func (s *containerRouter) wsContainersAttach(ctx context.Context, w http.Respons
|
||||
done := make(chan struct{})
|
||||
started := make(chan struct{})
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
|
||||
setupStreams := func() (io.ReadCloser, io.Writer, io.Writer, error) {
|
||||
wsChan := make(chan *websocket.Conn)
|
||||
h := func(conn *websocket.Conn) {
|
||||
@@ -609,11 +516,6 @@ func (s *containerRouter) wsContainersAttach(ctx context.Context, w http.Respons
|
||||
}()
|
||||
|
||||
conn := <-wsChan
|
||||
// In case version 1.28 and above, a binary frame will be sent.
|
||||
// See 28176 for details.
|
||||
if versions.GreaterThanOrEqualTo(version, "1.28") {
|
||||
conn.PayloadType = websocket.BinaryFrame
|
||||
}
|
||||
return conn, conn, conn, nil
|
||||
}
|
||||
|
||||
@@ -632,11 +534,7 @@ func (s *containerRouter) wsContainersAttach(ctx context.Context, w http.Respons
|
||||
close(done)
|
||||
select {
|
||||
case <-started:
|
||||
if err != nil {
|
||||
logrus.Errorf("Error attaching websocket: %s", err)
|
||||
} else {
|
||||
logrus.Debug("websocket connection was closed by client")
|
||||
}
|
||||
logrus.Errorf("Error attaching websocket: %s", err)
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
@@ -648,12 +546,12 @@ func (s *containerRouter) postContainersPrune(ctx context.Context, w http.Respon
|
||||
return err
|
||||
}
|
||||
|
||||
pruneFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
pruneFilters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
pruneReport, err := s.backend.ContainersPrune(ctx, pruneFilters)
|
||||
pruneReport, err := s.backend.ContainersPrune(pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,30 +1,20 @@
|
||||
package container // import "github.com/docker/docker/api/server/router/container"
|
||||
package container
|
||||
|
||||
import (
|
||||
"compress/flate"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
gddohttputil "github.com/golang/gddo/httputil"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type pathError struct{}
|
||||
|
||||
func (pathError) Error() string {
|
||||
return "Path cannot be empty"
|
||||
}
|
||||
|
||||
func (pathError) InvalidParameter() {}
|
||||
|
||||
// postContainersCopy is deprecated in favor of getContainersArchive.
|
||||
func (s *containerRouter) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
// Deprecated since 1.8, Errors out since 1.12
|
||||
@@ -39,25 +29,32 @@ func (s *containerRouter) postContainersCopy(ctx context.Context, w http.Respons
|
||||
|
||||
cfg := types.CopyConfig{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if cfg.Resource == "" {
|
||||
return pathError{}
|
||||
return fmt.Errorf("Path cannot be empty")
|
||||
}
|
||||
|
||||
data, err := s.backend.ContainerCopy(vars["name"], cfg.Resource)
|
||||
if err != nil {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "no such container") {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("Could not find the file %s in container %s", cfg.Resource, vars["name"])
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer data.Close()
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-tar")
|
||||
_, err = io.Copy(w, data)
|
||||
return err
|
||||
if _, err := io.Copy(w, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// // Encode the stat to JSON, base64 encode, and place in a header.
|
||||
@@ -89,29 +86,6 @@ func (s *containerRouter) headContainersArchive(ctx context.Context, w http.Resp
|
||||
return setContainerPathStatHeader(stat, w.Header())
|
||||
}
|
||||
|
||||
func writeCompressedResponse(w http.ResponseWriter, r *http.Request, body io.Reader) error {
|
||||
var cw io.Writer
|
||||
switch gddohttputil.NegotiateContentEncoding(r, []string{"gzip", "deflate"}) {
|
||||
case "gzip":
|
||||
gw := gzip.NewWriter(w)
|
||||
defer gw.Close()
|
||||
cw = gw
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
case "deflate":
|
||||
fw, err := flate.NewWriter(w, flate.DefaultCompression)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fw.Close()
|
||||
cw = fw
|
||||
w.Header().Set("Content-Encoding", "deflate")
|
||||
default:
|
||||
cw = w
|
||||
}
|
||||
_, err := io.Copy(cw, body)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *containerRouter) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v, err := httputils.ArchiveFormValues(r, vars)
|
||||
if err != nil {
|
||||
@@ -129,7 +103,9 @@ func (s *containerRouter) getContainersArchive(ctx context.Context, w http.Respo
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-tar")
|
||||
return writeCompressedResponse(w, r, tarArchive)
|
||||
_, err = io.Copy(w, tarArchive)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *containerRouter) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -139,7 +115,5 @@ func (s *containerRouter) putContainersArchive(ctx context.Context, w http.Respo
|
||||
}
|
||||
|
||||
noOverwriteDirNonDir := httputils.BoolValue(r, "noOverwriteDirNonDir")
|
||||
copyUIDGID := httputils.BoolValue(r, "copyUIDGID")
|
||||
|
||||
return s.backend.ContainerExtractToDir(v.Name, v.Path, copyUIDGID, noOverwriteDirNonDir, r.Body)
|
||||
return s.backend.ContainerExtractToDir(v.Name, v.Path, noOverwriteDirNonDir, r.Body)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
package container // import "github.com/docker/docker/api/server/router/container"
|
||||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (s *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -26,14 +24,6 @@ func (s *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter
|
||||
return httputils.WriteJSON(w, http.StatusOK, eConfig)
|
||||
}
|
||||
|
||||
type execCommandError struct{}
|
||||
|
||||
func (execCommandError) Error() string {
|
||||
return "No exec command specified"
|
||||
}
|
||||
|
||||
func (execCommandError) InvalidParameter() {}
|
||||
|
||||
func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
@@ -45,14 +35,11 @@ func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.Re
|
||||
|
||||
execConfig := &types.ExecConfig{}
|
||||
if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(execConfig.Cmd) == 0 {
|
||||
return execCommandError{}
|
||||
return fmt.Errorf("No exec command specified")
|
||||
}
|
||||
|
||||
// Register an instance of Exec in container.
|
||||
@@ -88,10 +75,7 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
|
||||
|
||||
execStartCheck := &types.ExecStartCheck{}
|
||||
if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if exists, err := s.backend.ExecExists(execName); !exists {
|
||||
@@ -134,7 +118,7 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
|
||||
return err
|
||||
}
|
||||
stdout.Write([]byte(err.Error() + "\r\n"))
|
||||
logrus.Errorf("Error running exec %s in container: %v", execName, err)
|
||||
logrus.Errorf("Error running exec in container: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -145,11 +129,11 @@ func (s *containerRouter) postContainerExecResize(ctx context.Context, w http.Re
|
||||
}
|
||||
height, err := strconv.Atoi(r.Form.Get("h"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
width, err := strconv.Atoi(r.Form.Get("w"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return s.backend.ContainerExecResize(vars["name"], height, width)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package container // import "github.com/docker/docker/api/server/router/container"
|
||||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// getContainersByName inspects container's configuration and serializes it as json.
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package debug // import "github.com/docker/docker/api/server/router/debug"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"expvar"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
)
|
||||
|
||||
// NewRouter creates a new debug router
|
||||
// The debug router holds endpoints for debug the daemon, such as those for pprof.
|
||||
func NewRouter() router.Router {
|
||||
r := &debugRouter{}
|
||||
r.initRoutes()
|
||||
return r
|
||||
}
|
||||
|
||||
type debugRouter struct {
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
func (r *debugRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.NewGetRoute("/vars", frameworkAdaptHandler(expvar.Handler())),
|
||||
router.NewGetRoute("/pprof/", frameworkAdaptHandlerFunc(pprof.Index)),
|
||||
router.NewGetRoute("/pprof/cmdline", frameworkAdaptHandlerFunc(pprof.Cmdline)),
|
||||
router.NewGetRoute("/pprof/profile", frameworkAdaptHandlerFunc(pprof.Profile)),
|
||||
router.NewGetRoute("/pprof/symbol", frameworkAdaptHandlerFunc(pprof.Symbol)),
|
||||
router.NewGetRoute("/pprof/trace", frameworkAdaptHandlerFunc(pprof.Trace)),
|
||||
router.NewGetRoute("/pprof/{name}", handlePprof),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *debugRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
func frameworkAdaptHandler(handler http.Handler) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
handler.ServeHTTP(w, r)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func frameworkAdaptHandlerFunc(handler http.HandlerFunc) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
handler(w, r)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package debug // import "github.com/docker/docker/api/server/router/debug"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
)
|
||||
|
||||
func handlePprof(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
pprof.Handler(vars["name"]).ServeHTTP(w, r)
|
||||
return nil
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package distribution // import "github.com/docker/docker/api/server/router/distribution"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
// Backend is all the methods that need to be implemented
|
||||
// to provide image specific functionality.
|
||||
type Backend interface {
|
||||
GetRepository(context.Context, reference.Named, *types.AuthConfig) (distribution.Repository, bool, error)
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package distribution // import "github.com/docker/docker/api/server/router/distribution"
|
||||
|
||||
import "github.com/docker/docker/api/server/router"
|
||||
|
||||
// distributionRouter is a router to talk with the registry
|
||||
type distributionRouter struct {
|
||||
backend Backend
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// NewRouter initializes a new distribution router
|
||||
func NewRouter(backend Backend) router.Router {
|
||||
r := &distributionRouter{
|
||||
backend: backend,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
}
|
||||
|
||||
// Routes returns the available routes
|
||||
func (r *distributionRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
// initRoutes initializes the routes in the distribution router
|
||||
func (r *distributionRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
// GET
|
||||
router.NewGetRoute("/distribution/{name:.*}/json", r.getDistributionInfo),
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package distribution // import "github.com/docker/docker/api/server/router/distribution"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/manifest/manifestlist"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
var (
|
||||
config = &types.AuthConfig{}
|
||||
authEncoded = r.Header.Get("X-Registry-Auth")
|
||||
distributionInspect registrytypes.DistributionInspect
|
||||
)
|
||||
|
||||
if authEncoded != "" {
|
||||
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
|
||||
if err := json.NewDecoder(authJSON).Decode(&config); err != nil {
|
||||
// for a search it is not an error if no auth was given
|
||||
// to increase compatibility with the existing api it is defaulting to be empty
|
||||
config = &types.AuthConfig{}
|
||||
}
|
||||
}
|
||||
|
||||
image := vars["name"]
|
||||
|
||||
ref, err := reference.ParseAnyReference(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
namedRef, ok := ref.(reference.Named)
|
||||
if !ok {
|
||||
if _, ok := ref.(reference.Digested); ok {
|
||||
// full image ID
|
||||
return errors.Errorf("no manifest found for full image ID")
|
||||
}
|
||||
return errors.Errorf("unknown image reference format: %s", image)
|
||||
}
|
||||
|
||||
distrepo, _, err := s.backend.GetRepository(ctx, namedRef, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
blobsrvc := distrepo.Blobs(ctx)
|
||||
|
||||
if canonicalRef, ok := namedRef.(reference.Canonical); !ok {
|
||||
namedRef = reference.TagNameOnly(namedRef)
|
||||
|
||||
taggedRef, ok := namedRef.(reference.NamedTagged)
|
||||
if !ok {
|
||||
return errors.Errorf("image reference not tagged: %s", image)
|
||||
}
|
||||
|
||||
descriptor, err := distrepo.Tags(ctx).Get(ctx, taggedRef.Tag())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
distributionInspect.Descriptor = v1.Descriptor{
|
||||
MediaType: descriptor.MediaType,
|
||||
Digest: descriptor.Digest,
|
||||
Size: descriptor.Size,
|
||||
}
|
||||
} else {
|
||||
// TODO(nishanttotla): Once manifests can be looked up as a blob, the
|
||||
// descriptor should be set using blobsrvc.Stat(ctx, canonicalRef.Digest())
|
||||
// instead of having to manually fill in the fields
|
||||
distributionInspect.Descriptor.Digest = canonicalRef.Digest()
|
||||
}
|
||||
|
||||
// we have a digest, so we can retrieve the manifest
|
||||
mnfstsrvc, err := distrepo.Manifests(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mnfst, err := mnfstsrvc.Get(ctx, distributionInspect.Descriptor.Digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mediaType, payload, err := mnfst.Payload()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// update MediaType because registry might return something incorrect
|
||||
distributionInspect.Descriptor.MediaType = mediaType
|
||||
if distributionInspect.Descriptor.Size == 0 {
|
||||
distributionInspect.Descriptor.Size = int64(len(payload))
|
||||
}
|
||||
|
||||
// retrieve platform information depending on the type of manifest
|
||||
switch mnfstObj := mnfst.(type) {
|
||||
case *manifestlist.DeserializedManifestList:
|
||||
for _, m := range mnfstObj.Manifests {
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, v1.Platform{
|
||||
Architecture: m.Platform.Architecture,
|
||||
OS: m.Platform.OS,
|
||||
OSVersion: m.Platform.OSVersion,
|
||||
OSFeatures: m.Platform.OSFeatures,
|
||||
Variant: m.Platform.Variant,
|
||||
})
|
||||
}
|
||||
case *schema2.DeserializedManifest:
|
||||
configJSON, err := blobsrvc.Get(ctx, mnfstObj.Config.Digest)
|
||||
var platform v1.Platform
|
||||
if err == nil {
|
||||
err := json.Unmarshal(configJSON, &platform)
|
||||
if err == nil && (platform.OS != "" || platform.Architecture != "") {
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, platform)
|
||||
}
|
||||
}
|
||||
case *schema1.SignedManifest:
|
||||
platform := v1.Platform{
|
||||
Architecture: mnfstObj.Architecture,
|
||||
OS: "linux",
|
||||
}
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, platform)
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, distributionInspect)
|
||||
}
|
||||
@@ -1,12 +1,19 @@
|
||||
package router // import "github.com/docker/docker/api/server/router"
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
apierrors "github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
)
|
||||
|
||||
var (
|
||||
errExperimentalFeature = errors.New("This experimental feature is disabled by default. Start the Docker daemon with --experimental in order to enable it.")
|
||||
)
|
||||
|
||||
// ExperimentalRoute defines an experimental API route that can be enabled or disabled.
|
||||
type ExperimentalRoute interface {
|
||||
Route
|
||||
@@ -32,16 +39,8 @@ func (r *experimentalRoute) Disable() {
|
||||
r.handler = experimentalHandler
|
||||
}
|
||||
|
||||
type notImplementedError struct{}
|
||||
|
||||
func (notImplementedError) Error() string {
|
||||
return "This experimental feature is disabled by default. Start the Docker daemon in experimental mode in order to enable it."
|
||||
}
|
||||
|
||||
func (notImplementedError) NotImplemented() {}
|
||||
|
||||
func experimentalHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return notImplementedError{}
|
||||
return apierrors.NewErrorWithStatusCode(errExperimentalFeature, http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Handler returns returns the APIFunc to let the server wrap it in middlewares.
|
||||
|
||||
@@ -1,41 +1,45 @@
|
||||
package image // import "github.com/docker/docker/api/server/router/image"
|
||||
package image
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Backend is all the methods that need to be implemented
|
||||
// to provide image specific functionality.
|
||||
type Backend interface {
|
||||
containerBackend
|
||||
imageBackend
|
||||
importExportBackend
|
||||
registryBackend
|
||||
}
|
||||
|
||||
type containerBackend interface {
|
||||
Commit(name string, config *backend.ContainerCommitConfig) (imageID string, err error)
|
||||
}
|
||||
|
||||
type imageBackend interface {
|
||||
ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
|
||||
ImageHistory(imageName string) ([]*image.HistoryResponseItem, error)
|
||||
ImageDelete(imageRef string, force, prune bool) ([]types.ImageDelete, error)
|
||||
ImageHistory(imageName string) ([]*types.ImageHistory, error)
|
||||
Images(imageFilters filters.Args, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error)
|
||||
LookupImage(name string) (*types.ImageInspect, error)
|
||||
TagImage(imageName, repository, tag string) (string, error)
|
||||
ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error)
|
||||
TagImage(imageName, repository, tag string) error
|
||||
ImagesPrune(pruneFilters filters.Args) (*types.ImagesPruneReport, error)
|
||||
}
|
||||
|
||||
type importExportBackend interface {
|
||||
LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error
|
||||
ImportImage(src string, repository, platform string, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error
|
||||
ImportImage(src string, repository, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error
|
||||
ExportImage(names []string, outStream io.Writer) error
|
||||
}
|
||||
|
||||
type registryBackend interface {
|
||||
PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
|
||||
PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
|
||||
PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
|
||||
SearchRegistryForImages(ctx context.Context, filtersArgs string, term string, limit int, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
package image // import "github.com/docker/docker/api/server/router/image"
|
||||
package image
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
)
|
||||
|
||||
// imageRouter is a router to talk with the image controller
|
||||
type imageRouter struct {
|
||||
backend Backend
|
||||
decoder httputils.ContainerDecoder
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// NewRouter initializes a new image router
|
||||
func NewRouter(backend Backend) router.Router {
|
||||
r := &imageRouter{backend: backend}
|
||||
func NewRouter(backend Backend, decoder httputils.ContainerDecoder) router.Router {
|
||||
r := &imageRouter{
|
||||
backend: backend,
|
||||
decoder: decoder,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
}
|
||||
@@ -33,11 +38,12 @@ func (r *imageRouter) initRoutes() {
|
||||
router.NewGetRoute("/images/{name:.*}/history", r.getImagesHistory),
|
||||
router.NewGetRoute("/images/{name:.*}/json", r.getImagesByName),
|
||||
// POST
|
||||
router.NewPostRoute("/commit", r.postCommit),
|
||||
router.NewPostRoute("/images/load", r.postImagesLoad),
|
||||
router.NewPostRoute("/images/create", r.postImagesCreate, router.WithCancel),
|
||||
router.NewPostRoute("/images/{name:.*}/push", r.postImagesPush, router.WithCancel),
|
||||
router.Cancellable(router.NewPostRoute("/images/create", r.postImagesCreate)),
|
||||
router.Cancellable(router.NewPostRoute("/images/{name:.*}/push", r.postImagesPush)),
|
||||
router.NewPostRoute("/images/{name:.*}/tag", r.postImagesTag),
|
||||
router.NewPostRoute("/images/prune", r.postImagesPrune, router.WithCancel),
|
||||
router.NewPostRoute("/images/prune", r.postImagesPrune),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/images/{name:.*}", r.deleteImages),
|
||||
}
|
||||
|
||||
@@ -1,99 +1,125 @@
|
||||
package image // import "github.com/docker/docker/api/server/router/image"
|
||||
package image
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/registry"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (s *imageRouter) postCommit(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cname := r.Form.Get("container")
|
||||
|
||||
pause := httputils.BoolValue(r, "pause")
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if r.FormValue("pause") == "" && versions.GreaterThanOrEqualTo(version, "1.13") {
|
||||
pause = true
|
||||
}
|
||||
|
||||
c, _, _, err := s.decoder.DecodeConfig(r.Body)
|
||||
if err != nil && err != io.EOF { //Do not fail if body is empty.
|
||||
return err
|
||||
}
|
||||
if c == nil {
|
||||
c = &container.Config{}
|
||||
}
|
||||
|
||||
commitCfg := &backend.ContainerCommitConfig{
|
||||
ContainerCommitConfig: types.ContainerCommitConfig{
|
||||
Pause: pause,
|
||||
Repo: r.Form.Get("repo"),
|
||||
Tag: r.Form.Get("tag"),
|
||||
Author: r.Form.Get("author"),
|
||||
Comment: r.Form.Get("comment"),
|
||||
Config: c,
|
||||
MergeConfigs: true,
|
||||
},
|
||||
Changes: r.Form["changes"],
|
||||
}
|
||||
|
||||
imgID, err := s.backend.Commit(cname, commitCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &types.IDResponse{
|
||||
ID: string(imgID),
|
||||
})
|
||||
}
|
||||
|
||||
// Creates an image from Pull or from Import
|
||||
func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
image = r.Form.Get("fromImage")
|
||||
repo = r.Form.Get("repo")
|
||||
tag = r.Form.Get("tag")
|
||||
message = r.Form.Get("message")
|
||||
err error
|
||||
output = ioutils.NewWriteFlusher(w)
|
||||
platform *specs.Platform
|
||||
image = r.Form.Get("fromImage")
|
||||
repo = r.Form.Get("repo")
|
||||
tag = r.Form.Get("tag")
|
||||
message = r.Form.Get("message")
|
||||
err error
|
||||
output = ioutils.NewWriteFlusher(w)
|
||||
)
|
||||
defer output.Close()
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.GreaterThanOrEqualTo(version, "1.32") {
|
||||
apiPlatform := r.FormValue("platform")
|
||||
if apiPlatform != "" {
|
||||
sp, err := platforms.Parse(apiPlatform)
|
||||
if err != nil {
|
||||
return err
|
||||
if image != "" { //pull
|
||||
metaHeaders := map[string][]string{}
|
||||
for k, v := range r.Header {
|
||||
if strings.HasPrefix(k, "X-Meta-") {
|
||||
metaHeaders[k] = v
|
||||
}
|
||||
if err := system.ValidatePlatform(sp); err != nil {
|
||||
return err
|
||||
}
|
||||
platform = &sp
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
if image != "" { //pull
|
||||
metaHeaders := map[string][]string{}
|
||||
for k, v := range r.Header {
|
||||
if strings.HasPrefix(k, "X-Meta-") {
|
||||
metaHeaders[k] = v
|
||||
}
|
||||
authEncoded := r.Header.Get("X-Registry-Auth")
|
||||
authConfig := &types.AuthConfig{}
|
||||
if authEncoded != "" {
|
||||
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
|
||||
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
|
||||
// for a pull it is not an error if no auth was given
|
||||
// to increase compatibility with the existing api it is defaulting to be empty
|
||||
authConfig = &types.AuthConfig{}
|
||||
}
|
||||
|
||||
authEncoded := r.Header.Get("X-Registry-Auth")
|
||||
authConfig := &types.AuthConfig{}
|
||||
if authEncoded != "" {
|
||||
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
|
||||
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
|
||||
// for a pull it is not an error if no auth was given
|
||||
// to increase compatibility with the existing api it is defaulting to be empty
|
||||
authConfig = &types.AuthConfig{}
|
||||
}
|
||||
}
|
||||
err = s.backend.PullImage(ctx, image, tag, platform, metaHeaders, authConfig, output)
|
||||
} else { //import
|
||||
src := r.Form.Get("fromSrc")
|
||||
// 'err' MUST NOT be defined within this block, we need any error
|
||||
// generated from the download to be available to the output
|
||||
// stream processing below
|
||||
os := ""
|
||||
if platform != nil {
|
||||
os = platform.OS
|
||||
}
|
||||
err = s.backend.ImportImage(src, repo, os, tag, message, r.Body, output, r.Form["changes"])
|
||||
}
|
||||
|
||||
err = s.backend.PullImage(ctx, image, tag, metaHeaders, authConfig, output)
|
||||
} else { //import
|
||||
src := r.Form.Get("fromSrc")
|
||||
// 'err' MUST NOT be defined within this block, we need any error
|
||||
// generated from the download to be available to the output
|
||||
// stream processing below
|
||||
err = s.backend.ImportImage(src, repo, tag, message, r.Body, output, r.Form["changes"])
|
||||
}
|
||||
if err != nil {
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
output.Write(streamformatter.FormatError(err))
|
||||
sf := streamformatter.NewJSONStreamFormatter()
|
||||
output.Write(sf.FormatError(err))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -122,7 +148,7 @@ func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter,
|
||||
} else {
|
||||
// the old format is supported for compatibility if there was no authConfig header
|
||||
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
|
||||
return errors.Wrap(errdefs.InvalidParameter(err), "Bad parameters and missing X-Registry-Auth")
|
||||
return fmt.Errorf("Bad parameters and missing X-Registry-Auth: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +164,8 @@ func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter,
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
output.Write(streamformatter.FormatError(err))
|
||||
sf := streamformatter.NewJSONStreamFormatter()
|
||||
output.Write(sf.FormatError(err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -163,7 +190,8 @@ func (s *imageRouter) getImagesGet(ctx context.Context, w http.ResponseWriter, r
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
output.Write(streamformatter.FormatError(err))
|
||||
sf := streamformatter.NewJSONStreamFormatter()
|
||||
output.Write(sf.FormatError(err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -179,19 +207,11 @@ func (s *imageRouter) postImagesLoad(ctx context.Context, w http.ResponseWriter,
|
||||
output := ioutils.NewWriteFlusher(w)
|
||||
defer output.Close()
|
||||
if err := s.backend.LoadImage(r.Body, output, quiet); err != nil {
|
||||
output.Write(streamformatter.FormatError(err))
|
||||
output.Write(streamformatter.NewJSONStreamFormatter().FormatError(err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type missingImageError struct{}
|
||||
|
||||
func (missingImageError) Error() string {
|
||||
return "image name cannot be blank"
|
||||
}
|
||||
|
||||
func (missingImageError) InvalidParameter() {}
|
||||
|
||||
func (s *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
@@ -200,7 +220,7 @@ func (s *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter, r
|
||||
name := vars["name"]
|
||||
|
||||
if strings.TrimSpace(name) == "" {
|
||||
return missingImageError{}
|
||||
return fmt.Errorf("image name cannot be blank")
|
||||
}
|
||||
|
||||
force := httputils.BoolValue(r, "force")
|
||||
@@ -228,14 +248,14 @@ func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
||||
return err
|
||||
}
|
||||
|
||||
imageFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
imageFilters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
filterParam := r.Form.Get("filter")
|
||||
// FIXME(vdemeester) This has been deprecated in 1.13, and is target for removal for v17.12
|
||||
if filterParam != "" {
|
||||
if versions.LessThan(version, "1.28") && filterParam != "" {
|
||||
imageFilters.Add("reference", filterParam)
|
||||
}
|
||||
|
||||
@@ -261,7 +281,7 @@ func (s *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter,
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := s.backend.TagImage(vars["name"], r.Form.Get("repo"), r.Form.Get("tag")); err != nil {
|
||||
if err := s.backend.TagImage(vars["name"], r.Form.Get("repo"), r.Form.Get("tag")); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
@@ -311,12 +331,12 @@ func (s *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWriter
|
||||
return err
|
||||
}
|
||||
|
||||
pruneFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
pruneFilters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pruneReport, err := s.backend.ImagesPrune(ctx, pruneFilters)
|
||||
pruneReport, err := s.backend.ImagesPrune(pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
package router // import "github.com/docker/docker/api/server/router"
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// RouteWrapper wraps a route with extra functionality.
|
||||
// It is passed in when creating a new route.
|
||||
type RouteWrapper func(r Route) Route
|
||||
|
||||
// localRoute defines an individual API route to connect
|
||||
// with the docker daemon. It implements Route.
|
||||
type localRoute struct {
|
||||
@@ -35,42 +31,38 @@ func (l localRoute) Path() string {
|
||||
}
|
||||
|
||||
// NewRoute initializes a new local route for the router.
|
||||
func NewRoute(method, path string, handler httputils.APIFunc, opts ...RouteWrapper) Route {
|
||||
var r Route = localRoute{method, path, handler}
|
||||
for _, o := range opts {
|
||||
r = o(r)
|
||||
}
|
||||
return r
|
||||
func NewRoute(method, path string, handler httputils.APIFunc) Route {
|
||||
return localRoute{method, path, handler}
|
||||
}
|
||||
|
||||
// NewGetRoute initializes a new route with the http method GET.
|
||||
func NewGetRoute(path string, handler httputils.APIFunc, opts ...RouteWrapper) Route {
|
||||
return NewRoute("GET", path, handler, opts...)
|
||||
func NewGetRoute(path string, handler httputils.APIFunc) Route {
|
||||
return NewRoute("GET", path, handler)
|
||||
}
|
||||
|
||||
// NewPostRoute initializes a new route with the http method POST.
|
||||
func NewPostRoute(path string, handler httputils.APIFunc, opts ...RouteWrapper) Route {
|
||||
return NewRoute("POST", path, handler, opts...)
|
||||
func NewPostRoute(path string, handler httputils.APIFunc) Route {
|
||||
return NewRoute("POST", path, handler)
|
||||
}
|
||||
|
||||
// NewPutRoute initializes a new route with the http method PUT.
|
||||
func NewPutRoute(path string, handler httputils.APIFunc, opts ...RouteWrapper) Route {
|
||||
return NewRoute("PUT", path, handler, opts...)
|
||||
func NewPutRoute(path string, handler httputils.APIFunc) Route {
|
||||
return NewRoute("PUT", path, handler)
|
||||
}
|
||||
|
||||
// NewDeleteRoute initializes a new route with the http method DELETE.
|
||||
func NewDeleteRoute(path string, handler httputils.APIFunc, opts ...RouteWrapper) Route {
|
||||
return NewRoute("DELETE", path, handler, opts...)
|
||||
func NewDeleteRoute(path string, handler httputils.APIFunc) Route {
|
||||
return NewRoute("DELETE", path, handler)
|
||||
}
|
||||
|
||||
// NewOptionsRoute initializes a new route with the http method OPTIONS.
|
||||
func NewOptionsRoute(path string, handler httputils.APIFunc, opts ...RouteWrapper) Route {
|
||||
return NewRoute("OPTIONS", path, handler, opts...)
|
||||
func NewOptionsRoute(path string, handler httputils.APIFunc) Route {
|
||||
return NewRoute("OPTIONS", path, handler)
|
||||
}
|
||||
|
||||
// NewHeadRoute initializes a new route with the http method HEAD.
|
||||
func NewHeadRoute(path string, handler httputils.APIFunc, opts ...RouteWrapper) Route {
|
||||
return NewRoute("HEAD", path, handler, opts...)
|
||||
func NewHeadRoute(path string, handler httputils.APIFunc) Route {
|
||||
return NewRoute("HEAD", path, handler)
|
||||
}
|
||||
|
||||
func cancellableHandler(h httputils.APIFunc) httputils.APIFunc {
|
||||
@@ -93,9 +85,9 @@ func cancellableHandler(h httputils.APIFunc) httputils.APIFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// WithCancel makes new route which embeds http.CloseNotifier feature to
|
||||
// Cancellable makes new route which embeds http.CloseNotifier feature to
|
||||
// context.Context of handler.
|
||||
func WithCancel(r Route) Route {
|
||||
func Cancellable(r Route) Route {
|
||||
return localRoute{
|
||||
method: r.Method(),
|
||||
path: r.Path(),
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package network // import "github.com/docker/docker/api/server/router/network"
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
@@ -13,20 +11,12 @@ import (
|
||||
// to provide network specific functionality.
|
||||
type Backend interface {
|
||||
FindNetwork(idName string) (libnetwork.Network, error)
|
||||
GetNetworks(filters.Args, types.NetworkListConfig) ([]types.NetworkResource, error)
|
||||
GetNetworkByName(idName string) (libnetwork.Network, error)
|
||||
GetNetworksByID(partialID string) []libnetwork.Network
|
||||
GetNetworks() []libnetwork.Network
|
||||
CreateNetwork(nc types.NetworkCreateRequest) (*types.NetworkCreateResponse, error)
|
||||
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
|
||||
DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error
|
||||
DeleteNetwork(networkID string) error
|
||||
NetworksPrune(ctx context.Context, pruneFilters filters.Args) (*types.NetworksPruneReport, error)
|
||||
}
|
||||
|
||||
// ClusterBackend is all the methods that need to be implemented
|
||||
// to provide cluster network specific functionality.
|
||||
type ClusterBackend interface {
|
||||
GetNetworks(filters.Args) ([]types.NetworkResource, error)
|
||||
GetNetwork(name string) (types.NetworkResource, error)
|
||||
GetNetworksByName(name string) ([]types.NetworkResource, error)
|
||||
CreateNetwork(nc types.NetworkCreateRequest) (string, error)
|
||||
RemoveNetwork(name string) error
|
||||
DeleteNetwork(name string) error
|
||||
NetworksPrune(pruneFilters filters.Args) (*types.NetworksPruneReport, error)
|
||||
}
|
||||
|
||||
@@ -1 +1,96 @@
|
||||
package network // import "github.com/docker/docker/api/server/router/network"
|
||||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
|
||||
var (
|
||||
// AcceptedFilters is an acceptable filters for validation
|
||||
AcceptedFilters = map[string]bool{
|
||||
"driver": true,
|
||||
"type": true,
|
||||
"name": true,
|
||||
"id": true,
|
||||
"label": true,
|
||||
}
|
||||
)
|
||||
|
||||
func filterNetworkByType(nws []types.NetworkResource, netType string) (retNws []types.NetworkResource, err error) {
|
||||
switch netType {
|
||||
case "builtin":
|
||||
for _, nw := range nws {
|
||||
if runconfig.IsPreDefinedNetwork(nw.Name) {
|
||||
retNws = append(retNws, nw)
|
||||
}
|
||||
}
|
||||
case "custom":
|
||||
for _, nw := range nws {
|
||||
if !runconfig.IsPreDefinedNetwork(nw.Name) {
|
||||
retNws = append(retNws, nw)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid filter: 'type'='%s'", netType)
|
||||
}
|
||||
return retNws, nil
|
||||
}
|
||||
|
||||
// filterNetworks filters network list according to user specified filter
|
||||
// and returns user chosen networks
|
||||
func filterNetworks(nws []types.NetworkResource, filter filters.Args) ([]types.NetworkResource, error) {
|
||||
// if filter is empty, return original network list
|
||||
if filter.Len() == 0 {
|
||||
return nws, nil
|
||||
}
|
||||
|
||||
if err := filter.Validate(AcceptedFilters); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
displayNet := []types.NetworkResource{}
|
||||
for _, nw := range nws {
|
||||
if filter.Include("driver") {
|
||||
if !filter.ExactMatch("driver", nw.Driver) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Include("name") {
|
||||
if !filter.Match("name", nw.Name) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Include("id") {
|
||||
if !filter.Match("id", nw.ID) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if filter.Include("label") {
|
||||
if !filter.MatchKVList("label", nw.Labels) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
displayNet = append(displayNet, nw)
|
||||
}
|
||||
|
||||
if filter.Include("type") {
|
||||
var typeNet []types.NetworkResource
|
||||
errFilter := filter.WalkValues("type", func(fval string) error {
|
||||
passList, err := filterNetworkByType(displayNet, fval)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
typeNet = append(typeNet, passList...)
|
||||
return nil
|
||||
})
|
||||
if errFilter != nil {
|
||||
return nil, errFilter
|
||||
}
|
||||
displayNet = typeNet
|
||||
}
|
||||
|
||||
return displayNet, nil
|
||||
}
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
package network // import "github.com/docker/docker/api/server/router/network"
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/daemon/cluster"
|
||||
)
|
||||
|
||||
// networkRouter is a router to talk with the network controller
|
||||
type networkRouter struct {
|
||||
backend Backend
|
||||
cluster ClusterBackend
|
||||
routes []router.Route
|
||||
backend Backend
|
||||
clusterProvider *cluster.Cluster
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// NewRouter initializes a new network router
|
||||
func NewRouter(b Backend, c ClusterBackend) router.Router {
|
||||
func NewRouter(b Backend, c *cluster.Cluster) router.Router {
|
||||
r := &networkRouter{
|
||||
backend: b,
|
||||
cluster: c,
|
||||
backend: b,
|
||||
clusterProvider: c,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
@@ -36,7 +37,7 @@ func (r *networkRouter) initRoutes() {
|
||||
router.NewPostRoute("/networks/create", r.postNetworkCreate),
|
||||
router.NewPostRoute("/networks/{id:.*}/connect", r.postNetworkConnect),
|
||||
router.NewPostRoute("/networks/{id:.*}/disconnect", r.postNetworkDisconnect),
|
||||
router.NewPostRoute("/networks/prune", r.postNetworksPrune, router.WithCancel),
|
||||
router.NewPostRoute("/networks/prune", r.postNetworksPrune),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/networks/{id:.*}", r.deleteNetwork),
|
||||
}
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
package network // import "github.com/docker/docker/api/server/router/network"
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/libnetwork"
|
||||
netconst "github.com/docker/libnetwork/datastore"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/docker/libnetwork/networkdb"
|
||||
)
|
||||
|
||||
func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -24,184 +19,50 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit
|
||||
return err
|
||||
}
|
||||
|
||||
filter, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
filter := r.Form.Get("filters")
|
||||
netFilters, err := filters.FromParam(filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := network.ValidateFilters(filter); err != nil {
|
||||
return err
|
||||
}
|
||||
list := []types.NetworkResource{}
|
||||
|
||||
var list []types.NetworkResource
|
||||
nr, err := n.cluster.GetNetworks(filter)
|
||||
if err == nil {
|
||||
list = nr
|
||||
if nr, err := n.clusterProvider.GetNetworks(); err == nil {
|
||||
list = append(list, nr...)
|
||||
}
|
||||
|
||||
// Combine the network list returned by Docker daemon if it is not already
|
||||
// returned by the cluster manager
|
||||
localNetworks, err := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: versions.LessThan(httputils.VersionFromContext(ctx), "1.28")})
|
||||
SKIP:
|
||||
for _, nw := range n.backend.GetNetworks() {
|
||||
for _, nl := range list {
|
||||
if nl.ID == nw.ID() {
|
||||
continue SKIP
|
||||
}
|
||||
}
|
||||
list = append(list, *n.buildNetworkResource(nw))
|
||||
}
|
||||
|
||||
list, err = filterNetworks(list, netFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var idx map[string]bool
|
||||
if len(list) > 0 {
|
||||
idx = make(map[string]bool, len(list))
|
||||
for _, n := range list {
|
||||
idx[n.ID] = true
|
||||
}
|
||||
}
|
||||
for _, n := range localNetworks {
|
||||
if idx[n.ID] {
|
||||
continue
|
||||
}
|
||||
list = append(list, n)
|
||||
}
|
||||
|
||||
if list == nil {
|
||||
list = []types.NetworkResource{}
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, list)
|
||||
}
|
||||
|
||||
type invalidRequestError struct {
|
||||
cause error
|
||||
}
|
||||
|
||||
func (e invalidRequestError) Error() string {
|
||||
return e.cause.Error()
|
||||
}
|
||||
|
||||
func (e invalidRequestError) InvalidParameter() {}
|
||||
|
||||
type ambigousResultsError string
|
||||
|
||||
func (e ambigousResultsError) Error() string {
|
||||
return "network " + string(e) + " is ambiguous"
|
||||
}
|
||||
|
||||
func (ambigousResultsError) InvalidParameter() {}
|
||||
|
||||
func nameConflict(name string) error {
|
||||
return errdefs.Conflict(libnetwork.NetworkNameError(name))
|
||||
}
|
||||
|
||||
func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
term := vars["id"]
|
||||
var (
|
||||
verbose bool
|
||||
err error
|
||||
)
|
||||
if v := r.URL.Query().Get("verbose"); v != "" {
|
||||
if verbose, err = strconv.ParseBool(v); err != nil {
|
||||
return errors.Wrapf(invalidRequestError{err}, "invalid value for verbose: %s", v)
|
||||
nw, err := n.backend.FindNetwork(vars["id"])
|
||||
if err != nil {
|
||||
if nr, err := n.clusterProvider.GetNetwork(vars["id"]); err == nil {
|
||||
return httputils.WriteJSON(w, http.StatusOK, nr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
scope := r.URL.Query().Get("scope")
|
||||
|
||||
// In case multiple networks have duplicate names, return error.
|
||||
// TODO (yongtang): should we wrap with version here for backward compatibility?
|
||||
|
||||
// First find based on full ID, return immediately once one is found.
|
||||
// If a network appears both in swarm and local, assume it is in local first
|
||||
|
||||
// For full name and partial ID, save the result first, and process later
|
||||
// in case multiple records was found based on the same term
|
||||
listByFullName := map[string]types.NetworkResource{}
|
||||
listByPartialID := map[string]types.NetworkResource{}
|
||||
|
||||
// TODO(@cpuguy83): All this logic for figuring out which network to return does not belong here
|
||||
// Instead there should be a backend function to just get one network.
|
||||
filter := filters.NewArgs(filters.Arg("idOrName", term))
|
||||
if scope != "" {
|
||||
filter.Add("scope", scope)
|
||||
}
|
||||
nw, _ := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: true, Verbose: verbose})
|
||||
for _, network := range nw {
|
||||
if network.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, network)
|
||||
}
|
||||
if network.Name == term {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
|
||||
nwk, err := n.cluster.GetNetwork(term)
|
||||
if err == nil {
|
||||
// If the get network is passed with a specific network ID / partial network ID
|
||||
// or if the get network was passed with a network name and scope as swarm
|
||||
// return the network. Skipped using isMatchingScope because it is true if the scope
|
||||
// is not set which would be case if the client API v1.30
|
||||
if strings.HasPrefix(nwk.ID, term) || (netconst.SwarmScope == scope) {
|
||||
// If we have a previous match "backend", return it, we need verbose when enabled
|
||||
// ex: overlay/partial_ID or name/swarm_scope
|
||||
if nwv, ok := listByPartialID[nwk.ID]; ok {
|
||||
nwk = nwv
|
||||
} else if nwv, ok := listByFullName[nwk.ID]; ok {
|
||||
nwk = nwv
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, nwk)
|
||||
}
|
||||
}
|
||||
|
||||
nr, _ := n.cluster.GetNetworks(filter)
|
||||
for _, network := range nr {
|
||||
if network.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, network)
|
||||
}
|
||||
if network.Name == term {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByFullName) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByFullName[network.ID]; !ok {
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByPartialID) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByPartialID[network.ID]; !ok {
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find based on full name, returns true only if no duplicates
|
||||
if len(listByFullName) == 1 {
|
||||
for _, v := range listByFullName {
|
||||
return httputils.WriteJSON(w, http.StatusOK, v)
|
||||
}
|
||||
}
|
||||
if len(listByFullName) > 1 {
|
||||
return errors.Wrapf(ambigousResultsError(term), "%d matches found based on name", len(listByFullName))
|
||||
}
|
||||
|
||||
// Find based on partial ID, returns true only if no duplicates
|
||||
if len(listByPartialID) == 1 {
|
||||
for _, v := range listByPartialID {
|
||||
return httputils.WriteJSON(w, http.StatusOK, v)
|
||||
}
|
||||
}
|
||||
if len(listByPartialID) > 1 {
|
||||
return errors.Wrapf(ambigousResultsError(term), "%d matches found based on ID prefix", len(listByPartialID))
|
||||
}
|
||||
|
||||
return libnetwork.ErrNoSuchNetwork(term)
|
||||
return httputils.WriteJSON(w, http.StatusOK, n.buildNetworkResource(nw))
|
||||
}
|
||||
|
||||
func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -216,39 +77,23 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&create); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 {
|
||||
return nameConflict(create.Name)
|
||||
if nws, err := n.clusterProvider.GetNetworksByName(create.Name); err == nil && len(nws) > 0 {
|
||||
return libnetwork.NetworkNameError(create.Name)
|
||||
}
|
||||
|
||||
nw, err := n.backend.CreateNetwork(create)
|
||||
if err != nil {
|
||||
var warning string
|
||||
if _, ok := err.(libnetwork.NetworkNameError); ok {
|
||||
// check if user defined CheckDuplicate, if set true, return err
|
||||
// otherwise prepare a warning message
|
||||
if create.CheckDuplicate {
|
||||
return nameConflict(create.Name)
|
||||
}
|
||||
warning = libnetwork.NetworkNameError(create.Name).Error()
|
||||
}
|
||||
|
||||
if _, ok := err.(libnetwork.ManagerRedirectError); !ok {
|
||||
return err
|
||||
}
|
||||
id, err := n.cluster.CreateNetwork(create)
|
||||
id, err := n.clusterProvider.CreateNetwork(create)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nw = &types.NetworkCreateResponse{
|
||||
ID: id,
|
||||
Warning: warning,
|
||||
}
|
||||
nw = &types.NetworkCreateResponse{ID: id}
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusCreated, nw)
|
||||
@@ -265,16 +110,9 @@ func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseW
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&connect); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Unlike other operations, we does not check ambiguity of the name/ID here.
|
||||
// The reason is that, In case of attachable network in swarm scope, the actual local network
|
||||
// may not be available at the time. At the same time, inside daemon `ConnectContainerToNetwork`
|
||||
// does the ambiguity check anyway. Therefore, passing the name to daemon would be enough.
|
||||
return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig)
|
||||
}
|
||||
|
||||
@@ -289,10 +127,7 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force)
|
||||
@@ -302,113 +137,172 @@ func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nw, err := n.findUniqueNetwork(vars["id"])
|
||||
if err != nil {
|
||||
return err
|
||||
if _, err := n.clusterProvider.GetNetwork(vars["id"]); err == nil {
|
||||
if err = n.clusterProvider.RemoveNetwork(vars["id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return nil
|
||||
}
|
||||
if nw.Scope == "swarm" {
|
||||
if err = n.cluster.RemoveNetwork(nw.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := n.backend.DeleteNetwork(nw.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := n.backend.DeleteNetwork(vars["id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *networkRouter) buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
|
||||
r := &types.NetworkResource{}
|
||||
if nw == nil {
|
||||
return r
|
||||
}
|
||||
|
||||
info := nw.Info()
|
||||
r.Name = nw.Name()
|
||||
r.ID = nw.ID()
|
||||
r.Created = info.Created()
|
||||
r.Scope = info.Scope()
|
||||
if n.clusterProvider.IsManager() {
|
||||
if _, err := n.clusterProvider.GetNetwork(nw.ID()); err == nil {
|
||||
r.Scope = "swarm"
|
||||
}
|
||||
} else if info.Dynamic() {
|
||||
r.Scope = "swarm"
|
||||
}
|
||||
r.Driver = nw.Type()
|
||||
r.EnableIPv6 = info.IPv6Enabled()
|
||||
r.Internal = info.Internal()
|
||||
r.Attachable = info.Attachable()
|
||||
r.Options = info.DriverOptions()
|
||||
r.Containers = make(map[string]types.EndpointResource)
|
||||
buildIpamResources(r, info)
|
||||
r.Labels = info.Labels()
|
||||
|
||||
peers := info.Peers()
|
||||
if len(peers) != 0 {
|
||||
r.Peers = buildPeerInfoResources(peers)
|
||||
}
|
||||
|
||||
epl := nw.Endpoints()
|
||||
for _, e := range epl {
|
||||
ei := e.Info()
|
||||
if ei == nil {
|
||||
continue
|
||||
}
|
||||
sb := ei.Sandbox()
|
||||
tmpID := e.ID()
|
||||
key := "ep-" + tmpID
|
||||
if sb != nil {
|
||||
key = sb.ContainerID()
|
||||
}
|
||||
|
||||
r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo {
|
||||
peerInfo := make([]network.PeerInfo, 0, len(peers))
|
||||
for _, peer := range peers {
|
||||
peerInfo = append(peerInfo, network.PeerInfo{
|
||||
Name: peer.Name,
|
||||
IP: peer.IP,
|
||||
})
|
||||
}
|
||||
return peerInfo
|
||||
}
|
||||
|
||||
func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) {
|
||||
id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig()
|
||||
|
||||
ipv4Info, ipv6Info := nwInfo.IpamInfo()
|
||||
|
||||
r.IPAM.Driver = id
|
||||
|
||||
r.IPAM.Options = opts
|
||||
|
||||
r.IPAM.Config = []network.IPAMConfig{}
|
||||
for _, ip4 := range ipv4conf {
|
||||
if ip4.PreferredPool == "" {
|
||||
continue
|
||||
}
|
||||
iData := network.IPAMConfig{}
|
||||
iData.Subnet = ip4.PreferredPool
|
||||
iData.IPRange = ip4.SubPool
|
||||
iData.Gateway = ip4.Gateway
|
||||
iData.AuxAddress = ip4.AuxAddresses
|
||||
r.IPAM.Config = append(r.IPAM.Config, iData)
|
||||
}
|
||||
|
||||
if len(r.IPAM.Config) == 0 {
|
||||
for _, ip4Info := range ipv4Info {
|
||||
iData := network.IPAMConfig{}
|
||||
iData.Subnet = ip4Info.IPAMData.Pool.String()
|
||||
iData.Gateway = ip4Info.IPAMData.Gateway.IP.String()
|
||||
r.IPAM.Config = append(r.IPAM.Config, iData)
|
||||
}
|
||||
}
|
||||
|
||||
hasIpv6Conf := false
|
||||
for _, ip6 := range ipv6conf {
|
||||
if ip6.PreferredPool == "" {
|
||||
continue
|
||||
}
|
||||
hasIpv6Conf = true
|
||||
iData := network.IPAMConfig{}
|
||||
iData.Subnet = ip6.PreferredPool
|
||||
iData.IPRange = ip6.SubPool
|
||||
iData.Gateway = ip6.Gateway
|
||||
iData.AuxAddress = ip6.AuxAddresses
|
||||
r.IPAM.Config = append(r.IPAM.Config, iData)
|
||||
}
|
||||
|
||||
if !hasIpv6Conf {
|
||||
for _, ip6Info := range ipv6Info {
|
||||
if ip6Info.IPAMData.Pool == nil {
|
||||
continue
|
||||
}
|
||||
iData := network.IPAMConfig{}
|
||||
iData.Subnet = ip6Info.IPAMData.Pool.String()
|
||||
iData.Gateway = ip6Info.IPAMData.Gateway.String()
|
||||
r.IPAM.Config = append(r.IPAM.Config, iData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo) types.EndpointResource {
|
||||
er := types.EndpointResource{}
|
||||
|
||||
er.EndpointID = id
|
||||
er.Name = name
|
||||
ei := info
|
||||
if ei == nil {
|
||||
return er
|
||||
}
|
||||
|
||||
if iface := ei.Iface(); iface != nil {
|
||||
if mac := iface.MacAddress(); mac != nil {
|
||||
er.MacAddress = mac.String()
|
||||
}
|
||||
if ip := iface.Address(); ip != nil && len(ip.IP) > 0 {
|
||||
er.IPv4Address = ip.String()
|
||||
}
|
||||
|
||||
if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 {
|
||||
er.IPv6Address = ipv6.String()
|
||||
}
|
||||
}
|
||||
return er
|
||||
}
|
||||
|
||||
func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pruneFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pruneReport, err := n.backend.NetworksPrune(ctx, pruneFilters)
|
||||
pruneReport, err := n.backend.NetworksPrune(filters.Args{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, pruneReport)
|
||||
}
|
||||
|
||||
// findUniqueNetwork will search network across different scopes (both local and swarm).
|
||||
// NOTE: This findUniqueNetwork is different from FindNetwork in the daemon.
|
||||
// In case multiple networks have duplicate names, return error.
|
||||
// First find based on full ID, return immediately once one is found.
|
||||
// If a network appears both in swarm and local, assume it is in local first
|
||||
// For full name and partial ID, save the result first, and process later
|
||||
// in case multiple records was found based on the same term
|
||||
// TODO (yongtang): should we wrap with version here for backward compatibility?
|
||||
func (n *networkRouter) findUniqueNetwork(term string) (types.NetworkResource, error) {
|
||||
listByFullName := map[string]types.NetworkResource{}
|
||||
listByPartialID := map[string]types.NetworkResource{}
|
||||
|
||||
filter := filters.NewArgs(filters.Arg("idOrName", term))
|
||||
nw, _ := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: true})
|
||||
for _, network := range nw {
|
||||
if network.ID == term {
|
||||
return network, nil
|
||||
}
|
||||
if network.Name == term && !network.Ingress {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
|
||||
nr, _ := n.cluster.GetNetworks(filter)
|
||||
for _, network := range nr {
|
||||
if network.ID == term {
|
||||
return network, nil
|
||||
}
|
||||
if network.Name == term {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByFullName) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByFullName[network.ID]; !ok {
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByPartialID) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByPartialID[network.ID]; !ok {
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find based on full name, returns true only if no duplicates
|
||||
if len(listByFullName) == 1 {
|
||||
for _, v := range listByFullName {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
if len(listByFullName) > 1 {
|
||||
return types.NetworkResource{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName)))
|
||||
}
|
||||
|
||||
// Find based on partial ID, returns true only if no duplicates
|
||||
if len(listByPartialID) == 1 {
|
||||
for _, v := range listByPartialID {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
if len(listByPartialID) > 1 {
|
||||
return types.NetworkResource{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID)))
|
||||
}
|
||||
|
||||
return types.NetworkResource{}, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term))
|
||||
}
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
package plugin // import "github.com/docker/docker/api/server/router/plugin"
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
enginetypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/plugin"
|
||||
"github.com/docker/docker/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Backend for Plugin
|
||||
type Backend interface {
|
||||
Disable(name string, config *enginetypes.PluginDisableConfig) error
|
||||
Enable(name string, config *enginetypes.PluginEnableConfig) error
|
||||
List(filters.Args) ([]enginetypes.Plugin, error)
|
||||
List() ([]enginetypes.Plugin, error)
|
||||
Inspect(name string) (*enginetypes.Plugin, error)
|
||||
Remove(name string, config *enginetypes.PluginRmConfig) error
|
||||
Set(name string, args []string) error
|
||||
Privileges(ctx context.Context, ref reference.Named, metaHeaders http.Header, authConfig *enginetypes.AuthConfig) (enginetypes.PluginPrivileges, error)
|
||||
Pull(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges, outStream io.Writer, opts ...plugin.CreateOpt) error
|
||||
Pull(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges, outStream io.Writer) error
|
||||
Push(ctx context.Context, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, outStream io.Writer) error
|
||||
Upgrade(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *enginetypes.AuthConfig, privileges enginetypes.PluginPrivileges, outStream io.Writer) error
|
||||
CreateFromContext(ctx context.Context, tarCtx io.ReadCloser, options *enginetypes.PluginCreateOptions) error
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package plugin // import "github.com/docker/docker/api/server/router/plugin"
|
||||
package plugin
|
||||
|
||||
import "github.com/docker/docker/api/server/router"
|
||||
|
||||
@@ -30,9 +30,9 @@ func (r *pluginRouter) initRoutes() {
|
||||
router.NewDeleteRoute("/plugins/{name:.*}", r.removePlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/enable", r.enablePlugin), // PATCH?
|
||||
router.NewPostRoute("/plugins/{name:.*}/disable", r.disablePlugin),
|
||||
router.NewPostRoute("/plugins/pull", r.pullPlugin, router.WithCancel),
|
||||
router.NewPostRoute("/plugins/{name:.*}/push", r.pushPlugin, router.WithCancel),
|
||||
router.NewPostRoute("/plugins/{name:.*}/upgrade", r.upgradePlugin, router.WithCancel),
|
||||
router.Cancellable(router.NewPostRoute("/plugins/pull", r.pullPlugin)),
|
||||
router.Cancellable(router.NewPostRoute("/plugins/{name:.*}/push", r.pushPlugin)),
|
||||
router.Cancellable(router.NewPostRoute("/plugins/{name:.*}/upgrade", r.upgradePlugin)),
|
||||
router.NewPostRoute("/plugins/{name:.*}/set", r.setPlugin),
|
||||
router.NewPostRoute("/plugins/create", r.createPlugin),
|
||||
}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
package plugin // import "github.com/docker/docker/api/server/router/plugin"
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func parseHeaders(headers http.Header) (map[string][]string, *types.AuthConfig) {
|
||||
@@ -48,27 +46,39 @@ func parseHeaders(headers http.Header) (map[string][]string, *types.AuthConfig)
|
||||
// be returned.
|
||||
func parseRemoteRef(remote string) (reference.Named, string, error) {
|
||||
// Parse remote reference, supporting remotes with name and tag
|
||||
remoteRef, err := reference.ParseNormalizedNamed(remote)
|
||||
// NOTE: Using distribution reference to handle references
|
||||
// containing both a name and digest
|
||||
remoteRef, err := distreference.ParseNamed(remote)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
type canonicalWithTag interface {
|
||||
reference.Canonical
|
||||
Tag() string
|
||||
var tag string
|
||||
if t, ok := remoteRef.(distreference.Tagged); ok {
|
||||
tag = t.Tag()
|
||||
}
|
||||
|
||||
if canonical, ok := remoteRef.(canonicalWithTag); ok {
|
||||
remoteRef, err = reference.WithDigest(reference.TrimNamed(remoteRef), canonical.Digest())
|
||||
// Convert distribution reference to docker reference
|
||||
// TODO: remove when docker reference changes reconciled upstream
|
||||
ref, err := reference.WithName(remoteRef.Name())
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if d, ok := remoteRef.(distreference.Digested); ok {
|
||||
ref, err = reference.WithDigest(ref, d.Digest())
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return remoteRef, canonical.Tag(), nil
|
||||
} else if tag != "" {
|
||||
ref, err = reference.WithTag(ref, tag)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
} else {
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
}
|
||||
|
||||
remoteRef = reference.TagNameOnly(remoteRef)
|
||||
|
||||
return remoteRef, "", nil
|
||||
return ref, tag, nil
|
||||
}
|
||||
|
||||
func (pr *pluginRouter) getPrivileges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -123,7 +133,7 @@ func (pr *pluginRouter) upgradePlugin(ctx context.Context, w http.ResponseWriter
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
output.Write(streamformatter.FormatError(err))
|
||||
output.Write(streamformatter.NewJSONStreamFormatter().FormatError(err))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -162,7 +172,7 @@ func (pr *pluginRouter) pullPlugin(ctx context.Context, w http.ResponseWriter, r
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
output.Write(streamformatter.FormatError(err))
|
||||
output.Write(streamformatter.NewJSONStreamFormatter().FormatError(err))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -177,24 +187,24 @@ func getName(ref reference.Named, tag, name string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
name = reference.FamiliarString(nt)
|
||||
name = nt.String()
|
||||
} else {
|
||||
name = reference.FamiliarString(reference.TagNameOnly(trimmed))
|
||||
name = reference.WithDefaultTag(trimmed).String()
|
||||
}
|
||||
} else {
|
||||
name = reference.FamiliarString(ref)
|
||||
name = ref.String()
|
||||
}
|
||||
} else {
|
||||
localRef, err := reference.ParseNormalizedNamed(name)
|
||||
localRef, err := reference.ParseNamed(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, ok := localRef.(reference.Canonical); ok {
|
||||
return "", errors.New("cannot use digest in plugin tag")
|
||||
}
|
||||
if reference.IsNameOnly(localRef) {
|
||||
if distreference.IsNameOnly(localRef) {
|
||||
// TODO: log change in name to out stream
|
||||
name = reference.FamiliarString(reference.TagNameOnly(localRef))
|
||||
name = reference.WithDefaultTag(localRef).String()
|
||||
}
|
||||
}
|
||||
return name, nil
|
||||
@@ -270,7 +280,7 @@ func (pr *pluginRouter) pushPlugin(ctx context.Context, w http.ResponseWriter, r
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
output.Write(streamformatter.FormatError(err))
|
||||
output.Write(streamformatter.NewJSONStreamFormatter().FormatError(err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -278,10 +288,7 @@ func (pr *pluginRouter) pushPlugin(ctx context.Context, w http.ResponseWriter, r
|
||||
func (pr *pluginRouter) setPlugin(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var args []string
|
||||
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
if err := pr.backend.Set(vars["name"], args); err != nil {
|
||||
return err
|
||||
@@ -291,15 +298,7 @@ func (pr *pluginRouter) setPlugin(ctx context.Context, w http.ResponseWriter, r
|
||||
}
|
||||
|
||||
func (pr *pluginRouter) listPlugins(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pluginFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l, err := pr.backend.List(pluginFilters)
|
||||
l, err := pr.backend.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package router // import "github.com/docker/docker/api/server/router"
|
||||
package router
|
||||
|
||||
import "github.com/docker/docker/api/server/httputils"
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package session // import "github.com/docker/docker/api/server/router/session"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Backend abstracts an session receiver from an http request.
|
||||
type Backend interface {
|
||||
HandleHTTPRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) error
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package session // import "github.com/docker/docker/api/server/router/session"
|
||||
|
||||
import "github.com/docker/docker/api/server/router"
|
||||
|
||||
// sessionRouter is a router to talk with the session controller
|
||||
type sessionRouter struct {
|
||||
backend Backend
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// NewRouter initializes a new session router
|
||||
func NewRouter(b Backend) router.Router {
|
||||
r := &sessionRouter{
|
||||
backend: b,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
}
|
||||
|
||||
// Routes returns the available routers to the session controller
|
||||
func (r *sessionRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
func (r *sessionRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.NewPostRoute("/session", r.startSession),
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package session // import "github.com/docker/docker/api/server/router/session"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
)
|
||||
|
||||
func (sr *sessionRouter) startSession(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
err := sr.backend.HandleHTTPRequest(ctx, w, r)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
package swarm // import "github.com/docker/docker/api/server/router/swarm"
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
basictypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
types "github.com/docker/docker/api/types/swarm"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Backend abstracts a swarm manager.
|
||||
// Backend abstracts an swarm commands manager.
|
||||
type Backend interface {
|
||||
Init(req types.InitRequest) (string, error)
|
||||
Join(req types.JoinRequest) error
|
||||
@@ -17,32 +16,21 @@ type Backend interface {
|
||||
Update(uint64, types.Spec, types.UpdateFlags) error
|
||||
GetUnlockKey() (string, error)
|
||||
UnlockSwarm(req types.UnlockRequest) error
|
||||
|
||||
GetServices(basictypes.ServiceListOptions) ([]types.Service, error)
|
||||
GetService(idOrName string, insertDefaults bool) (types.Service, error)
|
||||
CreateService(types.ServiceSpec, string, bool) (*basictypes.ServiceCreateResponse, error)
|
||||
UpdateService(string, uint64, types.ServiceSpec, basictypes.ServiceUpdateOptions, bool) (*basictypes.ServiceUpdateResponse, error)
|
||||
GetService(string) (types.Service, error)
|
||||
CreateService(types.ServiceSpec, string) (*basictypes.ServiceCreateResponse, error)
|
||||
UpdateService(string, uint64, types.ServiceSpec, string, string) (*basictypes.ServiceUpdateResponse, error)
|
||||
RemoveService(string) error
|
||||
|
||||
ServiceLogs(context.Context, *backend.LogSelector, *basictypes.ContainerLogsOptions) (<-chan *backend.LogMessage, error)
|
||||
|
||||
ServiceLogs(context.Context, string, *backend.ContainerLogsConfig, chan struct{}) error
|
||||
GetNodes(basictypes.NodeListOptions) ([]types.Node, error)
|
||||
GetNode(string) (types.Node, error)
|
||||
UpdateNode(string, uint64, types.NodeSpec) error
|
||||
RemoveNode(string, bool) error
|
||||
|
||||
GetTasks(basictypes.TaskListOptions) ([]types.Task, error)
|
||||
GetTask(string) (types.Task, error)
|
||||
|
||||
GetSecrets(opts basictypes.SecretListOptions) ([]types.Secret, error)
|
||||
CreateSecret(s types.SecretSpec) (string, error)
|
||||
RemoveSecret(idOrName string) error
|
||||
RemoveSecret(id string) error
|
||||
GetSecret(id string) (types.Secret, error)
|
||||
UpdateSecret(idOrName string, version uint64, spec types.SecretSpec) error
|
||||
|
||||
GetConfigs(opts basictypes.ConfigListOptions) ([]types.Config, error)
|
||||
CreateConfig(s types.ConfigSpec) (string, error)
|
||||
RemoveConfig(id string) error
|
||||
GetConfig(id string) (types.Config, error)
|
||||
UpdateConfig(idOrName string, version uint64, spec types.ConfigSpec) error
|
||||
UpdateSecret(id string, version uint64, spec types.SecretSpec) error
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package swarm // import "github.com/docker/docker/api/server/router/swarm"
|
||||
package swarm
|
||||
|
||||
import "github.com/docker/docker/api/server/router"
|
||||
|
||||
@@ -31,33 +31,22 @@ func (sr *swarmRouter) initRoutes() {
|
||||
router.NewGetRoute("/swarm/unlockkey", sr.getUnlockKey),
|
||||
router.NewPostRoute("/swarm/update", sr.updateCluster),
|
||||
router.NewPostRoute("/swarm/unlock", sr.unlockCluster),
|
||||
|
||||
router.NewGetRoute("/services", sr.getServices),
|
||||
router.NewGetRoute("/services/{id}", sr.getService),
|
||||
router.NewPostRoute("/services/create", sr.createService),
|
||||
router.NewPostRoute("/services/{id}/update", sr.updateService),
|
||||
router.NewDeleteRoute("/services/{id}", sr.removeService),
|
||||
router.NewGetRoute("/services/{id}/logs", sr.getServiceLogs, router.WithCancel),
|
||||
|
||||
router.Experimental(router.Cancellable(router.NewGetRoute("/services/{id}/logs", sr.getServiceLogs))),
|
||||
router.NewGetRoute("/nodes", sr.getNodes),
|
||||
router.NewGetRoute("/nodes/{id}", sr.getNode),
|
||||
router.NewDeleteRoute("/nodes/{id}", sr.removeNode),
|
||||
router.NewPostRoute("/nodes/{id}/update", sr.updateNode),
|
||||
|
||||
router.NewGetRoute("/tasks", sr.getTasks),
|
||||
router.NewGetRoute("/tasks/{id}", sr.getTask),
|
||||
router.NewGetRoute("/tasks/{id}/logs", sr.getTaskLogs, router.WithCancel),
|
||||
|
||||
router.NewGetRoute("/secrets", sr.getSecrets),
|
||||
router.NewPostRoute("/secrets/create", sr.createSecret),
|
||||
router.NewDeleteRoute("/secrets/{id}", sr.removeSecret),
|
||||
router.NewGetRoute("/secrets/{id}", sr.getSecret),
|
||||
router.NewPostRoute("/secrets/{id}/update", sr.updateSecret),
|
||||
|
||||
router.NewGetRoute("/configs", sr.getConfigs),
|
||||
router.NewPostRoute("/configs/create", sr.createConfig),
|
||||
router.NewDeleteRoute("/configs/{id}", sr.removeConfig),
|
||||
router.NewGetRoute("/configs/{id}", sr.getConfig),
|
||||
router.NewPostRoute("/configs/{id}/update", sr.updateConfig),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,25 @@
|
||||
package swarm // import "github.com/docker/docker/api/server/router/swarm"
|
||||
package swarm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
basictypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
types "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (sr *swarmRouter) initCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var req types.InitRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
// DefaultAddrPool and SubnetSize were added in API 1.39. Ignore on older API versions.
|
||||
if versions.LessThan(version, "1.39") {
|
||||
req.DefaultAddrPool = nil
|
||||
req.SubnetSize = 0
|
||||
return err
|
||||
}
|
||||
nodeID, err := sr.backend.Init(req)
|
||||
if err != nil {
|
||||
@@ -44,10 +32,7 @@ func (sr *swarmRouter) initCluster(ctx context.Context, w http.ResponseWriter, r
|
||||
func (sr *swarmRouter) joinCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var req types.JoinRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
return sr.backend.Join(req)
|
||||
}
|
||||
@@ -74,17 +59,14 @@ func (sr *swarmRouter) inspectCluster(ctx context.Context, w http.ResponseWriter
|
||||
func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var swarm types.Spec
|
||||
if err := json.NewDecoder(r.Body).Decode(&swarm); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
rawVersion := r.URL.Query().Get("version")
|
||||
version, err := strconv.ParseUint(rawVersion, 10, 64)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("invalid swarm version '%s': %v", rawVersion, err)
|
||||
return errdefs.InvalidParameter(err)
|
||||
return errors.NewBadRequestError(err)
|
||||
}
|
||||
|
||||
var flags types.UpdateFlags
|
||||
@@ -93,7 +75,7 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter,
|
||||
rot, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("invalid value for rotateWorkerToken: %s", value)
|
||||
return errdefs.InvalidParameter(err)
|
||||
return errors.NewBadRequestError(err)
|
||||
}
|
||||
|
||||
flags.RotateWorkerToken = rot
|
||||
@@ -103,7 +85,7 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter,
|
||||
rot, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("invalid value for rotateManagerToken: %s", value)
|
||||
return errdefs.InvalidParameter(err)
|
||||
return errors.NewBadRequestError(err)
|
||||
}
|
||||
|
||||
flags.RotateManagerToken = rot
|
||||
@@ -112,7 +94,7 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter,
|
||||
if value := r.URL.Query().Get("rotateManagerUnlockKey"); value != "" {
|
||||
rot, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("invalid value for rotateManagerUnlockKey: %s", value))
|
||||
return errors.NewBadRequestError(fmt.Errorf("invalid value for rotateManagerUnlockKey: %s", value))
|
||||
}
|
||||
|
||||
flags.RotateManagerUnlockKey = rot
|
||||
@@ -128,10 +110,7 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter,
|
||||
func (sr *swarmRouter) unlockCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var req types.UnlockRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sr.backend.UnlockSwarm(req); err != nil {
|
||||
@@ -157,9 +136,9 @@ func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filter, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
filter, err := filters.FromParam(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
services, err := sr.backend.GetServices(basictypes.ServiceListOptions{Filters: filter})
|
||||
@@ -172,17 +151,7 @@ func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r
|
||||
}
|
||||
|
||||
func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var insertDefaults bool
|
||||
if value := r.URL.Query().Get("insertDefaults"); value != "" {
|
||||
var err error
|
||||
insertDefaults, err = strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("invalid value for insertDefaults: %s", value)
|
||||
return errors.Wrapf(errdefs.InvalidParameter(err), "invalid value for insertDefaults: %s", value)
|
||||
}
|
||||
}
|
||||
|
||||
service, err := sr.backend.GetService(vars["id"], insertDefaults)
|
||||
service, err := sr.backend.GetService(vars["id"])
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting service %s: %v", vars["id"], err)
|
||||
return err
|
||||
@@ -194,21 +163,13 @@ func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r
|
||||
func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var service types.ServiceSpec
|
||||
if err := json.NewDecoder(r.Body).Decode(&service); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns "" if the header does not exist
|
||||
encodedAuth := r.Header.Get("X-Registry-Auth")
|
||||
cliVersion := r.Header.Get("version")
|
||||
queryRegistry := false
|
||||
if cliVersion != "" && versions.LessThan(cliVersion, "1.30") {
|
||||
queryRegistry = true
|
||||
}
|
||||
|
||||
resp, err := sr.backend.CreateService(service, encodedAuth, queryRegistry)
|
||||
resp, err := sr.backend.CreateService(service, encodedAuth)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error creating service %s: %v", service.Name, err)
|
||||
return err
|
||||
@@ -220,32 +181,22 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
|
||||
func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var service types.ServiceSpec
|
||||
if err := json.NewDecoder(r.Body).Decode(&service); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
rawVersion := r.URL.Query().Get("version")
|
||||
version, err := strconv.ParseUint(rawVersion, 10, 64)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("invalid service version '%s': %v", rawVersion, err)
|
||||
return errdefs.InvalidParameter(err)
|
||||
return errors.NewBadRequestError(err)
|
||||
}
|
||||
|
||||
var flags basictypes.ServiceUpdateOptions
|
||||
|
||||
// Get returns "" if the header does not exist
|
||||
flags.EncodedRegistryAuth = r.Header.Get("X-Registry-Auth")
|
||||
flags.RegistryAuthFrom = r.URL.Query().Get("registryAuthFrom")
|
||||
flags.Rollback = r.URL.Query().Get("rollback")
|
||||
cliVersion := r.Header.Get("version")
|
||||
queryRegistry := false
|
||||
if cliVersion != "" && versions.LessThan(cliVersion, "1.30") {
|
||||
queryRegistry = true
|
||||
}
|
||||
encodedAuth := r.Header.Get("X-Registry-Auth")
|
||||
|
||||
resp, err := sr.backend.UpdateService(vars["id"], version, service, flags, queryRegistry)
|
||||
registryAuthFrom := r.URL.Query().Get("registryAuthFrom")
|
||||
|
||||
resp, err := sr.backend.UpdateService(vars["id"], version, service, encodedAuth, registryAuthFrom)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error updating service %s: %v", vars["id"], err)
|
||||
return err
|
||||
@@ -261,35 +212,60 @@ func (sr *swarmRouter) removeService(ctx context.Context, w http.ResponseWriter,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sr *swarmRouter) getTaskLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// make a selector to pass to the helper function
|
||||
selector := &backend.LogSelector{
|
||||
Tasks: []string{vars["id"]},
|
||||
}
|
||||
return sr.swarmLogs(ctx, w, r, selector)
|
||||
}
|
||||
|
||||
func (sr *swarmRouter) getServiceLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// make a selector to pass to the helper function
|
||||
selector := &backend.LogSelector{
|
||||
Services: []string{vars["id"]},
|
||||
// Args are validated before the stream starts because when it starts we're
|
||||
// sending HTTP 200 by writing an empty chunk of data to tell the client that
|
||||
// daemon is going to stream. By sending this initial HTTP 200 we can't report
|
||||
// any error after the stream starts (i.e. container not found, wrong parameters)
|
||||
// with the appropriate status code.
|
||||
stdout, stderr := httputils.BoolValue(r, "stdout"), httputils.BoolValue(r, "stderr")
|
||||
if !(stdout || stderr) {
|
||||
return fmt.Errorf("Bad parameters: you must choose at least one stream")
|
||||
}
|
||||
return sr.swarmLogs(ctx, w, r, selector)
|
||||
|
||||
serviceName := vars["id"]
|
||||
logsConfig := &backend.ContainerLogsConfig{
|
||||
ContainerLogsOptions: basictypes.ContainerLogsOptions{
|
||||
Follow: httputils.BoolValue(r, "follow"),
|
||||
Timestamps: httputils.BoolValue(r, "timestamps"),
|
||||
Since: r.Form.Get("since"),
|
||||
Tail: r.Form.Get("tail"),
|
||||
ShowStdout: stdout,
|
||||
ShowStderr: stderr,
|
||||
Details: httputils.BoolValue(r, "details"),
|
||||
},
|
||||
OutStream: w,
|
||||
}
|
||||
|
||||
if logsConfig.Details {
|
||||
return fmt.Errorf("Bad parameters: details is not currently supported")
|
||||
}
|
||||
|
||||
chStarted := make(chan struct{})
|
||||
if err := sr.backend.ServiceLogs(ctx, serviceName, logsConfig, chStarted); err != nil {
|
||||
select {
|
||||
case <-chStarted:
|
||||
// The client may be expecting all of the data we're sending to
|
||||
// be multiplexed, so send it through OutStream, which will
|
||||
// have been set up to handle that if needed.
|
||||
fmt.Fprintf(logsConfig.OutStream, "Error grabbing service logs: %v\n", err)
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filter, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
filter, err := filters.FromParam(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -316,17 +292,14 @@ func (sr *swarmRouter) getNode(ctx context.Context, w http.ResponseWriter, r *ht
|
||||
func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var node types.NodeSpec
|
||||
if err := json.NewDecoder(r.Body).Decode(&node); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
rawVersion := r.URL.Query().Get("version")
|
||||
version, err := strconv.ParseUint(rawVersion, 10, 64)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("invalid node version '%s': %v", rawVersion, err)
|
||||
return errdefs.InvalidParameter(err)
|
||||
return errors.NewBadRequestError(err)
|
||||
}
|
||||
|
||||
if err := sr.backend.UpdateNode(vars["id"], version, node); err != nil {
|
||||
@@ -354,7 +327,7 @@ func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *h
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filter, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
filter, err := filters.FromParam(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -382,7 +355,7 @@ func (sr *swarmRouter) getSecrets(ctx context.Context, w http.ResponseWriter, r
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
filters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
filters, err := filters.FromParam(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -398,14 +371,7 @@ func (sr *swarmRouter) getSecrets(ctx context.Context, w http.ResponseWriter, r
|
||||
func (sr *swarmRouter) createSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var secret types.SecretSpec
|
||||
if err := json.NewDecoder(r.Body).Decode(&secret); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if secret.Templating != nil && versions.LessThan(version, "1.37") {
|
||||
return errdefs.InvalidParameter(errors.Errorf("secret templating is not supported on the specified API version: %s", version))
|
||||
return err
|
||||
}
|
||||
|
||||
id, err := sr.backend.CreateSecret(secret)
|
||||
@@ -439,96 +405,19 @@ func (sr *swarmRouter) getSecret(ctx context.Context, w http.ResponseWriter, r *
|
||||
func (sr *swarmRouter) updateSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var secret types.SecretSpec
|
||||
if err := json.NewDecoder(r.Body).Decode(&secret); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return errors.NewBadRequestError(err)
|
||||
}
|
||||
|
||||
rawVersion := r.URL.Query().Get("version")
|
||||
version, err := strconv.ParseUint(rawVersion, 10, 64)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("invalid secret version"))
|
||||
return errors.NewBadRequestError(fmt.Errorf("invalid secret version"))
|
||||
}
|
||||
|
||||
id := vars["id"]
|
||||
return sr.backend.UpdateSecret(id, version, secret)
|
||||
}
|
||||
|
||||
func (sr *swarmRouter) getConfigs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
if err := sr.backend.UpdateSecret(id, version, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
filters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configs, err := sr.backend.GetConfigs(basictypes.ConfigListOptions{Filters: filters})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, configs)
|
||||
}
|
||||
|
||||
func (sr *swarmRouter) createConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var config types.ConfigSpec
|
||||
if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if config.Templating != nil && versions.LessThan(version, "1.37") {
|
||||
return errdefs.InvalidParameter(errors.Errorf("config templating is not supported on the specified API version: %s", version))
|
||||
}
|
||||
|
||||
id, err := sr.backend.CreateConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &basictypes.ConfigCreateResponse{
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
func (sr *swarmRouter) removeConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := sr.backend.RemoveConfig(vars["id"]); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sr *swarmRouter) getConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
config, err := sr.backend.GetConfig(vars["id"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, config)
|
||||
}
|
||||
|
||||
func (sr *swarmRouter) updateConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var config types.ConfigSpec
|
||||
if err := json.NewDecoder(r.Body).Decode(&config); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
rawVersion := r.URL.Query().Get("version")
|
||||
version, err := strconv.ParseUint(rawVersion, 10, 64)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("invalid config version"))
|
||||
}
|
||||
|
||||
id := vars["id"]
|
||||
return sr.backend.UpdateConfig(id, version, config)
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
package swarm // import "github.com/docker/docker/api/server/router/swarm"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
basictypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
)
|
||||
|
||||
// swarmLogs takes an http response, request, and selector, and writes the logs
|
||||
// specified by the selector to the response
|
||||
func (sr *swarmRouter) swarmLogs(ctx context.Context, w io.Writer, r *http.Request, selector *backend.LogSelector) error {
|
||||
// Args are validated before the stream starts because when it starts we're
|
||||
// sending HTTP 200 by writing an empty chunk of data to tell the client that
|
||||
// daemon is going to stream. By sending this initial HTTP 200 we can't report
|
||||
// any error after the stream starts (i.e. container not found, wrong parameters)
|
||||
// with the appropriate status code.
|
||||
stdout, stderr := httputils.BoolValue(r, "stdout"), httputils.BoolValue(r, "stderr")
|
||||
if !(stdout || stderr) {
|
||||
return fmt.Errorf("Bad parameters: you must choose at least one stream")
|
||||
}
|
||||
|
||||
// there is probably a neater way to manufacture the ContainerLogsOptions
|
||||
// struct, probably in the caller, to eliminate the dependency on net/http
|
||||
logsConfig := &basictypes.ContainerLogsOptions{
|
||||
Follow: httputils.BoolValue(r, "follow"),
|
||||
Timestamps: httputils.BoolValue(r, "timestamps"),
|
||||
Since: r.Form.Get("since"),
|
||||
Tail: r.Form.Get("tail"),
|
||||
ShowStdout: stdout,
|
||||
ShowStderr: stderr,
|
||||
Details: httputils.BoolValue(r, "details"),
|
||||
}
|
||||
|
||||
tty := false
|
||||
// checking for whether logs are TTY involves iterating over every service
|
||||
// and task. idk if there is a better way
|
||||
for _, service := range selector.Services {
|
||||
s, err := sr.backend.GetService(service, false)
|
||||
if err != nil {
|
||||
// maybe should return some context with this error?
|
||||
return err
|
||||
}
|
||||
tty = (s.Spec.TaskTemplate.ContainerSpec != nil && s.Spec.TaskTemplate.ContainerSpec.TTY) || tty
|
||||
}
|
||||
for _, task := range selector.Tasks {
|
||||
t, err := sr.backend.GetTask(task)
|
||||
if err != nil {
|
||||
// as above
|
||||
return err
|
||||
}
|
||||
tty = t.Spec.ContainerSpec.TTY || tty
|
||||
}
|
||||
|
||||
msgs, err := sr.backend.ServiceLogs(ctx, selector, logsConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
httputils.WriteLogStream(ctx, w, msgs, logsConfig, !tty)
|
||||
return nil
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
package system // import "github.com/docker/docker/api/server/router/system"
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Backend is the methods that need to be implemented to provide
|
||||
@@ -15,14 +14,8 @@ import (
|
||||
type Backend interface {
|
||||
SystemInfo() (*types.Info, error)
|
||||
SystemVersion() types.Version
|
||||
SystemDiskUsage(ctx context.Context) (*types.DiskUsage, error)
|
||||
SystemDiskUsage() (*types.DiskUsage, error)
|
||||
SubscribeToEvents(since, until time.Time, ef filters.Args) ([]events.Message, chan interface{})
|
||||
UnsubscribeFromEvents(chan interface{})
|
||||
AuthenticateToRegistry(ctx context.Context, authConfig *types.AuthConfig) (string, string, error)
|
||||
}
|
||||
|
||||
// ClusterBackend is all the methods that need to be implemented
|
||||
// to provide cluster system specific functionality.
|
||||
type ClusterBackend interface {
|
||||
Info() swarm.Info
|
||||
}
|
||||
|
||||
@@ -1,39 +1,32 @@
|
||||
package system // import "github.com/docker/docker/api/server/router/system"
|
||||
package system
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/builder/builder-next"
|
||||
"github.com/docker/docker/builder/fscache"
|
||||
"github.com/docker/docker/daemon/cluster"
|
||||
)
|
||||
|
||||
// systemRouter provides information about the Docker system overall.
|
||||
// It gathers information about host, daemon and container events.
|
||||
type systemRouter struct {
|
||||
backend Backend
|
||||
cluster ClusterBackend
|
||||
routes []router.Route
|
||||
fscache *fscache.FSCache // legacy
|
||||
builder *buildkit.Builder
|
||||
features *map[string]bool
|
||||
backend Backend
|
||||
clusterProvider *cluster.Cluster
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// NewRouter initializes a new system router
|
||||
func NewRouter(b Backend, c ClusterBackend, fscache *fscache.FSCache, builder *buildkit.Builder, features *map[string]bool) router.Router {
|
||||
func NewRouter(b Backend, c *cluster.Cluster) router.Router {
|
||||
r := &systemRouter{
|
||||
backend: b,
|
||||
cluster: c,
|
||||
fscache: fscache,
|
||||
builder: builder,
|
||||
features: features,
|
||||
backend: b,
|
||||
clusterProvider: c,
|
||||
}
|
||||
|
||||
r.routes = []router.Route{
|
||||
router.NewOptionsRoute("/{anyroute:.*}", optionsHandler),
|
||||
router.NewGetRoute("/_ping", r.pingHandler),
|
||||
router.NewGetRoute("/events", r.getEvents, router.WithCancel),
|
||||
router.NewGetRoute("/_ping", pingHandler),
|
||||
router.Cancellable(router.NewGetRoute("/events", r.getEvents)),
|
||||
router.NewGetRoute("/info", r.getInfo),
|
||||
router.NewGetRoute("/version", r.getVersion),
|
||||
router.NewGetRoute("/system/df", r.getDiskUsage, router.WithCancel),
|
||||
router.NewGetRoute("/system/df", r.getDiskUsage),
|
||||
router.NewPostRoute("/auth", r.postAuth),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package system // import "github.com/docker/docker/api/server/router/system"
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/router/build"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
@@ -16,9 +17,7 @@ import (
|
||||
timetypes "github.com/docker/docker/api/types/time"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
pkgerrors "github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -26,11 +25,7 @@ func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *systemRouter) pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
builderVersion := build.BuilderVersion(*s.features)
|
||||
if bv := builderVersion; bv != "" {
|
||||
w.Header().Set("Builder-Version", string(bv))
|
||||
}
|
||||
func pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
_, err := w.Write([]byte{'O', 'K'})
|
||||
return err
|
||||
}
|
||||
@@ -40,8 +35,8 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.cluster != nil {
|
||||
info.Swarm = s.cluster.Info()
|
||||
if s.clusterProvider != nil {
|
||||
info.Swarm = s.clusterProvider.Info()
|
||||
}
|
||||
|
||||
if versions.LessThan(httputils.VersionFromContext(ctx), "1.25") {
|
||||
@@ -65,77 +60,25 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht
|
||||
old.SecurityOptions = nameOnlySecurityOptions
|
||||
return httputils.WriteJSON(w, http.StatusOK, old)
|
||||
}
|
||||
if versions.LessThan(httputils.VersionFromContext(ctx), "1.39") {
|
||||
if info.KernelVersion == "" {
|
||||
info.KernelVersion = "<unknown>"
|
||||
}
|
||||
if info.OperatingSystem == "" {
|
||||
info.OperatingSystem = "<unknown>"
|
||||
}
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, info)
|
||||
}
|
||||
|
||||
func (s *systemRouter) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
info := s.backend.SystemVersion()
|
||||
info.APIVersion = api.DefaultVersion
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, info)
|
||||
}
|
||||
|
||||
func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
var du *types.DiskUsage
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
du, err = s.backend.SystemDiskUsage(ctx)
|
||||
return err
|
||||
})
|
||||
|
||||
var builderSize int64 // legacy
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
builderSize, err = s.fscache.DiskUsage(ctx)
|
||||
if err != nil {
|
||||
return pkgerrors.Wrap(err, "error getting fscache build cache usage")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
var buildCache []*types.BuildCache
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
buildCache, err = s.builder.DiskUsage(ctx)
|
||||
if err != nil {
|
||||
return pkgerrors.Wrap(err, "error getting build cache usage")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err := eg.Wait(); err != nil {
|
||||
du, err := s.backend.SystemDiskUsage()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, b := range buildCache {
|
||||
builderSize += b.Size
|
||||
}
|
||||
|
||||
du.BuilderSize = builderSize
|
||||
du.BuildCache = buildCache
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, du)
|
||||
}
|
||||
|
||||
type invalidRequestError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e invalidRequestError) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
func (e invalidRequestError) InvalidParameter() {}
|
||||
|
||||
func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
@@ -156,7 +99,7 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
||||
)
|
||||
if !until.IsZero() {
|
||||
if until.Before(since) {
|
||||
return invalidRequestError{fmt.Errorf("`since` time (%s) cannot be after `until` time (%s)", r.Form.Get("since"), r.Form.Get("until"))}
|
||||
return errors.NewBadRequestError(fmt.Errorf("`since` time (%s) cannot be after `until` time (%s)", r.Form.Get("since"), r.Form.Get("until")))
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
@@ -165,11 +108,11 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
||||
|
||||
if !onlyPastEvents {
|
||||
dur := until.Sub(now)
|
||||
timeout = time.After(dur)
|
||||
timeout = time.NewTimer(dur).C
|
||||
}
|
||||
}
|
||||
|
||||
ef, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
ef, err := filters.FromParam(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package volume // import "github.com/docker/docker/api/server/router/volume"
|
||||
package volume
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/volume/service/opts"
|
||||
// TODO return types need to be refactored into pkg
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
@@ -12,9 +9,9 @@ import (
|
||||
// Backend is the methods that need to be implemented to provide
|
||||
// volume specific functionality
|
||||
type Backend interface {
|
||||
List(ctx context.Context, filter filters.Args) ([]*types.Volume, []string, error)
|
||||
Get(ctx context.Context, name string, opts ...opts.GetOption) (*types.Volume, error)
|
||||
Create(ctx context.Context, name, driverName string, opts ...opts.CreateOption) (*types.Volume, error)
|
||||
Remove(ctx context.Context, name string, opts ...opts.RemoveOption) error
|
||||
Prune(ctx context.Context, pruneFilters filters.Args) (*types.VolumesPruneReport, error)
|
||||
Volumes(filter string) ([]*types.Volume, []string, error)
|
||||
VolumeInspect(name string) (*types.Volume, error)
|
||||
VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error)
|
||||
VolumeRm(name string, force bool) error
|
||||
VolumesPrune(pruneFilters filters.Args) (*types.VolumesPruneReport, error)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package volume // import "github.com/docker/docker/api/server/router/volume"
|
||||
package volume
|
||||
|
||||
import "github.com/docker/docker/api/server/router"
|
||||
|
||||
@@ -29,7 +29,7 @@ func (r *volumeRouter) initRoutes() {
|
||||
router.NewGetRoute("/volumes/{name:.*}", r.getVolumeByName),
|
||||
// POST
|
||||
router.NewPostRoute("/volumes/create", r.postVolumesCreate),
|
||||
router.NewPostRoute("/volumes/prune", r.postVolumesPrune, router.WithCancel),
|
||||
router.NewPostRoute("/volumes/prune", r.postVolumesPrune),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/volumes/{name:.*}", r.deleteVolumes),
|
||||
}
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
package volume // import "github.com/docker/docker/api/server/router/volume"
|
||||
package volume
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
volumetypes "github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/volume/service/opts"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (v *volumeRouter) getVolumesList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -19,15 +15,11 @@ func (v *volumeRouter) getVolumesList(ctx context.Context, w http.ResponseWriter
|
||||
return err
|
||||
}
|
||||
|
||||
filters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(errors.Wrap(err, "error reading volume filters"))
|
||||
}
|
||||
volumes, warnings, err := v.backend.List(ctx, filters)
|
||||
volumes, warnings, err := v.backend.Volumes(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, &volumetypes.VolumeListOKBody{Volumes: volumes, Warnings: warnings})
|
||||
return httputils.WriteJSON(w, http.StatusOK, &volumetypes.VolumesListOKBody{Volumes: volumes, Warnings: warnings})
|
||||
}
|
||||
|
||||
func (v *volumeRouter) getVolumeByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -35,7 +27,7 @@ func (v *volumeRouter) getVolumeByName(ctx context.Context, w http.ResponseWrite
|
||||
return err
|
||||
}
|
||||
|
||||
volume, err := v.backend.Get(ctx, vars["name"], opts.WithGetResolveStatus)
|
||||
volume, err := v.backend.VolumeInspect(vars["name"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -51,15 +43,12 @@ func (v *volumeRouter) postVolumesCreate(ctx context.Context, w http.ResponseWri
|
||||
return err
|
||||
}
|
||||
|
||||
var req volumetypes.VolumeCreateBody
|
||||
var req volumetypes.VolumesCreateBody
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
if err == io.EOF {
|
||||
return errdefs.InvalidParameter(errors.New("got EOF while reading request body"))
|
||||
}
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
|
||||
volume, err := v.backend.Create(ctx, req.Name, req.Driver, opts.WithCreateOptions(req.DriverOpts), opts.WithCreateLabels(req.Labels))
|
||||
volume, err := v.backend.VolumeCreate(req.Name, req.Driver, req.DriverOpts, req.Labels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -71,7 +60,7 @@ func (v *volumeRouter) deleteVolumes(ctx context.Context, w http.ResponseWriter,
|
||||
return err
|
||||
}
|
||||
force := httputils.BoolValue(r, "force")
|
||||
if err := v.backend.Remove(ctx, vars["name"], opts.WithPurgeOnError(force)); err != nil {
|
||||
if err := v.backend.VolumeRm(vars["name"], force); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
@@ -83,12 +72,7 @@ func (v *volumeRouter) postVolumesPrune(ctx context.Context, w http.ResponseWrit
|
||||
return err
|
||||
}
|
||||
|
||||
pruneFilters, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pruneReport, err := v.backend.Prune(ctx, pruneFilters)
|
||||
pruneReport, err := v.backend.VolumesPrune(filters.Args{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package server // import "github.com/docker/docker/api/server"
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package server // import "github.com/docker/docker/api/server"
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/middleware"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/api/server/router/debug"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// versionMatcher defines a variable matcher to be parsed by the router
|
||||
@@ -23,6 +23,7 @@ const versionMatcher = "/v{version:[0-9.]+}"
|
||||
// Config provides the configuration for the API server
|
||||
type Config struct {
|
||||
Logging bool
|
||||
EnableCors bool
|
||||
CorsHeaders string
|
||||
Version string
|
||||
SocketGroup string
|
||||
@@ -90,12 +91,13 @@ func (s *Server) serveAPI() error {
|
||||
}(srv)
|
||||
}
|
||||
|
||||
for range s.servers {
|
||||
for i := 0; i < len(s.servers); i++ {
|
||||
err := <-chErrors
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -126,11 +128,7 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
|
||||
// apply to all requests. Data that is specific to the
|
||||
// immediate function being called should still be passed
|
||||
// as 'args' on the function call.
|
||||
|
||||
// use intermediate variable to prevent "should not use basic type
|
||||
// string as key in context.WithValue" golint errors
|
||||
var ki interface{} = dockerversion.UAStringKey
|
||||
ctx := context.WithValue(context.Background(), ki, r.Header.Get("User-Agent"))
|
||||
ctx := context.WithValue(context.Background(), httputils.UAStringKey, r.Header.Get("User-Agent"))
|
||||
handlerFunc := s.handlerWithGlobalMiddlewares(handler)
|
||||
|
||||
vars := mux.Vars(r)
|
||||
@@ -140,33 +138,30 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
|
||||
|
||||
if err := handlerFunc(ctx, w, r, vars); err != nil {
|
||||
statusCode := httputils.GetHTTPErrorStatusCode(err)
|
||||
if statusCode >= 500 {
|
||||
logrus.Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
|
||||
errFormat := "%v"
|
||||
if statusCode == http.StatusInternalServerError {
|
||||
errFormat = "%+v"
|
||||
}
|
||||
logrus.Errorf("Handler for %s %s returned error: "+errFormat, r.Method, r.URL.Path, err)
|
||||
httputils.MakeErrorHandler(err)(w, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InitRouter initializes the list of routers for the server.
|
||||
// This method also enables the Go profiler.
|
||||
func (s *Server) InitRouter(routers ...router.Router) {
|
||||
// This method also enables the Go profiler if enableProfiler is true.
|
||||
func (s *Server) InitRouter(enableProfiler bool, routers ...router.Router) {
|
||||
s.routers = append(s.routers, routers...)
|
||||
|
||||
m := s.createMux()
|
||||
if enableProfiler {
|
||||
profilerSetup(m)
|
||||
}
|
||||
s.routerSwapper = &routerSwapper{
|
||||
router: m,
|
||||
}
|
||||
}
|
||||
|
||||
type pageNotFoundError struct{}
|
||||
|
||||
func (pageNotFoundError) Error() string {
|
||||
return "page not found"
|
||||
}
|
||||
|
||||
func (pageNotFoundError) NotFound() {}
|
||||
|
||||
// createMux initializes the main router the server uses.
|
||||
func (s *Server) createMux() *mux.Router {
|
||||
m := mux.NewRouter()
|
||||
@@ -182,14 +177,8 @@ func (s *Server) createMux() *mux.Router {
|
||||
}
|
||||
}
|
||||
|
||||
debugRouter := debug.NewRouter()
|
||||
s.routers = append(s.routers, debugRouter)
|
||||
for _, r := range debugRouter.Routes() {
|
||||
f := s.makeHTTPHandler(r.Handler())
|
||||
m.Path("/debug" + r.Path()).Handler(f)
|
||||
}
|
||||
|
||||
notFoundHandler := httputils.MakeErrorHandler(pageNotFoundError{})
|
||||
err := errors.NewRequestNotFoundError(fmt.Errorf("page not found"))
|
||||
notFoundHandler := httputils.MakeErrorHandler(err)
|
||||
m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler)
|
||||
m.NotFoundHandler = notFoundHandler
|
||||
|
||||
@@ -207,3 +196,15 @@ func (s *Server) Wait(waitChan chan error) {
|
||||
}
|
||||
waitChan <- nil
|
||||
}
|
||||
|
||||
// DisableProfiler reloads the server mux without adding the profiler routes.
|
||||
func (s *Server) DisableProfiler() {
|
||||
s.routerSwapper.Swap(s.createMux())
|
||||
}
|
||||
|
||||
// EnableProfiler reloads the server mux adding the profiler routes.
|
||||
func (s *Server) EnableProfiler() {
|
||||
m := s.createMux()
|
||||
profilerSetup(m)
|
||||
s.routerSwapper.Swap(m)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user