mirror of https://github.com/etcd-io/etcd.git
Compare commits
1008 Commits
etcdutl/v3
...
main
Author | SHA1 | Date |
---|---|---|
|
13cda0d741 | |
|
ccf605f918 | |
|
04dc26ca3a | |
|
3ed4fbeb75 | |
|
913de280d4 | |
|
e856c7b856 | |
|
0347848c6e | |
|
33ce465fdf | |
|
cd8bec065e | |
|
1443b31e82 | |
|
ea948875da | |
|
12832786f2 | |
|
c6d9cd4562 | |
|
f072712e29 | |
|
52f8ae1f4f | |
|
1b760a97fa | |
|
67ae7a54b9 | |
|
3783f6498c | |
|
f375b629de | |
|
5f63db7e29 | |
|
58cc32be99 | |
|
c3d5543bb9 | |
|
5f0c21dbe7 | |
|
6680e5aa2f | |
|
eda4371c33 | |
|
1eb4d3cd0a | |
|
251ac2cd7b | |
|
13e3329a9f | |
|
12457c0e8c | |
|
4b1be577a8 | |
|
756fb6a3c4 | |
|
26a2e09445 | |
|
1825eb0ace | |
|
3f7aed4960 | |
|
030ecec42e | |
|
01419ee120 | |
|
0682abca88 | |
|
c2cac612b0 | |
|
472662fee0 | |
|
f44e2755d5 | |
|
4e8cbd70d6 | |
|
d02a151e08 | |
|
61255fcdb2 | |
|
da9555ff88 | |
|
c47eb71ce1 | |
|
ebb0d07894 | |
|
4aeee55d1b | |
|
05f9017cc5 | |
|
f672fb3007 | |
|
f5c2825e40 | |
|
7ef1c753f9 | |
|
0ff58ea379 | |
|
e971b3f643 | |
|
5b8269958f | |
|
bac58a12f0 | |
|
b13121f1c9 | |
|
b5c6379579 | |
|
f8868e8583 | |
|
e2caff5b76 | |
|
58123d5315 | |
|
75e35405f5 | |
|
6b073dae4b | |
|
c515c6acc1 | |
|
0581728bf1 | |
|
e6461fb369 | |
|
0e2a4212ed | |
|
8da0b3e0ab | |
|
cb7e990f2d | |
|
512c3f074d | |
|
ae37aa2db0 | |
|
f79fc2c4d6 | |
|
318563dbde | |
|
d6e8ecc4a2 | |
|
336ce41638 | |
|
7137745866 | |
|
72ad0a304b | |
|
c94441037c | |
|
e0b1765692 | |
|
54f829eb45 | |
|
68b0024f70 | |
|
3dfc777f75 | |
|
c67a543a00 | |
|
df6b790d7c | |
|
a3e477ed48 | |
|
f1079598e0 | |
|
810d69619e | |
|
a1aa3cd63e | |
|
a0524d251b | |
|
aebb3752ae | |
|
daa07a64a7 | |
|
264b049111 | |
|
7971c50dec | |
|
a1a54cdb79 | |
|
5bb0441d96 | |
|
61f2665dd5 | |
|
3aa5d02918 | |
|
daa9d08bb0 | |
|
c6d220b831 | |
|
ea69bcafdb | |
|
6badba8608 | |
|
5dfebd8fda | |
|
0888376fab | |
|
7b9ea29f9a | |
|
05f35c4cc3 | |
|
f76be5f3af | |
|
302f332b4f | |
|
a2e5192544 | |
|
fcfe91a935 | |
|
80b28c66b0 | |
|
042f75812b | |
|
7ae29499eb | |
|
dec5fe49cc | |
|
65d3ee5526 | |
|
1a09432e43 | |
|
10bb5e0372 | |
|
34e3ad26d6 | |
|
fea5029bab | |
|
e061aa27db | |
|
4471a4d001 | |
|
792f763e83 | |
|
2a74015caa | |
|
30ebb3f2be | |
|
baf616a35c | |
|
d354bce059 | |
|
1223406a7b | |
|
e1f9fc4e84 | |
|
cfd17b5060 | |
|
1f0ecf8321 | |
|
f84fb66cbe | |
|
8ff509c137 | |
|
24b5ac7f90 | |
|
045930b783 | |
|
4c46235bb8 | |
|
bf5f9af3ee | |
|
a291faad71 | |
|
fb303a8360 | |
|
a8a97a5d9c | |
|
b8693fb17a | |
|
5af30121bf | |
|
87172a157e | |
|
d058f42ffd | |
|
40f4ea8c48 | |
|
e53bad4fdc | |
|
625333c8bd | |
|
233021b2d7 | |
|
5dde6104e0 | |
|
2f5a091512 | |
|
e8090a2c73 | |
|
2356ac2b8b | |
|
4993175bf2 | |
|
4e3e13eac9 | |
|
798c983dd8 | |
|
ea627c79e2 | |
|
a110ee35b8 | |
|
e3e5a84307 | |
|
02a4c53e59 | |
|
033b9e270d | |
|
3fbf1bbf51 | |
|
61c62abc54 | |
|
075509c848 | |
|
a93551f8b2 | |
|
587388fb3d | |
|
0d66443de9 | |
|
85b7dd4693 | |
|
9671fb369c | |
|
dc7d95e243 | |
|
b883f0dd11 | |
|
f1a6777ec1 | |
|
fe91daaf83 | |
|
e4176d9859 | |
|
f10ebf6f9d | |
|
26c08aab1f | |
|
345f4f895c | |
|
aea7741e19 | |
|
9fb8c3685f | |
|
cf0369e4ad | |
|
44a094a20a | |
|
866bc0717c | |
|
2c311cc948 | |
|
4b9846924e | |
|
a15cd5e0ac | |
|
721ba5bc24 | |
|
2e242a63fb | |
|
046b064728 | |
|
e4bf5e0ba7 | |
|
df8d67ae82 | |
|
361312435e | |
|
763a5fd3c1 | |
|
f35ae20758 | |
|
7a79b05f7d | |
|
9092857864 | |
|
6792656b74 | |
|
eabcedf785 | |
|
39fb26d031 | |
|
3ea0a5e4ff | |
|
0199ccabe0 | |
|
36d8f5465f | |
|
d5537ec250 | |
|
674260e85d | |
|
b51415c3f6 | |
|
b42b5f9d32 | |
|
ab2cb8dcdb | |
|
c9e373db43 | |
|
b013138901 | |
|
d80924d3af | |
|
3773a3b064 | |
|
d744c19762 | |
|
ee6d86f9b3 | |
|
762582c48c | |
|
e08120e696 | |
|
015d7c5704 | |
|
1a2efc3c47 | |
|
973847aa24 | |
|
bc47e77116 | |
|
795cca9bc3 | |
|
084394a17a | |
|
a8c4903b70 | |
|
b3b0fdc513 | |
|
dc7fe2a94e | |
|
9e4c432bb0 | |
|
fd8d737838 | |
|
6f8ef3cc30 | |
|
c6804c8d8c | |
|
cc240d6c08 | |
|
955f94cf65 | |
|
500642c0b6 | |
|
0458e119a7 | |
|
fb7e3f2460 | |
|
3dfa3e3b5a | |
|
2e309c1b2b | |
|
0ae02826d9 | |
|
33a458068d | |
|
32eeee612e | |
|
ae8a57fb76 | |
|
511f795e1b | |
|
4cd8c08e6e | |
|
87a2ed37ab | |
|
2129bbf9e9 | |
|
f4ecf54482 | |
|
eab99c53bf | |
|
86fa2e0991 | |
|
be6e482948 | |
|
745f31c12d | |
|
5dfd6e05a4 | |
|
d4a1798487 | |
|
b64a02a5a5 | |
|
52ce705dc7 | |
|
fba53f1034 | |
|
88d7e777f8 | |
|
e6be3f3723 | |
|
c68e3f4275 | |
|
db4dfbde2b | |
|
d61b803d3b | |
|
4f2ede9638 | |
|
d37ff81bbb | |
|
b6a4e35319 | |
|
9bc99b1634 | |
|
cc29bc0391 | |
|
2e3c87e413 | |
|
dcaddc60c2 | |
|
6aaf32b661 | |
|
f6d6111eca | |
|
3303c356d0 | |
|
8142396ae8 | |
|
40393403a5 | |
|
abf23ea86c | |
|
b11ab1d0cb | |
|
9f5ba66961 | |
|
1e357cfc90 | |
|
1432e63f49 | |
|
bfbf25ca04 | |
|
91d931ad08 | |
|
989dd8e9a9 | |
|
6d60b4c850 | |
|
7847848865 | |
|
a091a6d716 | |
|
85191bd75b | |
|
dc80204eef | |
|
5074f65cb6 | |
|
04e31213b4 | |
|
780aef5f6e | |
|
57c01974ea | |
|
843658f16c | |
|
707bc6fbc0 | |
|
7dd65ecd1c | |
|
3154df0d4d | |
|
b8d1accc7d | |
|
2e455e5680 | |
|
58d65781e8 | |
|
84caef6ac8 | |
|
c58c0bd1c6 | |
|
50e0672184 | |
|
87d3908208 | |
|
df4a65acb7 | |
|
bbe99cecb6 | |
|
3be967f201 | |
|
37209aed8b | |
|
5b11ed4622 | |
|
1934e1126c | |
|
58dadb1f1d | |
|
ea5b6030a6 | |
|
fa7b780498 | |
|
d4f85e58a3 | |
|
93d4e087c7 | |
|
10fbccbd39 | |
|
a756eaf122 | |
|
ab267ab803 | |
|
47ac8bdf22 | |
|
3f9f0745ca | |
|
abab2cdfa8 | |
|
02b4add11d | |
|
d8c3007ca6 | |
|
f89b3ae183 | |
|
66ba3990ab | |
|
4d32b9ab73 | |
|
7e467f7e19 | |
|
2553e66210 | |
|
154995c5ad | |
|
32c7792f48 | |
|
1bd07cd2af | |
|
2e5a835689 | |
|
54ddc02b94 | |
|
ba585ea26c | |
|
22f8d56ca7 | |
|
7c651c43c2 | |
|
a6c57a791b | |
|
90f398fe00 | |
|
0c19ee442c | |
|
f989f2361c | |
|
1fbf7a77c0 | |
|
029f02cf0d | |
|
2aa01b6cc3 | |
|
ba8f9fffb9 | |
|
97b2845f37 | |
|
be1e58af99 | |
|
fe1393cac0 | |
|
6651d64e22 | |
|
9707af3b23 | |
|
142cdbfc5f | |
|
d5b71e7eeb | |
|
fb5b53495b | |
|
7a576bfaab | |
|
d465a15dc3 | |
|
03c0f758ce | |
|
de65862cc2 | |
|
b431e05e5e | |
|
98ab934211 | |
|
3d3fcc6942 | |
|
41d6379e84 | |
|
6bbbca8a21 | |
|
09fb9576cc | |
|
bbb2db6435 | |
|
e97ebb9364 | |
|
b0f4b1c737 | |
|
84ed1cd100 | |
|
edb9abda4c | |
|
9b09800633 | |
|
e6769d7724 | |
|
2d10b4cbb6 | |
|
f23c9d7fd3 | |
|
193189637e | |
|
c272adec29 | |
|
ec416efcc2 | |
|
ecfea37975 | |
|
f598a198e9 | |
|
b6167b7c5d | |
|
b6616c25dc | |
|
b2008781b6 | |
|
020077d520 | |
|
61126b9fd1 | |
|
b5e397922b | |
|
28d6ed75bc | |
|
0a93a28e7a | |
|
76d18dc936 | |
|
c904edc174 | |
|
3f8df6d6b1 | |
|
5e4ae51ed4 | |
|
b039448e2f | |
|
f1a4f10324 | |
|
929ac02dbe | |
|
bfd476f7c3 | |
|
18d30da95c | |
|
74fa9d7d94 | |
|
90722adaa1 | |
|
c84b416f84 | |
|
69f0771c87 | |
|
d4dda0a1c8 | |
|
b3b9e986e0 | |
|
3057ae1160 | |
|
45f4ab7953 | |
|
918e182209 | |
|
0fb9499f8b | |
|
0e40709eac | |
|
ae01ad849a | |
|
c36d8a7d78 | |
|
d8ca9eb39d | |
|
7aa8288130 | |
|
6115db53a8 | |
|
d9651182f7 | |
|
d9f4f8118c | |
|
14e33a817f | |
|
629741db60 | |
|
b7db5568f4 | |
|
9349b23f0f | |
|
225269df69 | |
|
fb5bc004e7 | |
|
823556cfe4 | |
|
96e40b27d2 | |
|
61375682c2 | |
|
7728d8fc8e | |
|
15612bd968 | |
|
ebcfdd0185 | |
|
3a3962442e | |
|
457c2186a6 | |
|
2a225549c8 | |
|
c604bfdf44 | |
|
622a0100d8 | |
|
8859f41bf7 | |
|
c0132db604 | |
|
6e2be32266 | |
|
256bfd25d4 | |
|
6c807b30f2 | |
|
e7b3aa738f | |
|
55ee50089f | |
|
1f7fdc39a6 | |
|
c4f3290322 | |
|
e2fcdeccdb | |
|
0167cb3075 | |
|
c849507a38 | |
|
ed4b331c62 | |
|
27bfe80df3 | |
|
4312b20009 | |
|
0287b75950 | |
|
a119975319 | |
|
a4dc023d65 | |
|
2ba6ba7dcc | |
|
be2c3ca801 | |
|
4119b58e69 | |
|
558e48f155 | |
|
fc0e79492c | |
|
ce21dd5db2 | |
|
882713c4b6 | |
|
4f45c346ba | |
|
f2f647682f | |
|
56254468f2 | |
|
73fdbfe848 | |
|
f19aca6858 | |
|
0b68c64527 | |
|
4800faaf70 | |
|
c675eef4c7 | |
|
a029b090cb | |
|
d68eac5a37 | |
|
d545dfd4e6 | |
|
9410e64a42 | |
|
dbf884e422 | |
|
32c4fbfba7 | |
|
216328bb31 | |
|
4c65b6eb41 | |
|
d1bf06c60d | |
|
47c840533d | |
|
2e99e46f5a | |
|
cb40b4e226 | |
|
be8f09a9dc | |
|
19908558c9 | |
|
1280c5bf73 | |
|
d3478bfcc6 | |
|
afbb3b437c | |
|
e5572b2b6f | |
|
14448c52f5 | |
|
cdc0f9e6d2 | |
|
592c195ae2 | |
|
c47a2916be | |
|
e7dd2aca55 | |
|
08864da0ab | |
|
c6dd1c552f | |
|
9564549df4 | |
|
4ff8b06dab | |
|
8a64f7a810 | |
|
a7d1fd5ca8 | |
|
ff6d645779 | |
|
a460abc7f9 | |
|
61489056d5 | |
|
690f315b9e | |
|
fd0599461e | |
|
d564fb9699 | |
|
4a611b631d | |
|
d40a5946d1 | |
|
a426b0fc9a | |
|
b90252f859 | |
|
b605213c05 | |
|
68230c1482 | |
|
750618c2e3 | |
|
f206a8a579 | |
|
7770640d66 | |
|
a54e7e00c8 | |
|
6becfe6461 | |
|
5e9a6ef1ad | |
|
452f0a1f10 | |
|
ecd8a37e81 | |
|
67dae5b26e | |
|
73f440bf3f | |
|
8f155a3999 | |
|
a87600eeb2 | |
|
0c43c4b868 | |
|
4cdcaa069c | |
|
a7d8b942e2 | |
|
7c4e448717 | |
|
41fd9ad055 | |
|
9be7d684a8 | |
|
67738de788 | |
|
094a4adfd6 | |
|
11452157c1 | |
|
f27a4d5b7f | |
|
d1aae3164a | |
|
92092f19a4 | |
|
dcd9f98f5a | |
|
be23337121 | |
|
6d5eb7b5fc | |
|
3546091fdf | |
|
56bc42a65f | |
|
1399c066e0 | |
|
276839a2e4 | |
|
bbba58b64e | |
|
5363cc6a5c | |
|
7a979db6d1 | |
|
102efd7bd6 | |
|
626e638d77 | |
|
bcf4deee68 | |
|
2044e24503 | |
|
47de6a90fc | |
|
ed9aa56f02 | |
|
207d9f7663 | |
|
0b4b31f346 | |
|
567e9a76cb | |
|
9045ef9122 | |
|
7085d3a1b4 | |
|
7b011cbb2f | |
|
ddd5f68b8e | |
|
c34c6b3c0e | |
|
d794d9a54e | |
|
aac5a97aa7 | |
|
26d212dd36 | |
|
9aae00c0fd | |
|
bce900db12 | |
|
8f69168578 | |
|
358d245a45 | |
|
216ce8f465 | |
|
e4ee974bed | |
|
da989fe183 | |
|
270f6a9522 | |
|
24e0999e4f | |
|
9704426df6 | |
|
3fb4ecd0ba | |
|
5a6ffdc0bb | |
|
cd42de79da | |
|
49767381e8 | |
|
be396789db | |
|
03177c1a3a | |
|
b5ef870433 | |
|
4a8827b1e9 | |
|
80b550f42d | |
|
b6de745906 | |
|
fa80bbda68 | |
|
6e0213be06 | |
|
2ff63aa9e5 | |
|
cd2a292431 | |
|
11809a312e | |
|
297e9d1d58 | |
|
a6b9029d4a | |
|
1158c17d4f | |
|
c3f7b11a86 | |
|
dc310f2d32 | |
|
7530a65c31 | |
|
baa7ed90f5 | |
|
9284ac347d | |
|
aedae3a4fa | |
|
d4b56bdebd | |
|
822b5aad78 | |
|
51954f7e85 | |
|
7a58009841 | |
|
e3a2e1f438 | |
|
94c632c464 | |
|
8e28df0496 | |
|
1cc7eedca4 | |
|
6e1d8153ac | |
|
dbb76f3fcd | |
|
b2f243c59b | |
|
efe7f8158c | |
|
24b9a32c03 | |
|
c70cb53fe7 | |
|
ab2248ae25 | |
|
7f8da618e5 | |
|
158b9e0d46 | |
|
994cebcbbd | |
|
3860239a9b | |
|
15850236b3 | |
|
eae9a91a20 | |
|
1ab5ed13a2 | |
|
4ad65d9d7c | |
|
15e8ec7524 | |
|
29419f7c37 | |
|
7a43280da7 | |
|
07c6977011 | |
|
90e17d8b43 | |
|
965603e2de | |
|
c940bf55bf | |
|
d610b0431b | |
|
f5bc7615ed | |
|
b1e76801e7 | |
|
0a0fde11ac | |
|
c590dd6c58 | |
|
a5834f89bb | |
|
28d10d35c0 | |
|
43a43f3229 | |
|
64cd6b643b | |
|
1ba42cedaa | |
|
8da854dc69 | |
|
8f63a8d6d8 | |
|
28546faaab | |
|
e4fb13d93a | |
|
88bba4d86e | |
|
ef211761b3 | |
|
1a3a5a491e | |
|
a28659010f | |
|
881cce9943 | |
|
021aece959 | |
|
d3f49a1334 | |
|
dd14d92af7 | |
|
e80f3258d4 | |
|
e271b78223 | |
|
2310515a91 | |
|
51e38f43eb | |
|
3cf32c009c | |
|
e70740be45 | |
|
8ca65f523d | |
|
4d698b3dd2 | |
|
c3d7b2a316 | |
|
abf043919b | |
|
a4bbb46b86 | |
|
2876a4ece5 | |
|
9d246198b5 | |
|
799f07bfff | |
|
21a976e9e2 | |
|
da2837c54a | |
|
de5e4a5281 | |
|
cfb58eea7d | |
|
cc90010466 | |
|
6608dfb2a5 | |
|
491199f4f0 | |
|
aa8238f511 | |
|
1fa4e01ad6 | |
|
f5dbde1d19 | |
|
4fec4ca20c | |
|
c6ae58ee8d | |
|
0ee26e9438 | |
|
bf27b54f43 | |
|
035631f511 | |
|
b3bcfe802e | |
|
fa38b54dd5 | |
|
f35125b31f | |
|
6b87e2cb68 | |
|
0392f5470d | |
|
8f933a5b58 | |
|
27ff3ecfc3 | |
|
ca818927c2 | |
|
09f897de4d | |
|
028f107327 | |
|
0a9c51210b | |
|
dd23499144 | |
|
7f51b1bf3b | |
|
638b410173 | |
|
818dec3f2f | |
|
21515e1454 | |
|
061e59aef2 | |
|
5ac6079c80 | |
|
aa2a025f7b | |
|
ca6f942723 | |
|
58086dadeb | |
|
916b5a941e | |
|
0b9d021403 | |
|
4585ee9280 | |
|
ff151eea12 | |
|
03839c99c7 | |
|
be71a86f7f | |
|
59c2581a14 | |
|
08c09be0bb | |
|
ddeaba726c | |
|
4591695bf1 | |
|
4443221dc4 | |
|
8318e06fdf | |
|
84d8924822 | |
|
2d4fd6747b | |
|
833b2c4263 | |
|
b90c5bce98 | |
|
d4db4386a8 | |
|
650232cd64 | |
|
d3cebaec93 | |
|
1c77c1480e | |
|
4b7e512a66 | |
|
a730bbda20 | |
|
5a8fba4660 | |
|
86ab134ed3 | |
|
282cc69b2d | |
|
c5a5afda65 | |
|
3f524812e1 | |
|
0cec47ad42 | |
|
0ad7ea497c | |
|
3a2e497d00 | |
|
e9fcb41983 | |
|
898f33ffac | |
|
0ff4a1a2a2 | |
|
8949669ff8 | |
|
b0958f620a | |
|
3084319165 | |
|
25889c08c1 | |
|
4b76a9d4c6 | |
|
928581eae2 | |
|
5ec2b2cbc6 | |
|
3b66c82934 | |
|
fbaf89bfcf | |
|
d4868711e2 | |
|
dbf444ca96 | |
|
ab98cddd30 | |
|
ad13c0dac1 | |
|
d6416b8773 | |
|
03b253714d | |
|
ba600b25c2 | |
|
aa2472e617 | |
|
7351ab86c0 | |
|
df935aa3b4 | |
|
9f6a829815 | |
|
aac61b5f4f | |
|
37eaafa5a7 | |
|
a203755b3c | |
|
839985d96e | |
|
ccec08989f | |
|
eb7662d6cb | |
|
43bbbbfc0b | |
|
cad737b595 | |
|
b8762ac6ed | |
|
6caa1ecd0b | |
|
c983744ac2 | |
|
eaeea10e7f | |
|
022688bc6d | |
|
1cf63f1899 | |
|
0fbac24b29 | |
|
fe44a4bb81 | |
|
c19290acc7 | |
|
375a71a520 | |
|
c065b833f4 | |
|
924a2e68c8 | |
|
afe2641a46 | |
|
02d62f69a3 | |
|
d1f080129f | |
|
2733667894 | |
|
e2b37cfae8 | |
|
c80e61792e | |
|
2514f03944 | |
|
dedbb5160d | |
|
35d56cce0f | |
|
5c7b322817 | |
|
dc56041835 | |
|
dfb9df419c | |
|
3b9ee9bb2c | |
|
5ee55a69e0 | |
|
d6d6769afb | |
|
26d537b33f | |
|
92f8fa367a | |
|
1db0fc5818 | |
|
baeb60ab82 | |
|
473a5ffa05 | |
|
211f9e52cb | |
|
f4a08f77d4 | |
|
6b76999f51 | |
|
9c7ffc32f0 | |
|
fd4fc82d40 | |
|
ee2f4e0e9b | |
|
e55e55b1bb | |
|
a36e5bdfac | |
|
5e272463f7 | |
|
29878cf735 | |
|
dc45df0cad | |
|
fb53c4a376 | |
|
343b14ba06 | |
|
cd077a806d | |
|
53b88df4a7 | |
|
495176a033 | |
|
dd233b46cd | |
|
4ea0bb6e46 | |
|
bb855eb570 | |
|
2e568f6ff6 | |
|
4aee7f109b | |
|
5eac5996f7 | |
|
3a6b064da3 | |
|
040e5ed65c | |
|
b988791c8e | |
|
2555efddbf | |
|
d05b8b7611 | |
|
b692041b69 | |
|
f07e2ae4ed | |
|
49b4137746 | |
|
40f21b203b | |
|
a2eedb9093 | |
|
5122d43d87 | |
|
d100da7431 | |
|
e31514dc84 | |
|
630fb0a43b | |
|
c571cff478 | |
|
be3eee2597 | |
|
82a3e6fe27 | |
|
c2701197fb | |
|
aedecad09f | |
|
5eeacec087 | |
|
41cc8cd3f7 | |
|
a72780654d | |
|
75742cf025 | |
|
395a03843d | |
|
8b4c2cc11e | |
|
ce5620760b | |
|
a5bef1b837 | |
|
d87cb88d57 | |
|
175f18ee8e | |
|
b92073d1cb | |
|
2717859dab | |
|
6c69b1a709 | |
|
dc6db52c34 | |
|
3e207cfda0 | |
|
a3b17f5ba8 | |
|
05d57531e4 | |
|
6984bbe731 | |
|
5eca42b3cf | |
|
f4c40b7fd0 | |
|
3f20b705fe | |
|
619d949b8d | |
|
4804c48d8b | |
|
ffb6ff9acf | |
|
6635bf633e | |
|
3c916bb258 | |
|
dc09500b8f | |
|
d0dda55867 | |
|
06edd83d28 | |
|
f4e1d0e1bc | |
|
d0b8863552 | |
|
85d90d9dd9 | |
|
890990c32c | |
|
22b5b78530 | |
|
9f1709e015 | |
|
8e4de789e5 | |
|
7e66d3a9fc | |
|
930bf4c41b | |
|
5dea90cc95 | |
|
b88df6ea53 | |
|
f0a1ec501b | |
|
7456d52dab | |
|
31650ab0c8 | |
|
028773129a | |
|
b58e9f522f | |
|
316991e8d1 | |
|
31ff0a9cc8 | |
|
b9ceba8c9f | |
|
5da0dc0091 | |
|
04710062d1 | |
|
7c866508ef | |
|
fa3dca3f41 | |
|
a9b24c6523 | |
|
ceb11b7ce9 | |
|
e69f9c78ac | |
|
bf9d6f588c | |
|
fa9233bbbc | |
|
215ab98a5f | |
|
3d381537cc | |
|
d23b0785c1 | |
|
9fcb5f6ae4 | |
|
e2459c0323 | |
|
65691111dc | |
|
2f15f0859f | |
|
4523ff77c9 | |
|
edfb9b7565 | |
|
7c7f69e35a | |
|
25d8e7fb40 | |
|
f9c68849ab | |
|
4ef3b376b7 | |
|
e99f20a639 | |
|
3e43e4594e | |
|
4ce48cea70 | |
|
b16bd864ef | |
|
ed975c2677 | |
|
3a2cece119 | |
|
a6b3c93cb4 | |
|
5c147c0144 | |
|
9b31bdc7a8 | |
|
ac064e860c | |
|
b9298ed950 | |
|
f5409c4227 | |
|
d42b0434a6 | |
|
a423349c07 | |
|
b1ecb206b4 | |
|
49fbd1ef95 | |
|
d76671ca80 | |
|
6ecb6fba34 | |
|
a8d8c1887f | |
|
16b1460b5d | |
|
47e764fd6b | |
|
99683d59ac | |
|
db2213b70a | |
|
66748c0d46 | |
|
3763a67606 | |
|
4a9ab7c380 | |
|
78a7ca618e | |
|
48fcef5b47 | |
|
6784151a1b | |
|
df26009e75 | |
|
5e89197c28 | |
|
f1af8b9e92 | |
|
8e44d3ac65 | |
|
6d66d828b4 | |
|
628435abdb | |
|
c81fb870bb | |
|
498bbc5982 | |
|
43df62f6b9 | |
|
a081904832 | |
|
4cef06bad9 | |
|
d83346bfe7 | |
|
f954f76012 | |
|
022b9b22cf | |
|
d52bd901b4 | |
|
2de17bd396 | |
|
cbc14d78e6 | |
|
ac7d3e9335 | |
|
65159a2b96 | |
|
091b6ed718 | |
|
97c63c9fde | |
|
8ce740cb26 | |
|
1c7f0062fc | |
|
68c2fae46a | |
|
6f86f4fbb0 | |
|
f312736892 | |
|
49f34c9751 | |
|
82c371a471 | |
|
a29b97ab8c | |
|
8575de3bab | |
|
9d57554c4c | |
|
cf6f4fbb94 | |
|
ef65923cf7 | |
|
deb9178089 | |
|
1e3710a90f | |
|
e10f01edfe | |
|
d86775c276 | |
|
e37cdc66c4 | |
|
6f27da2aee | |
|
c0c9f7c344 | |
|
eb7607bd8b | |
|
c86bb08fa9 | |
|
189eb92e3c | |
|
c733872ea3 | |
|
0bbc42a3de | |
|
14cf6694e9 | |
|
5c9db9c840 | |
|
b1e513cfe9 | |
|
8c52b414f3 | |
|
91762ccd4f | |
|
5fa8c1f6b8 | |
|
865ed4a0b6 | |
|
fb2cdc31c7 | |
|
3bd966d6b5 | |
|
de10fd6565 | |
|
075fb1058a | |
|
b77a28cbb5 | |
|
8af64f886c | |
|
9c30af2ff5 | |
|
eea79ca9a5 | |
|
fe81901c74 | |
|
e37615a483 | |
|
7073c4140f | |
|
8b99f8e025 | |
|
dd6791c560 | |
|
1f4b3cdf52 | |
|
7ba8929e7b | |
|
95efe44ae0 | |
|
f30cbaac11 | |
|
57dc6f375a | |
|
c0e7e8c873 | |
|
5414dbab4a | |
|
1709422e21 | |
|
fefce5498f | |
|
0dfc7ab52c | |
|
5703e6b387 | |
|
53d44f0f9c | |
|
5802231328 | |
|
f197f44537 | |
|
b746159a22 | |
|
a9b8cba602 | |
|
1ea4f435cc | |
|
ad3301099a | |
|
fa2926adb0 | |
|
04cce9759b | |
|
b31311ebb0 | |
|
2cffac9916 | |
|
ab88026649 | |
|
2908d45333 | |
|
948a464f16 | |
|
e499f01400 | |
|
097be8cff3 | |
|
38bb52acd3 | |
|
89dd13f93b | |
|
94758c1760 | |
|
6c866548dc | |
|
7fb484cd8a |
|
@ -3,7 +3,7 @@
|
|||
{
|
||||
"name": "Go",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/go:1.23-bookworm",
|
||||
"image": "mcr.microsoft.com/devcontainers/go:1.24-bookworm",
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
|
||||
|
|
|
@ -10,7 +10,7 @@ body:
|
|||
label: Bug report criteria
|
||||
description: Please confirm this bug report meets the following criteria.
|
||||
options:
|
||||
- label: This bug report is not security related, security issues should be disclosed privately via [etcd maintainers](mailto:etcd-maintainers@googlegroups.com).
|
||||
- label: This bug report is not security related, security issues should be disclosed privately via security@etcd.io.
|
||||
- label: This is not a support request or question, support requests or questions should be raised in the etcd [discussion forums](https://github.com/etcd-io/etcd/discussions).
|
||||
- label: You have read the etcd [bug reporting guidelines](https://github.com/etcd-io/etcd/blob/main/Documentation/contributor-guide/reporting_bugs.md).
|
||||
- label: Existing open issues along with etcd [frequently asked questions](https://etcd.io/docs/latest/faq) have been checked and this is not a duplicate.
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
---
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 90
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 21
|
||||
|
||||
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||
exemptLabels:
|
||||
- "stage/tracked"
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: false
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: stale
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 21 days if no further activity occurs. Thank you for your contributions.
|
||||
# Comment to post when removing the stale label.
|
||||
# unmarkComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Comment to post when closing a stale Issue or Pull Request.
|
||||
# closeComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 30
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
# only: issues
|
||||
|
||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||
# pulls:
|
||||
# daysUntilStale: 30
|
||||
# markComment: >
|
||||
# This pull request has been automatically marked as stale because it has not had
|
||||
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||
# for your contributions.
|
||||
|
||||
# issues:
|
||||
# exemptLabels:
|
||||
# - confirmed
|
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
name: Build and trigger Antithesis exploration
|
||||
|
||||
on:
|
||||
# pull_request:
|
||||
# branches: [main]
|
||||
schedule:
|
||||
- cron: "0 0 * * *" # run every day at midnight
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
test:
|
||||
description: 'Test name'
|
||||
required: false
|
||||
type: string
|
||||
duration:
|
||||
description: 'Duration (exploration hours)'
|
||||
required: true
|
||||
type: int
|
||||
description:
|
||||
description: 'Description (avoid quotes, please!)'
|
||||
required: true
|
||||
type: string
|
||||
etcd_ref:
|
||||
description: 'etcd version to build etcd-server from'
|
||||
required: false
|
||||
type: string
|
||||
email:
|
||||
description: 'Additional email notification recipient (separate with ;)'
|
||||
required: true
|
||||
type: string
|
||||
cfg_node_count:
|
||||
description: 'Number of nodes in the etcd cluster'
|
||||
required: false
|
||||
type: int
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
env:
|
||||
REGISTRY: us-central1-docker.pkg.dev
|
||||
REPOSITORY: molten-verve-216720/linuxfoundation-repository
|
||||
|
||||
jobs:
|
||||
build-and-push-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
environment: Antithesis
|
||||
env:
|
||||
CFG_NODE_COUNT: ${{ inputs.cfg_node_count || 3 }}
|
||||
steps:
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Login to Antithesis Docker Registry
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: _json_key
|
||||
password: ${{ secrets.ANTITHESIS_CONTAINER_REGISTRY_TOKEN }}
|
||||
|
||||
- name: Build and push config image
|
||||
working-directory: ./tests/antithesis
|
||||
run: |
|
||||
make antithesis-build-config-image IMAGE_TAG=${{ inputs.etcd_ref || 'main' }}_${{ github.sha }}
|
||||
export IMAGE="${{ env.REGISTRY }}/${{ env.REPOSITORY }}/etcd-config:${{ inputs.etcd_ref || 'main' }}_${{ github.sha }}"
|
||||
docker tag etcd-config:latest $IMAGE
|
||||
docker push $IMAGE
|
||||
|
||||
- name: Build and push client image
|
||||
working-directory: ./tests/antithesis
|
||||
run: |
|
||||
make antithesis-build-client-docker-image
|
||||
export IMAGE="${{ env.REGISTRY }}/${{ env.REPOSITORY }}/etcd-client:${{ inputs.etcd_ref || 'main' }}_${{ github.sha }}"
|
||||
docker tag etcd-client:latest $IMAGE
|
||||
docker push $IMAGE
|
||||
|
||||
- name: Build and push etcd image
|
||||
working-directory: ./tests/antithesis
|
||||
run: |
|
||||
make antithesis-build-etcd-image REF=${{ inputs.etcd_ref || 'main' }}
|
||||
export IMAGE="${{ env.REGISTRY }}/${{ env.REPOSITORY }}/etcd-server:${{ inputs.etcd_ref || 'main' }}_${{ github.sha }}"
|
||||
docker tag etcd-server:latest $IMAGE
|
||||
docker push $IMAGE
|
||||
|
||||
- name: Run Antithesis Tests
|
||||
uses: antithesishq/antithesis-trigger-action@6c0a27302c0a3cd97d87d40bd6704e673abed4bb # main commit on Mar 13, 2025
|
||||
with:
|
||||
notebook_name: etcd
|
||||
tenant: linuxfoundation
|
||||
username: ${{ secrets.ANTITHESIS_WEBHOOK_USERNAME }}
|
||||
password: ${{ secrets.ANTITHESIS_WEBHOOK_PASSWORD }}
|
||||
github_token: ${{ secrets.GH_PAT }}
|
||||
config_image: us-central1-docker.pkg.dev/molten-verve-216720/linuxfoundation-repository/etcd-config:${{ inputs.etcd_ref || 'main' }}_${{ github.sha }}
|
||||
images: us-central1-docker.pkg.dev/molten-verve-216720/linuxfoundation-repository/etcd-client:${{ inputs.etcd_ref || 'main' }}_${{ github.sha }};us-central1-docker.pkg.dev/molten-verve-216720/linuxfoundation-repository/etcd-server:${{ inputs.etcd_ref || 'main' }}_${{ github.sha }};docker.io/library/ubuntu:latest;us-central1-docker.pkg.dev/molten-verve-216720/linuxfoundation-repository/etcd-config:${{ inputs.etcd_ref || 'main' }}_${{ github.sha }}
|
||||
description: ${{ inputs.description || 'etcd nightly antithesis run' }}
|
||||
email_recipients: ${{ inputs.email || 'siarkowicz@google.com' }}
|
||||
test_name: ${{ inputs.test || 'etcd nightly antithesis run' }}
|
||||
additional_parameters: |-
|
||||
custom.duration = ${{ inputs.duration || 12 }}
|
||||
antithesis.source = ${{ inputs.etcd_ref || 'main' }}
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
name: Verify Antithesis Docker Compose Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'tests/antithesis/**'
|
||||
- '.github/workflows/antithesis-verify.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'tests/antithesis/**'
|
||||
- '.github/workflows/antithesis-verify.yml'
|
||||
|
||||
jobs:
|
||||
test-docker-compose:
|
||||
strategy:
|
||||
matrix:
|
||||
node-count: [1, 3]
|
||||
name: Test ${{ matrix.node-count }}-node cluster
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build etcd-server and etcd-client images
|
||||
run: |
|
||||
make -C tests/antithesis antithesis-build-etcd-image
|
||||
make -C tests/antithesis antithesis-build-client-docker-image CFG_NODE_COUNT=${{ matrix.node-count }}
|
||||
|
||||
- name: Run docker-compose up
|
||||
working-directory: ./tests/antithesis
|
||||
run: |
|
||||
make antithesis-docker-compose-up CFG_NODE_COUNT=${{ matrix.node-count }} &
|
||||
|
||||
- name: Check for healthy cluster
|
||||
working-directory: ./tests/antithesis
|
||||
run: |
|
||||
timeout=120
|
||||
interval=10
|
||||
end_time=$(( $(date +%s) + timeout ))
|
||||
|
||||
while [ $(date +%s) -lt $end_time ]; do
|
||||
# The client container might not be running yet, so ignore errors from docker compose logs
|
||||
if docker compose -f config/docker-compose-${{ matrix.node-count }}-node.yml logs client 2>/dev/null | grep -q "Client \[entrypoint\]: cluster is healthy!"; then
|
||||
echo "Cluster is healthy!"
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting for cluster to become healthy..."
|
||||
sleep $interval
|
||||
done
|
||||
|
||||
echo "Cluster did not become healthy in ${timeout} seconds."
|
||||
docker compose -f config/docker-compose-${{ matrix.node-count }}-node.yml logs
|
||||
exit 1
|
||||
|
||||
- name: Run traffic
|
||||
working-directory: ./tests/antithesis
|
||||
run: make antithesis-run-container-traffic CFG_NODE_COUNT=${{ matrix.node-count }}
|
||||
|
||||
- name: Run validation
|
||||
working-directory: ./tests/antithesis
|
||||
run: make antithesis-run-container-validation CFG_NODE_COUNT=${{ matrix.node-count }}
|
||||
|
||||
- name: Clean up
|
||||
if: always()
|
||||
working-directory: ./tests/antithesis
|
||||
run: make antithesis-clean CFG_NODE_COUNT=${{ matrix.node-count }}
|
|
@ -40,7 +40,7 @@ jobs:
|
|||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
|
||||
uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
with:
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
|
@ -50,6 +50,6 @@ jobs:
|
|||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
|
||||
uses: github/codeql-action/autobuild@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
|
||||
uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
|
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- id: goversion
|
||||
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
|
||||
- uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
|
||||
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: ${{ steps.goversion.outputs.goversion }}
|
||||
- env:
|
||||
|
|
|
@ -28,7 +28,7 @@ jobs:
|
|||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
|
@ -42,7 +42,7 @@ jobs:
|
|||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
|
@ -50,6 +50,6 @@ jobs:
|
|||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
|
||||
uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
name: Mark and close stale issues and PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 #v9.1.0
|
||||
with:
|
||||
days-until-stale: 90
|
||||
days-until-close: 21
|
||||
stale-issue-label: 'stale'
|
||||
stale-pr-label: 'stale'
|
||||
exempt-labels: 'stage/tracked,help wanted'
|
||||
exempt-projects: false
|
||||
exempt-milestones: false
|
||||
exempt-assignees: false
|
||||
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 21 days if no further activity occurs. Thank you for your contributions.'
|
||||
stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed after 21 days if no further activity occurs. Thank you for your contributions.'
|
||||
close-issue-message: ''
|
||||
close-pr-message: ''
|
||||
operations-per-run: 30
|
|
@ -1 +1 @@
|
|||
1.23.11
|
||||
1.24.5
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v2.3.8](https://github.com/etcd-io/etcd/releases/tag/v2.3.8) (2017-02-17)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v2.3.7...v2.3.8).
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.5*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.16](https://github.com/etcd-io/etcd/releases/tag/v3.0.16) (2016-11-13)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.15...v3.0.16) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.4*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.15](https://github.com/etcd-io/etcd/releases/tag/v3.0.15) (2016-11-11)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.14...v3.0.15) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix cancel watch request with wrong range end.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.14](https://github.com/etcd-io/etcd/releases/tag/v3.0.14) (2016-11-04)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.13...v3.0.14) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Added
|
||||
|
||||
- v3 `etcdctl migrate` command now supports `--no-ttl` flag to discard keys on transform.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.13](https://github.com/etcd-io/etcd/releases/tag/v3.0.13) (2016-10-24)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.12...v3.0.13) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.12](https://github.com/etcd-io/etcd/releases/tag/v3.0.12) (2016-10-07)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.11...v3.0.12) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.11](https://github.com/etcd-io/etcd/releases/tag/v3.0.11) (2016-10-07)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.10...v3.0.11) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Added
|
||||
|
||||
- Server returns previous key-value (optional)
|
||||
- `clientv3.WithPrevKV` option
|
||||
- v3 etcdctl `put,watch,del --prev-kv` flag
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.10](https://github.com/etcd-io/etcd/releases/tag/v3.0.10) (2016-09-23)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.9...v3.0.10) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.9](https://github.com/etcd-io/etcd/releases/tag/v3.0.9) (2016-09-15)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.8...v3.0.9) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Added
|
||||
|
||||
- Warn on domain names on listen URLs (v3.2 will reject domain names).
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.8](https://github.com/etcd-io/etcd/releases/tag/v3.0.8) (2016-09-09)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.7...v3.0.8) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Other
|
||||
|
||||
- Allow only IP addresses in listen URLs (domain names are rejected).
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.7](https://github.com/etcd-io/etcd/releases/tag/v3.0.7) (2016-08-31)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.6...v3.0.7) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Other
|
||||
|
||||
- SRV records only allow A records (RFC 2052).
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.6](https://github.com/etcd-io/etcd/releases/tag/v3.0.6) (2016-08-19)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.5...v3.0.6) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.5](https://github.com/etcd-io/etcd/releases/tag/v3.0.5) (2016-08-19)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.4...v3.0.5) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Other
|
||||
|
||||
- SRV records (e.g., infra1.example.com) must match the discovery domain (i.e., example.com) if no custom certificate authority is given.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.4](https://github.com/etcd-io/etcd/releases/tag/v3.0.4) (2016-07-27)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.3...v3.0.4) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Added
|
||||
|
||||
- v2 `etcdctl ls` command now supports `--output=json`.
|
||||
- Add /var/lib/etcd directory to etcd official Docker image.
|
||||
|
||||
### Other
|
||||
|
||||
- v2 auth can now use common name from TLS certificate when `--client-cert-auth` is enabled.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.3*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.3](https://github.com/etcd-io/etcd/releases/tag/v3.0.3) (2016-07-15)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.2...v3.0.3) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Other
|
||||
|
||||
- Revert Dockerfile to use `CMD`, instead of `ENTRYPOINT`, to support `etcdctl` run.
|
||||
- Docker commands for v3.0.2 won't work without specifying executable binary paths.
|
||||
- v3 etcdctl default endpoints are now `127.0.0.1:2379`.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.2*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.2](https://github.com/etcd-io/etcd/releases/tag/v3.0.2) (2016-07-08)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.1...v3.0.2) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Other
|
||||
|
||||
- Dockerfile uses `ENTRYPOINT`, instead of `CMD`, to run etcd without binary path specified.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.2*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.1](https://github.com/etcd-io/etcd/releases/tag/v3.0.1) (2016-07-01)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.0...v3.0.1) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.2*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.0.0](https://github.com/etcd-io/etcd/releases/tag/v3.0.0) (2016-06-30)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v2.3.0...v3.0.0) and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_0/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.6.2*](https://golang.org/doc/devel/release.html#go1.6).
|
||||
|
||||
|
||||
---
|
||||
|
|
@ -0,0 +1,574 @@
|
|||
|
||||
|
||||
Previous change logs can be found at [CHANGELOG-3.0](https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.0.md).
|
||||
|
||||
---
|
||||
|
||||
## [v3.1.21](https://github.com/etcd-io/etcd/releases/tag/v3.1.21) (2019-TBD)
|
||||
|
||||
### etcdctl v3
|
||||
|
||||
- [Strip out insecure endpoints from DNS SRV records when using discovery](https://github.com/etcd-io/etcd/pull/10443) with etcdctl v2
|
||||
- Add [`etcdctl endpoint health --write-out` support](https://github.com/etcd-io/etcd/pull/9540).
|
||||
- Previously, [`etcdctl endpoint health --write-out json` did not work](https://github.com/etcd-io/etcd/issues/9532).
|
||||
- The command output is changed. Previously, if endpoint is unreachable, the command output is
|
||||
"\<endpoint\> is unhealthy: failed to connect: \<error message\>". This change unified the error message, all error types
|
||||
now have the same output "\<endpoint\> is unhealthy: failed to commit proposal: \<error message\>".
|
||||
|
||||
### Metrics, Monitoring
|
||||
|
||||
See [List of metrics](https://github.com/etcd-io/etcd/tree/main/Documentation/metrics) for all metrics per release.
|
||||
|
||||
Note that any `etcd_debugging_*` metrics are experimental and subject to change.
|
||||
|
||||
- Fix bug where [db_compaction_total_duration_milliseconds metric incorrectly measured duration as 0](https://github.com/etcd-io/etcd/pull/10646).
|
||||
|
||||
---
|
||||
|
||||
## [v3.1.20](https://github.com/etcd-io/etcd/releases/tag/v3.1.20) (2018-10-10)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.19...v3.1.20) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Improved
|
||||
|
||||
- Improve ["became inactive" warning log](https://github.com/etcd-io/etcd/pull/10024), which indicates message send to a peer failed.
|
||||
- Improve [read index wait timeout warning log](https://github.com/etcd-io/etcd/pull/10026), which indicates that local node might have slow network.
|
||||
- Add [gRPC interceptor for debugging logs](https://github.com/etcd-io/etcd/pull/9990); enable `etcd --debug` flag to see per-request debug information.
|
||||
- Add [consistency check in snapshot status](https://github.com/etcd-io/etcd/pull/10109). If consistency check on snapshot file fails, `snapshot status` returns `"snapshot file integrity check failed..."` error.
|
||||
|
||||
### Metrics, Monitoring
|
||||
|
||||
See [List of metrics](https://github.com/etcd-io/etcd/tree/main/Documentation/metrics) for all metrics per release.
|
||||
|
||||
Note that any `etcd_debugging_*` metrics are experimental and subject to change.
|
||||
|
||||
- Improve [`etcd_network_peer_round_trip_time_seconds`](https://github.com/etcd-io/etcd/pull/10155) Prometheus metric to track leader heartbeats.
|
||||
- Previously, it only samples the TCP connection for snapshot messages.
|
||||
- Display all registered [gRPC metrics at start](https://github.com/etcd-io/etcd/pull/10034).
|
||||
- Add [`etcd_snap_db_fsync_duration_seconds_count`](https://github.com/etcd-io/etcd/pull/9997) Prometheus metric.
|
||||
- Add [`etcd_snap_db_save_total_duration_seconds_bucket`](https://github.com/etcd-io/etcd/pull/9997) Prometheus metric.
|
||||
- Add [`etcd_network_snapshot_send_success`](https://github.com/etcd-io/etcd/pull/9997) Prometheus metric.
|
||||
- Add [`etcd_network_snapshot_send_failures`](https://github.com/etcd-io/etcd/pull/9997) Prometheus metric.
|
||||
- Add [`etcd_network_snapshot_send_total_duration_seconds`](https://github.com/etcd-io/etcd/pull/9997) Prometheus metric.
|
||||
- Add [`etcd_network_snapshot_receive_success`](https://github.com/etcd-io/etcd/pull/9997) Prometheus metric.
|
||||
- Add [`etcd_network_snapshot_receive_failures`](https://github.com/etcd-io/etcd/pull/9997) Prometheus metric.
|
||||
- Add [`etcd_network_snapshot_receive_total_duration_seconds`](https://github.com/etcd-io/etcd/pull/9997) Prometheus metric.
|
||||
- Add [`etcd_server_id`](https://github.com/etcd-io/etcd/pull/9998) Prometheus metric.
|
||||
- Add [`etcd_server_health_success`](https://github.com/etcd-io/etcd/pull/10156) Prometheus metric.
|
||||
- Add [`etcd_server_health_failures`](https://github.com/etcd-io/etcd/pull/10156) Prometheus metric.
|
||||
- Add [`etcd_server_read_indexes_failed_total`](https://github.com/etcd-io/etcd/pull/10094) Prometheus metric.
|
||||
|
||||
### client v3
|
||||
|
||||
- Fix logic on [release lock key if cancelled](https://github.com/etcd-io/etcd/pull/10153) in `clientv3/concurrency` package.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.7*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.19](https://github.com/etcd-io/etcd/releases/tag/v3.1.19) (2018-07-24)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.18...v3.1.19) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Improved
|
||||
|
||||
- Improve [Raft Read Index timeout warning messages](https://github.com/etcd-io/etcd/pull/9897).
|
||||
|
||||
### Metrics, Monitoring
|
||||
|
||||
See [List of metrics](https://github.com/etcd-io/etcd/tree/main/Documentation/metrics) for all metrics per release.
|
||||
|
||||
Note that any `etcd_debugging_*` metrics are experimental and subject to change.
|
||||
|
||||
- Add [`etcd_server_go_version`](https://github.com/etcd-io/etcd/pull/9957) Prometheus metric.
|
||||
- Add [`etcd_server_slow_read_indexes_total`](https://github.com/etcd-io/etcd/pull/9897) Prometheus metric.
|
||||
- Add [`etcd_server_quota_backend_bytes`](https://github.com/etcd-io/etcd/pull/9820) Prometheus metric.
|
||||
- Use it with `etcd_mvcc_db_total_size_in_bytes` and `etcd_mvcc_db_total_size_in_use_in_bytes`.
|
||||
- `etcd_server_quota_backend_bytes 2.147483648e+09` means current quota size is 2 GB.
|
||||
- `etcd_mvcc_db_total_size_in_bytes 20480` means current physically allocated DB size is 20 KB.
|
||||
- `etcd_mvcc_db_total_size_in_use_in_bytes 16384` means future DB size if defragment operation is complete.
|
||||
- `etcd_mvcc_db_total_size_in_bytes - etcd_mvcc_db_total_size_in_use_in_bytes` is the number of bytes that can be saved on disk with defragment operation.
|
||||
- Add [`etcd_mvcc_db_total_size_in_bytes`](https://github.com/etcd-io/etcd/pull/9819) Prometheus metric.
|
||||
- In addition to [`etcd_debugging_mvcc_db_total_size_in_bytes`](https://github.com/etcd-io/etcd/pull/9819).
|
||||
- Add [`etcd_mvcc_db_total_size_in_use_in_bytes`](https://github.com/etcd-io/etcd/pull/9256) Prometheus metric.
|
||||
- Use it with `etcd_mvcc_db_total_size_in_bytes` and `etcd_mvcc_db_total_size_in_use_in_bytes`.
|
||||
- `etcd_server_quota_backend_bytes 2.147483648e+09` means current quota size is 2 GB.
|
||||
- `etcd_mvcc_db_total_size_in_bytes 20480` means current physically allocated DB size is 20 KB.
|
||||
- `etcd_mvcc_db_total_size_in_use_in_bytes 16384` means future DB size if defragment operation is complete.
|
||||
- `etcd_mvcc_db_total_size_in_bytes - etcd_mvcc_db_total_size_in_use_in_bytes` is the number of bytes that can be saved on disk with defragment operation.
|
||||
|
||||
### client v3
|
||||
|
||||
- Fix [lease keepalive interval updates when response queue is full](https://github.com/etcd-io/etcd/pull/9952).
|
||||
- If `<-chan *clientv3LeaseKeepAliveResponse` from `clientv3.Lease.KeepAlive` was never consumed or channel is full, client was [sending keepalive request every 500ms](https://github.com/etcd-io/etcd/issues/9911) instead of expected rate of every "TTL / 3" duration.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.7*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.18](https://github.com/etcd-io/etcd/releases/tag/v3.1.18) (2018-06-15)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.17...v3.1.18) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Metrics, Monitoring
|
||||
|
||||
See [List of metrics](https://github.com/etcd-io/etcd/tree/main/Documentation/metrics) for all metrics per release.
|
||||
|
||||
Note that any `etcd_debugging_*` metrics are experimental and subject to change.
|
||||
|
||||
- Add [`etcd_server_version`](https://github.com/etcd-io/etcd/pull/8960) Prometheus metric.
|
||||
- To replace [Kubernetes `etcd-version-monitor`](https://github.com/etcd-io/etcd/issues/8948).
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.7*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.17](https://github.com/etcd-io/etcd/releases/tag/v3.1.17) (2018-06-06)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.16...v3.1.17) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix [v3 snapshot recovery](https://github.com/etcd-io/etcd/issues/7628).
|
||||
- A follower receives a leader snapshot to be persisted as a `[SNAPSHOT-INDEX].snap.db` file on disk.
|
||||
- Now, server [ensures that the incoming snapshot be persisted on disk before loading it](https://github.com/etcd-io/etcd/pull/7876).
|
||||
- Otherwise, index mismatch happens and triggers server-side panic (e.g. newer WAL entry with outdated snapshot index).
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.7*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.16](https://github.com/etcd-io/etcd/releases/tag/v3.1.16) (2018-05-31)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.15...v3.1.16) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix [`mvcc` server panic from restore operation](https://github.com/etcd-io/etcd/pull/9775).
|
||||
- Let's assume that a watcher had been requested with a future revision X and sent to node A that became network-partitioned thereafter. Meanwhile, cluster makes progress. Then when the partition gets removed, the leader sends a snapshot to node A. Previously if the snapshot's latest revision is still lower than the watch revision X, **etcd server panicked** during snapshot restore operation.
|
||||
- Now, this server-side panic has been fixed.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.7*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.15](https://github.com/etcd-io/etcd/releases/tag/v3.1.15) (2018-05-09)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.14...v3.1.15) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### etcd server
|
||||
|
||||
- Purge old [`*.snap.db` snapshot files](https://github.com/etcd-io/etcd/pull/7967).
|
||||
- Previously, etcd did not respect `--max-snapshots` flag to purge old `*.snap.db` files.
|
||||
- Now, etcd purges old `*.snap.db` files to keep maximum `--max-snapshots` number of files on disk.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.7*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.14](https://github.com/etcd-io/etcd/releases/tag/v3.1.14) (2018-04-24)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.13...v3.1.14) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Metrics, Monitoring
|
||||
|
||||
See [List of metrics](https://github.com/etcd-io/etcd/tree/main/Documentation/metrics) for all metrics per release.
|
||||
|
||||
Note that any `etcd_debugging_*` metrics are experimental and subject to change.
|
||||
|
||||
- Add [`etcd_server_is_leader`](https://github.com/etcd-io/etcd/pull/9587) Prometheus metric.
|
||||
|
||||
### etcd server
|
||||
|
||||
- Add [`--initial-election-tick-advance`](https://github.com/etcd-io/etcd/pull/9591) flag to configure initial election tick fast-forward.
|
||||
- By default, `--initial-election-tick-advance=true`, then local member fast-forwards election ticks to speed up "initial" leader election trigger.
|
||||
- This benefits the case of larger election ticks. For instance, cross datacenter deployment may require longer election timeout of 10-second. If true, local node does not need wait up to 10-second. Instead, forwards its election ticks to 8-second, and have only 2-second left before leader election.
|
||||
- Major assumptions are that: cluster has no active leader thus advancing ticks enables faster leader election. Or cluster already has an established leader, and rejoining follower is likely to receive heartbeats from the leader after tick advance and before election timeout.
|
||||
- However, when network from leader to rejoining follower is congested, and the follower does not receive leader heartbeat within left election ticks, disruptive election has to happen thus affecting cluster availabilities.
|
||||
- Now, this can be disabled by setting `--initial-election-tick-advance=false`.
|
||||
- Disabling this would slow down initial bootstrap process for cross datacenter deployments. Make tradeoffs by configuring `--initial-election-tick-advance` at the cost of slow initial bootstrap.
|
||||
- If single-node, it advances ticks regardless.
|
||||
- Address [disruptive rejoining follower node](https://github.com/etcd-io/etcd/issues/9333).
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.7*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.13](https://github.com/etcd-io/etcd/releases/tag/v3.1.13) (2018-03-29)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.12...v3.1.13) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Improved
|
||||
|
||||
- Adjust [election timeout on server restart](https://github.com/etcd-io/etcd/pull/9415) to reduce [disruptive rejoining servers](https://github.com/etcd-io/etcd/issues/9333).
|
||||
- Previously, etcd fast-forwards election ticks on server start, with only one tick left for leader election. This is to speed up start phase, without having to wait until all election ticks elapse. Advancing election ticks is useful for cross datacenter deployments with larger election timeouts. However, it was affecting cluster availability if the last tick elapses before leader contacts the restarted node.
|
||||
- Now, when etcd restarts, it adjusts election ticks with more than one tick left, thus more time for leader to prevent disruptive restart.
|
||||
|
||||
### Metrics, Monitoring
|
||||
|
||||
See [List of metrics](https://github.com/etcd-io/etcd/tree/main/Documentation/metrics) for all metrics per release.
|
||||
|
||||
Note that any `etcd_debugging_*` metrics are experimental and subject to change.
|
||||
|
||||
- Add missing [`etcd_network_peer_sent_failures_total` count](https://github.com/etcd-io/etcd/pull/9437).
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.7*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.12](https://github.com/etcd-io/etcd/releases/tag/v3.1.12) (2018-03-08)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.11...v3.1.12) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix [`mvcc` "unsynced" watcher restore operation](https://github.com/etcd-io/etcd/pull/9297).
|
||||
- "unsynced" watcher is watcher that needs to be in sync with events that have happened.
|
||||
- That is, "unsynced" watcher is the slow watcher that was requested on old revision.
|
||||
- "unsynced" watcher restore operation was not correctly populating its underlying watcher group.
|
||||
- Which possibly causes [missing events from "unsynced" watchers](https://github.com/etcd-io/etcd/issues/9086).
|
||||
- A node gets network partitioned with a watcher on a future revision, and falls behind receiving a leader snapshot after partition gets removed. When applying this snapshot, etcd watch storage moves current synced watchers to unsynced since sync watchers might have become stale during network partition. And reset synced watcher group to restart watcher routines. Previously, there was a bug when moving from synced watcher group to unsynced, thus client would miss events when the watcher was requested to the network-partitioned node.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.7*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.11](https://github.com/etcd-io/etcd/releases/tag/v3.1.11) (2017-11-28)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.10...v3.1.11) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### etcd server
|
||||
|
||||
- [#8411](https://github.com/etcd-io/etcd/issues/8411),[#8806](https://github.com/etcd-io/etcd/pull/8806) backport "mvcc: sending events after restore"
|
||||
- [#8009](https://github.com/etcd-io/etcd/issues/8009),[#8902](https://github.com/etcd-io/etcd/pull/8902) backport coreos/bbolt v1.3.1-coreos.5
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.5*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.10](https://github.com/etcd-io/etcd/releases/tag/v3.1.10) (2017-07-14)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.9...v3.1.10) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Added
|
||||
|
||||
- Tag docker images with minor versions.
|
||||
- e.g. `docker pull quay.io/coreos/etcd:v3.1` to fetch latest v3.1 versions.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.8.3*](https://golang.org/doc/devel/release.html#go1.8).
|
||||
- Fix panic on `net/http.CloseNotify`
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.9](https://github.com/etcd-io/etcd/releases/tag/v3.1.9) (2017-06-09)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.8...v3.1.9) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### etcd server
|
||||
|
||||
- Allow v2 snapshot over 512MB.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.6*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.8](https://github.com/etcd-io/etcd/releases/tag/v3.1.8) (2017-05-19)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.7...v3.1.8) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.5*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.7](https://github.com/etcd-io/etcd/releases/tag/v3.1.7) (2017-04-28)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.6...v3.1.7) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.5*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.6](https://github.com/etcd-io/etcd/releases/tag/v3.1.6) (2017-04-19)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.5...v3.1.6) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fill in Auth API response header.
|
||||
- Remove auth check in Status API.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.5*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.5](https://github.com/etcd-io/etcd/releases/tag/v3.1.5) (2017-03-27)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.4...v3.1.5) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix raft memory leak issue.
|
||||
- Fix Windows file path issues.
|
||||
|
||||
### Other
|
||||
|
||||
- Add `/etc/nsswitch.conf` file to alpine-based Docker image.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.5*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.4](https://github.com/etcd-io/etcd/releases/tag/v3.1.4) (2017-03-22)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.3...v3.1.4) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.5*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.3](https://github.com/etcd-io/etcd/releases/tag/v3.1.3) (2017-03-10)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.2...v3.1.3) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### etcd gateway
|
||||
|
||||
- Fix `etcd gateway` schema handling in DNS discovery.
|
||||
- Fix sd_notify behaviors in `gateway`, `grpc-proxy`.
|
||||
|
||||
### gRPC Proxy
|
||||
|
||||
- Fix sd_notify behaviors in `gateway`, `grpc-proxy`.
|
||||
|
||||
### Other
|
||||
|
||||
- Use machine default host when advertise URLs are default values(`localhost:2379,2380`) AND if listen URL is `0.0.0.0`.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.5*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.2](https://github.com/etcd-io/etcd/releases/tag/v3.1.2) (2017-02-24)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.1...v3.1.2) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### etcd gateway
|
||||
|
||||
- Fix `etcd gateway` with multiple endpoints.
|
||||
|
||||
### Other
|
||||
|
||||
- Use IPv4 default host, by default (when IPv4 and IPv6 are available).
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.5*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.1](https://github.com/etcd-io/etcd/releases/tag/v3.1.1) (2017-02-17)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.1.0...v3.1.1) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.5*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## [v3.1.0](https://github.com/etcd-io/etcd/releases/tag/v3.1.0) (2017-01-20)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.0.0...v3.1.0) and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.1 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_1/).**
|
||||
|
||||
### Improved
|
||||
|
||||
- Faster linearizable reads (implements Raft [read-index](https://github.com/etcd-io/etcd/pull/6212)).
|
||||
- v3 authentication API is now stable.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- Deprecated following gRPC metrics in favor of [go-grpc-prometheus](https://github.com/grpc-ecosystem/go-grpc-prometheus).
|
||||
- `etcd_grpc_requests_total`
|
||||
- `etcd_grpc_requests_failed_total`
|
||||
- `etcd_grpc_active_streams`
|
||||
- `etcd_grpc_unary_requests_duration_seconds`
|
||||
|
||||
### Dependency
|
||||
|
||||
- Upgrade [`github.com/ugorji/go/codec`](https://github.com/ugorji/go) to [**`ugorji/go@9c7f9b7`**](https://github.com/ugorji/go/commit/9c7f9b7a2bc3a520f7c7b30b34b7f85f47fe27b6), and [regenerate v2 `client`](https://github.com/etcd-io/etcd/pull/6945).
|
||||
|
||||
### Security, Authentication
|
||||
|
||||
See [security doc](https://etcd.io/docs/latest/op-guide/security/) for more details.
|
||||
|
||||
- SRV records (e.g., infra1.example.com) must match the discovery domain (i.e., example.com) if no custom certificate authority is given.
|
||||
- `TLSConfig.ServerName` is ignored with user-provided certificates for backwards compatibility; to be deprecated.
|
||||
- For example, `etcd --discovery-srv=example.com` will only authenticate peers/clients when the provided certs have root domain `example.com` as an entry in Subject Alternative Name (SAN) field.
|
||||
|
||||
### etcd server
|
||||
|
||||
- Automatic leadership transfer when leader steps down.
|
||||
- etcd flags
|
||||
- `--strict-reconfig-check` flag is set by default.
|
||||
- Add `--log-output` flag.
|
||||
- Add `--metrics` flag.
|
||||
- etcd uses default route IP if advertise URL is not given.
|
||||
- Cluster rejects removing members if quorum will be lost.
|
||||
- Discovery now has upper limit for waiting on retries.
|
||||
- Warn on binding listeners through domain names; to be deprecated.
|
||||
- v3.0 and v3.1 with `--auto-compaction-retention=10` run periodic compaction on v3 key-value store for every 10-hour.
|
||||
- Compactor only supports periodic compaction.
|
||||
- Compactor records latest revisions every 5-minute, until it reaches the first compaction period (e.g. 10-hour).
|
||||
- In order to retain key-value history of last compaction period, it uses the last revision that was fetched before compaction period, from the revision records that were collected every 5-minute.
|
||||
- When `--auto-compaction-retention=10`, compactor uses revision 100 for compact revision where revision 100 is the latest revision fetched from 10 hours ago.
|
||||
- If compaction succeeds or requested revision has already been compacted, it resets period timer and starts over with new historical revision records (e.g. restart revision collect and compact for the next 10-hour period).
|
||||
- If compaction fails, it retries in 5 minutes.
|
||||
|
||||
### client v3
|
||||
|
||||
- Add `SetEndpoints` method; update endpoints at runtime.
|
||||
- Add `Sync` method; auto-update endpoints at runtime.
|
||||
- Add `Lease TimeToLive` API; fetch lease information.
|
||||
- replace Config.Logger field with global logger.
|
||||
- Get API responses are sorted in ascending order by default.
|
||||
|
||||
### etcdctl v3
|
||||
|
||||
- Add `lease timetolive` command.
|
||||
- Add `--print-value-only` flag to get command.
|
||||
- Add `--dest-prefix` flag to make-mirror command.
|
||||
- `get` command responses are sorted in ascending order by default.
|
||||
|
||||
### gRPC Proxy
|
||||
|
||||
- Experimental gRPC proxy feature.
|
||||
|
||||
### Other
|
||||
|
||||
- `recipes` now conform to sessions defined in `clientv3/concurrency`.
|
||||
- ACI has symlinks to `/usr/local/bin/etcd*`.
|
||||
|
||||
### Go
|
||||
|
||||
- Compile with [*Go 1.7.4*](https://golang.org/doc/devel/release.html#go1.7).
|
||||
|
||||
|
||||
---
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,741 @@
|
|||
|
||||
|
||||
Previous change logs can be found at [CHANGELOG-3.4](https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.4.md).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.23 (TBA)
|
||||
|
||||
---
|
||||
|
||||
## v3.5.22 (2025-07-22)
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix [the compaction pause duration metric is not emitted for every compaction batch](https://github.com/etcd-io/etcd/pull/19771)
|
||||
- Fix [mvcc: avoid double decrement of watcher gauge on close/cancel race](https://github.com/etcd-io/etcd/pull/20066)
|
||||
- Fix [Watch on future revision returns old events or notifications](https://github.com/etcd-io/etcd/pull/20290)
|
||||
- Fix [`--force-new-cluster` can't remove all other members in a corner case](https://github.com/etcd-io/etcd/pull/20339)
|
||||
- Fix [v2store check (IsMetaStoreOnly) returns wrong result even there is no any auth data](https://github.com/etcd-io/etcd/pull/20357)
|
||||
- Improve [help message for --quota-backend-bytes](https://github.com/etcd-io/etcd/pull/20380)
|
||||
|
||||
### Package `clientv3`
|
||||
|
||||
- [Replace `resolver.State.Addresses` with `resolver.State.Endpoint.Addresses`](https://github.com/etcd-io/etcd/pull/19783).
|
||||
- [Deprecated the Metadata field in the Endpoint struct from the client/v3/naming/endpoints package](https://github.com/etcd-io/etcd/pull/19846).
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Compile binaries using [go 1.23.11](https://github.com/etcd-io/etcd/pull/20321)
|
||||
|
||||
---
|
||||
|
||||
## v3.5.21 (2025-03-27)
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Bump [github.com/golang-jwt/jwt/v4 from 4.5.1 to 4.5.2 to address CVE-2025-30204](https://github.com/etcd-io/etcd/pull/19646).
|
||||
- Bump [bump golang.org/x/net from v0.36.0 to v0.38.0 to address CVE-2025-22870 and CVE-2025-22872](https://github.com/etcd-io/etcd/pull/19686).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.20 (2025-03-21)
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix [the learner promotion changes not being persisted into v3store (bbolt)](https://github.com/etcd-io/etcd/pull/19563)
|
||||
- Update [the RLock in Demoted method for read-only access to expiry](https://github.com/etcd-io/etcd/pull/19445)
|
||||
|
||||
### etcdctl
|
||||
|
||||
- Fix [command `etcdctl member promote` doesn't support json output](https://github.com/etcd-io/etcd/pull/19602)
|
||||
|
||||
### etcd grpc-proxy
|
||||
|
||||
- Fix [grpcproxy can get stuck in and endless loop causing high CPU usage](https://github.com/etcd-io/etcd/pull/19562)
|
||||
|
||||
---
|
||||
|
||||
## v3.5.19 (2025-03-05)
|
||||
|
||||
### etcd server
|
||||
- Backport [add learner status check to readyz endpoint](https://github.com/etcd-io/etcd/pull/19280).
|
||||
- Fix [performance regression due to uncertain compaction sleep interval](https://github.com/etcd-io/etcd/pull/19405).
|
||||
|
||||
### `tools/benchmark`
|
||||
- Backport [add mixed read-write performance evaluation scripts](https://github.com/etcd-io/etcd/pull/19275).
|
||||
|
||||
### Dependencies
|
||||
- Compile binaries using [go 1.23.7](https://github.com/etcd-io/etcd/pull/19528).
|
||||
- Bump [golang.org/x/crypto to v0.35.0 to address CVE-2025-22869](https://github.com/etcd-io/etcd/pull/19478).
|
||||
- Bump [golang.org/x/net to v0.36.0 to address CVE-2025-22870](https://github.com/etcd-io/etcd/pull/19530).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.18 (2025-01-24)
|
||||
|
||||
### etcd server
|
||||
- Avoid deadlock in etcd.Close when stopping during bootstrapping, see https://github.com/etcd-io/etcd/pull/19167 and https://github.com/etcd-io/etcd/pull/19258.
|
||||
- [Print warning messages if any of the deprecated v2store related flags is set](https://github.com/etcd-io/etcd/pull/18999)
|
||||
- Fix [missing delete event on watch opened on same revision as compaction request](https://github.com/etcd-io/etcd/pull/19249)
|
||||
|
||||
### Package `clientv3`
|
||||
- Fix [runtime panic that occurs when KeepAlive is called with a Context implemented by an uncomparable type](https://github.com/etcd-io/etcd/pull/18937)
|
||||
|
||||
### etcdutl v3
|
||||
- Add [command `etcdutl check v2store` to offline check whether v2store contains custom content](https://github.com/etcd-io/etcd/pull/19113)
|
||||
|
||||
### etcd grpc-proxy
|
||||
- Add [`tls min/max version to grpc proxy`](https://github.com/etcd-io/etcd/pull/18829) to support setting TLS min and max version.
|
||||
|
||||
### Dependencies
|
||||
- Bump [golang-jwt/jwt to 4.5.1 to address GO-2024-3250](https://github.com/etcd-io/etcd/pull/18899).
|
||||
- Compile binaries using [go 1.22.11](https://github.com/etcd-io/etcd/pull/19211).
|
||||
- Bump [golang.org/x/crypto to 0.32.0 to address CVE-2024-45337](https://github.com/etcd-io/etcd/pull/19154).
|
||||
- Bump [golang.org/x/net to 0.34.0 to address CVE-2024-45338](https://github.com/etcd-io/etcd/pull/19158).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.17 (2024-11-12)
|
||||
|
||||
### etcd server
|
||||
- Fix [watchserver related goroutine leakage](https://github.com/etcd-io/etcd/pull/18784)
|
||||
- Fix [risk of a partial write txn being applied](https://github.com/etcd-io/etcd/pull/18799)
|
||||
- Fix [panicking occurred due to improper error handling during defragmentation](https://github.com/etcd-io/etcd/pull/18842)
|
||||
- Fix [close temp file(s) in case an error happens during defragmentation](https://github.com/etcd-io/etcd/pull/18854)
|
||||
|
||||
### Dependencies
|
||||
- Compile binaries using [go 1.22.9](https://github.com/etcd-io/etcd/pull/18849).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.16 (2024-09-10)
|
||||
|
||||
### etcd server
|
||||
- Fix [performance regression issue caused by the `ensureLeadership` in lease renew](https://github.com/etcd-io/etcd/pull/18439).
|
||||
- [Keep the tombstone during compaction if it happens to be the compaction revision](https://github.com/etcd-io/etcd/pull/18474)
|
||||
- Add [`etcd --experimental-compaction-sleep-interval`](https://github.com/etcd-io/etcd/pull/18514) flag to control the sleep interval between each compaction batch.
|
||||
|
||||
### Dependencies
|
||||
- Compile binaries using [go 1.22.7](https://github.com/etcd-io/etcd/pull/18550).
|
||||
- Upgrade [bbolt to v1.3.11](https://github.com/etcd-io/etcd/pull/18489).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.15 (2024-07-19)
|
||||
|
||||
### etcd server
|
||||
- Fix [add prometheus metric registration for metric `etcd_disk_wal_write_duration_seconds`](https://github.com/etcd-io/etcd/pull/18174).
|
||||
- Add [Support multiple values for allowed client and peer TLS identities](https://github.com/etcd-io/etcd/pull/18160)
|
||||
- Fix [noisy logs from simple auth token expiration by reducing log level to debug](https://github.com/etcd-io/etcd/pull/18245)
|
||||
- [Differentiate the warning message for rejected client and peer connections](https://github.com/etcd-io/etcd/pull/18319)
|
||||
|
||||
### Package clientv3
|
||||
- [Print gRPC metadata in guaranteed order using the official go fmt pkg](https://github.com/etcd-io/etcd/pull/18312).
|
||||
|
||||
### Dependencies
|
||||
- Compile binaries using [go 1.21.12](https://github.com/etcd-io/etcd/pull/18271).
|
||||
- [Fully address CVE-2023-45288 and fix govulncheck CI check](https://github.com/etcd-io/etcd/pull/18170)
|
||||
|
||||
## v3.5.14 (2024-05-29)
|
||||
|
||||
### etcd server
|
||||
- Fix [LeaseTimeToLive returns error if leader changed](https://github.com/etcd-io/etcd/pull/17704).
|
||||
- Add [metrics `etcd_disk_wal_write_duration_seconds`](https://github.com/etcd-io/etcd/pull/17616).
|
||||
- Fix [ignore raft messages if member id mismatch](https://github.com/etcd-io/etcd/pull/17813).
|
||||
- Update [the compaction log when bootstrap](https://github.com/etcd-io/etcd/pull/17830).
|
||||
- Fix [Revision decreasing after panic during compaction](https://github.com/etcd-io/etcd/pull/17865)
|
||||
- Add [`etcd --experimental-stop-grpc-service-on-defrag`](https://github.com/etcd-io/etcd/pull/17914) to enable client failover on defrag.
|
||||
- Add [support for `AllowedCN` and `AllowedHostname` through config file](https://github.com/etcd-io/etcd/pull/18063)
|
||||
|
||||
### etcdutl v3
|
||||
- Add [`--initial-memory-map-size` to `snapshot restore` to avoid memory allocation issues](https://github.com/etcd-io/etcd/pull/17977)
|
||||
|
||||
### Package `clientv3`
|
||||
- Add [requests retry when receiving ErrGPRCNotSupportedForLearner and endpoints > 1](https://github.com/etcd-io/etcd/pull/17641).
|
||||
- Fix [initialization for mu in client context](https://github.com/etcd-io/etcd/pull/17699).
|
||||
|
||||
### Dependencies
|
||||
- Compile binaries using [go 1.21.10](https://github.com/etcd-io/etcd/pull/17980).
|
||||
- Upgrade [bbolt to v1.3.10](https://github.com/etcd-io/etcd/pull/17943).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.13 (2024-03-29)
|
||||
|
||||
### etcd server
|
||||
- Fix leases wrongly revoked by the leader by [ignoring old leader's leases revoking request](https://github.com/etcd-io/etcd/pull/17425).
|
||||
- Fix [no progress notification being sent for watch that doesn't get any events](https://github.com/etcd-io/etcd/pull/17566).
|
||||
- Fix [watch event loss after compaction](https://github.com/etcd-io/etcd/pull/17612).
|
||||
|
||||
### Package `clientv3`
|
||||
- Add [client backoff and retry config options](https://github.com/etcd-io/etcd/pull/17363).
|
||||
- [Ignore SetKeepAlivePeriod errors on OpenBSD](https://github.com/etcd-io/etcd/pull/17387).
|
||||
- [Support unix/unixs socket in client or peer URLs](https://github.com/etcd-io/etcd/pull/15940)
|
||||
|
||||
### gRPC Proxy
|
||||
- Add [three flags (see below) for grpc-proxy](https://github.com/etcd-io/etcd/pull/17447)
|
||||
- `--dial-keepalive-time`
|
||||
- `--dial-keepalive-timeout`
|
||||
- `--permit-without-stream`
|
||||
|
||||
### Dependencies
|
||||
- Upgrade [bbolt to v1.3.9](https://github.com/etcd-io/etcd/pull/17483).
|
||||
- Compile binaries using [go 1.21.8](https://github.com/etcd-io/etcd/pull/17537).
|
||||
- Upgrade [google.golang.org/protobuf to v1.33.0 to address CVE-2024-24786](https://github.com/etcd-io/etcd/pull/17553).
|
||||
- Upgrade github.com/sirupsen/logrus to v1.9.3 to address [PRISMA-2023-0056](https://github.com/etcd-io/etcd/pull/17482).
|
||||
|
||||
### Others
|
||||
- [Make CGO_ENABLED configurable](https://github.com/etcd-io/etcd/pull/17421).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.12 (2024-01-31)
|
||||
|
||||
### etcd server
|
||||
- Fix [not validating database consistent index, and panicking on nil backend](https://github.com/etcd-io/etcd/pull/17151)
|
||||
- Document [`experimental-enable-lease-checkpoint-persist` flag in etcd help](https://github.com/etcd-io/etcd/pull/17190)
|
||||
- Fix [needlessly flocking snapshot files when deleting](https://github.com/etcd-io/etcd/pull/17206)
|
||||
- Add [digest for etcd base image](https://github.com/etcd-io/etcd/pull/17205)
|
||||
- Fix [delete inconsistencies in read buffer](https://github.com/etcd-io/etcd/pull/17230)
|
||||
- Add [mvcc: print backend database size and size in use in compaction logs](https://github.com/etcd-io/etcd/pull/17291)
|
||||
|
||||
### Dependencies
|
||||
- Compile binaries using [go 1.20.13](https://github.com/etcd-io/etcd/pull/17275)
|
||||
- Upgrade [golang.org/x/crypto to v0.17+ to address CVE-2023-48795](https://github.com/etcd-io/etcd/pull/17346)
|
||||
|
||||
## v3.5.11 (2023-12-07)
|
||||
|
||||
### etcd server
|
||||
- Fix distributed tracing by ensuring `--experimental-distributed-tracing-sampling-rate` configuration option is available to [set tracing sample rate](https://github.com/etcd-io/etcd/pull/16951).
|
||||
- Fix [url redirects while checking peer urls during new member addition](https://github.com/etcd-io/etcd/pull/16986)
|
||||
- Add [livez/readyz HTTP endpoints](https://github.com/etcd-io/etcd/pull/17039)
|
||||
|
||||
### Dependencies
|
||||
- Compile binaries using [go 1.20.12](https://github.com/etcd-io/etcd/pull/17077)
|
||||
- Fix [CVE-2023-47108](https://github.com/advisories/GHSA-8pgv-569h-w5rw) by [bumping go.opentelemetry.io/otel to 1.20.0 and go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc to 0.46.0](https://github.com/etcd-io/etcd/pull/16946).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.10 (2023-10-27)
|
||||
|
||||
### etcd server
|
||||
- Fix [`--socket-reuse-port` and `--socket-reuse-address` not able to be set in configuration file](https://github.com/etcd-io/etcd/pull/16435).
|
||||
- Fix [corruption check may get a `ErrCompacted` error when server has just been compacted](https://github.com/etcd-io/etcd/pull/16048)
|
||||
- Improve [Lease put performance for the case that auth is disabled or the user is admin](https://github.com/etcd-io/etcd/pull/16019)
|
||||
- Improve [Skip getting authInfo from incoming context when auth is disabled](https://github.com/etcd-io/etcd/pull/16241)
|
||||
- Fix [Hash and HashKV have duplicated RESTful API](https://github.com/etcd-io/etcd/pull/16490)
|
||||
|
||||
### etcdutl v3
|
||||
- Add [optional --bump-revision and --mark-compacted flag to etcdutl snapshot restore operation](https://github.com/etcd-io/etcd/pull/16165).
|
||||
|
||||
### etcdctl v3
|
||||
- Add [optional --bump-revision and --mark-compacted flag to etcdctl snapshot restore operation](https://github.com/etcd-io/etcd/pull/16165).
|
||||
|
||||
### etcd grpc-proxy
|
||||
- Fix [Memberlist results not updated when proxy node down](https://github.com/etcd-io/etcd/pull/15907).
|
||||
|
||||
### Package `clientv3`
|
||||
- Fix [Multiple endpoints with same prefix got mixed up](https://github.com/etcd-io/etcd/pull/15939)
|
||||
- Fix [Unexpected blocking when barrier waits on a nonexistent key](https://github.com/etcd-io/etcd/pull/16188)
|
||||
- Fix [Reset auth token when failing to authenticate due to auth being disabled](https://github.com/etcd-io/etcd/pull/16241)
|
||||
- Fix [panic in etcd validate secure endpoints](https://github.com/etcd-io/etcd/pull/16565)
|
||||
|
||||
### Dependencies
|
||||
- Compile binaries using [go 1.20.10](https://github.com/etcd-io/etcd/pull/16745).
|
||||
- Upgrade gRPC to 1.58.3 in https://github.com/etcd-io/etcd/pull/16625, https://github.com/etcd-io/etcd/pull/16781 and https://github.com/etcd-io/etcd/pull/16790. Note that gRPC server will reject requests with connection header (refer to https://github.com/grpc/grpc-go/pull/4803).
|
||||
- Upgrade [bbolt to v1.3.8](https://github.com/etcd-io/etcd/pull/16833)
|
||||
|
||||
---
|
||||
|
||||
## v3.5.9 (2023-05-11)
|
||||
|
||||
### etcd server
|
||||
- Fix [LeaseTimeToLive API may return keys to clients which have no read permission on the keys](https://github.com/etcd-io/etcd/pull/15815).
|
||||
|
||||
### Dependencies
|
||||
- Compile binaries using [go 1.19.9](https://github.com/etcd-io/etcd/pull/15822).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.8 (2023-04-13)
|
||||
|
||||
### etcd server
|
||||
- Add [`etcd --tls-min-version --tls-max-version`](https://github.com/etcd-io/etcd/pull/15483) to enable support for TLS 1.3.
|
||||
- Add [`etcd --listen-client-http-urls`](https://github.com/etcd-io/etcd/pull/15589) flag to support separating http server from grpc one, thus giving full immunity to [watch stream starvation under high read load](https://github.com/etcd-io/etcd/issues/15402).
|
||||
- Change [http2 frame scheduler to random algorithm](https://github.com/etcd-io/etcd/pull/15452)
|
||||
- Fix [Watch response traveling back in time when reconnecting member downloads snapshot from the leader](https://github.com/etcd-io/etcd/pull/15515)
|
||||
- Fix [race when starting both secure & insecure gRPC servers on the same address](https://github.com/etcd-io/etcd/pull/15517)
|
||||
- Fix [server/auth: disallow creating empty permission ranges](https://github.com/etcd-io/etcd/pull/15619)
|
||||
- Fix [aligning zap log timestamp resolution to microseconds](https://github.com/etcd-io/etcd/pull/15240). Etcd now uses zap timestamp format: `2006-01-02T15:04:05.999999Z0700` (microsecond instead of milliseconds precision).
|
||||
- Fix [wsproxy did not print log in JSON format](https://github.com/etcd-io/etcd/pull/15661).
|
||||
- Fix [CVE-2021-28235](https://nvd.nist.gov/vuln/detail/CVE-2021-28235) by [clearing password after authenticating the user](https://github.com/etcd-io/etcd/pull/15653).
|
||||
- Fix [etcdserver may panic when parsing a JWT token without username or revision](https://github.com/etcd-io/etcd/pull/15676).
|
||||
- Fix [Requested watcher progress notifications are not synchronised with stream](https://github.com/etcd-io/etcd/pull/15695).
|
||||
|
||||
### Package `netutil`
|
||||
- Fix [consistently format IPv6 addresses for comparison](https://github.com/etcd-io/etcd/pull/15187).
|
||||
|
||||
### Package `clientv3`
|
||||
- Fix [etcd might send duplicated events to watch clients](https://github.com/etcd-io/etcd/pull/15274).
|
||||
|
||||
### Dependencies
|
||||
- Recommend [Go 1.19+](https://github.com/etcd-io/etcd/pull/15337).
|
||||
- Compile binaries using [go to 1.19.8](https://github.com/etcd-io/etcd/pull/15651)
|
||||
- Upgrade [golang.org/x/net to v0.7.0](https://github.com/etcd-io/etcd/pull/15337)
|
||||
- Upgrade [bbolt to v1.3.7](https://github.com/etcd-io/etcd/pull/15222).
|
||||
|
||||
### Docker image
|
||||
- [Remove nsswitch.conf from docker image](https://github.com/etcd-io/etcd/pull/15161)
|
||||
- Fix [etcd docker images all tagged with amd64 architecture](https://github.com/etcd-io/etcd/pull/15612)
|
||||
|
||||
---
|
||||
|
||||
## v3.5.7 (2023-01-20)
|
||||
|
||||
### etcd server
|
||||
- Fix [Remove memberID from data corrupt alarm](https://github.com/etcd-io/etcd/pull/14852).
|
||||
- Fix [Allow non mutating requests pass through quotaKVServer when NOSPACE](https://github.com/etcd-io/etcd/pull/14884).
|
||||
- Fix [nil pointer panic for readonly txn due to nil response](https://github.com/etcd-io/etcd/pull/14899).
|
||||
- Fix [The last record which was partially synced to disk isn't automatically repaired](https://github.com/etcd-io/etcd/pull/15069).
|
||||
- Fix [etcdserver might promote a non-started learner](https://github.com/etcd-io/etcd/pull/15096).
|
||||
|
||||
### Package `clientv3`
|
||||
- Reverted the fix to [auth invalid token and old revision errors in watch](https://github.com/etcd-io/etcd/pull/14995).
|
||||
|
||||
### Dependencies
|
||||
- Recommend [Go 1.17+](https://github.com/etcd-io/etcd/pull/15019).
|
||||
- Compile binaries using [Go 1.17.13](https://github.com/etcd-io/etcd/pull/15019)
|
||||
- Bumped [some dependencies](https://github.com/etcd-io/etcd/pull/15018) to address some HIGH Vulnerabilities.
|
||||
|
||||
### Docker image
|
||||
- Use [distroless base image](https://github.com/etcd-io/etcd/pull/15016) to address critical Vulnerabilities.
|
||||
- Updated [base image from base-debian11 to static-debian11 and removed dependency on busybox](https://github.com/etcd-io/etcd/pull/15037).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.6 (2022-11-21)
|
||||
|
||||
### etcd server
|
||||
- Fix [auth invalid token and old revision errors in watch](https://github.com/etcd-io/etcd/pull/14547)
|
||||
- Fix [avoid closing a watch with ID 0 incorrectly](https://github.com/etcd-io/etcd/pull/14563)
|
||||
- Fix [auth: fix data consistency issue caused by recovery from snapshot](https://github.com/etcd-io/etcd/pull/14648)
|
||||
- Fix [revision might be inconsistency between members when etcd crashes during processing defragmentation operation](https://github.com/etcd-io/etcd/pull/14733)
|
||||
- Fix [timestamp in inconsistent format](https://github.com/etcd-io/etcd/pull/14799)
|
||||
- Fix [Failed resolving host due to lost DNS record](https://github.com/etcd-io/etcd/pull/14573)
|
||||
|
||||
### Package `clientv3`
|
||||
- Fix [Add backoff before retry when watch stream returns unavailable](https://github.com/etcd-io/etcd/pull/14582).
|
||||
- Fix [stack overflow error in double barrier](https://github.com/etcd-io/etcd/pull/14658)
|
||||
- Fix [Refreshing token on CommonName based authentication causes segmentation violation in client](https://github.com/etcd-io/etcd/pull/14790).
|
||||
|
||||
### etcd grpc-proxy
|
||||
- Add [`etcd grpc-proxy start --listen-cipher-suites`](https://github.com/etcd-io/etcd/pull/14500) flag to support adding configurable cipher list.
|
||||
|
||||
---
|
||||
|
||||
## v3.5.5 (2022-09-15)
|
||||
|
||||
### Deprecations
|
||||
- Deprecated [SetKeepAlive and SetKeepAlivePeriod in limitListenerConn](https://github.com/etcd-io/etcd/pull/14366).
|
||||
|
||||
### Package `clientv3`
|
||||
- Fix [do not overwrite authTokenBundle on dial](https://github.com/etcd-io/etcd/pull/14132).
|
||||
- Fix [IsOptsWithPrefix returns false even if WithPrefix() is included](https://github.com/etcd-io/etcd/pull/14187).
|
||||
|
||||
### etcd server
|
||||
- [Build official darwin/arm64 artifacts](https://github.com/etcd-io/etcd/pull/14436).
|
||||
- Add [`etcd --max-concurrent-streams`](https://github.com/etcd-io/etcd/pull/14219) flag to configure the max concurrent streams each client can open at a time, and defaults to math.MaxUint32.
|
||||
- Add [`etcd --experimental-compact-hash-check-enabled --experimental-compact-hash-check-time`](https://github.com/etcd-io/etcd/issues/14039) flags to support enabling reliable corruption detection on compacted revisions.
|
||||
- Fix [unexpected error during txn](https://github.com/etcd-io/etcd/issues/14110).
|
||||
- Fix [lease leak issue due to tokenProvider isn't enabled when restoring auth store from a snapshot](https://github.com/etcd-io/etcd/pull/13205).
|
||||
- Fix [the race condition between goroutine and channel on the same leases to be revoked](https://github.com/etcd-io/etcd/pull/14087).
|
||||
- Fix [lessor may continue to schedule checkpoint after stepping down leader role](https://github.com/etcd-io/etcd/pull/14087).
|
||||
- Fix [Restrict the max size of each WAL entry to the remaining size of the WAL file](https://github.com/etcd-io/etcd/pull/14127).
|
||||
- Fix [Protect rangePermCache with a RW lock correctly](https://github.com/etcd-io/etcd/pull/14227)
|
||||
- Fix [memberID equals zero in corruption alarm](https://github.com/etcd-io/etcd/pull/14272)
|
||||
- Fix [Durability API guarantee broken in single node cluster](https://github.com/etcd-io/etcd/pull/14424)
|
||||
- Fix [etcd fails to start after performing alarm list operation and then power off/on](https://github.com/etcd-io/etcd/pull/14429)
|
||||
- Fix [authentication data not loaded on member startup](https://github.com/etcd-io/etcd/pull/14409)
|
||||
|
||||
### etcdctl v3
|
||||
|
||||
- Fix [etcdctl move-leader may fail for multiple endpoints](https://github.com/etcd-io/etcd/pull/14434)
|
||||
|
||||
|
||||
### Other
|
||||
- [Bump golang.org/x/crypto to latest version](https://github.com/etcd-io/etcd/pull/13996) to address [CVE-2022-27191](https://github.com/advisories/GHSA-8c26-wmh5-6g9v).
|
||||
- [Bump OpenTelemetry to 1.0.1 and gRPC to 1.41.0](https://github.com/etcd-io/etcd/pull/14312).
|
||||
|
||||
---
|
||||
|
||||
## v3.5.4 (2022-04-24)
|
||||
|
||||
### etcd server
|
||||
- Fix [etcd panic on startup (auth enabled)](https://github.com/etcd-io/etcd/pull/13946)
|
||||
|
||||
### package `client/pkg/v3`
|
||||
|
||||
- [Revert the change of trimming the trailing dot from SRV.Target](https://github.com/etcd-io/etcd/pull/13950) returned by DNS lookup
|
||||
|
||||
|
||||
---
|
||||
|
||||
## v3.5.3 (2022-04-13)
|
||||
|
||||
### etcd server
|
||||
- Fix [Provide a better liveness probe for when etcd runs as a Kubernetes pod](https://github.com/etcd-io/etcd/pull/13706)
|
||||
- Fix [inconsistent log format](https://github.com/etcd-io/etcd/pull/13864)
|
||||
- Fix [Inconsistent revision and data occurs](https://github.com/etcd-io/etcd/pull/13908)
|
||||
- Fix [Etcdserver is still in progress of processing LeaseGrantRequest when it receives a LeaseKeepAliveRequest on the same leaseID](https://github.com/etcd-io/etcd/pull/13932)
|
||||
- Fix [consistent_index coming from snapshot is overwritten by the old local value](https://github.com/etcd-io/etcd/pull/13933)
|
||||
- [Update container base image snapshot](https://github.com/etcd-io/etcd/pull/13862)
|
||||
- Fix [Defrag unsets backend options](https://github.com/etcd-io/etcd/pull/13701).
|
||||
|
||||
### package `client/pkg/v3`
|
||||
|
||||
- [Trim the suffix dot from the target](https://github.com/etcd-io/etcd/pull/13714) in SRV records returned by DNS lookup
|
||||
|
||||
### etcdctl v3
|
||||
|
||||
- [Always print the raft_term in decimal](https://github.com/etcd-io/etcd/pull/13727) when displaying member list in json.
|
||||
|
||||
---
|
||||
|
||||
## [v3.5.2](https://github.com/etcd-io/etcd/releases/tag/v3.5.2) (2022-02-01)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.5.1...v3.5.2) and [v3.5 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_5/) for any breaking changes.
|
||||
|
||||
### etcd server
|
||||
- Fix [exclude the same alarm type activated by multiple peers](https://github.com/etcd-io/etcd/pull/13476).
|
||||
- Add [`etcd --experimental-enable-lease-checkpoint-persist`](https://github.com/etcd-io/etcd/pull/13508) flag to enable checkpoint persisting.
|
||||
- Fix [Lease checkpoints don't prevent to reset ttl on leader change](https://github.com/etcd-io/etcd/pull/13508), requires enabling checkpoint persisting.
|
||||
- Fix [assertion failed due to tx closed when recovering v3 backend from a snapshot db](https://github.com/etcd-io/etcd/pull/13501)
|
||||
- Fix [segmentation violation(SIGSEGV) error due to premature unlocking of watchableStore](https://github.com/etcd-io/etcd/pull/13541)
|
||||
|
||||
---
|
||||
|
||||
## [v3.5.1](https://github.com/etcd-io/etcd/releases/tag/v3.5.1) (2021-10-15)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0...v3.5.1) and [v3.5 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_5/) for any breaking changes.
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix [self-signed-cert-validity parameter cannot be specified in the config file](https://github.com/etcd-io/etcd/pull/13237).
|
||||
- Fix [ensure that cluster members stored in v2store and backend are in sync](https://github.com/etcd-io/etcd/pull/13348)
|
||||
|
||||
### etcd client
|
||||
|
||||
- [Fix etcd client sends invalid :authority header](https://github.com/etcd-io/etcd/issues/13192)
|
||||
|
||||
### package clientv3
|
||||
|
||||
- Endpoints self identify now as `etcd-endpoints://{id}/{authority}` where authority is based on first endpoint passed, for example `etcd-endpoints://0xc0009d8540/localhost:2079`
|
||||
|
||||
### Other
|
||||
|
||||
- Updated [base image](https://github.com/etcd-io/etcd/pull/13386) from `debian:buster-v1.4.0` to `debian:bullseye-20210927` to fix the following critical CVEs:
|
||||
- [CVE-2021-3711](https://nvd.nist.gov/vuln/detail/CVE-2021-3711): miscalculation of a buffer size in openssl's SM2 decryption
|
||||
- [CVE-2021-35942](https://nvd.nist.gov/vuln/detail/CVE-2021-35942): integer overflow flaw in glibc
|
||||
- [CVE-2019-9893](https://nvd.nist.gov/vuln/detail/CVE-2019-9893): incorrect syscall argument generation in libseccomp
|
||||
- [CVE-2021-36159](https://nvd.nist.gov/vuln/detail/CVE-2021-36159): libfetch in apk-tools mishandles numeric strings in FTP and HTTP protocols to allow out of bound reads.
|
||||
|
||||
---
|
||||
|
||||
## v3.5.0 (2021-06)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.4.0...v3.5.0) and [v3.5 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_5/) for any breaking changes.
|
||||
|
||||
- [v3.5.0](https://github.com/etcd-io/etcd/releases/tag/v3.5.0) (2021 TBD), see [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0-rc.1...v3.5.0).
|
||||
- [v3.5.0-rc.1](https://github.com/etcd-io/etcd/releases/tag/v3.5.0-rc.1) (2021-06-10), see [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0-rc.0...v3.5.0-rc.1).
|
||||
- [v3.5.0-rc.0](https://github.com/etcd-io/etcd/releases/tag/v3.5.0-rc.0) (2021-06-04), see [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0-beta.4...v3.5.0-rc.0).
|
||||
- [v3.5.0-beta.4](https://github.com/etcd-io/etcd/releases/tag/v3.5.0-beta.4) (2021-05-26), see [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0-beta.3...v3.5.0-beta.4).
|
||||
- [v3.5.0-beta.3](https://github.com/etcd-io/etcd/releases/tag/v3.5.0-beta.3) (2021-05-18), see [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0-beta.2...v3.5.0-beta.3).
|
||||
- [v3.5.0-beta.2](https://github.com/etcd-io/etcd/releases/tag/v3.5.0-beta.2) (2021-05-18), see [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0-beta.1...v3.5.0-beta.2).
|
||||
- [v3.5.0-beta.1](https://github.com/etcd-io/etcd/releases/tag/v3.5.0-beta.1) (2021-05-18), see [code changes](https://github.com/etcd-io/etcd/compare/v3.4.0...v3.5.0-beta.1).
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v3.5 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_3_5/).**
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `go.etcd.io/etcd` Go packages have moved to `go.etcd.io/etcd/{api,pkg,raft,client,etcdctl,server,raft,tests}/v3` to follow the [Go modules](https://github.com/golang/go/wiki/Modules) conventions
|
||||
- `go.etcd.io/clientv3/snapshot` SnapshotManager class have moved to `go.etcd.io/clientv3/etcdctl`.
|
||||
The method `snapshot.Save` to download a snapshot from the remote server was preserved in 'go.etcd.io/clientv3/snapshot`.
|
||||
- `go.etcd.io/client' package got migrated to 'go.etcd.io/client/v2'.
|
||||
- Changed behavior of clientv3 API [MemberList](https://github.com/etcd-io/etcd/pull/11639).
|
||||
- Previously, it is directly served with server's local data, which could be stale.
|
||||
- Now, it is served with linearizable guarantee. If the server is disconnected from quorum, `MemberList` call will fail.
|
||||
- [gRPC gateway](https://github.com/grpc-ecosystem/grpc-gateway) only supports [`/v3`](TODO) endpoint.
|
||||
- Deprecated [`/v3beta`](https://github.com/etcd-io/etcd/pull/9298).
|
||||
- `curl -L http://localhost:2379/v3beta/kv/put -X POST -d '{"key": "Zm9v", "value": "YmFy"}'` doesn't work in v3.5. Use `curl -L http://localhost:2379/v3/kv/put -X POST -d '{"key": "Zm9v", "value": "YmFy"}'` instead.
|
||||
- **`etcd --experimental-enable-v2v3` flag remains experimental and to be deprecated.**
|
||||
- v2 storage emulation feature will be deprecated in the next release.
|
||||
- etcd 3.5 is the last version that supports V2 API. Flags `--enable-v2` and `--experimental-enable-v2v3` [are now deprecated](https://github.com/etcd-io/etcd/pull/12940) and will be removed in etcd v3.6 release.
|
||||
- **`etcd --experimental-backend-bbolt-freelist-type` flag has been deprecated.** Use **`etcd --backend-bbolt-freelist-type`** instead. The default type is hashmap and it is stable now.
|
||||
- **`etcd --debug` flag has been deprecated.** Use **`etcd --log-level=debug`** instead.
|
||||
- Remove [`embed.Config.Debug`](https://github.com/etcd-io/etcd/pull/10947).
|
||||
- **`etcd --log-output` flag has been deprecated.** Use **`etcd --log-outputs`** instead.
|
||||
- **`etcd --logger=zap --log-outputs=stderr`** is now the default.
|
||||
- **`etcd --logger=capnslog` flag value has been deprecated.**
|
||||
- **`etcd --logger=zap --log-outputs=default` flag value is not supported.**.
|
||||
- Use `etcd --logger=zap --log-outputs=stderr`.
|
||||
- Or, use `etcd --logger=zap --log-outputs=systemd/journal` to send logs to the local systemd journal.
|
||||
- Previously, if etcd parent process ID (PPID) is 1 (e.g. run with systemd), `etcd --logger=capnslog --log-outputs=default` redirects server logs to local systemd journal. And if write to journald fails, it writes to `os.Stderr` as a fallback.
|
||||
- However, even with PPID 1, it can fail to dial systemd journal (e.g. run embedded etcd with Docker container). Then, [every single log write will fail](https://github.com/etcd-io/etcd/pull/9729) and fall back to `os.Stderr`, which is inefficient.
|
||||
- To avoid this problem, systemd journal logging must be configured manually.
|
||||
- **`etcd --log-outputs=stderr`** is now the default.
|
||||
- **`etcd --log-package-levels` flag for `capnslog` has been deprecated.** Now, **`etcd --logger=zap --log-outputs=stderr`** is the default.
|
||||
- **`[CLIENT-URL]/config/local/log` endpoint has been deprecated, as is `etcd --log-package-levels` flag.**
|
||||
- `curl http://127.0.0.1:2379/config/local/log -XPUT -d '{"Level":"DEBUG"}'` won't work.
|
||||
- Please use `etcd --logger=zap --log-outputs=stderr` instead.
|
||||
- Deprecated `etcd_debugging_mvcc_db_total_size_in_bytes` Prometheus metric. Use `etcd_mvcc_db_total_size_in_bytes` instead.
|
||||
- Deprecated `etcd_debugging_mvcc_put_total` Prometheus metric. Use `etcd_mvcc_put_total` instead.
|
||||
- Deprecated `etcd_debugging_mvcc_delete_total` Prometheus metric. Use `etcd_mvcc_delete_total` instead.
|
||||
- Deprecated `etcd_debugging_mvcc_txn_total` Prometheus metric. Use `etcd_mvcc_txn_total` instead.
|
||||
- Deprecated `etcd_debugging_mvcc_range_total` Prometheus metric. Use `etcd_mvcc_range_total` instead.
|
||||
- Main branch `/version` outputs `3.5.0-pre`, instead of `3.4.0+git`.
|
||||
- Changed `proxy` package function signature to [support structured logger](https://github.com/etcd-io/etcd/pull/11614).
|
||||
- Previously, `NewClusterProxy(c *clientv3.Client, advaddr string, prefix string) (pb.ClusterServer, <-chan struct{})`, now `NewClusterProxy(lg *zap.Logger, c *clientv3.Client, advaddr string, prefix string) (pb.ClusterServer, <-chan struct{})`.
|
||||
- Previously, `Register(c *clientv3.Client, prefix string, addr string, ttl int)`, now `Register(lg *zap.Logger, c *clientv3.Client, prefix string, addr string, ttl int) <-chan struct{}`.
|
||||
- Previously, `NewHandler(t *http.Transport, urlsFunc GetProxyURLs, failureWait time.Duration, refreshInterval time.Duration) http.Handler`, now `NewHandler(lg *zap.Logger, t *http.Transport, urlsFunc GetProxyURLs, failureWait time.Duration, refreshInterval time.Duration) http.Handler`.
|
||||
- Changed `pkg/flags` function signature to [support structured logger](https://github.com/etcd-io/etcd/pull/11616).
|
||||
- Previously, `SetFlagsFromEnv(prefix string, fs *flag.FlagSet) error`, now `SetFlagsFromEnv(lg *zap.Logger, prefix string, fs *flag.FlagSet) error`.
|
||||
- Previously, `SetPflagsFromEnv(prefix string, fs *pflag.FlagSet) error`, now `SetPflagsFromEnv(lg *zap.Logger, prefix string, fs *pflag.FlagSet) error`.
|
||||
- ClientV3 supports [grpc resolver API](https://github.com/etcd-io/etcd/blob/main/client/v3/naming/resolver/resolver.go).
|
||||
- Endpoints can be managed using [endpoints.Manager](https://github.com/etcd-io/etcd/blob/main/client/v3/naming/endpoints/endpoints.go)
|
||||
- Previously supported [GRPCResolver was decomissioned](https://github.com/etcd-io/etcd/pull/12675). Use [resolver](https://github.com/etcd-io/etcd/blob/main/client/v3/naming/resolver/resolver.go) instead.
|
||||
- Turned on [--pre-vote by default](https://github.com/etcd-io/etcd/pull/12770). Should prevent disrupting RAFT leader by an individual member.
|
||||
- [ETCD_CLIENT_DEBUG env](https://github.com/etcd-io/etcd/pull/12786): Now supports log levels (debug, info, warn, error, dpanic, panic, fatal). Only when set, overrides application-wide grpc logging settings.
|
||||
- [Embed Etcd.Close()](https://github.com/etcd-io/etcd/pull/12828) needs to called exactly once and closes Etcd.Err() stream.
|
||||
- [Embed Etcd does not override global/grpc logger](https://github.com/etcd-io/etcd/pull/12861) be default any longer. If desired, please call `embed.Config::SetupGlobalLoggers()` explicitly.
|
||||
- [Embed Etcd custom logger should be configured using simpler builder `NewZapLoggerBuilder`](https://github.com/etcd-io/etcd/pull/12973).
|
||||
- Client errors of `context cancelled` or `context deadline exceeded` are exposed as `codes.Canceled` and `codes.DeadlineExceeded`, instead of `codes.Unknown`.
|
||||
|
||||
|
||||
### Storage format changes
|
||||
- [WAL log's snapshots persists raftpb.ConfState](https://github.com/etcd-io/etcd/pull/12735)
|
||||
- [Backend persists raftpb.ConfState](https://github.com/etcd-io/etcd/pull/12962) in the `meta` bucket `confState` key.
|
||||
- [Backend persists applied term](https://github.com/etcd-io/etcd/pull/) in the `meta` bucket.
|
||||
- Backend persists `downgrade` in the `cluster` bucket
|
||||
|
||||
### Security
|
||||
|
||||
- Add [`TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256` and `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256` to `etcd --cipher-suites`](https://github.com/etcd-io/etcd/pull/11864).
|
||||
- Changed [the format of WAL entries related to auth for not keeping password as a plain text](https://github.com/etcd-io/etcd/pull/11943).
|
||||
- Add third party [Security Audit Report](https://github.com/etcd-io/etcd/pull/12201).
|
||||
- A [log warning](https://github.com/etcd-io/etcd/pull/12242) is added when etcd uses any existing directory that has a permission different than 700 on Linux and 777 on Windows.
|
||||
- Add optional [`ClientCertFile` and `ClientKeyFile`](https://github.com/etcd-io/etcd/pull/12705) options for peer and client tls configuration when split certificates are used.
|
||||
|
||||
### Metrics, Monitoring
|
||||
|
||||
See [List of metrics](https://etcd.io/docs/latest/metrics/) for all metrics per release.
|
||||
|
||||
Note that any `etcd_debugging_*` metrics are experimental and subject to change.
|
||||
|
||||
- Deprecated `etcd_debugging_mvcc_db_total_size_in_bytes` Prometheus metric. Use `etcd_mvcc_db_total_size_in_bytes` instead.
|
||||
- Deprecated `etcd_debugging_mvcc_put_total` Prometheus metric. Use `etcd_mvcc_put_total` instead.
|
||||
- Deprecated `etcd_debugging_mvcc_delete_total` Prometheus metric. Use `etcd_mvcc_delete_total` instead.
|
||||
- Deprecated `etcd_debugging_mvcc_txn_total` Prometheus metric. Use `etcd_mvcc_txn_total` instead.
|
||||
- Deprecated `etcd_debugging_mvcc_range_total` Prometheus metric. Use `etcd_mvcc_range_total` instead.
|
||||
- Add [`etcd_debugging_mvcc_current_revision`](https://github.com/etcd-io/etcd/pull/11126) Prometheus metric.
|
||||
- Add [`etcd_debugging_mvcc_compact_revision`](https://github.com/etcd-io/etcd/pull/11126) Prometheus metric.
|
||||
- Change [`etcd_cluster_version`](https://github.com/etcd-io/etcd/pull/11254) Prometheus metrics to include only major and minor version.
|
||||
- Add [`etcd_debugging_mvcc_total_put_size_in_bytes`](https://github.com/etcd-io/etcd/pull/11374) Prometheus metric.
|
||||
- Add [`etcd_server_client_requests_total` with `"type"` and `"client_api_version"` labels](https://github.com/etcd-io/etcd/pull/11687).
|
||||
- Add [`etcd_wal_write_bytes_total`](https://github.com/etcd-io/etcd/pull/11738).
|
||||
- Add [`etcd_debugging_auth_revision`](https://github.com/etcd-io/etcd/commit/f14d2a087f7b0fd6f7980b95b5e0b945109c95f3).
|
||||
- Add [`os_fd_used` and `os_fd_limit` to monitor current OS file descriptors](https://github.com/etcd-io/etcd/pull/12214).
|
||||
- Add [`etcd_disk_defrag_inflight`](https://github.com/etcd-io/etcd/pull/13395).
|
||||
|
||||
### etcd server
|
||||
|
||||
- Add [don't attempt to grant nil permission to a role](https://github.com/etcd-io/etcd/pull/13086).
|
||||
- Add [don't activate alarms w/missing AlarmType](https://github.com/etcd-io/etcd/pull/13084).
|
||||
- Add [`TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256` and `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256` to `etcd --cipher-suites`](https://github.com/etcd-io/etcd/pull/11864).
|
||||
- Automatically [create parent directory if it does not exist](https://github.com/etcd-io/etcd/pull/9626) (fix [issue#9609](https://github.com/etcd-io/etcd/issues/9609)).
|
||||
- v4.0 will configure `etcd --enable-v2=true --enable-v2v3=/aaa` to enable v2 API server that is backed by **v3 storage**.
|
||||
- [`etcd --backend-bbolt-freelist-type`] flag is now stable.
|
||||
- `etcd --experimental-backend-bbolt-freelist-type` has been deprecated.
|
||||
- Support [downgrade API](https://github.com/etcd-io/etcd/pull/11715).
|
||||
- Deprecate v2 apply on cluster version. [Use v3 request to set cluster version and recover cluster version from v3 backend](https://github.com/etcd-io/etcd/pull/11427).
|
||||
- [Use v2 api to update cluster version to support mixed version cluster during upgrade](https://github.com/etcd-io/etcd/pull/12988).
|
||||
- [Fix corruption bug in defrag](https://github.com/etcd-io/etcd/pull/11613).
|
||||
- Fix [quorum protection logic when promoting a learner](https://github.com/etcd-io/etcd/pull/11640).
|
||||
- Improve [peer corruption checker](https://github.com/etcd-io/etcd/pull/11621) to work when peer mTLS is enabled.
|
||||
- Log [`[CLIENT-PORT]/health` check in server side](https://github.com/etcd-io/etcd/pull/11704).
|
||||
- Log [successful etcd server-side health check in debug level](https://github.com/etcd-io/etcd/pull/12677).
|
||||
- Improve [compaction performance when latest index is greater than 1-million](https://github.com/etcd-io/etcd/pull/11734).
|
||||
- [Refactor consistentindex](https://github.com/etcd-io/etcd/pull/11699).
|
||||
- [Add log when etcdserver failed to apply command](https://github.com/etcd-io/etcd/pull/11670).
|
||||
- Improve [count-only range performance](https://github.com/etcd-io/etcd/pull/11771).
|
||||
- Remove [redundant storage restore operation to shorten the startup time](https://github.com/etcd-io/etcd/pull/11779).
|
||||
- With 40 million key test data,it can shorten the startup time from 5 min to 2.5 min.
|
||||
- [Fix deadlock bug in mvcc](https://github.com/etcd-io/etcd/pull/11817).
|
||||
- Fix [inconsistency between WAL and server snapshot](https://github.com/etcd-io/etcd/pull/11888).
|
||||
- Previously, server restore fails if it had crashed after persisting raft hard state but before saving snapshot.
|
||||
- See https://github.com/etcd-io/etcd/issues/10219 for more.
|
||||
- Add [missing CRC checksum check in WAL validate method otherwise causes panic](https://github.com/etcd-io/etcd/pull/11924).
|
||||
- See https://github.com/etcd-io/etcd/issues/11918.
|
||||
- Improve logging around snapshot send and receive.
|
||||
- [Push down RangeOptions.limit argv into index tree to reduce memory overhead](https://github.com/etcd-io/etcd/pull/11990).
|
||||
- Add [reason field for /health response](https://github.com/etcd-io/etcd/pull/11983).
|
||||
- Add [exclude alarms from health check conditionally](https://github.com/etcd-io/etcd/pull/12880).
|
||||
- Add [`etcd --unsafe-no-fsync`](https://github.com/etcd-io/etcd/pull/11946) flag.
|
||||
- Setting the flag disables all uses of fsync, which is unsafe and will cause data loss. This flag makes it possible to run an etcd node for testing and development without placing lots of load on the file system.
|
||||
- Add [`etcd --auth-token-ttl`](https://github.com/etcd-io/etcd/pull/11980) flag to customize `simpleTokenTTL` settings.
|
||||
- Improve [`runtime.FDUsage` call pattern to reduce objects malloc of Memory Usage and CPU Usage](https://github.com/etcd-io/etcd/pull/11986).
|
||||
- Improve [mvcc.watchResponse channel Memory Usage](https://github.com/etcd-io/etcd/pull/11987).
|
||||
- Log [expensive request info in UnaryInterceptor](https://github.com/etcd-io/etcd/pull/12086).
|
||||
- [Fix invalid Go type in etcdserverpb](https://github.com/etcd-io/etcd/pull/12000).
|
||||
- [Improve healthcheck by using v3 range request and its corresponding timeout](https://github.com/etcd-io/etcd/pull/12195).
|
||||
- Add [`etcd --experimental-watch-progress-notify-interval`](https://github.com/etcd-io/etcd/pull/12216) flag to make watch progress notify interval configurable.
|
||||
- Fix [server panic in slow writes warnings](https://github.com/etcd-io/etcd/issues/12197).
|
||||
- Fixed via [PR#12238](https://github.com/etcd-io/etcd/pull/12238).
|
||||
- [Fix server panic](https://github.com/etcd-io/etcd/pull/12288) when force-new-cluster flag is enabled in a cluster which had learner node.
|
||||
- Add [`etcd --self-signed-cert-validity`](https://github.com/etcd-io/etcd/pull/12429) flag to support setting certificate expiration time.
|
||||
- Notice, certificates generated by etcd are valid for 1 year by default when specifying the auto-tls or peer-auto-tls option.
|
||||
- Add [`etcd --experimental-warning-apply-duration`](https://github.com/etcd-io/etcd/pull/12448) flag which allows apply duration threshold to be configurable.
|
||||
- Add [`etcd --experimental-memory-mlock`](https://github.com/etcd-io/etcd/pull/TODO) flag which prevents etcd memory pages to be swapped out.
|
||||
- Add [`etcd --socket-reuse-port`](https://github.com/etcd-io/etcd/pull/12702) flag
|
||||
- Setting this flag enables `SO_REUSEPORT` which allows rebind of a port already in use. User should take caution when using this flag to ensure flock is properly enforced.
|
||||
- Add [`etcd --socket-reuse-address`](https://github.com/etcd-io/etcd/pull/12702) flag
|
||||
- Setting this flag enables `SO_REUSEADDR` which allows binding to an address in `TIME_WAIT` state, improving etcd restart time.
|
||||
- Reduce [around 30% memory allocation by logging range response size without marshal](https://github.com/etcd-io/etcd/pull/12871).
|
||||
- `ETCD_VERIFY="all"` environment triggers [additional verification of consistency](https://github.com/etcd-io/etcd/pull/12901) of etcd data-dir files.
|
||||
- Add [`etcd --enable-log-rotation`](https://github.com/etcd-io/etcd/pull/12774) boolean flag which enables log rotation if true.
|
||||
- Add [`etcd --log-rotation-config-json`](https://github.com/etcd-io/etcd/pull/12774) flag which allows passthrough of JSON config to configure log rotation for a file output target.
|
||||
- Add experimental distributed tracing boolean flag [`--experimental-enable-distributed-tracing`](https://github.com/etcd-io/etcd/pull/12919) which enables tracing.
|
||||
- Add [`etcd --experimental-distributed-tracing-address`](https://github.com/etcd-io/etcd/pull/12919) string flag which allows configuring the OpenTelemetry collector address.
|
||||
- Add [`etcd --experimental-distributed-tracing-service-name`](https://github.com/etcd-io/etcd/pull/12919) string flag which allows changing the default "etcd" service name.
|
||||
- Add [`etcd --experimental-distributed-tracing-instance-id`](https://github.com/etcd-io/etcd/pull/12919) string flag which configures an instance ID, which must be unique per etcd instance.
|
||||
- Add [`--experimental-bootstrap-defrag-threshold-megabytes`](https://github.com/etcd-io/etcd/pull/12941) which configures a threshold for the unused db size and etcdserver will automatically perform defragmentation on bootstrap when it exceeds this value. The functionality is disabled if the value is 0.
|
||||
|
||||
### Package `runtime`
|
||||
|
||||
- Optimize [`runtime.FDUsage` by removing unnecessary sorting](https://github.com/etcd-io/etcd/pull/12214).
|
||||
|
||||
### Package `embed`
|
||||
|
||||
- Remove [`embed.Config.Debug`](https://github.com/etcd-io/etcd/pull/10947).
|
||||
- Use `embed.Config.LogLevel` instead.
|
||||
- Add [`embed.Config.ZapLoggerBuilder`](https://github.com/etcd-io/etcd/pull/11147) to allow creating a custom zap logger.
|
||||
- Replace [global `*zap.Logger` with etcd server logger object](https://github.com/etcd-io/etcd/pull/12212).
|
||||
- Add [`embed.Config.EnableLogRotation`](https://github.com/etcd-io/etcd/pull/12774) which enables log rotation if true.
|
||||
- Add [`embed.Config.LogRotationConfigJSON`](https://github.com/etcd-io/etcd/pull/12774) to allow passthrough of JSON config to configure log rotation for a file output target.
|
||||
- Add [`embed.Config.ExperimentalEnableDistributedTracing`](https://github.com/etcd-io/etcd/pull/12919) which enables experimental distributed tracing if true.
|
||||
- Add [`embed.Config.ExperimentalDistributedTracingAddress`](https://github.com/etcd-io/etcd/pull/12919) which allows overriding default collector address.
|
||||
- Add [`embed.Config.ExperimentalDistributedTracingServiceName`](https://github.com/etcd-io/etcd/pull/12919) which allows overriding default "etcd" service name.
|
||||
- Add [`embed.Config.ExperimentalDistributedTracingServiceInstanceID`](https://github.com/etcd-io/etcd/pull/12919) which allows configuring an instance ID, which must be uniquer per etcd instance.
|
||||
|
||||
### Package `clientv3`
|
||||
|
||||
- Remove [excessive watch cancel logging messages](https://github.com/etcd-io/etcd/pull/12187).
|
||||
- See [kubernetes/kubernetes#93450](https://github.com/kubernetes/kubernetes/issues/93450).
|
||||
- Add [`TryLock`](https://github.com/etcd-io/etcd/pull/11104) method to `clientv3/concurrency/Mutex`. A non-blocking method on `Mutex` which does not wait to get lock on the Mutex, returns immediately if Mutex is locked by another session.
|
||||
- Fix [client balancer failover against multiple endpoints](https://github.com/etcd-io/etcd/pull/11184).
|
||||
- Fix [`"kube-apiserver: failover on multi-member etcd cluster fails certificate check on DNS mismatch"`](https://github.com/kubernetes/kubernetes/issues/83028).
|
||||
- Fix [IPv6 endpoint parsing in client](https://github.com/etcd-io/etcd/pull/11211).
|
||||
- Fix ["1.16: etcd client does not parse IPv6 addresses correctly when members are joining" (kubernetes#83550)](https://github.com/kubernetes/kubernetes/issues/83550).
|
||||
- Fix [errors caused by grpc changing balancer/resolver API](https://github.com/etcd-io/etcd/pull/11564). This change is compatible with grpc >= [v1.26.0](https://github.com/grpc/grpc-go/releases/tag/v1.26.0), but is not compatible with < v1.26.0 version.
|
||||
- Use [ServerName as the authority](https://github.com/etcd-io/etcd/pull/11574) after bumping to grpc v1.26.0. Remove workaround in [#11184](https://github.com/etcd-io/etcd/pull/11184).
|
||||
- Fix [`"hasleader"` metadata embedding](https://github.com/etcd-io/etcd/pull/11687).
|
||||
- Previously, `clientv3.WithRequireLeader(ctx)` was overwriting existing context keys.
|
||||
- Fix [watch leak caused by lazy cancellation](https://github.com/etcd-io/etcd/pull/11850). When clients cancel their watches, a cancel request will now be immediately sent to the server instead of waiting for the next watch event.
|
||||
- Make sure [save snapshot downloads checksum for integrity checks](https://github.com/etcd-io/etcd/pull/11896).
|
||||
- Fix [auth token invalid after watch reconnects](https://github.com/etcd-io/etcd/pull/12264). Get AuthToken automatically when clientConn is ready.
|
||||
- Improve [clientv3:get AuthToken gracefully without extra connection](https://github.com/etcd-io/etcd/pull/12165).
|
||||
- Changed [clientv3 dialing code](https://github.com/etcd-io/etcd/pull/12671) to use grpc resolver API instead of custom balancer.
|
||||
- Endpoints self identify now as `etcd-endpoints://{id}/#initially={list of endpoints}` e.g. `etcd-endpoints://0xc0009d8540/#initially=[localhost:2079]`
|
||||
- Make sure [save snapshot downloads checksum for integrity checks](https://github.com/etcd-io/etcd/pull/11896).
|
||||
|
||||
### Package `lease`
|
||||
|
||||
- Fix [memory leak in follower nodes](https://github.com/etcd-io/etcd/pull/11731).
|
||||
- https://github.com/etcd-io/etcd/issues/11495
|
||||
- https://github.com/etcd-io/etcd/issues/11730
|
||||
- Make sure [grant/revoke won't be applied repeatedly after restarting etcd](https://github.com/etcd-io/etcd/pull/11935).
|
||||
|
||||
### Package `wal`
|
||||
|
||||
- Add [`etcd_wal_write_bytes_total`](https://github.com/etcd-io/etcd/pull/11738).
|
||||
- Handle [out-of-range slice bound in `ReadAll` and entry limit in `decodeRecord`](https://github.com/etcd-io/etcd/pull/11793).
|
||||
|
||||
### etcdctl v3
|
||||
|
||||
- Fix `etcdctl member add` command to prevent potential timeout. ([PR#11194](https://github.com/etcd-io/etcd/pull/11194) and [PR#11638](https://github.com/etcd-io/etcd/pull/11638))
|
||||
- Add [`etcdctl watch --progress-notify`](https://github.com/etcd-io/etcd/pull/11462) flag.
|
||||
- Add [`etcdctl auth status`](https://github.com/etcd-io/etcd/pull/11536) command to check if authentication is enabled
|
||||
- Add [`etcdctl get --count-only`](https://github.com/etcd-io/etcd/pull/11743) flag for output type `fields`.
|
||||
- Add [`etcdctl member list -w=json --hex`](https://github.com/etcd-io/etcd/pull/11812) flag to print memberListResponse in hex format json.
|
||||
- Changed [`etcdctl lock <lockname> exec-command`](https://github.com/etcd-io/etcd/pull/12829) to return exit code of exec-command.
|
||||
- [New tool: `etcdutl`](https://github.com/etcd-io/etcd/pull/12971) incorporated functionality of: `etcdctl snapshot status|restore`, `etcdctl backup`, `etcdctl defrag --data-dir ...`.
|
||||
- [ETCDCTL_API=3 `etcdctl migrate`](https://github.com/etcd-io/etcd/pull/12971) has been decommissioned. Use etcd <=v3.4 to restore v2 storage.
|
||||
|
||||
### gRPC gateway
|
||||
|
||||
- [gRPC gateway](https://github.com/grpc-ecosystem/grpc-gateway) only supports [`/v3`](TODO) endpoint.
|
||||
- Deprecated [`/v3beta`](https://github.com/etcd-io/etcd/pull/9298).
|
||||
- `curl -L http://localhost:2379/v3beta/kv/put -X POST -d '{"key": "Zm9v", "value": "YmFy"}'` does work in v3.5. Use `curl -L http://localhost:2379/v3/kv/put -X POST -d '{"key": "Zm9v", "value": "YmFy"}'` instead.
|
||||
- Set [`enable-grpc-gateway`](https://github.com/etcd-io/etcd/pull/12297) flag to true when using a config file to keep the defaults the same as the command line configuration.
|
||||
|
||||
### gRPC Proxy
|
||||
|
||||
- Fix [`panic on error`](https://github.com/etcd-io/etcd/pull/11694) for metrics handler.
|
||||
- Add [gRPC keepalive related flags](https://github.com/etcd-io/etcd/pull/11711) `grpc-keepalive-min-time`, `grpc-keepalive-interval` and `grpc-keepalive-timeout`.
|
||||
- [Fix grpc watch proxy hangs when failed to cancel a watcher](https://github.com/etcd-io/etcd/pull/12030) .
|
||||
- Add [metrics handler for grpcproxy self](https://github.com/etcd-io/etcd/pull/12107).
|
||||
- Add [health handler for grpcproxy self](https://github.com/etcd-io/etcd/pull/12114).
|
||||
|
||||
### Auth
|
||||
|
||||
- Fix [NoPassword check when adding user through GRPC gateway](https://github.com/etcd-io/etcd/pull/11418) ([issue#11414](https://github.com/etcd-io/etcd/issues/11414))
|
||||
- Fix bug where [some auth related messages are logged at wrong level](https://github.com/etcd-io/etcd/pull/11586)
|
||||
- [Fix a data corruption bug by saving consistent index](https://github.com/etcd-io/etcd/pull/11652).
|
||||
- [Improve checkPassword performance](https://github.com/etcd-io/etcd/pull/11735).
|
||||
- [Add authRevision field in AuthStatus](https://github.com/etcd-io/etcd/pull/11659).
|
||||
- Fix [a bug of not refreshing expired tokens](https://github.com/etcd-io/etcd/pull/13308).
|
||||
-
|
||||
### API
|
||||
|
||||
- Add [`/v3/auth/status`](https://github.com/etcd-io/etcd/pull/11536) endpoint to check if authentication is enabled
|
||||
- [Add `Linearizable` field to `etcdserverpb.MemberListRequest`](https://github.com/etcd-io/etcd/pull/11639).
|
||||
- [Learner support Snapshot RPC](https://github.com/etcd-io/etcd/pull/12890/).
|
||||
|
||||
### Package `netutil`
|
||||
|
||||
- Remove [`netutil.DropPort/RecoverPort/SetLatency/RemoveLatency`](https://github.com/etcd-io/etcd/pull/12491).
|
||||
- These are not used anymore. They were only used for older versions of functional testing.
|
||||
- Removed to adhere to best security practices, minimize arbitrary shell invocation.
|
||||
|
||||
### `tools/etcd-dump-metrics`
|
||||
|
||||
- Implement [input validation to prevent arbitrary shell invocation](https://github.com/etcd-io/etcd/pull/12491).
|
||||
|
||||
### Dependency
|
||||
|
||||
- Upgrade [`google.golang.org/grpc`](https://github.com/grpc/grpc-go/releases) from [**`v1.23.0`**](https://github.com/grpc/grpc-go/releases/tag/v1.23.0) to [**`v1.37.0`**](https://github.com/grpc/grpc-go/releases/tag/v1.37.0).
|
||||
- Upgrade [`go.uber.org/zap`](https://github.com/uber-go/zap/releases) from [**`v1.14.1`**](https://github.com/uber-go/zap/releases/tag/v1.14.1) to [**`v1.16.0`**](https://github.com/uber-go/zap/releases/tag/v1.16.0).
|
||||
|
||||
### Platforms
|
||||
|
||||
- etcd now [officially supports `arm64`](https://github.com/etcd-io/etcd/pull/12929).
|
||||
- See https://github.com/etcd-io/etcd/pull/12928 for adding automated tests with `arm64` EC2 instances (Graviton 2).
|
||||
- See https://github.com/etcd-io/website/pull/273 for new platform support tier policies.
|
||||
|
||||
### Release
|
||||
|
||||
- Add s390x build support ([PR#11548](https://github.com/etcd-io/etcd/pull/11548) and [PR#11358](https://github.com/etcd-io/etcd/pull/11358))
|
||||
|
||||
### Go
|
||||
|
||||
- Require [*Go 1.16+*](https://github.com/etcd-io/etcd/pull/11110).
|
||||
- Compile with [*Go 1.16+*](https://golang.org/doc/devel/release.html#go1.16)
|
||||
- etcd uses [go modules](https://github.com/etcd-io/etcd/pull/12279) (instead of vendor dir) to track dependencies.
|
||||
|
||||
### Project Governance
|
||||
|
||||
- The etcd team has added, a well defined and openly discussed, project [governance](https://github.com/etcd-io/etcd/pull/11175).
|
||||
|
||||
|
||||
---
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
|
||||
|
||||
Previous change logs can be found at [CHANGELOG-3.5](https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.5.md).
|
||||
|
||||
---
|
||||
|
||||
## v3.6.5 (TBA)
|
||||
|
||||
### etcd server
|
||||
|
||||
- [Remove the flag `--experimental-snapshot-catch-up-entries` from `etcd --help` output](https://github.com/etcd-io/etcd/pull/20422)
|
||||
|
||||
---
|
||||
|
||||
## v3.6.4 (2025-07-25)
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix [etcdserver bootstrap failure when replaying learner promotion operation due to not exist in v3store](https://github.com/etcd-io/etcd/pull/20387)
|
||||
|
||||
---
|
||||
|
||||
## v3.6.3 (2025-07-22)
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix [v2store check (IsMetaStoreOnly) returns wrong result even there is no any auth data](https://github.com/etcd-io/etcd/pull/20370)
|
||||
- Improve [help message for --quota-backend-bytes](https://github.com/etcd-io/etcd/pull/20352)
|
||||
|
||||
---
|
||||
|
||||
## v3.6.2 (2025-07-09)
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix [Watch on future revision returns old events or notifications](https://github.com/etcd-io/etcd/pull/20286)
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [Bump bbolt to v1.4.2](https://github.com/etcd-io/etcd/pull/20267)
|
||||
- Compile binaries using [go 1.23.11](https://github.com/etcd-io/etcd/pull/20314).
|
||||
|
||||
---
|
||||
|
||||
## v3.6.1 (2025-06-06)
|
||||
|
||||
### etcd server
|
||||
|
||||
- [Replaced the deprecated/removed `UnaryServerInterceptor` and `StreamServerInterceptor` in otelgrpc with `NewServerHandler`](https://github.com/etcd-io/etcd/pull/20043)
|
||||
- [Add protection on `PromoteMember` and `UpdateRaftAttributes` to prevent panicking](https://github.com/etcd-io/etcd/pull/20051)
|
||||
- [Fix the issue that `--force-new-cluster` can't remove all other members in a corner case](https://github.com/etcd-io/etcd/pull/20071)
|
||||
- Fix [mvcc: avoid double decrement of watcher gauge on close/cancel race](https://github.com/etcd-io/etcd/pull/20067)
|
||||
- [Add validation to ensure there is no empty v3discovery endpoint](https://github.com/etcd-io/etcd/pull/20113)
|
||||
|
||||
### etcdctl
|
||||
|
||||
- Fix [command `etcdctl endpoint health` doesn't work when options are set via environment variables](https://github.com/etcd-io/etcd/pull/20121)
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Compile binaries using [go 1.23.10](https://github.com/etcd-io/etcd/pull/20128).
|
||||
|
||||
---
|
||||
|
||||
## v3.6.0 (2025-05-15)
|
||||
|
||||
There isn't any production code change since v3.6.0-rc.5.
|
||||
|
||||
---
|
||||
|
||||
## v3.6.0-rc.5 (2025-05-08)
|
||||
|
||||
### etcd server
|
||||
|
||||
- Fix [the compaction pause duration metric is not emitted for every compaction batch](https://github.com/etcd-io/etcd/pull/19770)
|
||||
|
||||
### Package `clientv3`
|
||||
|
||||
- [Replace `resolver.State.Addresses` with `resolver.State.Endpoint.Addresses`](https://github.com/etcd-io/etcd/pull/19782).
|
||||
- [Deprecated the Metadata field in the Endpoint struct from the client/v3/naming/endpoints package](https://github.com/etcd-io/etcd/pull/19842).
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Compile binaries using [go 1.23.9](https://github.com/etcd-io/etcd/pull/19867).
|
||||
|
||||
---
|
||||
|
||||
## v3.6.0-rc.4 (2025-04-15)
|
||||
|
||||
### etcd server
|
||||
|
||||
- [Switch to validating v3 when v2 and v3 are synchronized](https://github.com/etcd-io/etcd/pull/19703).
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Compile binaries using [go 1.23.8](https://github.com/etcd-io/etcd/pull/19724)
|
||||
|
||||
---
|
||||
|
||||
## v3.6.0-rc.3 (2025-03-27)
|
||||
|
||||
### etcd server
|
||||
|
||||
- [Auto sync members in v3store for the issues which have already been affected by #19557](https://github.com/etcd-io/etcd/pull/19636).
|
||||
- [Move `client/internal/v2` into `server/internel/clientv2`](https://github.com/etcd-io/etcd/pull/19673).
|
||||
- [Replace ExperimentalMaxLearners with a Feature Gate](https://github.com/etcd-io/etcd/pull/19560).
|
||||
|
||||
### etcd grpc-proxy
|
||||
|
||||
- Fix [grpcproxy can get stuck in and endless loop causing high CPU usage](https://github.com/etcd-io/etcd/pull/19562)
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Bump [github.com/golang-jwt/jwt/v5 from 5.2.1 to 5.2.2 to address CVE-2025-30204](https://github.com/etcd-io/etcd/pull/19647).
|
||||
- Bump [bump golang.org/x/net from v0.37.0 to v0.38.0 to address CVE-2025-22872](https://github.com/etcd-io/etcd/pull/19687).
|
||||
|
||||
---
|
||||
|
||||
## v3.6.0-rc.2 (2025-03-05)
|
||||
|
||||
### etcd server
|
||||
|
||||
- Add [Prometheus metric to query server feature gates](https://github.com/etcd-io/etcd/pull/19495).
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Compile binaries using [go 1.23.7](https://github.com/etcd-io/etcd/pull/19527).
|
||||
- Bump [golang.org/x/net to v0.36.0 to address CVE-2025-22870](https://github.com/etcd-io/etcd/pull/19531).
|
||||
- Bump [github.com/grpc-ecosystem/grpc-gateway/v2 to v2.26.3 to fix the issue of etcdserver crashing on receiving REST watch stream requests](https://github.com/etcd-io/etcd/pull/19522).
|
||||
|
||||
---
|
||||
|
||||
## v3.6.0-rc.1 (2025-02-25)
|
||||
|
||||
### etcdctl v3
|
||||
|
||||
- Add [`DowngradeInfo` in result of endpoint status](https://github.com/etcd-io/etcd/pull/19471)
|
||||
|
||||
### etcd server
|
||||
|
||||
- Add [`DowngradeInfo` to endpoint status response](https://github.com/etcd-io/etcd/pull/19471)
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Bump [golang.org/x/crypto to v0.35.0 to address CVE-2025-22869](https://github.com/etcd-io/etcd/pull/19480).
|
||||
|
||||
---
|
||||
|
||||
## v3.6.0-rc.0 (2025-02-13)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0...v3.6.0).
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `etcd` will no longer start on data dir created by newer versions (for example etcd v3.6 will not run on v3.7+ data dir). To downgrade data dir please check out `etcdutl migrate` command.
|
||||
- `etcd` doesn't support serving client requests on the peer listen endpoints (--listen-peer-urls). See [pull/13565](https://github.com/etcd-io/etcd/pull/13565).
|
||||
- `etcdctl` will sleep(2s) in case of range delete without `--range` flag. See [pull/13747](https://github.com/etcd-io/etcd/pull/13747)
|
||||
- Applications which depend on etcd v3.6 packages must be built with go version >= v1.18.
|
||||
|
||||
#### Flags Removed
|
||||
|
||||
- The following flags have been removed:
|
||||
|
||||
- `--enable-v2`
|
||||
- `--experimental-enable-v2v3`
|
||||
- `--proxy`
|
||||
- `--proxy-failure-wait`
|
||||
- `--proxy-refresh-interval`
|
||||
- `--proxy-dial-timeout`
|
||||
- `--proxy-write-timeout`
|
||||
- `--proxy-read-timeout`
|
||||
|
||||
### Deprecations
|
||||
|
||||
- Deprecated [V2 discovery](https://etcd.io/docs/v3.5/dev-internal/discovery_protocol/).
|
||||
- Deprecated [SetKeepAlive and SetKeepAlivePeriod in limitListenerConn](https://github.com/etcd-io/etcd/pull/14356).
|
||||
- Removed [etcdctl defrag --data-dir](https://github.com/etcd-io/etcd/pull/13793).
|
||||
- Removed [etcdctl snapshot status](https://github.com/etcd-io/etcd/pull/13809).
|
||||
- Removed [etcdctl snapshot restore](https://github.com/etcd-io/etcd/pull/13809).
|
||||
- Removed [NewZapCoreLoggerBuilder in server/embed](https://github.com/etcd-io/etcd/pull/19404)
|
||||
|
||||
### etcdctl v3
|
||||
|
||||
- Add command to generate [shell completion](https://github.com/etcd-io/etcd/pull/13133).
|
||||
- When print endpoint status, [show db size in use](https://github.com/etcd-io/etcd/pull/13639)
|
||||
- [Always print the raft_term in decimal](https://github.com/etcd-io/etcd/pull/13711) when displaying member list in json.
|
||||
- [Add one more field `storageVersion`](https://github.com/etcd-io/etcd/pull/13773) into the response of command `etcdctl endpoint status`.
|
||||
- Add [`--max-txn-ops`](https://github.com/etcd-io/etcd/pull/14340) flag to make-mirror command.
|
||||
- Add [`--consistency`](https://github.com/etcd-io/etcd/pull/15261) flag to member list command.
|
||||
- Display [field `hash_revision`](https://github.com/etcd-io/etcd/pull/14812) for `etcdctl endpoint hash` command.
|
||||
- Add [`--max-request-bytes` and `--max-recv-bytes`](https://github.com/etcd-io/etcd/pull/18718) global flags.
|
||||
|
||||
### etcdutl v3
|
||||
|
||||
- Add command to generate [shell completion](https://github.com/etcd-io/etcd/pull/13142).
|
||||
- Add `migrate` command for downgrading/upgrading etcd data dir files.
|
||||
- Add [optional --bump-revision and --mark-compacted flag to etcdutl snapshot restore operation](https://github.com/etcd-io/etcd/pull/16029).
|
||||
- Add [hashkv](https://github.com/etcd-io/etcd/pull/15965) command to print hash of keys and values up to given revision
|
||||
- Removed [legacy etcdutl backup](https://github.com/etcd-io/etcd/pull/16662)
|
||||
- [Count the number of keys from users perspective](https://github.com/etcd-io/etcd/pull/19344)
|
||||
|
||||
### Package `clientv3`
|
||||
|
||||
- [Support serializable `MemberList` operation](https://github.com/etcd-io/etcd/pull/15261).
|
||||
|
||||
### Package `server`
|
||||
|
||||
- Package `mvcc` was moved to `storage/mvcc`
|
||||
- Package `mvcc/backend` was moved to `storage/backend`
|
||||
- Package `mvcc/buckets` was moved to `storage/schema`
|
||||
- Package `wal` was moved to `storage/wal`
|
||||
- Package `datadir` was moved to `storage/datadir`
|
||||
|
||||
### Package `raft`
|
||||
- [Decouple raft from etcd](https://github.com/etcd-io/etcd/issues/14713). Migrated raft to a separate [repository](https://github.com/etcd-io/raft), and renamed raft module to `go.etcd.io/raft/v3`.
|
||||
|
||||
### etcd server
|
||||
|
||||
- Add [`etcd --log-format`](https://github.com/etcd-io/etcd/pull/13339) flag to support log format.
|
||||
- Add [`etcd --experimental-max-learners`](https://github.com/etcd-io/etcd/pull/13377) flag to allow configuration of learner max membership.
|
||||
- Add [`etcd --experimental-enable-lease-checkpoint-persist`](https://github.com/etcd-io/etcd/pull/13508) flag to handle upgrade from v3.5.2 clusters with this feature enabled.
|
||||
- Add [`etcdctl make-mirror --rev`](https://github.com/etcd-io/etcd/pull/13519) flag to support incremental mirror.
|
||||
- Add [v3 discovery](https://github.com/etcd-io/etcd/pull/13635) to bootstrap a new etcd cluster.
|
||||
- Add [field `storage`](https://github.com/etcd-io/etcd/pull/13772) into the response body of endpoint `/version`.
|
||||
- Add [`etcd --max-concurrent-streams`](https://github.com/etcd-io/etcd/pull/14169) flag to configure the max concurrent streams each client can open at a time, and defaults to math.MaxUint32.
|
||||
- Add [`etcd grpc-proxy --experimental-enable-grpc-logging`](https://github.com/etcd-io/etcd/pull/14266) flag to logging all grpc requests and responses.
|
||||
- Add [`etcd --experimental-compact-hash-check-enabled --experimental-compact-hash-check-time`](https://github.com/etcd-io/etcd/issues/14039) flags to support enabling reliable corruption detection on compacted revisions.
|
||||
- Add [Protection on maintenance request when auth is enabled](https://github.com/etcd-io/etcd/pull/14663).
|
||||
- Graduated [`--experimental-warning-unary-request-duration` to `--warning-unary-request-duration`](https://github.com/etcd-io/etcd/pull/14414). Note the experimental flag is deprecated and will be decommissioned in v3.7.
|
||||
- Add [field `hash_revision` into `HashKVResponse`](https://github.com/etcd-io/etcd/pull/14537).
|
||||
- Add [`etcd --experimental-snapshot-catch-up-entries`](https://github.com/etcd-io/etcd/pull/15033) flag to configure number of entries for a slow follower to catch up after compacting the raft storage entries and defaults to 5k.
|
||||
- Decreased [`--snapshot-count` default value from 100,000 to 10,000](https://github.com/etcd-io/etcd/pull/15408)
|
||||
- Add [`etcd --tls-min-version --tls-max-version`](https://github.com/etcd-io/etcd/pull/15156) to enable support for TLS 1.3.
|
||||
- Add [quota to endpoint status response](https://github.com/etcd-io/etcd/pull/17877)
|
||||
- Add [feature gate `SetMemberLocalAddr`](https://github.com/etcd-io/etcd/pull/19413) to [enable using the first specified and non-loopback local address from initial-advertise-peer-urls as the local address when communicating with a peer]((https://github.com/etcd-io/etcd/pull/17661))
|
||||
- Add [Support multiple values for allowed client and peer TLS identities](https://github.com/etcd-io/etcd/pull/18015)
|
||||
- Add [`embed.Config.GRPCAdditionalServerOptions`](https://github.com/etcd-io/etcd/pull/14066) to support updating the default internal gRPC configuration for embedded use cases.
|
||||
|
||||
### etcd grpc-proxy
|
||||
|
||||
- Add [`etcd grpc-proxy start --endpoints-auto-sync-interval`](https://github.com/etcd-io/etcd/pull/14354) flag to enable and configure interval of auto sync of endpoints with server.
|
||||
- Add [`etcd grpc-proxy start --listen-cipher-suites`](https://github.com/etcd-io/etcd/pull/14308) flag to support adding configurable cipher list.
|
||||
- Add [`tls min/max version to grpc proxy`](https://github.com/etcd-io/etcd/pull/18816) to support setting TLS min and max version.
|
||||
|
||||
### tools/benchmark
|
||||
|
||||
- [Add etcd client autoSync flag](https://github.com/etcd-io/etcd/pull/13416)
|
||||
|
||||
### Metrics, Monitoring
|
||||
|
||||
See [List of metrics](https://etcd.io/docs/latest/metrics/) for all metrics per release.
|
||||
|
||||
- Add [`etcd_disk_defrag_inflight`](https://github.com/etcd-io/etcd/pull/13371).
|
||||
- Add [`etcd_debugging_server_alarms`](https://github.com/etcd-io/etcd/pull/14276).
|
||||
- Add [`etcd_server_range_duration_seconds`](https://github.com/etcd-io/etcd/pull/17983).
|
||||
|
||||
### Go
|
||||
- Require [Go 1.23+](https://github.com/etcd-io/etcd/pull/16594).
|
||||
- Compile with [Go 1.23+](https://go.dev/doc/devel/release#go1.21.minor). Please refer to [gc-guide](https://go.dev/doc/gc-guide) to configure `GOGC` and `GOMEMLIMIT` properly.
|
||||
|
||||
### Other
|
||||
|
||||
- Use Distroless as base image to make the image less vulnerable and reduce image size.
|
||||
- [Upgrade grpc-gateway from v1 to v2](https://github.com/etcd-io/etcd/pull/16595).
|
||||
- [Switch from grpc-ecosystem/go-grpc-prometheus to grpc-ecosystem/go-grpc-middleware/providers/prometheus](https://github.com/etcd-io/etcd/pull/19195).
|
||||
|
||||
---
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
Previous change logs can be found at [CHANGELOG-3.6](https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.6.md).
|
||||
|
||||
---
|
||||
|
||||
## v3.7.0 (TBD)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- [Removed all deprecated experimental flags](https://github.com/etcd-io/etcd/pull/19959)
|
||||
- [Removed v2discovery](https://github.com/etcd-io/etcd/pull/20109)
|
||||
- [Removed client/v2](https://github.com/etcd-io/etcd/pull/20117)
|
||||
|
||||
### etcd server
|
||||
|
||||
- [Update go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc to v0.61.0 and replaced the deprecated `UnaryServerInterceptor` and `StreamServerInterceptor` with `NewServerHandler`](https://github.com/etcd-io/etcd/pull/20017)
|
||||
- [Add Support for Unix Socket endpoints](https://github.com/etcd-io/etcd/pull/19760)
|
||||
|
||||
### Package `pkg`
|
||||
|
||||
- [Optimize find performance by splitting intervals with the same left endpoint by their right endpoints](https://github.com/etcd-io/etcd/pull/19768)
|
||||
- [netutil: Refactor IPv6 address comparison logic](https://github.com/etcd-io/etcd/pull/20365)
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Compile binaries using [go 1.24.5](https://github.com/etcd-io/etcd/pull/20320)
|
||||
|
||||
### Deprecations
|
||||
|
||||
- Deprecated [UsageFunc in pkg/cobrautl](https://github.com/etcd-io/etcd/pull/18356).
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
|
||||
Previous change logs can be found at [CHANGELOG-3.x](https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.x.md).
|
||||
|
||||
---
|
||||
|
||||
## v4.0.0 (TBD)
|
||||
|
||||
See [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0...v4.0.0) and [v4.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_4_0/) for any breaking changes.
|
||||
|
||||
**Again, before running upgrades from any previous release, please make sure to read change logs below and [v4.0 upgrade guide](https://etcd.io/docs/latest/upgrades/upgrade_4_0/).**
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- [Secure etcd by default](https://github.com/etcd-io/etcd/issues/9475)?
|
||||
- Deprecate [`etcd --proxy*`](TODO) flags; **no more v2 proxy**.
|
||||
- Deprecate [v2 storage backend](https://github.com/etcd-io/etcd/issues/9232); **no more v2 store**.
|
||||
- v2 API is still supported via [v2 emulation](TODO).
|
||||
- Deprecate [`etcdctl backup`](TODO) command.
|
||||
- `clientv3.Client.KeepAlive(ctx context.Context, id LeaseID) (<-chan *LeaseKeepAliveResponse, error)` is now [`clientv4.Client.KeepAlive(ctx context.Context, id LeaseID) <-chan *LeaseKeepAliveResponse`](TODO).
|
||||
- Similar to `Watch`, [`KeepAlive` does not return errors](https://github.com/etcd-io/etcd/issues/7488).
|
||||
- If there's an unknown server error, kill all open channels and create a new stream on the next `KeepAlive` call.
|
||||
- Rename `github.com/coreos/client` to `github.com/coreos/clientv2`.
|
||||
- [`etcd --experimental-initial-corrupt-check`](TODO) has been deprecated.
|
||||
- Use [`etcd --initial-corrupt-check`](TODO) instead.
|
||||
- [`etcd --experimental-corrupt-check-time`](TODO) has been deprecated.
|
||||
- Use [`etcd --corrupt-check-time`](TODO) instead.
|
||||
- Enable TLS 1.13, deprecate TLS cipher suites.
|
||||
|
||||
### etcd server
|
||||
|
||||
- [`etcd --initial-corrupt-check`](TODO) flag is now stable (`etcd --experimental-initial-corrupt-check` has been deprecated).
|
||||
- `etcd --initial-corrupt-check=true` by default, to check cluster database hashes before serving client/peer traffic.
|
||||
- [`etcd --corrupt-check-time`](TODO) flag is now stable (`etcd --experimental-corrupt-check-time` has been deprecated).
|
||||
- `etcd --corrupt-check-time=12h` by default, to check cluster database hashes for every 12-hour.
|
||||
- Enable TLS 1.13, deprecate TLS cipher suites.
|
||||
|
||||
### Go
|
||||
|
||||
- Require [*Go 2*](https://blog.golang.org/go2draft).
|
||||
|
||||
|
||||
---
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# Change logs
|
||||
|
||||
## Production recommendation
|
||||
|
||||
The minimum recommended etcd versions to run in **production** are v3.4.22+ and v3.5.6+. Refer to the [versioning policy](https://etcd.io/docs/v3.5/op-guide/versioning/) for more details.
|
||||
|
||||
### v3.5 data corruption issue
|
||||
|
||||
Running etcd v3.5.2, v3.5.1 and v3.5.0 under high load can cause a data corruption issue.
|
||||
If etcd process is killed, occasionally some committed transactions are not reflected on all the members.
|
||||
Recommendation is to upgrade to v3.5.4+.
|
||||
|
||||
If you have encountered data corruption, please follow instructions on https://etcd.io/docs/v3.5/op-guide/data_corruption/.
|
||||
|
||||
## Change log rules
|
||||
1. Each patch release only includes changes against previous patch release.
|
||||
For example, the change log of v3.5.5 should only include items which are new to v3.5.4.
|
||||
2. For the first release (e.g. 3.4.0, 3.5.0, 3.6.0, 4.0.0 etc.) for each minor or major
|
||||
version, it only includes changes which are new to the first release of previous minor
|
||||
or major version. For example, v3.5.0 should only include items which are new to v3.4.0,
|
||||
and v3.6.0 should only include items which are new to v3.5.0.
|
|
@ -1,5 +1,5 @@
|
|||
ARG ARCH=amd64
|
||||
FROM --platform=linux/${ARCH} gcr.io/distroless/static-debian12@sha256:3f2b64ef97bd285e36132c684e6b2ae8f2723293d09aae046196cca64251acac
|
||||
FROM --platform=linux/${ARCH} gcr.io/distroless/static-debian12@sha256:b7b9a6953e7bed6baaf37329331051d7bdc1b99c885f6dbeb72d75b1baad54f9
|
||||
|
||||
ADD etcd /usr/local/bin/
|
||||
ADD etcdctl /usr/local/bin/
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
# Bump etcd Version in Kubernetes
|
||||
|
||||
This guide will walk through the update of etcd in Kubernetes to a new version (`kubernetes/kubernetes` repository).
|
||||
|
||||
> Currently we bump etcd v3.5.x for K8s release-1.33 and lower versions, and we bump etcd v3.6.x for K8s release-1.34 and higher versions.
|
||||
|
||||
You can use this [issue](https://github.com/kubernetes/kubernetes/issues/131101) as a reference when updating the etcd version in Kubernetes.
|
||||
|
||||
Bumping the etcd version in Kubernetes consists of two steps.
|
||||
|
||||
* Bump etcd client SDK
|
||||
* Bump etcd image
|
||||
|
||||
> The commented lines in this document signifies the line to be changed
|
||||
|
||||
## Bump etcd client SDK
|
||||
|
||||
> Reference: [link](https://github.com/kubernetes/kubernetes/pull/131103)
|
||||
|
||||
You can refer to the guide [here](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/vendor.md) under the **Adding or updating a dependency** section.
|
||||
|
||||
1. Get all the etcd modules used in Kubernetes.
|
||||
|
||||
```bash
|
||||
$ grep 'go.etcd.io/etcd/' go.mod | awk '{print $1}'
|
||||
go.etcd.io/etcd/api/v3
|
||||
go.etcd.io/etcd/client/pkg/v3
|
||||
go.etcd.io/etcd/client/v3
|
||||
go.etcd.io/etcd/client/v2
|
||||
go.etcd.io/etcd/pkg/v3
|
||||
go.etcd.io/etcd/raft/v3
|
||||
go.etcd.io/etcd/server/v3
|
||||
```
|
||||
|
||||
2. For each module, in the root directory of the `kubernetes/kubernetes` repository, fetch the new version in `go.mod` using the following command (using `client/v3` as an example):
|
||||
|
||||
```bash
|
||||
hack/pin-dependency.sh go.etcd.io/etcd/client/v3 NEW_VERSION
|
||||
```
|
||||
|
||||
3. Rebuild the `vendor` directory and update the `go.mod` files for all staging repositories using the command below. This automatically updates the licenses.
|
||||
|
||||
```bash
|
||||
hack/update-vendor.sh
|
||||
```
|
||||
|
||||
4. Check if the new dependency requires newer versions of existing dependencies we have pinned. You can check this by:
|
||||
|
||||
* Running `hack/lint-dependencies.sh` against your branch and against `master` and comparing the results.
|
||||
* Checking if any new `replace` directives were added to `go.mod` files of components inside the staging directory.
|
||||
|
||||
## Bump etcd image
|
||||
|
||||
### Build etcd image
|
||||
|
||||
> Reference: [link 1](https://github.com/kubernetes/kubernetes/pull/131105) [link 2](https://github.com/kubernetes/kubernetes/pull/131126)
|
||||
|
||||
1. In `build/dependencies.yaml`, update the `version` of `etcd-image` to the new version. Update `golang: etcd release version` if necessary.
|
||||
|
||||
```yaml
|
||||
- name: "etcd-image"
|
||||
# version: 3.5.17
|
||||
version: 3.5.21
|
||||
refPaths:
|
||||
- path: cluster/images/etcd/Makefile
|
||||
match: BUNDLED_ETCD_VERSIONS\?|
|
||||
---
|
||||
- name: "golang: etcd release version"
|
||||
# version: 1.22.9
|
||||
version: 1.23.7 # https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.6.md
|
||||
```
|
||||
|
||||
2. In `cluster/images/etcd/Makefile`, include the new version in `BUNDLED_ETCD_VERSIONS` and update the `LATEST_ETCD_VERSION` as well (the image tag will be generated from the `LATEST_ETCD_VERSION`). Update `GOLANG_VERSION` according to the version used to compile that release version (`"golang: etcd release version"` in step 1).
|
||||
|
||||
```Makefile
|
||||
# BUNDLED_ETCD_VERSIONS?=3.4.18 3.5.17
|
||||
BUNDLED_ETCD_VERSIONS?=3.4.18 3.5.21
|
||||
|
||||
# LATEST_ETCD_VERSION?=3.5.17
|
||||
LATEST_ETCD_VERSION?=3.5.21
|
||||
|
||||
# GOLANG_VERSION := 1.22.9
|
||||
GOLANG_VERSION := 1.23.7
|
||||
```
|
||||
|
||||
3. In `cluster/images/etcd/migrate/options.go`, include the new version in the `supportedEtcdVersions` slice.
|
||||
|
||||
```go
|
||||
var (
|
||||
// supportedEtcdVersions = []string{"3.4.18", "3.5.17"}
|
||||
supportedEtcdVersions = []string{"3.4.18", "3.5.21"}
|
||||
)
|
||||
```
|
||||
|
||||
### Publish etcd image
|
||||
|
||||
> Reference: [link](https://github.com/kubernetes/k8s.io/pull/7957)
|
||||
|
||||
1. When the previous step is merged, a post-commit job will run to build the image. You can find the newly built image in the [registry](https://gcr.io/k8s-staging-etcd/etcd).
|
||||
|
||||
2. Locate the newly built image and copy its SHA256 digest.
|
||||
|
||||
3. Inside the `kubernetes/k8s.io` repository, in `registry.k8s.io/images/k8s-staging-etcd/images.yaml`, create a new entry for the desired version and copy the SHA256 digest.
|
||||
|
||||
```yaml
|
||||
"sha256:b4a9e4a7e1cf08844c7c4db6a19cab380fbf0aad702b8c01e578e9543671b9f9": ["3.5.17-0"]
|
||||
# ADD:
|
||||
"sha256:d58c035df557080a27387d687092e3fc2b64c6d0e3162dc51453a115f847d121": ["3.5.21-0"]
|
||||
```
|
||||
|
||||
### Update to use the new etcd image
|
||||
|
||||
> Reference: [link](https://github.com/kubernetes/kubernetes/pull/131144)
|
||||
|
||||
1. In `build/dependencies.yaml`, change the `version` of `etcd` to the new version.
|
||||
|
||||
```yaml
|
||||
# etcd
|
||||
- name: "etcd"
|
||||
# version: 3.5.17
|
||||
version: 3.5.21
|
||||
refPaths:
|
||||
- path: cluster/gce/manifests/etcd.manifest
|
||||
match: etcd_docker_tag|etcd_version
|
||||
```
|
||||
|
||||
2. In `cluster/gce/manifests/etcd.manifest`, change the image tag to the new image tag and `TARGET_VERSION` to the new version.
|
||||
|
||||
```manifest
|
||||
// "image": "{{ pillar.get('etcd_docker_repository', 'registry.k8s.io/etcd') }}:{{ pillar.get('etcd_docker_tag', '3.5.17-0') }}",
|
||||
|
||||
"image": "{{ pillar.get('etcd_docker_repository', 'registry.k8s.io/etcd') }}:{{ pillar.get('etcd_docker_tag', '3.5.21-0') }}",
|
||||
|
||||
---
|
||||
|
||||
{ "name": "TARGET_VERSION",
|
||||
// "value": "{{ pillar.get('etcd_version', '3.5.17') }}"
|
||||
"value": "{{ pillar.get('etcd_version', '3.5.21') }}"
|
||||
},
|
||||
```
|
||||
|
||||
3. In `cluster/gce/upgrade-aliases.sh`, update the exports for `ETCD_IMAGE` to the new image tag and `ETCD_VERSION` to the new version.
|
||||
|
||||
```sh
|
||||
# export ETCD_IMAGE=3.5.17-0
|
||||
export ETCD_IMAGE=3.5.21-0
|
||||
# export ETCD_VERSION=3.5.17
|
||||
export ETCD_VERSION=3.5.21
|
||||
```
|
||||
|
||||
4. In `cmd/kubeadm/app/constants/constants.go`, change the `DefaultEtcdVersion` to the new version. In the same file, update `SupportedEtcdVersion` accordingly.
|
||||
|
||||
```go
|
||||
// DefaultEtcdVersion = "3.5.17-0"
|
||||
DefaultEtcdVersion = "3.5.21-0"
|
||||
|
||||
---
|
||||
|
||||
SupportedEtcdVersion = map[uint8]string{
|
||||
// 30: "3.5.17-0",
|
||||
// 31: "3.5.17-0",
|
||||
// 32: "3.5.17-0",
|
||||
// 33: "3.5.17-0",
|
||||
30: "3.5.21-0",
|
||||
31: "3.5.21-0",
|
||||
32: "3.5.21-0",
|
||||
33: "3.5.21-0",
|
||||
}
|
||||
```
|
||||
|
||||
5. In `hack/lib/etcd.sh`, update the `ETCD_VERSION`.
|
||||
|
||||
```sh
|
||||
# ETCD_VERSION=${ETCD_VERSION:-3.5.17}
|
||||
ETCD_VERSION=${ETCD_VERSION:-3.5.21}
|
||||
```
|
||||
|
||||
6. In `staging/src/k8s.io/sample-apiserver/artifacts/example/deployment.yaml`, update the etcd image used.
|
||||
|
||||
```yaml
|
||||
- name: etcd
|
||||
# image: gcr.io/etcd-development/etcd:v3.5.17
|
||||
image: gcr.io/etcd-development/etcd:v3.5.21
|
||||
```
|
||||
|
||||
7. In `test/utils/image/manifest.go`, update the etcd image tag.
|
||||
|
||||
```go
|
||||
// configs[Etcd] = Config{list.GcEtcdRegistry, "etcd", "3.5.17-0"}
|
||||
configs[Etcd] = Config{list.GcEtcdRegistry, "etcd", "3.5.21-0"}
|
||||
```
|
|
@ -147,11 +147,11 @@ References:
|
|||
|
||||
[bbolt](https://github.com/etcd-io/bbolt) and [raft](https://github.com/etcd-io/raft) are two core dependencies of etcd.
|
||||
|
||||
Both etcd 3.4.x and 3.5.x depend on bbolt 1.3.x, and etcd 3.6.x (`main` branch) depends on bbolt 1.4.x.
|
||||
Both etcd 3.4.x and 3.5.x depend on bbolt 1.3.x, and etcd 3.6.x depends on bbolt 1.4.x.
|
||||
|
||||
raft is included in the etcd repository for release-3.4 and release-3.5 branches, so etcd 3.4.x and 3.5.x do not depend on any
|
||||
external raft module. We moved raft into [a separate repository](https://github.com/etcd-io/raft) starting from 3.6 (`main` branch), and the first raft
|
||||
release will be v3.6.0, so etcd 3.6.x will depend on raft 3.6.x.
|
||||
external raft module. We moved raft into [a separate repository](https://github.com/etcd-io/raft) starting from 3.6, and the first raft
|
||||
release is v3.6.0, so etcd 3.6.0 depends on raft v3.6.0.
|
||||
|
||||
Please see the table below:
|
||||
|
||||
|
|
|
@ -4,80 +4,84 @@ This document provides an overview of etcd features and general development guid
|
|||
|
||||
## Overview
|
||||
|
||||
The etcd features fall into three stages, experimental, stable, and unsafe.
|
||||
The etcd features fall into three stages: Alpha, Beta, and GA.
|
||||
|
||||
### Experimental
|
||||
### Alpha
|
||||
|
||||
Any new feature is usually added as an experimental feature. An experimental feature is characterized as below:
|
||||
Any new feature is usually added as an Alpha feature. An Alpha feature is characterized as below:
|
||||
- Might be buggy due to a lack of user testing. Enabling the feature may not work as expected.
|
||||
- Disabled by default when added initially.
|
||||
- Disabled by default.
|
||||
- Support for such a feature may be dropped at any time without notice
|
||||
- Feature-related issues may be given lower priorities.
|
||||
- It can be removed in the next minor or major release without following the feature deprecation policy unless it graduates to a stable future.
|
||||
- It can be removed in the next minor or major release without following the feature deprecation policy unless it graduates to a more stable stage.
|
||||
|
||||
### Stable
|
||||
### Beta
|
||||
|
||||
A stable feature is characterized as below:
|
||||
A Beta feature is characterized as below:
|
||||
- Supported as part of the supported releases of etcd.
|
||||
- May be enabled by default.
|
||||
- Enabled by default.
|
||||
- Discontinuation of support must follow the feature deprecation policy.
|
||||
|
||||
### Unsafe
|
||||
### GA
|
||||
|
||||
Unsafe features are rare and listed under the `Unsafe feature:` section in the etcd usage documentation. By default, they are disabled. They should be used with caution following documentation. An unsafe feature can be removed in the next minor or major release without following the feature deprecation policy.
|
||||
A GA feature is characterized as below:
|
||||
- Supported as part of the supported releases of etcd.
|
||||
- Always enabled; you cannot disable it. The corresponding feature gate is no longer needed.
|
||||
- Discontinuation of support must follow the feature deprecation policy.
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
### Adding a new feature
|
||||
|
||||
Any new enhancements to the etcd are typically added as an experimental feature. The general development requirements are listed below. They can be somewhat flexible depending on the scope of the feature and review discussions and will evolve over time.
|
||||
- Open an issue
|
||||
Any new enhancements to the etcd are typically added as an Alpha feature.
|
||||
|
||||
etcd follows the Kubernetes [KEP process](https://github.com/kubernetes/enhancements/blob/master/keps/sig-architecture/0000-kep-process/README.md) for new enhancements. The general development requirements are listed below. They can be somewhat flexible depending on the scope of the feature and review discussions and will evolve over time.
|
||||
- Open a [KEP](https://github.com/kubernetes/enhancements/issues) issue
|
||||
- It must provide a clear need for the proposed feature.
|
||||
- It should list development work items as checkboxes. There must be one work item towards future graduation to a stable future.
|
||||
- Label the issue with `type/feature` and `experimental`.
|
||||
- It should list development work items as checkboxes. There must be one work item towards future graduation to Beta.
|
||||
- Label the issue with `/sig etcd`.
|
||||
- Keep the issue open for tracking purposes until a decision is made on graduation.
|
||||
- Open a Pull Request (PR)
|
||||
- Open a [KEP](https://github.com/kubernetes/enhancements) Pull Request (PR).
|
||||
- The KEP template can be simplified for etcd.
|
||||
- It must provide clear graduation criteria for each stage.
|
||||
- The KEP doc should reside in [keps/sig-etcd](https://github.com/kubernetes/enhancements/tree/master/keps/sig-etcd/)
|
||||
- Open Pull Requests (PRs) in [etcd](https://github.com/etcd-io/etcd)
|
||||
- Provide unit tests. Integration tests are also recommended as possible.
|
||||
- Provide robust e2e test coverage. If the feature being added is complicated or quickly needed, maintainers can decide to go with e2e tests for basic coverage initially and have robust coverage added at a later time before the feature graduation to the stable feature.
|
||||
- Provide logs for proper debugging.
|
||||
- Provide metrics and benchmarks as needed.
|
||||
- The Feature should be disabled by default.
|
||||
- Any configuration flags related to the implementation of the feature must be prefixed with `experimental` e.g. `--experimental-feature-name`.
|
||||
- Add an Alpha [feature gate](https://etcd.io/docs/v3.6/feature-gates/).
|
||||
- Any code changes or configuration flags related to the implementation of the feature must be gated with the feature gate e.g. `if cfg.ServerFeatureGate.Enabled(features.FeatureName)`.
|
||||
- Add a CHANGELOG entry.
|
||||
- At least two maintainers must approve feature requirements and related code changes.
|
||||
- At least two maintainers must approve the KEP and related code changes.
|
||||
|
||||
### Graduating an Experimental feature to Stable
|
||||
### Graduating a feature to the next stage
|
||||
|
||||
It is important that experimental features don't get stuck in that stage. They should be revisited and moved to the stable stage following the graduation steps as described here.
|
||||
|
||||
#### Locate graduation candidate
|
||||
Decide if an experimental feature is ready for graduation to the stable stage.
|
||||
- Find the issue that was used to enable the experimental feature initially. One way to find such issues is to search for issues with `type/feature` and `experimental` labels.
|
||||
- Fix any known open issues against the feature.
|
||||
- Make sure the feature was enabled for at least one previous release. Check the PR(s) reference from the issue to see when the feature-related code changes were merged.
|
||||
It is important that features don't get stuck in one stage. They should be revisited and moved to the next stage once they meet the graduation criteria listed in the KEP. A feature should stay at one stage for at least one release before being promoted.
|
||||
|
||||
#### Provide implementation
|
||||
If an experimental feature is found ready for graduation to the stable stage, open a Pull Request (PR) with the following changes.
|
||||
- Add robust e2e tests if not already provided.
|
||||
- Add a new stable feature flag identical to the experimental feature flag but without the `--experimental` prefix.
|
||||
- Deprecate the experimental feature following the [feature deprecation policy](#Deprecating-a-feature).
|
||||
- Implementation must ensure that both the graduated and deprecated experimental feature flags work as expected. Note that both these flags will co-exist for the timeframe described in the feature deprecation policy.
|
||||
- Enable the graduated feature by default if needed.
|
||||
|
||||
If a feature is found ready for graduation to the next stage, open a Pull Request (PR) with the following changes.
|
||||
- Update the feature `PreRelease` stage in `server/features/etcd_features.go`.
|
||||
- Update the status in the original KEP issue.
|
||||
|
||||
At least two maintainers must approve the work. Patch releases should not be considered for graduation.
|
||||
|
||||
### Deprecating a feature
|
||||
|
||||
#### Experimental
|
||||
An experimental feature deprecates when it graduates to the stable stage.
|
||||
- Add a deprecation message in the documentation of the experimental feature with a recommendation to use a related stable feature. e.g. `DEPRECATED. Use <feature-name> instead.`
|
||||
- Add a `deprecated` label in the issue that was initially used to enable the experimental feature.
|
||||
#### Alpha
|
||||
Alpha features can be removed without going through the deprecation process.
|
||||
- Remove the feature gate in `server/features/etcd_features.go`, and clean up all relevant code.
|
||||
- Close the original KEP issue with reasons to drop the feature.
|
||||
|
||||
#### Stable
|
||||
As the project evolves, a stable feature may sometimes need to be deprecated and removed. Such a situation should be handled using the steps below:
|
||||
- Create an issue for tracking purposes.
|
||||
- Add a deprecation message in the feature usage documentation before a planned release for feature deprecation. e.g. `To be deprecated in <release>.`. If a new feature replaces the `To be deprecated` feature, then also provide a message saying so. e.g. `Use <feature-name> instead.`.
|
||||
- Deprecate the feature in the planned release with a message as part of the feature usage documentation. e.g. `DEPRECATED`. If a new feature replaces the deprecated feature, then also provide a message saying so. e.g. `DEPRECATED. Use <feature-name> instead.`.
|
||||
- Add a `deprecated` label in the related issue.
|
||||
#### Beta and GA
|
||||
As the project evolves, a Beta/GA feature may sometimes need to be deprecated and removed. Such a situation should be handled using the steps below:
|
||||
|
||||
Remove the deprecated feature in the following release. Close any related issue(s). At least two maintainers must approve the work. Patch releases should not be considered for deprecation.
|
||||
- A Beta/GA feature can only be deprecated after at least 2 minor or major releases.
|
||||
- Update original KEP issue if it has not been closed or create a new etcd issue with reasons and steps to deprecate the feature.
|
||||
- Add the feature deprecation documentation in the release notes and feature gates documentation of the next minor/major release.
|
||||
- In the next minor/major release, set the feature gate to `{Default: false, PreRelease: featuregate.Deprecated, LockedToDefault: false}` in `server/features/etcd_features.go`. Deprecated feature gates must respond with a warning when used.
|
||||
- If the feature has GAed, and the original gated codes has been cleaned up, add the disablement codes back with the feature gate.
|
||||
- In the minor/major release after the next, set the feature gate to `{Default: false, PreRelease: featuregate.Deprecated, LockedToDefault: true}` in `server/features/etcd_features.go`, and start cleaning the code.
|
||||
|
||||
At least two maintainers must approve the work. Patch releases should not be considered for deprecation.
|
||||
|
|
|
@ -6,15 +6,17 @@ The procedure includes some manual steps for sanity checking, but it can probabl
|
|||
|
||||
## Release management
|
||||
|
||||
The following pool of release candidates manages the release of each etcd major/minor version as well as manages patches
|
||||
Under the leadership of **James Blair** [@jmhbnz](https://github.com/jmhbnz) and **Ivan Valdes Castillo** [@ivanvc](https://github.com/ivanvc), the following pool of release candidates manages the release of each etcd major/minor version as well as manages patches
|
||||
to each stable release branch. They are responsible for communicating the timelines and status of each release and
|
||||
for ensuring the stability of the release branch.
|
||||
|
||||
- Benjamin Wang [@ahrtr](https://github.com/ahrtr)
|
||||
- Fu Wei [@fuweid](https://github.com/fuweid)
|
||||
- James Blair [@jmhbnz](https://github.com/jmhbnz)
|
||||
- Ivan Valdes Castillo [@ivanvc](https://github.com/ivanvc)
|
||||
- Marek Siarkowicz [@serathius](https://github.com/serathius)
|
||||
- Sahdev Zala [@spzala](https://github.com/spzala)
|
||||
- Wenjia Zhang [@wenjiaswe](https://github.com/wenjiaswe)
|
||||
- Siyuan Zhang [@siyuanfoundation](https://github.com/siyuanfoundation)
|
||||
|
||||
All release version numbers follow the format of [semantic versioning 2.0.0](http://semver.org/).
|
||||
|
||||
|
@ -68,10 +70,14 @@ which don't need to be executed before releasing each version.
|
|||
|
||||
### Release steps
|
||||
|
||||
At least one day before the release:
|
||||
|
||||
1. Raise an issue to publish the release plan, e.g. [issues/17350](https://github.com/etcd-io/etcd/issues/17350).
|
||||
2. Raise a `kubernetes/org` pull request to temporarily elevate permissions for the GitHub release team.
|
||||
3. Once permissions are elevated, temporarily relax [branch protections](https://github.com/etcd-io/etcd/settings/branches) to allow pushing changes directly to `release-*` branches in GitHub.
|
||||
4. Verify you can pass the authentication to the image registries,
|
||||
2. Raise a `kubernetes/org` pull request ([example PR](https://github.com/kubernetes/org/pull/5582)) to ensure members of the release team are added to the [release github team](https://github.com/orgs/etcd-io/teams/release-etcd).
|
||||
|
||||
On the day of the release:
|
||||
|
||||
1. Verify you can pass the authentication to the image registries,
|
||||
- `docker login gcr.io`
|
||||
- `docker login quay.io`
|
||||
- If the release person doesn't have access to 1password, one of the owners (@ahrtr, @ivanvc, @jmhbnz, @serathius) needs to share the password with them per [this guide](https://support.1password.com/share-items/). See rough steps below,
|
||||
|
@ -80,45 +86,52 @@ which don't need to be executed before releasing each version.
|
|||
- Select `Password of quay.io`.
|
||||
- Click `Share` on the top right, and set expiration as `1 hour` and only available to the release person using his/her email.
|
||||
- Click `Copy Link` then send the link to the release person via slack or email.
|
||||
5. Clone the etcd repository and checkout the target branch,
|
||||
2. Clone the etcd repository and checkout the target branch,
|
||||
- `git clone --branch release-3.X git@github.com:etcd-io/etcd.git`
|
||||
6. Run the release script under the repository's root directory, replacing `${VERSION}` with a value without the `v` prefix, i.e. `3.5.13`.
|
||||
3. Run the release script under the repository's root directory, replacing `${VERSION}` with a value without the `v` prefix, i.e. `3.5.13`.
|
||||
- `DRY_RUN=false ./scripts/release.sh ${VERSION}`
|
||||
- **NOTE:** When doing a pre-release (i.e., a version from the main branch, 3.6.0-alpha.2), you will need to explicitly set the branch to main:
|
||||
```
|
||||
|
||||
```bash
|
||||
DRY_RUN=false BRANCH=main ./scripts/release.sh ${VERSION}
|
||||
```
|
||||
|
||||
It generates all release binaries under the directory `/tmp/etcd-release-${VERSION}/etcd/release/` and images. Binaries are pushed to the Google Cloud bucket
|
||||
under project `etcd-development`, and images are pushed to `quay.io` and `gcr.io`.
|
||||
7. Publish the release page on GitHub
|
||||
- It is advisable to do a dry run before the actual release. This will create a `/tmp` directory. Do **NOT** forget to remove this directory before the actual release.
|
||||
|
||||
```bash
|
||||
DRY_RUN=true BRANCH=${BRANCH} ./scripts/release.sh ${VERSION}
|
||||
```
|
||||
|
||||
4. Publish the release page on GitHub
|
||||
- Open the **draft** release URL shown by the release script
|
||||
- Click the pen button at the top right to edit the release
|
||||
- Review that it looks correct, reviewing that the bottom checkboxes are checked depending on the
|
||||
release version (v3.4 no checkboxes, v3.5 has the set as latest release checkbox checked,
|
||||
v3.6 has the set as pre-release checkbox checked)
|
||||
release version (v3.4 & v3.5 no checkboxes, v3.6 has the set as latest release checkbox checked,
|
||||
v3.7 has the set as pre-release checkbox checked)
|
||||
- Then, publish the release
|
||||
8. Announce to the etcd-dev googlegroup
|
||||
5. Announce to the etcd-dev googlegroup
|
||||
|
||||
Follow the format of previous release emails sent to etcd-dev@googlegroups.com, see an example below. After sending out the email, ask one of the mailing list maintainers to approve the email from the pending list. Additionally, label the release email as `Release`.
|
||||
|
||||
```text
|
||||
Hello,
|
||||
```text
|
||||
Hello,
|
||||
|
||||
etcd v3.4.30 is now public!
|
||||
etcd v3.4.30 is now public!
|
||||
|
||||
https://github.com/etcd-io/etcd/releases/tag/v3.4.30
|
||||
https://github.com/etcd-io/etcd/releases/tag/v3.4.30
|
||||
|
||||
Thanks to everyone who contributed to the release!
|
||||
Thanks to everyone who contributed to the release!
|
||||
|
||||
etcd team
|
||||
```
|
||||
etcd team
|
||||
```
|
||||
|
||||
9. Update the changelog to reflect the correct release date.
|
||||
10. Paste the release link to the issue raised in Step 1 and close the issue.
|
||||
11. Restore standard branch protection settings and raise a follow-up `kubernetes/org` pull request to return to least privilege permissions.
|
||||
12. Crease a new stable branch through `git push origin release-${VERSION_MAJOR}.${VERSION_MINOR}` if this is a new major or minor stable release.
|
||||
13. Re-generate a new password for quay.io if needed (e.g. shared to a contributor who isn't in the release team, and we should rotate the password at least once every 3 months).
|
||||
6. Update the changelog to reflect the correct release date.
|
||||
7. Paste the release link to the issue raised in Step 1 and close the issue.
|
||||
8. Raise a follow-up `kubernetes/org` pull request to return the GitHub release team to empty, least privilege state.
|
||||
9. Crease a new stable branch through `git push origin release-${VERSION_MAJOR}.${VERSION_MINOR}` if this is a new major or minor stable release.
|
||||
10. Re-generate a new password for quay.io if needed (e.g. shared to a contributor who isn't in the release team, and we should rotate the password at least once every 3 months).
|
||||
|
||||
#### Release known issues
|
||||
|
||||
|
|
|
@ -12,18 +12,18 @@ Each item has an assigned priority. Refer to [priority definitions](https://gith
|
|||
|
||||
For a full list of tasks in `v3.6.0`, please see [milestone etcd-v3.6](https://github.com/etcd-io/etcd/milestone/38).
|
||||
|
||||
| Title | Priority | Status | Note |
|
||||
|--------------------------------------------------------------------------------------------------------------------|----------|-------------|--------------------------------------------------------------------------------------------------------------|
|
||||
| [Support downgrade](https://github.com/etcd-io/etcd/issues/11716) | priority/important-soon | In progress | etcd will support downgrade starting from 3.6.0. But it will also support offline downgrade from 3.5 to 3.4. |
|
||||
| [StoreV2 deprecation](https://github.com/etcd-io/etcd/issues/12913) | priority/important-soon | In progress | This task will be covered in both 3.6 and 3.7. |
|
||||
| [Release raft 3.6.0](https://github.com/etcd-io/raft/issues/89) | priority/important-soon | Not started | etcd 3.6.0 will depends on raft 3.6.0 |
|
||||
| [Release bbolt 1.4.0](https://github.com/etcd-io/bbolt/issues/553) | priority/important-soon | Not started | etcd 3.6.0 will depends on bbolt 1.4.0 |
|
||||
| [Support /livez and /readyz endpoints](https://github.com/etcd-io/etcd/issues/16007) | priority/important-longterm | In progress | It provides clearer APIs, and can also work around the stalled writes issue |
|
||||
| Title | Priority | Status | Note |
|
||||
|--------------------------------------------------------------------------------------------------------------------|-----------------------------|-------------|--------------------------------------------------------------------------------------------------------------|
|
||||
| [Support downgrade](https://github.com/etcd-io/etcd/issues/11716) | priority/important-soon | In progress | etcd will support downgrade starting from 3.6.0. But it will also support offline downgrade from 3.5 to 3.4. |
|
||||
| [StoreV2 deprecation](https://github.com/etcd-io/etcd/issues/12913) | priority/important-soon | In progress | This task will be covered in both 3.6 and 3.7. |
|
||||
| [Release raft 3.6.0](https://github.com/etcd-io/raft/issues/89) | priority/important-soon | Completed | etcd 3.6.0 will depends on raft 3.6.0 |
|
||||
| [Release bbolt 1.4.0](https://github.com/etcd-io/bbolt/issues/553) | priority/important-soon | Completed | etcd 3.6.0 will depends on bbolt 1.4.0 |
|
||||
| [Support /livez and /readyz endpoints](https://github.com/etcd-io/etcd/issues/16007) | priority/important-longterm | Completed | It provides clearer APIs, and can also work around the stalled writes issue |
|
||||
| [Bump gRPC](https://github.com/etcd-io/etcd/issues/16290) | priority/important-longterm | Completed | It isn't guaranteed to be resolved in 3.6, and might be postponed to 3.7 depending on the effort and risk. |
|
||||
| [Deprecate grpc-gateway or bump it](https://github.com/etcd-io/etcd/issues/14499) | priority/important-longterm | Completed | It isn't guaranteed to be resolved in 3.6, and might be postponed to 3.7 depending on the effort and risk. |
|
||||
| [bbolt: Add logger into bbolt](https://github.com/etcd-io/bbolt/issues/509) | priority/important-longterm | Completed | It's important to diagnose bbolt issues |
|
||||
| [bbolt: Add surgery commands](https://github.com/etcd-io/bbolt/issues/370) | priority/important-longterm | Completed | Surgery commands are important for fixing corrupted db files |
|
||||
| [Evaluate and (Gradulate or deprecate/remove) experimental features](https://github.com/etcd-io/etcd/issues/16292) | priority/backlog | Not started | This task will be covered in both 3.6 and 3.7. |
|
||||
| [Evaluate and (Gradulate or deprecate/remove) experimental features](https://github.com/etcd-io/etcd/issues/16292) | priority/backlog | Not started | This task will be covered in both 3.6 and 3.7. |
|
||||
|
||||
## v3.7.0
|
||||
|
||||
|
@ -32,8 +32,9 @@ For a full list of tasks in `v3.7.0`, please see [milestone etcd-v3.7](https://g
|
|||
| Title | Priority | Note |
|
||||
|-------------------------------------------------------------------------------------------------------------------|----------|-----------------------------------------------------------------------------------|
|
||||
| [StoreV2 deprecation](https://github.com/etcd-io/etcd/issues/12913) | P0 | Finish the remaining tasks 3.7. |
|
||||
| [Support range stream](https://github.com/etcd-io/etcd/issues/12342) | P0 | to be investigated & discussed. |
|
||||
| [Refactor lease: Lease might be revoked by mistake by old leader](https://github.com/etcd-io/etcd/issues/15247) | P1 | to be investigated & discussed |
|
||||
| [Integrate raft's new feature (async write) into etcd](https://github.com/etcd-io/etcd/issues/16291) | P1 | It should improve the performance |
|
||||
| [Integrate raft's new feature (async write) into etcd](https://github.com/etcd-io/etcd/issues/16291) | P1 | It should improve the performance |
|
||||
| [bbolt: Support customizing the bbolt rebalance threshold](https://github.com/etcd-io/bbolt/issues/422) | P2 | It may get rid of etcd's defragmentation. Both bbolt and etcd need to be changed. |
|
||||
| [Evaluate and (graduate or deprecate/remove) experimental features](https://github.com/etcd-io/etcd/issues/16292) | P2 | Finish the remaining tasks 3.7. |
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ Following are a few example searches on PR for convenience:
|
|||
|
||||
## Scope
|
||||
|
||||
These guidelines serve as a primary document for managing PRs in `etcd`. Everyone is welcome to help manage PRs but the work and responsibilities discussed in this document are created with `etcd` maintainers and active contributors in mind.
|
||||
These guidelines serve as a primary document for managing PRs and review policy in `etcd`. Everyone is welcome to help manage PRs but the work and responsibilities discussed in this document are created with `etcd` maintainers and active contributors in mind.
|
||||
|
||||
## Ensure tests are run
|
||||
|
||||
|
@ -30,3 +30,32 @@ Reviewers are responsive in a timely fashion, but considering everyone is busy,
|
|||
## Verify important labels are in place
|
||||
|
||||
Make sure that appropriate reviewers are added to the PR. Also, make sure that a milestone is identified. If any of these or other important labels are missing, add them. If a correct label cannot be decided, leave a comment for the maintainers to do so as needed.
|
||||
|
||||
## Review policy
|
||||
|
||||
To ensure code quality and shared ownership, this review policy applies to all pull requests (PRs).
|
||||
|
||||
### Default rule
|
||||
|
||||
PRs should get at least two approvals (/lgtm or GitHub review approval) before merging.
|
||||
|
||||
Notes:
|
||||
|
||||
* Approvals should come from a maintainer, reviewer, or submodule owner familiar with the relevant code or area.
|
||||
* If there’s disagreement, maintainers should discuss and agree before merging.
|
||||
|
||||
### Exceptions for Less Impactful PRs
|
||||
|
||||
For low-risk changes — such as:
|
||||
|
||||
* CI workflows
|
||||
* Documentation
|
||||
* Comments
|
||||
|
||||
The rule can be relaxed:
|
||||
|
||||
* One approval is generally enough.
|
||||
|
||||
However:
|
||||
|
||||
* If the author is a maintainer, they should still get approval from another maintainer, reviewer, or submodule owner, even for minor changes.
|
||||
|
|
|
@ -36,7 +36,12 @@ weeks inactive voting period and as long as two maintainers are on board.
|
|||
|
||||
Changes in project governance could be initiated by opening a GitHub PR.
|
||||
|
||||
## SIG-etcd Governance
|
||||
|
||||
[SIG-etcd Governance] is documented in the Kubernetes/community repository.
|
||||
|
||||
[community membership]: /Documentation/contributor-guide/community-membership.md
|
||||
[Code of Conduct]: /code-of-conduct.md
|
||||
[contributor guide]: /CONTRIBUTING.md
|
||||
[maintainers]: /OWNERS
|
||||
[SIG-etcd Governance]: https://github.com/kubernetes/community/blob/master/sig-etcd/charter.md#deviations-from-sig-governance
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -187,7 +187,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2013 The etcd Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
16
Makefile
16
Makefile
|
@ -1,6 +1,8 @@
|
|||
REPOSITORY_ROOT := $(shell git rev-parse --show-toplevel)
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
include tests/robustness/makefile.mk
|
||||
include $(REPOSITORY_ROOT)/tests/robustness/Makefile
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
|
@ -54,9 +56,10 @@ test-grpcproxy-e2e: build
|
|||
test-e2e-release: build
|
||||
PASSES="release e2e" ./scripts/test.sh $(GO_TEST_FLAGS)
|
||||
|
||||
# When we release the first 3.7.0-alpha.0, we can remove `VERSION="3.7.99"` below.
|
||||
.PHONY: test-release
|
||||
test-release:
|
||||
PASSES="release_tests" ./scripts/test.sh $(GO_TEST_FLAGS)
|
||||
PASSES="release_tests" VERSION="3.7.99" ./scripts/test.sh $(GO_TEST_FLAGS)
|
||||
|
||||
.PHONY: test-robustness
|
||||
test-robustness:
|
||||
|
@ -184,12 +187,9 @@ endif
|
|||
|
||||
# Tools
|
||||
|
||||
GOLANGCI_LINT_VERSION = $(shell cd tools/mod && go list -m -f {{.Version}} github.com/golangci/golangci-lint)
|
||||
.PHONY: install-golangci-lint
|
||||
install-golangci-lint:
|
||||
ifeq (, $(shell which golangci-lint))
|
||||
$(shell curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin $(GOLANGCI_LINT_VERSION))
|
||||
endif
|
||||
./scripts/verify_golangci-lint_version.sh
|
||||
|
||||
.PHONY: install-lazyfs
|
||||
install-lazyfs: bin/lazyfs
|
||||
|
@ -225,3 +225,7 @@ verify-go-versions:
|
|||
.PHONY: sync-toolchain-directive
|
||||
sync-toolchain-directive:
|
||||
./scripts/sync_go_toolchain_directive.sh
|
||||
|
||||
.PHONY: markdown-diff-lint
|
||||
markdown-diff-lint:
|
||||
./scripts/markdown_diff_lint.sh
|
||||
|
|
16
OWNERS
16
OWNERS
|
@ -2,11 +2,23 @@
|
|||
|
||||
approvers:
|
||||
- ahrtr # Benjamin Wang <benjamin.ahrtr@gmail.com> <benjamin.wang@broadcom.com>
|
||||
- fuweid # Wei Fu <fuweid89@gmail.com>
|
||||
- jmhbnz # James Blair <jablair@redhat.com> <mail@jamesblair.net>
|
||||
- serathius # Marek Siarkowicz <siarkowicz@google.com> <marek.siarkowicz@gmail.com>
|
||||
- spzala # Sahdev Zala <spzala@us.ibm.com>
|
||||
- wenjiaswe # Wenjia Zhang <wenjiazhang@google.com> <wenjia.swe@gmail.com>
|
||||
reviewers:
|
||||
- fuweid # Wei Fu <fuweid89@gmail.com>
|
||||
- ivanvc # Ivan Valdes <ivan@vald.es>
|
||||
- siyuanfoundation # Siyuan Zhang <sizhang@google.com> <physicsbug@gmail.com>
|
||||
emeritus_approvers:
|
||||
- bdarnell # Ben Darnell <ben@bendarnell.com>
|
||||
- fanminshi # Fanmin Shi <fanmin.shi@gmail.com>
|
||||
- gyuho # Gyuho Lee <gyuhox@gmail.com>
|
||||
- hexfusion # Sam Batschelet <sbatsche@redhat.com>
|
||||
- heyitsanthony # Anthony Romano <romanoanthony061@gmail.com>
|
||||
- jingyih # Jingyi Hu <jingyih@google.com>
|
||||
- jpbetz # Joe Betz <jpbetz@google.com>
|
||||
- mitake # Hitoshi Mitake <h.mitake@gmail.com>
|
||||
- philips # Brandon Philips <brandon@ifup.org>
|
||||
- ptabor # Piotr Tabor <piotr.tabor@gmail.com>
|
||||
- wenjiaswe # Wenjia Zhang <wenjiazhang@google.com> <wenjia.swe@gmail.com>
|
||||
- xiang90 # Xiang Li <xiangli.cs@gmail.com>
|
||||
|
|
28
README.md
28
README.md
|
@ -5,7 +5,7 @@
|
|||
[](https://github.com/etcd-io/etcd/actions/workflows/tests.yaml)
|
||||
[](https://github.com/etcd-io/etcd/actions/workflows/codeql-analysis.yml)
|
||||
[](https://etcd.io/docs)
|
||||
[](https://godoc.org/github.com/etcd-io/etcd)
|
||||
[](https://godocs.io/go.etcd.io/etcd/v3)
|
||||
[](https://github.com/etcd-io/etcd/releases)
|
||||
[](https://github.com/etcd-io/etcd/blob/main/LICENSE)
|
||||
[](https://scorecard.dev/viewer/?uri=github.com/etcd-io/etcd)
|
||||
|
@ -42,6 +42,18 @@ See [etcdctl][etcdctl] for a simple command line client.
|
|||
[vulcand]: https://github.com/vulcand/vulcand
|
||||
[etcdctl]: https://github.com/etcd-io/etcd/tree/main/etcdctl
|
||||
|
||||
## Documentation
|
||||
|
||||
The most common API documentation you'll need can be found here:
|
||||
|
||||
* [go.etcd.io/etcd/api/v3](https://godocs.io/go.etcd.io/etcd/api/v3)
|
||||
* [go.etcd.io/etcd/client/pkg/v3](https://godocs.io/go.etcd.io/etcd/client/pkg/v3)
|
||||
* [go.etcd.io/etcd/client/v3](https://godocs.io/go.etcd.io/etcd/client/v3)
|
||||
* [go.etcd.io/etcd/etcdctl/v3](https://godocs.io/go.etcd.io/etcd/etcdctl/v3)
|
||||
* [go.etcd.io/etcd/pkg/v3](https://godocs.io/go.etcd.io/etcd/pkg/v3)
|
||||
* [go.etcd.io/etcd/raft/v3](https://godocs.io/go.etcd.io/etcd/raft/v3)
|
||||
* [go.etcd.io/etcd/server/v3](https://godocs.io/go.etcd.io/etcd/server/v3)
|
||||
|
||||
## Maintainers
|
||||
|
||||
[Maintainers](OWNERS) strive to shape an inclusive open source project culture where users are heard and contributors feel respected and empowered. Maintainers aim to build productive relationships across different companies and disciplines. Read more about [Maintainers role and responsibilities](Documentation/contributor-guide/community-membership.md#maintainers).
|
||||
|
@ -186,19 +198,7 @@ See [PR management](https://github.com/etcd-io/etcd/blob/main/Documentation/cont
|
|||
|
||||
## etcd Emeritus Maintainers
|
||||
|
||||
These emeritus maintainers dedicated a part of their career to etcd and reviewed code, triaged bugs and pushed the project forward over a substantial period of time. Their contribution is greatly appreciated.
|
||||
|
||||
* Fanmin Shi
|
||||
* Anthony Romano
|
||||
* Brandon Philips
|
||||
* Joe Betz
|
||||
* Gyuho Lee
|
||||
* Jingyi Hu
|
||||
* Xiang Li
|
||||
* Ben Darnell
|
||||
* Sam Batschelet
|
||||
* Piotr Tabor
|
||||
* Hitoshi Mitake
|
||||
etcd [emeritus maintainers](OWNERS) dedicated a part of their career to etcd and reviewed code, triaged bugs and pushed the project forward over a substantial period of time. Their contribution is greatly appreciated.
|
||||
|
||||
### License
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2020 The etcd Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -46,6 +46,9 @@ func request_KV_Range_0(ctx context.Context, marshaler runtime.Marshaler, client
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.Range(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -70,6 +73,9 @@ func request_KV_Put_0(ctx context.Context, marshaler runtime.Marshaler, client e
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.Put(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -94,6 +100,9 @@ func request_KV_DeleteRange_0(ctx context.Context, marshaler runtime.Marshaler,
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.DeleteRange(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -118,6 +127,9 @@ func request_KV_Txn_0(ctx context.Context, marshaler runtime.Marshaler, client e
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.Txn(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -142,6 +154,9 @@ func request_KV_Compact_0(ctx context.Context, marshaler runtime.Marshaler, clie
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.Compact(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -209,6 +224,9 @@ func request_Lease_LeaseGrant_0(ctx context.Context, marshaler runtime.Marshaler
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.LeaseGrant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -233,6 +251,9 @@ func request_Lease_LeaseRevoke_0(ctx context.Context, marshaler runtime.Marshale
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.LeaseRevoke(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -257,6 +278,9 @@ func request_Lease_LeaseRevoke_1(ctx context.Context, marshaler runtime.Marshale
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.LeaseRevoke(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -324,6 +348,9 @@ func request_Lease_LeaseTimeToLive_0(ctx context.Context, marshaler runtime.Mars
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.LeaseTimeToLive(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -348,6 +375,9 @@ func request_Lease_LeaseTimeToLive_1(ctx context.Context, marshaler runtime.Mars
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.LeaseTimeToLive(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -372,6 +402,9 @@ func request_Lease_LeaseLeases_0(ctx context.Context, marshaler runtime.Marshale
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.LeaseLeases(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -396,6 +429,9 @@ func request_Lease_LeaseLeases_1(ctx context.Context, marshaler runtime.Marshale
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.LeaseLeases(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -420,6 +456,9 @@ func request_Cluster_MemberAdd_0(ctx context.Context, marshaler runtime.Marshale
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.MemberAdd(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -444,6 +483,9 @@ func request_Cluster_MemberRemove_0(ctx context.Context, marshaler runtime.Marsh
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.MemberRemove(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -468,6 +510,9 @@ func request_Cluster_MemberUpdate_0(ctx context.Context, marshaler runtime.Marsh
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.MemberUpdate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -492,6 +537,9 @@ func request_Cluster_MemberList_0(ctx context.Context, marshaler runtime.Marshal
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.MemberList(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -516,6 +564,9 @@ func request_Cluster_MemberPromote_0(ctx context.Context, marshaler runtime.Mars
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.MemberPromote(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -540,6 +591,9 @@ func request_Maintenance_Alarm_0(ctx context.Context, marshaler runtime.Marshale
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.Alarm(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -564,6 +618,9 @@ func request_Maintenance_Status_0(ctx context.Context, marshaler runtime.Marshal
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.Status(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -588,6 +645,9 @@ func request_Maintenance_Defragment_0(ctx context.Context, marshaler runtime.Mar
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.Defragment(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -612,6 +672,9 @@ func request_Maintenance_Hash_0(ctx context.Context, marshaler runtime.Marshaler
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.Hash(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -636,6 +699,9 @@ func request_Maintenance_HashKV_0(ctx context.Context, marshaler runtime.Marshal
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.HashKV(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -660,6 +726,9 @@ func request_Maintenance_Snapshot_0(ctx context.Context, marshaler runtime.Marsh
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
stream, err := client.Snapshot(ctx, &protoReq)
|
||||
if err != nil {
|
||||
return nil, metadata, err
|
||||
|
@ -680,6 +749,9 @@ func request_Maintenance_MoveLeader_0(ctx context.Context, marshaler runtime.Mar
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.MoveLeader(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -704,6 +776,9 @@ func request_Maintenance_Downgrade_0(ctx context.Context, marshaler runtime.Mars
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.Downgrade(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -728,6 +803,9 @@ func request_Auth_AuthEnable_0(ctx context.Context, marshaler runtime.Marshaler,
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.AuthEnable(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -752,6 +830,9 @@ func request_Auth_AuthDisable_0(ctx context.Context, marshaler runtime.Marshaler
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.AuthDisable(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -776,6 +857,9 @@ func request_Auth_AuthStatus_0(ctx context.Context, marshaler runtime.Marshaler,
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.AuthStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -800,6 +884,9 @@ func request_Auth_Authenticate_0(ctx context.Context, marshaler runtime.Marshale
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.Authenticate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -824,6 +911,9 @@ func request_Auth_UserAdd_0(ctx context.Context, marshaler runtime.Marshaler, cl
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.UserAdd(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -848,6 +938,9 @@ func request_Auth_UserGet_0(ctx context.Context, marshaler runtime.Marshaler, cl
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.UserGet(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -872,6 +965,9 @@ func request_Auth_UserList_0(ctx context.Context, marshaler runtime.Marshaler, c
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.UserList(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -896,6 +992,9 @@ func request_Auth_UserDelete_0(ctx context.Context, marshaler runtime.Marshaler,
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.UserDelete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -920,6 +1019,9 @@ func request_Auth_UserChangePassword_0(ctx context.Context, marshaler runtime.Ma
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.UserChangePassword(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -944,6 +1046,9 @@ func request_Auth_UserGrantRole_0(ctx context.Context, marshaler runtime.Marshal
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.UserGrantRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -968,6 +1073,9 @@ func request_Auth_UserRevokeRole_0(ctx context.Context, marshaler runtime.Marsha
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.UserRevokeRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -992,6 +1100,9 @@ func request_Auth_RoleAdd_0(ctx context.Context, marshaler runtime.Marshaler, cl
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.RoleAdd(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -1016,6 +1127,9 @@ func request_Auth_RoleGet_0(ctx context.Context, marshaler runtime.Marshaler, cl
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.RoleGet(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -1040,6 +1154,9 @@ func request_Auth_RoleList_0(ctx context.Context, marshaler runtime.Marshaler, c
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.RoleList(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -1064,6 +1181,9 @@ func request_Auth_RoleDelete_0(ctx context.Context, marshaler runtime.Marshaler,
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.RoleDelete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -1088,6 +1208,9 @@ func request_Auth_RoleGrantPermission_0(ctx context.Context, marshaler runtime.M
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.RoleGrantPermission(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
@ -1112,6 +1235,9 @@ func request_Auth_RoleRevokePermission_0(ctx context.Context, marshaler runtime.
|
|||
if err := marshaler.NewDecoder(req.Body).Decode(protov1.MessageV2(&protoReq)); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
msg, err := client.RoleRevokePermission(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return protov1.MessageV2(msg), metadata, err
|
||||
}
|
||||
|
|
29
api/go.mod
29
api/go.mod
|
@ -1,29 +1,30 @@
|
|||
module go.etcd.io/etcd/api/v3
|
||||
|
||||
go 1.23.0
|
||||
go 1.24
|
||||
|
||||
toolchain go1.23.11
|
||||
toolchain go1.24.5
|
||||
|
||||
require (
|
||||
github.com/coreos/go-semver v0.3.1
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/protobuf v1.5.4
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb
|
||||
google.golang.org/grpc v1.71.1
|
||||
google.golang.org/protobuf v1.36.5
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822
|
||||
google.golang.org/grpc v1.74.2
|
||||
google.golang.org/protobuf v1.36.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect
|
||||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
|
|
69
api/go.sum
69
api/go.sum
|
@ -1,10 +1,9 @@
|
|||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
|
@ -15,34 +14,34 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
|||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -52,20 +51,20 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
|
@ -74,14 +73,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
|
||||
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
var (
|
||||
// MinClusterVersion is the min cluster version this etcd binary is compatible with.
|
||||
MinClusterVersion = "3.0.0"
|
||||
Version = "3.6.4"
|
||||
Version = "3.7.0-alpha.0"
|
||||
APIVersion = "unknown"
|
||||
|
||||
// Git SHA Value will be set during build
|
||||
|
@ -43,6 +43,7 @@ var (
|
|||
V3_5 = semver.Version{Major: 3, Minor: 5}
|
||||
V3_6 = semver.Version{Major: 3, Minor: 6}
|
||||
V3_7 = semver.Version{Major: 3, Minor: 7}
|
||||
V3_8 = semver.Version{Major: 3, Minor: 8}
|
||||
V4_0 = semver.Version{Major: 4, Minor: 0}
|
||||
|
||||
// AllVersions keeps all the versions in ascending order.
|
||||
|
|
|
@ -10,6 +10,15 @@
|
|||
},
|
||||
{
|
||||
"project": "github.com/anishathalye/porcupine",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT License",
|
||||
"confidence": 0.96875
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "github.com/antithesishq/antithesis-sdk-go",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT License",
|
||||
|
@ -36,7 +45,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"project": "github.com/cenkalti/backoff/v4",
|
||||
"project": "github.com/cenkalti/backoff/v5",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT License",
|
||||
|
@ -260,33 +269,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "github.com/klauspost/compress",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 0.9376299376299376
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "github.com/klauspost/compress/internal/snapref",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "BSD 3-clause \"New\" or \"Revised\" License",
|
||||
"confidence": 0.9663865546218487
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "github.com/klauspost/compress/zstd/internal/xxhash",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT License",
|
||||
"confidence": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "github.com/mattn/go-colorable",
|
||||
"licenses": [
|
||||
|
@ -323,6 +305,24 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "github.com/olekukonko/errors",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT License",
|
||||
"confidence": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "github.com/olekukonko/ll",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT License",
|
||||
"confidence": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "github.com/olekukonko/tablewriter",
|
||||
"licenses": [
|
||||
|
@ -472,7 +472,7 @@
|
|||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
"confidence": 0.9988925802879292
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -481,7 +481,7 @@
|
|||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
"confidence": 0.9988925802879292
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -490,7 +490,7 @@
|
|||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
"confidence": 0.9988925802879292
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -499,7 +499,7 @@
|
|||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
"confidence": 0.9988925802879292
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -508,7 +508,7 @@
|
|||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
"confidence": 0.9988925802879292
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -517,7 +517,7 @@
|
|||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
"confidence": 0.9988925802879292
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -526,7 +526,7 @@
|
|||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
"confidence": 0.9988925802879292
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -535,7 +535,7 @@
|
|||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
"confidence": 0.9988925802879292
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -544,7 +544,7 @@
|
|||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
"confidence": 0.9988925802879292
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -665,6 +665,19 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "go.yaml.in/yaml/v2",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
},
|
||||
{
|
||||
"type": "MIT License",
|
||||
"confidence": 0.8975609756097561
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "golang.org/x/crypto",
|
||||
"licenses": [
|
||||
|
@ -773,15 +786,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "sigs.k8s.io/json",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 0.9617021276595744
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "sigs.k8s.io/yaml",
|
||||
"licenses": [
|
||||
|
@ -794,18 +798,5 @@
|
|||
"confidence": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"project": "sigs.k8s.io/yaml/goyaml.v2",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "Apache License 2.0",
|
||||
"confidence": 1
|
||||
},
|
||||
{
|
||||
"type": "MIT License",
|
||||
"confidence": 0.8975609756097561
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 The etcd Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,4 @@
|
|||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
labels:
|
||||
- area/cache
|
|
@ -0,0 +1,3 @@
|
|||
# etcd cache
|
||||
|
||||
Experimental etcd client cache library.
|
|
@ -0,0 +1,388 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
// TODO: add gap-free replay for arbitrary startRevs and drop this guard.
|
||||
// Returned when an option combination isn’t yet handled by the cache (e.g. WithPrevKV, WithProgressNotify for Watch(), WithCountOnly for Get()).
|
||||
ErrUnsupportedRequest = errors.New("cache: unsupported request parameters")
|
||||
// Returned when the requested key or key‑range is invalid (empty or reversed) or lies outside c.prefix.
|
||||
ErrKeyRangeInvalid = errors.New("cache: invalid or out‑of‑range key range")
|
||||
)
|
||||
|
||||
// Cache buffers a single etcd Watch for a given key‐prefix and fan‑outs local watchers.
|
||||
type Cache struct {
|
||||
prefix string // prefix is the key-prefix this shard is responsible for ("" = root).
|
||||
cfg Config // immutable runtime configuration
|
||||
watcher clientv3.Watcher
|
||||
kv clientv3.KV
|
||||
demux *demux // demux fans incoming events out to active watchers and manages resync.
|
||||
store *store // last‑observed snapshot
|
||||
ready chan struct{}
|
||||
stop context.CancelFunc
|
||||
waitGroup sync.WaitGroup
|
||||
internalCtx context.Context
|
||||
}
|
||||
|
||||
// New builds a cache shard that watches only the requested prefix.
|
||||
// For the root cache pass "".
|
||||
func New(client *clientv3.Client, prefix string, opts ...Option) (*Cache, error) {
|
||||
cfg := defaultConfig()
|
||||
for _, opt := range opts {
|
||||
opt(&cfg)
|
||||
}
|
||||
|
||||
if cfg.HistoryWindowSize <= 0 {
|
||||
return nil, fmt.Errorf("invalid HistoryWindowSize %d (must be > 0)", cfg.HistoryWindowSize)
|
||||
}
|
||||
|
||||
internalCtx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
cache := &Cache{
|
||||
prefix: prefix,
|
||||
cfg: cfg,
|
||||
watcher: client.Watcher,
|
||||
kv: client.KV,
|
||||
store: newStore(),
|
||||
ready: make(chan struct{}),
|
||||
stop: cancel,
|
||||
internalCtx: internalCtx,
|
||||
}
|
||||
|
||||
cache.demux = NewDemux(internalCtx, &cache.waitGroup, cfg.HistoryWindowSize, cfg.ResyncInterval)
|
||||
|
||||
cache.waitGroup.Add(1)
|
||||
go func() {
|
||||
defer cache.waitGroup.Done()
|
||||
cache.getWatchLoop(internalCtx)
|
||||
}()
|
||||
|
||||
return cache, nil
|
||||
}
|
||||
|
||||
// Watch registers a cache-backed watcher for a given key or prefix.
|
||||
// It returns a WatchChan that streams WatchResponses containing events.
|
||||
func (c *Cache) Watch(ctx context.Context, key string, opts ...clientv3.OpOption) clientv3.WatchChan {
|
||||
if err := c.WaitReady(ctx); err != nil {
|
||||
emptyWatchChan := make(chan clientv3.WatchResponse)
|
||||
close(emptyWatchChan)
|
||||
return emptyWatchChan
|
||||
}
|
||||
|
||||
op := clientv3.OpWatch(key, opts...)
|
||||
startRev := op.Rev()
|
||||
|
||||
if startRev != 0 {
|
||||
if oldest := c.demux.PeekOldest(); oldest != 0 && startRev < oldest {
|
||||
ch := make(chan clientv3.WatchResponse, 1)
|
||||
ch <- clientv3.WatchResponse{
|
||||
Canceled: true,
|
||||
CompactRevision: startRev,
|
||||
}
|
||||
close(ch)
|
||||
return ch
|
||||
}
|
||||
}
|
||||
|
||||
pred, err := c.validateWatch(key, op)
|
||||
if err != nil {
|
||||
ch := make(chan clientv3.WatchResponse, 1)
|
||||
ch <- clientv3.WatchResponse{Canceled: true, CancelReason: err.Error()}
|
||||
close(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
w := newWatcher(c.cfg.PerWatcherBufferSize, pred)
|
||||
c.demux.Register(w, startRev)
|
||||
|
||||
responseChan := make(chan clientv3.WatchResponse)
|
||||
c.waitGroup.Add(1)
|
||||
go func() {
|
||||
defer c.waitGroup.Done()
|
||||
defer close(responseChan)
|
||||
defer c.demux.Unregister(w)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-c.internalCtx.Done():
|
||||
return
|
||||
case events, ok := <-w.eventQueue:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-c.internalCtx.Done():
|
||||
return
|
||||
case responseChan <- clientv3.WatchResponse{Events: events}:
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
return responseChan
|
||||
}
|
||||
|
||||
func (c *Cache) Get(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) {
|
||||
if err := c.WaitReady(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
op := clientv3.OpGet(key, opts...)
|
||||
|
||||
if _, err := c.validateGet(key, op); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
startKey := []byte(key)
|
||||
endKey := op.RangeBytes()
|
||||
kvs, rev, err := c.store.Get(startKey, endKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &clientv3.GetResponse{
|
||||
Header: &pb.ResponseHeader{Revision: rev},
|
||||
Kvs: kvs,
|
||||
Count: int64(len(kvs)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Ready reports whether the cache has finished its initial load.
|
||||
func (c *Cache) Ready() bool {
|
||||
select {
|
||||
case <-c.ready:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// WaitReady blocks until the cache is ready or the ctx is cancelled.
|
||||
func (c *Cache) WaitReady(ctx context.Context) error {
|
||||
select {
|
||||
case <-c.ready:
|
||||
return ctx.Err()
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache) WaitForRevision(ctx context.Context, rev int64) error {
|
||||
for {
|
||||
if c.store.LatestRev() >= rev {
|
||||
return nil
|
||||
}
|
||||
select {
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close cancels the private context and blocks until all goroutines return.
|
||||
func (c *Cache) Close() {
|
||||
c.stop()
|
||||
c.waitGroup.Wait()
|
||||
}
|
||||
|
||||
func (c *Cache) getWatchLoop(ctx context.Context) {
|
||||
cfg := defaultConfig()
|
||||
backoff := cfg.InitialBackoff
|
||||
for {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return
|
||||
}
|
||||
if err := c.getWatch(ctx); err != nil {
|
||||
fmt.Printf("getWatch failed, will retry after %v: %v\n", backoff, err)
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(backoff):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache) getWatch(ctx context.Context) error {
|
||||
getResp, err := c.get(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.watch(ctx, getResp.Header.Revision+1)
|
||||
}
|
||||
|
||||
func (c *Cache) get(ctx context.Context) (*clientv3.GetResponse, error) {
|
||||
resp, err := c.kv.Get(ctx, c.prefix, clientv3.WithPrefix())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.store.Restore(resp.Kvs, resp.Header.Revision)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *Cache) watch(ctx context.Context, rev int64) error {
|
||||
readyOnce := sync.Once{}
|
||||
for {
|
||||
watchCh := c.watcher.Watch(
|
||||
ctx,
|
||||
c.prefix,
|
||||
clientv3.WithPrefix(),
|
||||
clientv3.WithRev(rev),
|
||||
clientv3.WithProgressNotify(),
|
||||
clientv3.WithCreatedNotify(),
|
||||
)
|
||||
|
||||
for resp := range watchCh {
|
||||
readyOnce.Do(func() { close(c.ready) })
|
||||
if err := resp.Err(); err != nil {
|
||||
c.demux.Purge()
|
||||
c.resetReady()
|
||||
c.store.Reset()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.store.Apply(resp.Events); err != nil {
|
||||
c.demux.Purge()
|
||||
c.resetReady()
|
||||
c.store.Reset()
|
||||
return err
|
||||
}
|
||||
c.demux.Broadcast(resp.Events)
|
||||
}
|
||||
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache) resetReady() {
|
||||
select {
|
||||
case <-c.ready:
|
||||
c.ready = make(chan struct{})
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache) validateWatch(key string, op clientv3.Op) (pred KeyPredicate, err error) {
|
||||
switch {
|
||||
case op.IsPrevKV():
|
||||
return nil, fmt.Errorf("%w: PrevKV not supported", ErrUnsupportedRequest)
|
||||
case op.IsFragment():
|
||||
return nil, fmt.Errorf("%w: Fragment not supported", ErrUnsupportedRequest)
|
||||
case op.IsProgressNotify():
|
||||
return nil, fmt.Errorf("%w: ProgressNotify not supported", ErrUnsupportedRequest)
|
||||
case op.IsCreatedNotify():
|
||||
return nil, fmt.Errorf("%w: CreatedNotify not supported", ErrUnsupportedRequest)
|
||||
case op.IsFilterPut():
|
||||
return nil, fmt.Errorf("%w: FilterPut not supported", ErrUnsupportedRequest)
|
||||
case op.IsFilterDelete():
|
||||
return nil, fmt.Errorf("%w: FilterDelete not supported", ErrUnsupportedRequest)
|
||||
}
|
||||
|
||||
startKey := []byte(key)
|
||||
endKey := op.RangeBytes() // nil = single key, {0}=FromKey, else explicit range
|
||||
|
||||
if err := c.validateRange(startKey, endKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return KeyPredForRange(startKey, endKey), nil
|
||||
}
|
||||
|
||||
func (c *Cache) validateGet(key string, op clientv3.Op) (KeyPredicate, error) {
|
||||
switch {
|
||||
case op.IsCountOnly():
|
||||
return nil, fmt.Errorf("%w: CountOnly not supported", ErrUnsupportedRequest)
|
||||
case op.IsPrevKV():
|
||||
return nil, fmt.Errorf("%w: PrevKV not supported", ErrUnsupportedRequest)
|
||||
case op.IsSortSet():
|
||||
return nil, fmt.Errorf("%w: SortSet not supported", ErrUnsupportedRequest)
|
||||
case op.Limit() != 0:
|
||||
return nil, fmt.Errorf("%w: Limit(%d) not supported", ErrUnsupportedRequest, op.Limit())
|
||||
case op.MinModRev() != 0:
|
||||
return nil, fmt.Errorf("%w: MinModRev(%d) not supported", ErrUnsupportedRequest, op.MinModRev())
|
||||
case op.MaxModRev() != 0:
|
||||
return nil, fmt.Errorf("%w: MaxModRev(%d) not supported", ErrUnsupportedRequest, op.MaxModRev())
|
||||
case op.MinCreateRev() != 0:
|
||||
return nil, fmt.Errorf("%w: MinCreateRev(%d) not supported", ErrUnsupportedRequest, op.MinCreateRev())
|
||||
case op.MaxCreateRev() != 0:
|
||||
return nil, fmt.Errorf("%w: MaxCreateRev(%d) not supported", ErrUnsupportedRequest, op.MaxCreateRev())
|
||||
// cache now only serves serializable reads of the latest revision (rev == 0).
|
||||
case op.Rev() != 0:
|
||||
return nil, fmt.Errorf("%w: Rev(%d) not supported", ErrUnsupportedRequest, op.Rev())
|
||||
case !op.IsSerializable():
|
||||
return nil, fmt.Errorf("%w: non-serializable request", ErrUnsupportedRequest)
|
||||
}
|
||||
|
||||
startKey := []byte(key)
|
||||
endKey := op.RangeBytes()
|
||||
|
||||
if err := c.validateRange(startKey, endKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return KeyPredForRange(startKey, endKey), nil
|
||||
}
|
||||
|
||||
func (c *Cache) validateRange(startKey, endKey []byte) error {
|
||||
prefixStart := []byte(c.prefix)
|
||||
prefixEnd := []byte(clientv3.GetPrefixRangeEnd(c.prefix))
|
||||
|
||||
isSingleKey := len(endKey) == 0
|
||||
isFromKey := len(endKey) == 1 && endKey[0] == 0
|
||||
|
||||
switch {
|
||||
case isSingleKey:
|
||||
if c.prefix == "" {
|
||||
return nil
|
||||
}
|
||||
if bytes.Compare(startKey, prefixStart) < 0 || bytes.Compare(startKey, prefixEnd) >= 0 {
|
||||
return ErrKeyRangeInvalid
|
||||
}
|
||||
return nil
|
||||
|
||||
case isFromKey:
|
||||
if c.prefix != "" {
|
||||
return ErrKeyRangeInvalid
|
||||
}
|
||||
return nil
|
||||
|
||||
default:
|
||||
if bytes.Compare(endKey, startKey) <= 0 {
|
||||
return ErrKeyRangeInvalid
|
||||
}
|
||||
if c.prefix == "" {
|
||||
return nil
|
||||
}
|
||||
if bytes.Compare(startKey, prefixStart) < 0 || bytes.Compare(endKey, prefixEnd) > 0 {
|
||||
return ErrKeyRangeInvalid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,493 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
||||
mvccpb "go.etcd.io/etcd/api/v3/mvccpb"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
func TestCacheWatchAtomicOrderedDelivery(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
sentBatches [][]*clientv3.Event
|
||||
wantBatch []*clientv3.Event
|
||||
}{
|
||||
{
|
||||
name: "single_event",
|
||||
sentBatches: [][]*clientv3.Event{
|
||||
{event(mvccpb.PUT, "/a", 5)},
|
||||
},
|
||||
wantBatch: []*clientv3.Event{
|
||||
event(mvccpb.PUT, "/a", 5),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "same_revision_batch",
|
||||
sentBatches: [][]*clientv3.Event{
|
||||
{
|
||||
event(mvccpb.PUT, "/a", 10),
|
||||
event(mvccpb.PUT, "/b", 10),
|
||||
},
|
||||
},
|
||||
wantBatch: []*clientv3.Event{
|
||||
event(mvccpb.PUT, "/a", 10),
|
||||
event(mvccpb.PUT, "/b", 10),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mixed_revisions_in_single_response",
|
||||
sentBatches: [][]*clientv3.Event{
|
||||
{
|
||||
event(mvccpb.PUT, "/a", 11),
|
||||
event(mvccpb.PUT, "/b", 11),
|
||||
event(mvccpb.PUT, "/c", 12),
|
||||
},
|
||||
},
|
||||
wantBatch: []*clientv3.Event{
|
||||
event(mvccpb.PUT, "/a", 11),
|
||||
event(mvccpb.PUT, "/b", 11),
|
||||
event(mvccpb.PUT, "/c", 12),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mixed_event_types_same_revision",
|
||||
sentBatches: [][]*clientv3.Event{
|
||||
{
|
||||
event(mvccpb.PUT, "/x", 5),
|
||||
event(mvccpb.PUT, "/y", 6),
|
||||
event(mvccpb.DELETE, "/x", 6),
|
||||
},
|
||||
},
|
||||
wantBatch: []*clientv3.Event{
|
||||
event(mvccpb.PUT, "/x", 5),
|
||||
event(mvccpb.PUT, "/y", 6),
|
||||
event(mvccpb.DELETE, "/x", 6),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all_events_in_one_response",
|
||||
sentBatches: [][]*clientv3.Event{
|
||||
{
|
||||
event(mvccpb.PUT, "/a", 2),
|
||||
event(mvccpb.PUT, "/b", 2),
|
||||
event(mvccpb.PUT, "/c", 3),
|
||||
event(mvccpb.PUT, "/d", 4),
|
||||
event(mvccpb.PUT, "/e", 4),
|
||||
event(mvccpb.PUT, "/f", 5),
|
||||
event(mvccpb.PUT, "/g", 6),
|
||||
event(mvccpb.PUT, "/h", 6),
|
||||
event(mvccpb.PUT, "/i", 7),
|
||||
event(mvccpb.PUT, "/j", 7),
|
||||
},
|
||||
},
|
||||
wantBatch: []*clientv3.Event{
|
||||
event(mvccpb.PUT, "/a", 2),
|
||||
event(mvccpb.PUT, "/b", 2),
|
||||
event(mvccpb.PUT, "/c", 3),
|
||||
event(mvccpb.PUT, "/d", 4),
|
||||
event(mvccpb.PUT, "/e", 4),
|
||||
event(mvccpb.PUT, "/f", 5),
|
||||
event(mvccpb.PUT, "/g", 6),
|
||||
event(mvccpb.PUT, "/h", 6),
|
||||
event(mvccpb.PUT, "/i", 7),
|
||||
event(mvccpb.PUT, "/j", 7),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "one_revision_group_per_response",
|
||||
sentBatches: [][]*clientv3.Event{
|
||||
{event(mvccpb.PUT, "/a", 2), event(mvccpb.PUT, "/b", 2)},
|
||||
{event(mvccpb.PUT, "/c", 3)},
|
||||
{event(mvccpb.PUT, "/d", 4), event(mvccpb.PUT, "/e", 4)},
|
||||
{event(mvccpb.PUT, "/f", 5)},
|
||||
{event(mvccpb.PUT, "/g", 6), event(mvccpb.PUT, "/h", 6)},
|
||||
{event(mvccpb.PUT, "/i", 7), event(mvccpb.PUT, "/j", 7)},
|
||||
},
|
||||
wantBatch: []*clientv3.Event{
|
||||
event(mvccpb.PUT, "/a", 2),
|
||||
event(mvccpb.PUT, "/b", 2),
|
||||
event(mvccpb.PUT, "/c", 3),
|
||||
event(mvccpb.PUT, "/d", 4),
|
||||
event(mvccpb.PUT, "/e", 4),
|
||||
event(mvccpb.PUT, "/f", 5),
|
||||
event(mvccpb.PUT, "/g", 6),
|
||||
event(mvccpb.PUT, "/h", 6),
|
||||
event(mvccpb.PUT, "/i", 7),
|
||||
event(mvccpb.PUT, "/j", 7),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "two_revision_groups_per_response",
|
||||
sentBatches: [][]*clientv3.Event{
|
||||
{event(mvccpb.PUT, "/a", 2), event(mvccpb.PUT, "/b", 2), event(mvccpb.PUT, "/c", 3)},
|
||||
{event(mvccpb.PUT, "/d", 4), event(mvccpb.PUT, "/e", 4), event(mvccpb.PUT, "/f", 5)},
|
||||
{event(mvccpb.PUT, "/g", 6), event(mvccpb.PUT, "/h", 6)},
|
||||
{event(mvccpb.PUT, "/i", 7), event(mvccpb.PUT, "/j", 7)},
|
||||
},
|
||||
wantBatch: []*clientv3.Event{
|
||||
event(mvccpb.PUT, "/a", 2),
|
||||
event(mvccpb.PUT, "/b", 2),
|
||||
event(mvccpb.PUT, "/c", 3),
|
||||
event(mvccpb.PUT, "/d", 4),
|
||||
event(mvccpb.PUT, "/e", 4),
|
||||
event(mvccpb.PUT, "/f", 5),
|
||||
event(mvccpb.PUT, "/g", 6),
|
||||
event(mvccpb.PUT, "/h", 6),
|
||||
event(mvccpb.PUT, "/i", 7),
|
||||
event(mvccpb.PUT, "/j", 7),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "three_revision_groups_per_response",
|
||||
sentBatches: [][]*clientv3.Event{
|
||||
{
|
||||
event(mvccpb.PUT, "/a", 2), event(mvccpb.PUT, "/b", 2),
|
||||
event(mvccpb.PUT, "/c", 3),
|
||||
event(mvccpb.PUT, "/d", 4), event(mvccpb.PUT, "/e", 4),
|
||||
},
|
||||
{
|
||||
event(mvccpb.PUT, "/f", 5),
|
||||
event(mvccpb.PUT, "/g", 6), event(mvccpb.PUT, "/h", 6),
|
||||
event(mvccpb.PUT, "/i", 7), event(mvccpb.PUT, "/j", 7),
|
||||
},
|
||||
},
|
||||
wantBatch: []*clientv3.Event{
|
||||
event(mvccpb.PUT, "/a", 2),
|
||||
event(mvccpb.PUT, "/b", 2),
|
||||
event(mvccpb.PUT, "/c", 3),
|
||||
event(mvccpb.PUT, "/d", 4),
|
||||
event(mvccpb.PUT, "/e", 4),
|
||||
event(mvccpb.PUT, "/f", 5),
|
||||
event(mvccpb.PUT, "/g", 6),
|
||||
event(mvccpb.PUT, "/h", 6),
|
||||
event(mvccpb.PUT, "/i", 7),
|
||||
event(mvccpb.PUT, "/j", 7),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mw := newMockWatcher(16)
|
||||
fakeClient := &clientv3.Client{
|
||||
Watcher: mw,
|
||||
KV: &kvStub{},
|
||||
}
|
||||
cache, err := New(fakeClient, "")
|
||||
if err != nil {
|
||||
t.Fatalf("New cache: %v", err)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("New cache: %v", err)
|
||||
}
|
||||
defer cache.Close()
|
||||
|
||||
mw.responses <- clientv3.WatchResponse{}
|
||||
<-mw.registered
|
||||
|
||||
ctxWait, cancelWait := context.WithTimeout(t.Context(), time.Second)
|
||||
if err := cache.WaitReady(ctxWait); err != nil {
|
||||
t.Fatalf("cache did not become Ready(): %v", err)
|
||||
}
|
||||
cancelWait()
|
||||
|
||||
ctx, cancel := context.WithTimeout(t.Context(), 2*time.Second)
|
||||
defer cancel()
|
||||
watchCh := cache.Watch(ctx, "", clientv3.WithPrefix())
|
||||
|
||||
for _, batch := range tt.sentBatches {
|
||||
mw.responses <- clientv3.WatchResponse{Events: batch}
|
||||
}
|
||||
close(mw.responses)
|
||||
|
||||
got := collectAndAssertAtomicEvents(ctx, t, watchCh, len(tt.wantBatch))
|
||||
|
||||
if diff := cmp.Diff(tt.wantBatch, got); diff != "" {
|
||||
t.Fatalf("event mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateWatchRange(t *testing.T) {
|
||||
type tc struct {
|
||||
name string
|
||||
watchKey string
|
||||
opts []clientv3.OpOption
|
||||
cachePrefix string
|
||||
wantErr bool
|
||||
}
|
||||
|
||||
tests := []tc{
|
||||
{
|
||||
name: "single key",
|
||||
watchKey: "/a",
|
||||
cachePrefix: "",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "prefix single key",
|
||||
watchKey: "/foo/a",
|
||||
cachePrefix: "/foo",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "single key outside prefix returns error",
|
||||
watchKey: "/z",
|
||||
cachePrefix: "/foo",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "explicit range",
|
||||
watchKey: "/a",
|
||||
opts: []clientv3.OpOption{clientv3.WithRange("/b")},
|
||||
cachePrefix: "",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "exact prefix range",
|
||||
watchKey: "/a",
|
||||
opts: []clientv3.OpOption{clientv3.WithRange("/b")},
|
||||
cachePrefix: "/a",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "prefix subrange",
|
||||
watchKey: "/foo",
|
||||
opts: []clientv3.OpOption{clientv3.WithRange("/foo/a")},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "reverse range returns error",
|
||||
watchKey: "/b",
|
||||
opts: []clientv3.OpOption{clientv3.WithRange("/a")},
|
||||
cachePrefix: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty range returns error",
|
||||
watchKey: "/foo",
|
||||
opts: []clientv3.OpOption{clientv3.WithRange("/foo")},
|
||||
cachePrefix: "",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "range starting below cache prefix returns error",
|
||||
watchKey: "/a",
|
||||
opts: []clientv3.OpOption{clientv3.WithRange("/foo")},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "range encompassing cache prefix returns error",
|
||||
watchKey: "/a",
|
||||
opts: []clientv3.OpOption{clientv3.WithRange("/z")},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "range crossing prefixEnd returns error",
|
||||
watchKey: "/foo",
|
||||
opts: []clientv3.OpOption{clientv3.WithRange("/z")},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty prefix",
|
||||
watchKey: "",
|
||||
opts: []clientv3.OpOption{clientv3.WithPrefix()},
|
||||
cachePrefix: "",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty prefix with cachePrefix returns error",
|
||||
watchKey: "",
|
||||
opts: []clientv3.OpOption{clientv3.WithPrefix()},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "prefix watch matches cachePrefix exactly",
|
||||
watchKey: "/foo",
|
||||
opts: []clientv3.OpOption{clientv3.WithPrefix()},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "prefix watch inside cachePrefix",
|
||||
watchKey: "/foo/bar",
|
||||
opts: []clientv3.OpOption{clientv3.WithPrefix()},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "prefix starting below cachePrefix returns error",
|
||||
watchKey: "/a",
|
||||
opts: []clientv3.OpOption{clientv3.WithPrefix()},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "prefix starting above shard prefixEnd returns error",
|
||||
watchKey: "/fop",
|
||||
opts: []clientv3.OpOption{clientv3.WithPrefix()},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "fromKey open‑ended",
|
||||
watchKey: "/a",
|
||||
opts: []clientv3.OpOption{clientv3.WithFromKey()},
|
||||
cachePrefix: "",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "fromKey starting at prefix start",
|
||||
watchKey: "/foo",
|
||||
opts: []clientv3.OpOption{clientv3.WithFromKey()},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "fromKey starting below prefixEnd",
|
||||
watchKey: "/a",
|
||||
opts: []clientv3.OpOption{clientv3.WithFromKey()},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "fromKey starting above prefixEnd returns error",
|
||||
watchKey: "/fop",
|
||||
opts: []clientv3.OpOption{clientv3.WithFromKey()},
|
||||
cachePrefix: "/foo",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tests {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
dummyCache := &Cache{prefix: c.cachePrefix}
|
||||
op := clientv3.OpGet(c.watchKey, c.opts...)
|
||||
err := dummyCache.validateRange([]byte(c.watchKey), op.RangeBytes())
|
||||
if gotErr := err != nil; gotErr != c.wantErr {
|
||||
t.Fatalf("validateWatchRange(%q, %q, %v) err=%v, wantErr=%v",
|
||||
c.cachePrefix, c.watchKey, c.opts, err, c.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockWatcher struct {
|
||||
responses chan clientv3.WatchResponse
|
||||
registered chan struct{}
|
||||
}
|
||||
|
||||
type kvStub struct{}
|
||||
|
||||
func (kvStub) Get(ctx context.Context, key string, _ ...clientv3.OpOption) (*clientv3.GetResponse, error) {
|
||||
return &clientv3.GetResponse{Header: &pb.ResponseHeader{Revision: 0}}, nil
|
||||
}
|
||||
|
||||
func (kvStub) Put(ctx context.Context, key, val string, _ ...clientv3.OpOption) (*clientv3.PutResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (kvStub) Delete(ctx context.Context, key string, _ ...clientv3.OpOption) (*clientv3.DeleteResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (kvStub) Compact(ctx context.Context, rev int64, _ ...clientv3.CompactOption) (*clientv3.CompactResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (kvStub) Do(ctx context.Context, op clientv3.Op) (clientv3.OpResponse, error) {
|
||||
return clientv3.OpResponse{}, nil
|
||||
}
|
||||
|
||||
func (kvStub) Txn(ctx context.Context) clientv3.Txn {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newMockWatcher(buf int) *mockWatcher {
|
||||
return &mockWatcher{
|
||||
responses: make(chan clientv3.WatchResponse, buf),
|
||||
registered: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockWatcher) Watch(_ context.Context, _ string, _ ...clientv3.OpOption) clientv3.WatchChan {
|
||||
select { // prevent “close of closed channel” on re-watch
|
||||
case <-m.registered:
|
||||
default:
|
||||
close(m.registered)
|
||||
}
|
||||
return m.responses
|
||||
}
|
||||
|
||||
func (m *mockWatcher) RequestProgress(_ context.Context) error { return nil }
|
||||
|
||||
func (m *mockWatcher) Close() error { close(m.responses); return nil }
|
||||
|
||||
func event(eventType mvccpb.Event_EventType, key string, rev int64) *clientv3.Event {
|
||||
return &clientv3.Event{
|
||||
Type: eventType,
|
||||
Kv: &mvccpb.KeyValue{
|
||||
Key: []byte(key),
|
||||
ModRevision: rev,
|
||||
CreateRevision: rev,
|
||||
Version: 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func collectAndAssertAtomicEvents(ctx context.Context, t *testing.T, watchCh clientv3.WatchChan, wantCount int) []*clientv3.Event {
|
||||
t.Helper()
|
||||
var events []*clientv3.Event
|
||||
var lastRevision int64
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Fatalf("timed out waiting for events (%d/%d received)",
|
||||
len(events), wantCount)
|
||||
|
||||
case resp, ok := <-watchCh:
|
||||
if !ok {
|
||||
return events
|
||||
}
|
||||
if len(resp.Events) != 0 && resp.Events[0].Kv.ModRevision == lastRevision {
|
||||
t.Fatalf("same revision found as in previous response: %d", lastRevision)
|
||||
}
|
||||
for _, ev := range resp.Events {
|
||||
if ev.Kv.ModRevision < lastRevision {
|
||||
t.Fatalf("revision went backwards: last %d, now %d", lastRevision, ev.Kv.ModRevision)
|
||||
}
|
||||
events = append(events, ev)
|
||||
lastRevision = ev.Kv.ModRevision
|
||||
}
|
||||
if wantCount != 0 && len(events) >= wantCount {
|
||||
return events
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import "time"
|
||||
|
||||
type Config struct {
|
||||
// PerWatcherBufferSize caps each watcher’s buffered channel.
|
||||
// Bigger values tolerate brief client slow-downs at the cost of extra memory.
|
||||
PerWatcherBufferSize int
|
||||
// HistoryWindowSize is the max events kept in memory for replay.
|
||||
// It defines how far back the cache can replay events to lagging watchers
|
||||
HistoryWindowSize int
|
||||
// ResyncInterval controls how often the demux attempts to catch a lagging watcher up by replaying events from History.
|
||||
ResyncInterval time.Duration
|
||||
// InitialBackoff is the first delay to wait before retrying an upstream etcd Watch after it ends with an error.
|
||||
InitialBackoff time.Duration
|
||||
// MaxBackoff caps the exponential back-off between successive upstream watch retries.
|
||||
MaxBackoff time.Duration
|
||||
// GetTimeout is the timeout applied to the first Get() used to bootstrap the cache.
|
||||
GetTimeout time.Duration
|
||||
}
|
||||
|
||||
// TODO: tune via performance/load tests.
|
||||
func defaultConfig() Config {
|
||||
return Config{
|
||||
PerWatcherBufferSize: 10,
|
||||
HistoryWindowSize: 2048,
|
||||
ResyncInterval: 50 * time.Millisecond,
|
||||
InitialBackoff: 50 * time.Millisecond,
|
||||
MaxBackoff: 2 * time.Second,
|
||||
GetTimeout: 5 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
type Option func(*Config)
|
||||
|
||||
func WithPerWatcherBufferSize(n int) Option {
|
||||
return func(c *Config) { c.PerWatcherBufferSize = n }
|
||||
}
|
||||
|
||||
func WithHistoryWindowSize(n int) Option {
|
||||
return func(c *Config) { c.HistoryWindowSize = n }
|
||||
}
|
||||
|
||||
func WithResyncInterval(d time.Duration) Option {
|
||||
return func(c *Config) { c.ResyncInterval = d }
|
||||
}
|
||||
|
||||
func WithInitialBackoff(d time.Duration) Option {
|
||||
return func(c *Config) { c.InitialBackoff = d }
|
||||
}
|
||||
|
||||
func WithMaxBackoff(d time.Duration) Option {
|
||||
return func(c *Config) { c.MaxBackoff = d }
|
||||
}
|
||||
|
||||
func WithGetTimeout(d time.Duration) Option {
|
||||
return func(c *Config) { c.GetTimeout = d }
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
type demux struct {
|
||||
mu sync.RWMutex
|
||||
// activeWatchers & laggingWatchers hold the first revision the watcher still needs (nextRev).
|
||||
activeWatchers map[*watcher]int64
|
||||
laggingWatchers map[*watcher]int64
|
||||
history *ringBuffer
|
||||
resyncInterval time.Duration
|
||||
}
|
||||
|
||||
func NewDemux(ctx context.Context, wg *sync.WaitGroup, historyWindowSize int, resyncInterval time.Duration) *demux {
|
||||
d := newDemux(historyWindowSize, resyncInterval)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
d.resyncLoop(ctx)
|
||||
}()
|
||||
return d
|
||||
}
|
||||
|
||||
func newDemux(historyWindowSize int, resyncInterval time.Duration) *demux {
|
||||
return &demux{
|
||||
activeWatchers: make(map[*watcher]int64),
|
||||
laggingWatchers: make(map[*watcher]int64),
|
||||
history: newRingBuffer(historyWindowSize),
|
||||
resyncInterval: resyncInterval,
|
||||
}
|
||||
}
|
||||
|
||||
// resyncLoop periodically tries to catch lagging watchers up by replaying events from History.
|
||||
func (d *demux) resyncLoop(ctx context.Context) {
|
||||
timer := time.NewTimer(d.resyncInterval)
|
||||
defer timer.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-timer.C:
|
||||
d.resyncLaggingWatchers()
|
||||
timer.Reset(d.resyncInterval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *demux) Register(w *watcher, startingRev int64) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
latestRev := d.history.PeekLatest()
|
||||
|
||||
// Special case: 0 means “newest”.
|
||||
if startingRev == 0 {
|
||||
if latestRev == 0 {
|
||||
d.activeWatchers[w] = 0
|
||||
return
|
||||
}
|
||||
startingRev = latestRev + 1
|
||||
}
|
||||
|
||||
if startingRev <= latestRev {
|
||||
d.laggingWatchers[w] = startingRev
|
||||
} else {
|
||||
d.activeWatchers[w] = startingRev
|
||||
}
|
||||
}
|
||||
|
||||
func (d *demux) Unregister(w *watcher) {
|
||||
func() {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
delete(d.activeWatchers, w)
|
||||
delete(d.laggingWatchers, w)
|
||||
}()
|
||||
w.Stop()
|
||||
}
|
||||
|
||||
func (d *demux) Broadcast(events []*clientv3.Event) {
|
||||
if len(events) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
d.history.Append(events)
|
||||
|
||||
lastRev := events[len(events)-1].Kv.ModRevision
|
||||
for w, nextRev := range d.activeWatchers {
|
||||
start := len(events)
|
||||
for i, ev := range events {
|
||||
if ev.Kv.ModRevision >= nextRev {
|
||||
start = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if start == len(events) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !w.enqueueEvent(events[start:]) { // overflow → lagging
|
||||
d.laggingWatchers[w] = nextRev
|
||||
delete(d.activeWatchers, w)
|
||||
} else {
|
||||
d.activeWatchers[w] = lastRev + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Purge is called when etcd compaction invalidates our cached history, so clients should resubscribe.
|
||||
func (d *demux) Purge() {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.history.RebaseHistory()
|
||||
for w := range d.activeWatchers {
|
||||
w.Stop()
|
||||
}
|
||||
for w := range d.laggingWatchers {
|
||||
w.Stop()
|
||||
}
|
||||
d.activeWatchers = make(map[*watcher]int64)
|
||||
d.laggingWatchers = make(map[*watcher]int64)
|
||||
}
|
||||
|
||||
func (d *demux) resyncLaggingWatchers() {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
oldestRev := d.history.PeekOldest()
|
||||
for w, nextRev := range d.laggingWatchers {
|
||||
if oldestRev != 0 && nextRev < oldestRev {
|
||||
w.Stop()
|
||||
delete(d.laggingWatchers, w)
|
||||
continue
|
||||
}
|
||||
// TODO: re-enable key‐predicate in Filter when non‐zero startRev or performance tuning is needed
|
||||
missed := d.history.Filter(nextRev)
|
||||
|
||||
enqueueFailed := false
|
||||
for _, eventBatch := range missed {
|
||||
if !w.enqueueEvent(eventBatch) { // buffer overflow: watcher still lagging
|
||||
enqueueFailed = true
|
||||
break
|
||||
}
|
||||
nextRev = eventBatch[0].Kv.ModRevision + 1
|
||||
}
|
||||
|
||||
if !enqueueFailed {
|
||||
delete(d.laggingWatchers, w)
|
||||
d.activeWatchers[w] = nextRev
|
||||
} else {
|
||||
d.laggingWatchers[w] = nextRev
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *demux) PeekOldest() int64 {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
return d.history.PeekOldest()
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"go.etcd.io/etcd/api/v3/mvccpb"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
func TestBroadcastBatching(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []int64
|
||||
wantRevs []int64
|
||||
wantSizes []int
|
||||
}{
|
||||
{
|
||||
name: "two groups",
|
||||
input: []int64{14, 14, 15, 15, 15},
|
||||
wantRevs: []int64{14},
|
||||
wantSizes: []int{5},
|
||||
},
|
||||
{
|
||||
name: "single group",
|
||||
input: []int64{7, 7, 7},
|
||||
wantRevs: []int64{7},
|
||||
wantSizes: []int{3},
|
||||
},
|
||||
{
|
||||
name: "all distinct",
|
||||
input: []int64{1, 2, 3},
|
||||
wantRevs: []int64{1},
|
||||
wantSizes: []int{3},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d := newDemux(16, 10*time.Millisecond)
|
||||
w := newWatcher(len(tt.input)+1, nil)
|
||||
d.Register(w, 0)
|
||||
|
||||
d.Broadcast(eventRevs(tt.input...))
|
||||
|
||||
gotRevs, gotSizes := readBatches(t, w, len(tt.wantRevs))
|
||||
|
||||
if diff := cmp.Diff(tt.wantRevs, gotRevs); diff != "" {
|
||||
t.Fatalf("revision mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(tt.wantSizes, gotSizes); diff != "" {
|
||||
t.Fatalf("batch size mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlowWatcherResync(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []int64
|
||||
wantInitialRevs []int64
|
||||
wantInitialSizes []int
|
||||
wantResyncRevs []int64
|
||||
wantResyncSizes []int
|
||||
}{
|
||||
{
|
||||
name: "single event overflow",
|
||||
input: []int64{1, 2, 3},
|
||||
wantInitialRevs: []int64{1},
|
||||
wantInitialSizes: []int{3},
|
||||
wantResyncRevs: []int64{},
|
||||
wantResyncSizes: []int{},
|
||||
},
|
||||
{
|
||||
name: "multi events batch overflow",
|
||||
input: []int64{10, 10, 11, 12, 12},
|
||||
wantInitialRevs: []int64{10},
|
||||
wantInitialSizes: []int{5},
|
||||
wantResyncRevs: []int64{},
|
||||
wantResyncSizes: []int{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d := newDemux(16, 10*time.Millisecond)
|
||||
w := newWatcher(1, nil)
|
||||
d.Register(w, 0)
|
||||
|
||||
d.Broadcast(eventRevs(tt.input...))
|
||||
|
||||
gotInitRevs, gotInitSizes := readBatches(t, w, len(tt.wantInitialRevs))
|
||||
if diff := cmp.Diff(tt.wantInitialRevs, gotInitRevs); diff != "" {
|
||||
t.Fatalf("initial revs mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(tt.wantInitialSizes, gotInitSizes); diff != "" {
|
||||
t.Fatalf("initial batch sizes mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
gotRevs, gotSizes := make([]int64, 0, len(tt.wantResyncRevs)), make([]int, 0, len(tt.wantResyncRevs))
|
||||
for len(gotRevs) < len(tt.wantResyncRevs) {
|
||||
d.resyncLaggingWatchers()
|
||||
revs, sizes := readBatches(t, w, 1)
|
||||
gotRevs = append(gotRevs, revs...)
|
||||
gotSizes = append(gotSizes, sizes...)
|
||||
}
|
||||
if diff := cmp.Diff(tt.wantResyncRevs, gotRevs); diff != "" {
|
||||
t.Fatalf("resync revs mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(tt.wantResyncSizes, gotSizes); diff != "" {
|
||||
t.Fatalf("resync batch sizes mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func eventRevs(revs ...int64) []*clientv3.Event {
|
||||
events := make([]*clientv3.Event, 0, len(revs))
|
||||
for _, r := range revs {
|
||||
kv := &mvccpb.KeyValue{
|
||||
Key: []byte("k"),
|
||||
Value: []byte("v"),
|
||||
ModRevision: r,
|
||||
}
|
||||
events = append(events, &clientv3.Event{
|
||||
Type: clientv3.EventTypePut,
|
||||
Kv: kv,
|
||||
})
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
func readBatches(t *testing.T, w *watcher, n int) (revs []int64, sizes []int) {
|
||||
t.Helper()
|
||||
timeout := time.After(2 * time.Second)
|
||||
for len(revs) < n {
|
||||
select {
|
||||
case batch := <-w.eventQueue:
|
||||
revs = append(revs, batch[0].Kv.ModRevision)
|
||||
sizes = append(sizes, len(batch))
|
||||
case <-timeout:
|
||||
t.Fatalf("timed out waiting for %d batches; got %d", n, len(revs))
|
||||
}
|
||||
}
|
||||
return revs, sizes
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
module go.etcd.io/etcd/cache/v3
|
||||
|
||||
go 1.24
|
||||
|
||||
toolchain go1.24.5
|
||||
|
||||
require (
|
||||
github.com/google/go-cmp v0.7.0
|
||||
go.etcd.io/etcd/api/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/client/v3 v3.6.0-alpha.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0-alpha.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
go.etcd.io/etcd/api/v3 => ../api
|
||||
go.etcd.io/etcd/client/pkg/v3 => ../client/pkg
|
||||
go.etcd.io/etcd/client/v3 => ../client/v3
|
||||
)
|
|
@ -0,0 +1,107 @@
|
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import "bytes"
|
||||
|
||||
type Prefix string
|
||||
|
||||
func (prefix Prefix) Match(key []byte) bool {
|
||||
if prefix == "" {
|
||||
return true
|
||||
}
|
||||
prefixLen := len(prefix)
|
||||
return len(key) >= prefixLen && string(key[:prefixLen]) == string(prefix)
|
||||
}
|
||||
|
||||
func ExactKey(key []byte) KeyPredicate {
|
||||
return func(k []byte) bool { return bytes.Equal(k, key) }
|
||||
}
|
||||
|
||||
func FromKey(start []byte) KeyPredicate {
|
||||
return func(k []byte) bool { return bytes.Compare(k, start) >= 0 }
|
||||
}
|
||||
|
||||
func Range(start, end []byte) KeyPredicate {
|
||||
return func(k []byte) bool {
|
||||
return bytes.Compare(k, start) >= 0 &&
|
||||
bytes.Compare(k, end) < 0
|
||||
}
|
||||
}
|
||||
|
||||
func KeyPredForRange(start, end []byte) KeyPredicate {
|
||||
if len(end) == 0 {
|
||||
return ExactKey(start)
|
||||
}
|
||||
if len(end) == 1 && end[0] == 0 {
|
||||
return FromKey(start)
|
||||
}
|
||||
return Range(start, end)
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
type ringBuffer struct {
|
||||
buffer []batch
|
||||
// head is the index immediately after the last non-empty entry in the buffer (i.e., the next write position).
|
||||
head, tail, size int
|
||||
}
|
||||
|
||||
// batch groups all events that share one ModRevision.
|
||||
type batch struct {
|
||||
rev int64
|
||||
events []*clientv3.Event
|
||||
}
|
||||
|
||||
type KeyPredicate = func([]byte) bool
|
||||
|
||||
func newRingBuffer(capacity int) *ringBuffer {
|
||||
// assume capacity > 0 – validated by Cache
|
||||
return &ringBuffer{
|
||||
buffer: make([]batch, capacity),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ringBuffer) Append(events []*clientv3.Event) {
|
||||
start := 0
|
||||
for end := 1; end < len(events); end++ {
|
||||
if events[end].Kv.ModRevision != events[start].Kv.ModRevision {
|
||||
r.append(batch{
|
||||
rev: events[start].Kv.ModRevision,
|
||||
events: events[start:end],
|
||||
})
|
||||
start = end
|
||||
}
|
||||
}
|
||||
if start < len(events) {
|
||||
r.append(batch{
|
||||
rev: events[start].Kv.ModRevision,
|
||||
events: events[start:],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ringBuffer) append(b batch) {
|
||||
if len(b.events) == 0 {
|
||||
return
|
||||
}
|
||||
if r.size == len(r.buffer) {
|
||||
r.tail = (r.tail + 1) % len(r.buffer)
|
||||
} else {
|
||||
r.size++
|
||||
}
|
||||
r.buffer[r.head] = b
|
||||
r.head = (r.head + 1) % len(r.buffer)
|
||||
}
|
||||
|
||||
// Filter returns all events in the buffer whose ModRevision is >= minRev.
|
||||
// TODO: use binary search on the ring buffer to locate the first entry >= nextRev instead of a full scan
|
||||
func (r *ringBuffer) Filter(minRev int64) (eventBatches [][]*clientv3.Event) {
|
||||
eventBatches = make([][]*clientv3.Event, 0, r.size)
|
||||
|
||||
for n, i := 0, r.tail; n < r.size; n, i = n+1, (i+1)%len(r.buffer) {
|
||||
eventBatch := r.buffer[i]
|
||||
if eventBatch.events == nil {
|
||||
panic(fmt.Sprintf("ringBuffer.Filter: unexpected nil eventBatch at index %d", i))
|
||||
}
|
||||
if eventBatch.rev >= minRev {
|
||||
eventBatches = append(eventBatches, eventBatch.events)
|
||||
}
|
||||
}
|
||||
return eventBatches
|
||||
}
|
||||
|
||||
// PeekLatest returns the most recently-appended event (or nil if empty).
|
||||
func (r *ringBuffer) PeekLatest() int64 {
|
||||
if r.size == 0 {
|
||||
return 0
|
||||
}
|
||||
idx := (r.head - 1 + len(r.buffer)) % len(r.buffer)
|
||||
return r.buffer[idx].rev
|
||||
}
|
||||
|
||||
// PeekOldest returns the oldest event currently stored (or nil if empty).
|
||||
func (r *ringBuffer) PeekOldest() int64 {
|
||||
if r.size == 0 {
|
||||
return 0
|
||||
}
|
||||
return r.buffer[r.tail].rev
|
||||
}
|
||||
|
||||
func (r *ringBuffer) RebaseHistory() {
|
||||
r.head, r.tail, r.size = 0, 0, 0
|
||||
for i := range r.buffer {
|
||||
r.buffer[i] = batch{}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,308 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"go.etcd.io/etcd/api/v3/mvccpb"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
func TestPeekLatestAndOldest(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
capacity int
|
||||
revs []int64
|
||||
wantLatestRev int64
|
||||
wantOldestRev int64
|
||||
}{
|
||||
{
|
||||
name: "empty_buffer",
|
||||
capacity: 4,
|
||||
revs: nil,
|
||||
wantLatestRev: 0,
|
||||
wantOldestRev: 0,
|
||||
},
|
||||
{
|
||||
name: "single_element",
|
||||
capacity: 8,
|
||||
revs: []int64{1},
|
||||
wantLatestRev: 1,
|
||||
wantOldestRev: 1,
|
||||
},
|
||||
{
|
||||
name: "ascending_fill",
|
||||
capacity: 4,
|
||||
revs: []int64{1, 2, 3, 4},
|
||||
wantLatestRev: 4,
|
||||
wantOldestRev: 1,
|
||||
},
|
||||
{
|
||||
name: "overwrite_when_full",
|
||||
capacity: 3,
|
||||
revs: []int64{5, 6, 7, 8},
|
||||
wantLatestRev: 8,
|
||||
wantOldestRev: 6,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
rb := newRingBuffer(tt.capacity)
|
||||
for _, r := range tt.revs {
|
||||
batch, err := makeEventBatch(r, "k", 1)
|
||||
if err != nil {
|
||||
t.Fatalf("makeEventBatch(%d, k, 1) failed: %v", r, err)
|
||||
}
|
||||
rb.Append(batch)
|
||||
}
|
||||
|
||||
latestRev := rb.PeekLatest()
|
||||
oldestRev := rb.PeekOldest()
|
||||
|
||||
gotLatestRev := latestRev
|
||||
gotOldestRev := oldestRev
|
||||
|
||||
if tt.wantLatestRev != gotLatestRev {
|
||||
t.Fatalf("PeekLatest()=%d, want=%d", gotLatestRev, tt.wantLatestRev)
|
||||
}
|
||||
if tt.wantOldestRev != gotOldestRev {
|
||||
t.Fatalf("PeekOldest()=%d, want=%d", gotOldestRev, tt.wantOldestRev)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
capacity int
|
||||
revs []int64
|
||||
minRev int64
|
||||
wantFilteredRevs []int64
|
||||
wantLatestRev int64
|
||||
}{
|
||||
{
|
||||
name: "no_filter",
|
||||
capacity: 5,
|
||||
revs: []int64{1, 2, 3},
|
||||
minRev: 0,
|
||||
wantFilteredRevs: []int64{1, 2, 3},
|
||||
wantLatestRev: 3,
|
||||
},
|
||||
{
|
||||
name: "partial_match",
|
||||
capacity: 5,
|
||||
revs: []int64{10, 11, 12, 13},
|
||||
minRev: 12,
|
||||
wantFilteredRevs: []int64{12, 13},
|
||||
wantLatestRev: 13,
|
||||
},
|
||||
{
|
||||
name: "filter_when_full",
|
||||
capacity: 3,
|
||||
revs: []int64{20, 21, 22, 23, 24},
|
||||
minRev: 23,
|
||||
wantFilteredRevs: []int64{23, 24},
|
||||
wantLatestRev: 24,
|
||||
},
|
||||
{
|
||||
name: "none_match",
|
||||
capacity: 4,
|
||||
revs: []int64{30, 31},
|
||||
minRev: 100,
|
||||
wantFilteredRevs: []int64{},
|
||||
wantLatestRev: 31,
|
||||
},
|
||||
{
|
||||
name: "empty_buffer",
|
||||
capacity: 3,
|
||||
revs: nil,
|
||||
minRev: 0,
|
||||
wantFilteredRevs: []int64{},
|
||||
wantLatestRev: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
rb := newRingBuffer(tt.capacity)
|
||||
for _, r := range tt.revs {
|
||||
batch, err := makeEventBatch(r, "k", 11)
|
||||
if err != nil {
|
||||
t.Fatalf("makeEventBatch(%d, k, 11) failed: %v", r, err)
|
||||
}
|
||||
rb.Append(batch)
|
||||
}
|
||||
|
||||
gotBatches := rb.Filter(tt.minRev)
|
||||
gotRevs := make([]int64, len(gotBatches))
|
||||
for i, b := range gotBatches {
|
||||
gotRevs[i] = b[0].Kv.ModRevision
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(tt.wantFilteredRevs, gotRevs); diff != "" {
|
||||
t.Fatalf("Filter() revisions mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAtomicOrdered(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
capacity int
|
||||
inputs []struct {
|
||||
rev int64
|
||||
key string
|
||||
size int
|
||||
}
|
||||
wantRev []int64
|
||||
wantSize []int
|
||||
}{
|
||||
{
|
||||
name: "unfiltered",
|
||||
capacity: 5,
|
||||
inputs: []struct {
|
||||
rev int64
|
||||
key string
|
||||
size int
|
||||
}{
|
||||
{5, "a", 1},
|
||||
{10, "b", 3},
|
||||
{15, "c", 7},
|
||||
{20, "d", 11},
|
||||
},
|
||||
wantRev: []int64{5, 10, 15, 20},
|
||||
wantSize: []int{1, 3, 7, 11},
|
||||
},
|
||||
{
|
||||
name: "across_wrap",
|
||||
capacity: 3,
|
||||
inputs: []struct {
|
||||
rev int64
|
||||
key string
|
||||
size int
|
||||
}{
|
||||
{1, "a", 2},
|
||||
{2, "b", 1},
|
||||
{3, "c", 3},
|
||||
{4, "d", 7},
|
||||
},
|
||||
wantRev: []int64{2, 3, 4},
|
||||
wantSize: []int{1, 3, 7},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rb := newRingBuffer(tt.capacity)
|
||||
for _, in := range tt.inputs {
|
||||
batch, err := makeEventBatch(in.rev, in.key, in.size)
|
||||
if err != nil {
|
||||
t.Fatalf("makeEventBatch(%d, k, 1) failed: %v", in.rev, err)
|
||||
}
|
||||
rb.Append(batch)
|
||||
}
|
||||
|
||||
gotBatches := rb.Filter(0)
|
||||
if len(gotBatches) != len(tt.wantRev) {
|
||||
t.Fatalf("len(got) = %d, want %d", len(gotBatches), len(tt.wantRev))
|
||||
}
|
||||
for i, b := range gotBatches {
|
||||
if b[0].Kv.ModRevision != tt.wantRev[i] {
|
||||
t.Errorf("at idx %d: rev = %d, want %d", i, b[0].Kv.ModRevision, tt.wantRev[i])
|
||||
}
|
||||
if batchSize := len(b); batchSize != tt.wantSize[i] {
|
||||
t.Errorf("at rev %d: events.len = %d, want %d", b[0].Kv.ModRevision, batchSize, tt.wantSize[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRebaseHistory(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
revs []int64
|
||||
}{
|
||||
{
|
||||
name: "rebase_empty_buffer",
|
||||
revs: nil,
|
||||
},
|
||||
{
|
||||
name: "rebase_after_data",
|
||||
revs: []int64{7, 8, 9},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
rb := newRingBuffer(4)
|
||||
for _, r := range tt.revs {
|
||||
batch, err := makeEventBatch(r, "k", 1)
|
||||
if err != nil {
|
||||
t.Fatalf("makeEventBatch(%d, k, 1) failed: %v", r, err)
|
||||
}
|
||||
rb.Append(batch)
|
||||
}
|
||||
|
||||
rb.RebaseHistory()
|
||||
|
||||
oldestRev := rb.PeekOldest()
|
||||
|
||||
latestRev := rb.PeekLatest()
|
||||
|
||||
if oldestRev != 0 {
|
||||
t.Fatalf("PeekOldest()=%d, want=%d", oldestRev, 0)
|
||||
}
|
||||
if latestRev != 0 {
|
||||
t.Fatalf("PeekLatest()=%d, want=%d", latestRev, 0)
|
||||
}
|
||||
|
||||
batches := rb.Filter(0)
|
||||
if len(batches) != 0 {
|
||||
t.Fatalf("Filter() len(events)=%d, want=%d", len(batches), 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func makeEventBatch(rev int64, key string, batchSize int) ([]*clientv3.Event, error) {
|
||||
if batchSize < 0 {
|
||||
return nil, fmt.Errorf("invalid batchSize %d", batchSize)
|
||||
}
|
||||
events := make([]*clientv3.Event, batchSize)
|
||||
for i := range events {
|
||||
events[i] = &clientv3.Event{
|
||||
Kv: &mvccpb.KeyValue{
|
||||
Key: []byte(fmt.Sprintf("%s-%d", key, i)),
|
||||
ModRevision: rev,
|
||||
},
|
||||
}
|
||||
}
|
||||
return events, nil
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"go.etcd.io/etcd/api/v3/mvccpb"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
var ErrNotInitialized = fmt.Errorf("cache: store not initialized")
|
||||
|
||||
type store struct {
|
||||
mu sync.RWMutex
|
||||
kvs map[string]*mvccpb.KeyValue
|
||||
latestRev int64
|
||||
}
|
||||
|
||||
func newStore() *store {
|
||||
return &store{kvs: make(map[string]*mvccpb.KeyValue)}
|
||||
}
|
||||
|
||||
func (s *store) Get(startKey, endKey []byte) ([]*mvccpb.KeyValue, int64, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
if s.latestRev == 0 {
|
||||
return nil, 0, ErrNotInitialized
|
||||
}
|
||||
|
||||
var out []*mvccpb.KeyValue
|
||||
switch {
|
||||
case len(endKey) == 0:
|
||||
out = s.getSingle(startKey)
|
||||
case isPrefixScan(endKey):
|
||||
out = s.scanPrefix(startKey)
|
||||
default:
|
||||
out = s.scanRange(startKey, endKey)
|
||||
}
|
||||
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
return bytes.Compare(out[i].Key, out[j].Key) < 0 // default: lexicographical, ascending‐by‐key sort
|
||||
})
|
||||
return out, s.latestRev, nil
|
||||
}
|
||||
|
||||
func (s *store) Restore(kvs []*mvccpb.KeyValue, rev int64) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.kvs = make(map[string]*mvccpb.KeyValue, len(kvs))
|
||||
for _, kv := range kvs {
|
||||
s.kvs[string(kv.Key)] = kv
|
||||
}
|
||||
s.latestRev = rev
|
||||
}
|
||||
|
||||
// Reset purges all in-memory state when the upstream watch stream reports compaction.
|
||||
func (s *store) Reset() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.kvs = make(map[string]*mvccpb.KeyValue)
|
||||
s.latestRev = 0
|
||||
}
|
||||
|
||||
func (s *store) Apply(events []*clientv3.Event) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
for _, ev := range events {
|
||||
if ev.Kv.ModRevision < s.latestRev {
|
||||
return fmt.Errorf("cache: stale event batch (rev %d < latest %d)", ev.Kv.ModRevision, s.latestRev)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ev := range events {
|
||||
switch ev.Type {
|
||||
case clientv3.EventTypeDelete:
|
||||
delete(s.kvs, string(ev.Kv.Key))
|
||||
case clientv3.EventTypePut:
|
||||
s.kvs[string(ev.Kv.Key)] = ev.Kv
|
||||
}
|
||||
if ev.Kv.ModRevision > s.latestRev {
|
||||
s.latestRev = ev.Kv.ModRevision
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *store) LatestRev() int64 {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return s.latestRev
|
||||
}
|
||||
|
||||
// getSingle fetches one key or nil
|
||||
func (s *store) getSingle(key []byte) []*mvccpb.KeyValue {
|
||||
if kv, ok := s.kvs[string(key)]; ok {
|
||||
return []*mvccpb.KeyValue{kv}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// scanPrefix returns all keys >= startKey
|
||||
func (s *store) scanPrefix(startKey []byte) []*mvccpb.KeyValue {
|
||||
var res []*mvccpb.KeyValue
|
||||
for _, kv := range s.kvs {
|
||||
if bytes.Compare(kv.Key, startKey) >= 0 {
|
||||
res = append(res, kv)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// scanRange returns all keys in [startKey, endKey)
|
||||
func (s *store) scanRange(startKey, endKey []byte) []*mvccpb.KeyValue {
|
||||
var res []*mvccpb.KeyValue
|
||||
for _, kv := range s.kvs {
|
||||
if bytes.Compare(kv.Key, startKey) >= 0 && bytes.Compare(kv.Key, endKey) < 0 {
|
||||
res = append(res, kv)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// isPrefixScan detects endKey=={0} semantics
|
||||
func isPrefixScan(endKey []byte) bool {
|
||||
return len(endKey) == 1 && endKey[0] == 0
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
// watcher holds one client’s buffered stream of events.
|
||||
type watcher struct {
|
||||
eventQueue chan []*clientv3.Event
|
||||
keyPred KeyPredicate
|
||||
stopped int32
|
||||
done chan struct{} // closed together with Stop()
|
||||
}
|
||||
|
||||
func newWatcher(bufSize int, pred KeyPredicate) *watcher {
|
||||
return &watcher{
|
||||
eventQueue: make(chan []*clientv3.Event, bufSize),
|
||||
keyPred: pred,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// true -> events delivered (or filtered/duplicate)
|
||||
// false -> buffer full (caller should mark watcher “lagging”)
|
||||
func (w *watcher) enqueueEvent(eventBatch []*clientv3.Event) bool {
|
||||
if w.keyPred != nil {
|
||||
filtered := make([]*clientv3.Event, 0, len(eventBatch))
|
||||
for _, event := range eventBatch {
|
||||
if w.keyPred(event.Kv.Key) {
|
||||
filtered = append(filtered, event)
|
||||
}
|
||||
}
|
||||
if len(filtered) == 0 {
|
||||
return true
|
||||
}
|
||||
eventBatch = filtered
|
||||
}
|
||||
select {
|
||||
case w.eventQueue <- eventBatch:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Stop closes the event channel atomically.
|
||||
func (w *watcher) Stop() {
|
||||
if atomic.CompareAndSwapInt32(&w.stopped, 0, 1) {
|
||||
close(w.eventQueue)
|
||||
close(w.done)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) Done() <-chan struct{} { return w.done }
|
|
@ -187,7 +187,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2020 The etcd Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
)
|
||||
|
||||
func TestLockAndUnlock(t *testing.T) {
|
||||
f, err := os.CreateTemp("", "lock")
|
||||
f, err := os.CreateTemp(t.TempDir(), "lock")
|
||||
require.NoError(t, err)
|
||||
f.Close()
|
||||
defer func() {
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
module go.etcd.io/etcd/client/pkg/v3
|
||||
|
||||
go 1.23.0
|
||||
go 1.24
|
||||
|
||||
toolchain go1.23.11
|
||||
toolchain go1.24.5
|
||||
|
||||
require (
|
||||
github.com/coreos/go-systemd/v22 v22.5.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/sys v0.31.0
|
||||
golang.org/x/sys v0.34.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
|
@ -12,11 +12,11 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
|
@ -25,8 +25,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
|
|
@ -19,9 +19,6 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.etcd.io/etcd/client/pkg/v3/verify"
|
||||
)
|
||||
|
||||
|
@ -31,15 +28,12 @@ func BeforeTest(tb testing.TB) {
|
|||
|
||||
revertVerifyFunc := verify.EnableAllVerifications()
|
||||
|
||||
path, err := os.Getwd()
|
||||
require.NoError(tb, err)
|
||||
tempDir := tb.TempDir()
|
||||
require.NoError(tb, os.Chdir(tempDir))
|
||||
tb.Chdir(tempDir)
|
||||
tb.Logf("Changing working directory to: %s", tempDir)
|
||||
|
||||
tb.Cleanup(func() {
|
||||
revertVerifyFunc()
|
||||
assert.NoError(tb, os.Chdir(path))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ func NewURLs(strs []string) (URLs, error) {
|
|||
return nil, fmt.Errorf("URL must not contain a path: %s", in)
|
||||
}
|
||||
case "unix", "unixs":
|
||||
break
|
||||
default:
|
||||
return nil, fmt.Errorf("URL scheme must be http, https, unix, or unixs: %s", in)
|
||||
}
|
||||
|
|
|
@ -66,9 +66,18 @@ func DisableVerifications() func() {
|
|||
|
||||
// Verify performs verification if the assertions are enabled.
|
||||
// In the default setup running in tests and skipped in the production code.
|
||||
func Verify(f func()) {
|
||||
func Verify(msg string, f VerifyFunc) {
|
||||
if IsVerificationEnabled(envVerifyValueAssert) {
|
||||
f()
|
||||
ok, details := f()
|
||||
verifier(ok, msg, details)
|
||||
}
|
||||
}
|
||||
|
||||
type VerifyFunc func() (condition bool, details map[string]any)
|
||||
|
||||
func verifier(condition bool, msg string, details map[string]any) {
|
||||
if !condition {
|
||||
panic(fmt.Sprintf("%s. details: %v.", msg, details))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2020 The etcd Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -43,6 +43,7 @@ import (
|
|||
var (
|
||||
ErrNoAvailableEndpoints = errors.New("etcdclient: no available endpoints")
|
||||
ErrOldCluster = errors.New("etcdclient: old cluster version")
|
||||
ErrMutuallyExclusiveCfg = errors.New("Username/Password and Token configurations are mutually exclusive")
|
||||
)
|
||||
|
||||
// Client provides and manages an etcd v3 client session.
|
||||
|
@ -69,7 +70,10 @@ type Client struct {
|
|||
// Username is a user name for authentication.
|
||||
Username string
|
||||
// Password is a password for authentication.
|
||||
Password string
|
||||
Password string
|
||||
// Token is a JWT used for authentication instead of a password.
|
||||
Token string
|
||||
|
||||
authTokenBundle credentials.PerRPCCredentialsBundle
|
||||
|
||||
callOpts []grpc.CallOption
|
||||
|
@ -197,10 +201,8 @@ func (c *Client) Sync(ctx context.Context) error {
|
|||
}
|
||||
// The linearizable `MemberList` returned successfully, so the
|
||||
// endpoints shouldn't be empty.
|
||||
verify.Verify(func() {
|
||||
if len(eps) == 0 {
|
||||
panic("empty endpoints returned from etcd cluster")
|
||||
}
|
||||
verify.Verify("empty endpoints returned from etcd cluster", func() (bool, map[string]any) {
|
||||
return len(eps) > 0, nil
|
||||
})
|
||||
c.SetEndpoints(eps...)
|
||||
c.lg.Debug("set etcd endpoints by autoSync", zap.Strings("endpoints", eps))
|
||||
|
@ -288,6 +290,11 @@ func (c *Client) Dial(ep string) (*grpc.ClientConn, error) {
|
|||
func (c *Client) getToken(ctx context.Context) error {
|
||||
var err error // return last error in a case of fail
|
||||
|
||||
if c.Token != "" {
|
||||
c.authTokenBundle.UpdateAuthToken(c.Token)
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.Username == "" || c.Password == "" {
|
||||
return nil
|
||||
}
|
||||
|
@ -376,6 +383,10 @@ func newClient(cfg *Config) (*Client, error) {
|
|||
creds = credentials.NewTransportCredential(cfg.TLS)
|
||||
}
|
||||
|
||||
if cfg.Token != "" && (cfg.Username != "" || cfg.Password != "") {
|
||||
return nil, ErrMutuallyExclusiveCfg
|
||||
}
|
||||
|
||||
// use a temporary skeleton client to bootstrap first connection
|
||||
baseCtx := context.TODO()
|
||||
if cfg.Context != nil {
|
||||
|
@ -414,6 +425,12 @@ func newClient(cfg *Config) (*Client, error) {
|
|||
client.Password = cfg.Password
|
||||
client.authTokenBundle = credentials.NewPerRPCCredentialBundle()
|
||||
}
|
||||
|
||||
if cfg.Token != "" {
|
||||
client.Token = cfg.Token
|
||||
client.authTokenBundle = credentials.NewPerRPCCredentialBundle()
|
||||
}
|
||||
|
||||
if cfg.MaxCallSendMsgSize > 0 || cfg.MaxCallRecvMsgSize > 0 {
|
||||
if cfg.MaxCallRecvMsgSize > 0 && cfg.MaxCallSendMsgSize > cfg.MaxCallRecvMsgSize {
|
||||
return nil, fmt.Errorf("gRPC message recv limit (%d bytes) must be greater than send limit (%d bytes)", cfg.MaxCallRecvMsgSize, cfg.MaxCallSendMsgSize)
|
||||
|
|
|
@ -196,18 +196,18 @@ func TestBackoffJitterFraction(t *testing.T) {
|
|||
|
||||
func TestIsHaltErr(t *testing.T) {
|
||||
assert.Truef(t,
|
||||
isHaltErr(context.TODO(), errors.New("etcdserver: some etcdserver error")),
|
||||
isHaltErr(t.Context(), errors.New("etcdserver: some etcdserver error")),
|
||||
"error created by errors.New should be unavailable error",
|
||||
)
|
||||
assert.Falsef(t,
|
||||
isHaltErr(context.TODO(), rpctypes.ErrGRPCStopped),
|
||||
isHaltErr(t.Context(), rpctypes.ErrGRPCStopped),
|
||||
`error "%v" should not be halt error`, rpctypes.ErrGRPCStopped,
|
||||
)
|
||||
assert.Falsef(t,
|
||||
isHaltErr(context.TODO(), rpctypes.ErrGRPCNoLeader),
|
||||
isHaltErr(t.Context(), rpctypes.ErrGRPCNoLeader),
|
||||
`error "%v" should not be halt error`, rpctypes.ErrGRPCNoLeader,
|
||||
)
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
assert.Falsef(t,
|
||||
isHaltErr(ctx, nil),
|
||||
"no error and active context should be halt error",
|
||||
|
@ -221,18 +221,18 @@ func TestIsHaltErr(t *testing.T) {
|
|||
|
||||
func TestIsUnavailableErr(t *testing.T) {
|
||||
assert.Falsef(t,
|
||||
isUnavailableErr(context.TODO(), errors.New("etcdserver: some etcdserver error")),
|
||||
isUnavailableErr(t.Context(), errors.New("etcdserver: some etcdserver error")),
|
||||
"error created by errors.New should not be unavailable error",
|
||||
)
|
||||
assert.Truef(t,
|
||||
isUnavailableErr(context.TODO(), rpctypes.ErrGRPCStopped),
|
||||
isUnavailableErr(t.Context(), rpctypes.ErrGRPCStopped),
|
||||
`error "%v" should be unavailable error`, rpctypes.ErrGRPCStopped,
|
||||
)
|
||||
assert.Falsef(t,
|
||||
isUnavailableErr(context.TODO(), rpctypes.ErrGRPCNotCapable),
|
||||
isUnavailableErr(t.Context(), rpctypes.ErrGRPCNotCapable),
|
||||
"error %v should not be unavailable error", rpctypes.ErrGRPCNotCapable,
|
||||
)
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
assert.Falsef(t,
|
||||
isUnavailableErr(ctx, nil),
|
||||
"no error and active context should not be unavailable error",
|
||||
|
@ -245,7 +245,7 @@ func TestIsUnavailableErr(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCloseCtxClient(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
c := NewCtxClient(ctx)
|
||||
err := c.Close()
|
||||
// Close returns ctx.toErr, a nil error means an open Done channel
|
||||
|
@ -255,7 +255,7 @@ func TestCloseCtxClient(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWithLogger(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
c := NewCtxClient(ctx)
|
||||
if c.lg == nil {
|
||||
t.Errorf("unexpected nil in *zap.Logger")
|
||||
|
@ -268,7 +268,7 @@ func TestWithLogger(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestZapWithLogger(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
lg := zap.NewNop()
|
||||
c := NewCtxClient(ctx, WithZapLogger(lg))
|
||||
|
||||
|
@ -317,6 +317,75 @@ func TestAuthTokenBundleNoOverwrite(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewWithOnlyJWT(t *testing.T) {
|
||||
// This call in particular changes working directory to the tmp dir of
|
||||
// the test. The `etcd-auth-test:1` can be created in local directory,
|
||||
// not exceeding the longest allowed path on OsX.
|
||||
testutil.BeforeTest(t)
|
||||
|
||||
// Create a mock AuthServer to handle Authenticate RPCs.
|
||||
lis, err := net.Listen("unix", "etcd-auth-test:1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer lis.Close()
|
||||
addr := "unix://" + lis.Addr().String()
|
||||
srv := grpc.NewServer()
|
||||
// Having a token removes the need to ever call Authenticate on the
|
||||
// server. If that happens then this will cause a connection failure.
|
||||
etcdserverpb.RegisterAuthServer(srv, mockFailingAuthServer{})
|
||||
go srv.Serve(lis)
|
||||
defer srv.Stop()
|
||||
|
||||
c, err := NewClient(t, Config{
|
||||
DialTimeout: 5 * time.Second,
|
||||
Endpoints: []string{addr},
|
||||
Token: "foo",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
meta, err := c.authTokenBundle.PerRPCCredentials().GetRequestMetadata(t.Context(), "")
|
||||
if err != nil {
|
||||
t.Errorf("Error building request metadata: %s", err)
|
||||
}
|
||||
|
||||
if tok, ok := meta[rpctypes.TokenFieldNameGRPC]; !ok {
|
||||
t.Error("Token was not successfuly set in the auth bundle")
|
||||
} else if tok != "foo" {
|
||||
t.Errorf("Incorrect token set in auth bundle, got '%s', expected 'foo'", tok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOnlyJWTExclusivity(t *testing.T) {
|
||||
testutil.BeforeTest(t)
|
||||
|
||||
// Create a mock AuthServer to handle Authenticate RPCs.
|
||||
lis, err := net.Listen("unix", "etcd-auth-test:1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer lis.Close()
|
||||
addr := "unix://" + lis.Addr().String()
|
||||
srv := grpc.NewServer()
|
||||
// Having a token removes the need to ever call Authenticate on the
|
||||
// server. If that happens then this will cause a connection failure.
|
||||
etcdserverpb.RegisterAuthServer(srv, mockFailingAuthServer{})
|
||||
go srv.Serve(lis)
|
||||
defer srv.Stop()
|
||||
|
||||
_, err = NewClient(t, Config{
|
||||
DialTimeout: 5 * time.Second,
|
||||
Endpoints: []string{addr},
|
||||
Token: "foo",
|
||||
Username: "user",
|
||||
Password: "pass",
|
||||
})
|
||||
require.ErrorIs(t, ErrMutuallyExclusiveCfg, err)
|
||||
}
|
||||
|
||||
func TestSyncFiltersMembers(t *testing.T) {
|
||||
c, _ := NewClient(t, Config{Endpoints: []string{"http://254.0.0.1:12345"}})
|
||||
defer c.Close()
|
||||
|
@ -327,7 +396,7 @@ func TestSyncFiltersMembers(t *testing.T) {
|
|||
{ID: 2, Name: "isStartedAndNotLearner", ClientURLs: []string{"http://254.0.0.3:12345"}, IsLearner: false},
|
||||
},
|
||||
}
|
||||
c.Sync(context.Background())
|
||||
c.Sync(t.Context())
|
||||
|
||||
endpoints := c.Endpoints()
|
||||
if len(endpoints) != 1 || endpoints[0] != "http://254.0.0.3:12345" {
|
||||
|
@ -421,7 +490,7 @@ func TestClientRejectOldCluster(t *testing.T) {
|
|||
endpointToVersion[tt.endpoints[j]] = tt.versions[j]
|
||||
}
|
||||
c := &Client{
|
||||
ctx: context.Background(),
|
||||
ctx: t.Context(),
|
||||
endpoints: tt.endpoints,
|
||||
epMu: new(sync.RWMutex),
|
||||
Maintenance: &mockMaintenance{
|
||||
|
@ -476,6 +545,14 @@ func (mm mockMaintenance) Downgrade(ctx context.Context, action DowngradeAction,
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
type mockFailingAuthServer struct {
|
||||
*etcdserverpb.UnimplementedAuthServer
|
||||
}
|
||||
|
||||
func (mockFailingAuthServer) Authenticate(context.Context, *etcdserverpb.AuthenticateRequest) (*etcdserverpb.AuthenticateResponse, error) {
|
||||
return nil, errors.New("this auth server always fails")
|
||||
}
|
||||
|
||||
type mockAuthServer struct {
|
||||
*etcdserverpb.UnimplementedAuthServer
|
||||
}
|
||||
|
|
|
@ -66,6 +66,9 @@ type Config struct {
|
|||
// Password is a password for authentication.
|
||||
Password string `json:"password"`
|
||||
|
||||
// Token is a JWT used for authentication instead of a password.
|
||||
Token string `json:"token"`
|
||||
|
||||
// RejectOldCluster when set will refuse to create a client against an outdated cluster.
|
||||
RejectOldCluster bool `json:"reject-old-cluster"`
|
||||
|
||||
|
@ -130,6 +133,7 @@ type SecureConfig struct {
|
|||
type AuthConfig struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func (cs *ConfigSpec) Clone() *ConfigSpec {
|
||||
|
@ -157,7 +161,7 @@ func (cs *ConfigSpec) Clone() *ConfigSpec {
|
|||
}
|
||||
|
||||
func (cfg AuthConfig) Empty() bool {
|
||||
return cfg.Username == "" && cfg.Password == ""
|
||||
return cfg.Username == "" && cfg.Password == "" && cfg.Token == ""
|
||||
}
|
||||
|
||||
// NewClientConfig creates a Config based on the provided ConfigSpec.
|
||||
|
@ -180,6 +184,7 @@ func NewClientConfig(confSpec *ConfigSpec, lg *zap.Logger) (*Config, error) {
|
|||
if confSpec.Auth != nil {
|
||||
cfg.Username = confSpec.Auth.Username
|
||||
cfg.Password = confSpec.Auth.Password
|
||||
cfg.Token = confSpec.Auth.Token
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
|
|
|
@ -71,6 +71,25 @@ func TestNewClientConfig(t *testing.T) {
|
|||
Password: "changeme",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "JWT specified",
|
||||
spec: ConfigSpec{
|
||||
Endpoints: []string{"http://192.168.0.12:2379"},
|
||||
DialTimeout: 1 * time.Second,
|
||||
KeepAliveTime: 4 * time.Second,
|
||||
KeepAliveTimeout: 6 * time.Second,
|
||||
Auth: &AuthConfig{
|
||||
Token: "test",
|
||||
},
|
||||
},
|
||||
expectedConf: Config{
|
||||
Endpoints: []string{"http://192.168.0.12:2379"},
|
||||
DialTimeout: 1 * time.Second,
|
||||
DialKeepAliveTime: 4 * time.Second,
|
||||
DialKeepAliveTimeout: 6 * time.Second,
|
||||
Token: "test",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default secure transport",
|
||||
spec: ConfigSpec{
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
package credentials
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -25,7 +24,7 @@ import (
|
|||
|
||||
func TestUpdateAuthToken(t *testing.T) {
|
||||
bundle := NewPerRPCCredentialBundle()
|
||||
ctx := context.TODO()
|
||||
ctx := t.Context()
|
||||
|
||||
metadataBeforeUpdate, _ := bundle.PerRPCCredentials().GetRequestMetadata(ctx)
|
||||
assert.Empty(t, metadataBeforeUpdate)
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
package clientv3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
|
@ -27,7 +26,7 @@ import (
|
|||
)
|
||||
|
||||
func TestMetadataWithRequireLeader(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
ctx := t.Context()
|
||||
_, ok := metadata.FromOutgoingContext(ctx)
|
||||
require.Falsef(t, ok, "expected no outgoing metadata ctx key")
|
||||
|
||||
|
@ -48,7 +47,7 @@ func TestMetadataWithRequireLeader(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMetadataWithClientAPIVersion(t *testing.T) {
|
||||
ctx := withVersion(WithRequireLeader(context.TODO()))
|
||||
ctx := withVersion(WithRequireLeader(t.Context()))
|
||||
|
||||
md, ok := metadata.FromOutgoingContext(ctx)
|
||||
require.Truef(t, ok, "expected outgoing metadata ctx key")
|
||||
|
|
|
@ -1,44 +1,47 @@
|
|||
module go.etcd.io/etcd/client/v3
|
||||
|
||||
go 1.23.0
|
||||
go 1.24
|
||||
|
||||
toolchain go1.23.11
|
||||
toolchain go1.24.5
|
||||
|
||||
require (
|
||||
github.com/coreos/go-semver v0.3.1
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.etcd.io/etcd/api/v3 v3.6.4
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.4
|
||||
go.etcd.io/etcd/api/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0-alpha.0
|
||||
go.uber.org/zap v1.27.0
|
||||
google.golang.org/grpc v1.71.1
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
google.golang.org/grpc v1.74.2
|
||||
sigs.k8s.io/yaml v1.5.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.65.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
|
|||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
|
@ -19,21 +19,20 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
|||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
|
@ -42,40 +41,44 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
|||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
|
||||
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -85,20 +88,20 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
|
@ -107,18 +110,18 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
|
||||
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
|
||||
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
|
||||
|
|
|
@ -60,7 +60,7 @@ func (r *EtcdManualResolver) SetEndpoints(endpoints []string) {
|
|||
}
|
||||
|
||||
func (r EtcdManualResolver) updateState() {
|
||||
if r.CC != nil {
|
||||
if getCC(r) != nil {
|
||||
eps := make([]resolver.Endpoint, len(r.endpoints))
|
||||
for i, ep := range r.endpoints {
|
||||
addr, serverName := endpoint.Interpret(ep)
|
||||
|
@ -75,3 +75,13 @@ func (r EtcdManualResolver) updateState() {
|
|||
r.UpdateState(state)
|
||||
}
|
||||
}
|
||||
|
||||
func getCC(r EtcdManualResolver) (cc resolver.ClientConn) {
|
||||
defer func() {
|
||||
if rec := recover(); rec != nil {
|
||||
cc = nil
|
||||
}
|
||||
}()
|
||||
|
||||
return r.CC()
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ func (kv *kv) Compact(ctx context.Context, rev int64, opts ...CompactOption) (*C
|
|||
if err != nil {
|
||||
return nil, ContextError(ctx, err)
|
||||
}
|
||||
return (*CompactResponse)(resp), err
|
||||
return (*CompactResponse)(resp), nil
|
||||
}
|
||||
|
||||
func (kv *kv) Txn(ctx context.Context) Txn {
|
||||
|
|
|
@ -127,10 +127,31 @@ func (op Op) IsKeysOnly() bool { return op.keysOnly }
|
|||
// IsCountOnly returns whether countOnly is set.
|
||||
func (op Op) IsCountOnly() bool { return op.countOnly }
|
||||
|
||||
// IsSortSet returns true if WithSort is set.
|
||||
func (op Op) IsSortSet() bool { return op.sort != nil }
|
||||
|
||||
func (op Op) IsOptsWithFromKey() bool { return op.isOptsWithFromKey }
|
||||
|
||||
func (op Op) IsOptsWithPrefix() bool { return op.isOptsWithPrefix }
|
||||
|
||||
// IsPrevKV returns whether WithPrevKV() is set.
|
||||
func (op Op) IsPrevKV() bool { return op.prevKV }
|
||||
|
||||
// IsFragment returns whether WithFragment() is set.
|
||||
func (op Op) IsFragment() bool { return op.fragment }
|
||||
|
||||
// IsProgressNotify returns whether WithProgressNotify() is set.
|
||||
func (op Op) IsProgressNotify() bool { return op.progressNotify }
|
||||
|
||||
// IsCreatedNotify returns whether WithCreatedNotify() is set.
|
||||
func (op Op) IsCreatedNotify() bool { return op.createdNotify }
|
||||
|
||||
// IsFilterPut returns whether WithFilterPut() is set.
|
||||
func (op Op) IsFilterPut() bool { return op.filterPut }
|
||||
|
||||
// IsFilterDelete returns whether WithFilterDelete() is set.
|
||||
func (op Op) IsFilterDelete() bool { return op.filterDelete }
|
||||
|
||||
// MinModRev returns the operation's minimum modify revision.
|
||||
func (op Op) MinModRev() int64 { return op.minModRev }
|
||||
|
||||
|
@ -308,7 +329,7 @@ func OpTxn(cmps []Cmp, thenOps []Op, elseOps []Op) Op {
|
|||
return Op{t: tTxn, cmps: cmps, thenOps: thenOps, elseOps: elseOps}
|
||||
}
|
||||
|
||||
func opWatch(key string, opts ...OpOption) Op {
|
||||
func OpWatch(key string, opts ...OpOption) Op {
|
||||
ret := Op{t: tRange, key: []byte(key)}
|
||||
ret.applyOpts(opts)
|
||||
switch {
|
||||
|
|
|
@ -76,7 +76,7 @@ func TestKvOrdering(t *testing.T) {
|
|||
tt.prevRev,
|
||||
sync.RWMutex{},
|
||||
}
|
||||
res, err := kv.Get(context.TODO(), "mockKey")
|
||||
res, err := kv.Get(t.Context(), "mockKey")
|
||||
if err != nil {
|
||||
t.Errorf("#%d: expected response %+v, got error %+v", i, tt.response, err)
|
||||
}
|
||||
|
@ -131,9 +131,9 @@ func TestTxnOrdering(t *testing.T) {
|
|||
sync.RWMutex{},
|
||||
}
|
||||
txn := &txnOrdering{
|
||||
kv.Txn(context.Background()),
|
||||
kv.Txn(t.Context()),
|
||||
kv,
|
||||
context.Background(),
|
||||
t.Context(),
|
||||
sync.Mutex{},
|
||||
[]clientv3.Cmp{},
|
||||
[]clientv3.Op{},
|
||||
|
|
|
@ -351,11 +351,11 @@ func isContextError(err error) bool {
|
|||
func contextErrToGRPCErr(err error) error {
|
||||
switch {
|
||||
case errors.Is(err, context.DeadlineExceeded):
|
||||
return status.Errorf(codes.DeadlineExceeded, err.Error())
|
||||
return status.Error(codes.DeadlineExceeded, err.Error())
|
||||
case errors.Is(err, context.Canceled):
|
||||
return status.Errorf(codes.Canceled, err.Error())
|
||||
return status.Error(codes.Canceled, err.Error())
|
||||
default:
|
||||
return status.Errorf(codes.Unknown, err.Error())
|
||||
return status.Error(codes.Unknown, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
package clientv3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -44,7 +43,7 @@ func TestTxnPanics(t *testing.T) {
|
|||
{
|
||||
f: func(errc chan string) {
|
||||
defer df(errc)
|
||||
kv.Txn(context.TODO()).If(cmp).If(cmp)
|
||||
kv.Txn(t.Context()).If(cmp).If(cmp)
|
||||
},
|
||||
|
||||
err: "cannot call If twice!",
|
||||
|
@ -52,7 +51,7 @@ func TestTxnPanics(t *testing.T) {
|
|||
{
|
||||
f: func(errc chan string) {
|
||||
defer df(errc)
|
||||
kv.Txn(context.TODO()).Then(op).If(cmp)
|
||||
kv.Txn(t.Context()).Then(op).If(cmp)
|
||||
},
|
||||
|
||||
err: "cannot call If after Then!",
|
||||
|
@ -60,7 +59,7 @@ func TestTxnPanics(t *testing.T) {
|
|||
{
|
||||
f: func(errc chan string) {
|
||||
defer df(errc)
|
||||
kv.Txn(context.TODO()).Else(op).If(cmp)
|
||||
kv.Txn(t.Context()).Else(op).If(cmp)
|
||||
},
|
||||
|
||||
err: "cannot call If after Else!",
|
||||
|
@ -68,7 +67,7 @@ func TestTxnPanics(t *testing.T) {
|
|||
{
|
||||
f: func(errc chan string) {
|
||||
defer df(errc)
|
||||
kv.Txn(context.TODO()).Then(op).Then(op)
|
||||
kv.Txn(t.Context()).Then(op).Then(op)
|
||||
},
|
||||
|
||||
err: "cannot call Then twice!",
|
||||
|
@ -76,7 +75,7 @@ func TestTxnPanics(t *testing.T) {
|
|||
{
|
||||
f: func(errc chan string) {
|
||||
defer df(errc)
|
||||
kv.Txn(context.TODO()).Else(op).Then(op)
|
||||
kv.Txn(t.Context()).Else(op).Then(op)
|
||||
},
|
||||
|
||||
err: "cannot call Then after Else!",
|
||||
|
@ -84,7 +83,7 @@ func TestTxnPanics(t *testing.T) {
|
|||
{
|
||||
f: func(errc chan string) {
|
||||
defer df(errc)
|
||||
kv.Txn(context.TODO()).Else(op).Else(op)
|
||||
kv.Txn(t.Context()).Else(op).Else(op)
|
||||
},
|
||||
|
||||
err: "cannot call Else twice!",
|
||||
|
|
|
@ -105,8 +105,8 @@ type WatchResponse struct {
|
|||
|
||||
closeErr error
|
||||
|
||||
// cancelReason is a reason of canceling watch
|
||||
cancelReason string
|
||||
// CancelReason is a reason of canceling watch
|
||||
CancelReason string
|
||||
}
|
||||
|
||||
// IsCreate returns true if the event tells that the key is newly created.
|
||||
|
@ -127,8 +127,8 @@ func (wr *WatchResponse) Err() error {
|
|||
case wr.CompactRevision != 0:
|
||||
return v3rpc.ErrCompacted
|
||||
case wr.Canceled:
|
||||
if len(wr.cancelReason) != 0 {
|
||||
return v3rpc.Error(status.Error(codes.FailedPrecondition, wr.cancelReason))
|
||||
if len(wr.CancelReason) != 0 {
|
||||
return v3rpc.Error(status.Error(codes.FailedPrecondition, wr.CancelReason))
|
||||
}
|
||||
return v3rpc.ErrFutureRev
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ func (w *watcher) newWatcherGRPCStream(inctx context.Context) *watchGRPCStream {
|
|||
|
||||
// Watch posts a watch request to run() and waits for a new watcher channel
|
||||
func (w *watcher) Watch(ctx context.Context, key string, opts ...OpOption) WatchChan {
|
||||
ow := opWatch(key, opts...)
|
||||
ow := OpWatch(key, opts...)
|
||||
|
||||
var filters []pb.WatchCreateRequest_FilterType
|
||||
if ow.filterPut {
|
||||
|
@ -580,7 +580,7 @@ func (w *watchGRPCStream) run() {
|
|||
case pbresp := <-w.respc:
|
||||
if cur == nil || pbresp.Created || pbresp.Canceled {
|
||||
cur = pbresp
|
||||
} else if cur != nil && cur.WatchId == pbresp.WatchId {
|
||||
} else if cur.WatchId == pbresp.WatchId {
|
||||
// merge new events
|
||||
cur.Events = append(cur.Events, pbresp.Events...)
|
||||
// update "Fragment" field; last response with "Fragment" == false
|
||||
|
@ -723,7 +723,7 @@ func (w *watchGRPCStream) dispatchEvent(pbresp *pb.WatchResponse) bool {
|
|||
CompactRevision: pbresp.CompactRevision,
|
||||
Created: pbresp.Created,
|
||||
Canceled: pbresp.Canceled,
|
||||
cancelReason: pbresp.CancelReason,
|
||||
CancelReason: pbresp.CancelReason,
|
||||
}
|
||||
|
||||
// watch IDs are zero indexed, so request notify watch responses are assigned a watch ID of InvalidWatchID to
|
||||
|
|
|
@ -72,7 +72,7 @@ func TestStreamKeyFromCtx(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "multiple keys",
|
||||
ctx: metadata.NewOutgoingContext(context.Background(), metadata.MD{
|
||||
ctx: metadata.NewOutgoingContext(t.Context(), metadata.MD{
|
||||
"key1": []string{"value1"},
|
||||
"key2": []string{"value2a", "value2b"},
|
||||
}),
|
||||
|
@ -80,19 +80,19 @@ func TestStreamKeyFromCtx(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "no keys",
|
||||
ctx: metadata.NewOutgoingContext(context.Background(), metadata.MD{}),
|
||||
ctx: metadata.NewOutgoingContext(t.Context(), metadata.MD{}),
|
||||
expected: "map[]",
|
||||
},
|
||||
{
|
||||
name: "only one key",
|
||||
ctx: metadata.NewOutgoingContext(context.Background(), metadata.MD{
|
||||
ctx: metadata.NewOutgoingContext(t.Context(), metadata.MD{
|
||||
"key1": []string{"value1", "value1a"},
|
||||
}),
|
||||
expected: "map[key1:[value1 value1a]]",
|
||||
},
|
||||
{
|
||||
name: "no metadata",
|
||||
ctx: context.Background(),
|
||||
ctx: t.Context(),
|
||||
expected: "",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ func TestConfigFromFile(t *testing.T) {
|
|||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
tmpfile, err := os.CreateTemp("", "clientcfg")
|
||||
tmpfile, err := os.CreateTemp(t.TempDir(), "clientcfg")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"go.etcd.io/etcd/client/pkg/v3/fileutil"
|
||||
"go.etcd.io/etcd/client/pkg/v3/types"
|
||||
"go.etcd.io/etcd/server/v3/etcdserver/api/rafthttp"
|
||||
|
@ -34,8 +36,6 @@ import (
|
|||
"go.etcd.io/etcd/server/v3/storage/wal/walpb"
|
||||
"go.etcd.io/raft/v3"
|
||||
"go.etcd.io/raft/v3/raftpb"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type commit struct {
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2020 The etcd Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -182,7 +182,7 @@ func newCheckPerfCommand(cmd *cobra.Command, args []string) {
|
|||
bar := pb.New(cfg.duration)
|
||||
bar.Start()
|
||||
|
||||
r := report.NewReport("%4.4f")
|
||||
r := report.NewReport("%4.4f", "", false)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(len(clients))
|
||||
|
@ -353,7 +353,7 @@ func newCheckDatascaleCommand(cmd *cobra.Command, args []string) {
|
|||
ksize, vsize := 512, 512
|
||||
k, v := make([]byte, ksize), string(make([]byte, vsize))
|
||||
|
||||
r := report.NewReport("%4.4f")
|
||||
r := report.NewReport("%4.4f", "", false)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(clients))
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ type GlobalFlags struct {
|
|||
|
||||
User string
|
||||
Password string
|
||||
Token string
|
||||
|
||||
Debug bool
|
||||
}
|
||||
|
@ -290,13 +291,22 @@ func authCfgFromCmd(cmd *cobra.Command) *clientv3.AuthConfig {
|
|||
if err != nil {
|
||||
cobrautl.ExitWithError(cobrautl.ExitBadArgs, err)
|
||||
}
|
||||
tokenFlag, err := cmd.Flags().GetString("auth-jwt-token")
|
||||
if err != nil {
|
||||
cobrautl.ExitWithError(cobrautl.ExitBadArgs, err)
|
||||
}
|
||||
|
||||
if userFlag == "" {
|
||||
if userFlag == "" && tokenFlag == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var cfg clientv3.AuthConfig
|
||||
|
||||
if tokenFlag != "" {
|
||||
cfg.Token = tokenFlag
|
||||
return &cfg
|
||||
}
|
||||
|
||||
if passwordFlag == "" {
|
||||
splitted := strings.SplitN(userFlag, ":", 2)
|
||||
if len(splitted) < 2 {
|
||||
|
|
|
@ -17,20 +17,53 @@ package command
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
type jsonPrinter struct {
|
||||
isHex bool
|
||||
writer io.Writer
|
||||
isHex bool
|
||||
printer
|
||||
}
|
||||
|
||||
type (
|
||||
HexResponseHeader pb.ResponseHeader
|
||||
HexMember pb.Member
|
||||
)
|
||||
|
||||
func (h *HexResponseHeader) MarshalJSON() ([]byte, error) {
|
||||
type Alias pb.ResponseHeader
|
||||
|
||||
return json.Marshal(&struct {
|
||||
ClusterID string `json:"cluster_id"`
|
||||
MemberID string `json:"member_id"`
|
||||
Alias
|
||||
}{
|
||||
ClusterID: fmt.Sprintf("%x", h.ClusterId),
|
||||
MemberID: fmt.Sprintf("%x", h.MemberId),
|
||||
Alias: (Alias)(*h),
|
||||
})
|
||||
}
|
||||
|
||||
func (m *HexMember) MarshalJSON() ([]byte, error) {
|
||||
type Alias pb.Member
|
||||
|
||||
return json.Marshal(&struct {
|
||||
ID string `json:"ID"`
|
||||
Alias
|
||||
}{
|
||||
ID: fmt.Sprintf("%x", m.ID),
|
||||
Alias: (Alias)(*m),
|
||||
})
|
||||
}
|
||||
|
||||
func newJSONPrinter(isHex bool) printer {
|
||||
return &jsonPrinter{
|
||||
writer: os.Stdout,
|
||||
isHex: isHex,
|
||||
printer: &printerRPC{newPrinterUnsupported("json"), printJSON},
|
||||
}
|
||||
|
@ -40,61 +73,106 @@ func (p *jsonPrinter) EndpointHealth(r []epHealth) { printJSON(r) }
|
|||
func (p *jsonPrinter) EndpointStatus(r []epStatus) { printJSON(r) }
|
||||
func (p *jsonPrinter) EndpointHashKV(r []epHashKV) { printJSON(r) }
|
||||
|
||||
func (p *jsonPrinter) MemberList(r clientv3.MemberListResponse) {
|
||||
if p.isHex {
|
||||
printMemberListWithHexJSON(r)
|
||||
} else {
|
||||
printJSON(r)
|
||||
}
|
||||
}
|
||||
func (p *jsonPrinter) MemberAdd(r clientv3.MemberAddResponse) { p.printJSON(r) }
|
||||
func (p *jsonPrinter) MemberRemove(_ uint64, r clientv3.MemberRemoveResponse) { p.printJSON(r) }
|
||||
func (p *jsonPrinter) MemberUpdate(_ uint64, r clientv3.MemberUpdateResponse) { p.printJSON(r) }
|
||||
func (p *jsonPrinter) MemberPromote(_ uint64, r clientv3.MemberPromoteResponse) { p.printJSON(r) }
|
||||
func (p *jsonPrinter) MemberList(r clientv3.MemberListResponse) { p.printJSON(r) }
|
||||
|
||||
func printJSON(v any) {
|
||||
func printJSONTo(w io.Writer, v any) {
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
fmt.Fprintln(w, string(b))
|
||||
}
|
||||
|
||||
func printMemberListWithHexJSON(r clientv3.MemberListResponse) {
|
||||
var buffer strings.Builder
|
||||
var b []byte
|
||||
buffer.WriteString("{\"header\":{\"cluster_id\":\"")
|
||||
b = strconv.AppendUint(nil, r.Header.ClusterId, 16)
|
||||
buffer.Write(b)
|
||||
buffer.WriteString("\",\"member_id\":\"")
|
||||
b = strconv.AppendUint(nil, r.Header.MemberId, 16)
|
||||
buffer.Write(b)
|
||||
buffer.WriteString("\",\"raft_term\":")
|
||||
b = strconv.AppendUint(nil, r.Header.RaftTerm, 10)
|
||||
buffer.Write(b)
|
||||
buffer.WriteByte('}')
|
||||
for i := 0; i < len(r.Members); i++ {
|
||||
if i == 0 {
|
||||
buffer.WriteString(",\"members\":[{\"ID\":\"")
|
||||
} else {
|
||||
buffer.WriteString(",{\"ID\":\"")
|
||||
}
|
||||
b = strconv.AppendUint(nil, r.Members[i].ID, 16)
|
||||
buffer.Write(b)
|
||||
buffer.WriteString("\",\"name\":\"" + r.Members[i].Name + "\"," + "\"peerURLs\":")
|
||||
b, err := json.Marshal(r.Members[i].PeerURLs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
buffer.Write(b)
|
||||
buffer.WriteString(",\"clientURLs\":")
|
||||
b, err = json.Marshal(r.Members[i].ClientURLs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
buffer.Write(b)
|
||||
buffer.WriteByte('}')
|
||||
if i == len(r.Members)-1 {
|
||||
buffer.WriteString("]")
|
||||
}
|
||||
}
|
||||
buffer.WriteString("}")
|
||||
fmt.Println(buffer.String())
|
||||
func printJSON(v any) {
|
||||
printJSONTo(os.Stdout, v)
|
||||
}
|
||||
|
||||
func (p *jsonPrinter) printJSON(v any) {
|
||||
var data any
|
||||
if !p.isHex {
|
||||
printJSONTo(p.writer, v)
|
||||
return
|
||||
}
|
||||
|
||||
switch r := v.(type) {
|
||||
case clientv3.MemberAddResponse:
|
||||
type Alias clientv3.MemberAddResponse
|
||||
|
||||
data = &struct {
|
||||
Header *HexResponseHeader `json:"header"`
|
||||
Member *HexMember `json:"member"`
|
||||
Members []*HexMember `json:"members"`
|
||||
*Alias
|
||||
}{
|
||||
Header: (*HexResponseHeader)(r.Header),
|
||||
Member: (*HexMember)(r.Member),
|
||||
Members: toHexMembers(r.Members),
|
||||
Alias: (*Alias)(&r),
|
||||
}
|
||||
case clientv3.MemberRemoveResponse:
|
||||
type Alias clientv3.MemberRemoveResponse
|
||||
|
||||
data = &struct {
|
||||
Header *HexResponseHeader `json:"header"`
|
||||
Members []*HexMember `json:"members"`
|
||||
*Alias
|
||||
}{
|
||||
Header: (*HexResponseHeader)(r.Header),
|
||||
Members: toHexMembers(r.Members),
|
||||
Alias: (*Alias)(&r),
|
||||
}
|
||||
case clientv3.MemberUpdateResponse:
|
||||
type Alias clientv3.MemberUpdateResponse
|
||||
|
||||
data = &struct {
|
||||
Header *HexResponseHeader `json:"header"`
|
||||
Members []*HexMember `json:"members"`
|
||||
*Alias
|
||||
}{
|
||||
Header: (*HexResponseHeader)(r.Header),
|
||||
Members: toHexMembers(r.Members),
|
||||
Alias: (*Alias)(&r),
|
||||
}
|
||||
case clientv3.MemberPromoteResponse:
|
||||
type Alias clientv3.MemberPromoteResponse
|
||||
|
||||
data = &struct {
|
||||
Header *HexResponseHeader `json:"header"`
|
||||
Members []*HexMember `json:"members"`
|
||||
*Alias
|
||||
}{
|
||||
Header: (*HexResponseHeader)(r.Header),
|
||||
Members: toHexMembers(r.Members),
|
||||
Alias: (*Alias)(&r),
|
||||
}
|
||||
case clientv3.MemberListResponse:
|
||||
type Alias clientv3.MemberListResponse
|
||||
|
||||
data = &struct {
|
||||
Header *HexResponseHeader `json:"header"`
|
||||
Members []*HexMember `json:"members"`
|
||||
*Alias
|
||||
}{
|
||||
Header: (*HexResponseHeader)(r.Header),
|
||||
Members: toHexMembers(r.Members),
|
||||
Alias: (*Alias)(&r),
|
||||
}
|
||||
default:
|
||||
data = v
|
||||
}
|
||||
|
||||
printJSONTo(p.writer, data)
|
||||
}
|
||||
|
||||
func toHexMembers(members []*pb.Member) []*HexMember {
|
||||
hexMembers := make([]*HexMember, len(members))
|
||||
for i, member := range members {
|
||||
hexMembers[i] = (*HexMember)(member)
|
||||
}
|
||||
return hexMembers
|
||||
}
|
||||
|
|
|
@ -0,0 +1,328 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
keyHeader = "header"
|
||||
keyMember = "member"
|
||||
keyMembers = "members"
|
||||
|
||||
keyClusterID = "cluster_id"
|
||||
keyMemberID = "member_id"
|
||||
keyRaftTerm = "raft_term"
|
||||
keyRevision = "revision"
|
||||
keyID = "ID"
|
||||
)
|
||||
|
||||
func assertNumericFieldEqual(t *testing.T, obj map[string]any, key string, want int64) {
|
||||
raw, ok := obj[key]
|
||||
require.Truef(t, ok, "missing key %q in map %v", key, obj)
|
||||
|
||||
n, ok := raw.(json.Number)
|
||||
require.Truef(t, ok, "field %q is not json.Number: %v", key, raw)
|
||||
|
||||
val, err := n.Int64()
|
||||
require.NoErrorf(t, err, "failed to convert field %q to int64: %v", key, n)
|
||||
|
||||
assert.Equalf(t, want, val, "unexpected value for field %q", key)
|
||||
}
|
||||
|
||||
func assertHexFieldEqual(t *testing.T, obj map[string]any, key string, want string) {
|
||||
raw, ok := obj[key]
|
||||
require.Truef(t, ok, "missing key %q in map %v", key, obj)
|
||||
|
||||
str, ok := raw.(string)
|
||||
require.Truef(t, ok, "field %q is not a string: %v", key, str)
|
||||
|
||||
assert.Equalf(t, want, str, "unexpected value for hex field %q", key)
|
||||
}
|
||||
|
||||
func assertHeader(t *testing.T, testGroup *testScenario, tt *testCase, got map[string]any) {
|
||||
rawHeader, ok := got[keyHeader]
|
||||
require.Truef(t, ok, "output does not contain %q field: %v", keyHeader, got)
|
||||
header, ok := rawHeader.(map[string]any)
|
||||
require.Truef(t, ok, "field %q is not map[string]any: %v", keyHeader, rawHeader)
|
||||
|
||||
if testGroup.isHex {
|
||||
assertHexFieldEqual(t, header, keyClusterID, tt.wantHexString)
|
||||
assertHexFieldEqual(t, header, keyMemberID, tt.wantHexString)
|
||||
} else {
|
||||
assertNumericFieldEqual(t, header, keyClusterID, tt.wantDecimalNumber)
|
||||
assertNumericFieldEqual(t, header, keyMemberID, tt.wantDecimalNumber)
|
||||
}
|
||||
assertNumericFieldEqual(t, header, keyRaftTerm, tt.wantDecimalNumber)
|
||||
assertNumericFieldEqual(t, header, keyRevision, tt.wantDecimalNumber)
|
||||
}
|
||||
|
||||
func assertMember(t *testing.T, testGroup *testScenario, tt *testCase, rawMember any) {
|
||||
member, ok := rawMember.(map[string]any)
|
||||
require.Truef(t, ok, "field %q is not map[string]any: %v", keyMember, rawMember)
|
||||
|
||||
if testGroup.isHex {
|
||||
assertHexFieldEqual(t, member, keyID, tt.wantHexString)
|
||||
} else {
|
||||
assertNumericFieldEqual(t, member, keyID, tt.wantDecimalNumber)
|
||||
}
|
||||
}
|
||||
|
||||
func assertMembers(t *testing.T, testGroup *testScenario, tt *testCase, got map[string]any) {
|
||||
rawMembers, ok := got[keyMembers]
|
||||
require.Truef(t, ok, "output does not contain %q field: %v", keyMembers, got)
|
||||
members, ok := rawMembers.([]any)
|
||||
require.Truef(t, ok, "field %q is not []any: %v", keyMembers, rawMembers)
|
||||
|
||||
for _, rawMember := range members {
|
||||
assertMember(t, testGroup, tt, rawMember)
|
||||
}
|
||||
}
|
||||
|
||||
type testCase struct {
|
||||
number uint64
|
||||
wantHexString string
|
||||
wantDecimalNumber int64
|
||||
}
|
||||
|
||||
type testScenario struct {
|
||||
name string
|
||||
isHex bool
|
||||
cases []testCase
|
||||
}
|
||||
|
||||
var testCases = []testCase{
|
||||
{1, "1", 1},
|
||||
{100, "64", 100},
|
||||
{1234567890, "499602d2", 1234567890},
|
||||
{math.MaxInt64, "7fffffffffffffff", math.MaxInt64},
|
||||
}
|
||||
|
||||
func TestMemberAdd(t *testing.T) {
|
||||
tests := []testScenario{
|
||||
{name: "decimal", isHex: false, cases: testCases},
|
||||
{name: "hex", isHex: true, cases: testCases},
|
||||
}
|
||||
|
||||
for _, testGroup := range tests {
|
||||
t.Run(testGroup.name, func(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
p := &jsonPrinter{writer: &buffer, isHex: testGroup.isHex}
|
||||
|
||||
for _, tt := range testGroup.cases {
|
||||
t.Run(fmt.Sprintf("number=%d", tt.number), func(t *testing.T) {
|
||||
buffer.Reset()
|
||||
decoder := json.NewDecoder(&buffer)
|
||||
decoder.UseNumber()
|
||||
|
||||
response := clientv3.MemberAddResponse{
|
||||
Header: &pb.ResponseHeader{
|
||||
ClusterId: tt.number,
|
||||
MemberId: tt.number,
|
||||
Revision: int64(tt.number),
|
||||
RaftTerm: tt.number,
|
||||
},
|
||||
Member: &pb.Member{ID: tt.number},
|
||||
Members: []*pb.Member{{ID: tt.number}},
|
||||
}
|
||||
p.MemberAdd(response)
|
||||
|
||||
var got map[string]any
|
||||
err := decoder.Decode(&got)
|
||||
require.NoErrorf(t, err, "failed to decode JSON")
|
||||
|
||||
assertHeader(t, &testGroup, &tt, got)
|
||||
|
||||
rawMember, ok := got[keyMember]
|
||||
require.Truef(t, ok, "output does not contain %q field: %v", keyMember, got)
|
||||
assertMember(t, &testGroup, &tt, rawMember)
|
||||
|
||||
assertMembers(t, &testGroup, &tt, got)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemberRemove(t *testing.T) {
|
||||
tests := []testScenario{
|
||||
{name: "decimal", isHex: false, cases: testCases},
|
||||
{name: "hex", isHex: true, cases: testCases},
|
||||
}
|
||||
|
||||
for _, testGroup := range tests {
|
||||
t.Run(testGroup.name, func(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
p := &jsonPrinter{writer: &buffer, isHex: testGroup.isHex}
|
||||
|
||||
for _, tt := range testGroup.cases {
|
||||
t.Run(fmt.Sprintf("number=%d", tt.number), func(t *testing.T) {
|
||||
buffer.Reset()
|
||||
decoder := json.NewDecoder(&buffer)
|
||||
decoder.UseNumber()
|
||||
|
||||
response := clientv3.MemberRemoveResponse{
|
||||
Header: &pb.ResponseHeader{
|
||||
ClusterId: tt.number,
|
||||
MemberId: tt.number,
|
||||
Revision: int64(tt.number),
|
||||
RaftTerm: tt.number,
|
||||
},
|
||||
Members: []*pb.Member{{ID: tt.number}},
|
||||
}
|
||||
p.MemberRemove(0, response)
|
||||
|
||||
var got map[string]any
|
||||
err := decoder.Decode(&got)
|
||||
require.NoErrorf(t, err, "failed to decode JSON")
|
||||
|
||||
assertHeader(t, &testGroup, &tt, got)
|
||||
assertMembers(t, &testGroup, &tt, got)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemberUpdate(t *testing.T) {
|
||||
tests := []testScenario{
|
||||
{name: "decimal", isHex: false, cases: testCases},
|
||||
{name: "hex", isHex: true, cases: testCases},
|
||||
}
|
||||
|
||||
for _, testGroup := range tests {
|
||||
t.Run(testGroup.name, func(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
p := &jsonPrinter{writer: &buffer, isHex: testGroup.isHex}
|
||||
|
||||
for _, tt := range testGroup.cases {
|
||||
t.Run(fmt.Sprintf("number=%d", tt.number), func(t *testing.T) {
|
||||
buffer.Reset()
|
||||
decoder := json.NewDecoder(&buffer)
|
||||
decoder.UseNumber()
|
||||
|
||||
response := clientv3.MemberUpdateResponse{
|
||||
Header: &pb.ResponseHeader{
|
||||
ClusterId: tt.number,
|
||||
MemberId: tt.number,
|
||||
Revision: int64(tt.number),
|
||||
RaftTerm: tt.number,
|
||||
},
|
||||
Members: []*pb.Member{{ID: tt.number}},
|
||||
}
|
||||
p.MemberUpdate(0, response)
|
||||
|
||||
var got map[string]any
|
||||
err := decoder.Decode(&got)
|
||||
require.NoErrorf(t, err, "failed to decode JSON")
|
||||
|
||||
assertHeader(t, &testGroup, &tt, got)
|
||||
assertMembers(t, &testGroup, &tt, got)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemberPromote(t *testing.T) {
|
||||
tests := []testScenario{
|
||||
{name: "decimal", isHex: false, cases: testCases},
|
||||
{name: "hex", isHex: true, cases: testCases},
|
||||
}
|
||||
|
||||
for _, testGroup := range tests {
|
||||
t.Run(testGroup.name, func(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
p := &jsonPrinter{writer: &buffer, isHex: testGroup.isHex}
|
||||
|
||||
for _, tt := range testGroup.cases {
|
||||
t.Run(fmt.Sprintf("number=%d", tt.number), func(t *testing.T) {
|
||||
buffer.Reset()
|
||||
decoder := json.NewDecoder(&buffer)
|
||||
decoder.UseNumber()
|
||||
|
||||
response := clientv3.MemberPromoteResponse{
|
||||
Header: &pb.ResponseHeader{
|
||||
ClusterId: tt.number,
|
||||
MemberId: tt.number,
|
||||
Revision: int64(tt.number),
|
||||
RaftTerm: tt.number,
|
||||
},
|
||||
Members: []*pb.Member{{ID: tt.number}},
|
||||
}
|
||||
p.MemberPromote(0, response)
|
||||
|
||||
var got map[string]any
|
||||
err := decoder.Decode(&got)
|
||||
require.NoErrorf(t, err, "failed to decode JSON")
|
||||
|
||||
assertHeader(t, &testGroup, &tt, got)
|
||||
assertMembers(t, &testGroup, &tt, got)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemberList(t *testing.T) {
|
||||
tests := []testScenario{
|
||||
{name: "decimal", isHex: false, cases: testCases},
|
||||
{name: "hex", isHex: true, cases: testCases},
|
||||
}
|
||||
|
||||
for _, testGroup := range tests {
|
||||
t.Run(testGroup.name, func(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
p := &jsonPrinter{writer: &buffer, isHex: testGroup.isHex}
|
||||
|
||||
for _, tt := range testGroup.cases {
|
||||
t.Run(fmt.Sprintf("number=%d", tt.number), func(t *testing.T) {
|
||||
buffer.Reset()
|
||||
decoder := json.NewDecoder(&buffer)
|
||||
decoder.UseNumber()
|
||||
|
||||
response := clientv3.MemberListResponse{
|
||||
Header: &pb.ResponseHeader{
|
||||
ClusterId: tt.number,
|
||||
MemberId: tt.number,
|
||||
Revision: int64(tt.number),
|
||||
RaftTerm: tt.number,
|
||||
},
|
||||
Members: []*pb.Member{{ID: tt.number}},
|
||||
}
|
||||
p.MemberList(response)
|
||||
|
||||
var got map[string]any
|
||||
err := decoder.Decode(&got)
|
||||
require.NoErrorf(t, err, "failed to decode JSON")
|
||||
|
||||
assertHeader(t, &testGroup, &tt, got)
|
||||
assertMembers(t, &testGroup, &tt, got)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
|
||||
v3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
@ -26,44 +27,44 @@ type tablePrinter struct{ printer }
|
|||
|
||||
func (tp *tablePrinter) MemberList(r v3.MemberListResponse) {
|
||||
hdr, rows := makeMemberListTable(r)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader(hdr)
|
||||
cfgBuilder := tablewriter.NewConfigBuilder().WithRowAlignment(tw.AlignRight)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithConfig(cfgBuilder.Build()))
|
||||
table.Header(hdr)
|
||||
for _, row := range rows {
|
||||
table.Append(row)
|
||||
}
|
||||
table.SetAlignment(tablewriter.ALIGN_RIGHT)
|
||||
table.Render()
|
||||
}
|
||||
|
||||
func (tp *tablePrinter) EndpointHealth(r []epHealth) {
|
||||
hdr, rows := makeEndpointHealthTable(r)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader(hdr)
|
||||
cfgBuilder := tablewriter.NewConfigBuilder().WithRowAlignment(tw.AlignRight)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithConfig(cfgBuilder.Build()))
|
||||
table.Header(hdr)
|
||||
for _, row := range rows {
|
||||
table.Append(row)
|
||||
}
|
||||
table.SetAlignment(tablewriter.ALIGN_RIGHT)
|
||||
table.Render()
|
||||
}
|
||||
|
||||
func (tp *tablePrinter) EndpointStatus(r []epStatus) {
|
||||
hdr, rows := makeEndpointStatusTable(r)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader(hdr)
|
||||
cfgBuilder := tablewriter.NewConfigBuilder().WithRowAlignment(tw.AlignRight)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithConfig(cfgBuilder.Build()))
|
||||
table.Header(hdr)
|
||||
for _, row := range rows {
|
||||
table.Append(row)
|
||||
}
|
||||
table.SetAlignment(tablewriter.ALIGN_RIGHT)
|
||||
table.Render()
|
||||
}
|
||||
|
||||
func (tp *tablePrinter) EndpointHashKV(r []epHashKV) {
|
||||
hdr, rows := makeEndpointHashKVTable(r)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader(hdr)
|
||||
cfgBuilder := tablewriter.NewConfigBuilder().WithRowAlignment(tw.AlignRight)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithConfig(cfgBuilder.Build()))
|
||||
table.Header(hdr)
|
||||
for _, row := range rows {
|
||||
table.Append(row)
|
||||
}
|
||||
table.SetAlignment(tablewriter.ALIGN_RIGHT)
|
||||
table.Render()
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"go.etcd.io/etcd/api/v3/version"
|
||||
"go.etcd.io/etcd/etcdctl/v3/ctlv3/command"
|
||||
"go.etcd.io/etcd/etcdctl/v3/util"
|
||||
"go.etcd.io/etcd/pkg/v3/cobrautl"
|
||||
)
|
||||
|
||||
|
@ -69,6 +70,7 @@ func init() {
|
|||
rootCmd.PersistentFlags().StringVar(&globalFlags.TLS.CertFile, "cert", "", "identify secure client using this TLS certificate file")
|
||||
rootCmd.PersistentFlags().StringVar(&globalFlags.TLS.KeyFile, "key", "", "identify secure client using this TLS key file")
|
||||
rootCmd.PersistentFlags().StringVar(&globalFlags.TLS.TrustedCAFile, "cacert", "", "verify certificates of TLS-enabled secure servers using this CA bundle")
|
||||
rootCmd.PersistentFlags().StringVar(&globalFlags.Token, "auth-jwt-token", "", "JWT token used for authentication (if this option is used, --user and --password should not be set)")
|
||||
rootCmd.PersistentFlags().StringVar(&globalFlags.User, "user", "", "username[:password] for authentication (prompt if password is not supplied)")
|
||||
rootCmd.PersistentFlags().StringVar(&globalFlags.Password, "password", "", "password for authentication (if this option is used, --user option shouldn't include password)")
|
||||
rootCmd.PersistentFlags().StringVarP(&globalFlags.TLS.ServerName, "discovery-srv", "d", "", "domain name to query for SRV records describing cluster endpoints")
|
||||
|
@ -102,7 +104,7 @@ func init() {
|
|||
}
|
||||
|
||||
func usageFunc(c *cobra.Command) error {
|
||||
return cobrautl.UsageFunc(c, version.Version, version.APIVersion)
|
||||
return util.UsageFunc(c, version.Version, version.APIVersion)
|
||||
}
|
||||
|
||||
func Start() error {
|
||||
|
|
|
@ -1,48 +1,50 @@
|
|||
module go.etcd.io/etcd/etcdctl/v3
|
||||
|
||||
go 1.23.0
|
||||
go 1.24
|
||||
|
||||
toolchain go1.23.11
|
||||
toolchain go1.24.5
|
||||
|
||||
require (
|
||||
github.com/bgentry/speakeasy v0.2.0
|
||||
github.com/cheggaaa/pb/v3 v3.1.6
|
||||
github.com/cheggaaa/pb/v3 v3.1.7
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/pflag v1.0.6
|
||||
github.com/olekukonko/tablewriter v1.0.9
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/pflag v1.0.7
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.etcd.io/etcd/api/v3 v3.6.4
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.4
|
||||
go.etcd.io/etcd/client/v3 v3.6.4
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.4
|
||||
go.etcd.io/etcd/api/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/client/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.0-alpha.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/time v0.9.0
|
||||
google.golang.org/grpc v1.71.1
|
||||
golang.org/x/time v0.12.0
|
||||
google.golang.org/grpc v1.74.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
|
|
113
etcdctl/go.sum
113
etcdctl/go.sum
|
@ -6,21 +6,21 @@ github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE5
|
|||
github.com/bgentry/speakeasy v0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheggaaa/pb/v3 v3.1.6 h1:h0x+vd7EiUohAJ29DJtJy+SNAc55t/elW3jCD086EXk=
|
||||
github.com/cheggaaa/pb/v3 v3.1.6/go.mod h1:urxmfVtaxT+9aWk92DbsvXFZtNSWQSO5TRAp+MJ3l1s=
|
||||
github.com/cheggaaa/pb/v3 v3.1.7 h1:2FsIW307kt7A/rz/ZI2lvPO+v3wKazzE4K/0LtTWsOI=
|
||||
github.com/cheggaaa/pb/v3 v3.1.7/go.mod h1:/Ji89zfVPeC/u5j8ukD0MBPHt2bzTYp74lQ7KlgFWTQ=
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
|
@ -32,18 +32,16 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
|||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
|
@ -52,50 +50,53 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP
|
|||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
||||
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
||||
github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8=
|
||||
github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
|
||||
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
|
@ -111,8 +112,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -120,14 +121,14 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
|
@ -136,14 +137,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
|
||||
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// copied from https://github.com/rkt/rkt/blob/master/rkt/help.go
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
commandUsageTemplate *template.Template
|
||||
templFuncs = template.FuncMap{
|
||||
"descToLines": func(s string) []string {
|
||||
// trim leading/trailing whitespace and split into slice of lines
|
||||
return strings.Split(strings.Trim(s, "\n\t "), "\n")
|
||||
},
|
||||
"cmdName": func(cmd *cobra.Command, startCmd *cobra.Command) string {
|
||||
parts := []string{cmd.Name()}
|
||||
for cmd.HasParent() && cmd.Parent().Name() != startCmd.Name() {
|
||||
cmd = cmd.Parent()
|
||||
parts = append([]string{cmd.Name()}, parts...)
|
||||
}
|
||||
return strings.Join(parts, " ")
|
||||
},
|
||||
"indent": func(s string) string {
|
||||
pad := strings.Repeat(" ", 2)
|
||||
return pad + strings.Replace(s, "\n", "\n"+pad, -1)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
commandUsage := `
|
||||
{{ $cmd := .Cmd }}\
|
||||
{{ $cmdname := cmdName .Cmd .Cmd.Root }}\
|
||||
NAME:
|
||||
{{if not .Cmd.HasParent}}\
|
||||
{{printf "%s - %s" .Cmd.Name .Cmd.Short | indent}}
|
||||
{{else}}\
|
||||
{{printf "%s - %s" $cmdname .Cmd.Short | indent}}
|
||||
{{end}}\
|
||||
|
||||
USAGE:
|
||||
{{printf "%s" .Cmd.UseLine | indent}}
|
||||
{{ if not .Cmd.HasParent }}\
|
||||
|
||||
VERSION:
|
||||
{{printf "%s" .Version | indent}}
|
||||
{{end}}\
|
||||
{{if .Cmd.HasSubCommands}}\
|
||||
|
||||
API VERSION:
|
||||
{{.APIVersion | indent}}
|
||||
{{end}}\
|
||||
{{if .Cmd.HasExample}}\
|
||||
|
||||
Examples:
|
||||
{{.Cmd.Example}}
|
||||
{{end}}\
|
||||
{{if .Cmd.HasSubCommands}}\
|
||||
|
||||
COMMANDS:
|
||||
{{range .SubCommands}}\
|
||||
{{ $cmdname := cmdName . $cmd }}\
|
||||
{{ if .Runnable }}\
|
||||
{{printf "%s\t%s" $cmdname .Short | indent}}
|
||||
{{end}}\
|
||||
{{end}}\
|
||||
{{end}}\
|
||||
{{ if .Cmd.Long }}\
|
||||
|
||||
DESCRIPTION:
|
||||
{{range $line := descToLines .Cmd.Long}}{{printf "%s" $line | indent}}
|
||||
{{end}}\
|
||||
{{end}}\
|
||||
{{if .Cmd.HasLocalFlags}}\
|
||||
|
||||
OPTIONS:
|
||||
{{.LocalFlags}}\
|
||||
{{end}}\
|
||||
{{if .Cmd.HasInheritedFlags}}\
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
{{.GlobalFlags}}\
|
||||
{{end}}
|
||||
`[1:]
|
||||
|
||||
commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(strings.ReplaceAll(commandUsage, "\\\n", "")))
|
||||
}
|
||||
|
||||
func etcdFlagUsages(flagSet *pflag.FlagSet) string {
|
||||
x := new(strings.Builder)
|
||||
|
||||
flagSet.VisitAll(func(flag *pflag.Flag) {
|
||||
if len(flag.Deprecated) > 0 {
|
||||
return
|
||||
}
|
||||
var format string
|
||||
if len(flag.Shorthand) > 0 {
|
||||
format = " -%s, --%s"
|
||||
} else {
|
||||
format = " %s --%s"
|
||||
}
|
||||
if len(flag.NoOptDefVal) > 0 {
|
||||
format = format + "["
|
||||
}
|
||||
if flag.Value.Type() == "string" {
|
||||
// put quotes on the value
|
||||
format = format + "=%q"
|
||||
} else {
|
||||
format = format + "=%s"
|
||||
}
|
||||
if len(flag.NoOptDefVal) > 0 {
|
||||
format = format + "]"
|
||||
}
|
||||
format = format + "\t%s\n"
|
||||
shorthand := flag.Shorthand
|
||||
fmt.Fprintf(x, format, shorthand, flag.Name, flag.DefValue, flag.Usage)
|
||||
})
|
||||
|
||||
return x.String()
|
||||
}
|
||||
|
||||
func getSubCommands(cmd *cobra.Command) []*cobra.Command {
|
||||
var subCommands []*cobra.Command
|
||||
for _, subCmd := range cmd.Commands() {
|
||||
subCommands = append(subCommands, subCmd)
|
||||
subCommands = append(subCommands, getSubCommands(subCmd)...)
|
||||
}
|
||||
return subCommands
|
||||
}
|
||||
|
||||
func UsageFunc(cmd *cobra.Command, version, APIVersion string) error {
|
||||
subCommands := getSubCommands(cmd)
|
||||
tabOut := getTabOutWithWriter(os.Stdout)
|
||||
commandUsageTemplate.Execute(tabOut, struct {
|
||||
Cmd *cobra.Command
|
||||
LocalFlags string
|
||||
GlobalFlags string
|
||||
SubCommands []*cobra.Command
|
||||
Version string
|
||||
APIVersion string
|
||||
}{
|
||||
cmd,
|
||||
etcdFlagUsages(cmd.LocalFlags()),
|
||||
etcdFlagUsages(cmd.InheritedFlags()),
|
||||
subCommands,
|
||||
version,
|
||||
APIVersion,
|
||||
})
|
||||
tabOut.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTabOutWithWriter(writer io.Writer) *tabwriter.Writer {
|
||||
aTabOut := new(tabwriter.Writer)
|
||||
aTabOut.Init(writer, 0, 8, 1, '\t', 0)
|
||||
return aTabOut
|
||||
}
|
|
@ -187,7 +187,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2020 The etcd Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
etcdutl
|
||||
========
|
||||
# etcdutl
|
||||
|
||||
`etcdutl` is a command line administration utility for [etcd][etcd].
|
||||
|
||||
|
@ -8,7 +7,7 @@ For operations over a network, please use `etcdctl`.
|
|||
|
||||
### DEFRAG [options]
|
||||
|
||||
DEFRAG directly defragments an etcd data directory while etcd is not running.
|
||||
DEFRAG directly defragments an etcd data directory while etcd is not running.
|
||||
When an etcd member reclaims storage space from deleted and compacted keys, the space is kept in a free list and the database file remains the same size. By defragmenting the database, the etcd member releases this free space back to the file system.
|
||||
|
||||
In order to defrag a live etcd instances over the network, please use `etcdctl defrag` instead.
|
||||
|
@ -36,7 +35,6 @@ To defragment a data directory directly, use the `--data-dir` flag:
|
|||
|
||||
DEFRAG returns a zero exit code only if it succeeded in defragmenting all given endpoints.
|
||||
|
||||
|
||||
### SNAPSHOT RESTORE [options] \<filename\>
|
||||
|
||||
SNAPSHOT RESTORE creates an etcd data directory for an etcd cluster member from a backend database snapshot and a new cluster configuration. Restoring the snapshot into each member for a new cluster configuration will initialize a new etcd cluster preloaded by the snapshot data.
|
||||
|
@ -174,6 +172,74 @@ Prints etcd version and API version.
|
|||
# API version: 3.1
|
||||
```
|
||||
|
||||
### LIST-BUCKET [options] \<data dir or db file path\>
|
||||
|
||||
`list-bucket` prints all bucket names.
|
||||
|
||||
#### Flags
|
||||
|
||||
- timeout -- Time to wait to obtain a file lock on db file, 0 to block indefinitely.
|
||||
|
||||
##### Examples for LIST-BUCKET
|
||||
|
||||
```bash
|
||||
|
||||
$ ./etcdutl list-bucket ~/tmp/etcd/default.etcd/member/snap/db
|
||||
alarm
|
||||
auth
|
||||
authRoles
|
||||
authUsers
|
||||
cluster
|
||||
key
|
||||
lease
|
||||
members
|
||||
members_removed
|
||||
meta
|
||||
```
|
||||
|
||||
### ITERATE-BUCKET [options] \<data dir or db file path\> \<bucket name\>
|
||||
|
||||
`iterate-bucket` lists key-value pairs in a given bucket in reverse order.
|
||||
|
||||
#### Flags for ITERATE-BUCKET
|
||||
|
||||
- timeout -- Time to wait to obtain a file lock on db file, 0 to block indefinitely.
|
||||
- limit -- Max number of key-value pairs to iterate (0 to iterate all).
|
||||
- decode -- true to decode Protocol Buffer encoded data.
|
||||
|
||||
##### Examples for ITERATE-BUCKET
|
||||
|
||||
```bash
|
||||
|
||||
# with `--decode` option
|
||||
$ ./etcdutl iterate-bucket ~/tmp/etcd/default.etcd/member/snap/db key --decode
|
||||
rev={Revision:{Main:4 Sub:0} tombstone:false}, value=[key "k1" | val "v3" | created 2 | mod 4 | ver 3]
|
||||
rev={Revision:{Main:3 Sub:0} tombstone:false}, value=[key "k1" | val "v2" | created 2 | mod 3 | ver 2]
|
||||
rev={Revision:{Main:2 Sub:0} tombstone:false}, value=[key "k1" | val "v1" | created 2 | mod 2 | ver 1]
|
||||
|
||||
# without `--decode` option
|
||||
$ ./etcdutl iterate-bucket ~/tmp/etcd/default.etcd/member/snap/db key
|
||||
key="\x00\x00\x00\x00\x00\x00\x00\x04_\x00\x00\x00\x00\x00\x00\x00\x00", value="\n\x02k1\x10\x02\x18\x04 \x03*\x02v3"
|
||||
key="\x00\x00\x00\x00\x00\x00\x00\x03_\x00\x00\x00\x00\x00\x00\x00\x00", value="\n\x02k1\x10\x02\x18\x03 \x02*\x02v2"
|
||||
key="\x00\x00\x00\x00\x00\x00\x00\x02_\x00\x00\x00\x00\x00\x00\x00\x00", value="\n\x02k1\x10\x02\x18\x02 \x01*\x02v1"
|
||||
```
|
||||
|
||||
### HASH [options] \<data dir or db file path\>
|
||||
|
||||
`hash` prints the hash of the db file.
|
||||
|
||||
#### Flags for HASH
|
||||
|
||||
- timeout -- Time to wait to obtain a file lock on db file, 0 to block indefinitely.
|
||||
|
||||
##### Examples for HASH
|
||||
|
||||
```bash
|
||||
|
||||
$ ./etcdutl hash ~/tmp/etcd/default.etcd/member/snap/db
|
||||
db path: /Users/wachao/tmp/etcd/default.etcd/member/snap/db
|
||||
Hash: 4031086527
|
||||
```
|
||||
|
||||
## Exit codes
|
||||
|
||||
|
|
|
@ -45,6 +45,9 @@ func init() {
|
|||
etcdutl.NewVersionCommand(),
|
||||
etcdutl.NewCompletionCommand(),
|
||||
etcdutl.NewMigrateCommand(),
|
||||
etcdutl.NewListBucketCommand(),
|
||||
etcdutl.NewIterateBucketCommand(),
|
||||
etcdutl.NewHashCommand(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
// Copyright 2025 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package etcdutl
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
|
||||
bolt "go.etcd.io/bbolt"
|
||||
"go.etcd.io/etcd/api/v3/authpb"
|
||||
"go.etcd.io/etcd/api/v3/mvccpb"
|
||||
"go.etcd.io/etcd/client/pkg/v3/fileutil"
|
||||
"go.etcd.io/etcd/server/v3/lease/leasepb"
|
||||
"go.etcd.io/etcd/server/v3/storage/backend"
|
||||
"go.etcd.io/etcd/server/v3/storage/datadir"
|
||||
"go.etcd.io/etcd/server/v3/storage/mvcc"
|
||||
"go.etcd.io/etcd/server/v3/storage/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
// TODO: add this configure to top level etcdutl command
|
||||
flockTimeout time.Duration
|
||||
iterateBucketLimit uint64
|
||||
iterateBucketDecode bool
|
||||
)
|
||||
|
||||
func NewListBucketCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "list-bucket [data dir or db file path]",
|
||||
Short: "bucket lists all buckets.",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: listBucketCommandFunc,
|
||||
}
|
||||
|
||||
// TODO: add this flag to top level etctutl command
|
||||
cmd.PersistentFlags().DurationVar(&flockTimeout, "timeout", 10*time.Second, "time to wait to obtain a file lock on db file, 0 to block indefinitely")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func NewIterateBucketCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "iterate-bucket [data dir or db file path] [bucket name]",
|
||||
Short: "iterate-bucket lists key-value pairs in reverse order.",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: iterateBucketCommandFunc,
|
||||
}
|
||||
|
||||
// TODO: add this flag to top level etctutl command
|
||||
cmd.PersistentFlags().DurationVar(&flockTimeout, "timeout", 10*time.Second, "time to wait to obtain a file lock on db file, 0 to block indefinitely")
|
||||
cmd.PersistentFlags().Uint64Var(&iterateBucketLimit, "limit", 0, "max number of key-value pairs to iterate (0 to iterate all)")
|
||||
cmd.PersistentFlags().BoolVar(&iterateBucketDecode, "decode", false, "true to decode Protocol Buffer encoded data")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func NewHashCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "hash [data dir or db file path]",
|
||||
Short: "hash computes the hash of db file.",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: getHashCommandFunc,
|
||||
}
|
||||
|
||||
// TODO: add this flag to top level etctutl command
|
||||
cmd.PersistentFlags().DurationVar(&flockTimeout, "timeout", 10*time.Second, "time to wait to obtain a file lock on db file, 0 to block indefinitely")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func listBucketCommandFunc(_ *cobra.Command, args []string) {
|
||||
lg := GetLogger()
|
||||
dp := args[0]
|
||||
if !strings.HasSuffix(dp, "db") {
|
||||
dp = filepath.Join(datadir.ToSnapDir(dp), "db")
|
||||
}
|
||||
|
||||
if !fileutil.Exist(dp) {
|
||||
lg.Fatal("db file not exist", zap.String("path", dp))
|
||||
}
|
||||
|
||||
bts, err := getBuckets(dp)
|
||||
if err != nil {
|
||||
lg.Fatal("Failed to get buckets", zap.Error(err))
|
||||
}
|
||||
for _, b := range bts {
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func getBuckets(dbPath string) (buckets []string, err error) {
|
||||
db, derr := bolt.Open(dbPath, 0o600, &bolt.Options{Timeout: flockTimeout})
|
||||
if derr != nil {
|
||||
return nil, fmt.Errorf("failed to open bolt DB %w", derr)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
err = db.View(func(tx *bolt.Tx) error {
|
||||
return tx.ForEach(func(b []byte, _ *bolt.Bucket) error {
|
||||
buckets = append(buckets, string(b))
|
||||
return nil
|
||||
})
|
||||
})
|
||||
return buckets, err
|
||||
}
|
||||
|
||||
func iterateBucketCommandFunc(_ *cobra.Command, args []string) {
|
||||
lg := GetLogger()
|
||||
dp := args[0]
|
||||
if !strings.HasSuffix(dp, "db") {
|
||||
dp = filepath.Join(datadir.ToSnapDir(dp), "db")
|
||||
}
|
||||
if !fileutil.Exist(dp) {
|
||||
lg.Fatal("db file not exist", zap.String("path", dp))
|
||||
}
|
||||
bucket := args[1]
|
||||
err := iterateBucket(dp, bucket, iterateBucketLimit, iterateBucketDecode)
|
||||
if err != nil {
|
||||
lg.Fatal("Failed to iterate bucket", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
type decoder func(k, v []byte)
|
||||
|
||||
// key is the bucket name, and value is the function to decode K/V in the bucket.
|
||||
var decoders = map[string]decoder{
|
||||
"key": keyDecoder,
|
||||
"lease": leaseDecoder,
|
||||
"auth": authDecoder,
|
||||
"authRoles": authRolesDecoder,
|
||||
"authUsers": authUsersDecoder,
|
||||
"meta": metaDecoder,
|
||||
}
|
||||
|
||||
func defaultDecoder(k, v []byte) {
|
||||
fmt.Printf("key=%q, value=%q\n", k, v)
|
||||
}
|
||||
|
||||
func keyDecoder(k, v []byte) {
|
||||
rev := mvcc.BytesToBucketKey(k)
|
||||
var kv mvccpb.KeyValue
|
||||
if err := kv.Unmarshal(v); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("rev=%+v, value=[key %q | val %q | created %d | mod %d | ver %d]\n", rev, string(kv.Key), string(kv.Value), kv.CreateRevision, kv.ModRevision, kv.Version)
|
||||
}
|
||||
|
||||
func bytesToLeaseID(bytes []byte) int64 {
|
||||
if len(bytes) != 8 {
|
||||
panic(fmt.Errorf("lease ID must be 8-byte"))
|
||||
}
|
||||
return int64(binary.BigEndian.Uint64(bytes))
|
||||
}
|
||||
|
||||
func leaseDecoder(k, v []byte) {
|
||||
leaseID := bytesToLeaseID(k)
|
||||
var lpb leasepb.Lease
|
||||
if err := lpb.Unmarshal(v); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("lease ID=%016x, TTL=%ds, remaining TTL=%ds\n", leaseID, lpb.TTL, lpb.RemainingTTL)
|
||||
}
|
||||
|
||||
func authDecoder(k, v []byte) {
|
||||
if string(k) == "authRevision" {
|
||||
rev := binary.BigEndian.Uint64(v)
|
||||
fmt.Printf("key=%q, value=%v\n", k, rev)
|
||||
} else {
|
||||
fmt.Printf("key=%q, value=%v\n", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func authRolesDecoder(_, v []byte) {
|
||||
role := &authpb.Role{}
|
||||
err := role.Unmarshal(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("role=%q, keyPermission=%v\n", string(role.Name), role.KeyPermission)
|
||||
}
|
||||
|
||||
func authUsersDecoder(_, v []byte) {
|
||||
user := &authpb.User{}
|
||||
err := user.Unmarshal(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("user=%q, roles=%q, option=%v\n", user.Name, user.Roles, user.Options)
|
||||
}
|
||||
|
||||
func metaDecoder(k, v []byte) {
|
||||
if string(k) == string(schema.MetaConsistentIndexKeyName) || string(k) == string(schema.MetaTermKeyName) {
|
||||
fmt.Printf("key=%q, value=%v\n", k, binary.BigEndian.Uint64(v))
|
||||
} else if string(k) == string(schema.ScheduledCompactKeyName) || string(k) == string(schema.FinishedCompactKeyName) {
|
||||
rev := mvcc.BytesToRev(v)
|
||||
fmt.Printf("key=%q, value=%v\n", k, rev)
|
||||
} else {
|
||||
defaultDecoder(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func iterateBucket(dbPath, bucket string, limit uint64, decode bool) (err error) {
|
||||
db, err := bolt.Open(dbPath, 0o600, &bolt.Options{Timeout: flockTimeout})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open bolt DB %w", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
err = db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte(bucket))
|
||||
if b == nil {
|
||||
return fmt.Errorf("got nil bucket for %s", bucket)
|
||||
}
|
||||
|
||||
c := b.Cursor()
|
||||
|
||||
// iterate in reverse order (use First() and Next() for ascending order)
|
||||
for k, v := c.Last(); k != nil; k, v = c.Prev() {
|
||||
// TODO: remove sensitive information
|
||||
// (https://github.com/etcd-io/etcd/issues/7620)
|
||||
if dec, ok := decoders[bucket]; decode && ok {
|
||||
dec(k, v)
|
||||
} else {
|
||||
defaultDecoder(k, v)
|
||||
}
|
||||
|
||||
limit--
|
||||
if limit == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func getHashCommandFunc(_ *cobra.Command, args []string) {
|
||||
lg := GetLogger()
|
||||
dp := args[0]
|
||||
if !strings.HasSuffix(dp, "db") {
|
||||
dp = filepath.Join(datadir.ToSnapDir(dp), "db")
|
||||
}
|
||||
if !fileutil.Exist(dp) {
|
||||
lg.Fatal("db file not exist", zap.String("path", dp))
|
||||
}
|
||||
|
||||
hash, err := getHash(dp)
|
||||
if err != nil {
|
||||
lg.Fatal("failed to get hash", zap.Error(err))
|
||||
}
|
||||
fmt.Printf("db path: %s\nHash: %d\n", dp, hash)
|
||||
}
|
||||
|
||||
func getHash(dbPath string) (hash uint32, err error) {
|
||||
b := backend.NewDefaultBackend(zap.NewNop(), dbPath)
|
||||
return b.Hash(schema.DefaultIgnores)
|
||||
}
|
|
@ -18,6 +18,7 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/olekukonko/tablewriter/tw"
|
||||
|
||||
"go.etcd.io/etcd/etcdutl/v3/snapshot"
|
||||
)
|
||||
|
@ -26,22 +27,22 @@ type tablePrinter struct{ printer }
|
|||
|
||||
func (tp *tablePrinter) DBStatus(r snapshot.Status) {
|
||||
hdr, rows := makeDBStatusTable(r)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader(hdr)
|
||||
cfgBuilder := tablewriter.NewConfigBuilder().WithRowAlignment(tw.AlignRight)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithConfig(cfgBuilder.Build()))
|
||||
table.Header(hdr)
|
||||
for _, row := range rows {
|
||||
table.Append(row)
|
||||
}
|
||||
table.SetAlignment(tablewriter.ALIGN_RIGHT)
|
||||
table.Render()
|
||||
}
|
||||
|
||||
func (tp *tablePrinter) DBHashKV(r HashKV) {
|
||||
hdr, rows := makeDBHashKVTable(r)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader(hdr)
|
||||
cfgBuilder := tablewriter.NewConfigBuilder().WithRowAlignment(tw.AlignRight)
|
||||
table := tablewriter.NewTable(os.Stdout, tablewriter.WithConfig(cfgBuilder.Build()))
|
||||
table.Header(hdr)
|
||||
for _, row := range rows {
|
||||
table.Append(row)
|
||||
}
|
||||
table.SetAlignment(tablewriter.ALIGN_RIGHT)
|
||||
table.Render()
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
module go.etcd.io/etcd/etcdutl/v3
|
||||
|
||||
go 1.23.0
|
||||
go 1.24
|
||||
|
||||
toolchain go1.23.11
|
||||
toolchain go1.24.5
|
||||
|
||||
replace (
|
||||
go.etcd.io/etcd/api/v3 => ../api
|
||||
|
@ -23,74 +23,78 @@ replace (
|
|||
require (
|
||||
github.com/coreos/go-semver v0.3.1
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/olekukonko/tablewriter v1.0.9
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.etcd.io/bbolt v1.4.2
|
||||
go.etcd.io/etcd/api/v3 v3.6.4
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.4
|
||||
go.etcd.io/etcd/client/v3 v3.6.4
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.4
|
||||
go.etcd.io/etcd/server/v3 v3.6.4
|
||||
go.etcd.io/etcd/api/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/client/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/server/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/raft/v3 v3.6.0
|
||||
go.uber.org/zap v1.27.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jonboulle/clockwork v0.5.0 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.65.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spf13/pflag v1.0.7 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
|
||||
go.opentelemetry.io/otel v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/time v0.9.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/grpc v1.71.1 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/crypto v0.40.0 // indirect
|
||||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
sigs.k8s.io/yaml v1.5.0 // indirect
|
||||
)
|
||||
|
|
163
etcdutl/go.sum
163
etcdutl/go.sum
|
@ -1,7 +1,7 @@
|
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
|
||||
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=
|
||||
|
@ -10,85 +10,95 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
|
|||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
||||
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
||||
github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8=
|
||||
github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
|
||||
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
|
@ -105,35 +115,39 @@ go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ=
|
|||
go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 h1:rbRJ8BBoVMsQShESYZ0FkvcITu8X8QNwJogcLUmDNNw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
|
||||
go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
|
||||
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
|
@ -141,25 +155,26 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
|
@ -168,14 +183,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
|
||||
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
@ -184,7 +199,5 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYs
|
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
|
||||
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
package snapshot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
@ -44,7 +43,7 @@ func TestSnapshotStatus(t *testing.T) {
|
|||
status, err := NewV3(zap.NewNop()).Status(dbpath)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, uint32(0x62132b4d), status.Hash)
|
||||
assert.Equal(t, uint32(0xe7a6e44b), status.Hash)
|
||||
assert.Equal(t, int64(11), status.Revision)
|
||||
}
|
||||
|
||||
|
@ -136,7 +135,7 @@ func TestSnapshotStatusTotalKey(t *testing.T) {
|
|||
Key: []byte(key),
|
||||
Value: val,
|
||||
}
|
||||
_, err := srv.Put(context.TODO(), &req)
|
||||
_, err := srv.Put(t.Context(), &req)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
@ -150,10 +149,10 @@ func TestSnapshotStatusTotalKey(t *testing.T) {
|
|||
key := []byte("key1")
|
||||
for i := 0; i < 3; i++ {
|
||||
if i < 2 {
|
||||
_, err := srv.Put(context.TODO(), &etcdserverpb.PutRequest{Key: key, Value: []byte(strconv.Itoa(i))})
|
||||
_, err := srv.Put(t.Context(), &etcdserverpb.PutRequest{Key: key, Value: []byte(strconv.Itoa(i))})
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
_, err := srv.DeleteRange(context.TODO(), &etcdserverpb.DeleteRangeRequest{Key: key})
|
||||
_, err := srv.DeleteRange(t.Context(), &etcdserverpb.DeleteRangeRequest{Key: key})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
@ -166,9 +165,9 @@ func TestSnapshotStatusTotalKey(t *testing.T) {
|
|||
// key1: create -> delete -> re-create -> delete
|
||||
key := []byte("key1")
|
||||
for i := 0; i < 2; i++ {
|
||||
_, err := srv.Put(context.TODO(), &etcdserverpb.PutRequest{Key: key, Value: make([]byte, 1)})
|
||||
_, err := srv.Put(t.Context(), &etcdserverpb.PutRequest{Key: key, Value: make([]byte, 1)})
|
||||
require.NoError(t, err)
|
||||
_, err = srv.DeleteRange(context.TODO(), &etcdserverpb.DeleteRangeRequest{Key: key})
|
||||
_, err = srv.DeleteRange(t.Context(), &etcdserverpb.DeleteRangeRequest{Key: key})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
},
|
||||
|
@ -181,10 +180,10 @@ func TestSnapshotStatusTotalKey(t *testing.T) {
|
|||
key := []byte("key1")
|
||||
for i := 0; i < 5; i++ {
|
||||
if i%2 == 0 {
|
||||
_, err := srv.Put(context.TODO(), &etcdserverpb.PutRequest{Key: key, Value: make([]byte, 1)})
|
||||
_, err := srv.Put(t.Context(), &etcdserverpb.PutRequest{Key: key, Value: make([]byte, 1)})
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
_, err := srv.DeleteRange(context.TODO(), &etcdserverpb.DeleteRangeRequest{Key: key})
|
||||
_, err := srv.DeleteRange(t.Context(), &etcdserverpb.DeleteRangeRequest{Key: key})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
@ -195,11 +194,11 @@ func TestSnapshotStatusTotalKey(t *testing.T) {
|
|||
name: "mixed deletions",
|
||||
prepare: func(srv *etcdserver.EtcdServer) {
|
||||
// Put("key1") -> Put("key2")-> Delete("key1")
|
||||
_, err := srv.Put(context.TODO(), &etcdserverpb.PutRequest{Key: []byte("key1"), Value: make([]byte, 1)})
|
||||
_, err := srv.Put(t.Context(), &etcdserverpb.PutRequest{Key: []byte("key1"), Value: make([]byte, 1)})
|
||||
require.NoError(t, err)
|
||||
_, err = srv.Put(context.TODO(), &etcdserverpb.PutRequest{Key: []byte("key2"), Value: make([]byte, 1)})
|
||||
_, err = srv.Put(t.Context(), &etcdserverpb.PutRequest{Key: []byte("key2"), Value: make([]byte, 1)})
|
||||
require.NoError(t, err)
|
||||
_, err = srv.DeleteRange(context.TODO(), &etcdserverpb.DeleteRangeRequest{Key: []byte("key1")})
|
||||
_, err = srv.DeleteRange(t.Context(), &etcdserverpb.DeleteRangeRequest{Key: []byte("key1")})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
expected: 1,
|
||||
|
@ -228,7 +227,7 @@ func insertKeys(t *testing.T, numKeys, valueSize int) func(*etcdserver.EtcdServe
|
|||
Key: []byte(strconv.Itoa(i)),
|
||||
Value: val,
|
||||
}
|
||||
_, err := srv.Put(context.TODO(), &req)
|
||||
_, err := srv.Put(t.Context(), &req)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
|
94
go.mod
94
go.mod
|
@ -1,11 +1,12 @@
|
|||
module go.etcd.io/etcd/v3
|
||||
|
||||
go 1.23.0
|
||||
go 1.24
|
||||
|
||||
toolchain go1.23.11
|
||||
toolchain go1.24.5
|
||||
|
||||
replace (
|
||||
go.etcd.io/etcd/api/v3 => ./api
|
||||
go.etcd.io/etcd/cache/v3 => ./cache
|
||||
go.etcd.io/etcd/client/pkg/v3 => ./client/pkg
|
||||
go.etcd.io/etcd/client/v3 => ./client/v3
|
||||
go.etcd.io/etcd/etcdctl/v3 => ./etcdctl
|
||||
|
@ -17,87 +18,88 @@ replace (
|
|||
|
||||
require (
|
||||
github.com/bgentry/speakeasy v0.2.0
|
||||
github.com/cheggaaa/pb/v3 v3.1.6
|
||||
github.com/cheggaaa/pb/v3 v3.1.7
|
||||
github.com/coreos/go-semver v0.3.1
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.etcd.io/bbolt v1.4.2
|
||||
go.etcd.io/etcd/api/v3 v3.6.4
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.4
|
||||
go.etcd.io/etcd/client/v3 v3.6.4
|
||||
go.etcd.io/etcd/etcdctl/v3 v3.6.4
|
||||
go.etcd.io/etcd/etcdutl/v3 v3.6.4
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.4
|
||||
go.etcd.io/etcd/server/v3 v3.6.4
|
||||
go.etcd.io/etcd/tests/v3 v3.6.4
|
||||
go.etcd.io/etcd/api/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/client/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/etcdctl/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/etcdutl/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/pkg/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/server/v3 v3.6.0-alpha.0
|
||||
go.etcd.io/etcd/tests/v3 v3.0.0-00010101000000-000000000000
|
||||
go.etcd.io/raft/v3 v3.6.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/time v0.9.0
|
||||
google.golang.org/grpc v1.71.1
|
||||
google.golang.org/protobuf v1.36.5
|
||||
golang.org/x/time v0.12.0
|
||||
google.golang.org/grpc v1.74.2
|
||||
google.golang.org/protobuf v1.36.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jonboulle/clockwork v0.5.0 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // indirect
|
||||
github.com/olekukonko/tablewriter v1.0.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.65.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spf13/pflag v1.0.7 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||
go.etcd.io/gofail v0.2.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
|
||||
go.opentelemetry.io/otel v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.36.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/crypto v0.40.0 // indirect
|
||||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
sigs.k8s.io/yaml v1.5.0 // indirect
|
||||
)
|
||||
|
|
164
go.sum
164
go.sum
|
@ -6,13 +6,13 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
|||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E=
|
||||
github.com/bgentry/speakeasy v0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
|
||||
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheggaaa/pb/v3 v3.1.6 h1:h0x+vd7EiUohAJ29DJtJy+SNAc55t/elW3jCD086EXk=
|
||||
github.com/cheggaaa/pb/v3 v3.1.6/go.mod h1:urxmfVtaxT+9aWk92DbsvXFZtNSWQSO5TRAp+MJ3l1s=
|
||||
github.com/cheggaaa/pb/v3 v3.1.7 h1:2FsIW307kt7A/rz/ZI2lvPO+v3wKazzE4K/0LtTWsOI=
|
||||
github.com/cheggaaa/pb/v3 v3.1.7/go.mod h1:/Ji89zfVPeC/u5j8ukD0MBPHt2bzTYp74lQ7KlgFWTQ=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=
|
||||
|
@ -21,10 +21,11 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
|
|||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
|
@ -36,19 +37,19 @@ github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/
|
|||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
@ -58,29 +59,28 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
|
|||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
|
@ -93,42 +93,46 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP
|
|||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
||||
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
||||
github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8=
|
||||
github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
|
||||
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
|
||||
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
|
@ -150,24 +154,24 @@ go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ=
|
|||
go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 h1:rbRJ8BBoVMsQShESYZ0FkvcITu8X8QNwJogcLUmDNNw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
|
||||
go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
|
@ -177,11 +181,15 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
|
|||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
|
||||
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
|
@ -197,16 +205,16 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -214,14 +222,14 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
|
||||
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
|
@ -239,19 +247,19 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
|
||||
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
@ -263,7 +271,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
|
||||
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue