Compare commits
4719 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
801fd16e3e | ||
![]() |
6667e96dad | ||
![]() |
ee8b788538 | ||
![]() |
96c9353e9b | ||
![]() |
ab570ab3d6 | ||
![]() |
7532420f3b | ||
![]() |
a4d5b6b4d0 | ||
![]() |
e829cca0ee | ||
![]() |
82d8f8d6e6 | ||
![]() |
6c68be24a2 | ||
![]() |
b7c059886c | ||
![]() |
745e2356ab | ||
![]() |
29f24a828b | ||
![]() |
0d6a1a212b | ||
![]() |
f5209d23a8 | ||
![]() |
442f29a699 | ||
![]() |
f07644e17e | ||
![]() |
d3c051318f | ||
![]() |
5368c3a04f | ||
![]() |
8d5d655db0 | ||
![]() |
f51e18f58e | ||
![]() |
57dd56726a | ||
![]() |
f9dfd139ec | ||
![]() |
051d587447 | ||
![]() |
9954d7c6bd | ||
![]() |
cd7240f6d9 | ||
![]() |
17b8631545 | ||
![]() |
8383c487c6 | ||
![]() |
7a54a16740 | ||
![]() |
2fabb28813 | ||
![]() |
5ae5969739 | ||
![]() |
3485cfbb1e | ||
![]() |
3b81ca4969 | ||
![]() |
80572929e1 | ||
![]() |
fb92caf2aa | ||
![]() |
61269e718f | ||
![]() |
d25b0bd7ea | ||
![]() |
d8b768149b | ||
![]() |
6d30487d2e | ||
![]() |
329d403e20 | ||
![]() |
d66589496e | ||
![]() |
e1ca74361b | ||
![]() |
cf933115b6 | ||
![]() |
9fa76786ab | ||
![]() |
9160b9fda6 | ||
![]() |
8599f2a3fb | ||
![]() |
0a48d26fbc | ||
![]() |
330a6f959f | ||
![]() |
c4689034fd | ||
![]() |
4eed3dcdfe | ||
![]() |
c187f95fe1 | ||
![]() |
a33b302d54 | ||
![]() |
484480f56a | ||
![]() |
aff003139c | ||
![]() |
1014f481de | ||
![]() |
d57b899904 | ||
![]() |
fde80fe2e7 | ||
![]() |
bfdb8918f9 | ||
![]() |
83ae9927fb | ||
![]() |
14a8fac092 | ||
![]() |
59c5059081 | ||
![]() |
1552e30a05 | ||
![]() |
c64314fd55 | ||
![]() |
61e2199b78 | ||
![]() |
ea72f9f72c | ||
![]() |
8b79278316 | ||
![]() |
22726fb63b | ||
![]() |
963e1f3eed | ||
![]() |
3312b82515 | ||
![]() |
ad8a5a5732 | ||
![]() |
0c2d83b5fb | ||
![]() |
f696e0d2a7 | ||
![]() |
330d777c53 | ||
![]() |
3d2a56e7cf | ||
![]() |
4531a371f2 | ||
![]() |
731a64069f | ||
![]() |
dade279565 | ||
![]() |
23e1af45c6 | ||
![]() |
e7c60a30e6 | ||
![]() |
641e341eed | ||
![]() |
dd146571ea | ||
![]() |
fe70ee9477 | ||
![]() |
307962dbd5 | ||
![]() |
7e56442cee | ||
![]() |
ebf300c165 | ||
![]() |
2e4ebf032a | ||
![]() |
153de36b3f | ||
![]() |
4ff655f4b8 | ||
![]() |
1c03312378 | ||
![]() |
f512dba037 | ||
![]() |
89dc2860ba | ||
![]() |
6f3892dc99 | ||
![]() |
a9bca45e92 | ||
![]() |
fe8fb9b9a1 | ||
![]() |
70e46f2c7c | ||
![]() |
23339a6147 | ||
![]() |
4bd30829d1 | ||
![]() |
971562b005 | ||
![]() |
d742659877 | ||
![]() |
4f46c44725 | ||
![]() |
1f539a6e85 | ||
![]() |
959c2ee6cf | ||
![]() |
25c9e6e8df | ||
![]() |
762ec4b60c | ||
![]() |
979f03f9f6 | ||
![]() |
7b414f5703 | ||
![]() |
ff05850e7e | ||
![]() |
cdf70c0a51 | ||
![]() |
40c681355e | ||
![]() |
790c3039d0 | ||
![]() |
10bdc7136c | ||
![]() |
a8abb67c5e | ||
![]() |
1ca89d7eae | ||
![]() |
f40bdf5f63 | ||
![]() |
3f73d23ea0 | ||
![]() |
77b05b97f4 | ||
![]() |
e3bc82f7d4 | ||
![]() |
342923b01c | ||
![]() |
15122b3b1c | ||
![]() |
388ecf65bc | ||
![]() |
bb3ab1edb7 | ||
![]() |
da245cab15 | ||
![]() |
1cfd763214 | ||
![]() |
0ce714a085 | ||
![]() |
bcb4794eea | ||
![]() |
0d5ef431a1 | ||
![]() |
03cddc62f4 | ||
![]() |
825635a5bf | ||
![]() |
ec19fd6fed | ||
![]() |
d19f6d4b6d | ||
![]() |
b8165a9cd1 | ||
![]() |
a6a445d86b | ||
![]() |
0fb845858d | ||
![]() |
db2263749b | ||
![]() |
1abf17c779 | ||
![]() |
294fc9762e | ||
![]() |
eef352b565 | ||
![]() |
f4c696eef1 | ||
![]() |
5a009cdd5b | ||
![]() |
2f1a32e3e5 | ||
![]() |
72f1f82f28 | ||
![]() |
52a80b40e2 | ||
![]() |
288a14e264 | ||
![]() |
b37ced2551 | ||
![]() |
a535a65c4b | ||
![]() |
582de4bc3c | ||
![]() |
a6e7e67d3a | ||
![]() |
1b108bdfeb | ||
![]() |
74e2f23e1a | ||
![]() |
e8496b1ee4 | ||
![]() |
d66177591e | ||
![]() |
bf30fee58a | ||
![]() |
608d77d740 | ||
![]() |
66adfc729a | ||
![]() |
ab4b5a4890 | ||
![]() |
f5a5e3f203 | ||
![]() |
773f792b88 | ||
![]() |
4adc40ac40 | ||
![]() |
8921897e3b | ||
![]() |
37545cc644 | ||
![]() |
6c10086976 | ||
![]() |
ef5295cda4 | ||
![]() |
49b77753cb | ||
![]() |
d91665a2ac | ||
![]() |
4e53936f0a | ||
![]() |
cb8c8e9631 | ||
![]() |
c4fc6c3371 | ||
![]() |
0f30791a0d | ||
![]() |
4e8d9a4522 | ||
![]() |
7c7e453255 | ||
![]() |
06628e383a | ||
![]() |
4046928978 | ||
![]() |
21835a5696 | ||
![]() |
b32cfc3b3a | ||
![]() |
49fd8df9b9 | ||
![]() |
72ec187dfe | ||
![]() |
83cda67f73 | ||
![]() |
460b4aebdf | ||
![]() |
57b7ffa7f6 | ||
![]() |
cadb124ab6 | ||
![]() |
046827c657 | ||
![]() |
04c9d7f6a3 | ||
![]() |
b2921509e5 | ||
![]() |
f04f69e366 | ||
![]() |
7f69142aa0 | ||
![]() |
97a5435d33 | ||
![]() |
91d9307738 | ||
![]() |
12dea3fa9e | ||
![]() |
137a9d6a4c | ||
![]() |
9f4e824a6e | ||
![]() |
f8e6801533 | ||
![]() |
ef681124ca | ||
![]() |
7ebd88d2d9 | ||
![]() |
4f30a930ad | ||
![]() |
a580544d82 | ||
![]() |
b8aa8579ca | ||
![]() |
225ccc0cfd | ||
![]() |
d19d98b136 | ||
![]() |
ebf3f8c7fe | ||
![]() |
a242208be3 | ||
![]() |
2af2496c8c | ||
![]() |
fc0e5401f2 | ||
![]() |
8517c3386c | ||
![]() |
6c3b3523c9 | ||
![]() |
d40b140c08 | ||
![]() |
81428bf11b | ||
![]() |
230cb53d3b | ||
![]() |
7b0ab1011c | ||
![]() |
3ca1d751e5 | ||
![]() |
589dc5e647 | ||
![]() |
62b33a2604 | ||
![]() |
5fe96e234d | ||
![]() |
84eecc4a30 | ||
![]() |
261dccc98a | ||
![]() |
2c9c5e1c03 | ||
![]() |
b649e272bb | ||
![]() |
e4de4dea5c | ||
![]() |
b37f8c8070 | ||
![]() |
9be820d8ca | ||
![]() |
f6fa6ff9ed | ||
![]() |
220835106b | ||
![]() |
2c25ca9dba | ||
![]() |
94f9f39b24 | ||
![]() |
da643c0b8a | ||
![]() |
9083c2f10d | ||
![]() |
44167988c3 | ||
![]() |
2d31532a00 | ||
![]() |
60358bfcab | ||
![]() |
f5722da5e0 | ||
![]() |
951e42cd60 | ||
![]() |
e01a1c5d09 | ||
![]() |
fa467caf4d | ||
![]() |
59ad1690f7 | ||
![]() |
b04a2dad6b | ||
![]() |
bc6d88c09a | ||
![]() |
a79bb1e832 | ||
![]() |
e68f71259a | ||
![]() |
dd6992617e | ||
![]() |
31545c3b67 | ||
![]() |
f90b03ee5d | ||
![]() |
16aa7dd67f | ||
![]() |
8cdb5a9070 | ||
![]() |
ffd294ebcc | ||
![]() |
881260148f | ||
![]() |
432390320e | ||
![]() |
c70d7905fb | ||
![]() |
0eecd59153 | ||
![]() |
6aea26b431 | ||
![]() |
913478b428 | ||
![]() |
901b90593d | ||
![]() |
349abc64ed | ||
![]() |
24fe934a7b | ||
![]() |
05b883bdc8 | ||
![]() |
c516804d6f | ||
![]() |
445d500aeb | ||
![]() |
1ffaf469ba | ||
![]() |
842d1b3c12 | ||
![]() |
83c02f7a11 | ||
![]() |
14df52b709 | ||
![]() |
ff5f780f2b | ||
![]() |
5689dabfb3 | ||
![]() |
7d081179e9 | ||
![]() |
3865c63d45 | ||
![]() |
1d473549e8 | ||
![]() |
b2aaf5c2b0 | ||
![]() |
cbd45e83cf | ||
![]() |
cba87125b2 | ||
![]() |
2a41ce93fe | ||
![]() |
c42ae61e62 | ||
![]() |
d9e082ff54 | ||
![]() |
8761bffcaf | ||
![]() |
56aeb548b2 | ||
![]() |
38827ba290 | ||
![]() |
9d1541526c | ||
![]() |
7bf8d2606e | ||
![]() |
bf053be997 | ||
![]() |
101241c804 | ||
![]() |
bddd892e91 | ||
![]() |
2aa13e950d | ||
![]() |
70a4a9c969 | ||
![]() |
a0f12f96eb | ||
![]() |
3d354593c9 | ||
![]() |
9faf4855d5 | ||
![]() |
4eb95d01bc | ||
![]() |
7c2975d2df | ||
![]() |
903412d0fc | ||
![]() |
b8a71a1c44 | ||
![]() |
443f56efb0 | ||
![]() |
b4fbe226e8 | ||
![]() |
5bcd2f6860 | ||
![]() |
999f90ac1c | ||
![]() |
a60546b084 | ||
![]() |
ef7766304c | ||
![]() |
6932939326 | ||
![]() |
10a72f2504 | ||
![]() |
a60fef0c41 | ||
![]() |
86b86412a1 | ||
![]() |
03a17a2887 | ||
![]() |
a26c953b94 | ||
![]() |
571af915d5 | ||
![]() |
97478c99f8 | ||
![]() |
b71c2792d2 | ||
![]() |
57e8352c9e | ||
![]() |
4ab11a1148 | ||
![]() |
23d80f729e | ||
![]() |
419f5a6372 | ||
![]() |
475019d70a | ||
![]() |
63c354aae2 | ||
![]() |
9e075f3808 | ||
![]() |
beb97f7fdf | ||
![]() |
d2f12e6d51 | ||
![]() |
14503ccebd | ||
![]() |
e1897cbde4 | ||
![]() |
0fef6e1c99 | ||
![]() |
6b01719ffb | ||
![]() |
19a04efa2f | ||
![]() |
8758d08bb4 | ||
![]() |
ffd877f948 | ||
![]() |
b3a0ff9944 | ||
![]() |
83f790cccc | ||
![]() |
d1974aa492 | ||
![]() |
ed93110e11 | ||
![]() |
570d5a9645 | ||
![]() |
f0dd554e3c | ||
![]() |
dfdf2adf0c | ||
![]() |
2970b320aa | ||
![]() |
ef25f0aa52 | ||
![]() |
7fa116830b | ||
![]() |
1b1147e46b | ||
![]() |
d26bdfe226 | ||
![]() |
f1e6958295 | ||
![]() |
27ac2beca0 | ||
![]() |
9e10605e77 | ||
![]() |
2c01d53d96 | ||
![]() |
d69729e053 | ||
![]() |
10d344d176 | ||
![]() |
df57a080b6 | ||
![]() |
8826f402f9 | ||
![]() |
6f242f1a28 | ||
![]() |
4d0d5ee10d | ||
![]() |
1251982cf7 | ||
![]() |
203ffb1c09 | ||
![]() |
cae5d323e1 | ||
![]() |
7f1b700227 | ||
![]() |
f1730a6512 | ||
![]() |
f7192bb0b4 | ||
![]() |
2156635843 | ||
![]() |
91ea04089b | ||
![]() |
2ef0b53e51 | ||
![]() |
6b83319773 | ||
![]() |
ee3c710f22 | ||
![]() |
74d51e8553 | ||
![]() |
e910a79e2b | ||
![]() |
9fcea5b933 | ||
![]() |
e61c425cc2 | ||
![]() |
10d6f5213a | ||
![]() |
9c92c07acf | ||
![]() |
0616b4190e | ||
![]() |
89470a7114 | ||
![]() |
701dd989f1 | ||
![]() |
7c4828f8fb | ||
![]() |
7964cae9e8 | ||
![]() |
e37172c613 | ||
![]() |
c59e93a67b | ||
![]() |
83af50aee3 | ||
![]() |
4d7c11c208 | ||
![]() |
8070a9aa66 | ||
![]() |
ca683c1c77 | ||
![]() |
025967efd0 | ||
![]() |
add2c4c79b | ||
![]() |
8604cc400d | ||
![]() |
e240ba44b7 | ||
![]() |
82dda18898 | ||
![]() |
dd20bf4862 | ||
![]() |
f5cf22ca99 | ||
![]() |
0c3b8ccda7 | ||
![]() |
810ef4d0b6 | ||
![]() |
2cc627932a | ||
![]() |
968f05910a | ||
![]() |
8c64b85fb9 | ||
![]() |
dae33031e0 | ||
![]() |
a2026ee442 | ||
![]() |
5a3c463a37 | ||
![]() |
9babc02283 | ||
![]() |
a83557d747 | ||
![]() |
2200c0137f | ||
![]() |
d21d0884ae | ||
![]() |
3e230cfdcc | ||
![]() |
f42b8ae8db | ||
![]() |
7a920fd275 | ||
![]() |
584e60e820 | ||
![]() |
8ee908e47c | ||
![]() |
835cdcac95 | ||
![]() |
f4a93b6993 | ||
![]() |
b20dccba5e | ||
![]() |
44bf407d4d | ||
![]() |
8a81b9d35f | ||
![]() |
ecb217cf69 | ||
![]() |
2df4755725 | ||
![]() |
3a8191225a | ||
![]() |
08251978a8 | ||
![]() |
5d396e0533 | ||
![]() |
4a1839ef1d | ||
![]() |
b7fd571b0a | ||
![]() |
00a2626b56 | ||
![]() |
e27a785f43 | ||
![]() |
fb53ee6ba3 | ||
![]() |
0ffddc6bb8 | ||
![]() |
987fe37ed1 | ||
![]() |
d53b7d7e46 | ||
![]() |
39c5c16521 | ||
![]() |
5792bf7ab3 | ||
![]() |
982e777d49 | ||
![]() |
f472dda2e9 | ||
![]() |
ca40ac030c | ||
![]() |
0818a476e5 | ||
![]() |
a0b53f6fd2 | ||
![]() |
2ddec74d59 | ||
![]() |
794f7127ef | ||
![]() |
5e13f54f57 | ||
![]() |
d131f00fff | ||
![]() |
7d4ee14147 | ||
![]() |
0f507ef624 | ||
![]() |
21136865ac | ||
![]() |
a8e8a4cdad | ||
![]() |
6ee58c2d29 | ||
![]() |
905477c8ae | ||
![]() |
d70fe8803c | ||
![]() |
e94ec8068d | ||
![]() |
71bfffdad1 | ||
![]() |
931568032a | ||
![]() |
ee6cbc540e | ||
![]() |
6d34bb71a0 | ||
![]() |
388ba9a69c | ||
![]() |
3eb1527fdb | ||
![]() |
93861bb5e6 | ||
![]() |
7f94acb6ab | ||
![]() |
97a5614d23 | ||
![]() |
5c2eda6f71 | ||
![]() |
96d461d27e | ||
![]() |
877ebbe038 | ||
![]() |
96ac22768a | ||
![]() |
c6156dc51b | ||
![]() |
537348763f | ||
![]() |
c7b3cb101b | ||
![]() |
69d2923e4e | ||
![]() |
86198815a2 | ||
![]() |
d864df5a1d | ||
![]() |
bd4ff31775 | ||
![]() |
e245fb76de | ||
![]() |
3147a013fb | ||
![]() |
f7ef0e9fc7 | ||
![]() |
e8346c53d9 | ||
![]() |
3a617e5463 | ||
![]() |
43ffb1ee9d | ||
![]() |
115c7673dc | ||
![]() |
f7e2357745 | ||
![]() |
314ea05f8d | ||
![]() |
13f46948dd | ||
![]() |
4b09bc2145 | ||
![]() |
49637d0206 | ||
![]() |
eccb1a3eb8 | ||
![]() |
0b1921649f | ||
![]() |
4544bedea3 | ||
![]() |
6f44138269 | ||
![]() |
9a41cc58d9 | ||
![]() |
ac2a028dcc | ||
![]() |
8906adc8d4 | ||
![]() |
0bb84f5cef | ||
![]() |
80c44b4b2e | ||
![]() |
2da96d6c12 | ||
![]() |
0b64499a24 | ||
![]() |
9763709c05 | ||
![]() |
250886741b | ||
![]() |
f4beb130b0 | ||
![]() |
df43311f3d | ||
![]() |
9f37672ca8 | ||
![]() |
c25773ecbf | ||
![]() |
f19f233ca5 | ||
![]() |
ca67dbd12c | ||
![]() |
cac52f7173 | ||
![]() |
00c9785e2e | ||
![]() |
0d51cf9db8 | ||
![]() |
1786517338 | ||
![]() |
22a504935f | ||
![]() |
05d952b246 | ||
![]() |
d86d24de35 | ||
![]() |
20bd690844 | ||
![]() |
34668a5945 | ||
![]() |
1090aaaedd | ||
![]() |
c482383458 | ||
![]() |
43bf65c174 | ||
![]() |
a3a42c459e | ||
![]() |
c87e0ad209 | ||
![]() |
cd53b7380c | ||
![]() |
fb19f1fc20 | ||
![]() |
3602ba0afd | ||
![]() |
f0eef50273 | ||
![]() |
b6a5c2968b | ||
![]() |
6100190e5c | ||
![]() |
17fd6562bf | ||
![]() |
4979605212 | ||
![]() |
fcc651972e | ||
![]() |
42a07883f7 | ||
![]() |
5a3a101af2 | ||
![]() |
6803dd8c90 | ||
![]() |
82acb922cb | ||
![]() |
e5dbe10e65 | ||
![]() |
8528ed3409 | ||
![]() |
570b8a794c | ||
![]() |
5ad5334c2e | ||
![]() |
417826376f | ||
![]() |
e30610aaa3 | ||
![]() |
a0466ca8e1 | ||
![]() |
13a384a6fa | ||
![]() |
52e3fff828 | ||
![]() |
521123944a | ||
![]() |
d54be2ee6d | ||
![]() |
64a6cc3afd | ||
![]() |
a88cd68d3e | ||
![]() |
27e85c7b68 | ||
![]() |
a404017a86 | ||
![]() |
41a2aa2ee2 | ||
![]() |
2799417da1 | ||
![]() |
407ad89ff0 | ||
![]() |
94b4765363 | ||
![]() |
c5187380d8 | ||
![]() |
0a9bc3b507 | ||
![]() |
17c3829528 | ||
![]() |
058b30023f | ||
![]() |
dfdd5169a2 | ||
![]() |
844ca49743 | ||
![]() |
2767d9ba05 | ||
![]() |
f16a2179a6 | ||
![]() |
e2086b941f | ||
![]() |
f07c45e4f2 | ||
![]() |
307fe9c716 | ||
![]() |
dfced4b557 | ||
![]() |
75fd873fe6 | ||
![]() |
c655b7dc78 | ||
![]() |
a8f7c5ee48 | ||
![]() |
0046b16d87 | ||
![]() |
31ccdbb7a8 | ||
![]() |
5bbcc41c20 | ||
![]() |
cb1af229f2 | ||
![]() |
349a52b279 | ||
![]() |
42afac91d7 | ||
![]() |
5841ed4e5e | ||
![]() |
56bb143a4d | ||
![]() |
3784316d46 | ||
![]() |
9a0cde66ba | ||
![]() |
bfb810445c | ||
![]() |
f2e1105056 | ||
![]() |
f07387466a | ||
![]() |
9c8752505f | ||
![]() |
17d80442cc | ||
![]() |
d35e923a4c | ||
![]() |
67de5c84d3 | ||
![]() |
5bcbedb7ee | ||
![]() |
35789fce99 | ||
![]() |
7c1914411f | ||
![]() |
5581efe7cd | ||
![]() |
66cf6e3a7a | ||
![]() |
4a40d10b60 | ||
![]() |
c72e458a72 | ||
![]() |
768146b1b0 | ||
![]() |
615dfdf672 | ||
![]() |
7cbf01b994 | ||
![]() |
05695c2458 | ||
![]() |
ae6468b4b9 | ||
![]() |
c183fcf116 | ||
![]() |
982f85b281 | ||
![]() |
bd481592ff | ||
![]() |
ed15f1d717 | ||
![]() |
4f9c865edd | ||
![]() |
436bf27e6c | ||
![]() |
038729a7ab | ||
![]() |
8b0468e9ee | ||
![]() |
568c064795 | ||
![]() |
e8f4bfb374 | ||
![]() |
ec041193f9 | ||
![]() |
66325f7271 | ||
![]() |
0dc07ccc3a | ||
![]() |
a1f6b64e24 | ||
![]() |
efadb70ef8 | ||
![]() |
641050c93f | ||
![]() |
83de55b370 | ||
![]() |
508a2d979a | ||
![]() |
1fd682930a | ||
![]() |
f7065ab207 | ||
![]() |
84d2229ffe | ||
![]() |
7d08d84b03 | ||
![]() |
ae9fbcb82c | ||
![]() |
bdc7d0c2db | ||
![]() |
8390bc5683 | ||
![]() |
f760cb4f97 | ||
![]() |
a5a15c7782 | ||
![]() |
71ebfc7c63 | ||
![]() |
af4f6c124d | ||
![]() |
60ed73bb91 | ||
![]() |
d3e08fe3cf | ||
![]() |
24da5233dd | ||
![]() |
d22c775e04 | ||
![]() |
fa4deb02af | ||
![]() |
97d32bb7d7 | ||
![]() |
2c47a6df0d | ||
![]() |
353bccdf22 | ||
![]() |
9045bea756 | ||
![]() |
8afd6daa3a | ||
![]() |
a6d9462cb1 | ||
![]() |
5c4189e6b2 | ||
![]() |
e954cdc188 | ||
![]() |
4ff8436ebd | ||
![]() |
9de132dbf6 | ||
![]() |
f0efb90f21 | ||
![]() |
2a02403a94 | ||
![]() |
a42726f866 | ||
![]() |
b12cf05c82 | ||
![]() |
9f50e06993 | ||
![]() |
b5a5ecf4a3 | ||
![]() |
f5d05b43d7 | ||
![]() |
ba86626642 | ||
![]() |
312450d079 | ||
![]() |
c58acf06c2 | ||
![]() |
3eba4216e0 | ||
![]() |
6d90f1168b | ||
![]() |
c4d2968183 | ||
![]() |
075e1141b8 | ||
![]() |
87041b207f | ||
![]() |
770271d98f | ||
![]() |
a759acd958 | ||
![]() |
3bcb01a84f | ||
![]() |
36dd2f029f | ||
![]() |
608238ead6 | ||
![]() |
3a15c6c9d7 | ||
![]() |
8f89f10b40 | ||
![]() |
6e2e7641f9 | ||
![]() |
92175dd78c | ||
![]() |
cd1709b0d4 | ||
![]() |
2c45df2ab4 | ||
![]() |
0790864064 | ||
![]() |
ac6c791880 | ||
![]() |
a9d0128bd7 | ||
![]() |
92cc0d6257 | ||
![]() |
28f48ce1ac | ||
![]() |
ef1a85ca5e | ||
![]() |
659d7b190f | ||
![]() |
7af5682b3c | ||
![]() |
0fb6ba4ccc | ||
![]() |
d7141cfd06 | ||
![]() |
0e62dbadcd | ||
![]() |
afc7e581e6 | ||
![]() |
72303ef11a | ||
![]() |
4aa1bea04a | ||
![]() |
71c9aec834 | ||
![]() |
e8e20c0897 | ||
![]() |
18a0e144c2 | ||
![]() |
e27ffdab0f | ||
![]() |
c41f94eda3 | ||
![]() |
22b08a10ff | ||
![]() |
97d91aff7b | ||
![]() |
13225400c8 | ||
![]() |
adba0c2b63 | ||
![]() |
782fe1fe82 | ||
![]() |
1dd415df1a | ||
![]() |
7082aecd54 | ||
![]() |
e6f46e637c | ||
![]() |
b7042cb767 | ||
![]() |
372cd16b88 | ||
![]() |
22597efa06 | ||
![]() |
1f9098e7d0 | ||
![]() |
0aa96c5512 | ||
![]() |
03a8188a9a | ||
![]() |
6b1baf8dd2 | ||
![]() |
a38b5d7430 | ||
![]() |
00a863b25e | ||
![]() |
0f337e9c14 | ||
![]() |
dd41f86339 | ||
![]() |
2af17cd3f5 | ||
![]() |
9a5393d500 | ||
![]() |
12128189eb | ||
![]() |
c3c1ee0150 | ||
![]() |
07d2ad30e5 | ||
![]() |
9cebefa717 | ||
![]() |
8aacbb3ba9 | ||
![]() |
e9042385ac | ||
![]() |
b9e27acabc | ||
![]() |
585d74bad1 | ||
![]() |
0a26cdf344 | ||
![]() |
12c7411b6b | ||
![]() |
fbdc02534a | ||
![]() |
e2b78f074b | ||
![]() |
cc6d826fdd | ||
![]() |
6d2c4f87af | ||
![]() |
69c23cc0c9 | ||
![]() |
e7001c1455 | ||
![]() |
7df554acb0 | ||
![]() |
08632253d9 | ||
![]() |
ce574949f7 | ||
![]() |
57a37ed583 | ||
![]() |
1f6c42c678 | ||
![]() |
f8159163c1 | ||
![]() |
d5a3fccb06 | ||
![]() |
7ad5396f79 | ||
![]() |
9b184e1268 | ||
![]() |
7b0f8122b2 | ||
![]() |
b7ba0615d0 | ||
![]() |
dbe86d9d37 | ||
![]() |
0be7a1e33b | ||
![]() |
8fa736945a | ||
![]() |
fc8fcf85a2 | ||
![]() |
5fa4cfcabf | ||
![]() |
84ba2558e2 | ||
![]() |
b8f2caa80a | ||
![]() |
90f37f48e2 | ||
![]() |
6fae583dba | ||
![]() |
53d405c37f | ||
![]() |
f714730c40 | ||
![]() |
a5b4670c79 | ||
![]() |
abdaf7c2b5 | ||
![]() |
4f9db655ed | ||
![]() |
488f2bd141 | ||
![]() |
214ab2caef | ||
![]() |
6ae6dcfc53 | ||
![]() |
8712c6df22 | ||
![]() |
341e7b35a6 | ||
![]() |
60b7e2bbbe | ||
![]() |
882b79b254 | ||
![]() |
1ffc120558 | ||
![]() |
dc23efd3a2 | ||
![]() |
f74ca4ed36 | ||
![]() |
46f7ab808b | ||
![]() |
0252a6f475 | ||
![]() |
1ea1d561c7 | ||
![]() |
141cb65e51 | ||
![]() |
437bc829bf | ||
![]() |
52d9b0cb56 | ||
![]() |
f9135cdeb5 | ||
![]() |
7bc56c5365 | ||
![]() |
13915f6521 | ||
![]() |
6a2542dacf | ||
![]() |
cf5a3bc531 | ||
![]() |
388216fc45 | ||
![]() |
69b7952b8b | ||
![]() |
43a82dab90 | ||
![]() |
c378b1bf4c | ||
![]() |
5eaf898fcb | ||
![]() |
1da85f7bdc | ||
![]() |
f6a160d34e | ||
![]() |
ae726dcd2b | ||
![]() |
cf1ea9237c | ||
![]() |
9603adb5b4 | ||
![]() |
7a9b680a9c | ||
![]() |
523b907359 | ||
![]() |
8b7af1d0fc | ||
![]() |
3bb13c7eb4 | ||
![]() |
581cba2a56 | ||
![]() |
f5cc497eac | ||
![]() |
ab8968437b | ||
![]() |
0c6e9121b2 | ||
![]() |
c22fc41ddf | ||
![]() |
0751141003 | ||
![]() |
87c87bccb5 | ||
![]() |
529d19bad8 | ||
![]() |
eb9ce779f6 | ||
![]() |
c84e889a69 | ||
![]() |
35a51fd697 | ||
![]() |
bb4e9c72d7 | ||
![]() |
dc1e73cbbf | ||
![]() |
1eb0751803 | ||
![]() |
74cf9a0f60 | ||
![]() |
27f3abd893 | ||
![]() |
ba321d318b | ||
![]() |
18b1aec0ee | ||
![]() |
ec259ddfee | ||
![]() |
2b0d667b14 | ||
![]() |
e48b58e1be | ||
![]() |
44511f9e43 | ||
![]() |
2cdd4906ac | ||
![]() |
d6a656cf7f | ||
![]() |
1997933508 | ||
![]() |
7e1c8a5be3 | ||
![]() |
2f80a91b3e | ||
![]() |
21334593d1 | ||
![]() |
d90e5f283a | ||
![]() |
aa5d1a8897 | ||
![]() |
79c759393f | ||
![]() |
f58f02f3e6 | ||
![]() |
2cf230951f | ||
![]() |
9e6d012e9c | ||
![]() |
bd70d66a62 | ||
![]() |
1602e2f4f1 | ||
![]() |
d91bf690ef | ||
![]() |
61d5e5ca9a | ||
![]() |
f8275cb303 | ||
![]() |
279e6658ac | ||
![]() |
d11a772080 | ||
![]() |
f3cc93630e | ||
![]() |
77ea269b86 | ||
![]() |
3b1d9f1a26 | ||
![]() |
3a14b1235c | ||
![]() |
30f739db44 | ||
![]() |
cd41f655f9 | ||
![]() |
92884c25b3 | ||
![]() |
dbdfc71026 | ||
![]() |
e8c72adf54 | ||
![]() |
4d2a324fce | ||
![]() |
7d991b6e42 | ||
![]() |
fcf03cdfa9 | ||
![]() |
7028a03ffa | ||
![]() |
49ad10261e | ||
![]() |
c14bd4f1ad | ||
![]() |
65973c6c40 | ||
![]() |
291eaf0a77 | ||
![]() |
86cd6da76e | ||
![]() |
a69ffc3e20 | ||
![]() |
b524ed2dda | ||
![]() |
33d2ec08ba | ||
![]() |
c51a262e34 | ||
![]() |
fc8d9cb8f7 | ||
![]() |
f66f464802 | ||
![]() |
12c70b4386 | ||
![]() |
a0615f6839 | ||
![]() |
312fbb6d41 | ||
![]() |
afe281964d | ||
![]() |
bea729c030 | ||
![]() |
8ba8a59697 | ||
![]() |
659e7b52df | ||
![]() |
294274e10e | ||
![]() |
eaaf1ea96d | ||
![]() |
abf9d0b07f | ||
![]() |
3b4207896d | ||
![]() |
90dfb1c8ad | ||
![]() |
82a318db5f | ||
![]() |
0f9f9a132e | ||
![]() |
1931a1bdc7 | ||
![]() |
424ae36046 | ||
![]() |
bc94dfc7d2 | ||
![]() |
68eead6628 | ||
![]() |
debcb76939 | ||
![]() |
7cb1efebec | ||
![]() |
a58b0a3d9c | ||
![]() |
4046ae5e2f | ||
![]() |
6af9204938 | ||
![]() |
862caf826c | ||
![]() |
0bf6ffba43 | ||
![]() |
08e4e88482 | ||
![]() |
4fa5a79833 | ||
![]() |
484e6b784c | ||
![]() |
6a810b4259 | ||
![]() |
c786c3a974 | ||
![]() |
d5eba1bfe5 | ||
![]() |
2a38569337 | ||
![]() |
713c7d49a1 | ||
![]() |
7f68e3107e | ||
![]() |
97549d923c | ||
![]() |
410feab962 | ||
![]() |
757a004a90 | ||
![]() |
f270057e0c | ||
![]() |
7dc5f9d0b1 | ||
![]() |
aa2fa2caa3 | ||
![]() |
49f3e7d233 | ||
![]() |
df59a357ec | ||
![]() |
bcc0315003 | ||
![]() |
baca6cb417 | ||
![]() |
c8134fa046 | ||
![]() |
a189832454 | ||
![]() |
029519a149 | ||
![]() |
faa843fcef | ||
![]() |
f179243876 | ||
![]() |
028ed1bb22 | ||
![]() |
bb99b3f02e | ||
![]() |
d3533eee68 | ||
![]() |
488fe76eb8 | ||
![]() |
75546e1e46 | ||
![]() |
ec7c2b784a | ||
![]() |
08035dc805 | ||
![]() |
e18f5a5304 | ||
![]() |
c8b9dfb25e | ||
![]() |
fcb89da9c2 | ||
![]() |
61d94850a7 | ||
![]() |
0f163170a7 | ||
![]() |
faecc65cd3 | ||
![]() |
ae6960cf91 | ||
![]() |
3bfb6a9420 | ||
![]() |
fd40dfaf58 | ||
![]() |
e72c4818c4 | ||
![]() |
8ae94cafa5 | ||
![]() |
3a0af5ad30 | ||
![]() |
718fafed26 | ||
![]() |
61d8f57f2a | ||
![]() |
e262cd38ad | ||
![]() |
5dde37c846 | ||
![]() |
49d088d9ce | ||
![]() |
c3eed9fa3e | ||
![]() |
c5ea3d595c | ||
![]() |
f6533a1df1 | ||
![]() |
2249db0c73 | ||
![]() |
bcf52efbb6 | ||
![]() |
9b399814e7 | ||
![]() |
2ef69899de | ||
![]() |
9709b7e458 | ||
![]() |
65cfcc28ab | ||
![]() |
cfb8ca520a | ||
![]() |
4cd2654a9d | ||
![]() |
203bac0ec4 | ||
![]() |
964ab7158c | ||
![]() |
05523e289b | ||
![]() |
ce1ee98aba | ||
![]() |
5ce8eee0a4 | ||
![]() |
b1676a289c | ||
![]() |
cfdca8dc1d | ||
![]() |
d2865f1e8a | ||
![]() |
35eba19a65 | ||
![]() |
2f65748927 | ||
![]() |
0fd0e8255f | ||
![]() |
54fcd40aa4 | ||
![]() |
b93a532bcd | ||
![]() |
7786f8512b | ||
![]() |
4394c61e6c | ||
![]() |
8e84bc3931 | ||
![]() |
f877360dc1 | ||
![]() |
f678459593 | ||
![]() |
681c94ca17 | ||
![]() |
ab099ab076 | ||
![]() |
d154421092 | ||
![]() |
2d79f7653f | ||
![]() |
0af1650158 | ||
![]() |
68e73ceb67 | ||
![]() |
2f28582b55 | ||
![]() |
f4776ef9df | ||
![]() |
75324c4cc8 | ||
![]() |
604f4eed65 | ||
![]() |
847f3060d4 | ||
![]() |
93fffa299c | ||
![]() |
e6ae462268 | ||
![]() |
8641d2da3b | ||
![]() |
0ab7267ae3 | ||
![]() |
ba46bda149 | ||
![]() |
f13d8c2026 | ||
![]() |
a3fdad84ad | ||
![]() |
6af7d6ea2d | ||
![]() |
c89668f8e5 | ||
![]() |
b275f95f37 | ||
![]() |
9b02a84a5a | ||
![]() |
fb53da508f | ||
![]() |
15bcc707e6 | ||
![]() |
84036d3e18 | ||
![]() |
34e923e3e3 | ||
![]() |
1eadfb0e28 | ||
![]() |
3b423ea778 | ||
![]() |
981a878cf5 | ||
![]() |
677d41aa3b | ||
![]() |
7c8d02d1bc | ||
![]() |
f0b89e63b9 | ||
![]() |
63b2a2138d | ||
![]() |
99638f5f76 | ||
![]() |
774e677cc8 | ||
![]() |
524eef5d75 | ||
![]() |
33564a0c03 | ||
![]() |
e1d85da306 | ||
![]() |
5bff90cea2 | ||
![]() |
d47b3ef4c9 | ||
![]() |
7e66d9900c | ||
![]() |
f5a611a74c | ||
![]() |
8074e7a437 | ||
![]() |
5504ef7a84 | ||
![]() |
ea729aea4a | ||
![]() |
587d509ddd | ||
![]() |
d06af368ad | ||
![]() |
a7acfffea6 | ||
![]() |
876d4e5484 | ||
![]() |
7995e3288f | ||
![]() |
0c0943bcdf | ||
![]() |
58785c2932 | ||
![]() |
c14694a424 | ||
![]() |
49cea49cfa | ||
![]() |
6979503a85 | ||
![]() |
755f008c1e | ||
![]() |
796da163f9 | ||
![]() |
7d9d601e6d | ||
![]() |
29ac09ee9d | ||
![]() |
c1a289e05a | ||
![]() |
02011af7b0 | ||
![]() |
49e04102c1 | ||
![]() |
3cb8e9526e | ||
![]() |
26f63600c1 | ||
![]() |
6fd893bd3a | ||
![]() |
d5d41c2849 | ||
![]() |
ed1a61dcb7 | ||
![]() |
5b19725de2 | ||
![]() |
0ac748a340 | ||
![]() |
26c054edbf | ||
![]() |
39393f651e | ||
![]() |
587ad8845a | ||
![]() |
c1ab6eda4b | ||
![]() |
409ea700c7 | ||
![]() |
050e6066af | ||
![]() |
8068038a60 | ||
![]() |
90cc178baa | ||
![]() |
5baf486545 | ||
![]() |
ec32f0db82 | ||
![]() |
02a932d63f | ||
![]() |
2f138d860e | ||
![]() |
d3f4876f41 | ||
![]() |
891241e7e7 | ||
![]() |
3c2b06099d | ||
![]() |
6ca1b9e4ce | ||
![]() |
fb3cc5e716 | ||
![]() |
217054ddea | ||
![]() |
123ade3763 | ||
![]() |
7257c77e19 | ||
![]() |
60e88c873e | ||
![]() |
d9dce8e0d0 | ||
![]() |
4be5b4147d | ||
![]() |
4e8ba395f2 | ||
![]() |
0dae0f2b5e | ||
![]() |
30cd8b8fca | ||
![]() |
1c50526092 | ||
![]() |
a99bb24ea8 | ||
![]() |
e9efc0a361 | ||
![]() |
171f153e2c | ||
![]() |
29977d5058 | ||
![]() |
d60de4cafd | ||
![]() |
dcf7287d64 | ||
![]() |
cd95cd0671 | ||
![]() |
df34db1158 | ||
![]() |
5a83bebf76 | ||
![]() |
29ddf2214d | ||
![]() |
f44b085da6 | ||
![]() |
53ebecea7c | ||
![]() |
ae75dafe47 | ||
![]() |
63a9d72ee8 | ||
![]() |
4356962c69 | ||
![]() |
38c4ceb00a | ||
![]() |
34f5793521 | ||
![]() |
bd23c7729e | ||
![]() |
205e4de3fd | ||
![]() |
7cabe08399 | ||
![]() |
153d7e4038 | ||
![]() |
987f76ea78 | ||
![]() |
27e064e7e9 | ||
![]() |
1b9411ef77 | ||
![]() |
e0476beb78 | ||
![]() |
808120e5b8 | ||
![]() |
9d578a2e6d | ||
![]() |
fc4d035e7a | ||
![]() |
c9ccbfad11 | ||
![]() |
59c5f6e35b | ||
![]() |
61c78d9438 | ||
![]() |
ee9f0ed895 | ||
![]() |
052562ffd5 | ||
![]() |
98323ac114 | ||
![]() |
4776a9e6fb | ||
![]() |
460e1b3600 | ||
![]() |
4f0cab3b74 | ||
![]() |
79589354df | ||
![]() |
44a25f31a8 | ||
![]() |
91eee33f62 | ||
![]() |
1f096174d6 | ||
![]() |
a54a34ef0e | ||
![]() |
7d5445e312 | ||
![]() |
417018659b | ||
![]() |
e36260f39a | ||
![]() |
8f756fe679 | ||
![]() |
a73dfe68d3 | ||
![]() |
7e0cb4c46f | ||
![]() |
f5535d516f | ||
![]() |
dcc80204bc | ||
![]() |
70158284b7 | ||
![]() |
a66ddb7c59 | ||
![]() |
d7266afc7e | ||
![]() |
df3a321164 | ||
![]() |
aeb8972281 | ||
![]() |
b4a08b3b7c | ||
![]() |
52da88201c | ||
![]() |
c44c9dfa79 | ||
![]() |
3cf409aa9e | ||
![]() |
6a8a792019 | ||
![]() |
452ca90fe5 | ||
![]() |
f2c67ea82f | ||
![]() |
a7b44ea10f | ||
![]() |
0cf113e250 | ||
![]() |
777e9f2710 | ||
![]() |
619d98ab49 | ||
![]() |
164167ea91 | ||
![]() |
aad51c0b4e | ||
![]() |
dca89c67ef | ||
![]() |
f800215946 | ||
![]() |
8166818791 | ||
![]() |
c3ca4f5de0 | ||
![]() |
74641d2006 | ||
![]() |
4af420f978 | ||
![]() |
4039b9c9c4 | ||
![]() |
4f4a897dda | ||
![]() |
4b40d82233 | ||
![]() |
9536fabaa8 | ||
![]() |
43dccc6c1a | ||
![]() |
5a72ed3406 | ||
![]() |
06115bf82c | ||
![]() |
285ab8c861 | ||
![]() |
e28da7686e | ||
![]() |
a837cb444c | ||
![]() |
5f884478e5 | ||
![]() |
885eceba1d | ||
![]() |
6ce6b63482 | ||
![]() |
268e72f10f | ||
![]() |
c388416aac | ||
![]() |
5c297fcc09 | ||
![]() |
7d2a6f2030 | ||
![]() |
a4522b6a8f | ||
![]() |
f7ddfdbae6 | ||
![]() |
d1108b8a06 | ||
![]() |
9c161cc65a | ||
![]() |
f482857959 | ||
![]() |
f1102e98bb | ||
![]() |
ba4d491562 | ||
![]() |
5b3086db1f | ||
![]() |
16e4bc9827 | ||
![]() |
89d7b77022 | ||
![]() |
c867ac4527 | ||
![]() |
980a5bc72a | ||
![]() |
4292f42308 | ||
![]() |
50062b413c | ||
![]() |
d63cab5193 | ||
![]() |
8e2e1f3d28 | ||
![]() |
d3f4580519 | ||
![]() |
58c5986f8b | ||
![]() |
707bb9b9ed | ||
![]() |
eafb618594 | ||
![]() |
ba32bebd05 | ||
![]() |
4562f07887 | ||
![]() |
8c661b5e9a | ||
![]() |
cf95278122 | ||
![]() |
1baec48367 | ||
![]() |
908821d48a | ||
![]() |
02fd8485fa | ||
![]() |
dbb2bd727d | ||
![]() |
5cc978c6a0 | ||
![]() |
86fb048e59 | ||
![]() |
b4ff5234bd | ||
![]() |
cdb44010c9 | ||
![]() |
29d863d451 | ||
![]() |
0253fedf03 | ||
![]() |
d28bd54f2a | ||
![]() |
e97716a95a | ||
![]() |
5338c06c2a | ||
![]() |
cf9073397c | ||
![]() |
46d11bddbb | ||
![]() |
7bb54c3dc5 | ||
![]() |
70589b8548 | ||
![]() |
1f965317b6 | ||
![]() |
bcca214e36 | ||
![]() |
33cf73f699 | ||
![]() |
804ef16822 | ||
![]() |
c85398b020 | ||
![]() |
29da565133 | ||
![]() |
0456c0db87 | ||
![]() |
749d4abd41 | ||
![]() |
f05dce8d3a | ||
![]() |
e3feb05175 | ||
![]() |
b85185e659 | ||
![]() |
0d27579fc7 | ||
![]() |
f6576e9a74 | ||
![]() |
26730c891a | ||
![]() |
91cb91a304 | ||
![]() |
fd3066c168 | ||
![]() |
a7dd561c4a | ||
![]() |
79521da5cc | ||
![]() |
6f625ae65a | ||
![]() |
af22957b94 | ||
![]() |
9357bcb582 | ||
![]() |
488559a330 | ||
![]() |
d9b5445f39 | ||
![]() |
095d2a29a3 | ||
![]() |
6040283f23 | ||
![]() |
5c3d0fbc5e | ||
![]() |
9664f33e0d | ||
![]() |
2df698025c | ||
![]() |
25fb4dd50d | ||
![]() |
670bc0a46c | ||
![]() |
96f85def5b | ||
![]() |
2a14b6cf60 | ||
![]() |
d7c6fd2f80 | ||
![]() |
e260808a57 | ||
![]() |
14d2535f13 | ||
![]() |
4e219ebafb | ||
![]() |
4662e9889c | ||
![]() |
919fe72f60 | ||
![]() |
80a9fc6d36 | ||
![]() |
cdb3f9fb8d | ||
![]() |
40fde69be9 | ||
![]() |
c2aa895908 | ||
![]() |
e1bacd18a3 | ||
![]() |
70892220c8 | ||
![]() |
03decbc1e6 | ||
![]() |
bb1fb9aaad | ||
![]() |
5a34c7c245 | ||
![]() |
bb7408e851 | ||
![]() |
6c1c76d02a | ||
![]() |
e3d8e979de | ||
![]() |
f51c5e1a5c | ||
![]() |
b5f5987959 | ||
![]() |
42af8795a3 | ||
![]() |
8047b69ba3 | ||
![]() |
f20abbc96c | ||
![]() |
796c05ca32 | ||
![]() |
3e43f8e9f4 | ||
![]() |
4cbac66746 | ||
![]() |
c279c48a0e | ||
![]() |
0a82696d70 | ||
![]() |
8777592397 | ||
![]() |
adea457841 | ||
![]() |
3205ace201 | ||
![]() |
c5389354ac | ||
![]() |
ebef4efb88 | ||
![]() |
9670d9364d | ||
![]() |
7bce33eb0f | ||
![]() |
0f77875220 | ||
![]() |
9498d897ab | ||
![]() |
30f09b4a1a | ||
![]() |
95b92b1f97 | ||
![]() |
ec69501e94 | ||
![]() |
5b3e6555a3 | ||
![]() |
48cacbca24 | ||
![]() |
aacd100a70 | ||
![]() |
44dbbeb196 | ||
![]() |
bcbbd9538f | ||
![]() |
056be8b7b0 | ||
![]() |
b33ad6fff6 | ||
![]() |
6f6ef7906a | ||
![]() |
bea1462f4f | ||
![]() |
bb8bc1ffc8 | ||
![]() |
3bc45d78c9 | ||
![]() |
949f8c9f2a | ||
![]() |
1800dd0876 | ||
![]() |
1946aead21 | ||
![]() |
0679ae984b | ||
![]() |
bc33c27796 | ||
![]() |
f2e163b75d | ||
![]() |
db806533e6 | ||
![]() |
b81b27c21f | ||
![]() |
cff4f20c44 | ||
![]() |
e1d0aacb6a | ||
![]() |
d7caea206e | ||
![]() |
2835d1f7b2 | ||
![]() |
26c5d1ea0d | ||
![]() |
f0698dae14 | ||
![]() |
0cd02ab1b4 | ||
![]() |
e78152aecb | ||
![]() |
aca9ea42bd | ||
![]() |
d871a665de | ||
![]() |
a67b7554c8 | ||
![]() |
8d21af5be3 | ||
![]() |
fe30e5730f | ||
![]() |
a293cd6ab9 | ||
![]() |
f3aa9e151d | ||
![]() |
5f062032f7 | ||
![]() |
53345fe357 | ||
![]() |
2edb858b18 | ||
![]() |
87de23a6cd | ||
![]() |
23f2e0fea7 | ||
![]() |
37ca57e9d5 | ||
![]() |
3149c3efe6 | ||
![]() |
0a3fc95be6 | ||
![]() |
fcabc48ee4 | ||
![]() |
cbc2a71c27 | ||
![]() |
491758a446 | ||
![]() |
c587ba3422 | ||
![]() |
2c4551d86d | ||
![]() |
4de8459265 | ||
![]() |
b8ba263099 | ||
![]() |
25a813e924 | ||
![]() |
f6fa56194f | ||
![]() |
ee77ba5e49 | ||
![]() |
f99c4ec798 | ||
![]() |
1f6bacc486 | ||
![]() |
28d057cb0e | ||
![]() |
34400dd4a2 | ||
![]() |
e0e6ae741e | ||
![]() |
c47cdd5f39 | ||
![]() |
bc2c8279de | ||
![]() |
77a1411f9b | ||
![]() |
6f27bef9fc | ||
![]() |
77f7c83114 | ||
![]() |
e8a7a9435f | ||
![]() |
591c98cdbe | ||
![]() |
5b16dd6469 | ||
![]() |
ad877271f3 | ||
![]() |
7d30dafd69 | ||
![]() |
4a276afeb5 | ||
![]() |
3d70af4ee4 | ||
![]() |
e2c23ed57d | ||
![]() |
1239c96413 | ||
![]() |
c4f55b53b0 | ||
![]() |
16063c7456 | ||
![]() |
a4822abe37 | ||
![]() |
f9f439763a | ||
![]() |
4001241ccf | ||
![]() |
9e3ed7b429 | ||
![]() |
e465ebf2f3 | ||
![]() |
aa282973d4 | ||
![]() |
f66c000229 | ||
![]() |
a1d966c492 | ||
![]() |
7c0c525764 | ||
![]() |
2c0ad62b24 | ||
![]() |
2c89640ab9 | ||
![]() |
a9fcb775e5 | ||
![]() |
3197160114 | ||
![]() |
f91c3cfda6 | ||
![]() |
dcc75e1563 | ||
![]() |
a384102fdf | ||
![]() |
bb5402e6fb | ||
![]() |
603f49706e | ||
![]() |
f6e44bc0e8 | ||
![]() |
605c8fb75d | ||
![]() |
324cb3d08f | ||
![]() |
f3143745b2 | ||
![]() |
b1855bb4af | ||
![]() |
479079c6b1 | ||
![]() |
95aea39348 | ||
![]() |
97e28de7e2 | ||
![]() |
618d9b5d54 | ||
![]() |
7cda3fb7b5 | ||
![]() |
ca1307c56e | ||
![]() |
a8ea752a93 | ||
![]() |
2e60051c92 | ||
![]() |
642cf261a8 | ||
![]() |
e3975fba84 | ||
![]() |
7f9cce2b50 | ||
![]() |
430a5f8581 | ||
![]() |
41c186c344 | ||
![]() |
b94e88c1e2 | ||
![]() |
42a51cb285 | ||
![]() |
bd7b27b5c8 | ||
![]() |
3d62ab9585 | ||
![]() |
7f6bd671fe | ||
![]() |
0c66111c40 | ||
![]() |
51f0e7b0e4 | ||
![]() |
13b775a96e | ||
![]() |
7c202d2fa4 | ||
![]() |
724db8650c | ||
![]() |
1337a66130 | ||
![]() |
3614749b55 | ||
![]() |
90b756b2a1 | ||
![]() |
d5b067e04a | ||
![]() |
286704bf6f | ||
![]() |
34e71b374b | ||
![]() |
c8773e10b1 | ||
![]() |
a728bd0ee9 | ||
![]() |
221b73e23d | ||
![]() |
2246297ae6 | ||
![]() |
c217e3c87a | ||
![]() |
8cd5f04ea3 | ||
![]() |
fd6dd6935b | ||
![]() |
79a4cbbec9 | ||
![]() |
d7a31cfb2d | ||
![]() |
f549aaa205 | ||
![]() |
9249b34be8 | ||
![]() |
4401ccac22 | ||
![]() |
d3afa80b96 | ||
![]() |
0e80073e01 | ||
![]() |
0d9da7367d | ||
![]() |
4ff252456b | ||
![]() |
6203e3660d | ||
![]() |
6eeef51c6a | ||
![]() |
8b95ea4a35 | ||
![]() |
3a520c1c0f | ||
![]() |
e852ba55a5 | ||
![]() |
06a640084f | ||
![]() |
1ed5d91555 | ||
![]() |
4dbfe7e17e | ||
![]() |
d8a51d2887 | ||
![]() |
093481618d | ||
![]() |
7444b88f5d | ||
![]() |
7c865c156f | ||
![]() |
e061793212 | ||
![]() |
e6907243af | ||
![]() |
3936c57294 | ||
![]() |
207c4d537c | ||
![]() |
601c9b29e6 | ||
![]() |
313a090c0e | ||
![]() |
9d3b1f9419 | ||
![]() |
47f9e70385 | ||
![]() |
ee5a91e663 | ||
![]() |
299bd58c5a | ||
![]() |
7b96663082 | ||
![]() |
bd17d27658 | ||
![]() |
0b4a70ca2c | ||
![]() |
542fe0da40 | ||
![]() |
338fc49060 | ||
![]() |
7cfb81ba04 | ||
![]() |
34dc2f10b4 | ||
![]() |
54d84229ce | ||
![]() |
1c34831291 | ||
![]() |
3ff75aeb07 | ||
![]() |
2cb94ade6c | ||
![]() |
3350f815c7 | ||
![]() |
39fe25b69e | ||
![]() |
68b67b3230 | ||
![]() |
cf5657d4bb | ||
![]() |
d5425f28ae | ||
![]() |
bddd826d7a | ||
![]() |
83cac3c3e3 | ||
![]() |
5d87dc98ea | ||
![]() |
f13065b1f7 | ||
![]() |
a24d254397 | ||
![]() |
07e28a968b | ||
![]() |
2394b07bce | ||
![]() |
563bb58c8d | ||
![]() |
e19e541e2c | ||
![]() |
acf825def2 | ||
![]() |
3092b261e2 | ||
![]() |
554036040b | ||
![]() |
6fc3ead321 | ||
![]() |
73041028b6 | ||
![]() |
54dc8d2968 | ||
![]() |
d97e4300ee | ||
![]() |
d50585b05b | ||
![]() |
51d8a975ab | ||
![]() |
9670db3904 | ||
![]() |
a046616249 | ||
![]() |
f29155950f | ||
![]() |
0354791147 | ||
![]() |
87dd1de046 | ||
![]() |
bd6cadffb0 | ||
![]() |
6d93db06db | ||
![]() |
171ecf8cf2 | ||
![]() |
81ab8db1c3 | ||
![]() |
04a47e88d2 | ||
![]() |
19c07198b6 | ||
![]() |
bfd8c6deb7 | ||
![]() |
4bd0553274 | ||
![]() |
ff503882f7 | ||
![]() |
4c03618fab | ||
![]() |
6c563cda82 | ||
![]() |
0c4397deaf | ||
![]() |
ccb37fa567 | ||
![]() |
05c60724ed | ||
![]() |
3bd3cdd82e | ||
![]() |
b94f928be6 | ||
![]() |
85769732c2 | ||
![]() |
24405e8044 | ||
![]() |
28861e0c47 | ||
![]() |
bf692d47fb | ||
![]() |
a1833d8b4d | ||
![]() |
96faee9762 | ||
![]() |
e598ffcdf8 | ||
![]() |
32e2c53467 | ||
![]() |
5a4962f80d | ||
![]() |
30a57db97c | ||
![]() |
bd523abd44 | ||
![]() |
a07f6470b7 | ||
![]() |
a33043f0e0 | ||
![]() |
1ffbbe798a | ||
![]() |
336e1e9b7e | ||
![]() |
7f281907dd | ||
![]() |
babf907bfd | ||
![]() |
7ec9f304e9 | ||
![]() |
5e15ed314b | ||
![]() |
cc9c930e29 | ||
![]() |
24102aa8ca | ||
![]() |
bbcd662532 | ||
![]() |
20f9635469 | ||
![]() |
35e9d688ba | ||
![]() |
8ae5dc4aae | ||
![]() |
37b2ea9a8d | ||
![]() |
62e55fd58a | ||
![]() |
00e7ef5c3c | ||
![]() |
01cc1cc923 | ||
![]() |
14c5f7bf1d | ||
![]() |
0937aef261 | ||
![]() |
b805599ef6 | ||
![]() |
55b664046c | ||
![]() |
39b2bf51ca | ||
![]() |
a232f9463c | ||
![]() |
982e5afd1c | ||
![]() |
9c84994830 | ||
![]() |
f5d6af13d0 | ||
![]() |
863909a749 | ||
![]() |
0a8bd82a37 | ||
![]() |
5ab8d41d9f | ||
![]() |
de2447c2ab | ||
![]() |
76915b16e7 | ||
![]() |
3b04fd10e8 | ||
![]() |
9641c90eaf | ||
![]() |
7fbc3a9bc0 | ||
![]() |
ff85c363a8 | ||
![]() |
0b69c2c42f | ||
![]() |
78479b1915 | ||
![]() |
ff328e748d | ||
![]() |
4f28802f09 | ||
![]() |
75308e471c | ||
![]() |
5fa011dc0c | ||
![]() |
fd15ddbc30 | ||
![]() |
4229032676 | ||
![]() |
cdb5947316 | ||
![]() |
5d5eeac310 | ||
![]() |
51d647122a | ||
![]() |
29dcf646a3 | ||
![]() |
d0d3ddd045 | ||
![]() |
0313544f4a | ||
![]() |
c63a952dc9 | ||
![]() |
9127285985 | ||
![]() |
f22b112005 | ||
![]() |
8832cdf6e1 | ||
![]() |
c6bded3475 | ||
![]() |
8c7e19c5ff | ||
![]() |
6ebfa57364 | ||
![]() |
c41121cc48 | ||
![]() |
4acbf7d8c3 | ||
![]() |
ccae064209 | ||
![]() |
833b514d98 | ||
![]() |
f8a4b6755d | ||
![]() |
a8975c9042 | ||
![]() |
12e27dfd8f | ||
![]() |
7c0f6741eb | ||
![]() |
cd204f1118 | ||
![]() |
4215a1542b | ||
![]() |
bc77104fed | ||
![]() |
6ce5aa1cd5 | ||
![]() |
c3ab3f1dde | ||
![]() |
d582a26107 | ||
![]() |
5e7eade1f7 | ||
![]() |
b7d29c1e23 | ||
![]() |
de27973538 | ||
![]() |
6cc6682f5f | ||
![]() |
97e782ee2b | ||
![]() |
e6d9d216dd | ||
![]() |
820f37b1a6 | ||
![]() |
c44f8958f6 | ||
![]() |
0434b653c8 | ||
![]() |
fa3ddc5116 | ||
![]() |
6dcefa3739 | ||
![]() |
78ccd5d07c | ||
![]() |
43740ab642 | ||
![]() |
550e628f05 | ||
![]() |
5728516371 | ||
![]() |
c2004fb8c4 | ||
![]() |
7e506f71f3 | ||
![]() |
0c6f8f9290 | ||
![]() |
e9ad878df6 | ||
![]() |
9e797a6db9 | ||
![]() |
4982c70db4 | ||
![]() |
0f7a65e59b | ||
![]() |
3d8b8dc09a | ||
![]() |
c0ece8d4f3 | ||
![]() |
081b74b97d | ||
![]() |
152036f0aa | ||
![]() |
5f59f7bb49 | ||
![]() |
a4ceb0e4ac | ||
![]() |
ee7ca6822a | ||
![]() |
06499c52e2 | ||
![]() |
da5ed8b35b | ||
![]() |
ce4e325504 | ||
![]() |
a3c97beee0 | ||
![]() |
150b657bad | ||
![]() |
9b7784781d | ||
![]() |
3b4ccb2eca | ||
![]() |
e8dc902781 | ||
![]() |
642e9917ff | ||
![]() |
de391bc48b | ||
![]() |
776c376227 | ||
![]() |
efea287b44 | ||
![]() |
1cb45e582c | ||
![]() |
075a2d89b9 | ||
![]() |
b5376c7cec | ||
![]() |
62725ab277 | ||
![]() |
0be416dfdc | ||
![]() |
150b1c8c73 | ||
![]() |
2c95ddf4f3 | ||
![]() |
791549508a | ||
![]() |
dbb4d54e01 | ||
![]() |
09470db089 | ||
![]() |
1847dc4b7f | ||
![]() |
032797ea4b | ||
![]() |
7abd7fa739 | ||
![]() |
1148a24e64 | ||
![]() |
9c4e82435e | ||
![]() |
2243046bf8 | ||
![]() |
dffccfd0f1 | ||
![]() |
5dbd198b53 | ||
![]() |
4bf1a946f9 | ||
![]() |
96516002cc | ||
![]() |
417328e44e | ||
![]() |
97206b7cba | ||
![]() |
74fafbda51 | ||
![]() |
237eb3b5f1 | ||
![]() |
8dfaf0c780 | ||
![]() |
0ffa3dd870 | ||
![]() |
14af90b868 | ||
![]() |
2004f60bd6 | ||
![]() |
366a5f1d74 | ||
![]() |
e9b3a16cdc | ||
![]() |
aa9eb76b0d | ||
![]() |
02db973460 | ||
![]() |
536826d66f | ||
![]() |
6fc6b9bf31 | ||
![]() |
47a3b31ff6 | ||
![]() |
75097cf09a | ||
![]() |
6dd78a9ac2 | ||
![]() |
84a4f37cf7 | ||
![]() |
159b168eea | ||
![]() |
ebb9fade23 | ||
![]() |
c243efb0cd | ||
![]() |
3a4a04e462 | ||
![]() |
d390f86080 | ||
![]() |
a74f1ab423 | ||
![]() |
d864d1eb97 | ||
![]() |
7aa0bc5790 | ||
![]() |
823d0b3765 | ||
![]() |
b8de6c01b5 | ||
![]() |
c3f2bd1009 | ||
![]() |
7ff38506ab | ||
![]() |
32d5e6312d | ||
![]() |
daa4618da8 | ||
![]() |
7b7019a4da | ||
![]() |
5380f3f0c4 | ||
![]() |
f33370219b | ||
![]() |
b526ce268f | ||
![]() |
e19edd3f25 | ||
![]() |
b9f9e20f01 | ||
![]() |
af535233cc | ||
![]() |
9af5484fcc | ||
![]() |
6cf939fcc0 | ||
![]() |
afee36d07d | ||
![]() |
8c6a46f643 | ||
![]() |
1dcb11f81d | ||
![]() |
a49b71b481 | ||
![]() |
726dbc0f29 | ||
![]() |
a9a0ffaf51 | ||
![]() |
f6959bc597 | ||
![]() |
e0f171f342 | ||
![]() |
79a0f82ca1 | ||
![]() |
be90e5e1d4 | ||
![]() |
77c2613d3a | ||
![]() |
5da2dd98e9 | ||
![]() |
f1a7028900 | ||
![]() |
19f6f0b3db | ||
![]() |
47bf587f84 | ||
![]() |
a0a8d9d057 | ||
![]() |
cc1627ae10 | ||
![]() |
2832886761 | ||
![]() |
2689484402 | ||
![]() |
acdad37160 | ||
![]() |
f1a6e16258 | ||
![]() |
b6ba2a4f75 | ||
![]() |
3f8cbd8ec9 | ||
![]() |
e10eca3d1a | ||
![]() |
aefbd49038 | ||
![]() |
28d201feb7 | ||
![]() |
d43e61758a | ||
![]() |
69c19cf0b0 | ||
![]() |
1f5322a94e | ||
![]() |
aef703fa1b | ||
![]() |
bea39a49bc | ||
![]() |
bb7b7522b1 | ||
![]() |
94e924906c | ||
![]() |
4e4f62b6db | ||
![]() |
aa59b0f5a2 | ||
![]() |
14b53c6318 | ||
![]() |
062c80199f | ||
![]() |
0f871f8cb7 | ||
![]() |
10a3a3bc49 | ||
![]() |
8d404ac408 | ||
![]() |
9331d6de1e | ||
![]() |
a65c948e7e | ||
![]() |
8309206160 | ||
![]() |
51a1c5f3b4 | ||
![]() |
7f6dda359b | ||
![]() |
328c6159f2 | ||
![]() |
f6f6c32138 | ||
![]() |
333e04e84e | ||
![]() |
fa79b5d59f | ||
![]() |
0161aad462 | ||
![]() |
5123ae4352 | ||
![]() |
2928c5ae92 | ||
![]() |
62ec14d9ec | ||
![]() |
f443006fa2 | ||
![]() |
70ad5b818f | ||
![]() |
8569e8684f | ||
![]() |
3fcb3d94c7 | ||
![]() |
26a9d6474a | ||
![]() |
5a02ed5e84 | ||
![]() |
9ea50365d6 | ||
![]() |
2f8e957713 | ||
![]() |
32e79c464a | ||
![]() |
5512c7e838 | ||
![]() |
d6b8298cfd | ||
![]() |
8b21609654 | ||
![]() |
f8181b8875 | ||
![]() |
6a61bacafe | ||
![]() |
dc061d2ed3 | ||
![]() |
40b1389917 | ||
![]() |
15435f7293 | ||
![]() |
9afb688f5f | ||
![]() |
639449f84e | ||
![]() |
b75e831567 | ||
![]() |
5b53ddfcdd | ||
![]() |
ebe2347ac6 | ||
![]() |
aa764e6009 | ||
![]() |
fa13b0715f | ||
![]() |
79495c5b6a | ||
![]() |
df2f25a977 | ||
![]() |
6c036f267f | ||
![]() |
55192de9e3 | ||
![]() |
a3867992b7 | ||
![]() |
f6b2e34268 | ||
![]() |
318b3d4fe5 | ||
![]() |
cb394a62e5 | ||
![]() |
8f64e2e925 | ||
![]() |
3dea2f230a | ||
![]() |
634f6ec1d4 | ||
![]() |
385f6429be | ||
![]() |
350223201e | ||
![]() |
b688af2226 | ||
![]() |
70baaec6a5 | ||
![]() |
12d1f4f385 | ||
![]() |
3e5b2a6ef6 | ||
![]() |
4824c60893 | ||
![]() |
f6a5318f94 | ||
![]() |
2aabd64477 | ||
![]() |
b18e170631 | ||
![]() |
136e86bb5c | ||
![]() |
4862d39144 | ||
![]() |
b249376bb0 | ||
![]() |
cd49f9affd | ||
![]() |
6d5204b63e | ||
![]() |
f10e182ca7 | ||
![]() |
cfd431d4d5 | ||
![]() |
d52f20048d | ||
![]() |
e9b09b49fd | ||
![]() |
73894af9ff | ||
![]() |
ce01d779df | ||
![]() |
211d3a8c32 | ||
![]() |
95e99e629c | ||
![]() |
6c6e1fb13d | ||
![]() |
1e579a7a2a | ||
![]() |
263c00f27c | ||
![]() |
b71951c70c | ||
![]() |
87cedbe443 | ||
![]() |
976da91fb7 | ||
![]() |
b4d6eca9b8 | ||
![]() |
07e6b0ac70 | ||
![]() |
498da44aab | ||
![]() |
79f5aac2d0 | ||
![]() |
713066accc | ||
![]() |
210abfaef6 | ||
![]() |
53a6661684 | ||
![]() |
04422f5ec1 | ||
![]() |
dd26e6b15e | ||
![]() |
3d94eb9bcd | ||
![]() |
bc7f341f29 | ||
![]() |
bd5d6480e7 | ||
![]() |
6eaefe5bf5 | ||
![]() |
43aa67a982 | ||
![]() |
759698581e | ||
![]() |
13648a0e21 | ||
![]() |
56597db804 | ||
![]() |
78828f9b58 | ||
![]() |
0d9cf9e66b | ||
![]() |
64f5d9b119 | ||
![]() |
1fa586de52 | ||
![]() |
b4c59d25d6 | ||
![]() |
bd2c553870 | ||
![]() |
143b3b2ef3 | ||
![]() |
01214bafd2 | ||
![]() |
b92cf68add | ||
![]() |
b63400fa4a | ||
![]() |
9668613541 | ||
![]() |
c881360e88 | ||
![]() |
b9bf407929 | ||
![]() |
8631e69cdf | ||
![]() |
f3d29db6a2 | ||
![]() |
a365fb0e9d | ||
![]() |
95abde479a | ||
![]() |
35456d2eb1 | ||
![]() |
aecfa55c4c | ||
![]() |
0e3b2ec267 | ||
![]() |
53afd2ae9f | ||
![]() |
d74f0a47de | ||
![]() |
71f4916357 | ||
![]() |
4b0d38de06 | ||
![]() |
9b9348ce86 | ||
![]() |
e2fc596de4 | ||
![]() |
c0568a95d8 | ||
![]() |
2b583c0923 | ||
![]() |
69cf2ad6a5 | ||
![]() |
20b770237c | ||
![]() |
405f571ae8 | ||
![]() |
2eccf0e8d1 | ||
![]() |
389b21a341 | ||
![]() |
13c4eaea92 | ||
![]() |
8f0b62e4d9 | ||
![]() |
bb5813a93d | ||
![]() |
cec49ba976 | ||
![]() |
0e7186af95 | ||
![]() |
8c3b14ee85 | ||
![]() |
77539e7bc7 | ||
![]() |
79fa17e181 | ||
![]() |
18c5d863d6 | ||
![]() |
6cbe06ff3f | ||
![]() |
3553b4c684 | ||
![]() |
a479b287c7 | ||
![]() |
70ae5c13ea | ||
![]() |
8383430946 | ||
![]() |
bedcc94de4 | ||
![]() |
dfaff9598c | ||
![]() |
eb56493f4e | ||
![]() |
3e8af0817a | ||
![]() |
4f47013feb | ||
![]() |
2be118379e | ||
![]() |
b8ff8ea58e | ||
![]() |
331854a126 | ||
![]() |
fa517bb420 | ||
![]() |
5d15da8290 | ||
![]() |
3ffa00909d | ||
![]() |
764419ed4e | ||
![]() |
fc15e08a6c | ||
![]() |
dff53a02ef | ||
![]() |
d6f340e784 | ||
![]() |
f44fbab3ec | ||
![]() |
6dba98cf38 | ||
![]() |
6c4153f348 | ||
![]() |
e690cdb6a3 | ||
![]() |
3c10db669e | ||
![]() |
a01bcf9767 | ||
![]() |
cc414a2012 | ||
![]() |
3b9f4395cf | ||
![]() |
d146e592d8 | ||
![]() |
cf15460a3b | ||
![]() |
219d4d9db9 | ||
![]() |
d125823d3f | ||
![]() |
2010f4338e | ||
![]() |
ad91fc1b00 | ||
![]() |
5dc44f03f0 | ||
![]() |
fc302d7b7b | ||
![]() |
a866e50e6e | ||
![]() |
1c937c5816 | ||
![]() |
6cef3c2b77 | ||
![]() |
06e540c271 | ||
![]() |
2afa4eba43 | ||
![]() |
3218e26a22 | ||
![]() |
986de11464 | ||
![]() |
9efe6501bb | ||
![]() |
7f965d55c7 | ||
![]() |
678ce73907 | ||
![]() |
01ac4892e0 | ||
![]() |
f7ce59f7dc | ||
![]() |
0c522c6bbf | ||
![]() |
16f152b1ec | ||
![]() |
73ffb48bfb | ||
![]() |
73e47ee39c | ||
![]() |
9aed6308d4 | ||
![]() |
c22ec82477 | ||
![]() |
bd0111c1f4 | ||
![]() |
42d34e40f9 | ||
![]() |
a64adda4e7 | ||
![]() |
c85a33d74b | ||
![]() |
d979d2af45 | ||
![]() |
513063bcf9 | ||
![]() |
d83ead8434 | ||
![]() |
64de635626 | ||
![]() |
cff341e5e6 | ||
![]() |
56b62640a2 | ||
![]() |
cbe692ffd1 | ||
![]() |
e2f9d6c4c3 | ||
![]() |
b325dcbff6 | ||
![]() |
9889585a79 | ||
![]() |
e8f0f5a4ce | ||
![]() |
b3e249f401 | ||
![]() |
0503cf2510 | ||
![]() |
fc5702b284 | ||
![]() |
a443c2b18d | ||
![]() |
dca7544320 | ||
![]() |
52b5b5be98 | ||
![]() |
b9d9504df5 | ||
![]() |
7b66ae1531 | ||
![]() |
16cda4138d | ||
![]() |
59aa3dce8a | ||
![]() |
ea2d686468 | ||
![]() |
f1240393d9 | ||
![]() |
18a0ff2b2b | ||
![]() |
178125ae39 | ||
![]() |
7b28bc51e6 | ||
![]() |
f8363690ca | ||
![]() |
cb36f57299 | ||
![]() |
72648f0ba6 | ||
![]() |
17571ff199 | ||
![]() |
917dae58e1 | ||
![]() |
e0f5bb4820 | ||
![]() |
225691e258 | ||
![]() |
8376595621 | ||
![]() |
91a3a95385 | ||
![]() |
48ea7ec970 | ||
![]() |
8bf62010a4 | ||
![]() |
c0562d4eed | ||
![]() |
8070f15966 | ||
![]() |
014fefee1d | ||
![]() |
a9e8110fe3 | ||
![]() |
80d158e0de | ||
![]() |
dffe634c19 | ||
![]() |
896f246888 | ||
![]() |
5fe81ef1bb | ||
![]() |
6da42ca830 | ||
![]() |
051d51b222 | ||
![]() |
303e2b124e | ||
![]() |
05deecaa45 | ||
![]() |
d4e1c072e2 | ||
![]() |
f661bd8ee5 | ||
![]() |
de4ba13400 | ||
![]() |
1e4e9161c5 | ||
![]() |
bf1fb97575 | ||
![]() |
b039bbc678 | ||
![]() |
79b467808e | ||
![]() |
74feadacf8 | ||
![]() |
0899ba4a3f | ||
![]() |
3cb52a6359 | ||
![]() |
26be2bc6b9 | ||
![]() |
e0da5cb929 | ||
![]() |
220fba06e7 | ||
![]() |
3c8b68c636 | ||
![]() |
38e26c4717 | ||
![]() |
8b69cb4482 | ||
![]() |
435ecfe6e0 | ||
![]() |
3d3ce9812f | ||
![]() |
742475bc8d | ||
![]() |
4cc796ab93 | ||
![]() |
58dc0fcd1e | ||
![]() |
87fff769f4 | ||
![]() |
71da8c13e1 | ||
![]() |
89b542b421 | ||
![]() |
cfc117826a | ||
![]() |
1614b534fe | ||
![]() |
11a0c2779b | ||
![]() |
6598cba32f | ||
![]() |
43956e1b71 | ||
![]() |
ae008570ff | ||
![]() |
510cac5f5b | ||
![]() |
2cccb1f02c | ||
![]() |
8a1ca49657 | ||
![]() |
16785b9b7b | ||
![]() |
5b0fa7aaca | ||
![]() |
972d80b596 | ||
![]() |
0da721ec38 | ||
![]() |
d9442aab88 | ||
![]() |
2afe18d2ce | ||
![]() |
8b989ac665 | ||
![]() |
3d0a7d819c | ||
![]() |
74354043ff | ||
![]() |
2b449e0e65 | ||
![]() |
36a0946aa9 | ||
![]() |
2884018e7f | ||
![]() |
2ef7b479a5 | ||
![]() |
0485b8f0fb | ||
![]() |
fd4ec26313 | ||
![]() |
64e01c627f | ||
![]() |
94dc10378d | ||
![]() |
67e2c1d482 | ||
![]() |
ad68883c5a | ||
![]() |
32fcde6d9e | ||
![]() |
df03357d19 | ||
![]() |
808fed550d | ||
![]() |
87fc8c772b | ||
![]() |
6dbc9c1c53 | ||
![]() |
7047964bd6 | ||
![]() |
821ef5cbaf | ||
![]() |
05ef5559c3 | ||
![]() |
63d477b20e | ||
![]() |
f9cae2acbe | ||
![]() |
6841a53d17 | ||
![]() |
4ab4330677 | ||
![]() |
2aa24519da | ||
![]() |
5d722b35d9 | ||
![]() |
eba15fe905 | ||
![]() |
76b736c242 | ||
![]() |
ea5f21ceac | ||
![]() |
8b6203b613 | ||
![]() |
0f4ba145ee | ||
![]() |
f2be77a5ab | ||
![]() |
40adb4317b | ||
![]() |
3e52785aae | ||
![]() |
481dde8b70 | ||
![]() |
93b5c31541 | ||
![]() |
b663c7c5c3 | ||
![]() |
4b19b2f4ba | ||
![]() |
b32c7594a5 | ||
![]() |
c8930105bc | ||
![]() |
b1c112d35e | ||
![]() |
4f9540f19f | ||
![]() |
8153a7760e | ||
![]() |
a018bb1da7 | ||
![]() |
12d8029d56 | ||
![]() |
d1aa1979b4 | ||
![]() |
7a59913b1a | ||
![]() |
0034a98eb1 | ||
![]() |
eb3ace962d | ||
![]() |
25be5c9cfc | ||
![]() |
01a9c5b70e | ||
![]() |
bbb9255562 | ||
![]() |
3b71197fb8 | ||
![]() |
f3e62199ea | ||
![]() |
d7a9f15775 | ||
![]() |
f576f568a3 | ||
![]() |
9249e0b3f8 | ||
![]() |
2b028dc55b | ||
![]() |
33b4285eb1 | ||
![]() |
ddb3d46533 | ||
![]() |
27a27db73f | ||
![]() |
91cab53a3e | ||
![]() |
2cbed9d2a8 | ||
![]() |
603547fa19 | ||
![]() |
07f2df69c7 | ||
![]() |
5158a33f15 | ||
![]() |
1c6dae1291 | ||
![]() |
cc79024761 | ||
![]() |
45de99aa06 | ||
![]() |
7d429125d2 | ||
![]() |
6ce92aa523 | ||
![]() |
9e9a17950a | ||
![]() |
0eea8d69b2 | ||
![]() |
8c4af5dacb | ||
![]() |
982bc0e228 | ||
![]() |
9bd2b7e7af | ||
![]() |
5bd8aa5246 | ||
![]() |
d7fb4dd170 | ||
![]() |
584f016e99 | ||
![]() |
0ac039f979 | ||
![]() |
d5cb7cdeae | ||
![]() |
69c9adb7d3 | ||
![]() |
fced566714 | ||
![]() |
47af265234 | ||
![]() |
74d9850bb9 | ||
![]() |
a1202648ff | ||
![]() |
8d482accd1 | ||
![]() |
971083d419 | ||
![]() |
5e2a1195d7 | ||
![]() |
39a13456c1 | ||
![]() |
2f17d5fa8f | ||
![]() |
95bbbc0418 | ||
![]() |
97daeb0020 | ||
![]() |
1a51898d2e | ||
![]() |
476e788090 | ||
![]() |
e2d400bea9 | ||
![]() |
6df4a00bb9 | ||
![]() |
7c13985fa1 | ||
![]() |
d8f42ee21a | ||
![]() |
a40d00c421 | ||
![]() |
66b379785e | ||
![]() |
d8cd4f6421 | ||
![]() |
fc5c16f491 | ||
![]() |
e9f1888560 | ||
![]() |
eadaaa7f79 | ||
![]() |
99ab11bb90 | ||
![]() |
9174eb00e2 | ||
![]() |
7c2665298a | ||
![]() |
d9b7a5f01a | ||
![]() |
4445169cb5 | ||
![]() |
4269712d06 | ||
![]() |
c203171ef6 | ||
![]() |
6d37ab0a83 | ||
![]() |
03db2f8c3d | ||
![]() |
8197752d68 | ||
![]() |
7baab8bd6c | ||
![]() |
4d674897f3 | ||
![]() |
935c04f33a | ||
![]() |
975031bfcb | ||
![]() |
5919a2944a | ||
![]() |
5438356348 | ||
![]() |
a908460adb | ||
![]() |
ce053a14aa | ||
![]() |
077208287b | ||
![]() |
be0f4a4737 | ||
![]() |
9200c6be90 | ||
![]() |
6ec03d6745 | ||
![]() |
6f2e0fac19 | ||
![]() |
86299bbd35 | ||
![]() |
fca38bcd0a | ||
![]() |
70e620f791 | ||
![]() |
490fee7d45 | ||
![]() |
bf48d3ec29 | ||
![]() |
a78381c399 | ||
![]() |
0d76fc431a | ||
![]() |
b2bde4a7d8 | ||
![]() |
0e0c725224 | ||
![]() |
ed9cd96bdb | ||
![]() |
1bbc9d1ae4 | ||
![]() |
2870559b2c | ||
![]() |
597ab901b9 | ||
![]() |
3e8fda0a70 | ||
![]() |
d69b1fdb72 | ||
![]() |
10aff57b26 | ||
![]() |
198ba185c7 | ||
![]() |
da9e44a620 | ||
![]() |
c30c3f94c7 | ||
![]() |
31d09f6ee9 | ||
![]() |
492c09276d | ||
![]() |
13180c1c49 | ||
![]() |
68991ae240 | ||
![]() |
7a44e4cde0 | ||
![]() |
e5cffc07b3 | ||
![]() |
1d8108b009 | ||
![]() |
a0bba26919 | ||
![]() |
ad2760ec80 | ||
![]() |
4d8e3f54cc | ||
![]() |
427f95c4e6 | ||
![]() |
5a39bee635 | ||
![]() |
7379d18018 | ||
![]() |
f3b76bc1da | ||
![]() |
a8c0b05052 | ||
![]() |
8caf974dcd | ||
![]() |
437ced91ec | ||
![]() |
ca5ac19ea4 | ||
![]() |
536e3692c6 | ||
![]() |
5fe05d3eeb | ||
![]() |
02dc5ea720 | ||
![]() |
0f7bf67f83 | ||
![]() |
e1ad4aa002 | ||
![]() |
5bd44cf3c4 | ||
![]() |
77c03221c9 | ||
![]() |
d12ec5f796 | ||
![]() |
dfd331b2c8 | ||
![]() |
77103c7c03 | ||
![]() |
4af4adc7ba | ||
![]() |
a44c25c2f1 | ||
![]() |
954d50b88a | ||
![]() |
20889dbac6 | ||
![]() |
a5ee0d6af8 | ||
![]() |
b378669836 | ||
![]() |
65978e6982 | ||
![]() |
478f4aed63 | ||
![]() |
37cbdeb1f2 | ||
![]() |
e4134d5c0d | ||
![]() |
d713b7ed45 | ||
![]() |
8291893239 | ||
![]() |
7e4ffa3fa9 | ||
![]() |
b3ed92d88b | ||
![]() |
08815cb1b9 | ||
![]() |
1bc7a2aacd | ||
![]() |
126a089382 | ||
![]() |
42fa7a1951 | ||
![]() |
d4d645d32a | ||
![]() |
7ced56b356 | ||
![]() |
5ef9e2632f | ||
![]() |
48cc28e4ef | ||
![]() |
96b473a0bd | ||
![]() |
f70e1b315f | ||
![]() |
704a19b25d | ||
![]() |
d5b1e43b8f | ||
![]() |
d16579971e | ||
![]() |
0ec73a7892 | ||
![]() |
afd4805278 | ||
![]() |
24fef11e44 | ||
![]() |
64c6f72988 | ||
![]() |
edafcb2c39 | ||
![]() |
e57b807a42 | ||
![]() |
be8ff186d6 | ||
![]() |
9484520327 | ||
![]() |
a5f45b47a3 | ||
![]() |
454b6a7cf5 | ||
![]() |
483a1933a2 | ||
![]() |
49dce504bf | ||
![]() |
5da84141c4 | ||
![]() |
44ab4d44e0 | ||
![]() |
6791b8051a | ||
![]() |
9d3590f375 | ||
![]() |
35d180126a | ||
![]() |
b835c28383 | ||
![]() |
51fad48097 | ||
![]() |
6b2ee07a26 | ||
![]() |
203c683dff | ||
![]() |
3cfc1ffb0a | ||
![]() |
3b77e38b8e | ||
![]() |
df86d855f5 | ||
![]() |
f5e64a9eaa | ||
![]() |
d431345bf3 | ||
![]() |
30916df3d3 | ||
![]() |
4f4dd2d995 | ||
![]() |
287130a254 | ||
![]() |
7145129f27 | ||
![]() |
410a52b763 | ||
![]() |
741c28ae9f | ||
![]() |
e84b72710b | ||
![]() |
e235763a38 | ||
![]() |
4c30bf1667 | ||
![]() |
cb53ce9f89 | ||
![]() |
f463e50719 | ||
![]() |
359ab384fd | ||
![]() |
b11bdb9212 | ||
![]() |
64609120d8 | ||
![]() |
2990defea7 | ||
![]() |
d7aa47ddb8 | ||
![]() |
296040b1f4 | ||
![]() |
033f882314 | ||
![]() |
b615d195b2 | ||
![]() |
c5c8f433e6 | ||
![]() |
82190c7296 | ||
![]() |
6f2a242193 | ||
![]() |
6025938ee9 | ||
![]() |
2659f7f740 | ||
![]() |
a8fd1e3135 | ||
![]() |
d78893921a | ||
![]() |
e942499c66 | ||
![]() |
9ba41b791e | ||
![]() |
f3a6b0fd08 | ||
![]() |
f061f39145 | ||
![]() |
124b1141d7 | ||
![]() |
6cba44277f | ||
![]() |
f329397077 | ||
![]() |
db7fef6e50 | ||
![]() |
8b843732b3 | ||
![]() |
eaf141c86a | ||
![]() |
028eab9ebb | ||
![]() |
7310a7cd0c | ||
![]() |
4ecc01f3ad | ||
![]() |
48ff8a95cc | ||
![]() |
8e51b8b59c | ||
![]() |
058a6e94a1 | ||
![]() |
750c441dfd | ||
![]() |
468d6616bf | ||
![]() |
375c4eb31c | ||
![]() |
034e7e153f | ||
![]() |
0c6b616656 | ||
![]() |
79a198bc08 | ||
![]() |
7799f23627 | ||
![]() |
1aa17222e7 | ||
![]() |
29eb0be134 | ||
![]() |
5491f9a9a9 | ||
![]() |
a972dbd682 | ||
![]() |
5563b09ac2 | ||
![]() |
780e8b2332 | ||
![]() |
12a19dcd84 | ||
![]() |
235cd6c6b2 | ||
![]() |
bcea83ab9b | ||
![]() |
37dcdac218 | ||
![]() |
ba513805d0 | ||
![]() |
f8c0d92a22 | ||
![]() |
75d7e053dc | ||
![]() |
010c3718e3 | ||
![]() |
531dbd7af5 | ||
![]() |
3f8ca3553d | ||
![]() |
eb68c5e747 | ||
![]() |
e0b065cc33 | ||
![]() |
2da589d454 | ||
![]() |
738b16d873 | ||
![]() |
82bb3d8d2b | ||
![]() |
4e709e75da | ||
![]() |
c471255153 | ||
![]() |
ee79423124 | ||
![]() |
0761240c43 | ||
![]() |
ddd33c6bbd | ||
![]() |
aad2dbb93d | ||
![]() |
47063ca3ae | ||
![]() |
9c2cd65c0d | ||
![]() |
93d050f504 | ||
![]() |
ad0c928ab5 | ||
![]() |
1198fe8f6b | ||
![]() |
20900b76f9 | ||
![]() |
995da1e51d | ||
![]() |
c74a083672 | ||
![]() |
9f9d57590b | ||
![]() |
534858aaed | ||
![]() |
7c360778bb | ||
![]() |
e21ff6c0c9 | ||
![]() |
948f55d0b7 | ||
![]() |
fa5c13542c | ||
![]() |
077049d0b9 | ||
![]() |
6846c63252 | ||
![]() |
9d1e690751 | ||
![]() |
6552441b46 | ||
![]() |
8d514f4e2e | ||
![]() |
c219b09d4a | ||
![]() |
e11555218b | ||
![]() |
37b908aa62 | ||
![]() |
96635e9e18 | ||
![]() |
41f235a2f8 | ||
![]() |
1ead2dd35d | ||
![]() |
dab9ffb252 | ||
![]() |
e1db9e9848 | ||
![]() |
6b7705d5b2 | ||
![]() |
92975f0c11 | ||
![]() |
2a59188760 | ||
![]() |
f93cfb2e31 | ||
![]() |
16e6d8af55 | ||
![]() |
0c2699da27 | ||
![]() |
79c72390b9 | ||
![]() |
193f16238b | ||
![]() |
f2c0df5cd6 | ||
![]() |
81e7cd9339 | ||
![]() |
509015b498 | ||
![]() |
f9e2eed55d | ||
![]() |
cdac084fb4 | ||
![]() |
c395496e06 | ||
![]() |
1370b3c679 | ||
![]() |
f7f0a17ea2 | ||
![]() |
d93d3e2d75 | ||
![]() |
2cb982b506 | ||
![]() |
b39362295a | ||
![]() |
1d0bb72c5b | ||
![]() |
b1ead679f3 | ||
![]() |
ee9fe2c838 | ||
![]() |
3379414c76 | ||
![]() |
5e4878ed2b | ||
![]() |
06b991f48f | ||
![]() |
e57479dc30 | ||
![]() |
ecfa4f5866 | ||
![]() |
93e65a2a6c | ||
![]() |
daa3166cb6 | ||
![]() |
ce2e6b5cda | ||
![]() |
0a126a85a4 | ||
![]() |
ebcb230cff | ||
![]() |
749d7449f9 | ||
![]() |
8b7ec57cb4 | ||
![]() |
6fee7c8f8b | ||
![]() |
1686540594 | ||
![]() |
080844b9b3 | ||
![]() |
8c301fa933 | ||
![]() |
43007108e6 | ||
![]() |
e3f20f5088 | ||
![]() |
83477ce8d0 | ||
![]() |
e4ce676d3d | ||
![]() |
d29240d9eb | ||
![]() |
21dcbada2d | ||
![]() |
93853eca94 | ||
![]() |
c5c977855d | ||
![]() |
68ebfa2f18 | ||
![]() |
27698f1d13 | ||
![]() |
462d6ef826 | ||
![]() |
e477a57cc5 | ||
![]() |
a0e1155b28 | ||
![]() |
6b1b71ced4 | ||
![]() |
49b55b220e | ||
![]() |
079a9d4562 | ||
![]() |
41261ea4ec | ||
![]() |
c57097bcd4 | ||
![]() |
5b3acc15d1 | ||
![]() |
f9a83daebb | ||
![]() |
8b167535db | ||
![]() |
7366e44019 | ||
![]() |
7d548c6c00 | ||
![]() |
a490248f4d | ||
![]() |
c90229ed9a | ||
![]() |
3aef732e61 | ||
![]() |
98d3da79ef | ||
![]() |
d519bde5da | ||
![]() |
1980deffae | ||
![]() |
b60c02b065 | ||
![]() |
a2e9ae0055 | ||
![]() |
065b00b787 | ||
![]() |
bf42ccfbec | ||
![]() |
c9397ec8d4 | ||
![]() |
c87c4b5bbf | ||
![]() |
0066138379 | ||
![]() |
d8056ddecd | ||
![]() |
e4c866f387 | ||
![]() |
2216d3ca8d | ||
![]() |
2ab2503b6c | ||
![]() |
914888cf8b | ||
![]() |
51bcf5954f | ||
![]() |
96ca669fa4 | ||
![]() |
e77f9d2327 | ||
![]() |
ab9ff592c5 | ||
![]() |
a940462fc7 | ||
![]() |
6817b3697b | ||
![]() |
51bbcdb3c5 | ||
![]() |
0921360133 | ||
![]() |
98592608d4 | ||
![]() |
126525c03e | ||
![]() |
b216669a02 | ||
![]() |
753c190ef9 | ||
![]() |
d1ebe6689f | ||
![]() |
afe8d3076f | ||
![]() |
16f80f649b | ||
![]() |
42653787ea | ||
![]() |
ea4baa24b1 | ||
![]() |
04e54c6bb0 | ||
![]() |
829374337f | ||
![]() |
9717734d1c | ||
![]() |
9bb0e7a5ee | ||
![]() |
564a13285f | ||
![]() |
0fc6bf9a6e | ||
![]() |
f0127f1617 | ||
![]() |
e97492e579 | ||
![]() |
11c6ec6eb2 | ||
![]() |
6fb6635ceb | ||
![]() |
cdcb7c28c5 | ||
![]() |
ce00af8590 | ||
![]() |
9cee34bc94 | ||
![]() |
ba02bbb3b4 | ||
![]() |
569e1a4b77 | ||
![]() |
3721a525ce | ||
![]() |
b8220f5d0d | ||
![]() |
11abd0742e | ||
![]() |
6944d2dddb | ||
![]() |
2fd88c7ca4 | ||
![]() |
cda187222e | ||
![]() |
bc80c5d067 | ||
![]() |
332ffe8d74 | ||
![]() |
4c4149a09c | ||
![]() |
4d09e60f5b | ||
![]() |
c14a9f5b3d | ||
![]() |
e21e802fc6 | ||
![]() |
58d2f21dae | ||
![]() |
a3b0181503 | ||
![]() |
2409a36e29 | ||
![]() |
824abbf8d9 | ||
![]() |
e9b6965079 | ||
![]() |
b32e41f016 | ||
![]() |
7e7c7bbc17 | ||
![]() |
95b96eebdd | ||
![]() |
fb61b07bcf | ||
![]() |
c94ccd4207 | ||
![]() |
acfd3934a7 | ||
![]() |
b576682bdc | ||
![]() |
c37b58bbc3 | ||
![]() |
e515bef423 | ||
![]() |
a373983a86 | ||
![]() |
05988f88b7 | ||
![]() |
ec11aea880 | ||
![]() |
fded42c3bd | ||
![]() |
1da079f211 | ||
![]() |
84000190d3 | ||
![]() |
ddec605aef | ||
![]() |
96a1c444cc | ||
![]() |
0db4a32b9c | ||
![]() |
4e69e16fde | ||
![]() |
c3d533f37f | ||
![]() |
02815416bb | ||
![]() |
6331a3a346 | ||
![]() |
2f61620339 | ||
![]() |
202907b14c | ||
![]() |
4ee0cf6878 | ||
![]() |
a1c9a686b0 | ||
![]() |
20364bd658 | ||
![]() |
8846c7e0ae | ||
![]() |
99a8e53573 | ||
![]() |
6dff1b8c82 | ||
![]() |
8ea78b34ab | ||
![]() |
9f4acceb6a | ||
![]() |
cffe563d4d | ||
![]() |
6b6fed06b1 | ||
![]() |
46c7319f02 | ||
![]() |
c3020d8cdb | ||
![]() |
94c975e25a | ||
![]() |
9ffca1fedd | ||
![]() |
754bc52a79 | ||
![]() |
42690b6d57 | ||
![]() |
2ea6794c97 | ||
![]() |
f6258f70cb | ||
![]() |
892e9f2c23 | ||
![]() |
a4bdfb963f | ||
![]() |
85ccb25eb8 | ||
![]() |
aba8e04ab1 | ||
![]() |
3e4c9d90cf | ||
![]() |
7055244547 | ||
![]() |
ed0dbb8518 | ||
![]() |
b770a50dee | ||
![]() |
18d77ff455 | ||
![]() |
92f1ddaf0a | ||
![]() |
70f57409c3 | ||
![]() |
e8f206972a | ||
![]() |
e58a60902c | ||
![]() |
3c905d0db9 | ||
![]() |
e4d809b2b0 | ||
![]() |
a61494e634 | ||
![]() |
f379af6d17 | ||
![]() |
75ee002347 | ||
![]() |
e638351ef9 | ||
![]() |
a93298d4db | ||
![]() |
a6d5db3f9b | ||
![]() |
2b0655a71a | ||
![]() |
a96e6044cc | ||
![]() |
647ed1d205 | ||
![]() |
13472c6cf1 | ||
![]() |
b6ad25bf5e | ||
![]() |
40908c5fcd | ||
![]() |
97285711f3 | ||
![]() |
a718ccd0c5 | ||
![]() |
d547477bc2 | ||
![]() |
264dbad43a | ||
![]() |
ec79d0fc05 | ||
![]() |
eaa9494b71 | ||
![]() |
03390be5fa | ||
![]() |
252e94f499 | ||
![]() |
3229517b2c | ||
![]() |
b8ac06d9d1 | ||
![]() |
7747327561 | ||
![]() |
60d2eeaa5b | ||
![]() |
14de8ba4ea | ||
![]() |
46cf8cecc8 | ||
![]() |
fc7a3befda | ||
![]() |
a2154e1249 | ||
![]() |
a764cd5a40 | ||
![]() |
210932b3bf | ||
![]() |
e236994b76 | ||
![]() |
9213e35011 | ||
![]() |
4b3900a257 | ||
![]() |
050de1e4f6 | ||
![]() |
a083677af2 | ||
![]() |
74db0e9339 | ||
![]() |
48124bac18 | ||
![]() |
011a32a4ad | ||
![]() |
7ed5a30b5c | ||
![]() |
bb5a1eb99d | ||
![]() |
1437037ed2 | ||
![]() |
f930559076 | ||
![]() |
1216328c2d | ||
![]() |
651086d1d9 | ||
![]() |
1291bbfa50 | ||
![]() |
79af23e1ea | ||
![]() |
ac1514abf4 | ||
![]() |
99968eec3f | ||
![]() |
f18ac2d0bc | ||
![]() |
b2663a0f73 | ||
![]() |
83b2daca6a | ||
![]() |
169fab5146 | ||
![]() |
4175a550fd | ||
![]() |
091991606a | ||
![]() |
784ba59a08 | ||
![]() |
dd5ea7e996 | ||
![]() |
bba21735bf | ||
![]() |
0b75c02276 | ||
![]() |
801cd50744 | ||
![]() |
6187ada21f | ||
![]() |
882f7bbf1f | ||
![]() |
32e716e848 | ||
![]() |
65e2149b3e | ||
![]() |
1cd937a867 | ||
![]() |
540e150e4e | ||
![]() |
fffcbdae4c | ||
![]() |
6f3fcbcfe1 | ||
![]() |
eb6437b4db | ||
![]() |
defa8ba7b4 | ||
![]() |
f349754b55 | ||
![]() |
3af2963c74 | ||
![]() |
dc17f5e613 | ||
![]() |
485977de57 | ||
![]() |
2cc5c2d2e6 | ||
![]() |
e74028554e | ||
![]() |
7b02ccda86 | ||
![]() |
17a35bc645 | ||
![]() |
d2a6956afb | ||
![]() |
8d923c60b9 | ||
![]() |
425ccb1241 | ||
![]() |
c0edf0861b | ||
![]() |
5cc1c6eca0 | ||
![]() |
bb5ace2efb | ||
![]() |
9bd3e011e1 | ||
![]() |
89a4e6b889 | ||
![]() |
846bcd7dd1 | ||
![]() |
b7f5db432f | ||
![]() |
2d12dc3a58 | ||
![]() |
316c7331eb | ||
![]() |
fb017754e1 | ||
![]() |
ee2ac6c205 | ||
![]() |
47276bdb28 | ||
![]() |
0af6d9e291 | ||
![]() |
3146ecbae6 | ||
![]() |
b9833a2059 | ||
![]() |
540d6539be | ||
![]() |
3e0565e17c | ||
![]() |
9d4abbbc30 | ||
![]() |
6592646632 | ||
![]() |
5e9a354ff1 | ||
![]() |
2aac054f52 | ||
![]() |
f7552f1de4 | ||
![]() |
7c697f58f2 | ||
![]() |
a1d2132bf6 | ||
![]() |
225e2562c9 | ||
![]() |
a31411c679 | ||
![]() |
4c281fb29a | ||
![]() |
a08abec9f8 | ||
![]() |
d2452c2102 | ||
![]() |
b335e3d305 | ||
![]() |
6d3bcd8017 | ||
![]() |
8caf63896c | ||
![]() |
a78c06e3f0 | ||
![]() |
5f48fc36e1 | ||
![]() |
647c2a6cdd | ||
![]() |
7f8b1cd7f9 | ||
![]() |
33565f1533 | ||
![]() |
d8bc5828cd | ||
![]() |
fdc9b7cceb | ||
![]() |
9f6dbbc7ea | ||
![]() |
24ad2e5db6 | ||
![]() |
19bd0730ef | ||
![]() |
b1569b9c18 | ||
![]() |
e2dad6c3ff | ||
![]() |
8d4982ed33 | ||
![]() |
1741771b67 | ||
![]() |
7d7225fae6 | ||
![]() |
e60cda7051 | ||
![]() |
d18b89ced6 | ||
![]() |
b873d70369 | ||
![]() |
5d25143ef3 | ||
![]() |
3887475971 | ||
![]() |
8805e38398 | ||
![]() |
ddae599cab | ||
![]() |
dd1c95edcd | ||
![]() |
3c1de2e667 | ||
![]() |
ddd9665289 | ||
![]() |
6876e45f9e | ||
![]() |
0aca7f2a0d | ||
![]() |
db381fb21b | ||
![]() |
0215a62d5b | ||
![]() |
56261fabcb | ||
![]() |
76d8bfdff4 | ||
![]() |
325786430b | ||
![]() |
0fe2ac0437 | ||
![]() |
7dd547c5ff | ||
![]() |
74da6a6363 | ||
![]() |
da05a2ef7f | ||
![]() |
cdb1293eea | ||
![]() |
165dfd6c3e | ||
![]() |
8d070e30f5 | ||
![]() |
5dbb5cc3e5 | ||
![]() |
786c9adaa2 | ||
![]() |
3b28a24e97 | ||
![]() |
eb76c93098 | ||
![]() |
b3843992fc | ||
![]() |
5ff7be32f0 | ||
![]() |
e010223186 | ||
![]() |
21e50b89c9 | ||
![]() |
404160ad87 | ||
![]() |
ab60412cb4 | ||
![]() |
21c0a54a6b | ||
![]() |
66c497c5f1 | ||
![]() |
3ecceafa32 | ||
![]() |
4d831949a7 | ||
![]() |
fc94ed0a86 | ||
![]() |
3fae7ea16f | ||
![]() |
19d860fa9d | ||
![]() |
cfa08f8366 | ||
![]() |
97455cc31f | ||
![]() |
d2e7a6e799 | ||
![]() |
98a44bb18e | ||
![]() |
a9788886e6 | ||
![]() |
3ba67ee214 | ||
![]() |
2a6ff3c24f | ||
![]() |
4bef3e9ed3 | ||
![]() |
59b5c6075f | ||
![]() |
ed798d651a | ||
![]() |
3cc5d62f8a | ||
![]() |
e1c92184f0 | ||
![]() |
78cf11575d | ||
![]() |
32acecbf5e | ||
![]() |
71589848a0 | ||
![]() |
2b402ff8b7 | ||
![]() |
f139017bd0 | ||
![]() |
a6048fc792 | ||
![]() |
197b0b16e3 | ||
![]() |
1f9eb9ab07 | ||
![]() |
c7d4f2afdb | ||
![]() |
038a361a91 | ||
![]() |
d41d2c3751 | ||
![]() |
32d58144fd | ||
![]() |
8a094fe609 | ||
![]() |
dea870f4ea | ||
![]() |
8c4dfc9e6a | ||
![]() |
0b1c1877c5 | ||
![]() |
9ff169ccf4 | ||
![]() |
1aae94074e | ||
![]() |
ccfc2e5d8d | ||
![]() |
0f9c8e684a | ||
![]() |
5433b88e2d | ||
![]() |
9aecb906fb | ||
![]() |
800ea039ec | ||
![]() |
49f76a34b5 | ||
![]() |
17c99f7164 | ||
![]() |
717cd0aaa8 | ||
![]() |
1916c996d6 | ||
![]() |
1910fdde81 | ||
![]() |
4d34c1cd68 | ||
![]() |
d63569c73d | ||
![]() |
7bdeb1dfc1 | ||
![]() |
ff7ca32b79 | ||
![]() |
79c7d26495 | ||
![]() |
4295806736 | ||
![]() |
ff2342154b | ||
![]() |
cc51f0b3d3 | ||
![]() |
0f6eeecac0 | ||
![]() |
d222bf097c | ||
![]() |
0b592467d9 | ||
![]() |
742ac6e275 | ||
![]() |
038449467e | ||
![]() |
982e4fb448 | ||
![]() |
d099e47e00 | ||
![]() |
a6da1480b5 | ||
![]() |
9a1f2e6d7c | ||
![]() |
ff40d2d787 | ||
![]() |
eb9a5392bc | ||
![]() |
c679da9ae1 | ||
![]() |
90e87c4753 | ||
![]() |
66137ae429 | ||
![]() |
06aaf87aab | ||
![]() |
637ca59375 | ||
![]() |
8d67d0c1a8 | ||
![]() |
4d3238dc0b | ||
![]() |
b08bff8ba3 | ||
![]() |
5210f48bfc | ||
![]() |
fabc1d5bef | ||
![]() |
abc05cf335 | ||
![]() |
988f5ac342 | ||
![]() |
d43b398746 | ||
![]() |
a25434654e | ||
![]() |
1178319313 | ||
![]() |
50eb2d2782 | ||
![]() |
18bf3aa442 | ||
![]() |
ed32f5e241 | ||
![]() |
2cd23ffeec | ||
![]() |
d58df1fc6c | ||
![]() |
098b0fd1a0 | ||
![]() |
44124ab6b0 | ||
![]() |
3a643154be | ||
![]() |
5efe72415d | ||
![]() |
fd72b134d5 | ||
![]() |
735537d6b1 | ||
![]() |
1eaea43581 | ||
![]() |
7daaa00120 | ||
![]() |
f1ca793980 | ||
![]() |
1e55ace875 | ||
![]() |
2ebd97dec1 | ||
![]() |
487ea81316 | ||
![]() |
8f7bbc39a4 | ||
![]() |
9a692a3802 | ||
![]() |
e410e27547 | ||
![]() |
13fb24458c | ||
![]() |
b42e367045 | ||
![]() |
0db4174513 | ||
![]() |
37d4b0bee9 | ||
![]() |
88f6a92d22 | ||
![]() |
a4c54362c3 | ||
![]() |
fb7ec1555c | ||
![]() |
79ca6630d4 | ||
![]() |
d5dc675d37 | ||
![]() |
10505cac52 | ||
![]() |
5045a2de24 | ||
![]() |
3512b04093 | ||
![]() |
1b28b0ed5a | ||
![]() |
02c9f038b3 | ||
![]() |
b9b8b6597a | ||
![]() |
f1d5385515 | ||
![]() |
91b976ba46 | ||
![]() |
f17c9e4aeb | ||
![]() |
df5deab20b | ||
![]() |
9b9c5242eb | ||
![]() |
7e01865fb6 | ||
![]() |
1e3cdd3512 | ||
![]() |
53d1b12bc0 | ||
![]() |
c5126d1435 | ||
![]() |
a7bc65fbd8 | ||
![]() |
1d68544fbf | ||
![]() |
cf4df9d8ae | ||
![]() |
6506579e18 | ||
![]() |
a93aadc2e6 | ||
![]() |
3a31f81838 | ||
![]() |
4373547857 | ||
![]() |
d3d2823edf | ||
![]() |
86108812b8 | ||
![]() |
ddd67b2535 | ||
![]() |
6e98a7f2c9 | ||
![]() |
ecbd126d6a | ||
![]() |
7796891381 | ||
![]() |
871cf72363 | ||
![]() |
49f8e4f1e3 | ||
![]() |
6d79864135 | ||
![]() |
d4f3858a40 | ||
![]() |
0cc6e445d7 | ||
![]() |
411a9e1b86 | ||
![]() |
424a1c5d21 | ||
![]() |
ab35df454d | ||
![]() |
87f8be8110 | ||
![]() |
34964c2454 | ||
![]() |
cb14534d78 | ||
![]() |
2d3a1418c2 | ||
![]() |
61757032da | ||
![]() |
1545693255 | ||
![]() |
6e4bd3bbc2 | ||
![]() |
f8dec8f1c6 | ||
![]() |
6690d2969c | ||
![]() |
0cdfd5f275 | ||
![]() |
ccd834ea25 | ||
![]() |
41356227f2 | ||
![]() |
1b3c2743cc | ||
![]() |
50d2c94bd6 | ||
![]() |
6d139e5e95 | ||
![]() |
054add40a1 | ||
![]() |
7a821d4c99 | ||
![]() |
668af4be82 | ||
![]() |
de9f12ea96 | ||
![]() |
1be26e9f0c | ||
![]() |
b42c65d796 | ||
![]() |
f450ea64e6 | ||
![]() |
f3645a2aa3 | ||
![]() |
3b15156e4d | ||
![]() |
2ea5c1af57 | ||
![]() |
0d8087fbbc | ||
![]() |
405f4589a6 | ||
![]() |
967c7bc5d3 | ||
![]() |
3ceb3810d7 | ||
![]() |
ae737656f9 | ||
![]() |
c2630c93f2 | ||
![]() |
dedf5747cc | ||
![]() |
7ec9561a77 | ||
![]() |
5a200ade7c | ||
![]() |
1371aee3cc | ||
![]() |
9548916aa8 | ||
![]() |
72b2469be0 | ||
![]() |
484785456c | ||
![]() |
be220af9fb | ||
![]() |
bafcfdf8c5 | ||
![]() |
5d5f2e3a93 | ||
![]() |
348a79958d | ||
![]() |
2f0ba0a7e5 | ||
![]() |
9e6370819b | ||
![]() |
46ce4ec8cf | ||
![]() |
9983d896de | ||
![]() |
7c43e8c45a | ||
![]() |
f0791afade | ||
![]() |
135d8f04f9 | ||
![]() |
ae1ca67178 | ||
![]() |
d922f94d93 | ||
![]() |
3309e45ca1 | ||
![]() |
2ad499f93e | ||
![]() |
bd6868557d | ||
![]() |
7821d2d788 | ||
![]() |
e46674b6a7 | ||
![]() |
e58c267d66 | ||
![]() |
3b443c8cfc | ||
![]() |
8d76acfe6c | ||
![]() |
56fb56ccf0 | ||
![]() |
0538cdd226 | ||
![]() |
66ff1e063e | ||
![]() |
685b3d820a | ||
![]() |
f70d9933d1 | ||
![]() |
9e817251a8 | ||
![]() |
17882ed614 | ||
![]() |
3f7fde76c2 | ||
![]() |
4603b6d6b6 | ||
![]() |
03885e1b00 | ||
![]() |
4e0319c878 | ||
![]() |
b07d2a3827 | ||
![]() |
9e43c11480 | ||
![]() |
5fee4439a0 | ||
![]() |
563fc92dd4 | ||
![]() |
b587c5a2f8 | ||
![]() |
e8be792130 | ||
![]() |
e3e715666f | ||
![]() |
06221297bf | ||
![]() |
a8b1ce2447 | ||
![]() |
71d7908656 | ||
![]() |
ecaab085db | ||
![]() |
f445ee1e6c | ||
![]() |
307b09e7eb | ||
![]() |
c651a53558 | ||
![]() |
d9d9950d8d | ||
![]() |
2ad37e1832 | ||
![]() |
cad97135b3 | ||
![]() |
de363f1404 | ||
![]() |
fb96b94ed0 | ||
![]() |
316781be48 | ||
![]() |
9c14f98583 | ||
![]() |
55608d8381 | ||
![]() |
a3b12ec420 | ||
![]() |
dc76b90705 | ||
![]() |
7d0488b11e | ||
![]() |
152c482fee | ||
![]() |
913b0f51ca | ||
![]() |
fdc7a78652 | ||
![]() |
88f4bf4ae4 | ||
![]() |
fd0b109bf7 | ||
![]() |
8d9a40a820 | ||
![]() |
acce6043e0 | ||
![]() |
a87313497b | ||
![]() |
43b1afb2cf | ||
![]() |
5f36d4af15 | ||
![]() |
698fa85f38 | ||
![]() |
8a4b095a94 | ||
![]() |
0e8eea5a70 | ||
![]() |
2b6761fd3e | ||
![]() |
7d7749ee47 | ||
![]() |
5c052e6c04 | ||
![]() |
506b86773d | ||
![]() |
3e6092f5b2 | ||
![]() |
05cb0e5a7d | ||
![]() |
4cadee65b3 | ||
![]() |
2adec6c8c0 | ||
![]() |
66cf0e3f55 | ||
![]() |
dbb48e4b29 | ||
![]() |
b7e8868235 | ||
![]() |
1c2d8c8663 | ||
![]() |
ab0377746a | ||
![]() |
bf3c156654 | ||
![]() |
c1d420ec60 | ||
![]() |
0df38c3e2b | ||
![]() |
0ea9305f99 | ||
![]() |
8d375b44eb | ||
![]() |
167fa429f0 | ||
![]() |
bf5ae17c16 | ||
![]() |
9613da63dc | ||
![]() |
e510abbc8c | ||
![]() |
3eebf4d162 | ||
![]() |
e22758bfb2 | ||
![]() |
8142051a3b | ||
![]() |
0ea41eaa51 | ||
![]() |
021e89d702 | ||
![]() |
dffad6b0b7 | ||
![]() |
3a4158e4fa | ||
![]() |
939a4eb5c9 | ||
![]() |
17feabcba0 | ||
![]() |
4e2f000b3c | ||
![]() |
3cad7f99e0 | ||
![]() |
04f21d86cf | ||
![]() |
44a6587608 | ||
![]() |
1e9ebfb00c | ||
![]() |
9d8fcb3296 | ||
![]() |
a813d7e961 | ||
![]() |
881fff1a2f | ||
![]() |
e974599593 | ||
![]() |
1845a915b0 | ||
![]() |
4597f50deb | ||
![]() |
751888979c | ||
![]() |
0ffd3225d2 | ||
![]() |
2d0e899819 | ||
![]() |
f117aef2ea | ||
![]() |
c80f205f86 | ||
![]() |
31bf00d3ec | ||
![]() |
3eca54384d | ||
![]() |
79dd264517 | ||
![]() |
56fbbde2ed | ||
![]() |
820975595c | ||
![]() |
93c7b25ccd | ||
![]() |
43378636d0 | ||
![]() |
73c637ad60 | ||
![]() |
fc1e698914 | ||
![]() |
55d18b7db9 | ||
![]() |
630fc3839e | ||
![]() |
489543cd25 | ||
![]() |
8ff481b436 | ||
![]() |
ce3ad31e2e | ||
![]() |
12bf850c84 | ||
![]() |
18a0ab6b3b | ||
![]() |
520aa08d42 | ||
![]() |
52af6d957e | ||
![]() |
993ca8c6de | ||
![]() |
0f3c5d3893 | ||
![]() |
a1e1038736 | ||
![]() |
9fe5ac6614 | ||
![]() |
214e200f95 | ||
![]() |
2379b49177 | ||
![]() |
16d5d4b6e1 | ||
![]() |
0970cb054c | ||
![]() |
801202349a | ||
![]() |
2d31697d82 | ||
![]() |
d8b784a15e | ||
![]() |
da8e07edb5 | ||
![]() |
c0c4a16053 | ||
![]() |
b6154189e8 | ||
![]() |
1bc0d7080a | ||
![]() |
5bc0832766 | ||
![]() |
081b5e3d4e | ||
![]() |
7665feeb52 | ||
![]() |
5400366b90 | ||
![]() |
a343ed13e5 | ||
![]() |
ed7b2a64f8 | ||
![]() |
aca8dde362 | ||
![]() |
599a258421 | ||
![]() |
fd03a52468 | ||
![]() |
391f9635cc | ||
![]() |
4ec063fade | ||
![]() |
f66684fdeb | ||
![]() |
c399963243 | ||
![]() |
7d9bb170b7 | ||
![]() |
9ff00e35f8 | ||
![]() |
4876c09b2a | ||
![]() |
8df3db4b97 | ||
![]() |
117ceac82b | ||
![]() |
e502c69140 | ||
![]() |
9791756284 | ||
![]() |
c33b31116c | ||
![]() |
dc11d2a2d8 | ||
![]() |
54a125f677 | ||
![]() |
81359cecdf | ||
![]() |
660c04803e | ||
![]() |
f9ea1dac30 | ||
![]() |
38e791fb2f | ||
![]() |
d0df6c983c | ||
![]() |
5745ba6a8e | ||
![]() |
005150ed69 | ||
![]() |
f72548956f | ||
![]() |
bbb94fd499 | ||
![]() |
46c27e4552 | ||
![]() |
4ecb587eff | ||
![]() |
a82c434447 | ||
![]() |
1261fe69a3 | ||
![]() |
20a1d23b39 | ||
![]() |
eb7738221c | ||
![]() |
7103efac9d | ||
![]() |
e7980275c0 | ||
![]() |
1e1efe1f61 | ||
![]() |
ad2ab4927c | ||
![]() |
9a9dfb1d0d | ||
![]() |
3903f16cd6 | ||
![]() |
5bf405b2af | ||
![]() |
5b1282c708 | ||
![]() |
d81e0f5789 | ||
![]() |
2fbbd04979 | ||
![]() |
890959eea8 | ||
![]() |
bc37e3f830 | ||
![]() |
d69f9fe266 | ||
![]() |
cca3af03ac | ||
![]() |
61656464d8 | ||
![]() |
f846349824 | ||
![]() |
d89590eab9 | ||
![]() |
e6ac640d2e | ||
![]() |
f531e3cf69 | ||
![]() |
3886faced8 | ||
![]() |
d0efca893b | ||
![]() |
9bc78bdc5b | ||
![]() |
93e5c99fff | ||
![]() |
7fe0f73838 | ||
![]() |
9b83875c13 | ||
![]() |
9cb5da400c | ||
![]() |
45483a1d0d | ||
![]() |
86183ebf55 | ||
![]() |
edf802956e | ||
![]() |
a948ee9601 | ||
![]() |
03fc3aad12 | ||
![]() |
3d0bdfaa70 | ||
![]() |
5a922dc162 | ||
![]() |
49fa3d82b7 | ||
![]() |
f696a1b3b3 | ||
![]() |
8cf66ed732 | ||
![]() |
c957ad0067 | ||
![]() |
0154746b9f | ||
![]() |
f645a6d43e | ||
![]() |
860db986fc | ||
![]() |
74a0fdf961 | ||
![]() |
e5dbd28afd | ||
![]() |
3ce6efc4dd | ||
![]() |
106c694993 | ||
![]() |
a5d46a15f5 | ||
![]() |
893d28469f | ||
![]() |
f66374f6a8 | ||
![]() |
81e62af94a | ||
![]() |
f691b13450 | ||
![]() |
5c78cbd3be | ||
![]() |
cf9a76fe8f | ||
![]() |
790dd8cc92 | ||
![]() |
87019144f6 | ||
![]() |
7ca38d64d2 | ||
![]() |
9434919f76 | ||
![]() |
be4abf9d6e | ||
![]() |
41a230758c | ||
![]() |
70229b55ec | ||
![]() |
dd3b71d17c | ||
![]() |
1bdceb8a65 | ||
![]() |
3f09316e3b | ||
![]() |
b52765c8c9 | ||
![]() |
79bf167c0d | ||
![]() |
8ed900263e | ||
![]() |
1d46597c8b | ||
![]() |
f32f09e78f | ||
![]() |
b67446a8fa | ||
![]() |
8aa1060c34 | ||
![]() |
e3708a89cc | ||
![]() |
e251837445 | ||
![]() |
644e3d4cdb | ||
![]() |
f8b5fe5724 | ||
![]() |
c8d2c6ea77 | ||
![]() |
0fa873c0fe | ||
![]() |
00037cd44b | ||
![]() |
e0f36f9d8b | ||
![]() |
bea751beb7 | ||
![]() |
ba47cdcc0b | ||
![]() |
4aa2876c75 | ||
![]() |
58c027ac8b | ||
![]() |
4d04068184 | ||
![]() |
1e195acee4 | ||
![]() |
e8a79114b8 | ||
![]() |
f6cc8e3512 | ||
![]() |
465cbccdaf | ||
![]() |
be541997af | ||
![]() |
c2c83e16a2 | ||
![]() |
c8f8d11ac4 | ||
![]() |
878ee341d6 | ||
![]() |
1b178dffa3 | ||
![]() |
2fa8f54d08 | ||
![]() |
705cd2cabe | ||
![]() |
36d28b73fc | ||
![]() |
5530226366 | ||
![]() |
750218c5e5 | ||
![]() |
36935bd869 | ||
![]() |
816cd9802f | ||
![]() |
3beda17773 | ||
![]() |
781740c19d | ||
![]() |
92e38b6e27 | ||
![]() |
773a9d85a1 | ||
![]() |
00545ef4d6 | ||
![]() |
e59f7fba6a | ||
![]() |
d2a5948ae8 | ||
![]() |
348f83670a | ||
![]() |
6b9968e8b1 | ||
![]() |
d94d51d00b | ||
![]() |
126e212fb0 | ||
![]() |
ae64fd8d6f | ||
![]() |
027f70562e | ||
![]() |
e1dd9c0396 | ||
![]() |
4a34c501c1 | ||
![]() |
cb788bea9c | ||
![]() |
013e44ec5d | ||
![]() |
c9012c798e | ||
![]() |
0fa65ad6d5 | ||
![]() |
f6b50d52d4 | ||
![]() |
61a0e79ad6 | ||
![]() |
b8e963595e | ||
![]() |
0233029d5a | ||
![]() |
c733cf223d | ||
![]() |
7c93e4a09b | ||
![]() |
a0ef2ac59c | ||
![]() |
f537ef5746 | ||
![]() |
0656059ae7 | ||
![]() |
49d1e1c9b1 | ||
![]() |
328de8442d | ||
![]() |
ea13744e53 | ||
![]() |
f7b6aefe0e | ||
![]() |
9c63abbfe7 | ||
![]() |
a75354c045 | ||
![]() |
e7393d0fc5 | ||
![]() |
15b9176d53 | ||
![]() |
efc7a2abc3 | ||
![]() |
77be7b777c | ||
![]() |
a17029ba49 | ||
![]() |
24804e67f5 | ||
![]() |
845b328734 | ||
![]() |
4c459ddabd | ||
![]() |
e85c69e1b7 | ||
![]() |
f09b1022aa | ||
![]() |
d0f6fa036b | ||
![]() |
77053da5c6 | ||
![]() |
9e3a6ccf69 | ||
![]() |
713c9280ca | ||
![]() |
0d761d19b9 | ||
![]() |
5a9201ff47 | ||
![]() |
85f1a2809f | ||
![]() |
4f511bd06e | ||
![]() |
bb2c5617d6 | ||
![]() |
cba6f2d426 | ||
![]() |
54130b542d | ||
![]() |
0a334ea081 | ||
![]() |
17d94cf3b9 | ||
![]() |
6f4ccb6832 | ||
![]() |
988d26afe4 | ||
![]() |
270d4ec23d | ||
![]() |
6caaa8cadc | ||
![]() |
bae49ff278 | ||
![]() |
4f48a4ea2a | ||
![]() |
0fa7a4e3b4 | ||
![]() |
d7e6e33d07 | ||
![]() |
965eda3b9a | ||
![]() |
66dfc0169f | ||
![]() |
1855a55d8c | ||
![]() |
72dc7a0f7b | ||
![]() |
b19dbee3f7 | ||
![]() |
c7ccc68b15 | ||
![]() |
be34e93f20 | ||
![]() |
cb76638699 | ||
![]() |
88992de283 | ||
![]() |
fed1c96e10 | ||
![]() |
7489b51f61 | ||
![]() |
2cf6389142 | ||
![]() |
f5050d4ef2 | ||
![]() |
0ac3bf837b | ||
![]() |
8c87641258 | ||
![]() |
c14463d1e4 | ||
![]() |
90e82a2c05 | ||
![]() |
105b9834fb | ||
![]() |
44cf27b5fc | ||
![]() |
142f46cac1 | ||
![]() |
0ac02ba342 | ||
![]() |
ab131642a1 | ||
![]() |
b98c05dc50 | ||
![]() |
664c0d3201 | ||
![]() |
3e4ce10342 | ||
![]() |
0a2e3f14e7 | ||
![]() |
bc1dec71c5 | ||
![]() |
9752e43644 | ||
![]() |
d4fd582fb2 | ||
![]() |
58504620c5 | ||
![]() |
6f0e28d024 | ||
![]() |
53c813961e | ||
![]() |
c76331e13f | ||
![]() |
e828895f20 | ||
![]() |
2d49080056 | ||
![]() |
6a8964b75b | ||
![]() |
a082bbcb30 | ||
![]() |
1c84f63a40 | ||
![]() |
889427b334 | ||
![]() |
a050db4a6f | ||
![]() |
09d39c023c | ||
![]() |
3b569cc686 | ||
![]() |
bbeaeee3c7 | ||
![]() |
9db5dc9a46 | ||
![]() |
d742188e3b | ||
![]() |
3a8c97be45 | ||
![]() |
605e8f53b1 | ||
![]() |
34303ccd55 | ||
![]() |
127cd9def1 | ||
![]() |
2987393768 | ||
![]() |
ee17ecbd39 | ||
![]() |
5e9ecffb4f | ||
![]() |
146df5fbd3 | ||
![]() |
8224c74f08 | ||
![]() |
058a31e479 | ||
![]() |
a2c29e9128 | ||
![]() |
7531f05c7c | ||
![]() |
7b3acdff5d | ||
![]() |
3991faf464 | ||
![]() |
2fa66cfce2 | ||
![]() |
06619763a2 | ||
![]() |
a1f6a70522 | ||
![]() |
1816fb66c7 | ||
![]() |
02dec48bab | ||
![]() |
40ff225b8e | ||
![]() |
37a9d6aabe | ||
![]() |
c7d2c2aa9f | ||
![]() |
3bbffe96e1 | ||
![]() |
6f14c8ee5a | ||
![]() |
06d843c2c4 | ||
![]() |
af677245fb | ||
![]() |
8f716ca06a | ||
![]() |
ad9d70b0e6 | ||
![]() |
239e0a2d43 | ||
![]() |
e528b227a6 | ||
![]() |
e807ae4f2e | ||
![]() |
44d0522848 | ||
![]() |
a8f5c524a0 | ||
![]() |
d7e5708bb4 | ||
![]() |
45ee4d7c78 | ||
![]() |
0bcdbbeedc | ||
![]() |
7cda1fc4b6 | ||
![]() |
4026148ef1 | ||
![]() |
a0741cacef | ||
![]() |
088aff1620 | ||
![]() |
b3428bcf88 | ||
![]() |
f8b468fda2 | ||
![]() |
bba77163ff | ||
![]() |
f61142cce5 | ||
![]() |
c55662f247 | ||
![]() |
b0b3c62a84 | ||
![]() |
117cdb28ce | ||
![]() |
6f719c74a9 | ||
![]() |
608a122aef | ||
![]() |
74dbb721aa | ||
![]() |
17f17c284c | ||
![]() |
a34060cdb4 | ||
![]() |
168ca2dcc8 | ||
![]() |
22f303e422 | ||
![]() |
f52e935f36 | ||
![]() |
f71439d527 | ||
![]() |
669940065f | ||
![]() |
520dc12c0e | ||
![]() |
293c814688 | ||
![]() |
c477cda59f | ||
![]() |
3e4c4df664 | ||
![]() |
324290a5eb | ||
![]() |
de90b5e9ad | ||
![]() |
11261594d8 | ||
![]() |
e3215702ae | ||
![]() |
2323f9deda | ||
![]() |
9822185d53 | ||
![]() |
6588b3eef0 | ||
![]() |
a026f3be4b | ||
![]() |
4ea1c9f8e5 | ||
![]() |
e068c38618 | ||
![]() |
7aa36717bb | ||
![]() |
fb5df9722b | ||
![]() |
a9e7360775 | ||
![]() |
7568bbc491 | ||
![]() |
e979518a69 | ||
![]() |
47e9caede7 | ||
![]() |
0c751f904f | ||
![]() |
be39be87f6 | ||
![]() |
91c2b12205 | ||
![]() |
19ad4ac03d | ||
![]() |
a48f19157a | ||
![]() |
ef6f5367dc | ||
![]() |
5997ad8512 | ||
![]() |
0a6a726d26 | ||
![]() |
248745004a | ||
![]() |
0021339b92 | ||
![]() |
0ffaa6c785 | ||
![]() |
3c59ef247f | ||
![]() |
01dbe23b6f | ||
![]() |
8273db28f3 | ||
![]() |
9a8b45c133 | ||
![]() |
18ac200efe | ||
![]() |
2f0e308c7d | ||
![]() |
a9f17a28db | ||
![]() |
88f6b637a0 | ||
![]() |
855c684708 | ||
![]() |
ca2fe6859f | ||
![]() |
f8791db4be | ||
![]() |
89ac2061f5 | ||
![]() |
cd779dae46 | ||
![]() |
d4e7a87b96 | ||
![]() |
10a7435ebb | ||
![]() |
3606d6a7cd | ||
![]() |
73db49f8ef | ||
![]() |
2f9e3cca3d | ||
![]() |
432390c4c4 | ||
![]() |
99a65dc93e | ||
![]() |
8657c87c8c | ||
![]() |
9f6649b248 | ||
![]() |
5c1d6c957b | ||
![]() |
68fe202f06 | ||
![]() |
6c81e2ce3f | ||
![]() |
bc0392af66 | ||
![]() |
e5008ced28 | ||
![]() |
c97db54e54 | ||
![]() |
50d7164978 | ||
![]() |
bb21e0f191 | ||
![]() |
d6c4e17411 | ||
![]() |
782a369f92 | ||
![]() |
a4a3efb75b | ||
![]() |
a770153af0 | ||
![]() |
9104cd5441 | ||
![]() |
530974e724 | ||
![]() |
a27953f716 | ||
![]() |
b0eed5ade6 | ||
![]() |
4a886a3e8f | ||
![]() |
e40c4c997e | ||
![]() |
c030f7f40d | ||
![]() |
f8cfd3a61f | ||
![]() |
faaa4fdf18 | ||
![]() |
8f5a9a741b | ||
![]() |
25b51cad3d | ||
![]() |
a1f7c644be | ||
![]() |
e6258e6590 | ||
![]() |
9cf8c4f689 | ||
![]() |
854ec3ffb3 | ||
![]() |
51cdd7ceac | ||
![]() |
860e83e52f | ||
![]() |
8a35fb0d1c | ||
![]() |
0bd30e90bb | ||
![]() |
92aa6e6282 | ||
![]() |
78792eae68 | ||
![]() |
94feb31516 | ||
![]() |
b62445871e | ||
![]() |
4e27640076 | ||
![]() |
81f9f90e47 | ||
![]() |
243a55d603 | ||
![]() |
c4c54683a9 | ||
![]() |
174802e15f | ||
![]() |
93fb9db1b0 | ||
![]() |
33eb63e380 | ||
![]() |
efb6950299 | ||
![]() |
dacec4ec82 | ||
![]() |
a4e3c67e44 | ||
![]() |
e66995d840 | ||
![]() |
713e02e03e | ||
![]() |
97921915a8 | ||
![]() |
0c68b655f6 | ||
![]() |
dea3f2b417 | ||
![]() |
02b8412572 | ||
![]() |
b8b68e6ea9 | ||
![]() |
a36286cf89 | ||
![]() |
c7de76569e | ||
![]() |
a53b44a266 | ||
![]() |
c910e47f53 | ||
![]() |
c53e22af19 | ||
![]() |
046cc9e776 | ||
![]() |
d31fa84c7c | ||
![]() |
3539452ef0 | ||
![]() |
3ba527d82a | ||
![]() |
5287b2ddbf | ||
![]() |
2b654b37f1 | ||
![]() |
2e19a4d56b | ||
![]() |
7008a51449 | ||
![]() |
b138373c6d | ||
![]() |
0e43963acb | ||
![]() |
eaeaa7b7fd | ||
![]() |
335907d187 | ||
![]() |
80f8432b52 | ||
![]() |
5f369ff1d4 | ||
![]() |
bedb338dad | ||
![]() |
62be425bcc | ||
![]() |
afc6e3fa46 | ||
![]() |
b3a8b6b198 | ||
![]() |
eaa56afda9 | ||
![]() |
1ca85e835c | ||
![]() |
7b6f71dced | ||
![]() |
22776f8fdb | ||
![]() |
e304e82b66 | ||
![]() |
b5568723ce | ||
![]() |
c132f42985 | ||
![]() |
ab3fa46502 | ||
![]() |
c758d8b040 | ||
![]() |
79409e35e1 | ||
![]() |
0137446248 | ||
![]() |
e564932792 | ||
![]() |
91725ddc92 | ||
![]() |
dee7ff4a92 | ||
![]() |
21677816a0 | ||
![]() |
a0e8922d13 | ||
![]() |
db11ed27bd | ||
![]() |
3bcb350711 | ||
![]() |
521c2b25c2 | ||
![]() |
0de32693d0 | ||
![]() |
4c0d75bc8e | ||
![]() |
8413828995 | ||
![]() |
af32603ae3 | ||
![]() |
043dbc05df | ||
![]() |
666334bd48 | ||
![]() |
85169a04cf | ||
![]() |
f97763d7b3 | ||
![]() |
cf83842304 | ||
![]() |
0e4d3feb94 | ||
![]() |
843fcc96f7 | ||
![]() |
719b08313f | ||
![]() |
b39c255d8c | ||
![]() |
d634ae9b60 | ||
![]() |
5e7f42e17e | ||
![]() |
7950abcc46 | ||
![]() |
dd61302f5b | ||
![]() |
0a440776e7 | ||
![]() |
31f4ec92f6 | ||
![]() |
c41c8c2f86 | ||
![]() |
22098745e7 | ||
![]() |
b54af02b51 | ||
![]() |
a264f2dc55 | ||
![]() |
6f08fe20e9 | ||
![]() |
a08a254df3 | ||
![]() |
28edc8e2d6 | ||
![]() |
5595311209 | ||
![]() |
d478e13639 | ||
![]() |
13f4262354 | ||
![]() |
6a69560847 | ||
![]() |
27cca19c9a | ||
![]() |
befff0e13f | ||
![]() |
142b522946 | ||
![]() |
52d9883812 | ||
![]() |
6c9dd8b650 | ||
![]() |
9900c7a348 | ||
![]() |
e8011d7872 | ||
![]() |
540d1e0561 | ||
![]() |
48ad9e19e4 | ||
![]() |
cc19eba579 | ||
![]() |
3119b1ef7f | ||
![]() |
a654cbfd2f | ||
![]() |
0d68591c8e | ||
![]() |
c07196dc2f | ||
![]() |
2b9de2e24a | ||
![]() |
390532cbc6 | ||
![]() |
b3e6aa9316 | ||
![]() |
3775939303 | ||
![]() |
1776f72c96 | ||
![]() |
54f0b0ec4b | ||
![]() |
65c371ed6e | ||
![]() |
c0eb207b76 | ||
![]() |
89ae725d23 | ||
![]() |
94ef26428b | ||
![]() |
143c092187 | ||
![]() |
c4d7294b5c | ||
![]() |
ad03a09451 | ||
![]() |
abdf23c6c0 | ||
![]() |
cd2e7fafd4 | ||
![]() |
22324ec288 | ||
![]() |
b3c5352386 | ||
![]() |
40cc022c70 | ||
![]() |
67aa86f1e0 | ||
![]() |
95e207933d | ||
![]() |
25f95b0000 | ||
![]() |
b34ffc99b8 | ||
![]() |
170a1c4709 | ||
![]() |
877baae03e | ||
![]() |
b80f16157e | ||
![]() |
0c008cc4f8 | ||
![]() |
0104f8f64a | ||
![]() |
d2d6ef431f | ||
![]() |
ed8782fe0a | ||
![]() |
518be73a5c | ||
![]() |
f676dab8dc | ||
![]() |
f481f9333d | ||
![]() |
f49c88f1c4 | ||
![]() |
17b2c89116 | ||
![]() |
9b5c21309b | ||
![]() |
596c8960b2 | ||
![]() |
d783e7df83 | ||
![]() |
a7a6ac112e | ||
![]() |
4f716c731a | ||
![]() |
65c6ba1fc4 | ||
![]() |
ff14f8ef16 | ||
![]() |
824dc51341 | ||
![]() |
e66e6bb28a | ||
![]() |
dcfe23a038 | ||
![]() |
0b83fd3217 | ||
![]() |
9052e33a10 | ||
![]() |
71fa3b1337 | ||
![]() |
945704208a | ||
![]() |
94639eb66f | ||
![]() |
ffd75c2e0c | ||
![]() |
98c1140c44 | ||
![]() |
17723691e5 | ||
![]() |
803c21f4b2 | ||
![]() |
eb20ed1f69 | ||
![]() |
d62a88eb0d | ||
![]() |
2cff71d71c | ||
![]() |
833096ce42 | ||
![]() |
af6b5d55db | ||
![]() |
f53feeea8b | ||
![]() |
219ced474d | ||
![]() |
2504e4ad0d | ||
![]() |
8be470eea8 | ||
![]() |
c71555f030 | ||
![]() |
581f005aad | ||
![]() |
0e91d2e0e9 | ||
![]() |
0425baf883 | ||
![]() |
f96b9bf761 | ||
![]() |
ae09fe3da7 | ||
![]() |
483b03562a | ||
![]() |
bb5cae2c94 | ||
![]() |
868c897ad7 | ||
![]() |
4cd84c4b13 | ||
![]() |
228f82fcda | ||
![]() |
5bb0e7080a | ||
![]() |
dae48a8064 | ||
![]() |
4c02882f8a | ||
![]() |
6d212fa045 | ||
![]() |
102090916e | ||
![]() |
582dd705c1 | ||
![]() |
d6cc02d301 | ||
![]() |
50a4951ddc | ||
![]() |
4733127a04 | ||
![]() |
7037c48e58 | ||
![]() |
0246332954 | ||
![]() |
ffb2c1fb4a | ||
![]() |
ef161d4aeb | ||
![]() |
9032e6779d | ||
![]() |
c83fce86d4 | ||
![]() |
3a3f98b32b | ||
![]() |
4a8c4110e3 | ||
![]() |
566a2e4c79 | ||
![]() |
a0572a40ab | ||
![]() |
d3dec8fae1 | ||
![]() |
d7deec1993 | ||
![]() |
a254dad2e5 | ||
![]() |
28327f10a2 | ||
![]() |
b139a7636f | ||
![]() |
8dbc5df952 | ||
![]() |
155e8d7d78 | ||
![]() |
d42495033e | ||
![]() |
8d1e56e210 | ||
![]() |
0867d3173c | ||
![]() |
1dcf7d5b03 | ||
![]() |
1e1d326b50 | ||
![]() |
62296f9281 | ||
![]() |
cf3ce189ab | ||
![]() |
805aea501a | ||
![]() |
92cbd1c69e | ||
![]() |
fb80e8a1c4 | ||
![]() |
9275a771bf | ||
![]() |
4f81f9d5ea | ||
![]() |
65aa43bf66 | ||
![]() |
d73aba2500 | ||
![]() |
9a8b8009f4 | ||
![]() |
dc30785947 | ||
![]() |
62227e1bba | ||
![]() |
1ef0a1b1be | ||
![]() |
5db247da9d | ||
![]() |
214cd9d1e6 | ||
![]() |
a558074474 | ||
![]() |
cba3edbc37 | ||
![]() |
bb19265ba8 | ||
![]() |
2d397beb00 | ||
![]() |
6ab12ec8f4 | ||
![]() |
c1bd5e9144 | ||
![]() |
bffe6d5670 | ||
![]() |
eaa7b49bd6 | ||
![]() |
89fb8b32f6 | ||
![]() |
c12d7b6d21 | ||
![]() |
6834304feb | ||
![]() |
aa80c33360 | ||
![]() |
c9d632e485 | ||
![]() |
d3778d65fa | ||
![]() |
3208dcabdc | ||
![]() |
1449c82484 | ||
![]() |
937491288e | ||
![]() |
73e09ddecf | ||
![]() |
8fb13036ee | ||
![]() |
fdcab58ccf | ||
![]() |
57af88a654 | ||
![]() |
9353fc6a27 | ||
![]() |
9409b5623d | ||
![]() |
deb4910c5b | ||
![]() |
e9275392c1 | ||
![]() |
1616a09b61 | ||
![]() |
bbe6e9e8d1 | ||
![]() |
7e7b0622a6 | ||
![]() |
b37d34307d | ||
![]() |
1fdfd45995 | ||
![]() |
fcb52454ac | ||
![]() |
01fd23b625 | ||
![]() |
b9fe30dad4 | ||
![]() |
f15d5a0661 | ||
![]() |
d131147a5c | ||
![]() |
83280d44d0 | ||
![]() |
e8a82ed24d | ||
![]() |
113e95ec02 | ||
![]() |
b565b496ba | ||
![]() |
27ba1766e7 | ||
![]() |
0b3af098e1 | ||
![]() |
9bcf5bed05 | ||
![]() |
491467b0b9 | ||
![]() |
347a5f68da | ||
![]() |
e37985f590 | ||
![]() |
84ea9ee0f9 | ||
![]() |
04c90b8cf5 | ||
![]() |
8086f40123 | ||
![]() |
722d477bc6 | ||
![]() |
31ee158394 | ||
![]() |
1de3966b84 | ||
![]() |
2910163df1 | ||
![]() |
040b5bbc52 | ||
![]() |
456ea1bb1d | ||
![]() |
d109e429dd | ||
![]() |
237c15888d | ||
![]() |
a5ebd28797 | ||
![]() |
155e39187c | ||
![]() |
8e69882c03 | ||
![]() |
f5106148e3 | ||
![]() |
eef2d20e23 | ||
![]() |
d8e3e6d606 | ||
![]() |
865fdf4dcd | ||
![]() |
2f9987c816 | ||
![]() |
5b908cfb5f | ||
![]() |
5fed968b1d | ||
![]() |
0e4efb15f5 | ||
![]() |
ad8804885c | ||
![]() |
e7d75c8db7 | ||
![]() |
018347f802 | ||
![]() |
61c434c030 | ||
![]() |
ffbbe3d103 | ||
![]() |
0eb7b49a17 | ||
![]() |
288cf20f98 | ||
![]() |
c5d4b6b311 | ||
![]() |
efb97da0da | ||
![]() |
d68b68fc43 | ||
![]() |
42f1be8030 | ||
![]() |
83dd99177f | ||
![]() |
46dae0b8bb | ||
![]() |
4e750caf96 | ||
![]() |
a756fa60ef | ||
![]() |
2cf09c5446 | ||
![]() |
087369aeeb | ||
![]() |
940730093b | ||
![]() |
bc0885f364 | ||
![]() |
1bd486666b | ||
![]() |
ab5e69c442 | ||
![]() |
e155cb4fee | ||
![]() |
12df6024db | ||
![]() |
598c295707 | ||
![]() |
c42b304f62 | ||
![]() |
2a7908c939 | ||
![]() |
c4ed09ad4e | ||
![]() |
ab78900e29 | ||
![]() |
980701114f | ||
![]() |
799cc143c9 | ||
![]() |
205e5278c6 | ||
![]() |
3330fc2e93 | ||
![]() |
bcb8f69cc5 | ||
![]() |
1eb09c8ce2 | ||
![]() |
b97ee34947 | ||
![]() |
bee4b80754 | ||
![]() |
0787ea8b26 | ||
![]() |
204cbfb68d | ||
![]() |
e6d4475a6c | ||
![]() |
a959487597 | ||
![]() |
9015cb7111 | ||
![]() |
96cfb076ce | ||
![]() |
3a5598affa | ||
![]() |
36151bd1d7 | ||
![]() |
6a91e09218 | ||
![]() |
3f935d0e2c | ||
![]() |
f95e9b68d6 | ||
![]() |
46f7c92c9a | ||
![]() |
87ca9490b0 | ||
![]() |
ff447f4fd5 | ||
![]() |
bffb35612c | ||
![]() |
01365cbd74 | ||
![]() |
6059d38f21 | ||
![]() |
451b8579ef | ||
![]() |
774cd9a26c | ||
![]() |
d3cd746067 | ||
![]() |
38b0c47f37 | ||
![]() |
ebda2fa2b5 | ||
![]() |
39f59c3289 | ||
![]() |
ad7f1a8dcc | ||
![]() |
32c4c15f15 | ||
![]() |
5008409b5c | ||
![]() |
19cd5ff164 | ||
![]() |
64adea1ce1 | ||
![]() |
19db33afc9 | ||
![]() |
59880cb855 | ||
![]() |
604a2d67b5 | ||
![]() |
380a2dfc3a | ||
![]() |
7841ce781c | ||
![]() |
ba9bcf92f6 | ||
![]() |
6db4af7bd5 | ||
![]() |
c545473920 | ||
![]() |
ec878a3d89 | ||
![]() |
09ea6744fe | ||
![]() |
6a516acb2e | ||
![]() |
6919b9879b | ||
![]() |
298d3aa8b8 | ||
![]() |
c63ea32a17 | ||
![]() |
3314f4ef09 | ||
![]() |
2e67c85c13 | ||
![]() |
c4c53659f1 | ||
![]() |
2e67c827bb | ||
![]() |
3e39ec60da | ||
![]() |
83d7ae76e8 | ||
![]() |
72ea8cfb43 | ||
![]() |
13b36ce063 | ||
![]() |
6371675bf9 | ||
![]() |
54512f2184 | ||
![]() |
b10de9186c | ||
![]() |
c766258e9c | ||
![]() |
d20ddb6807 | ||
![]() |
5f1938f545 | ||
![]() |
ade06e284b | ||
![]() |
35cbdc9661 | ||
![]() |
9300aca2a6 | ||
![]() |
9af68a2415 | ||
![]() |
19f3448c21 | ||
![]() |
ed95e1a9ff | ||
![]() |
879b023706 | ||
![]() |
8d9a357a67 | ||
![]() |
a4bc2922c2 | ||
![]() |
420591c4a2 | ||
![]() |
f0307892ea | ||
![]() |
5e19d7ec54 | ||
![]() |
81d704d15d | ||
![]() |
b19c11621a | ||
![]() |
69c9dfd6d5 | ||
![]() |
6cba7d22e9 | ||
![]() |
0007490b21 | ||
![]() |
aac5e5906d | ||
![]() |
e19dff9285 | ||
![]() |
32b299f63e | ||
![]() |
07387913a8 | ||
![]() |
ef7ab7bde8 | ||
![]() |
6a90113e68 | ||
![]() |
3d58b43efe | ||
![]() |
44a4ffd96f | ||
![]() |
186d3ba70e | ||
![]() |
a4cbaa958d | ||
![]() |
25c3421802 | ||
![]() |
a449f77774 | ||
![]() |
388fe4aea8 | ||
![]() |
0141c6db81 | ||
![]() |
00157a42d3 | ||
![]() |
487fa4a469 | ||
![]() |
7b0d2464ff | ||
![]() |
7b13076f56 | ||
![]() |
389dacd6e2 | ||
![]() |
24496fe097 | ||
![]() |
8fb71ce208 | ||
![]() |
a8eb15eafb | ||
![]() |
77f9c550bd | ||
![]() |
3cfd3e626c | ||
![]() |
0426c76142 | ||
![]() |
18ef26761d | ||
![]() |
e214503789 | ||
![]() |
28382c58ec | ||
![]() |
6549a270e9 | ||
![]() |
94dea2018e | ||
![]() |
da4d627e79 | ||
![]() |
ddaba6d576 | ||
![]() |
8c9a240597 | ||
![]() |
d9694c27c2 | ||
![]() |
200edf8030 | ||
![]() |
12c76d4a15 | ||
![]() |
4bbc37687e | ||
![]() |
0ff5ce825c | ||
![]() |
84f64925bc | ||
![]() |
18f85467e7 | ||
![]() |
d331bc3b03 | ||
![]() |
52bc1ad744 | ||
![]() |
0200623ef7 | ||
![]() |
f577f31f50 | ||
![]() |
a7b2b29b79 | ||
![]() |
9da935629e | ||
![]() |
42053a0fc3 | ||
![]() |
383e23fd61 | ||
![]() |
cc1884dc04 | ||
![]() |
1523c78c34 | ||
![]() |
683b076a6e | ||
![]() |
676250adf9 | ||
![]() |
521b8c02cc | ||
![]() |
92e954a2f0 | ||
![]() |
381fa4afca | ||
![]() |
a6a539497a | ||
![]() |
cd8a090e67 | ||
![]() |
40408d1640 | ||
![]() |
5d88037e37 | ||
![]() |
57b229012a | ||
![]() |
5fd603ce60 | ||
![]() |
eaa74497b8 | ||
![]() |
93fa093122 | ||
![]() |
36a2dd36a0 | ||
![]() |
3760b589f6 | ||
![]() |
3d97f1e22d | ||
![]() |
1907027b7b | ||
![]() |
86c76aa734 | ||
![]() |
e1c3305015 | ||
![]() |
672383bc56 | ||
![]() |
b94d1604a9 | ||
![]() |
6326ad1729 | ||
![]() |
0f0fce5dcc | ||
![]() |
0cbe6524db | ||
![]() |
0ef0dab2f7 | ||
![]() |
806b4fbcad | ||
![]() |
d178a71b7c | ||
![]() |
05b3356631 | ||
![]() |
08d5e3d0fa | ||
![]() |
9e7ed25c64 | ||
![]() |
a44f547343 | ||
![]() |
fb77973201 | ||
![]() |
c4872b4519 | ||
![]() |
ad371893f2 | ||
![]() |
9f3e5eead5 | ||
![]() |
dec81e489f | ||
![]() |
f7e59cbccc | ||
![]() |
73261bb8c7 | ||
![]() |
0e30c50648 | ||
![]() |
85fddc0081 | ||
![]() |
8feeaecb84 | ||
![]() |
e854b2a459 | ||
![]() |
5cdd6ab7cd | ||
![]() |
1981706196 | ||
![]() |
66ca24d3a2 | ||
![]() |
c1756e1b63 | ||
![]() |
c1a9e82d3e | ||
![]() |
3910417695 | ||
![]() |
a491d2e8a5 | ||
![]() |
bade242ddd | ||
![]() |
426e3926ef | ||
![]() |
dc52e08bb5 | ||
![]() |
b2fe29ba79 | ||
![]() |
7c1b7842c6 | ||
![]() |
efe17dbdb4 | ||
![]() |
0588a83380 | ||
![]() |
38adf7a694 | ||
![]() |
3df160a410 | ||
![]() |
458a29d700 | ||
![]() |
e1058e6bc3 | ||
![]() |
62344f515c | ||
![]() |
e5e6480694 | ||
![]() |
85b80ce3bb | ||
![]() |
4769809555 | ||
![]() |
23a27d4c8a | ||
![]() |
64f9ea1cf5 | ||
![]() |
a5898e3a2d | ||
![]() |
2cc6a86fd3 | ||
![]() |
8f1bc3a3b7 | ||
![]() |
b0e20e1b3c | ||
![]() |
066fb6c69e | ||
![]() |
b41580d66e | ||
![]() |
341c9e77a8 | ||
![]() |
9a8b46518b | ||
![]() |
1e48b64538 | ||
![]() |
4113a88523 | ||
![]() |
26c4429f7e | ||
![]() |
b7e92237c5 | ||
![]() |
d6d0e4c942 | ||
![]() |
1b44e7dba2 | ||
![]() |
052a5b0319 | ||
![]() |
8a46a2a364 | ||
![]() |
4f17d17009 | ||
![]() |
61f266f660 | ||
![]() |
af8e955e8f | ||
![]() |
30b0cb0cd4 | ||
![]() |
62a4a45a72 | ||
![]() |
a2d758acc9 | ||
![]() |
9f004830a5 | ||
![]() |
dbd76848ca | ||
![]() |
72568286ab | ||
![]() |
8bb58153e7 | ||
![]() |
40069797ef | ||
![]() |
07ba3e35d3 | ||
![]() |
d591710f82 | ||
![]() |
0004a187ba | ||
![]() |
ca807edac0 | ||
![]() |
7f4431d2f6 | ||
![]() |
25dc760162 | ||
![]() |
4651269dc8 | ||
![]() |
882ddf4b16 | ||
![]() |
d806d0760d | ||
![]() |
b529870558 | ||
![]() |
454fa93113 | ||
![]() |
2799bbc562 | ||
![]() |
b4500c477e | ||
![]() |
fd1912de97 | ||
![]() |
7ca03c1a79 | ||
![]() |
870104c36c | ||
![]() |
a2cea992c2 | ||
![]() |
a6cb8efd81 | ||
![]() |
9d7bd47cb6 | ||
![]() |
d9fb730148 | ||
![]() |
08516af897 | ||
![]() |
be18f92bf4 | ||
![]() |
ec1bb21649 | ||
![]() |
e8ad01594a | ||
![]() |
4e5c3b82cb | ||
![]() |
a5979a2106 | ||
![]() |
6f4fbef827 | ||
![]() |
06e4b7d1f8 | ||
![]() |
5f6b0a7b00 | ||
![]() |
40908fca45 | ||
![]() |
6eab4f55fa | ||
![]() |
18f8ab6fbd | ||
![]() |
bccc3a652b | ||
![]() |
de5ac5410d | ||
![]() |
ef5ee6c707 | ||
![]() |
028b3cbe15 | ||
![]() |
079ed04a6b | ||
![]() |
81ccfd44e4 | ||
![]() |
6a02afa56f | ||
![]() |
0557569947 | ||
![]() |
7bbf2fb652 | ||
![]() |
3b84630e14 | ||
![]() |
79f9ffd401 | ||
![]() |
71fa64a272 | ||
![]() |
4965f19626 | ||
![]() |
4bb95eef6f | ||
![]() |
5ecb161850 | ||
![]() |
67b9f120d5 | ||
![]() |
b7d242f094 | ||
![]() |
6a15f40803 | ||
![]() |
a0f9caec99 | ||
![]() |
010077ba0f | ||
![]() |
7b2308980c | ||
![]() |
c2a087a9f7 | ||
![]() |
1b64f2e28b | ||
![]() |
d0096bba21 | ||
![]() |
32ace57479 | ||
![]() |
0411336b49 | ||
![]() |
9a0953a0a0 | ||
![]() |
07be7b087d | ||
![]() |
e2a89b7ad1 | ||
![]() |
8a20564847 | ||
![]() |
8404507b9b | ||
![]() |
0f7c9cd27e | ||
![]() |
6174d00c03 | ||
![]() |
bbb1b82232 | ||
![]() |
d43bc26717 | ||
![]() |
57ba2df970 | ||
![]() |
4f3c5b2568 | ||
![]() |
781b7d4820 | ||
![]() |
f39b83e232 | ||
![]() |
fe6706a2ce | ||
![]() |
cea8e9b583 | ||
![]() |
14da1bfe40 | ||
![]() |
7493debe26 | ||
![]() |
7d3e1ad943 | ||
![]() |
81945da0ac | ||
![]() |
735e250326 | ||
![]() |
55d15e9d05 | ||
![]() |
9d5e754caa | ||
![]() |
0040fb93d6 | ||
![]() |
970ad4e3c7 | ||
![]() |
8d6da1e100 | ||
![]() |
6c829007cc | ||
![]() |
e7f034fe4e | ||
![]() |
6bb909f152 | ||
![]() |
2006d9f7d1 | ||
![]() |
66a0289081 | ||
![]() |
a181a825c8 | ||
![]() |
def549c8f6 | ||
![]() |
4c07d58592 | ||
![]() |
98f36bba9a | ||
![]() |
781fd745ed | ||
![]() |
57c2545cd5 | ||
![]() |
2a478f9215 | ||
![]() |
1bef9e3fbf | ||
![]() |
be1829f63d | ||
![]() |
e1743888ed | ||
![]() |
b76ccfef5f | ||
![]() |
9899820a17 | ||
![]() |
4112481170 | ||
![]() |
5a01c1dad1 | ||
![]() |
8d15e7d742 | ||
![]() |
407e3a4552 | ||
![]() |
4386e3f7c0 | ||
![]() |
775dcab7a2 | ||
![]() |
8d0dc69027 | ||
![]() |
5dd50a381a | ||
![]() |
9fa38435aa | ||
![]() |
952e1e62c5 | ||
![]() |
5bc17c3e54 | ||
![]() |
3d71555a47 | ||
![]() |
6509ebc594 | ||
![]() |
f9d4589976 | ||
![]() |
1e88fe578e | ||
![]() |
3d73d32499 | ||
![]() |
c207947508 | ||
![]() |
6743bf3173 | ||
![]() |
e7904c5faa | ||
![]() |
ef7e4ec3c6 | ||
![]() |
346a438da8 | ||
![]() |
aeafa2a28f | ||
![]() |
ad4073edc1 | ||
![]() |
dcd6c1d2e2 | ||
![]() |
2bdc7fb0a1 | ||
![]() |
7d23c50599 | ||
![]() |
6750d1bac8 | ||
![]() |
4fd91c3f37 | ||
![]() |
84cbe29d5b | ||
![]() |
60ee6f739f | ||
![]() |
317d3d10b8 | ||
![]() |
5de229644f | ||
![]() |
f2f884a92f | ||
![]() |
1f32e3c95d | ||
![]() |
6c0aa5b00a | ||
![]() |
542c735926 | ||
![]() |
6c5ca9779b | ||
![]() |
7b1245dc7f | ||
![]() |
22529b81f8 | ||
![]() |
7fc29c1435 | ||
![]() |
d1e3705c1a | ||
![]() |
3e2f0c7a39 | ||
![]() |
ada6ddc794 | ||
![]() |
a4ce46e06c | ||
![]() |
ba31a9645c | ||
![]() |
afa41b16ea | ||
![]() |
caeb591fa3 | ||
![]() |
04dc007c76 | ||
![]() |
ac79a02ace | ||
![]() |
4f1d1422de | ||
![]() |
40b3fc727d | ||
![]() |
fffa94787c | ||
![]() |
4fdc1bb1fb | ||
![]() |
43b8dffb83 | ||
![]() |
b9921a5560 | ||
![]() |
08735b4aa8 | ||
![]() |
64cb636b06 | ||
![]() |
4f43cb660a | ||
![]() |
27530efedb | ||
![]() |
92eca900b0 | ||
![]() |
c93c9bca8e | ||
![]() |
0f2956ab5d | ||
![]() |
413f66f1a3 | ||
![]() |
201fdf67ac | ||
![]() |
0760c6f4e1 | ||
![]() |
cfa2f9a2f2 | ||
![]() |
67d010bd2c | ||
![]() |
94672c89cc | ||
![]() |
61acc9939f | ||
![]() |
72119f5d9b | ||
![]() |
0f7b0897cc | ||
![]() |
8deb92d653 | ||
![]() |
1c550c36b3 | ||
![]() |
86ec93ccaf | ||
![]() |
0fc17c42af | ||
![]() |
51fe170224 | ||
![]() |
27bd49f4bf | ||
![]() |
2400bc66ef | ||
![]() |
6ad1e347a3 | ||
![]() |
8dd5dae91a | ||
![]() |
19c5d21e6f | ||
![]() |
17fb29c9e8 | ||
![]() |
7ff0f654fb | ||
![]() |
0a004fd361 | ||
![]() |
4fa853f5de | ||
![]() |
24e371c812 | ||
![]() |
d4d242ba76 | ||
![]() |
dee3f716b3 | ||
![]() |
8a8202fcdc | ||
![]() |
0955c88c2e | ||
![]() |
30e5333ce3 | ||
![]() |
d006242d73 | ||
![]() |
69f72417f4 | ||
![]() |
ee34a8ac29 | ||
![]() |
bca90530fa | ||
![]() |
d68fa0382d | ||
![]() |
1311687d0d | ||
![]() |
081c00c7df | ||
![]() |
b3a6ae71c1 | ||
![]() |
43d6eb7173 | ||
![]() |
dd8983f96c | ||
![]() |
4917bcc039 | ||
![]() |
3ce2a7d026 | ||
![]() |
a9fa147a92 | ||
![]() |
f058afc861 | ||
![]() |
2e66c0b6f0 | ||
![]() |
55ceb5047c | ||
![]() |
cfef1b11e5 | ||
![]() |
af10b35ba9 | ||
![]() |
96155f626d | ||
![]() |
6b2328e5cc | ||
![]() |
82d563243f | ||
![]() |
40429857c3 | ||
![]() |
ec3c08d618 | ||
![]() |
c0309cfe69 | ||
![]() |
f29a3eb9c7 | ||
![]() |
264706f804 | ||
![]() |
3246db3755 | ||
![]() |
624daf8d9e | ||
![]() |
3c585e6567 | ||
![]() |
34f459423a | ||
![]() |
6176ab5901 | ||
![]() |
ffcddc908e | ||
![]() |
058010187b | ||
![]() |
75bdbf02a6 | ||
![]() |
90431d1857 | ||
![]() |
e35700eb50 | ||
![]() |
b43a7ac530 | ||
![]() |
c9d2b7df77 | ||
![]() |
620fbb5655 | ||
![]() |
de705907a5 | ||
![]() |
6fd2d4e772 | ||
![]() |
0242fef89c | ||
![]() |
402e0b58ca | ||
![]() |
3db11af44b | ||
![]() |
0ee5518e76 | ||
![]() |
ec000ce555 | ||
![]() |
f595434abc | ||
![]() |
8f1bc0bccc | ||
![]() |
1870d5f4aa | ||
![]() |
d33428f0bf | ||
![]() |
a35bcd01c5 | ||
![]() |
89de943401 | ||
![]() |
9582dd10e1 | ||
![]() |
11cceea58a | ||
![]() |
8d5b17e939 | ||
![]() |
2e74e307d0 | ||
![]() |
0fc13104e7 | ||
![]() |
c7c02eea81 | ||
![]() |
6742f74e0e | ||
![]() |
1ffdac4502 | ||
![]() |
c3a5641132 | ||
![]() |
1fccb39316 | ||
![]() |
3b9b5842b3 | ||
![]() |
838fc976c8 | ||
![]() |
07b2e4cb79 | ||
![]() |
145817a9cf | ||
![]() |
56e64270f3 | ||
![]() |
533ecb44b1 | ||
![]() |
7fbf321c2a | ||
![]() |
27aea4956c | ||
![]() |
a19ee75bd1 | ||
![]() |
a9c5a40087 | ||
![]() |
ab7bc6b7d2 | ||
![]() |
7bd051eeec | ||
![]() |
0b8444aa0c | ||
![]() |
2c9684e35c | ||
![]() |
247f90c82e | ||
![]() |
c218211012 | ||
![]() |
e034b7b04d | ||
![]() |
968a0bcd63 | ||
![]() |
4347080b46 | ||
![]() |
59c77c8f5b | ||
![]() |
1515e02c8a | ||
![]() |
76ce3fd9c9 | ||
![]() |
89a9d7d650 | ||
![]() |
c1729f876c | ||
![]() |
ce2abb82c0 | ||
![]() |
88c6ec40a4 | ||
![]() |
a5e1baf3ab | ||
![]() |
49940ab5ee | ||
![]() |
1f22b15030 | ||
![]() |
a8b20ed105 | ||
![]() |
ab677c41ea | ||
![]() |
07b1aa822c | ||
![]() |
5b6b42162b | ||
![]() |
26659d5eb8 | ||
![]() |
bd6217bb74 | ||
![]() |
0a861e68df | ||
![]() |
109eafc3f8 | ||
![]() |
974e4540bd | ||
![]() |
d502ef0035 | ||
![]() |
e4a6520d6e | ||
![]() |
618f26ccbc | ||
![]() |
7b4e4c08b5 | ||
![]() |
271243d382 | ||
![]() |
c523d6d25c | ||
![]() |
6f435e0bb9 | ||
![]() |
6c1df4f9c5 | ||
![]() |
5607c4be00 | ||
![]() |
b14d203884 | ||
![]() |
60ace31be0 | ||
![]() |
f0be4d126d | ||
![]() |
50a7c67363 | ||
![]() |
481185fb8a | ||
![]() |
f8c7eb295f | ||
![]() |
4c0e0979b4 | ||
![]() |
3c69b9f2c5 | ||
![]() |
62bc40c6e7 | ||
![]() |
a392e6cecb | ||
![]() |
0249afc523 | ||
![]() |
02ee154558 | ||
![]() |
0440ca07ba | ||
![]() |
f73d72bfdc | ||
![]() |
b44b3193d0 | ||
![]() |
572ca799db | ||
![]() |
c3a6de9ec8 | ||
![]() |
8d193d81af | ||
![]() |
e2114731e7 | ||
![]() |
8a2e1245d4 | ||
![]() |
f63dea4337 | ||
![]() |
cd51c9fafb | ||
![]() |
f71fe8476a | ||
![]() |
b04f1416f6 | ||
![]() |
ddb42f3ad2 | ||
![]() |
05042ce472 | ||
![]() |
0695a910c6 | ||
![]() |
9d9cca49b4 | ||
![]() |
0c7b930952 | ||
![]() |
4eb9b5f20e | ||
![]() |
188724a597 | ||
![]() |
e9f1b83a4a | ||
![]() |
786e6d80ba | ||
![]() |
ecb4ed172b | ||
![]() |
dc0c2340b8 | ||
![]() |
31441778fa | ||
![]() |
412c650e05 | ||
![]() |
db1663a1e5 | ||
![]() |
173d16b233 | ||
![]() |
73fe903c96 | ||
![]() |
8cd244a318 | ||
![]() |
c78af57e21 | ||
![]() |
0f1eeed5c2 | ||
![]() |
e31e9180cd | ||
![]() |
3564d03b0f | ||
![]() |
0dde471278 | ||
![]() |
ee5d8f43e1 | ||
![]() |
4a8b3b8bc5 | ||
![]() |
18ca7546f6 | ||
![]() |
91f14e751f | ||
![]() |
a4f3c08db4 | ||
![]() |
1e13247d6d | ||
![]() |
762fc76cf9 | ||
![]() |
96355b4f1c | ||
![]() |
5b4d930ae5 | ||
![]() |
7f3602f1c9 | ||
![]() |
89555e45f2 | ||
![]() |
e3d80cfc15 | ||
![]() |
3582c9da70 | ||
![]() |
cf82687f23 | ||
![]() |
5dff494b87 | ||
![]() |
cd381aea56 | ||
![]() |
267108e113 | ||
![]() |
4831ff9f27 | ||
![]() |
09cc2f9d0e | ||
![]() |
528428919e | ||
![]() |
571baffd59 | ||
![]() |
46f4a45769 | ||
![]() |
7d574f5ac6 | ||
![]() |
a8a8bd1e42 | ||
![]() |
67da3f7e6b | ||
![]() |
58dd03a471 | ||
![]() |
2f1c382a6d | ||
![]() |
a5be811269 | ||
![]() |
6ca4eda960 | ||
![]() |
9ce2b30b81 | ||
![]() |
e332c41e9d | ||
![]() |
95824f2b5f | ||
![]() |
be4f4644a8 | ||
![]() |
7014c0d65d | ||
![]() |
e37a2d1879 | ||
![]() |
a7c8fdc55b | ||
![]() |
fd16e003fb | ||
![]() |
4d48c00f94 | ||
![]() |
489e7b61bf | ||
![]() |
8520b322aa | ||
![]() |
e352e8deed | ||
![]() |
323ab8ef97 | ||
![]() |
0af7b4961a | ||
![]() |
c5c3568573 | ||
![]() |
1a3d8019d1 | ||
![]() |
3e1601a980 | ||
![]() |
49de15cdcc | ||
![]() |
55fd77f724 | ||
![]() |
08dccc2cb4 | ||
![]() |
8e2fd56394 | ||
![]() |
6d59619d6e | ||
![]() |
6d20ea5c38 | ||
![]() |
a39ba095eb | ||
![]() |
511a909ae6 | ||
![]() |
419c47a80a | ||
![]() |
f53692a632 | ||
![]() |
5fe640f579 | ||
![]() |
74cc242acc | ||
![]() |
39461732ab | ||
![]() |
6b9d9da8ef | ||
![]() |
5e50d002f1 | ||
![]() |
b7af3716a1 | ||
![]() |
8596486743 | ||
![]() |
cd54f31984 | ||
![]() |
a354970eaa | ||
![]() |
fd3cf7193b | ||
![]() |
0f2376d58e | ||
![]() |
85fa72c599 | ||
![]() |
82c19beec4 | ||
![]() |
c0fa14e8af | ||
![]() |
1d7ceb2fee | ||
![]() |
2597a71623 | ||
![]() |
9b428a3d33 | ||
![]() |
7b9877bd8a | ||
![]() |
8ad8c6d887 | ||
![]() |
7602edfd06 | ||
![]() |
5a98363a92 | ||
![]() |
9b71a46899 | ||
![]() |
3cb933db9d | ||
![]() |
a73d78f8d5 | ||
![]() |
924edb948c | ||
![]() |
c7e77dba7f | ||
![]() |
de7af816e7 | ||
![]() |
098be5ffdd | ||
![]() |
eb29361d9d | ||
![]() |
f6b695d2fb | ||
![]() |
9f8bd80487 | ||
![]() |
dba081975a | ||
![]() |
36688496ca | ||
![]() |
807c849431 | ||
![]() |
4c8af0e2f9 | ||
![]() |
60864229b8 | ||
![]() |
b8bf60c590 | ||
![]() |
7860686a8d | ||
![]() |
df731c745a | ||
![]() |
2e04be3fb9 | ||
![]() |
a0a16bbed6 | ||
![]() |
4dd86a0b33 | ||
![]() |
f3e6b7065a | ||
![]() |
ff81dc3544 | ||
![]() |
105eee7e24 | ||
![]() |
779a5b3029 | ||
![]() |
1eadbdd9fa | ||
![]() |
58413c15cb | ||
![]() |
9dab00a76e | ||
![]() |
a9fe88e395 | ||
![]() |
96929d406f | ||
![]() |
518179f63e | ||
![]() |
cba36a064d | ||
![]() |
ff76e05913 | ||
![]() |
670ce6785d | ||
![]() |
5ba4ba0baf | ||
![]() |
878906630b | ||
![]() |
0f052eb4f5 | ||
![]() |
609d87003a | ||
![]() |
cddaa84777 | ||
![]() |
306b8c89e8 | ||
![]() |
31fb92c609 | ||
![]() |
561a010161 | ||
![]() |
a33d1f9a7c | ||
![]() |
0670621291 | ||
![]() |
c9c55df1f2 | ||
![]() |
de4af86e98 | ||
![]() |
13f99eb65f | ||
![]() |
0db50996b7 | ||
![]() |
52f8a4283e | ||
![]() |
1557892c37 | ||
![]() |
d983fa0ebe | ||
![]() |
c543c39692 | ||
![]() |
8b36298d7f | ||
![]() |
d59758450b | ||
![]() |
509f19f611 | ||
![]() |
18bb8fee3c | ||
![]() |
e8c4740108 | ||
![]() |
5b9492a58e | ||
![]() |
a4d081cc17 | ||
![]() |
1ac44105f9 | ||
![]() |
5cfc9c374c | ||
![]() |
b9fd2cf605 | ||
![]() |
6cef06b940 | ||
![]() |
91bb776bb8 | ||
![]() |
cc2134ea83 | ||
![]() |
f679d8c821 | ||
![]() |
5f114b65b4 | ||
![]() |
1d7cd76ee9 | ||
![]() |
939451554f | ||
![]() |
5e0599cb6e | ||
![]() |
2640aec0d7 | ||
![]() |
65fdd10d4e | ||
![]() |
3e8573a85a | ||
![]() |
cefc89e5a5 | ||
![]() |
80e0fc4901 | ||
![]() |
8e8d9a3650 | ||
![]() |
6373de3304 | ||
![]() |
8b748bd326 | ||
![]() |
d0731af939 | ||
![]() |
f7277806c8 | ||
![]() |
d52ffce38f | ||
![]() |
bd98bf38e9 | ||
![]() |
5dcaad0dd3 | ||
![]() |
1808c67d53 | ||
![]() |
c500d8824d | ||
![]() |
6217f8001e | ||
![]() |
0ec426a57b | ||
![]() |
5f698d1121 | ||
![]() |
a09f8dbe6e | ||
![]() |
fa2799804c | ||
![]() |
15b8e4a490 | ||
![]() |
18e322bc7c | ||
![]() |
6a2f385aea | ||
![]() |
4bafaa00aa | ||
![]() |
57d2d6ef62 | ||
![]() |
b75246202a | ||
![]() |
ce550fa9c2 | ||
![]() |
92d2e12a4d | ||
![]() |
313a7d716d | ||
![]() |
68d7736e9e | ||
![]() |
74b84d00b3 | ||
![]() |
500c026818 | ||
![]() |
0cbb92bcc5 | ||
![]() |
c7d74a2366 | ||
![]() |
549d24b437 | ||
![]() |
ab37723fa2 | ||
![]() |
ba138d6201 | ||
![]() |
e14924570c | ||
![]() |
7f0cf432e9 | ||
![]() |
c3f0cd7457 | ||
![]() |
6b7974cf16 | ||
![]() |
23b8fcc74d | ||
![]() |
4b84a33217 | ||
![]() |
774e25de13 | ||
![]() |
d8d990f2e3 | ||
![]() |
464882e398 | ||
![]() |
2646beac87 | ||
![]() |
d082bbcc05 | ||
![]() |
b6a2441eb9 | ||
![]() |
61e5cf083a | ||
![]() |
e6ee27a541 | ||
![]() |
1e97933876 | ||
![]() |
d4314f7c1f | ||
![]() |
a4ac991d02 | ||
![]() |
5675d3a8fe | ||
![]() |
7b7d1132e8 | ||
![]() |
360238e9e1 | ||
![]() |
b58de39ca7 | ||
![]() |
6f8ea5b26e | ||
![]() |
d2276ff3f2 | ||
![]() |
c6eab4077a | ||
![]() |
8dd14509d7 | ||
![]() |
031c731c68 | ||
![]() |
ca52e0a244 | ||
![]() |
f27b74f0f7 | ||
![]() |
327c8fc52f | ||
![]() |
2d7d81bc46 | ||
![]() |
ff1b933d96 | ||
![]() |
b28e66cf4f | ||
![]() |
9d74c7ab99 | ||
![]() |
239d9c5eda | ||
![]() |
6ccda5a041 | ||
![]() |
724feb898f | ||
![]() |
9a849cc83a | ||
![]() |
cff2b5b338 | ||
![]() |
301fed8a45 | ||
![]() |
a4b28e23cf | ||
![]() |
502d3a1fcb | ||
![]() |
54de892d1e | ||
![]() |
af1edfd368 | ||
![]() |
73785fff07 | ||
![]() |
4a14453d2d | ||
![]() |
8d9d5a3bb5 | ||
![]() |
9162840c1e | ||
![]() |
8925f735a1 | ||
![]() |
3a7fda78a2 | ||
![]() |
4d708225bd | ||
![]() |
226e07144e | ||
![]() |
6560e0b136 | ||
![]() |
b6b0b0a05f | ||
![]() |
bff3e85625 | ||
![]() |
7a9791f096 | ||
![]() |
89ab14a115 | ||
![]() |
1d2a669445 | ||
![]() |
2d511f28f2 | ||
![]() |
7b0bd43a27 | ||
![]() |
6b7e19ff42 | ||
![]() |
44626eaf81 | ||
![]() |
4f08f8df1e | ||
![]() |
37a241768d | ||
![]() |
c8fc98937d | ||
![]() |
df965f51bf | ||
![]() |
9861dd069b | ||
![]() |
ad8d255bb9 | ||
![]() |
88d9ab1af5 | ||
![]() |
7797480eb0 | ||
![]() |
acd0aa7d38 | ||
![]() |
f0680670d2 | ||
![]() |
33b27e2cca | ||
![]() |
7e44b7cddd | ||
![]() |
e05f614267 | ||
![]() |
4e46d9f963 | ||
![]() |
7376bf948b | ||
![]() |
1192b468e9 | ||
![]() |
30295c1750 | ||
![]() |
9031de6a9b | ||
![]() |
2279803c8c | ||
![]() |
a263241ea1 | ||
![]() |
68f27cdfc2 | ||
![]() |
5c96365c94 | ||
![]() |
50fb999bb1 | ||
![]() |
43956c1bfc | ||
![]() |
5371c889a8 | ||
![]() |
e0db8207f3 | ||
![]() |
ebf339628a | ||
![]() |
e0286d7f4e | ||
![]() |
dc2b34af6a | ||
![]() |
d4579a983e | ||
![]() |
7e8df0e2c9 | ||
![]() |
340711db3d | ||
![]() |
e60bddcc60 | ||
![]() |
f1d71f7cc3 | ||
![]() |
051e604adc | ||
![]() |
d4d5e0ae0c | ||
![]() |
9100e3c087 | ||
![]() |
510beeccf4 | ||
![]() |
0f5ac7761d | ||
![]() |
074635002e | ||
![]() |
69f077f1aa | ||
![]() |
eb0edeafdd | ||
![]() |
982f09f837 | ||
![]() |
1000e4ee7d | ||
![]() |
3dae8e9fc2 | ||
![]() |
7ca66e3cfc | ||
![]() |
7819811835 | ||
![]() |
e3a7a1c6ae | ||
![]() |
360d38adb1 | ||
![]() |
2b7416ef34 | ||
![]() |
d817f4dcee | ||
![]() |
55d1a56826 | ||
![]() |
04c339a12b | ||
![]() |
a02abca49a | ||
![]() |
39f3adc079 | ||
![]() |
05eacf92fe | ||
![]() |
eaf1a604f2 | ||
![]() |
d8a43399a8 | ||
![]() |
818ee96219 | ||
![]() |
857cb260c7 | ||
![]() |
6e21389917 | ||
![]() |
f34567bf41 | ||
![]() |
26c65447df | ||
![]() |
71cb54cec4 | ||
![]() |
c5d2c8fb80 | ||
![]() |
f4c0ec8ffc | ||
![]() |
9772c68e54 | ||
![]() |
547da0d575 | ||
![]() |
31f654a704 | ||
![]() |
ba2ff69894 | ||
![]() |
2bfc7aedab | ||
![]() |
45f845a260 | ||
![]() |
ef5b279887 | ||
![]() |
e278d3f185 | ||
![]() |
342b44bf20 | ||
![]() |
3e8405aa82 | ||
![]() |
7ff4b64319 | ||
![]() |
f7fe2c2290 | ||
![]() |
12744335c0 | ||
![]() |
0e0b300a1c | ||
![]() |
a61f7abf5a | ||
![]() |
1213881712 | ||
![]() |
6cc644abef | ||
![]() |
7bdc0a6291 | ||
![]() |
a1bc0a6d79 | ||
![]() |
98d8343aa2 | ||
![]() |
49f021ebf0 | ||
![]() |
d515863abc | ||
![]() |
e3a18e1990 | ||
![]() |
f499c6b9ec | ||
![]() |
669fbed1ac | ||
![]() |
4d3b32bf3d | ||
![]() |
0e9a66d35a | ||
![]() |
7624f8aeb1 | ||
![]() |
75577fe7a8 | ||
![]() |
a290f5d04c | ||
![]() |
5571d5139b | ||
![]() |
498803bec9 | ||
![]() |
c492105b8f | ||
![]() |
67c36d5d6e | ||
![]() |
2fbc30739b | ||
![]() |
a46ce37d25 | ||
![]() |
992961c56c | ||
![]() |
6acf0972ec | ||
![]() |
9c8b0b6050 | ||
![]() |
e4cd1933c6 | ||
![]() |
91bd9a6642 | ||
![]() |
b529fe0995 | ||
![]() |
b94f7157ca | ||
![]() |
046b3fc5dd | ||
![]() |
6b70975efc | ||
![]() |
6e0e5d7a31 | ||
![]() |
2527e6dd09 | ||
![]() |
7b510fda0c | ||
![]() |
5de77049db | ||
![]() |
00795d55df | ||
![]() |
0136a7c1bb | ||
![]() |
d61c85f7df | ||
![]() |
ff3d2eb589 | ||
![]() |
9464898b47 | ||
![]() |
7d74269c0d | ||
![]() |
11b03710ed | ||
![]() |
c7d2099ddb | ||
![]() |
c8a0e1da12 | ||
![]() |
2a7bd485a6 | ||
![]() |
4f08346686 | ||
![]() |
dc4ab45e05 | ||
![]() |
a26d82c2f8 | ||
![]() |
c8d18e27bd | ||
![]() |
34b8670b1a | ||
![]() |
e01f84538a | ||
![]() |
68bf777ece | ||
![]() |
494dadb8a3 | ||
![]() |
f02cdb50be | ||
![]() |
efb1f141a4 | ||
![]() |
10829dd222 | ||
![]() |
1de20b2012 | ||
![]() |
264b41fb9e | ||
![]() |
be628115ba | ||
![]() |
e258d66f17 | ||
![]() |
9cd67df5b2 | ||
![]() |
0910306bf9 | ||
![]() |
ea2011360c | ||
![]() |
ee230d8fdd | ||
![]() |
52c1a2fae8 | ||
![]() |
e4e819b49c | ||
![]() |
6668801d40 | ||
![]() |
39f7b2b6d0 | ||
![]() |
5b0eb69635 | ||
![]() |
5daceee6ca | ||
![]() |
755dd793b6 | ||
![]() |
878dc898b9 | ||
![]() |
094069adc7 | ||
![]() |
98ce26624b | ||
![]() |
4336271b57 | ||
![]() |
ab6b40e5a9 | ||
![]() |
b1a6d5388d | ||
![]() |
aca80d1cda | ||
![]() |
dddb4d25d2 | ||
![]() |
1992190162 | ||
![]() |
99bde59229 | ||
![]() |
1a1a885423 | ||
![]() |
4e39cdd9bb | ||
![]() |
9f0cb20d9f | ||
![]() |
b768d69c04 | ||
![]() |
5d13b38479 | ||
![]() |
798021af9f | ||
![]() |
35cba9b1c9 | ||
![]() |
8d067bbdb4 | ||
![]() |
a893540b66 | ||
![]() |
afeb4c7a6e | ||
![]() |
d3e3d43482 | ||
![]() |
9fba1514d2 | ||
![]() |
aec4853498 | ||
![]() |
33121d3d45 | ||
![]() |
2293de1c82 | ||
![]() |
af7236f85a | ||
![]() |
25345f2c04 | ||
![]() |
7b153b9e28 | ||
![]() |
70dc392bfa | ||
![]() |
8d5eebcc6e | ||
![]() |
4981b04d10 | ||
![]() |
ea4dd1bbf6 | ||
![]() |
ec5fbce415 | ||
![]() |
6c0e0d6250 | ||
![]() |
b4c828e6a0 | ||
![]() |
a0f6d0798a | ||
![]() |
2d3c380c0f | ||
![]() |
deb21faad0 | ||
![]() |
2478cfa966 | ||
![]() |
cc0ed694ee | ||
![]() |
0dfad687a0 | ||
![]() |
fbdb24ec6a | ||
![]() |
dcf8828165 | ||
![]() |
99db1f6a07 | ||
![]() |
bf2f48aec0 | ||
![]() |
002f9c37ca | ||
![]() |
2a86b2bdb9 | ||
![]() |
1f587cf86c | ||
![]() |
3e2529e881 | ||
![]() |
15e5d4067a | ||
![]() |
3b5fb3ec87 | ||
![]() |
2603af65e5 | ||
![]() |
f06f78e638 | ||
![]() |
0b81042dc3 | ||
![]() |
3c89e44f3e | ||
![]() |
7225aba3af | ||
![]() |
1de5aa45ce | ||
![]() |
1f9cf17713 | ||
![]() |
79b8613c95 | ||
![]() |
599deba8c7 | ||
![]() |
cc9e627f8e | ||
![]() |
81a45f92c5 | ||
![]() |
64eb25dff9 | ||
![]() |
29a75f0428 | ||
![]() |
3ec6dfa346 | ||
![]() |
b1d5d7edeb | ||
![]() |
f817826408 | ||
![]() |
6c6315a1b3 | ||
![]() |
29af4e0f27 | ||
![]() |
e908876506 | ||
![]() |
c01507da42 | ||
![]() |
06f01227c5 | ||
![]() |
f26e4f4c52 | ||
![]() |
518ab82942 | ||
![]() |
6b43181cfa | ||
![]() |
ebeec0dd96 | ||
![]() |
a961b70b2b | ||
![]() |
0dda8605e6 | ||
![]() |
06151b8a4d | ||
![]() |
638eb1907e | ||
![]() |
a2d4e1c246 | ||
![]() |
7d01dbf6fa | ||
![]() |
fcb98254b1 | ||
![]() |
e2061c9708 | ||
![]() |
79c320c1cf | ||
![]() |
48f5dca2ce | ||
![]() |
dbc1a6fa9a |
7450 changed files with 757182 additions and 309459 deletions
22
.DEREK.yml
22
.DEREK.yml
|
@ -1,22 +0,0 @@
|
|||
curators:
|
||||
- aboch
|
||||
- alexellis
|
||||
- andrewhsu
|
||||
- anonymuse
|
||||
- arkodg
|
||||
- chanwit
|
||||
- ehazlett
|
||||
- fntlnz
|
||||
- gianarb
|
||||
- kolyshkin
|
||||
- mgoelzer
|
||||
- olljanat
|
||||
- programmerq
|
||||
- rheinwein
|
||||
- ripcurld0
|
||||
- thajeztah
|
||||
|
||||
features:
|
||||
- comments
|
||||
- pr_description_required
|
||||
|
21
.devcontainer/devcontainer.json
Normal file
21
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "moby",
|
||||
"build": {
|
||||
"context": "..",
|
||||
"dockerfile": "../Dockerfile",
|
||||
"target": "devcontainer"
|
||||
},
|
||||
"workspaceFolder": "/go/src/github.com/docker/docker",
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/go/src/github.com/docker/docker,type=bind,consistency=cached",
|
||||
|
||||
"remoteUser": "root",
|
||||
"runArgs": ["--privileged"],
|
||||
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"golang.go"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,4 @@
|
|||
.git
|
||||
.go-pkg-cache
|
||||
.gopath
|
||||
bundles
|
||||
bundles/
|
||||
cli/winresources/**/winres.json
|
||||
cli/winresources/**/*.syso
|
||||
vendor/pkg
|
||||
|
|
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
|
@ -5,8 +5,6 @@
|
|||
|
||||
builder/** @tonistiigi
|
||||
contrib/mkimage/** @tianon
|
||||
daemon/graphdriver/devmapper/** @rhvgoyal
|
||||
daemon/graphdriver/overlay/** @dmcgowan
|
||||
daemon/graphdriver/overlay2/** @dmcgowan
|
||||
daemon/graphdriver/windows/** @johnstep
|
||||
daemon/logger/awslogs/** @samuelkarp
|
||||
|
|
70
.github/ISSUE_TEMPLATE.md
vendored
70
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,70 +0,0 @@
|
|||
<!--
|
||||
If you are reporting a new issue, make sure that we do not have any duplicates
|
||||
already open. You can ensure this by searching the issue list for this
|
||||
repository. If there is a duplicate, please close your issue and add a comment
|
||||
to the existing issue instead.
|
||||
|
||||
If you suspect your issue is a bug, please edit your issue description to
|
||||
include the BUG REPORT INFORMATION shown below. If you fail to provide this
|
||||
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
|
||||
|
||||
---------------------------------------------------
|
||||
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:
|
||||
|
||||
- Docker Support Forums - https://forums.docker.com
|
||||
- Slack - community.docker.com #general 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
|
||||
---------------------------------------------------
|
||||
Use the commands below to provide key information from your environment:
|
||||
You do NOT have to include this information if this is a FEATURE REQUEST
|
||||
-->
|
||||
|
||||
**Description**
|
||||
|
||||
<!--
|
||||
Briefly describe the problem you are having in a few paragraphs.
|
||||
-->
|
||||
|
||||
**Steps to reproduce the issue:**
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**Describe the results you received:**
|
||||
|
||||
|
||||
**Describe the results you expected:**
|
||||
|
||||
|
||||
**Additional information you deem important (e.g. issue happens only occasionally):**
|
||||
|
||||
**Output of `docker version`:**
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
**Output of `docker info`:**
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
**Additional environment details (AWS, VirtualBox, physical, etc.):**
|
146
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
146
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
|
@ -0,0 +1,146 @@
|
|||
name: Bug report
|
||||
description: Create a report to help us improve
|
||||
labels:
|
||||
- kind/bug
|
||||
- status/0-triage
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking the time to report a bug!
|
||||
If this is a security issue please report it to the [Docker Security team](mailto:security@docker.com).
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please give a clear and concise description of the bug
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Reproduce
|
||||
description: Steps to reproduce the bug
|
||||
placeholder: |
|
||||
1. docker run ...
|
||||
2. docker kill ...
|
||||
3. docker rm ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: What is the expected behavior?
|
||||
placeholder: |
|
||||
E.g. "`docker rm` should remove the container and cleanup all associated data"
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: docker version
|
||||
description: Output of `docker version`
|
||||
render: bash
|
||||
placeholder: |
|
||||
Client:
|
||||
Version: 20.10.17
|
||||
API version: 1.41
|
||||
Go version: go1.17.11
|
||||
Git commit: 100c70180fde3601def79a59cc3e996aa553c9b9
|
||||
Built: Mon Jun 6 21:36:39 UTC 2022
|
||||
OS/Arch: linux/amd64
|
||||
Context: default
|
||||
Experimental: true
|
||||
|
||||
Server:
|
||||
Engine:
|
||||
Version: 20.10.17
|
||||
API version: 1.41 (minimum version 1.12)
|
||||
Go version: go1.17.11
|
||||
Git commit: a89b84221c8560e7a3dee2a653353429e7628424
|
||||
Built: Mon Jun 6 22:32:38 2022
|
||||
OS/Arch: linux/amd64
|
||||
Experimental: true
|
||||
containerd:
|
||||
Version: 1.6.6
|
||||
GitCommit: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1
|
||||
runc:
|
||||
Version: 1.1.2
|
||||
GitCommit: a916309fff0f838eb94e928713dbc3c0d0ac7aa4
|
||||
docker-init:
|
||||
Version: 0.19.0
|
||||
GitCommit:
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
label: docker info
|
||||
description: Output of `docker info`
|
||||
render: bash
|
||||
placeholder: |
|
||||
Client:
|
||||
Context: default
|
||||
Debug Mode: false
|
||||
Plugins:
|
||||
buildx: Docker Buildx (Docker Inc., 0.8.2)
|
||||
compose: Docker Compose (Docker Inc., 2.6.0)
|
||||
|
||||
Server:
|
||||
Containers: 4
|
||||
Running: 2
|
||||
Paused: 0
|
||||
Stopped: 2
|
||||
Images: 80
|
||||
Server Version: 20.10.17
|
||||
Storage Driver: overlay2
|
||||
Backing Filesystem: xfs
|
||||
Supports d_type: true
|
||||
Native Overlay Diff: false
|
||||
userxattr: false
|
||||
Logging Driver: local
|
||||
Cgroup Driver: cgroupfs
|
||||
Cgroup Version: 1
|
||||
Plugins:
|
||||
Volume: local
|
||||
Network: bridge host ipvlan macvlan null overlay
|
||||
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
|
||||
Swarm: inactive
|
||||
Runtimes: runc io.containerd.runc.v2 io.containerd.runtime.v1.linux
|
||||
Default Runtime: runc
|
||||
Init Binary: docker-init
|
||||
containerd version: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1
|
||||
runc version: a916309fff0f838eb94e928713dbc3c0d0ac7aa4
|
||||
init version:
|
||||
Security Options:
|
||||
apparmor
|
||||
seccomp
|
||||
Profile: default
|
||||
Kernel Version: 5.13.0-1031-azure
|
||||
Operating System: Ubuntu 20.04.4 LTS
|
||||
OSType: linux
|
||||
Architecture: x86_64
|
||||
CPUs: 4
|
||||
Total Memory: 15.63GiB
|
||||
Name: dev
|
||||
ID: UC44:2RFL:7NQ5:GGFW:34O5:DYRE:CLOH:VLGZ:64AZ:GFXC:PY6H:SAHY
|
||||
Docker Root Dir: /var/lib/docker
|
||||
Debug Mode: true
|
||||
File Descriptors: 46
|
||||
Goroutines: 134
|
||||
System Time: 2022-07-06T18:07:54.812439392Z
|
||||
EventsListeners: 0
|
||||
Registry: https://index.docker.io/v1/
|
||||
Labels:
|
||||
Experimental: true
|
||||
Insecure Registries:
|
||||
127.0.0.0/8
|
||||
Live Restore Enabled: true
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional Info
|
||||
description: Additional info you want to provide such as logs, system info, environment, etc.
|
||||
validations:
|
||||
required: false
|
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Security and Vulnerabilities
|
||||
url: https://github.com/moby/moby/blob/master/SECURITY.md
|
||||
about: Please report any security issues or vulnerabilities responsibly to the Docker security team. Please do not use the public issue tracker.
|
||||
- name: Questions and Discussions
|
||||
url: https://github.com/moby/moby/discussions/new
|
||||
about: Use Github Discussions to ask questions and/or open discussion topics.
|
13
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
13
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
name: Feature request
|
||||
description: Missing functionality? Come tell us about it!
|
||||
labels:
|
||||
- kind/feature
|
||||
- status/0-triage
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: What is the feature you want to see?
|
||||
validations:
|
||||
required: true
|
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -22,9 +22,12 @@ Please provide the following information:
|
|||
**- Description for the changelog**
|
||||
<!--
|
||||
Write a short (one line) summary that describes the changes in this
|
||||
pull request for inclusion in the changelog:
|
||||
pull request for inclusion in the changelog.
|
||||
It must be placed inside the below triple backticks section:
|
||||
-->
|
||||
```markdown changelog
|
||||
|
||||
```
|
||||
|
||||
**- A picture of a cute animal (not mandatory but encouraged)**
|
||||
|
||||
|
|
27
.github/actions/setup-runner/action.yml
vendored
Normal file
27
.github/actions/setup-runner/action.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
name: 'Setup Runner'
|
||||
description: 'Composite action to set up the GitHub Runner for jobs in the test.yml workflow'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- run: |
|
||||
sudo modprobe ip_vs
|
||||
sudo modprobe ipv6
|
||||
sudo modprobe ip6table_filter
|
||||
sudo modprobe -r overlay
|
||||
sudo modprobe overlay redirect_dir=off
|
||||
shell: bash
|
||||
- run: |
|
||||
if [ ! -e /etc/docker/daemon.json ]; then
|
||||
echo '{}' | sudo tee /etc/docker/daemon.json >/dev/null
|
||||
fi
|
||||
DOCKERD_CONFIG=$(jq '.+{"experimental":true,"live-restore":true,"ipv6":true,"fixed-cidr-v6":"2001:db8:1::/64"}' /etc/docker/daemon.json)
|
||||
sudo tee /etc/docker/daemon.json <<<"$DOCKERD_CONFIG" >/dev/null
|
||||
sudo service docker restart
|
||||
shell: bash
|
||||
- run: |
|
||||
./contrib/check-config.sh || true
|
||||
shell: bash
|
||||
- run: |
|
||||
docker info
|
||||
shell: bash
|
14
.github/actions/setup-tracing/action.yml
vendored
Normal file
14
.github/actions/setup-tracing/action.yml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
name: 'Setup Tracing'
|
||||
description: 'Composite action to set up the tracing for test jobs'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- run: |
|
||||
set -e
|
||||
# Jaeger is set up on Windows through an inline run step. If you update Jaeger here, don't forget to update
|
||||
# the version set in .github/workflows/.windows.yml.
|
||||
docker run -d --net=host --name jaeger -e COLLECTOR_OTLP_ENABLED=true jaegertracing/all-in-one:1.46
|
||||
docker0_ip="$(ip -f inet addr show docker0 | grep -Po 'inet \K[\d.]+')"
|
||||
echo "OTEL_EXPORTER_OTLP_ENDPOINT=http://${docker0_ip}:4318" >> "${GITHUB_ENV}"
|
||||
shell: bash
|
48
.github/workflows/.dco.yml
vendored
Normal file
48
.github/workflows/.dco.yml
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
# reusable workflow
|
||||
name: .dco
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
ALPINE_VERSION: 3.16
|
||||
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Dump context
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
console.log(JSON.stringify(context, null, 2));
|
||||
-
|
||||
name: Get base ref
|
||||
id: base-ref
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
if (/^refs\/pull\//.test(context.ref) && context.payload?.pull_request?.base?.ref != undefined) {
|
||||
return context.payload.pull_request.base.ref;
|
||||
}
|
||||
return context.ref.replace(/^refs\/heads\//g, '');
|
||||
-
|
||||
name: Validate
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v "$(pwd):/workspace" \
|
||||
-e VALIDATE_REPO \
|
||||
-e VALIDATE_BRANCH \
|
||||
alpine:${{ env.ALPINE_VERSION }} sh -c 'apk add --no-cache -q bash git openssh-client && git config --system --add safe.directory /workspace && cd /workspace && hack/validate/dco'
|
||||
env:
|
||||
VALIDATE_REPO: ${{ github.server_url }}/${{ github.repository }}.git
|
||||
VALIDATE_BRANCH: ${{ steps.base-ref.outputs.result }}
|
35
.github/workflows/.test-prepare.yml
vendored
Normal file
35
.github/workflows/.test-prepare.yml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
# reusable workflow
|
||||
name: .test-prepare
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
matrix:
|
||||
description: Test matrix
|
||||
value: ${{ jobs.run.outputs.matrix }}
|
||||
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-20.04
|
||||
outputs:
|
||||
matrix: ${{ steps.set.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Create matrix
|
||||
id: set
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
let matrix = ['graphdriver'];
|
||||
if ("${{ contains(github.event.pull_request.labels.*.name, 'containerd-integration') || github.event_name != 'pull_request' }}" == "true") {
|
||||
matrix.push('snapshotter');
|
||||
}
|
||||
await core.group(`Set matrix`, async () => {
|
||||
core.info(`matrix: ${JSON.stringify(matrix)}`);
|
||||
core.setOutput('matrix', JSON.stringify(matrix));
|
||||
});
|
445
.github/workflows/.test.yml
vendored
Normal file
445
.github/workflows/.test.yml
vendored
Normal file
|
@ -0,0 +1,445 @@
|
|||
# reusable workflow
|
||||
name: .test
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
storage:
|
||||
required: true
|
||||
type: string
|
||||
default: "graphdriver"
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.9"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
ITG_CLI_MATRIX_SIZE: 6
|
||||
DOCKER_EXPERIMENTAL: 1
|
||||
DOCKER_GRAPHDRIVER: ${{ inputs.storage == 'snapshotter' && 'overlayfs' || 'overlay2' }}
|
||||
TEST_INTEGRATION_USE_SNAPSHOTTER: ${{ inputs.storage == 'snapshotter' && '1' || '' }}
|
||||
|
||||
jobs:
|
||||
unit:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-unit
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p bundles /tmp/reports
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C /tmp/reports
|
||||
sudo chown -R $(id -u):$(id -g) /tmp/reports
|
||||
tree -nh /tmp/reports
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
directory: ./bundles
|
||||
env_vars: RUNNER_OS
|
||||
flags: unit
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-unit-${{ inputs.storage }}
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
unit-report:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 10
|
||||
if: always()
|
||||
needs:
|
||||
- unit
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: test-reports-unit-${{ inputs.storage }}
|
||||
path: /tmp/reports
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
docker-py:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up tracing
|
||||
uses: ./.github/actions/setup-tracing
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-docker-py
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p bundles /tmp/reports
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C /tmp/reports
|
||||
sudo chown -R $(id -u):$(id -g) /tmp/reports
|
||||
tree -nh /tmp/reports
|
||||
|
||||
curl -sSLf localhost:16686/api/traces?service=integration-test-client > /tmp/reports/jaeger-trace.json
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-docker-py/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-docker-py-${{ inputs.storage }}
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
integration-flaky:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-integration-flaky
|
||||
env:
|
||||
TEST_SKIP_INTEGRATION_CLI: 1
|
||||
|
||||
integration:
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-20.04
|
||||
- ubuntu-22.04
|
||||
mode:
|
||||
- ""
|
||||
- rootless
|
||||
- systemd
|
||||
#- rootless-systemd FIXME: https://github.com/moby/moby/issues/44084
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up tracing
|
||||
uses: ./.github/actions/setup-tracing
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
CACHE_DEV_SCOPE=dev
|
||||
if [[ "${{ matrix.mode }}" == *"rootless"* ]]; then
|
||||
echo "DOCKER_ROOTLESS=1" >> $GITHUB_ENV
|
||||
fi
|
||||
if [[ "${{ matrix.mode }}" == *"systemd"* ]]; then
|
||||
echo "SYSTEMD=true" >> $GITHUB_ENV
|
||||
CACHE_DEV_SCOPE="${CACHE_DEV_SCOPE}systemd"
|
||||
fi
|
||||
echo "CACHE_DEV_SCOPE=${CACHE_DEV_SCOPE}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=${{ env.CACHE_DEV_SCOPE }}
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-integration
|
||||
env:
|
||||
TEST_SKIP_INTEGRATION_CLI: 1
|
||||
TESTCOVERAGE: 1
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
reportsName=${{ matrix.os }}
|
||||
if [ -n "${{ matrix.mode }}" ]; then
|
||||
reportsName="$reportsName-${{ matrix.mode }}"
|
||||
fi
|
||||
reportsPath="/tmp/reports/$reportsName"
|
||||
echo "TESTREPORTS_NAME=$reportsName" >> $GITHUB_ENV
|
||||
|
||||
mkdir -p bundles $reportsPath
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C $reportsPath
|
||||
sudo chown -R $(id -u):$(id -g) $reportsPath
|
||||
tree -nh $reportsPath
|
||||
|
||||
curl -sSLf localhost:16686/api/traces?service=integration-test-client > $reportsPath/jaeger-trace.json
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
directory: ./bundles/test-integration
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration,${{ matrix.mode }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-integration/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-integration-${{ inputs.storage }}-${{ env.TESTREPORTS_NAME }}
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
integration-report:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 10
|
||||
if: always()
|
||||
needs:
|
||||
- integration
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: test-reports-integration-${{ inputs.storage }}-*
|
||||
merge-multiple: true
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
integration-cli-prepare:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
outputs:
|
||||
matrix: ${{ steps.tests.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Install gotestlist
|
||||
run:
|
||||
go install github.com/crazy-max/gotestlist/cmd/gotestlist@${{ env.GOTESTLIST_VERSION }}
|
||||
-
|
||||
name: Create matrix
|
||||
id: tests
|
||||
working-directory: ./integration-cli
|
||||
run: |
|
||||
# This step creates a matrix for integration-cli tests. Tests suites
|
||||
# are distributed in integration-cli job through a matrix. There is
|
||||
# also overrides being added to the matrix like "./..." to run
|
||||
# "Test integration" step exclusively and specific tests suites that
|
||||
# take a long time to run.
|
||||
matrix="$(gotestlist -d ${{ env.ITG_CLI_MATRIX_SIZE }} -o "./..." -o "DockerSwarmSuite" -o "DockerNetworkSuite|DockerExternalVolumeSuite" ./...)"
|
||||
echo "matrix=$matrix" >> $GITHUB_OUTPUT
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.tests.outputs.matrix }}
|
||||
|
||||
integration-cli:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- integration-cli-prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test: ${{ fromJson(needs.integration-cli-prepare.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up tracing
|
||||
uses: ./.github/actions/setup-tracing
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-integration
|
||||
env:
|
||||
TEST_SKIP_INTEGRATION: 1
|
||||
TESTCOVERAGE: 1
|
||||
TESTFLAGS: "-test.run (${{ matrix.test }})/"
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
reportsName=$(echo -n "${{ matrix.test }}" | sha256sum | cut -d " " -f 1)
|
||||
reportsPath=/tmp/reports/$reportsName
|
||||
echo "TESTREPORTS_NAME=$reportsName" >> $GITHUB_ENV
|
||||
|
||||
mkdir -p bundles $reportsPath
|
||||
echo "${{ matrix.test }}" | tr -s '|' '\n' | tee -a "$reportsPath/tests.txt"
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \( -name '*-report.json' -o -name '*.log' -o -name '*.out' -o -name '*.prof' -o -name '*-report.xml' \) -print | xargs sudo tar -czf /tmp/reports.tar.gz
|
||||
tar -xzf /tmp/reports.tar.gz -C $reportsPath
|
||||
sudo chown -R $(id -u):$(id -g) $reportsPath
|
||||
tree -nh $reportsPath
|
||||
|
||||
curl -sSLf localhost:16686/api/traces?service=integration-test-client > $reportsPath/jaeger-trace.json
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
directory: ./bundles/test-integration
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration-cli
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-integration/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-reports-integration-cli-${{ inputs.storage }}-${{ env.TESTREPORTS_NAME }}
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
integration-cli-report:
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 10
|
||||
if: always()
|
||||
needs:
|
||||
- integration-cli
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: test-reports-integration-cli-${{ inputs.storage }}-*
|
||||
merge-multiple: true
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
551
.github/workflows/.windows.yml
vendored
Normal file
551
.github/workflows/.windows.yml
vendored
Normal file
|
@ -0,0 +1,551 @@
|
|||
# reusable workflow
|
||||
name: .windows
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
os:
|
||||
required: true
|
||||
type: string
|
||||
storage:
|
||||
required: true
|
||||
type: string
|
||||
default: "graphdriver"
|
||||
send_coverage:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.9"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
|
||||
WINDOWS_BASE_TAG_2019: ltsc2019
|
||||
WINDOWS_BASE_TAG_2022: ltsc2022
|
||||
TEST_IMAGE_NAME: moby:test
|
||||
TEST_CTN_NAME: moby
|
||||
DOCKER_BUILDKIT: 0
|
||||
ITG_CLI_MATRIX_SIZE: 6
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ inputs.os }}
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
BIN_OUT: ${{ github.workspace }}\out
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
name: Env
|
||||
run: |
|
||||
Get-ChildItem Env: | Out-String
|
||||
-
|
||||
name: Init
|
||||
run: |
|
||||
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build"
|
||||
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod"
|
||||
If ("${{ inputs.os }}" -eq "windows-2019") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
} ElseIf ("${{ inputs.os }}" -eq "windows-2022") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
-
|
||||
name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~\AppData\Local\go-build
|
||||
~\go\pkg\mod
|
||||
${{ github.workspace }}\go-build
|
||||
${{ env.GOPATH }}\pkg\mod
|
||||
key: ${{ inputs.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
|
||||
restore-keys: |
|
||||
${{ inputs.os }}-${{ github.job }}-
|
||||
-
|
||||
name: Docker info
|
||||
run: |
|
||||
docker info
|
||||
-
|
||||
name: Build base image
|
||||
run: |
|
||||
& docker build `
|
||||
--build-arg WINDOWS_BASE_IMAGE `
|
||||
--build-arg WINDOWS_BASE_IMAGE_TAG `
|
||||
--build-arg GO_VERSION `
|
||||
-t ${{ env.TEST_IMAGE_NAME }} `
|
||||
-f Dockerfile.windows .
|
||||
-
|
||||
name: Build binaries
|
||||
run: |
|
||||
& docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" `
|
||||
-v "${{ github.workspace }}\go-build:C:\Users\ContainerAdministrator\AppData\Local\go-build" `
|
||||
-v "${{ github.workspace }}\go\pkg\mod:C:\gopath\pkg\mod" `
|
||||
${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -Daemon -Client
|
||||
-
|
||||
name: Copy artifacts
|
||||
run: |
|
||||
New-Item -ItemType "directory" -Path "${{ env.BIN_OUT }}"
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\docker.exe" ${{ env.BIN_OUT }}\
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\dockerd.exe" ${{ env.BIN_OUT }}\
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\bin\gotestsum.exe" ${{ env.BIN_OUT }}\
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd.exe" ${{ env.BIN_OUT }}\
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd-shim-runhcs-v1.exe" ${{ env.BIN_OUT }}\
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-${{ inputs.storage }}-${{ inputs.os }}
|
||||
path: ${{ env.BIN_OUT }}/*
|
||||
if-no-files-found: error
|
||||
retention-days: 2
|
||||
|
||||
unit-test:
|
||||
runs-on: ${{ inputs.os }}
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
name: Env
|
||||
run: |
|
||||
Get-ChildItem Env: | Out-String
|
||||
-
|
||||
name: Init
|
||||
run: |
|
||||
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build"
|
||||
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod"
|
||||
New-Item -ItemType "directory" -Path "bundles"
|
||||
If ("${{ inputs.os }}" -eq "windows-2019") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
} ElseIf ("${{ inputs.os }}" -eq "windows-2022") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
-
|
||||
name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~\AppData\Local\go-build
|
||||
~\go\pkg\mod
|
||||
${{ github.workspace }}\go-build
|
||||
${{ env.GOPATH }}\pkg\mod
|
||||
key: ${{ inputs.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
|
||||
restore-keys: |
|
||||
${{ inputs.os }}-${{ github.job }}-
|
||||
-
|
||||
name: Docker info
|
||||
run: |
|
||||
docker info
|
||||
-
|
||||
name: Build base image
|
||||
run: |
|
||||
& docker build `
|
||||
--build-arg WINDOWS_BASE_IMAGE `
|
||||
--build-arg WINDOWS_BASE_IMAGE_TAG `
|
||||
--build-arg GO_VERSION `
|
||||
-t ${{ env.TEST_IMAGE_NAME }} `
|
||||
-f Dockerfile.windows .
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
& docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" `
|
||||
-v "${{ github.workspace }}\go-build:C:\Users\ContainerAdministrator\AppData\Local\go-build" `
|
||||
-v "${{ github.workspace }}\go\pkg\mod:C:\gopath\pkg\mod" `
|
||||
-v "${{ env.GOPATH }}\src\github.com\docker\docker\bundles:C:\gopath\src\github.com\docker\docker\bundles" `
|
||||
${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -TestUnit
|
||||
-
|
||||
name: Send to Codecov
|
||||
if: inputs.send_coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker
|
||||
directory: bundles
|
||||
env_vars: RUNNER_OS
|
||||
flags: unit
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports
|
||||
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
||||
retention-days: 1
|
||||
|
||||
unit-test-report:
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
needs:
|
||||
- unit-test
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports
|
||||
path: /tmp/artifacts
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/artifacts -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
integration-test-prepare:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.tests.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Install gotestlist
|
||||
run:
|
||||
go install github.com/crazy-max/gotestlist/cmd/gotestlist@${{ env.GOTESTLIST_VERSION }}
|
||||
-
|
||||
name: Create matrix
|
||||
id: tests
|
||||
working-directory: ./integration-cli
|
||||
run: |
|
||||
# This step creates a matrix for integration-cli tests. Tests suites
|
||||
# are distributed in integration-test job through a matrix. There is
|
||||
# also an override being added to the matrix like "./..." to run
|
||||
# "Test integration" step exclusively.
|
||||
matrix="$(gotestlist -d ${{ env.ITG_CLI_MATRIX_SIZE }} -o "./..." ./...)"
|
||||
echo "matrix=$matrix" >> $GITHUB_OUTPUT
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.tests.outputs.matrix }}
|
||||
|
||||
integration-test:
|
||||
runs-on: ${{ inputs.os }}
|
||||
continue-on-error: ${{ inputs.storage == 'snapshotter' && github.event_name != 'pull_request' }}
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build
|
||||
- integration-test-prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
storage:
|
||||
- ${{ inputs.storage }}
|
||||
runtime:
|
||||
- builtin
|
||||
- containerd
|
||||
test: ${{ fromJson(needs.integration-test-prepare.outputs.matrix) }}
|
||||
exclude:
|
||||
- storage: snapshotter
|
||||
runtime: builtin
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
BIN_OUT: ${{ github.workspace }}\out
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
name: Set up Jaeger
|
||||
run: |
|
||||
# Jaeger is set up on Linux through the setup-tracing action. If you update Jaeger here, don't forget to
|
||||
# update the version set in .github/actions/setup-tracing/action.yml.
|
||||
Invoke-WebRequest -Uri "https://github.com/jaegertracing/jaeger/releases/download/v1.46.0/jaeger-1.46.0-windows-amd64.tar.gz" -OutFile ".\jaeger-1.46.0-windows-amd64.tar.gz"
|
||||
tar -zxvf ".\jaeger-1.46.0-windows-amd64.tar.gz"
|
||||
Start-Process '.\jaeger-1.46.0-windows-amd64\jaeger-all-in-one.exe'
|
||||
echo "OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
shell: pwsh
|
||||
-
|
||||
name: Env
|
||||
run: |
|
||||
Get-ChildItem Env: | Out-String
|
||||
-
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: build-${{ inputs.storage }}-${{ inputs.os }}
|
||||
path: ${{ env.BIN_OUT }}
|
||||
-
|
||||
name: Init
|
||||
run: |
|
||||
New-Item -ItemType "directory" -Path "bundles"
|
||||
If ("${{ inputs.os }}" -eq "windows-2019") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
} ElseIf ("${{ inputs.os }}" -eq "windows-2022") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
Write-Output "${{ env.BIN_OUT }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
|
||||
$testName = ([System.BitConverter]::ToString((New-Object System.Security.Cryptography.SHA256Managed).ComputeHash([System.Text.Encoding]::UTF8.GetBytes("${{ matrix.test }}"))) -replace '-').ToLower()
|
||||
echo "TESTREPORTS_NAME=$testName" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
-
|
||||
# removes docker service that is currently installed on the runner. we
|
||||
# could use Uninstall-Package but not yet available on Windows runners.
|
||||
# more info: https://github.com/actions/virtual-environments/blob/d3a5bad25f3b4326c5666bab0011ac7f1beec95e/images/win/scripts/Installers/Install-Docker.ps1#L11
|
||||
name: Removing current daemon
|
||||
run: |
|
||||
if (Get-Service docker -ErrorAction SilentlyContinue) {
|
||||
$dockerVersion = (docker version -f "{{.Server.Version}}")
|
||||
Write-Host "Current installed Docker version: $dockerVersion"
|
||||
# remove service
|
||||
Stop-Service -Force -Name docker
|
||||
Remove-Service -Name docker
|
||||
# removes event log entry. we could use "Remove-EventLog -LogName -Source docker"
|
||||
# but this cmd is not available atm
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
& reg delete "HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\docker" /f 2>&1 | Out-Null
|
||||
$ErrorActionPreference = "Stop"
|
||||
Write-Host "Service removed"
|
||||
}
|
||||
-
|
||||
name: Starting containerd
|
||||
if: matrix.runtime == 'containerd'
|
||||
run: |
|
||||
Write-Host "Generating config"
|
||||
& "${{ env.BIN_OUT }}\containerd.exe" config default | Out-File "$env:TEMP\ctn.toml" -Encoding ascii
|
||||
Write-Host "Creating service"
|
||||
New-Item -ItemType Directory "$env:TEMP\ctn-root" -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item -ItemType Directory "$env:TEMP\ctn-state" -ErrorAction SilentlyContinue | Out-Null
|
||||
Start-Process -Wait "${{ env.BIN_OUT }}\containerd.exe" `
|
||||
-ArgumentList "--log-level=debug", `
|
||||
"--config=$env:TEMP\ctn.toml", `
|
||||
"--address=\\.\pipe\containerd-containerd", `
|
||||
"--root=$env:TEMP\ctn-root", `
|
||||
"--state=$env:TEMP\ctn-state", `
|
||||
"--log-file=$env:TEMP\ctn.log", `
|
||||
"--register-service"
|
||||
Write-Host "Starting service"
|
||||
Start-Service -Name containerd
|
||||
Start-Sleep -Seconds 5
|
||||
Write-Host "Service started successfully!"
|
||||
-
|
||||
name: Starting test daemon
|
||||
run: |
|
||||
Write-Host "Creating service"
|
||||
If ("${{ matrix.runtime }}" -eq "containerd") {
|
||||
$runtimeArg="--containerd=\\.\pipe\containerd-containerd"
|
||||
echo "DOCKER_WINDOWS_CONTAINERD_RUNTIME=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
New-Item -ItemType Directory "$env:TEMP\moby-root" -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item -ItemType Directory "$env:TEMP\moby-exec" -ErrorAction SilentlyContinue | Out-Null
|
||||
Start-Process -Wait -NoNewWindow "${{ env.BIN_OUT }}\dockerd" `
|
||||
-ArgumentList $runtimeArg, "--debug", `
|
||||
"--host=npipe:////./pipe/docker_engine", `
|
||||
"--data-root=$env:TEMP\moby-root", `
|
||||
"--exec-root=$env:TEMP\moby-exec", `
|
||||
"--pidfile=$env:TEMP\docker.pid", `
|
||||
"--register-service"
|
||||
If ("${{ inputs.storage }}" -eq "snapshotter") {
|
||||
# Make the env-var visible to the service-managed dockerd, as there's no CLI flag for this option.
|
||||
& reg add "HKLM\SYSTEM\CurrentControlSet\Services\docker" /v Environment /t REG_MULTI_SZ /s '@' /d TEST_INTEGRATION_USE_SNAPSHOTTER=1
|
||||
echo "TEST_INTEGRATION_USE_SNAPSHOTTER=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
Write-Host "Starting service"
|
||||
Start-Service -Name docker
|
||||
Write-Host "Service started successfully!"
|
||||
-
|
||||
name: Waiting for test daemon to start
|
||||
run: |
|
||||
$tries=20
|
||||
Write-Host "Waiting for the test daemon to start..."
|
||||
While ($true) {
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
& "${{ env.BIN_OUT }}\docker" version
|
||||
$ErrorActionPreference = "Stop"
|
||||
If ($LastExitCode -eq 0) {
|
||||
break
|
||||
}
|
||||
$tries--
|
||||
If ($tries -le 0) {
|
||||
Throw "Failed to get a response from the daemon"
|
||||
}
|
||||
Write-Host -NoNewline "."
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
Write-Host "Test daemon started and replied!"
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: Docker info
|
||||
run: |
|
||||
& "${{ env.BIN_OUT }}\docker" info
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: Building contrib/busybox
|
||||
run: |
|
||||
& "${{ env.BIN_OUT }}\docker" build -t busybox `
|
||||
--build-arg WINDOWS_BASE_IMAGE `
|
||||
--build-arg WINDOWS_BASE_IMAGE_TAG `
|
||||
.\contrib\busybox\
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: List images
|
||||
run: |
|
||||
& "${{ env.BIN_OUT }}\docker" images
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Test integration
|
||||
if: matrix.test == './...'
|
||||
run: |
|
||||
.\hack\make.ps1 -TestIntegration
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
GO111MODULE: "off"
|
||||
TEST_CLIENT_BINARY: ${{ env.BIN_OUT }}\docker
|
||||
-
|
||||
name: Test integration-cli
|
||||
if: matrix.test != './...'
|
||||
run: |
|
||||
.\hack\make.ps1 -TestIntegrationCli
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
GO111MODULE: "off"
|
||||
TEST_CLIENT_BINARY: ${{ env.BIN_OUT }}\docker
|
||||
INTEGRATION_TESTRUN: ${{ matrix.test }}
|
||||
-
|
||||
name: Send to Codecov
|
||||
if: inputs.send_coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker
|
||||
directory: bundles
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration,${{ matrix.runtime }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # used to upload coverage reports: https://github.com/moby/buildkit/pull/4660#issue-2142122533
|
||||
-
|
||||
name: Docker info
|
||||
run: |
|
||||
& "${{ env.BIN_OUT }}\docker" info
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: Stop containerd
|
||||
if: always() && matrix.runtime == 'containerd'
|
||||
run: |
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
Stop-Service -Force -Name containerd
|
||||
$ErrorActionPreference = "Stop"
|
||||
-
|
||||
name: Containerd logs
|
||||
if: always() && matrix.runtime == 'containerd'
|
||||
run: |
|
||||
Copy-Item "$env:TEMP\ctn.log" -Destination ".\bundles\containerd.log"
|
||||
Get-Content "$env:TEMP\ctn.log" | Out-Host
|
||||
-
|
||||
name: Stop daemon
|
||||
if: always()
|
||||
run: |
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
Stop-Service -Force -Name docker
|
||||
$ErrorActionPreference = "Stop"
|
||||
-
|
||||
# as the daemon is registered as a service we have to check the event
|
||||
# logs against the docker provider.
|
||||
name: Daemon event logs
|
||||
if: always()
|
||||
run: |
|
||||
Get-WinEvent -ea SilentlyContinue `
|
||||
-FilterHashtable @{ProviderName= "docker"; LogName = "application"} |
|
||||
Sort-Object @{Expression="TimeCreated";Descending=$false} |
|
||||
ForEach-Object {"$($_.TimeCreated.ToUniversalTime().ToString("o")) [$($_.LevelDisplayName)] $($_.Message)"} |
|
||||
Tee-Object -file ".\bundles\daemon.log"
|
||||
-
|
||||
name: Download Jaeger traces
|
||||
if: always()
|
||||
run: |
|
||||
Invoke-WebRequest `
|
||||
-Uri "http://127.0.0.1:16686/api/traces?service=integration-test-client" `
|
||||
-OutFile ".\bundles\jaeger-trace.json"
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-${{ env.TESTREPORTS_NAME }}
|
||||
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
||||
retention-days: 1
|
||||
|
||||
integration-test-report:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: ${{ inputs.storage == 'snapshotter' && github.event_name != 'pull_request' }}
|
||||
if: always()
|
||||
needs:
|
||||
- integration-test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
storage:
|
||||
- ${{ inputs.storage }}
|
||||
runtime:
|
||||
- builtin
|
||||
- containerd
|
||||
exclude:
|
||||
- storage: snapshotter
|
||||
runtime: builtin
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-*
|
||||
merge-multiple: true
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
191
.github/workflows/bin-image.yml
vendored
Normal file
191
.github/workflows/bin-image.yml
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
name: bin-image
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
MOBYBIN_REPO_SLUG: moby/moby-bin
|
||||
DOCKER_GITCOMMIT: ${{ github.sha }}
|
||||
VERSION: ${{ github.ref }}
|
||||
PLATFORM: Moby Engine - Nightly
|
||||
PRODUCT: moby-bin
|
||||
PACKAGER_NAME: The Moby Project
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
prepare:
|
||||
runs-on: ubuntu-20.04
|
||||
outputs:
|
||||
platforms: ${{ steps.platforms.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.MOBYBIN_REPO_SLUG }}
|
||||
### versioning strategy
|
||||
## push semver tag v23.0.0
|
||||
# moby/moby-bin:23.0.0
|
||||
# moby/moby-bin:latest
|
||||
## push semver prelease tag v23.0.0-beta.1
|
||||
# moby/moby-bin:23.0.0-beta.1
|
||||
## push on master
|
||||
# moby/moby-bin:master
|
||||
## push on 23.0 branch
|
||||
# moby/moby-bin:23.0
|
||||
## any push
|
||||
# moby/moby-bin:sha-ad132f5
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=sha
|
||||
-
|
||||
name: Rename meta bake definition file
|
||||
# see https://github.com/docker/metadata-action/issues/381#issuecomment-1918607161
|
||||
run: |
|
||||
bakeFile="${{ steps.meta.outputs.bake-file }}"
|
||||
mv "${bakeFile#cwd://}" "/tmp/bake-meta.json"
|
||||
-
|
||||
name: Upload meta bake definition
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp/bake-meta.json
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
-
|
||||
name: Create platforms matrix
|
||||
id: platforms
|
||||
run: |
|
||||
echo "matrix=$(docker buildx bake bin-image-cross --print | jq -cr '.target."bin-image-cross".platforms')" >>${GITHUB_OUTPUT}
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
- prepare
|
||||
if: always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ${{ fromJson(needs.prepare.outputs.platforms) }}
|
||||
steps:
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Download meta bake definition
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_MOBYBIN_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_MOBYBIN_TOKEN }}
|
||||
-
|
||||
name: Build
|
||||
id: bake
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
files: |
|
||||
./docker-bake.hcl
|
||||
/tmp/bake-meta.json
|
||||
targets: bin-image
|
||||
set: |
|
||||
*.platform=${{ matrix.platform }}
|
||||
*.output=type=image,name=${{ env.MOBYBIN_REPO_SLUG }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' && github.repository == 'moby/moby' }}
|
||||
*.tags=
|
||||
-
|
||||
name: Export digest
|
||||
if: github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
digest="${{ fromJSON(steps.bake.outputs.metadata)['bin-image']['containerimage.digest'] }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
-
|
||||
name: Upload digest
|
||||
if: github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- build
|
||||
if: always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
steps:
|
||||
-
|
||||
name: Download meta bake definition
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp
|
||||
-
|
||||
name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_MOBYBIN_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_MOBYBIN_TOKEN }}
|
||||
-
|
||||
name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
set -x
|
||||
docker buildx imagetools create $(jq -cr '.target."docker-metadata-action".tags | map("-t " + .) | join(" ")' /tmp/bake-meta.json) \
|
||||
$(printf '${{ env.MOBYBIN_REPO_SLUG }}@sha256:%s ' *)
|
||||
-
|
||||
name: Inspect image
|
||||
run: |
|
||||
set -x
|
||||
docker buildx imagetools inspect ${{ env.MOBYBIN_REPO_SLUG }}:$(jq -cr '.target."docker-metadata-action".args.DOCKER_META_VERSION' /tmp/bake-meta.json)
|
139
.github/workflows/buildkit.yml
vendored
Normal file
139
.github/workflows/buildkit.yml
vendored
Normal file
|
@ -0,0 +1,139 @@
|
|||
name: buildkit
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.9"
|
||||
DESTDIR: ./build
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: binary
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: binary
|
||||
path: ${{ env.DESTDIR }}
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build
|
||||
env:
|
||||
TEST_IMAGE_BUILD: "0"
|
||||
TEST_IMAGE_ID: "buildkit-tests"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
worker:
|
||||
- dockerd
|
||||
- dockerd-containerd
|
||||
pkg:
|
||||
- client
|
||||
- cmd/buildctl
|
||||
- solver
|
||||
- frontend
|
||||
- frontend/dockerfile
|
||||
typ:
|
||||
- integration
|
||||
steps:
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
disabledFeatures="cache_backend_azblob,cache_backend_s3"
|
||||
if [ "${{ matrix.worker }}" = "dockerd" ]; then
|
||||
disabledFeatures="${disabledFeatures},merge_diff"
|
||||
fi
|
||||
echo "BUILDKIT_TEST_DISABLE_FEATURES=${disabledFeatures}" >> $GITHUB_ENV
|
||||
# Expose `ACTIONS_RUNTIME_TOKEN` and `ACTIONS_CACHE_URL`, which is used
|
||||
# in BuildKit's test suite to skip/unskip cache exporters:
|
||||
# https://github.com/moby/buildkit/blob/567a99433ca23402d5e9b9f9124005d2e59b8861/client/client_test.go#L5407-L5411
|
||||
-
|
||||
name: Expose GitHub Runtime
|
||||
uses: crazy-max/ghaction-github-runtime@v3
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: moby
|
||||
-
|
||||
name: BuildKit ref
|
||||
run: |
|
||||
echo "$(./hack/buildkit-ref)" >> $GITHUB_ENV
|
||||
working-directory: moby
|
||||
-
|
||||
name: Checkout BuildKit ${{ env.BUILDKIT_REF }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ env.BUILDKIT_REPO }}
|
||||
ref: ${{ env.BUILDKIT_REF }}
|
||||
path: buildkit
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Download binary artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: binary
|
||||
path: ./buildkit/build/moby/
|
||||
-
|
||||
name: Update daemon.json
|
||||
run: |
|
||||
sudo rm -f /etc/docker/daemon.json
|
||||
sudo service docker restart
|
||||
docker version
|
||||
docker info
|
||||
-
|
||||
name: Build test image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
workdir: ./buildkit
|
||||
targets: integration-tests
|
||||
set: |
|
||||
*.output=type=docker,name=${{ env.TEST_IMAGE_ID }}
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
./hack/test ${{ matrix.typ }}
|
||||
env:
|
||||
CONTEXT: "."
|
||||
TEST_DOCKERD: "1"
|
||||
TEST_DOCKERD_BINARY: "./build/moby/dockerd"
|
||||
TESTPKGS: "./${{ matrix.pkg }}"
|
||||
TESTFLAGS: "-v --parallel=1 --timeout=30m --run=//worker=${{ matrix.worker }}$"
|
||||
working-directory: buildkit
|
171
.github/workflows/ci.yml
vendored
171
.github/workflows/ci.yml
vendored
|
@ -9,17 +9,20 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]{2}'
|
||||
tags:
|
||||
- 'v*'
|
||||
- '[0-9]+.[0-9]+'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
BUNDLES_OUTPUT: ./bundles
|
||||
DESTDIR: ./build
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
@ -29,48 +32,60 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v1
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
set: |
|
||||
*.cache-from=type=gha,scope=build-${{ matrix.target }}
|
||||
*.cache-to=type=gha,scope=build-${{ matrix.target }}
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
path: ${{ env.BUNDLES_OUTPUT }}
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
name: List artifacts
|
||||
run: |
|
||||
tree -nh ${{ env.DESTDIR }}
|
||||
-
|
||||
name: Check artifacts
|
||||
run: |
|
||||
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
|
||||
|
||||
cross:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm/v5
|
||||
- linux/arm/v6
|
||||
- linux/arm/v7
|
||||
- linux/arm64
|
||||
- linux/ppc64le
|
||||
- linux/s390x
|
||||
- windows/amd64
|
||||
- windows/arm64
|
||||
prepare-cross:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- validate-dco
|
||||
outputs:
|
||||
matrix: ${{ steps.platforms.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
run: |
|
||||
matrix="$(docker buildx bake binary-cross --print | jq -cr '.target."binary-cross".platforms')"
|
||||
echo "matrix=$matrix" >> $GITHUB_OUTPUT
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.platforms.outputs.matrix }}
|
||||
|
||||
cross:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
- prepare-cross
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ${{ fromJson(needs.prepare-cross.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
|
@ -80,93 +95,19 @@ jobs:
|
|||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v1
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: cross
|
||||
targets: all
|
||||
set: |
|
||||
*.cache-from=type=gha,scope=cross-${{ env.PLATFORM_PAIR }}
|
||||
*.cache-to=type=gha,scope=cross-${{ env.PLATFORM_PAIR }}
|
||||
env:
|
||||
DOCKER_CROSSPLATFORMS: ${{ matrix.platform }}
|
||||
*.platform=${{ matrix.platform }}
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: cross-${{ env.PLATFORM_PAIR }}
|
||||
path: ${{ env.BUNDLES_OUTPUT }}
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
test-buildkit:
|
||||
needs:
|
||||
- build
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pkg:
|
||||
- ./client
|
||||
- ./cmd/buildctl
|
||||
- ./solver
|
||||
- ./frontend
|
||||
- ./frontend/dockerfile
|
||||
typ:
|
||||
- integration
|
||||
include:
|
||||
- pkg: ./...
|
||||
skip-integration-tests: 1
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: moby
|
||||
-
|
||||
name: BuildKit ref
|
||||
name: List artifacts
|
||||
run: |
|
||||
./hack/go-mod-prepare.sh
|
||||
echo "BUILDKIT_REF=0da740f7d4f782a52b416a44f564ac37504b9ee1" >> $GITHUB_ENV
|
||||
# FIXME(thaJeztah) temporarily overriding version to use for tests to include https://github.com/moby/buildkit/pull/2872
|
||||
# echo "BUILDKIT_REF=$(./hack/buildkit-ref)" >> $GITHUB_ENV
|
||||
working-directory: moby
|
||||
tree -nh ${{ env.DESTDIR }}
|
||||
-
|
||||
name: Checkout BuildKit ${{ env.BUILDKIT_REF }}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: "moby/buildkit"
|
||||
ref: ${{ env.BUILDKIT_REF }}
|
||||
path: buildkit
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
-
|
||||
name: Download binary artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: binary
|
||||
path: ./buildkit/build/moby/
|
||||
-
|
||||
name: Update daemon.json
|
||||
name: Check artifacts
|
||||
run: |
|
||||
sudo rm /etc/docker/daemon.json
|
||||
sudo service docker restart
|
||||
docker version
|
||||
docker info
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
./hack/test ${{ matrix.typ }}
|
||||
env:
|
||||
CONTEXT: "."
|
||||
TEST_DOCKERD: "1"
|
||||
TEST_DOCKERD_BINARY: "./build/moby/binary-daemon/dockerd"
|
||||
TESTPKGS: "${{ matrix.pkg }}"
|
||||
TESTFLAGS: "-v --parallel=1 --timeout=30m --run=//worker=dockerd$"
|
||||
SKIP_INTEGRATION_TESTS: "${{ matrix.skip-integration-tests }}"
|
||||
working-directory: buildkit
|
||||
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
|
||||
|
|
177
.github/workflows/test.yml
vendored
Normal file
177
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,177 @@
|
|||
name: test
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.21.9"
|
||||
GIT_PAGER: "cat"
|
||||
PAGER: "cat"
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
build-dev:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
mode:
|
||||
- ""
|
||||
- systemd
|
||||
steps:
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
if [ "${{ matrix.mode }}" = "systemd" ]; then
|
||||
echo "SYSTEMD=true" >> $GITHUB_ENV
|
||||
fi
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
*.cache-from=type=gha,scope=dev${{ matrix.mode }}
|
||||
*.cache-to=type=gha,scope=dev${{ matrix.mode }},mode=max
|
||||
*.output=type=cacheonly
|
||||
|
||||
test:
|
||||
needs:
|
||||
- build-dev
|
||||
- validate-dco
|
||||
uses: ./.github/workflows/.test.yml
|
||||
secrets: inherit
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
storage:
|
||||
- graphdriver
|
||||
- snapshotter
|
||||
with:
|
||||
storage: ${{ matrix.storage }}
|
||||
|
||||
validate-prepare:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
outputs:
|
||||
matrix: ${{ steps.scripts.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Create matrix
|
||||
id: scripts
|
||||
run: |
|
||||
scripts=$(cd ./hack/validate && jq -nc '$ARGS.positional - ["all", "default", "dco"] | map(select(test("[.]")|not)) + ["generate-files"]' --args *)
|
||||
echo "matrix=$scripts" >> $GITHUB_OUTPUT
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.scripts.outputs.matrix }}
|
||||
|
||||
validate:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- validate-prepare
|
||||
- build-dev
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
script: ${{ fromJson(needs.validate-prepare.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Validate
|
||||
run: |
|
||||
make -o build validate-${{ matrix.script }}
|
||||
|
||||
smoke-prepare:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
outputs:
|
||||
matrix: ${{ steps.platforms.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
run: |
|
||||
matrix="$(docker buildx bake binary-smoketest --print | jq -cr '.target."binary-smoketest".platforms')"
|
||||
echo "matrix=$matrix" >> $GITHUB_OUTPUT
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.platforms.outputs.matrix }}
|
||||
|
||||
smoke:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- smoke-prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ${{ fromJson(needs.smoke-prepare.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Test
|
||||
uses: docker/bake-action@v4
|
||||
with:
|
||||
targets: binary-smoketest
|
||||
set: |
|
||||
*.platform=${{ matrix.platform }}
|
62
.github/workflows/validate-pr.yml
vendored
Normal file
62
.github/workflows/validate-pr.yml
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
name: validate-pr
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
check-area-label:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Missing `area/` label
|
||||
if: contains(join(github.event.pull_request.labels.*.name, ','), 'impact/') && !contains(join(github.event.pull_request.labels.*.name, ','), 'area/')
|
||||
run: |
|
||||
echo "::error::Every PR with an 'impact/*' label should also have an 'area/*' label"
|
||||
exit 1
|
||||
- name: OK
|
||||
run: exit 0
|
||||
|
||||
check-changelog:
|
||||
if: contains(join(github.event.pull_request.labels.*.name, ','), 'impact/')
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
PR_BODY: |
|
||||
${{ github.event.pull_request.body }}
|
||||
steps:
|
||||
- name: Check changelog description
|
||||
run: |
|
||||
# Extract the `markdown changelog` note code block
|
||||
block=$(echo -n "$PR_BODY" | tr -d '\r' | awk '/^```markdown changelog$/{flag=1;next}/^```$/{flag=0}flag')
|
||||
|
||||
# Strip empty lines
|
||||
desc=$(echo "$block" | awk NF)
|
||||
|
||||
if [ -z "$desc" ]; then
|
||||
echo "::error::Changelog section is empty. Please provide a description for the changelog."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
len=$(echo -n "$desc" | wc -c)
|
||||
if [[ $len -le 6 ]]; then
|
||||
echo "::error::Description looks too short: $desc"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "This PR will be included in the release notes with the following note:"
|
||||
echo "$desc"
|
||||
|
||||
check-pr-branch:
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
steps:
|
||||
# Backports or PR that target a release branch directly should mention the target branch in the title, for example:
|
||||
# [X.Y backport] Some change that needs backporting to X.Y
|
||||
# [X.Y] Change directly targeting the X.Y branch
|
||||
- name: Get branch from PR title
|
||||
id: title_branch
|
||||
run: echo "$PR_TITLE" | sed -n 's/^\[\([0-9]*\.[0-9]*\)[^]]*\].*/branch=\1/p' >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check release branch
|
||||
if: github.event.pull_request.base.ref != steps.title_branch.outputs.branch && !(github.event.pull_request.base.ref == 'master' && steps.title_branch.outputs.branch == '')
|
||||
run: echo "::error::PR title suggests targetting the ${{ steps.title_branch.outputs.branch }} branch, but is opened against ${{ github.event.pull_request.base.ref }}" && exit 1
|
33
.github/workflows/windows-2019.yml
vendored
Normal file
33
.github/workflows/windows-2019.yml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
name: windows-2019
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 10 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
test-prepare:
|
||||
uses: ./.github/workflows/.test-prepare.yml
|
||||
needs:
|
||||
- validate-dco
|
||||
|
||||
run:
|
||||
needs:
|
||||
- test-prepare
|
||||
uses: ./.github/workflows/.windows.yml
|
||||
secrets: inherit
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
storage: ${{ fromJson(needs.test-prepare.outputs.matrix) }}
|
||||
with:
|
||||
os: windows-2019
|
||||
storage: ${{ matrix.storage }}
|
||||
send_coverage: false
|
36
.github/workflows/windows-2022.yml
vendored
Normal file
36
.github/workflows/windows-2022.yml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
name: windows-2022
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
test-prepare:
|
||||
uses: ./.github/workflows/.test-prepare.yml
|
||||
needs:
|
||||
- validate-dco
|
||||
|
||||
run:
|
||||
needs:
|
||||
- test-prepare
|
||||
uses: ./.github/workflows/.windows.yml
|
||||
secrets: inherit
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
storage: ${{ fromJson(needs.test-prepare.outputs.matrix) }}
|
||||
with:
|
||||
os: windows-2022
|
||||
storage: ${{ matrix.storage }}
|
||||
send_coverage: true
|
519
.github/workflows/windows.yml
vendored
519
.github/workflows/windows.yml
vendored
|
@ -1,519 +0,0 @@
|
|||
name: windows
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]{2}'
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: 1.18.3
|
||||
GOTESTLIST_VERSION: v0.2.0
|
||||
TESTSTAT_VERSION: v0.1.3
|
||||
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
|
||||
WINDOWS_BASE_TAG_2019: ltsc2019
|
||||
WINDOWS_BASE_TAG_2022: ltsc2022
|
||||
TEST_IMAGE_NAME: moby:test
|
||||
TEST_CTN_NAME: moby
|
||||
DOCKER_BUILDKIT: 0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- windows-2019
|
||||
- windows-2022
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
BIN_OUT: ${{ github.workspace }}\out
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
name: Env
|
||||
run: |
|
||||
Get-ChildItem Env: | Out-String
|
||||
-
|
||||
name: Init
|
||||
run: |
|
||||
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build"
|
||||
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod"
|
||||
If ("${{ matrix.os }}" -eq "windows-2019") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
} ElseIf ("${{ matrix.os }}" -eq "windows-2022") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
-
|
||||
name: Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~\AppData\Local\go-build
|
||||
~\go\pkg\mod
|
||||
${{ github.workspace }}\go-build
|
||||
${{ env.GOPATH }}\pkg\mod
|
||||
key: ${{ matrix.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-${{ github.job }}-
|
||||
-
|
||||
name: Docker info
|
||||
run: |
|
||||
docker info
|
||||
-
|
||||
name: Build base image
|
||||
run: |
|
||||
docker pull ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }}
|
||||
docker tag ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }} microsoft/windowsservercore
|
||||
docker build --build-arg GO_VERSION -t ${{ env.TEST_IMAGE_NAME }} -f Dockerfile.windows .
|
||||
-
|
||||
name: Build binaries
|
||||
run: |
|
||||
& docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" `
|
||||
-v "${{ github.workspace }}\go-build:C:\Users\ContainerAdministrator\AppData\Local\go-build" `
|
||||
-v "${{ github.workspace }}\go\pkg\mod:C:\gopath\pkg\mod" `
|
||||
${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -Daemon -Client
|
||||
-
|
||||
name: Copy artifacts
|
||||
run: |
|
||||
New-Item -ItemType "directory" -Path "${{ env.BIN_OUT }}"
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\docker.exe" ${{ env.BIN_OUT }}\
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\dockerd.exe" ${{ env.BIN_OUT }}\
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\bin\gotestsum.exe" ${{ env.BIN_OUT }}\
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd.exe" ${{ env.BIN_OUT }}\
|
||||
docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd-shim-runhcs-v1.exe" ${{ env.BIN_OUT }}\
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build-${{ matrix.os }}
|
||||
path: ${{ env.BIN_OUT }}/*
|
||||
if-no-files-found: error
|
||||
retention-days: 2
|
||||
|
||||
unit-test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- windows-2019
|
||||
- windows-2022
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
name: Env
|
||||
run: |
|
||||
Get-ChildItem Env: | Out-String
|
||||
-
|
||||
name: Init
|
||||
run: |
|
||||
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build"
|
||||
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod"
|
||||
New-Item -ItemType "directory" -Path "bundles"
|
||||
If ("${{ matrix.os }}" -eq "windows-2019") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
} ElseIf ("${{ matrix.os }}" -eq "windows-2022") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
-
|
||||
name: Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~\AppData\Local\go-build
|
||||
~\go\pkg\mod
|
||||
${{ github.workspace }}\go-build
|
||||
${{ env.GOPATH }}\pkg\mod
|
||||
key: ${{ matrix.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-${{ github.job }}-
|
||||
-
|
||||
name: Docker info
|
||||
run: |
|
||||
docker info
|
||||
-
|
||||
name: Build base image
|
||||
run: |
|
||||
docker pull ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }}
|
||||
docker tag ${{ env.WINDOWS_BASE_IMAGE }}:${{ env.WINDOWS_BASE_IMAGE_TAG }} microsoft/windowsservercore
|
||||
docker build --build-arg GO_VERSION -t ${{ env.TEST_IMAGE_NAME }} -f Dockerfile.windows .
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
& docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" `
|
||||
-v "${{ github.workspace }}\go-build:C:\Users\ContainerAdministrator\AppData\Local\go-build" `
|
||||
-v "${{ github.workspace }}\go\pkg\mod:C:\gopath\pkg\mod" `
|
||||
-v "${{ env.GOPATH }}\src\github.com\docker\docker\bundles:C:\gopath\src\github.com\docker\docker\bundles" `
|
||||
${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -TestUnit
|
||||
-
|
||||
name: Send to Codecov
|
||||
if: matrix.os == 'windows-2022'
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker
|
||||
directory: bundles
|
||||
env_vars: RUNNER_OS
|
||||
flags: unit
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.os }}-unit-reports
|
||||
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
||||
|
||||
unit-test-report:
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
needs:
|
||||
- unit-test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- windows-2019
|
||||
- windows-2022
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.os }}-unit-reports
|
||||
path: /tmp/artifacts
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
teststat -markdown $(find /tmp/artifacts -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
integration-test-prepare:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.tests.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Install gotestlist
|
||||
run:
|
||||
go install github.com/crazy-max/gotestlist/cmd/gotestlist@${{ env.GOTESTLIST_VERSION }}
|
||||
-
|
||||
name: Create matrix
|
||||
id: tests
|
||||
working-directory: ./integration-cli
|
||||
run: |
|
||||
# Distribute integration-cli tests for the matrix in integration-test job.
|
||||
# Also prepend ./... to the matrix. This is a special case to run "Test integration" step exclusively.
|
||||
matrix="$(gotestlist -d 4 ./...)"
|
||||
matrix="$(echo "$matrix" | jq -c '. |= ["./..."] + .')"
|
||||
echo "::set-output name=matrix::$matrix"
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.tests.outputs.matrix }}
|
||||
|
||||
integration-test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs:
|
||||
- build
|
||||
- integration-test-prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- windows-2019
|
||||
- windows-2022
|
||||
runtime:
|
||||
- builtin
|
||||
- containerd
|
||||
test: ${{ fromJson(needs.integration-test-prepare.outputs.matrix) }}
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
BIN_OUT: ${{ github.workspace }}\out
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
name: Env
|
||||
run: |
|
||||
Get-ChildItem Env: | Out-String
|
||||
-
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: build-${{ matrix.os }}
|
||||
path: ${{ env.BIN_OUT }}
|
||||
-
|
||||
name: Init
|
||||
run: |
|
||||
New-Item -ItemType "directory" -Path "bundles"
|
||||
If ("${{ matrix.os }}" -eq "windows-2019") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2019 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
} ElseIf ("${{ matrix.os }}" -eq "windows-2022") {
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
Write-Output "${{ env.BIN_OUT }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
-
|
||||
# removes docker service that is currently installed on the runner. we
|
||||
# could use Uninstall-Package but not yet available on Windows runners.
|
||||
# more info: https://github.com/actions/virtual-environments/blob/d3a5bad25f3b4326c5666bab0011ac7f1beec95e/images/win/scripts/Installers/Install-Docker.ps1#L11
|
||||
name: Removing current daemon
|
||||
run: |
|
||||
if (Get-Service docker -ErrorAction SilentlyContinue) {
|
||||
$dockerVersion = (docker version -f "{{.Server.Version}}")
|
||||
Write-Host "Current installed Docker version: $dockerVersion"
|
||||
# remove service
|
||||
Stop-Service -Force -Name docker
|
||||
Remove-Service -Name docker
|
||||
# removes event log entry. we could use "Remove-EventLog -LogName -Source docker"
|
||||
# but this cmd is only available since windows-2022
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
& reg delete "HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\docker" /f 2>&1 | Out-Null
|
||||
$ErrorActionPreference = "Stop"
|
||||
Write-Host "Service removed"
|
||||
}
|
||||
-
|
||||
name: Starting containerd
|
||||
if: matrix.runtime == 'containerd'
|
||||
run: |
|
||||
Write-Host "Generating config"
|
||||
& "${{ env.BIN_OUT }}\containerd.exe" config default | Out-File "$env:TEMP\ctn.toml" -Encoding ascii
|
||||
Write-Host "Creating service"
|
||||
New-Item -ItemType Directory "$env:TEMP\ctn-root" -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item -ItemType Directory "$env:TEMP\ctn-state" -ErrorAction SilentlyContinue | Out-Null
|
||||
Start-Process -Wait "${{ env.BIN_OUT }}\containerd.exe" `
|
||||
-ArgumentList "--log-level=debug", `
|
||||
"--config=$env:TEMP\ctn.toml", `
|
||||
"--address=\\.\pipe\containerd-containerd", `
|
||||
"--root=$env:TEMP\ctn-root", `
|
||||
"--state=$env:TEMP\ctn-state", `
|
||||
"--log-file=$env:TEMP\ctn.log", `
|
||||
"--register-service"
|
||||
Write-Host "Starting service"
|
||||
Start-Service -Name containerd
|
||||
Start-Sleep -Seconds 5
|
||||
Write-Host "Service started successfully!"
|
||||
-
|
||||
name: Starting test daemon
|
||||
run: |
|
||||
Write-Host "Creating service"
|
||||
If ("${{ matrix.runtime }}" -eq "containerd") {
|
||||
$runtimeArg="--containerd=\\.\pipe\containerd-containerd"
|
||||
echo "DOCKER_WINDOWS_CONTAINERD_RUNTIME=1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
}
|
||||
New-Item -ItemType Directory "$env:TEMP\moby-root" -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item -ItemType Directory "$env:TEMP\moby-exec" -ErrorAction SilentlyContinue | Out-Null
|
||||
Start-Process -Wait -NoNewWindow "${{ env.BIN_OUT }}\dockerd" `
|
||||
-ArgumentList $runtimeArg, "--debug", `
|
||||
"--host=npipe:////./pipe/docker_engine", `
|
||||
"--data-root=$env:TEMP\moby-root", `
|
||||
"--exec-root=$env:TEMP\moby-exec", `
|
||||
"--pidfile=$env:TEMP\docker.pid", `
|
||||
"--register-service"
|
||||
Write-Host "Starting service"
|
||||
Start-Service -Name docker
|
||||
Write-Host "Service started successfully!"
|
||||
-
|
||||
name: Waiting for test daemon to start
|
||||
run: |
|
||||
$tries=20
|
||||
Write-Host "Waiting for the test daemon to start..."
|
||||
While ($true) {
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
& "${{ env.BIN_OUT }}\docker" version
|
||||
$ErrorActionPreference = "Stop"
|
||||
If ($LastExitCode -eq 0) {
|
||||
break
|
||||
}
|
||||
$tries--
|
||||
If ($tries -le 0) {
|
||||
Throw "Failed to get a response from the daemon"
|
||||
}
|
||||
Write-Host -NoNewline "."
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
Write-Host "Test daemon started and replied!"
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: Docker info
|
||||
run: |
|
||||
& "${{ env.BIN_OUT }}\docker" info
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: Building contrib/busybox
|
||||
run: |
|
||||
& "${{ env.BIN_OUT }}\docker" build -t busybox `
|
||||
--build-arg WINDOWS_BASE_IMAGE `
|
||||
--build-arg WINDOWS_BASE_IMAGE_TAG `
|
||||
.\contrib\busybox\
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: List images
|
||||
run: |
|
||||
& "${{ env.BIN_OUT }}\docker" images
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Test integration
|
||||
if: matrix.test == './...'
|
||||
run: |
|
||||
.\hack\make.ps1 -TestIntegration
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
GO111MODULE: "off"
|
||||
TEST_CLIENT_BINARY: ${{ env.BIN_OUT }}\docker
|
||||
-
|
||||
name: Test integration-cli
|
||||
if: matrix.test != './...'
|
||||
run: |
|
||||
.\hack\make.ps1 -TestIntegrationCli
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
GO111MODULE: "off"
|
||||
TEST_CLIENT_BINARY: ${{ env.BIN_OUT }}\docker
|
||||
INTEGRATION_TESTRUN: ${{ matrix.test }}
|
||||
-
|
||||
name: Send to Codecov
|
||||
if: matrix.os == 'windows-2022'
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
working-directory: ${{ env.GOPATH }}\src\github.com\docker\docker
|
||||
directory: bundles
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration,${{ matrix.runtime }}
|
||||
-
|
||||
name: Docker info
|
||||
run: |
|
||||
& "${{ env.BIN_OUT }}\docker" info
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: Stop containerd
|
||||
if: always() && matrix.runtime == 'containerd'
|
||||
run: |
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
Stop-Service -Force -Name containerd
|
||||
$ErrorActionPreference = "Stop"
|
||||
-
|
||||
name: Containerd logs
|
||||
if: always() && matrix.runtime == 'containerd'
|
||||
run: |
|
||||
Copy-Item "$env:TEMP\ctn.log" -Destination ".\bundles\containerd.log"
|
||||
Get-Content "$env:TEMP\ctn.log" | Out-Host
|
||||
-
|
||||
name: Stop daemon
|
||||
if: always()
|
||||
run: |
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
Stop-Service -Force -Name docker
|
||||
$ErrorActionPreference = "Stop"
|
||||
-
|
||||
# as the daemon is registered as a service we have to check the event
|
||||
# logs against the docker provider.
|
||||
name: Daemon event logs
|
||||
if: always()
|
||||
run: |
|
||||
Get-WinEvent -ea SilentlyContinue `
|
||||
-FilterHashtable @{ProviderName= "docker"; LogName = "application"} |
|
||||
Select-Object -Property TimeCreated, @{N='Detailed Message'; E={$_.Message}} |
|
||||
Sort-Object @{Expression="TimeCreated";Descending=$false} |
|
||||
Select-Object -ExpandProperty 'Detailed Message' | Tee-Object -file ".\bundles\daemon.log"
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.os }}-integration-reports-${{ matrix.runtime }}
|
||||
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
||||
|
||||
integration-test-report:
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
needs:
|
||||
- integration-test
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- windows-2019
|
||||
- windows-2022
|
||||
runtime:
|
||||
- builtin
|
||||
- containerd
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.os }}-integration-reports-${{ matrix.runtime }}
|
||||
path: /tmp/artifacts
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
teststat -markdown $(find /tmp/artifacts -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
43
.gitignore
vendored
43
.gitignore
vendored
|
@ -1,27 +1,28 @@
|
|||
# Docker project generated files to ignore
|
||||
# if you want to ignore files created by your editor/tools,
|
||||
# please consider a global .gitignore https://help.github.com/articles/ignoring-files
|
||||
*.exe
|
||||
*.exe~
|
||||
*.gz
|
||||
# If you want to ignore files created by your editor/tools, please consider a
|
||||
# [global .gitignore](https://help.github.com/articles/ignoring-files).
|
||||
|
||||
*~
|
||||
*.bak
|
||||
*.orig
|
||||
test.main
|
||||
.*.swp
|
||||
.DS_Store
|
||||
# a .bashrc may be added to customize the build environment
|
||||
thumbs.db
|
||||
|
||||
# local repository customization
|
||||
.envrc
|
||||
.bashrc
|
||||
.editorconfig
|
||||
.gopath/
|
||||
.go-pkg-cache/
|
||||
bundles/
|
||||
cli/winresources/**/winres.json
|
||||
cli/winresources/**/*.syso
|
||||
cmd/dockerd/dockerd
|
||||
contrib/builder/rpm/*/changelog
|
||||
vendor/pkg/
|
||||
go-test-report.json
|
||||
profile.out
|
||||
junit-report.xml
|
||||
|
||||
# top-level go.mod is not meant to be checked in
|
||||
/go.mod
|
||||
# build artifacts
|
||||
bundles/
|
||||
cli/winresources/*/*.syso
|
||||
cli/winresources/*/winres.json
|
||||
contrib/builder/rpm/*/changelog
|
||||
|
||||
# ci artifacts
|
||||
*.exe
|
||||
*.gz
|
||||
go-test-report.json
|
||||
junit-report.xml
|
||||
profile.out
|
||||
test.main
|
||||
|
|
137
.golangci.yml
Normal file
137
.golangci.yml
Normal file
|
@ -0,0 +1,137 @@
|
|||
linters:
|
||||
enable:
|
||||
- depguard
|
||||
- dupword # Checks for duplicate words in the source code.
|
||||
- goimports
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- importas
|
||||
- ineffassign
|
||||
- misspell
|
||||
- revive
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unused
|
||||
|
||||
disable:
|
||||
- errcheck
|
||||
|
||||
run:
|
||||
concurrency: 2
|
||||
modules-download-mode: vendor
|
||||
|
||||
skip-dirs:
|
||||
- docs
|
||||
|
||||
linters-settings:
|
||||
dupword:
|
||||
ignore:
|
||||
- "true" # some tests use this as expected output
|
||||
- "false" # some tests use this as expected output
|
||||
- "root" # for tests using "ls" output with files owned by "root:root"
|
||||
importas:
|
||||
# Do not allow unaliased imports of aliased packages.
|
||||
no-unaliased: true
|
||||
|
||||
alias:
|
||||
# Enforce alias to prevent it accidentally being used instead of our
|
||||
# own errdefs package (or vice-versa).
|
||||
- pkg: github.com/containerd/containerd/errdefs
|
||||
alias: cerrdefs
|
||||
- pkg: github.com/opencontainers/image-spec/specs-go/v1
|
||||
alias: ocispec
|
||||
|
||||
govet:
|
||||
check-shadowing: false
|
||||
depguard:
|
||||
rules:
|
||||
main:
|
||||
deny:
|
||||
- pkg: io/ioutil
|
||||
desc: The io/ioutil package has been deprecated, see https://go.dev/doc/go1.16#ioutil
|
||||
- pkg: "github.com/stretchr/testify/assert"
|
||||
desc: Use "gotest.tools/v3/assert" instead
|
||||
- pkg: "github.com/stretchr/testify/require"
|
||||
desc: Use "gotest.tools/v3/assert" instead
|
||||
- pkg: "github.com/stretchr/testify/suite"
|
||||
desc: Do not use
|
||||
revive:
|
||||
rules:
|
||||
# FIXME make sure all packages have a description. Currently, there's many packages without.
|
||||
- name: package-comments
|
||||
disabled: true
|
||||
issues:
|
||||
# The default exclusion rules are a bit too permissive, so copying the relevant ones below
|
||||
exclude-use-default: false
|
||||
|
||||
exclude-rules:
|
||||
# We prefer to use an "exclude-list" so that new "default" exclusions are not
|
||||
# automatically inherited. We can decide whether or not to follow upstream
|
||||
# defaults when updating golang-ci-lint versions.
|
||||
# Unfortunately, this means we have to copy the whole exclusion pattern, as
|
||||
# (unlike the "include" option), the "exclude" option does not take exclusion
|
||||
# ID's.
|
||||
#
|
||||
# These exclusion patterns are copied from the default excluses at:
|
||||
# https://github.com/golangci/golangci-lint/blob/v1.46.2/pkg/config/issues.go#L10-L104
|
||||
|
||||
# EXC0001
|
||||
- text: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*print(f|ln)?|os\\.(Un)?Setenv). is not checked"
|
||||
linters:
|
||||
- errcheck
|
||||
# EXC0006
|
||||
- text: "Use of unsafe calls should be audited"
|
||||
linters:
|
||||
- gosec
|
||||
# EXC0007
|
||||
- text: "Subprocess launch(ed with variable|ing should be audited)"
|
||||
linters:
|
||||
- gosec
|
||||
# EXC0008
|
||||
# TODO: evaluate these and fix where needed: G307: Deferring unsafe method "*os.File" on type "Close" (gosec)
|
||||
- text: "(G104|G307)"
|
||||
linters:
|
||||
- gosec
|
||||
# EXC0009
|
||||
- text: "(Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)"
|
||||
linters:
|
||||
- gosec
|
||||
# EXC0010
|
||||
- text: "Potential file inclusion via variable"
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# Looks like the match in "EXC0007" above doesn't catch this one
|
||||
# TODO: consider upstreaming this to golangci-lint's default exclusion rules
|
||||
- text: "G204: Subprocess launched with a potential tainted input or cmd arguments"
|
||||
linters:
|
||||
- gosec
|
||||
# Looks like the match in "EXC0009" above doesn't catch this one
|
||||
# TODO: consider upstreaming this to golangci-lint's default exclusion rules
|
||||
- text: "G306: Expect WriteFile permissions to be 0600 or less"
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- errcheck
|
||||
- gosec
|
||||
|
||||
# Suppress golint complaining about generated types in api/types/
|
||||
- text: "type name will be used as (container|volume)\\.(Container|Volume).* by other packages, and that stutters; consider calling this"
|
||||
path: "api/types/(volume|container)/"
|
||||
linters:
|
||||
- revive
|
||||
# FIXME temporarily suppress these (see https://github.com/gotestyourself/gotest.tools/issues/272)
|
||||
- text: "SA1019: (assert|cmp|is)\\.ErrorType is deprecated"
|
||||
linters:
|
||||
- staticcheck
|
||||
|
||||
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
|
||||
max-issues-per-linter: 0
|
||||
|
||||
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
|
||||
max-same-issues: 0
|
72
.mailmap
72
.mailmap
|
@ -1,14 +1,14 @@
|
|||
# Generate AUTHORS: hack/generate-authors.sh
|
||||
|
||||
# Tip for finding duplicates (besides scanning the output of AUTHORS for name
|
||||
# duplicates that aren't also email duplicates): scan the output of:
|
||||
# git log --format='%aE - %aN' | sort -uf
|
||||
# This file lists the canonical name and email of contributors, and is used to
|
||||
# generate AUTHORS (in hack/generate-authors.sh).
|
||||
#
|
||||
# For explanation on this file format: man git-shortlog
|
||||
# To find new duplicates, regenerate AUTHORS and scan for name duplicates, or
|
||||
# run the following to find email duplicates:
|
||||
# git log --format='%aE - %aN' | sort -uf | awk -v IGNORECASE=1 '$1 in a {print a[$1]; print}; {a[$1]=$0}'
|
||||
#
|
||||
# For an explanation of this file format, consult gitmailmap(5).
|
||||
|
||||
<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>
|
||||
Aaron L. Xu <liker.xu@foxmail.com> <likexu@harmonycloud.cn>
|
||||
Aaron Lehmann <alehmann@netflix.com>
|
||||
Aaron Lehmann <alehmann@netflix.com> <aaron.lehmann@docker.com>
|
||||
Abhinandan Prativadi <aprativadi@gmail.com>
|
||||
|
@ -32,12 +32,12 @@ Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> <suda.kyoto@gmail.com>
|
|||
Akshay Moghe <akshay.moghe@gmail.com>
|
||||
Albin Kerouanton <albinker@gmail.com>
|
||||
Albin Kerouanton <albinker@gmail.com> <albin@akerouanton.name>
|
||||
Albin Kerouanton <albinker@gmail.com> <557933+akerouanton@users.noreply.github.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>
|
||||
Alessandro Boch <aboch@tetrationanalytics.com>
|
||||
Alessandro Boch <aboch@tetrationanalytics.com> <aboch@docker.com>
|
||||
Alessandro Boch <aboch@tetrationanalytics.com> <aboch@socketplane.io>
|
||||
Alessandro Boch <aboch@tetrationanalytics.com> <aboch@users.noreply.github.com>
|
||||
|
@ -50,6 +50,7 @@ Alexander Larsson <alexl@redhat.com> <alexander.larsson@gmail.com>
|
|||
Alexander Morozov <lk4d4math@gmail.com>
|
||||
Alexander Morozov <lk4d4math@gmail.com> <lk4d4@docker.com>
|
||||
Alexandre Beslic <alexandre.beslic@gmail.com> <abronan@docker.com>
|
||||
Alexandre González <agonzalezro@gmail.com>
|
||||
Alexis Ries <ries.alexis@gmail.com>
|
||||
Alexis Ries <ries.alexis@gmail.com> <alexis.ries.ext@orange.com>
|
||||
Alexis Thomas <fr.alexisthomas@gmail.com>
|
||||
|
@ -67,6 +68,8 @@ Andrey Kolomentsev <andrey.kolomentsev@docker.com> <andrey.kolomentsev@gmail.com
|
|||
André Martins <aanm90@gmail.com> <martins@noironetworks.com>
|
||||
Andy Rothfusz <github@developersupport.net> <github@metaliveblog.com>
|
||||
Andy Smith <github@anarkystic.com>
|
||||
Andy Zhang <andy.zhangtao@hotmail.com>
|
||||
Andy Zhang <andy.zhangtao@hotmail.com> <ztao@tibco-support.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>
|
||||
|
@ -85,6 +88,7 @@ Arnaud Porterie <icecrime@gmail.com> <arnaud.porterie@docker.com>
|
|||
Arnaud Rebillout <arnaud.rebillout@collabora.com>
|
||||
Arnaud Rebillout <arnaud.rebillout@collabora.com> <elboulangero@gmail.com>
|
||||
Arthur Gautier <baloo@gandi.net> <superbaloo+registrations.github@superbaloo.net>
|
||||
Artur Meyster <arthurfbi@yahoo.com>
|
||||
Avi Miller <avi.miller@oracle.com> <avi.miller@gmail.com>
|
||||
Ben Bonnefoy <frenchben@docker.com>
|
||||
Ben Golub <ben.golub@dotcloud.com>
|
||||
|
@ -100,8 +104,13 @@ Bily Zhang <xcoder@tenxcloud.com>
|
|||
Bin Liu <liubin0329@gmail.com>
|
||||
Bin Liu <liubin0329@gmail.com> <liubin0329@users.noreply.github.com>
|
||||
Bingshen Wang <bingshen.wbs@alibaba-inc.com>
|
||||
Bjorn Neergaard <bjorn@neersighted.com>
|
||||
Bjorn Neergaard <bjorn@neersighted.com> <bjorn.neergaard@docker.com>
|
||||
Bjorn Neergaard <bjorn@neersighted.com> <bneergaard@mirantis.com>
|
||||
Boaz Shuster <ripcurld.github@gmail.com>
|
||||
Bojun Zhu <bojun.zhu@foxmail.com>
|
||||
Boqin Qin <bobbqqin@gmail.com>
|
||||
Boshi Lian <farmer1992@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>
|
||||
|
@ -136,6 +145,8 @@ Cristian Ariza <dev@cristianrz.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 fliter <imcusg@gmail.com>
|
||||
cui fliter <imcusg@gmail.com> cuishuang <imcusg@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>
|
||||
|
@ -162,6 +173,8 @@ 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 Dooling <dooling@gmail.com>
|
||||
David Dooling <dooling@gmail.com> <david.dooling@docker.com>
|
||||
David M. Karr <davidmichaelkarr@gmail.com>
|
||||
David Sheets <dsheets@docker.com> <sheets@alum.mit.edu>
|
||||
David Sissitka <me@dsissitka.com>
|
||||
|
@ -208,6 +221,8 @@ 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>
|
||||
Filipe Pina <hzlu1ot0@duck.com>
|
||||
Filipe Pina <hzlu1ot0@duck.com> <636320+fopina@users.noreply.github.com>
|
||||
Francisco Carriedo <fcarriedo@gmail.com>
|
||||
Frank Rosquin <frank.rosquin+github@gmail.com> <frank.rosquin@gmail.com>
|
||||
Frank Yang <yyb196@gmail.com>
|
||||
|
@ -240,31 +255,37 @@ 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>
|
||||
Hao Shu Wei <haoshuwei24@gmail.com>
|
||||
Hao Shu Wei <haoshuwei24@gmail.com> <haoshuwei1989@163.com>
|
||||
Hao Shu Wei <haoshuwei24@gmail.com> <haosw@cn.ibm.com>
|
||||
Harald Albers <github@albersweb.de> <albers@users.noreply.github.com>
|
||||
Harald Niesche <harald@niesche.de>
|
||||
Harold Cooper <hrldcpr@gmail.com>
|
||||
Harry Zhang <harryz@hyper.sh>
|
||||
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>
|
||||
He Simei <hesimei@zju.edu.cn>
|
||||
Helen Xie <chenjg@harmonycloud.cn>
|
||||
Hiroyuki Sasagawa <hs19870702@gmail.com>
|
||||
Hollie Teal <hollie@docker.com>
|
||||
Hollie Teal <hollie@docker.com> <hollie.teal@docker.com>
|
||||
Hollie Teal <hollie@docker.com> <hollietealok@users.noreply.github.com>
|
||||
hsinko <21551195@zju.edu.cn> <hsinko@users.noreply.github.com>
|
||||
Hu Keping <hukeping@huawei.com>
|
||||
Huajin Tong <fliterdashen@gmail.com>
|
||||
Hui Kang <hkang.sunysb@gmail.com>
|
||||
Hui Kang <hkang.sunysb@gmail.com> <kangh@us.ibm.com>
|
||||
Huu Nguyen <huu@prismskylabs.com> <whoshuu@gmail.com>
|
||||
Hyeongkyu Lee <hyeongkyu.lee@navercorp.com>
|
||||
Hyzhou Zhy <hyzhou.zhy@alibaba-inc.com>
|
||||
Hyzhou Zhy <hyzhou.zhy@alibaba-inc.com> <1187766782@qq.com>
|
||||
Ian Campbell <ian.campbell@docker.com>
|
||||
Ian Campbell <ian.campbell@docker.com> <ijc@docker.com>
|
||||
Ilya Khlopotov <ilya.khlopotov@gmail.com>
|
||||
Iskander Sharipov <quasilyte@gmail.com>
|
||||
Ivan Babrou <ibobrik@gmail.com>
|
||||
Ivan Markin <sw@nogoegst.net> <twim@riseup.net>
|
||||
Jack Laxson <jackjrabbit@gmail.com>
|
||||
Jacob Atzen <jacob@jacobatzen.dk> <jatzen@gmail.com>
|
||||
|
@ -276,6 +297,7 @@ Jakub Drahos <jdrahos@pulsepoint.com> <jack.drahos@gmail.com>
|
|||
James Nesbitt <jnesbitt@mirantis.com>
|
||||
James Nesbitt <jnesbitt@mirantis.com> <james.nesbitt@wunderkraut.com>
|
||||
Jamie Hannaford <jamie@limetree.org> <jamie.hannaford@rackspace.com>
|
||||
Jan Götte <jaseg@jaseg.net>
|
||||
Jana Radhakrishnan <mrjana@docker.com>
|
||||
Jana Radhakrishnan <mrjana@docker.com> <mrjana@socketplane.io>
|
||||
Javier Bassi <javierbassi@gmail.com>
|
||||
|
@ -315,8 +337,8 @@ John Howard <github@lowenna.com> <10522484+lowenna@users.noreply.github.com>
|
|||
John Howard <github@lowenna.com> <jhoward@microsoft.com>
|
||||
John Howard <github@lowenna.com> <jhoward@ntdev.microsoft.com>
|
||||
John Howard <github@lowenna.com> <jhowardmsft@users.noreply.github.com>
|
||||
John Howard <github@lowenna.com> <John.Howard@microsoft.com>
|
||||
John Howard <github@lowenna.com> <john.howard@microsoft.com>
|
||||
John Howard <github@lowenna.com> <john@lowenna.com>
|
||||
John Stephens <johnstep@docker.com> <johnstep@users.noreply.github.com>
|
||||
Jon Surrell <jon.surrell@gmail.com> <jon.surrell@automattic.com>
|
||||
Jonathan Choy <jonathan.j.choy@gmail.com>
|
||||
|
@ -358,7 +380,9 @@ Ken Cochrane <kencochrane@gmail.com> <KenCochrane@gmail.com>
|
|||
Ken Herner <kherner@progress.com> <chosenken@gmail.com>
|
||||
Ken Reese <krrgithub@gmail.com>
|
||||
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
||||
Kevin Alvarez <crazy-max@users.noreply.github.com>
|
||||
Kevin Alvarez <github@crazymax.dev>
|
||||
Kevin Alvarez <github@crazymax.dev> <1951866+crazy-max@users.noreply.github.com>
|
||||
Kevin Alvarez <github@crazymax.dev> <crazy-max@users.noreply.github.com>
|
||||
Kevin Feyrer <kevin.feyrer@btinternet.com> <kevinfeyrer@users.noreply.github.com>
|
||||
Kevin Kern <kaiwentan@harmonycloud.cn>
|
||||
Kevin Meredith <kevin.m.meredith@gmail.com>
|
||||
|
@ -458,14 +482,20 @@ Mikael Davranche <mikael.davranche@corp.ovh.com>
|
|||
Mikael Davranche <mikael.davranche@corp.ovh.com> <mikael.davranche@corp.ovh.net>
|
||||
Mike Casas <mkcsas0@gmail.com> <mikecasas@users.noreply.github.com>
|
||||
Mike Goelzer <mike.goelzer@docker.com> <mgoelzer@docker.com>
|
||||
Milas Bowman <devnull@milas.dev>
|
||||
Milas Bowman <devnull@milas.dev> <milasb@gmail.com>
|
||||
Milas Bowman <devnull@milas.dev> <milas.bowman@docker.com>
|
||||
Milind Chawre <milindchawre@gmail.com>
|
||||
Misty Stanley-Jones <misty@docker.com> <misty@apache.org>
|
||||
Mohammad Banikazemi <MBanikazemi@gmail.com>
|
||||
Mohammad Banikazemi <MBanikazemi@gmail.com> <mb@us.ibm.com>
|
||||
Mohd Sadiq <mohdsadiq058@gmail.com> <mohdsadiq058@gmail.com>
|
||||
Mohd Sadiq <mohdsadiq058@gmail.com> <42430865+msadiq058@users.noreply.github.com>
|
||||
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>
|
||||
mrfly <mr.wrfly@gmail.com> <wrfly@users.noreply.github.com>
|
||||
Nace Oroz <orkica@gmail.com>
|
||||
Natasha Jarus <linuxmercedes@gmail.com>
|
||||
Nathan LeClaire <nathan.leclaire@docker.com> <nathan.leclaire@gmail.com>
|
||||
|
@ -507,6 +537,7 @@ Qiang Huang <h.huangqiang@huawei.com> <qhuang@10.0.2.15>
|
|||
Qin TianHuan <tianhuan@bingotree.cn>
|
||||
Ray Tsang <rayt@google.com> <saturnism@users.noreply.github.com>
|
||||
Renaud Gaubert <rgaubert@nvidia.com> <renaud.gaubert@gmail.com>
|
||||
Richard Scothern <richard.scothern@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>
|
||||
|
@ -529,11 +560,15 @@ Sandeep Bansal <sabansal@microsoft.com>
|
|||
Sandeep Bansal <sabansal@microsoft.com> <msabansal@microsoft.com>
|
||||
Santhosh Manohar <santhosh@docker.com>
|
||||
Sargun Dhillon <sargun@netflix.com> <sargun@sargun.me>
|
||||
Satoshi Tagomori <tagomoris@gmail.com>
|
||||
Sean Lee <seanlee@tw.ibm.com> <scaleoutsean@users.noreply.github.com>
|
||||
Sebastiaan van Stijn <github@gone.nl>
|
||||
Sebastiaan van Stijn <github@gone.nl> <moby@example.com>
|
||||
Sebastiaan van Stijn <github@gone.nl> <sebastiaan@ws-key-sebas3.dpi1.dpi>
|
||||
Sebastiaan van Stijn <github@gone.nl> <thaJeztah@users.noreply.github.com>
|
||||
Sebastian Thomschke <sebthom@users.noreply.github.com>
|
||||
Seongyeol Lim <seongyeol37@gmail.com>
|
||||
Serhii Nakon <serhii.n@thescimus.com>
|
||||
Shaun Kaasten <shaunk@gmail.com>
|
||||
Shawn Landden <shawn@churchofgit.com> <shawnlandden@gmail.com>
|
||||
Shengbo Song <thomassong@tencent.com>
|
||||
|
@ -542,8 +577,6 @@ Shih-Yuan Lee <fourdollars@gmail.com>
|
|||
Shishir Mahajan <shishir.mahajan@redhat.com> <smahajan@redhat.com>
|
||||
Shu-Wai Chow <shu-wai.chow@seattlechildrens.org>
|
||||
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>
|
||||
Smark Meng <smark@freecoop.net>
|
||||
|
@ -582,6 +615,7 @@ Sylvain Baubeau <lebauce@gmail.com>
|
|||
Sylvain Baubeau <lebauce@gmail.com> <sbaubeau@redhat.com>
|
||||
Sylvain Bellemare <sylvain@ascribe.io>
|
||||
Sylvain Bellemare <sylvain@ascribe.io> <sylvain.bellemare@ezeep.com>
|
||||
Takuto Sato <tockn.jp@gmail.com>
|
||||
Tangi Colin <tangicolin@gmail.com>
|
||||
Tejesh Mehta <tejesh.mehta@gmail.com> <tj@init.me>
|
||||
Terry Chu <zue.hterry@gmail.com>
|
||||
|
@ -662,6 +696,7 @@ 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>
|
||||
Wei-Ting Kuo <waitingkuo0527@gmail.com>
|
||||
Wen Cheng Ma <wenchma@cn.ibm.com>
|
||||
Wenjun Tang <tangwj2@lenovo.com> <dodia@163.com>
|
||||
Wewang Xiaorenfine <wang.xiaoren@zte.com.cn>
|
||||
|
@ -680,6 +715,8 @@ Xiaodong Liu <liuxiaodong@loongson.cn>
|
|||
Xiaodong Zhang <a4012017@sina.com>
|
||||
Xiaohua Ding <xiao_hua_ding@sina.cn>
|
||||
Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
|
||||
Xinfeng Liu <XinfengLiu@icloud.com>
|
||||
Xinfeng Liu <XinfengLiu@icloud.com> <xinfeng.liu@gmail.com>
|
||||
Xuecong Liao <satorulogic@gmail.com>
|
||||
Yamasaki Masahide <masahide.y@gmail.com>
|
||||
Yao Zaiyong <yaozaiyong@hotmail.com>
|
||||
|
@ -696,12 +733,15 @@ 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>
|
||||
Yuan Sun <sunyuan3@huawei.com>
|
||||
Yue Zhang <zy675793960@yeah.net>
|
||||
Yufei Xiong <yufei.xiong@qq.com>
|
||||
Zach Gershman <zachgersh@gmail.com>
|
||||
Zach Gershman <zachgersh@gmail.com> <zachgersh@users.noreply.github.com>
|
||||
Zachary Jaffee <zjaffee@us.ibm.com> <zij@case.edu>
|
||||
Zachary Jaffee <zjaffee@us.ibm.com> <zjaffee@apache.org>
|
||||
Zhang Kun <zkazure@gmail.com>
|
||||
Zhang Wentao <zhangwentao234@huawei.com>
|
||||
ZhangHang <stevezhang2014@gmail.com>
|
||||
Zhenkun Bi <bi.zhenkun@zte.com.cn>
|
||||
Zhou Hao <zhouhao@cn.fujitsu.com>
|
||||
|
|
121
AUTHORS
121
AUTHORS
|
@ -1,5 +1,6 @@
|
|||
# This file lists all individuals having contributed content to the repository.
|
||||
# For how it is generated, see `hack/generate-authors.sh`.
|
||||
# File @generated by hack/generate-authors.sh. DO NOT EDIT.
|
||||
# This file lists all contributors to the repository.
|
||||
# See hack/generate-authors.sh to make modifications.
|
||||
|
||||
Aanand Prasad <aanand.prasad@gmail.com>
|
||||
Aaron Davidson <aaron@databricks.com>
|
||||
|
@ -9,7 +10,6 @@ Aaron Huslage <huslage@gmail.com>
|
|||
Aaron L. Xu <liker.xu@foxmail.com>
|
||||
Aaron Lehmann <alehmann@netflix.com>
|
||||
Aaron Welch <welch@packet.net>
|
||||
Aaron.L.Xu <likexu@harmonycloud.cn>
|
||||
Abel Muiño <amuino@gmail.com>
|
||||
Abhijeet Kasurde <akasurde@redhat.com>
|
||||
Abhinandan Prativadi <aprativadi@gmail.com>
|
||||
|
@ -17,6 +17,7 @@ Abhinav Ajgaonkar <abhinav316@gmail.com>
|
|||
Abhishek Chanda <abhishek.becs@gmail.com>
|
||||
Abhishek Sharma <abhishek@asharma.me>
|
||||
Abin Shahab <ashahab@altiscale.com>
|
||||
Abirdcfly <fp544037857@gmail.com>
|
||||
Ada Mancini <ada@docker.com>
|
||||
Adam Avilla <aavilla@yp.com>
|
||||
Adam Dobrawy <naczelnik@jawnosc.tk>
|
||||
|
@ -26,8 +27,10 @@ Adam Miller <admiller@redhat.com>
|
|||
Adam Mills <adam@armills.info>
|
||||
Adam Pointer <adam.pointer@skybettingandgaming.com>
|
||||
Adam Singer <financeCoding@gmail.com>
|
||||
Adam Thornton <adam.thornton@maryville.com>
|
||||
Adam Walz <adam@adamwalz.net>
|
||||
Adam Williams <awilliams@mirantis.com>
|
||||
AdamKorcz <adam@adalogics.com>
|
||||
Addam Hardy <addam.hardy@gmail.com>
|
||||
Aditi Rajagopal <arajagopal@us.ibm.com>
|
||||
Aditya <aditya@netroy.in>
|
||||
|
@ -80,6 +83,7 @@ Alex Goodman <wagoodman@gmail.com>
|
|||
Alex Nordlund <alexander.nordlund@nasdaq.com>
|
||||
Alex Olshansky <i@creagenics.com>
|
||||
Alex Samorukov <samm@os2.kiev.ua>
|
||||
Alex Stockinger <alex@atomicjar.com>
|
||||
Alex Warhawk <ax.warhawk@gmail.com>
|
||||
Alexander Artemenko <svetlyak.40wt@gmail.com>
|
||||
Alexander Boyd <alex@opengroove.org>
|
||||
|
@ -161,7 +165,6 @@ Andrey Kolomentsev <andrey.kolomentsev@docker.com>
|
|||
Andrey Petrov <andrey.petrov@shazow.net>
|
||||
Andrey Stolbovsky <andrey.stolbovsky@gmail.com>
|
||||
André Martins <aanm90@gmail.com>
|
||||
andy <ztao@tibco-support.com>
|
||||
Andy Chambers <anchambers@paypal.com>
|
||||
andy diller <dillera@gmail.com>
|
||||
Andy Goldstein <agoldste@redhat.com>
|
||||
|
@ -170,6 +173,8 @@ Andy Lindeman <alindeman@salesforce.com>
|
|||
Andy Rothfusz <github@developersupport.net>
|
||||
Andy Smith <github@anarkystic.com>
|
||||
Andy Wilson <wilson.andrew.j+github@gmail.com>
|
||||
Andy Zhang <andy.zhangtao@hotmail.com>
|
||||
Aneesh Kulkarni <askthefactorcamera@gmail.com>
|
||||
Anes Hasicic <anes.hasicic@gmail.com>
|
||||
Angel Velazquez <angelcar@amazon.com>
|
||||
Anil Belur <askb23@gmail.com>
|
||||
|
@ -197,6 +202,7 @@ Anusha Ragunathan <anusha.ragunathan@docker.com>
|
|||
Anyu Wang <wanganyu@outlook.com>
|
||||
apocas <petermdias@gmail.com>
|
||||
Arash Deshmeh <adeshmeh@ca.ibm.com>
|
||||
arcosx <arcosx@outlook.com>
|
||||
ArikaChen <eaglesora@gmail.com>
|
||||
Arko Dasgupta <arko@tetrate.io>
|
||||
Arnaud Lefebvre <a.lefebvre@outlook.fr>
|
||||
|
@ -209,6 +215,7 @@ Artur Meyster <arthurfbi@yahoo.com>
|
|||
Arun Gupta <arun.gupta@gmail.com>
|
||||
Asad Saeeduddin <masaeedu@gmail.com>
|
||||
Asbjørn Enge <asbjorn@hanafjedle.net>
|
||||
Austin Vazquez <macedonv@amazon.com>
|
||||
averagehuman <averagehuman@users.noreply.github.com>
|
||||
Avi Das <andas222@gmail.com>
|
||||
Avi Kivity <avi@scylladb.com>
|
||||
|
@ -222,6 +229,7 @@ Barnaby Gray <barnaby@pickle.me.uk>
|
|||
Barry Allard <barry.allard@gmail.com>
|
||||
Bartłomiej Piotrowski <b@bpiotrowski.pl>
|
||||
Bastiaan Bakker <bbakker@xebia.com>
|
||||
Bastien Pascard <bpascard@hotmail.com>
|
||||
bdevloed <boris.de.vloed@gmail.com>
|
||||
Bearice Ren <bearice@gmail.com>
|
||||
Ben Bonnefoy <frenchben@docker.com>
|
||||
|
@ -229,6 +237,8 @@ Ben Firshman <ben@firshman.co.uk>
|
|||
Ben Golub <ben.golub@dotcloud.com>
|
||||
Ben Gould <ben@bengould.co.uk>
|
||||
Ben Hall <ben@benhall.me.uk>
|
||||
Ben Langfeld <ben@langfeld.me>
|
||||
Ben Lovy <ben@deciduously.com>
|
||||
Ben Sargent <ben@brokendigits.com>
|
||||
Ben Severson <BenSeverson@users.noreply.github.com>
|
||||
Ben Toews <mastahyeti@gmail.com>
|
||||
|
@ -237,6 +247,7 @@ Benjamin Atkin <ben@benatkin.com>
|
|||
Benjamin Baker <Benjamin.baker@utexas.edu>
|
||||
Benjamin Boudreau <boudreau.benjamin@gmail.com>
|
||||
Benjamin Böhmke <benjamin@boehmke.net>
|
||||
Benjamin Wang <wachao@vmware.com>
|
||||
Benjamin Yolken <yolken@stripe.com>
|
||||
Benny Ng <benny.tpng@gmail.com>
|
||||
Benoit Chesneau <bchesneau@gmail.com>
|
||||
|
@ -254,10 +265,11 @@ Billy Ridgway <wrridgwa@us.ibm.com>
|
|||
Bily Zhang <xcoder@tenxcloud.com>
|
||||
Bin Liu <liubin0329@gmail.com>
|
||||
Bingshen Wang <bingshen.wbs@alibaba-inc.com>
|
||||
Bjorn Neergaard <bneergaard@mirantis.com>
|
||||
Bjorn Neergaard <bjorn@neersighted.com>
|
||||
Blake Geno <blakegeno@gmail.com>
|
||||
Boaz Shuster <ripcurld.github@gmail.com>
|
||||
bobby abbott <ttobbaybbob@gmail.com>
|
||||
Bojun Zhu <bojun.zhu@foxmail.com>
|
||||
Boqin Qin <bobbqqin@gmail.com>
|
||||
Boris Pruessmann <boris@pruessmann.org>
|
||||
Boshi Lian <farmer1992@gmail.com>
|
||||
|
@ -270,6 +282,7 @@ Brandon Liu <bdon@bdon.org>
|
|||
Brandon Philips <brandon.philips@coreos.com>
|
||||
Brandon Rhodes <brandon@rhodesmill.org>
|
||||
Brendan Dixon <brendand@microsoft.com>
|
||||
Brennan Kinney <5098581+polarathene@users.noreply.github.com>
|
||||
Brent Salisbury <brent.salisbury@docker.com>
|
||||
Brett Higgins <brhiggins@arbor.net>
|
||||
Brett Kochendorfer <brett.kochendorfer@gmail.com>
|
||||
|
@ -339,6 +352,7 @@ Charlie Drage <charlie@charliedrage.com>
|
|||
Charlie Lewis <charliel@lab41.org>
|
||||
Chase Bolt <chase.bolt@gmail.com>
|
||||
ChaYoung You <yousbe@gmail.com>
|
||||
Chee Hau Lim <ch33hau@gmail.com>
|
||||
Chen Chao <cc272309126@gmail.com>
|
||||
Chen Chuanliang <chen.chuanliang@zte.com.cn>
|
||||
Chen Hanxiao <chenhanxiao@cn.fujitsu.com>
|
||||
|
@ -353,6 +367,7 @@ chenyuzhu <chenyuzhi@oschina.cn>
|
|||
Chetan Birajdar <birajdar.chetan@gmail.com>
|
||||
Chewey <prosto-chewey@users.noreply.github.com>
|
||||
Chia-liang Kao <clkao@clkao.org>
|
||||
Chiranjeevi Tirunagari <vchiranjeeviak.tirunagari@gmail.com>
|
||||
chli <chli@freewheel.tv>
|
||||
Cholerae Hu <choleraehyq@gmail.com>
|
||||
Chris Alfonso <calfonso@redhat.com>
|
||||
|
@ -423,8 +438,8 @@ Cristian Staretu <cristian.staretu@gmail.com>
|
|||
cristiano balducci <cristiano.balducci@gmail.com>
|
||||
Cristina Yenyxe Gonzalez Garcia <cristina.yenyxe@gmail.com>
|
||||
Cruceru Calin-Cristian <crucerucalincristian@gmail.com>
|
||||
cui fliter <imcusg@gmail.com>
|
||||
CUI Wei <ghostplant@qq.com>
|
||||
cuishuang <imcusg@gmail.com>
|
||||
Cuong Manh Le <cuong.manhle.vn@gmail.com>
|
||||
Cyprian Gracz <cyprian.gracz@micro-jumbo.eu>
|
||||
Cyril F <cyrilf7x@gmail.com>
|
||||
|
@ -503,6 +518,7 @@ David Dooling <dooling@gmail.com>
|
|||
David Gageot <david@gageot.net>
|
||||
David Gebler <davidgebler@gmail.com>
|
||||
David Glasser <glasser@davidglasser.net>
|
||||
David Karlsson <35727626+dvdksn@users.noreply.github.com>
|
||||
David Lawrence <david.lawrence@docker.com>
|
||||
David Lechner <david@lechnology.com>
|
||||
David M. Karr <davidmichaelkarr@gmail.com>
|
||||
|
@ -545,7 +561,6 @@ Derek Ch <denc716@gmail.com>
|
|||
Derek McGowan <derek@mcg.dev>
|
||||
Deric Crago <deric.crago@gmail.com>
|
||||
Deshi Xiao <dxiao@redhat.com>
|
||||
devmeyster <arthurfbi@yahoo.com>
|
||||
Devon Estes <devon.estes@klarna.com>
|
||||
Devvyn Murphy <devvyn@devvyn.com>
|
||||
Dharmit Shah <shahdharmit@gmail.com>
|
||||
|
@ -593,6 +608,7 @@ Donald Huang <don.hcd@gmail.com>
|
|||
Dong Chen <dongluo.chen@docker.com>
|
||||
Donghwa Kim <shanytt@gmail.com>
|
||||
Donovan Jones <git@gamma.net.nz>
|
||||
Dorin Geman <dorin.geman@docker.com>
|
||||
Doron Podoleanu <doronp@il.ibm.com>
|
||||
Doug Davis <dug@us.ibm.com>
|
||||
Doug MacEachern <dougm@vmware.com>
|
||||
|
@ -627,8 +643,10 @@ Emily Rose <emily@contactvibe.com>
|
|||
Emir Ozer <emirozer@yandex.com>
|
||||
Eng Zer Jun <engzerjun@gmail.com>
|
||||
Enguerran <engcolson@gmail.com>
|
||||
Enrico Weigelt, metux IT consult <info@metux.net>
|
||||
Eohyung Lee <liquidnuker@gmail.com>
|
||||
epeterso <epeterson@breakpoint-labs.com>
|
||||
er0k <er0k@er0k.net>
|
||||
Eric Barch <barch@tomesoftware.com>
|
||||
Eric Curtin <ericcurtin17@gmail.com>
|
||||
Eric G. Noriega <enoriega@vizuri.com>
|
||||
|
@ -650,6 +668,8 @@ Erik Dubbelboer <erik@dubbelboer.com>
|
|||
Erik Hollensbe <github@hollensbe.org>
|
||||
Erik Inge Bolsø <knan@redpill-linpro.com>
|
||||
Erik Kristensen <erik@erikkristensen.com>
|
||||
Erik Sipsma <erik@sipsma.dev>
|
||||
Erik Sjölund <erik.sjolund@gmail.com>
|
||||
Erik St. Martin <alakriti@gmail.com>
|
||||
Erik Weathers <erikdw@gmail.com>
|
||||
Erno Hopearuoho <erno.hopearuoho@gmail.com>
|
||||
|
@ -665,6 +685,7 @@ Evan Allrich <evan@unguku.com>
|
|||
Evan Carmi <carmi@users.noreply.github.com>
|
||||
Evan Hazlett <ejhazlett@gmail.com>
|
||||
Evan Krall <krall@yelp.com>
|
||||
Evan Lezar <elezar@nvidia.com>
|
||||
Evan Phoenix <evan@fallingsnow.net>
|
||||
Evan Wies <evan@neomantra.net>
|
||||
Evelyn Xu <evelynhsu21@gmail.com>
|
||||
|
@ -707,9 +728,11 @@ Fengtu Wang <wangfengtu@huawei.com>
|
|||
Ferenc Szabo <pragmaticfrank@gmail.com>
|
||||
Fernando <fermayo@gmail.com>
|
||||
Fero Volar <alian@alian.info>
|
||||
Feroz Salam <feroz.salam@sourcegraph.com>
|
||||
Ferran Rodenas <frodenas@gmail.com>
|
||||
Filipe Brandenburger <filbranden@google.com>
|
||||
Filipe Oliveira <contato@fmoliveira.com.br>
|
||||
Filipe Pina <hzlu1ot0@duck.com>
|
||||
Flavio Castelli <fcastelli@suse.com>
|
||||
Flavio Crisciani <flavio.crisciani@docker.com>
|
||||
Florian <FWirtz@users.noreply.github.com>
|
||||
|
@ -732,6 +755,7 @@ Frank Groeneveld <frank@ivaldi.nl>
|
|||
Frank Herrmann <fgh@4gh.tv>
|
||||
Frank Macreery <frank@macreery.com>
|
||||
Frank Rosquin <frank.rosquin+github@gmail.com>
|
||||
Frank Villaro-Dixon <frank.villarodixon@merkle.com>
|
||||
Frank Yang <yyb196@gmail.com>
|
||||
Fred Lifton <fred.lifton@docker.com>
|
||||
Frederick F. Kautz IV <fkautz@redhat.com>
|
||||
|
@ -747,6 +771,7 @@ Félix Baylac-Jacqué <baylac.felix@gmail.com>
|
|||
Félix Cantournet <felix.cantournet@cloudwatt.com>
|
||||
Gabe Rosenhouse <gabe@missionst.com>
|
||||
Gabor Nagy <mail@aigeruth.hu>
|
||||
Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
|
||||
Gabriel Goller <gabrielgoller123@gmail.com>
|
||||
Gabriel L. Somlo <gsomlo@gmail.com>
|
||||
Gabriel Linder <linder.gabriel@gmail.com>
|
||||
|
@ -822,7 +847,7 @@ Hamish Hutchings <moredhel@aoeu.me>
|
|||
Hannes Ljungberg <hannes@5monkeys.se>
|
||||
Hans Kristian Flaatten <hans@starefossen.com>
|
||||
Hans Rødtang <hansrodtang@gmail.com>
|
||||
Hao Shu Wei <haosw@cn.ibm.com>
|
||||
Hao Shu Wei <haoshuwei24@gmail.com>
|
||||
Hao Zhang <21521210@zju.edu.cn>
|
||||
Harald Albers <github@albersweb.de>
|
||||
Harald Niesche <harald@niesche.de>
|
||||
|
@ -848,9 +873,12 @@ Hongbin Lu <hongbin034@gmail.com>
|
|||
Hongxu Jia <hongxu.jia@windriver.com>
|
||||
Honza Pokorny <me@honza.ca>
|
||||
Hsing-Hui Hsu <hsinghui@amazon.com>
|
||||
Hsing-Yu (David) Chen <davidhsingyuchen@gmail.com>
|
||||
hsinko <21551195@zju.edu.cn>
|
||||
Hu Keping <hukeping@huawei.com>
|
||||
Hu Tao <hutao@cn.fujitsu.com>
|
||||
Huajin Tong <fliterdashen@gmail.com>
|
||||
huang-jl <1046678590@qq.com>
|
||||
HuanHuan Ye <logindaveye@gmail.com>
|
||||
Huanzhong Zhang <zhanghuanzhong90@gmail.com>
|
||||
Huayi Zhang <irachex@gmail.com>
|
||||
|
@ -861,10 +889,9 @@ Hui Kang <hkang.sunysb@gmail.com>
|
|||
Hunter Blanks <hunter@twilio.com>
|
||||
huqun <huqun@zju.edu.cn>
|
||||
Huu Nguyen <huu@prismskylabs.com>
|
||||
hyeongkyu.lee <hyeongkyu.lee@navercorp.com>
|
||||
Hyeongkyu Lee <hyeongkyu.lee@navercorp.com>
|
||||
Hyzhou Zhy <hyzhou.zhy@alibaba-inc.com>
|
||||
Iago López Galeiras <iago@kinvolk.io>
|
||||
Ian Babrou <ibobrik@gmail.com>
|
||||
Ian Bishop <ianbishop@pace7.com>
|
||||
Ian Bull <irbull@gmail.com>
|
||||
Ian Calvert <ianjcalvert@gmail.com>
|
||||
|
@ -881,6 +908,8 @@ Igor Dolzhikov <bluesriverz@gmail.com>
|
|||
Igor Karpovich <i.karpovich@currencysolutions.com>
|
||||
Iliana Weller <iweller@amazon.com>
|
||||
Ilkka Laukkanen <ilkka@ilkka.io>
|
||||
Illia Antypenko <ilya@antipenko.pp.ua>
|
||||
Illo Abdulrahim <abdulrahim.illo@nokia.com>
|
||||
Ilya Dmitrichenko <errordeveloper@gmail.com>
|
||||
Ilya Gusev <mail@igusev.ru>
|
||||
Ilya Khlopotov <ilya.khlopotov@gmail.com>
|
||||
|
@ -931,6 +960,8 @@ Jamie Hannaford <jamie@limetree.org>
|
|||
Jamshid Afshar <jafshar@yahoo.com>
|
||||
Jan Breig <git@pygos.space>
|
||||
Jan Chren <dev.rindeal@gmail.com>
|
||||
Jan Garcia <github-public@n-garcia.com>
|
||||
Jan Götte <jaseg@jaseg.net>
|
||||
Jan Keromnes <janx@linux.com>
|
||||
Jan Koprowski <jan.koprowski@gmail.com>
|
||||
Jan Pazdziora <jpazdziora@redhat.com>
|
||||
|
@ -942,8 +973,8 @@ Jannick Fahlbusch <git@jf-projects.de>
|
|||
Januar Wayong <januar@gmail.com>
|
||||
Jared Biel <jared.biel@bolderthinking.com>
|
||||
Jared Hocutt <jaredh@netapp.com>
|
||||
Jaroslav Jindrak <dzejrou@gmail.com>
|
||||
Jaroslaw Zabiello <hipertracker@gmail.com>
|
||||
jaseg <jaseg@jaseg.net>
|
||||
Jasmine Hegman <jasmine@jhegman.com>
|
||||
Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Jason Divock <jdivock@gmail.com>
|
||||
|
@ -967,6 +998,7 @@ Jean Rouge <rougej+github@gmail.com>
|
|||
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||
Jean-Christophe Berthon <huygens@berthon.eu>
|
||||
Jean-Michel Rouet <jm.rouet@gmail.com>
|
||||
Jean-Paul Calderone <exarkun@twistedmatrix.com>
|
||||
Jean-Pierre Huynh <jean-pierre.huynh@ounet.fr>
|
||||
Jean-Tiare Le Bigot <jt@yadutaf.fr>
|
||||
|
@ -985,6 +1017,7 @@ Jeffrey Bolle <jeffreybolle@gmail.com>
|
|||
Jeffrey Morgan <jmorganca@gmail.com>
|
||||
Jeffrey van Gogh <jvg@google.com>
|
||||
Jenny Gebske <jennifer@gebske.de>
|
||||
Jeongseok Kang <piono623@naver.com>
|
||||
Jeremy Chambers <jeremy@thehipbot.com>
|
||||
Jeremy Grosser <jeremy@synack.me>
|
||||
Jeremy Huntwork <jhuntwork@lightcubesolutions.com>
|
||||
|
@ -997,10 +1030,12 @@ Jeroen Jacobs <github@jeroenj.be>
|
|||
Jesse Dearing <jesse.dearing@gmail.com>
|
||||
Jesse Dubay <jesse@thefortytwo.net>
|
||||
Jessica Frazelle <jess@oxide.computer>
|
||||
Jeyanthinath Muthuram <jeyanthinath10@gmail.com>
|
||||
Jezeniel Zapanta <jpzapanta22@gmail.com>
|
||||
Jhon Honce <jhonce@redhat.com>
|
||||
Ji.Zhilong <zhilongji@gmail.com>
|
||||
Jian Liao <jliao@alauda.io>
|
||||
Jian Zeng <anonymousknight96@gmail.com>
|
||||
Jian Zhang <zhangjian.fnst@cn.fujitsu.com>
|
||||
Jiang Jinyang <jjyruby@gmail.com>
|
||||
Jianyong Wu <jianyong.wu@arm.com>
|
||||
|
@ -1125,6 +1160,7 @@ junxu <xujun@cmss.chinamobile.com>
|
|||
Jussi Nummelin <jussi.nummelin@gmail.com>
|
||||
Justas Brazauskas <brazauskasjustas@gmail.com>
|
||||
Justen Martin <jmart@the-coder.com>
|
||||
Justin Chadwell <me@jedevc.com>
|
||||
Justin Cormack <justin.cormack@docker.com>
|
||||
Justin Force <justin.force@gmail.com>
|
||||
Justin Keller <85903732+jk-vb@users.noreply.github.com>
|
||||
|
@ -1167,6 +1203,7 @@ Ke Xu <leonhartx.k@gmail.com>
|
|||
Kei Ohmura <ohmura.kei@gmail.com>
|
||||
Keith Hudgins <greenman@greenman.org>
|
||||
Keli Hu <dev@keli.hu>
|
||||
Ken Bannister <kb2ma@runbox.com>
|
||||
Ken Cochrane <kencochrane@gmail.com>
|
||||
Ken Herner <kherner@progress.com>
|
||||
Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com>
|
||||
|
@ -1176,7 +1213,7 @@ Kenjiro Nakayama <nakayamakenjiro@gmail.com>
|
|||
Kent Johnson <kentoj@gmail.com>
|
||||
Kenta Tada <Kenta.Tada@sony.com>
|
||||
Kevin "qwazerty" Houdebert <kevin.houdebert@gmail.com>
|
||||
Kevin Alvarez <crazy-max@users.noreply.github.com>
|
||||
Kevin Alvarez <github@crazymax.dev>
|
||||
Kevin Burke <kev@inburke.com>
|
||||
Kevin Clark <kevin.clark@gmail.com>
|
||||
Kevin Feyrer <kevin.feyrer@btinternet.com>
|
||||
|
@ -1199,6 +1236,7 @@ Kimbro Staken <kstaken@kstaken.com>
|
|||
Kir Kolyshkin <kolyshkin@gmail.com>
|
||||
Kiran Gangadharan <kiran.daredevil@gmail.com>
|
||||
Kirill SIbirev <l0kix2@gmail.com>
|
||||
Kirk Easterson <kirk.easterson@gmail.com>
|
||||
knappe <tyler.knappe@gmail.com>
|
||||
Kohei Tsuruta <coheyxyz@gmail.com>
|
||||
Koichi Shiraishi <k@zchee.io>
|
||||
|
@ -1208,13 +1246,13 @@ Konstantin Gribov <grossws@gmail.com>
|
|||
Konstantin L <sw.double@gmail.com>
|
||||
Konstantin Pelykh <kpelykh@zettaset.com>
|
||||
Kostadin Plachkov <k.n.plachkov@gmail.com>
|
||||
kpcyrd <git@rxv.cc>
|
||||
Krasi Georgiev <krasi@vip-consult.solutions>
|
||||
Krasimir Georgiev <support@vip-consult.co.uk>
|
||||
Kris-Mikael Krister <krismikael@protonmail.com>
|
||||
Kristian Haugene <kristian.haugene@capgemini.com>
|
||||
Kristina Zabunova <triara.xiii@gmail.com>
|
||||
Krystian Wojcicki <kwojcicki@sympatico.ca>
|
||||
Kun Zhang <zkazure@gmail.com>
|
||||
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
|
||||
Kunal Tyagi <tyagi.kunal@live.com>
|
||||
Kyle Conroy <kyle.j.conroy@gmail.com>
|
||||
|
@ -1234,15 +1272,16 @@ Lars Kellogg-Stedman <lars@redhat.com>
|
|||
Lars R. Damerow <lars@pixar.com>
|
||||
Lars-Magnus Skog <ralphtheninja@riseup.net>
|
||||
Laszlo Meszaros <lacienator@gmail.com>
|
||||
Laura Brehm <laurabrehm@hey.com>
|
||||
Laura Frank <ljfrank@gmail.com>
|
||||
Laurent Bernaille <laurent.bernaille@datadoghq.com>
|
||||
Laurent Erignoux <lerignoux@gmail.com>
|
||||
Laurie Voss <github@seldo.com>
|
||||
Leandro Motta Barros <lmb@stackedboxes.org>
|
||||
Leandro Siqueira <leandro.siqueira@gmail.com>
|
||||
Lee Calcote <leecalcote@gmail.com>
|
||||
Lee Chao <932819864@qq.com>
|
||||
Lee, Meng-Han <sunrisedm4@gmail.com>
|
||||
leeplay <hyeongkyu.lee@navercorp.com>
|
||||
Lei Gong <lgong@alauda.io>
|
||||
Lei Jitang <leijitang@huawei.com>
|
||||
Leiiwang <u2takey@gmail.com>
|
||||
|
@ -1269,7 +1308,6 @@ Lifubang <lifubang@acmcoder.com>
|
|||
Lihua Tang <lhtang@alauda.io>
|
||||
Lily Guo <lily.guo@docker.com>
|
||||
limeidan <limeidan@loongson.cn>
|
||||
limsy <seongyeol37@gmail.com>
|
||||
Lin Lu <doraalin@163.com>
|
||||
LingFaKe <lingfake@huawei.com>
|
||||
Linus Heckemann <lheckemann@twig-world.com>
|
||||
|
@ -1290,6 +1328,7 @@ Lorenzo Fontana <fontanalorenz@gmail.com>
|
|||
Lotus Fenn <fenn.lotus@gmail.com>
|
||||
Louis Delossantos <ldelossa.ld@gmail.com>
|
||||
Louis Opter <kalessin@kalessin.fr>
|
||||
Luboslav Pivarc <lpivarc@redhat.com>
|
||||
Luca Favatella <luca.favatella@erlang-solutions.com>
|
||||
Luca Marturana <lucamarturana@gmail.com>
|
||||
Luca Orlandi <luca.orlandi@gmail.com>
|
||||
|
@ -1299,6 +1338,7 @@ Lucas Chi <lucas@teacherspayteachers.com>
|
|||
Lucas Molas <lmolas@fundacionsadosky.org.ar>
|
||||
Lucas Silvestre <lukas.silvestre@gmail.com>
|
||||
Luciano Mores <leslau@gmail.com>
|
||||
Luis Henrique Mulinari <luis.mulinari@gmail.com>
|
||||
Luis Martínez de Bartolomé Izquierdo <lmartinez@biicode.com>
|
||||
Luiz Svoboda <luizek@gmail.com>
|
||||
Lukas Heeren <lukas-heeren@hotmail.com>
|
||||
|
@ -1327,6 +1367,7 @@ Manuel Meurer <manuel@krautcomputing.com>
|
|||
Manuel Rüger <manuel@rueg.eu>
|
||||
Manuel Woelker <github@manuel.woelker.org>
|
||||
mapk0y <mapk0y@gmail.com>
|
||||
Marat Radchenko <marat@slonopotamus.org>
|
||||
Marc Abramowitz <marc@marc-abramowitz.com>
|
||||
Marc Kuo <kuomarc2@gmail.com>
|
||||
Marc Tamsky <mtamsky@gmail.com>
|
||||
|
@ -1347,6 +1388,7 @@ Marius Gundersen <me@mariusgundersen.net>
|
|||
Marius Sturm <marius@graylog.com>
|
||||
Marius Voila <marius.voila@gmail.com>
|
||||
Mark Allen <mrallen1@yahoo.com>
|
||||
Mark Feit <mfeit@internet2.edu>
|
||||
Mark Jeromin <mark.jeromin@sysfrog.net>
|
||||
Mark McGranaghan <mmcgrana@gmail.com>
|
||||
Mark McKinstry <mmckinst@umich.edu>
|
||||
|
@ -1362,8 +1404,10 @@ Markus Fix <lispmeister@gmail.com>
|
|||
Markus Kortlang <hyp3rdino@googlemail.com>
|
||||
Martijn Dwars <ikben@martijndwars.nl>
|
||||
Martijn van Oosterhout <kleptog@svana.org>
|
||||
Martin Braun <braun@neuroforge.de>
|
||||
Martin Dojcak <martin.dojcak@lablabs.io>
|
||||
Martin Honermeyer <maze@strahlungsfrei.de>
|
||||
Martin Jirku <martin@jirku.sk>
|
||||
Martin Kelly <martin@surround.io>
|
||||
Martin Mosegaard Amdisen <martin.amdisen@praqma.com>
|
||||
Martin Muzatko <martin@happy-css.com>
|
||||
|
@ -1442,6 +1486,7 @@ Michael Holzheu <holzheu@linux.vnet.ibm.com>
|
|||
Michael Hudson-Doyle <michael.hudson@canonical.com>
|
||||
Michael Huettermann <michael@huettermann.net>
|
||||
Michael Irwin <mikesir87@gmail.com>
|
||||
Michael Kebe <michael.kebe@hkm.de>
|
||||
Michael Kuehn <micha@kuehn.io>
|
||||
Michael Käufl <docker@c.michael-kaeufl.de>
|
||||
Michael Neale <michael.neale@gmail.com>
|
||||
|
@ -1490,10 +1535,11 @@ Mike Lundy <mike@fluffypenguin.org>
|
|||
Mike MacCana <mike.maccana@gmail.com>
|
||||
Mike Naberezny <mike@naberezny.com>
|
||||
Mike Snitzer <snitzer@redhat.com>
|
||||
Mike Sul <mike.sul@foundries.io>
|
||||
mikelinjie <294893458@qq.com>
|
||||
Mikhail Sobolev <mss@mawhrin.net>
|
||||
Miklos Szegedi <miklos.szegedi@cloudera.com>
|
||||
Milas Bowman <milasb@gmail.com>
|
||||
Milas Bowman <devnull@milas.dev>
|
||||
Milind Chawre <milindchawre@gmail.com>
|
||||
Miloslav Trmač <mitr@redhat.com>
|
||||
mingqing <limingqing@cyou-inc.com>
|
||||
|
@ -1505,6 +1551,7 @@ mlarcher <github@ringabell.org>
|
|||
Mohammad Banikazemi <MBanikazemi@gmail.com>
|
||||
Mohammad Nasirifar <farnasirim@gmail.com>
|
||||
Mohammed Aaqib Ansari <maaquib@gmail.com>
|
||||
Mohd Sadiq <mohdsadiq058@gmail.com>
|
||||
Mohit Soni <mosoni@ebay.com>
|
||||
Moorthy RS <rsmoorthy@gmail.com>
|
||||
Morgan Bauer <mbauer@us.ibm.com>
|
||||
|
@ -1556,6 +1603,7 @@ Nick Neisen <nwneisen@gmail.com>
|
|||
Nick Parker <nikaios@gmail.com>
|
||||
Nick Payne <nick@kurai.co.uk>
|
||||
Nick Russo <nicholasjamesrusso@gmail.com>
|
||||
Nick Santos <nick.santos@docker.com>
|
||||
Nick Stenning <nick.stenning@digital.cabinet-office.gov.uk>
|
||||
Nick Stinemates <nick@stinemates.org>
|
||||
Nick Wood <nwood@microsoft.com>
|
||||
|
@ -1577,6 +1625,7 @@ NikolaMandic <mn080202@gmail.com>
|
|||
Nikolas Garofil <nikolas.garofil@uantwerpen.be>
|
||||
Nikolay Edigaryev <edigaryev@gmail.com>
|
||||
Nikolay Milovanov <nmil@itransformers.net>
|
||||
ningmingxiao <ning.mingxiao@zte.com.cn>
|
||||
Nirmal Mehta <nirmalkmehta@gmail.com>
|
||||
Nishant Totla <nishanttotla@gmail.com>
|
||||
NIWA Hideyuki <niwa.niwa@nifty.ne.jp>
|
||||
|
@ -1585,6 +1634,7 @@ Noah Treuhaft <noah.treuhaft@docker.com>
|
|||
NobodyOnSE <ich@sektor.selfip.com>
|
||||
noducks <onemannoducks@gmail.com>
|
||||
Nolan Darilek <nolan@thewordnerd.info>
|
||||
Nolan Miles <nolanpmiles@gmail.com>
|
||||
Noriki Nakamura <noriki.nakamura@miraclelinux.com>
|
||||
nponeccop <andy.melnikov@gmail.com>
|
||||
Nurahmadie <nurahmadie@gmail.com>
|
||||
|
@ -1608,6 +1658,7 @@ Omri Shiv <Omri.Shiv@teradata.com>
|
|||
Onur Filiz <onur.filiz@microsoft.com>
|
||||
Oriol Francès <oriolfa@gmail.com>
|
||||
Oscar Bonilla <6f6231@gmail.com>
|
||||
oscar.chen <2972789494@qq.com>
|
||||
Oskar Niburski <oskarniburski@gmail.com>
|
||||
Otto Kekäläinen <otto@seravo.fi>
|
||||
Ouyang Liduo <oyld0210@163.com>
|
||||
|
@ -1639,6 +1690,7 @@ Paul Lietar <paul@lietar.net>
|
|||
Paul Liljenberg <liljenberg.paul@gmail.com>
|
||||
Paul Morie <pmorie@gmail.com>
|
||||
Paul Nasrat <pnasrat@gmail.com>
|
||||
Paul Seiffert <paul.seiffert@jimdo.com>
|
||||
Paul Weaver <pauweave@cisco.com>
|
||||
Paulo Gomes <pjbgf@linux.com>
|
||||
Paulo Ribeiro <paigr.io@gmail.com>
|
||||
|
@ -1652,6 +1704,7 @@ Pavlos Ratis <dastergon@gentoo.org>
|
|||
Pavol Vargovcik <pallly.vargovcik@gmail.com>
|
||||
Pawel Konczalski <mail@konczalski.de>
|
||||
Paweł Gronowski <pawel.gronowski@docker.com>
|
||||
payall4u <payall4u@qq.com>
|
||||
Peeyush Gupta <gpeeyush@linux.vnet.ibm.com>
|
||||
Peggy Li <peggyli.224@gmail.com>
|
||||
Pei Su <sillyousu@gmail.com>
|
||||
|
@ -1678,9 +1731,12 @@ Petr Švihlík <svihlik.petr@gmail.com>
|
|||
Petros Angelatos <petrosagg@gmail.com>
|
||||
Phil <underscorephil@gmail.com>
|
||||
Phil Estes <estesp@gmail.com>
|
||||
Phil Sphicas <phil.sphicas@att.com>
|
||||
Phil Spitler <pspitler@gmail.com>
|
||||
Philip Alexander Etling <paetling@gmail.com>
|
||||
Philip K. Warren <pkwarren@gmail.com>
|
||||
Philip Monroe <phil@philmonroe.com>
|
||||
Philipp Fruck <dev@p-fruck.de>
|
||||
Philipp Gillé <philipp.gille@gmail.com>
|
||||
Philipp Wahala <philipp.wahala@gmail.com>
|
||||
Philipp Weissensteiner <mail@philippweissensteiner.com>
|
||||
|
@ -1718,6 +1774,7 @@ Quentin Brossard <qbrossard@gmail.com>
|
|||
Quentin Perez <qperez@ocs.online.net>
|
||||
Quentin Tayssier <qtayssier@gmail.com>
|
||||
r0n22 <cameron.regan@gmail.com>
|
||||
Rachit Sharma <rachitsharma613@gmail.com>
|
||||
Radostin Stoyanov <rstoyanov1@gmail.com>
|
||||
Rafal Jeczalik <rjeczalik@gmail.com>
|
||||
Rafe Colton <rafael.colton@gmail.com>
|
||||
|
@ -1749,8 +1806,8 @@ Ricardo N Feliciano <FelicianoTech@gmail.com>
|
|||
Rich Horwood <rjhorwood@apple.com>
|
||||
Rich Moyse <rich@moyse.us>
|
||||
Rich Seymour <rseymour@gmail.com>
|
||||
Richard <richard.scothern@gmail.com>
|
||||
Richard Burnison <rburnison@ebay.com>
|
||||
Richard Hansen <rhansen@rhansen.org>
|
||||
Richard Harvey <richard@squarecows.com>
|
||||
Richard Mathie <richard.mathie@amey.co.uk>
|
||||
Richard Metzler <richard@paadee.com>
|
||||
|
@ -1766,6 +1823,7 @@ Ritesh H Shukla <sritesh@vmware.com>
|
|||
Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
|
||||
Rob Cowsill <42620235+rcowsill@users.noreply.github.com>
|
||||
Rob Gulewich <rgulewich@netflix.com>
|
||||
Rob Murray <rob.murray@docker.com>
|
||||
Rob Vesse <rvesse@dotnetrdf.org>
|
||||
Robert Bachmann <rb@robertbachmann.at>
|
||||
Robert Bittle <guywithnose@gmail.com>
|
||||
|
@ -1815,6 +1873,7 @@ Rory Hunter <roryhunter2@gmail.com>
|
|||
Rory McCune <raesene@gmail.com>
|
||||
Ross Boucher <rboucher@gmail.com>
|
||||
Rovanion Luckey <rovanion.luckey@gmail.com>
|
||||
Roy Reznik <roy@wiz.io>
|
||||
Royce Remer <royceremer@gmail.com>
|
||||
Rozhnov Alexandr <nox73@ya.ru>
|
||||
Rudolph Gottesheim <r.gottesheim@loot.at>
|
||||
|
@ -1846,9 +1905,9 @@ ryancooper7 <ryan.cooper7@gmail.com>
|
|||
RyanDeng <sheldon.d1018@gmail.com>
|
||||
Ryo Nakao <nakabonne@gmail.com>
|
||||
Ryoga Saito <contact@proelbtn.com>
|
||||
Régis Behmo <regis@behmo.com>
|
||||
Rémy Greinhofer <remy.greinhofer@livelovely.com>
|
||||
s. rannou <mxs@sbrk.org>
|
||||
s00318865 <sunyuan3@huawei.com>
|
||||
Sabin Basyal <sabin.basyal@gmail.com>
|
||||
Sachin Joshi <sachin_jayant_joshi@hotmail.com>
|
||||
Sagar Hani <sagarhani33@gmail.com>
|
||||
|
@ -1863,6 +1922,7 @@ Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
|
|||
Sam Neirinck <sam@samneirinck.com>
|
||||
Sam Reis <sreis@atlassian.com>
|
||||
Sam Rijs <srijs@airpost.net>
|
||||
Sam Thibault <sam.thibault@docker.com>
|
||||
Sam Whited <sam@samwhited.com>
|
||||
Sambuddha Basu <sambuddhabasu1@gmail.com>
|
||||
Sami Wagiaalla <swagiaal@redhat.com>
|
||||
|
@ -1886,6 +1946,7 @@ Satoshi Tagomori <tagomoris@gmail.com>
|
|||
Scott Bessler <scottbessler@gmail.com>
|
||||
Scott Collier <emailscottcollier@gmail.com>
|
||||
Scott Johnston <scott@docker.com>
|
||||
Scott Moser <smoser@brickies.net>
|
||||
Scott Percival <scottp@lastyard.com>
|
||||
Scott Stamp <scottstamp851@gmail.com>
|
||||
Scott Walls <sawalls@umich.edu>
|
||||
|
@ -1901,6 +1962,7 @@ Sebastiaan van Steenis <mail@superseb.nl>
|
|||
Sebastiaan van Stijn <github@gone.nl>
|
||||
Sebastian Höffner <sebastian.hoeffner@mevis.fraunhofer.de>
|
||||
Sebastian Radloff <sradloff23@gmail.com>
|
||||
Sebastian Thomschke <sebthom@users.noreply.github.com>
|
||||
Sebastien Goasguen <runseb@gmail.com>
|
||||
Senthil Kumar Selvaraj <senthil.thecoder@gmail.com>
|
||||
Senthil Kumaran <senthil@uthcode.com>
|
||||
|
@ -1912,6 +1974,7 @@ Sergey Evstifeev <sergey.evstifeev@gmail.com>
|
|||
Sergii Kabashniuk <skabashnyuk@codenvy.com>
|
||||
Sergio Lopez <slp@redhat.com>
|
||||
Serhat Gülçiçek <serhat25@gmail.com>
|
||||
Serhii Nakon <serhii.n@thescimus.com>
|
||||
SeungUkLee <lsy931106@gmail.com>
|
||||
Sevki Hasirci <s@sevki.org>
|
||||
Shane Canon <scanon@lbl.gov>
|
||||
|
@ -1938,7 +2001,6 @@ Shourya Sarcar <shourya.sarcar@gmail.com>
|
|||
Shu-Wai Chow <shu-wai.chow@seattlechildrens.org>
|
||||
shuai-z <zs.broccoli@gmail.com>
|
||||
Shukui Yang <yangshukui@huawei.com>
|
||||
Shuwei Hao <haosw@cn.ibm.com>
|
||||
Sian Lerk Lau <kiawin@gmail.com>
|
||||
Siarhei Rasiukevich <s_rasiukevich@wargaming.net>
|
||||
Sidhartha Mani <sidharthamn@gmail.com>
|
||||
|
@ -1946,7 +2008,6 @@ sidharthamani <sid@rancher.com>
|
|||
Silas Sewell <silas@sewell.org>
|
||||
Silvan Jegen <s.jegen@gmail.com>
|
||||
Simão Reis <smnrsti@gmail.com>
|
||||
Simei He <hesimei@zju.edu.cn>
|
||||
Simon Barendse <simon.barendse@gmail.com>
|
||||
Simon Eskildsen <sirup@sirupsen.com>
|
||||
Simon Ferquel <simon.ferquel@docker.com>
|
||||
|
@ -1976,6 +2037,7 @@ Stanislav Bondarenko <stanislav.bondarenko@gmail.com>
|
|||
Stanislav Levin <slev@altlinux.org>
|
||||
Steeve Morin <steeve.morin@gmail.com>
|
||||
Stefan Berger <stefanb@linux.vnet.ibm.com>
|
||||
Stefan Gehrig <stefan.gehrig.hn@googlemail.com>
|
||||
Stefan J. Wernli <swernli@microsoft.com>
|
||||
Stefan Praszalowicz <stefan@greplin.com>
|
||||
Stefan S. <tronicum@user.github.com>
|
||||
|
@ -1983,6 +2045,7 @@ Stefan Scherer <stefan.scherer@docker.com>
|
|||
Stefan Staudenmeyer <doerte@instana.com>
|
||||
Stefan Weil <sw@weilnetz.de>
|
||||
Steffen Butzer <steffen.butzer@outlook.com>
|
||||
Stephan Henningsen <stephan-henningsen@users.noreply.github.com>
|
||||
Stephan Spindler <shutefan@gmail.com>
|
||||
Stephen Benjamin <stephen@redhat.com>
|
||||
Stephen Crosby <stevecrozz@gmail.com>
|
||||
|
@ -2022,7 +2085,7 @@ Sébastien Stormacq <sebsto@users.noreply.github.com>
|
|||
Sören Tempel <soeren+git@soeren-tempel.net>
|
||||
Tabakhase <mail@tabakhase.com>
|
||||
Tadej Janež <tadej.j@nez.si>
|
||||
TAGOMORI Satoshi <tagomoris@gmail.com>
|
||||
Takuto Sato <tockn.jp@gmail.com>
|
||||
tang0th <tang0th@gmx.com>
|
||||
Tangi Colin <tangicolin@gmail.com>
|
||||
Tatsuki Sugiura <sugi@nemui.org>
|
||||
|
@ -2035,7 +2098,6 @@ Tejaswini Duggaraju <naduggar@microsoft.com>
|
|||
Tejesh Mehta <tejesh.mehta@gmail.com>
|
||||
Terry Chu <zue.hterry@gmail.com>
|
||||
terryding77 <550147740@qq.com>
|
||||
tgic <farmer1992@gmail.com>
|
||||
Thatcher Peskens <thatcher@docker.com>
|
||||
theadactyl <thea.lamkin@gmail.com>
|
||||
Thell 'Bo' Fowler <thell@tbfowler.name>
|
||||
|
@ -2059,6 +2121,7 @@ Thomas Swift <tgs242@gmail.com>
|
|||
Thomas Tanaka <thomas.tanaka@oracle.com>
|
||||
Thomas Texier <sharkone@en-mousse.org>
|
||||
Ti Zhou <tizhou1986@gmail.com>
|
||||
Tiago Seabra <tlgs@users.noreply.github.com>
|
||||
Tianon Gravi <admwiggin@gmail.com>
|
||||
Tianyi Wang <capkurmagati@gmail.com>
|
||||
Tibor Vass <teabee89@gmail.com>
|
||||
|
@ -2184,6 +2247,7 @@ Vinod Kulkarni <vinod.kulkarni@gmail.com>
|
|||
Vishal Doshi <vishal.doshi@gmail.com>
|
||||
Vishnu Kannan <vishnuk@google.com>
|
||||
Vitaly Ostrosablin <vostrosablin@virtuozzo.com>
|
||||
Vitor Anjos <bartier@users.noreply.github.com>
|
||||
Vitor Monteiro <vmrmonteiro@gmail.com>
|
||||
Vivek Agarwal <me@vivek.im>
|
||||
Vivek Dasgupta <vdasgupt@redhat.com>
|
||||
|
@ -2197,7 +2261,7 @@ VladimirAus <v_roudakov@yahoo.com>
|
|||
Vladislav Kolesnikov <vkolesnikov@beget.ru>
|
||||
Vlastimil Zeman <vlastimil.zeman@diffblue.com>
|
||||
Vojtech Vitek (V-Teq) <vvitek@redhat.com>
|
||||
waitingkuo <waitingkuo0527@gmail.com>
|
||||
voloder <110066198+voloder@users.noreply.github.com>
|
||||
Walter Leibbrandt <github@wrl.co.za>
|
||||
Walter Stanish <walter@pratyeka.org>
|
||||
Wang Chao <chao.wang@ucloud.cn>
|
||||
|
@ -2227,11 +2291,11 @@ Wendel Fleming <wfleming@usc.edu>
|
|||
Wenjun Tang <tangwj2@lenovo.com>
|
||||
Wenkai Yin <yinw@vmware.com>
|
||||
wenlxie <wenlxie@ebay.com>
|
||||
Wentao Zhang <zhangwentao234@huawei.com>
|
||||
Wenxuan Zhao <viz@linux.com>
|
||||
Wenyu You <21551128@zju.edu.cn>
|
||||
Wenzhi Liang <wenzhi.liang@gmail.com>
|
||||
Wes Morgan <cap10morgan@gmail.com>
|
||||
Wesley Pettit <wppttt@amazon.com>
|
||||
Wewang Xiaorenfine <wang.xiaoren@zte.com.cn>
|
||||
Wiktor Kwapisiewicz <wiktor@metacode.biz>
|
||||
Will Dietz <w@wdtz.org>
|
||||
|
@ -2269,8 +2333,9 @@ Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
|
|||
xichengliudui <1693291525@qq.com>
|
||||
xiekeyang <xiekeyang@huawei.com>
|
||||
Ximo Guanter Gonzálbez <joaquin.guantergonzalbez@telefonica.com>
|
||||
xin.li <xin.li@daocloud.io>
|
||||
Xinbo Weng <xihuanbo_0521@zju.edu.cn>
|
||||
Xinfeng Liu <xinfeng.liu@gmail.com>
|
||||
Xinfeng Liu <XinfengLiu@icloud.com>
|
||||
Xinzi Zhou <imdreamrunner@gmail.com>
|
||||
Xiuming Chen <cc@cxm.cc>
|
||||
Xuecong Liao <satorulogic@gmail.com>
|
||||
|
@ -2280,12 +2345,14 @@ Yahya <ya7yaz@gmail.com>
|
|||
yalpul <yalpul@gmail.com>
|
||||
YAMADA Tsuyoshi <tyamada@minimum2scp.org>
|
||||
Yamasaki Masahide <masahide.y@gmail.com>
|
||||
Yamazaki Masashi <masi19bw@gmail.com>
|
||||
Yan Feng <yanfeng2@huawei.com>
|
||||
Yan Zhu <yanzhu@alauda.io>
|
||||
Yang Bai <hamo.by@gmail.com>
|
||||
Yang Li <idealhack@gmail.com>
|
||||
Yang Pengfei <yangpengfei4@huawei.com>
|
||||
yangchenliang <yangchenliang@huawei.com>
|
||||
Yann Autissier <yann.autissier@gmail.com>
|
||||
Yanqiang Miao <miao.yanqiang@zte.com.cn>
|
||||
Yao Zaiyong <yaozaiyong@hotmail.com>
|
||||
Yash Murty <yashmurty@gmail.com>
|
||||
|
@ -2305,6 +2372,7 @@ Yosef Fertel <yfertel@gmail.com>
|
|||
You-Sheng Yang (楊有勝) <vicamo@gmail.com>
|
||||
youcai <omegacoleman@gmail.com>
|
||||
Youcef YEKHLEF <yyekhlef@gmail.com>
|
||||
Youfu Zhang <zhangyoufu@gmail.com>
|
||||
Yu Changchun <yuchangchun1@huawei.com>
|
||||
Yu Chengxia <yuchengxia@huawei.com>
|
||||
Yu Peng <yu.peng36@zte.com.cn>
|
||||
|
@ -2333,6 +2401,7 @@ Zen Lin(Zhinan Lin) <linzhinan@huawei.com>
|
|||
Zhang Kun <zkazure@gmail.com>
|
||||
Zhang Wei <zhangwei555@huawei.com>
|
||||
Zhang Wentao <zhangwentao234@huawei.com>
|
||||
zhangguanzhang <zhangguanzhang@qq.com>
|
||||
ZhangHang <stevezhang2014@gmail.com>
|
||||
zhangxianwei <xianwei.zw@alibaba-inc.com>
|
||||
Zhenan Ye <21551168@zju.edu.cn>
|
||||
|
@ -2357,9 +2426,9 @@ Zou Yu <zouyu7@huawei.com>
|
|||
zqh <zqhxuyuan@gmail.com>
|
||||
Zuhayr Elahi <zuhayr.elahi@docker.com>
|
||||
Zunayed Ali <zunayed@gmail.com>
|
||||
Álex González <agonzalezro@gmail.com>
|
||||
Álvaro Lázaro <alvaro.lazaro.g@gmail.com>
|
||||
Átila Camurça Alves <camurca.home@gmail.com>
|
||||
吴小白 <296015668@qq.com>
|
||||
尹吉峰 <jifeng.yin@gmail.com>
|
||||
屈骏 <qujun@tiduyun.com>
|
||||
徐俊杰 <paco.xu@daocloud.io>
|
||||
|
|
3609
CHANGELOG.md
3609
CHANGELOG.md
File diff suppressed because it is too large
Load diff
|
@ -72,7 +72,7 @@ anybody starts working on it.
|
|||
We are always thrilled to receive pull requests. We do our best to process them
|
||||
quickly. If your pull request is not accepted on the first try,
|
||||
don't get discouraged! Our contributor's guide explains [the review process we
|
||||
use for simple changes](https://docs.docker.com/opensource/workflow/make-a-contribution/).
|
||||
use for simple changes](https://docs.docker.com/contribute/overview/).
|
||||
|
||||
### Design and cleanup proposals
|
||||
|
||||
|
@ -101,7 +101,7 @@ the contributors guide.
|
|||
<td>
|
||||
<p>
|
||||
Register for the Docker Community Slack at
|
||||
<a href="https://dockr.ly/slack" target="_blank">https://dockr.ly/slack</a>.
|
||||
<a href="https://dockr.ly/comm-slack" target="_blank">https://dockr.ly/comm-slack</a>.
|
||||
We use the #moby-project channel for general discussion, and there are separate channels for other Moby projects such as #containerd.
|
||||
</p>
|
||||
</td>
|
||||
|
@ -309,36 +309,6 @@ 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
|
||||
|
||||
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
|
||||
|
@ -452,6 +422,6 @@ The rules:
|
|||
guidelines. Since you've read all the rules, you now know that.
|
||||
|
||||
If you are having trouble getting into the mood of idiomatic Go, we recommend
|
||||
reading through [Effective Go](https://golang.org/doc/effective_go.html). The
|
||||
[Go Blog](https://blog.golang.org) is also a great resource. Drinking the
|
||||
reading through [Effective Go](https://go.dev/doc/effective_go). The
|
||||
[Go Blog](https://go.dev/blog/) is also a great resource. Drinking the
|
||||
kool-aid is a lot easier than going thirsty.
|
||||
|
|
764
Dockerfile
764
Dockerfile
|
@ -1,81 +1,127 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
# syntax=docker/dockerfile:1.7
|
||||
|
||||
ARG GO_VERSION=1.21.9
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
ARG XX_VERSION=1.4.0
|
||||
|
||||
ARG CROSS="false"
|
||||
ARG SYSTEMD="false"
|
||||
ARG GO_VERSION=1.18.3
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG VPNKIT_VERSION=0.5.0
|
||||
|
||||
ARG BASE_DEBIAN_DISTRO="bullseye"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
ARG DOCKERCLI_REPOSITORY="https://github.com/docker/cli.git"
|
||||
ARG DOCKERCLI_VERSION=v26.0.0
|
||||
# cli version used for integration-cli tests
|
||||
ARG DOCKERCLI_INTEGRATION_REPOSITORY="https://github.com/docker/cli.git"
|
||||
ARG DOCKERCLI_INTEGRATION_VERSION=v17.06.2-ce
|
||||
ARG BUILDX_VERSION=0.13.1
|
||||
ARG COMPOSE_VERSION=v2.25.0
|
||||
|
||||
FROM ${GOLANG_IMAGE} AS base
|
||||
ARG SYSTEMD="false"
|
||||
ARG DOCKER_STATIC=1
|
||||
|
||||
# REGISTRY_VERSION specifies the version of the registry to download from
|
||||
# https://hub.docker.com/r/distribution/distribution. This version of
|
||||
# the registry is used to test schema 2 manifests. Generally, the version
|
||||
# specified here should match a current release.
|
||||
ARG REGISTRY_VERSION=2.8.3
|
||||
|
||||
# delve is currently only supported on linux/amd64 and linux/arm64;
|
||||
# https://github.com/go-delve/delve/blob/v1.8.1/pkg/proc/native/support_sentinel.go#L1-L6
|
||||
ARG DELVE_SUPPORTED=${TARGETPLATFORM#linux/amd64} DELVE_SUPPORTED=${DELVE_SUPPORTED#linux/arm64}
|
||||
ARG DELVE_SUPPORTED=${DELVE_SUPPORTED:+"unsupported"}
|
||||
ARG DELVE_SUPPORTED=${DELVE_SUPPORTED:-"supported"}
|
||||
|
||||
# cross compilation helper
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
||||
# dummy stage to make sure the image is built for deps that don't support some
|
||||
# architectures
|
||||
FROM --platform=$BUILDPLATFORM busybox AS build-dummy
|
||||
RUN mkdir -p /build
|
||||
FROM scratch AS binary-dummy
|
||||
COPY --from=build-dummy /build /build
|
||||
|
||||
# base
|
||||
FROM --platform=$BUILDPLATFORM ${GOLANG_IMAGE} AS base
|
||||
COPY --from=xx / /
|
||||
RUN echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
|
||||
ARG APT_MIRROR
|
||||
RUN sed -ri "s/(httpredir|deb).debian.org/${APT_MIRROR:-deb.debian.org}/g" /etc/apt/sources.list \
|
||||
&& sed -ri "s/(security).debian.org/${APT_MIRROR:-security.debian.org}/g" /etc/apt/sources.list
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y file
|
||||
ENV GO111MODULE=off
|
||||
ENV GOTOOLCHAIN=local
|
||||
|
||||
FROM base AS criu
|
||||
ARG DEBIAN_FRONTEND
|
||||
ADD --chmod=0644 https://download.opensuse.org/repositories/devel:/tools:/criu/Debian_11/Release.key /etc/apt/trusted.gpg.d/criu.gpg.asc
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-criu-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-criu-aptcache,target=/var/cache/apt \
|
||||
echo 'deb https://download.opensuse.org/repositories/devel:/tools:/criu/Debian_11/ /' > /etc/apt/sources.list.d/criu.list \
|
||||
echo 'deb https://download.opensuse.org/repositories/devel:/tools:/criu/Debian_12/ /' > /etc/apt/sources.list.d/criu.list \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends criu \
|
||||
&& install -D /usr/sbin/criu /build/criu
|
||||
&& install -D /usr/sbin/criu /build/criu \
|
||||
&& /build/criu --version
|
||||
|
||||
# registry
|
||||
FROM base AS registry-src
|
||||
WORKDIR /usr/src/registry
|
||||
RUN git init . && git remote add origin "https://github.com/distribution/distribution.git"
|
||||
|
||||
FROM base AS registry
|
||||
WORKDIR /go/src/github.com/docker/distribution
|
||||
|
||||
# REGISTRY_VERSION specifies the version of the registry to build and install
|
||||
# from the https://github.com/docker/distribution repository. This version of
|
||||
# the registry is used to test both schema 1 and schema 2 manifests. Generally,
|
||||
# the version specified here should match a current release.
|
||||
ARG REGISTRY_VERSION=v2.3.0
|
||||
|
||||
# REGISTRY_VERSION_SCHEMA1 specifies the version of the registry to build and
|
||||
# install from the https://github.com/docker/distribution repository. This is
|
||||
# an older (pre v2.3.0) version of the registry that only supports schema1
|
||||
# manifests. This version of the registry is not working on arm64, so installation
|
||||
# is skipped on that architecture.
|
||||
ARG REGISTRY_VERSION_SCHEMA1=v2.1.0
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=from=registry-src,src=/usr/src/registry,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=registry-build-$TARGETPLATFORM \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=tmpfs,target=/go/src/ \
|
||||
set -x \
|
||||
&& git clone https://github.com/docker/distribution.git . \
|
||||
&& git checkout -q "$REGISTRY_VERSION" \
|
||||
&& GOPATH="/go/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|armhf|ppc64*|s390x) \
|
||||
git checkout -q "$REGISTRY_VERSION_SCHEMA1"; \
|
||||
GOPATH="/go/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH"; \
|
||||
go build -buildmode=pie -o /build/registry-v2-schema1 github.com/docker/distribution/cmd/registry; \
|
||||
;; \
|
||||
esac
|
||||
--mount=type=tmpfs,target=/go/src <<EOT
|
||||
set -ex
|
||||
export GOPATH="/go/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH"
|
||||
# Make the /build directory no matter what so that it doesn't fail on arm64 or
|
||||
# any other platform where we don't build this registry
|
||||
mkdir /build
|
||||
case $TARGETPLATFORM in
|
||||
linux/amd64|linux/arm/v7|linux/ppc64le|linux/s390x)
|
||||
git fetch -q --depth 1 origin "${REGISTRY_VERSION_SCHEMA1}" +refs/tags/*:refs/tags/*
|
||||
git checkout -q FETCH_HEAD
|
||||
CGO_ENABLED=0 xx-go build -o /build/registry-v2-schema1 -v ./cmd/registry
|
||||
xx-verify /build/registry-v2-schema1
|
||||
;;
|
||||
esac
|
||||
EOT
|
||||
|
||||
FROM base AS swagger
|
||||
WORKDIR $GOPATH/src/github.com/go-swagger/go-swagger
|
||||
FROM distribution/distribution:$REGISTRY_VERSION AS registry-v2
|
||||
RUN mkdir /build && mv /bin/registry /build/registry-v2
|
||||
|
||||
# go-swagger
|
||||
FROM base AS swagger-src
|
||||
WORKDIR /usr/src/swagger
|
||||
# Currently uses a fork from https://github.com/kolyshkin/go-swagger/tree/golang-1.13-fix
|
||||
# TODO: move to under moby/ or fix upstream go-swagger to work for us.
|
||||
RUN git init . && git remote add origin "https://github.com/kolyshkin/go-swagger.git"
|
||||
# GO_SWAGGER_COMMIT specifies the version of the go-swagger binary to build and
|
||||
# install. Go-swagger is used in CI for validating swagger.yaml in hack/validate/swagger-gen
|
||||
#
|
||||
# Currently uses a fork from https://github.com/kolyshkin/go-swagger/tree/golang-1.13-fix,
|
||||
# TODO: move to under moby/ or fix upstream go-swagger to work for us.
|
||||
ENV GO_SWAGGER_COMMIT c56166c036004ba7a3a321e5951ba472b9ae298c
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=tmpfs,target=/go/src/ \
|
||||
set -x \
|
||||
&& git clone https://github.com/kolyshkin/go-swagger.git . \
|
||||
&& git checkout -q "$GO_SWAGGER_COMMIT" \
|
||||
&& go build -o /build/swagger github.com/go-swagger/go-swagger/cmd/swagger
|
||||
ARG GO_SWAGGER_COMMIT=c56166c036004ba7a3a321e5951ba472b9ae298c
|
||||
RUN git fetch -q --depth 1 origin "${GO_SWAGGER_COMMIT}" && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS swagger
|
||||
WORKDIR /go/src/github.com/go-swagger/go-swagger
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=from=swagger-src,src=/usr/src/swagger,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=swagger-build-$TARGETPLATFORM \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=tmpfs,target=/go/src/ <<EOT
|
||||
set -e
|
||||
xx-go build -o /build/swagger ./cmd/swagger
|
||||
xx-verify /build/swagger
|
||||
EOT
|
||||
|
||||
# frozen-images
|
||||
# See also frozenImages in "testutil/environment/protect.go" (which needs to
|
||||
# be updated when adding images to this list)
|
||||
FROM debian:${BASE_DEBIAN_DISTRO} AS frozen-images
|
||||
ARG DEBIAN_FRONTEND
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-frozen-images-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-frozen-images-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
@ -85,88 +131,38 @@ RUN --mount=type=cache,sharing=locked,id=moby-frozen-images-aptlib,target=/var/l
|
|||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
RUN /download-frozen-image-v2.sh /build \
|
||||
busybox:latest@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209 \
|
||||
busybox:glibc@sha256:1f81263701cddf6402afe9f33fca0266d9fff379e59b1748f33d3072da71ee85 \
|
||||
debian:bullseye-slim@sha256:dacf278785a4daa9de07596ec739dbc07131e189942772210709c5c0777e8437 \
|
||||
debian:bookworm-slim@sha256:2bc5c236e9b262645a323e9088dfa3bb1ecb16cc75811daf40a23a824d665be9 \
|
||||
hello-world:latest@sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9 \
|
||||
arm32v7/hello-world:latest@sha256:50b8560ad574c779908da71f7ce370c0a2471c098d44d1c8f6b513c5a55eeeb1
|
||||
# See also frozenImages in "testutil/environment/protect.go" (which needs to be updated when adding images to this list)
|
||||
|
||||
FROM base AS cross-false
|
||||
|
||||
FROM --platform=linux/amd64 base AS cross-true
|
||||
ARG DEBIAN_FRONTEND
|
||||
RUN dpkg --add-architecture arm64
|
||||
RUN dpkg --add-architecture armel
|
||||
RUN dpkg --add-architecture armhf
|
||||
RUN dpkg --add-architecture ppc64el
|
||||
RUN dpkg --add-architecture s390x
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-cross-true-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-cross-true-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
crossbuild-essential-arm64 \
|
||||
crossbuild-essential-armel \
|
||||
crossbuild-essential-armhf \
|
||||
crossbuild-essential-ppc64el \
|
||||
crossbuild-essential-s390x
|
||||
|
||||
FROM cross-${CROSS} AS dev-base
|
||||
|
||||
FROM dev-base AS runtime-dev-cross-false
|
||||
ARG DEBIAN_FRONTEND
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-cross-false-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-cross-false-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
binutils-mingw-w64 \
|
||||
g++-mingw-w64-x86-64 \
|
||||
libapparmor-dev \
|
||||
libbtrfs-dev \
|
||||
libdevmapper-dev \
|
||||
libseccomp-dev \
|
||||
libsystemd-dev \
|
||||
libudev-dev
|
||||
|
||||
FROM --platform=linux/amd64 runtime-dev-cross-false AS runtime-dev-cross-true
|
||||
ARG DEBIAN_FRONTEND
|
||||
# These crossbuild packages rely on gcc-<arch>, but this doesn't want to install
|
||||
# on non-amd64 systems, so other architectures cannot crossbuild amd64.
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-cross-true-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-cross-true-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
libapparmor-dev:arm64 \
|
||||
libapparmor-dev:armel \
|
||||
libapparmor-dev:armhf \
|
||||
libapparmor-dev:ppc64el \
|
||||
libapparmor-dev:s390x \
|
||||
libseccomp-dev:arm64 \
|
||||
libseccomp-dev:armel \
|
||||
libseccomp-dev:armhf \
|
||||
libseccomp-dev:ppc64el \
|
||||
libseccomp-dev:s390x
|
||||
|
||||
FROM runtime-dev-cross-${CROSS} AS runtime-dev
|
||||
|
||||
FROM base AS delve
|
||||
# delve
|
||||
FROM base AS delve-src
|
||||
WORKDIR /usr/src/delve
|
||||
RUN git init . && git remote add origin "https://github.com/go-delve/delve.git"
|
||||
# DELVE_VERSION specifies the version of the Delve debugger binary
|
||||
# from the https://github.com/go-delve/delve repository.
|
||||
# It can be used to run Docker with a possibility of
|
||||
# attaching debugger to it.
|
||||
#
|
||||
ARG DELVE_VERSION=v1.8.1
|
||||
# Delve on Linux is currently only supported on amd64 and arm64;
|
||||
# https://github.com/go-delve/delve/blob/v1.8.1/pkg/proc/native/support_sentinel.go#L1-L6
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
case $(dpkg --print-architecture) in \
|
||||
amd64|arm64) \
|
||||
GOBIN=/build/ GO111MODULE=on go install "github.com/go-delve/delve/cmd/dlv@${DELVE_VERSION}" \
|
||||
&& /build/dlv --help \
|
||||
;; \
|
||||
*) \
|
||||
mkdir -p /build/ \
|
||||
;; \
|
||||
esac
|
||||
ARG DELVE_VERSION=v1.21.1
|
||||
RUN git fetch -q --depth 1 origin "${DELVE_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS delve-supported
|
||||
WORKDIR /usr/src/delve
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=from=delve-src,src=/usr/src/delve,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=delve-build-$TARGETPLATFORM \
|
||||
--mount=type=cache,target=/go/pkg/mod <<EOT
|
||||
set -e
|
||||
GO111MODULE=on xx-go build -o /build/dlv ./cmd/dlv
|
||||
xx-verify /build/dlv
|
||||
EOT
|
||||
|
||||
FROM binary-dummy AS delve-unsupported
|
||||
FROM delve-${DELVE_SUPPORTED} AS delve
|
||||
|
||||
FROM base AS tomll
|
||||
# GOTOML_VERSION specifies the version of the tomll binary to build and install
|
||||
|
@ -183,88 +179,216 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
|
|||
|
||||
FROM base AS gowinres
|
||||
# GOWINRES_VERSION defines go-winres tool version
|
||||
ARG GOWINRES_VERSION=v0.2.3
|
||||
ARG GOWINRES_VERSION=v0.3.1
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
GOBIN=/build/ GO111MODULE=on go install "github.com/tc-hib/go-winres@${GOWINRES_VERSION}" \
|
||||
&& /build/go-winres --help
|
||||
|
||||
FROM dev-base AS containerd
|
||||
ARG DEBIAN_FRONTEND
|
||||
# containerd
|
||||
FROM base AS containerd-src
|
||||
WORKDIR /usr/src/containerd
|
||||
RUN git init . && git remote add origin "https://github.com/containerd/containerd.git"
|
||||
# CONTAINERD_VERSION is used to build containerd binaries, and used for the
|
||||
# integration tests. The distributed docker .deb and .rpm packages depend on a
|
||||
# separate (containerd.io) package, which may be a different version as is
|
||||
# specified here. The containerd golang package is also pinned in vendor.mod.
|
||||
# When updating the binary version you may also need to update the vendor
|
||||
# version to pick up bug fixes or new APIs, however, usually the Go packages
|
||||
# are built from a commit from the master branch.
|
||||
ARG CONTAINERD_VERSION=v1.7.15
|
||||
RUN git fetch -q --depth 1 origin "${CONTAINERD_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS containerd-build
|
||||
WORKDIR /go/src/github.com/containerd/containerd
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-containerd-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-containerd-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
libbtrfs-dev
|
||||
ARG CONTAINERD_VERSION
|
||||
COPY /hack/dockerfile/install/install.sh /hack/dockerfile/install/containerd.installer /
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
PREFIX=/build /install.sh containerd
|
||||
apt-get update && xx-apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libbtrfs-dev \
|
||||
libsecret-1-dev \
|
||||
pkg-config
|
||||
ARG DOCKER_STATIC
|
||||
RUN --mount=from=containerd-src,src=/usr/src/containerd,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=containerd-build-$TARGETPLATFORM <<EOT
|
||||
set -e
|
||||
export CC=$(xx-info)-gcc
|
||||
export CGO_ENABLED=$([ "$DOCKER_STATIC" = "1" ] && echo "0" || echo "1")
|
||||
xx-go --wrap
|
||||
make $([ "$DOCKER_STATIC" = "1" ] && echo "STATIC=1") binaries
|
||||
xx-verify $([ "$DOCKER_STATIC" = "1" ] && echo "--static") bin/containerd
|
||||
xx-verify $([ "$DOCKER_STATIC" = "1" ] && echo "--static") bin/containerd-shim-runc-v2
|
||||
xx-verify $([ "$DOCKER_STATIC" = "1" ] && echo "--static") bin/ctr
|
||||
mkdir /build
|
||||
mv bin/containerd bin/containerd-shim-runc-v2 bin/ctr /build
|
||||
EOT
|
||||
|
||||
FROM containerd-build AS containerd-linux
|
||||
FROM binary-dummy AS containerd-windows
|
||||
FROM containerd-${TARGETOS} AS containerd
|
||||
|
||||
FROM base AS golangci_lint
|
||||
ARG GOLANGCI_LINT_VERSION=v1.46.2
|
||||
ARG GOLANGCI_LINT_VERSION=v1.55.2
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
GOBIN=/build/ GO111MODULE=on go install "github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINT_VERSION}" \
|
||||
&& /build/golangci-lint --version
|
||||
|
||||
FROM base AS gotestsum
|
||||
ARG GOTESTSUM_VERSION=v1.8.1
|
||||
ARG GOTESTSUM_VERSION=v1.8.2
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
GOBIN=/build/ GO111MODULE=on go install "gotest.tools/gotestsum@${GOTESTSUM_VERSION}" \
|
||||
&& /build/gotestsum --version
|
||||
|
||||
FROM base AS shfmt
|
||||
ARG SHFMT_VERSION=v3.0.2
|
||||
ARG SHFMT_VERSION=v3.8.0
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
GOBIN=/build/ GO111MODULE=on go install "mvdan.cc/sh/v3/cmd/shfmt@${SHFMT_VERSION}" \
|
||||
&& /build/shfmt --version
|
||||
|
||||
FROM dev-base AS dockercli
|
||||
ARG DOCKERCLI_CHANNEL
|
||||
FROM base AS gopls
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
GOBIN=/build/ GO111MODULE=on go install "golang.org/x/tools/gopls@latest" \
|
||||
&& /build/gopls version
|
||||
|
||||
FROM base AS dockercli
|
||||
WORKDIR /go/src/github.com/docker/cli
|
||||
ARG DOCKERCLI_REPOSITORY
|
||||
ARG DOCKERCLI_VERSION
|
||||
COPY /hack/dockerfile/install/install.sh /hack/dockerfile/install/dockercli.installer /
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
PREFIX=/build /install.sh dockercli
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=source=hack/dockerfile/cli.sh,target=/download-or-build-cli.sh \
|
||||
--mount=type=cache,id=dockercli-git-$TARGETPLATFORM,sharing=locked,target=./.git \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=dockercli-build-$TARGETPLATFORM \
|
||||
rm -f ./.git/*.lock \
|
||||
&& /download-or-build-cli.sh ${DOCKERCLI_VERSION} ${DOCKERCLI_REPOSITORY} /build \
|
||||
&& /build/docker --version
|
||||
|
||||
FROM runtime-dev AS runc
|
||||
ARG RUNC_VERSION
|
||||
ARG RUNC_BUILDTAGS
|
||||
COPY /hack/dockerfile/install/install.sh /hack/dockerfile/install/runc.installer /
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
PREFIX=/build /install.sh runc
|
||||
FROM base AS dockercli-integration
|
||||
WORKDIR /go/src/github.com/docker/cli
|
||||
ARG DOCKERCLI_INTEGRATION_REPOSITORY
|
||||
ARG DOCKERCLI_INTEGRATION_VERSION
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=source=hack/dockerfile/cli.sh,target=/download-or-build-cli.sh \
|
||||
--mount=type=cache,id=dockercli-git-$TARGETPLATFORM,sharing=locked,target=./.git \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=dockercli-build-$TARGETPLATFORM \
|
||||
rm -f ./.git/*.lock \
|
||||
&& /download-or-build-cli.sh ${DOCKERCLI_INTEGRATION_VERSION} ${DOCKERCLI_INTEGRATION_REPOSITORY} /build \
|
||||
&& /build/docker --version
|
||||
|
||||
FROM dev-base AS tini
|
||||
ARG DEBIAN_FRONTEND
|
||||
ARG TINI_VERSION
|
||||
# runc
|
||||
FROM base AS runc-src
|
||||
WORKDIR /usr/src/runc
|
||||
RUN git init . && git remote add origin "https://github.com/opencontainers/runc.git"
|
||||
# RUNC_VERSION should match the version that is used by the containerd version
|
||||
# that is used. If you need to update runc, open a pull request in the containerd
|
||||
# project first, and update both after that is merged. When updating RUNC_VERSION,
|
||||
# consider updating runc in vendor.mod accordingly.
|
||||
ARG RUNC_VERSION=v1.1.12
|
||||
RUN git fetch -q --depth 1 origin "${RUNC_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS runc-build
|
||||
WORKDIR /go/src/github.com/opencontainers/runc
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-runc-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-runc-aptcache,target=/var/cache/apt \
|
||||
apt-get update && xx-apt-get install -y --no-install-recommends \
|
||||
dpkg-dev \
|
||||
gcc \
|
||||
libc6-dev \
|
||||
libseccomp-dev \
|
||||
pkg-config
|
||||
ARG DOCKER_STATIC
|
||||
RUN --mount=from=runc-src,src=/usr/src/runc,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=runc-build-$TARGETPLATFORM <<EOT
|
||||
set -e
|
||||
xx-go --wrap
|
||||
CGO_ENABLED=1 make "$([ "$DOCKER_STATIC" = "1" ] && echo "static" || echo "runc")"
|
||||
xx-verify $([ "$DOCKER_STATIC" = "1" ] && echo "--static") runc
|
||||
mkdir /build
|
||||
mv runc /build/
|
||||
EOT
|
||||
|
||||
FROM runc-build AS runc-linux
|
||||
FROM binary-dummy AS runc-windows
|
||||
FROM runc-${TARGETOS} AS runc
|
||||
|
||||
# tini
|
||||
FROM base AS tini-src
|
||||
WORKDIR /usr/src/tini
|
||||
RUN git init . && git remote add origin "https://github.com/krallin/tini.git"
|
||||
# TINI_VERSION specifies the version of tini (docker-init) to build. This
|
||||
# binary is used when starting containers with the `--init` option.
|
||||
ARG TINI_VERSION=v0.19.0
|
||||
RUN git fetch -q --depth 1 origin "${TINI_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS tini-build
|
||||
WORKDIR /go/src/github.com/krallin/tini
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-tini-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-tini-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
cmake \
|
||||
vim-common
|
||||
COPY /hack/dockerfile/install/install.sh /hack/dockerfile/install/tini.installer /
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
PREFIX=/build /install.sh tini
|
||||
apt-get update && apt-get install -y --no-install-recommends cmake
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-tini-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-tini-aptcache,target=/var/cache/apt \
|
||||
xx-apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libc6-dev \
|
||||
pkg-config
|
||||
RUN --mount=from=tini-src,src=/usr/src/tini,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=tini-build-$TARGETPLATFORM <<EOT
|
||||
set -e
|
||||
CC=$(xx-info)-gcc cmake .
|
||||
make tini-static
|
||||
xx-verify --static tini-static
|
||||
mkdir /build
|
||||
mv tini-static /build/docker-init
|
||||
EOT
|
||||
|
||||
FROM dev-base AS rootlesskit
|
||||
ARG ROOTLESSKIT_VERSION
|
||||
ARG PREFIX=/build
|
||||
COPY /hack/dockerfile/install/install.sh /hack/dockerfile/install/rootlesskit.installer /
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
FROM tini-build AS tini-linux
|
||||
FROM binary-dummy AS tini-windows
|
||||
FROM tini-${TARGETOS} AS tini
|
||||
|
||||
# rootlesskit
|
||||
FROM base AS rootlesskit-src
|
||||
WORKDIR /usr/src/rootlesskit
|
||||
RUN git init . && git remote add origin "https://github.com/rootless-containers/rootlesskit.git"
|
||||
# When updating, also update vendor.mod and hack/dockerfile/install/rootlesskit.installer accordingly.
|
||||
ARG ROOTLESSKIT_VERSION=v2.0.2
|
||||
RUN git fetch -q --depth 1 origin "${ROOTLESSKIT_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS rootlesskit-build
|
||||
WORKDIR /go/src/github.com/rootless-containers/rootlesskit
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-rootlesskit-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-rootlesskit-aptcache,target=/var/cache/apt \
|
||||
apt-get update && xx-apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
libc6-dev \
|
||||
pkg-config
|
||||
ENV GO111MODULE=on
|
||||
ARG DOCKER_STATIC
|
||||
RUN --mount=from=rootlesskit-src,src=/usr/src/rootlesskit,rw \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
/install.sh rootlesskit \
|
||||
&& "${PREFIX}"/rootlesskit --version \
|
||||
&& "${PREFIX}"/rootlesskit-docker-proxy --help
|
||||
COPY ./contrib/dockerd-rootless.sh /build
|
||||
COPY ./contrib/dockerd-rootless-setuptool.sh /build
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=rootlesskit-build-$TARGETPLATFORM <<EOT
|
||||
set -e
|
||||
export CGO_ENABLED=$([ "$DOCKER_STATIC" = "1" ] && echo "0" || echo "1")
|
||||
xx-go build -o /build/rootlesskit -ldflags="$([ "$DOCKER_STATIC" != "1" ] && echo "-linkmode=external")" ./cmd/rootlesskit
|
||||
xx-verify $([ "$DOCKER_STATIC" = "1" ] && echo "--static") /build/rootlesskit
|
||||
xx-go build -o /build/rootlesskit-docker-proxy -ldflags="$([ "$DOCKER_STATIC" != "1" ] && echo "-linkmode=external")" ./cmd/rootlesskit-docker-proxy
|
||||
xx-verify $([ "$DOCKER_STATIC" = "1" ] && echo "--static") /build/rootlesskit-docker-proxy
|
||||
EOT
|
||||
COPY --link ./contrib/dockerd-rootless.sh /build/
|
||||
COPY --link ./contrib/dockerd-rootless-setuptool.sh /build/
|
||||
|
||||
FROM rootlesskit-build AS rootlesskit-linux
|
||||
FROM binary-dummy AS rootlesskit-windows
|
||||
FROM rootlesskit-${TARGETOS} AS rootlesskit
|
||||
|
||||
FROM base AS crun
|
||||
ARG CRUN_VERSION=1.4.5
|
||||
ARG CRUN_VERSION=1.12
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-crun-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-crun-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
@ -288,17 +412,99 @@ RUN --mount=type=tmpfs,target=/tmp/crun-build \
|
|||
./configure --bindir=/build && \
|
||||
make -j install
|
||||
|
||||
FROM --platform=amd64 djs55/vpnkit:${VPNKIT_VERSION} AS vpnkit-amd64
|
||||
# vpnkit
|
||||
# use dummy scratch stage to avoid build to fail for unsupported platforms
|
||||
FROM scratch AS vpnkit-windows
|
||||
FROM scratch AS vpnkit-linux-386
|
||||
FROM scratch AS vpnkit-linux-arm
|
||||
FROM scratch AS vpnkit-linux-ppc64le
|
||||
FROM scratch AS vpnkit-linux-riscv64
|
||||
FROM scratch AS vpnkit-linux-s390x
|
||||
FROM djs55/vpnkit:${VPNKIT_VERSION} AS vpnkit-linux-amd64
|
||||
FROM djs55/vpnkit:${VPNKIT_VERSION} AS vpnkit-linux-arm64
|
||||
FROM vpnkit-linux-${TARGETARCH} AS vpnkit-linux
|
||||
FROM vpnkit-${TARGETOS} AS vpnkit
|
||||
|
||||
FROM --platform=arm64 djs55/vpnkit:${VPNKIT_VERSION} AS vpnkit-arm64
|
||||
# containerutility
|
||||
FROM base AS containerutil-src
|
||||
WORKDIR /usr/src/containerutil
|
||||
RUN git init . && git remote add origin "https://github.com/docker-archive/windows-container-utility.git"
|
||||
ARG CONTAINERUTILITY_VERSION=aa1ba87e99b68e0113bd27ec26c60b88f9d4ccd9
|
||||
RUN git fetch -q --depth 1 origin "${CONTAINERUTILITY_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM scratch AS vpnkit
|
||||
COPY --from=vpnkit-amd64 /vpnkit /build/vpnkit.x86_64
|
||||
COPY --from=vpnkit-arm64 /vpnkit /build/vpnkit.aarch64
|
||||
FROM base AS containerutil-build
|
||||
WORKDIR /usr/src/containerutil
|
||||
ARG TARGETPLATFORM
|
||||
RUN xx-apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
g++ \
|
||||
libc6-dev \
|
||||
pkg-config
|
||||
RUN --mount=from=containerutil-src,src=/usr/src/containerutil,rw \
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=containerutil-build-$TARGETPLATFORM <<EOT
|
||||
set -e
|
||||
CC="$(xx-info)-gcc" CXX="$(xx-info)-g++" make
|
||||
xx-verify --static containerutility.exe
|
||||
mkdir /build
|
||||
mv containerutility.exe /build/
|
||||
EOT
|
||||
|
||||
# TODO: Some of this is only really needed for testing, it would be nice to split this up
|
||||
FROM runtime-dev AS dev-systemd-false
|
||||
ARG DEBIAN_FRONTEND
|
||||
FROM binary-dummy AS containerutil-linux
|
||||
FROM containerutil-build AS containerutil-windows-amd64
|
||||
FROM containerutil-windows-${TARGETARCH} AS containerutil-windows
|
||||
FROM containerutil-${TARGETOS} AS containerutil
|
||||
FROM docker/buildx-bin:${BUILDX_VERSION} as buildx
|
||||
FROM docker/compose-bin:${COMPOSE_VERSION} as compose
|
||||
|
||||
FROM base AS dev-systemd-false
|
||||
COPY --link --from=frozen-images /build/ /docker-frozen-images
|
||||
COPY --link --from=swagger /build/ /usr/local/bin/
|
||||
COPY --link --from=delve /build/ /usr/local/bin/
|
||||
COPY --link --from=tomll /build/ /usr/local/bin/
|
||||
COPY --link --from=gowinres /build/ /usr/local/bin/
|
||||
COPY --link --from=tini /build/ /usr/local/bin/
|
||||
COPY --link --from=registry /build/ /usr/local/bin/
|
||||
COPY --link --from=registry-v2 /build/ /usr/local/bin/
|
||||
|
||||
# Skip the CRIU stage for now, as the opensuse package repository is sometimes
|
||||
# unstable, and we're currently not using it in CI.
|
||||
#
|
||||
# FIXME(thaJeztah): re-enable this stage when https://github.com/moby/moby/issues/38963 is resolved (see https://github.com/moby/moby/pull/38984)
|
||||
# COPY --link --from=criu /build/ /usr/local/bin/
|
||||
COPY --link --from=gotestsum /build/ /usr/local/bin/
|
||||
COPY --link --from=golangci_lint /build/ /usr/local/bin/
|
||||
COPY --link --from=shfmt /build/ /usr/local/bin/
|
||||
COPY --link --from=runc /build/ /usr/local/bin/
|
||||
COPY --link --from=containerd /build/ /usr/local/bin/
|
||||
COPY --link --from=rootlesskit /build/ /usr/local/bin/
|
||||
COPY --link --from=vpnkit / /usr/local/bin/
|
||||
COPY --link --from=containerutil /build/ /usr/local/bin/
|
||||
COPY --link --from=crun /build/ /usr/local/bin/
|
||||
COPY --link hack/dockerfile/etc/docker/ /etc/docker/
|
||||
COPY --link --from=buildx /buildx /usr/local/libexec/docker/cli-plugins/docker-buildx
|
||||
COPY --link --from=compose /docker-compose /usr/libexec/docker/cli-plugins/docker-compose
|
||||
|
||||
ENV PATH=/usr/local/cli:$PATH
|
||||
ENV TEST_CLIENT_BINARY=/usr/local/cli-integration/docker
|
||||
ENV CONTAINERD_ADDRESS=/run/docker/containerd/containerd.sock
|
||||
ENV CONTAINERD_NAMESPACE=moby
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
VOLUME /var/lib/docker
|
||||
VOLUME /home/unprivilegeduser/.local/share/docker
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
FROM dev-systemd-false AS dev-systemd-true
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-dev-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
dbus \
|
||||
dbus-user-session \
|
||||
systemd \
|
||||
systemd-sysv
|
||||
ENTRYPOINT ["hack/dind-systemd"]
|
||||
|
||||
FROM dev-systemd-${SYSTEMD} AS dev-base
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser \
|
||||
&& mkdir -p /home/unprivilegeduser/.local/share/docker \
|
||||
|
@ -309,6 +515,9 @@ RUN ln -sfv /go/src/github.com/docker/docker/.bashrc ~/.bashrc
|
|||
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
|
||||
# Set dev environment as safe git directory to prevent "dubious ownership" errors
|
||||
# when bind-mounting the source into the dev-container. See https://github.com/moby/moby/pull/44930
|
||||
RUN git config --global --add safe.directory $GOPATH/src/github.com/docker/docker
|
||||
# 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 --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
||||
|
@ -329,10 +538,8 @@ RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
|||
net-tools \
|
||||
patch \
|
||||
pigz \
|
||||
python3-pip \
|
||||
python3-setuptools \
|
||||
python3-wheel \
|
||||
sudo \
|
||||
systemd-journal-remote \
|
||||
thin-provisioning-tools \
|
||||
uidmap \
|
||||
vim \
|
||||
|
@ -341,115 +548,124 @@ RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
|||
xz-utils \
|
||||
zip \
|
||||
zstd
|
||||
|
||||
|
||||
# Switch to use iptables instead of nftables (to match the CI hosts)
|
||||
# TODO use some kind of runtime auto-detection instead if/when nftables is supported (https://github.com/moby/moby/issues/26824)
|
||||
RUN update-alternatives --set iptables /usr/sbin/iptables-legacy || true \
|
||||
&& update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy || true \
|
||||
&& update-alternatives --set arptables /usr/sbin/arptables-legacy || true
|
||||
|
||||
RUN pip3 install yamllint==1.26.1
|
||||
|
||||
COPY --from=dockercli /build/ /usr/local/cli
|
||||
COPY --from=frozen-images /build/ /docker-frozen-images
|
||||
COPY --from=swagger /build/ /usr/local/bin/
|
||||
COPY --from=delve /build/ /usr/local/bin/
|
||||
COPY --from=tomll /build/ /usr/local/bin/
|
||||
COPY --from=gowinres /build/ /usr/local/bin/
|
||||
COPY --from=tini /build/ /usr/local/bin/
|
||||
COPY --from=registry /build/ /usr/local/bin/
|
||||
COPY --from=criu /build/ /usr/local/bin/
|
||||
COPY --from=gotestsum /build/ /usr/local/bin/
|
||||
COPY --from=golangci_lint /build/ /usr/local/bin/
|
||||
COPY --from=shfmt /build/ /usr/local/bin/
|
||||
COPY --from=runc /build/ /usr/local/bin/
|
||||
COPY --from=containerd /build/ /usr/local/bin/
|
||||
COPY --from=rootlesskit /build/ /usr/local/bin/
|
||||
COPY --from=vpnkit /build/ /usr/local/bin/
|
||||
COPY --from=crun /build/ /usr/local/bin/
|
||||
COPY hack/dockerfile/etc/docker/ /etc/docker/
|
||||
ENV PATH=/usr/local/cli:$PATH
|
||||
ARG DOCKER_BUILDTAGS
|
||||
ENV DOCKER_BUILDTAGS="${DOCKER_BUILDTAGS}"
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
VOLUME /var/lib/docker
|
||||
VOLUME /home/unprivilegeduser/.local/share/docker
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
FROM dev-systemd-false AS dev-systemd-true
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-dev-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
dbus \
|
||||
dbus-user-session \
|
||||
systemd \
|
||||
systemd-sysv
|
||||
RUN mkdir -p hack \
|
||||
&& curl -o hack/dind-systemd https://raw.githubusercontent.com/AkihiroSuda/containerized-systemd/b70bac0daeea120456764248164c21684ade7d0d/docker-entrypoint.sh \
|
||||
&& chmod +x hack/dind-systemd
|
||||
ENTRYPOINT ["hack/dind-systemd"]
|
||||
apt-get update && apt-get install --no-install-recommends -y \
|
||||
gcc \
|
||||
pkg-config \
|
||||
dpkg-dev \
|
||||
libapparmor-dev \
|
||||
libseccomp-dev \
|
||||
libsecret-1-dev \
|
||||
libsystemd-dev \
|
||||
libudev-dev \
|
||||
yamllint
|
||||
COPY --link --from=dockercli /build/ /usr/local/cli
|
||||
COPY --link --from=dockercli-integration /build/ /usr/local/cli-integration
|
||||
|
||||
FROM dev-systemd-${SYSTEMD} AS dev
|
||||
|
||||
FROM runtime-dev AS binary-base
|
||||
ARG DOCKER_GITCOMMIT=HEAD
|
||||
ENV DOCKER_GITCOMMIT=${DOCKER_GITCOMMIT}
|
||||
ARG VERSION
|
||||
ENV VERSION=${VERSION}
|
||||
ARG PLATFORM
|
||||
ENV PLATFORM=${PLATFORM}
|
||||
ARG PRODUCT
|
||||
ENV PRODUCT=${PRODUCT}
|
||||
ARG DEFAULT_PRODUCT_LICENSE
|
||||
ENV DEFAULT_PRODUCT_LICENSE=${DEFAULT_PRODUCT_LICENSE}
|
||||
ARG PACKAGER_NAME
|
||||
ENV PACKAGER_NAME=${PACKAGER_NAME}
|
||||
ARG DOCKER_BUILDTAGS
|
||||
ENV DOCKER_BUILDTAGS="${DOCKER_BUILDTAGS}"
|
||||
ENV PREFIX=/build
|
||||
# TODO: This is here because hack/make.sh binary copies these extras binaries
|
||||
# from $PATH into the bundles dir.
|
||||
# It would be nice to handle this in a different way.
|
||||
COPY --from=tini /build/ /usr/local/bin/
|
||||
COPY --from=runc /build/ /usr/local/bin/
|
||||
COPY --from=containerd /build/ /usr/local/bin/
|
||||
COPY --from=rootlesskit /build/ /usr/local/bin/
|
||||
COPY --from=vpnkit /build/ /usr/local/bin/
|
||||
COPY --from=gowinres /build/ /usr/local/bin/
|
||||
FROM base AS build
|
||||
COPY --from=gowinres /build/ /usr/local/bin/
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
|
||||
FROM binary-base AS build-binary
|
||||
RUN --mount=type=cache,target=/root/.cache \
|
||||
--mount=type=bind,target=.,ro \
|
||||
ENV GO111MODULE=off
|
||||
ENV CGO_ENABLED=1
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-build-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-build-aptcache,target=/var/cache/apt \
|
||||
apt-get update && apt-get install --no-install-recommends -y \
|
||||
clang \
|
||||
lld \
|
||||
llvm
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=type=cache,sharing=locked,id=moby-build-aptlib,target=/var/lib/apt \
|
||||
--mount=type=cache,sharing=locked,id=moby-build-aptcache,target=/var/cache/apt \
|
||||
xx-apt-get install --no-install-recommends -y \
|
||||
dpkg-dev \
|
||||
gcc \
|
||||
libapparmor-dev \
|
||||
libc6-dev \
|
||||
libseccomp-dev \
|
||||
libsecret-1-dev \
|
||||
libsystemd-dev \
|
||||
libudev-dev \
|
||||
pkg-config
|
||||
ARG DOCKER_BUILDTAGS
|
||||
ARG DOCKER_DEBUG
|
||||
ARG DOCKER_GITCOMMIT=HEAD
|
||||
ARG DOCKER_LDFLAGS
|
||||
ARG DOCKER_STATIC
|
||||
ARG VERSION
|
||||
ARG PLATFORM
|
||||
ARG PRODUCT
|
||||
ARG DEFAULT_PRODUCT_LICENSE
|
||||
ARG PACKAGER_NAME
|
||||
# PREFIX overrides DEST dir in make.sh script otherwise it fails because of
|
||||
# read only mount in current work dir
|
||||
ENV PREFIX=/tmp
|
||||
RUN <<EOT
|
||||
# in bullseye arm64 target does not link with lld so configure it to use ld instead
|
||||
if [ "$(xx-info arch)" = "arm64" ]; then
|
||||
XX_CC_PREFER_LINKER=ld xx-clang --setup-target-triple
|
||||
fi
|
||||
EOT
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=tmpfs,target=cli/winresources/dockerd \
|
||||
--mount=type=tmpfs,target=cli/winresources/docker-proxy \
|
||||
hack/make.sh binary
|
||||
|
||||
FROM binary-base AS build-dynbinary
|
||||
RUN --mount=type=cache,target=/root/.cache \
|
||||
--mount=type=bind,target=.,ro \
|
||||
--mount=type=tmpfs,target=cli/winresources/dockerd \
|
||||
--mount=type=tmpfs,target=cli/winresources/docker-proxy \
|
||||
hack/make.sh dynbinary
|
||||
|
||||
FROM binary-base AS build-cross
|
||||
ARG DOCKER_CROSSPLATFORMS
|
||||
RUN --mount=type=cache,target=/root/.cache \
|
||||
--mount=type=bind,target=.,ro \
|
||||
--mount=type=tmpfs,target=cli/winresources/dockerd \
|
||||
--mount=type=tmpfs,target=cli/winresources/docker-proxy \
|
||||
hack/make.sh cross
|
||||
--mount=type=cache,target=/root/.cache/go-build,id=moby-build-$TARGETPLATFORM <<EOT
|
||||
set -e
|
||||
target=$([ "$DOCKER_STATIC" = "1" ] && echo "binary" || echo "dynbinary")
|
||||
xx-go --wrap
|
||||
PKG_CONFIG=$(xx-go env PKG_CONFIG) ./hack/make.sh $target
|
||||
xx-verify $([ "$DOCKER_STATIC" = "1" ] && echo "--static") /tmp/bundles/${target}-daemon/dockerd$([ "$(xx-info os)" = "windows" ] && echo ".exe")
|
||||
xx-verify $([ "$DOCKER_STATIC" = "1" ] && echo "--static") /tmp/bundles/${target}-daemon/docker-proxy$([ "$(xx-info os)" = "windows" ] && echo ".exe")
|
||||
mkdir /build
|
||||
mv /tmp/bundles/${target}-daemon/* /build/
|
||||
EOT
|
||||
|
||||
# usage:
|
||||
# > docker buildx bake binary
|
||||
# > DOCKER_STATIC=0 docker buildx bake binary
|
||||
# or
|
||||
# > make binary
|
||||
# > make dynbinary
|
||||
FROM scratch AS binary
|
||||
COPY --from=build-binary /build/bundles/ /
|
||||
COPY --from=build /build/ /
|
||||
|
||||
FROM scratch AS dynbinary
|
||||
COPY --from=build-dynbinary /build/bundles/ /
|
||||
# usage:
|
||||
# > docker buildx bake all
|
||||
FROM scratch AS all
|
||||
COPY --link --from=tini /build/ /
|
||||
COPY --link --from=runc /build/ /
|
||||
COPY --link --from=containerd /build/ /
|
||||
COPY --link --from=rootlesskit /build/ /
|
||||
COPY --link --from=containerutil /build/ /
|
||||
COPY --link --from=vpnkit / /
|
||||
COPY --link --from=build /build /
|
||||
|
||||
FROM scratch AS cross
|
||||
COPY --from=build-cross /build/bundles/ /
|
||||
# smoke tests
|
||||
# usage:
|
||||
# > docker buildx bake binary-smoketest
|
||||
FROM --platform=$TARGETPLATFORM base AS smoketest
|
||||
WORKDIR /usr/local/bin
|
||||
COPY --from=build /build .
|
||||
RUN <<EOT
|
||||
set -ex
|
||||
file dockerd
|
||||
dockerd --version
|
||||
file docker-proxy
|
||||
docker-proxy --version
|
||||
EOT
|
||||
|
||||
FROM dev AS final
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
# devcontainer is a stage used by .devcontainer/devcontainer.json
|
||||
FROM dev-base AS devcontainer
|
||||
COPY --link . .
|
||||
COPY --link --from=gopls /build/ /usr/local/bin/
|
||||
|
||||
# usage:
|
||||
# > make shell
|
||||
# > SYSTEMD=true make shell
|
||||
FROM dev-base AS dev
|
||||
COPY --link . .
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
ARG GO_VERSION=1.18.3
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine AS base
|
||||
ENV GO111MODULE=off
|
||||
RUN apk --no-cache add \
|
||||
bash \
|
||||
btrfs-progs-dev \
|
||||
build-base \
|
||||
curl \
|
||||
lvm2-dev \
|
||||
jq
|
||||
|
||||
RUN mkdir -p /build/
|
||||
RUN mkdir -p /go/src/github.com/docker/docker/
|
||||
WORKDIR /go/src/github.com/docker/docker/
|
||||
|
||||
FROM base AS frozen-images
|
||||
# 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 \
|
||||
busybox:latest@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209 \
|
||||
busybox:latest@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209 \
|
||||
debian:bullseye-slim@sha256:dacf278785a4daa9de07596ec739dbc07131e189942772210709c5c0777e8437 \
|
||||
hello-world:latest@sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9 \
|
||||
arm32v7/hello-world:latest@sha256:50b8560ad574c779908da71f7ce370c0a2471c098d44d1c8f6b513c5a55eeeb1
|
||||
# See also frozenImages in "testutil/environment/protect.go" (which needs to be updated when adding images to this list)
|
||||
|
||||
FROM base AS dockercli
|
||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||
COPY hack/dockerfile/install/dockercli.installer ./
|
||||
RUN PREFIX=/build ./install.sh dockercli
|
||||
|
||||
# TestDockerCLIBuildSuite dependency
|
||||
FROM base AS contrib
|
||||
COPY contrib/syscall-test /build/syscall-test
|
||||
COPY contrib/httpserver/Dockerfile /build/httpserver/Dockerfile
|
||||
COPY contrib/httpserver contrib/httpserver
|
||||
RUN CGO_ENABLED=0 go build -buildmode=pie -o /build/httpserver/httpserver github.com/docker/docker/contrib/httpserver
|
||||
|
||||
# Build the integration tests and copy the resulting binaries to /build/tests
|
||||
FROM base AS builder
|
||||
|
||||
# Set tag and add sources
|
||||
COPY . .
|
||||
# Copy test sources tests that use assert can print errors
|
||||
RUN mkdir -p /build${PWD} && find integration integration-cli -name \*_test.go -exec cp --parents '{}' /build${PWD} \;
|
||||
# Build and install test binaries
|
||||
ARG DOCKER_GITCOMMIT=undefined
|
||||
RUN hack/make.sh build-integration-test-binary
|
||||
RUN mkdir -p /build/tests && find . -name test.main -exec cp --parents '{}' /build/tests \;
|
||||
|
||||
## Generate testing image
|
||||
FROM alpine:3.10 as runner
|
||||
|
||||
ENV DOCKER_REMOTE_DAEMON=1
|
||||
ENV DOCKER_INTEGRATION_DAEMON_DEST=/
|
||||
ENTRYPOINT ["/scripts/run.sh"]
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN addgroup docker && adduser -D -G docker unprivilegeduser -s /bin/ash
|
||||
|
||||
# GNU tar is used for generating the emptyfs image
|
||||
RUN apk --no-cache add \
|
||||
bash \
|
||||
ca-certificates \
|
||||
g++ \
|
||||
git \
|
||||
inetutils-ping \
|
||||
iptables \
|
||||
libcap2-bin \
|
||||
pigz \
|
||||
tar \
|
||||
xz
|
||||
|
||||
COPY hack/test/e2e-run.sh /scripts/run.sh
|
||||
COPY hack/make/.ensure-emptyfs /scripts/ensure-emptyfs.sh
|
||||
|
||||
COPY integration/testdata /tests/integration/testdata
|
||||
COPY integration/build/testdata /tests/integration/build/testdata
|
||||
COPY integration-cli/fixtures /tests/integration-cli/fixtures
|
||||
|
||||
COPY --from=frozen-images /build/ /docker-frozen-images
|
||||
COPY --from=dockercli /build/ /usr/bin/
|
||||
COPY --from=contrib /build/ /tests/contrib/
|
||||
COPY --from=builder /build/ /
|
|
@ -5,17 +5,14 @@
|
|||
|
||||
# This represents the bare minimum required to build and test Docker.
|
||||
|
||||
ARG GO_VERSION=1.18.3
|
||||
ARG GO_VERSION=1.21.9
|
||||
|
||||
ARG BASE_DEBIAN_DISTRO="bullseye"
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
|
||||
FROM ${GOLANG_IMAGE}
|
||||
ENV GO111MODULE=off
|
||||
|
||||
# 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
|
||||
ENV GOTOOLCHAIN=local
|
||||
|
||||
# Compile and runtime deps
|
||||
# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#build-dependencies
|
||||
|
@ -24,11 +21,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
build-essential \
|
||||
curl \
|
||||
cmake \
|
||||
gcc \
|
||||
git \
|
||||
libapparmor-dev \
|
||||
libbtrfs-dev \
|
||||
libdevmapper-dev \
|
||||
libseccomp-dev \
|
||||
ca-certificates \
|
||||
e2fsprogs \
|
||||
|
|
|
@ -154,21 +154,17 @@
|
|||
|
||||
# The number of build steps below are explicitly minimised to improve performance.
|
||||
|
||||
# Extremely important - do not change the following line to reference a "specific" image,
|
||||
# such as `mcr.microsoft.com/windows/servercore:ltsc2019`. If using this Dockerfile in process
|
||||
# isolated containers, the kernel of the host must match the container image, and hence
|
||||
# would fail between Windows Server 2016 (aka RS1) and Windows Server 2019 (aka RS5).
|
||||
# It is expected that the image `microsoft/windowsservercore:latest` is present, and matches
|
||||
# the hosts kernel version before doing a build.
|
||||
FROM microsoft/windowsservercore
|
||||
ARG WINDOWS_BASE_IMAGE=mcr.microsoft.com/windows/servercore
|
||||
ARG WINDOWS_BASE_IMAGE_TAG=ltsc2022
|
||||
FROM ${WINDOWS_BASE_IMAGE}:${WINDOWS_BASE_IMAGE_TAG}
|
||||
|
||||
# Use PowerShell as the default shell
|
||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||
|
||||
ARG GO_VERSION=1.18.3
|
||||
ARG CONTAINERD_VERSION=v1.6.6
|
||||
ARG GOTESTSUM_VERSION=v1.8.1
|
||||
ARG GOWINRES_VERSION=v0.2.3
|
||||
ARG GO_VERSION=1.21.9
|
||||
ARG GOTESTSUM_VERSION=v1.8.2
|
||||
ARG GOWINRES_VERSION=v0.3.1
|
||||
ARG CONTAINERD_VERSION=v1.7.15
|
||||
|
||||
# Environment variable notes:
|
||||
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
|
||||
|
@ -179,6 +175,7 @@ ENV GO_VERSION=${GO_VERSION} `
|
|||
GIT_VERSION=2.11.1 `
|
||||
GOPATH=C:\gopath `
|
||||
GO111MODULE=off `
|
||||
GOTOOLCHAIN=local `
|
||||
FROM_DOCKERFILE=1 `
|
||||
GOTESTSUM_VERSION=${GOTESTSUM_VERSION} `
|
||||
GOWINRES_VERSION=${GOWINRES_VERSION}
|
||||
|
@ -223,8 +220,8 @@ RUN `
|
|||
Download-File $location C:\gitsetup.zip; `
|
||||
`
|
||||
Write-Host INFO: Downloading go...; `
|
||||
$dlGoVersion=$Env:GO_VERSION -replace '\.0$',''; `
|
||||
Download-File "https://golang.org/dl/go${dlGoVersion}.windows-amd64.zip" C:\go.zip; `
|
||||
$dlGoVersion=$Env:GO_VERSION; `
|
||||
Download-File "https://go.dev/dl/go${dlGoVersion}.windows-amd64.zip" C:\go.zip; `
|
||||
`
|
||||
Write-Host INFO: Downloading compiler 1 of 3...; `
|
||||
Download-File https://raw.githubusercontent.com/moby/docker-tdmgcc/master/gcc.zip C:\gcc.zip; `
|
||||
|
|
911
Jenkinsfile
vendored
911
Jenkinsfile
vendored
|
@ -8,21 +8,13 @@ pipeline {
|
|||
timestamps()
|
||||
}
|
||||
parameters {
|
||||
booleanParam(name: 'unit_validate', defaultValue: true, description: 'amd64 (x86_64) unit tests and vendor check')
|
||||
booleanParam(name: 'validate_force', defaultValue: false, description: 'force validation steps to be run, even if no changes were detected')
|
||||
booleanParam(name: 'amd64', defaultValue: true, description: 'amd64 (x86_64) Build/Test')
|
||||
booleanParam(name: 'rootless', defaultValue: true, description: 'amd64 (x86_64) Build/Test (Rootless mode)')
|
||||
booleanParam(name: 'cgroup2', defaultValue: true, description: 'amd64 (x86_64) Build/Test (cgroup v2)')
|
||||
booleanParam(name: 'arm64', defaultValue: true, description: 'ARM (arm64) Build/Test')
|
||||
booleanParam(name: 's390x', defaultValue: false, description: 'IBM Z (s390x) Build/Test')
|
||||
booleanParam(name: 'ppc64le', defaultValue: false, description: 'PowerPC (ppc64le) Build/Test')
|
||||
booleanParam(name: 'dco', defaultValue: true, description: 'Run the DCO check')
|
||||
}
|
||||
environment {
|
||||
DOCKER_BUILDKIT = '1'
|
||||
DOCKER_EXPERIMENTAL = '1'
|
||||
DOCKER_GRAPHDRIVER = 'overlay2'
|
||||
APT_MIRROR = 'cdn-fastly.deb.debian.org'
|
||||
CHECK_CONFIG_COMMIT = '33a3680e08d1007e72c3b3f1454f823d8e9948ee'
|
||||
TESTDEBUG = '0'
|
||||
TIMEOUT = '120m'
|
||||
|
@ -44,7 +36,7 @@ pipeline {
|
|||
beforeAgent true
|
||||
expression { params.dco }
|
||||
}
|
||||
agent { label 'amd64 && ubuntu-1804 && overlay2' }
|
||||
agent { label 'arm64 && ubuntu-2004' }
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm \
|
||||
|
@ -57,904 +49,6 @@ pipeline {
|
|||
}
|
||||
stage('Build') {
|
||||
parallel {
|
||||
stage('unit-validate') {
|
||||
when {
|
||||
beforeAgent true
|
||||
expression { params.unit_validate }
|
||||
}
|
||||
agent { label 'amd64 && ubuntu-1804 && overlay2' }
|
||||
environment {
|
||||
// On master ("non-pull-request"), force running some validation checks (vendor, swagger),
|
||||
// even if no files were changed. This allows catching problems caused by pull-requests
|
||||
// that were merged out-of-sequence.
|
||||
TEST_FORCE_VALIDATE = sh returnStdout: true, script: 'if [ "${BRANCH_NAME%%-*}" != "PR" ] || [ "${CHANGE_TARGET:-master}" != "master" ] || [ "${validate_force}" = "true" ]; then echo "1"; fi'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh 'docker build --force-rm --build-arg APT_MIRROR --build-arg CROSS=true -t docker:${GIT_COMMIT} .'
|
||||
}
|
||||
}
|
||||
stage("Validate") {
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
-v "$WORKSPACE/.git:/go/src/github.com/docker/docker/.git" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TEST_FORCE_VALIDATE \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/validate/default
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Docker-py") {
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-docker-py
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/test-docker-py/junit-report.xml', allowEmptyResults: true
|
||||
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo 'Chowning /workspace to jenkins user'
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=docker-py
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
tar -czf ${bundleName}-bundles.tar.gz bundles/test-docker-py/*.xml bundles/test-docker-py/*.log
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("Static") {
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh binary
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Cross") {
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh cross
|
||||
'''
|
||||
}
|
||||
}
|
||||
// needs to be last stage that calls make.sh for the junit report to work
|
||||
stage("Unit tests") {
|
||||
steps {
|
||||
sh '''
|
||||
sudo modprobe ip6table_filter
|
||||
'''
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/test/unit
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/junit-report*.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("Validate vendor") {
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/.git:/go/src/github.com/docker/docker/.git" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TEST_FORCE_VALIDATE \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/validate/vendor
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo 'Ensuring container killed.'
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo 'Chowning /workspace to jenkins user'
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=unit
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
tar -czvf ${bundleName}-bundles.tar.gz bundles/junit-report*.xml bundles/go-test-report*.json bundles/profile*.out
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('amd64') {
|
||||
when {
|
||||
beforeAgent true
|
||||
expression { params.amd64 }
|
||||
}
|
||||
agent { label 'amd64 && ubuntu-1804 && overlay2' }
|
||||
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
# todo: include ip_vs in base image
|
||||
sudo modprobe ip_vs
|
||||
|
||||
docker build --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Run tests") {
|
||||
steps {
|
||||
sh '''#!/bin/bash
|
||||
# bash is needed so 'jobs -p' works properly
|
||||
# it also accepts setting inline envvars for functions without explicitly exporting
|
||||
set -x
|
||||
|
||||
run_tests() {
|
||||
[ -n "$TESTDEBUG" ] && rm= || rm=--rm;
|
||||
docker run $rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles/${TEST_INTEGRATION_DEST}:/go/src/github.com/docker/docker/bundles" \
|
||||
-v "$WORKSPACE/bundles/dynbinary-daemon:/go/src/github.com/docker/docker/bundles/dynbinary-daemon" \
|
||||
-v "$WORKSPACE/.git:/go/src/github.com/docker/docker/.git" \
|
||||
--name "$CONTAINER_NAME" \
|
||||
-e KEEPBUNDLE=1 \
|
||||
-e TESTDEBUG \
|
||||
-e TESTFLAGS \
|
||||
-e TEST_SKIP_INTEGRATION \
|
||||
-e TEST_SKIP_INTEGRATION_CLI \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
"$1" \
|
||||
test-integration
|
||||
}
|
||||
|
||||
trap "exit" INT TERM
|
||||
trap 'pids=$(jobs -p); echo "Remaining pids to kill: [$pids]"; [ -z "$pids" ] || kill $pids' EXIT
|
||||
|
||||
CONTAINER_NAME=docker-pr$BUILD_NUMBER
|
||||
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
-v "$WORKSPACE/.git:/go/src/github.com/docker/docker/.git" \
|
||||
--name ${CONTAINER_NAME}-build \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary
|
||||
|
||||
# flaky + integration
|
||||
TEST_INTEGRATION_DEST=1 CONTAINER_NAME=${CONTAINER_NAME}-1 TEST_SKIP_INTEGRATION_CLI=1 run_tests test-integration-flaky &
|
||||
|
||||
# integration-cli first set
|
||||
TEST_INTEGRATION_DEST=2 CONTAINER_NAME=${CONTAINER_NAME}-2 TEST_SKIP_INTEGRATION=1 TESTFLAGS="-test.run Test(DockerSuite|DockerNetworkSuite|DockerHubPullSuite|DockerRegistrySuite|DockerSchema1RegistrySuite|DockerRegistryAuthTokenSuite|DockerRegistryAuthHtpasswdSuite)/" run_tests &
|
||||
|
||||
# integration-cli second set
|
||||
TEST_INTEGRATION_DEST=3 CONTAINER_NAME=${CONTAINER_NAME}-3 TEST_SKIP_INTEGRATION=1 TESTFLAGS="-test.run Test(DockerSwarmSuite|DockerDaemonSuite|DockerExternalVolumeSuite)/" run_tests &
|
||||
|
||||
c=0
|
||||
for job in $(jobs -p); do
|
||||
wait ${job} || c=$?
|
||||
done
|
||||
exit $c
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
cids=$(docker ps -aq -f name=docker-pr${BUILD_NUMBER}-*)
|
||||
[ -n "$cids" ] && docker rm -vf $cids || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=amd64
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('rootless') {
|
||||
when {
|
||||
beforeAgent true
|
||||
expression { params.rootless }
|
||||
}
|
||||
agent { label 'amd64 && ubuntu-1804 && overlay2' }
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
docker build --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Integration tests") {
|
||||
environment {
|
||||
DOCKER_ROOTLESS = '1'
|
||||
TEST_SKIP_INTEGRATION_CLI = '1'
|
||||
}
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_ROOTLESS \
|
||||
-e TEST_SKIP_INTEGRATION_CLI \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-integration
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=amd64-rootless
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('cgroup2') {
|
||||
when {
|
||||
beforeAgent true
|
||||
expression { params.cgroup2 }
|
||||
}
|
||||
agent { label 'amd64 && ubuntu-2004 && cgroup2' }
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
docker build --force-rm --build-arg APT_MIRROR --build-arg SYSTEMD=true -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Integration tests") {
|
||||
environment {
|
||||
DOCKER_SYSTEMD = '1' // recommended cgroup driver for v2
|
||||
TEST_SKIP_INTEGRATION_CLI = '1' // CLI tests do not support v2
|
||||
}
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_SYSTEMD \
|
||||
-e TEST_SKIP_INTEGRATION_CLI \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-integration
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=amd64-cgroup2
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stage('s390x') {
|
||||
when {
|
||||
beforeAgent true
|
||||
// Skip this stage on PRs unless the checkbox is selected
|
||||
anyOf {
|
||||
not { changeRequest() }
|
||||
expression { params.s390x }
|
||||
}
|
||||
}
|
||||
agent { label 's390x-ubuntu-2004' }
|
||||
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
docker build --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Unit tests") {
|
||||
steps {
|
||||
sh '''
|
||||
sudo modprobe ip6table_filter
|
||||
'''
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/test/unit
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/junit-report*.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("Integration tests") {
|
||||
environment { TEST_SKIP_INTEGRATION_CLI = '1' }
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TESTDEBUG \
|
||||
-e TEST_SKIP_INTEGRATION_CLI \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-integration
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=s390x-integration
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('s390x integration-cli') {
|
||||
when {
|
||||
beforeAgent true
|
||||
// Skip this stage on PRs unless the checkbox is selected
|
||||
anyOf {
|
||||
not { changeRequest() }
|
||||
expression { params.s390x }
|
||||
}
|
||||
}
|
||||
agent { label 's390x-ubuntu-2004' }
|
||||
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
docker build --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Integration-cli tests") {
|
||||
environment { TEST_SKIP_INTEGRATION = '1' }
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TEST_SKIP_INTEGRATION \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-integration
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=s390x-integration-cli
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('ppc64le') {
|
||||
when {
|
||||
beforeAgent true
|
||||
// Skip this stage on PRs unless the checkbox is selected
|
||||
anyOf {
|
||||
not { changeRequest() }
|
||||
expression { params.ppc64le }
|
||||
}
|
||||
}
|
||||
agent { label 'ppc64le-ubuntu-1604' }
|
||||
// ppc64le machines run on Docker 18.06, and buildkit has some
|
||||
// bugs on that version. Build and use buildx instead.
|
||||
environment {
|
||||
USE_BUILDX = '1'
|
||||
DOCKER_BUILDKIT = '0'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
make bundles/buildx
|
||||
bundles/buildx build --load --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Unit tests") {
|
||||
steps {
|
||||
sh '''
|
||||
sudo modprobe ip6table_filter
|
||||
'''
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/test/unit
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/junit-report*.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
stage("Integration tests") {
|
||||
environment { TEST_SKIP_INTEGRATION_CLI = '1' }
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TESTDEBUG \
|
||||
-e TEST_SKIP_INTEGRATION_CLI \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-integration
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=ppc64le-integration
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('ppc64le integration-cli') {
|
||||
when {
|
||||
beforeAgent true
|
||||
// Skip this stage on PRs unless the checkbox is selected
|
||||
anyOf {
|
||||
not { changeRequest() }
|
||||
expression { params.ppc64le }
|
||||
}
|
||||
}
|
||||
agent { label 'ppc64le-ubuntu-1604' }
|
||||
// ppc64le machines run on Docker 18.06, and buildkit has some
|
||||
// bugs on that version. Build and use buildx instead.
|
||||
environment {
|
||||
USE_BUILDX = '1'
|
||||
DOCKER_BUILDKIT = '0'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage("Print info") {
|
||||
steps {
|
||||
sh 'docker version'
|
||||
sh 'docker info'
|
||||
sh '''
|
||||
echo "check-config.sh version: ${CHECK_CONFIG_COMMIT}"
|
||||
curl -fsSL -o ${WORKSPACE}/check-config.sh "https://raw.githubusercontent.com/moby/moby/${CHECK_CONFIG_COMMIT}/contrib/check-config.sh" \
|
||||
&& bash ${WORKSPACE}/check-config.sh || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh '''
|
||||
make bundles/buildx
|
||||
bundles/buildx build --load --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage("Integration-cli tests") {
|
||||
environment { TEST_SKIP_INTEGRATION = '1' }
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm -t --privileged \
|
||||
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||
--name docker-pr$BUILD_NUMBER \
|
||||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TEST_SKIP_INTEGRATION \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
docker:${GIT_COMMIT} \
|
||||
hack/make.sh \
|
||||
dynbinary \
|
||||
test-integration
|
||||
'''
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit testResults: 'bundles/**/*-report.xml', allowEmptyResults: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
sh '''
|
||||
echo "Ensuring container killed."
|
||||
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||
'''
|
||||
|
||||
sh '''
|
||||
echo "Chowning /workspace to jenkins user"
|
||||
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||
'''
|
||||
|
||||
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE', message: 'Failed to create bundles.tar.gz') {
|
||||
sh '''
|
||||
bundleName=ppc64le-integration-cli
|
||||
echo "Creating ${bundleName}-bundles.tar.gz"
|
||||
# exclude overlay2 directories
|
||||
find bundles -path '*/root/*overlay2' -prune -o -type f \\( -name '*-report.json' -o -name '*.log' -o -name '*.prof' -o -name '*-report.xml' \\) -print | xargs tar -czf ${bundleName}-bundles.tar.gz
|
||||
'''
|
||||
|
||||
archiveArtifacts artifacts: '*-bundles.tar.gz', allowEmptyArchive: true
|
||||
}
|
||||
}
|
||||
cleanup {
|
||||
sh 'make clean'
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('arm64') {
|
||||
when {
|
||||
beforeAgent true
|
||||
|
@ -979,7 +73,7 @@ pipeline {
|
|||
}
|
||||
stage("Build dev image") {
|
||||
steps {
|
||||
sh 'docker build --force-rm --build-arg APT_MIRROR -t docker:${GIT_COMMIT} .'
|
||||
sh 'docker build --force-rm -t docker:${GIT_COMMIT} .'
|
||||
}
|
||||
}
|
||||
stage("Unit tests") {
|
||||
|
@ -1017,6 +111,7 @@ pipeline {
|
|||
-e DOCKER_GITCOMMIT=${GIT_COMMIT} \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e TESTDEBUG \
|
||||
-e TEST_INTEGRATION_USE_SNAPSHOTTER \
|
||||
-e TEST_SKIP_INTEGRATION_CLI \
|
||||
-e TIMEOUT \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
|
|
62
MAINTAINERS
62
MAINTAINERS
|
@ -24,15 +24,21 @@
|
|||
# subsystem maintainers accountable. If ownership is unclear, they are the de facto owners.
|
||||
|
||||
people = [
|
||||
"akerouanton",
|
||||
"akihirosuda",
|
||||
"anusha",
|
||||
"coolljt0725",
|
||||
"corhere",
|
||||
"cpuguy83",
|
||||
"crazy-max",
|
||||
"estesp",
|
||||
"johnstep",
|
||||
"justincormack",
|
||||
"kolyshkin",
|
||||
"laurazard",
|
||||
"mhbauer",
|
||||
"neersighted",
|
||||
"rumpl",
|
||||
"runcom",
|
||||
"samuelkarp",
|
||||
"stevvooe",
|
||||
|
@ -43,6 +49,7 @@
|
|||
"unclejack",
|
||||
"vdemeester",
|
||||
"vieux",
|
||||
"vvoland",
|
||||
"yongtang"
|
||||
]
|
||||
|
||||
|
@ -61,15 +68,15 @@
|
|||
people = [
|
||||
"alexellis",
|
||||
"andrewhsu",
|
||||
"corhere",
|
||||
"bsousaa",
|
||||
"dmcgowan",
|
||||
"fntlnz",
|
||||
"gianarb",
|
||||
"ndeloof",
|
||||
"neersighted",
|
||||
"olljanat",
|
||||
"programmerq",
|
||||
"ripcurld",
|
||||
"rumpl",
|
||||
"robmry",
|
||||
"sam-thibault",
|
||||
"samwhited",
|
||||
"thajeztah"
|
||||
]
|
||||
|
@ -277,6 +284,11 @@
|
|||
Email = "aaron.lehmann@docker.com"
|
||||
GitHub = "aaronlehmann"
|
||||
|
||||
[people.akerouanton]
|
||||
Name = "Albin Kerouanton"
|
||||
Email = "albinker@gmail.com"
|
||||
GitHub = "akerouanton"
|
||||
|
||||
[people.alexellis]
|
||||
Name = "Alex Ellis"
|
||||
Email = "alexellis2@gmail.com"
|
||||
|
@ -306,6 +318,11 @@
|
|||
Name = "Anusha Ragunathan"
|
||||
Email = "anusha@docker.com"
|
||||
GitHub = "anusha-ragunathan"
|
||||
|
||||
[people.bsousaa]
|
||||
Name = "Bruno de Sousa"
|
||||
Email = "bruno.sousa@docker.com"
|
||||
GitHub = "bsousaa"
|
||||
|
||||
[people.calavera]
|
||||
Name = "David Calavera"
|
||||
|
@ -327,6 +344,11 @@
|
|||
Email = "cpuguy83@gmail.com"
|
||||
GitHub = "cpuguy83"
|
||||
|
||||
[people.crazy-max]
|
||||
Name = "Kevin Alvarez"
|
||||
Email = "contact@crazymax.dev"
|
||||
GitHub = "crazy-max"
|
||||
|
||||
[people.crosbymichael]
|
||||
Name = "Michael Crosby"
|
||||
Email = "crosbymichael@gmail.com"
|
||||
|
@ -337,6 +359,11 @@
|
|||
Email = "dnephin@gmail.com"
|
||||
GitHub = "dnephin"
|
||||
|
||||
[people.dmcgowan]
|
||||
Name = "Derek McGowan"
|
||||
Email = "derek@mcgstyle.net"
|
||||
GitHub = "dmcgowan"
|
||||
|
||||
[people.duglin]
|
||||
Name = "Doug Davis"
|
||||
Email = "dug@us.ibm.com"
|
||||
|
@ -397,6 +424,11 @@
|
|||
Email = "kolyshkin@gmail.com"
|
||||
GitHub = "kolyshkin"
|
||||
|
||||
[people.laurazard]
|
||||
Name = "Laura Brehm"
|
||||
Email = "laura.brehm@docker.com"
|
||||
GitHub = "laurazard"
|
||||
|
||||
[people.lk4d4]
|
||||
Name = "Alexander Morozov"
|
||||
Email = "lk4d4@docker.com"
|
||||
|
@ -432,14 +464,9 @@
|
|||
Email = "mrjana@docker.com"
|
||||
GitHub = "mrjana"
|
||||
|
||||
[people.ndeloof]
|
||||
Name = "Nicolas De Loof"
|
||||
Email = "nicolas.deloof@gmail.com"
|
||||
GitHub = "ndeloof"
|
||||
|
||||
[people.neersighted]
|
||||
Name = "Bjorn Neergaard"
|
||||
Email = "bneergaard@mirantis.com"
|
||||
Email = "bjorn@neersighted.com"
|
||||
GitHub = "neersighted"
|
||||
|
||||
[people.olljanat]
|
||||
|
@ -452,6 +479,11 @@
|
|||
Email = "jeff@docker.com"
|
||||
GitHub = "programmerq"
|
||||
|
||||
[people.robmry]
|
||||
Name = "Rob Murray"
|
||||
Email = "rob.murray@docker.com"
|
||||
GitHub = "robmry"
|
||||
|
||||
[people.ripcurld]
|
||||
Name = "Boaz Shuster"
|
||||
Email = "ripcurld.github@gmail.com"
|
||||
|
@ -467,6 +499,11 @@
|
|||
Email = "runcom@redhat.com"
|
||||
GitHub = "runcom"
|
||||
|
||||
[people.sam-thibault]
|
||||
Name = "Sam Thibault"
|
||||
Email = "sam.thibault@docker.com"
|
||||
GitHub = "sam-thibault"
|
||||
|
||||
[people.samuelkarp]
|
||||
Name = "Samuel Karp"
|
||||
Email = "me@samuelkarp.com"
|
||||
|
@ -536,6 +573,11 @@
|
|||
Name = "Vishnu Kannan"
|
||||
Email = "vishnuk@google.com"
|
||||
GitHub = "vishh"
|
||||
|
||||
[people.vvoland]
|
||||
Name = "Paweł Gronowski"
|
||||
Email = "pawel.gronowski@docker.com"
|
||||
GitHub = "vvoland"
|
||||
|
||||
[people.yongtang]
|
||||
Name = "Yong Tang"
|
||||
|
|
144
Makefile
144
Makefile
|
@ -1,31 +1,13 @@
|
|||
.PHONY: all binary dynbinary build cross help install manpages run shell test test-docker-py test-integration test-unit validate win
|
||||
.PHONY: all binary dynbinary build cross help install manpages run shell test test-docker-py test-integration test-unit validate validate-% win
|
||||
|
||||
BUILDX_VERSION ?= v0.8.2
|
||||
|
||||
ifdef USE_BUILDX
|
||||
BUILDX ?= $(shell command -v buildx)
|
||||
BUILDX ?= $(shell command -v docker-buildx)
|
||||
DOCKER_BUILDX_CLI_PLUGIN_PATH ?= ~/.docker/cli-plugins/docker-buildx
|
||||
BUILDX ?= $(shell if [ -x "$(DOCKER_BUILDX_CLI_PLUGIN_PATH)" ]; then echo $(DOCKER_BUILDX_CLI_PLUGIN_PATH); fi)
|
||||
endif
|
||||
|
||||
ifndef USE_BUILDX
|
||||
DOCKER_BUILDKIT := 1
|
||||
export DOCKER_BUILDKIT
|
||||
endif
|
||||
|
||||
BUILDX ?= bundles/buildx
|
||||
DOCKER ?= docker
|
||||
BUILDX ?= $(DOCKER) buildx
|
||||
|
||||
# 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/.*: //'))
|
||||
DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info -f '{{ .Driver }}' 2>&1))
|
||||
export DOCKER_GRAPHDRIVER
|
||||
|
||||
# get OS/Arch of docker engine
|
||||
DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKER_ENGINE_OSARCH}')
|
||||
DOCKERFILE := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKERFILE}')
|
||||
|
||||
DOCKER_GITCOMMIT := $(shell git rev-parse --short HEAD || echo unsupported)
|
||||
DOCKER_GITCOMMIT := $(shell git rev-parse HEAD)
|
||||
export DOCKER_GITCOMMIT
|
||||
|
||||
# allow overriding the repository and branch that validation scripts are running
|
||||
|
@ -34,6 +16,9 @@ export VALIDATE_REPO
|
|||
export VALIDATE_BRANCH
|
||||
export VALIDATE_ORIGIN_BRANCH
|
||||
|
||||
export PAGER
|
||||
export GIT_PAGER
|
||||
|
||||
# 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
|
||||
|
@ -42,11 +27,9 @@ export VALIDATE_ORIGIN_BRANCH
|
|||
# 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
|
||||
# make DOCKER_LDFLAGS="-X github.com/docker/docker/daemon/graphdriver.priority=overlay2,zfs" dynbinary
|
||||
#
|
||||
DOCKER_ENVS := \
|
||||
-e DOCKER_CROSSPLATFORMS \
|
||||
-e BUILD_APT_MIRROR \
|
||||
-e BUILDFLAGS \
|
||||
-e KEEPBUNDLE \
|
||||
-e DOCKER_BUILD_ARGS \
|
||||
|
@ -56,6 +39,10 @@ DOCKER_ENVS := \
|
|||
-e DOCKER_BUILDKIT \
|
||||
-e DOCKER_BASH_COMPLETION_PATH \
|
||||
-e DOCKER_CLI_PATH \
|
||||
-e DOCKERCLI_VERSION \
|
||||
-e DOCKERCLI_REPOSITORY \
|
||||
-e DOCKERCLI_INTEGRATION_VERSION \
|
||||
-e DOCKERCLI_INTEGRATION_REPOSITORY \
|
||||
-e DOCKER_DEBUG \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKER_GITCOMMIT \
|
||||
|
@ -69,10 +56,15 @@ DOCKER_ENVS := \
|
|||
-e DOCKER_USERLANDPROXY \
|
||||
-e DOCKERD_ARGS \
|
||||
-e DELVE_PORT \
|
||||
-e GITHUB_ACTIONS \
|
||||
-e TEST_FORCE_VALIDATE \
|
||||
-e TEST_INTEGRATION_DIR \
|
||||
-e TEST_INTEGRATION_USE_SNAPSHOTTER \
|
||||
-e TEST_INTEGRATION_FAIL_FAST \
|
||||
-e TEST_SKIP_INTEGRATION \
|
||||
-e TEST_SKIP_INTEGRATION_CLI \
|
||||
-e TEST_IGNORE_CGROUP_CHECK \
|
||||
-e TESTCOVERAGE \
|
||||
-e TESTDEBUG \
|
||||
-e TESTDIRS \
|
||||
-e TESTFLAGS \
|
||||
|
@ -87,7 +79,12 @@ DOCKER_ENVS := \
|
|||
-e PLATFORM \
|
||||
-e DEFAULT_PRODUCT_LICENSE \
|
||||
-e PRODUCT \
|
||||
-e PACKAGER_NAME
|
||||
-e PACKAGER_NAME \
|
||||
-e PAGER \
|
||||
-e GIT_PAGER \
|
||||
-e OTEL_EXPORTER_OTLP_ENDPOINT \
|
||||
-e OTEL_EXPORTER_OTLP_PROTOCOL \
|
||||
-e OTEL_SERVICE_NAME
|
||||
# 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`
|
||||
|
@ -118,9 +115,7 @@ DOCKER_IMAGE := docker-dev
|
|||
DOCKER_PORT_FORWARD := $(if $(DOCKER_PORT),-p "$(DOCKER_PORT)",)
|
||||
DELVE_PORT_FORWARD := $(if $(DELVE_PORT),-p "$(DELVE_PORT)",)
|
||||
|
||||
DOCKER_FLAGS := $(DOCKER) run --rm -i --privileged $(DOCKER_CONTAINER_NAME) $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD) $(DELVE_PORT_FORWARD)
|
||||
BUILD_APT_MIRROR := $(if $(DOCKER_BUILD_APT_MIRROR),--build-arg APT_MIRROR=$(DOCKER_BUILD_APT_MIRROR))
|
||||
export BUILD_APT_MIRROR
|
||||
DOCKER_FLAGS := $(DOCKER) run --rm --privileged $(DOCKER_CONTAINER_NAME) $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD) $(DELVE_PORT_FORWARD)
|
||||
|
||||
SWAGGER_DOCS_PORT ?= 9000
|
||||
|
||||
|
@ -137,46 +132,42 @@ ifeq ($(INTERACTIVE), 1)
|
|||
DOCKER_FLAGS += -t
|
||||
endif
|
||||
|
||||
# on GitHub Runners input device is not a TTY but we allocate a pseudo-one,
|
||||
# otherwise keep STDIN open even if not attached if not a GitHub Runner.
|
||||
ifeq ($(GITHUB_ACTIONS),true)
|
||||
DOCKER_FLAGS += -t
|
||||
else
|
||||
DOCKER_FLAGS += -i
|
||||
endif
|
||||
|
||||
DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)"
|
||||
|
||||
DOCKER_BUILD_ARGS += --build-arg=GO_VERSION
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_VERSION
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_REPOSITORY
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_INTEGRATION_VERSION
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_INTEGRATION_REPOSITORY
|
||||
ifdef DOCKER_SYSTEMD
|
||||
DOCKER_BUILD_ARGS += --build-arg=SYSTEMD=true
|
||||
endif
|
||||
|
||||
BUILD_OPTS := ${BUILD_APT_MIRROR} ${DOCKER_BUILD_ARGS} ${DOCKER_BUILD_OPTS} -f "$(DOCKERFILE)"
|
||||
ifdef USE_BUILDX
|
||||
BUILD_OPTS += $(BUILDX_BUILD_EXTRA_OPTS)
|
||||
BUILD_OPTS := ${DOCKER_BUILD_ARGS} ${DOCKER_BUILD_OPTS}
|
||||
BUILD_CMD := $(BUILDX) build
|
||||
else
|
||||
BUILD_CMD := $(DOCKER) build
|
||||
endif
|
||||
|
||||
# This is used for the legacy "build" target and anything still depending on it
|
||||
BUILD_CROSS =
|
||||
ifdef DOCKER_CROSS
|
||||
BUILD_CROSS = --build-arg CROSS=$(DOCKER_CROSS)
|
||||
endif
|
||||
ifdef DOCKER_CROSSPLATFORMS
|
||||
BUILD_CROSS = --build-arg CROSS=true
|
||||
endif
|
||||
|
||||
VERSION_AUTOGEN_ARGS = --build-arg VERSION --build-arg DOCKER_GITCOMMIT --build-arg PRODUCT --build-arg PLATFORM --build-arg DEFAULT_PRODUCT_LICENSE --build-arg PACKAGER_NAME
|
||||
BAKE_CMD := $(BUILDX) bake
|
||||
|
||||
default: binary
|
||||
|
||||
all: build ## validate all checks, build linux binaries, run all tests,\ncross build non-linux binaries, and generate archives
|
||||
$(DOCKER_RUN_DOCKER) bash -c 'hack/validate/default && hack/make.sh'
|
||||
|
||||
binary: buildx ## build statically linked linux binaries
|
||||
$(BUILD_CMD) $(BUILD_OPTS) --output=bundles/ --target=$@ $(VERSION_AUTOGEN_ARGS) .
|
||||
binary: bundles ## build statically linked linux binaries
|
||||
$(BAKE_CMD) binary
|
||||
|
||||
dynbinary: buildx ## build dynamically linked linux binaries
|
||||
$(BUILD_CMD) $(BUILD_OPTS) --output=bundles/ --target=$@ $(VERSION_AUTOGEN_ARGS) .
|
||||
dynbinary: bundles ## build dynamically linked linux binaries
|
||||
$(BAKE_CMD) dynbinary
|
||||
|
||||
cross: BUILD_OPTS += --build-arg CROSS=true --build-arg DOCKER_CROSSPLATFORMS
|
||||
cross: buildx ## cross build the binaries for darwin, freebsd and\nwindows
|
||||
$(BUILD_CMD) $(BUILD_OPTS) --output=bundles/ --target=$@ $(VERSION_AUTOGEN_ARGS) .
|
||||
cross: bundles ## cross build the binaries
|
||||
$(BAKE_CMD) binary-cross
|
||||
|
||||
bundles:
|
||||
mkdir bundles
|
||||
|
@ -199,21 +190,18 @@ run: build ## run the docker daemon in a container
|
|||
|
||||
.PHONY: build
|
||||
ifeq ($(BIND_DIR), .)
|
||||
build: shell_target := --target=dev
|
||||
build: shell_target := --target=dev-base
|
||||
else
|
||||
build: shell_target := --target=final
|
||||
build: shell_target := --target=dev
|
||||
endif
|
||||
ifdef USE_BUILDX
|
||||
build: buildx_load := --load
|
||||
endif
|
||||
build: buildx
|
||||
$(BUILD_CMD) $(BUILD_OPTS) $(shell_target) $(buildx_load) $(BUILD_CROSS) -t "$(DOCKER_IMAGE)" .
|
||||
build: bundles
|
||||
$(BUILD_CMD) $(BUILD_OPTS) $(shell_target) --load -t "$(DOCKER_IMAGE)" .
|
||||
|
||||
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
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-integration test-docker-py
|
||||
|
||||
test-docker-py: build ## run the docker-py tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-docker-py
|
||||
|
@ -237,8 +225,16 @@ test-unit: build ## run the unit tests
|
|||
validate: build ## validate DCO, Seccomp profile generation, gofmt,\n./pkg/ isolation, golint, tests, tomls, go vet and vendor
|
||||
$(DOCKER_RUN_DOCKER) hack/validate/all
|
||||
|
||||
win: build ## cross build the binary for windows
|
||||
$(DOCKER_RUN_DOCKER) DOCKER_CROSSPLATFORMS=windows/amd64 hack/make.sh cross
|
||||
validate-generate-files:
|
||||
$(BUILD_CMD) --target "validate" \
|
||||
--output "type=cacheonly" \
|
||||
--file "./hack/dockerfiles/generate-files.Dockerfile" .
|
||||
|
||||
validate-%: build ## validate specific check
|
||||
$(DOCKER_RUN_DOCKER) hack/validate/$*
|
||||
|
||||
win: bundles ## cross build the binary for windows
|
||||
$(BAKE_CMD) --set *.platform=windows/amd64 binary
|
||||
|
||||
.PHONY: swagger-gen
|
||||
swagger-gen:
|
||||
|
@ -256,13 +252,15 @@ swagger-docs: ## preview the API documentation
|
|||
-p $(SWAGGER_DOCS_PORT):80 \
|
||||
bfirsh/redoc:1.14.0
|
||||
|
||||
.PHONY: buildx
|
||||
ifdef USE_BUILDX
|
||||
ifeq ($(BUILDX), bundles/buildx)
|
||||
buildx: bundles/buildx ## build buildx cli tool
|
||||
endif
|
||||
endif
|
||||
|
||||
bundles/buildx: bundles ## build buildx CLI tool
|
||||
curl -fsSL https://raw.githubusercontent.com/moby/buildkit/70deac12b5857a1aa4da65e90b262368e2f71500/hack/install-buildx | VERSION="$(BUILDX_VERSION)" BINDIR="$(@D)" bash
|
||||
$@ version
|
||||
.PHONY: generate-files
|
||||
generate-files:
|
||||
$(eval $@_TMP_OUT := $(shell mktemp -d -t moby-output.XXXXXXXXXX))
|
||||
@if [ -z "$($@_TMP_OUT)" ]; then \
|
||||
echo "Temp dir is not set"; \
|
||||
exit 1; \
|
||||
fi
|
||||
$(BUILD_CMD) --target "update" \
|
||||
--output "type=local,dest=$($@_TMP_OUT)" \
|
||||
--file "./hack/dockerfiles/generate-files.Dockerfile" .
|
||||
cp -R "$($@_TMP_OUT)"/. .
|
||||
rm -rf "$($@_TMP_OUT)"/*
|
||||
|
|
|
@ -14,7 +14,7 @@ Moby is an open project guided by strong principles, aiming to be modular, flexi
|
|||
It is open to the community to help set its direction.
|
||||
|
||||
- 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.
|
||||
- Batteries included but swappable: Moby includes enough components to build fully featured container systems, 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.
|
||||
|
|
|
@ -37,6 +37,6 @@ There is hopefully enough example material in the file for you to copy a similar
|
|||
|
||||
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.
|
||||
Run `make swagger-docs` and a preview will be running at `http://localhost:9000`. Some of the styling may be incorrect, but you'll be able to ensure that it is generating the correct documentation.
|
||||
|
||||
The production documentation is generated by vendoring `swagger.yaml` into [docker/docker.github.io](https://github.com/docker/docker.github.io).
|
||||
|
|
|
@ -2,8 +2,17 @@ package api // import "github.com/docker/docker/api"
|
|||
|
||||
// Common constants for daemon and client.
|
||||
const (
|
||||
// DefaultVersion of Current REST API
|
||||
DefaultVersion = "1.42"
|
||||
// DefaultVersion of the current REST API.
|
||||
DefaultVersion = "1.45"
|
||||
|
||||
// MinSupportedAPIVersion is the minimum API version that can be supported
|
||||
// by the API server, specified as "major.minor". Note that the daemon
|
||||
// may be configured with a different minimum API version, as returned
|
||||
// in [github.com/docker/docker/api/types.Version.MinAPIVersion].
|
||||
//
|
||||
// API requests for API versions lower than the configured version produce
|
||||
// an error.
|
||||
MinSupportedAPIVersion = "1.24"
|
||||
|
||||
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||
// command to specify that no base image is to be used.
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package api // import "github.com/docker/docker/api"
|
||||
|
||||
// MinVersion represents Minimum REST API version supported
|
||||
const MinVersion = "1.12"
|
|
@ -1,8 +0,0 @@
|
|||
package api // import "github.com/docker/docker/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.
|
||||
// Hence also allowing 1.24 on Windows.
|
||||
const MinVersion string = "1.24"
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
|
@ -21,7 +21,7 @@ import (
|
|||
// ImageComponent provides an interface for working with images
|
||||
type ImageComponent interface {
|
||||
SquashImage(from string, to string) (string, error)
|
||||
TagImageWithReference(image.ID, reference.Named) error
|
||||
TagImage(context.Context, image.ID, reference.Named) error
|
||||
}
|
||||
|
||||
// Builder defines interface for running a build
|
||||
|
@ -54,7 +54,7 @@ func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string
|
|||
options := config.Options
|
||||
useBuildKit := options.Version == types.BuilderBuildKit
|
||||
|
||||
tagger, err := NewTagger(b.imageComponent, config.ProgressWriter.StdoutFormatter, options.Tags)
|
||||
tags, err := sanitizeRepoAndTags(options.Tags)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string
|
|||
return "", nil
|
||||
}
|
||||
|
||||
var imageID = build.ImageID
|
||||
imageID := build.ImageID
|
||||
if options.Squash {
|
||||
if imageID, err = squashBuild(build, b.imageComponent); err != nil {
|
||||
return "", err
|
||||
|
@ -92,8 +92,8 @@ func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string
|
|||
stdout := config.ProgressWriter.StdoutFormatter
|
||||
fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
|
||||
}
|
||||
if imageID != "" {
|
||||
err = tagger.TagImages(image.ID(imageID))
|
||||
if imageID != "" && !useBuildKit {
|
||||
err = tagImages(ctx, b.imageComponent, config.ProgressWriter.StdoutFormatter, image.ID(imageID), tags)
|
||||
}
|
||||
return imageID, err
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOpti
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to prune build cache")
|
||||
}
|
||||
b.eventsService.Log("prune", events.BuilderEventType, events.Actor{
|
||||
b.eventsService.Log(events.ActionPrune, events.BuilderEventType, events.Actor{
|
||||
Attributes: map[string]string{
|
||||
"reclaimed": strconv.FormatInt(buildCacheSize, 10),
|
||||
},
|
||||
|
|
|
@ -1,55 +1,31 @@
|
|||
package build // import "github.com/docker/docker/api/server/backend/build"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/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 {
|
||||
// tagImages creates image tags for the imageID.
|
||||
func tagImages(ctx context.Context, ic ImageComponent, stdout io.Writer, imageID image.ID, repoAndTags []reference.Named) error {
|
||||
for _, rt := range repoAndTags {
|
||||
if err := ic.TagImage(ctx, imageID, rt); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(bt.stdout, "Successfully tagged %s\n", reference.FamiliarString(rt))
|
||||
_, _ = fmt.Fprintln(stdout, "Successfully tagged", 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{})
|
||||
)
|
||||
// to a slice of repoAndTag. It removes duplicates, and validates each name
|
||||
// to not contain a digest.
|
||||
func sanitizeRepoAndTags(names []string) (repoAndTags []reference.Named, err error) {
|
||||
uniqNames := map[string]struct{}{}
|
||||
for _, repo := range names {
|
||||
if repo == "" {
|
||||
continue
|
||||
|
@ -60,14 +36,12 @@ func sanitizeRepoAndTags(names []string) ([]reference.Named, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
if _, ok := ref.(reference.Digested); ok {
|
||||
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)
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httpstatus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/gorilla/mux"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// makeErrorHandler makes an HTTP handler that decodes a Docker error and
|
||||
// returns it in the response.
|
||||
func makeErrorHandler(err error) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
statusCode := httpstatus.FromError(err)
|
||||
vars := mux.Vars(r)
|
||||
if apiVersionSupportsJSONErrors(vars["version"]) {
|
||||
response := &types.ErrorResponse{
|
||||
Message: err.Error(),
|
||||
}
|
||||
_ = httputils.WriteJSON(w, statusCode, response)
|
||||
} else {
|
||||
http.Error(w, status.Convert(err).Message(), statusCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func apiVersionSupportsJSONErrors(version string) bool {
|
||||
const firstAPIVersionWithJSONErrors = "1.23"
|
||||
return version == "" || versions.GreaterThan(version, firstAPIVersionWithJSONErrors)
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
package httpstatus // import "github.com/docker/docker/api/server/httpstatus"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
containerderrors "github.com/containerd/containerd/errdefs"
|
||||
cerrdefs "github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
@ -19,7 +20,7 @@ type causer interface {
|
|||
// FromError retrieves status code from error message.
|
||||
func FromError(err error) int {
|
||||
if err == nil {
|
||||
logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling")
|
||||
log.G(context.TODO()).WithError(err).Error("unexpected HTTP error handling")
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
|
@ -65,10 +66,11 @@ func FromError(err error) int {
|
|||
return FromError(e.Cause())
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
log.G(context.TODO()).WithFields(log.Fields{
|
||||
"module": "api",
|
||||
"error": err,
|
||||
"error_type": fmt.Sprintf("%T", err),
|
||||
}).Debugf("FIXME: Got an API for which error does not match any expected type!!!: %+v", err)
|
||||
}).Debug("FIXME: Got an API for which error does not match any expected type!!!")
|
||||
}
|
||||
|
||||
if statusCode == 0 {
|
||||
|
@ -132,17 +134,17 @@ func statusCodeFromDistributionError(err error) int {
|
|||
// consumed directly (not through gRPC)
|
||||
func statusCodeFromContainerdError(err error) int {
|
||||
switch {
|
||||
case containerderrors.IsInvalidArgument(err):
|
||||
case cerrdefs.IsInvalidArgument(err):
|
||||
return http.StatusBadRequest
|
||||
case containerderrors.IsNotFound(err):
|
||||
case cerrdefs.IsNotFound(err):
|
||||
return http.StatusNotFound
|
||||
case containerderrors.IsAlreadyExists(err):
|
||||
case cerrdefs.IsAlreadyExists(err):
|
||||
return http.StatusConflict
|
||||
case containerderrors.IsFailedPrecondition(err):
|
||||
case cerrdefs.IsFailedPrecondition(err):
|
||||
return http.StatusPreconditionFailed
|
||||
case containerderrors.IsUnavailable(err):
|
||||
case cerrdefs.IsUnavailable(err):
|
||||
return http.StatusServiceUnavailable
|
||||
case containerderrors.IsNotImplemented(err):
|
||||
case cerrdefs.IsNotImplemented(err):
|
||||
return http.StatusNotImplemented
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
|
|
|
@ -12,5 +12,4 @@ import (
|
|||
// container configuration.
|
||||
type ContainerDecoder interface {
|
||||
DecodeConfig(src io.Reader) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error)
|
||||
DecodeHostConfig(src io.Reader) (*container.HostConfig, error)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
)
|
||||
|
||||
// BoolValue transforms a form value in different formats into a boolean type.
|
||||
|
@ -41,6 +44,38 @@ func Int64ValueOrDefault(r *http.Request, field string, def int64) (int64, error
|
|||
return def, nil
|
||||
}
|
||||
|
||||
// RepoTagReference parses form values "repo" and "tag" and returns a valid
|
||||
// reference with repository and tag.
|
||||
// If repo is empty, then a nil reference is returned.
|
||||
// If no tag is given, then the default "latest" tag is set.
|
||||
func RepoTagReference(repo, tag string) (reference.NamedTagged, error) {
|
||||
if repo == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ref, err := reference.ParseNormalizedNamed(repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, isDigested := ref.(reference.Digested); isDigested {
|
||||
return nil, fmt.Errorf("cannot import digest reference")
|
||||
}
|
||||
|
||||
if tag != "" {
|
||||
return reference.WithTag(ref, tag)
|
||||
}
|
||||
|
||||
withDefaultTag := reference.TagNameOnly(ref)
|
||||
|
||||
namedTagged, ok := withDefaultTag.(reference.NamedTagged)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected reference: %q", ref.String())
|
||||
}
|
||||
|
||||
return namedTagged, nil
|
||||
}
|
||||
|
||||
// ArchiveOptions stores archive information for different operations.
|
||||
type ArchiveOptions struct {
|
||||
Name string
|
||||
|
|
|
@ -33,7 +33,7 @@ func TestJsonContentType(t *testing.T) {
|
|||
|
||||
func TestReadJSON(t *testing.T) {
|
||||
t.Run("nil body", func(t *testing.T) {
|
||||
req, err := http.NewRequest("POST", "https://example.com/some/path", nil)
|
||||
req, err := http.NewRequest(http.MethodPost, "https://example.com/some/path", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ func TestReadJSON(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("empty body", func(t *testing.T) {
|
||||
req, err := http.NewRequest("POST", "https://example.com/some/path", strings.NewReader(""))
|
||||
req, err := http.NewRequest(http.MethodPost, "https://example.com/some/path", strings.NewReader(""))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ func TestReadJSON(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("with valid request", func(t *testing.T) {
|
||||
req, err := http.NewRequest("POST", "https://example.com/some/path", strings.NewReader(`{"SomeField":"some value"}`))
|
||||
req, err := http.NewRequest(http.MethodPost, "https://example.com/some/path", strings.NewReader(`{"SomeField":"some value"}`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ func TestReadJSON(t *testing.T) {
|
|||
}
|
||||
})
|
||||
t.Run("with whitespace", func(t *testing.T) {
|
||||
req, err := http.NewRequest("POST", "https://example.com/some/path", strings.NewReader(`
|
||||
req, err := http.NewRequest(http.MethodPost, "https://example.com/some/path", strings.NewReader(`
|
||||
|
||||
{"SomeField":"some value"}
|
||||
|
||||
|
@ -95,7 +95,7 @@ func TestReadJSON(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("with extra content", func(t *testing.T) {
|
||||
req, err := http.NewRequest("POST", "https://example.com/some/path", strings.NewReader(`{"SomeField":"some value"} and more content`))
|
||||
req, err := http.NewRequest(http.MethodPost, "https://example.com/some/path", strings.NewReader(`{"SomeField":"some value"} and more content`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ func TestReadJSON(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("invalid JSON", func(t *testing.T) {
|
||||
req, err := http.NewRequest("POST", "https://example.com/some/path", strings.NewReader(`{invalid json`))
|
||||
req, err := http.NewRequest(http.MethodPost, "https://example.com/some/path", strings.NewReader(`{invalid json`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
"net/url"
|
||||
"sort"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
|
@ -16,7 +16,7 @@ import (
|
|||
|
||||
// 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) {
|
||||
func WriteLogStream(_ context.Context, w io.Writer, msgs <-chan *backend.LogMessage, config *container.LogsOptions, mux bool) {
|
||||
wf := ioutils.NewWriteFlusher(w)
|
||||
defer wf.Close()
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package server // import "github.com/docker/docker/api/server"
|
||||
|
||||
import (
|
||||
"github.com/containerd/log"
|
||||
"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
|
||||
|
@ -16,7 +16,7 @@ func (s *Server) handlerWithGlobalMiddlewares(handler httputils.APIFunc) httputi
|
|||
next = m.WrapHandler(next)
|
||||
}
|
||||
|
||||
if logrus.GetLevel() == logrus.DebugLevel {
|
||||
if log.GetLevel() == log.DebugLevel {
|
||||
next = middleware.DebugRequestMiddleware(next)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ import (
|
|||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
)
|
||||
|
||||
// CORSMiddleware injects CORS headers to each request
|
||||
|
@ -28,9 +29,9 @@ func (c CORSMiddleware) WrapHandler(handler func(ctx context.Context, w http.Res
|
|||
corsHeaders = "*"
|
||||
}
|
||||
|
||||
logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
|
||||
log.G(ctx).Debugf("CORS header is enabled and set to: %s", corsHeaders)
|
||||
w.Header().Add("Access-Control-Allow-Origin", corsHeaders)
|
||||
w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
|
||||
w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, "+registry.AuthHeader)
|
||||
w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
|
|
|
@ -8,15 +8,15 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// DebugRequestMiddleware dumps the request to logger
|
||||
func DebugRequestMiddleware(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 {
|
||||
logrus.Debugf("Calling %s %s", r.Method, r.RequestURI)
|
||||
log.G(ctx).Debugf("Calling %s %s", r.Method, r.RequestURI)
|
||||
|
||||
if r.Method != http.MethodPost {
|
||||
return handler(ctx, w, r, vars)
|
||||
|
@ -44,9 +44,9 @@ func DebugRequestMiddleware(handler func(ctx context.Context, w http.ResponseWri
|
|||
maskSecretKeys(postForm)
|
||||
formStr, errMarshal := json.Marshal(postForm)
|
||||
if errMarshal == nil {
|
||||
logrus.Debugf("form data: %s", string(formStr))
|
||||
log.G(ctx).Debugf("form data: %s", string(formStr))
|
||||
} else {
|
||||
logrus.Debugf("form data: %q", postForm)
|
||||
log.G(ctx).Debugf("form data: %q", postForm)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
)
|
||||
|
@ -13,19 +14,40 @@ import (
|
|||
// VersionMiddleware is a middleware that
|
||||
// validates the client and server versions.
|
||||
type VersionMiddleware struct {
|
||||
serverVersion string
|
||||
defaultVersion string
|
||||
minVersion string
|
||||
serverVersion string
|
||||
|
||||
// defaultAPIVersion is the default API version provided by the API server,
|
||||
// specified as "major.minor". It is usually configured to the latest API
|
||||
// version [github.com/docker/docker/api.DefaultVersion].
|
||||
//
|
||||
// API requests for API versions greater than this version are rejected by
|
||||
// the server and produce a [versionUnsupportedError].
|
||||
defaultAPIVersion string
|
||||
|
||||
// minAPIVersion is the minimum API version provided by the API server,
|
||||
// specified as "major.minor".
|
||||
//
|
||||
// API requests for API versions lower than this version are rejected by
|
||||
// the server and produce a [versionUnsupportedError].
|
||||
minAPIVersion string
|
||||
}
|
||||
|
||||
// NewVersionMiddleware creates a new VersionMiddleware
|
||||
// with the default versions.
|
||||
func NewVersionMiddleware(s, d, m string) VersionMiddleware {
|
||||
return VersionMiddleware{
|
||||
serverVersion: s,
|
||||
defaultVersion: d,
|
||||
minVersion: m,
|
||||
// NewVersionMiddleware creates a VersionMiddleware with the given versions.
|
||||
func NewVersionMiddleware(serverVersion, defaultAPIVersion, minAPIVersion string) (*VersionMiddleware, error) {
|
||||
if versions.LessThan(defaultAPIVersion, api.MinSupportedAPIVersion) || versions.GreaterThan(defaultAPIVersion, api.DefaultVersion) {
|
||||
return nil, fmt.Errorf("invalid default API version (%s): must be between %s and %s", defaultAPIVersion, api.MinSupportedAPIVersion, api.DefaultVersion)
|
||||
}
|
||||
if versions.LessThan(minAPIVersion, api.MinSupportedAPIVersion) || versions.GreaterThan(minAPIVersion, api.DefaultVersion) {
|
||||
return nil, fmt.Errorf("invalid minimum API version (%s): must be between %s and %s", minAPIVersion, api.MinSupportedAPIVersion, api.DefaultVersion)
|
||||
}
|
||||
if versions.GreaterThan(minAPIVersion, defaultAPIVersion) {
|
||||
return nil, fmt.Errorf("invalid API version: the minimum API version (%s) is higher than the default version (%s)", minAPIVersion, defaultAPIVersion)
|
||||
}
|
||||
return &VersionMiddleware{
|
||||
serverVersion: serverVersion,
|
||||
defaultAPIVersion: defaultAPIVersion,
|
||||
minAPIVersion: minAPIVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type versionUnsupportedError struct {
|
||||
|
@ -45,21 +67,20 @@ func (e versionUnsupportedError) InvalidParameter() {}
|
|||
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("API-Version", v.defaultAPIVersion)
|
||||
w.Header().Set("OSType", runtime.GOOS)
|
||||
|
||||
apiVersion := vars["version"]
|
||||
if apiVersion == "" {
|
||||
apiVersion = v.defaultVersion
|
||||
apiVersion = v.defaultAPIVersion
|
||||
}
|
||||
if versions.LessThan(apiVersion, v.minVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, minVersion: v.minVersion}
|
||||
if versions.LessThan(apiVersion, v.minAPIVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, minVersion: v.minAPIVersion}
|
||||
}
|
||||
if versions.GreaterThan(apiVersion, v.defaultVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultVersion}
|
||||
if versions.GreaterThan(apiVersion, v.defaultAPIVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultAPIVersion}
|
||||
}
|
||||
ctx = context.WithValue(ctx, httputils.APIVersionKey{}, apiVersion)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,27 +2,82 @@ package middleware // import "github.com/docker/docker/api/server/middleware"
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestNewVersionMiddlewareValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
doc, defaultVersion, minVersion, expectedErr string
|
||||
}{
|
||||
{
|
||||
doc: "defaults",
|
||||
defaultVersion: api.DefaultVersion,
|
||||
minVersion: api.MinSupportedAPIVersion,
|
||||
},
|
||||
{
|
||||
doc: "invalid default lower than min",
|
||||
defaultVersion: api.MinSupportedAPIVersion,
|
||||
minVersion: api.DefaultVersion,
|
||||
expectedErr: fmt.Sprintf("invalid API version: the minimum API version (%s) is higher than the default version (%s)", api.DefaultVersion, api.MinSupportedAPIVersion),
|
||||
},
|
||||
{
|
||||
doc: "invalid default too low",
|
||||
defaultVersion: "0.1",
|
||||
minVersion: api.MinSupportedAPIVersion,
|
||||
expectedErr: fmt.Sprintf("invalid default API version (0.1): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
|
||||
},
|
||||
{
|
||||
doc: "invalid default too high",
|
||||
defaultVersion: "9999.9999",
|
||||
minVersion: api.DefaultVersion,
|
||||
expectedErr: fmt.Sprintf("invalid default API version (9999.9999): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
|
||||
},
|
||||
{
|
||||
doc: "invalid minimum too low",
|
||||
defaultVersion: api.MinSupportedAPIVersion,
|
||||
minVersion: "0.1",
|
||||
expectedErr: fmt.Sprintf("invalid minimum API version (0.1): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
|
||||
},
|
||||
{
|
||||
doc: "invalid minimum too high",
|
||||
defaultVersion: api.DefaultVersion,
|
||||
minVersion: "9999.9999",
|
||||
expectedErr: fmt.Sprintf("invalid minimum API version (9999.9999): must be between %s and %s", api.MinSupportedAPIVersion, api.DefaultVersion),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
_, err := NewVersionMiddleware("1.2.3", tc.defaultVersion, tc.minVersion)
|
||||
if tc.expectedErr == "" {
|
||||
assert.Check(t, err)
|
||||
} else {
|
||||
assert.Check(t, is.Error(err, tc.expectedErr))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionMiddlewareVersion(t *testing.T) {
|
||||
defaultVersion := "1.10.0"
|
||||
minVersion := "1.2.0"
|
||||
expectedVersion := defaultVersion
|
||||
expectedVersion := "<not set>"
|
||||
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))
|
||||
return nil
|
||||
}
|
||||
|
||||
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
|
||||
m, err := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
|
||||
assert.NilError(t, err)
|
||||
h := m.WrapHandler(handler)
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
|
||||
|
@ -35,19 +90,19 @@ func TestVersionMiddlewareVersion(t *testing.T) {
|
|||
errString string
|
||||
}{
|
||||
{
|
||||
expectedVersion: "1.10.0",
|
||||
expectedVersion: api.DefaultVersion,
|
||||
},
|
||||
{
|
||||
reqVersion: "1.9.0",
|
||||
expectedVersion: "1.9.0",
|
||||
reqVersion: api.MinSupportedAPIVersion,
|
||||
expectedVersion: api.MinSupportedAPIVersion,
|
||||
},
|
||||
{
|
||||
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",
|
||||
errString: fmt.Sprintf("client version 0.1 is too old. Minimum supported API version is %s, please upgrade your client to a newer version", api.MinSupportedAPIVersion),
|
||||
},
|
||||
{
|
||||
reqVersion: "9999.9999",
|
||||
errString: "client version 9999.9999 is too new. Maximum supported API version is 1.10.0",
|
||||
errString: fmt.Sprintf("client version 9999.9999 is too new. Maximum supported API version is %s", api.DefaultVersion),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -71,9 +126,8 @@ func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
|
|||
return nil
|
||||
}
|
||||
|
||||
defaultVersion := "1.10.0"
|
||||
minVersion := "1.2.0"
|
||||
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
|
||||
m, err := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
|
||||
assert.NilError(t, err)
|
||||
h := m.WrapHandler(handler)
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
|
||||
|
@ -81,12 +135,12 @@ func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
|
||||
vars := map[string]string{"version": "0.1"}
|
||||
err := h(ctx, resp, req, vars)
|
||||
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"), "Docker/1.2.3"))
|
||||
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("API-Version"), api.DefaultVersion))
|
||||
assert.Check(t, is.Equal(hdr.Get("OSType"), runtime.GOOS))
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ type Backend interface {
|
|||
|
||||
// Prune build cache
|
||||
PruneCache(context.Context, types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error)
|
||||
|
||||
Cancel(context.Context, string) error
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
package build // import "github.com/docker/docker/api/server/router/build"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
// 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
|
||||
daemon experimentalProvider
|
||||
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, d experimentalProvider) router.Router {
|
||||
r := &buildRouter{
|
||||
backend: b,
|
||||
daemon: d,
|
||||
features: features,
|
||||
backend: b,
|
||||
daemon: d,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
|
@ -37,17 +37,24 @@ func (r *buildRouter) initRoutes() {
|
|||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
// BuilderVersion derives the default docker builder version from the config.
|
||||
//
|
||||
// The default on Linux is version "2" (BuildKit), but the daemon can be
|
||||
// configured to recommend version "1" (classic Builder). Windows does not
|
||||
// yet support BuildKit for native Windows images, and uses "1" (classic builder)
|
||||
// as a default.
|
||||
//
|
||||
// This value is only a recommendation as advertised by the daemon, and 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
|
||||
}
|
||||
// TODO(thaJeztah) move the default to daemon/config
|
||||
if runtime.GOOS == "windows" {
|
||||
return types.BuilderV1
|
||||
}
|
||||
|
||||
bv := types.BuilderBuildKit
|
||||
if v, ok := features["buildkit"]; ok && !v {
|
||||
bv = types.BuilderV1
|
||||
}
|
||||
return bv
|
||||
}
|
||||
|
|
|
@ -14,28 +14,26 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"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/registry"
|
||||
"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"
|
||||
)
|
||||
|
||||
type invalidIsolationError string
|
||||
|
||||
func (e invalidIsolationError) Error() string {
|
||||
return fmt.Sprintf("Unsupported isolation: %q", string(e))
|
||||
type invalidParam struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (e invalidIsolationError) InvalidParameter() {}
|
||||
func (e invalidParam) InvalidParameter() {}
|
||||
|
||||
func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBuildOptions, error) {
|
||||
options := &types.ImageBuildOptions{
|
||||
|
@ -44,6 +42,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
SuppressOutput: httputils.BoolValue(r, "q"),
|
||||
NoCache: httputils.BoolValue(r, "nocache"),
|
||||
ForceRemove: httputils.BoolValue(r, "forcerm"),
|
||||
PullParent: httputils.BoolValue(r, "pull"),
|
||||
MemorySwap: httputils.Int64ValueOrZero(r, "memswap"),
|
||||
Memory: httputils.Int64ValueOrZero(r, "memory"),
|
||||
CPUShares: httputils.Int64ValueOrZero(r, "cpushares"),
|
||||
|
@ -64,20 +63,18 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
}
|
||||
|
||||
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"))
|
||||
// SecurityOpt only supports "credentials-spec" on Windows, and not used on other platforms.
|
||||
return nil, invalidParam{errors.New("security options are not supported on " + runtime.GOOS)}
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if httputils.BoolValue(r, "forcerm") && versions.GreaterThanOrEqualTo(version, "1.12") {
|
||||
if httputils.BoolValue(r, "forcerm") {
|
||||
options.Remove = true
|
||||
} else if r.FormValue("rm") == "" && versions.GreaterThanOrEqualTo(version, "1.12") {
|
||||
} else if r.FormValue("rm") == "" {
|
||||
options.Remove = true
|
||||
} else {
|
||||
options.Remove = httputils.BoolValue(r, "rm")
|
||||
}
|
||||
if httputils.BoolValue(r, "pull") && versions.GreaterThanOrEqualTo(version, "1.16") {
|
||||
options.PullParent = true
|
||||
}
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.GreaterThanOrEqualTo(version, "1.32") {
|
||||
options.Platform = r.FormValue("platform")
|
||||
}
|
||||
|
@ -86,7 +83,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
if outputsJSON != "" {
|
||||
var outputs []types.ImageBuildOutput
|
||||
if err := json.Unmarshal([]byte(outputsJSON), &outputs); err != nil {
|
||||
return nil, err
|
||||
return nil, invalidParam{errors.Wrap(err, "invalid outputs specified")}
|
||||
}
|
||||
options.Outputs = outputs
|
||||
}
|
||||
|
@ -103,14 +100,14 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
if i := r.FormValue("isolation"); i != "" {
|
||||
options.Isolation = container.Isolation(i)
|
||||
if !options.Isolation.IsValid() {
|
||||
return nil, invalidIsolationError(options.Isolation)
|
||||
return nil, invalidParam{errors.Errorf("unsupported isolation: %q", i)}
|
||||
}
|
||||
}
|
||||
|
||||
if ulimitsJSON := r.FormValue("ulimits"); ulimitsJSON != "" {
|
||||
var buildUlimits = []*units.Ulimit{}
|
||||
buildUlimits := []*units.Ulimit{}
|
||||
if err := json.Unmarshal([]byte(ulimitsJSON), &buildUlimits); err != nil {
|
||||
return nil, errors.Wrap(errdefs.InvalidParameter(err), "error reading ulimit settings")
|
||||
return nil, invalidParam{errors.Wrap(err, "error reading ulimit settings")}
|
||||
}
|
||||
options.Ulimits = buildUlimits
|
||||
}
|
||||
|
@ -128,25 +125,25 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||
// so that it can print a warning about "foo" being unused if there is
|
||||
// no "ARG foo" in the Dockerfile.
|
||||
if buildArgsJSON := r.FormValue("buildargs"); buildArgsJSON != "" {
|
||||
var buildArgs = map[string]*string{}
|
||||
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, invalidParam{errors.Wrap(err, "error reading build args")}
|
||||
}
|
||||
options.BuildArgs = buildArgs
|
||||
}
|
||||
|
||||
if labelsJSON := r.FormValue("labels"); labelsJSON != "" {
|
||||
var labels = map[string]string{}
|
||||
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, invalidParam{errors.Wrap(err, "error reading labels")}
|
||||
}
|
||||
options.Labels = labels
|
||||
}
|
||||
|
||||
if cacheFromJSON := r.FormValue("cachefrom"); cacheFromJSON != "" {
|
||||
var cacheFrom = []string{}
|
||||
cacheFrom := []string{}
|
||||
if err := json.Unmarshal([]byte(cacheFromJSON), &cacheFrom); err != nil {
|
||||
return nil, err
|
||||
return nil, invalidParam{errors.Wrap(err, "error reading cache-from")}
|
||||
}
|
||||
options.CacheFrom = cacheFrom
|
||||
}
|
||||
|
@ -169,7 +166,7 @@ func parseVersion(s string) (types.BuilderVersion, error) {
|
|||
case types.BuilderBuildKit:
|
||||
return types.BuilderBuildKit, nil
|
||||
default:
|
||||
return "", errors.Errorf("invalid version %q", s)
|
||||
return "", invalidParam{errors.Errorf("invalid version %q", s)}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,7 +176,7 @@ func (br *buildRouter) postPrune(ctx context.Context, w http.ResponseWriter, r *
|
|||
}
|
||||
fltrs, err := filters.FromJSON(r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not parse filters")
|
||||
return err
|
||||
}
|
||||
ksfv := r.FormValue("keep-storage")
|
||||
if ksfv == "" {
|
||||
|
@ -187,7 +184,7 @@ func (br *buildRouter) postPrune(ctx context.Context, w http.ResponseWriter, r *
|
|||
}
|
||||
ks, err := strconv.Atoi(ksfv)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "keep-storage is in bytes and expects an integer, got %v", ksfv)
|
||||
return invalidParam{errors.Wrapf(err, "keep-storage is in bytes and expects an integer, got %v", ksfv)}
|
||||
}
|
||||
|
||||
opts := types.BuildCachePruneOptions{
|
||||
|
@ -208,7 +205,7 @@ func (br *buildRouter) postCancel(ctx context.Context, w http.ResponseWriter, r
|
|||
|
||||
id := r.FormValue("id")
|
||||
if id == "" {
|
||||
return errors.Errorf("build ID not provided")
|
||||
return invalidParam{errors.New("build ID not provided")}
|
||||
}
|
||||
|
||||
return br.backend.Cancel(ctx, id)
|
||||
|
@ -238,7 +235,6 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
|||
defer func() { _ = output.Close() }()
|
||||
|
||||
errf := func(err error) error {
|
||||
|
||||
if httputils.BoolValue(r, "q") && notVerboseBuffer.Len() > 0 {
|
||||
_, _ = output.Write(notVerboseBuffer.Bytes())
|
||||
}
|
||||
|
@ -250,7 +246,7 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
|||
}
|
||||
_, err = output.Write(streamformatter.FormatError(err))
|
||||
if err != nil {
|
||||
logrus.Warnf("could not write error response: %v", err)
|
||||
log.G(ctx).Warnf("could not write error response: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -262,7 +258,7 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
|||
buildOptions.AuthConfigs = getAuthConfigs(r.Header)
|
||||
|
||||
if buildOptions.Squash && !br.daemon.HasExperimental() {
|
||||
return errdefs.InvalidParameter(errors.New("squash is only supported with experimental mode"))
|
||||
return invalidParam{errors.New("squash is only supported with experimental mode")}
|
||||
}
|
||||
|
||||
out := io.Writer(output)
|
||||
|
@ -296,8 +292,8 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
|||
return nil
|
||||
}
|
||||
|
||||
func getAuthConfigs(header http.Header) map[string]types.AuthConfig {
|
||||
authConfigs := map[string]types.AuthConfig{}
|
||||
func getAuthConfigs(header http.Header) map[string]registry.AuthConfig {
|
||||
authConfigs := map[string]registry.AuthConfig{}
|
||||
authConfigsEncoded := header.Get("X-Registry-Config")
|
||||
|
||||
if authConfigsEncoded == "" {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package checkpoint // import "github.com/docker/docker/api/server/router/checkpoint"
|
||||
|
||||
import "github.com/docker/docker/api/types"
|
||||
import "github.com/docker/docker/api/types/checkpoint"
|
||||
|
||||
// Backend for Checkpoint
|
||||
type Backend interface {
|
||||
CheckpointCreate(container string, config types.CheckpointCreateOptions) error
|
||||
CheckpointDelete(container string, config types.CheckpointDeleteOptions) error
|
||||
CheckpointList(container string, config types.CheckpointListOptions) ([]types.Checkpoint, error)
|
||||
CheckpointCreate(container string, config checkpoint.CreateOptions) error
|
||||
CheckpointDelete(container string, config checkpoint.DeleteOptions) error
|
||||
CheckpointList(container string, config checkpoint.ListOptions) ([]checkpoint.Summary, error)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/checkpoint"
|
||||
)
|
||||
|
||||
func (s *checkpointRouter) postContainerCheckpoint(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -13,7 +13,7 @@ func (s *checkpointRouter) postContainerCheckpoint(ctx context.Context, w http.R
|
|||
return err
|
||||
}
|
||||
|
||||
var options types.CheckpointCreateOptions
|
||||
var options checkpoint.CreateOptions
|
||||
if err := httputils.ReadJSON(r, &options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -32,10 +32,9 @@ func (s *checkpointRouter) getContainerCheckpoints(ctx context.Context, w http.R
|
|||
return err
|
||||
}
|
||||
|
||||
checkpoints, err := s.backend.CheckpointList(vars["name"], types.CheckpointListOptions{
|
||||
checkpoints, err := s.backend.CheckpointList(vars["name"], checkpoint.ListOptions{
|
||||
CheckpointDir: r.Form.Get("dir"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -48,11 +47,10 @@ func (s *checkpointRouter) deleteContainerCheckpoint(ctx context.Context, w http
|
|||
return err
|
||||
}
|
||||
|
||||
err := s.backend.CheckpointDelete(vars["name"], types.CheckpointDeleteOptions{
|
||||
err := s.backend.CheckpointDelete(vars["name"], checkpoint.DeleteOptions{
|
||||
CheckpointDir: r.Form.Get("dir"),
|
||||
CheckpointID: vars["checkpoint"],
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -24,22 +24,21 @@ type execBackend interface {
|
|||
// copyBackend includes functions to implement to provide container copy functionality.
|
||||
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
|
||||
ContainerExport(ctx context.Context, name string, out io.Writer) error
|
||||
ContainerExtractToDir(name, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error
|
||||
ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error)
|
||||
}
|
||||
|
||||
// stateBackend includes functions to implement to provide container state lifecycle functionality.
|
||||
type stateBackend interface {
|
||||
ContainerCreate(config types.ContainerCreateConfig) (container.CreateResponse, error)
|
||||
ContainerCreate(ctx context.Context, config backend.ContainerCreateConfig) (container.CreateResponse, error)
|
||||
ContainerKill(name string, signal string) error
|
||||
ContainerPause(name string) error
|
||||
ContainerRename(oldName, newName string) error
|
||||
ContainerResize(name string, height, width int) error
|
||||
ContainerRestart(ctx context.Context, name string, options container.StopOptions) error
|
||||
ContainerRm(name string, config *types.ContainerRmConfig) error
|
||||
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
|
||||
ContainerRm(name string, config *backend.ContainerRmConfig) error
|
||||
ContainerStart(ctx context.Context, name string, checkpoint string, checkpointDir string) error
|
||||
ContainerStop(ctx context.Context, name string, options container.StopOptions) error
|
||||
ContainerUnpause(name string) error
|
||||
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)
|
||||
|
@ -48,13 +47,12 @@ type stateBackend interface {
|
|||
|
||||
// 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)
|
||||
ContainerChanges(ctx context.Context, name string) ([]archive.Change, error)
|
||||
ContainerInspect(ctx context.Context, name string, size bool, version string) (interface{}, error)
|
||||
ContainerLogs(ctx context.Context, name string, config *container.LogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
||||
ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
|
||||
ContainerTop(name string, psArgs string) (*container.ContainerTopOKBody, error)
|
||||
|
||||
Containers(config *types.ContainerListOptions) ([]*types.Container, error)
|
||||
Containers(ctx context.Context, config *container.ListOptions) ([]*types.Container, error)
|
||||
}
|
||||
|
||||
// attachBackend includes function to implement to provide container attaching functionality.
|
||||
|
@ -68,7 +66,7 @@ type systemBackend interface {
|
|||
}
|
||||
|
||||
type commitBackend interface {
|
||||
CreateImageFromContainer(name string, config *backend.CreateImageConfig) (imageID string, err error)
|
||||
CreateImageFromContainer(ctx context.Context, name string, config *backend.CreateImageConfig) (imageID string, err error)
|
||||
}
|
||||
|
||||
// Backend is all the methods that need to be implemented to provide container specific functionality.
|
||||
|
|
|
@ -56,7 +56,6 @@ func (r *containerRouter) initRoutes() {
|
|||
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 (API v1.20), errors out since 1.12 (API v1.24)
|
||||
router.NewPostRoute("/containers/{name:.*}/exec", r.postContainerExecCreate),
|
||||
router.NewPostRoute("/exec/{name:.*}/start", r.postContainerExecStart),
|
||||
router.NewPostRoute("/exec/{name:.*}/resize", r.postContainerExecResize),
|
||||
|
|
|
@ -8,8 +8,10 @@ import (
|
|||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httpstatus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -17,13 +19,14 @@ import (
|
|||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
containerpkg "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/docker/docker/runconfig"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
|
@ -36,29 +39,24 @@ func (s *containerRouter) postCommit(ctx context.Context, w http.ResponseWriter,
|
|||
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.
|
||||
if err != nil && !errors.Is(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"),
|
||||
ref, err := httputils.RepoTagReference(r.Form.Get("repo"), r.Form.Get("tag"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
imgID, err := s.backend.CreateImageFromContainer(ctx, r.Form.Get("container"), &backend.CreateImageConfig{
|
||||
Pause: httputils.BoolValueOrDefault(r, "pause", true), // TODO(dnephin): remove pause arg, and always pause in backend
|
||||
Tag: ref,
|
||||
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
|
||||
}
|
||||
|
@ -75,7 +73,7 @@ func (s *containerRouter) getContainersJSON(ctx context.Context, w http.Response
|
|||
return err
|
||||
}
|
||||
|
||||
config := &types.ContainerListOptions{
|
||||
config := &container.ListOptions{
|
||||
All: httputils.BoolValue(r, "all"),
|
||||
Size: httputils.BoolValue(r, "size"),
|
||||
Since: r.Form.Get("since"),
|
||||
|
@ -91,7 +89,7 @@ func (s *containerRouter) getContainersJSON(ctx context.Context, w http.Response
|
|||
config.Limit = limit
|
||||
}
|
||||
|
||||
containers, err := s.backend.Containers(config)
|
||||
containers, err := s.backend.Containers(ctx, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -113,14 +111,11 @@ func (s *containerRouter) getContainersStats(ctx context.Context, w http.Respons
|
|||
oneShot = httputils.BoolValueOrDefault(r, "one-shot", false)
|
||||
}
|
||||
|
||||
config := &backend.ContainerStatsConfig{
|
||||
return s.backend.ContainerStats(ctx, vars["name"], &backend.ContainerStatsConfig{
|
||||
Stream: stream,
|
||||
OneShot: oneShot,
|
||||
OutStream: w,
|
||||
Version: httputils.VersionFromContext(ctx),
|
||||
}
|
||||
|
||||
return s.backend.ContainerStats(ctx, vars["name"], config)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *containerRouter) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -139,7 +134,7 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response
|
|||
}
|
||||
|
||||
containerName := vars["name"]
|
||||
logsConfig := &types.ContainerLogsOptions{
|
||||
logsConfig := &container.LogsOptions{
|
||||
Follow: httputils.BoolValue(r, "follow"),
|
||||
Timestamps: httputils.BoolValue(r, "timestamps"),
|
||||
Since: r.Form.Get("since"),
|
||||
|
@ -170,17 +165,9 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response
|
|||
}
|
||||
|
||||
func (s *containerRouter) getContainersExport(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return s.backend.ContainerExport(vars["name"], w)
|
||||
return s.backend.ContainerExport(ctx, 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
|
||||
|
@ -188,33 +175,17 @@ func (s *containerRouter) postContainersStart(ctx context.Context, w http.Respon
|
|||
// net/http otherwise seems to swallow any headers related to chunked encoding
|
||||
// including r.TransferEncoding
|
||||
// allow a nil body for backwards compatibility
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
var hostConfig *container.HostConfig
|
||||
//
|
||||
// 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{}
|
||||
}
|
||||
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c, err := s.decoder.DecodeHostConfig(r.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hostConfig = c
|
||||
return errdefs.InvalidParameter(errors.New("starting container with non-empty request body was deprecated since API v1.22 and removed in v1.24"))
|
||||
}
|
||||
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
checkpoint := r.Form.Get("checkpoint")
|
||||
checkpointDir := r.Form.Get("checkpoint-dir")
|
||||
if err := s.backend.ContainerStart(vars["name"], hostConfig, checkpoint, checkpointDir); err != nil {
|
||||
if err := s.backend.ContainerStart(ctx, vars["name"], r.Form.Get("checkpoint"), r.Form.Get("checkpoint-dir")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -250,25 +221,14 @@ func (s *containerRouter) postContainersStop(ctx context.Context, w http.Respons
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *containerRouter) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *containerRouter) postContainersKill(_ context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
if err := s.backend.ContainerKill(name, r.Form.Get("signal")); err != nil {
|
||||
var isStopped bool
|
||||
if errdefs.IsConflict(err) {
|
||||
isStopped = true
|
||||
}
|
||||
|
||||
// Return error that's not caused because the container is stopped.
|
||||
// Return error if the container is not running and the api is >= 1.20
|
||||
// to keep backwards compatibility.
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.GreaterThanOrEqualTo(version, "1.20") || !isStopped {
|
||||
return errors.Wrapf(err, "Cannot kill container: %s", name)
|
||||
}
|
||||
return errors.Wrapf(err, "cannot kill container: %s", name)
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
@ -397,7 +357,7 @@ func (s *containerRouter) postContainersWait(ctx context.Context, w http.Respons
|
|||
}
|
||||
|
||||
func (s *containerRouter) getContainersChanges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
changes, err := s.backend.ContainerChanges(vars["name"])
|
||||
changes, err := s.backend.ContainerChanges(ctx, vars["name"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -484,23 +444,55 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
|||
|
||||
config, hostConfig, networkingConfig, err := s.decoder.DecodeConfig(r.Body)
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return errdefs.InvalidParameter(errors.New("invalid JSON: got EOF while reading request body"))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
return errdefs.InvalidParameter(runconfig.ErrEmptyConfig)
|
||||
}
|
||||
if hostConfig == nil {
|
||||
hostConfig = &container.HostConfig{}
|
||||
}
|
||||
if networkingConfig == nil {
|
||||
networkingConfig = &network.NetworkingConfig{}
|
||||
}
|
||||
if networkingConfig.EndpointsConfig == nil {
|
||||
networkingConfig.EndpointsConfig = make(map[string]*network.EndpointSettings)
|
||||
}
|
||||
// The NetworkMode "default" is used as a way to express a container should
|
||||
// be attached to the OS-dependant default network, in an OS-independent
|
||||
// way. Doing this conversion as soon as possible ensures we have less
|
||||
// NetworkMode to handle down the path (including in the
|
||||
// backward-compatibility layer we have just below).
|
||||
//
|
||||
// Note that this is not the only place where this conversion has to be
|
||||
// done (as there are various other places where containers get created).
|
||||
if hostConfig.NetworkMode == "" || hostConfig.NetworkMode.IsDefault() {
|
||||
hostConfig.NetworkMode = runconfig.DefaultDaemonNetworkMode()
|
||||
if nw, ok := networkingConfig.EndpointsConfig[network.NetworkDefault]; ok {
|
||||
networkingConfig.EndpointsConfig[hostConfig.NetworkMode.NetworkName()] = nw
|
||||
delete(networkingConfig.EndpointsConfig, network.NetworkDefault)
|
||||
}
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
adjustCPUShares := versions.LessThan(version, "1.19")
|
||||
|
||||
// When using API 1.24 and under, the client is responsible for removing the container
|
||||
if hostConfig != nil && versions.LessThan(version, "1.25") {
|
||||
if versions.LessThan(version, "1.25") {
|
||||
hostConfig.AutoRemove = false
|
||||
}
|
||||
|
||||
if hostConfig != nil && versions.LessThan(version, "1.40") {
|
||||
if versions.LessThan(version, "1.40") {
|
||||
// Ignore BindOptions.NonRecursive because it was added in API 1.40.
|
||||
for _, m := range hostConfig.Mounts {
|
||||
if bo := m.BindOptions; bo != nil {
|
||||
bo.NonRecursive = false
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore KernelMemoryTCP because it was added in API 1.40.
|
||||
hostConfig.KernelMemoryTCP = 0
|
||||
|
||||
|
@ -509,14 +501,26 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
|||
hostConfig.IpcMode = container.IPCModeShareable
|
||||
}
|
||||
}
|
||||
if hostConfig != nil && versions.LessThan(version, "1.41") && !s.cgroup2 {
|
||||
|
||||
if versions.LessThan(version, "1.41") {
|
||||
// Older clients expect the default to be "host" on cgroup v1 hosts
|
||||
if hostConfig.CgroupnsMode.IsEmpty() {
|
||||
if !s.cgroup2 && hostConfig.CgroupnsMode.IsEmpty() {
|
||||
hostConfig.CgroupnsMode = container.CgroupnsModeHost
|
||||
}
|
||||
}
|
||||
|
||||
if hostConfig != nil && versions.LessThan(version, "1.42") {
|
||||
var platform *ocispec.Platform
|
||||
if versions.GreaterThanOrEqualTo(version, "1.41") {
|
||||
if v := r.Form.Get("platform"); v != "" {
|
||||
p, err := platforms.Parse(v)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
platform = &p
|
||||
}
|
||||
}
|
||||
|
||||
if versions.LessThan(version, "1.42") {
|
||||
for _, m := range hostConfig.Mounts {
|
||||
// Ignore BindOptions.CreateMountpoint because it was added in API 1.42.
|
||||
if bo := m.BindOptions; bo != nil {
|
||||
|
@ -536,9 +540,14 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
|||
bo.CreateMountpoint = false
|
||||
}
|
||||
}
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
// ConsoleSize is not respected by Linux daemon before API 1.42
|
||||
hostConfig.ConsoleSize = [2]uint{0, 0}
|
||||
}
|
||||
}
|
||||
|
||||
if hostConfig != nil && versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
// Ignore KernelMemory removed in API 1.42.
|
||||
hostConfig.KernelMemory = 0
|
||||
for _, m := range hostConfig.Mounts {
|
||||
|
@ -554,23 +563,63 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
|||
}
|
||||
}
|
||||
|
||||
if hostConfig != nil && runtime.GOOS == "linux" && versions.LessThan(version, "1.42") {
|
||||
// ConsoleSize is not respected by Linux daemon before API 1.42
|
||||
hostConfig.ConsoleSize = [2]uint{0, 0}
|
||||
if versions.LessThan(version, "1.43") {
|
||||
// Ignore Annotations because it was added in API v1.43.
|
||||
hostConfig.Annotations = nil
|
||||
}
|
||||
|
||||
var platform *specs.Platform
|
||||
if versions.GreaterThanOrEqualTo(version, "1.41") {
|
||||
if v := r.Form.Get("platform"); v != "" {
|
||||
p, err := platforms.Parse(v)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
defaultReadOnlyNonRecursive := false
|
||||
if versions.LessThan(version, "1.44") {
|
||||
if config.Healthcheck != nil {
|
||||
// StartInterval was added in API 1.44
|
||||
config.Healthcheck.StartInterval = 0
|
||||
}
|
||||
|
||||
// Set ReadOnlyNonRecursive to true because it was added in API 1.44
|
||||
// Before that all read-only mounts were non-recursive.
|
||||
// Keep that behavior for clients on older APIs.
|
||||
defaultReadOnlyNonRecursive = true
|
||||
|
||||
for _, m := range hostConfig.Mounts {
|
||||
if m.Type == mount.TypeBind {
|
||||
if m.BindOptions != nil && m.BindOptions.ReadOnlyForceRecursive {
|
||||
// NOTE: that technically this is a breaking change for older
|
||||
// API versions, and we should ignore the new field.
|
||||
// However, this option may be incorrectly set by a client with
|
||||
// the expectation that the failing to apply recursive read-only
|
||||
// is enforced, so we decided to produce an error instead,
|
||||
// instead of silently ignoring.
|
||||
return errdefs.InvalidParameter(errors.New("BindOptions.ReadOnlyForceRecursive needs API v1.44 or newer"))
|
||||
}
|
||||
}
|
||||
platform = &p
|
||||
}
|
||||
|
||||
// Creating a container connected to several networks is not supported until v1.44.
|
||||
if len(networkingConfig.EndpointsConfig) > 1 {
|
||||
l := make([]string, 0, len(networkingConfig.EndpointsConfig))
|
||||
for k := range networkingConfig.EndpointsConfig {
|
||||
l = append(l, k)
|
||||
}
|
||||
return errdefs.InvalidParameter(errors.Errorf("Container cannot be created with multiple network endpoints: %s", strings.Join(l, ", ")))
|
||||
}
|
||||
}
|
||||
|
||||
if hostConfig != nil && hostConfig.PidsLimit != nil && *hostConfig.PidsLimit <= 0 {
|
||||
if versions.LessThan(version, "1.45") {
|
||||
for _, m := range hostConfig.Mounts {
|
||||
if m.VolumeOptions != nil && m.VolumeOptions.Subpath != "" {
|
||||
return errdefs.InvalidParameter(errors.New("VolumeOptions.Subpath needs API v1.45 or newer"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var warnings []string
|
||||
if warn, err := handleMACAddressBC(config, hostConfig, networkingConfig, version); err != nil {
|
||||
return err
|
||||
} else if warn != "" {
|
||||
warnings = append(warnings, warn)
|
||||
}
|
||||
|
||||
if hostConfig.PidsLimit != nil && *hostConfig.PidsLimit <= 0 {
|
||||
// Don't set a limit if either no limit was specified, or "unlimited" was
|
||||
// explicitly set.
|
||||
// Both `0` and `-1` are accepted as "unlimited", and historically any
|
||||
|
@ -578,28 +627,107 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
|
|||
hostConfig.PidsLimit = nil
|
||||
}
|
||||
|
||||
ccr, err := s.backend.ContainerCreate(types.ContainerCreateConfig{
|
||||
Name: name,
|
||||
Config: config,
|
||||
HostConfig: hostConfig,
|
||||
NetworkingConfig: networkingConfig,
|
||||
AdjustCPUShares: adjustCPUShares,
|
||||
Platform: platform,
|
||||
ccr, err := s.backend.ContainerCreate(ctx, backend.ContainerCreateConfig{
|
||||
Name: name,
|
||||
Config: config,
|
||||
HostConfig: hostConfig,
|
||||
NetworkingConfig: networkingConfig,
|
||||
Platform: platform,
|
||||
DefaultReadOnlyNonRecursive: defaultReadOnlyNonRecursive,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ccr.Warnings = append(ccr.Warnings, warnings...)
|
||||
return httputils.WriteJSON(w, http.StatusCreated, ccr)
|
||||
}
|
||||
|
||||
// handleMACAddressBC takes care of backward-compatibility for the container-wide MAC address by mutating the
|
||||
// networkingConfig to set the endpoint-specific MACAddress field introduced in API v1.44. It returns a warning message
|
||||
// or an error if the container-wide field was specified for API >= v1.44.
|
||||
func handleMACAddressBC(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, version string) (string, error) {
|
||||
deprecatedMacAddress := config.MacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
|
||||
|
||||
// For older versions of the API, migrate the container-wide MAC address to EndpointsConfig.
|
||||
if versions.LessThan(version, "1.44") {
|
||||
if deprecatedMacAddress == "" {
|
||||
// If a MAC address is supplied in EndpointsConfig, discard it because the old API
|
||||
// would have ignored it.
|
||||
for _, ep := range networkingConfig.EndpointsConfig {
|
||||
ep.MacAddress = ""
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
if !hostConfig.NetworkMode.IsBridge() && !hostConfig.NetworkMode.IsUserDefined() {
|
||||
return "", runconfig.ErrConflictContainerNetworkAndMac
|
||||
}
|
||||
|
||||
// There cannot be more than one entry in EndpointsConfig with API < 1.44.
|
||||
|
||||
// If there's no EndpointsConfig, create a place to store the configured address. It is
|
||||
// safe to use NetworkMode as the network name, whether it's a name or id/short-id, as
|
||||
// it will be normalised later and there is no other EndpointSettings object that might
|
||||
// refer to this network/endpoint.
|
||||
if len(networkingConfig.EndpointsConfig) == 0 {
|
||||
nwName := hostConfig.NetworkMode.NetworkName()
|
||||
networkingConfig.EndpointsConfig[nwName] = &network.EndpointSettings{}
|
||||
}
|
||||
// There's exactly one network in EndpointsConfig, either from the API or just-created.
|
||||
// Migrate the container-wide setting to it.
|
||||
// No need to check for a match between NetworkMode and the names/ids in EndpointsConfig,
|
||||
// the old version of the API would have applied the address to this network anyway.
|
||||
for _, ep := range networkingConfig.EndpointsConfig {
|
||||
ep.MacAddress = deprecatedMacAddress
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// The container-wide MacAddress parameter is deprecated and should now be specified in EndpointsConfig.
|
||||
if deprecatedMacAddress == "" {
|
||||
return "", nil
|
||||
}
|
||||
var warning string
|
||||
if hostConfig.NetworkMode.IsBridge() || hostConfig.NetworkMode.IsUserDefined() {
|
||||
nwName := hostConfig.NetworkMode.NetworkName()
|
||||
// If there's no endpoint config, create a place to store the configured address.
|
||||
if len(networkingConfig.EndpointsConfig) == 0 {
|
||||
networkingConfig.EndpointsConfig[nwName] = &network.EndpointSettings{
|
||||
MacAddress: deprecatedMacAddress,
|
||||
}
|
||||
} else {
|
||||
// There is existing endpoint config - if it's not indexed by NetworkMode.Name(), we
|
||||
// can't tell which network the container-wide settings was intended for. NetworkMode,
|
||||
// the keys in EndpointsConfig and the NetworkID in EndpointsConfig may mix network
|
||||
// name/id/short-id. It's not safe to create EndpointsConfig under the NetworkMode
|
||||
// name to store the container-wide MAC address, because that may result in two sets
|
||||
// of EndpointsConfig for the same network and one set will be discarded later. So,
|
||||
// reject the request ...
|
||||
ep, ok := networkingConfig.EndpointsConfig[nwName]
|
||||
if !ok {
|
||||
return "", errdefs.InvalidParameter(errors.New("if a container-wide MAC address is supplied, HostConfig.NetworkMode must match the identity of a network in NetworkSettings.Networks"))
|
||||
}
|
||||
// ep is the endpoint that needs the container-wide MAC address; migrate the address
|
||||
// to it, or bail out if there's a mismatch.
|
||||
if ep.MacAddress == "" {
|
||||
ep.MacAddress = deprecatedMacAddress
|
||||
} else if ep.MacAddress != deprecatedMacAddress {
|
||||
return "", errdefs.InvalidParameter(errors.New("the container-wide MAC address must match the endpoint-specific MAC address for the main network, or be left empty"))
|
||||
}
|
||||
}
|
||||
}
|
||||
warning = "The container-wide MacAddress field is now deprecated. It should be specified in EndpointsConfig instead."
|
||||
config.MacAddress = "" //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
|
||||
|
||||
return warning, nil
|
||||
}
|
||||
|
||||
func (s *containerRouter) deleteContainers(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
config := &types.ContainerRmConfig{
|
||||
config := &backend.ContainerRmConfig{
|
||||
ForceRemove: httputils.BoolValue(r, "force"),
|
||||
RemoveVolume: httputils.BoolValue(r, "v"),
|
||||
RemoveLink: httputils.BoolValue(r, "link"),
|
||||
|
@ -684,11 +812,11 @@ func (s *containerRouter) postContainersAttach(ctx context.Context, w http.Respo
|
|||
}
|
||||
|
||||
if err = s.backend.ContainerAttach(containerName, attachConfig); err != nil {
|
||||
logrus.WithError(err).Errorf("Handler for %s %s returned error", r.Method, r.URL.Path)
|
||||
log.G(ctx).WithError(err).Errorf("Handler for %s %s returned error", r.Method, r.URL.Path)
|
||||
// Remember to close stream if error happens
|
||||
conn, _, errHijack := hijacker.Hijack()
|
||||
if errHijack != nil {
|
||||
logrus.WithError(err).Errorf("Handler for %s %s: unable to close stream; error when hijacking connection", r.Method, r.URL.Path)
|
||||
log.G(ctx).WithError(err).Errorf("Handler for %s %s: unable to close stream; error when hijacking connection", r.Method, r.URL.Path)
|
||||
} else {
|
||||
statusCode := httpstatus.FromError(err)
|
||||
statusText := http.StatusText(statusCode)
|
||||
|
@ -758,9 +886,9 @@ func (s *containerRouter) wsContainersAttach(ctx context.Context, w http.Respons
|
|||
select {
|
||||
case <-started:
|
||||
if err != nil {
|
||||
logrus.Errorf("Error attaching websocket: %s", err)
|
||||
log.G(ctx).Errorf("Error attaching websocket: %s", err)
|
||||
} else {
|
||||
logrus.Debug("websocket connection was closed by client")
|
||||
log.G(ctx).Debug("websocket connection was closed by client")
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
|
|
160
api/server/router/container/container_routes_test.go
Normal file
160
api/server/router/container/container_routes_test.go
Normal file
|
@ -0,0 +1,160 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestHandleMACAddressBC(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
apiVersion string
|
||||
ctrWideMAC string
|
||||
networkMode container.NetworkMode
|
||||
epConfig map[string]*network.EndpointSettings
|
||||
expEpWithCtrWideMAC string
|
||||
expEpWithNoMAC string
|
||||
expCtrWideMAC string
|
||||
expWarning string
|
||||
expError string
|
||||
}{
|
||||
{
|
||||
name: "old api ctr-wide mac mix id and name",
|
||||
apiVersion: "1.43",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetId",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
|
||||
expEpWithCtrWideMAC: "aNetName",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
{
|
||||
name: "old api clear ep mac",
|
||||
apiVersion: "1.43",
|
||||
networkMode: "aNetId",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {MacAddress: "11:22:33:44:55:66"}},
|
||||
expEpWithNoMAC: "aNetName",
|
||||
},
|
||||
{
|
||||
name: "old api no-network ctr-wide mac",
|
||||
apiVersion: "1.43",
|
||||
networkMode: "none",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
expError: "conflicting options: mac-address and the network mode",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
{
|
||||
name: "old api create ep",
|
||||
apiVersion: "1.43",
|
||||
networkMode: "aNetId",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
epConfig: map[string]*network.EndpointSettings{},
|
||||
expEpWithCtrWideMAC: "aNetId",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
{
|
||||
name: "old api migrate ctr-wide mac",
|
||||
apiVersion: "1.43",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetName",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
|
||||
expEpWithCtrWideMAC: "aNetName",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
{
|
||||
name: "new api no macs",
|
||||
apiVersion: "1.44",
|
||||
networkMode: "aNetId",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
|
||||
},
|
||||
{
|
||||
name: "new api ep specific mac",
|
||||
apiVersion: "1.44",
|
||||
networkMode: "aNetName",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {MacAddress: "11:22:33:44:55:66"}},
|
||||
},
|
||||
{
|
||||
name: "new api migrate ctr-wide mac to new ep",
|
||||
apiVersion: "1.44",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetName",
|
||||
epConfig: map[string]*network.EndpointSettings{},
|
||||
expEpWithCtrWideMAC: "aNetName",
|
||||
expWarning: "The container-wide MacAddress field is now deprecated",
|
||||
expCtrWideMAC: "",
|
||||
},
|
||||
{
|
||||
name: "new api migrate ctr-wide mac to existing ep",
|
||||
apiVersion: "1.44",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetName",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
|
||||
expEpWithCtrWideMAC: "aNetName",
|
||||
expWarning: "The container-wide MacAddress field is now deprecated",
|
||||
expCtrWideMAC: "",
|
||||
},
|
||||
{
|
||||
name: "new api mode vs name mismatch",
|
||||
apiVersion: "1.44",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetId",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {}},
|
||||
expError: "if a container-wide MAC address is supplied, HostConfig.NetworkMode must match the identity of a network in NetworkSettings.Networks",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
{
|
||||
name: "new api mac mismatch",
|
||||
apiVersion: "1.44",
|
||||
ctrWideMAC: "11:22:33:44:55:66",
|
||||
networkMode: "aNetName",
|
||||
epConfig: map[string]*network.EndpointSettings{"aNetName": {MacAddress: "00:11:22:33:44:55"}},
|
||||
expError: "the container-wide MAC address must match the endpoint-specific MAC address",
|
||||
expCtrWideMAC: "11:22:33:44:55:66",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cfg := &container.Config{
|
||||
MacAddress: tc.ctrWideMAC, //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
|
||||
}
|
||||
hostCfg := &container.HostConfig{
|
||||
NetworkMode: tc.networkMode,
|
||||
}
|
||||
epConfig := make(map[string]*network.EndpointSettings, len(tc.epConfig))
|
||||
for k, v := range tc.epConfig {
|
||||
v := v
|
||||
epConfig[k] = v
|
||||
}
|
||||
netCfg := &network.NetworkingConfig{
|
||||
EndpointsConfig: epConfig,
|
||||
}
|
||||
|
||||
warning, err := handleMACAddressBC(cfg, hostCfg, netCfg, tc.apiVersion)
|
||||
|
||||
if tc.expError == "" {
|
||||
assert.Check(t, err)
|
||||
} else {
|
||||
assert.Check(t, is.ErrorContains(err, tc.expError))
|
||||
}
|
||||
if tc.expWarning == "" {
|
||||
assert.Check(t, is.Equal(warning, ""))
|
||||
} else {
|
||||
assert.Check(t, is.Contains(warning, tc.expWarning))
|
||||
}
|
||||
if tc.expEpWithCtrWideMAC != "" {
|
||||
got := netCfg.EndpointsConfig[tc.expEpWithCtrWideMAC].MacAddress
|
||||
assert.Check(t, is.Equal(got, tc.ctrWideMAC))
|
||||
}
|
||||
if tc.expEpWithNoMAC != "" {
|
||||
got := netCfg.EndpointsConfig[tc.expEpWithNoMAC].MacAddress
|
||||
assert.Check(t, is.Equal(got, ""))
|
||||
}
|
||||
gotCtrWideMAC := cfg.MacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
|
||||
assert.Check(t, is.Equal(gotCtrWideMAC, tc.expCtrWideMAC))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -11,49 +11,10 @@ import (
|
|||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
gddohttputil "github.com/golang/gddo/httputil"
|
||||
)
|
||||
|
||||
type pathError struct{}
|
||||
|
||||
func (pathError) Error() string {
|
||||
return "Path cannot be empty"
|
||||
}
|
||||
|
||||
func (pathError) InvalidParameter() {}
|
||||
|
||||
// postContainersCopy is deprecated in favor of getContainersArchive.
|
||||
//
|
||||
// Deprecated since 1.8 (API v1.20), errors out since 1.12 (API v1.24)
|
||||
func (s *containerRouter) postContainersCopy(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.GreaterThanOrEqualTo(version, "1.24") {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return nil
|
||||
}
|
||||
|
||||
cfg := types.CopyConfig{}
|
||||
if err := httputils.ReadJSON(r, &cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cfg.Resource == "" {
|
||||
return pathError{}
|
||||
}
|
||||
|
||||
data, err := s.backend.ContainerCopy(vars["name"], cfg.Resource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer data.Close()
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-tar")
|
||||
_, err = io.Copy(w, data)
|
||||
return err
|
||||
}
|
||||
|
||||
// // Encode the stat to JSON, base64 encode, and place in a header.
|
||||
// setContainerPathStatHeader encodes the stat to JSON, base64 encode, and place in a header.
|
||||
func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
|
||||
statJSON, err := json.Marshal(stat)
|
||||
if err != nil {
|
||||
|
|
|
@ -7,13 +7,13 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (s *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -56,7 +56,7 @@ func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.Re
|
|||
// Register an instance of Exec in container.
|
||||
id, err := s.backend.ContainerExecCreate(vars["name"], execConfig)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error setting up exec command in container %s: %v", vars["name"], err)
|
||||
log.G(ctx).Errorf("Error setting up exec command in container %s: %v", vars["name"], err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -71,15 +71,6 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
|
|||
return err
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.LessThan(version, "1.22") {
|
||||
// API versions before 1.22 did not enforce application/json content-type.
|
||||
// Allow older clients to work by patching the content-type.
|
||||
if r.Header.Get("Content-Type") != "application/json" {
|
||||
r.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
execName = vars["name"]
|
||||
stdin, inStream io.ReadCloser
|
||||
|
@ -96,6 +87,8 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
|
|||
}
|
||||
|
||||
if execStartCheck.ConsoleSize != nil {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
|
||||
// Not supported before 1.42
|
||||
if versions.LessThan(version, "1.42") {
|
||||
execStartCheck.ConsoleSize = nil
|
||||
|
@ -154,7 +147,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)
|
||||
log.G(ctx).Errorf("Error running exec %s in container: %v", execName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ func (s *containerRouter) getContainersByName(ctx context.Context, w http.Respon
|
|||
displaySize := httputils.BoolValue(r, "size")
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
json, err := s.backend.ContainerInspect(vars["name"], displaySize, version)
|
||||
json, err := s.backend.ContainerInspect(ctx, vars["name"], displaySize, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ package distribution // import "github.com/docker/docker/api/server/router/distr
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
)
|
||||
|
||||
// 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, error)
|
||||
GetRepositories(context.Context, reference.Named, *registry.AuthConfig) ([]distribution.Repository, error)
|
||||
}
|
||||
|
|
|
@ -2,20 +2,20 @@ package distribution // import "github.com/docker/docker/api/server/router/distr
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
"os"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution"
|
||||
"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/docker/docker/api/types/registry"
|
||||
distributionpkg "github.com/docker/docker/distribution"
|
||||
"github.com/docker/docker/errdefs"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -26,25 +26,10 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
|
|||
|
||||
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"]
|
||||
imgName := vars["name"]
|
||||
|
||||
// TODO why is reference.ParseAnyReference() / reference.ParseNormalizedNamed() not using the reference.ErrTagInvalidFormat (and so on) errors?
|
||||
ref, err := reference.ParseAnyReference(image)
|
||||
ref, err := reference.ParseAnyReference(imgName)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
@ -54,28 +39,58 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
|
|||
// full image ID
|
||||
return errors.Errorf("no manifest found for full image ID")
|
||||
}
|
||||
return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", image))
|
||||
return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", imgName))
|
||||
}
|
||||
|
||||
distrepo, err := s.backend.GetRepository(ctx, namedRef, config)
|
||||
// For a search it is not an error if no auth was given. Ignore invalid
|
||||
// AuthConfig to increase compatibility with the existing API.
|
||||
authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader))
|
||||
repos, err := s.backend.GetRepositories(ctx, namedRef, authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
blobsrvc := distrepo.Blobs(ctx)
|
||||
|
||||
// Fetch the manifest; if a mirror is configured, try the mirror first,
|
||||
// but continue with upstream on failure.
|
||||
//
|
||||
// FIXME(thaJeztah): construct "repositories" on-demand;
|
||||
// GetRepositories() will attempt to connect to all endpoints (registries),
|
||||
// but we may only need the first one if it contains the manifest we're
|
||||
// looking for, or if the configured mirror is a pull-through mirror.
|
||||
//
|
||||
// Logic for this could be implemented similar to "distribution.Pull()",
|
||||
// which uses the "pullEndpoints" utility to iterate over the list
|
||||
// of endpoints;
|
||||
//
|
||||
// - https://github.com/moby/moby/blob/12c7411b6b7314bef130cd59f1c7384a7db06d0b/distribution/pull.go#L17-L31
|
||||
// - https://github.com/moby/moby/blob/12c7411b6b7314bef130cd59f1c7384a7db06d0b/distribution/pull.go#L76-L152
|
||||
var lastErr error
|
||||
for _, repo := range repos {
|
||||
distributionInspect, err := s.fetchManifest(ctx, repo, namedRef)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, distributionInspect)
|
||||
}
|
||||
return lastErr
|
||||
}
|
||||
|
||||
func (s *distributionRouter) fetchManifest(ctx context.Context, distrepo distribution.Repository, namedRef reference.Named) (registry.DistributionInspect, error) {
|
||||
var distributionInspect registry.DistributionInspect
|
||||
if canonicalRef, ok := namedRef.(reference.Canonical); !ok {
|
||||
namedRef = reference.TagNameOnly(namedRef)
|
||||
|
||||
taggedRef, ok := namedRef.(reference.NamedTagged)
|
||||
if !ok {
|
||||
return errdefs.InvalidParameter(errors.Errorf("image reference not tagged: %s", image))
|
||||
return registry.DistributionInspect{}, errdefs.InvalidParameter(errors.Errorf("image reference not tagged: %s", namedRef))
|
||||
}
|
||||
|
||||
descriptor, err := distrepo.Tags(ctx).Get(ctx, taggedRef.Tag())
|
||||
if err != nil {
|
||||
return err
|
||||
return registry.DistributionInspect{}, err
|
||||
}
|
||||
distributionInspect.Descriptor = v1.Descriptor{
|
||||
distributionInspect.Descriptor = ocispec.Descriptor{
|
||||
MediaType: descriptor.MediaType,
|
||||
Digest: descriptor.Digest,
|
||||
Size: descriptor.Size,
|
||||
|
@ -90,7 +105,7 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
|
|||
// we have a digest, so we can retrieve the manifest
|
||||
mnfstsrvc, err := distrepo.Manifests(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
return registry.DistributionInspect{}, err
|
||||
}
|
||||
mnfst, err := mnfstsrvc.Get(ctx, distributionInspect.Descriptor.Digest)
|
||||
if err != nil {
|
||||
|
@ -102,14 +117,14 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
|
|||
reference.ErrNameEmpty,
|
||||
reference.ErrNameTooLong,
|
||||
reference.ErrNameNotCanonical:
|
||||
return errdefs.InvalidParameter(err)
|
||||
return registry.DistributionInspect{}, errdefs.InvalidParameter(err)
|
||||
}
|
||||
return err
|
||||
return registry.DistributionInspect{}, err
|
||||
}
|
||||
|
||||
mediaType, payload, err := mnfst.Payload()
|
||||
if err != nil {
|
||||
return err
|
||||
return registry.DistributionInspect{}, err
|
||||
}
|
||||
// update MediaType because registry might return something incorrect
|
||||
distributionInspect.Descriptor.MediaType = mediaType
|
||||
|
@ -121,7 +136,7 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
|
|||
switch mnfstObj := mnfst.(type) {
|
||||
case *manifestlist.DeserializedManifestList:
|
||||
for _, m := range mnfstObj.Manifests {
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, v1.Platform{
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, ocispec.Platform{
|
||||
Architecture: m.Platform.Architecture,
|
||||
OS: m.Platform.OS,
|
||||
OSVersion: m.Platform.OSVersion,
|
||||
|
@ -130,8 +145,9 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
|
|||
})
|
||||
}
|
||||
case *schema2.DeserializedManifest:
|
||||
configJSON, err := blobsrvc.Get(ctx, mnfstObj.Config.Digest)
|
||||
var platform v1.Platform
|
||||
blobStore := distrepo.Blobs(ctx)
|
||||
configJSON, err := blobStore.Get(ctx, mnfstObj.Config.Digest)
|
||||
var platform ocispec.Platform
|
||||
if err == nil {
|
||||
err := json.Unmarshal(configJSON, &platform)
|
||||
if err == nil && (platform.OS != "" || platform.Architecture != "") {
|
||||
|
@ -139,12 +155,14 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res
|
|||
}
|
||||
}
|
||||
case *schema1.SignedManifest:
|
||||
platform := v1.Platform{
|
||||
if os.Getenv("DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE") == "" {
|
||||
return registry.DistributionInspect{}, distributionpkg.DeprecatedSchema1ImageError(namedRef)
|
||||
}
|
||||
platform := ocispec.Platform{
|
||||
Architecture: mnfstObj.Architecture,
|
||||
OS: "linux",
|
||||
}
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, platform)
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, distributionInspect)
|
||||
return distributionInspect, nil
|
||||
}
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
package grpc // import "github.com/docker/docker/api/server/router/grpc"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/server/router"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"github.com/moby/buildkit/util/grpcerrors"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"golang.org/x/net/http2"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
@ -15,12 +20,12 @@ type grpcRouter struct {
|
|||
|
||||
// NewRouter initializes a new grpc http router
|
||||
func NewRouter(backends ...Backend) router.Router {
|
||||
unary := grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptor(), grpcerrors.UnaryServerInterceptor))
|
||||
stream := grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(otelgrpc.StreamServerInterceptor(), grpcerrors.StreamServerInterceptor)) //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
|
||||
|
||||
r := &grpcRouter{
|
||||
h2Server: &http2.Server{},
|
||||
grpcServer: grpc.NewServer(
|
||||
grpc.UnaryInterceptor(grpcerrors.UnaryServerInterceptor),
|
||||
grpc.StreamInterceptor(grpcerrors.StreamServerInterceptor),
|
||||
),
|
||||
h2Server: &http2.Server{},
|
||||
grpcServer: grpc.NewServer(unary, stream),
|
||||
}
|
||||
for _, b := range backends {
|
||||
b.RegisterGRPC(r.grpcServer)
|
||||
|
@ -39,3 +44,17 @@ func (gr *grpcRouter) initRoutes() {
|
|||
router.NewPostRoute("/grpc", gr.serveGRPC),
|
||||
}
|
||||
}
|
||||
|
||||
func unaryInterceptor() grpc.UnaryServerInterceptor {
|
||||
withTrace := otelgrpc.UnaryServerInterceptor() //nolint:staticcheck // TODO(thaJeztah): ignore SA1019 for deprecated options: see https://github.com/moby/moby/issues/47437
|
||||
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
|
||||
// This method is used by the clients to send their traces to buildkit so they can be included
|
||||
// in the daemon trace and stored in the build history record. This method can not be traced because
|
||||
// it would cause an infinite loop.
|
||||
if strings.HasSuffix(info.FullMethod, "opentelemetry.proto.collector.trace.v1.TraceService/Export") {
|
||||
return handler(ctx, req)
|
||||
}
|
||||
return withTrace(ctx, req, info, handler)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,14 @@ import (
|
|||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"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"
|
||||
dockerimage "github.com/docker/docker/image"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// Backend is all the methods that need to be implemented
|
||||
|
@ -21,22 +23,25 @@ type Backend interface {
|
|||
}
|
||||
|
||||
type imageBackend interface {
|
||||
ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
|
||||
ImageHistory(imageName string) ([]*image.HistoryResponseItem, error)
|
||||
Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error)
|
||||
GetImage(refOrID string, platform *specs.Platform) (retImg *dockerimage.Image, retErr error)
|
||||
TagImage(imageName, repository, tag string) (string, error)
|
||||
ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]image.DeleteResponse, error)
|
||||
ImageHistory(ctx context.Context, imageName string) ([]*image.HistoryResponseItem, error)
|
||||
Images(ctx context.Context, opts image.ListOptions) ([]*image.Summary, error)
|
||||
GetImage(ctx context.Context, refOrID string, options backend.GetImageOpts) (*dockerimage.Image, error)
|
||||
TagImage(ctx context.Context, id dockerimage.ID, newRef reference.Named) error
|
||||
ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error)
|
||||
}
|
||||
|
||||
type importExportBackend interface {
|
||||
LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error
|
||||
ImportImage(src string, repository string, platform *specs.Platform, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error
|
||||
ExportImage(names []string, outStream io.Writer) error
|
||||
LoadImage(ctx context.Context, inTar io.ReadCloser, outStream io.Writer, quiet bool) error
|
||||
ImportImage(ctx context.Context, ref reference.Named, platform *ocispec.Platform, msg string, layerReader io.Reader, changes []string) (dockerimage.ID, error)
|
||||
ExportImage(ctx context.Context, 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
|
||||
PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
|
||||
SearchRegistryForImages(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error)
|
||||
PullImage(ctx context.Context, ref reference.Named, platform *ocispec.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
|
||||
PushImage(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
|
||||
}
|
||||
|
||||
type Searcher interface {
|
||||
Search(ctx context.Context, searchFilters filters.Args, term string, limit int, authConfig *registry.AuthConfig, headers map[string][]string) ([]registry.SearchResult, error)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
// imageRouter is a router to talk with the image controller
|
||||
type imageRouter struct {
|
||||
backend Backend
|
||||
searcher Searcher
|
||||
referenceBackend reference.Store
|
||||
imageStore image.Store
|
||||
layerStore layer.Store
|
||||
|
@ -17,39 +18,40 @@ type imageRouter struct {
|
|||
}
|
||||
|
||||
// NewRouter initializes a new image router
|
||||
func NewRouter(backend Backend, referenceBackend reference.Store, imageStore image.Store, layerStore layer.Store) router.Router {
|
||||
r := &imageRouter{
|
||||
func NewRouter(backend Backend, searcher Searcher, referenceBackend reference.Store, imageStore image.Store, layerStore layer.Store) router.Router {
|
||||
ir := &imageRouter{
|
||||
backend: backend,
|
||||
searcher: searcher,
|
||||
referenceBackend: referenceBackend,
|
||||
imageStore: imageStore,
|
||||
layerStore: layerStore,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
ir.initRoutes()
|
||||
return ir
|
||||
}
|
||||
|
||||
// Routes returns the available routes to the image controller
|
||||
func (r *imageRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
func (ir *imageRouter) Routes() []router.Route {
|
||||
return ir.routes
|
||||
}
|
||||
|
||||
// initRoutes initializes the routes in the image router
|
||||
func (r *imageRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
func (ir *imageRouter) initRoutes() {
|
||||
ir.routes = []router.Route{
|
||||
// GET
|
||||
router.NewGetRoute("/images/json", r.getImagesJSON),
|
||||
router.NewGetRoute("/images/search", r.getImagesSearch),
|
||||
router.NewGetRoute("/images/get", r.getImagesGet),
|
||||
router.NewGetRoute("/images/{name:.*}/get", r.getImagesGet),
|
||||
router.NewGetRoute("/images/{name:.*}/history", r.getImagesHistory),
|
||||
router.NewGetRoute("/images/{name:.*}/json", r.getImagesByName),
|
||||
router.NewGetRoute("/images/json", ir.getImagesJSON),
|
||||
router.NewGetRoute("/images/search", ir.getImagesSearch),
|
||||
router.NewGetRoute("/images/get", ir.getImagesGet),
|
||||
router.NewGetRoute("/images/{name:.*}/get", ir.getImagesGet),
|
||||
router.NewGetRoute("/images/{name:.*}/history", ir.getImagesHistory),
|
||||
router.NewGetRoute("/images/{name:.*}/json", ir.getImagesByName),
|
||||
// POST
|
||||
router.NewPostRoute("/images/load", r.postImagesLoad),
|
||||
router.NewPostRoute("/images/create", r.postImagesCreate),
|
||||
router.NewPostRoute("/images/{name:.*}/push", r.postImagesPush),
|
||||
router.NewPostRoute("/images/{name:.*}/tag", r.postImagesTag),
|
||||
router.NewPostRoute("/images/prune", r.postImagesPrune),
|
||||
router.NewPostRoute("/images/load", ir.postImagesLoad),
|
||||
router.NewPostRoute("/images/create", ir.postImagesCreate),
|
||||
router.NewPostRoute("/images/{name:.*}/push", ir.postImagesPush),
|
||||
router.NewPostRoute("/images/{name:.*}/tag", ir.postImagesTag),
|
||||
router.NewPostRoute("/images/prune", ir.postImagesPrune),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/images/{name:.*}", r.deleteImages),
|
||||
router.NewDeleteRoute("/images/{name:.*}", ir.deleteImages),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,43 +2,50 @@ package image // import "github.com/docker/docker/api/server/router/image"
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api"
|
||||
"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/filters"
|
||||
imagetypes "github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/builder/remotecontext"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
|
||||
func (ir *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")
|
||||
img = r.Form.Get("fromImage")
|
||||
repo = r.Form.Get("repo")
|
||||
tag = r.Form.Get("tag")
|
||||
message = r.Form.Get("message")
|
||||
comment = r.Form.Get("message")
|
||||
progressErr error
|
||||
output = ioutils.NewWriteFlusher(w)
|
||||
platform *specs.Platform
|
||||
platform *ocispec.Platform
|
||||
)
|
||||
defer output.Close()
|
||||
|
||||
|
@ -55,7 +62,7 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite
|
|||
}
|
||||
}
|
||||
|
||||
if image != "" { // pull
|
||||
if img != "" { // pull
|
||||
metaHeaders := map[string][]string{}
|
||||
for k, v := range r.Header {
|
||||
if strings.HasPrefix(k, "X-Meta-") {
|
||||
|
@ -63,20 +70,80 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite
|
|||
}
|
||||
}
|
||||
|
||||
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{}
|
||||
// Special case: "pull -a" may send an image name with a
|
||||
// trailing :. This is ugly, but let's not break API
|
||||
// compatibility.
|
||||
imgName := strings.TrimSuffix(img, ":")
|
||||
|
||||
ref, err := reference.ParseNormalizedNamed(imgName)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
// TODO(thaJeztah) this could use a WithTagOrDigest() utility
|
||||
if tag != "" {
|
||||
// The "tag" could actually be a digest.
|
||||
var dgst digest.Digest
|
||||
dgst, err = digest.Parse(tag)
|
||||
if err == nil {
|
||||
ref, err = reference.WithDigest(reference.TrimNamed(ref), dgst)
|
||||
} else {
|
||||
ref, err = reference.WithTag(ref, tag)
|
||||
}
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
}
|
||||
progressErr = s.backend.PullImage(ctx, image, tag, platform, metaHeaders, authConfig, output)
|
||||
|
||||
if err := validateRepoName(ref); err != nil {
|
||||
return errdefs.Forbidden(err)
|
||||
}
|
||||
|
||||
// For a pull it is not an error if no auth was given. Ignore invalid
|
||||
// AuthConfig to increase compatibility with the existing API.
|
||||
authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader))
|
||||
progressErr = ir.backend.PullImage(ctx, ref, platform, metaHeaders, authConfig, output)
|
||||
} else { // import
|
||||
src := r.Form.Get("fromSrc")
|
||||
progressErr = s.backend.ImportImage(src, repo, platform, tag, message, r.Body, output, r.Form["changes"])
|
||||
|
||||
tagRef, err := httputils.RepoTagReference(repo, tag)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
if len(comment) == 0 {
|
||||
comment = "Imported from " + src
|
||||
}
|
||||
|
||||
var layerReader io.ReadCloser
|
||||
defer r.Body.Close()
|
||||
if src == "-" {
|
||||
layerReader = r.Body
|
||||
} else {
|
||||
if len(strings.Split(src, "://")) == 1 {
|
||||
src = "http://" + src
|
||||
}
|
||||
u, err := url.Parse(src)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
resp, err := remotecontext.GetWithStatusError(u.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
output.Write(streamformatter.FormatStatus("", "Downloading from %s", u))
|
||||
progressOutput := streamformatter.NewJSONProgressOutput(output, true)
|
||||
layerReader = progress.NewProgressReader(resp.Body, progressOutput, resp.ContentLength, "", "Importing")
|
||||
defer layerReader.Close()
|
||||
}
|
||||
|
||||
var id image.ID
|
||||
id, progressErr = ir.backend.ImportImage(ctx, tagRef, platform, comment, layerReader, r.Form["changes"])
|
||||
|
||||
if progressErr == nil {
|
||||
output.Write(streamformatter.FormatStatus("", id.String()))
|
||||
}
|
||||
}
|
||||
if progressErr != nil {
|
||||
if !output.Flushed() {
|
||||
|
@ -88,7 +155,7 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (ir *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
metaHeaders := map[string][]string{}
|
||||
for k, v := range r.Header {
|
||||
if strings.HasPrefix(k, "X-Meta-") {
|
||||
|
@ -98,32 +165,47 @@ func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter,
|
|||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
authConfig := &types.AuthConfig{}
|
||||
|
||||
authEncoded := r.Header.Get("X-Registry-Auth")
|
||||
if authEncoded != "" {
|
||||
// the new format is to handle the authConfig as a header
|
||||
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
|
||||
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
|
||||
// to increase compatibility to existing api it is defaulting to be empty
|
||||
authConfig = &types.AuthConfig{}
|
||||
}
|
||||
var authConfig *registry.AuthConfig
|
||||
if authEncoded := r.Header.Get(registry.AuthHeader); authEncoded != "" {
|
||||
// the new format is to handle the authConfig as a header. Ignore invalid
|
||||
// AuthConfig to increase compatibility with the existing API.
|
||||
authConfig, _ = registry.DecodeAuthConfig(authEncoded)
|
||||
} 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")
|
||||
var err error
|
||||
authConfig, err = registry.DecodeAuthConfigBody(r.Body)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "bad parameters and missing X-Registry-Auth")
|
||||
}
|
||||
}
|
||||
|
||||
image := vars["name"]
|
||||
tag := r.Form.Get("tag")
|
||||
|
||||
output := ioutils.NewWriteFlusher(w)
|
||||
defer output.Close()
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if err := s.backend.PushImage(ctx, image, tag, metaHeaders, authConfig, output); err != nil {
|
||||
img := vars["name"]
|
||||
tag := r.Form.Get("tag")
|
||||
|
||||
var ref reference.Named
|
||||
|
||||
// Tag is empty only in case PushOptions.All is true.
|
||||
if tag != "" {
|
||||
r, err := httputils.RepoTagReference(img, tag)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
ref = r
|
||||
} else {
|
||||
r, err := reference.ParseNormalizedNamed(img)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
ref = r
|
||||
}
|
||||
|
||||
if err := ir.backend.PushImage(ctx, ref, metaHeaders, authConfig, output); err != nil {
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
|
@ -132,7 +214,7 @@ func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *imageRouter) getImagesGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (ir *imageRouter) getImagesGet(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -148,7 +230,7 @@ func (s *imageRouter) getImagesGet(ctx context.Context, w http.ResponseWriter, r
|
|||
names = r.Form["names"]
|
||||
}
|
||||
|
||||
if err := s.backend.ExportImage(names, output); err != nil {
|
||||
if err := ir.backend.ExportImage(ctx, names, output); err != nil {
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
|
@ -157,7 +239,7 @@ func (s *imageRouter) getImagesGet(ctx context.Context, w http.ResponseWriter, r
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *imageRouter) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (ir *imageRouter) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -167,7 +249,7 @@ 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 {
|
||||
if err := ir.backend.LoadImage(ctx, r.Body, output, quiet); err != nil {
|
||||
_, _ = output.Write(streamformatter.FormatError(err))
|
||||
}
|
||||
return nil
|
||||
|
@ -181,7 +263,7 @@ func (missingImageError) Error() string {
|
|||
|
||||
func (missingImageError) InvalidParameter() {}
|
||||
|
||||
func (s *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (ir *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
|
||||
}
|
||||
|
@ -195,7 +277,7 @@ func (s *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter, r
|
|||
force := httputils.BoolValue(r, "force")
|
||||
prune := !httputils.BoolValue(r, "noprune")
|
||||
|
||||
list, err := s.backend.ImageDelete(name, force, prune)
|
||||
list, err := ir.backend.ImageDelete(ctx, name, force, prune)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -203,25 +285,37 @@ func (s *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter, r
|
|||
return httputils.WriteJSON(w, http.StatusOK, list)
|
||||
}
|
||||
|
||||
func (s *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
image, err := s.backend.GetImage(vars["name"], nil)
|
||||
func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
img, err := ir.backend.GetImage(ctx, vars["name"], backend.GetImageOpts{Details: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
imageInspect, err := s.toImageInspect(image)
|
||||
imageInspect, err := ir.toImageInspect(img)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.LessThan(version, "1.44") {
|
||||
imageInspect.VirtualSize = imageInspect.Size //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
|
||||
|
||||
if imageInspect.Created == "" {
|
||||
// backwards compatibility for Created not existing returning "0001-01-01T00:00:00Z"
|
||||
// https://github.com/moby/moby/issues/47368
|
||||
imageInspect.Created = time.Time{}.Format(time.RFC3339Nano)
|
||||
}
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.45") {
|
||||
imageInspect.Container = "" //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45.
|
||||
imageInspect.ContainerConfig = nil //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45.
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, imageInspect)
|
||||
}
|
||||
|
||||
func (s *imageRouter) toImageInspect(img *image.Image) (*types.ImageInspect, error) {
|
||||
refs := s.referenceBackend.References(img.ID().Digest())
|
||||
repoTags := []string{}
|
||||
repoDigests := []string{}
|
||||
for _, ref := range refs {
|
||||
func (ir *imageRouter) toImageInspect(img *image.Image) (*types.ImageInspect, error) {
|
||||
var repoTags, repoDigests []string
|
||||
for _, ref := range img.Details.References {
|
||||
switch ref.(type) {
|
||||
case reference.NamedTagged:
|
||||
repoTags = append(repoTags, reference.FamiliarString(ref))
|
||||
|
@ -230,30 +324,22 @@ func (s *imageRouter) toImageInspect(img *image.Image) (*types.ImageInspect, err
|
|||
}
|
||||
}
|
||||
|
||||
var size int64
|
||||
var layerMetadata map[string]string
|
||||
layerID := img.RootFS.ChainID()
|
||||
if layerID != "" {
|
||||
l, err := s.layerStore.Get(layerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer layer.ReleaseAndLog(s.layerStore, l)
|
||||
size = l.Size()
|
||||
layerMetadata, err = l.Metadata()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
comment := img.Comment
|
||||
if len(comment) == 0 && len(img.History) > 0 {
|
||||
comment = img.History[len(img.History)-1].Comment
|
||||
}
|
||||
|
||||
lastUpdated, err := s.imageStore.GetLastUpdated(img.ID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Make sure we output empty arrays instead of nil.
|
||||
if repoTags == nil {
|
||||
repoTags = []string{}
|
||||
}
|
||||
if repoDigests == nil {
|
||||
repoDigests = []string{}
|
||||
}
|
||||
|
||||
var created string
|
||||
if img.Created != nil {
|
||||
created = img.Created.Format(time.RFC3339Nano)
|
||||
}
|
||||
|
||||
return &types.ImageInspect{
|
||||
|
@ -262,9 +348,9 @@ func (s *imageRouter) toImageInspect(img *image.Image) (*types.ImageInspect, err
|
|||
RepoDigests: repoDigests,
|
||||
Parent: img.Parent.String(),
|
||||
Comment: comment,
|
||||
Created: img.Created.Format(time.RFC3339Nano),
|
||||
Container: img.Container,
|
||||
ContainerConfig: &img.ContainerConfig,
|
||||
Created: created,
|
||||
Container: img.Container, //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45.
|
||||
ContainerConfig: &img.ContainerConfig, //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.45.
|
||||
DockerVersion: img.DockerVersion,
|
||||
Author: img.Author,
|
||||
Config: img.Config,
|
||||
|
@ -272,15 +358,14 @@ func (s *imageRouter) toImageInspect(img *image.Image) (*types.ImageInspect, err
|
|||
Variant: img.Variant,
|
||||
Os: img.OperatingSystem(),
|
||||
OsVersion: img.OSVersion,
|
||||
Size: size,
|
||||
VirtualSize: size, // TODO: field unused, deprecate
|
||||
Size: img.Details.Size,
|
||||
GraphDriver: types.GraphDriverData{
|
||||
Name: s.layerStore.DriverName(),
|
||||
Data: layerMetadata,
|
||||
Name: img.Details.Driver,
|
||||
Data: img.Details.Metadata,
|
||||
},
|
||||
RootFS: rootFSToAPIType(img.RootFS),
|
||||
Metadata: types.ImageMetadata{
|
||||
LastTagTime: lastUpdated,
|
||||
Metadata: imagetypes.Metadata{
|
||||
LastTagTime: img.Details.LastUpdated,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
@ -296,7 +381,7 @@ func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -321,7 +406,7 @@ func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
|||
sharedSize = httputils.BoolValue(r, "shared-size")
|
||||
}
|
||||
|
||||
images, err := s.backend.Images(ctx, types.ImageListOptions{
|
||||
images, err := ir.backend.Images(ctx, imagetypes.ListOptions{
|
||||
All: httputils.BoolValue(r, "all"),
|
||||
Filters: imageFilters,
|
||||
SharedSize: sharedSize,
|
||||
|
@ -330,12 +415,32 @@ func (s *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
|||
return err
|
||||
}
|
||||
|
||||
useNone := versions.LessThan(version, "1.43")
|
||||
withVirtualSize := versions.LessThan(version, "1.44")
|
||||
for _, img := range images {
|
||||
if useNone {
|
||||
if len(img.RepoTags) == 0 && len(img.RepoDigests) == 0 {
|
||||
img.RepoTags = append(img.RepoTags, "<none>:<none>")
|
||||
img.RepoDigests = append(img.RepoDigests, "<none>@<none>")
|
||||
}
|
||||
} else {
|
||||
if img.RepoTags == nil {
|
||||
img.RepoTags = []string{}
|
||||
}
|
||||
if img.RepoDigests == nil {
|
||||
img.RepoDigests = []string{}
|
||||
}
|
||||
}
|
||||
if withVirtualSize {
|
||||
img.VirtualSize = img.Size //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
|
||||
}
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, images)
|
||||
}
|
||||
|
||||
func (s *imageRouter) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
name := vars["name"]
|
||||
history, err := s.backend.ImageHistory(name)
|
||||
func (ir *imageRouter) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
history, err := ir.backend.ImageHistory(ctx, vars["name"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -343,40 +448,37 @@ func (s *imageRouter) getImagesHistory(ctx context.Context, w http.ResponseWrite
|
|||
return httputils.WriteJSON(w, http.StatusOK, history)
|
||||
}
|
||||
|
||||
func (s *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (ir *imageRouter) postImagesTag(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 := s.backend.TagImage(vars["name"], r.Form.Get("repo"), r.Form.Get("tag")); err != nil {
|
||||
|
||||
ref, err := httputils.RepoTagReference(r.Form.Get("repo"), r.Form.Get("tag"))
|
||||
if ref == nil || err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
refName := reference.FamiliarName(ref)
|
||||
if refName == string(digest.Canonical) {
|
||||
return errdefs.InvalidParameter(errors.New("refusing to create an ambiguous tag using digest algorithm as name"))
|
||||
}
|
||||
|
||||
img, err := ir.backend.GetImage(ctx, vars["name"], backend.GetImageOpts{})
|
||||
if err != nil {
|
||||
return errdefs.NotFound(err)
|
||||
}
|
||||
|
||||
if err := ir.backend.TagImage(ctx, img.ID(), ref); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (ir *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
config *types.AuthConfig
|
||||
authEncoded = r.Header.Get("X-Registry-Auth")
|
||||
headers = map[string][]string{}
|
||||
)
|
||||
|
||||
if authEncoded != "" {
|
||||
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
|
||||
if err := json.NewDecoder(authJSON).Decode(&config); err != nil {
|
||||
// for a search it is not an error if no auth was given
|
||||
// to increase compatibility with the existing api it is defaulting to be empty
|
||||
config = &types.AuthConfig{}
|
||||
}
|
||||
}
|
||||
for k, v := range r.Header {
|
||||
if strings.HasPrefix(k, "X-Meta-") {
|
||||
headers[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
var limit int
|
||||
if r.Form.Get("limit") != "" {
|
||||
|
@ -391,14 +493,26 @@ func (s *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWriter
|
|||
return err
|
||||
}
|
||||
|
||||
query, err := s.backend.SearchRegistryForImages(ctx, searchFilters, r.Form.Get("term"), limit, config, headers)
|
||||
// For a search it is not an error if no auth was given. Ignore invalid
|
||||
// AuthConfig to increase compatibility with the existing API.
|
||||
authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader))
|
||||
|
||||
headers := http.Header{}
|
||||
for k, v := range r.Header {
|
||||
k = http.CanonicalHeaderKey(k)
|
||||
if strings.HasPrefix(k, "X-Meta-") {
|
||||
headers[k] = v
|
||||
}
|
||||
}
|
||||
headers.Set("User-Agent", dockerversion.DockerUserAgent(ctx))
|
||||
res, err := ir.searcher.Search(ctx, searchFilters, r.Form.Get("term"), limit, authConfig, headers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, query.Results)
|
||||
return httputils.WriteJSON(w, http.StatusOK, res)
|
||||
}
|
||||
|
||||
func (s *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (ir *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -408,9 +522,18 @@ func (s *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWriter
|
|||
return err
|
||||
}
|
||||
|
||||
pruneReport, err := s.backend.ImagesPrune(ctx, pruneFilters)
|
||||
pruneReport, err := ir.backend.ImagesPrune(ctx, pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, pruneReport)
|
||||
}
|
||||
|
||||
// validateRepoName validates the name of a repository.
|
||||
func validateRepoName(name reference.Named) error {
|
||||
familiarName := reference.FamiliarName(name)
|
||||
if familiarName == api.NoBaseImageSpecifier {
|
||||
return fmt.Errorf("'%s' is a reserved name", familiarName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -4,16 +4,15 @@ import (
|
|||
"context"
|
||||
|
||||
"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/network"
|
||||
"github.com/docker/docker/libnetwork"
|
||||
)
|
||||
|
||||
// Backend is all the methods that need to be implemented
|
||||
// to provide network specific functionality.
|
||||
type Backend interface {
|
||||
FindNetwork(idName string) (libnetwork.Network, error)
|
||||
GetNetworks(filters.Args, types.NetworkListConfig) ([]types.NetworkResource, error)
|
||||
GetNetworks(filters.Args, backend.NetworkListConfig) ([]types.NetworkResource, error)
|
||||
CreateNetwork(nc types.NetworkCreateRequest) (*types.NetworkCreateResponse, error)
|
||||
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
|
||||
DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
package network // import "github.com/docker/docker/api/server/router/network"
|
|
@ -8,12 +8,13 @@ import (
|
|||
|
||||
"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/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libnetwork"
|
||||
netconst "github.com/docker/docker/libnetwork/datastore"
|
||||
"github.com/docker/docker/libnetwork/scope"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -39,7 +40,7 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit
|
|||
|
||||
// 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")})
|
||||
localNetworks, err := n.backend.GetNetworks(filter, backend.NetworkListConfig{Detailed: versions.LessThan(httputils.VersionFromContext(ctx), "1.28")})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -83,10 +84,6 @@ func (e ambigousResultsError) Error() string {
|
|||
|
||||
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
|
||||
|
@ -102,7 +99,7 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
|||
return errors.Wrapf(invalidRequestError{err}, "invalid value for verbose: %s", v)
|
||||
}
|
||||
}
|
||||
scope := r.URL.Query().Get("scope")
|
||||
networkScope := 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?
|
||||
|
@ -118,23 +115,23 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
|||
// 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)
|
||||
if networkScope != "" {
|
||||
filter.Add("scope", networkScope)
|
||||
}
|
||||
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)
|
||||
networks, _ := n.backend.GetNetworks(filter, backend.NetworkListConfig{Detailed: true, Verbose: verbose})
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, nw)
|
||||
}
|
||||
if network.Name == term {
|
||||
if nw.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
|
||||
listByFullName[nw.ID] = nw
|
||||
}
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
if strings.HasPrefix(nw.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
|
||||
listByPartialID[nw.ID] = nw
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +141,7 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
|||
// 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 strings.HasPrefix(nwk.ID, term) || networkScope == scope.Swarm {
|
||||
// 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 {
|
||||
|
@ -156,25 +153,25 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
|||
}
|
||||
}
|
||||
|
||||
nr, _ := n.cluster.GetNetworks(filter)
|
||||
for _, network := range nr {
|
||||
if network.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, network)
|
||||
networks, _ = n.cluster.GetNetworks(filter)
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, nw)
|
||||
}
|
||||
if network.Name == term {
|
||||
if nw.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 _, ok := listByFullName[nw.ID]; !ok {
|
||||
listByFullName[nw.ID] = nw
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
if strings.HasPrefix(nw.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
|
||||
if _, ok := listByPartialID[nw.ID]; !ok {
|
||||
listByPartialID[nw.ID] = nw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,21 +210,15 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
|
|||
}
|
||||
|
||||
if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 {
|
||||
return nameConflict(create.Name)
|
||||
return libnetwork.NetworkNameError(create.Name)
|
||||
}
|
||||
|
||||
// For a Swarm-scoped network, this call to backend.CreateNetwork is used to
|
||||
// validate the configuration. The network will not be created but, if the
|
||||
// configuration is valid, ManagerRedirectError will be returned and handled
|
||||
// below.
|
||||
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
|
||||
}
|
||||
|
@ -236,8 +227,7 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
|
|||
return err
|
||||
}
|
||||
nw = &types.NetworkCreateResponse{
|
||||
ID: id,
|
||||
Warning: warning,
|
||||
ID: id,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,42 +316,42 @@ func (n *networkRouter) findUniqueNetwork(term string) (types.NetworkResource, e
|
|||
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
|
||||
networks, _ := n.backend.GetNetworks(filter, backend.NetworkListConfig{Detailed: true})
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return nw, nil
|
||||
}
|
||||
if network.Name == term && !network.Ingress {
|
||||
if nw.Name == term && !nw.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
|
||||
listByFullName[nw.ID] = nw
|
||||
}
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
if strings.HasPrefix(nw.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
|
||||
listByPartialID[nw.ID] = nw
|
||||
}
|
||||
}
|
||||
|
||||
nr, _ := n.cluster.GetNetworks(filter)
|
||||
for _, network := range nr {
|
||||
if network.ID == term {
|
||||
return network, nil
|
||||
networks, _ = n.cluster.GetNetworks(filter)
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return nw, nil
|
||||
}
|
||||
if network.Name == term {
|
||||
if nw.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 _, ok := listByFullName[nw.ID]; !ok {
|
||||
listByFullName[nw.ID] = nw
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
if strings.HasPrefix(nw.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
|
||||
if _, ok := listByPartialID[nw.ID]; !ok {
|
||||
listByPartialID[nw.ID] = nw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,23 +5,25 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
enginetypes "github.com/docker/docker/api/types"
|
||||
"github.com/distribution/reference"
|
||||
"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/registry"
|
||||
"github.com/docker/docker/plugin"
|
||||
)
|
||||
|
||||
// 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)
|
||||
Inspect(name string) (*enginetypes.Plugin, error)
|
||||
Remove(name string, config *enginetypes.PluginRmConfig) error
|
||||
Disable(name string, config *backend.PluginDisableConfig) error
|
||||
Enable(name string, config *backend.PluginEnableConfig) error
|
||||
List(filters.Args) ([]types.Plugin, error)
|
||||
Inspect(name string) (*types.Plugin, error)
|
||||
Remove(name string, config *backend.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
|
||||
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
|
||||
Privileges(ctx context.Context, ref reference.Named, metaHeaders http.Header, authConfig *registry.AuthConfig) (types.PluginPrivileges, error)
|
||||
Pull(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer, opts ...plugin.CreateOpt) error
|
||||
Push(ctx context.Context, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, outStream io.Writer) error
|
||||
Upgrade(ctx context.Context, ref reference.Named, name string, metaHeaders http.Header, authConfig *registry.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer) error
|
||||
CreateFromContext(ctx context.Context, tarCtx io.ReadCloser, options *types.PluginCreateOptions) error
|
||||
}
|
||||
|
|
|
@ -2,23 +2,22 @@ package plugin // import "github.com/docker/docker/api/server/router/plugin"
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/distribution/reference"
|
||||
"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/filters"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func parseHeaders(headers http.Header) (map[string][]string, *types.AuthConfig) {
|
||||
|
||||
func parseHeaders(headers http.Header) (map[string][]string, *registry.AuthConfig) {
|
||||
metaHeaders := map[string][]string{}
|
||||
for k, v := range headers {
|
||||
if strings.HasPrefix(k, "X-Meta-") {
|
||||
|
@ -26,16 +25,8 @@ func parseHeaders(headers http.Header) (map[string][]string, *types.AuthConfig)
|
|||
}
|
||||
}
|
||||
|
||||
// Get X-Registry-Auth
|
||||
authEncoded := headers.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 {
|
||||
authConfig = &types.AuthConfig{}
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore invalid AuthConfig to increase compatibility with the existing API.
|
||||
authConfig, _ := registry.DecodeAuthConfig(headers.Get(registry.AuthHeader))
|
||||
return metaHeaders, authConfig
|
||||
}
|
||||
|
||||
|
@ -196,7 +187,8 @@ func (pr *pluginRouter) createPlugin(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
options := &types.PluginCreateOptions{
|
||||
RepoName: r.FormValue("name")}
|
||||
RepoName: r.FormValue("name"),
|
||||
}
|
||||
|
||||
if err := pr.backend.CreateFromContext(ctx, r.Body, options); err != nil {
|
||||
return err
|
||||
|
@ -216,7 +208,7 @@ func (pr *pluginRouter) enablePlugin(ctx context.Context, w http.ResponseWriter,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config := &types.PluginEnableConfig{Timeout: timeout}
|
||||
config := &backend.PluginEnableConfig{Timeout: timeout}
|
||||
|
||||
return pr.backend.Enable(name, config)
|
||||
}
|
||||
|
@ -227,7 +219,7 @@ func (pr *pluginRouter) disablePlugin(ctx context.Context, w http.ResponseWriter
|
|||
}
|
||||
|
||||
name := vars["name"]
|
||||
config := &types.PluginDisableConfig{
|
||||
config := &backend.PluginDisableConfig{
|
||||
ForceDisable: httputils.BoolValue(r, "force"),
|
||||
}
|
||||
|
||||
|
@ -240,7 +232,7 @@ func (pr *pluginRouter) removePlugin(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
name := vars["name"]
|
||||
config := &types.PluginRmConfig{
|
||||
config := &backend.PluginRmConfig{
|
||||
ForceRemove: httputils.BoolValue(r, "force"),
|
||||
}
|
||||
return pr.backend.Remove(name, config)
|
||||
|
|
|
@ -3,46 +3,41 @@ package swarm // import "github.com/docker/docker/api/server/router/swarm"
|
|||
import (
|
||||
"context"
|
||||
|
||||
basictypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
types "github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
)
|
||||
|
||||
// Backend abstracts a swarm manager.
|
||||
type Backend interface {
|
||||
Init(req types.InitRequest) (string, error)
|
||||
Join(req types.JoinRequest) error
|
||||
Leave(force bool) error
|
||||
Inspect() (types.Swarm, error)
|
||||
Update(uint64, types.Spec, types.UpdateFlags) error
|
||||
Init(req swarm.InitRequest) (string, error)
|
||||
Join(req swarm.JoinRequest) error
|
||||
Leave(ctx context.Context, force bool) error
|
||||
Inspect() (swarm.Swarm, error)
|
||||
Update(uint64, swarm.Spec, swarm.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)
|
||||
UnlockSwarm(req swarm.UnlockRequest) error
|
||||
GetServices(types.ServiceListOptions) ([]swarm.Service, error)
|
||||
GetService(idOrName string, insertDefaults bool) (swarm.Service, error)
|
||||
CreateService(swarm.ServiceSpec, string, bool) (*swarm.ServiceCreateResponse, error)
|
||||
UpdateService(string, uint64, swarm.ServiceSpec, types.ServiceUpdateOptions, bool) (*swarm.ServiceUpdateResponse, error)
|
||||
RemoveService(string) error
|
||||
|
||||
ServiceLogs(context.Context, *backend.LogSelector, *basictypes.ContainerLogsOptions) (<-chan *backend.LogMessage, error)
|
||||
|
||||
GetNodes(basictypes.NodeListOptions) ([]types.Node, error)
|
||||
GetNode(string) (types.Node, error)
|
||||
UpdateNode(string, uint64, types.NodeSpec) error
|
||||
ServiceLogs(context.Context, *backend.LogSelector, *container.LogsOptions) (<-chan *backend.LogMessage, error)
|
||||
GetNodes(types.NodeListOptions) ([]swarm.Node, error)
|
||||
GetNode(string) (swarm.Node, error)
|
||||
UpdateNode(string, uint64, swarm.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)
|
||||
GetTasks(types.TaskListOptions) ([]swarm.Task, error)
|
||||
GetTask(string) (swarm.Task, error)
|
||||
GetSecrets(opts types.SecretListOptions) ([]swarm.Secret, error)
|
||||
CreateSecret(s swarm.SecretSpec) (string, error)
|
||||
RemoveSecret(idOrName 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)
|
||||
GetSecret(id string) (swarm.Secret, error)
|
||||
UpdateSecret(idOrName string, version uint64, spec swarm.SecretSpec) error
|
||||
GetConfigs(opts types.ConfigListOptions) ([]swarm.Config, error)
|
||||
CreateConfig(s swarm.ConfigSpec) (string, error)
|
||||
RemoveConfig(id string) error
|
||||
GetConfig(id string) (types.Config, error)
|
||||
UpdateConfig(idOrName string, version uint64, spec types.ConfigSpec) error
|
||||
GetConfig(id string) (swarm.Config, error)
|
||||
UpdateConfig(idOrName string, version uint64, spec swarm.ConfigSpec) error
|
||||
}
|
||||
|
|
|
@ -6,15 +6,16 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"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"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
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"
|
||||
)
|
||||
|
||||
func (sr *swarmRouter) initCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -35,7 +36,7 @@ func (sr *swarmRouter) initCluster(ctx context.Context, w http.ResponseWriter, r
|
|||
}
|
||||
nodeID, err := sr.backend.Init(req)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error initializing swarm: %v", err)
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error initializing swarm")
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, nodeID)
|
||||
|
@ -55,13 +56,13 @@ func (sr *swarmRouter) leaveCluster(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
force := httputils.BoolValue(r, "force")
|
||||
return sr.backend.Leave(force)
|
||||
return sr.backend.Leave(ctx, force)
|
||||
}
|
||||
|
||||
func (sr *swarmRouter) inspectCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
swarm, err := sr.backend.Inspect()
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting swarm: %v", err)
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting swarm")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -113,7 +114,7 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
if err := sr.backend.Update(version, swarm, flags); err != nil {
|
||||
logrus.Errorf("Error configuring swarm: %v", err)
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error configuring swarm")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -126,7 +127,7 @@ func (sr *swarmRouter) unlockCluster(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
|
||||
if err := sr.backend.UnlockSwarm(req); err != nil {
|
||||
logrus.Errorf("Error unlocking swarm: %v", err)
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error unlocking swarm")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -135,7 +136,7 @@ func (sr *swarmRouter) unlockCluster(ctx context.Context, w http.ResponseWriter,
|
|||
func (sr *swarmRouter) getUnlockKey(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
unlockKey, err := sr.backend.GetUnlockKey()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("Error retrieving swarm unlock key")
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error retrieving swarm unlock key")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -167,7 +168,7 @@ func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r
|
|||
|
||||
services, err := sr.backend.GetServices(basictypes.ServiceListOptions{Filters: filter, Status: status})
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting services: %v", err)
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting services")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -193,7 +194,10 @@ func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r
|
|||
|
||||
service, err := sr.backend.GetService(vars["id"], insertDefaults)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting service %s: %v", vars["id"], err)
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
"error": err,
|
||||
"service-id": vars["id"],
|
||||
}).Debug("Error getting service")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -205,9 +209,13 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
|
|||
if err := httputils.ReadJSON(r, &service); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(thaJeztah): remove logentries check and migration code in release v26.0.0.
|
||||
if service.TaskTemplate.LogDriver != nil && service.TaskTemplate.LogDriver.Name == "logentries" {
|
||||
return errdefs.InvalidParameter(errors.New("the logentries logging driver has been deprecated and removed"))
|
||||
}
|
||||
|
||||
// Get returns "" if the header does not exist
|
||||
encodedAuth := r.Header.Get("X-Registry-Auth")
|
||||
encodedAuth := r.Header.Get(registry.AuthHeader)
|
||||
queryRegistry := false
|
||||
if v := httputils.VersionFromContext(ctx); v != "" {
|
||||
if versions.LessThan(v, "1.30") {
|
||||
|
@ -215,9 +223,21 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
adjustForAPIVersion(v, &service)
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.LessThan(version, "1.44") {
|
||||
if service.TaskTemplate.ContainerSpec != nil && service.TaskTemplate.ContainerSpec.Healthcheck != nil {
|
||||
// StartInterval was added in API 1.44
|
||||
service.TaskTemplate.ContainerSpec.Healthcheck.StartInterval = 0
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := sr.backend.CreateService(service, encodedAuth, queryRegistry)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error creating service %s: %v", service.Name, err)
|
||||
log.G(ctx).WithFields(log.Fields{
|
||||
"error": err,
|
||||
"service-name": service.Name,
|
||||
}).Debug("Error creating service")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -229,6 +249,10 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
|
|||
if err := httputils.ReadJSON(r, &service); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(thaJeztah): remove logentries check and migration code in release v26.0.0.
|
||||
if service.TaskTemplate.LogDriver != nil && service.TaskTemplate.LogDriver.Name == "logentries" {
|
||||
return errdefs.InvalidParameter(errors.New("the logentries logging driver has been deprecated and removed"))
|
||||
}
|
||||
|
||||
rawVersion := r.URL.Query().Get("version")
|
||||
version, err := strconv.ParseUint(rawVersion, 10, 64)
|
||||
|
@ -240,7 +264,7 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
|
|||
var flags basictypes.ServiceUpdateOptions
|
||||
|
||||
// Get returns "" if the header does not exist
|
||||
flags.EncodedRegistryAuth = r.Header.Get("X-Registry-Auth")
|
||||
flags.EncodedRegistryAuth = r.Header.Get(registry.AuthHeader)
|
||||
flags.RegistryAuthFrom = r.URL.Query().Get("registryAuthFrom")
|
||||
flags.Rollback = r.URL.Query().Get("rollback")
|
||||
queryRegistry := false
|
||||
|
@ -253,7 +277,10 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
|
|||
|
||||
resp, err := sr.backend.UpdateService(vars["id"], version, service, flags, queryRegistry)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error updating service %s: %v", vars["id"], err)
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
"error": err,
|
||||
"service-id": vars["id"],
|
||||
}).Debug("Error updating service")
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, resp)
|
||||
|
@ -261,7 +288,10 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
|
|||
|
||||
func (sr *swarmRouter) removeService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := sr.backend.RemoveService(vars["id"]); err != nil {
|
||||
logrus.Errorf("Error removing service %s: %v", vars["id"], err)
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
"error": err,
|
||||
"service-id": vars["id"],
|
||||
}).Debug("Error removing service")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -302,7 +332,7 @@ func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *h
|
|||
|
||||
nodes, err := sr.backend.GetNodes(basictypes.NodeListOptions{Filters: filter})
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting nodes: %v", err)
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting nodes")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -312,7 +342,10 @@ func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *h
|
|||
func (sr *swarmRouter) getNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
node, err := sr.backend.GetNode(vars["id"])
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting node %s: %v", vars["id"], err)
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
"error": err,
|
||||
"node-id": vars["id"],
|
||||
}).Debug("Error getting node")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -333,7 +366,10 @@ func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r
|
|||
}
|
||||
|
||||
if err := sr.backend.UpdateNode(vars["id"], version, node); err != nil {
|
||||
logrus.Errorf("Error updating node %s: %v", vars["id"], err)
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
"error": err,
|
||||
"node-id": vars["id"],
|
||||
}).Debug("Error updating node")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -347,7 +383,10 @@ func (sr *swarmRouter) removeNode(ctx context.Context, w http.ResponseWriter, r
|
|||
force := httputils.BoolValue(r, "force")
|
||||
|
||||
if err := sr.backend.RemoveNode(vars["id"], force); err != nil {
|
||||
logrus.Errorf("Error removing node %s: %v", vars["id"], err)
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
"error": err,
|
||||
"node-id": vars["id"],
|
||||
}).Debug("Error removing node")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -364,7 +403,7 @@ func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *h
|
|||
|
||||
tasks, err := sr.backend.GetTasks(basictypes.TaskListOptions{Filters: filter})
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting tasks: %v", err)
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting tasks")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -374,7 +413,10 @@ func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *h
|
|||
func (sr *swarmRouter) getTask(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
task, err := sr.backend.GetTask(vars["id"])
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting task %s: %v", vars["id"], err)
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
"error": err,
|
||||
"task-id": vars["id"],
|
||||
}).Debug("Error getting task")
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"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/container"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
)
|
||||
|
@ -25,9 +26,9 @@ func (sr *swarmRouter) swarmLogs(ctx context.Context, w http.ResponseWriter, r *
|
|||
return fmt.Errorf("Bad parameters: you must choose at least one stream")
|
||||
}
|
||||
|
||||
// there is probably a neater way to manufacture the ContainerLogsOptions
|
||||
// there is probably a neater way to manufacture the LogsOptions
|
||||
// struct, probably in the caller, to eliminate the dependency on net/http
|
||||
logsConfig := &basictypes.ContainerLogsOptions{
|
||||
logsConfig := &container.LogsOptions{
|
||||
Follow: httputils.BoolValue(r, "follow"),
|
||||
Timestamps: httputils.BoolValue(r, "timestamps"),
|
||||
Since: r.Form.Get("since"),
|
||||
|
@ -118,4 +119,13 @@ func adjustForAPIVersion(cliVersion string, service *swarm.ServiceSpec) {
|
|||
service.Mode.ReplicatedJob = nil
|
||||
service.Mode.GlobalJob = nil
|
||||
}
|
||||
|
||||
if versions.LessThan(cliVersion, "1.44") {
|
||||
// seccomp, apparmor, and no_new_privs were added in 1.44.
|
||||
if service.TaskTemplate.ContainerSpec != nil && service.TaskTemplate.ContainerSpec.Privileges != nil {
|
||||
service.TaskTemplate.ContainerSpec.Privileges.Seccomp = nil
|
||||
service.TaskTemplate.ContainerSpec.Privileges.AppArmor = nil
|
||||
service.TaskTemplate.ContainerSpec.Privileges.NoNewPrivileges = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,7 @@ import (
|
|||
)
|
||||
|
||||
func TestAdjustForAPIVersion(t *testing.T) {
|
||||
var (
|
||||
expectedSysctls = map[string]string{"foo": "bar"}
|
||||
)
|
||||
expectedSysctls := map[string]string{"foo": "bar"}
|
||||
// testing the negative -- does this leave everything else alone? -- is
|
||||
// prohibitively time-consuming to write, because it would need an object
|
||||
// with literally every field filled in.
|
||||
|
@ -115,5 +113,4 @@ func TestAdjustForAPIVersion(t *testing.T) {
|
|||
if len(spec.TaskTemplate.ContainerSpec.Ulimits) != 0 {
|
||||
t.Error("Ulimits were not stripped from spec")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,9 @@ import (
|
|||
"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/registry"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/api/types/system"
|
||||
)
|
||||
|
||||
// DiskUsageOptions holds parameters for system disk usage query.
|
||||
|
@ -25,18 +27,18 @@ type DiskUsageOptions struct {
|
|||
// Backend is the methods that need to be implemented to provide
|
||||
// system specific functionality.
|
||||
type Backend interface {
|
||||
SystemInfo() *types.Info
|
||||
SystemVersion() types.Version
|
||||
SystemInfo(context.Context) (*system.Info, error)
|
||||
SystemVersion(context.Context) (types.Version, error)
|
||||
SystemDiskUsage(ctx context.Context, opts DiskUsageOptions) (*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)
|
||||
AuthenticateToRegistry(ctx context.Context, authConfig *registry.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
|
||||
Info(context.Context) swarm.Info
|
||||
}
|
||||
|
||||
// StatusProvider provides methods to get the swarm status of the current node.
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.19
|
||||
|
||||
package system // import "github.com/docker/docker/api/server/router/system"
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/api/types/system"
|
||||
buildkit "github.com/docker/docker/builder/builder-next"
|
||||
"resenje.org/singleflight"
|
||||
)
|
||||
|
||||
// systemRouter provides information about the Docker system overall.
|
||||
|
@ -12,11 +17,16 @@ type systemRouter struct {
|
|||
cluster ClusterBackend
|
||||
routes []router.Route
|
||||
builder *buildkit.Builder
|
||||
features *map[string]bool
|
||||
features func() map[string]bool
|
||||
|
||||
// collectSystemInfo is a single-flight for the /info endpoint,
|
||||
// unique per API version (as different API versions may return
|
||||
// a different API response).
|
||||
collectSystemInfo singleflight.Group[string, *system.Info]
|
||||
}
|
||||
|
||||
// NewRouter initializes a new system router
|
||||
func NewRouter(b Backend, c ClusterBackend, builder *buildkit.Builder, features *map[string]bool) router.Router {
|
||||
func NewRouter(b Backend, c ClusterBackend, builder *buildkit.Builder, features func() map[string]bool) router.Router {
|
||||
r := &systemRouter{
|
||||
backend: b,
|
||||
cluster: c,
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/router/build"
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -14,11 +15,11 @@ import (
|
|||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/api/types/system"
|
||||
timetypes "github.com/docker/docker/api/types/time"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
|
@ -31,7 +32,7 @@ func (s *systemRouter) pingHandler(ctx context.Context, w http.ResponseWriter, r
|
|||
w.Header().Add("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
w.Header().Add("Pragma", "no-cache")
|
||||
|
||||
builderVersion := build.BuilderVersion(*s.features)
|
||||
builderVersion := build.BuilderVersion(s.features())
|
||||
if bv := builderVersion; bv != "" {
|
||||
w.Header().Set("Builder-Version", string(bv))
|
||||
}
|
||||
|
@ -57,51 +58,58 @@ func (s *systemRouter) swarmStatus() string {
|
|||
}
|
||||
|
||||
func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
info := s.backend.SystemInfo()
|
||||
|
||||
if s.cluster != nil {
|
||||
info.Swarm = s.cluster.Info()
|
||||
info.Warnings = append(info.Warnings, info.Swarm.Warnings...)
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.LessThan(version, "1.25") {
|
||||
// TODO: handle this conversion in engine-api
|
||||
type oldInfo struct {
|
||||
*types.Info
|
||||
ExecutionDriver string
|
||||
}
|
||||
old := &oldInfo{
|
||||
Info: info,
|
||||
ExecutionDriver: "<not supported>",
|
||||
}
|
||||
nameOnlySecurityOptions := []string{}
|
||||
kvSecOpts, err := types.DecodeSecurityOptions(old.SecurityOptions)
|
||||
info, _, _ := s.collectSystemInfo.Do(ctx, version, func(ctx context.Context) (*system.Info, error) {
|
||||
info, err := s.backend.SystemInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
for _, s := range kvSecOpts {
|
||||
nameOnlySecurityOptions = append(nameOnlySecurityOptions, s.Name)
|
||||
|
||||
if s.cluster != nil {
|
||||
info.Swarm = s.cluster.Info(ctx)
|
||||
info.Warnings = append(info.Warnings, info.Swarm.Warnings...)
|
||||
}
|
||||
old.SecurityOptions = nameOnlySecurityOptions
|
||||
return httputils.WriteJSON(w, http.StatusOK, old)
|
||||
}
|
||||
if versions.LessThan(version, "1.39") {
|
||||
if info.KernelVersion == "" {
|
||||
info.KernelVersion = "<unknown>"
|
||||
|
||||
if versions.LessThan(version, "1.25") {
|
||||
// TODO: handle this conversion in engine-api
|
||||
kvSecOpts, err := system.DecodeSecurityOptions(info.SecurityOptions)
|
||||
if err != nil {
|
||||
info.Warnings = append(info.Warnings, err.Error())
|
||||
}
|
||||
var nameOnly []string
|
||||
for _, so := range kvSecOpts {
|
||||
nameOnly = append(nameOnly, so.Name)
|
||||
}
|
||||
info.SecurityOptions = nameOnly
|
||||
info.ExecutionDriver = "<not supported>" //nolint:staticcheck // ignore SA1019 (ExecutionDriver is deprecated)
|
||||
}
|
||||
if info.OperatingSystem == "" {
|
||||
info.OperatingSystem = "<unknown>"
|
||||
if versions.LessThan(version, "1.39") {
|
||||
if info.KernelVersion == "" {
|
||||
info.KernelVersion = "<unknown>"
|
||||
}
|
||||
if info.OperatingSystem == "" {
|
||||
info.OperatingSystem = "<unknown>"
|
||||
}
|
||||
}
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
info.KernelMemory = false
|
||||
}
|
||||
if versions.LessThan(version, "1.44") {
|
||||
for k, rt := range info.Runtimes {
|
||||
// Status field introduced in API v1.44.
|
||||
info.Runtimes[k] = system.RuntimeWithStatus{Runtime: rt.Runtime}
|
||||
}
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
info.KernelMemory = false
|
||||
}
|
||||
return info, nil
|
||||
})
|
||||
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, err := s.backend.SystemVersion(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, info)
|
||||
}
|
||||
|
@ -116,7 +124,7 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
|
|||
var getContainers, getImages, getVolumes, getBuildCache bool
|
||||
typeStrs, ok := r.Form["type"]
|
||||
if versions.LessThan(version, "1.42") || !ok {
|
||||
getContainers, getImages, getVolumes, getBuildCache = true, true, true, true
|
||||
getContainers, getImages, getVolumes, getBuildCache = true, true, true, s.builder != nil
|
||||
} else {
|
||||
for _, typ := range typeStrs {
|
||||
switch types.DiskUsageObject(typ) {
|
||||
|
@ -174,6 +182,20 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
|
|||
if versions.LessThan(version, "1.42") {
|
||||
for _, b := range buildCache {
|
||||
builderSize += b.Size
|
||||
// Parents field was added in API 1.42 to replace the Parent field.
|
||||
b.Parents = nil
|
||||
}
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
for _, b := range buildCache {
|
||||
// Parent field is deprecated in API v1.42 and up, as it is deprecated
|
||||
// in BuildKit. Empty the field to omit it in the API response.
|
||||
b.Parent = "" //nolint:staticcheck // ignore SA1019 (Parent field is deprecated)
|
||||
}
|
||||
}
|
||||
if versions.LessThan(version, "1.44") {
|
||||
for _, b := range systemDiskUsage.Images {
|
||||
b.VirtualSize = b.Size //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,7 +287,7 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
|||
case ev := <-l:
|
||||
jev, ok := ev.(events.Message)
|
||||
if !ok {
|
||||
logrus.Warnf("unexpected event message: %q", ev)
|
||||
log.G(ctx).Warnf("unexpected event message: %q", ev)
|
||||
continue
|
||||
}
|
||||
if err := enc.Encode(jev); err != nil {
|
||||
|
@ -274,14 +296,14 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
|||
case <-timeout:
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
logrus.Debug("Client context cancelled, stop sending events")
|
||||
log.G(ctx).Debug("Client context cancelled, stop sending events")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *systemRouter) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var config *types.AuthConfig
|
||||
var config *registry.AuthConfig
|
||||
err := json.NewDecoder(r.Body).Decode(&config)
|
||||
r.Body.Close()
|
||||
if err != nil {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
|
@ -13,7 +14,6 @@ import (
|
|||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/volume/service/opts"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -116,10 +116,10 @@ func (v *volumeRouter) postVolumesCreate(ctx context.Context, w http.ResponseWri
|
|||
// Instead, we will allow creating a volume with a duplicate name, which
|
||||
// should not break anything.
|
||||
if req.ClusterVolumeSpec != nil && versions.GreaterThanOrEqualTo(version, clusterVolumesVersion) {
|
||||
logrus.Debug("using cluster volume")
|
||||
log.G(ctx).Debug("using cluster volume")
|
||||
vol, err = v.cluster.CreateVolume(req)
|
||||
} else {
|
||||
logrus.Debug("using regular volume")
|
||||
log.G(ctx).Debug("using regular volume")
|
||||
vol, err = v.backend.Create(ctx, req.Name, req.Driver, opts.WithCreateOptions(req.DriverOpts), opts.WithCreateLabels(req.Labels))
|
||||
}
|
||||
|
||||
|
@ -159,20 +159,29 @@ func (v *volumeRouter) deleteVolumes(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
force := httputils.BoolValue(r, "force")
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
|
||||
// First we try deleting local volume. The volume may not be found as a
|
||||
// local volume, but could be a cluster volume, so we ignore "not found"
|
||||
// errors at this stage. Note that no "not found" error is produced if
|
||||
// "force" is enabled.
|
||||
err := v.backend.Remove(ctx, vars["name"], opts.WithPurgeOnError(force))
|
||||
if err != nil {
|
||||
if errdefs.IsNotFound(err) && versions.GreaterThanOrEqualTo(version, clusterVolumesVersion) && v.cluster.IsManager() {
|
||||
err := v.cluster.RemoveVolume(vars["name"], force)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
if err != nil && !errdefs.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If no volume was found, the volume may be a cluster volume. If force
|
||||
// is enabled, the volume backend won't return an error for non-existing
|
||||
// volumes, so we don't know if removal succeeded (or not volume existed).
|
||||
// In that case we always try to delete cluster volumes as well.
|
||||
if errdefs.IsNotFound(err) || force {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.GreaterThanOrEqualTo(version, clusterVolumesVersion) && v.cluster.IsManager() {
|
||||
err = v.cluster.RemoveVolume(vars["name"], force)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return nil
|
||||
}
|
||||
|
@ -187,6 +196,12 @@ func (v *volumeRouter) postVolumesPrune(ctx context.Context, w http.ResponseWrit
|
|||
return err
|
||||
}
|
||||
|
||||
// API version 1.42 changes behavior where prune should only prune anonymous volumes.
|
||||
// To keep older API behavior working, we need to add this filter option to consider all (local) volumes for pruning, not just anonymous ones.
|
||||
if versions.LessThan(httputils.VersionFromContext(ctx), "1.42") {
|
||||
pruneFilters.Add("all", "true")
|
||||
}
|
||||
|
||||
pruneReport, err := v.backend.Prune(ctx, pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -78,8 +78,7 @@ func TestGetVolumeByNameFoundRegular(t *testing.T) {
|
|||
v := &volumeRouter{
|
||||
backend: &fakeVolumeBackend{
|
||||
volumes: map[string]*volume.Volume{
|
||||
|
||||
"volume1": &volume.Volume{
|
||||
"volume1": {
|
||||
Name: "volume1",
|
||||
},
|
||||
},
|
||||
|
@ -98,7 +97,7 @@ func TestGetVolumeByNameFoundSwarm(t *testing.T) {
|
|||
swarm: true,
|
||||
manager: true,
|
||||
volumes: map[string]*volume.Volume{
|
||||
"volume1": &volume.Volume{
|
||||
"volume1": {
|
||||
Name: "volume1",
|
||||
},
|
||||
},
|
||||
|
@ -108,20 +107,21 @@ func TestGetVolumeByNameFoundSwarm(t *testing.T) {
|
|||
_, err := callGetVolume(v, "volume1")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestListVolumes(t *testing.T) {
|
||||
v := &volumeRouter{
|
||||
backend: &fakeVolumeBackend{
|
||||
volumes: map[string]*volume.Volume{
|
||||
"v1": &volume.Volume{Name: "v1"},
|
||||
"v2": &volume.Volume{Name: "v2"},
|
||||
"v1": {Name: "v1"},
|
||||
"v2": {Name: "v2"},
|
||||
},
|
||||
},
|
||||
cluster: &fakeClusterBackend{
|
||||
swarm: true,
|
||||
manager: true,
|
||||
volumes: map[string]*volume.Volume{
|
||||
"v3": &volume.Volume{Name: "v3"},
|
||||
"v4": &volume.Volume{Name: "v4"},
|
||||
"v3": {Name: "v3"},
|
||||
"v4": {Name: "v4"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ func TestListVolumesNoSwarm(t *testing.T) {
|
|||
v := &volumeRouter{
|
||||
backend: &fakeVolumeBackend{
|
||||
volumes: map[string]*volume.Volume{
|
||||
"v1": &volume.Volume{Name: "v1"},
|
||||
"v2": &volume.Volume{Name: "v2"},
|
||||
"v1": {Name: "v1"},
|
||||
"v2": {Name: "v2"},
|
||||
},
|
||||
},
|
||||
cluster: &fakeClusterBackend{},
|
||||
|
@ -155,8 +155,8 @@ func TestListVolumesNoManager(t *testing.T) {
|
|||
v := &volumeRouter{
|
||||
backend: &fakeVolumeBackend{
|
||||
volumes: map[string]*volume.Volume{
|
||||
"v1": &volume.Volume{Name: "v1"},
|
||||
"v2": &volume.Volume{Name: "v2"},
|
||||
"v1": {Name: "v1"},
|
||||
"v2": {Name: "v2"},
|
||||
},
|
||||
},
|
||||
cluster: &fakeClusterBackend{swarm: true},
|
||||
|
@ -318,7 +318,7 @@ func TestUpdateVolume(t *testing.T) {
|
|||
swarm: true,
|
||||
manager: true,
|
||||
volumes: map[string]*volume.Volume{
|
||||
"vol1": &volume.Volume{
|
||||
"vol1": {
|
||||
Name: "vo1",
|
||||
ClusterVolume: &volume.ClusterVolume{
|
||||
ID: "vol1",
|
||||
|
@ -409,7 +409,7 @@ func TestUpdateVolumeNotFound(t *testing.T) {
|
|||
func TestVolumeRemove(t *testing.T) {
|
||||
b := &fakeVolumeBackend{
|
||||
volumes: map[string]*volume.Volume{
|
||||
"vol1": &volume.Volume{
|
||||
"vol1": {
|
||||
Name: "vol1",
|
||||
},
|
||||
},
|
||||
|
@ -436,7 +436,7 @@ func TestVolumeRemoveSwarm(t *testing.T) {
|
|||
swarm: true,
|
||||
manager: true,
|
||||
volumes: map[string]*volume.Volume{
|
||||
"vol1": &volume.Volume{
|
||||
"vol1": {
|
||||
Name: "vol1",
|
||||
ClusterVolume: &volume.ClusterVolume{},
|
||||
},
|
||||
|
@ -494,7 +494,7 @@ func TestVolumeRemoveNotFoundNoManager(t *testing.T) {
|
|||
func TestVolumeRemoveFoundNoSwarm(t *testing.T) {
|
||||
b := &fakeVolumeBackend{
|
||||
volumes: map[string]*volume.Volume{
|
||||
"vol1": &volume.Volume{
|
||||
"vol1": {
|
||||
Name: "vol1",
|
||||
},
|
||||
},
|
||||
|
@ -518,7 +518,7 @@ func TestVolumeRemoveFoundNoSwarm(t *testing.T) {
|
|||
func TestVolumeRemoveNoSwarmInUse(t *testing.T) {
|
||||
b := &fakeVolumeBackend{
|
||||
volumes: map[string]*volume.Volume{
|
||||
"inuse": &volume.Volume{
|
||||
"inuse": {
|
||||
Name: "inuse",
|
||||
},
|
||||
},
|
||||
|
@ -544,7 +544,7 @@ func TestVolumeRemoveSwarmForce(t *testing.T) {
|
|||
swarm: true,
|
||||
manager: true,
|
||||
volumes: map[string]*volume.Volume{
|
||||
"vol1": &volume.Volume{
|
||||
"vol1": {
|
||||
Name: "vol1",
|
||||
ClusterVolume: &volume.ClusterVolume{},
|
||||
Options: map[string]string{"mustforce": "yes"},
|
||||
|
@ -574,6 +574,7 @@ func TestVolumeRemoveSwarmForce(t *testing.T) {
|
|||
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, len(b.volumes), 0)
|
||||
assert.Equal(t, len(c.volumes), 0)
|
||||
}
|
||||
|
||||
type fakeVolumeBackend struct {
|
||||
|
@ -616,9 +617,16 @@ func (b *fakeVolumeBackend) Create(_ context.Context, name, driverName string, _
|
|||
return v, nil
|
||||
}
|
||||
|
||||
func (b *fakeVolumeBackend) Remove(_ context.Context, name string, _ ...opts.RemoveOption) error {
|
||||
func (b *fakeVolumeBackend) Remove(_ context.Context, name string, o ...opts.RemoveOption) error {
|
||||
removeOpts := &opts.RemoveConfig{}
|
||||
for _, opt := range o {
|
||||
opt(removeOpts)
|
||||
}
|
||||
|
||||
if v, ok := b.volumes[name]; !ok {
|
||||
return errdefs.NotFound(fmt.Errorf("volume %s not found", name))
|
||||
if !removeOpts.PurgeOnError {
|
||||
return errdefs.NotFound(fmt.Errorf("volume %s not found", name))
|
||||
}
|
||||
} else if v.Name == "inuse" {
|
||||
return errdefs.Conflict(fmt.Errorf("volume in use"))
|
||||
}
|
||||
|
|
|
@ -2,124 +2,37 @@ package server // import "github.com/docker/docker/api/server"
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/httpstatus"
|
||||
"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/api/types"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
)
|
||||
|
||||
// versionMatcher defines a variable matcher to be parsed by the router
|
||||
// when a request is about to be served.
|
||||
const versionMatcher = "/v{version:[0-9.]+}"
|
||||
|
||||
// Config provides the configuration for the API server
|
||||
type Config struct {
|
||||
CorsHeaders string
|
||||
Version string
|
||||
SocketGroup string
|
||||
TLSConfig *tls.Config
|
||||
// Hosts is a list of addresses for the API to listen on.
|
||||
Hosts []string
|
||||
}
|
||||
|
||||
// Server contains instance details for the server
|
||||
type Server struct {
|
||||
cfg *Config
|
||||
servers []*HTTPServer
|
||||
routers []router.Router
|
||||
middlewares []middleware.Middleware
|
||||
}
|
||||
|
||||
// New returns a new instance of the server based on the specified configuration.
|
||||
// It allocates resources which will be needed for ServeAPI(ports, unix-sockets).
|
||||
func New(cfg *Config) *Server {
|
||||
return &Server{
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
// UseMiddleware appends a new middleware to the request chain.
|
||||
// This needs to be called before the API routes are configured.
|
||||
func (s *Server) UseMiddleware(m middleware.Middleware) {
|
||||
s.middlewares = append(s.middlewares, m)
|
||||
}
|
||||
|
||||
// Accept sets a listener the server accepts connections into.
|
||||
func (s *Server) Accept(addr string, listeners ...net.Listener) {
|
||||
for _, listener := range listeners {
|
||||
httpServer := &HTTPServer{
|
||||
srv: &http.Server{
|
||||
Addr: addr,
|
||||
},
|
||||
l: listener,
|
||||
}
|
||||
s.servers = append(s.servers, httpServer)
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes servers and thus stop receiving requests
|
||||
func (s *Server) Close() {
|
||||
for _, srv := range s.servers {
|
||||
if err := srv.Close(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// serveAPI loops through all initialized servers and spawns goroutine
|
||||
// with Serve method for each. It sets createMux() as Handler also.
|
||||
func (s *Server) serveAPI() error {
|
||||
var chErrors = make(chan error, len(s.servers))
|
||||
for _, srv := range s.servers {
|
||||
srv.srv.Handler = s.createMux()
|
||||
go func(srv *HTTPServer) {
|
||||
var err error
|
||||
logrus.Infof("API listen on %s", srv.l.Addr())
|
||||
if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
|
||||
err = nil
|
||||
}
|
||||
chErrors <- err
|
||||
}(srv)
|
||||
}
|
||||
|
||||
for range s.servers {
|
||||
err := <-chErrors
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HTTPServer contains an instance of http server and the listener.
|
||||
// srv *http.Server, contains configuration to create an http server and a mux router with all api end points.
|
||||
// l net.Listener, is a TCP or Socket listener that dispatches incoming request to the router.
|
||||
type HTTPServer struct {
|
||||
srv *http.Server
|
||||
l net.Listener
|
||||
}
|
||||
|
||||
// Serve starts listening for inbound requests.
|
||||
func (s *HTTPServer) Serve() error {
|
||||
return s.srv.Serve(s.l)
|
||||
}
|
||||
|
||||
// Close closes the HTTPServer from listening for the inbound requests.
|
||||
func (s *HTTPServer) Close() error {
|
||||
return s.l.Close()
|
||||
}
|
||||
|
||||
func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) makeHTTPHandler(handler httputils.APIFunc, operation string) http.HandlerFunc {
|
||||
return otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Define the context that we'll pass around to share info
|
||||
// like the docker-request-id.
|
||||
//
|
||||
|
@ -131,6 +44,7 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
|
|||
// use intermediate variable to prevent "should not use basic type
|
||||
// string as key in context.WithValue" golint errors
|
||||
ctx := context.WithValue(r.Context(), dockerversion.UAStringKey{}, r.Header.Get("User-Agent"))
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
handlerFunc := s.handlerWithGlobalMiddlewares(handler)
|
||||
|
||||
|
@ -142,65 +56,45 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
|
|||
if err := handlerFunc(ctx, w, r, vars); err != nil {
|
||||
statusCode := httpstatus.FromError(err)
|
||||
if statusCode >= 500 {
|
||||
logrus.Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
|
||||
log.G(ctx).Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
|
||||
}
|
||||
makeErrorHandler(err)(w, r)
|
||||
_ = httputils.WriteJSON(w, statusCode, &types.ErrorResponse{
|
||||
Message: err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}), operation).ServeHTTP
|
||||
}
|
||||
|
||||
// InitRouter initializes the list of routers for the server.
|
||||
// This method also enables the Go profiler.
|
||||
func (s *Server) InitRouter(routers ...router.Router) {
|
||||
s.routers = append(s.routers, routers...)
|
||||
}
|
||||
|
||||
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 {
|
||||
// CreateMux returns a new mux with all the routers registered.
|
||||
func (s *Server) CreateMux(routers ...router.Router) *mux.Router {
|
||||
m := mux.NewRouter()
|
||||
|
||||
logrus.Debug("Registering routers")
|
||||
for _, apiRouter := range s.routers {
|
||||
log.G(context.TODO()).Debug("Registering routers")
|
||||
for _, apiRouter := range routers {
|
||||
for _, r := range apiRouter.Routes() {
|
||||
f := s.makeHTTPHandler(r.Handler())
|
||||
f := s.makeHTTPHandler(r.Handler(), r.Method()+" "+r.Path())
|
||||
|
||||
logrus.Debugf("Registering %s, %s", r.Method(), r.Path())
|
||||
log.G(context.TODO()).Debugf("Registering %s, %s", r.Method(), r.Path())
|
||||
m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f)
|
||||
m.Path(r.Path()).Methods(r.Method()).Handler(f)
|
||||
}
|
||||
}
|
||||
|
||||
debugRouter := debug.NewRouter()
|
||||
s.routers = append(s.routers, debugRouter)
|
||||
for _, r := range debugRouter.Routes() {
|
||||
f := s.makeHTTPHandler(r.Handler())
|
||||
f := s.makeHTTPHandler(r.Handler(), r.Method()+" "+r.Path())
|
||||
m.Path("/debug" + r.Path()).Handler(f)
|
||||
}
|
||||
|
||||
notFoundHandler := makeErrorHandler(pageNotFoundError{})
|
||||
notFoundHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_ = httputils.WriteJSON(w, http.StatusNotFound, &types.ErrorResponse{
|
||||
Message: "page not found",
|
||||
})
|
||||
})
|
||||
|
||||
m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler)
|
||||
m.NotFoundHandler = notFoundHandler
|
||||
m.MethodNotAllowedHandler = notFoundHandler
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// Wait blocks the server goroutine until it exits.
|
||||
// It sends an error message if there is any error during
|
||||
// the API execution.
|
||||
func (s *Server) Wait(waitChan chan error) {
|
||||
if err := s.serveAPI(); err != nil {
|
||||
logrus.Errorf("ServeAPI error: %v", err)
|
||||
waitChan <- err
|
||||
return
|
||||
}
|
||||
waitChan <- nil
|
||||
}
|
||||
|
|
|
@ -13,14 +13,13 @@ import (
|
|||
)
|
||||
|
||||
func TestMiddlewares(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Version: "0.1omega2",
|
||||
}
|
||||
srv := &Server{
|
||||
cfg: cfg,
|
||||
}
|
||||
srv := &Server{}
|
||||
|
||||
srv.UseMiddleware(middleware.NewVersionMiddleware("0.1omega2", api.DefaultVersion, api.MinVersion))
|
||||
m, err := middleware.NewVersionMiddleware("0.1omega2", api.DefaultVersion, api.MinSupportedAPIVersion)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
srv.UseMiddleware(*m)
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
|
588
api/swagger.yaml
588
api/swagger.yaml
File diff suppressed because it is too large
Load diff
|
@ -1,22 +0,0 @@
|
|||
package types // import "github.com/docker/docker/api/types"
|
||||
|
||||
// AuthConfig contains authorization information for connecting to a Registry
|
||||
type AuthConfig struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Auth string `json:"auth,omitempty"`
|
||||
|
||||
// Email is an optional value associated with the username.
|
||||
// This field is deprecated and will be removed in a later
|
||||
// version of docker.
|
||||
Email string `json:"email,omitempty"`
|
||||
|
||||
ServerAddress string `json:"serveraddress,omitempty"`
|
||||
|
||||
// IdentityToken is used to authenticate the user and get
|
||||
// an access token for the registry.
|
||||
IdentityToken string `json:"identitytoken,omitempty"`
|
||||
|
||||
// RegistryToken is a bearer token to be sent to a registry
|
||||
RegistryToken string `json:"registrytoken,omitempty"`
|
||||
}
|
|
@ -5,9 +5,29 @@ import (
|
|||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// ContainerCreateConfig is the parameter set to ContainerCreate()
|
||||
type ContainerCreateConfig struct {
|
||||
Name string
|
||||
Config *container.Config
|
||||
HostConfig *container.HostConfig
|
||||
NetworkingConfig *network.NetworkingConfig
|
||||
Platform *ocispec.Platform
|
||||
DefaultReadOnlyNonRecursive bool
|
||||
}
|
||||
|
||||
// ContainerRmConfig holds arguments for the container remove
|
||||
// operation. This struct is used to tell the backend what operations
|
||||
// to perform.
|
||||
type ContainerRmConfig struct {
|
||||
ForceRemove, RemoveVolume, RemoveLink bool
|
||||
}
|
||||
|
||||
// ContainerAttachConfig holds the streams to use when connecting to a container to view logs.
|
||||
type ContainerAttachConfig struct {
|
||||
GetStreams func(multiplexed bool) (io.ReadCloser, io.Writer, io.Writer, error)
|
||||
|
@ -70,7 +90,6 @@ type ContainerStatsConfig struct {
|
|||
Stream bool
|
||||
OneShot bool
|
||||
OutStream io.Writer
|
||||
Version string
|
||||
}
|
||||
|
||||
// ExecInspect holds information about a running process started
|
||||
|
@ -102,8 +121,7 @@ type ExecProcessConfig struct {
|
|||
// CreateImageConfig is the configuration for creating an image from a
|
||||
// container.
|
||||
type CreateImageConfig struct {
|
||||
Repo string
|
||||
Tag string
|
||||
Tag reference.NamedTagged
|
||||
Pause bool
|
||||
Author string
|
||||
Comment string
|
||||
|
@ -111,6 +129,13 @@ type CreateImageConfig struct {
|
|||
Changes []string
|
||||
}
|
||||
|
||||
// GetImageOpts holds parameters to retrieve image information
|
||||
// from the backend.
|
||||
type GetImageOpts struct {
|
||||
Platform *ocispec.Platform
|
||||
Details bool
|
||||
}
|
||||
|
||||
// CommitConfig is the configuration for creating an image as part of a build.
|
||||
type CommitConfig struct {
|
||||
Author string
|
||||
|
@ -122,3 +147,25 @@ type CommitConfig struct {
|
|||
ContainerOS string
|
||||
ParentImageID string
|
||||
}
|
||||
|
||||
// PluginRmConfig holds arguments for plugin remove.
|
||||
type PluginRmConfig struct {
|
||||
ForceRemove bool
|
||||
}
|
||||
|
||||
// PluginEnableConfig holds arguments for plugin enable
|
||||
type PluginEnableConfig struct {
|
||||
Timeout int
|
||||
}
|
||||
|
||||
// PluginDisableConfig holds arguments for plugin disable.
|
||||
type PluginDisableConfig struct {
|
||||
ForceDisable bool
|
||||
}
|
||||
|
||||
// NetworkListConfig stores the options available for listing networks
|
||||
type NetworkListConfig struct {
|
||||
// TODO(@cpuguy83): naming is hard, this is pulled from what was being used in the router before moving here
|
||||
Detailed bool
|
||||
Verbose bool
|
||||
}
|
||||
|
|
|
@ -4,8 +4,9 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// PullOption defines different modes for accessing images
|
||||
|
@ -39,7 +40,7 @@ type BuildConfig struct {
|
|||
// GetImageAndLayerOptions are the options supported by GetImageAndReleasableLayer
|
||||
type GetImageAndLayerOptions struct {
|
||||
PullOption PullOption
|
||||
AuthConfig map[string]types.AuthConfig
|
||||
AuthConfig map[string]registry.AuthConfig
|
||||
Output io.Writer
|
||||
Platform *specs.Platform
|
||||
Platform *ocispec.Platform
|
||||
}
|
||||
|
|
7
api/types/checkpoint/list.go
Normal file
7
api/types/checkpoint/list.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package checkpoint
|
||||
|
||||
// Summary represents the details of a checkpoint when listing endpoints.
|
||||
type Summary struct {
|
||||
// Name is the name of the checkpoint.
|
||||
Name string
|
||||
}
|
19
api/types/checkpoint/options.go
Normal file
19
api/types/checkpoint/options.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package checkpoint
|
||||
|
||||
// CreateOptions holds parameters to create a checkpoint from a container.
|
||||
type CreateOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
Exit bool
|
||||
}
|
||||
|
||||
// ListOptions holds parameters to list checkpoints for a container.
|
||||
type ListOptions struct {
|
||||
CheckpointDir string
|
||||
}
|
||||
|
||||
// DeleteOptions holds parameters to delete a checkpoint from a container.
|
||||
type DeleteOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
}
|
|
@ -7,47 +7,10 @@ import (
|
|||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
units "github.com/docker/go-units"
|
||||
)
|
||||
|
||||
// CheckpointCreateOptions holds parameters to create a checkpoint from a container
|
||||
type CheckpointCreateOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
Exit bool
|
||||
}
|
||||
|
||||
// CheckpointListOptions holds parameters to list checkpoints for a container
|
||||
type CheckpointListOptions struct {
|
||||
CheckpointDir string
|
||||
}
|
||||
|
||||
// CheckpointDeleteOptions holds parameters to delete a checkpoint from a container
|
||||
type CheckpointDeleteOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
}
|
||||
|
||||
// ContainerAttachOptions holds parameters to attach to a container.
|
||||
type ContainerAttachOptions struct {
|
||||
Stream bool
|
||||
Stdin bool
|
||||
Stdout bool
|
||||
Stderr bool
|
||||
DetachKeys string
|
||||
Logs bool
|
||||
}
|
||||
|
||||
// ContainerCommitOptions holds parameters to commit changes into a container.
|
||||
type ContainerCommitOptions struct {
|
||||
Reference string
|
||||
Comment string
|
||||
Author string
|
||||
Changes []string
|
||||
Pause bool
|
||||
Config *container.Config
|
||||
}
|
||||
|
||||
// ContainerExecInspect holds information returned by exec inspect.
|
||||
type ContainerExecInspect struct {
|
||||
ExecID string `json:"ID"`
|
||||
|
@ -57,42 +20,6 @@ type ContainerExecInspect struct {
|
|||
Pid int
|
||||
}
|
||||
|
||||
// ContainerListOptions holds parameters to list containers with.
|
||||
type ContainerListOptions struct {
|
||||
Size bool
|
||||
All bool
|
||||
Latest bool
|
||||
Since string
|
||||
Before string
|
||||
Limit int
|
||||
Filters filters.Args
|
||||
}
|
||||
|
||||
// ContainerLogsOptions holds parameters to filter logs with.
|
||||
type ContainerLogsOptions struct {
|
||||
ShowStdout bool
|
||||
ShowStderr bool
|
||||
Since string
|
||||
Until string
|
||||
Timestamps bool
|
||||
Follow bool
|
||||
Tail string
|
||||
Details bool
|
||||
}
|
||||
|
||||
// ContainerRemoveOptions holds parameters to remove containers.
|
||||
type ContainerRemoveOptions struct {
|
||||
RemoveVolumes bool
|
||||
RemoveLinks bool
|
||||
Force bool
|
||||
}
|
||||
|
||||
// ContainerStartOptions holds parameters to start containers.
|
||||
type ContainerStartOptions struct {
|
||||
CheckpointID string
|
||||
CheckpointDir string
|
||||
}
|
||||
|
||||
// CopyToContainerOptions holds information
|
||||
// about files to copy into a container
|
||||
type CopyToContainerOptions struct {
|
||||
|
@ -180,7 +107,7 @@ type ImageBuildOptions struct {
|
|||
// at all (nil). See the parsing of buildArgs in
|
||||
// api/server/router/build/build_routes.go for even more info.
|
||||
BuildArgs map[string]*string
|
||||
AuthConfigs map[string]AuthConfig
|
||||
AuthConfigs map[string]registry.AuthConfig
|
||||
Context io.Reader
|
||||
Labels map[string]string
|
||||
// squash the resulting image's layers to the parent
|
||||
|
@ -230,42 +157,12 @@ type ImageBuildResponse struct {
|
|||
OSType string
|
||||
}
|
||||
|
||||
// ImageCreateOptions holds information to create images.
|
||||
type ImageCreateOptions struct {
|
||||
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry.
|
||||
Platform string // Platform is the target platform of the image if it needs to be pulled from the registry.
|
||||
}
|
||||
|
||||
// ImageImportSource holds source information for ImageImport
|
||||
type ImageImportSource struct {
|
||||
Source io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this.
|
||||
SourceName string // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute.
|
||||
}
|
||||
|
||||
// ImageImportOptions holds information to import images from the client host.
|
||||
type ImageImportOptions struct {
|
||||
Tag string // Tag is the name to tag this image with. This attribute is deprecated.
|
||||
Message string // Message is the message to tag the image with
|
||||
Changes []string // Changes are the raw changes to apply to this image
|
||||
Platform string // Platform is the target platform of the image
|
||||
}
|
||||
|
||||
// ImageListOptions holds parameters to list images with.
|
||||
type ImageListOptions struct {
|
||||
// All controls whether all images in the graph are filtered, or just
|
||||
// the heads.
|
||||
All bool
|
||||
|
||||
// Filters is a JSON-encoded set of filter arguments.
|
||||
Filters filters.Args
|
||||
|
||||
// SharedSize indicates whether the shared size of images should be computed.
|
||||
SharedSize bool
|
||||
|
||||
// ContainerCount indicates whether container count should be computed.
|
||||
ContainerCount bool
|
||||
}
|
||||
|
||||
// ImageLoadResponse returns information to the client about a load process.
|
||||
type ImageLoadResponse struct {
|
||||
// Body must be closed to avoid a resource leak
|
||||
|
@ -273,14 +170,6 @@ type ImageLoadResponse struct {
|
|||
JSON bool
|
||||
}
|
||||
|
||||
// ImagePullOptions holds information to pull images.
|
||||
type ImagePullOptions struct {
|
||||
All bool
|
||||
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
|
||||
PrivilegeFunc RequestPrivilegeFunc
|
||||
Platform string
|
||||
}
|
||||
|
||||
// RequestPrivilegeFunc is a function interface that
|
||||
// clients can supply to retry operations after
|
||||
// getting an authorization error.
|
||||
|
@ -289,15 +178,6 @@ type ImagePullOptions struct {
|
|||
// if the privilege request fails.
|
||||
type RequestPrivilegeFunc func() (string, error)
|
||||
|
||||
// ImagePushOptions holds information to push images.
|
||||
type ImagePushOptions ImagePullOptions
|
||||
|
||||
// ImageRemoveOptions holds parameters to remove images.
|
||||
type ImageRemoveOptions struct {
|
||||
Force bool
|
||||
PruneChildren bool
|
||||
}
|
||||
|
||||
// ImageSearchOptions holds parameters to search images with.
|
||||
type ImageSearchOptions struct {
|
||||
RegistryAuth string
|
||||
|
@ -306,14 +186,6 @@ type ImageSearchOptions struct {
|
|||
Limit int
|
||||
}
|
||||
|
||||
// ResizeOptions holds parameters to resize a tty.
|
||||
// It can be used to resize container ttys and
|
||||
// exec process ttys too.
|
||||
type ResizeOptions struct {
|
||||
Height uint
|
||||
Width uint
|
||||
}
|
||||
|
||||
// NodeListOptions holds parameters to list nodes with.
|
||||
type NodeListOptions struct {
|
||||
Filters filters.Args
|
||||
|
@ -339,15 +211,6 @@ type ServiceCreateOptions struct {
|
|||
QueryRegistry bool
|
||||
}
|
||||
|
||||
// ServiceCreateResponse contains the information returned to a client
|
||||
// on the creation of a new service.
|
||||
type ServiceCreateResponse struct {
|
||||
// ID is the ID of the created service.
|
||||
ID string
|
||||
// Warnings is a set of non-fatal warning messages to pass on to the user.
|
||||
Warnings []string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Values for RegistryAuthFrom in ServiceUpdateOptions
|
||||
const (
|
||||
RegistryAuthFromSpec = "spec"
|
||||
|
|
|
@ -1,32 +1,5 @@
|
|||
package types // import "github.com/docker/docker/api/types"
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// configs holds structs used for internal communication between the
|
||||
// frontend (such as an http server) and the backend (such as the
|
||||
// docker daemon).
|
||||
|
||||
// ContainerCreateConfig is the parameter set to ContainerCreate()
|
||||
type ContainerCreateConfig struct {
|
||||
Name string
|
||||
Config *container.Config
|
||||
HostConfig *container.HostConfig
|
||||
NetworkingConfig *network.NetworkingConfig
|
||||
Platform *specs.Platform
|
||||
AdjustCPUShares bool
|
||||
}
|
||||
|
||||
// ContainerRmConfig holds arguments for the container remove
|
||||
// operation. This struct is used to tell the backend what operations
|
||||
// to perform.
|
||||
type ContainerRmConfig struct {
|
||||
ForceRemove, RemoveVolume, RemoveLink bool
|
||||
}
|
||||
|
||||
// ExecConfig is a small subset of the Config struct that holds the configuration
|
||||
// for the exec feature of docker.
|
||||
type ExecConfig struct {
|
||||
|
@ -43,25 +16,3 @@ type ExecConfig struct {
|
|||
WorkingDir string // Working directory
|
||||
Cmd []string // Execution commands and args
|
||||
}
|
||||
|
||||
// PluginRmConfig holds arguments for plugin remove.
|
||||
type PluginRmConfig struct {
|
||||
ForceRemove bool
|
||||
}
|
||||
|
||||
// PluginEnableConfig holds arguments for plugin enable
|
||||
type PluginEnableConfig struct {
|
||||
Timeout int
|
||||
}
|
||||
|
||||
// PluginDisableConfig holds arguments for plugin disable.
|
||||
type PluginDisableConfig struct {
|
||||
ForceDisable bool
|
||||
}
|
||||
|
||||
// NetworkListConfig stores the options available for listing networks
|
||||
type NetworkListConfig struct {
|
||||
// TODO(@cpuguy83): naming is hard, this is pulled from what was being used in the router before moving here
|
||||
Detailed bool
|
||||
Verbose bool
|
||||
}
|
||||
|
|
15
api/types/container/change_type.go
Normal file
15
api/types/container/change_type.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package container
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
// ChangeType Kind of change
|
||||
//
|
||||
// Can be one of:
|
||||
//
|
||||
// - `0`: Modified ("C")
|
||||
// - `1`: Added ("A")
|
||||
// - `2`: Deleted ("D")
|
||||
//
|
||||
// swagger:model ChangeType
|
||||
type ChangeType uint8
|
23
api/types/container/change_types.go
Normal file
23
api/types/container/change_types.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package container
|
||||
|
||||
const (
|
||||
// ChangeModify represents the modify operation.
|
||||
ChangeModify ChangeType = 0
|
||||
// ChangeAdd represents the add operation.
|
||||
ChangeAdd ChangeType = 1
|
||||
// ChangeDelete represents the delete operation.
|
||||
ChangeDelete ChangeType = 2
|
||||
)
|
||||
|
||||
func (ct ChangeType) String() string {
|
||||
switch ct {
|
||||
case ChangeModify:
|
||||
return "C"
|
||||
case ChangeAdd:
|
||||
return "A"
|
||||
case ChangeDelete:
|
||||
return "D"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/go-connections/nat"
|
||||
dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// MinimumDuration puts a minimum on user configured duration.
|
||||
|
@ -33,25 +34,7 @@ type StopOptions struct {
|
|||
}
|
||||
|
||||
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
|
||||
type HealthConfig struct {
|
||||
// Test is the test to perform to check that the container is healthy.
|
||||
// An empty slice means to inherit the default.
|
||||
// The options are:
|
||||
// {} : inherit healthcheck
|
||||
// {"NONE"} : disable healthcheck
|
||||
// {"CMD", args...} : exec arguments directly
|
||||
// {"CMD-SHELL", command} : run command with system's default shell
|
||||
Test []string `json:",omitempty"`
|
||||
|
||||
// Zero means to inherit. Durations are expressed as integer nanoseconds.
|
||||
Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks.
|
||||
Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung.
|
||||
StartPeriod time.Duration `json:",omitempty"` // The start period for the container to initialize before the retries starts to count down.
|
||||
|
||||
// Retries is the number of consecutive failures needed to consider a container as unhealthy.
|
||||
// Zero means inherit.
|
||||
Retries int `json:",omitempty"`
|
||||
}
|
||||
type HealthConfig = dockerspec.HealthcheckConfig
|
||||
|
||||
// ExecStartOptions holds the options to start container's exec.
|
||||
type ExecStartOptions struct {
|
||||
|
@ -87,10 +70,13 @@ type Config struct {
|
|||
WorkingDir string // Current directory (PWD) in the command will be launched
|
||||
Entrypoint strslice.StrSlice // Entrypoint to run when starting the container
|
||||
NetworkDisabled bool `json:",omitempty"` // Is network disabled
|
||||
MacAddress string `json:",omitempty"` // Mac Address of the container
|
||||
OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile
|
||||
Labels map[string]string // List of labels set to this container
|
||||
StopSignal string `json:",omitempty"` // Signal to stop a container
|
||||
StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container
|
||||
Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
|
||||
// Mac Address of the container.
|
||||
//
|
||||
// Deprecated: this field is deprecated since API v1.44. Use EndpointSettings.MacAddress instead.
|
||||
MacAddress string `json:",omitempty"`
|
||||
OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile
|
||||
Labels map[string]string // List of labels set to this container
|
||||
StopSignal string `json:",omitempty"` // Signal to stop a container
|
||||
StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container
|
||||
Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
package container // import "github.com/docker/docker/api/types/container"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Code generated by `swagger generate operation`. DO NOT EDIT.
|
||||
//
|
||||
// See hack/generate-swagger-api.sh
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// ContainerChangeResponseItem change item in response to ContainerChanges operation
|
||||
// swagger:model ContainerChangeResponseItem
|
||||
type ContainerChangeResponseItem struct {
|
||||
|
||||
// Kind of change
|
||||
// Required: true
|
||||
Kind uint8 `json:"Kind"`
|
||||
|
||||
// Path to file that has changed
|
||||
// Required: true
|
||||
Path string `json:"Path"`
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue