mirror of
https://github.com/moby/moby.git
synced 2026-01-12 19:21:41 +00:00
Compare commits
569 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
852759a7df | ||
|
|
55fa16e22f | ||
|
|
f91551869e | ||
|
|
e0ce0ff8d5 | ||
|
|
02aa896934 | ||
|
|
e0b4fc1aae | ||
|
|
e264217787 | ||
|
|
e633d64982 | ||
|
|
76b88fb5ff | ||
|
|
b8bc11af70 | ||
|
|
8ffaef6d61 | ||
|
|
69b5ded97b | ||
|
|
257d4ec79a | ||
|
|
c593074455 | ||
|
|
f11b55ffec | ||
|
|
b3888ed899 | ||
|
|
a162f3c0f4 | ||
|
|
4977af06ee | ||
|
|
f87c7381b4 | ||
|
|
12627c2449 | ||
|
|
1ea6c4be57 | ||
|
|
4f26525b13 | ||
|
|
00f3d189e4 | ||
|
|
f110a9d310 | ||
|
|
b81579adf4 | ||
|
|
9d3a6a2133 | ||
|
|
f406728e41 | ||
|
|
6f483e7dbb | ||
|
|
a9f4dd168e | ||
|
|
d22068f8e3 | ||
|
|
fca702de7f | ||
|
|
f78a7726d7 | ||
|
|
61afffeeb3 | ||
|
|
b38e74c4e0 | ||
|
|
dac56638ad | ||
|
|
20e1af3616 | ||
|
|
858919d399 | ||
|
|
141ad39e38 | ||
|
|
db968c672b | ||
|
|
61c51fbb5a | ||
|
|
44e6f3da60 | ||
|
|
8a19bb7193 | ||
|
|
17af50f46b | ||
|
|
ffb63c0bae | ||
|
|
593b754d8f | ||
|
|
70d91b6799 | ||
|
|
2918d5869c | ||
|
|
73e729ff16 | ||
|
|
8b38739e3f | ||
|
|
3205a51dc5 | ||
|
|
2c69aba317 | ||
|
|
825d37b4c8 | ||
|
|
0bd850e91d | ||
|
|
7e8b823636 | ||
|
|
f483457e62 | ||
|
|
97433635a6 | ||
|
|
811585331c | ||
|
|
b5b8d18b44 | ||
|
|
fa9203d106 | ||
|
|
9e5b86f647 | ||
|
|
d49e068e55 | ||
|
|
aaff302323 | ||
|
|
0269da5c4e | ||
|
|
f928838f31 | ||
|
|
6af38fa650 | ||
|
|
40948c0c0e | ||
|
|
542fc0b225 | ||
|
|
4eb67b8666 | ||
|
|
511d1ff9e4 | ||
|
|
eb6829fbe1 | ||
|
|
bb380809cf | ||
|
|
f1ef52f46b | ||
|
|
73f189766e | ||
|
|
4b404144d2 | ||
|
|
77127f73e8 | ||
|
|
9322bca5da | ||
|
|
31c1dbc320 | ||
|
|
e7c3374177 | ||
|
|
2262f18df9 | ||
|
|
f35f4fd251 | ||
|
|
c174407f95 | ||
|
|
fda3acd7a6 | ||
|
|
293a701da6 | ||
|
|
854ca341c0 | ||
|
|
d052b06a73 | ||
|
|
dfcd445ce6 | ||
|
|
5331e7a65c | ||
|
|
1c9cd6a5f8 | ||
|
|
083ef6617b | ||
|
|
4d14c7db67 | ||
|
|
56c010e607 | ||
|
|
ca7e071d6e | ||
|
|
214fcf4fa7 | ||
|
|
99dfa74582 | ||
|
|
6da9a14f9a | ||
|
|
7960922b15 | ||
|
|
cf66ca7f6a | ||
|
|
4976360dfc | ||
|
|
b02250f248 | ||
|
|
20c3e748bd | ||
|
|
19266d1abb | ||
|
|
fd1e5c8812 | ||
|
|
ca3fc36ac9 | ||
|
|
4ee6efffda | ||
|
|
47244dc581 | ||
|
|
fac0982e6c | ||
|
|
123b6d815f | ||
|
|
f766b33a59 | ||
|
|
75a9dd1354 | ||
|
|
3d8f7d0683 | ||
|
|
2961e8c00a | ||
|
|
6d987381d5 | ||
|
|
f5c7673ff8 | ||
|
|
9d596a1bfa | ||
|
|
e6aa30b26e | ||
|
|
afcd2cde95 | ||
|
|
d0b5a5a8a5 | ||
|
|
f0b5ca47fb | ||
|
|
7cbc844564 | ||
|
|
bfbb1dd890 | ||
|
|
8a9a6702d0 | ||
|
|
56d9d85c99 | ||
|
|
cd849ff653 | ||
|
|
6d5c35c0ce | ||
|
|
311b9ff0aa | ||
|
|
af608045ee | ||
|
|
3cf363e1ee | ||
|
|
05d7386665 | ||
|
|
649c9440f2 | ||
|
|
9b20b1a5fe | ||
|
|
dd37b0b960 | ||
|
|
7058c0d24d | ||
|
|
57bd388582 | ||
|
|
05d95fd503 | ||
|
|
c2e7c32b34 | ||
|
|
2783345d3a | ||
|
|
a9e20aeaed | ||
|
|
a8d0a58b24 | ||
|
|
c981f8aff7 | ||
|
|
73814c48df | ||
|
|
7986f70a47 | ||
|
|
88eb323a7f | ||
|
|
535b70e90c | ||
|
|
dde5995051 | ||
|
|
8864727bae | ||
|
|
81d73e17f7 | ||
|
|
d8c62df0b6 | ||
|
|
d7a1fcef8f | ||
|
|
a22da0d5c4 | ||
|
|
85234039a6 | ||
|
|
9702281ba0 | ||
|
|
01860dc813 | ||
|
|
fad4b16c01 | ||
|
|
daf599ea0a | ||
|
|
1dffa3a814 | ||
|
|
f9b8a35ac4 | ||
|
|
a27bf4611e | ||
|
|
122b11a1fe | ||
|
|
58c1c7b8dc | ||
|
|
f87492689e | ||
|
|
3715eaf078 | ||
|
|
3b09657d72 | ||
|
|
31f49bd685 | ||
|
|
37796c7029 | ||
|
|
fa2f6f98be | ||
|
|
51dc5fb58f | ||
|
|
4e11c149d1 | ||
|
|
0b97ecddb0 | ||
|
|
710c748801 | ||
|
|
b340a777c0 | ||
|
|
e996dffe56 | ||
|
|
334719141c | ||
|
|
0702941de6 | ||
|
|
f0808d3673 | ||
|
|
bed0c789dd | ||
|
|
20c688f84d | ||
|
|
19039eae0b | ||
|
|
164a1a0f14 | ||
|
|
30fe6540a5 | ||
|
|
1320e79bd8 | ||
|
|
a1ba69a82b | ||
|
|
00108c57b5 | ||
|
|
1f3ea9841e | ||
|
|
74e3528a5a | ||
|
|
58224457c3 | ||
|
|
b81261f5c0 | ||
|
|
df983b7990 | ||
|
|
92563c9688 | ||
|
|
f014c349a0 | ||
|
|
eb2607b9f6 | ||
|
|
e2ab5f72eb | ||
|
|
ab7ac16a64 | ||
|
|
8216da20af | ||
|
|
1a7969545d | ||
|
|
c35376c455 | ||
|
|
5d4cc0b5b5 | ||
|
|
c78abd96ce | ||
|
|
6282d95b9e | ||
|
|
1d983e2e8a | ||
|
|
d2e9a19358 | ||
|
|
73f6053bb3 | ||
|
|
de13951b9d | ||
|
|
7741a89966 | ||
|
|
377af4c9b4 | ||
|
|
088cec8f0f | ||
|
|
8ff9ef2a7a | ||
|
|
ed2f5d1d85 | ||
|
|
aade22d31e | ||
|
|
1d10e8633d | ||
|
|
63422515ba | ||
|
|
49671250f6 | ||
|
|
e0661af25c | ||
|
|
b83f5a89f4 | ||
|
|
a7cc790265 | ||
|
|
20130006b7 | ||
|
|
e6c959b172 | ||
|
|
4ac2355d62 | ||
|
|
ac2a80fcc3 | ||
|
|
5eef5a7f59 | ||
|
|
aaf84dd4cf | ||
|
|
a99e62fa3d | ||
|
|
e239799583 | ||
|
|
bb22b8a418 | ||
|
|
fb6784bdf0 | ||
|
|
277429622f | ||
|
|
8d43772b09 | ||
|
|
74bf46aea6 | ||
|
|
b76a0c7d00 | ||
|
|
54953f2f5a | ||
|
|
e4ecfef405 | ||
|
|
3897724f4a | ||
|
|
821e6d8b42 | ||
|
|
0c131f58ba | ||
|
|
448ae33f87 | ||
|
|
3ce0dc7e35 | ||
|
|
600aa7b7a5 | ||
|
|
f1cc5760d9 | ||
|
|
215c6e7aec | ||
|
|
635524ea26 | ||
|
|
6f8cf86c30 | ||
|
|
ad7a03eb33 | ||
|
|
ff50c6e166 | ||
|
|
bb06416756 | ||
|
|
5d2c383d72 | ||
|
|
15bd07b4fd | ||
|
|
cc39fb9f6b | ||
|
|
bf2b8a05a0 | ||
|
|
e67f9dadc6 | ||
|
|
314b84b023 | ||
|
|
72947f5022 | ||
|
|
7e7bc0f1bc | ||
|
|
5f0df8c534 | ||
|
|
25b709df48 | ||
|
|
b7d1e98ae7 | ||
|
|
c370341900 | ||
|
|
ea0a6f7c33 | ||
|
|
749e687e1b | ||
|
|
128838227e | ||
|
|
8895c32ba9 | ||
|
|
00e46f85f6 | ||
|
|
b7c5385b81 | ||
|
|
ba9875c2f5 | ||
|
|
4cd50eb1ed | ||
|
|
a49bca97df | ||
|
|
d6536d44e9 | ||
|
|
a6f8e97342 | ||
|
|
2ef88a3cbf | ||
|
|
e426ae045b | ||
|
|
6be708aa7d | ||
|
|
b6568d2dd5 | ||
|
|
02241b05fc | ||
|
|
3a6899c6fd | ||
|
|
77e2d29b8a | ||
|
|
9e5726d3de | ||
|
|
7927cae910 | ||
|
|
45ba926c6d | ||
|
|
6c4121a943 | ||
|
|
fcb68e55fa | ||
|
|
3029f554cc | ||
|
|
b76ffecee8 | ||
|
|
96a2b214cb | ||
|
|
35a8b00b18 | ||
|
|
fed26d5b3c | ||
|
|
a61e2b4c9c | ||
|
|
eede7f09c7 | ||
|
|
907f838603 | ||
|
|
52c92be4c5 | ||
|
|
f022632503 | ||
|
|
bd41493132 | ||
|
|
5164e5f6d6 | ||
|
|
2b2a72cc65 | ||
|
|
98a6422cbc | ||
|
|
aab94fb340 | ||
|
|
1be48ec553 | ||
|
|
d4a26c1530 | ||
|
|
d63f7fb201 | ||
|
|
4f0747b0df | ||
|
|
ff0144de3b | ||
|
|
a936ae7e98 | ||
|
|
4c29864b02 | ||
|
|
3c5c192baf | ||
|
|
572de8764e | ||
|
|
5dded3340c | ||
|
|
8b24eea65e | ||
|
|
8ab6d025f6 | ||
|
|
bd1ae65aab | ||
|
|
2e3f3fd1e0 | ||
|
|
544032f7a4 | ||
|
|
0df2e1bdd8 | ||
|
|
05f82fdd00 | ||
|
|
151686a5c8 | ||
|
|
31567e0973 | ||
|
|
d94f2dcab2 | ||
|
|
bff68bf2cc | ||
|
|
8443a06149 | ||
|
|
36e9e796c6 | ||
|
|
e916ec1584 | ||
|
|
eb34c0b6d2 | ||
|
|
8bdf6d1baf | ||
|
|
26a457e7a3 | ||
|
|
b9904ba319 | ||
|
|
e7c333cb6e | ||
|
|
fcb87e8ae1 | ||
|
|
68c0cec772 | ||
|
|
738d8417e0 | ||
|
|
a5c0fda157 | ||
|
|
deea880581 | ||
|
|
962a4f434f | ||
|
|
cea5829402 | ||
|
|
69d77bc150 | ||
|
|
ff667ed932 | ||
|
|
efe9e90ef5 | ||
|
|
2d2df4376b | ||
|
|
ae8e3294dd | ||
|
|
892857179a | ||
|
|
147b87a03e | ||
|
|
a3f1f4eeb0 | ||
|
|
5bba60b1bb | ||
|
|
632fc235d6 | ||
|
|
75a90f85ad | ||
|
|
fa909dfaf4 | ||
|
|
d09fe00d36 | ||
|
|
bdaadec788 | ||
|
|
547ea18fbb | ||
|
|
597a5f9794 | ||
|
|
fee4db80a0 | ||
|
|
3fe7652ad9 | ||
|
|
08321a0994 | ||
|
|
959889efd9 | ||
|
|
6c5144d3e5 | ||
|
|
661fe9f3bb | ||
|
|
9ff2c3918c | ||
|
|
a4b1a5aef4 | ||
|
|
71f749be8d | ||
|
|
6c7f6c2d47 | ||
|
|
ecd494abf3 | ||
|
|
0e88c57c47 | ||
|
|
a3049653c1 | ||
|
|
4ffc61430b | ||
|
|
d3893b58ff | ||
|
|
1d9c8619cd | ||
|
|
64f79562fb | ||
|
|
05cf8e8130 | ||
|
|
5892aae60f | ||
|
|
7adb590e16 | ||
|
|
b5aacf8161 | ||
|
|
b732cfd392 | ||
|
|
50fb65f0f5 | ||
|
|
32bcbdfe65 | ||
|
|
f66ef31605 | ||
|
|
acb95e4544 | ||
|
|
335ed29345 | ||
|
|
0ef846ce2e | ||
|
|
4a1747d2e4 | ||
|
|
af25852baa | ||
|
|
7a9c831e6a | ||
|
|
649bb2b9b8 | ||
|
|
457399013b | ||
|
|
3bd0f582c9 | ||
|
|
be50480621 | ||
|
|
016ad9b3e8 | ||
|
|
87778af711 | ||
|
|
8bf037b246 | ||
|
|
8afe75ffa9 | ||
|
|
e2bade43e7 | ||
|
|
e0091d6616 | ||
|
|
42f3f7ed86 | ||
|
|
aace62f6d3 | ||
|
|
bb50485dfd | ||
|
|
5dcea89ce1 | ||
|
|
01eb4835c9 | ||
|
|
cd44aba8db | ||
|
|
2435d75b89 | ||
|
|
80d1e863f5 | ||
|
|
ee29fd944b | ||
|
|
b8ee9a7829 | ||
|
|
d9e097e328 | ||
|
|
2bef272269 | ||
|
|
3f9d07570a | ||
|
|
806849eb62 | ||
|
|
c24c37bd8a | ||
|
|
c306276ab1 | ||
|
|
6eb4d7f33b | ||
|
|
186eb805f6 | ||
|
|
d5e31e03b6 | ||
|
|
85ad299668 | ||
|
|
4735ce7ff2 | ||
|
|
e84365f967 | ||
|
|
5899e935d4 | ||
|
|
4d5f1d6bbc | ||
|
|
96534f015d | ||
|
|
49e24566d0 | ||
|
|
6424ae830b | ||
|
|
6055b07292 | ||
|
|
98518e0734 | ||
|
|
2f379ecfd6 | ||
|
|
8b61625a5e | ||
|
|
575d03df66 | ||
|
|
a13eea29fb | ||
|
|
136893e33b | ||
|
|
290fc0440c | ||
|
|
0556ba23a4 | ||
|
|
35a29c7328 | ||
|
|
6bca2bf3bf | ||
|
|
210c4d6f4b | ||
|
|
f50cb0c7bd | ||
|
|
0a6a5a9140 | ||
|
|
f3743766e9 | ||
|
|
e6a7df0e00 | ||
|
|
d3c5b613ac | ||
|
|
7ed0771d20 | ||
|
|
6285ec378c | ||
|
|
c92fd5220a | ||
|
|
aaa8a90747 | ||
|
|
5e48bbd14c | ||
|
|
6776279896 | ||
|
|
7db3243e34 | ||
|
|
aec7a80c6f | ||
|
|
d7aa1e14e5 | ||
|
|
5652c59647 | ||
|
|
458af2b1e0 | ||
|
|
58729344aa | ||
|
|
3d96894184 | ||
|
|
789a8755b8 | ||
|
|
f7298b326e | ||
|
|
1c18ad6ca6 | ||
|
|
ae4a10df67 | ||
|
|
24c882c3e0 | ||
|
|
03a0ee4202 | ||
|
|
df620567eb | ||
|
|
b3133d7471 | ||
|
|
8c552012ae | ||
|
|
aa47b29dbc | ||
|
|
61d547fd06 | ||
|
|
e5fbc3f75a | ||
|
|
1a078977e1 | ||
|
|
c4198e6053 | ||
|
|
8e70a1b23e | ||
|
|
c671434cd2 | ||
|
|
647ba03224 | ||
|
|
2f65bb7bb5 | ||
|
|
961fe27408 | ||
|
|
087cf6f238 | ||
|
|
0b9d68f59d | ||
|
|
cbf0779bfc | ||
|
|
0139309fef | ||
|
|
18278d3dc1 | ||
|
|
e1c7956764 | ||
|
|
4b3329d3dd | ||
|
|
32d442aee1 | ||
|
|
75afe3201b | ||
|
|
8018ee4689 | ||
|
|
ed376a603f | ||
|
|
1d45ea52f4 | ||
|
|
a27b0381a6 | ||
|
|
1fc19772e0 | ||
|
|
9bdb6adf92 | ||
|
|
7dbab75fec | ||
|
|
e7b1501832 | ||
|
|
4217d9ea0a | ||
|
|
4c6b8e737f | ||
|
|
e370f224ae | ||
|
|
ac1a867282 | ||
|
|
2949fee1d3 | ||
|
|
7861aa7e80 | ||
|
|
ebe29481ec | ||
|
|
f9c68e5fbc | ||
|
|
3452a76589 | ||
|
|
fec801a103 | ||
|
|
143a25144a | ||
|
|
f5899cc1f6 | ||
|
|
d9e39914a7 | ||
|
|
0a59892a88 | ||
|
|
042f0799db | ||
|
|
ec8ec9056c | ||
|
|
659604f9ee | ||
|
|
6660133ffb | ||
|
|
67b3563d09 | ||
|
|
7a4ea19803 | ||
|
|
ae6e9333c0 | ||
|
|
0d9acd24fe | ||
|
|
37bc639704 | ||
|
|
04eccf8165 | ||
|
|
24722779ff | ||
|
|
9d8acb7bd1 | ||
|
|
4b78458e4b | ||
|
|
d64bab35ee | ||
|
|
329d671aef | ||
|
|
4cc2081119 | ||
|
|
27df42255c | ||
|
|
9ee7d30aef | ||
|
|
8a4b7c5af8 | ||
|
|
7d50989467 | ||
|
|
a753ca64e2 | ||
|
|
ac1c329245 | ||
|
|
5276c2b6e0 | ||
|
|
1b0d37bdc2 | ||
|
|
baf1fd1c3f | ||
|
|
992dc33fc5 | ||
|
|
ef1545ed4a | ||
|
|
876f5eda51 | ||
|
|
463850e59e | ||
|
|
47a3dad256 | ||
|
|
a0bc3ebae4 | ||
|
|
922b6aa672 | ||
|
|
0e605cf972 | ||
|
|
878c41791b | ||
|
|
654e80abc2 | ||
|
|
0869b089e4 | ||
|
|
3467ba6451 | ||
|
|
f9b886c01b | ||
|
|
07140c0eca | ||
|
|
d5ad186d49 | ||
|
|
4d924c35f7 | ||
|
|
ea662c5c8a | ||
|
|
68b7ba0d03 | ||
|
|
821e4ec4c7 | ||
|
|
5ea7b8d091 | ||
|
|
1331b8c39a | ||
|
|
907f037141 | ||
|
|
a5b597ea51 | ||
|
|
8bbfa32741 | ||
|
|
807e415260 | ||
|
|
8587a1c617 | ||
|
|
9717369913 | ||
|
|
ed0c147c8f | ||
|
|
90be9ab802 | ||
|
|
d73f7031e0 | ||
|
|
ea7f7f168e | ||
|
|
233c49438b | ||
|
|
2b7424512a | ||
|
|
f77a3274b4 | ||
|
|
c76bb6a3a3 | ||
|
|
71846e82c1 | ||
|
|
ecbc27aa22 | ||
|
|
c01f02cfcb | ||
|
|
ce79cd19f6 | ||
|
|
1235338836 | ||
|
|
763d2b7996 | ||
|
|
e9eff01dca | ||
|
|
69ef9a7f90 | ||
|
|
86770904be | ||
|
|
31b98f9502 | ||
|
|
bfffb0974e | ||
|
|
e28bc0d271 | ||
|
|
d169a57306 | ||
|
|
63640838ba | ||
|
|
269e55a915 | ||
|
|
012dd239ce |
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"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,6 +1,4 @@
|
||||
/.git
|
||||
|
||||
# build artifacts
|
||||
/bundles/
|
||||
/cli/winresources/dockerd/winres.json
|
||||
/cli/winresources/dockerd/*.syso
|
||||
.git
|
||||
bundles/
|
||||
cli/winresources/**/winres.json
|
||||
cli/winresources/**/*.syso
|
||||
|
||||
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -5,6 +5,7 @@
|
||||
|
||||
builder/** @tonistiigi
|
||||
contrib/mkimage/** @tianon
|
||||
daemon/graphdriver/devmapper/** @rhvgoyal
|
||||
daemon/graphdriver/overlay2/** @dmcgowan
|
||||
daemon/graphdriver/windows/** @johnstep
|
||||
daemon/logger/awslogs/** @samuelkarp
|
||||
|
||||
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -19,18 +19,12 @@ Please provide the following information:
|
||||
|
||||
**- How to verify it**
|
||||
|
||||
**- Human readable description for the release notes**
|
||||
**- Description for the changelog**
|
||||
<!--
|
||||
Write a short (one line) summary that describes the changes in this
|
||||
pull request for inclusion in the changelog.
|
||||
It must be placed inside the below triple backticks section.
|
||||
|
||||
NOTE: Only fill this section if changes introduced in this PR are user-facing.
|
||||
The PR must have a relevant impact/ label.
|
||||
pull request for inclusion in the changelog:
|
||||
-->
|
||||
```markdown changelog
|
||||
|
||||
```
|
||||
|
||||
**- A picture of a cute animal (not mandatory but encouraged)**
|
||||
|
||||
|
||||
14
.github/actions/setup-tracing/action.yml
vendored
14
.github/actions/setup-tracing/action.yml
vendored
@@ -1,14 +0,0 @@
|
||||
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
|
||||
26
.github/workflows/.dco.yml
vendored
26
.github/workflows/.dco.yml
vendored
@@ -3,41 +3,31 @@ name: .dco
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
ALPINE_VERSION: "3.21"
|
||||
ALPINE_VERSION: 3.16
|
||||
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Dump context
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
console.log(JSON.stringify(context, null, 2));
|
||||
-
|
||||
name: Get base ref
|
||||
id: base-ref
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
@@ -49,12 +39,10 @@ jobs:
|
||||
name: Validate
|
||||
run: |
|
||||
docker run --rm \
|
||||
--quiet \
|
||||
-v ./:/workspace \
|
||||
-w /workspace \
|
||||
-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 && hack/validate/dco'
|
||||
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 }}
|
||||
|
||||
45
.github/workflows/.test-prepare.yml
vendored
45
.github/workflows/.test-prepare.yml
vendored
@@ -1,45 +0,0 @@
|
||||
# reusable workflow
|
||||
name: .test-prepare
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
matrix:
|
||||
description: Test matrix
|
||||
value: ${{ jobs.run.outputs.matrix }}
|
||||
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
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));
|
||||
});
|
||||
123
.github/workflows/.test-unit.yml
vendored
123
.github/workflows/.test-unit.yml
vendored
@@ -1,123 +0,0 @@
|
||||
# reusable workflow
|
||||
name: .test-unit
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.24.3"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest
|
||||
|
||||
jobs:
|
||||
unit:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
mode:
|
||||
- ""
|
||||
- firewalld
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
CACHE_DEV_SCOPE=dev
|
||||
if [[ "${{ matrix.mode }}" == *"firewalld"* ]]; then
|
||||
echo "FIREWALLD=true" >> $GITHUB_ENV
|
||||
CACHE_DEV_SCOPE="${CACHE_DEV_SCOPE}firewalld"
|
||||
fi
|
||||
echo "CACHE_DEV_SCOPE=${CACHE_DEV_SCOPE}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=${{ env.CACHE_DEV_SCOPE }}
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-unit
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p bundles /tmp/reports
|
||||
find bundles -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--${{ matrix.mode }}
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
unit-report:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
if: always()
|
||||
needs:
|
||||
- unit
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: test-reports-unit-*
|
||||
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
|
||||
472
.github/workflows/.test.yml
vendored
472
.github/workflows/.test.yml
vendored
@@ -1,472 +0,0 @@
|
||||
# reusable workflow
|
||||
name: .test
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
storage:
|
||||
required: true
|
||||
type: string
|
||||
default: "graphdriver"
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.24.3"
|
||||
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' || '' }}
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest
|
||||
|
||||
jobs:
|
||||
docker-py:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
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
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make TEST_SKIP_INTEGRATION_CLI=1 -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-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
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
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
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-prepare:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10 # guardrails timeout for the whole job
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
outputs:
|
||||
includes: ${{ steps.set.outputs.includes }}
|
||||
steps:
|
||||
-
|
||||
name: Create matrix includes
|
||||
id: set
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
let includes = [
|
||||
{ os: 'ubuntu-22.04', mode: '' },
|
||||
{ os: 'ubuntu-22.04', mode: 'rootless' },
|
||||
{ os: 'ubuntu-22.04', mode: 'systemd' },
|
||||
{ os: 'ubuntu-24.04', mode: '' },
|
||||
// { os: 'ubuntu-24.04', mode: 'rootless' }, // FIXME: https://github.com/moby/moby/pull/49579#issuecomment-2698622223
|
||||
{ os: 'ubuntu-24.04', mode: 'systemd' },
|
||||
// { os: 'ubuntu-24.04', mode: 'rootless-systemd' }, // FIXME: https://github.com/moby/moby/issues/44084
|
||||
];
|
||||
if ("${{ inputs.storage }}" == "snapshotter") {
|
||||
includes.push({ os: 'ubuntu-24.04', mode: 'firewalld' });
|
||||
}
|
||||
await core.group(`Set matrix`, async () => {
|
||||
core.info(`matrix: ${JSON.stringify(includes)}`);
|
||||
core.setOutput('includes', JSON.stringify(includes));
|
||||
});
|
||||
-
|
||||
name: Show matrix
|
||||
run: |
|
||||
echo ${{ steps.set.outputs.includes }}
|
||||
|
||||
integration:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
needs:
|
||||
- integration-prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include: ${{ fromJson(needs.integration-prepare.outputs.includes) }}
|
||||
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
|
||||
if [[ "${{ matrix.mode }}" == *"firewalld"* ]]; then
|
||||
echo "FIREWALLD=true" >> $GITHUB_ENV
|
||||
CACHE_DEV_SCOPE="${CACHE_DEV_SCOPE}firewalld"
|
||||
fi
|
||||
echo "CACHE_DEV_SCOPE=${CACHE_DEV_SCOPE}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
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-24.04
|
||||
timeout-minutes: 10
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
if: always()
|
||||
needs:
|
||||
- integration
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
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-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
outputs:
|
||||
matrix: ${{ steps.set.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
name: Install gotestlist
|
||||
run:
|
||||
go install github.com/crazy-max/gotestlist/cmd/gotestlist@${{ env.GOTESTLIST_VERSION }}
|
||||
-
|
||||
name: Create test 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: Create gha matrix
|
||||
id: set
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
let matrix = {
|
||||
test: ${{ steps.tests.outputs.matrix }},
|
||||
include: [],
|
||||
};
|
||||
// For some reasons, GHA doesn't combine a dynamically defined
|
||||
// 'include' with other matrix variables that aren't part of the
|
||||
// include items.
|
||||
// Moreover, since the goal is to run only relevant tests with
|
||||
// firewalld enabled to minimize the number of CI jobs, we
|
||||
// statically define the list of test suites that we want to run.
|
||||
if ("${{ inputs.storage }}" == "snapshotter") {
|
||||
matrix.include.push({
|
||||
'mode': 'firewalld',
|
||||
'test': 'DockerCLINetworkSuite|DockerCLIPortSuite|DockerDaemonSuite'
|
||||
});
|
||||
matrix.include.push({
|
||||
'mode': 'firewalld',
|
||||
'test': 'DockerSwarmSuite'
|
||||
});
|
||||
matrix.include.push({
|
||||
'mode': 'firewalld',
|
||||
'test': 'DockerNetworkSuite'
|
||||
});
|
||||
}
|
||||
await core.group(`Set matrix`, async () => {
|
||||
core.info(`matrix: ${JSON.stringify(matrix)}`);
|
||||
core.setOutput('matrix', JSON.stringify(matrix));
|
||||
});
|
||||
-
|
||||
name: Show final gha matrix
|
||||
run: |
|
||||
echo ${{ steps.set.outputs.matrix }}
|
||||
|
||||
integration-cli:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
needs:
|
||||
- integration-cli-prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ 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: Prepare
|
||||
run: |
|
||||
CACHE_DEV_SCOPE=dev
|
||||
if [[ "${{ matrix.mode }}" == *"firewalld"* ]]; then
|
||||
echo "FIREWALLD=true" >> $GITHUB_ENV
|
||||
CACHE_DEV_SCOPE="${CACHE_DEV_SCOPE}firewalld"
|
||||
fi
|
||||
echo "CACHE_DEV_SCOPE=${CACHE_DEV_SCOPE}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
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-24.04
|
||||
timeout-minutes: 10
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
if: always()
|
||||
needs:
|
||||
- integration-cli
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
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
|
||||
198
.github/workflows/.windows.yml
vendored
198
.github/workflows/.windows.yml
vendored
@@ -3,34 +3,21 @@ name: .windows
|
||||
|
||||
# TODO: hide reusable workflow from the UI. Tracked in https://github.com/community/community/discussions/12025
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
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.24.3"
|
||||
GO_VERSION: "1.20.13"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
TESTSTAT_VERSION: v0.1.3
|
||||
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
|
||||
WINDOWS_BASE_TAG_2019: ltsc2019
|
||||
WINDOWS_BASE_TAG_2022: ltsc2022
|
||||
@@ -42,7 +29,6 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ inputs.os }}
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
@@ -53,7 +39,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
@@ -72,7 +58,7 @@ jobs:
|
||||
}
|
||||
-
|
||||
name: Cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~\AppData\Local\go-build
|
||||
@@ -89,12 +75,9 @@ jobs:
|
||||
-
|
||||
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 .
|
||||
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: |
|
||||
@@ -113,16 +96,16 @@ jobs:
|
||||
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
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build-${{ inputs.storage }}-${{ inputs.os }}
|
||||
name: build-${{ inputs.os }}
|
||||
path: ${{ env.BIN_OUT }}/*
|
||||
if-no-files-found: error
|
||||
retention-days: 2
|
||||
|
||||
unit-test:
|
||||
runs-on: ${{ inputs.os }}
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
timeout-minutes: 120
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
@@ -132,7 +115,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ${{ env.GOPATH }}/src/github.com/docker/docker
|
||||
-
|
||||
@@ -152,7 +135,7 @@ jobs:
|
||||
}
|
||||
-
|
||||
name: Cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~\AppData\Local\go-build
|
||||
@@ -169,12 +152,9 @@ jobs:
|
||||
-
|
||||
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 .
|
||||
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: |
|
||||
@@ -186,40 +166,36 @@ jobs:
|
||||
-
|
||||
name: Send to Codecov
|
||||
if: inputs.send_coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v3
|
||||
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
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports
|
||||
name: ${{ inputs.os }}-unit-reports
|
||||
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
||||
retention-days: 1
|
||||
|
||||
unit-test-report:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
needs:
|
||||
- unit-test
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-unit-reports
|
||||
name: ${{ inputs.os }}-unit-reports
|
||||
path: /tmp/artifacts
|
||||
-
|
||||
name: Install teststat
|
||||
@@ -228,23 +204,21 @@ jobs:
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/artifacts -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
||||
teststat -markdown $(find /tmp/artifacts -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
integration-test-prepare:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.tests.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
name: Install gotestlist
|
||||
run:
|
||||
@@ -267,23 +241,17 @@ jobs:
|
||||
|
||||
integration-test:
|
||||
runs-on: ${{ inputs.os }}
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
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
|
||||
@@ -294,28 +262,18 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
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
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: build-${{ inputs.storage }}-${{ inputs.os }}
|
||||
name: build-${{ inputs.os }}
|
||||
path: ${{ env.BIN_OUT }}
|
||||
-
|
||||
name: Init
|
||||
@@ -327,9 +285,6 @@ jobs:
|
||||
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.
|
||||
@@ -349,12 +304,33 @@ jobs:
|
||||
$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="--default-runtime=io.containerd.runhcs.v1"
|
||||
$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
|
||||
@@ -366,11 +342,6 @@ jobs:
|
||||
"--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!"
|
||||
@@ -394,17 +365,6 @@ jobs:
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
Write-Host "Test daemon started and replied!"
|
||||
If ("${{ matrix.runtime }}" -eq "containerd") {
|
||||
$containerdProcesses = Get-Process -Name containerd -ErrorAction:SilentlyContinue
|
||||
If (-not $containerdProcesses) {
|
||||
Throw "containerd process is not running"
|
||||
} else {
|
||||
foreach ($process in $containerdProcesses) {
|
||||
$processPath = (Get-Process -Id $process.Id -FileVersionInfo).FileName
|
||||
Write-Output "Running containerd instance binary Path: $($processPath)"
|
||||
}
|
||||
}
|
||||
}
|
||||
env:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
@@ -430,10 +390,9 @@ jobs:
|
||||
DOCKER_HOST: npipe:////./pipe/docker_engine
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
name: Test integration
|
||||
if: matrix.test == './...'
|
||||
@@ -456,19 +415,31 @@ jobs:
|
||||
-
|
||||
name: Send to Codecov
|
||||
if: inputs.send_coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
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 }}
|
||||
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()
|
||||
@@ -487,54 +458,37 @@ jobs:
|
||||
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
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-${{ env.TESTREPORTS_NAME }}
|
||||
name: ${{ inputs.os }}-integration-reports-${{ matrix.runtime }}
|
||||
path: ${{ env.GOPATH }}\src\github.com\docker\docker\bundles\*
|
||||
retention-days: 1
|
||||
|
||||
integration-test-report:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
continue-on-error: ${{ inputs.storage == 'snapshotter' && github.event_name != 'pull_request' }}
|
||||
runs-on: ubuntu-latest
|
||||
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
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: ${{ inputs.os }}-${{ inputs.storage }}-integration-reports-${{ matrix.runtime }}-*
|
||||
merge-multiple: true
|
||||
name: ${{ inputs.os }}-integration-reports-${{ matrix.runtime }}
|
||||
path: /tmp/artifacts
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
@@ -542,4 +496,4 @@ jobs:
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
find /tmp/reports -type f -name '*-go-test-report.json' -exec teststat -markdown {} \+ >> $GITHUB_STEP_SUMMARY
|
||||
teststat -markdown $(find /tmp/artifacts -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
276
.github/workflows/arm64.yml
vendored
276
.github/workflows/arm64.yml
vendored
@@ -1,276 +0,0 @@
|
||||
name: arm64
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
- '[0-9]+.x'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.24.3"
|
||||
TESTSTAT_VERSION: v0.1.25
|
||||
DESTDIR: ./build
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest
|
||||
DOCKER_EXPERIMENTAL: 1
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 20 # guardrails timeout for the whole job
|
||||
needs:
|
||||
- validate-dco
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- binary
|
||||
- dynbinary
|
||||
steps:
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
-
|
||||
name: List artifacts
|
||||
run: |
|
||||
tree -nh ${{ env.DESTDIR }}
|
||||
-
|
||||
name: Check artifacts
|
||||
run: |
|
||||
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
|
||||
|
||||
build-dev:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
needs:
|
||||
- validate-dco
|
||||
steps:
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
*.cache-from=type=gha,scope=dev-arm64
|
||||
*.cache-to=type=gha,scope=dev-arm64,mode=max
|
||||
*.output=type=cacheonly
|
||||
|
||||
test-unit:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
needs:
|
||||
- build-dev
|
||||
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
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev-arm64
|
||||
-
|
||||
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-arm64-graphdriver
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
test-unit-report:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
if: always()
|
||||
needs:
|
||||
- test-unit
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: test-reports-unit-arm64-*
|
||||
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
|
||||
|
||||
test-integration:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
needs:
|
||||
- build-dev
|
||||
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
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
dev.cache-from=type=gha,scope=dev-arm64
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
make -o build test-integration
|
||||
env:
|
||||
TEST_SKIP_INTEGRATION_CLI: 1
|
||||
TESTCOVERAGE: 1
|
||||
-
|
||||
name: Prepare reports
|
||||
if: always()
|
||||
run: |
|
||||
reportsPath="/tmp/reports/arm64-graphdriver"
|
||||
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
|
||||
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-arm64-graphdriver
|
||||
path: /tmp/reports/*
|
||||
retention-days: 1
|
||||
|
||||
test-integration-report:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
continue-on-error: ${{ github.event_name != 'pull_request' }}
|
||||
if: always()
|
||||
needs:
|
||||
- test-integration
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/reports
|
||||
pattern: test-reports-integration-arm64-*
|
||||
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
|
||||
74
.github/workflows/bin-image.yml
vendored
74
.github/workflows/bin-image.yml
vendored
@@ -1,14 +1,5 @@
|
||||
name: bin-image
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
@@ -19,7 +10,6 @@ on:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
- '[0-9]+.x'
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
@@ -31,8 +21,6 @@ env:
|
||||
PLATFORM: Moby Engine - Nightly
|
||||
PRODUCT: moby-bin
|
||||
PACKAGER_NAME: The Moby Project
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
@@ -40,18 +28,17 @@ jobs:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
prepare:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-20.04
|
||||
outputs:
|
||||
platforms: ${{ steps.platforms.outputs.matrix }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ env.MOBYBIN_REPO_SLUG }}
|
||||
@@ -59,7 +46,7 @@ jobs:
|
||||
## push semver tag v23.0.0
|
||||
# moby/moby-bin:23.0.0
|
||||
# moby/moby-bin:latest
|
||||
## push semver prerelease tag v23.0.0-beta.1
|
||||
## push semver prelease tag v23.0.0-beta.1
|
||||
# moby/moby-bin:23.0.0-beta.1
|
||||
## push on master
|
||||
# moby/moby-bin:master
|
||||
@@ -74,13 +61,11 @@ jobs:
|
||||
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"
|
||||
mv "${{ steps.meta.outputs.bake-file }}" "/tmp/bake-meta.json"
|
||||
-
|
||||
name: Upload meta bake definition
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp/bake-meta.json
|
||||
@@ -93,8 +78,7 @@ jobs:
|
||||
echo "matrix=$(docker buildx bake bin-image-cross --print | jq -cr '.target."bin-image-cross".platforms')" >>${GITHUB_OUTPUT}
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
- prepare
|
||||
@@ -106,43 +90,33 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Download meta bake definition
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_MOBYBIN_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_MOBYBIN_TOKEN }}
|
||||
-
|
||||
name: Build
|
||||
id: bake
|
||||
uses: docker/bake-action@v6
|
||||
uses: docker/bake-action@v3
|
||||
with:
|
||||
source: .
|
||||
files: |
|
||||
./docker-bake.hcl
|
||||
/tmp/bake-meta.json
|
||||
@@ -161,43 +135,37 @@ jobs:
|
||||
-
|
||||
name: Upload digest
|
||||
if: github.event_name != 'pull_request' && github.repository == 'moby/moby'
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
name: digests
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
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
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: bake-meta
|
||||
path: /tmp
|
||||
-
|
||||
name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: digests
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_MOBYBIN_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_MOBYBIN_TOKEN }}
|
||||
|
||||
292
.github/workflows/buildkit.yml
vendored
292
.github/workflows/buildkit.yml
vendored
@@ -1,14 +1,5 @@
|
||||
name: buildkit
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
@@ -19,54 +10,47 @@ on:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
- '[0-9]+.x'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.24.3"
|
||||
ALPINE_VERSION: "3.18"
|
||||
GO_VERSION: "1.20.12"
|
||||
DESTDIR: ./build
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
build-linux:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v6
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: binary
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binary
|
||||
path: ${{ env.DESTDIR }}
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
test-linux:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
test:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-linux
|
||||
env:
|
||||
TEST_IMAGE_BUILD: "0"
|
||||
TEST_IMAGE_ID: "buildkit-tests"
|
||||
- build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -90,23 +74,11 @@ jobs:
|
||||
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
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: moby
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
-
|
||||
name: BuildKit ref
|
||||
run: |
|
||||
@@ -114,24 +86,20 @@ jobs:
|
||||
working-directory: moby
|
||||
-
|
||||
name: Checkout BuildKit ${{ env.BUILDKIT_REF }}
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: ${{ env.BUILDKIT_REPO }}
|
||||
ref: ${{ env.BUILDKIT_REF }}
|
||||
path: buildkit
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Download binary artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: binary
|
||||
path: ./buildkit/build/moby/
|
||||
@@ -142,15 +110,6 @@ jobs:
|
||||
sudo service docker restart
|
||||
docker version
|
||||
docker info
|
||||
-
|
||||
name: Build test image
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
source: .
|
||||
workdir: ./buildkit
|
||||
targets: integration-tests
|
||||
set: |
|
||||
*.output=type=docker,name=${{ env.TEST_IMAGE_ID }}
|
||||
-
|
||||
name: Test
|
||||
run: |
|
||||
@@ -160,215 +119,6 @@ jobs:
|
||||
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
|
||||
|
||||
build-windows:
|
||||
runs-on: windows-2022
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- validate-dco
|
||||
env:
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
BIN_OUT: ${{ github.workspace }}\out
|
||||
WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
|
||||
WINDOWS_BASE_TAG_2022: ltsc2022
|
||||
TEST_IMAGE_NAME: moby:test
|
||||
TEST_CTN_NAME: moby
|
||||
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: Moby - Init
|
||||
run: |
|
||||
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build"
|
||||
New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod"
|
||||
echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
- 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
|
||||
go install github.com/distribution/distribution/v3/cmd/registry@latest
|
||||
|
||||
- name: Checkout BuildKit
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: moby/buildkit
|
||||
ref: master
|
||||
path: buildkit
|
||||
|
||||
- name: Add buildctl to binaries
|
||||
run: |
|
||||
go install ./cmd/buildctl
|
||||
working-directory: buildkit
|
||||
|
||||
- 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 }}\
|
||||
cp ${{ env.GOPATH }}\bin\registry.exe ${{ env.BIN_OUT }}
|
||||
cp ${{ env.GOPATH }}\bin\buildctl.exe ${{ env.BIN_OUT }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-windows
|
||||
path: ${{ env.BIN_OUT }}/*
|
||||
if-no-files-found: error
|
||||
retention-days: 2
|
||||
|
||||
test-windows:
|
||||
runs-on: windows-2022
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
needs:
|
||||
- build-windows
|
||||
env:
|
||||
TEST_IMAGE_BUILD: "0"
|
||||
TEST_IMAGE_ID: "buildkit-tests"
|
||||
GOPATH: ${{ github.workspace }}\go
|
||||
GOBIN: ${{ github.workspace }}\go\bin
|
||||
BIN_OUT: ${{ github.workspace }}\out
|
||||
TESTFLAGS: "-v --timeout=90m"
|
||||
TEST_DOCKERD: "1"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
worker:
|
||||
- dockerd-containerd
|
||||
pkg:
|
||||
- ./client#1-4
|
||||
- ./client#2-4
|
||||
- ./client#3-4
|
||||
- ./client#4-4
|
||||
- ./cmd/buildctl
|
||||
- ./frontend
|
||||
- ./frontend/dockerfile#1-12
|
||||
- ./frontend/dockerfile#2-12
|
||||
- ./frontend/dockerfile#3-12
|
||||
- ./frontend/dockerfile#4-12
|
||||
- ./frontend/dockerfile#5-12
|
||||
- ./frontend/dockerfile#6-12
|
||||
- ./frontend/dockerfile#7-12
|
||||
- ./frontend/dockerfile#8-12
|
||||
- ./frontend/dockerfile#9-12
|
||||
- ./frontend/dockerfile#10-12
|
||||
- ./frontend/dockerfile#11-12
|
||||
- ./frontend/dockerfile#12-12
|
||||
steps:
|
||||
- name: Prepare
|
||||
shell: bash
|
||||
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
|
||||
- name: Expose GitHub Runtime
|
||||
uses: crazy-max/ghaction-github-runtime@v3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: moby
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: vendor.sum
|
||||
- name: BuildKit ref
|
||||
shell: bash
|
||||
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: Download Moby artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: build-windows
|
||||
path: ${{ env.BIN_OUT }}
|
||||
|
||||
- name: Add binaries to PATH
|
||||
run: |
|
||||
ls ${{ env.BIN_OUT }}
|
||||
Write-Output "${{ env.BIN_OUT }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
|
||||
- name: Test Prep
|
||||
shell: bash
|
||||
run: |
|
||||
TESTPKG=$(echo "${{ matrix.pkg }}" | awk '-F#' '{print $1}')
|
||||
echo "TESTPKG=$TESTPKG" >> $GITHUB_ENV
|
||||
echo "TEST_REPORT_NAME=${{ github.job }}-$(echo "${{ matrix.pkg }}-${{ matrix.worker }}" | tr -dc '[:alnum:]-\n\r' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
||||
testFlags="${{ env.TESTFLAGS }}"
|
||||
testSlice=$(echo "${{ matrix.pkg }}" | awk '-F#' '{print $2}')
|
||||
testSliceOffset=""
|
||||
if [ -n "$testSlice" ]; then
|
||||
testSliceOffset="slice=$testSlice/"
|
||||
fi
|
||||
if [ -n "${{ matrix.worker }}" ]; then
|
||||
testFlags="${testFlags} --run=TestIntegration/$testSliceOffset.*/worker=${{ matrix.worker }}"
|
||||
fi
|
||||
echo "TESTFLAGS=${testFlags}" >> $GITHUB_ENV
|
||||
- name: Test
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p ./bin/testreports
|
||||
gotestsum \
|
||||
--jsonfile="./bin/testreports/go-test-report-${{ env.TEST_REPORT_NAME }}.json" \
|
||||
--junitfile="./bin/testreports/junit-report-${{ env.TEST_REPORT_NAME }}.xml" \
|
||||
--packages="${{ env.TESTPKG }}" \
|
||||
-- \
|
||||
"-mod=vendor" \
|
||||
"-coverprofile" "./bin/testreports/coverage-${{ env.TEST_REPORT_NAME }}.txt" \
|
||||
"-covermode" "atomic" ${{ env.TESTFLAGS }}
|
||||
# Skip buildkit tests checking the digest (see https://github.com/moby/buildkit/pull/3736)
|
||||
TESTFLAGS: "-v --parallel=1 --timeout=30m --run=/^Test([^R]|.[^e]|..[^p]|...[^r]|....[^o]|.....[^S])/worker=${{ matrix.worker }}$"
|
||||
working-directory: buildkit
|
||||
|
||||
111
.github/workflows/ci.yml
vendored
111
.github/workflows/ci.yml
vendored
@@ -1,14 +1,5 @@
|
||||
name: ci
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
@@ -19,21 +10,17 @@ on:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
- '[0-9]+.x'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
DESTDIR: ./build
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
strategy:
|
||||
@@ -44,15 +31,16 @@ jobs:
|
||||
- dynbinary
|
||||
steps:
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v6
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
-
|
||||
@@ -63,10 +51,17 @@ jobs:
|
||||
name: Check artifacts
|
||||
run: |
|
||||
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
|
||||
-
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.target }}
|
||||
path: ${{ env.DESTDIR }}
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
prepare-cross:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- validate-dco
|
||||
outputs:
|
||||
@@ -74,7 +69,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
@@ -87,8 +82,7 @@ jobs:
|
||||
echo ${{ steps.platforms.outputs.matrix }}
|
||||
|
||||
cross:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
- prepare-cross
|
||||
@@ -97,6 +91,11 @@ jobs:
|
||||
matrix:
|
||||
platform: ${{ fromJson(needs.prepare-cross.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
@@ -104,14 +103,10 @@ jobs:
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build
|
||||
uses: docker/bake-action@v6
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: all
|
||||
set: |
|
||||
@@ -124,53 +119,11 @@ jobs:
|
||||
name: Check artifacts
|
||||
run: |
|
||||
find ${{ env.DESTDIR }} -type f -exec file -e ascii -- {} +
|
||||
|
||||
govulncheck:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
permissions:
|
||||
# required to write sarif report
|
||||
security-events: write
|
||||
# required to check out the repository
|
||||
contents: read
|
||||
steps:
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Run
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
targets: govulncheck
|
||||
env:
|
||||
GOVULNCHECK_FORMAT: sarif
|
||||
-
|
||||
name: Upload SARIF report
|
||||
if: ${{ github.event_name != 'pull_request' && github.repository == 'moby/moby' }}
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: ${{ env.DESTDIR }}/govulncheck.out
|
||||
|
||||
build-dind:
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- validate-dco
|
||||
steps:
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
-
|
||||
name: Build dind image
|
||||
uses: docker/bake-action@v6
|
||||
with:
|
||||
targets: dind
|
||||
set: |
|
||||
*.output=type=cacheonly
|
||||
name: cross-${{ env.PLATFORM_PAIR }}
|
||||
path: ${{ env.DESTDIR }}
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
71
.github/workflows/codeql.yml
vendored
71
.github/workflows/codeql.yml
vendored
@@ -1,71 +0,0 @@
|
||||
name: codeql
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
- '[0-9]+.x'
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: ["master"]
|
||||
schedule:
|
||||
# ┌───────────── minute (0 - 59)
|
||||
# │ ┌───────────── hour (0 - 23)
|
||||
# │ │ ┌───────────── day of the month (1 - 31)
|
||||
# │ │ │ ┌───────────── month (1 - 12)
|
||||
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday)
|
||||
# │ │ │ │ │
|
||||
# │ │ │ │ │
|
||||
# │ │ │ │ │
|
||||
# * * * * *
|
||||
- cron: '0 9 * * 4'
|
||||
|
||||
jobs:
|
||||
codeql:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
# CodeQL 2.16.4's auto-build added support for multi-module repositories,
|
||||
# and is trying to be smart by searching for modules in every directory,
|
||||
# including vendor directories. If no module is found, it's creating one
|
||||
# which is ... not what we want, so let's give it a "go.mod".
|
||||
# see: https://github.com/docker/cli/pull/4944#issuecomment-2002034698
|
||||
- name: Create go.mod
|
||||
run: |
|
||||
ln -s vendor.mod go.mod
|
||||
ln -s vendor.sum go.sum
|
||||
- name: Update Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.24.3"
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: go
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:go"
|
||||
500
.github/workflows/test.yml
vendored
500
.github/workflows/test.yml
vendored
@@ -1,14 +1,5 @@
|
||||
name: test
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
@@ -19,23 +10,22 @@ on:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
- '[0-9]+.x'
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.24.3"
|
||||
GIT_PAGER: "cat"
|
||||
PAGER: "cat"
|
||||
SETUP_BUILDX_VERSION: edge
|
||||
SETUP_BUILDKIT_IMAGE: moby/buildkit:latest
|
||||
GO_VERSION: "1.20.13"
|
||||
GOTESTLIST_VERSION: v0.3.1
|
||||
TESTSTAT_VERSION: v0.1.3
|
||||
ITG_CLI_MATRIX_SIZE: 6
|
||||
DOCKER_EXPERIMENTAL: 1
|
||||
DOCKER_GRAPHDRIVER: overlay2
|
||||
|
||||
jobs:
|
||||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
build-dev:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
strategy:
|
||||
@@ -51,16 +41,15 @@ jobs:
|
||||
if [ "${{ matrix.mode }}" = "systemd" ]; then
|
||||
echo "SYSTEMD=true" >> $GITHUB_ENV
|
||||
fi
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
@@ -68,31 +57,8 @@ jobs:
|
||||
*.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 }}
|
||||
|
||||
test-unit:
|
||||
needs:
|
||||
- build-dev
|
||||
- validate-dco
|
||||
uses: ./.github/workflows/.test-unit.yml
|
||||
secrets: inherit
|
||||
|
||||
validate-prepare:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
outputs:
|
||||
@@ -100,12 +66,12 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Create matrix
|
||||
id: scripts
|
||||
run: |
|
||||
scripts=$(cd ./hack/validate && jq -nc '$ARGS.positional - ["all", "default", "dco"] | map(select(test("[.]")|not)) + ["generate-files"]' --args *)
|
||||
scripts=$(jq -ncR '[inputs]' <<< "$(ls -I .validate -I all -I default -I dco -I golangci-lint.yml -I yamllint.yaml -A ./hack/validate/)")
|
||||
echo "matrix=$scripts" >> $GITHUB_OUTPUT
|
||||
-
|
||||
name: Show matrix
|
||||
@@ -113,8 +79,8 @@ jobs:
|
||||
echo ${{ steps.scripts.outputs.matrix }}
|
||||
|
||||
validate:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- validate-prepare
|
||||
- build-dev
|
||||
@@ -125,7 +91,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
@@ -133,14 +99,10 @@ jobs:
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v6
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: dev
|
||||
set: |
|
||||
@@ -150,9 +112,403 @@ jobs:
|
||||
run: |
|
||||
make -o build validate-${{ matrix.script }}
|
||||
|
||||
smoke-prepare:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10 # guardrails timeout for the whole job
|
||||
unit:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-dev
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v2
|
||||
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@v3
|
||||
with:
|
||||
directory: ./bundles
|
||||
env_vars: RUNNER_OS
|
||||
flags: unit
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: unit-reports
|
||||
path: /tmp/reports/*
|
||||
|
||||
unit-report:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 10
|
||||
if: always()
|
||||
needs:
|
||||
- unit
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: unit-reports
|
||||
path: /tmp/reports
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
teststat -markdown $(find /tmp/reports -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
docker-py:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-dev
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v2
|
||||
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
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-docker-py/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: docker-py-reports
|
||||
path: /tmp/reports/*
|
||||
|
||||
integration-flaky:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-dev
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v2
|
||||
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 }}
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-dev
|
||||
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@v3
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
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@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v2
|
||||
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: |
|
||||
reportsPath="/tmp/reports/${{ matrix.os }}"
|
||||
if [ -n "${{ matrix.mode }}" ]; then
|
||||
reportsPath="$reportsPath-${{ matrix.mode }}"
|
||||
fi
|
||||
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
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
directory: ./bundles/test-integration
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration,${{ matrix.mode }}
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-integration/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: integration-reports
|
||||
path: /tmp/reports/*
|
||||
|
||||
integration-report:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 10
|
||||
if: always()
|
||||
needs:
|
||||
- integration
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: integration-reports
|
||||
path: /tmp/reports
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
teststat -markdown $(find /tmp/reports -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
integration-cli-prepare:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
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: |
|
||||
# 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
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- build-dev
|
||||
- integration-cli-prepare
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test: ${{ fromJson(needs.integration-cli-prepare.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up runner
|
||||
uses: ./.github/actions/setup-runner
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Build dev image
|
||||
uses: docker/bake-action@v2
|
||||
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: |
|
||||
reportsPath=/tmp/reports/$(echo -n "${{ matrix.test }}" | sha256sum | cut -d " " -f 1)
|
||||
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
|
||||
-
|
||||
name: Send to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
directory: ./bundles/test-integration
|
||||
env_vars: RUNNER_OS
|
||||
flags: integration-cli
|
||||
-
|
||||
name: Test daemon logs
|
||||
if: always()
|
||||
run: |
|
||||
cat bundles/test-integration/docker.log
|
||||
-
|
||||
name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: integration-cli-reports
|
||||
path: /tmp/reports/*
|
||||
|
||||
integration-cli-report:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 10
|
||||
if: always()
|
||||
needs:
|
||||
- integration-cli
|
||||
steps:
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
-
|
||||
name: Download reports
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: integration-cli-reports
|
||||
path: /tmp/reports
|
||||
-
|
||||
name: Install teststat
|
||||
run: |
|
||||
go install github.com/vearutop/teststat@${{ env.TESTSTAT_VERSION }}
|
||||
-
|
||||
name: Create summary
|
||||
run: |
|
||||
teststat -markdown $(find /tmp/reports -type f -name '*.json' -print0 | xargs -0) >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
prepare-smoke:
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- validate-dco
|
||||
outputs:
|
||||
@@ -160,7 +516,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Create matrix
|
||||
id: platforms
|
||||
@@ -173,15 +529,17 @@ jobs:
|
||||
echo ${{ steps.platforms.outputs.matrix }}
|
||||
|
||||
smoke:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20 # guardrails timeout for the whole job
|
||||
runs-on: ubuntu-20.04
|
||||
needs:
|
||||
- smoke-prepare
|
||||
- prepare-smoke
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: ${{ fromJson(needs.smoke-prepare.outputs.matrix) }}
|
||||
platform: ${{ fromJson(needs.prepare-smoke.outputs.matrix) }}
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
@@ -189,17 +547,13 @@ jobs:
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: ${{ env.SETUP_BUILDX_VERSION }}
|
||||
driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }}
|
||||
buildkitd-flags: --debug
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Test
|
||||
uses: docker/bake-action@v6
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
targets: binary-smoketest
|
||||
set: |
|
||||
|
||||
88
.github/workflows/validate-pr.yml
vendored
88
.github/workflows/validate-pr.yml
vendored
@@ -1,88 +0,0 @@
|
||||
name: validate-pr
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, labeled, unlabeled, synchronize]
|
||||
|
||||
jobs:
|
||||
check-area-label:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
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:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
env:
|
||||
HAS_IMPACT_LABEL: ${{ contains(join(github.event.pull_request.labels.*.name, ','), 'impact/') }}
|
||||
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 [ "$HAS_IMPACT_LABEL" = "true" ]; then
|
||||
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
|
||||
else
|
||||
if [ -n "$desc" ]; then
|
||||
echo "::error::PR has a changelog description, but no changelog label"
|
||||
echo "::error::Please add the relevant 'impact/' label to the PR or remove the changelog description"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "This PR will be included in the release notes with the following note:"
|
||||
echo "$desc"
|
||||
|
||||
check-pr-branch:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 120 # guardrails timeout for the whole job
|
||||
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: Check release branch
|
||||
id: title_branch
|
||||
run: |
|
||||
# get the intended major version prefix ("[27.1 backport]" -> "27.") from the PR title.
|
||||
[[ "$PR_TITLE" =~ ^\[([0-9]*\.)[^]]*\] ]] && branch="${BASH_REMATCH[1]}"
|
||||
|
||||
# get major version prefix from the release branch ("27.x -> "27.")
|
||||
[[ "$GITHUB_BASE_REF" =~ ^([0-9]*\.) ]] && target_branch="${BASH_REMATCH[1]}" || target_branch="$GITHUB_BASE_REF"
|
||||
|
||||
if [[ "$target_branch" != "$branch" ]] && ! [[ "$GITHUB_BASE_REF" == "master" && "$branch" == "" ]]; then
|
||||
echo "::error::PR is opened against the $GITHUB_BASE_REF branch, but its title suggests otherwise."
|
||||
exit 1
|
||||
fi
|
||||
22
.github/workflows/windows-2019.yml
vendored
22
.github/workflows/windows-2019.yml
vendored
@@ -1,14 +1,5 @@
|
||||
name: windows-2019
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
@@ -22,21 +13,10 @@ jobs:
|
||||
validate-dco:
|
||||
uses: ./.github/workflows/.dco.yml
|
||||
|
||||
test-prepare:
|
||||
uses: ./.github/workflows/.test-prepare.yml
|
||||
needs:
|
||||
- validate-dco
|
||||
|
||||
run:
|
||||
needs:
|
||||
- test-prepare
|
||||
- validate-dco
|
||||
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
|
||||
|
||||
23
.github/workflows/windows-2022.yml
vendored
23
.github/workflows/windows-2022.yml
vendored
@@ -1,14 +1,5 @@
|
||||
name: windows-2022
|
||||
|
||||
# Default to 'contents: read', which grants actions to read commits.
|
||||
#
|
||||
# If any permission is set, any permission not included in the list is
|
||||
# implicitly set to "none".
|
||||
#
|
||||
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
@@ -19,28 +10,16 @@ on:
|
||||
branches:
|
||||
- 'master'
|
||||
- '[0-9]+.[0-9]+'
|
||||
- '[0-9]+.x'
|
||||
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
|
||||
- validate-dco
|
||||
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
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -14,9 +14,10 @@ thumbs.db
|
||||
.editorconfig
|
||||
|
||||
# build artifacts
|
||||
/bundles/
|
||||
/cli/winresources/dockerd/*.syso
|
||||
/cli/winresources/dockerd/winres.json
|
||||
bundles/
|
||||
cli/winresources/*/*.syso
|
||||
cli/winresources/*/winres.json
|
||||
contrib/builder/rpm/*/changelog
|
||||
|
||||
# ci artifacts
|
||||
*.exe
|
||||
|
||||
263
.golangci.yml
263
.golangci.yml
@@ -1,263 +0,0 @@
|
||||
version: "2"
|
||||
|
||||
run:
|
||||
# prevent golangci-lint from deducting the go version to lint for through go.mod,
|
||||
# which causes it to fallback to go1.17 semantics.
|
||||
go: "1.24.3"
|
||||
concurrency: 2
|
||||
# Only supported with go modules enabled (build flag -mod=vendor only valid when using modules)
|
||||
# modules-download-mode: vendor
|
||||
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- asasalint # Detects "[]any" used as argument for variadic "func(...any)".
|
||||
- copyloopvar # Detects places where loop variables are copied.
|
||||
- depguard
|
||||
- dogsled # Detects assignments with too many blank identifiers.
|
||||
- dupword # Detects duplicate words.
|
||||
- durationcheck # Detect cases where two time.Duration values are being multiplied in possibly erroneous ways.
|
||||
- errchkjson # Detects unsupported types passed to json encoding functions and reports if checks for the returned error can be omitted.
|
||||
- exhaustive # Detects missing options in enum switch statements.
|
||||
- exptostd # Detects functions from golang.org/x/exp/ that can be replaced by std functions.
|
||||
- fatcontext # Detects nested contexts in loops and function literals.
|
||||
- forbidigo
|
||||
- gocheckcompilerdirectives # Detects invalid go compiler directive comments (//go:).
|
||||
- gosec # Detects security problems.
|
||||
- govet
|
||||
- iface # Detects incorrect use of interfaces. Currently only used for "identical" interfaces in the same package.
|
||||
- importas
|
||||
- ineffassign
|
||||
- makezero # Finds slice declarations with non-zero initial length.
|
||||
- mirror # Detects wrong mirror patterns of bytes/strings usage.
|
||||
- misspell # Detects commonly misspelled English words in comments.
|
||||
- nakedret # Detects uses of naked returns.
|
||||
- nilnesserr # Detects returning nil errors. It combines the features of nilness and nilerr,
|
||||
- nosprintfhostport # Detects misuse of Sprintf to construct a host with port in a URL.
|
||||
- reassign # Detects reassigning a top-level variable in another package.
|
||||
- revive # Metalinter; drop-in replacement for golint.
|
||||
- spancheck # Detects mistakes with OpenTelemetry/Census spans.
|
||||
- staticcheck
|
||||
- unconvert # Detects unnecessary type conversions.
|
||||
- unused
|
||||
- usestdlibvars # Detects the possibility to use variables/constants from the Go standard library.
|
||||
- wastedassign # Detects wasted assignment statements.
|
||||
|
||||
disable:
|
||||
- errcheck
|
||||
- spancheck # FIXME
|
||||
|
||||
settings:
|
||||
depguard:
|
||||
rules:
|
||||
main:
|
||||
deny:
|
||||
- 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
|
||||
- pkg: "github.com/containerd/containerd/pkg/userns"
|
||||
desc: Use github.com/moby/sys/userns instead.
|
||||
- pkg: "github.com/tonistiigi/fsutil"
|
||||
desc: The fsutil module does not have a stable API, so we should not have a direct dependency unless necessary.
|
||||
|
||||
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"
|
||||
|
||||
exhaustive:
|
||||
# Program elements to check for exhaustiveness.
|
||||
# Default: [ switch ]
|
||||
check:
|
||||
- switch
|
||||
# - map # TODO(thaJeztah): also enable for maps
|
||||
# Presence of "default" case in switch statements satisfies exhaustiveness,
|
||||
# even if all enum members are not listed.
|
||||
# Default: false
|
||||
#
|
||||
# TODO(thaJeztah): consider not allowing this to catch new values being added (and falling through to "default")
|
||||
default-signifies-exhaustive: true
|
||||
|
||||
forbidigo:
|
||||
forbid:
|
||||
- pkg: ^sync/atomic$
|
||||
pattern: ^atomic\.(Add|CompareAndSwap|Load|Store|Swap).
|
||||
msg: Go 1.19 atomic types should be used instead.
|
||||
- pkg: ^regexp$
|
||||
pattern: ^regexp\.MustCompile
|
||||
msg: Use internal/lazyregexp.New instead.
|
||||
- pkg: github.com/vishvananda/netlink$
|
||||
pattern: ^netlink\.(Handle\.)?(AddrList|BridgeVlanList|ChainList|ClassList|ConntrackTableList|ConntrackDeleteFilter$|ConntrackDeleteFilters|DevLinkGetDeviceList|DevLinkGetAllPortList|DevlinkGetDeviceParams|FilterList|FouList|GenlFamilyList|GTPPDPList|LinkByName|LinkByAlias|LinkList|LinkSubscribeWithOptions|NeighList$|NeighProxyList|NeighListExecute|NeighSubscribeWithOptions|LinkGetProtinfo|QdiscList|RdmaLinkList|RdmaLinkByName|RdmaLinkDel|RouteList|RouteListFilteredIter|RuleListFiltered$|RouteSubscribeWithOptions|RuleList$|RuleListFiltered|SocketGet|SocketDiagTCPInfo|SocketDiagTCP|SocketDiagUDPInfo|SocketDiagUDP|UnixSocketDiagInfo|UnixSocketDiag|VDPAGetDevConfigList|VDPAGetDevList|VDPAGetMGMTDevList|XfrmPolicyList|XfrmStateList)
|
||||
msg: Use internal nlwrap package for EINTR handling.
|
||||
- pkg: github.com/docker/docker/internal/nlwrap$
|
||||
pattern: ^nlwrap.Handle.(BridgeVlanList|ChainList|ClassList|ConntrackDeleteFilter$|DevLinkGetDeviceList|DevLinkGetAllPortList|DevlinkGetDeviceParams|FilterList|FouList|GenlFamilyList|GTPPDPList|LinkByAlias|LinkSubscribeWithOptions|NeighList$|NeighProxyList|NeighListExecute|NeighSubscribeWithOptions|LinkGetProtinfo|QdiscList|RdmaLinkList|RdmaLinkByName|RdmaLinkDel|RouteListFilteredIter|RuleListFiltered$|RouteSubscribeWithOptions|RuleList$|RuleListFiltered|SocketGet|SocketDiagTCPInfo|SocketDiagTCP|SocketDiagUDPInfo|SocketDiagUDP|UnixSocketDiagInfo|UnixSocketDiag|VDPAGetDevConfigList|VDPAGetDevList|VDPAGetMGMTDevList)
|
||||
msg: Add a wrapper to nlwrap.Handle for EINTR handling and update the list in .golangci.yml.
|
||||
analyze-types: true
|
||||
|
||||
gosec:
|
||||
excludes:
|
||||
- G104 # G104: Errors unhandled; (TODO: reduce unhandled errors, or explicitly ignore)
|
||||
- G115 # G115: integer overflow conversion; (TODO: verify these: https://github.com/moby/moby/issues/48358)
|
||||
- G204 # G204: Subprocess launched with variable; too many false positives.
|
||||
- G301 # G301: Expect directory permissions to be 0750 or less (also EXC0009); too restrictive
|
||||
- G302 # G302: Expect file permissions to be 0600 or less (also EXC0009); too restrictive
|
||||
- G304 # G304: Potential file inclusion via variable.
|
||||
- G306 # G306: Expect WriteFile permissions to be 0600 or less (too restrictive; also flags "0o644" permissions)
|
||||
- G307 # G307: Deferring unsafe method "*os.File" on type "Close" (also EXC0008); (TODO: evaluate these and fix where needed: G307: Deferring unsafe method "*os.File" on type "Close")
|
||||
- G504 # G504: Blocklisted import net/http/cgi: Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386); (only affects go < 1.6.3)
|
||||
|
||||
govet:
|
||||
enable-all: true
|
||||
disable:
|
||||
- fieldalignment # TODO: evaluate which ones should be updated.
|
||||
|
||||
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/errdefs
|
||||
alias: cerrdefs
|
||||
- pkg: github.com/containerd/containerd/images
|
||||
alias: c8dimages
|
||||
- pkg: github.com/opencontainers/image-spec/specs-go/v1
|
||||
alias: ocispec
|
||||
- pkg: go.etcd.io/bbolt
|
||||
alias: bolt
|
||||
# Enforce that gotest.tools/v3/assert/cmp is always aliased as "is"
|
||||
- pkg: gotest.tools/v3/assert/cmp
|
||||
alias: is
|
||||
|
||||
nakedret:
|
||||
# Disallow naked returns if func has more lines of code than this setting.
|
||||
# Default: 30
|
||||
max-func-lines: 0
|
||||
|
||||
revive:
|
||||
rules:
|
||||
# FIXME make sure all packages have a description. Currently, there's many packages without.
|
||||
- name: package-comments
|
||||
disabled: true
|
||||
|
||||
staticcheck:
|
||||
checks:
|
||||
- all
|
||||
- -QF1008 # Omit embedded fields from selector expression; https://staticcheck.dev/docs/checks/#QF1008
|
||||
- -ST1000 # Incorrect or missing package comment; https://staticcheck.dev/docs/checks/#ST1000
|
||||
- -ST1003 # Poorly chosen identifier; https://staticcheck.dev/docs/checks/#ST1003
|
||||
- -ST1005 # Incorrectly formatted error string; https://staticcheck.dev/docs/checks/#ST1005
|
||||
|
||||
spancheck:
|
||||
# Default: ["end"]
|
||||
checks:
|
||||
- end # check that `span.End()` is called
|
||||
- record-error # check that `span.RecordError(err)` is called when an error is returned
|
||||
- set-status # check that `span.SetStatus(codes.Error, msg)` is called when an error is returned
|
||||
|
||||
usestdlibvars:
|
||||
# Suggest the use of http.MethodXX.
|
||||
http-method: true
|
||||
# Suggest the use of http.StatusXX.
|
||||
http-status-code: true
|
||||
|
||||
exclusions:
|
||||
paths:
|
||||
- volume/drivers/proxy.go # TODO: this is a generated file but with an invalid header, see https://github.com/moby/moby/pull/46274
|
||||
|
||||
rules:
|
||||
# We prefer to use an "linters.exclusions.rules" 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 excludes at:
|
||||
# https://github.com/golangci/golangci-lint/blob/v1.61.0/pkg/config/issues.go#L11-L104
|
||||
#
|
||||
# The default list of exclusions can be found at:
|
||||
# https://golangci-lint.run/usage/false-positives/#default-exclusions
|
||||
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- errcheck
|
||||
|
||||
- text: "G404: Use of weak random number generator"
|
||||
path: _test\.go
|
||||
linters:
|
||||
- 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: ignoring unused assigns to ctx for now; too many hits in libnetwork/xxx functions that setup traces
|
||||
- text: "assigned to ctx, but never used afterwards"
|
||||
linters:
|
||||
- wastedassign
|
||||
|
||||
- text: "ineffectual assignment to ctx"
|
||||
source: "ctx[, ].*=.*\\(ctx[,)]"
|
||||
linters:
|
||||
- ineffassign
|
||||
|
||||
- text: "SA4006: this value of ctx is never used"
|
||||
source: "ctx[, ].*=.*\\(ctx[,)]"
|
||||
linters:
|
||||
- staticcheck
|
||||
|
||||
# FIXME(thaJeztah): ignoring these transitional utilities until BuildKit is vendored with https://github.com/moby/moby/pull/49743
|
||||
- text: "SA1019: idtools\\.(ToUserIdentityMapping|FromUserIdentityMapping) is deprecated"
|
||||
linters:
|
||||
- staticcheck
|
||||
|
||||
# Ignore "nested context in function literal (fatcontext)" as we intentionally set up tracing on a base-context for tests.
|
||||
# FIXME(thaJeztah): see if there's a more iodiomatic way to do this.
|
||||
- text: 'nested context in function literal'
|
||||
path: '((main|check)_(linux_|)test\.go)|testutil/helpers\.go'
|
||||
linters:
|
||||
- fatcontext
|
||||
|
||||
- text: '^shadow: declaration of "(ctx|err|ok)" shadows declaration'
|
||||
linters:
|
||||
- govet
|
||||
- text: '^shadow: declaration of "(out)" shadows declaration'
|
||||
path: _test\.go
|
||||
linters:
|
||||
- govet
|
||||
- text: 'use of `regexp.MustCompile` forbidden'
|
||||
path: _test\.go
|
||||
linters:
|
||||
- forbidigo
|
||||
- text: 'use of `regexp.MustCompile` forbidden'
|
||||
path: "internal/lazyregexp"
|
||||
linters:
|
||||
- forbidigo
|
||||
- text: 'use of `regexp.MustCompile` forbidden'
|
||||
path: "libnetwork/cmd/networkdb-test/dbclient"
|
||||
linters:
|
||||
- forbidigo
|
||||
|
||||
# Log a warning if an exclusion rule is unused.
|
||||
# Default: false
|
||||
warn-unused: true
|
||||
|
||||
issues:
|
||||
# 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
|
||||
48
.mailmap
48
.mailmap
@@ -7,7 +7,6 @@
|
||||
#
|
||||
# For an explanation of this file format, consult gitmailmap(5).
|
||||
|
||||
Aaron Yoshitake <airandfingers@gmail.com>
|
||||
Aaron L. Xu <liker.xu@foxmail.com>
|
||||
Aaron L. Xu <liker.xu@foxmail.com> <likexu@harmonycloud.cn>
|
||||
Aaron Lehmann <alehmann@netflix.com>
|
||||
@@ -31,10 +30,7 @@ Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
|
||||
Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> <suda.akihiro@lab.ntt.co.jp>
|
||||
Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> <suda.kyoto@gmail.com>
|
||||
Akshay Moghe <akshay.moghe@gmail.com>
|
||||
Alano Terblanche <alano.terblanche@docker.com>
|
||||
Alano Terblanche <alano.terblanche@docker.com> <18033717+Benehiko@users.noreply.github.com>
|
||||
Albin Kerouanton <albinker@gmail.com>
|
||||
Albin Kerouanton <albinker@gmail.com> <557933+akerouanton@users.noreply.github.com>
|
||||
Albin Kerouanton <albinker@gmail.com> <albin@akerouanton.name>
|
||||
Aleksa Sarai <asarai@suse.de>
|
||||
Aleksa Sarai <asarai@suse.de> <asarai@suse.com>
|
||||
@@ -62,8 +58,6 @@ Allen Sun <allensun.shl@alibaba-inc.com> <allen.sun@daocloud.io>
|
||||
Allen Sun <allensun.shl@alibaba-inc.com> <shlallen1990@gmail.com>
|
||||
Anca Iordache <anca.iordache@docker.com>
|
||||
Andrea Denisse Gómez <crypto.andrea@protonmail.ch>
|
||||
Andrew Baxter <423qpsxzhh8k3h@s.rendaw.me>
|
||||
Andrew Baxter <423qpsxzhh8k3h@s.rendaw.me> andrew <>
|
||||
Andrew Kim <taeyeonkim90@gmail.com>
|
||||
Andrew Kim <taeyeonkim90@gmail.com> <akim01@fortinet.com>
|
||||
Andrew Weiss <andrew.weiss@docker.com> <andrew.weiss@microsoft.com>
|
||||
@@ -94,9 +88,6 @@ 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>
|
||||
Austin Vazquez <austin.vazquez.dev@gmail.com>
|
||||
Austin Vazquez <austin.vazquez.dev@gmail.com> <55906459+austinvazquez@users.noreply.github.com>
|
||||
Austin Vazquez <austin.vazquez.dev@gmail.com> <macedonv@amazon.com>
|
||||
Avi Miller <avi.miller@oracle.com> <avi.miller@gmail.com>
|
||||
Ben Bonnefoy <frenchben@docker.com>
|
||||
Ben Golub <ben.golub@dotcloud.com>
|
||||
@@ -112,9 +103,6 @@ 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>
|
||||
@@ -127,7 +115,6 @@ Brian Goff <cpuguy83@gmail.com> <bgoff@cpuguy83-mbp.home>
|
||||
Brian Goff <cpuguy83@gmail.com> <bgoff@cpuguy83-mbp.local>
|
||||
Brian Goff <cpuguy83@gmail.com> <brian.goff@microsoft.com>
|
||||
Brian Goff <cpuguy83@gmail.com> <cpuguy@hey.com>
|
||||
Calvin Liu <flycalvin@qq.com>
|
||||
Cameron Sparr <gh@sparr.email>
|
||||
Carlos de Paula <me@carlosedp.com>
|
||||
Chander Govindarajan <chandergovind@gmail.com>
|
||||
@@ -139,8 +126,6 @@ Chen Mingjie <chenmingjie0828@163.com>
|
||||
Chen Qiu <cheney-90@hotmail.com>
|
||||
Chen Qiu <cheney-90@hotmail.com> <21321229@zju.edu.cn>
|
||||
Chengfei Shang <cfshang@alauda.io>
|
||||
Chengyu Zhu <hudson@cyzhu.com>
|
||||
Chentianze <cmoman@126.com>
|
||||
Chris Dias <cdias@microsoft.com>
|
||||
Chris McKinnel <chris.mckinnel@tangentlabs.co.uk>
|
||||
Chris Price <cprice@mirantis.com>
|
||||
@@ -149,8 +134,6 @@ Chris Telfer <ctelfer@docker.com>
|
||||
Chris Telfer <ctelfer@docker.com> <ctelfer@users.noreply.github.com>
|
||||
Christopher Biscardi <biscarch@sketcht.com>
|
||||
Christopher Latham <sudosurootdev@gmail.com>
|
||||
Christopher Petito <chrisjpetito@gmail.com>
|
||||
Christopher Petito <chrisjpetito@gmail.com> <47751006+krissetto@users.noreply.github.com>
|
||||
Christy Norman <christy@linux.vnet.ibm.com>
|
||||
Chun Chen <ramichen@tencent.com> <chenchun.feed@gmail.com>
|
||||
Corbin Coleman <corbin.coleman@docker.com>
|
||||
@@ -158,8 +141,6 @@ 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>
|
||||
@@ -186,8 +167,6 @@ 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>
|
||||
@@ -234,8 +213,6 @@ 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>
|
||||
@@ -287,7 +264,6 @@ 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>
|
||||
@@ -354,8 +330,6 @@ 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 A. Sternberg <jonathansternberg@gmail.com>
|
||||
Jonathan A. Sternberg <jonathansternberg@gmail.com> <jonathan.sternberg@docker.com>
|
||||
Jonathan Choy <jonathan.j.choy@gmail.com>
|
||||
Jonathan Choy <jonathan.j.choy@gmail.com> <oni@tetsujinlabs.com>
|
||||
Jordan Arentsen <blissdev@gmail.com>
|
||||
@@ -395,9 +369,7 @@ 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 <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 Alvarez <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>
|
||||
@@ -497,21 +469,15 @@ 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> <milas.bowman@docker.com>
|
||||
Milas Bowman <devnull@milas.dev> <milasb@gmail.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> <42430865+msadiq058@users.noreply.github.com>
|
||||
Mohd Sadiq <mohdsadiq058@gmail.com> <mohdsadiq058@gmail.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>
|
||||
Myeongjoon Kim <kimmj8409@gmail.com>
|
||||
Nace Oroz <orkica@gmail.com>
|
||||
Natasha Jarus <linuxmercedes@gmail.com>
|
||||
Nathan LeClaire <nathan.leclaire@docker.com> <nathan.leclaire@gmail.com>
|
||||
@@ -531,11 +497,8 @@ Olli Janatuinen <olli.janatuinen@gmail.com> <olljanat@users.noreply.github.com>
|
||||
Onur Filiz <onur.filiz@microsoft.com>
|
||||
Onur Filiz <onur.filiz@microsoft.com> <ofiliz@users.noreply.github.com>
|
||||
Ouyang Liduo <oyld0210@163.com>
|
||||
Patrick St. laurent <patrick@saint-laurent.us>
|
||||
Patrick Stapleton <github@gdi2290.com>
|
||||
Paul Liljenberg <liljenberg.paul@gmail.com> <letters@paulnotcom.se>
|
||||
Paweł Gronowski <pawel.gronowski@docker.com>
|
||||
Paweł Gronowski <pawel.gronowski@docker.com> <me@woland.xyz>
|
||||
Pavel Tikhomirov <ptikhomirov@virtuozzo.com> <ptikhomirov@parallels.com>
|
||||
Pawel Konczalski <mail@konczalski.de>
|
||||
Peter Choi <phkchoi89@gmail.com> <reikani@Peters-MacBook-Pro.local>
|
||||
@@ -557,21 +520,16 @@ 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>
|
||||
Rob Murray <rob.murray@docker.com>
|
||||
Rob Murray <rob.murray@docker.com> <148866618+robmry@users.noreply.github.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>
|
||||
Robin Thoni <robin@rthoni.com>
|
||||
Rodrigo Campos <rodrigoca@microsoft.com>
|
||||
Rodrigo Campos <rodrigoca@microsoft.com> <rodrigo@kinvolk.io>
|
||||
Roman Dudin <katrmr@gmail.com> <decadent@users.noreply.github.com>
|
||||
Rong Zhang <rongzhang@alauda.io>
|
||||
Rongxiang Song <tinysong1226@gmail.com>
|
||||
Rony Weng <ronyweng@synology.com>
|
||||
Ross Boucher <rboucher@gmail.com>
|
||||
Rui Cao <ruicao@alauda.io>
|
||||
Rui JingAn <quiterace@gmail.com>
|
||||
Runshen Zhu <runshen.zhu@gmail.com>
|
||||
Ryan Stelly <ryan.stelly@live.com>
|
||||
Ryoga Saito <contact@proelbtn.com>
|
||||
@@ -590,9 +548,7 @@ 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>
|
||||
@@ -739,8 +695,6 @@ 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>
|
||||
|
||||
122
AUTHORS
122
AUTHORS
@@ -2,10 +2,7 @@
|
||||
# This file lists all contributors to the repository.
|
||||
# See hack/generate-authors.sh to make modifications.
|
||||
|
||||
17neverends <ionianrise@gmail.com>
|
||||
7sunarni <710720732@qq.com>
|
||||
Aanand Prasad <aanand.prasad@gmail.com>
|
||||
Aarni Koskela <akx@iki.fi>
|
||||
Aaron Davidson <aaron@databricks.com>
|
||||
Aaron Feng <aaron.feng@gmail.com>
|
||||
Aaron Hnatiw <aaron@griddio.com>
|
||||
@@ -13,8 +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 Yoshitake <airandfingers@gmail.com>
|
||||
Abdur Rehman <abdur_rehman@mentor.com>
|
||||
Abel Muiño <amuino@gmail.com>
|
||||
Abhijeet Kasurde <akasurde@redhat.com>
|
||||
Abhinandan Prativadi <aprativadi@gmail.com>
|
||||
@@ -28,13 +23,10 @@ Adam Avilla <aavilla@yp.com>
|
||||
Adam Dobrawy <naczelnik@jawnosc.tk>
|
||||
Adam Eijdenberg <adam.eijdenberg@gmail.com>
|
||||
Adam Kunk <adam.kunk@tiaa-cref.org>
|
||||
Adam Lamers <adam.lamers@wmsdev.pl>
|
||||
Adam Miller <admiller@redhat.com>
|
||||
Adam Mills <adam@armills.info>
|
||||
Adam Pointer <adam.pointer@skybettingandgaming.com>
|
||||
Adam Simon <adamsimon85100@gmail.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>
|
||||
@@ -69,7 +61,6 @@ alambike <alambike@gmail.com>
|
||||
Alan Hoyle <alan@alanhoyle.com>
|
||||
Alan Scherger <flyinprogrammer@gmail.com>
|
||||
Alan Thompson <cloojure@gmail.com>
|
||||
Alano Terblanche <alano.terblanche@docker.com>
|
||||
Albert Callarisa <shark234@gmail.com>
|
||||
Albert Zhang <zhgwenming@gmail.com>
|
||||
Albin Kerouanton <albinker@gmail.com>
|
||||
@@ -125,7 +116,6 @@ amangoel <amangoel@gmail.com>
|
||||
Amen Belayneh <amenbelayneh@gmail.com>
|
||||
Ameya Gawde <agawde@mirantis.com>
|
||||
Amir Goldstein <amir73il@aquasec.com>
|
||||
AmirBuddy <badinlu.amirhossein@gmail.com>
|
||||
Amit Bakshi <ambakshi@gmail.com>
|
||||
Amit Krishnan <amit.krishnan@oracle.com>
|
||||
Amit Shukla <amit.shukla@docker.com>
|
||||
@@ -150,7 +140,6 @@ Andreas Tiefenthaler <at@an-ti.eu>
|
||||
Andrei Gherzan <andrei@resin.io>
|
||||
Andrei Ushakov <aushakov@netflix.com>
|
||||
Andrei Vagin <avagin@gmail.com>
|
||||
Andrew Baxter <423qpsxzhh8k3h@s.rendaw.me>
|
||||
Andrew C. Bodine <acbodine@us.ibm.com>
|
||||
Andrew Clay Shafer <andrewcshafer@gmail.com>
|
||||
Andrew Duckworth <grillopress@gmail.com>
|
||||
@@ -175,7 +164,6 @@ Andrey Kolomentsev <andrey.kolomentsev@docker.com>
|
||||
Andrey Petrov <andrey.petrov@shazow.net>
|
||||
Andrey Stolbovsky <andrey.stolbovsky@gmail.com>
|
||||
André Martins <aanm90@gmail.com>
|
||||
Andrés Maldonado <maldonado@codelutin.com>
|
||||
Andy Chambers <anchambers@paypal.com>
|
||||
andy diller <dillera@gmail.com>
|
||||
Andy Goldstein <agoldste@redhat.com>
|
||||
@@ -185,12 +173,10 @@ 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>
|
||||
Anil Madhavapeddy <anil@recoil.org>
|
||||
Anirudh Aithal <aithal@amazon.com>
|
||||
Ankit Jain <ajatkj@yahoo.co.in>
|
||||
Ankush Agarwal <ankushagarwal11@gmail.com>
|
||||
Anonmily <michelle@michelleliu.io>
|
||||
@@ -205,7 +191,6 @@ Anton Löfgren <anton.lofgren@gmail.com>
|
||||
Anton Nikitin <anton.k.nikitin@gmail.com>
|
||||
Anton Polonskiy <anton.polonskiy@gmail.com>
|
||||
Anton Tiurin <noxiouz@yandex.ru>
|
||||
Antonio Aguilar <antonio@zoftko.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com>
|
||||
Antonis Kalipetis <akalipetis@gmail.com>
|
||||
Antony Messerli <amesserl@rackspace.com>
|
||||
@@ -228,13 +213,13 @@ Artur Meyster <arthurfbi@yahoo.com>
|
||||
Arun Gupta <arun.gupta@gmail.com>
|
||||
Asad Saeeduddin <masaeedu@gmail.com>
|
||||
Asbjørn Enge <asbjorn@hanafjedle.net>
|
||||
Ashly Mathew <ashly.mathew@sap.com>
|
||||
Austin Vazquez <austin.vazquez.dev@gmail.com>
|
||||
Austin Vazquez <macedonv@amazon.com>
|
||||
averagehuman <averagehuman@users.noreply.github.com>
|
||||
Avi Das <andas222@gmail.com>
|
||||
Avi Kivity <avi@scylladb.com>
|
||||
Avi Miller <avi.miller@oracle.com>
|
||||
Avi Vaid <avaid1996@gmail.com>
|
||||
ayoshitake <airandfingers@gmail.com>
|
||||
Azat Khuyiyakhmetov <shadow_uz@mail.ru>
|
||||
Bao Yonglei <baoyonglei@huawei.com>
|
||||
Bardia Keyoumarsi <bkeyouma@ucsc.edu>
|
||||
@@ -251,7 +236,6 @@ 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>
|
||||
@@ -278,7 +262,7 @@ 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 <bjorn@neersighted.com>
|
||||
Bjorn Neergaard <bneergaard@mirantis.com>
|
||||
Blake Geno <blakegeno@gmail.com>
|
||||
Boaz Shuster <ripcurld.github@gmail.com>
|
||||
bobby abbott <ttobbaybbob@gmail.com>
|
||||
@@ -295,8 +279,6 @@ Brandon Liu <bdon@bdon.org>
|
||||
Brandon Philips <brandon.philips@coreos.com>
|
||||
Brandon Rhodes <brandon@rhodesmill.org>
|
||||
Brendan Dixon <brendand@microsoft.com>
|
||||
Brendon Smith <bws@bws.bio>
|
||||
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>
|
||||
@@ -330,7 +312,6 @@ Burke Libbey <burke@libbey.me>
|
||||
Byung Kang <byung.kang.ctr@amrdec.army.mil>
|
||||
Caleb Spare <cespare@gmail.com>
|
||||
Calen Pennington <cale@edx.org>
|
||||
Calvin Liu <flycalvin@qq.com>
|
||||
Cameron Boehmer <cameron.boehmer@gmail.com>
|
||||
Cameron Sparr <gh@sparr.email>
|
||||
Cameron Spear <cameronspear@gmail.com>
|
||||
@@ -350,14 +331,12 @@ Casey Bisson <casey.bisson@joyent.com>
|
||||
Catalin Pirvu <pirvu.catalin94@gmail.com>
|
||||
Ce Gao <ce.gao@outlook.com>
|
||||
Cedric Davies <cedricda@microsoft.com>
|
||||
Cesar Talledo <cesar.talledo@docker.com>
|
||||
Cezar Sa Espinola <cezarsa@gmail.com>
|
||||
Chad Swenson <chadswen@gmail.com>
|
||||
Chance Zibolski <chance.zibolski@gmail.com>
|
||||
Chander Govindarajan <chandergovind@gmail.com>
|
||||
Chanhun Jeong <keyolk@gmail.com>
|
||||
Chao Wang <wangchao.fnst@cn.fujitsu.com>
|
||||
Charity Kathure <ckathure@microsoft.com>
|
||||
Charles Chan <charleswhchan@users.noreply.github.com>
|
||||
Charles Hooper <charles.hooper@dotcloud.com>
|
||||
Charles Law <claw@conduce.com>
|
||||
@@ -379,14 +358,11 @@ Chen Qiu <cheney-90@hotmail.com>
|
||||
Cheng-mean Liu <soccerl@microsoft.com>
|
||||
Chengfei Shang <cfshang@alauda.io>
|
||||
Chengguang Xu <cgxu519@gmx.com>
|
||||
Chengyu Zhu <hudson@cyzhu.com>
|
||||
Chentianze <cmoman@126.com>
|
||||
Chenyang Yan <memory.yancy@gmail.com>
|
||||
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>
|
||||
@@ -428,7 +404,6 @@ Christopher Crone <christopher.crone@docker.com>
|
||||
Christopher Currie <codemonkey+github@gmail.com>
|
||||
Christopher Jones <tophj@linux.vnet.ibm.com>
|
||||
Christopher Latham <sudosurootdev@gmail.com>
|
||||
Christopher Petito <chrisjpetito@gmail.com>
|
||||
Christopher Rigor <crigor@gmail.com>
|
||||
Christy Norman <christy@linux.vnet.ibm.com>
|
||||
Chun Chen <ramichen@tencent.com>
|
||||
@@ -458,8 +433,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>
|
||||
@@ -494,7 +469,6 @@ Daniel Farrell <dfarrell@redhat.com>
|
||||
Daniel Garcia <daniel@danielgarcia.info>
|
||||
Daniel Gasienica <daniel@gasienica.ch>
|
||||
Daniel Grunwell <mwgrunny@gmail.com>
|
||||
Daniel Guns <danbguns@gmail.com>
|
||||
Daniel Helfand <helfand.4@gmail.com>
|
||||
Daniel Hiltgen <daniel.hiltgen@docker.com>
|
||||
Daniel J Walsh <dwalsh@redhat.com>
|
||||
@@ -539,7 +513,6 @@ 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>
|
||||
@@ -629,7 +602,6 @@ 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>
|
||||
@@ -664,7 +636,6 @@ 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>
|
||||
@@ -690,7 +661,6 @@ 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>
|
||||
@@ -706,7 +676,6 @@ 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>
|
||||
@@ -753,7 +722,6 @@ 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>
|
||||
@@ -776,9 +744,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>
|
||||
François Scala <github@arcenik.net>
|
||||
Fred Lifton <fred.lifton@docker.com>
|
||||
Frederick F. Kautz IV <fkautz@redhat.com>
|
||||
Frederico F. de Oliveira <FreddieOliveira@users.noreply.github.com>
|
||||
@@ -799,7 +765,6 @@ Gabriel L. Somlo <gsomlo@gmail.com>
|
||||
Gabriel Linder <linder.gabriel@gmail.com>
|
||||
Gabriel Monroy <gabriel@opdemand.com>
|
||||
Gabriel Nicolas Avellaneda <avellaneda.gabriel@gmail.com>
|
||||
Gabriel Tomitsuka <gabriel@tomitsuka.com>
|
||||
Gaetan de Villele <gdevillele@gmail.com>
|
||||
Galen Sampson <galen.sampson@gmail.com>
|
||||
Gang Qiao <qiaohai8866@gmail.com>
|
||||
@@ -814,9 +779,7 @@ GennadySpb <lipenkov@gmail.com>
|
||||
Geoff Levand <geoff@infradead.org>
|
||||
Geoffrey Bachelet <grosfrais@gmail.com>
|
||||
Geon Kim <geon0250@gmail.com>
|
||||
George Adams <georgeadams1995@gmail.com>
|
||||
George Kontridze <george@bugsnag.com>
|
||||
George Ma <mayangang@outlook.com>
|
||||
George MacRorie <gmacr31@gmail.com>
|
||||
George Xie <georgexsh@gmail.com>
|
||||
Georgi Hristozov <georgi@forkbomb.nl>
|
||||
@@ -843,7 +806,6 @@ Gopikannan Venugopalsamy <gopikannan.venugopalsamy@gmail.com>
|
||||
Gosuke Miyashita <gosukenator@gmail.com>
|
||||
Gou Rao <gou@portworx.com>
|
||||
Govinda Fichtner <govinda.fichtner@googlemail.com>
|
||||
Grace Choi <grace.54109@gmail.com>
|
||||
Grant Millar <rid@cylo.io>
|
||||
Grant Reaber <grant.reaber@gmail.com>
|
||||
Graydon Hoare <graydon@pobox.com>
|
||||
@@ -903,8 +865,6 @@ 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>
|
||||
@@ -939,7 +899,6 @@ Illo Abdulrahim <abdulrahim.illo@nokia.com>
|
||||
Ilya Dmitrichenko <errordeveloper@gmail.com>
|
||||
Ilya Gusev <mail@igusev.ru>
|
||||
Ilya Khlopotov <ilya.khlopotov@gmail.com>
|
||||
imalasong <2879499479@qq.com>
|
||||
imre Fitos <imre.fitos+github@gmail.com>
|
||||
inglesp <peter.inglesby@gmail.com>
|
||||
Ingo Gottwald <in.gottwald@gmail.com>
|
||||
@@ -957,7 +916,6 @@ J Bruni <joaohbruni@yahoo.com.br>
|
||||
J. Nunn <jbnunn@gmail.com>
|
||||
Jack Danger Canty <jackdanger@squareup.com>
|
||||
Jack Laxson <jackjrabbit@gmail.com>
|
||||
Jack Walker <90711509+j2walker@users.noreply.github.com>
|
||||
Jacob Atzen <jacob@jacobatzen.dk>
|
||||
Jacob Edelman <edelman.jd@gmail.com>
|
||||
Jacob Tomlinson <jacob@tom.linson.uk>
|
||||
@@ -984,7 +942,6 @@ James Nugent <james@jen20.com>
|
||||
James Sanders <james3sanders@gmail.com>
|
||||
James Turnbull <james@lovedthanlost.net>
|
||||
James Watkins-Harvey <jwatkins@progi-media.com>
|
||||
Jameson Hyde <jameson.hyde@docker.com>
|
||||
Jamie Hannaford <jamie@limetree.org>
|
||||
Jamshid Afshar <jafshar@yahoo.com>
|
||||
Jan Breig <git@pygos.space>
|
||||
@@ -1002,7 +959,6 @@ 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>
|
||||
Jasmine Hegman <jasmine@jhegman.com>
|
||||
Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
@@ -1018,7 +974,6 @@ Jason Shepherd <jason@jasonshepherd.net>
|
||||
Jason Smith <jasonrichardsmith@gmail.com>
|
||||
Jason Sommer <jsdirv@gmail.com>
|
||||
Jason Stangroome <jason@codeassassin.com>
|
||||
Jasper Siepkes <siepkes@serviceplanet.nl>
|
||||
Javier Bassi <javierbassi@gmail.com>
|
||||
jaxgeller <jacksongeller@gmail.com>
|
||||
Jay <teguhwpurwanto@gmail.com>
|
||||
@@ -1028,7 +983,6 @@ 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>
|
||||
@@ -1047,7 +1001,6 @@ 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>
|
||||
@@ -1060,12 +1013,10 @@ 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>
|
||||
@@ -1083,16 +1034,13 @@ Jim Perrin <jperrin@centos.org>
|
||||
Jimmy Cuadra <jimmy@jimmycuadra.com>
|
||||
Jimmy Puckett <jimmy.puckett@spinen.com>
|
||||
Jimmy Song <rootsongjc@gmail.com>
|
||||
jinjiadu <jinjiadu@aliyun.com>
|
||||
Jinsoo Park <cellpjs@gmail.com>
|
||||
Jintao Zhang <zhangjintao9020@gmail.com>
|
||||
Jiri Appl <jiria@microsoft.com>
|
||||
Jiri Popelka <jpopelka@redhat.com>
|
||||
Jiuyue Ma <majiuyue@huawei.com>
|
||||
Jiří Župka <jzupka@redhat.com>
|
||||
jjimbo137 <115816493+jjimbo137@users.noreply.github.com>
|
||||
Joakim Roubert <joakim.roubert@axis.com>
|
||||
Joan Grau <grautxo.dev@proton.me>
|
||||
Joao Fernandes <joao.fernandes@docker.com>
|
||||
Joao Trindade <trindade.joao@gmail.com>
|
||||
Joe Beda <joe.github@bedafamily.com>
|
||||
@@ -1133,7 +1081,6 @@ Jon Johnson <jonjohnson@google.com>
|
||||
Jon Surrell <jon.surrell@gmail.com>
|
||||
Jon Wedaman <jweede@gmail.com>
|
||||
Jonas Dohse <jonas@dohse.ch>
|
||||
Jonas Geiler <git@jonasgeiler.com>
|
||||
Jonas Heinrich <Jonas@JonasHeinrich.com>
|
||||
Jonas Pfenniger <jonas@pfenniger.name>
|
||||
Jonathan A. Schweder <jonathanschweder@gmail.com>
|
||||
@@ -1177,7 +1124,6 @@ Josiah Kiehl <jkiehl@riotgames.com>
|
||||
José Tomás Albornoz <jojo@eljojo.net>
|
||||
Joyce Jang <mail@joycejang.com>
|
||||
JP <jpellerin@leapfrogonline.com>
|
||||
JSchltggr <jschltggr@gmail.com>
|
||||
Julian Taylor <jtaylor.debian@googlemail.com>
|
||||
Julien Barbier <write0@gmail.com>
|
||||
Julien Bisconti <veggiemonk@users.noreply.github.com>
|
||||
@@ -1195,7 +1141,6 @@ 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>
|
||||
@@ -1212,7 +1157,6 @@ K. Heller <pestophagous@gmail.com>
|
||||
Kai Blin <kai@samba.org>
|
||||
Kai Qiang Wu (Kennan) <wkq5325@gmail.com>
|
||||
Kaijie Chen <chen@kaijie.org>
|
||||
Kaita Nakamura <kaita.nakamura0830@gmail.com>
|
||||
Kamil Domański <kamil@domanski.co>
|
||||
Kamjar Gerami <kami.gerami@gmail.com>
|
||||
Kanstantsin Shautsou <kanstantsin.sha@gmail.com>
|
||||
@@ -1239,7 +1183,6 @@ 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>
|
||||
@@ -1249,7 +1192,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 <github@crazymax.dev>
|
||||
Kevin Alvarez <crazy-max@users.noreply.github.com>
|
||||
Kevin Burke <kev@inburke.com>
|
||||
Kevin Clark <kevin.clark@gmail.com>
|
||||
Kevin Feyrer <kevin.feyrer@btinternet.com>
|
||||
@@ -1282,12 +1225,10 @@ 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>
|
||||
Kristian Heljas <kristian@kristian.ee>
|
||||
Kristina Zabunova <triara.xiii@gmail.com>
|
||||
Krystian Wojcicki <kwojcicki@sympatico.ca>
|
||||
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
|
||||
@@ -1304,7 +1245,6 @@ Lakshan Perera <lakshan@laktek.com>
|
||||
Lalatendu Mohanty <lmohanty@redhat.com>
|
||||
Lance Chen <cyen0312@gmail.com>
|
||||
Lance Kinley <lkinley@loyaltymethods.com>
|
||||
Lars Andringa <l.s.andringa@rug.nl>
|
||||
Lars Butler <Lars.Butler@gmail.com>
|
||||
Lars Kellogg-Stedman <lars@redhat.com>
|
||||
Lars R. Damerow <lars@pixar.com>
|
||||
@@ -1314,7 +1254,6 @@ Laura Brehm <laurabrehm@hey.com>
|
||||
Laura Frank <ljfrank@gmail.com>
|
||||
Laurent Bernaille <laurent.bernaille@datadoghq.com>
|
||||
Laurent Erignoux <lerignoux@gmail.com>
|
||||
Laurent Goderre <laurent.goderre@docker.com>
|
||||
Laurie Voss <github@seldo.com>
|
||||
Leandro Motta Barros <lmb@stackedboxes.org>
|
||||
Leandro Siqueira <leandro.siqueira@gmail.com>
|
||||
@@ -1367,7 +1306,6 @@ 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>
|
||||
@@ -1395,7 +1333,6 @@ Madhan Raj Mookkandy <MadhanRaj.Mookkandy@microsoft.com>
|
||||
Madhav Puri <madhav.puri@gmail.com>
|
||||
Madhu Venugopal <mavenugo@gmail.com>
|
||||
Mageee <fangpuyi@foxmail.com>
|
||||
maggie44 <64841595+maggie44@users.noreply.github.com>
|
||||
Mahesh Tiyyagura <tmahesh@gmail.com>
|
||||
malnick <malnick@gmail..com>
|
||||
Malte Janduda <mail@janduda.net>
|
||||
@@ -1407,7 +1344,6 @@ 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>
|
||||
@@ -1447,7 +1383,6 @@ 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>
|
||||
@@ -1489,7 +1424,6 @@ Matthias Kühnle <git.nivoc@neverbox.com>
|
||||
Matthias Rampke <mr@soundcloud.com>
|
||||
Matthieu Fronton <m@tthieu.fr>
|
||||
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
|
||||
Matthieu MOREL <matthieu.morel35@gmail.com>
|
||||
Mattias Jernberg <nostrad@gmail.com>
|
||||
Mauricio Garavaglia <mauricio@medallia.com>
|
||||
mauriyouth <mauriyouth@gmail.com>
|
||||
@@ -1527,7 +1461,6 @@ 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>
|
||||
@@ -1576,11 +1509,10 @@ 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 <devnull@milas.dev>
|
||||
Milas Bowman <milasb@gmail.com>
|
||||
Milind Chawre <milindchawre@gmail.com>
|
||||
Miloslav Trmač <mitr@redhat.com>
|
||||
mingqing <limingqing@cyou-inc.com>
|
||||
@@ -1592,7 +1524,6 @@ 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>
|
||||
@@ -1607,7 +1538,6 @@ Muayyad Alsadi <alsadi@gmail.com>
|
||||
Muhammad Zohaib Aslam <zohaibse011@gmail.com>
|
||||
Mustafa Akın <mustafa91@gmail.com>
|
||||
Muthukumar R <muthur@gmail.com>
|
||||
Myeongjoon Kim <kimmj8409@gmail.com>
|
||||
Máximo Cuadros <mcuadros@gmail.com>
|
||||
Médi-Rémi Hashim <medimatrix@users.noreply.github.com>
|
||||
Nace Oroz <orkica@gmail.com>
|
||||
@@ -1622,7 +1552,6 @@ Natasha Jarus <linuxmercedes@gmail.com>
|
||||
Nate Brennand <nate.brennand@clever.com>
|
||||
Nate Eagleson <nate@nateeag.com>
|
||||
Nate Jones <nate@endot.org>
|
||||
Nathan Baulch <nathan.baulch@gmail.com>
|
||||
Nathan Carlson <carl4403@umn.edu>
|
||||
Nathan Herald <me@nathanherald.com>
|
||||
Nathan Hsieh <hsieh.nathan@gmail.com>
|
||||
@@ -1677,7 +1606,6 @@ 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>
|
||||
@@ -1685,7 +1613,6 @@ Nuutti Kotivuori <naked@iki.fi>
|
||||
nzwsch <hi@nzwsch.com>
|
||||
O.S. Tezer <ostezer@gmail.com>
|
||||
objectified <objectified@gmail.com>
|
||||
Octol1ttle <l1ttleofficial@outlook.com>
|
||||
Odin Ugedal <odin@ugedal.com>
|
||||
Oguz Bilgic <fisyonet@gmail.com>
|
||||
Oh Jinkyun <tintypemolly@gmail.com>
|
||||
@@ -1717,10 +1644,8 @@ Patrick Böänziger <patrick.baenziger@bsi-software.com>
|
||||
Patrick Devine <patrick.devine@docker.com>
|
||||
Patrick Haas <patrickhaas@google.com>
|
||||
Patrick Hemmer <patrick.hemmer@gmail.com>
|
||||
Patrick St. laurent <patrick@saint-laurent.us>
|
||||
Patrick Stapleton <github@gdi2290.com>
|
||||
Patrik Cyvoct <patrik@ptrk.io>
|
||||
Patrik Leifert <patrikleifert@hotmail.com>
|
||||
pattichen <craftsbear@gmail.com>
|
||||
Paul "TBBle" Hampson <Paul.Hampson@Pobox.com>
|
||||
Paul <paul9869@gmail.com>
|
||||
@@ -1736,7 +1661,6 @@ 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>
|
||||
@@ -1750,7 +1674,6 @@ 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>
|
||||
@@ -1780,9 +1703,7 @@ 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>
|
||||
@@ -1795,7 +1716,6 @@ Pierre Carrier <pierre@meteor.com>
|
||||
Pierre Dal-Pra <dalpra.pierre@gmail.com>
|
||||
Pierre Wacrenier <pierre.wacrenier@gmail.com>
|
||||
Pierre-Alain RIVIERE <pariviere@ippon.fr>
|
||||
pinglanlu <pinglanlu@outlook.com>
|
||||
Piotr Bogdan <ppbogdan@gmail.com>
|
||||
Piotr Karbowski <piotr.karbowski@protonmail.ch>
|
||||
Porjo <porjo38@yahoo.com.au>
|
||||
@@ -1821,9 +1741,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>
|
||||
Rafael Fernández López <ereslibre@ereslibre.es>
|
||||
Rafal Jeczalik <rjeczalik@gmail.com>
|
||||
Rafe Colton <rafael.colton@gmail.com>
|
||||
Raghavendra K T <raghavendra.kt@linux.vnet.ibm.com>
|
||||
@@ -1855,7 +1773,6 @@ Rich Horwood <rjhorwood@apple.com>
|
||||
Rich Moyse <rich@moyse.us>
|
||||
Rich Seymour <rseymour@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>
|
||||
@@ -1871,7 +1788,6 @@ 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>
|
||||
@@ -1879,7 +1795,6 @@ Robert Obryk <robryk@gmail.com>
|
||||
Robert Schneider <mail@shakeme.info>
|
||||
Robert Shade <robert.shade@gmail.com>
|
||||
Robert Stern <lexandro2000@gmail.com>
|
||||
Robert Sturla <robertsturla@outlook.com>
|
||||
Robert Terhaar <rterhaar@atlanticdynamic.com>
|
||||
Robert Wallis <smilingrob@gmail.com>
|
||||
Robert Wang <robert@arctic.tw>
|
||||
@@ -1891,7 +1806,7 @@ Robin Speekenbrink <robin@kingsquare.nl>
|
||||
Robin Thoni <robin@rthoni.com>
|
||||
robpc <rpcann@gmail.com>
|
||||
Rodolfo Carvalho <rhcarvalho@gmail.com>
|
||||
Rodrigo Campos <rodrigoca@microsoft.com>
|
||||
Rodrigo Campos <rodrigo@kinvolk.io>
|
||||
Rodrigo Vaz <rodrigo.vaz@gmail.com>
|
||||
Roel Van Nyen <roel.vannyen@gmail.com>
|
||||
Roger Peppe <rogpeppe@gmail.com>
|
||||
@@ -1927,7 +1842,6 @@ Royce Remer <royceremer@gmail.com>
|
||||
Rozhnov Alexandr <nox73@ya.ru>
|
||||
Rudolph Gottesheim <r.gottesheim@loot.at>
|
||||
Rui Cao <ruicao@alauda.io>
|
||||
Rui JingAn <quiterace@gmail.com>
|
||||
Rui Lopes <rgl@ruilopes.com>
|
||||
Ruilin Li <liruilin4@huawei.com>
|
||||
Runshen Zhu <runshen.zhu@gmail.com>
|
||||
@@ -1955,7 +1869,6 @@ 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>
|
||||
Sabin Basyal <sabin.basyal@gmail.com>
|
||||
@@ -1972,7 +1885,6 @@ 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>
|
||||
@@ -1996,7 +1908,6 @@ 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>
|
||||
@@ -2012,7 +1923,6 @@ 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>
|
||||
@@ -2024,13 +1934,11 @@ 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>
|
||||
Shane da Silva <shane@dasilva.io>
|
||||
Shaun Kaasten <shaunk@gmail.com>
|
||||
Shaun Thompson <shaun.thompson@docker.com>
|
||||
shaunol <shaunol@gmail.com>
|
||||
Shawn Landden <shawn@churchofgit.com>
|
||||
Shawn Siefkas <shawn.siefkas@meredith.com>
|
||||
@@ -2049,7 +1957,6 @@ Shijun Qin <qinshijun16@mails.ucas.ac.cn>
|
||||
Shishir Mahajan <shishir.mahajan@redhat.com>
|
||||
Shoubhik Bose <sbose78@gmail.com>
|
||||
Shourya Sarcar <shourya.sarcar@gmail.com>
|
||||
Shreenidhi Shedi <shreenidhi.shedi@broadcom.com>
|
||||
Shu-Wai Chow <shu-wai.chow@seattlechildrens.org>
|
||||
shuai-z <zs.broccoli@gmail.com>
|
||||
Shukui Yang <yangshukui@huawei.com>
|
||||
@@ -2089,7 +1996,6 @@ 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>
|
||||
@@ -2097,7 +2003,6 @@ 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>
|
||||
@@ -2137,7 +2042,6 @@ 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>
|
||||
Tadeusz Dudkiewicz <tadeusz.dudkiewicz@rtbhouse.com>
|
||||
Takuto Sato <tockn.jp@gmail.com>
|
||||
tang0th <tang0th@gmx.com>
|
||||
Tangi Colin <tangicolin@gmail.com>
|
||||
@@ -2145,7 +2049,6 @@ Tatsuki Sugiura <sugi@nemui.org>
|
||||
Tatsushi Inagaki <e29253@jp.ibm.com>
|
||||
Taylan Isikdemir <taylani@google.com>
|
||||
Taylor Jones <monitorjbl@gmail.com>
|
||||
tcpdumppy <847462026@qq.com>
|
||||
Ted M. Young <tedyoung@gmail.com>
|
||||
Tehmasp Chaudhri <tehmasp@gmail.com>
|
||||
Tejaswini Duggaraju <naduggar@microsoft.com>
|
||||
@@ -2238,7 +2141,6 @@ Tomek Mańko <tomek.manko@railgun-solutions.com>
|
||||
Tommaso Visconti <tommaso.visconti@gmail.com>
|
||||
Tomoya Tabuchi <t@tomoyat1.com>
|
||||
Tomáš Hrčka <thrcka@redhat.com>
|
||||
Tomáš Virtus <nechtom@gmail.com>
|
||||
tonic <tonicbupt@gmail.com>
|
||||
Tonny Xu <tonny.xu@gmail.com>
|
||||
Tony Abboud <tdabboud@hotmail.com>
|
||||
@@ -2283,7 +2185,6 @@ Victor I. Wood <viw@t2am.com>
|
||||
Victor Lyuboslavsky <victor@victoreda.com>
|
||||
Victor Marmol <vmarmol@google.com>
|
||||
Victor Palma <palma.victor@gmail.com>
|
||||
Victor Toni <victor.toni@gmail.com>
|
||||
Victor Vieux <victor.vieux@docker.com>
|
||||
Victoria Bialas <victoria.bialas@docker.com>
|
||||
Vijaya Kumar K <vijayak@caviumnetworks.com>
|
||||
@@ -2303,7 +2204,6 @@ 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>
|
||||
@@ -2317,7 +2217,6 @@ VladimirAus <v_roudakov@yahoo.com>
|
||||
Vladislav Kolesnikov <vkolesnikov@beget.ru>
|
||||
Vlastimil Zeman <vlastimil.zeman@diffblue.com>
|
||||
Vojtech Vitek (V-Teq) <vvitek@redhat.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>
|
||||
@@ -2335,7 +2234,6 @@ Wassim Dhif <wassimdhif@gmail.com>
|
||||
Wataru Ishida <ishida.wataru@lab.ntt.co.jp>
|
||||
Wayne Chang <wayne@neverfear.org>
|
||||
Wayne Song <wsong@docker.com>
|
||||
weebney <weebney@gmail.com>
|
||||
Weerasak Chongnguluam <singpor@gmail.com>
|
||||
Wei Fu <fuweid89@gmail.com>
|
||||
Wei Wu <wuwei4455@gmail.com>
|
||||
@@ -2352,7 +2250,6 @@ 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>
|
||||
@@ -2392,7 +2289,7 @@ 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 <XinfengLiu@icloud.com>
|
||||
Xinfeng Liu <xinfeng.liu@gmail.com>
|
||||
Xinzi Zhou <imdreamrunner@gmail.com>
|
||||
Xiuming Chen <cc@cxm.cc>
|
||||
Xuecong Liao <satorulogic@gmail.com>
|
||||
@@ -2430,7 +2327,6 @@ You-Sheng Yang (楊有勝) <vicamo@gmail.com>
|
||||
youcai <omegacoleman@gmail.com>
|
||||
Youcef YEKHLEF <yyekhlef@gmail.com>
|
||||
Youfu Zhang <zhangyoufu@gmail.com>
|
||||
YR Chen <stevapple@icloud.com>
|
||||
Yu Changchun <yuchangchun1@huawei.com>
|
||||
Yu Chengxia <yuchengxia@huawei.com>
|
||||
Yu Peng <yu.peng36@zte.com.cn>
|
||||
@@ -2459,7 +2355,6 @@ 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>
|
||||
@@ -2486,7 +2381,6 @@ Zuhayr Elahi <zuhayr.elahi@docker.com>
|
||||
Zunayed Ali <zunayed@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>
|
||||
|
||||
@@ -101,7 +101,7 @@ the contributors guide.
|
||||
<td>
|
||||
<p>
|
||||
Register for the Docker Community Slack at
|
||||
<a href="https://dockr.ly/comm-slack" target="_blank">https://dockr.ly/comm-slack</a>.
|
||||
<a href="https://dockr.ly/slack" target="_blank">https://dockr.ly/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>
|
||||
|
||||
256
Dockerfile
256
Dockerfile
@@ -1,49 +1,23 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG GO_VERSION=1.24.3
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG GO_VERSION=1.20.13
|
||||
ARG BASE_DEBIAN_DISTRO="bullseye"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
ARG XX_VERSION=1.6.1
|
||||
ARG XX_VERSION=1.2.1
|
||||
|
||||
# VPNKIT_VERSION is the version of the vpnkit binary which is used as a fallback
|
||||
# network driver for rootless.
|
||||
ARG VPNKIT_VERSION=0.6.0
|
||||
ARG VPNKIT_VERSION=0.5.0
|
||||
|
||||
# DOCKERCLI_VERSION is the version of the CLI to install in the dev-container.
|
||||
ARG DOCKERCLI_VERSION=v28.2.0-rc.2
|
||||
ARG DOCKERCLI_REPOSITORY="https://github.com/docker/cli.git"
|
||||
|
||||
ARG DOCKERCLI_VERSION=v24.0.2
|
||||
# cli version used for integration-cli tests
|
||||
ARG DOCKERCLI_INTEGRATION_REPOSITORY="https://github.com/docker/cli.git"
|
||||
ARG DOCKERCLI_INTEGRATION_VERSION=v18.06.3-ce
|
||||
|
||||
# BUILDX_VERSION is the version of buildx to install in the dev container.
|
||||
ARG BUILDX_VERSION=0.24.0
|
||||
|
||||
# COMPOSE_VERSION is the version of compose to install in the dev container.
|
||||
ARG COMPOSE_VERSION=v2.36.2
|
||||
ARG DOCKERCLI_INTEGRATION_VERSION=v17.06.2-ce
|
||||
ARG BUILDX_VERSION=0.11.2
|
||||
|
||||
ARG SYSTEMD="false"
|
||||
ARG FIREWALLD="false"
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
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=3.0.0
|
||||
|
||||
# delve is currently only supported on linux/amd64 and linux/arm64;
|
||||
# https://github.com/go-delve/delve/blob/v1.24.1/pkg/proc/native/support_sentinel.go#L1
|
||||
# https://github.com/go-delve/delve/blob/v1.24.1/pkg/proc/native/support_sentinel_linux.go#L1
|
||||
#
|
||||
# ppc64le support was added in v1.21.1, but is still experimental, and requires
|
||||
# the "-tags exp.linuxppc64le" build-tag to be set:
|
||||
# https://github.com/go-delve/delve/commit/71f12207175a1cc09668f856340d8a543c87dcca
|
||||
ARG DELVE_SUPPORTED=${TARGETPLATFORM#linux/amd64} DELVE_SUPPORTED=${DELVE_SUPPORTED#linux/arm64} DELVE_SUPPORTED=${DELVE_SUPPORTED#linux/ppc64le}
|
||||
ARG DELVE_SUPPORTED=${DELVE_SUPPORTED:+"unsupported"}
|
||||
ARG DELVE_SUPPORTED=${DELVE_SUPPORTED:-"supported"}
|
||||
|
||||
# cross compilation helper
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
||||
@@ -57,29 +31,61 @@ COPY --from=build-dummy /build /build
|
||||
# base
|
||||
FROM --platform=$BUILDPLATFORM ${GOLANG_IMAGE} AS base
|
||||
COPY --from=xx / /
|
||||
# Disable collecting local telemetry, as collected by Go and Delve;
|
||||
#
|
||||
# - https://github.com/go-delve/delve/blob/v1.24.1/CHANGELOG.md#1231-2024-09-23
|
||||
# - https://go.dev/doc/telemetry#background
|
||||
RUN go telemetry off && [ "$(go telemetry)" = "off" ] || { echo "Failed to disable Go telemetry"; exit 1; }
|
||||
RUN echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
|
||||
ARG APT_MIRROR
|
||||
RUN test -n "$APT_MIRROR" && sed -ri "s#(httpredir|deb|security).debian.org#${APT_MIRROR}#g" /etc/apt/sources.list || true
|
||||
ARG DEBIAN_FRONTEND
|
||||
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_12/ /' > /etc/apt/sources.list.d/criu.list \
|
||||
echo 'deb https://download.opensuse.org/repositories/devel:/tools:/criu/Debian_11/ /' > /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 \
|
||||
&& /build/criu --version
|
||||
&& install -D /usr/sbin/criu /build/criu
|
||||
|
||||
# registry
|
||||
FROM distribution/distribution:$REGISTRY_VERSION AS registry
|
||||
RUN mkdir /build && mv /bin/registry /build/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
|
||||
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 <<EOT
|
||||
set -ex
|
||||
git fetch -q --depth 1 origin "${REGISTRY_VERSION}" +refs/tags/*:refs/tags/*
|
||||
git checkout -q FETCH_HEAD
|
||||
export GOPATH="/go/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH"
|
||||
CGO_ENABLED=0 xx-go build -o /build/registry-v2 -v ./cmd/registry
|
||||
xx-verify /build/registry-v2
|
||||
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
|
||||
|
||||
# go-swagger
|
||||
FROM base AS swagger-src
|
||||
@@ -108,6 +114,7 @@ EOT
|
||||
# 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 \
|
||||
@@ -121,11 +128,9 @@ ARG TARGETVARIANT
|
||||
RUN /download-frozen-image-v2.sh /build \
|
||||
busybox:latest@sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209 \
|
||||
busybox:glibc@sha256:1f81263701cddf6402afe9f33fca0266d9fff379e59b1748f33d3072da71ee85 \
|
||||
debian:bookworm-slim@sha256:2bc5c236e9b262645a323e9088dfa3bb1ecb16cc75811daf40a23a824d665be9 \
|
||||
debian:bullseye-slim@sha256:dacf278785a4daa9de07596ec739dbc07131e189942772210709c5c0777e8437 \
|
||||
hello-world:latest@sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9 \
|
||||
arm32v7/hello-world:latest@sha256:50b8560ad574c779908da71f7ce370c0a2471c098d44d1c8f6b513c5a55eeeb1 \
|
||||
hello-world:amd64@sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042 \
|
||||
hello-world:arm64@sha256:963612c5503f3f1674f315c67089dee577d8cc6afc18565e0b4183ae355fb343
|
||||
arm32v7/hello-world:latest@sha256:50b8560ad574c779908da71f7ce370c0a2471c098d44d1c8f6b513c5a55eeeb1
|
||||
|
||||
# delve
|
||||
FROM base AS delve-src
|
||||
@@ -135,10 +140,10 @@ RUN git init . && git remote add origin "https://github.com/go-delve/delve.git"
|
||||
# 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.24.1
|
||||
ARG DELVE_VERSION=v1.20.1
|
||||
RUN git fetch -q --depth 1 origin "${DELVE_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
|
||||
|
||||
FROM base AS delve-supported
|
||||
FROM base AS delve-build
|
||||
WORKDIR /usr/src/delve
|
||||
ARG TARGETPLATFORM
|
||||
RUN --mount=from=delve-src,src=/usr/src/delve,rw \
|
||||
@@ -149,8 +154,29 @@ RUN --mount=from=delve-src,src=/usr/src/delve,rw \
|
||||
xx-verify /build/dlv
|
||||
EOT
|
||||
|
||||
FROM binary-dummy AS delve-unsupported
|
||||
FROM delve-${DELVE_SUPPORTED} AS delve
|
||||
# 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
|
||||
FROM binary-dummy AS delve-windows
|
||||
FROM binary-dummy AS delve-linux-arm
|
||||
FROM binary-dummy AS delve-linux-ppc64le
|
||||
FROM binary-dummy AS delve-linux-s390x
|
||||
FROM delve-build AS delve-linux-amd64
|
||||
FROM delve-build AS delve-linux-arm64
|
||||
FROM delve-linux-${TARGETARCH} AS delve-linux
|
||||
FROM delve-${TARGETOS} AS delve
|
||||
|
||||
FROM base AS tomll
|
||||
# GOTOML_VERSION specifies the version of the tomll binary to build and install
|
||||
# from the https://github.com/pelletier/go-toml repository. This binary is used
|
||||
# in CI in the hack/validate/toml script.
|
||||
#
|
||||
# When updating this version, consider updating the github.com/pelletier/go-toml
|
||||
# dependency in vendor.mod accordingly.
|
||||
ARG GOTOML_VERSION=v1.8.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/pelletier/go-toml/cmd/tomll@${GOTOML_VERSION}" \
|
||||
&& /build/tomll --help
|
||||
|
||||
FROM base AS gowinres
|
||||
# GOWINRES_VERSION defines go-winres tool version
|
||||
@@ -171,17 +197,17 @@ RUN git init . && git remote add origin "https://github.com/containerd/container
|
||||
# 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.27
|
||||
ARG CONTAINERD_VERSION=v1.7.13
|
||||
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 DEBIAN_FRONTEND
|
||||
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 && xx-apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
pkg-config
|
||||
gcc libbtrfs-dev libsecret-1-dev
|
||||
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
|
||||
@@ -202,32 +228,26 @@ FROM binary-dummy AS containerd-windows
|
||||
FROM containerd-${TARGETOS} AS containerd
|
||||
|
||||
FROM base AS golangci_lint
|
||||
ARG GOLANGCI_LINT_VERSION=v2.1.5
|
||||
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/v2/cmd/golangci-lint@${GOLANGCI_LINT_VERSION}" \
|
||||
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.12.0
|
||||
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.8.0
|
||||
ARG SHFMT_VERSION=v3.6.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 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
|
||||
@@ -238,8 +258,7 @@ RUN --mount=source=hack/dockerfile/cli.sh,target=/download-or-build-cli.sh \
|
||||
--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 \
|
||||
&& /build/docker completion bash >/completion.bash
|
||||
&& /build/docker --version
|
||||
|
||||
FROM base AS dockercli-integration
|
||||
WORKDIR /go/src/github.com/docker/cli
|
||||
@@ -261,19 +280,17 @@ RUN git init . && git remote add origin "https://github.com/opencontainers/runc.
|
||||
# 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.2.6
|
||||
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 DEBIAN_FRONTEND
|
||||
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 \
|
||||
gcc \
|
||||
libc6-dev \
|
||||
libseccomp-dev \
|
||||
pkg-config
|
||||
dpkg-dev gcc libc6-dev libseccomp-dev
|
||||
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
|
||||
@@ -300,6 +317,7 @@ RUN git fetch -q --depth 1 origin "${TINI_VERSION}" +refs/tags/*:refs/tags/* &&
|
||||
|
||||
FROM base AS tini-build
|
||||
WORKDIR /go/src/github.com/krallin/tini
|
||||
ARG DEBIAN_FRONTEND
|
||||
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
|
||||
@@ -307,9 +325,7 @@ 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
|
||||
gcc libc6-dev
|
||||
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
|
||||
@@ -329,18 +345,17 @@ 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.3.4
|
||||
ARG ROOTLESSKIT_VERSION=v1.1.1
|
||||
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 DEBIAN_FRONTEND
|
||||
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
|
||||
gcc libc6-dev
|
||||
ENV GO111MODULE=on
|
||||
ARG DOCKER_STATIC
|
||||
RUN --mount=from=rootlesskit-src,src=/usr/src/rootlesskit,rw \
|
||||
@@ -350,6 +365,8 @@ RUN --mount=from=rootlesskit-src,src=/usr/src/rootlesskit,rw \
|
||||
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/
|
||||
@@ -359,8 +376,7 @@ FROM binary-dummy AS rootlesskit-windows
|
||||
FROM rootlesskit-${TARGETOS} AS rootlesskit
|
||||
|
||||
FROM base AS crun
|
||||
# CRUN_VERSION is the version of crun to install in the dev-container.
|
||||
ARG CRUN_VERSION=1.21
|
||||
ARG CRUN_VERSION=1.4.5
|
||||
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 \
|
||||
@@ -372,6 +388,7 @@ RUN --mount=type=cache,sharing=locked,id=moby-crun-aptlib,target=/var/lib/apt \
|
||||
libseccomp-dev \
|
||||
libsystemd-dev \
|
||||
libtool \
|
||||
libudev-dev \
|
||||
libyajl-dev \
|
||||
python3 \
|
||||
;
|
||||
@@ -391,8 +408,8 @@ 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 moby/vpnkit-bin:${VPNKIT_VERSION} AS vpnkit-linux-amd64
|
||||
FROM moby/vpnkit-bin:${VPNKIT_VERSION} AS vpnkit-linux-arm64
|
||||
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
|
||||
|
||||
@@ -406,11 +423,7 @@ RUN git fetch -q --depth 1 origin "${CONTAINERUTILITY_VERSION}" +refs/tags/*:ref
|
||||
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 xx-apt-get install -y --no-install-recommends gcc g++ libc6-dev
|
||||
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
|
||||
@@ -424,13 +437,13 @@ 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 docker/buildx-bin:${BUILDX_VERSION} as buildx
|
||||
|
||||
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/
|
||||
@@ -451,7 +464,6 @@ 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
|
||||
@@ -473,23 +485,17 @@ RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
||||
systemd-sysv
|
||||
ENTRYPOINT ["hack/dind-systemd"]
|
||||
|
||||
FROM dev-systemd-${SYSTEMD} AS dev-firewalld-false
|
||||
|
||||
FROM dev-systemd-true AS dev-firewalld-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 \
|
||||
firewalld
|
||||
|
||||
FROM dev-firewalld-${FIREWALLD} AS dev-base
|
||||
FROM dev-systemd-${SYSTEMD} AS dev-base
|
||||
ARG DEBIAN_FRONTEND
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser \
|
||||
&& mkdir -p /home/unprivilegeduser/.local/share/docker \
|
||||
&& chown -R unprivilegeduser /home/unprivilegeduser
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv /go/src/github.com/docker/docker/.bashrc ~/.bashrc
|
||||
# Activate bash completion
|
||||
# Activate bash completion and include Docker's completion if mounted with DOCKER_BASH_COMPLETION_PATH
|
||||
RUN echo "source /usr/share/bash-completion/bash_completion" >> /etc/bash.bashrc
|
||||
RUN ln -s /usr/local/completion/bash/docker /etc/bash_completion.d/docker
|
||||
RUN ldconfig
|
||||
# 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
|
||||
@@ -505,18 +511,18 @@ RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
|
||||
inetutils-ping \
|
||||
iproute2 \
|
||||
iptables \
|
||||
nftables \
|
||||
jq \
|
||||
libcap2-bin \
|
||||
libnet1 \
|
||||
libnl-3-200 \
|
||||
libprotobuf-c1 \
|
||||
libyajl2 \
|
||||
nano \
|
||||
net-tools \
|
||||
netcat-openbsd \
|
||||
patch \
|
||||
pigz \
|
||||
python3-pip \
|
||||
python3-setuptools \
|
||||
python3-wheel \
|
||||
sudo \
|
||||
systemd-journal-remote \
|
||||
thin-provisioning-tools \
|
||||
@@ -527,16 +533,26 @@ 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
|
||||
ARG YAMLLINT_VERSION=1.27.1
|
||||
RUN pip3 install yamllint==${YAMLLINT_VERSION}
|
||||
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 --no-install-recommends -y \
|
||||
gcc \
|
||||
pkg-config \
|
||||
dpkg-dev \
|
||||
libapparmor-dev \
|
||||
libdevmapper-dev \
|
||||
libseccomp-dev \
|
||||
libsecret-1-dev \
|
||||
libsystemd-dev \
|
||||
yamllint
|
||||
libudev-dev
|
||||
COPY --link --from=dockercli /build/ /usr/local/cli
|
||||
COPY --link --from=dockercli /completion.bash /etc/bash_completion.d/docker
|
||||
COPY --link --from=dockercli-integration /build/ /usr/local/cli-integration
|
||||
|
||||
FROM base AS build
|
||||
@@ -544,6 +560,7 @@ COPY --from=gowinres /build/ /usr/local/bin/
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV GO111MODULE=off
|
||||
ENV CGO_ENABLED=1
|
||||
ARG DEBIAN_FRONTEND
|
||||
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 \
|
||||
@@ -554,11 +571,15 @@ 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 \
|
||||
libdevmapper-dev \
|
||||
libseccomp-dev \
|
||||
libsecret-1-dev \
|
||||
libsystemd-dev \
|
||||
pkg-config
|
||||
libudev-dev
|
||||
ARG DOCKER_BUILDTAGS
|
||||
ARG DOCKER_DEBUG
|
||||
ARG DOCKER_GITCOMMIT=HEAD
|
||||
@@ -580,13 +601,14 @@ RUN <<EOT
|
||||
EOT
|
||||
RUN --mount=type=bind,target=.,rw \
|
||||
--mount=type=tmpfs,target=cli/winresources/dockerd \
|
||||
--mount=type=tmpfs,target=cli/winresources/docker-proxy \
|
||||
--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-info os)" != "linux" ] || xx-verify $([ "$DOCKER_STATIC" = "1" ] && echo "--static") /tmp/bundles/${target}-daemon/docker-proxy
|
||||
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
|
||||
@@ -614,7 +636,7 @@ COPY --link --from=build /build /
|
||||
# smoke tests
|
||||
# usage:
|
||||
# > docker buildx bake binary-smoketest
|
||||
FROM base AS smoketest
|
||||
FROM --platform=$TARGETPLATFORM base AS smoketest
|
||||
WORKDIR /usr/local/bin
|
||||
COPY --from=build /build .
|
||||
RUN <<EOT
|
||||
@@ -625,20 +647,6 @@ RUN <<EOT
|
||||
docker-proxy --version
|
||||
EOT
|
||||
|
||||
# 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:
|
||||
# > docker buildx bake dind
|
||||
# > docker run -d --restart always --privileged --name devdind -p 12375:2375 docker-dind --debug --host=tcp://0.0.0.0:2375 --tlsverify=false
|
||||
FROM docker:dind AS dind
|
||||
COPY --link --from=dockercli /build/docker /usr/local/bin/
|
||||
COPY --link --from=buildx /buildx /usr/local/libexec/docker/cli-plugins/docker-buildx
|
||||
COPY --link --from=compose /docker-compose /usr/local/libexec/docker/cli-plugins/docker-compose
|
||||
COPY --link --from=all / /usr/local/bin/
|
||||
|
||||
# usage:
|
||||
# > make shell
|
||||
# > SYSTEMD=true make shell
|
||||
|
||||
@@ -5,14 +5,17 @@
|
||||
|
||||
# This represents the bare minimum required to build and test Docker.
|
||||
|
||||
ARG GO_VERSION=1.24.3
|
||||
ARG GO_VERSION=1.20.13
|
||||
|
||||
ARG BASE_DEBIAN_DISTRO="bookworm"
|
||||
ARG BASE_DEBIAN_DISTRO="bullseye"
|
||||
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
|
||||
|
||||
FROM ${GOLANG_IMAGE}
|
||||
ENV GO111MODULE=off
|
||||
ENV GOTOOLCHAIN=local
|
||||
|
||||
# allow replacing debian mirror
|
||||
ARG APT_MIRROR
|
||||
RUN test -n "$APT_MIRROR" && sed -ri "s#(httpredir|deb|security).debian.org#${APT_MIRROR}#g" /etc/apt/sources.list || true
|
||||
|
||||
# Compile and runtime deps
|
||||
# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#build-dependencies
|
||||
@@ -22,6 +25,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
cmake \
|
||||
git \
|
||||
libapparmor-dev \
|
||||
libdevmapper-dev \
|
||||
libseccomp-dev \
|
||||
ca-certificates \
|
||||
e2fsprogs \
|
||||
@@ -35,10 +40,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
vim-common \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install runc, containerd, and tini
|
||||
# Install runc, containerd, tini and docker-proxy
|
||||
# Please edit hack/dockerfile/install/<name>.installer to update them.
|
||||
COPY hack/dockerfile/install hack/dockerfile/install
|
||||
RUN set -e; for i in runc containerd tini dockercli; \
|
||||
RUN for i in runc containerd tini proxy dockercli; \
|
||||
do hack/dockerfile/install/install.sh $i; \
|
||||
done
|
||||
ENV PATH=/usr/local/cli:$PATH
|
||||
|
||||
@@ -154,19 +154,21 @@
|
||||
|
||||
# The number of build steps below are explicitly minimised to improve performance.
|
||||
|
||||
ARG WINDOWS_BASE_IMAGE=mcr.microsoft.com/windows/servercore
|
||||
ARG WINDOWS_BASE_IMAGE_TAG=ltsc2022
|
||||
FROM ${WINDOWS_BASE_IMAGE}:${WINDOWS_BASE_IMAGE_TAG}
|
||||
# Extremely important - do not change the following line to reference a "specific" image,
|
||||
# such as `mcr.microsoft.com/windows/servercore:ltsc2022`. 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
|
||||
|
||||
# Use PowerShell as the default shell
|
||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||
|
||||
ARG GO_VERSION=1.24.3
|
||||
ARG GOTESTSUM_VERSION=v1.12.0
|
||||
|
||||
# GOWINRES_VERSION is the version of go-winres to install.
|
||||
ARG GOWINRES_VERSION=v0.3.3
|
||||
ARG CONTAINERD_VERSION=v1.7.27
|
||||
ARG GO_VERSION=1.20.13
|
||||
ARG GOTESTSUM_VERSION=v1.8.2
|
||||
ARG GOWINRES_VERSION=v0.3.1
|
||||
ARG CONTAINERD_VERSION=v1.7.13
|
||||
|
||||
# Environment variable notes:
|
||||
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
|
||||
@@ -177,7 +179,6 @@ 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}
|
||||
@@ -222,7 +223,7 @@ RUN `
|
||||
Download-File $location C:\gitsetup.zip; `
|
||||
`
|
||||
Write-Host INFO: Downloading go...; `
|
||||
$dlGoVersion=$Env:GO_VERSION; `
|
||||
$dlGoVersion=$Env:GO_VERSION -replace '\.0$',''; `
|
||||
Download-File "https://go.dev/dl/go${dlGoVersion}.windows-amd64.zip" C:\go.zip; `
|
||||
`
|
||||
Write-Host INFO: Downloading compiler 1 of 3...; `
|
||||
|
||||
165
Jenkinsfile
vendored
Normal file
165
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
#!groovy
|
||||
pipeline {
|
||||
agent none
|
||||
|
||||
options {
|
||||
buildDiscarder(logRotator(daysToKeepStr: '30'))
|
||||
timeout(time: 2, unit: 'HOURS')
|
||||
timestamps()
|
||||
}
|
||||
parameters {
|
||||
booleanParam(name: 'arm64', defaultValue: true, description: 'ARM (arm64) Build/Test')
|
||||
booleanParam(name: 'dco', defaultValue: true, description: 'Run the DCO check')
|
||||
}
|
||||
environment {
|
||||
DOCKER_BUILDKIT = '1'
|
||||
DOCKER_EXPERIMENTAL = '1'
|
||||
DOCKER_GRAPHDRIVER = 'overlay2'
|
||||
CHECK_CONFIG_COMMIT = '33a3680e08d1007e72c3b3f1454f823d8e9948ee'
|
||||
TESTDEBUG = '0'
|
||||
TIMEOUT = '120m'
|
||||
}
|
||||
stages {
|
||||
stage('pr-hack') {
|
||||
when { changeRequest() }
|
||||
steps {
|
||||
script {
|
||||
echo "Workaround for PR auto-cancel feature. Borrowed from https://issues.jenkins-ci.org/browse/JENKINS-43353"
|
||||
def buildNumber = env.BUILD_NUMBER as int
|
||||
if (buildNumber > 1) milestone(buildNumber - 1)
|
||||
milestone(buildNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('DCO-check') {
|
||||
when {
|
||||
beforeAgent true
|
||||
expression { params.dco }
|
||||
}
|
||||
agent { label 'arm64 && ubuntu-2004' }
|
||||
steps {
|
||||
sh '''
|
||||
docker run --rm \
|
||||
-v "$WORKSPACE:/workspace" \
|
||||
-e VALIDATE_REPO=${GIT_URL} \
|
||||
-e VALIDATE_BRANCH=${CHANGE_TARGET} \
|
||||
alpine sh -c 'apk add --no-cache -q bash git openssh-client && git config --system --add safe.directory /workspace && cd /workspace && hack/validate/dco'
|
||||
'''
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
parallel {
|
||||
stage('arm64') {
|
||||
when {
|
||||
beforeAgent true
|
||||
expression { params.arm64 }
|
||||
}
|
||||
agent { label 'arm64 && ubuntu-2004' }
|
||||
environment {
|
||||
TEST_SKIP_INTEGRATION_CLI = '1'
|
||||
}
|
||||
|
||||
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 -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_INTEGRATION_USE_SNAPSHOTTER \
|
||||
-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=arm64-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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
598
MAINTAINERS
598
MAINTAINERS
@@ -1,33 +1,573 @@
|
||||
# Moby maintainers file
|
||||
#
|
||||
# See project/GOVERNANCE.md for committer versus reviewer roles
|
||||
# This file describes the maintainer groups within the moby/moby project.
|
||||
# More detail on Moby project governance is available in the
|
||||
# project/GOVERNANCE.md file found in this repository.
|
||||
#
|
||||
# COMMITTERS
|
||||
# GitHub ID, Name, Email address, GPG fingerprint
|
||||
"akerouanton","Albin Kerouanton","albinker@gmail.com"
|
||||
"AkihiroSuda","Akihiro Suda","akihiro.suda.cz@hco.ntt.co.jp"
|
||||
"austinvazquez","Austin Vazquez","macedonv@amazon.com"
|
||||
"corhere","Cory Snider","csnider@mirantis.com"
|
||||
"cpuguy83","Brian Goff","cpuguy83@gmail.com"
|
||||
"robmry","Rob Murray","rob.murray@docker.com"
|
||||
"thaJeztah","Sebastiaan van Stijn","github@gone.nl"
|
||||
"tianon","Tianon Gravi","admwiggin@gmail.com"
|
||||
"tonistiigi","Tõnis Tiigi","tonis@docker.com"
|
||||
"vvoland","Paweł Gronowski","pawel.gronowski@docker.com"
|
||||
# It is structured to be consumable by both humans and programs.
|
||||
# To extract its contents programmatically, use any TOML-compliant
|
||||
# parser.
|
||||
#
|
||||
# REVIEWERS
|
||||
# GitHub ID, Name, Email address, GPG fingerprint
|
||||
"coolljt0725","Lei Jitang","leijitang@huawei.com"
|
||||
"crazy-max","Kevin Alvarez","contact@crazymax.dev"
|
||||
"dmcgowan","Derek McGowan","derek@mcgstyle.net"
|
||||
"estesp","Phil Estes","estesp@linux.vnet.ibm.com"
|
||||
"justincormack","Justin Cormack","justin.cormack@docker.com"
|
||||
"kolyshkin","Kir Kolyshkin","kolyshkin@gmail.com"
|
||||
"laurazard","Laura Brehm","laurabrehm@hey.com"
|
||||
"neersighted","Bjorn Neergaard","bjorn@neersighted.com"
|
||||
"rumpl","Djordje Lukic","djordje.lukic@docker.com"
|
||||
"samuelkarp","Samuel Karp","me@samuelkarp.com"
|
||||
"stevvooe","Stephen Day","stephen.day@docker.com"
|
||||
"thompson-shaun","Shaun Thompson","shaun.thompson@docker.com"
|
||||
"tiborvass","Tibor Vass","tibor@docker.com"
|
||||
"unclejack","Cristian Staretu","cristian.staretu@gmail.com"
|
||||
# TODO(estesp): This file should not necessarily depend on docker/opensource
|
||||
# This file is compiled into the MAINTAINERS file in docker/opensource.
|
||||
#
|
||||
[Org]
|
||||
|
||||
[Org."Core maintainers"]
|
||||
|
||||
# The Core maintainers are the ghostbusters of the project: when there's a problem others
|
||||
# can't solve, they show up and fix it with bizarre devices and weaponry.
|
||||
# They have final say on technical implementation and coding style.
|
||||
# They are ultimately responsible for quality in all its forms: usability polish,
|
||||
# bugfixes, performance, stability, etc. When ownership can cleanly be passed to
|
||||
# a subsystem, they are responsible for doing so and holding the
|
||||
# subsystem maintainers accountable. If ownership is unclear, they are the de facto owners.
|
||||
|
||||
people = [
|
||||
"akihirosuda",
|
||||
"anusha",
|
||||
"coolljt0725",
|
||||
"corhere",
|
||||
"cpuguy83",
|
||||
"estesp",
|
||||
"johnstep",
|
||||
"justincormack",
|
||||
"kolyshkin",
|
||||
"mhbauer",
|
||||
"neersighted",
|
||||
"rumpl",
|
||||
"runcom",
|
||||
"samuelkarp",
|
||||
"stevvooe",
|
||||
"thajeztah",
|
||||
"tianon",
|
||||
"tibor",
|
||||
"tonistiigi",
|
||||
"unclejack",
|
||||
"vdemeester",
|
||||
"vieux",
|
||||
"vvoland",
|
||||
"yongtang"
|
||||
]
|
||||
|
||||
[Org.Curators]
|
||||
|
||||
# The curators help ensure that incoming issues and pull requests are properly triaged and
|
||||
# that our various contribution and reviewing processes are respected. With their knowledge of
|
||||
# the repository activity, they can also guide contributors to relevant material or
|
||||
# discussions.
|
||||
#
|
||||
# They are neither code nor docs reviewers, so they are never expected to merge. They can
|
||||
# however:
|
||||
# - close an issue or pull request when it's an exact duplicate
|
||||
# - close an issue or pull request when it's inappropriate or off-topic
|
||||
|
||||
people = [
|
||||
"akerouanton",
|
||||
"alexellis",
|
||||
"andrewhsu",
|
||||
"bsousaa",
|
||||
"crazy-max",
|
||||
"fntlnz",
|
||||
"gianarb",
|
||||
"laurazard",
|
||||
"olljanat",
|
||||
"programmerq",
|
||||
"ripcurld",
|
||||
"sam-thibault",
|
||||
"samwhited",
|
||||
"thajeztah"
|
||||
]
|
||||
|
||||
[Org.Alumni]
|
||||
|
||||
# This list contains maintainers that are no longer active on the project.
|
||||
# It is thanks to these people that the project has become what it is today.
|
||||
# Thank you!
|
||||
|
||||
people = [
|
||||
# Aaron Lehmann was a maintainer for swarmkit, the registry, and the engine,
|
||||
# and contributed many improvements, features, and bugfixes in those areas,
|
||||
# among which "automated service rollbacks", templated secrets and configs,
|
||||
# and resumable image layer downloads.
|
||||
"aaronlehmann",
|
||||
|
||||
# Harald Albers is the mastermind behind the bash completion scripts for the
|
||||
# Docker CLI. The completion scripts moved to the Docker CLI repository, so
|
||||
# you can now find him perform his magic in the https://github.com/docker/cli repository.
|
||||
"albers",
|
||||
|
||||
# Andrea Luzzardi started contributing to the Docker codebase in the "dotCloud"
|
||||
# era, even before it was called "Docker". He is one of the architects of both
|
||||
# Swarm and SwarmKit, and its integration into the Docker engine.
|
||||
"aluzzardi",
|
||||
|
||||
# David Calavera contributed many features to Docker, such as an improved
|
||||
# event system, dynamic configuration reloading, volume plugins, fancy
|
||||
# new templating options, and an external client credential store. As a
|
||||
# maintainer, David was release captain for Docker 1.8, and competing
|
||||
# with Jess Frazelle to be "top dream killer".
|
||||
# David is now doing amazing stuff as CTO for https://www.netlify.com,
|
||||
# and tweets as @calavera.
|
||||
"calavera",
|
||||
|
||||
# Michael Crosby was "chief maintainer" of the Docker project.
|
||||
# During his time as a maintainer, Michael contributed to many
|
||||
# milestones of the project; he was release captain of Docker v1.0.0,
|
||||
# started the development of "libcontainer" (what later became runc)
|
||||
# and containerd, as well as demoing cool hacks such as live migrating
|
||||
# a game server container with checkpoint/restore.
|
||||
#
|
||||
# Michael is currently a maintainer of containerd, but you may see
|
||||
# him around in other projects on GitHub.
|
||||
"crosbymichael",
|
||||
|
||||
# Before becoming a maintainer, Daniel Nephin was a core contributor
|
||||
# to "Fig" (now known as Docker Compose). As a maintainer for both the
|
||||
# Engine and Docker CLI, Daniel contributed many features, among which
|
||||
# the `docker stack` commands, allowing users to deploy their Docker
|
||||
# Compose projects as a Swarm service.
|
||||
"dnephin",
|
||||
|
||||
# Doug Davis contributed many features and fixes for the classic builder,
|
||||
# such as "wildcard" copy, the dockerignore file, custom paths/names
|
||||
# for the Dockerfile, as well as enhancements to the API and documentation.
|
||||
# Follow Doug on Twitter, where he tweets as @duginabox.
|
||||
"duglin",
|
||||
|
||||
# As a maintainer, Erik was responsible for the "builder", and
|
||||
# started the first designs for the new networking model in
|
||||
# Docker. Erik is now working on all kinds of plugins for Docker
|
||||
# (https://github.com/contiv) and various open source projects
|
||||
# in his own repository https://github.com/erikh. You may
|
||||
# still stumble into him in our issue tracker, or on IRC.
|
||||
"erikh",
|
||||
|
||||
# Evan Hazlett is the creator of the Shipyard and Interlock open source projects,
|
||||
# and the author of "Orca", which became the foundation of Docker Universal Control
|
||||
# Plane (UCP). As a maintainer, Evan helped integrating SwarmKit (secrets, tasks)
|
||||
# into the Docker engine.
|
||||
"ehazlett",
|
||||
|
||||
# Arnaud Porterie (AKA "icecrime") was in charge of maintaining the maintainers.
|
||||
# As a maintainer, he made life easier for contributors to the Docker open-source
|
||||
# projects, bringing order in the chaos by designing a triage- and review workflow
|
||||
# using labels (see https://icecrime.net/technology/a-structured-approach-to-labeling/),
|
||||
# and automating the hell out of things with his buddies GordonTheTurtle and Poule
|
||||
# (a chicken!).
|
||||
#
|
||||
# A lesser-known fact is that he created the first commit in the libnetwork repository
|
||||
# even though he didn't know anything about it. Some say, he's now selling stuff on
|
||||
# the internet ;-)
|
||||
"icecrime",
|
||||
|
||||
# After a false start with his first PR being rejected, James Turnbull became a frequent
|
||||
# contributor to the documentation, and became a docs maintainer on December 5, 2013. As
|
||||
# a maintainer, James lifted the docs to a higher standard, and introduced the community
|
||||
# guidelines ("three strikes"). James is currently changing the world as CTO of https://www.empatico.org,
|
||||
# meanwhile authoring various books that are worth checking out. You can find him on Twitter,
|
||||
# rambling as @kartar, and although no longer active as a maintainer, he's always "game" to
|
||||
# help out reviewing docs PRs, so you may still see him around in the repository.
|
||||
"jamtur01",
|
||||
|
||||
# Jessica Frazelle, also known as the "Keyser Söze of containers",
|
||||
# runs *everything* in containers. She started contributing to
|
||||
# Docker with a (fun fun) change involving both iptables and regular
|
||||
# expressions (coz, YOLO!) on July 10, 2014
|
||||
# https://github.com/docker/docker/pull/6950/commits/f3a68ffa390fb851115c77783fa4031f1d3b2995.
|
||||
# Jess was Release Captain for Docker 1.4, 1.6 and 1.7, and contributed
|
||||
# many features and improvement, among which "seccomp profiles" (making
|
||||
# containers a lot more secure). Besides being a maintainer, she
|
||||
# set up the CI infrastructure for the project, giving everyone
|
||||
# something to shout at if a PR failed ("noooo Janky!").
|
||||
# Be sure you don't miss her talks at a conference near you (a must-see),
|
||||
# read her blog at https://blog.jessfraz.com (a must-read), and
|
||||
# check out her open source projects on GitHub https://github.com/jessfraz (a must-try).
|
||||
"jessfraz",
|
||||
|
||||
# As a maintainer, John Howard managed to make the impossible possible;
|
||||
# to run Docker on Windows. After facing many challenges, teaching
|
||||
# fellow-maintainers that 'Windows is not Linux', and many changes in
|
||||
# Windows Server to facilitate containers, native Windows containers
|
||||
# saw the light of day in 2015.
|
||||
#
|
||||
# John is now enjoying life without containers: playing piano, painting,
|
||||
# and walking his dogs, but you may occasionally see him drop by on GitHub.
|
||||
"lowenna",
|
||||
|
||||
# Alexander Morozov contributed many features to Docker, worked on the premise of
|
||||
# what later became containerd (and worked on that too), and made a "stupid" Go
|
||||
# vendor tool specifically for docker/docker needs: vndr (https://github.com/LK4D4/vndr).
|
||||
# Not many know that Alexander is a master negotiator, being able to change course
|
||||
# of action with a single "Nope, we're not gonna do that".
|
||||
"lk4d4",
|
||||
|
||||
# Madhu Venugopal was part of the SocketPlane team that joined Docker.
|
||||
# As a maintainer, he was working with Jana for the Container Network
|
||||
# Model (CNM) implemented through libnetwork, and the "routing mesh" powering
|
||||
# Swarm mode networking.
|
||||
"mavenugo",
|
||||
|
||||
# As a maintainer, Kenfe-Mickaël Laventure worked on the container runtime,
|
||||
# integrating containerd 1.0 with the daemon, and adding support for custom
|
||||
# OCI runtimes, as well as implementing the `docker prune` subcommands,
|
||||
# which was a welcome feature to be added. You can keep up with Mickaél on
|
||||
# Twitter (@kmlaventure).
|
||||
"mlaventure",
|
||||
|
||||
# As a docs maintainer, Mary Anthony contributed greatly to the Docker
|
||||
# docs. She wrote the Docker Contributor Guide and Getting Started
|
||||
# Guides. She helped create a doc build system independent of
|
||||
# docker/docker project, and implemented a new docs.docker.com theme and
|
||||
# nav for 2015 Dockercon. Fun fact: the most inherited layer in DockerHub
|
||||
# public repositories was originally referenced in
|
||||
# maryatdocker/docker-whale back in May 2015.
|
||||
"moxiegirl",
|
||||
|
||||
# Jana Radhakrishnan was part of the SocketPlane team that joined Docker.
|
||||
# As a maintainer, he was the lead architect for the Container Network
|
||||
# Model (CNM) implemented through libnetwork, and the "routing mesh" powering
|
||||
# Swarm mode networking.
|
||||
#
|
||||
# Jana started new adventures in networking, but you can find him tweeting as @mrjana,
|
||||
# coding on GitHub https://github.com/mrjana, and he may be hiding on the Docker Community
|
||||
# slack channel :-)
|
||||
"mrjana",
|
||||
|
||||
# Sven Dowideit became a well known person in the Docker ecosphere, building
|
||||
# boot2docker, and became a regular contributor to the project, starting as
|
||||
# early as October 2013 (https://github.com/docker/docker/pull/2119), to become
|
||||
# a maintainer less than two months later (https://github.com/docker/docker/pull/3061).
|
||||
#
|
||||
# As a maintainer, Sven took on the task to convert the documentation from
|
||||
# ReStructuredText to Markdown, migrate to Hugo for generating the docs, and
|
||||
# writing tooling for building, testing, and publishing them.
|
||||
#
|
||||
# If you're not in the occasion to visit "the Australian office", you
|
||||
# can keep up with Sven on Twitter (@SvenDowideit), his blog http://fosiki.com,
|
||||
# and of course on GitHub.
|
||||
"sven",
|
||||
|
||||
# Vincent "vbatts!" Batts made his first contribution to the project
|
||||
# in November 2013, to become a maintainer a few months later, on
|
||||
# May 10, 2014 (https://github.com/docker/docker/commit/d6e666a87a01a5634c250358a94c814bf26cb778).
|
||||
# As a maintainer, Vincent made important contributions to core elements
|
||||
# of Docker, such as "distribution" (tarsum) and graphdrivers (btrfs, devicemapper).
|
||||
# He also contributed the "tar-split" library, an important element
|
||||
# for the content-addressable store.
|
||||
# Vincent is currently a member of the Open Containers Initiative
|
||||
# Technical Oversight Board (TOB), besides his work at Red Hat and
|
||||
# Project Atomic. You can still find him regularly hanging out in
|
||||
# our repository and the #docker-dev and #docker-maintainers IRC channels
|
||||
# for a chat, as he's always a lot of fun.
|
||||
"vbatts",
|
||||
|
||||
# Vishnu became a maintainer to help out on the daemon codebase and
|
||||
# libcontainer integration. He's currently involved in the
|
||||
# Open Containers Initiative, working on the specifications,
|
||||
# besides his work on cAdvisor and Kubernetes for Google.
|
||||
"vishh"
|
||||
]
|
||||
|
||||
[people]
|
||||
|
||||
# A reference list of all people associated with the project.
|
||||
# All other sections should refer to people by their canonical key
|
||||
# in the people section.
|
||||
|
||||
# ADD YOURSELF HERE IN ALPHABETICAL ORDER
|
||||
|
||||
[people.aaronlehmann]
|
||||
Name = "Aaron Lehmann"
|
||||
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"
|
||||
GitHub = "alexellis"
|
||||
|
||||
[people.akihirosuda]
|
||||
Name = "Akihiro Suda"
|
||||
Email = "akihiro.suda.cz@hco.ntt.co.jp"
|
||||
GitHub = "AkihiroSuda"
|
||||
|
||||
[people.aluzzardi]
|
||||
Name = "Andrea Luzzardi"
|
||||
Email = "al@docker.com"
|
||||
GitHub = "aluzzardi"
|
||||
|
||||
[people.albers]
|
||||
Name = "Harald Albers"
|
||||
Email = "github@albersweb.de"
|
||||
GitHub = "albers"
|
||||
|
||||
[people.andrewhsu]
|
||||
Name = "Andrew Hsu"
|
||||
Email = "andrewhsu@docker.com"
|
||||
GitHub = "andrewhsu"
|
||||
|
||||
[people.anusha]
|
||||
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"
|
||||
Email = "david.calavera@gmail.com"
|
||||
GitHub = "calavera"
|
||||
|
||||
[people.coolljt0725]
|
||||
Name = "Lei Jitang"
|
||||
Email = "leijitang@huawei.com"
|
||||
GitHub = "coolljt0725"
|
||||
|
||||
[people.corhere]
|
||||
Name = "Cory Snider"
|
||||
Email = "csnider@mirantis.com"
|
||||
GitHub = "corhere"
|
||||
|
||||
[people.cpuguy83]
|
||||
Name = "Brian Goff"
|
||||
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"
|
||||
GitHub = "crosbymichael"
|
||||
|
||||
[people.dnephin]
|
||||
Name = "Daniel Nephin"
|
||||
Email = "dnephin@gmail.com"
|
||||
GitHub = "dnephin"
|
||||
|
||||
[people.duglin]
|
||||
Name = "Doug Davis"
|
||||
Email = "dug@us.ibm.com"
|
||||
GitHub = "duglin"
|
||||
|
||||
[people.ehazlett]
|
||||
Name = "Evan Hazlett"
|
||||
Email = "ejhazlett@gmail.com"
|
||||
GitHub = "ehazlett"
|
||||
|
||||
[people.erikh]
|
||||
Name = "Erik Hollensbe"
|
||||
Email = "erik@docker.com"
|
||||
GitHub = "erikh"
|
||||
|
||||
[people.estesp]
|
||||
Name = "Phil Estes"
|
||||
Email = "estesp@linux.vnet.ibm.com"
|
||||
GitHub = "estesp"
|
||||
|
||||
[people.fntlnz]
|
||||
Name = "Lorenzo Fontana"
|
||||
Email = "fontanalorenz@gmail.com"
|
||||
GitHub = "fntlnz"
|
||||
|
||||
[people.gianarb]
|
||||
Name = "Gianluca Arbezzano"
|
||||
Email = "ga@thumpflow.com"
|
||||
GitHub = "gianarb"
|
||||
|
||||
[people.icecrime]
|
||||
Name = "Arnaud Porterie"
|
||||
Email = "icecrime@gmail.com"
|
||||
GitHub = "icecrime"
|
||||
|
||||
[people.jamtur01]
|
||||
Name = "James Turnbull"
|
||||
Email = "james@lovedthanlost.net"
|
||||
GitHub = "jamtur01"
|
||||
|
||||
[people.jessfraz]
|
||||
Name = "Jessie Frazelle"
|
||||
Email = "jess@linux.com"
|
||||
GitHub = "jessfraz"
|
||||
|
||||
[people.johnstep]
|
||||
Name = "John Stephens"
|
||||
Email = "johnstep@docker.com"
|
||||
GitHub = "johnstep"
|
||||
|
||||
[people.justincormack]
|
||||
Name = "Justin Cormack"
|
||||
Email = "justin.cormack@docker.com"
|
||||
GitHub = "justincormack"
|
||||
|
||||
[people.kolyshkin]
|
||||
Name = "Kir Kolyshkin"
|
||||
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"
|
||||
GitHub = "lk4d4"
|
||||
|
||||
[people.lowenna]
|
||||
Name = "John Howard"
|
||||
Email = "github@lowenna.com"
|
||||
GitHub = "lowenna"
|
||||
|
||||
[people.mavenugo]
|
||||
Name = "Madhu Venugopal"
|
||||
Email = "madhu@docker.com"
|
||||
GitHub = "mavenugo"
|
||||
|
||||
[people.mhbauer]
|
||||
Name = "Morgan Bauer"
|
||||
Email = "mbauer@us.ibm.com"
|
||||
GitHub = "mhbauer"
|
||||
|
||||
[people.mlaventure]
|
||||
Name = "Kenfe-Mickaël Laventure"
|
||||
Email = "mickael.laventure@gmail.com"
|
||||
GitHub = "mlaventure"
|
||||
|
||||
[people.moxiegirl]
|
||||
Name = "Mary Anthony"
|
||||
Email = "mary.anthony@docker.com"
|
||||
GitHub = "moxiegirl"
|
||||
|
||||
[people.mrjana]
|
||||
Name = "Jana Radhakrishnan"
|
||||
Email = "mrjana@docker.com"
|
||||
GitHub = "mrjana"
|
||||
|
||||
[people.neersighted]
|
||||
Name = "Bjorn Neergaard"
|
||||
Email = "bneergaard@mirantis.com"
|
||||
GitHub = "neersighted"
|
||||
|
||||
[people.olljanat]
|
||||
Name = "Olli Janatuinen"
|
||||
Email = "olli.janatuinen@gmail.com"
|
||||
GitHub = "olljanat"
|
||||
|
||||
[people.programmerq]
|
||||
Name = "Jeff Anderson"
|
||||
Email = "jeff@docker.com"
|
||||
GitHub = "programmerq"
|
||||
|
||||
[people.ripcurld]
|
||||
Name = "Boaz Shuster"
|
||||
Email = "ripcurld.github@gmail.com"
|
||||
GitHub = "ripcurld"
|
||||
|
||||
[people.rumpl]
|
||||
Name = "Djordje Lukic"
|
||||
Email = "djordje.lukic@docker.com"
|
||||
GitHub = "rumpl"
|
||||
|
||||
[people.runcom]
|
||||
Name = "Antonio Murdaca"
|
||||
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"
|
||||
GitHub = "samuelkarp"
|
||||
|
||||
[people.samwhited]
|
||||
Name = "Sam Whited"
|
||||
Email = "sam@samwhited.com"
|
||||
GitHub = "samwhited"
|
||||
|
||||
[people.shykes]
|
||||
Name = "Solomon Hykes"
|
||||
Email = "solomon@docker.com"
|
||||
GitHub = "shykes"
|
||||
|
||||
[people.stevvooe]
|
||||
Name = "Stephen Day"
|
||||
Email = "stephen.day@docker.com"
|
||||
GitHub = "stevvooe"
|
||||
|
||||
[people.sven]
|
||||
Name = "Sven Dowideit"
|
||||
Email = "SvenDowideit@home.org.au"
|
||||
GitHub = "SvenDowideit"
|
||||
|
||||
[people.thajeztah]
|
||||
Name = "Sebastiaan van Stijn"
|
||||
Email = "github@gone.nl"
|
||||
GitHub = "thaJeztah"
|
||||
|
||||
[people.tianon]
|
||||
Name = "Tianon Gravi"
|
||||
Email = "admwiggin@gmail.com"
|
||||
GitHub = "tianon"
|
||||
|
||||
[people.tibor]
|
||||
Name = "Tibor Vass"
|
||||
Email = "tibor@docker.com"
|
||||
GitHub = "tiborvass"
|
||||
|
||||
[people.tonistiigi]
|
||||
Name = "Tõnis Tiigi"
|
||||
Email = "tonis@docker.com"
|
||||
GitHub = "tonistiigi"
|
||||
|
||||
[people.unclejack]
|
||||
Name = "Cristian Staretu"
|
||||
Email = "cristian.staretu@gmail.com"
|
||||
GitHub = "unclejack"
|
||||
|
||||
[people.vbatts]
|
||||
Name = "Vincent Batts"
|
||||
Email = "vbatts@redhat.com"
|
||||
GitHub = "vbatts"
|
||||
|
||||
[people.vdemeester]
|
||||
Name = "Vincent Demeester"
|
||||
Email = "vincent@sbr.pm"
|
||||
GitHub = "vdemeester"
|
||||
|
||||
[people.vieux]
|
||||
Name = "Victor Vieux"
|
||||
Email = "vieux@docker.com"
|
||||
GitHub = "vieux"
|
||||
|
||||
[people.vishh]
|
||||
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"
|
||||
Email = "yong.tang.github@outlook.com"
|
||||
GitHub = "yongtang"
|
||||
|
||||
81
Makefile
81
Makefile
@@ -1,6 +1,12 @@
|
||||
.PHONY: all binary dynbinary build cross help install manpages run shell test test-docker-py test-integration test-unit validate validate-% win
|
||||
|
||||
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 -f {{ .Driver }} 2>&1))
|
||||
export DOCKER_GRAPHDRIVER
|
||||
|
||||
DOCKER_GITCOMMIT := $(shell git rev-parse HEAD)
|
||||
export DOCKER_GITCOMMIT
|
||||
|
||||
@@ -10,9 +16,6 @@ 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
|
||||
@@ -21,9 +24,10 @@ export GIT_PAGER
|
||||
# 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,zfs" dynbinary
|
||||
# make DOCKER_LDFLAGS="-X github.com/docker/docker/daemon/graphdriver.priority=overlay2,devicemapper" dynbinary
|
||||
#
|
||||
DOCKER_ENVS := \
|
||||
-e BUILD_APT_MIRROR \
|
||||
-e BUILDFLAGS \
|
||||
-e KEEPBUNDLE \
|
||||
-e DOCKER_BUILD_ARGS \
|
||||
@@ -31,6 +35,7 @@ DOCKER_ENVS := \
|
||||
-e DOCKER_BUILD_OPTS \
|
||||
-e DOCKER_BUILD_PKGS \
|
||||
-e DOCKER_BUILDKIT \
|
||||
-e DOCKER_BASH_COMPLETION_PATH \
|
||||
-e DOCKER_CLI_PATH \
|
||||
-e DOCKERCLI_VERSION \
|
||||
-e DOCKERCLI_REPOSITORY \
|
||||
@@ -49,7 +54,6 @@ DOCKER_ENVS := \
|
||||
-e DOCKER_USERLANDPROXY \
|
||||
-e DOCKERD_ARGS \
|
||||
-e DELVE_PORT \
|
||||
-e FIREWALLD \
|
||||
-e GITHUB_ACTIONS \
|
||||
-e TEST_FORCE_VALIDATE \
|
||||
-e TEST_INTEGRATION_DIR \
|
||||
@@ -72,22 +76,17 @@ DOCKER_ENVS := \
|
||||
-e PLATFORM \
|
||||
-e DEFAULT_PRODUCT_LICENSE \
|
||||
-e PRODUCT \
|
||||
-e PACKAGER_NAME \
|
||||
-e PAGER \
|
||||
-e GIT_PAGER \
|
||||
-e OTEL_EXPORTER_OTLP_ENDPOINT \
|
||||
-e OTEL_EXPORTER_OTLP_PROTOCOL \
|
||||
-e OTEL_SERVICE_NAME
|
||||
-e PACKAGER_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`
|
||||
# (default to no bind mount if DOCKER_HOST is set)
|
||||
# note: BINDDIR is supported for backwards-compatibility here
|
||||
BIND_DIR := $(if $(BINDDIR),$(BINDDIR),$(if $(DOCKER_HOST),,.))
|
||||
BIND_DIR := $(if $(BINDDIR),$(BINDDIR),$(if $(DOCKER_HOST),,bundles))
|
||||
|
||||
# DOCKER_MOUNT can be overridden, but use at your own risk!
|
||||
# DOCKER_MOUNT can be overriden, but use at your own risk!
|
||||
ifndef DOCKER_MOUNT
|
||||
DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)")
|
||||
DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)")
|
||||
DOCKER_MOUNT := $(if $(DOCKER_BINDDIR_MOUNT_OPTS),$(DOCKER_MOUNT):$(DOCKER_BINDDIR_MOUNT_OPTS),$(DOCKER_MOUNT))
|
||||
|
||||
# This allows the test suite to be able to run without worrying about the underlying fs used by the container running the daemon (e.g. aufs-on-aufs), so long as the host running the container is running a supported fs.
|
||||
@@ -97,14 +96,8 @@ DOCKER_MOUNT := $(if $(DOCKER_MOUNT),$(DOCKER_MOUNT),-v /go/src/github.com/docke
|
||||
|
||||
DOCKER_MOUNT_CACHE := -v docker-dev-cache:/root/.cache -v docker-mod-cache:/go/pkg/mod/
|
||||
DOCKER_MOUNT_CLI := $(if $(DOCKER_CLI_PATH),-v $(shell dirname $(DOCKER_CLI_PATH)):/usr/local/cli,)
|
||||
|
||||
ifdef BIND_GIT
|
||||
# Gets the common .git directory (even from inside a git worktree)
|
||||
GITDIR := $(shell realpath $(shell git rev-parse --git-common-dir))
|
||||
MOUNT_GITDIR := $(if $(GITDIR),-v "$(GITDIR):$(GITDIR)")
|
||||
endif
|
||||
|
||||
DOCKER_MOUNT := $(DOCKER_MOUNT) $(DOCKER_MOUNT_CACHE) $(DOCKER_MOUNT_CLI) $(DOCKER_MOUNT_BASH_COMPLETION) $(MOUNT_GITDIR)
|
||||
DOCKER_MOUNT_BASH_COMPLETION := $(if $(DOCKER_BASH_COMPLETION_PATH),-v $(shell dirname $(DOCKER_BASH_COMPLETION_PATH)):/usr/local/completion/bash,)
|
||||
DOCKER_MOUNT := $(DOCKER_MOUNT) $(DOCKER_MOUNT_CACHE) $(DOCKER_MOUNT_CLI) $(DOCKER_MOUNT_BASH_COMPLETION)
|
||||
endif # ifndef DOCKER_MOUNT
|
||||
|
||||
# This allows to set the docker-dev container name
|
||||
@@ -115,6 +108,8 @@ DOCKER_PORT_FORWARD := $(if $(DOCKER_PORT),-p "$(DOCKER_PORT)",)
|
||||
DELVE_PORT_FORWARD := $(if $(DELVE_PORT),-p "$(DELVE_PORT)",)
|
||||
|
||||
DOCKER_FLAGS := $(DOCKER) run --rm --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
|
||||
|
||||
SWAGGER_DOCS_PORT ?= 9000
|
||||
|
||||
@@ -142,6 +137,7 @@ endif
|
||||
DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)"
|
||||
|
||||
DOCKER_BUILD_ARGS += --build-arg=GO_VERSION
|
||||
DOCKER_BUILD_ARGS += --build-arg=APT_MIRROR
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_VERSION
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_REPOSITORY
|
||||
DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_INTEGRATION_VERSION
|
||||
@@ -149,29 +145,22 @@ DOCKER_BUILD_ARGS += --build-arg=DOCKERCLI_INTEGRATION_REPOSITORY
|
||||
ifdef DOCKER_SYSTEMD
|
||||
DOCKER_BUILD_ARGS += --build-arg=SYSTEMD=true
|
||||
endif
|
||||
ifdef FIREWALLD
|
||||
DOCKER_BUILD_ARGS += --build-arg=FIREWALLD=true
|
||||
endif
|
||||
|
||||
BUILD_OPTS := ${DOCKER_BUILD_ARGS} ${DOCKER_BUILD_OPTS}
|
||||
BUILD_OPTS := ${BUILD_APT_MIRROR} ${DOCKER_BUILD_ARGS} ${DOCKER_BUILD_OPTS}
|
||||
BUILD_CMD := $(BUILDX) build
|
||||
BAKE_CMD := $(BUILDX) bake
|
||||
|
||||
default: binary
|
||||
|
||||
.PHONY: all
|
||||
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'
|
||||
|
||||
.PHONY: binary
|
||||
binary: bundles ## build statically linked linux binaries
|
||||
$(BAKE_CMD) binary
|
||||
|
||||
.PHONY: dynbinary
|
||||
dynbinary: bundles ## build dynamically linked linux binaries
|
||||
$(BAKE_CMD) dynbinary
|
||||
|
||||
.PHONY: cross
|
||||
cross: bundles ## cross build the binaries
|
||||
$(BAKE_CMD) binary-cross
|
||||
|
||||
@@ -185,15 +174,12 @@ clean: clean-cache
|
||||
clean-cache: ## remove the docker volumes that are used for caching in the dev-container
|
||||
docker volume rm -f docker-dev-cache docker-mod-cache
|
||||
|
||||
.PHONY: help
|
||||
help: ## this help
|
||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9_-]+:.*?## / {gsub("\\\\n",sprintf("\n%22c",""), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||
|
||||
.PHONY: install
|
||||
install: ## install the linux binaries
|
||||
KEEPBUNDLE=1 hack/make.sh install-binary
|
||||
|
||||
.PHONY: run
|
||||
run: build ## run the docker daemon in a container
|
||||
$(DOCKER_RUN_DOCKER) sh -c "KEEPBUNDLE=1 hack/make.sh install-binary run"
|
||||
|
||||
@@ -206,22 +192,17 @@ endif
|
||||
build: bundles
|
||||
$(BUILD_CMD) $(BUILD_OPTS) $(shell_target) --load -t "$(DOCKER_IMAGE)" .
|
||||
|
||||
.PHONY: shell
|
||||
shell: build ## start a shell inside the build env
|
||||
$(DOCKER_RUN_DOCKER) bash
|
||||
|
||||
.PHONY: test
|
||||
test: build test-unit ## run the unit, integration and docker-py tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-integration test-docker-py
|
||||
|
||||
.PHONY: test-docker-py
|
||||
test-docker-py: build ## run the docker-py tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-docker-py
|
||||
|
||||
.PHONY: test-integration-cli
|
||||
test-integration-cli: test-integration ## (DEPRECATED) use test-integration
|
||||
|
||||
.PHONY: test-integration
|
||||
ifneq ($(and $(TEST_SKIP_INTEGRATION),$(TEST_SKIP_INTEGRATION_CLI)),)
|
||||
test-integration:
|
||||
@echo Both integrations suites skipped per environment variables
|
||||
@@ -230,29 +211,18 @@ test-integration: build ## run the integration tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-integration
|
||||
endif
|
||||
|
||||
.PHONY: test-integration-flaky
|
||||
test-integration-flaky: build ## run the stress test for all new integration tests
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-integration-flaky
|
||||
|
||||
.PHONY: test-unit
|
||||
test-unit: build ## run the unit tests
|
||||
$(DOCKER_RUN_DOCKER) hack/test/unit
|
||||
|
||||
.PHONY: validate
|
||||
validate: build ## validate DCO, Seccomp profile generation, gofmt,\n./pkg/ isolation, golint, tests, tomls, go vet and vendor
|
||||
$(DOCKER_RUN_DOCKER) hack/validate/all
|
||||
|
||||
.PHONY: validate-generate-files
|
||||
validate-generate-files:
|
||||
$(BUILD_CMD) --target "validate" \
|
||||
--output "type=cacheonly" \
|
||||
--file "./hack/dockerfiles/generate-files.Dockerfile" .
|
||||
|
||||
.PHONY: validate-%
|
||||
validate-%: build ## validate specific check
|
||||
$(DOCKER_RUN_DOCKER) hack/validate/$*
|
||||
|
||||
.PHONY: win
|
||||
win: bundles ## cross build the binary for windows
|
||||
$(BAKE_CMD) --set *.platform=windows/amd64 binary
|
||||
|
||||
@@ -271,16 +241,3 @@ swagger-docs: ## preview the API documentation
|
||||
-e 'REDOC_OPTIONS=hide-hostname="true" lazy-rendering' \
|
||||
-p $(SWAGGER_DOCS_PORT):80 \
|
||||
bfirsh/redoc:1.14.0
|
||||
|
||||
.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)"/*
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
The Moby Project
|
||||
================
|
||||
|
||||
[](https://pkg.go.dev/github.com/docker/docker)
|
||||
[](https://goreportcard.com/report/github.com/docker/docker)
|
||||
[](https://scorecard.dev/viewer/?uri=github.com/moby/moby)
|
||||
|
||||
|
||||

|
||||
|
||||
Moby is an open-source project created by Docker to enable and accelerate software containerization.
|
||||
@@ -37,7 +32,7 @@ New projects can be added if they fit with the community goals. Docker is commit
|
||||
However, other projects are also encouraged to use Moby as an upstream, and to reuse the components in diverse ways, and all these uses will be treated in the same way. External maintainers and contributors are welcomed.
|
||||
|
||||
The Moby project is not intended as a location for support or feature requests for Docker products, but as a place for contributors to work on open source code, fix bugs, and make the code more useful.
|
||||
The releases are supported by the maintainers, community and users, on a best efforts basis only. For customers who want enterprise or commercial support, [Docker Desktop](https://www.docker.com/products/docker-desktop/) and [Mirantis Container Runtime](https://www.mirantis.com/software/mirantis-container-runtime/) are the appropriate products for these use cases.
|
||||
The releases are supported by the maintainers, community and users, on a best efforts basis only, and are not intended for customers who want enterprise or commercial support; Docker EE is the appropriate product for these use cases.
|
||||
|
||||
-----
|
||||
|
||||
|
||||
43
SECURITY.md
43
SECURITY.md
@@ -1,42 +1,9 @@
|
||||
# Security Policy
|
||||
# Reporting security issues
|
||||
|
||||
The maintainers of the Moby project take security seriously. If you discover
|
||||
a security issue, please bring it to their attention right away!
|
||||
The Moby maintainers take security seriously. If you discover a security issue, please bring it to their attention right away!
|
||||
|
||||
## Reporting a Vulnerability
|
||||
### Reporting a Vulnerability
|
||||
|
||||
Please **DO NOT** file a public issue, instead send your report privately
|
||||
to [security@docker.com](mailto:security@docker.com).
|
||||
Please **DO NOT** file a public issue, instead send your report privately to security@docker.com.
|
||||
|
||||
Reporter(s) can expect a response within 72 hours, acknowledging the issue was
|
||||
received.
|
||||
|
||||
## Review Process
|
||||
|
||||
After receiving the report, an initial triage and technical analysis is
|
||||
performed to confirm the report and determine its scope. We may request
|
||||
additional information in this stage of the process.
|
||||
|
||||
Once a reviewer has confirmed the relevance of the report, a draft security
|
||||
advisory will be created on GitHub. The draft advisory will be used to discuss
|
||||
the issue with maintainers, the reporter(s), and where applicable, other
|
||||
affected parties under embargo.
|
||||
|
||||
If the vulnerability is accepted, a timeline for developing a patch, public
|
||||
disclosure, and patch release will be determined. If there is an embargo period
|
||||
on public disclosure before the patch release, the reporter(s) are expected to
|
||||
participate in the discussion of the timeline and abide by agreed upon dates
|
||||
for public disclosure.
|
||||
|
||||
## Accreditation
|
||||
|
||||
Security reports are greatly appreciated and we will publicly thank you,
|
||||
although we will keep your name confidential if you request it. We also like to
|
||||
send gifts - if you're into swag, make sure to let us know. We do not currently
|
||||
offer a paid security bounty program at this time.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
This project uses long-lived branches to maintain releases. Refer to
|
||||
[BRANCHES-AND-TAGS.md](project/BRANCHES-AND-TAGS.md) in the default branch to
|
||||
learn about the current maintenance status of each branch.
|
||||
Security reports are greatly appreciated and we will publicly thank you for it, although we keep your name confidential if you request it. We also like to send gifts—if you're into schwag, make sure to let us know. We currently do not offer a paid security bounty program, but are not ruling it out in the future.
|
||||
|
||||
@@ -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:9000`. 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`. 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,17 +2,8 @@ package api // import "github.com/docker/docker/api"
|
||||
|
||||
// Common constants for daemon and client.
|
||||
const (
|
||||
// DefaultVersion of the current REST API.
|
||||
DefaultVersion = "1.50"
|
||||
|
||||
// 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"
|
||||
// DefaultVersion of Current REST API
|
||||
DefaultVersion = "1.43"
|
||||
|
||||
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||
// command to specify that no base image is to be used.
|
||||
|
||||
7
api/common_unix.go
Normal file
7
api/common_unix.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package api // import "github.com/docker/docker/api"
|
||||
|
||||
// MinVersion represents Minimum REST API version supported
|
||||
const MinVersion = "1.12"
|
||||
8
api/common_windows.go
Normal file
8
api/common_windows.go
Normal file
@@ -0,0 +1,8 @@
|
||||
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,9 +5,9 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/build"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/builder"
|
||||
buildkit "github.com/docker/docker/builder/builder-next"
|
||||
@@ -52,62 +52,64 @@ func (b *Backend) RegisterGRPC(s *grpc.Server) {
|
||||
// Build builds an image from a Source
|
||||
func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string, error) {
|
||||
options := config.Options
|
||||
useBuildKit := options.Version == build.BuilderBuildKit
|
||||
useBuildKit := options.Version == types.BuilderBuildKit
|
||||
|
||||
tags, err := sanitizeRepoAndTags(options.Tags)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var buildResult *builder.Result
|
||||
var build *builder.Result
|
||||
if useBuildKit {
|
||||
buildResult, err = b.buildkit.Build(ctx, config)
|
||||
build, err = b.buildkit.Build(ctx, config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
buildResult, err = b.builder.Build(ctx, config)
|
||||
build, err = b.builder.Build(ctx, config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if buildResult == nil {
|
||||
if build == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
imageID := buildResult.ImageID
|
||||
var imageID = build.ImageID
|
||||
if options.Squash {
|
||||
if imageID, err = squashBuild(buildResult, b.imageComponent); err != nil {
|
||||
if imageID, err = squashBuild(build, b.imageComponent); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if config.ProgressWriter.AuxFormatter != nil {
|
||||
if err = config.ProgressWriter.AuxFormatter.Emit("moby.image.id", build.Result{ID: imageID}); err != nil {
|
||||
if err = config.ProgressWriter.AuxFormatter.Emit("moby.image.id", types.BuildResult{ID: imageID}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if imageID != "" && !useBuildKit {
|
||||
if !useBuildKit {
|
||||
stdout := config.ProgressWriter.StdoutFormatter
|
||||
_, _ = fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
|
||||
fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
|
||||
}
|
||||
if imageID != "" && !useBuildKit {
|
||||
err = tagImages(ctx, b.imageComponent, config.ProgressWriter.StdoutFormatter, image.ID(imageID), tags)
|
||||
}
|
||||
return imageID, err
|
||||
}
|
||||
|
||||
// PruneCache removes all cached build sources
|
||||
func (b *Backend) PruneCache(ctx context.Context, opts build.CachePruneOptions) (*build.CachePruneReport, error) {
|
||||
func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
|
||||
buildCacheSize, cacheIDs, err := b.buildkit.Prune(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to prune build cache")
|
||||
}
|
||||
b.eventsService.Log(events.ActionPrune, events.BuilderEventType, events.Actor{
|
||||
b.eventsService.Log("prune", events.BuilderEventType, events.Actor{
|
||||
Attributes: map[string]string{
|
||||
"reclaimed": strconv.FormatInt(buildCacheSize, 10),
|
||||
},
|
||||
})
|
||||
return &build.CachePruneReport{SpaceReclaimed: uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
|
||||
return &types.BuildCachePruneReport{SpaceReclaimed: uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
|
||||
}
|
||||
|
||||
// Cancel cancels the build by ID
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -24,7 +24,7 @@ func tagImages(ctx context.Context, ic ImageComponent, stdout io.Writer, imageID
|
||||
// sanitizeRepoAndTags parses the raw "t" parameter received from the client
|
||||
// to a slice of repoAndTag. It removes duplicates, and validates each name
|
||||
// to not contain a digest.
|
||||
func sanitizeRepoAndTags(names []string) (repoAndTags []reference.Named, _ error) {
|
||||
func sanitizeRepoAndTags(names []string) (repoAndTags []reference.Named, err error) {
|
||||
uniqNames := map[string]struct{}{}
|
||||
for _, repo := range names {
|
||||
if repo == "" {
|
||||
|
||||
34
api/server/errorhandler.go
Normal file
34
api/server/errorhandler.go
Normal file
@@ -0,0 +1,34 @@
|
||||
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,76 +1,81 @@
|
||||
package httpstatus // import "github.com/docker/docker/api/server/httpstatus"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/containerd/log"
|
||||
cerrdefs "github.com/containerd/containerd/errdefs"
|
||||
"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"
|
||||
)
|
||||
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
|
||||
// FromError retrieves status code from error message.
|
||||
func FromError(err error) int {
|
||||
if err == nil {
|
||||
log.G(context.TODO()).WithError(err).Error("unexpected HTTP error handling")
|
||||
logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling")
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
// Resolve the error to ensure status is chosen from the first outermost error
|
||||
rerr := cerrdefs.Resolve(err)
|
||||
var statusCode int
|
||||
|
||||
// Stop right there
|
||||
// Are you sure you should be adding a new error class here? Do one of the existing ones work?
|
||||
|
||||
// Note that the below functions are already checking the error causal chain for matches.
|
||||
// Only check errors from the errdefs package, no new error type checking may be added
|
||||
switch {
|
||||
case cerrdefs.IsNotFound(rerr):
|
||||
return http.StatusNotFound
|
||||
case cerrdefs.IsInvalidArgument(rerr):
|
||||
return http.StatusBadRequest
|
||||
case cerrdefs.IsConflict(rerr):
|
||||
return http.StatusConflict
|
||||
case cerrdefs.IsUnauthorized(rerr):
|
||||
return http.StatusUnauthorized
|
||||
case cerrdefs.IsUnavailable(rerr):
|
||||
return http.StatusServiceUnavailable
|
||||
case cerrdefs.IsPermissionDenied(rerr):
|
||||
return http.StatusForbidden
|
||||
case cerrdefs.IsNotModified(rerr):
|
||||
return http.StatusNotModified
|
||||
case cerrdefs.IsNotImplemented(rerr):
|
||||
return http.StatusNotImplemented
|
||||
case cerrdefs.IsInternal(rerr) || cerrdefs.IsDataLoss(rerr) || cerrdefs.IsDeadlineExceeded(rerr) || cerrdefs.IsCanceled(rerr):
|
||||
return http.StatusInternalServerError
|
||||
case errdefs.IsNotFound(err):
|
||||
statusCode = http.StatusNotFound
|
||||
case errdefs.IsInvalidParameter(err):
|
||||
statusCode = http.StatusBadRequest
|
||||
case errdefs.IsConflict(err):
|
||||
statusCode = http.StatusConflict
|
||||
case errdefs.IsUnauthorized(err):
|
||||
statusCode = http.StatusUnauthorized
|
||||
case errdefs.IsUnavailable(err):
|
||||
statusCode = http.StatusServiceUnavailable
|
||||
case errdefs.IsForbidden(err):
|
||||
statusCode = http.StatusForbidden
|
||||
case errdefs.IsNotModified(err):
|
||||
statusCode = http.StatusNotModified
|
||||
case errdefs.IsNotImplemented(err):
|
||||
statusCode = http.StatusNotImplemented
|
||||
case errdefs.IsSystem(err) || errdefs.IsUnknown(err) || errdefs.IsDataLoss(err) || errdefs.IsDeadline(err) || errdefs.IsCancelled(err):
|
||||
statusCode = http.StatusInternalServerError
|
||||
default:
|
||||
if statusCode := statusCodeFromGRPCError(err); statusCode != http.StatusInternalServerError {
|
||||
statusCode = statusCodeFromGRPCError(err)
|
||||
if statusCode != http.StatusInternalServerError {
|
||||
return statusCode
|
||||
}
|
||||
if statusCode := statusCodeFromDistributionError(err); statusCode != http.StatusInternalServerError {
|
||||
statusCode = statusCodeFromContainerdError(err)
|
||||
if statusCode != http.StatusInternalServerError {
|
||||
return statusCode
|
||||
}
|
||||
switch e := err.(type) {
|
||||
case interface{ Unwrap() error }:
|
||||
return FromError(e.Unwrap())
|
||||
case interface{ Unwrap() []error }:
|
||||
for _, ue := range e.Unwrap() {
|
||||
if statusCode := FromError(ue); statusCode != http.StatusInternalServerError {
|
||||
return statusCode
|
||||
}
|
||||
}
|
||||
statusCode = statusCodeFromDistributionError(err)
|
||||
if statusCode != http.StatusInternalServerError {
|
||||
return statusCode
|
||||
}
|
||||
if e, ok := err.(causer); ok {
|
||||
return FromError(e.Cause())
|
||||
}
|
||||
|
||||
if !cerrdefs.IsUnknown(err) {
|
||||
log.G(context.TODO()).WithFields(log.Fields{
|
||||
"module": "api",
|
||||
"error": err,
|
||||
"error_type": fmt.Sprintf("%T", err),
|
||||
}).Debug("FIXME: Got an API for which error does not match any expected type!!!")
|
||||
}
|
||||
|
||||
return http.StatusInternalServerError
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"module": "api",
|
||||
"error_type": fmt.Sprintf("%T", err),
|
||||
}).Debugf("FIXME: Got an API for which error does not match any expected type!!!: %+v", err)
|
||||
}
|
||||
|
||||
if statusCode == 0 {
|
||||
statusCode = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
return statusCode
|
||||
}
|
||||
|
||||
// statusCodeFromGRPCError returns status code according to gRPC error
|
||||
@@ -122,3 +127,24 @@ func statusCodeFromDistributionError(err error) int {
|
||||
}
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
// statusCodeFromContainerdError returns status code for containerd errors when
|
||||
// consumed directly (not through gRPC)
|
||||
func statusCodeFromContainerdError(err error) int {
|
||||
switch {
|
||||
case cerrdefs.IsInvalidArgument(err):
|
||||
return http.StatusBadRequest
|
||||
case cerrdefs.IsNotFound(err):
|
||||
return http.StatusNotFound
|
||||
case cerrdefs.IsAlreadyExists(err):
|
||||
return http.StatusConflict
|
||||
case cerrdefs.IsFailedPrecondition(err):
|
||||
return http.StatusPreconditionFailed
|
||||
case cerrdefs.IsUnavailable(err):
|
||||
return http.StatusServiceUnavailable
|
||||
case cerrdefs.IsNotImplemented(err):
|
||||
return http.StatusNotImplemented
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,5 @@ 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,27 +1,18 @@
|
||||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/docker/distribution/reference"
|
||||
)
|
||||
|
||||
// BoolValue transforms a form value in different formats into a boolean type.
|
||||
func BoolValue(r *http.Request, k string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(r.FormValue(k))) {
|
||||
case "", "0", "no", "false", "none":
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
s := strings.ToLower(strings.TrimSpace(r.FormValue(k)))
|
||||
return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
|
||||
}
|
||||
|
||||
// BoolValueOrDefault returns the default bool passed if the query param is
|
||||
@@ -33,29 +24,6 @@ func BoolValueOrDefault(r *http.Request, k string, d bool) bool {
|
||||
return BoolValue(r, k)
|
||||
}
|
||||
|
||||
// Uint32Value parses a form value into an uint32 type. It returns an error
|
||||
// if the field is not set, empty, incorrectly formatted, or out of range.
|
||||
func Uint32Value(r *http.Request, field string) (uint32, error) {
|
||||
// strconv.ParseUint returns an "strconv.ErrSyntax" for negative values,
|
||||
// not an "out of range". Strip the prefix before parsing, and use it
|
||||
// later to detect valid, but negative values.
|
||||
v, isNeg := strings.CutPrefix(r.Form.Get(field), "-")
|
||||
if v == "" || v[0] == '+' {
|
||||
// Fast-path for invalid values.
|
||||
return 0, strconv.ErrSyntax
|
||||
}
|
||||
|
||||
i, err := strconv.ParseUint(v, 10, 32)
|
||||
if err != nil {
|
||||
// Unwrap to remove the 'strconv.ParseUint: parsing "some-invalid-value":' prefix.
|
||||
return 0, errors.Unwrap(err)
|
||||
}
|
||||
if isNeg {
|
||||
return 0, strconv.ErrRange
|
||||
}
|
||||
return uint32(i), nil
|
||||
}
|
||||
|
||||
// Int64ValueOrZero parses a form value into an int64 type.
|
||||
// It returns 0 if the parsing fails.
|
||||
func Int64ValueOrZero(r *http.Request, k string) int64 {
|
||||
@@ -141,43 +109,3 @@ func ArchiveFormValues(r *http.Request, vars map[string]string) (ArchiveOptions,
|
||||
}
|
||||
return ArchiveOptions{name, path}, nil
|
||||
}
|
||||
|
||||
// DecodePlatform decodes the OCI platform JSON string into a Platform struct.
|
||||
func DecodePlatform(platformJSON string) (*ocispec.Platform, error) {
|
||||
var p ocispec.Platform
|
||||
|
||||
if err := json.Unmarshal([]byte(platformJSON), &p); err != nil {
|
||||
return nil, errdefs.InvalidParameter(errors.Wrap(err, "failed to parse platform"))
|
||||
}
|
||||
|
||||
hasAnyOptional := (p.Variant != "" || p.OSVersion != "" || len(p.OSFeatures) > 0)
|
||||
|
||||
if p.OS == "" && p.Architecture == "" && hasAnyOptional {
|
||||
return nil, errdefs.InvalidParameter(errors.New("optional platform fields provided, but OS and Architecture are missing"))
|
||||
}
|
||||
|
||||
if p.OS == "" || p.Architecture == "" {
|
||||
return nil, errdefs.InvalidParameter(errors.New("both OS and Architecture must be provided"))
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
// DecodePlatforms decodes the OCI platform JSON string into a Platform struct.
|
||||
//
|
||||
// Typically, the argument is a value of: r.Form["platform"]
|
||||
func DecodePlatforms(platformJSONs []string) ([]ocispec.Platform, error) {
|
||||
if len(platformJSONs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var output []ocispec.Platform
|
||||
for _, platform := range platformJSONs {
|
||||
p, err := DecodePlatform(platform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
output = append(output, *p)
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
package httputils // import "github.com/docker/docker/api/server/httputils"
|
||||
|
||||
import (
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestBoolValue(t *testing.T) {
|
||||
@@ -110,126 +103,3 @@ func TestInt64ValueOrDefaultWithError(t *testing.T) {
|
||||
t.Fatal("Expected an error.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint32Value(t *testing.T) {
|
||||
const valueNotSet = "unset"
|
||||
|
||||
tests := []struct {
|
||||
value string
|
||||
expected uint32
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
value: "0",
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
value: strconv.FormatUint(math.MaxUint32, 10),
|
||||
expected: math.MaxUint32,
|
||||
},
|
||||
{
|
||||
value: valueNotSet,
|
||||
expectedErr: strconv.ErrSyntax,
|
||||
},
|
||||
{
|
||||
value: "",
|
||||
expectedErr: strconv.ErrSyntax,
|
||||
},
|
||||
{
|
||||
value: "-1",
|
||||
expectedErr: strconv.ErrRange,
|
||||
},
|
||||
{
|
||||
value: "4294967296", // MaxUint32+1
|
||||
expectedErr: strconv.ErrRange,
|
||||
},
|
||||
{
|
||||
value: "not-a-number",
|
||||
expectedErr: strconv.ErrSyntax,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.value, func(t *testing.T) {
|
||||
r, _ := http.NewRequest(http.MethodPost, "", nil)
|
||||
r.Form = url.Values{}
|
||||
if tc.value != valueNotSet {
|
||||
r.Form.Set("field", tc.value)
|
||||
}
|
||||
out, err := Uint32Value(r, "field")
|
||||
assert.Check(t, is.Equal(tc.expected, out))
|
||||
assert.Check(t, is.ErrorIs(err, tc.expectedErr))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodePlatform(t *testing.T) {
|
||||
tests := []struct {
|
||||
doc string
|
||||
platformJSON string
|
||||
expected *ocispec.Platform
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
doc: "empty platform",
|
||||
expectedErr: `failed to parse platform: unexpected end of JSON input`,
|
||||
},
|
||||
{
|
||||
doc: "not JSON",
|
||||
platformJSON: `linux/ams64`,
|
||||
expectedErr: `failed to parse platform: invalid character 'l' looking for beginning of value`,
|
||||
},
|
||||
{
|
||||
doc: "malformed JSON",
|
||||
platformJSON: `{"architecture"`,
|
||||
expectedErr: `failed to parse platform: unexpected end of JSON input`,
|
||||
},
|
||||
{
|
||||
doc: "missing os",
|
||||
platformJSON: `{"architecture":"amd64","os":""}`,
|
||||
expectedErr: `both OS and Architecture must be provided`,
|
||||
},
|
||||
{
|
||||
doc: "variant without architecture",
|
||||
platformJSON: `{"architecture":"","os":"","variant":"v7"}`,
|
||||
expectedErr: `optional platform fields provided, but OS and Architecture are missing`,
|
||||
},
|
||||
{
|
||||
doc: "missing architecture",
|
||||
platformJSON: `{"architecture":"","os":"linux"}`,
|
||||
expectedErr: `both OS and Architecture must be provided`,
|
||||
},
|
||||
{
|
||||
doc: "os.version without os and architecture",
|
||||
platformJSON: `{"architecture":"","os":"","os.version":"12.0"}`,
|
||||
expectedErr: `optional platform fields provided, but OS and Architecture are missing`,
|
||||
},
|
||||
{
|
||||
doc: "os.features without os and architecture",
|
||||
platformJSON: `{"architecture":"","os":"","os.features":["a","b"]}`,
|
||||
expectedErr: `optional platform fields provided, but OS and Architecture are missing`,
|
||||
},
|
||||
{
|
||||
doc: "valid platform",
|
||||
platformJSON: `{"architecture":"arm64","os":"linux","os.version":"12.0", "os.features":["a","b"], "variant": "v7"}`,
|
||||
expected: &ocispec.Platform{
|
||||
Architecture: "arm64",
|
||||
OS: "linux",
|
||||
OSVersion: "12.0",
|
||||
OSFeatures: []string{"a", "b"},
|
||||
Variant: "v7",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
p, err := DecodePlatform(tc.platformJSON)
|
||||
assert.Check(t, is.DeepEqual(p, tc.expected))
|
||||
if tc.expectedErr != "" {
|
||||
assert.Check(t, cerrdefs.IsInvalidArgument(err))
|
||||
assert.Check(t, is.Error(err, tc.expectedErr))
|
||||
} else {
|
||||
assert.Check(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"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"
|
||||
@@ -17,11 +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 http.ResponseWriter, msgs <-chan *backend.LogMessage, config *container.LogsOptions, mux bool) {
|
||||
// See https://github.com/moby/moby/issues/47448
|
||||
// Trigger headers to be written immediately.
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
func WriteLogStream(_ context.Context, w io.Writer, msgs <-chan *backend.LogMessage, config *types.ContainerLogsOptions, 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 log.GetLevel() == log.DebugLevel {
|
||||
if logrus.GetLevel() == logrus.DebugLevel {
|
||||
next = middleware.DebugRequestMiddleware(next)
|
||||
}
|
||||
|
||||
|
||||
38
api/server/middleware/cors.go
Normal file
38
api/server/middleware/cors.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package middleware // import "github.com/docker/docker/api/server/middleware"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// CORSMiddleware injects CORS headers to each request
|
||||
// when it's configured.
|
||||
type CORSMiddleware struct {
|
||||
defaultHeaders string
|
||||
}
|
||||
|
||||
// NewCORSMiddleware creates a new CORSMiddleware with default headers.
|
||||
func NewCORSMiddleware(d string) CORSMiddleware {
|
||||
return CORSMiddleware{defaultHeaders: d}
|
||||
}
|
||||
|
||||
// WrapHandler returns a new handler function wrapping the previous one in the request chain.
|
||||
func (c CORSMiddleware) 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 {
|
||||
// If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*"
|
||||
// otherwise, all head values will be passed to HTTP handler
|
||||
corsHeaders := c.defaultHeaders
|
||||
if corsHeaders == "" {
|
||||
corsHeaders = "*"
|
||||
}
|
||||
|
||||
logrus.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, "+registry.AuthHeader)
|
||||
w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import (
|
||||
"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/pkg/ioutils"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -18,37 +16,17 @@ import (
|
||||
// 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 {
|
||||
logger := log.G(ctx)
|
||||
|
||||
// Use a variable for fields to prevent overhead of repeatedly
|
||||
// calling WithFields.
|
||||
fields := log.Fields{
|
||||
"module": "api",
|
||||
"method": r.Method,
|
||||
"request-url": r.RequestURI,
|
||||
"vars": vars,
|
||||
}
|
||||
handleWithLogs := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
logger.WithFields(fields).Debugf("handling %s request", r.Method)
|
||||
err := handler(ctx, w, r, vars)
|
||||
if err != nil {
|
||||
// TODO(thaJeztah): unify this with Server.makeHTTPHandler, which also logs internal server errors as error-log. See https://github.com/moby/moby/pull/48740#discussion_r1816675574
|
||||
fields["error-response"] = err
|
||||
fields["status"] = httpstatus.FromError(err)
|
||||
logger.WithFields(fields).Debugf("error response for %s request", r.Method)
|
||||
}
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("Calling %s %s", r.Method, r.RequestURI)
|
||||
|
||||
if r.Method != http.MethodPost {
|
||||
return handleWithLogs(ctx, w, r, vars)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return handleWithLogs(ctx, w, r, vars)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
maxBodySize := 4096 // 4KB
|
||||
if r.ContentLength > int64(maxBodySize) {
|
||||
return handleWithLogs(ctx, w, r, vars)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
|
||||
body := r.Body
|
||||
@@ -58,25 +36,21 @@ func DebugRequestMiddleware(handler func(ctx context.Context, w http.ResponseWri
|
||||
b, err := bufReader.Peek(maxBodySize)
|
||||
if err != io.EOF {
|
||||
// either there was an error reading, or the buffer is full (in which case the request is too large)
|
||||
return handleWithLogs(ctx, w, r, vars)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
|
||||
var postForm map[string]interface{}
|
||||
if err := json.Unmarshal(b, &postForm); err == nil {
|
||||
maskSecretKeys(postForm)
|
||||
// TODO(thaJeztah): is there a better way to detect if we're using JSON-formatted logs?
|
||||
if _, ok := logger.Logger.Formatter.(*logrus.JSONFormatter); ok {
|
||||
fields["form-data"] = postForm
|
||||
formStr, errMarshal := json.Marshal(postForm)
|
||||
if errMarshal == nil {
|
||||
logrus.Debugf("form data: %s", string(formStr))
|
||||
} else {
|
||||
if data, err := json.Marshal(postForm); err != nil {
|
||||
fields["form-data"] = postForm
|
||||
} else {
|
||||
fields["form-data"] = string(data)
|
||||
}
|
||||
logrus.Debugf("form data: %q", postForm)
|
||||
}
|
||||
}
|
||||
|
||||
return handleWithLogs(ctx, w, r, vars)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
)
|
||||
@@ -14,40 +13,19 @@ import (
|
||||
// VersionMiddleware is a middleware that
|
||||
// validates the client and server versions.
|
||||
type VersionMiddleware struct {
|
||||
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
|
||||
serverVersion string
|
||||
defaultVersion string
|
||||
minVersion string
|
||||
}
|
||||
|
||||
// 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)
|
||||
// NewVersionMiddleware creates a new VersionMiddleware
|
||||
// with the default versions.
|
||||
func NewVersionMiddleware(s, d, m string) VersionMiddleware {
|
||||
return VersionMiddleware{
|
||||
serverVersion: s,
|
||||
defaultVersion: d,
|
||||
minVersion: m,
|
||||
}
|
||||
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 {
|
||||
@@ -67,18 +45,18 @@ 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.defaultAPIVersion)
|
||||
w.Header().Set("Ostype", runtime.GOOS)
|
||||
w.Header().Set("API-Version", v.defaultVersion)
|
||||
w.Header().Set("OSType", runtime.GOOS)
|
||||
|
||||
apiVersion := vars["version"]
|
||||
if apiVersion == "" {
|
||||
apiVersion = v.defaultAPIVersion
|
||||
apiVersion = v.defaultVersion
|
||||
}
|
||||
if versions.LessThan(apiVersion, v.minAPIVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, minVersion: v.minAPIVersion}
|
||||
if versions.LessThan(apiVersion, v.minVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, minVersion: v.minVersion}
|
||||
}
|
||||
if versions.GreaterThan(apiVersion, v.defaultAPIVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultAPIVersion}
|
||||
if versions.GreaterThan(apiVersion, v.defaultVersion) {
|
||||
return versionUnsupportedError{version: apiVersion, maxVersion: v.defaultVersion}
|
||||
}
|
||||
ctx = context.WithValue(ctx, httputils.APIVersionKey{}, apiVersion)
|
||||
return handler(ctx, w, r, vars)
|
||||
|
||||
@@ -2,81 +2,27 @@ 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 {
|
||||
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) {
|
||||
expectedVersion := "<not set>"
|
||||
defaultVersion := "1.10.0"
|
||||
minVersion := "1.2.0"
|
||||
expectedVersion := defaultVersion
|
||||
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, err := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
|
||||
assert.NilError(t, err)
|
||||
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
|
||||
h := m.WrapHandler(handler)
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
|
||||
@@ -89,19 +35,19 @@ func TestVersionMiddlewareVersion(t *testing.T) {
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
expectedVersion: api.DefaultVersion,
|
||||
expectedVersion: "1.10.0",
|
||||
},
|
||||
{
|
||||
reqVersion: api.MinSupportedAPIVersion,
|
||||
expectedVersion: api.MinSupportedAPIVersion,
|
||||
reqVersion: "1.9.0",
|
||||
expectedVersion: "1.9.0",
|
||||
},
|
||||
{
|
||||
reqVersion: "0.1",
|
||||
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),
|
||||
errString: "client version 0.1 is too old. Minimum supported API version is 1.2.0, please upgrade your client to a newer version",
|
||||
},
|
||||
{
|
||||
reqVersion: "9999.9999",
|
||||
errString: fmt.Sprintf("client version 9999.9999 is too new. Maximum supported API version is %s", api.DefaultVersion),
|
||||
errString: "client version 9999.9999 is too new. Maximum supported API version is 1.10.0",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -125,8 +71,9 @@ func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
|
||||
m, err := NewVersionMiddleware("1.2.3", api.DefaultVersion, api.MinSupportedAPIVersion)
|
||||
assert.NilError(t, err)
|
||||
defaultVersion := "1.10.0"
|
||||
minVersion := "1.2.0"
|
||||
m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
|
||||
h := m.WrapHandler(handler)
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
|
||||
@@ -134,12 +81,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/1.2.3"))
|
||||
assert.Check(t, is.Contains(hdr.Get("Server"), "Docker/"+defaultVersion))
|
||||
assert.Check(t, is.Contains(hdr.Get("Server"), runtime.GOOS))
|
||||
assert.Check(t, is.Equal(hdr.Get("Api-Version"), api.DefaultVersion))
|
||||
assert.Check(t, is.Equal(hdr.Get("Ostype"), runtime.GOOS))
|
||||
assert.Check(t, is.Equal(hdr.Get("API-Version"), defaultVersion))
|
||||
assert.Check(t, is.Equal(hdr.Get("OSType"), runtime.GOOS))
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package build // import "github.com/docker/docker/api/server/router/build"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/build"
|
||||
)
|
||||
|
||||
// Backend abstracts an image builder whose only purpose is to build an image referenced by an imageID.
|
||||
@@ -13,8 +13,9 @@ type Backend interface {
|
||||
// TODO: make this return a reference instead of string
|
||||
Build(context.Context, backend.BuildConfig) (string, error)
|
||||
|
||||
// PruneCache prunes the build cache.
|
||||
PruneCache(context.Context, build.CachePruneOptions) (*build.CachePruneReport, error)
|
||||
// Prune build cache
|
||||
PruneCache(context.Context, types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error)
|
||||
|
||||
Cancel(context.Context, string) error
|
||||
}
|
||||
|
||||
|
||||
@@ -4,36 +4,38 @@ import (
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/api/types/build"
|
||||
"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
|
||||
backend Backend
|
||||
daemon experimentalProvider
|
||||
routes []router.Route
|
||||
features *map[string]bool
|
||||
}
|
||||
|
||||
// NewRouter initializes a new build router
|
||||
func NewRouter(b Backend, d experimentalProvider) router.Router {
|
||||
func NewRouter(b Backend, d experimentalProvider, features *map[string]bool) router.Router {
|
||||
r := &buildRouter{
|
||||
backend: b,
|
||||
daemon: d,
|
||||
backend: b,
|
||||
daemon: d,
|
||||
features: features,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
}
|
||||
|
||||
// Routes returns the available routers to the build controller
|
||||
func (br *buildRouter) Routes() []router.Route {
|
||||
return br.routes
|
||||
func (r *buildRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
func (br *buildRouter) initRoutes() {
|
||||
br.routes = []router.Route{
|
||||
router.NewPostRoute("/build", br.postBuild),
|
||||
router.NewPostRoute("/build/prune", br.postPrune),
|
||||
router.NewPostRoute("/build/cancel", br.postCancel),
|
||||
func (r *buildRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.NewPostRoute("/build", r.postBuild),
|
||||
router.NewPostRoute("/build/prune", r.postPrune),
|
||||
router.NewPostRoute("/build/cancel", r.postCancel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,22 +48,15 @@ func (br *buildRouter) initRoutes() {
|
||||
//
|
||||
// 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) build.BuilderVersion {
|
||||
func BuilderVersion(features map[string]bool) types.BuilderVersion {
|
||||
// TODO(thaJeztah) move the default to daemon/config
|
||||
bv := build.BuilderBuildKit
|
||||
if runtime.GOOS == "windows" {
|
||||
// BuildKit is not yet the default on Windows.
|
||||
bv = build.BuilderV1
|
||||
return types.BuilderV1
|
||||
}
|
||||
|
||||
// Allow the features field in the daemon config to override the
|
||||
// default builder to advertise.
|
||||
if enable, ok := features["buildkit"]; ok {
|
||||
if enable {
|
||||
bv = build.BuilderBuildKit
|
||||
} else {
|
||||
bv = build.BuilderV1
|
||||
}
|
||||
bv := types.BuilderBuildKit
|
||||
if v, ok := features["buildkit"]; ok && !v {
|
||||
bv = types.BuilderV1
|
||||
}
|
||||
return bv
|
||||
}
|
||||
|
||||
@@ -13,12 +13,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"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/build"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
@@ -26,7 +24,9 @@ import (
|
||||
"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 invalidParam struct {
|
||||
@@ -35,14 +35,13 @@ type invalidParam struct {
|
||||
|
||||
func (e invalidParam) InvalidParameter() {}
|
||||
|
||||
func newImageBuildOptions(ctx context.Context, r *http.Request) (*build.ImageBuildOptions, error) {
|
||||
options := &build.ImageBuildOptions{
|
||||
Version: build.BuilderV1, // Builder V1 is the default, but can be overridden
|
||||
func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBuildOptions, error) {
|
||||
options := &types.ImageBuildOptions{
|
||||
Version: types.BuilderV1, // Builder V1 is the default, but can be overridden
|
||||
Dockerfile: r.FormValue("dockerfile"),
|
||||
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"),
|
||||
@@ -67,21 +66,24 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*build.ImageBui
|
||||
return nil, invalidParam{errors.New("security options are not supported on " + runtime.GOOS)}
|
||||
}
|
||||
|
||||
if httputils.BoolValue(r, "forcerm") {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if httputils.BoolValue(r, "forcerm") && versions.GreaterThanOrEqualTo(version, "1.12") {
|
||||
options.Remove = true
|
||||
} else if r.FormValue("rm") == "" {
|
||||
} else if r.FormValue("rm") == "" && versions.GreaterThanOrEqualTo(version, "1.12") {
|
||||
options.Remove = true
|
||||
} else {
|
||||
options.Remove = httputils.BoolValue(r, "rm")
|
||||
}
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if httputils.BoolValue(r, "pull") && versions.GreaterThanOrEqualTo(version, "1.16") {
|
||||
options.PullParent = true
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.32") {
|
||||
options.Platform = r.FormValue("platform")
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.40") {
|
||||
outputsJSON := r.FormValue("outputs")
|
||||
if outputsJSON != "" {
|
||||
var outputs []build.ImageBuildOutput
|
||||
var outputs []types.ImageBuildOutput
|
||||
if err := json.Unmarshal([]byte(outputsJSON), &outputs); err != nil {
|
||||
return nil, invalidParam{errors.Wrap(err, "invalid outputs specified")}
|
||||
}
|
||||
@@ -105,7 +107,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*build.ImageBui
|
||||
}
|
||||
|
||||
if ulimitsJSON := r.FormValue("ulimits"); ulimitsJSON != "" {
|
||||
buildUlimits := []*container.Ulimit{}
|
||||
var buildUlimits = []*units.Ulimit{}
|
||||
if err := json.Unmarshal([]byte(ulimitsJSON), &buildUlimits); err != nil {
|
||||
return nil, invalidParam{errors.Wrap(err, "error reading ulimit settings")}
|
||||
}
|
||||
@@ -125,7 +127,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*build.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 != "" {
|
||||
buildArgs := map[string]*string{}
|
||||
var buildArgs = map[string]*string{}
|
||||
if err := json.Unmarshal([]byte(buildArgsJSON), &buildArgs); err != nil {
|
||||
return nil, invalidParam{errors.Wrap(err, "error reading build args")}
|
||||
}
|
||||
@@ -133,7 +135,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*build.ImageBui
|
||||
}
|
||||
|
||||
if labelsJSON := r.FormValue("labels"); labelsJSON != "" {
|
||||
labels := map[string]string{}
|
||||
var labels = map[string]string{}
|
||||
if err := json.Unmarshal([]byte(labelsJSON), &labels); err != nil {
|
||||
return nil, invalidParam{errors.Wrap(err, "error reading labels")}
|
||||
}
|
||||
@@ -141,7 +143,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*build.ImageBui
|
||||
}
|
||||
|
||||
if cacheFromJSON := r.FormValue("cachefrom"); cacheFromJSON != "" {
|
||||
cacheFrom := []string{}
|
||||
var cacheFrom = []string{}
|
||||
if err := json.Unmarshal([]byte(cacheFromJSON), &cacheFrom); err != nil {
|
||||
return nil, invalidParam{errors.Wrap(err, "error reading cache-from")}
|
||||
}
|
||||
@@ -159,12 +161,12 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*build.ImageBui
|
||||
return options, nil
|
||||
}
|
||||
|
||||
func parseVersion(s string) (build.BuilderVersion, error) {
|
||||
switch build.BuilderVersion(s) {
|
||||
case build.BuilderV1:
|
||||
return build.BuilderV1, nil
|
||||
case build.BuilderBuildKit:
|
||||
return build.BuilderBuildKit, nil
|
||||
func parseVersion(s string) (types.BuilderVersion, error) {
|
||||
switch types.BuilderVersion(s) {
|
||||
case types.BuilderV1:
|
||||
return types.BuilderV1, nil
|
||||
case types.BuilderBuildKit:
|
||||
return types.BuilderBuildKit, nil
|
||||
default:
|
||||
return "", invalidParam{errors.Errorf("invalid version %q", s)}
|
||||
}
|
||||
@@ -178,56 +180,19 @@ func (br *buildRouter) postPrune(ctx context.Context, w http.ResponseWriter, r *
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opts := build.CachePruneOptions{
|
||||
All: httputils.BoolValue(r, "all"),
|
||||
Filters: fltrs,
|
||||
ksfv := r.FormValue("keep-storage")
|
||||
if ksfv == "" {
|
||||
ksfv = "0"
|
||||
}
|
||||
ks, err := strconv.Atoi(ksfv)
|
||||
if err != nil {
|
||||
return invalidParam{errors.Wrapf(err, "keep-storage is in bytes and expects an integer, got %v", ksfv)}
|
||||
}
|
||||
|
||||
parseBytesFromFormValue := func(name string) (int64, error) {
|
||||
if fv := r.FormValue(name); fv != "" {
|
||||
bs, err := strconv.Atoi(fv)
|
||||
if err != nil {
|
||||
return 0, invalidParam{errors.Wrapf(err, "%s is in bytes and expects an integer, got %v", name, fv)}
|
||||
}
|
||||
return int64(bs), nil
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.GreaterThanOrEqualTo(version, "1.48") {
|
||||
if bs, err := parseBytesFromFormValue("reserved-space"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if bs == 0 {
|
||||
// Deprecated parameter. Only checked if reserved-space is not used.
|
||||
bs, err = parseBytesFromFormValue("keep-storage")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
opts.ReservedSpace = bs
|
||||
}
|
||||
|
||||
if bs, err := parseBytesFromFormValue("max-used-space"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
opts.MaxUsedSpace = bs
|
||||
}
|
||||
|
||||
if bs, err := parseBytesFromFormValue("min-free-space"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
opts.MinFreeSpace = bs
|
||||
}
|
||||
} else {
|
||||
// Only keep-storage was valid in pre-1.48 versions.
|
||||
if bs, err := parseBytesFromFormValue("keep-storage"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
opts.ReservedSpace = bs
|
||||
}
|
||||
opts := types.BuildCachePruneOptions{
|
||||
All: httputils.BoolValue(r, "all"),
|
||||
Filters: fltrs,
|
||||
KeepStorage: int64(ks),
|
||||
}
|
||||
|
||||
report, err := br.backend.PruneCache(ctx, opts)
|
||||
@@ -282,9 +247,8 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
||||
return err
|
||||
}
|
||||
_, err = output.Write(streamformatter.FormatError(err))
|
||||
// don't log broken pipe errors as this is the normal case when a client aborts.
|
||||
if err != nil && !errors.Is(err, syscall.EPIPE) {
|
||||
log.G(ctx).WithError(err).Warn("could not write error response")
|
||||
if err != nil {
|
||||
logrus.Warnf("could not write error response: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -319,9 +283,6 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
|
||||
ProgressWriter: buildProgressWriter(out, wantAux, createProgressReader),
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
log.G(ctx).Debug("build canceled")
|
||||
}
|
||||
return errf(err)
|
||||
}
|
||||
|
||||
@@ -353,14 +314,14 @@ type syncWriter struct {
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (s *syncWriter) Write(b []byte) (int, error) {
|
||||
func (s *syncWriter) Write(b []byte) (count int, err error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.w.Write(b)
|
||||
count, err = s.w.Write(b)
|
||||
s.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func buildProgressWriter(out io.Writer, wantAux bool, createProgressReader func(io.ReadCloser) io.ReadCloser) backend.ProgressWriter {
|
||||
// see https://github.com/moby/moby/pull/21406
|
||||
out = &syncWriter{w: out}
|
||||
|
||||
var aux *streamformatter.AuxFormatter
|
||||
@@ -381,12 +342,8 @@ type flusher interface {
|
||||
Flush()
|
||||
}
|
||||
|
||||
type nopFlusher struct{}
|
||||
|
||||
func (f *nopFlusher) Flush() {}
|
||||
|
||||
func wrapOutputBufferedUntilRequestRead(rc io.ReadCloser, out io.Writer) (io.ReadCloser, io.Writer) {
|
||||
var fl flusher = &nopFlusher{}
|
||||
var fl flusher = &ioutils.NopFlusher{}
|
||||
if f, ok := out.(flusher); ok {
|
||||
fl = f
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package checkpoint // import "github.com/docker/docker/api/server/router/checkpoint"
|
||||
|
||||
import "github.com/docker/docker/api/types/checkpoint"
|
||||
import "github.com/docker/docker/api/types"
|
||||
|
||||
// Backend for Checkpoint
|
||||
type Backend interface {
|
||||
CheckpointCreate(container string, config checkpoint.CreateOptions) error
|
||||
CheckpointDelete(container string, config checkpoint.DeleteOptions) error
|
||||
CheckpointList(container string, config checkpoint.ListOptions) ([]checkpoint.Summary, error)
|
||||
CheckpointCreate(container string, config types.CheckpointCreateOptions) error
|
||||
CheckpointDelete(container string, config types.CheckpointDeleteOptions) error
|
||||
CheckpointList(container string, config types.CheckpointListOptions) ([]types.Checkpoint, error)
|
||||
}
|
||||
|
||||
@@ -23,14 +23,14 @@ func NewRouter(b Backend, decoder httputils.ContainerDecoder) router.Router {
|
||||
}
|
||||
|
||||
// Routes returns the available routers to the checkpoint controller
|
||||
func (cr *checkpointRouter) Routes() []router.Route {
|
||||
return cr.routes
|
||||
func (r *checkpointRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
func (cr *checkpointRouter) initRoutes() {
|
||||
cr.routes = []router.Route{
|
||||
router.NewGetRoute("/containers/{name:.*}/checkpoints", cr.getContainerCheckpoints, router.Experimental),
|
||||
router.NewPostRoute("/containers/{name:.*}/checkpoints", cr.postContainerCheckpoint, router.Experimental),
|
||||
router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", cr.deleteContainerCheckpoint, router.Experimental),
|
||||
func (r *checkpointRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.NewGetRoute("/containers/{name:.*}/checkpoints", r.getContainerCheckpoints, router.Experimental),
|
||||
router.NewPostRoute("/containers/{name:.*}/checkpoints", r.postContainerCheckpoint, router.Experimental),
|
||||
router.NewDeleteRoute("/containers/{name}/checkpoints/{checkpoint}", r.deleteContainerCheckpoint, router.Experimental),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,20 +5,20 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/checkpoint"
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
func (cr *checkpointRouter) postContainerCheckpoint(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *checkpointRouter) postContainerCheckpoint(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var options checkpoint.CreateOptions
|
||||
var options types.CheckpointCreateOptions
|
||||
if err := httputils.ReadJSON(r, &options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := cr.backend.CheckpointCreate(vars["name"], options)
|
||||
err := s.backend.CheckpointCreate(vars["name"], options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -27,14 +27,15 @@ func (cr *checkpointRouter) postContainerCheckpoint(ctx context.Context, w http.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr *checkpointRouter) getContainerCheckpoints(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *checkpointRouter) getContainerCheckpoints(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
checkpoints, err := cr.backend.CheckpointList(vars["name"], checkpoint.ListOptions{
|
||||
checkpoints, err := s.backend.CheckpointList(vars["name"], types.CheckpointListOptions{
|
||||
CheckpointDir: r.Form.Get("dir"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -42,15 +43,16 @@ func (cr *checkpointRouter) getContainerCheckpoints(ctx context.Context, w http.
|
||||
return httputils.WriteJSON(w, http.StatusOK, checkpoints)
|
||||
}
|
||||
|
||||
func (cr *checkpointRouter) deleteContainerCheckpoint(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *checkpointRouter) deleteContainerCheckpoint(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := cr.backend.CheckpointDelete(vars["name"], checkpoint.DeleteOptions{
|
||||
err := s.backend.CheckpointDelete(vars["name"], types.CheckpointDeleteOptions{
|
||||
CheckpointDir: r.Form.Get("dir"),
|
||||
CheckpointID: vars["checkpoint"],
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,53 +4,57 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"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/moby/go-archive"
|
||||
containerpkg "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
)
|
||||
|
||||
// execBackend includes functions to implement to provide exec functionality.
|
||||
type execBackend interface {
|
||||
ContainerExecCreate(name string, options *container.ExecOptions) (string, error)
|
||||
ContainerExecCreate(name string, config *types.ExecConfig) (string, error)
|
||||
ContainerExecInspect(id string) (*backend.ExecInspect, error)
|
||||
ContainerExecResize(ctx context.Context, name string, height, width uint32) error
|
||||
ContainerExecStart(ctx context.Context, name string, options backend.ExecStartConfig) error
|
||||
ContainerExecResize(name string, height, width int) error
|
||||
ContainerExecStart(ctx context.Context, name string, options container.ExecStartOptions) error
|
||||
ExecExists(name string) (bool, error)
|
||||
}
|
||||
|
||||
// copyBackend includes functions to implement to provide container copy functionality.
|
||||
type copyBackend interface {
|
||||
ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *container.PathStat, err error)
|
||||
ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error)
|
||||
ContainerCopy(name string, res string) (io.ReadCloser, 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 *container.PathStat, err 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(ctx context.Context, config backend.ContainerCreateConfig) (container.CreateResponse, error)
|
||||
ContainerCreate(ctx context.Context, config types.ContainerCreateConfig) (container.CreateResponse, error)
|
||||
ContainerKill(name string, signal string) error
|
||||
ContainerPause(name string) error
|
||||
ContainerRename(oldName, newName string) error
|
||||
ContainerResize(ctx context.Context, name string, height, width uint32) error
|
||||
ContainerResize(name string, height, width int) error
|
||||
ContainerRestart(ctx context.Context, name string, options container.StopOptions) error
|
||||
ContainerRm(name string, config *backend.ContainerRmConfig) error
|
||||
ContainerStart(ctx context.Context, name string, checkpoint string, checkpointDir string) error
|
||||
ContainerRm(name string, config *types.ContainerRmConfig) error
|
||||
ContainerStart(ctx context.Context, name string, hostConfig *container.HostConfig, 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.UpdateResponse, error)
|
||||
ContainerWait(ctx context.Context, name string, condition container.WaitCondition) (<-chan container.StateStatus, error)
|
||||
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)
|
||||
ContainerWait(ctx context.Context, name string, condition containerpkg.WaitCondition) (<-chan containerpkg.StateStatus, error)
|
||||
}
|
||||
|
||||
// monitorBackend includes functions to implement to provide containers monitoring functionality.
|
||||
type monitorBackend interface {
|
||||
ContainerChanges(ctx context.Context, name string) ([]archive.Change, error)
|
||||
ContainerInspect(ctx context.Context, name string, options backend.ContainerInspectOptions) (*container.InspectResponse, error)
|
||||
ContainerLogs(ctx context.Context, name string, config *container.LogsOptions) (msgs <-chan *backend.LogMessage, tty bool, err error)
|
||||
ContainerInspect(ctx context.Context, 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)
|
||||
ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
|
||||
ContainerTop(name string, psArgs string) (*container.TopResponse, error)
|
||||
Containers(ctx context.Context, config *container.ListOptions) ([]*container.Summary, error)
|
||||
ContainerTop(name string, psArgs string) (*container.ContainerTopOKBody, error)
|
||||
|
||||
Containers(ctx context.Context, config *types.ContainerListOptions) ([]*types.Container, error)
|
||||
}
|
||||
|
||||
// attachBackend includes function to implement to provide container attaching functionality.
|
||||
@@ -60,7 +64,7 @@ type attachBackend interface {
|
||||
|
||||
// systemBackend includes functions to implement to provide system wide containers functionality
|
||||
type systemBackend interface {
|
||||
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (*container.PruneReport, error)
|
||||
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (*types.ContainersPruneReport, error)
|
||||
}
|
||||
|
||||
type commitBackend interface {
|
||||
|
||||
@@ -25,47 +25,48 @@ func NewRouter(b Backend, decoder httputils.ContainerDecoder, cgroup2 bool) rout
|
||||
}
|
||||
|
||||
// Routes returns the available routes to the container controller
|
||||
func (c *containerRouter) Routes() []router.Route {
|
||||
return c.routes
|
||||
func (r *containerRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
// initRoutes initializes the routes in container router
|
||||
func (c *containerRouter) initRoutes() {
|
||||
c.routes = []router.Route{
|
||||
func (r *containerRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
// HEAD
|
||||
router.NewHeadRoute("/containers/{name:.*}/archive", c.headContainersArchive),
|
||||
router.NewHeadRoute("/containers/{name:.*}/archive", r.headContainersArchive),
|
||||
// GET
|
||||
router.NewGetRoute("/containers/json", c.getContainersJSON),
|
||||
router.NewGetRoute("/containers/{name:.*}/export", c.getContainersExport),
|
||||
router.NewGetRoute("/containers/{name:.*}/changes", c.getContainersChanges),
|
||||
router.NewGetRoute("/containers/{name:.*}/json", c.getContainersByName),
|
||||
router.NewGetRoute("/containers/{name:.*}/top", c.getContainersTop),
|
||||
router.NewGetRoute("/containers/{name:.*}/logs", c.getContainersLogs),
|
||||
router.NewGetRoute("/containers/{name:.*}/stats", c.getContainersStats),
|
||||
router.NewGetRoute("/containers/{name:.*}/attach/ws", c.wsContainersAttach),
|
||||
router.NewGetRoute("/exec/{id:.*}/json", c.getExecByID),
|
||||
router.NewGetRoute("/containers/{name:.*}/archive", c.getContainersArchive),
|
||||
router.NewGetRoute("/containers/json", r.getContainersJSON),
|
||||
router.NewGetRoute("/containers/{name:.*}/export", r.getContainersExport),
|
||||
router.NewGetRoute("/containers/{name:.*}/changes", r.getContainersChanges),
|
||||
router.NewGetRoute("/containers/{name:.*}/json", r.getContainersByName),
|
||||
router.NewGetRoute("/containers/{name:.*}/top", r.getContainersTop),
|
||||
router.NewGetRoute("/containers/{name:.*}/logs", r.getContainersLogs),
|
||||
router.NewGetRoute("/containers/{name:.*}/stats", r.getContainersStats),
|
||||
router.NewGetRoute("/containers/{name:.*}/attach/ws", r.wsContainersAttach),
|
||||
router.NewGetRoute("/exec/{id:.*}/json", r.getExecByID),
|
||||
router.NewGetRoute("/containers/{name:.*}/archive", r.getContainersArchive),
|
||||
// POST
|
||||
router.NewPostRoute("/containers/create", c.postContainersCreate),
|
||||
router.NewPostRoute("/containers/{name:.*}/kill", c.postContainersKill),
|
||||
router.NewPostRoute("/containers/{name:.*}/pause", c.postContainersPause),
|
||||
router.NewPostRoute("/containers/{name:.*}/unpause", c.postContainersUnpause),
|
||||
router.NewPostRoute("/containers/{name:.*}/restart", c.postContainersRestart),
|
||||
router.NewPostRoute("/containers/{name:.*}/start", c.postContainersStart),
|
||||
router.NewPostRoute("/containers/{name:.*}/stop", c.postContainersStop),
|
||||
router.NewPostRoute("/containers/{name:.*}/wait", c.postContainersWait),
|
||||
router.NewPostRoute("/containers/{name:.*}/resize", c.postContainersResize),
|
||||
router.NewPostRoute("/containers/{name:.*}/attach", c.postContainersAttach),
|
||||
router.NewPostRoute("/containers/{name:.*}/exec", c.postContainerExecCreate),
|
||||
router.NewPostRoute("/exec/{name:.*}/start", c.postContainerExecStart),
|
||||
router.NewPostRoute("/exec/{name:.*}/resize", c.postContainerExecResize),
|
||||
router.NewPostRoute("/containers/{name:.*}/rename", c.postContainerRename),
|
||||
router.NewPostRoute("/containers/{name:.*}/update", c.postContainerUpdate),
|
||||
router.NewPostRoute("/containers/prune", c.postContainersPrune),
|
||||
router.NewPostRoute("/commit", c.postCommit),
|
||||
router.NewPostRoute("/containers/create", r.postContainersCreate),
|
||||
router.NewPostRoute("/containers/{name:.*}/kill", r.postContainersKill),
|
||||
router.NewPostRoute("/containers/{name:.*}/pause", r.postContainersPause),
|
||||
router.NewPostRoute("/containers/{name:.*}/unpause", r.postContainersUnpause),
|
||||
router.NewPostRoute("/containers/{name:.*}/restart", r.postContainersRestart),
|
||||
router.NewPostRoute("/containers/{name:.*}/start", r.postContainersStart),
|
||||
router.NewPostRoute("/containers/{name:.*}/stop", r.postContainersStop),
|
||||
router.NewPostRoute("/containers/{name:.*}/wait", r.postContainersWait),
|
||||
router.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),
|
||||
router.NewPostRoute("/containers/{name:.*}/rename", r.postContainerRename),
|
||||
router.NewPostRoute("/containers/{name:.*}/update", r.postContainerUpdate),
|
||||
router.NewPostRoute("/containers/prune", r.postContainersPrune),
|
||||
router.NewPostRoute("/commit", r.postCommit),
|
||||
// PUT
|
||||
router.NewPutRoute("/containers/{name:.*}/archive", c.putContainersArchive),
|
||||
router.NewPutRoute("/containers/{name:.*}/archive", r.putContainersArchive),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/containers/{name:.*}", c.deleteContainers),
|
||||
router.NewDeleteRoute("/containers/{name:.*}", r.deleteContainers),
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,350 +0,0 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/libnetwork/netlabel"
|
||||
"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: "unable to migrate container-wide MAC address to a specific network: 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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEpConfigForNetMode(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
apiVersion string
|
||||
networkMode string
|
||||
epConfig map[string]*network.EndpointSettings
|
||||
expEpId string
|
||||
expNumEps int
|
||||
expError bool
|
||||
}{
|
||||
{
|
||||
name: "old api no eps",
|
||||
apiVersion: "1.43",
|
||||
networkMode: "mynet",
|
||||
expNumEps: 1,
|
||||
},
|
||||
{
|
||||
name: "new api no eps",
|
||||
apiVersion: "1.44",
|
||||
networkMode: "mynet",
|
||||
expNumEps: 1,
|
||||
},
|
||||
{
|
||||
name: "old api with ep",
|
||||
apiVersion: "1.43",
|
||||
networkMode: "mynet",
|
||||
epConfig: map[string]*network.EndpointSettings{
|
||||
"anything": {EndpointID: "epone"},
|
||||
},
|
||||
expEpId: "epone",
|
||||
expNumEps: 1,
|
||||
},
|
||||
{
|
||||
name: "new api with matching ep",
|
||||
apiVersion: "1.44",
|
||||
networkMode: "mynet",
|
||||
epConfig: map[string]*network.EndpointSettings{
|
||||
"mynet": {EndpointID: "epone"},
|
||||
},
|
||||
expEpId: "epone",
|
||||
expNumEps: 1,
|
||||
},
|
||||
{
|
||||
name: "new api with mismatched ep",
|
||||
apiVersion: "1.44",
|
||||
networkMode: "mynet",
|
||||
epConfig: map[string]*network.EndpointSettings{
|
||||
"shortid": {EndpointID: "epone"},
|
||||
},
|
||||
expError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
netConfig := &network.NetworkingConfig{
|
||||
EndpointsConfig: tc.epConfig,
|
||||
}
|
||||
ep, err := epConfigForNetMode(tc.apiVersion, container.NetworkMode(tc.networkMode), netConfig)
|
||||
if tc.expError {
|
||||
assert.Check(t, is.ErrorContains(err, "HostConfig.NetworkMode must match the identity of a network in NetworkSettings.Networks"))
|
||||
} else {
|
||||
assert.Assert(t, err)
|
||||
assert.Check(t, is.Equal(ep.EndpointID, tc.expEpId))
|
||||
assert.Check(t, is.Len(netConfig.EndpointsConfig, tc.expNumEps))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleSysctlBC(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
apiVersion string
|
||||
networkMode string
|
||||
sysctls map[string]string
|
||||
epConfig map[string]*network.EndpointSettings
|
||||
expEpSysctls []string
|
||||
expSysctls map[string]string
|
||||
expWarningContains []string
|
||||
expError string
|
||||
}{
|
||||
{
|
||||
name: "migrate to new ep",
|
||||
apiVersion: "1.46",
|
||||
networkMode: "mynet",
|
||||
sysctls: map[string]string{
|
||||
"net.ipv6.conf.all.disable_ipv6": "0",
|
||||
"net.ipv6.conf.eth0.accept_ra": "2",
|
||||
"net.ipv6.conf.eth0.forwarding": "1",
|
||||
},
|
||||
expSysctls: map[string]string{
|
||||
"net.ipv6.conf.all.disable_ipv6": "0",
|
||||
},
|
||||
expEpSysctls: []string{"net.ipv6.conf.IFNAME.forwarding=1", "net.ipv6.conf.IFNAME.accept_ra=2"},
|
||||
expWarningContains: []string{
|
||||
"Migrated",
|
||||
"net.ipv6.conf.eth0.accept_ra", "net.ipv6.conf.IFNAME.accept_ra=2",
|
||||
"net.ipv6.conf.eth0.forwarding", "net.ipv6.conf.IFNAME.forwarding=1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "migrate nothing",
|
||||
apiVersion: "1.46",
|
||||
networkMode: "mynet",
|
||||
sysctls: map[string]string{
|
||||
"net.ipv6.conf.all.disable_ipv6": "0",
|
||||
},
|
||||
expSysctls: map[string]string{
|
||||
"net.ipv6.conf.all.disable_ipv6": "0",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "migration disabled for newer api",
|
||||
apiVersion: "1.48",
|
||||
networkMode: "mynet",
|
||||
sysctls: map[string]string{
|
||||
"net.ipv6.conf.eth0.accept_ra": "2",
|
||||
},
|
||||
expError: "must be supplied using driver option 'com.docker.network.endpoint.sysctls'",
|
||||
},
|
||||
{
|
||||
name: "only migrate eth0",
|
||||
apiVersion: "1.46",
|
||||
networkMode: "mynet",
|
||||
sysctls: map[string]string{
|
||||
"net.ipv6.conf.eth1.accept_ra": "2",
|
||||
},
|
||||
expError: "unable to determine network endpoint",
|
||||
},
|
||||
{
|
||||
name: "net name mismatch",
|
||||
apiVersion: "1.46",
|
||||
networkMode: "mynet",
|
||||
epConfig: map[string]*network.EndpointSettings{
|
||||
"shortid": {EndpointID: "epone"},
|
||||
},
|
||||
sysctls: map[string]string{
|
||||
"net.ipv6.conf.eth1.accept_ra": "2",
|
||||
},
|
||||
expError: "unable to find a network for sysctl",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
hostCfg := &container.HostConfig{
|
||||
NetworkMode: container.NetworkMode(tc.networkMode),
|
||||
Sysctls: map[string]string{},
|
||||
}
|
||||
for k, v := range tc.sysctls {
|
||||
hostCfg.Sysctls[k] = v
|
||||
}
|
||||
netCfg := &network.NetworkingConfig{
|
||||
EndpointsConfig: tc.epConfig,
|
||||
}
|
||||
|
||||
warnings, err := handleSysctlBC(hostCfg, netCfg, tc.apiVersion)
|
||||
|
||||
for _, s := range tc.expWarningContains {
|
||||
assert.Check(t, is.Contains(warnings, s))
|
||||
}
|
||||
|
||||
if tc.expError != "" {
|
||||
assert.Check(t, is.ErrorContains(err, tc.expError))
|
||||
} else {
|
||||
assert.Check(t, err)
|
||||
|
||||
assert.Check(t, is.DeepEqual(hostCfg.Sysctls, tc.expSysctls))
|
||||
|
||||
ep := netCfg.EndpointsConfig[tc.networkMode]
|
||||
if ep == nil {
|
||||
assert.Check(t, is.Nil(tc.expEpSysctls))
|
||||
} else {
|
||||
got, ok := ep.DriverOpts[netlabel.EndpointSysctls]
|
||||
assert.Check(t, ok)
|
||||
// Check for expected ep-sysctls.
|
||||
for _, want := range tc.expEpSysctls {
|
||||
assert.Check(t, is.Contains(got, want))
|
||||
}
|
||||
// Check for unexpected ep-sysctls.
|
||||
assert.Check(t, is.Len(got, len(strings.Join(tc.expEpSysctls, ","))))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,51 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
gddohttputil "github.com/golang/gddo/httputil"
|
||||
)
|
||||
|
||||
// setContainerPathStatHeader encodes the stat to JSON, base64 encode, and place in a header.
|
||||
func setContainerPathStatHeader(stat *container.PathStat, header http.Header) error {
|
||||
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.
|
||||
func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
|
||||
statJSON, err := json.Marshal(stat)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -29,13 +68,13 @@ func setContainerPathStatHeader(stat *container.PathStat, header http.Header) er
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *containerRouter) headContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *containerRouter) headContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v, err := httputils.ArchiveFormValues(r, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stat, err := c.backend.ContainerStatPath(v.Name, v.Path)
|
||||
stat, err := s.backend.ContainerStatPath(v.Name, v.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -66,13 +105,13 @@ func writeCompressedResponse(w http.ResponseWriter, r *http.Request, body io.Rea
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *containerRouter) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *containerRouter) getContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v, err := httputils.ArchiveFormValues(r, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tarArchive, stat, err := c.backend.ContainerArchivePath(v.Name, v.Path)
|
||||
tarArchive, stat, err := s.backend.ContainerArchivePath(v.Name, v.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -86,7 +125,7 @@ func (c *containerRouter) getContainersArchive(ctx context.Context, w http.Respo
|
||||
return writeCompressedResponse(w, r, tarArchive)
|
||||
}
|
||||
|
||||
func (c *containerRouter) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *containerRouter) putContainersArchive(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
v, err := httputils.ArchiveFormValues(r, vars)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -95,5 +134,5 @@ func (c *containerRouter) putContainersArchive(ctx context.Context, w http.Respo
|
||||
noOverwriteDirNonDir := httputils.BoolValue(r, "noOverwriteDirNonDir")
|
||||
copyUIDGID := httputils.BoolValue(r, "copyUIDGID")
|
||||
|
||||
return c.backend.ContainerExtractToDir(v.Name, v.Path, copyUIDGID, noOverwriteDirNonDir, r.Body)
|
||||
return s.backend.ContainerExtractToDir(v.Name, v.Path, copyUIDGID, noOverwriteDirNonDir, r.Body)
|
||||
}
|
||||
|
||||
@@ -5,20 +5,19 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"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/backend"
|
||||
"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/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (c *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
eConfig, err := c.backend.ContainerExecInspect(vars["id"])
|
||||
func (s *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
eConfig, err := s.backend.ContainerExecInspect(vars["id"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -34,12 +33,12 @@ func (execCommandError) Error() string {
|
||||
|
||||
func (execCommandError) InvalidParameter() {}
|
||||
|
||||
func (c *containerRouter) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
execConfig := &container.ExecOptions{}
|
||||
execConfig := &types.ExecConfig{}
|
||||
if err := httputils.ReadJSON(r, execConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -55,53 +54,60 @@ func (c *containerRouter) postContainerExecCreate(ctx context.Context, w http.Re
|
||||
}
|
||||
|
||||
// Register an instance of Exec in container.
|
||||
id, err := c.backend.ContainerExecCreate(vars["name"], execConfig)
|
||||
id, err := s.backend.ContainerExecCreate(vars["name"], execConfig)
|
||||
if err != nil {
|
||||
log.G(ctx).Errorf("Error setting up exec command in container %s: %v", vars["name"], err)
|
||||
logrus.Errorf("Error setting up exec command in container %s: %v", vars["name"], err)
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &container.ExecCreateResponse{
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &types.IDResponse{
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
|
||||
func (c *containerRouter) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
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
|
||||
stdout, stderr, outStream io.Writer
|
||||
)
|
||||
|
||||
options := &container.ExecStartOptions{}
|
||||
if err := httputils.ReadJSON(r, options); err != nil {
|
||||
execStartCheck := &types.ExecStartCheck{}
|
||||
if err := httputils.ReadJSON(r, execStartCheck); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exists, err := c.backend.ExecExists(execName); !exists {
|
||||
if exists, err := s.backend.ExecExists(execName); !exists {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.ConsoleSize != nil {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
|
||||
if execStartCheck.ConsoleSize != nil {
|
||||
// Not supported before 1.42
|
||||
if versions.LessThan(version, "1.42") {
|
||||
options.ConsoleSize = nil
|
||||
execStartCheck.ConsoleSize = nil
|
||||
}
|
||||
|
||||
// No console without tty
|
||||
if !options.Tty {
|
||||
options.ConsoleSize = nil
|
||||
if !execStartCheck.Tty {
|
||||
execStartCheck.ConsoleSize = nil
|
||||
}
|
||||
}
|
||||
|
||||
if !options.Detach {
|
||||
if !execStartCheck.Detach {
|
||||
var err error
|
||||
// Setting up the streaming http interface.
|
||||
inStream, outStream, err = httputils.HijackConnection(w)
|
||||
@@ -112,60 +118,59 @@ func (c *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
|
||||
|
||||
if _, ok := r.Header["Upgrade"]; ok {
|
||||
contentType := types.MediaTypeRawStream
|
||||
if !options.Tty && versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.42") {
|
||||
if !execStartCheck.Tty && versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.42") {
|
||||
contentType = types.MediaTypeMultiplexedStream
|
||||
}
|
||||
_, _ = fmt.Fprint(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: "+contentType+"\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n")
|
||||
fmt.Fprint(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: "+contentType+"\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n")
|
||||
} else {
|
||||
_, _ = fmt.Fprint(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n")
|
||||
fmt.Fprint(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n")
|
||||
}
|
||||
|
||||
// copy headers that were removed as part of hijack
|
||||
if err := w.Header().WriteSubset(outStream, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprint(outStream, "\r\n")
|
||||
fmt.Fprint(outStream, "\r\n")
|
||||
|
||||
stdin = inStream
|
||||
if options.Tty {
|
||||
stdout = outStream
|
||||
} else {
|
||||
stdout = outStream
|
||||
if !execStartCheck.Tty {
|
||||
stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
|
||||
stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
|
||||
}
|
||||
}
|
||||
|
||||
// Now run the user process in container.
|
||||
//
|
||||
// TODO: Maybe we should we pass ctx here if we're not detaching?
|
||||
err := c.backend.ContainerExecStart(context.Background(), execName, backend.ExecStartConfig{
|
||||
options := container.ExecStartOptions{
|
||||
Stdin: stdin,
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
ConsoleSize: options.ConsoleSize,
|
||||
})
|
||||
if err != nil {
|
||||
if options.Detach {
|
||||
ConsoleSize: execStartCheck.ConsoleSize,
|
||||
}
|
||||
|
||||
// Now run the user process in container.
|
||||
// Maybe we should we pass ctx here if we're not detaching?
|
||||
if err := s.backend.ContainerExecStart(context.Background(), execName, options); err != nil {
|
||||
if execStartCheck.Detach {
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprintf(stdout, "%v\r\n", err)
|
||||
log.G(ctx).Errorf("Error running exec %s in container: %v", execName, err)
|
||||
stdout.Write([]byte(err.Error() + "\r\n"))
|
||||
logrus.Errorf("Error running exec %s in container: %v", execName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *containerRouter) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *containerRouter) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
height, err := httputils.Uint32Value(r, "h")
|
||||
height, err := strconv.Atoi(r.Form.Get("h"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(errors.Wrapf(err, "invalid resize height %q", r.Form.Get("h")))
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
width, err := httputils.Uint32Value(r, "w")
|
||||
width, err := strconv.Atoi(r.Form.Get("w"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(errors.Wrapf(err, "invalid resize width %q", r.Form.Get("w")))
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
return c.backend.ContainerExecResize(ctx, vars["name"], height, width)
|
||||
return s.backend.ContainerExecResize(vars["name"], height, width)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.23
|
||||
|
||||
package container // import "github.com/docker/docker/api/server/router/container"
|
||||
|
||||
import (
|
||||
@@ -8,34 +5,17 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/internal/sliceutil"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
)
|
||||
|
||||
// getContainersByName inspects container's configuration and serializes it as json.
|
||||
func (c *containerRouter) getContainersByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
ctr, err := c.backend.ContainerInspect(ctx, vars["name"], backend.ContainerInspectOptions{
|
||||
Size: httputils.BoolValue(r, "size"),
|
||||
})
|
||||
func (s *containerRouter) getContainersByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
displaySize := httputils.BoolValue(r, "size")
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
json, err := s.backend.ContainerInspect(ctx, vars["name"], displaySize, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.LessThan(version, "1.45") {
|
||||
shortCID := stringid.TruncateID(ctr.ID)
|
||||
for nwName, ep := range ctr.NetworkSettings.Networks {
|
||||
if container.NetworkMode(nwName).IsUserDefined() {
|
||||
ep.Aliases = sliceutil.Dedup(append(ep.Aliases, shortCID, ctr.Config.Hostname))
|
||||
}
|
||||
}
|
||||
}
|
||||
if versions.LessThan(version, "1.48") {
|
||||
ctr.ImageManifestDescriptor = nil
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, ctr)
|
||||
return httputils.WriteJSON(w, http.StatusOK, json)
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/internal/unix_noeintr"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func notifyClosed(ctx context.Context, conn net.Conn, notify func()) {
|
||||
sc, ok := conn.(syscall.Conn)
|
||||
if !ok {
|
||||
log.G(ctx).Debug("notifyClosed: conn does not support close notifications")
|
||||
return
|
||||
}
|
||||
|
||||
rc, err := sc.SyscallConn()
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Warn("notifyClosed: failed get raw conn for close notifications")
|
||||
return
|
||||
}
|
||||
|
||||
epFd, err := unix_noeintr.EpollCreate()
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Warn("notifyClosed: failed to create epoll fd")
|
||||
return
|
||||
}
|
||||
defer unix.Close(epFd)
|
||||
|
||||
err = rc.Control(func(fd uintptr) {
|
||||
err := unix_noeintr.EpollCtl(epFd, unix.EPOLL_CTL_ADD, int(fd), &unix.EpollEvent{
|
||||
Events: unix.EPOLLHUP,
|
||||
Fd: int32(fd),
|
||||
})
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Warn("notifyClosed: failed to register fd for close notifications")
|
||||
return
|
||||
}
|
||||
|
||||
events := make([]unix.EpollEvent, 1)
|
||||
if _, err := unix_noeintr.EpollWait(epFd, events, -1); err != nil {
|
||||
log.G(ctx).WithError(err).Warn("notifyClosed: failed to wait for close notifications")
|
||||
return
|
||||
}
|
||||
notify()
|
||||
})
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Warn("notifyClosed: failed to register for close notifications")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
//go:build !linux
|
||||
|
||||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
func notifyClosed(ctx context.Context, conn net.Conn, notify func()) {}
|
||||
@@ -24,13 +24,13 @@ type debugRouter struct {
|
||||
|
||||
func (r *debugRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.NewGetRoute("/debug/vars", frameworkAdaptHandler(expvar.Handler())),
|
||||
router.NewGetRoute("/debug/pprof/", frameworkAdaptHandlerFunc(pprof.Index)),
|
||||
router.NewGetRoute("/debug/pprof/cmdline", frameworkAdaptHandlerFunc(pprof.Cmdline)),
|
||||
router.NewGetRoute("/debug/pprof/profile", frameworkAdaptHandlerFunc(pprof.Profile)),
|
||||
router.NewGetRoute("/debug/pprof/symbol", frameworkAdaptHandlerFunc(pprof.Symbol)),
|
||||
router.NewGetRoute("/debug/pprof/trace", frameworkAdaptHandlerFunc(pprof.Trace)),
|
||||
router.NewGetRoute("/debug/pprof/{name}", handlePprof),
|
||||
router.NewGetRoute("/vars", frameworkAdaptHandler(expvar.Handler())),
|
||||
router.NewGetRoute("/pprof/", frameworkAdaptHandlerFunc(pprof.Index)),
|
||||
router.NewGetRoute("/pprof/cmdline", frameworkAdaptHandlerFunc(pprof.Cmdline)),
|
||||
router.NewGetRoute("/pprof/profile", frameworkAdaptHandlerFunc(pprof.Profile)),
|
||||
router.NewGetRoute("/pprof/symbol", frameworkAdaptHandlerFunc(pprof.Symbol)),
|
||||
router.NewGetRoute("/pprof/trace", frameworkAdaptHandlerFunc(pprof.Trace)),
|
||||
router.NewGetRoute("/pprof/{name}", handlePprof),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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/registry"
|
||||
)
|
||||
|
||||
// Backend is all the methods that need to be implemented
|
||||
// to provide image specific functionality.
|
||||
type Backend interface {
|
||||
GetRepositories(context.Context, reference.Named, *registry.AuthConfig) ([]distribution.Repository, error)
|
||||
GetRepository(context.Context, reference.Named, *registry.AuthConfig) (distribution.Repository, error)
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ func NewRouter(backend Backend) router.Router {
|
||||
}
|
||||
|
||||
// Routes returns the available routes
|
||||
func (dr *distributionRouter) Routes() []router.Route {
|
||||
return dr.routes
|
||||
func (r *distributionRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
// initRoutes initializes the routes in the distribution router
|
||||
func (dr *distributionRouter) initRoutes() {
|
||||
dr.routes = []router.Route{
|
||||
func (r *distributionRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
// GET
|
||||
router.NewGetRoute("/distribution/{name:.*}/json", dr.getDistributionInfo),
|
||||
router.NewGetRoute("/distribution/{name:.*}/json", r.getDistributionInfo),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,30 +5,28 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"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/registry"
|
||||
distributionpkg "github.com/docker/docker/distribution"
|
||||
"github.com/docker/docker/errdefs"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (dr *distributionRouter) getDistributionInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
imgName := vars["name"]
|
||||
image := vars["name"]
|
||||
|
||||
// TODO why is reference.ParseAnyReference() / reference.ParseNormalizedNamed() not using the reference.ErrTagInvalidFormat (and so on) errors?
|
||||
ref, err := reference.ParseAnyReference(imgName)
|
||||
ref, err := reference.ParseAnyReference(image)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
@@ -38,56 +36,30 @@ func (dr *distributionRouter) getDistributionInfo(ctx context.Context, w http.Re
|
||||
// full image ID
|
||||
return errors.Errorf("no manifest found for full image ID")
|
||||
}
|
||||
return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", imgName))
|
||||
return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", image))
|
||||
}
|
||||
|
||||
// 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 := dr.backend.GetRepositories(ctx, namedRef, authConfig)
|
||||
distrepo, err := s.backend.GetRepository(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 := dr.fetchManifest(ctx, repo, namedRef)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, distributionInspect)
|
||||
}
|
||||
return lastErr
|
||||
}
|
||||
|
||||
func (dr *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 registry.DistributionInspect{}, errdefs.InvalidParameter(errors.Errorf("image reference not tagged: %s", namedRef))
|
||||
return errdefs.InvalidParameter(errors.Errorf("image reference not tagged: %s", image))
|
||||
}
|
||||
|
||||
descriptor, err := distrepo.Tags(ctx).Get(ctx, taggedRef.Tag())
|
||||
if err != nil {
|
||||
return registry.DistributionInspect{}, err
|
||||
return err
|
||||
}
|
||||
distributionInspect.Descriptor = ocispec.Descriptor{
|
||||
MediaType: descriptor.MediaType,
|
||||
@@ -104,7 +76,7 @@ func (dr *distributionRouter) fetchManifest(ctx context.Context, distrepo distri
|
||||
// we have a digest, so we can retrieve the manifest
|
||||
mnfstsrvc, err := distrepo.Manifests(ctx)
|
||||
if err != nil {
|
||||
return registry.DistributionInspect{}, err
|
||||
return err
|
||||
}
|
||||
mnfst, err := mnfstsrvc.Get(ctx, distributionInspect.Descriptor.Digest)
|
||||
if err != nil {
|
||||
@@ -116,14 +88,14 @@ func (dr *distributionRouter) fetchManifest(ctx context.Context, distrepo distri
|
||||
reference.ErrNameEmpty,
|
||||
reference.ErrNameTooLong,
|
||||
reference.ErrNameNotCanonical:
|
||||
return registry.DistributionInspect{}, errdefs.InvalidParameter(err)
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
return registry.DistributionInspect{}, err
|
||||
return err
|
||||
}
|
||||
|
||||
mediaType, payload, err := mnfst.Payload()
|
||||
if err != nil {
|
||||
return registry.DistributionInspect{}, err
|
||||
return err
|
||||
}
|
||||
// update MediaType because registry might return something incorrect
|
||||
distributionInspect.Descriptor.MediaType = mediaType
|
||||
@@ -144,8 +116,7 @@ func (dr *distributionRouter) fetchManifest(ctx context.Context, distrepo distri
|
||||
})
|
||||
}
|
||||
case *schema2.DeserializedManifest:
|
||||
blobStore := distrepo.Blobs(ctx)
|
||||
configJSON, err := blobStore.Get(ctx, mnfstObj.Config.Digest)
|
||||
configJSON, err := blobsrvc.Get(ctx, mnfstObj.Config.Digest)
|
||||
var platform ocispec.Platform
|
||||
if err == nil {
|
||||
err := json.Unmarshal(configJSON, &platform)
|
||||
@@ -153,10 +124,13 @@ func (dr *distributionRouter) fetchManifest(ctx context.Context, distrepo distri
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, platform)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(thaJeztah); we only use this to produce a nice error, but as a result, we can't remove libtrust as dependency - see if we can reduce the dependencies, but still able to detect it's a deprecated manifest
|
||||
case *schema1.SignedManifest:
|
||||
return registry.DistributionInspect{}, distributionpkg.DeprecatedSchema1ImageError(namedRef)
|
||||
platform := ocispec.Platform{
|
||||
Architecture: mnfstObj.Architecture,
|
||||
OS: "linux",
|
||||
}
|
||||
distributionInspect.Platforms = append(distributionInspect.Platforms, platform)
|
||||
}
|
||||
return distributionInspect, nil
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, distributionInspect)
|
||||
}
|
||||
|
||||
@@ -1,22 +1,8 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.23
|
||||
|
||||
package grpc // import "github.com/docker/docker/api/server/router/grpc"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/v2/defaults"
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/internal/otelutil"
|
||||
"github.com/moby/buildkit/util/grpcerrors"
|
||||
"github.com/moby/buildkit/util/stack"
|
||||
"github.com/moby/buildkit/util/tracing"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"golang.org/x/net/http2"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
@@ -29,18 +15,12 @@ type grpcRouter struct {
|
||||
|
||||
// NewRouter initializes a new grpc http router
|
||||
func NewRouter(backends ...Backend) router.Router {
|
||||
tp, _ := otelutil.NewTracerProvider(context.Background(), false)
|
||||
opts := []grpc.ServerOption{
|
||||
grpc.StatsHandler(tracing.ServerStatsHandler(otelgrpc.WithTracerProvider(tp))),
|
||||
grpc.ChainUnaryInterceptor(unaryInterceptor, grpcerrors.UnaryServerInterceptor),
|
||||
grpc.StreamInterceptor(grpcerrors.StreamServerInterceptor),
|
||||
grpc.MaxRecvMsgSize(defaults.DefaultMaxRecvMsgSize),
|
||||
grpc.MaxSendMsgSize(defaults.DefaultMaxSendMsgSize),
|
||||
}
|
||||
|
||||
r := &grpcRouter{
|
||||
h2Server: &http2.Server{},
|
||||
grpcServer: grpc.NewServer(opts...),
|
||||
h2Server: &http2.Server{},
|
||||
grpcServer: grpc.NewServer(
|
||||
grpc.UnaryInterceptor(grpcerrors.UnaryServerInterceptor),
|
||||
grpc.StreamInterceptor(grpcerrors.StreamServerInterceptor),
|
||||
),
|
||||
}
|
||||
for _, b := range backends {
|
||||
b.RegisterGRPC(r.grpcServer)
|
||||
@@ -59,21 +39,3 @@ func (gr *grpcRouter) initRoutes() {
|
||||
router.NewPostRoute("/grpc", gr.serveGRPC),
|
||||
}
|
||||
}
|
||||
|
||||
func unaryInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, _ 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)
|
||||
}
|
||||
|
||||
resp, err := handler(ctx, req)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Error(info.FullMethod)
|
||||
if log.GetLevel() >= log.DebugLevel {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%+v", stack.Formatter(grpcerrors.FromGRPC(err)))
|
||||
}
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
@@ -22,24 +22,23 @@ type Backend interface {
|
||||
}
|
||||
|
||||
type imageBackend interface {
|
||||
ImageDelete(ctx context.Context, imageRef string, options image.RemoveOptions) ([]image.DeleteResponse, error)
|
||||
ImageHistory(ctx context.Context, imageName string, platform *ocispec.Platform) ([]*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)
|
||||
ImageInspect(ctx context.Context, refOrID string, options backend.ImageInspectOpts) (*image.InspectResponse, error)
|
||||
ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
|
||||
ImageHistory(ctx context.Context, imageName string) ([]*image.HistoryResponseItem, error)
|
||||
Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error)
|
||||
GetImage(ctx context.Context, refOrID string, options image.GetImageOpts) (*dockerimage.Image, error)
|
||||
TagImage(ctx context.Context, id dockerimage.ID, newRef reference.Named) error
|
||||
ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*image.PruneReport, error)
|
||||
ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error)
|
||||
}
|
||||
|
||||
type importExportBackend interface {
|
||||
LoadImage(ctx context.Context, inTar io.ReadCloser, platform *ocispec.Platform, outStream io.Writer, quiet bool) 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, platform *ocispec.Platform, outStream io.Writer) error
|
||||
ExportImage(ctx context.Context, names []string, outStream io.Writer) error
|
||||
}
|
||||
|
||||
type registryBackend interface {
|
||||
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, platform *ocispec.Platform, metaHeaders map[string][]string, authConfig *registry.AuthConfig, outStream io.Writer) error
|
||||
PullImage(ctx context.Context, image, tag string, 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 {
|
||||
|
||||
@@ -2,20 +2,29 @@ package image // import "github.com/docker/docker/api/server/router/image"
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// imageRouter is a router to talk with the image controller
|
||||
type imageRouter struct {
|
||||
backend Backend
|
||||
searcher Searcher
|
||||
routes []router.Route
|
||||
backend Backend
|
||||
searcher Searcher
|
||||
referenceBackend reference.Store
|
||||
imageStore image.Store
|
||||
layerStore layer.Store
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// NewRouter initializes a new image router
|
||||
func NewRouter(backend Backend, searcher Searcher) router.Router {
|
||||
func NewRouter(backend Backend, searcher Searcher, referenceBackend reference.Store, imageStore image.Store, layerStore layer.Store) router.Router {
|
||||
ir := &imageRouter{
|
||||
backend: backend,
|
||||
searcher: searcher,
|
||||
backend: backend,
|
||||
searcher: searcher,
|
||||
referenceBackend: referenceBackend,
|
||||
imageStore: imageStore,
|
||||
layerStore: layerStore,
|
||||
}
|
||||
ir.initRoutes()
|
||||
return ir
|
||||
|
||||
@@ -2,7 +2,6 @@ package image // import "github.com/docker/docker/api/server/router/image"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -10,14 +9,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
imagetypes "github.com/docker/docker/api/types/image"
|
||||
opts "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"
|
||||
@@ -27,9 +24,6 @@ import (
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/go-connections/nat"
|
||||
dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
|
||||
"github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -58,7 +52,7 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
|
||||
if p := r.FormValue("platform"); p != "" {
|
||||
sp, err := platforms.Parse(p)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
return err
|
||||
}
|
||||
platform = &sp
|
||||
}
|
||||
@@ -72,39 +66,10 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
progressErr = ir.backend.PullImage(ctx, img, tag, platform, metaHeaders, authConfig, output)
|
||||
} else { // import
|
||||
src := r.Form.Get("fromSrc")
|
||||
|
||||
@@ -144,7 +109,7 @@ func (ir *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrit
|
||||
id, progressErr = ir.backend.ImportImage(ctx, tagRef, platform, comment, layerReader, r.Form["changes"])
|
||||
|
||||
if progressErr == nil {
|
||||
_, _ = output.Write(streamformatter.FormatStatus("", "%v", id.String()))
|
||||
output.Write(streamformatter.FormatStatus("", id.String()))
|
||||
}
|
||||
}
|
||||
if progressErr != nil {
|
||||
@@ -192,7 +157,7 @@ func (ir *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter
|
||||
|
||||
var ref reference.Named
|
||||
|
||||
// Tag is empty only in case PushOptions.All is true.
|
||||
// Tag is empty only in case ImagePushOptions.All is true.
|
||||
if tag != "" {
|
||||
r, err := httputils.RepoTagReference(img, tag)
|
||||
if err != nil {
|
||||
@@ -207,24 +172,7 @@ func (ir *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter
|
||||
ref = r
|
||||
}
|
||||
|
||||
var platform *ocispec.Platform
|
||||
// Platform is optional, and only supported in API version 1.46 and later.
|
||||
// However the PushOptions struct previously was an alias for the PullOptions struct
|
||||
// which also contained a Platform field.
|
||||
// This means that older clients may be sending a platform field, even
|
||||
// though it wasn't really supported by the server.
|
||||
// Don't break these clients and just ignore the platform field on older APIs.
|
||||
if versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.46") {
|
||||
if formPlatform := r.Form.Get("platform"); formPlatform != "" {
|
||||
p, err := httputils.DecodePlatform(formPlatform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
platform = p
|
||||
}
|
||||
}
|
||||
|
||||
if err := ir.backend.PushImage(ctx, ref, platform, metaHeaders, authConfig, output); err != nil {
|
||||
if err := ir.backend.PushImage(ctx, ref, metaHeaders, authConfig, output); err != nil {
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
@@ -249,22 +197,7 @@ func (ir *imageRouter) getImagesGet(ctx context.Context, w http.ResponseWriter,
|
||||
names = r.Form["names"]
|
||||
}
|
||||
|
||||
var platform *ocispec.Platform
|
||||
if versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.48") {
|
||||
if formPlatforms := r.Form["platform"]; len(formPlatforms) > 1 {
|
||||
// TODO(thaJeztah): remove once we support multiple platforms: see https://github.com/moby/moby/issues/48759
|
||||
return errdefs.InvalidParameter(errors.New("multiple platform parameters not supported"))
|
||||
}
|
||||
if formPlatform := r.Form.Get("platform"); formPlatform != "" {
|
||||
p, err := httputils.DecodePlatform(formPlatform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
platform = p
|
||||
}
|
||||
}
|
||||
|
||||
if err := ir.backend.ExportImage(ctx, names, platform, output); err != nil {
|
||||
if err := ir.backend.ExportImage(ctx, names, output); err != nil {
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
@@ -277,28 +210,13 @@ func (ir *imageRouter) postImagesLoad(ctx context.Context, w http.ResponseWriter
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var platform *ocispec.Platform
|
||||
if versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.48") {
|
||||
if formPlatforms := r.Form["platform"]; len(formPlatforms) > 1 {
|
||||
// TODO(thaJeztah): remove once we support multiple platforms: see https://github.com/moby/moby/issues/48759
|
||||
return errdefs.InvalidParameter(errors.New("multiple platform parameters not supported"))
|
||||
}
|
||||
if formPlatform := r.Form.Get("platform"); formPlatform != "" {
|
||||
p, err := httputils.DecodePlatform(formPlatform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
platform = p
|
||||
}
|
||||
}
|
||||
quiet := httputils.BoolValueOrDefault(r, "quiet", true)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
output := ioutils.NewWriteFlusher(w)
|
||||
defer output.Close()
|
||||
if err := ir.backend.LoadImage(ctx, r.Body, platform, output, quiet); err != nil {
|
||||
if err := ir.backend.LoadImage(ctx, r.Body, output, quiet); err != nil {
|
||||
_, _ = output.Write(streamformatter.FormatError(err))
|
||||
}
|
||||
return nil
|
||||
@@ -326,20 +244,7 @@ func (ir *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter,
|
||||
force := httputils.BoolValue(r, "force")
|
||||
prune := !httputils.BoolValue(r, "noprune")
|
||||
|
||||
var platforms []ocispec.Platform
|
||||
if versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.50") {
|
||||
p, err := httputils.DecodePlatforms(r.Form["platforms"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
platforms = p
|
||||
}
|
||||
|
||||
list, err := ir.backend.ImageDelete(ctx, name, imagetypes.RemoveOptions{
|
||||
Force: force,
|
||||
PruneChildren: prune,
|
||||
Platforms: platforms,
|
||||
})
|
||||
list, err := ir.backend.ImageDelete(ctx, name, force, prune)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -348,76 +253,83 @@ func (ir *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter,
|
||||
}
|
||||
|
||||
func (ir *imageRouter) getImagesByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var manifests bool
|
||||
if r.Form.Get("manifests") != "" && versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.48") {
|
||||
manifests = httputils.BoolValue(r, "manifests")
|
||||
}
|
||||
|
||||
var platform *ocispec.Platform
|
||||
if r.Form.Get("platform") != "" && versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.49") {
|
||||
p, err := httputils.DecodePlatform(r.Form.Get("platform"))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
platform = p
|
||||
}
|
||||
|
||||
if manifests && platform != nil {
|
||||
return errdefs.InvalidParameter(errors.New("conflicting options: manifests and platform options cannot both be set"))
|
||||
}
|
||||
|
||||
imageInspect, err := ir.backend.ImageInspect(ctx, vars["name"], backend.ImageInspectOpts{
|
||||
Manifests: manifests,
|
||||
Platform: platform,
|
||||
})
|
||||
img, err := ir.backend.GetImage(ctx, vars["name"], opts.GetImageOpts{Details: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure we output empty arrays instead of nil. While Go nil slice is functionally equivalent to an empty slice,
|
||||
// it matters for the JSON representation.
|
||||
if imageInspect.RepoTags == nil {
|
||||
imageInspect.RepoTags = []string{}
|
||||
}
|
||||
if imageInspect.RepoDigests == nil {
|
||||
imageInspect.RepoDigests = []string{}
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
if versions.LessThan(version, "1.48") {
|
||||
imageInspect.Descriptor = nil
|
||||
}
|
||||
if versions.LessThan(version, "1.50") {
|
||||
type imageInspectLegacy struct {
|
||||
imagetypes.InspectResponse
|
||||
LegacyConfig *container.Config `json:"Config"`
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, imageInspectLegacy{
|
||||
InspectResponse: *imageInspect,
|
||||
LegacyConfig: dockerOCIImageConfigToContainerConfig(*imageInspect.Config),
|
||||
})
|
||||
imageInspect, err := ir.toImageInspect(img)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, imageInspect)
|
||||
}
|
||||
|
||||
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))
|
||||
case reference.Canonical:
|
||||
repoDigests = append(repoDigests, reference.FamiliarString(ref))
|
||||
}
|
||||
}
|
||||
|
||||
comment := img.Comment
|
||||
if len(comment) == 0 && len(img.History) > 0 {
|
||||
comment = img.History[len(img.History)-1].Comment
|
||||
}
|
||||
|
||||
// Make sure we output empty arrays instead of nil.
|
||||
if repoTags == nil {
|
||||
repoTags = []string{}
|
||||
}
|
||||
if repoDigests == nil {
|
||||
repoDigests = []string{}
|
||||
}
|
||||
|
||||
return &types.ImageInspect{
|
||||
ID: img.ID().String(),
|
||||
RepoTags: repoTags,
|
||||
RepoDigests: repoDigests,
|
||||
Parent: img.Parent.String(),
|
||||
Comment: comment,
|
||||
Created: img.Created.Format(time.RFC3339Nano),
|
||||
Container: img.Container,
|
||||
ContainerConfig: &img.ContainerConfig,
|
||||
DockerVersion: img.DockerVersion,
|
||||
Author: img.Author,
|
||||
Config: img.Config,
|
||||
Architecture: img.Architecture,
|
||||
Variant: img.Variant,
|
||||
Os: img.OperatingSystem(),
|
||||
OsVersion: img.OSVersion,
|
||||
Size: img.Details.Size,
|
||||
VirtualSize: img.Details.Size, //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
|
||||
GraphDriver: types.GraphDriverData{
|
||||
Name: img.Details.Driver,
|
||||
Data: img.Details.Metadata,
|
||||
},
|
||||
RootFS: rootFSToAPIType(img.RootFS),
|
||||
Metadata: types.ImageMetadata{
|
||||
LastTagTime: img.Details.LastUpdated,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
|
||||
var layers []string
|
||||
for _, l := range rootfs.DiffIDs {
|
||||
layers = append(layers, l.String())
|
||||
}
|
||||
return types.RootFS{
|
||||
Type: rootfs.Type,
|
||||
Layers: layers,
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -443,24 +355,16 @@ func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
||||
sharedSize = httputils.BoolValue(r, "shared-size")
|
||||
}
|
||||
|
||||
var manifests bool
|
||||
if versions.GreaterThanOrEqualTo(version, "1.47") {
|
||||
manifests = httputils.BoolValue(r, "manifests")
|
||||
}
|
||||
|
||||
images, err := ir.backend.Images(ctx, imagetypes.ListOptions{
|
||||
images, err := ir.backend.Images(ctx, types.ImageListOptions{
|
||||
All: httputils.BoolValue(r, "all"),
|
||||
Filters: imageFilters,
|
||||
SharedSize: sharedSize,
|
||||
Manifests: manifests,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
useNone := versions.LessThan(version, "1.43")
|
||||
withVirtualSize := versions.LessThan(version, "1.44")
|
||||
noDescriptor := versions.LessThan(version, "1.48")
|
||||
for _, img := range images {
|
||||
if useNone {
|
||||
if len(img.RepoTags) == 0 && len(img.RepoDigests) == 0 {
|
||||
@@ -475,33 +379,13 @@ func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
|
||||
img.RepoDigests = []string{}
|
||||
}
|
||||
}
|
||||
if withVirtualSize {
|
||||
img.VirtualSize = img.Size //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
|
||||
}
|
||||
if noDescriptor {
|
||||
img.Descriptor = nil
|
||||
}
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, images)
|
||||
}
|
||||
|
||||
func (ir *imageRouter) getImagesHistory(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var platform *ocispec.Platform
|
||||
if versions.GreaterThanOrEqualTo(httputils.VersionFromContext(ctx), "1.48") {
|
||||
if formPlatform := r.Form.Get("platform"); formPlatform != "" {
|
||||
p, err := httputils.DecodePlatform(formPlatform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
platform = p
|
||||
}
|
||||
}
|
||||
history, err := ir.backend.ImageHistory(ctx, vars["name"], platform)
|
||||
history, err := ir.backend.ImageHistory(ctx, vars["name"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -519,12 +403,7 @@ func (ir *imageRouter) postImagesTag(ctx context.Context, w http.ResponseWriter,
|
||||
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{})
|
||||
img, err := ir.backend.GetImage(ctx, vars["name"], opts.GetImageOpts{})
|
||||
if err != nil {
|
||||
return errdefs.NotFound(err)
|
||||
}
|
||||
@@ -558,7 +437,7 @@ func (ir *imageRouter) getImagesSearch(ctx context.Context, w http.ResponseWrite
|
||||
// AuthConfig to increase compatibility with the existing API.
|
||||
authConfig, _ := registry.DecodeAuthConfig(r.Header.Get(registry.AuthHeader))
|
||||
|
||||
headers := http.Header{}
|
||||
var headers = http.Header{}
|
||||
for k, v := range r.Header {
|
||||
k = http.CanonicalHeaderKey(k)
|
||||
if strings.HasPrefix(k, "X-Meta-") {
|
||||
@@ -589,36 +468,3 @@ func (ir *imageRouter) postImagesPrune(ctx context.Context, w http.ResponseWrite
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// FIXME(thaJeztah): this is a copy of dockerOCIImageConfigToContainerConfig in daemon/containerd: https://github.com/moby/moby/blob/6b617699c500522aa6526cfcae4558333911b11f/daemon/containerd/imagespec.go#L107-L128
|
||||
func dockerOCIImageConfigToContainerConfig(cfg dockerspec.DockerOCIImageConfig) *container.Config {
|
||||
exposedPorts := make(nat.PortSet, len(cfg.ExposedPorts))
|
||||
for k, v := range cfg.ExposedPorts {
|
||||
exposedPorts[nat.Port(k)] = v
|
||||
}
|
||||
|
||||
return &container.Config{
|
||||
Entrypoint: cfg.Entrypoint,
|
||||
Env: cfg.Env,
|
||||
Cmd: cfg.Cmd,
|
||||
User: cfg.User,
|
||||
WorkingDir: cfg.WorkingDir,
|
||||
ExposedPorts: exposedPorts,
|
||||
Volumes: cfg.Volumes,
|
||||
Labels: cfg.Labels,
|
||||
ArgsEscaped: cfg.ArgsEscaped, //nolint:staticcheck // Ignore SA1019. Need to keep it in image.
|
||||
StopSignal: cfg.StopSignal,
|
||||
Healthcheck: cfg.Healthcheck,
|
||||
OnBuild: cfg.OnBuild,
|
||||
Shell: cfg.Shell,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,28 +3,30 @@ package network // import "github.com/docker/docker/api/server/router/network"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types"
|
||||
"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 {
|
||||
GetNetworks(filters.Args, backend.NetworkListConfig) ([]network.Inspect, error)
|
||||
CreateNetwork(ctx context.Context, nc network.CreateRequest) (*network.CreateResponse, error)
|
||||
ConnectContainerToNetwork(ctx context.Context, containerName, networkName string, endpointConfig *network.EndpointSettings) error
|
||||
FindNetwork(idName string) (libnetwork.Network, error)
|
||||
GetNetworks(filters.Args, types.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
|
||||
DeleteNetwork(networkID string) error
|
||||
NetworksPrune(ctx context.Context, pruneFilters filters.Args) (*network.PruneReport, error)
|
||||
NetworksPrune(ctx context.Context, pruneFilters filters.Args) (*types.NetworksPruneReport, error)
|
||||
}
|
||||
|
||||
// ClusterBackend is all the methods that need to be implemented
|
||||
// to provide cluster network specific functionality.
|
||||
type ClusterBackend interface {
|
||||
GetNetworks(filters.Args) ([]network.Inspect, error)
|
||||
GetNetwork(name string) (network.Inspect, error)
|
||||
GetNetworksByName(name string) ([]network.Inspect, error)
|
||||
CreateNetwork(nc network.CreateRequest) (string, error)
|
||||
GetNetworks(filters.Args) ([]types.NetworkResource, error)
|
||||
GetNetwork(name string) (types.NetworkResource, error)
|
||||
GetNetworksByName(name string) ([]types.NetworkResource, error)
|
||||
CreateNetwork(nc types.NetworkCreateRequest) (string, error)
|
||||
RemoveNetwork(name string) error
|
||||
}
|
||||
|
||||
1
api/server/router/network/filter.go
Normal file
1
api/server/router/network/filter.go
Normal file
@@ -0,0 +1 @@
|
||||
package network // import "github.com/docker/docker/api/server/router/network"
|
||||
@@ -22,22 +22,22 @@ func NewRouter(b Backend, c ClusterBackend) router.Router {
|
||||
}
|
||||
|
||||
// Routes returns the available routes to the network controller
|
||||
func (n *networkRouter) Routes() []router.Route {
|
||||
return n.routes
|
||||
func (r *networkRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
func (n *networkRouter) initRoutes() {
|
||||
n.routes = []router.Route{
|
||||
func (r *networkRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
// GET
|
||||
router.NewGetRoute("/networks", n.getNetworksList),
|
||||
router.NewGetRoute("/networks/", n.getNetworksList),
|
||||
router.NewGetRoute("/networks/{id:.+}", n.getNetwork),
|
||||
router.NewGetRoute("/networks", r.getNetworksList),
|
||||
router.NewGetRoute("/networks/", r.getNetworksList),
|
||||
router.NewGetRoute("/networks/{id:.+}", r.getNetwork),
|
||||
// POST
|
||||
router.NewPostRoute("/networks/create", n.postNetworkCreate),
|
||||
router.NewPostRoute("/networks/{id:.*}/connect", n.postNetworkConnect),
|
||||
router.NewPostRoute("/networks/{id:.*}/disconnect", n.postNetworkDisconnect),
|
||||
router.NewPostRoute("/networks/prune", n.postNetworksPrune),
|
||||
router.NewPostRoute("/networks/create", r.postNetworkCreate),
|
||||
router.NewPostRoute("/networks/{id:.*}/connect", r.postNetworkConnect),
|
||||
router.NewPostRoute("/networks/{id:.*}/disconnect", r.postNetworkDisconnect),
|
||||
router.NewPostRoute("/networks/prune", r.postNetworksPrune),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/networks/{id:.*}", n.deleteNetwork),
|
||||
router.NewDeleteRoute("/networks/{id:.*}", r.deleteNetwork),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,13 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libnetwork"
|
||||
"github.com/docker/docker/libnetwork/scope"
|
||||
netconst "github.com/docker/docker/libnetwork/datastore"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -31,7 +31,7 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit
|
||||
return err
|
||||
}
|
||||
|
||||
var list []network.Summary
|
||||
var list []types.NetworkResource
|
||||
nr, err := n.cluster.GetNetworks(filter)
|
||||
if err == nil {
|
||||
list = nr
|
||||
@@ -39,7 +39,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, backend.NetworkListConfig{Detailed: versions.LessThan(httputils.VersionFromContext(ctx), "1.28")})
|
||||
localNetworks, err := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: versions.LessThan(httputils.VersionFromContext(ctx), "1.28")})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -59,7 +59,7 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit
|
||||
}
|
||||
|
||||
if list == nil {
|
||||
list = []network.Summary{}
|
||||
list = []types.NetworkResource{}
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, list)
|
||||
@@ -75,13 +75,17 @@ func (e invalidRequestError) Error() string {
|
||||
|
||||
func (e invalidRequestError) InvalidParameter() {}
|
||||
|
||||
type ambiguousResultsError string
|
||||
type ambigousResultsError string
|
||||
|
||||
func (e ambiguousResultsError) Error() string {
|
||||
func (e ambigousResultsError) Error() string {
|
||||
return "network " + string(e) + " is ambiguous"
|
||||
}
|
||||
|
||||
func (ambiguousResultsError) InvalidParameter() {}
|
||||
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 {
|
||||
@@ -98,7 +102,7 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
||||
return errors.Wrapf(invalidRequestError{err}, "invalid value for verbose: %s", v)
|
||||
}
|
||||
}
|
||||
networkScope := r.URL.Query().Get("scope")
|
||||
scope := r.URL.Query().Get("scope")
|
||||
|
||||
// In case multiple networks have duplicate names, return error.
|
||||
// TODO (yongtang): should we wrap with version here for backward compatibility?
|
||||
@@ -108,29 +112,29 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
||||
|
||||
// For full name and partial ID, save the result first, and process later
|
||||
// in case multiple records was found based on the same term
|
||||
listByFullName := map[string]network.Inspect{}
|
||||
listByPartialID := map[string]network.Inspect{}
|
||||
listByFullName := map[string]types.NetworkResource{}
|
||||
listByPartialID := map[string]types.NetworkResource{}
|
||||
|
||||
// TODO(@cpuguy83): All this logic for figuring out which network to return does not belong here
|
||||
// Instead there should be a backend function to just get one network.
|
||||
filter := filters.NewArgs(filters.Arg("idOrName", term))
|
||||
if networkScope != "" {
|
||||
filter.Add("scope", networkScope)
|
||||
if scope != "" {
|
||||
filter.Add("scope", scope)
|
||||
}
|
||||
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)
|
||||
nw, _ := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: true, Verbose: verbose})
|
||||
for _, network := range nw {
|
||||
if network.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, network)
|
||||
}
|
||||
if nw.Name == term {
|
||||
if network.Name == term {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByFullName[nw.ID] = nw
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
if strings.HasPrefix(nw.ID, term) {
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByPartialID[nw.ID] = nw
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,37 +144,37 @@ 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) || networkScope == scope.Swarm {
|
||||
if strings.HasPrefix(nwk.ID, term) || (netconst.SwarmScope == scope) {
|
||||
// If we have a previous match "backend", return it, we need verbose when enabled
|
||||
// ex: overlay/partial_ID or name/swarm_scope
|
||||
if nwv, ok := listByPartialID[nwk.ID]; ok {
|
||||
nwk = nwv
|
||||
} else if nwv, ok = listByFullName[nwk.ID]; ok {
|
||||
} else if nwv, ok := listByFullName[nwk.ID]; ok {
|
||||
nwk = nwv
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, nwk)
|
||||
}
|
||||
}
|
||||
|
||||
networks, _ = n.cluster.GetNetworks(filter)
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, nw)
|
||||
nr, _ := n.cluster.GetNetworks(filter)
|
||||
for _, network := range nr {
|
||||
if network.ID == term {
|
||||
return httputils.WriteJSON(w, http.StatusOK, network)
|
||||
}
|
||||
if nw.Name == term {
|
||||
if network.Name == term {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByFullName) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByFullName[nw.ID]; !ok {
|
||||
listByFullName[nw.ID] = nw
|
||||
if _, ok := listByFullName[network.ID]; !ok {
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(nw.ID, term) {
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByPartialID) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByPartialID[nw.ID]; !ok {
|
||||
listByPartialID[nw.ID] = nw
|
||||
if _, ok := listByPartialID[network.ID]; !ok {
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,7 +186,7 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
||||
}
|
||||
}
|
||||
if len(listByFullName) > 1 {
|
||||
return errors.Wrapf(ambiguousResultsError(term), "%d matches found based on name", len(listByFullName))
|
||||
return errors.Wrapf(ambigousResultsError(term), "%d matches found based on name", len(listByFullName))
|
||||
}
|
||||
|
||||
// Find based on partial ID, returns true only if no duplicates
|
||||
@@ -192,7 +196,7 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
||||
}
|
||||
}
|
||||
if len(listByPartialID) > 1 {
|
||||
return errors.Wrapf(ambiguousResultsError(term), "%d matches found based on ID prefix", len(listByPartialID))
|
||||
return errors.Wrapf(ambigousResultsError(term), "%d matches found based on ID prefix", len(listByPartialID))
|
||||
}
|
||||
|
||||
return libnetwork.ErrNoSuchNetwork(term)
|
||||
@@ -203,28 +207,27 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
|
||||
return err
|
||||
}
|
||||
|
||||
var create network.CreateRequest
|
||||
var create types.NetworkCreateRequest
|
||||
if err := httputils.ReadJSON(r, &create); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 {
|
||||
return libnetwork.NetworkNameError(create.Name)
|
||||
return nameConflict(create.Name)
|
||||
}
|
||||
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
|
||||
// EnableIPv4 was introduced in API 1.48.
|
||||
if versions.LessThan(version, "1.48") {
|
||||
create.EnableIPv4 = nil
|
||||
}
|
||||
|
||||
// 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(ctx, create)
|
||||
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
|
||||
}
|
||||
@@ -232,8 +235,9 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nw = &network.CreateResponse{
|
||||
ID: id,
|
||||
nw = &types.NetworkCreateResponse{
|
||||
ID: id,
|
||||
Warning: warning,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +249,7 @@ func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseW
|
||||
return err
|
||||
}
|
||||
|
||||
var connect network.ConnectOptions
|
||||
var connect types.NetworkConnect
|
||||
if err := httputils.ReadJSON(r, &connect); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -254,7 +258,7 @@ func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseW
|
||||
// The reason is that, In case of attachable network in swarm scope, the actual local network
|
||||
// may not be available at the time. At the same time, inside daemon `ConnectContainerToNetwork`
|
||||
// does the ambiguity check anyway. Therefore, passing the name to daemon would be enough.
|
||||
return n.backend.ConnectContainerToNetwork(ctx, connect.Container, vars["id"], connect.EndpointConfig)
|
||||
return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig)
|
||||
}
|
||||
|
||||
func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
@@ -262,7 +266,7 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
|
||||
return err
|
||||
}
|
||||
|
||||
var disconnect network.DisconnectOptions
|
||||
var disconnect types.NetworkDisconnect
|
||||
if err := httputils.ReadJSON(r, &disconnect); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -317,47 +321,47 @@ func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWr
|
||||
// For full name and partial ID, save the result first, and process later
|
||||
// in case multiple records was found based on the same term
|
||||
// TODO (yongtang): should we wrap with version here for backward compatibility?
|
||||
func (n *networkRouter) findUniqueNetwork(term string) (network.Inspect, error) {
|
||||
listByFullName := map[string]network.Inspect{}
|
||||
listByPartialID := map[string]network.Inspect{}
|
||||
func (n *networkRouter) findUniqueNetwork(term string) (types.NetworkResource, error) {
|
||||
listByFullName := map[string]types.NetworkResource{}
|
||||
listByPartialID := map[string]types.NetworkResource{}
|
||||
|
||||
filter := filters.NewArgs(filters.Arg("idOrName", term))
|
||||
networks, _ := n.backend.GetNetworks(filter, backend.NetworkListConfig{Detailed: true})
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return nw, nil
|
||||
nw, _ := n.backend.GetNetworks(filter, types.NetworkListConfig{Detailed: true})
|
||||
for _, network := range nw {
|
||||
if network.ID == term {
|
||||
return network, nil
|
||||
}
|
||||
if nw.Name == term && !nw.Ingress {
|
||||
if network.Name == term && !network.Ingress {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByFullName[nw.ID] = nw
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
if strings.HasPrefix(nw.ID, term) {
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// No need to check the ID collision here as we are still in
|
||||
// local scope and the network ID is unique in this scope.
|
||||
listByPartialID[nw.ID] = nw
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
|
||||
networks, _ = n.cluster.GetNetworks(filter)
|
||||
for _, nw := range networks {
|
||||
if nw.ID == term {
|
||||
return nw, nil
|
||||
nr, _ := n.cluster.GetNetworks(filter)
|
||||
for _, network := range nr {
|
||||
if network.ID == term {
|
||||
return network, nil
|
||||
}
|
||||
if nw.Name == term {
|
||||
if network.Name == term {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByFullName) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByFullName[nw.ID]; !ok {
|
||||
listByFullName[nw.ID] = nw
|
||||
if _, ok := listByFullName[network.ID]; !ok {
|
||||
listByFullName[network.ID] = network
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(nw.ID, term) {
|
||||
if strings.HasPrefix(network.ID, term) {
|
||||
// Check the ID collision as we are in swarm scope here, and
|
||||
// the map (of the listByPartialID) may have already had a
|
||||
// network with the same ID (from local scope previously)
|
||||
if _, ok := listByPartialID[nw.ID]; !ok {
|
||||
listByPartialID[nw.ID] = nw
|
||||
if _, ok := listByPartialID[network.ID]; !ok {
|
||||
listByPartialID[network.ID] = network
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,7 +373,7 @@ func (n *networkRouter) findUniqueNetwork(term string) (network.Inspect, error)
|
||||
}
|
||||
}
|
||||
if len(listByFullName) > 1 {
|
||||
return network.Inspect{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName)))
|
||||
return types.NetworkResource{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName)))
|
||||
}
|
||||
|
||||
// Find based on partial ID, returns true only if no duplicates
|
||||
@@ -379,8 +383,8 @@ func (n *networkRouter) findUniqueNetwork(term string) (network.Inspect, error)
|
||||
}
|
||||
}
|
||||
if len(listByPartialID) > 1 {
|
||||
return network.Inspect{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID)))
|
||||
return types.NetworkResource{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID)))
|
||||
}
|
||||
|
||||
return network.Inspect{}, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term))
|
||||
return types.NetworkResource{}, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term))
|
||||
}
|
||||
|
||||
@@ -5,9 +5,8 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/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"
|
||||
@@ -15,11 +14,11 @@ import (
|
||||
|
||||
// Backend for Plugin
|
||||
type Backend interface {
|
||||
Disable(name string, config *backend.PluginDisableConfig) error
|
||||
Enable(name string, config *backend.PluginEnableConfig) error
|
||||
Disable(name string, config *types.PluginDisableConfig) error
|
||||
Enable(name string, config *types.PluginEnableConfig) error
|
||||
List(filters.Args) ([]types.Plugin, error)
|
||||
Inspect(name string) (*types.Plugin, error)
|
||||
Remove(name string, config *backend.PluginRmConfig) error
|
||||
Remove(name string, config *types.PluginRmConfig) error
|
||||
Set(name string, args []string) 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
|
||||
|
||||
@@ -18,22 +18,22 @@ func NewRouter(b Backend) router.Router {
|
||||
}
|
||||
|
||||
// Routes returns the available routers to the plugin controller
|
||||
func (pr *pluginRouter) Routes() []router.Route {
|
||||
return pr.routes
|
||||
func (r *pluginRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
func (pr *pluginRouter) initRoutes() {
|
||||
pr.routes = []router.Route{
|
||||
router.NewGetRoute("/plugins", pr.listPlugins),
|
||||
router.NewGetRoute("/plugins/{name:.*}/json", pr.inspectPlugin),
|
||||
router.NewGetRoute("/plugins/privileges", pr.getPrivileges),
|
||||
router.NewDeleteRoute("/plugins/{name:.*}", pr.removePlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/enable", pr.enablePlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/disable", pr.disablePlugin),
|
||||
router.NewPostRoute("/plugins/pull", pr.pullPlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/push", pr.pushPlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/upgrade", pr.upgradePlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/set", pr.setPlugin),
|
||||
router.NewPostRoute("/plugins/create", pr.createPlugin),
|
||||
func (r *pluginRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.NewGetRoute("/plugins", r.listPlugins),
|
||||
router.NewGetRoute("/plugins/{name:.*}/json", r.inspectPlugin),
|
||||
router.NewGetRoute("/plugins/privileges", r.getPrivileges),
|
||||
router.NewDeleteRoute("/plugins/{name:.*}", r.removePlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/enable", r.enablePlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/disable", r.disablePlugin),
|
||||
router.NewPostRoute("/plugins/pull", r.pullPlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/push", r.pushPlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/upgrade", r.upgradePlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/set", r.setPlugin),
|
||||
router.NewPostRoute("/plugins/create", r.createPlugin),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,9 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/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"
|
||||
@@ -187,8 +186,7 @@ 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
|
||||
@@ -208,7 +206,7 @@ func (pr *pluginRouter) enablePlugin(ctx context.Context, w http.ResponseWriter,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config := &backend.PluginEnableConfig{Timeout: timeout}
|
||||
config := &types.PluginEnableConfig{Timeout: timeout}
|
||||
|
||||
return pr.backend.Enable(name, config)
|
||||
}
|
||||
@@ -219,7 +217,7 @@ func (pr *pluginRouter) disablePlugin(ctx context.Context, w http.ResponseWriter
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
config := &backend.PluginDisableConfig{
|
||||
config := &types.PluginDisableConfig{
|
||||
ForceDisable: httputils.BoolValue(r, "force"),
|
||||
}
|
||||
|
||||
@@ -232,7 +230,7 @@ func (pr *pluginRouter) removePlugin(ctx context.Context, w http.ResponseWriter,
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
config := &backend.PluginRmConfig{
|
||||
config := &types.PluginRmConfig{
|
||||
ForceRemove: httputils.BoolValue(r, "force"),
|
||||
}
|
||||
return pr.backend.Remove(name, config)
|
||||
|
||||
@@ -18,12 +18,12 @@ func NewRouter(b Backend) router.Router {
|
||||
}
|
||||
|
||||
// Routes returns the available routers to the session controller
|
||||
func (sr *sessionRouter) Routes() []router.Route {
|
||||
return sr.routes
|
||||
func (r *sessionRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
func (sr *sessionRouter) initRoutes() {
|
||||
sr.routes = []router.Route{
|
||||
router.NewPostRoute("/session", sr.startSession),
|
||||
func (r *sessionRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
router.NewPostRoute("/session", r.startSession),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,40 +3,46 @@ 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/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
types "github.com/docker/docker/api/types/swarm"
|
||||
)
|
||||
|
||||
// Backend abstracts a swarm manager.
|
||||
type Backend interface {
|
||||
Init(req swarm.InitRequest) (string, error)
|
||||
Join(req swarm.JoinRequest) error
|
||||
Init(req types.InitRequest) (string, error)
|
||||
Join(req types.JoinRequest) error
|
||||
Leave(ctx context.Context, force bool) error
|
||||
Inspect() (swarm.Swarm, error)
|
||||
Update(uint64, swarm.Spec, swarm.UpdateFlags) error
|
||||
Inspect() (types.Swarm, error)
|
||||
Update(uint64, types.Spec, types.UpdateFlags) error
|
||||
GetUnlockKey() (string, error)
|
||||
UnlockSwarm(req swarm.UnlockRequest) error
|
||||
GetServices(swarm.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, swarm.ServiceUpdateOptions, bool) (*swarm.ServiceUpdateResponse, 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)
|
||||
RemoveService(string) error
|
||||
ServiceLogs(context.Context, *backend.LogSelector, *container.LogsOptions) (<-chan *backend.LogMessage, error)
|
||||
GetNodes(swarm.NodeListOptions) ([]swarm.Node, error)
|
||||
GetNode(string) (swarm.Node, error)
|
||||
UpdateNode(string, uint64, swarm.NodeSpec) 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
|
||||
RemoveNode(string, bool) error
|
||||
GetTasks(swarm.TaskListOptions) ([]swarm.Task, error)
|
||||
GetTask(string) (swarm.Task, error)
|
||||
GetSecrets(opts swarm.SecretListOptions) ([]swarm.Secret, error)
|
||||
CreateSecret(s swarm.SecretSpec) (string, error)
|
||||
|
||||
GetTasks(basictypes.TaskListOptions) ([]types.Task, error)
|
||||
GetTask(string) (types.Task, error)
|
||||
|
||||
GetSecrets(opts basictypes.SecretListOptions) ([]types.Secret, error)
|
||||
CreateSecret(s types.SecretSpec) (string, error)
|
||||
RemoveSecret(idOrName string) error
|
||||
GetSecret(id string) (swarm.Secret, error)
|
||||
UpdateSecret(idOrName string, version uint64, spec swarm.SecretSpec) error
|
||||
GetConfigs(opts swarm.ConfigListOptions) ([]swarm.Config, error)
|
||||
CreateConfig(s swarm.ConfigSpec) (string, error)
|
||||
GetSecret(id string) (types.Secret, error)
|
||||
UpdateSecret(idOrName string, version uint64, spec types.SecretSpec) error
|
||||
|
||||
GetConfigs(opts basictypes.ConfigListOptions) ([]types.Config, error)
|
||||
CreateConfig(s types.ConfigSpec) (string, error)
|
||||
RemoveConfig(id string) error
|
||||
GetConfig(id string) (swarm.Config, error)
|
||||
UpdateConfig(idOrName string, version uint64, spec swarm.ConfigSpec) error
|
||||
GetConfig(id string) (types.Config, error)
|
||||
UpdateConfig(idOrName string, version uint64, spec types.ConfigSpec) error
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ 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"
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"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 {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error initializing swarm")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error initializing swarm")
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, nodeID)
|
||||
@@ -61,7 +62,7 @@ func (sr *swarmRouter) leaveCluster(ctx context.Context, w http.ResponseWriter,
|
||||
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 {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting swarm")
|
||||
logrus.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 {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error configuring swarm")
|
||||
logrus.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 {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error unlocking swarm")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error unlocking swarm")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -135,11 +136,11 @@ 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 {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error retrieving swarm unlock key")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error retrieving swarm unlock key")
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, &types.UnlockKeyResponse{
|
||||
return httputils.WriteJSON(w, http.StatusOK, &basictypes.SwarmUnlockKeyResponse{
|
||||
UnlockKey: unlockKey,
|
||||
})
|
||||
}
|
||||
@@ -165,9 +166,9 @@ func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r
|
||||
}
|
||||
}
|
||||
|
||||
services, err := sr.backend.GetServices(types.ServiceListOptions{Filters: filter, Status: status})
|
||||
services, err := sr.backend.GetServices(basictypes.ServiceListOptions{Filters: filter, Status: status})
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting services")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error getting services")
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -193,7 +194,7 @@ func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r
|
||||
|
||||
service, err := sr.backend.GetService(vars["id"], insertDefaults)
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"service-id": vars["id"],
|
||||
}).Debug("Error getting service")
|
||||
@@ -218,10 +219,9 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
|
||||
}
|
||||
adjustForAPIVersion(v, &service)
|
||||
}
|
||||
|
||||
resp, err := sr.backend.CreateService(service, encodedAuth, queryRegistry)
|
||||
if err != nil {
|
||||
log.G(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"service-name": service.Name,
|
||||
}).Debug("Error creating service")
|
||||
@@ -244,7 +244,7 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
var flags types.ServiceUpdateOptions
|
||||
var flags basictypes.ServiceUpdateOptions
|
||||
|
||||
// Get returns "" if the header does not exist
|
||||
flags.EncodedRegistryAuth = r.Header.Get(registry.AuthHeader)
|
||||
@@ -260,7 +260,7 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
|
||||
|
||||
resp, err := sr.backend.UpdateService(vars["id"], version, service, flags, queryRegistry)
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"service-id": vars["id"],
|
||||
}).Debug("Error updating service")
|
||||
@@ -271,7 +271,7 @@ 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 {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"service-id": vars["id"],
|
||||
}).Debug("Error removing service")
|
||||
@@ -313,9 +313,9 @@ func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *h
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := sr.backend.GetNodes(types.NodeListOptions{Filters: filter})
|
||||
nodes, err := sr.backend.GetNodes(basictypes.NodeListOptions{Filters: filter})
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting nodes")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error getting nodes")
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ 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 {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"node-id": vars["id"],
|
||||
}).Debug("Error getting node")
|
||||
@@ -349,7 +349,7 @@ func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r
|
||||
}
|
||||
|
||||
if err := sr.backend.UpdateNode(vars["id"], version, node); err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"node-id": vars["id"],
|
||||
}).Debug("Error updating node")
|
||||
@@ -366,7 +366,7 @@ 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 {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"node-id": vars["id"],
|
||||
}).Debug("Error removing node")
|
||||
@@ -384,9 +384,9 @@ func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *h
|
||||
return err
|
||||
}
|
||||
|
||||
tasks, err := sr.backend.GetTasks(types.TaskListOptions{Filters: filter})
|
||||
tasks, err := sr.backend.GetTasks(basictypes.TaskListOptions{Filters: filter})
|
||||
if err != nil {
|
||||
log.G(ctx).WithContext(ctx).WithError(err).Debug("Error getting tasks")
|
||||
logrus.WithContext(ctx).WithError(err).Debug("Error getting tasks")
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -396,7 +396,7 @@ 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 {
|
||||
log.G(ctx).WithContext(ctx).WithFields(log.Fields{
|
||||
logrus.WithContext(ctx).WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
"task-id": vars["id"],
|
||||
}).Debug("Error getting task")
|
||||
@@ -415,7 +415,7 @@ func (sr *swarmRouter) getSecrets(ctx context.Context, w http.ResponseWriter, r
|
||||
return err
|
||||
}
|
||||
|
||||
secrets, err := sr.backend.GetSecrets(types.SecretListOptions{Filters: filters})
|
||||
secrets, err := sr.backend.GetSecrets(basictypes.SecretListOptions{Filters: filters})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -438,7 +438,7 @@ func (sr *swarmRouter) createSecret(ctx context.Context, w http.ResponseWriter,
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &types.SecretCreateResponse{
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &basictypes.SecretCreateResponse{
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
@@ -486,7 +486,7 @@ func (sr *swarmRouter) getConfigs(ctx context.Context, w http.ResponseWriter, r
|
||||
return err
|
||||
}
|
||||
|
||||
configs, err := sr.backend.GetConfigs(types.ConfigListOptions{Filters: filters})
|
||||
configs, err := sr.backend.GetConfigs(basictypes.ConfigListOptions{Filters: filters})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -510,7 +510,7 @@ func (sr *swarmRouter) createConfig(ctx context.Context, w http.ResponseWriter,
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &types.ConfigCreateResponse{
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &basictypes.ConfigCreateResponse{
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ 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"
|
||||
)
|
||||
@@ -22,13 +21,13 @@ func (sr *swarmRouter) swarmLogs(ctx context.Context, w http.ResponseWriter, r *
|
||||
// any error after the stream starts (i.e. container not found, wrong parameters)
|
||||
// with the appropriate status code.
|
||||
stdout, stderr := httputils.BoolValue(r, "stdout"), httputils.BoolValue(r, "stderr")
|
||||
if !stdout && !stderr {
|
||||
if !(stdout || stderr) {
|
||||
return fmt.Errorf("Bad parameters: you must choose at least one stream")
|
||||
}
|
||||
|
||||
// there is probably a neater way to manufacture the LogsOptions
|
||||
// there is probably a neater way to manufacture the ContainerLogsOptions
|
||||
// struct, probably in the caller, to eliminate the dependency on net/http
|
||||
logsConfig := &container.LogsOptions{
|
||||
logsConfig := &basictypes.ContainerLogsOptions{
|
||||
Follow: httputils.BoolValue(r, "follow"),
|
||||
Timestamps: httputils.BoolValue(r, "timestamps"),
|
||||
Since: r.Form.Get("since"),
|
||||
@@ -78,16 +77,6 @@ func adjustForAPIVersion(cliVersion string, service *swarm.ServiceSpec) {
|
||||
if cliVersion == "" {
|
||||
return
|
||||
}
|
||||
if versions.LessThan(cliVersion, "1.46") {
|
||||
if service.TaskTemplate.ContainerSpec != nil {
|
||||
for i, mount := range service.TaskTemplate.ContainerSpec.Mounts {
|
||||
if mount.TmpfsOptions != nil {
|
||||
mount.TmpfsOptions.Options = nil
|
||||
service.TaskTemplate.ContainerSpec.Mounts[i] = mount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if versions.LessThan(cliVersion, "1.40") {
|
||||
if service.TaskTemplate.ContainerSpec != nil {
|
||||
// Sysctls for docker swarm services weren't supported before
|
||||
@@ -129,26 +118,4 @@ func adjustForAPIVersion(cliVersion string, service *swarm.ServiceSpec) {
|
||||
service.Mode.ReplicatedJob = nil
|
||||
service.Mode.GlobalJob = nil
|
||||
}
|
||||
|
||||
if versions.LessThan(cliVersion, "1.44") {
|
||||
if service.TaskTemplate.ContainerSpec != nil {
|
||||
// seccomp, apparmor, and no_new_privs were added in 1.44.
|
||||
if service.TaskTemplate.ContainerSpec.Privileges != nil {
|
||||
service.TaskTemplate.ContainerSpec.Privileges.Seccomp = nil
|
||||
service.TaskTemplate.ContainerSpec.Privileges.AppArmor = nil
|
||||
service.TaskTemplate.ContainerSpec.Privileges.NoNewPrivileges = false
|
||||
}
|
||||
if service.TaskTemplate.ContainerSpec.Healthcheck != nil {
|
||||
// StartInterval was added in API 1.44
|
||||
service.TaskTemplate.ContainerSpec.Healthcheck.StartInterval = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if versions.LessThan(cliVersion, "1.46") {
|
||||
if service.TaskTemplate.ContainerSpec != nil && service.TaskTemplate.ContainerSpec.OomScoreAdj != 0 {
|
||||
// OomScoreAdj was added in API 1.46
|
||||
service.TaskTemplate.ContainerSpec.OomScoreAdj = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,14 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
||||
func TestAdjustForAPIVersion(t *testing.T) {
|
||||
expectedSysctls := map[string]string{"foo": "bar"}
|
||||
var (
|
||||
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.
|
||||
@@ -39,25 +40,13 @@ func TestAdjustForAPIVersion(t *testing.T) {
|
||||
ConfigName: "configRuntime",
|
||||
},
|
||||
},
|
||||
Ulimits: []*container.Ulimit{
|
||||
Ulimits: []*units.Ulimit{
|
||||
{
|
||||
Name: "nofile",
|
||||
Soft: 100,
|
||||
Hard: 200,
|
||||
},
|
||||
},
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: mount.TypeTmpfs,
|
||||
Source: "/foo",
|
||||
Target: "/bar",
|
||||
TmpfsOptions: &mount.TmpfsOptions{
|
||||
Options: [][]string{
|
||||
{"exec"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Placement: &swarm.Placement{
|
||||
MaxReplicas: 222,
|
||||
@@ -70,19 +59,6 @@ func TestAdjustForAPIVersion(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
adjustForAPIVersion("1.46", spec)
|
||||
if !reflect.DeepEqual(
|
||||
spec.TaskTemplate.ContainerSpec.Mounts[0].TmpfsOptions.Options,
|
||||
[][]string{{"exec"}},
|
||||
) {
|
||||
t.Error("TmpfsOptions.Options was stripped from spec")
|
||||
}
|
||||
|
||||
adjustForAPIVersion("1.45", spec)
|
||||
if len(spec.TaskTemplate.ContainerSpec.Mounts[0].TmpfsOptions.Options) != 0 {
|
||||
t.Error("TmpfsOptions.Options not stripped from spec")
|
||||
}
|
||||
|
||||
// first, does calling this with a later version correctly NOT strip
|
||||
// fields? do the later version first, so we can reuse this spec in the
|
||||
// next test.
|
||||
|
||||
@@ -5,12 +5,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/build"
|
||||
"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.
|
||||
@@ -28,9 +26,9 @@ type DiskUsageOptions struct {
|
||||
// Backend is the methods that need to be implemented to provide
|
||||
// system specific functionality.
|
||||
type Backend interface {
|
||||
SystemInfo(context.Context) (*system.Info, error)
|
||||
SystemVersion(context.Context) (types.Version, error)
|
||||
SystemDiskUsage(ctx context.Context, opts DiskUsageOptions) (*system.DiskUsage, error)
|
||||
SystemInfo() *types.Info
|
||||
SystemVersion() types.Version
|
||||
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 *registry.AuthConfig) (string, string, error)
|
||||
@@ -39,12 +37,7 @@ type Backend interface {
|
||||
// ClusterBackend is all the methods that need to be implemented
|
||||
// to provide cluster system specific functionality.
|
||||
type ClusterBackend interface {
|
||||
Info(context.Context) swarm.Info
|
||||
}
|
||||
|
||||
// BuildBackend provides build specific system information.
|
||||
type BuildBackend interface {
|
||||
DiskUsage(context.Context) ([]*build.CacheRecord, error)
|
||||
Info() swarm.Info
|
||||
}
|
||||
|
||||
// StatusProvider provides methods to get the swarm status of the current node.
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.23
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/docker/docker/api/types/system"
|
||||
)
|
||||
|
||||
// infoResponse is a wrapper around [system.Info] with a custom
|
||||
// marshal function for legacy fields.
|
||||
type infoResponse struct {
|
||||
*system.Info
|
||||
|
||||
// extraFields is for internal use to include deprecated fields on older API versions.
|
||||
extraFields map[string]any
|
||||
}
|
||||
|
||||
// MarshalJSON implements a custom marshaler to include legacy fields
|
||||
// in API responses.
|
||||
func (sc *infoResponse) MarshalJSON() ([]byte, error) {
|
||||
type tmp *system.Info
|
||||
base, err := json.Marshal((tmp)(sc.Info))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(sc.extraFields) == 0 {
|
||||
return base, nil
|
||||
}
|
||||
var merged map[string]any
|
||||
_ = json.Unmarshal(base, &merged)
|
||||
|
||||
for k, v := range sc.extraFields {
|
||||
merged[k] = v
|
||||
}
|
||||
return json.Marshal(merged)
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/system"
|
||||
)
|
||||
|
||||
func TestLegacyFields(t *testing.T) {
|
||||
infoResp := &infoResponse{
|
||||
Info: &system.Info{
|
||||
Containers: 10,
|
||||
},
|
||||
extraFields: map[string]any{
|
||||
"LegacyFoo": false,
|
||||
"LegacyBar": true,
|
||||
},
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(infoResp, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := `"LegacyFoo": false`; !strings.Contains(string(data), expected) {
|
||||
t.Errorf("legacy fields should contain %s: %s", expected, string(data))
|
||||
}
|
||||
if expected := `"LegacyBar": true`; !strings.Contains(string(data), expected) {
|
||||
t.Errorf("legacy fields should contain %s: %s", expected, string(data))
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.23
|
||||
//go:build go1.19
|
||||
|
||||
package system // import "github.com/docker/docker/api/server/router/system"
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"resenje.org/singleflight"
|
||||
buildkit "github.com/docker/docker/builder/builder-next"
|
||||
)
|
||||
|
||||
// systemRouter provides information about the Docker system overall.
|
||||
@@ -14,17 +14,12 @@ type systemRouter struct {
|
||||
backend Backend
|
||||
cluster ClusterBackend
|
||||
routes []router.Route
|
||||
builder BuildBackend
|
||||
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, *infoResponse]
|
||||
builder *buildkit.Builder
|
||||
features *map[string]bool
|
||||
}
|
||||
|
||||
// NewRouter initializes a new system router
|
||||
func NewRouter(b Backend, c ClusterBackend, builder BuildBackend, features func() map[string]bool) router.Router {
|
||||
func NewRouter(b Backend, c ClusterBackend, builder *buildkit.Builder, features *map[string]bool) router.Router {
|
||||
r := &systemRouter{
|
||||
backend: b,
|
||||
cluster: c,
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.23
|
||||
|
||||
package system // import "github.com/docker/docker/api/server/router/system"
|
||||
|
||||
import (
|
||||
@@ -10,20 +7,18 @@ 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"
|
||||
buildtypes "github.com/docker/docker/api/types/build"
|
||||
"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"
|
||||
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"
|
||||
)
|
||||
|
||||
@@ -36,7 +31,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))
|
||||
}
|
||||
@@ -62,93 +57,51 @@ 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)
|
||||
info, _, _ := s.collectSystemInfo.Do(ctx, version, func(ctx context.Context) (*infoResponse, error) {
|
||||
info, err := s.backend.SystemInfo(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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if s.cluster != nil {
|
||||
info.Swarm = s.cluster.Info(ctx)
|
||||
info.Warnings = append(info.Warnings, info.Swarm.Warnings...)
|
||||
for _, s := range kvSecOpts {
|
||||
nameOnlySecurityOptions = append(nameOnlySecurityOptions, s.Name)
|
||||
}
|
||||
|
||||
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
|
||||
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.39") {
|
||||
if info.KernelVersion == "" {
|
||||
info.KernelVersion = "<unknown>"
|
||||
}
|
||||
if info.OperatingSystem == "" {
|
||||
info.OperatingSystem = "<unknown>"
|
||||
}
|
||||
if info.OperatingSystem == "" {
|
||||
info.OperatingSystem = "<unknown>"
|
||||
}
|
||||
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.LessThan(version, "1.46") {
|
||||
// Containerd field introduced in API v1.46.
|
||||
info.Containerd = nil
|
||||
}
|
||||
if versions.LessThan(version, "1.47") {
|
||||
// Field is omitted in API 1.48 and up, but should still be included
|
||||
// in older versions, even if no values are set.
|
||||
info.RegistryConfig.ExtraFields = map[string]any{
|
||||
"AllowNondistributableArtifactsCIDRs": json.RawMessage(nil),
|
||||
"AllowNondistributableArtifactsHostnames": json.RawMessage(nil),
|
||||
}
|
||||
}
|
||||
if versions.LessThan(version, "1.49") {
|
||||
// FirewallBackend field introduced in API v1.49.
|
||||
info.FirewallBackend = nil
|
||||
}
|
||||
|
||||
extraFields := map[string]any{}
|
||||
if versions.LessThan(version, "1.49") {
|
||||
// Expected commits are omitted in API 1.49, but should still be
|
||||
// included in older versions.
|
||||
info.ContainerdCommit.Expected = info.ContainerdCommit.ID //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.49.
|
||||
info.RuncCommit.Expected = info.RuncCommit.ID //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.49.
|
||||
info.InitCommit.Expected = info.InitCommit.ID //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.49.
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
info.KernelMemory = false
|
||||
}
|
||||
if versions.LessThan(version, "1.50") {
|
||||
info.DiscoveredDevices = nil
|
||||
|
||||
// These fields are omitted in > API 1.49, and always false
|
||||
// older API versions.
|
||||
extraFields = map[string]any{
|
||||
"BridgeNfIptables": json.RawMessage("false"),
|
||||
"BridgeNfIp6tables": json.RawMessage("false"),
|
||||
}
|
||||
}
|
||||
return &infoResponse{Info: info, extraFields: extraFields}, nil
|
||||
})
|
||||
|
||||
}
|
||||
if versions.GreaterThanOrEqualTo(version, "1.42") {
|
||||
info.KernelMemory = false
|
||||
}
|
||||
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, err := s.backend.SystemVersion(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info := s.backend.SystemVersion()
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusOK, info)
|
||||
}
|
||||
@@ -183,7 +136,7 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
var systemDiskUsage *system.DiskUsage
|
||||
var systemDiskUsage *types.DiskUsage
|
||||
if getContainers || getImages || getVolumes {
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
@@ -196,7 +149,7 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
|
||||
})
|
||||
}
|
||||
|
||||
var buildCache []*buildtypes.CacheRecord
|
||||
var buildCache []*types.BuildCache
|
||||
if getBuildCache {
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
@@ -207,7 +160,7 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
|
||||
if buildCache == nil {
|
||||
// Ensure empty `BuildCache` field is represented as empty JSON array(`[]`)
|
||||
// instead of `null` to be consistent with `Images`, `Containers` etc.
|
||||
buildCache = []*buildtypes.CacheRecord{}
|
||||
buildCache = []*types.BuildCache{}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -232,42 +185,18 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
|
||||
b.Parent = "" //nolint:staticcheck // ignore SA1019 (Parent field is deprecated)
|
||||
}
|
||||
}
|
||||
if versions.LessThan(version, "1.44") && systemDiskUsage != nil && systemDiskUsage.Images != nil {
|
||||
for _, b := range systemDiskUsage.Images.Items {
|
||||
b.VirtualSize = b.Size //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44.
|
||||
}
|
||||
}
|
||||
|
||||
du := system.DiskUsage{}
|
||||
if getBuildCache {
|
||||
du.BuildCache = &buildtypes.CacheDiskUsage{
|
||||
TotalSize: builderSize,
|
||||
Items: buildCache,
|
||||
}
|
||||
du := types.DiskUsage{
|
||||
BuildCache: buildCache,
|
||||
BuilderSize: builderSize,
|
||||
}
|
||||
if systemDiskUsage != nil {
|
||||
du.LayersSize = systemDiskUsage.LayersSize
|
||||
du.Images = systemDiskUsage.Images
|
||||
du.Containers = systemDiskUsage.Containers
|
||||
du.Volumes = systemDiskUsage.Volumes
|
||||
}
|
||||
|
||||
// Use the old struct for the API return value.
|
||||
var v types.DiskUsage
|
||||
if du.Images != nil {
|
||||
v.LayersSize = du.Images.TotalSize
|
||||
v.Images = du.Images.Items
|
||||
}
|
||||
if du.Containers != nil {
|
||||
v.Containers = du.Containers.Items
|
||||
}
|
||||
if du.Volumes != nil {
|
||||
v.Volumes = du.Volumes.Items
|
||||
}
|
||||
if du.BuildCache != nil {
|
||||
v.BuildCache = du.BuildCache.Items
|
||||
}
|
||||
v.BuilderSize = builderSize
|
||||
return httputils.WriteJSON(w, http.StatusOK, v)
|
||||
return httputils.WriteJSON(w, http.StatusOK, du)
|
||||
}
|
||||
|
||||
type invalidRequestError struct {
|
||||
@@ -321,7 +250,6 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
output := ioutils.NewWriteFlusher(w)
|
||||
defer output.Close()
|
||||
output.Flush()
|
||||
@@ -331,18 +259,7 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
||||
buffered, l := s.backend.SubscribeToEvents(since, until, ef)
|
||||
defer s.backend.UnsubscribeFromEvents(l)
|
||||
|
||||
shouldSkip := func(ev events.Message) bool { return false }
|
||||
if versions.LessThan(httputils.VersionFromContext(ctx), "1.46") {
|
||||
// Image create events were added in API 1.46
|
||||
shouldSkip = func(ev events.Message) bool {
|
||||
return ev.Type == "image" && ev.Action == "create"
|
||||
}
|
||||
}
|
||||
|
||||
for _, ev := range buffered {
|
||||
if shouldSkip(ev) {
|
||||
continue
|
||||
}
|
||||
if err := enc.Encode(ev); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -357,10 +274,7 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
||||
case ev := <-l:
|
||||
jev, ok := ev.(events.Message)
|
||||
if !ok {
|
||||
log.G(ctx).Warnf("unexpected event message: %q", ev)
|
||||
continue
|
||||
}
|
||||
if shouldSkip(jev) {
|
||||
logrus.Warnf("unexpected event message: %q", ev)
|
||||
continue
|
||||
}
|
||||
if err := enc.Encode(jev); err != nil {
|
||||
@@ -369,7 +283,7 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
|
||||
case <-timeout:
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
log.G(ctx).Debug("Client context cancelled, stop sending events")
|
||||
logrus.Debug("Client context cancelled, stop sending events")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ package volume // import "github.com/docker/docker/api/server/router/volume"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/docker/docker/volume/service/opts"
|
||||
// TODO return types need to be refactored into pkg
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/volume/service/opts"
|
||||
)
|
||||
|
||||
// Backend is the methods that need to be implemented to provide
|
||||
@@ -15,7 +17,7 @@ type Backend interface {
|
||||
Get(ctx context.Context, name string, opts ...opts.GetOption) (*volume.Volume, error)
|
||||
Create(ctx context.Context, name, driverName string, opts ...opts.CreateOption) (*volume.Volume, error)
|
||||
Remove(ctx context.Context, name string, opts ...opts.RemoveOption) error
|
||||
Prune(ctx context.Context, pruneFilters filters.Args) (*volume.PruneReport, error)
|
||||
Prune(ctx context.Context, pruneFilters filters.Args) (*types.VolumesPruneReport, error)
|
||||
}
|
||||
|
||||
// ClusterBackend is the backend used for Swarm Cluster Volumes. Regular
|
||||
|
||||
@@ -20,21 +20,21 @@ func NewRouter(b Backend, cb ClusterBackend) router.Router {
|
||||
}
|
||||
|
||||
// Routes returns the available routes to the volumes controller
|
||||
func (v *volumeRouter) Routes() []router.Route {
|
||||
return v.routes
|
||||
func (r *volumeRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
func (v *volumeRouter) initRoutes() {
|
||||
v.routes = []router.Route{
|
||||
func (r *volumeRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
// GET
|
||||
router.NewGetRoute("/volumes", v.getVolumesList),
|
||||
router.NewGetRoute("/volumes/{name:.*}", v.getVolumeByName),
|
||||
router.NewGetRoute("/volumes", r.getVolumesList),
|
||||
router.NewGetRoute("/volumes/{name:.*}", r.getVolumeByName),
|
||||
// POST
|
||||
router.NewPostRoute("/volumes/create", v.postVolumesCreate),
|
||||
router.NewPostRoute("/volumes/prune", v.postVolumesPrune),
|
||||
router.NewPostRoute("/volumes/create", r.postVolumesCreate),
|
||||
router.NewPostRoute("/volumes/prune", r.postVolumesPrune),
|
||||
// PUT
|
||||
router.NewPutRoute("/volumes/{name:.*}", v.putVolumesUpdate),
|
||||
router.NewPutRoute("/volumes/{name:.*}", r.putVolumesUpdate),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/volumes/{name:.*}", v.deleteVolumes),
|
||||
router.NewDeleteRoute("/volumes/{name:.*}", r.deleteVolumes),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"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"
|
||||
@@ -15,6 +13,7 @@ import (
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/volume/service/opts"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -70,7 +69,7 @@ func (v *volumeRouter) getVolumeByName(ctx context.Context, w http.ResponseWrite
|
||||
// if the volume is not found in the regular volume backend, and the client
|
||||
// is using an API version greater than 1.42 (when cluster volumes were
|
||||
// introduced), then check if Swarm has the volume.
|
||||
if cerrdefs.IsNotFound(err) && versions.GreaterThanOrEqualTo(version, clusterVolumesVersion) && v.cluster.IsManager() {
|
||||
if errdefs.IsNotFound(err) && versions.GreaterThanOrEqualTo(version, clusterVolumesVersion) && v.cluster.IsManager() {
|
||||
swarmVol, err := v.cluster.GetVolume(vars["name"])
|
||||
// if swarm returns an error and that error indicates that swarm is not
|
||||
// initialized, return original NotFound error. Otherwise, we'd return
|
||||
@@ -117,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) {
|
||||
log.G(ctx).Debug("using cluster volume")
|
||||
logrus.Debug("using cluster volume")
|
||||
vol, err = v.cluster.CreateVolume(req)
|
||||
} else {
|
||||
log.G(ctx).Debug("using regular volume")
|
||||
logrus.Debug("using regular volume")
|
||||
vol, err = v.backend.Create(ctx, req.Name, req.Driver, opts.WithCreateOptions(req.DriverOpts), opts.WithCreateLabels(req.Labels))
|
||||
}
|
||||
|
||||
@@ -165,7 +164,7 @@ func (v *volumeRouter) deleteVolumes(ctx context.Context, w http.ResponseWriter,
|
||||
// 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 && !cerrdefs.IsNotFound(err) {
|
||||
if err != nil && !errdefs.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -173,7 +172,7 @@ func (v *volumeRouter) deleteVolumes(ctx context.Context, w http.ResponseWriter,
|
||||
// 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 cerrdefs.IsNotFound(err) || force {
|
||||
if errdefs.IsNotFound(err) || force {
|
||||
version := httputils.VersionFromContext(ctx)
|
||||
if versions.GreaterThanOrEqualTo(version, clusterVolumesVersion) && v.cluster.IsManager() {
|
||||
err = v.cluster.RemoveVolume(vars["name"], force)
|
||||
|
||||
@@ -5,14 +5,13 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
cerrdefs "github.com/containerd/errdefs"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/errdefs"
|
||||
@@ -22,7 +21,7 @@ import (
|
||||
func callGetVolume(v *volumeRouter, name string) (*httptest.ResponseRecorder, error) {
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
vars := map[string]string{"name": name}
|
||||
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/volumes/%s", name), nil)
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("/volumes/%s", name), nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err := v.getVolumeByName(ctx, resp, req, vars)
|
||||
@@ -32,7 +31,7 @@ func callGetVolume(v *volumeRouter, name string) (*httptest.ResponseRecorder, er
|
||||
func callListVolumes(v *volumeRouter) (*httptest.ResponseRecorder, error) {
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
vars := map[string]string{}
|
||||
req := httptest.NewRequest(http.MethodGet, "/volumes", nil)
|
||||
req := httptest.NewRequest("GET", "/volumes", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err := v.getVolumesList(ctx, resp, req, vars)
|
||||
@@ -48,7 +47,7 @@ func TestGetVolumeByNameNotFoundNoSwarm(t *testing.T) {
|
||||
_, err := callGetVolume(v, "notReal")
|
||||
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsNotFound(err))
|
||||
assert.Assert(t, errdefs.IsNotFound(err))
|
||||
}
|
||||
|
||||
func TestGetVolumeByNameNotFoundNotManager(t *testing.T) {
|
||||
@@ -60,7 +59,7 @@ func TestGetVolumeByNameNotFoundNotManager(t *testing.T) {
|
||||
_, err := callGetVolume(v, "notReal")
|
||||
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsNotFound(err))
|
||||
assert.Assert(t, errdefs.IsNotFound(err))
|
||||
}
|
||||
|
||||
func TestGetVolumeByNameNotFound(t *testing.T) {
|
||||
@@ -72,13 +71,14 @@ func TestGetVolumeByNameNotFound(t *testing.T) {
|
||||
_, err := callGetVolume(v, "notReal")
|
||||
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsNotFound(err))
|
||||
assert.Assert(t, errdefs.IsNotFound(err))
|
||||
}
|
||||
|
||||
func TestGetVolumeByNameFoundRegular(t *testing.T) {
|
||||
v := &volumeRouter{
|
||||
backend: &fakeVolumeBackend{
|
||||
volumes: map[string]*volume.Volume{
|
||||
|
||||
"volume1": {
|
||||
Name: "volume1",
|
||||
},
|
||||
@@ -108,7 +108,6 @@ func TestGetVolumeByNameFoundSwarm(t *testing.T) {
|
||||
_, err := callGetVolume(v, "volume1")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestListVolumes(t *testing.T) {
|
||||
v := &volumeRouter{
|
||||
backend: &fakeVolumeBackend{
|
||||
@@ -190,16 +189,17 @@ func TestCreateRegularVolume(t *testing.T) {
|
||||
Driver: "foodriver",
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(volumeCreate)
|
||||
assert.NilError(t, err)
|
||||
buf := bytes.Buffer{}
|
||||
e := json.NewEncoder(&buf)
|
||||
e.Encode(volumeCreate)
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodPost, "/volumes/create", &buf)
|
||||
req := httptest.NewRequest("POST", "/volumes/create", &buf)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
err = v.postVolumesCreate(ctx, resp, req, nil)
|
||||
err := v.postVolumesCreate(ctx, resp, req, nil)
|
||||
|
||||
assert.NilError(t, err)
|
||||
|
||||
respVolume := volume.Volume{}
|
||||
@@ -228,18 +228,18 @@ func TestCreateSwarmVolumeNoSwarm(t *testing.T) {
|
||||
Driver: "someCSI",
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(volumeCreate)
|
||||
assert.NilError(t, err)
|
||||
buf := bytes.Buffer{}
|
||||
json.NewEncoder(&buf).Encode(volumeCreate)
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodPost, "/volumes/create", &buf)
|
||||
req := httptest.NewRequest("POST", "/volumes/create", &buf)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
err = v.postVolumesCreate(ctx, resp, req, nil)
|
||||
err := v.postVolumesCreate(ctx, resp, req, nil)
|
||||
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsUnavailable(err))
|
||||
assert.Assert(t, errdefs.IsUnavailable(err))
|
||||
}
|
||||
|
||||
func TestCreateSwarmVolumeNotManager(t *testing.T) {
|
||||
@@ -257,18 +257,18 @@ func TestCreateSwarmVolumeNotManager(t *testing.T) {
|
||||
Driver: "someCSI",
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(volumeCreate)
|
||||
assert.NilError(t, err)
|
||||
buf := bytes.Buffer{}
|
||||
json.NewEncoder(&buf).Encode(volumeCreate)
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodPost, "/volumes/create", &buf)
|
||||
req := httptest.NewRequest("POST", "/volumes/create", &buf)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
err = v.postVolumesCreate(ctx, resp, req, nil)
|
||||
err := v.postVolumesCreate(ctx, resp, req, nil)
|
||||
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsUnavailable(err))
|
||||
assert.Assert(t, errdefs.IsUnavailable(err))
|
||||
}
|
||||
|
||||
func TestCreateVolumeCluster(t *testing.T) {
|
||||
@@ -289,16 +289,16 @@ func TestCreateVolumeCluster(t *testing.T) {
|
||||
Driver: "someCSI",
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(volumeCreate)
|
||||
assert.NilError(t, err)
|
||||
buf := bytes.Buffer{}
|
||||
json.NewEncoder(&buf).Encode(volumeCreate)
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodPost, "/volumes/create", &buf)
|
||||
req := httptest.NewRequest("POST", "/volumes/create", &buf)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
err = v.postVolumesCreate(ctx, resp, req, nil)
|
||||
err := v.postVolumesCreate(ctx, resp, req, nil)
|
||||
|
||||
assert.NilError(t, err)
|
||||
|
||||
respVolume := volume.Volume{}
|
||||
@@ -336,17 +336,15 @@ func TestUpdateVolume(t *testing.T) {
|
||||
Spec: &volume.ClusterVolumeSpec{},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(volumeUpdate)
|
||||
assert.NilError(t, err)
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
json.NewEncoder(&buf).Encode(volumeUpdate)
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodPost, "/volumes/vol1/update?version=0", &buf)
|
||||
req := httptest.NewRequest("POST", "/volumes/vol1/update?version=0", &buf)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err = v.putVolumesUpdate(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
err := v.putVolumesUpdate(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, c.volumes["vol1"].ClusterVolume.Meta.Version.Index, uint64(1))
|
||||
@@ -365,19 +363,17 @@ func TestUpdateVolumeNoSwarm(t *testing.T) {
|
||||
Spec: &volume.ClusterVolumeSpec{},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(volumeUpdate)
|
||||
assert.NilError(t, err)
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
json.NewEncoder(&buf).Encode(volumeUpdate)
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodPost, "/volumes/vol1/update?version=0", &buf)
|
||||
req := httptest.NewRequest("POST", "/volumes/vol1/update?version=0", &buf)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err = v.putVolumesUpdate(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
err := v.putVolumesUpdate(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsUnavailable(err))
|
||||
assert.Assert(t, errdefs.IsUnavailable(err))
|
||||
}
|
||||
|
||||
func TestUpdateVolumeNotFound(t *testing.T) {
|
||||
@@ -397,19 +393,17 @@ func TestUpdateVolumeNotFound(t *testing.T) {
|
||||
Spec: &volume.ClusterVolumeSpec{},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := json.NewEncoder(&buf).Encode(volumeUpdate)
|
||||
assert.NilError(t, err)
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
json.NewEncoder(&buf).Encode(volumeUpdate)
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodPost, "/volumes/vol1/update?version=0", &buf)
|
||||
req := httptest.NewRequest("POST", "/volumes/vol1/update?version=0", &buf)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err = v.putVolumesUpdate(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
err := v.putVolumesUpdate(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsNotFound(err))
|
||||
assert.Assert(t, errdefs.IsNotFound(err))
|
||||
}
|
||||
|
||||
func TestVolumeRemove(t *testing.T) {
|
||||
@@ -428,7 +422,7 @@ func TestVolumeRemove(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodDelete, "/volumes/vol1", nil)
|
||||
req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
@@ -455,7 +449,7 @@ func TestVolumeRemoveSwarm(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodDelete, "/volumes/vol1", nil)
|
||||
req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
@@ -472,12 +466,12 @@ func TestVolumeRemoveNotFoundNoSwarm(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodDelete, "/volumes/vol1", nil)
|
||||
req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsNotFound(err), err.Error())
|
||||
assert.Assert(t, errdefs.IsNotFound(err), err.Error())
|
||||
}
|
||||
|
||||
func TestVolumeRemoveNotFoundNoManager(t *testing.T) {
|
||||
@@ -489,12 +483,12 @@ func TestVolumeRemoveNotFoundNoManager(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodDelete, "/volumes/vol1", nil)
|
||||
req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsNotFound(err))
|
||||
assert.Assert(t, errdefs.IsNotFound(err))
|
||||
}
|
||||
|
||||
func TestVolumeRemoveFoundNoSwarm(t *testing.T) {
|
||||
@@ -513,7 +507,7 @@ func TestVolumeRemoveFoundNoSwarm(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodDelete, "/volumes/vol1", nil)
|
||||
req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
@@ -536,12 +530,12 @@ func TestVolumeRemoveNoSwarmInUse(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodDelete, "/volumes/inuse", nil)
|
||||
req := httptest.NewRequest("DELETE", "/volumes/inuse", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "inuse"})
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsConflict(err))
|
||||
assert.Assert(t, errdefs.IsConflict(err))
|
||||
}
|
||||
|
||||
func TestVolumeRemoveSwarmForce(t *testing.T) {
|
||||
@@ -564,16 +558,16 @@ func TestVolumeRemoveSwarmForce(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req := httptest.NewRequest(http.MethodDelete, "/volumes/vol1", nil)
|
||||
req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
|
||||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, cerrdefs.IsConflict(err))
|
||||
assert.Assert(t, errdefs.IsConflict(err))
|
||||
|
||||
ctx = context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
|
||||
req = httptest.NewRequest(http.MethodDelete, "/volumes/vol1?force=1", nil)
|
||||
req = httptest.NewRequest("DELETE", "/volumes/vol1?force=1", nil)
|
||||
resp = httptest.NewRecorder()
|
||||
|
||||
err = v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
|
||||
@@ -588,7 +582,7 @@ type fakeVolumeBackend struct {
|
||||
}
|
||||
|
||||
func (b *fakeVolumeBackend) List(_ context.Context, _ filters.Args) ([]*volume.Volume, []string, error) {
|
||||
var volumes []*volume.Volume
|
||||
volumes := []*volume.Volume{}
|
||||
for _, v := range b.volumes {
|
||||
volumes = append(volumes, v)
|
||||
}
|
||||
@@ -642,7 +636,7 @@ func (b *fakeVolumeBackend) Remove(_ context.Context, name string, o ...opts.Rem
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *fakeVolumeBackend) Prune(_ context.Context, _ filters.Args) (*volume.PruneReport, error) {
|
||||
func (b *fakeVolumeBackend) Prune(_ context.Context, _ filters.Args) (*types.VolumesPruneReport, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -678,12 +672,13 @@ func (c *fakeClusterBackend) GetVolume(nameOrID string) (volume.Volume, error) {
|
||||
return volume.Volume{}, errdefs.NotFound(fmt.Errorf("volume %s not found", nameOrID))
|
||||
}
|
||||
|
||||
func (c *fakeClusterBackend) GetVolumes(_ volume.ListOptions) ([]*volume.Volume, error) {
|
||||
func (c *fakeClusterBackend) GetVolumes(options volume.ListOptions) ([]*volume.Volume, error) {
|
||||
if err := c.checkSwarm(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var volumes []*volume.Volume
|
||||
volumes := []*volume.Volume{}
|
||||
|
||||
for _, v := range c.volumes {
|
||||
volumes = append(volumes, v)
|
||||
}
|
||||
|
||||
@@ -4,18 +4,14 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"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/types"
|
||||
"github.com/docker/docker/api/types/versions"
|
||||
"github.com/docker/docker/api/server/router/debug"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/docker/docker/internal/otelutil"
|
||||
"github.com/gorilla/mux"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"go.opentelemetry.io/otel/baggage"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// versionMatcher defines a variable matcher to be parsed by the router
|
||||
@@ -33,8 +29,8 @@ func (s *Server) UseMiddleware(m middleware.Middleware) {
|
||||
s.middlewares = append(s.middlewares, m)
|
||||
}
|
||||
|
||||
func (s *Server) makeHTTPHandler(handler httputils.APIFunc, operation string) http.HandlerFunc {
|
||||
return otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Define the context that we'll pass around to share info
|
||||
// like the docker-request-id.
|
||||
//
|
||||
@@ -45,11 +41,7 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc, operation string) ht
|
||||
|
||||
// use intermediate variable to prevent "should not use basic type
|
||||
// string as key in context.WithValue" golint errors
|
||||
ua := r.Header.Get("User-Agent")
|
||||
ctx := baggage.ContextWithBaggage(context.WithValue(r.Context(), dockerversion.UAStringKey{}, ua), otelutil.MustNewBaggage(
|
||||
otelutil.MustNewMemberRaw(otelutil.TriggerKey, "api"),
|
||||
))
|
||||
|
||||
ctx := context.WithValue(r.Context(), dockerversion.UAStringKey{}, r.Header.Get("User-Agent"))
|
||||
r = r.WithContext(ctx)
|
||||
handlerFunc := s.handlerWithGlobalMiddlewares(handler)
|
||||
|
||||
@@ -60,50 +52,44 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc, operation string) ht
|
||||
|
||||
if err := handlerFunc(ctx, w, r, vars); err != nil {
|
||||
statusCode := httpstatus.FromError(err)
|
||||
if statusCode >= http.StatusInternalServerError {
|
||||
log.G(ctx).Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
|
||||
}
|
||||
// While we no longer support API versions older 1.24 [api.MinSupportedAPIVersion],
|
||||
// a client may try to connect using an older version and expect a plain-text error
|
||||
// instead of a JSON error. This would result in an "API version too old" error
|
||||
// formatted in JSON being printed as-is.
|
||||
//
|
||||
// Let's be nice, and return errors in plain-text to provide a more readable error
|
||||
// to help the user understand the API version they're using is no longer supported.
|
||||
if v := vars["version"]; v != "" && versions.LessThan(v, "1.24") {
|
||||
http.Error(w, err.Error(), statusCode)
|
||||
} else {
|
||||
_ = httputils.WriteJSON(w, statusCode, &types.ErrorResponse{
|
||||
Message: err.Error(),
|
||||
})
|
||||
if statusCode >= 500 {
|
||||
logrus.Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
|
||||
}
|
||||
makeErrorHandler(err)(w, r)
|
||||
}
|
||||
}), operation).ServeHTTP
|
||||
}
|
||||
}
|
||||
|
||||
type pageNotFoundError struct{}
|
||||
|
||||
func (pageNotFoundError) Error() string {
|
||||
return "page not found"
|
||||
}
|
||||
|
||||
func (pageNotFoundError) NotFound() {}
|
||||
|
||||
// CreateMux returns a new mux with all the routers registered.
|
||||
func (s *Server) CreateMux(ctx context.Context, routers ...router.Router) *mux.Router {
|
||||
log.G(ctx).Debug("Registering routers")
|
||||
func (s *Server) CreateMux(routers ...router.Router) *mux.Router {
|
||||
m := mux.NewRouter()
|
||||
|
||||
logrus.Debug("Registering routers")
|
||||
for _, apiRouter := range routers {
|
||||
for _, r := range apiRouter.Routes() {
|
||||
if ctx.Err() != nil {
|
||||
return m
|
||||
}
|
||||
log.G(ctx).WithFields(log.Fields{"method": r.Method(), "path": r.Path()}).Debug("Registering route")
|
||||
f := s.makeHTTPHandler(r.Handler(), r.Method()+" "+r.Path())
|
||||
f := s.makeHTTPHandler(r.Handler())
|
||||
|
||||
logrus.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)
|
||||
}
|
||||
}
|
||||
|
||||
// Setup handlers for undefined paths and methods
|
||||
notFoundHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_ = httputils.WriteJSON(w, http.StatusNotFound, &types.ErrorResponse{
|
||||
Message: "page not found",
|
||||
})
|
||||
})
|
||||
debugRouter := debug.NewRouter()
|
||||
for _, r := range debugRouter.Routes() {
|
||||
f := s.makeHTTPHandler(r.Handler())
|
||||
m.Path("/debug" + r.Path()).Handler(f)
|
||||
}
|
||||
|
||||
notFoundHandler := makeErrorHandler(pageNotFoundError{})
|
||||
m.HandleFunc(versionMatcher+"/{path:.*}", notFoundHandler)
|
||||
m.NotFoundHandler = notFoundHandler
|
||||
m.MethodNotAllowedHandler = notFoundHandler
|
||||
|
||||
@@ -15,11 +15,7 @@ import (
|
||||
func TestMiddlewares(t *testing.T) {
|
||||
srv := &Server{}
|
||||
|
||||
m, err := middleware.NewVersionMiddleware("0.1omega2", api.DefaultVersion, api.MinSupportedAPIVersion)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
srv.UseMiddleware(*m)
|
||||
srv.UseMiddleware(middleware.NewVersionMiddleware("0.1omega2", api.DefaultVersion, api.MinVersion))
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "/containers/json", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
3000
api/swagger.yaml
3000
api/swagger.yaml
File diff suppressed because it is too large
Load Diff
7
api/types/auth.go
Normal file
7
api/types/auth.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package types // import "github.com/docker/docker/api/types"
|
||||
import "github.com/docker/docker/api/types/registry"
|
||||
|
||||
// AuthConfig contains authorization information for connecting to a Registry.
|
||||
//
|
||||
// Deprecated: use github.com/docker/docker/api/types/registry.AuthConfig
|
||||
type AuthConfig = registry.AuthConfig
|
||||
@@ -1,26 +0,0 @@
|
||||
package auxprogress
|
||||
|
||||
import (
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// ManifestPushedInsteadOfIndex is a note that is sent when a manifest is pushed
|
||||
// instead of an index. It is sent when the pushed image is an multi-platform
|
||||
// index, but the whole index couldn't be pushed.
|
||||
type ManifestPushedInsteadOfIndex struct {
|
||||
ManifestPushedInsteadOfIndex bool `json:"manifestPushedInsteadOfIndex"` // Always true
|
||||
|
||||
// OriginalIndex is the descriptor of the original image index.
|
||||
OriginalIndex ocispec.Descriptor `json:"originalIndex"`
|
||||
|
||||
// SelectedManifest is the descriptor of the manifest that was pushed instead.
|
||||
SelectedManifest ocispec.Descriptor `json:"selectedManifest"`
|
||||
}
|
||||
|
||||
// ContentMissing is a note that is sent when push fails because the content is missing.
|
||||
type ContentMissing struct {
|
||||
ContentMissing bool `json:"contentMissing"` // Always true
|
||||
|
||||
// Desc is the descriptor of the root object that was attempted to be pushed.
|
||||
Desc ocispec.Descriptor `json:"desc"`
|
||||
}
|
||||
@@ -5,32 +5,13 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
"github.com/docker/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, cancel func()) (io.ReadCloser, io.Writer, io.Writer, error)
|
||||
GetStreams func(multiplexed bool) (io.ReadCloser, io.Writer, io.Writer, error)
|
||||
UseStdin bool
|
||||
UseStdout bool
|
||||
UseStderr bool
|
||||
@@ -89,22 +70,8 @@ type LogSelector struct {
|
||||
type ContainerStatsConfig struct {
|
||||
Stream bool
|
||||
OneShot bool
|
||||
OutStream func() io.Writer
|
||||
}
|
||||
|
||||
// ContainerInspectOptions defines options for the backend.ContainerInspect
|
||||
// call.
|
||||
type ContainerInspectOptions struct {
|
||||
// Size controls whether to propagate the container's size fields.
|
||||
Size bool
|
||||
}
|
||||
|
||||
// ExecStartConfig holds the options to start container's exec.
|
||||
type ExecStartConfig struct {
|
||||
Stdin io.Reader
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
ConsoleSize *[2]uint `json:",omitempty"`
|
||||
OutStream io.Writer
|
||||
Version string
|
||||
}
|
||||
|
||||
// ExecInspect holds information about a running process started
|
||||
@@ -144,48 +111,14 @@ type CreateImageConfig struct {
|
||||
Changes []string
|
||||
}
|
||||
|
||||
// GetImageOpts holds parameters to retrieve image information
|
||||
// from the backend.
|
||||
type GetImageOpts struct {
|
||||
Platform *ocispec.Platform
|
||||
}
|
||||
|
||||
// ImageInspectOpts holds parameters to inspect an image.
|
||||
type ImageInspectOpts struct {
|
||||
Manifests bool
|
||||
Platform *ocispec.Platform
|
||||
}
|
||||
|
||||
// CommitConfig is the configuration for creating an image as part of a build.
|
||||
type CommitConfig struct {
|
||||
Author string
|
||||
Comment string
|
||||
Config *container.Config // TODO(thaJeztah); change this to [dockerspec.DockerOCIImageConfig]
|
||||
Config *container.Config
|
||||
ContainerConfig *container.Config
|
||||
ContainerID string
|
||||
ContainerMountLabel string
|
||||
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
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package backend // import "github.com/docker/docker/api/types/backend"
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/api/types/build"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
@@ -34,7 +34,7 @@ type ProgressWriter struct {
|
||||
type BuildConfig struct {
|
||||
Source io.ReadCloser
|
||||
ProgressWriter ProgressWriter
|
||||
Options *build.ImageBuildOptions
|
||||
Options *types.ImageBuildOptions
|
||||
}
|
||||
|
||||
// GetImageAndLayerOptions are the options supported by GetImageAndReleasableLayer
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user