mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-23 05:20:15 -05:00
Compare commits
580 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6b59c8124 | ||
|
|
4778cd52e7 | ||
|
|
1408c3debc | ||
|
|
1b2e55fe0c | ||
|
|
845710979f | ||
|
|
502d0844ca | ||
|
|
e9a49f7f68 | ||
|
|
0fce463517 | ||
|
|
5d5dd031b9 | ||
|
|
073eec198e | ||
|
|
b9ce1fe769 | ||
|
|
4f10e188aa | ||
|
|
4d0c8e9ff9 | ||
|
|
0c299ade5b | ||
|
|
1e6c97cefe | ||
|
|
0b2bfb8b4f | ||
|
|
f487376388 | ||
|
|
5bee8cedfc | ||
|
|
3c5fa0f2ab | ||
|
|
746738a2e4 | ||
|
|
b4cce7d192 | ||
|
|
b5d3819455 | ||
|
|
349bd20d57 | ||
|
|
6cf7ed88cb | ||
|
|
f346b98b86 | ||
|
|
865da8b83f | ||
|
|
db5c2a18c6 | ||
|
|
deee89d683 | ||
|
|
d788cee6d3 | ||
|
|
c24c187fbd | ||
|
|
9270c68d3c | ||
|
|
f3572f7d25 | ||
|
|
e75c64b781 | ||
|
|
6de0c7b036 | ||
|
|
c1de965871 | ||
|
|
476b82d527 | ||
|
|
c0415ff4dc | ||
|
|
4f596ba4aa | ||
|
|
814bc0e6d1 | ||
|
|
3fa95beb1f | ||
|
|
159306bae6 | ||
|
|
9a7b66e129 | ||
|
|
a3033e48cd | ||
|
|
16a3168588 | ||
|
|
f4420505bb | ||
|
|
1d998ec58d | ||
|
|
b065725310 | ||
|
|
93603b51d7 | ||
|
|
c54ce3fb14 | ||
|
|
64c2ee9b5e | ||
|
|
492f9b83f9 | ||
|
|
127540bb2b | ||
|
|
f6d869b9ff | ||
|
|
440e66ba42 | ||
|
|
5d1709f439 | ||
|
|
81cec702f3 | ||
|
|
463c9477c2 | ||
|
|
5b98feeb32 | ||
|
|
5ae69edded | ||
|
|
6d434e245e | ||
|
|
1b618e5de9 | ||
|
|
438e35a089 | ||
|
|
c230888d8a | ||
|
|
2541bb5302 | ||
|
|
f8e4d8c3a5 | ||
|
|
1f550c30c3 | ||
|
|
518bdfd84d | ||
|
|
f1d8d0f257 | ||
|
|
9d4ec051e7 | ||
|
|
3c386dfd1d | ||
|
|
90e8470fbb | ||
|
|
c219f1a261 | ||
|
|
035797c504 | ||
|
|
065127f7c6 | ||
|
|
59a52e16e3 | ||
|
|
bcd1359e34 | ||
|
|
680e5f630b | ||
|
|
2258a57787 | ||
|
|
5101e76d27 | ||
|
|
097d4e98af | ||
|
|
e1c573083e | ||
|
|
2b71e11fa3 | ||
|
|
4c4094e8a1 | ||
|
|
b74058dbbf | ||
|
|
aebefe706b | ||
|
|
421995bcc3 | ||
|
|
3f978d7870 | ||
|
|
6ab30db64c | ||
|
|
1af143dc7f | ||
|
|
44b479c56a | ||
|
|
337dbda364 | ||
|
|
3582a104bd | ||
|
|
e250ff63de | ||
|
|
3b5a56554a | ||
|
|
d23d8cdf55 | ||
|
|
940cd81083 | ||
|
|
fb466a4132 | ||
|
|
b11ac4b90a | ||
|
|
deee6102ec | ||
|
|
36cf2c323e | ||
|
|
9febfab9b6 | ||
|
|
5dc89de7ef | ||
|
|
0b334fc5e1 | ||
|
|
d6e269abb8 | ||
|
|
55d521d15d | ||
|
|
5df0ec0e25 | ||
|
|
d9878b38eb | ||
|
|
20980a6037 | ||
|
|
e71508b30c | ||
|
|
3720851da3 | ||
|
|
944abd8f57 | ||
|
|
e754b5a718 | ||
|
|
917fb38e1c | ||
|
|
6db8dd3956 | ||
|
|
63fad66258 | ||
|
|
738bef1e31 | ||
|
|
07894319c5 | ||
|
|
c7c5dca112 | ||
|
|
1efa53ce0e | ||
|
|
b77bd0b9e3 | ||
|
|
45c6181132 | ||
|
|
2ea415bc85 | ||
|
|
299a356076 | ||
|
|
9c517a8c91 | ||
|
|
8b0f58534b | ||
|
|
cb2de144bb | ||
|
|
b0768ae4b5 | ||
|
|
a7563532a1 | ||
|
|
80ec0c9236 | ||
|
|
c336b4ced7 | ||
|
|
0cce8f5df3 | ||
|
|
9680008790 | ||
|
|
17620483b2 | ||
|
|
16c9b7eaf0 | ||
|
|
058c299ccb | ||
|
|
668db6598d | ||
|
|
6c7cfac90c | ||
|
|
f2be11dcab | ||
|
|
837dd3a660 | ||
|
|
0c1fd1e341 | ||
|
|
15c50b3bf4 | ||
|
|
6af523c290 | ||
|
|
306e5a0dce | ||
|
|
d5f75ad8e0 | ||
|
|
eab949ba68 | ||
|
|
5904922fe3 | ||
|
|
146558eea9 | ||
|
|
7a1ee6e19b | ||
|
|
f308b61490 | ||
|
|
4522ac8e89 | ||
|
|
e0f155245f | ||
|
|
58ece4581b | ||
|
|
73e2efb458 | ||
|
|
67803b435a | ||
|
|
5c561dfdf1 | ||
|
|
5d14c966d5 | ||
|
|
4dcbb5d8e3 | ||
|
|
2573bf4a99 | ||
|
|
6f593d1bd8 | ||
|
|
182897c10a | ||
|
|
80b31a8574 | ||
|
|
0247c28d58 | ||
|
|
8bb4ad056d | ||
|
|
bd7e2f7b94 | ||
|
|
0478eb98fd | ||
|
|
efa757e4a4 | ||
|
|
cd9d05c31a | ||
|
|
d00fe96128 | ||
|
|
8df0f5ed75 | ||
|
|
8be4f679c3 | ||
|
|
16168b12fe | ||
|
|
0945ae1d42 | ||
|
|
e09014a485 | ||
|
|
6f35e9c69a | ||
|
|
89d07b0ac7 | ||
|
|
1e5dd90f3d | ||
|
|
8ef4d0a9c4 | ||
|
|
d59d498a62 | ||
|
|
2b55edc98e | ||
|
|
1b45acfa43 | ||
|
|
ef888ea90d | ||
|
|
fd327ad7c6 | ||
|
|
abd01d2922 | ||
|
|
c10f04bd95 | ||
|
|
38d6ad53cd | ||
|
|
5493a32e3b | ||
|
|
4f444274e1 | ||
|
|
d49123b36b | ||
|
|
b40c3f068c | ||
|
|
a93769ae9b | ||
|
|
8d3b2e3eeb | ||
|
|
e8b1834706 | ||
|
|
ef3c0da0cb | ||
|
|
80601fc0dc | ||
|
|
b9523caa70 | ||
|
|
a732547512 | ||
|
|
f0d807d719 | ||
|
|
601ebc0f0f | ||
|
|
87ef2d97fa | ||
|
|
e86e95db24 | ||
|
|
7b367c765c | ||
|
|
dccc3a0f21 | ||
|
|
22a7eaa005 | ||
|
|
2f7542c36e | ||
|
|
3eac173644 | ||
|
|
42fd54dd35 | ||
|
|
21207eba40 | ||
|
|
82c00913d3 | ||
|
|
11b20f4ca5 | ||
|
|
e33ff722f7 | ||
|
|
a935704368 | ||
|
|
4b6e44d15c | ||
|
|
82033a0c2f | ||
|
|
7759adb4a9 | ||
|
|
0fc4af406b | ||
|
|
92884a4cbd | ||
|
|
063217c3e6 | ||
|
|
e9bd5c4058 | ||
|
|
df529acdce | ||
|
|
9a5b5a7af6 | ||
|
|
3654897f60 | ||
|
|
84ff31c7b6 | ||
|
|
385cb02c9f | ||
|
|
123b641fcb | ||
|
|
98d876b120 | ||
|
|
9264617a28 | ||
|
|
beab7ce18c | ||
|
|
1b4b99d729 | ||
|
|
f825e8356e | ||
|
|
b7ab1b1f40 | ||
|
|
8814f3fa32 | ||
|
|
77843d8780 | ||
|
|
6e7538a834 | ||
|
|
f6a54930ea | ||
|
|
0bada429d3 | ||
|
|
b51c4af8d9 | ||
|
|
cb9815acb1 | ||
|
|
25952fc27c | ||
|
|
36b90c8619 | ||
|
|
f039bcf995 | ||
|
|
dd34f40618 | ||
|
|
f69610777d | ||
|
|
30c4fb2b51 | ||
|
|
9b3fde49fe | ||
|
|
6c46867a35 | ||
|
|
245a77a813 | ||
|
|
f5eacdc8b9 | ||
|
|
7f8023ca89 | ||
|
|
0569e20057 | ||
|
|
eadbb20ab2 | ||
|
|
f7caf637ce | ||
|
|
21975d75eb | ||
|
|
86d4932195 | ||
|
|
5c23253867 | ||
|
|
d9423e2c70 | ||
|
|
419edec7cc | ||
|
|
bd586b7a55 | ||
|
|
92562965cb | ||
|
|
e0d126da5c | ||
|
|
7f5a442750 | ||
|
|
b9124df8f5 | ||
|
|
8fe94446dc | ||
|
|
95f0c06ad1 | ||
|
|
b13e65d486 | ||
|
|
1c9ec51c5d | ||
|
|
8541da37f6 | ||
|
|
e41f6c34b6 | ||
|
|
8a993126a4 | ||
|
|
a5c8ec5f57 | ||
|
|
fb5d5b7cc5 | ||
|
|
ea415ab364 | ||
|
|
99ff445db7 | ||
|
|
b3e448bf5b | ||
|
|
587e3c76ff | ||
|
|
234c9bf1a7 | ||
|
|
36b5988068 | ||
|
|
2229fb36f5 | ||
|
|
4883496527 | ||
|
|
efd6331a61 | ||
|
|
adc3e19649 | ||
|
|
b2c0e8d4db | ||
|
|
186bbc85d4 | ||
|
|
f0cae1b4db | ||
|
|
4c600d80b3 | ||
|
|
8e30e535b0 | ||
|
|
36f9d383ad | ||
|
|
b258cbb996 | ||
|
|
84dce9a236 | ||
|
|
5fc01861c8 | ||
|
|
38eb7fb21b | ||
|
|
c99342318f | ||
|
|
23d84d81a6 | ||
|
|
6082e0c4df | ||
|
|
0b6de8e92b | ||
|
|
d9d7380969 | ||
|
|
44b8eaa20c | ||
|
|
670792f25a | ||
|
|
2b083d82df | ||
|
|
b227df74b6 | ||
|
|
c21637cb0f | ||
|
|
aad42fd3de | ||
|
|
24fc3ba005 | ||
|
|
1e369e40fc | ||
|
|
488943a2ec | ||
|
|
45bc0b60d1 | ||
|
|
9c651af32d | ||
|
|
15ece66e96 | ||
|
|
2231a7b280 | ||
|
|
8d092b49a9 | ||
|
|
38786ab291 | ||
|
|
0ac473af73 | ||
|
|
01600cdc4b | ||
|
|
c5c5399067 | ||
|
|
151ccb1609 | ||
|
|
941aa689d2 | ||
|
|
19a8ff314d | ||
|
|
97eb9a421e | ||
|
|
dd4b36a4bb | ||
|
|
50ef4f2ef1 | ||
|
|
01b768d33c | ||
|
|
f341ad4fcb | ||
|
|
2e7b4dbb9c | ||
|
|
5486216350 | ||
|
|
4132d79ea6 | ||
|
|
9fb773891f | ||
|
|
21d5703b4a | ||
|
|
9b62a97857 | ||
|
|
82c82f8ae2 | ||
|
|
5ed944dfc3 | ||
|
|
a7defc2d70 | ||
|
|
97070e2a05 | ||
|
|
196a4abfaa | ||
|
|
79a0fe0cec | ||
|
|
3ea736c283 | ||
|
|
eb1545c087 | ||
|
|
e991facc29 | ||
|
|
a95a7a1ada | ||
|
|
3446c1922b | ||
|
|
5f40284abc | ||
|
|
b19307f1be | ||
|
|
06c401d755 | ||
|
|
db3178cf69 | ||
|
|
646b0cee7c | ||
|
|
86dbae6412 | ||
|
|
87257623c6 | ||
|
|
8aac5f6318 | ||
|
|
f465a2bfa9 | ||
|
|
9dd03b6c90 | ||
|
|
3a2a38870c | ||
|
|
61707ab6d0 | ||
|
|
d0e51010bf | ||
|
|
032c218789 | ||
|
|
8564fa4536 | ||
|
|
eebccf7c78 | ||
|
|
6204c6b3cb | ||
|
|
35b3e51052 | ||
|
|
94a49aa404 | ||
|
|
f7681b36dd | ||
|
|
6e75e41023 | ||
|
|
2c8c334e88 | ||
|
|
f66600d7db | ||
|
|
9a597922f2 | ||
|
|
93601752a9 | ||
|
|
efb7e73195 | ||
|
|
5824d8df34 | ||
|
|
9904e5b932 | ||
|
|
879de39129 | ||
|
|
0fa3a2a7f8 | ||
|
|
a9b1bea4f8 | ||
|
|
75bcc548d7 | ||
|
|
0372869b8b | ||
|
|
a8545bfa39 | ||
|
|
07c160f67c | ||
|
|
67981d8f9a | ||
|
|
7be33b0607 | ||
|
|
6d054c527c | ||
|
|
d89054484d | ||
|
|
7c2eb19050 | ||
|
|
3f73faa3fe | ||
|
|
4794deb0ae | ||
|
|
dfa2577cf0 | ||
|
|
83bbcfb4ed | ||
|
|
3cb002977f | ||
|
|
56324caba1 | ||
|
|
1e970499af | ||
|
|
35900f8875 | ||
|
|
1e38489460 | ||
|
|
ee5ff08209 | ||
|
|
f139531358 | ||
|
|
63a0b10a0d | ||
|
|
5f43accb26 | ||
|
|
7e1ab4f34f | ||
|
|
5869f8c19c | ||
|
|
e398ce304e | ||
|
|
5c9f0ab07a | ||
|
|
3967e06815 | ||
|
|
1024830d13 | ||
|
|
378aba36b2 | ||
|
|
eebced529a | ||
|
|
e7a5788634 | ||
|
|
882dede6d3 | ||
|
|
b76d4fc661 | ||
|
|
131178e5d9 | ||
|
|
4488958347 | ||
|
|
680423707c | ||
|
|
f43909de77 | ||
|
|
5080aeaeb9 | ||
|
|
2b411eb69c | ||
|
|
bd2f697cab | ||
|
|
d322c0d390 | ||
|
|
c8d021729b | ||
|
|
07956c97f8 | ||
|
|
8d6f7a8942 | ||
|
|
57013e848b | ||
|
|
947a76803c | ||
|
|
e2964e284d | ||
|
|
e6114853ea | ||
|
|
f4526d4bc8 | ||
|
|
eb8a19abba | ||
|
|
e14a5c6b9a | ||
|
|
af4c0b8d0c | ||
|
|
8dc3877314 | ||
|
|
78168a3a21 | ||
|
|
4bcc4b9ab3 | ||
|
|
eb6d2dc0c4 | ||
|
|
81e6b3e198 | ||
|
|
0053f3b864 | ||
|
|
783503851e | ||
|
|
4dcecbf5c0 | ||
|
|
cffeb4a690 | ||
|
|
826640c2c5 | ||
|
|
8a4785e0e7 | ||
|
|
e7d8f3f446 | ||
|
|
b1c9159bd1 | ||
|
|
446ae35701 | ||
|
|
8f323c775a | ||
|
|
40d8aacea4 | ||
|
|
4c5d5fb218 | ||
|
|
ec30bcc030 | ||
|
|
61a591bcba | ||
|
|
fc9a62a2d8 | ||
|
|
b595461ae7 | ||
|
|
a3a1397e2d | ||
|
|
dbabedb90b | ||
|
|
dd4f2fe529 | ||
|
|
614d916978 | ||
|
|
ee16c0597c | ||
|
|
8e2fab3c9d | ||
|
|
c3a7892889 | ||
|
|
db7c0a88dd | ||
|
|
64119b3f8a | ||
|
|
6c171e11a2 | ||
|
|
7318fde6a0 | ||
|
|
6ce0cc6b1f | ||
|
|
3e81d1f1d8 | ||
|
|
d352d91210 | ||
|
|
434ba0a30a | ||
|
|
0f448f23a0 | ||
|
|
babb97f8a6 | ||
|
|
a6d637456d | ||
|
|
986545da52 | ||
|
|
0515f2f53c | ||
|
|
7307cda74d | ||
|
|
7778eab752 | ||
|
|
778580545b | ||
|
|
2bdd98f5cf | ||
|
|
043a5cf951 | ||
|
|
f7ce9202de | ||
|
|
287cc21981 | ||
|
|
d274f42aa8 | ||
|
|
de246ddc8f | ||
|
|
9e1c22b616 | ||
|
|
5ccba1f336 | ||
|
|
c18489687f | ||
|
|
56817b7de7 | ||
|
|
48d715008a | ||
|
|
10913ca00a | ||
|
|
444af91cce | ||
|
|
a3ef7f6d79 | ||
|
|
4b5fc32b81 | ||
|
|
60501659c5 | ||
|
|
aa44a5f6ed | ||
|
|
288dd8c220 | ||
|
|
8a70a65597 | ||
|
|
3badc66d4a | ||
|
|
85361fca67 | ||
|
|
a1862a65d9 | ||
|
|
023412356c | ||
|
|
7a469d6e44 | ||
|
|
f917ae6bca | ||
|
|
a487621b1d | ||
|
|
fe83b6b0af | ||
|
|
52d31ca8ef | ||
|
|
63b5723883 | ||
|
|
aa48ecefe0 | ||
|
|
12cebc705e | ||
|
|
2bcf66394f | ||
|
|
b7308d661e | ||
|
|
5f7f096d89 | ||
|
|
ac7ee2216e | ||
|
|
7330c7b0b4 | ||
|
|
4340cdc9e6 | ||
|
|
de4ca7c473 | ||
|
|
a181049508 | ||
|
|
718e86b06e | ||
|
|
487a2a0aa6 | ||
|
|
a496b6f46b | ||
|
|
c1fcf71d42 | ||
|
|
d1fa52b603 | ||
|
|
538e8141b2 | ||
|
|
62bcd91019 | ||
|
|
ba71d2978a | ||
|
|
4ae0951f5f | ||
|
|
e85d8effc1 | ||
|
|
90e4127227 | ||
|
|
28148d02bd | ||
|
|
205ffbbe83 | ||
|
|
9d173f0ea6 | ||
|
|
6161e40d43 | ||
|
|
95b19c7e33 | ||
|
|
97ee9b36a5 | ||
|
|
f9807f9f3a | ||
|
|
8007e8a269 | ||
|
|
63603679a5 | ||
|
|
16f9667fe8 | ||
|
|
d16524510a | ||
|
|
20b903b32d | ||
|
|
aa2ff8bdc6 | ||
|
|
93381c163b | ||
|
|
dd5eca9c6f | ||
|
|
54a38e37c6 | ||
|
|
4de25fdb5e | ||
|
|
1da40e6f5d | ||
|
|
0c43f69a5a | ||
|
|
8b758e8852 | ||
|
|
aa2da8372b | ||
|
|
5c7f58c8b5 | ||
|
|
cca5d1af04 | ||
|
|
60dfc95130 | ||
|
|
c685d280f5 | ||
|
|
acc38eb739 | ||
|
|
bb797e3727 | ||
|
|
b73353ef9b | ||
|
|
58a73c6306 | ||
|
|
68ad1e52c4 | ||
|
|
2189edaa17 | ||
|
|
28fdfded71 | ||
|
|
b0405d8eb6 | ||
|
|
cd3101ca31 | ||
|
|
7d193c78dd | ||
|
|
06b78b8261 | ||
|
|
c76ba6f8c3 | ||
|
|
580cbd45a3 | ||
|
|
0b2e0fb124 | ||
|
|
650cff8331 | ||
|
|
a63c0c5e9a | ||
|
|
6a84d20f5c | ||
|
|
30aad21936 | ||
|
|
1827e143cd | ||
|
|
12ec18be5c | ||
|
|
93d84478a4 | ||
|
|
54684101f7 | ||
|
|
f02a23098a | ||
|
|
a6876b7df9 | ||
|
|
a98dff619e | ||
|
|
29661cfa0b | ||
|
|
76713480e3 | ||
|
|
b783059846 | ||
|
|
a044d87f10 | ||
|
|
b337e2675d | ||
|
|
7fe511d6df | ||
|
|
c3d7560652 | ||
|
|
ae37684a79 | ||
|
|
26da21abe7 | ||
|
|
e112ac7721 | ||
|
|
5af51b089f | ||
|
|
8ffabad1e4 | ||
|
|
1404c69597 | ||
|
|
2b68f59b78 | ||
|
|
a004a9114f |
6
.backportrc.json
Normal file
6
.backportrc.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"repoOwner": "opencloud-eu",
|
||||||
|
"repoName": "opencloud",
|
||||||
|
"targetBranchChoices": ["main", "stable-2.0", "stable-4.0"],
|
||||||
|
"fork": false
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ exclude_paths:
|
|||||||
- 'tests/acceptance/expected-failures-*.md'
|
- 'tests/acceptance/expected-failures-*.md'
|
||||||
- 'tests/acceptance/bootstrap/**'
|
- 'tests/acceptance/bootstrap/**'
|
||||||
- 'tests/acceptance/TestHelpers/**'
|
- 'tests/acceptance/TestHelpers/**'
|
||||||
- 'tests/acceptance/run.sh'
|
- 'tests/acceptance/scripts/run.sh'
|
||||||
- 'vendor/**/*'
|
- 'vendor/**/*'
|
||||||
- 'tests/ocwrapper/vendor/**'
|
- 'tests/ocwrapper/vendor/**'
|
||||||
...
|
...
|
||||||
|
|||||||
132
.github/release_template.md
vendored
132
.github/release_template.md
vendored
@@ -3,79 +3,83 @@
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
* [ ] DEV/QA: Kickoff meeting [Kickoff meeting] (https://???)
|
* [ ] DEV/QA: bump web version
|
||||||
* [ ] DEV/QA: Define client versions and provide list of breaking changes for desktop/mobile team
|
* [ ] DEV/QA: bump reva version
|
||||||
* [ ] DEV/QA: Check new strings and align with clients
|
* [ ] DEV/QA: DEV: Create rc tag `vx.y.z-rc.x`
|
||||||
* [ ] DEV/DOCS: Create list of pending docs tasks
|
* [ ] DEV: update introductionVersion
|
||||||
* [ ] DEV: Create branch `release-x.x.x-rc.x` -> CODEFREEZE
|
* [ ] DEV: add new production version
|
||||||
* [ ] DEV: bump opencloud version in necessary files
|
|
||||||
* [ ] DEV: `changelog/CHANGELOG.tmpl`
|
|
||||||
* [ ] DEV: `pkg/version/version.go`
|
|
||||||
* [ ] DEV: `sonar-project.properties`
|
|
||||||
* [ ] DEV: prepare changelog folder in `changelog/x.x.x_????_??_??`
|
|
||||||
* [ ] DEV: Check successful CI run on release branch
|
|
||||||
* [ ] DEV: Create signed tag `vx.y.z-rc.x`
|
|
||||||
* [ ] DEV: Check successful CI run on `vx.y.z-rc.x` tag / BLOCKING for all further activity
|
|
||||||
* [ ] DEV: Merge back release branch
|
|
||||||
* [ ] DEV: bump released deployments to `vx.y.z-rc.x`
|
|
||||||
* [ ] DEV: https://cloud.opencloud.eu/
|
|
||||||
* [ ] DEV: needs snapshot and migration
|
|
||||||
|
|
||||||
### QA Phase
|
### QA Phase
|
||||||
|
|
||||||
* [ ] QA: Confirmatory testing (if needed)
|
* [ ] QA: Compatibility test with posix fs
|
||||||
* [ ] QA: [Compatibility test](???)
|
* [ ] QA: Compatibility test with decomposed fs
|
||||||
* [ ] QA: [Performance test](https://github.com/opencloud-eu/cdperf/tree/main/packages/k6-tests/src)
|
* [ ] DEV/QA: Performance test
|
||||||
* [ ] QA: Documentation test:
|
* [ ] STORAGE_USERS_DRIVER=posix
|
||||||
* [ ] QA: Single binary - setup
|
* [ ] 75vu's, 60m
|
||||||
* [ ] QA: Docker - setup
|
* [ ] 75vu's, 60m
|
||||||
* [ ] QA: Docker-compose - setup
|
* [ ] STORAGE_USERS_DRIVER=decomposed
|
||||||
* [ ] QA: helm/k8s - setup
|
* [ ] 75vu's, 60m
|
||||||
* [ ] QA: e2e with different deployment:
|
* [ ] 75vu's, 60m
|
||||||
* [ ] QA: [wopi](???.works)
|
* [ ] QA: documentation test
|
||||||
* [ ] QA: [traefik](???.works)
|
* [ ] QA: Review documentation
|
||||||
* [ ] QA: [ldap](???.works)
|
* [ ] QA: Verify all new features documented
|
||||||
|
* [ ] QA: Create upgrade documentation
|
||||||
|
* [ ] QA: Check installation guides
|
||||||
|
|
||||||
* [ ] QA: e2e with different storage:
|
* [ ] QA: e2e with different storage:
|
||||||
* [ ] QA: local
|
* [ ] QA: decomposed
|
||||||
* [ ] QA: nfs
|
* [ ] QA: decomposeds3
|
||||||
* [ ] QA: s3
|
* [ ] QA: posix
|
||||||
|
* [ ] QA: posix with enabled watch_fs
|
||||||
|
* [ ] QA: e2e with different deployments deployments:
|
||||||
|
* [ ] QA: e2e tests agains opencloud-charts
|
||||||
|
* [ ] QA: binary
|
||||||
|
* [ ] QA: multitanacy
|
||||||
|
* [ ] QA: docker using [docker-compose_test_plan](https://github.com/opencloud-eu/qa/blob/main/.github/ISSUE_TEMPLATE/docker-compose_test_plan_template.md)
|
||||||
* [ ] QA: Different clients:
|
* [ ] QA: Different clients:
|
||||||
* [ ] QA: desktop (define version) https://github.com/opencloud-eu/client/releases
|
* [ ] QA: desktop (define version) https://github.com/opencloud-eu/client/releases
|
||||||
* [ ] QA: against mac - smoke test
|
* [ ] QA: against mac - exploratory testing
|
||||||
* [ ] QA: against windows - smoke test
|
* [ ] QA: against windows - exploratory testing
|
||||||
* [ ] QA: against linux (use auto tests)
|
* [ ] QA: against linux (use auto tests)
|
||||||
* [ ] QA: android (define version) https://github.com/opencloud-eu/android/releases
|
* [ ] QA: android (define version) https://github.com/opencloud-eu/android/releases
|
||||||
* [ ] QA: ios (define version)
|
* [ ] QA: ios (define version)
|
||||||
* [ ] QA: [Smoke test](???) on Web Office (Collabora, Onlyoffice, Microsoft office)
|
* [ ] QA: check docs german translation
|
||||||
* [ ] QA: Smoke test Hello extension
|
* [ ] QA: german translations desktop at 100%
|
||||||
* [ ] QA: [Smoke test](???) ldap
|
* [ ] QA: exploratory testing
|
||||||
* [ ] QA: Collecting errors found
|
|
||||||
|
|
||||||
### After QA Phase
|
### Collected bugs
|
||||||
|
* [ ] Please place all bugs found here
|
||||||
|
|
||||||
* [ ] Brief company-wide heads up via mail @tbsbdr
|
### After QA Phase (IT related)
|
||||||
* [ ] Create list of changed ENV vars and send to release-coordination@opencloud.eu
|
|
||||||
* [ ] Variable Name
|
|
||||||
* [ ] Introduced in version
|
|
||||||
* [ ] Default Value
|
|
||||||
* [ ] Description
|
|
||||||
* [ ] dependencies with user other components
|
|
||||||
* [ ] DEV: Create branch `release-x.x.x`
|
|
||||||
* [ ] DEV: bump OpenCloud version in necessary files
|
|
||||||
* [ ] DEV: `pkg/version/version.go`
|
|
||||||
* [ ] DEV: `sonar-project.properties`
|
|
||||||
* [ ] DEV: released deployment versions
|
|
||||||
* [ ] DEV: prepare changelog folder in `changelog/x.x.x_???`
|
|
||||||
* [ ] Release Notes + Breaking Changes @tbsbdr
|
|
||||||
* [ ] Migration + Breaking Changes Admin Doc @???
|
|
||||||
* [ ] DEV: Create final signed tag
|
|
||||||
* [ ] DEV: Check successful CI run on `vx.y.z` tag / BLOCKING for all further activity
|
|
||||||
* [ ] Merge release notes
|
|
||||||
|
|
||||||
### Post-release communication
|
* [ ] QA:bump version in pkg/version.go
|
||||||
* [ ] DEV: Create a `docs-stable-x.y` branch based on the docs folder in the OpenCloud repo @micbar
|
* [ ] QA: Run CI
|
||||||
* [ ] DEV/QA: Ping documentation in RC about the new release tag (for opencloud/helm chart version bump in docs)
|
* [ ] DEV/QA: create final tag
|
||||||
* [ ] DEV/QA: Ping marketing to update all download links (download mirrors are updated at the full hour, wait with ping until download is actually available)
|
* [ ] QA: observe CI Run on tag
|
||||||
* [ ] DEV/QA: Ping @??? once the demo instances are running this release
|
* [ ] DEV/QA: Create a new `stable-*` branch
|
||||||
* [ ] DEV: Merge back release branch
|
* [ ] (opencloud)[https://github.com/opencloud-eu/opencloud/branches]
|
||||||
* [ ] DEV: Create stable-x.y branch in the OpenCloud repo from final tag
|
* [ ] (web)[https://github.com/opencloud-eu/web/branches]
|
||||||
|
* [ ] (reva)[https://github.com/opencloud-eu/reva/branches]
|
||||||
|
* [ ] (opencloud-compose)[https://github.com/opencloud-eu/opencloud-compose/branches]
|
||||||
|
* [ ] DEV/QA:: publish release notes to the docs
|
||||||
|
* [ ] DEV/QA:: update (demo.opencloud.eu)[https://demo.opencloud.eu/]
|
||||||
|
|
||||||
|
### After QA Phase ( Marketing / Product / Sales related )
|
||||||
|
|
||||||
|
* [ ] notify marketing that the release is ready @tbsbdr
|
||||||
|
* [ ] announce in the public channel (matrix channel)[https://matrix.to/#/#opencloud:matrix.org]
|
||||||
|
* [ ] press information @AnneGo137
|
||||||
|
* [ ] press information @AnneGo137
|
||||||
|
* [ ] Blogentry @AnneGo137
|
||||||
|
* [ ] Internal meeting (Groupe Pre-Webinar) @db-ot
|
||||||
|
* [ ] Partner briefing (Partner should be informed about features, new) @matthias
|
||||||
|
* [ ] Webinar DE & EN @AnneGo137
|
||||||
|
* [ ] Präsentation DE @tbsbdr / @db-ot
|
||||||
|
* [ ] Präsentation EN @tbsbdr / @db-ot
|
||||||
|
* [ ] Website ergänzen @AnneGo137
|
||||||
|
* [ ] Features @AnneGo137
|
||||||
|
* [ ] Service & Support - New Enterprise Features @tbsbdr
|
||||||
|
* [ ] OpenCloud_Benefits.pdf updates @AnneGo137
|
||||||
|
* [ ] Welcome Files: Features as media @tbsbdr
|
||||||
|
* [ ] Flyer update @AnneGo137
|
||||||
|
* [ ] Sales presentation @matthias
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -38,6 +38,7 @@ vendor-php
|
|||||||
# API acceptance tests - auto-generated files
|
# API acceptance tests - auto-generated files
|
||||||
.php-cs-fixer.cache
|
.php-cs-fixer.cache
|
||||||
suite-logs
|
suite-logs
|
||||||
|
tests/acceptance/filesForUpload/filesWithVirus/
|
||||||
|
|
||||||
# QA activity reports
|
# QA activity reports
|
||||||
tests/qa-activity-report/reports/
|
tests/qa-activity-report/reports/
|
||||||
|
|||||||
14
.make/go.mk
14
.make/go.mk
@@ -36,8 +36,18 @@ ifndef DATE
|
|||||||
DATE := $(shell date -u '+%Y%m%d')
|
DATE := $(shell date -u '+%Y%m%d')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LDFLAGS += -X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn -s -w -X "$(OC_REPO)/pkg/version.String=$(STRING)" -X "$(OC_REPO)/pkg/version.Tag=$(VERSION)" -X "$(OC_REPO)/pkg/version.Date=$(DATE)"
|
LDFLAGS += -X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn -s -w \
|
||||||
DEBUG_LDFLAGS += -X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn -X "$(OC_REPO)/pkg/version.String=$(STRING)" -X "$(OC_REPO)/pkg/version.Tag=$(VERSION)" -X "$(OC_REPO)/pkg/version.Date=$(DATE)"
|
-X "$(OC_REPO)/pkg/version.Edition=$(EDITION)" \
|
||||||
|
-X "$(OC_REPO)/pkg/version.String=$(STRING)" \
|
||||||
|
-X "$(OC_REPO)/pkg/version.Tag=$(VERSION)" \
|
||||||
|
-X "$(OC_REPO)/pkg/version.Date=$(DATE)"
|
||||||
|
|
||||||
|
DEBUG_LDFLAGS += -X google.golang.org/protobuf/reflect/protoregistry.conflictPolicy=warn \
|
||||||
|
-X "$(OC_REPO)/pkg/version.Edition=$(EDITION)" \
|
||||||
|
-X "$(OC_REPO)/pkg/version.String=$(STRING)" \
|
||||||
|
-X "$(OC_REPO)/pkg/version.Tag=$(VERSION)" \
|
||||||
|
-X "$(OC_REPO)/pkg/version.Date=$(DATE)"
|
||||||
|
|
||||||
DOCKER_LDFLAGS += -X "$(OC_REPO)/pkg/config/defaults.BaseDataPathType=path" -X "$(OC_REPO)/pkg/config/defaults.BaseDataPathValue=/var/lib/opencloud"
|
DOCKER_LDFLAGS += -X "$(OC_REPO)/pkg/config/defaults.BaseDataPathType=path" -X "$(OC_REPO)/pkg/config/defaults.BaseDataPathValue=/var/lib/opencloud"
|
||||||
DOCKER_LDFLAGS += -X "$(OC_REPO)/pkg/config/defaults.BaseConfigPathType=path" -X "$(OC_REPO)/pkg/config/defaults.BaseConfigPathValue=/etc/opencloud"
|
DOCKER_LDFLAGS += -X "$(OC_REPO)/pkg/config/defaults.BaseConfigPathType=path" -X "$(OC_REPO)/pkg/config/defaults.BaseConfigPathValue=/etc/opencloud"
|
||||||
|
|
||||||
|
|||||||
163
.vscode/launch.json
vendored
163
.vscode/launch.json
vendored
@@ -36,6 +36,68 @@
|
|||||||
// demo users
|
// demo users
|
||||||
"IDM_CREATE_DEMO_USERS": "true",
|
"IDM_CREATE_DEMO_USERS": "true",
|
||||||
// OC_RUN_SERVICES allows to start a subset of services even in the supervised mode
|
// OC_RUN_SERVICES allows to start a subset of services even in the supervised mode
|
||||||
|
//"OC_RUN_SERVICES": "settings,storage-system,graph,idp,idm,ocs,store,thumbnails,web,webdav,frontend,gateway,users,groups,auth-basic,storage-authmachine,storage-users,storage-shares,storage-publiclink,storage-system,app-provider,sharing,proxy",
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keep secrets and passwords in one block to allow easy uncommenting
|
||||||
|
*/
|
||||||
|
// user id of "admin", for user creation and admin role assignement
|
||||||
|
"OC_ADMIN_USER_ID": "some-admin-user-id-0000-000000000000", // FIXME currently must have the length of a UUID, see reva/pkg/storage/utils/decomposedfs/spaces.go:228
|
||||||
|
// admin user default password
|
||||||
|
"IDM_ADMIN_PASSWORD": "admin",
|
||||||
|
// system user
|
||||||
|
"OC_SYSTEM_USER_ID": "some-system-user-id-000-000000000000", // FIXME currently must have the length of a UUID, see reva/pkg/storage/utils/decomposedfs/spaces.go:228
|
||||||
|
"OC_SYSTEM_USER_API_KEY": "some-system-user-machine-auth-api-key",
|
||||||
|
// set some hardcoded secrets
|
||||||
|
"OC_JWT_SECRET": "some-opencloud-jwt-secret",
|
||||||
|
"OC_MACHINE_AUTH_API_KEY": "some-opencloud-machine-auth-api-key",
|
||||||
|
"OC_TRANSFER_SECRET": "some-opencloud-transfer-secret",
|
||||||
|
// collaboration
|
||||||
|
"COLLABORATION_WOPI_SECRET": "some-wopi-secret",
|
||||||
|
// idm ldap
|
||||||
|
"IDM_SVC_PASSWORD": "some-ldap-idm-password",
|
||||||
|
"GRAPH_LDAP_BIND_PASSWORD": "some-ldap-idm-password",
|
||||||
|
// reva ldap
|
||||||
|
"IDM_REVASVC_PASSWORD": "some-ldap-reva-password",
|
||||||
|
"GROUPS_LDAP_BIND_PASSWORD": "some-ldap-reva-password",
|
||||||
|
"USERS_LDAP_BIND_PASSWORD": "some-ldap-reva-password",
|
||||||
|
"AUTH_BASIC_LDAP_BIND_PASSWORD": "some-ldap-reva-password",
|
||||||
|
// idp ldap
|
||||||
|
"IDM_IDPSVC_PASSWORD": "some-ldap-idp-password",
|
||||||
|
"IDP_LDAP_BIND_PASSWORD": "some-ldap-idp-password",
|
||||||
|
// storage users mount ID
|
||||||
|
"GATEWAY_STORAGE_USERS_MOUNT_ID": "storage-users-1",
|
||||||
|
"STORAGE_USERS_MOUNT_ID": "storage-users-1",
|
||||||
|
// graph application ID
|
||||||
|
"GRAPH_APPLICATION_ID": "application-1",
|
||||||
|
|
||||||
|
// service accounts
|
||||||
|
"OC_SERVICE_ACCOUNT_ID": "service-account-id",
|
||||||
|
"OC_SERVICE_ACCOUNT_SECRET": "service-account-secret"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenCloud server with Groupware",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"buildFlags": [
|
||||||
|
// "-tags", "enable_vips"
|
||||||
|
],
|
||||||
|
"program": "${workspaceFolder}/opencloud/cmd/opencloud",
|
||||||
|
"args": ["server"],
|
||||||
|
"env": {
|
||||||
|
// log settings for human developers
|
||||||
|
"OC_LOG_LEVEL": "info",
|
||||||
|
"OC_LOG_PRETTY": "true",
|
||||||
|
"OC_LOG_COLOR": "true",
|
||||||
|
// set insecure options because we don't have valid certificates in dev environments
|
||||||
|
"OC_INSECURE": "true",
|
||||||
|
// enable basic auth for dev setup so that we can use curl for testing
|
||||||
|
"PROXY_ENABLE_BASIC_AUTH": "true",
|
||||||
|
// demo users
|
||||||
|
"IDM_CREATE_DEMO_USERS": "true",
|
||||||
|
// OC_RUN_SERVICES allows to start a subset of services even in the supervised mode
|
||||||
//"OC_RUN_SERVICES": "settings,storage-system,graph,idp,idm,ocs,store,thumbnails,web,webdav,frontend,gateway,users,groups,auth-basic,storage-authmachine,storage-users,storage-shares,storage-publiclink,storage-system,app-provider,sharing,proxy,ocdav",
|
//"OC_RUN_SERVICES": "settings,storage-system,graph,idp,idm,ocs,store,thumbnails,web,webdav,frontend,gateway,users,groups,auth-basic,storage-authmachine,storage-users,storage-shares,storage-publiclink,storage-system,app-provider,sharing,proxy,ocdav",
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -73,7 +135,77 @@
|
|||||||
|
|
||||||
// service accounts
|
// service accounts
|
||||||
"OC_SERVICE_ACCOUNT_ID": "service-account-id",
|
"OC_SERVICE_ACCOUNT_ID": "service-account-id",
|
||||||
"OC_SERVICE_ACCOUNT_SECRET": "service-account-secret"
|
"OC_SERVICE_ACCOUNT_SECRET": "service-account-secret",
|
||||||
|
|
||||||
|
"OC_ADD_RUN_SERVICES": "groupware",
|
||||||
|
"GROUPWARE_LOG_LEVEL": "trace"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OpenCloud server with external services",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"buildFlags": [
|
||||||
|
// "-tags", "enable_vips"
|
||||||
|
],
|
||||||
|
"program": "${workspaceFolder}/opencloud/cmd/opencloud",
|
||||||
|
"args": ["server"],
|
||||||
|
"env": {
|
||||||
|
"OC_URL": "https://localhost:9200/",
|
||||||
|
"PROXY_DEBUG_ADDR": "0.0.0.0:9205",
|
||||||
|
"OC_BASE_DATA_PATH": "${env:HOME}/.opencloud-with-external",
|
||||||
|
"OC_CONFIG_DIR": "${env:HOME}/.opencloud-with-external/config",
|
||||||
|
"GROUPWARE_LOG_LEVEL": "trace",
|
||||||
|
"OC_LOG_LEVEL": "info",
|
||||||
|
"OC_LOG_PRETTY": "true",
|
||||||
|
"OC_LOG_COLOR": "true",
|
||||||
|
"OC_INSECURE": "true",
|
||||||
|
"PROXY_ENABLE_BASIC_AUTH": "false",
|
||||||
|
"IDM_CREATE_DEMO_USERS": "false",
|
||||||
|
"OC_LDAP_URI": "ldaps://localhost:636",
|
||||||
|
"OC_LDAP_INSECURE": "true",
|
||||||
|
"OC_LDAP_BIND_DN": "cn=admin,dc=opencloud,dc=eu",
|
||||||
|
"OC_LDAP_BIND_PASSWORD": "admin",
|
||||||
|
"OC_LDAP_GROUP_BASE_DN": "ou=groups,dc=opencloud,dc=eu",
|
||||||
|
"OC_LDAP_GROUP_SCHEMA_ID": "entryUUID",
|
||||||
|
"OC_LDAP_USER_BASE_DN": "ou=users,dc=opencloud,dc=eu",
|
||||||
|
"OC_LDAP_USER_FILTER": "(objectclass=inetOrgPerson)",
|
||||||
|
"OC_LDAP_USER_SCHEMA_ID": "entryUUID",
|
||||||
|
"OC_LDAP_DISABLE_USER_MECHANISM": "none",
|
||||||
|
"OC_LDAP_SERVER_WRITE_ENABLED": "false",
|
||||||
|
"OC_EXCLUDE_RUN_SERVICES": "idm",
|
||||||
|
"OC_ADD_RUN_SERVICES": "notifications,groupware",
|
||||||
|
"NATS_NATS_HOST": "0.0.0.0",
|
||||||
|
"NATS_NATS_PORT": "9233",
|
||||||
|
"FRONTEND_ARCHIVER_MAX_SIZE": "10000000000",
|
||||||
|
"MICRO_REGISTRY_ADDRESS": "127.0.0.1:9233",
|
||||||
|
"NOTIFICATIONS_SMTP_HOST": "localhost",
|
||||||
|
"NOTIFICATIONS_SMTP_PORT": "2500",
|
||||||
|
"NOTIFICATIONS_SMTP_SENDER": "OpenCloud notifications <notifications@cloud.opencloud.test>",
|
||||||
|
"NOTIFICATIONS_SMTP_USERNAME": "notifications@cloud.opencloud.test",
|
||||||
|
"NOTIFICATIONS_SMTP_INSECURE": "true",
|
||||||
|
"NOTIFICATIONS_SMTP_PASSWORD": "",
|
||||||
|
"NOTIFICATIONS_SMTP_AUTHENTICATION": "",
|
||||||
|
"NOTIFICATIONS_SMTP_ENCRYPTION": "none",
|
||||||
|
"PROXY_AUTOPROVISION_ACCOUNTS": "false",
|
||||||
|
"PROXY_ROLE_ASSIGNMENT_DRIVER": "oidc",
|
||||||
|
"OC_OIDC_ISSUER": "https://keycloak.opencloud.test/realms/openCloud",
|
||||||
|
"PROXY_OIDC_REWRITE_WELLKNOWN": "true",
|
||||||
|
"WEB_OIDC_CLIENT_ID": "web",
|
||||||
|
"PROXY_USER_OIDC_CLAIM": "uuid",
|
||||||
|
"PROXY_USER_CS3_CLAIM": "userid",
|
||||||
|
"WEB_OPTION_ACCOUNT_EDIT_LINK_HREF": "https://keycloak.opencloud.test/realms/openCloud/account",
|
||||||
|
"OC_ADMIN_USER_ID": "",
|
||||||
|
"SETTINGS_SETUP_DEFAULT_ASSIGNMENTS": "false",
|
||||||
|
"GRAPH_ASSIGN_DEFAULT_USER_ROLE": "false",
|
||||||
|
"GRAPH_USERNAME_MATCH": "none",
|
||||||
|
"KEYCLOAK_DOMAIN": "keycloak.opencloud.test",
|
||||||
|
"IDM_ADMIN_PASSWORD": "admin",
|
||||||
|
"GRAPH_LDAP_SERVER_UUID": "true",
|
||||||
|
"GRAPH_LDAP_GROUP_CREATE_BASE_DN": "ou=custom,ou=groups,dc=opencloud,dc=eu",
|
||||||
|
"GRAPH_LDAP_REFINT_ENABLED": "true",
|
||||||
|
"GATEWAY_GRPC_ADDR": "0.0.0.0:9142",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -129,8 +261,6 @@
|
|||||||
"IDP_HTTP_ADDR": "127.0.0.1:10130",
|
"IDP_HTTP_ADDR": "127.0.0.1:10130",
|
||||||
"NATS_DEBUG_ADDR": "127.0.0.1:10234",
|
"NATS_DEBUG_ADDR": "127.0.0.1:10234",
|
||||||
"NATS_NATS_PORT": "10233",
|
"NATS_NATS_PORT": "10233",
|
||||||
"OCDAV_HTTP_ADDR": "127.0.0.1:10350",
|
|
||||||
"OCDAV_DEBUG_ADDR": "127.0.0.1:10163",
|
|
||||||
"OCM_DEBUG_ADDR": "127.0.0.1:10281",
|
"OCM_DEBUG_ADDR": "127.0.0.1:10281",
|
||||||
"OCM_HTTP_ADDR": "127.0.0.1:10280",
|
"OCM_HTTP_ADDR": "127.0.0.1:10280",
|
||||||
"OCM_GRPC_ADDR": "127.0.0.1:10282",
|
"OCM_GRPC_ADDR": "127.0.0.1:10282",
|
||||||
@@ -193,20 +323,21 @@
|
|||||||
"OC_LOG_COLOR": "true",
|
"OC_LOG_COLOR": "true",
|
||||||
"PROXY_ENABLE_BASIC_AUTH": "true",
|
"PROXY_ENABLE_BASIC_AUTH": "true",
|
||||||
"IDM_CREATE_DEMO_USERS": "true",
|
"IDM_CREATE_DEMO_USERS": "true",
|
||||||
"OC_ADMIN_USER_ID": "some-admin-user-id-0000-000000000000",
|
"OC_ADMIN_USER_ID": "fed-admin-user-id-0000-000000000000",
|
||||||
"IDM_ADMIN_PASSWORD": "admin",
|
"IDM_ADMIN_PASSWORD": "admin",
|
||||||
"OC_SYSTEM_USER_ID": "some-system-user-id-000-000000000000",
|
"OC_SYSTEM_USER_ID": "fed-system-user-id-000-000000000000",
|
||||||
"OC_SYSTEM_USER_API_KEY": "some-system-user-machine-auth-api-key",
|
"OC_SYSTEM_USER_API_KEY": "fed-system-user-machine-auth-api-key",
|
||||||
"OC_JWT_SECRET": "some-opencloud-jwt-secret",
|
"OC_JWT_SECRET": "fed-opencloud-jwt-secret",
|
||||||
"OC_MACHINE_AUTH_API_KEY": "some-opencloud-machine-auth-api-key",
|
"OC_MACHINE_AUTH_API_KEY": "fed-opencloud-machine-auth-api-key",
|
||||||
"OC_TRANSFER_SECRET": "some-opencloud-transfer-secret",
|
"OC_TRANSFER_SECRET": "fed-opencloud-transfer-secret",
|
||||||
"IDM_SVC_PASSWORD": "some-ldap-idm-password",
|
"COLLABORATION_WOPI_SECRET": "fed-wopi-secret",
|
||||||
"GRAPH_LDAP_BIND_PASSWORD": "some-ldap-idm-password",
|
"IDM_SVC_PASSWORD": "fed-ldap-idm-password",
|
||||||
"IDM_REVASVC_PASSWORD": "some-ldap-reva-password",
|
"GRAPH_LDAP_BIND_PASSWORD": "fed-ldap-idm-password",
|
||||||
"GROUPS_LDAP_BIND_PASSWORD": "some-ldap-reva-password",
|
"IDM_REVASVC_PASSWORD": "fed-ldap-reva-password",
|
||||||
"USERS_LDAP_BIND_PASSWORD": "some-ldap-reva-password",
|
"GROUPS_LDAP_BIND_PASSWORD": "fed-ldap-reva-password",
|
||||||
"AUTH_BASIC_LDAP_BIND_PASSWORD": "some-ldap-reva-password",
|
"USERS_LDAP_BIND_PASSWORD": "fed-ldap-reva-password",
|
||||||
"IDM_IDPSVC_PASSWORD": "some-ldap-idp-password",
|
"AUTH_BASIC_LDAP_BIND_PASSWORD": "fed-ldap-reva-password",
|
||||||
|
"IDM_IDPSVC_PASSWORD": "fed-ldap-idp-password",
|
||||||
"IDP_LDAP_BIND_PASSWORD": "some-ldap-idp-password",
|
"IDP_LDAP_BIND_PASSWORD": "some-ldap-idp-password",
|
||||||
"GRAPH_APPLICATION_ID": "application-1"
|
"GRAPH_APPLICATION_ID": "application-1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# The test runner source for UI tests
|
# The test runner source for UI tests
|
||||||
WEB_COMMITID=6abffcc9cff31c46a341105eb6030fec56338126
|
WEB_COMMITID=3120ea384c7a9d1f1ea0c328965951fc06d66900
|
||||||
WEB_BRANCH=main
|
WEB_BRANCH=main
|
||||||
|
|
||||||
|
|||||||
1160
.woodpecker.star
1160
.woodpecker.star
File diff suppressed because it is too large
Load Diff
111
CHANGELOG.md
111
CHANGELOG.md
@@ -1,5 +1,116 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [4.1.0](https://github.com/opencloud-eu/opencloud/releases/tag/v4.1.0) - 2025-12-15
|
||||||
|
|
||||||
|
### ❤️ Thanks to all contributors! ❤️
|
||||||
|
|
||||||
|
@JammingBen, @ScharfViktor, @Svanvith, @butonic, @flimmy, @fschade, @individual-it, @kulmann, @micbar, @prashant-gurung899, @saw-jan
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- fix typo [[#2024](https://github.com/opencloud-eu/opencloud/pull/2024)]
|
||||||
|
- [docs] update policies link [[#1996](https://github.com/opencloud-eu/opencloud/pull/1996)]
|
||||||
|
- fix the link in quickstart script for itself [[#1956](https://github.com/opencloud-eu/opencloud/pull/1956)]
|
||||||
|
|
||||||
|
### ✅ Tests
|
||||||
|
|
||||||
|
- [full-ci][tests-only] test: fix some test flakiness [[#2003](https://github.com/opencloud-eu/opencloud/pull/2003)]
|
||||||
|
- [tests-only] Skip test related pipelines for ready-release-go PRs [[#2011](https://github.com/opencloud-eu/opencloud/pull/2011)]
|
||||||
|
- [full-ci][tests-only] test: add test to check mismatch offset during TUS upload [[#1993](https://github.com/opencloud-eu/opencloud/pull/1993)]
|
||||||
|
- [full-ci][tests-only] test: proper resource existence check [[#1990](https://github.com/opencloud-eu/opencloud/pull/1990)]
|
||||||
|
- check propfing after renaming data in file system [[#1809](https://github.com/opencloud-eu/opencloud/pull/1809)]
|
||||||
|
- fix-get-attribute-test [[#1974](https://github.com/opencloud-eu/opencloud/pull/1974)]
|
||||||
|
|
||||||
|
### 📈 Enhancement
|
||||||
|
|
||||||
|
- Show edition in opencloud version command [[#2019](https://github.com/opencloud-eu/opencloud/pull/2019)]
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- fix: enforce trailing slash for server url [[#1995](https://github.com/opencloud-eu/opencloud/pull/1995)]
|
||||||
|
- fix: enhance resource creation with detailed process information [[#1978](https://github.com/opencloud-eu/opencloud/pull/1978)]
|
||||||
|
|
||||||
|
### 📦️ Dependencies
|
||||||
|
|
||||||
|
- chore: bump web to v4.3.0 [[#2030](https://github.com/opencloud-eu/opencloud/pull/2030)]
|
||||||
|
- reva-bump-2.41.0 [[#2032](https://github.com/opencloud-eu/opencloud/pull/2032)]
|
||||||
|
- build(deps): bump github.com/testcontainers/testcontainers-go from 0.39.0 to 0.40.0 [[#1931](https://github.com/opencloud-eu/opencloud/pull/1931)]
|
||||||
|
|
||||||
|
## [4.0.0](https://github.com/opencloud-eu/opencloud/releases/tag/v4.0.0) - 2025-12-01
|
||||||
|
|
||||||
|
### ❤️ Thanks to all contributors! ❤️
|
||||||
|
|
||||||
|
@AlexAndBear, @MahdiBaghbani, @ScharfViktor, @butonic, @dragonchaser, @flimmy, @fschade, @individual-it, @jnweiger, @kulmann, @micbar, @mikelolasagasti, @pbleser-oc, @rhafer, @schweigisito
|
||||||
|
|
||||||
|
### 💥 Breaking changes
|
||||||
|
|
||||||
|
- collaboration: Enable `InsertRemoteImage` option [[#1692](https://github.com/opencloud-eu/opencloud/pull/1692)]
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Fix typos in antivirus README documentation [[#1940](https://github.com/opencloud-eu/opencloud/pull/1940)]
|
||||||
|
- fix: add missing service README.md files with basic description [[#1859](https://github.com/opencloud-eu/opencloud/pull/1859)]
|
||||||
|
- Fix README.md files which contain broken or missing links [[#1854](https://github.com/opencloud-eu/opencloud/pull/1854)]
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- introduce OC_EVENTS_TLS_INSECURE [[#1936](https://github.com/opencloud-eu/opencloud/pull/1936)]
|
||||||
|
- kill unused env vars [[#1888](https://github.com/opencloud-eu/opencloud/pull/1888)]
|
||||||
|
- rc-handling was only active for the dryrun, not the real build-and-push [[#1919](https://github.com/opencloud-eu/opencloud/pull/1919)]
|
||||||
|
- handle objectguid endianess [[#1901](https://github.com/opencloud-eu/opencloud/pull/1901)]
|
||||||
|
- fix: add update server to default csp rules [[#1875](https://github.com/opencloud-eu/opencloud/pull/1875)]
|
||||||
|
- fix: add missing capability flag support-radicale [[#1891](https://github.com/opencloud-eu/opencloud/pull/1891)]
|
||||||
|
- fix opensearch client certificate [[#1890](https://github.com/opencloud-eu/opencloud/pull/1890)]
|
||||||
|
- Bump reva [[#1882](https://github.com/opencloud-eu/opencloud/pull/1882)]
|
||||||
|
- load two yaml configs [[#1617](https://github.com/opencloud-eu/opencloud/pull/1617)]
|
||||||
|
- make user cache tenant aware [[#1732](https://github.com/opencloud-eu/opencloud/pull/1732)]
|
||||||
|
- fix: sanitise markdow code to make docusaurus happy [[#1851](https://github.com/opencloud-eu/opencloud/pull/1851)]
|
||||||
|
- update launch.json [[#1843](https://github.com/opencloud-eu/opencloud/pull/1843)]
|
||||||
|
- docs: Fix auth-app examples in README [[#1844](https://github.com/opencloud-eu/opencloud/pull/1844)]
|
||||||
|
- fix: fix typo in treesize logging [[#1826](https://github.com/opencloud-eu/opencloud/pull/1826)]
|
||||||
|
- fix: set global signing secret fallback correctly [[#1781](https://github.com/opencloud-eu/opencloud/pull/1781)]
|
||||||
|
|
||||||
|
### 📈 Enhancement
|
||||||
|
|
||||||
|
- feat(ocm): add WAYF configuration for reva OCM service [[#1714](https://github.com/opencloud-eu/opencloud/pull/1714)]
|
||||||
|
- log missing name or id attributes [[#1914](https://github.com/opencloud-eu/opencloud/pull/1914)]
|
||||||
|
- collabora: Set IsAdminUser and IsAnonymousUser in CheckFileInfo [[#1745](https://github.com/opencloud-eu/opencloud/pull/1745)]
|
||||||
|
|
||||||
|
### ✅ Tests
|
||||||
|
|
||||||
|
- [full-ci] disable running ci with watch fs when full-ci [[#1902](https://github.com/opencloud-eu/opencloud/pull/1902)]
|
||||||
|
- api-tests: delete spaces before users [[#1877](https://github.com/opencloud-eu/opencloud/pull/1877)]
|
||||||
|
- update tika version [[#1872](https://github.com/opencloud-eu/opencloud/pull/1872)]
|
||||||
|
- add share sync to collaborativePosix suite [[#1806](https://github.com/opencloud-eu/opencloud/pull/1806)]
|
||||||
|
- removed test virus files from repo [[#1812](https://github.com/opencloud-eu/opencloud/pull/1812)]
|
||||||
|
- increase timeouts waiting for notification & search [[#1802](https://github.com/opencloud-eu/opencloud/pull/1802)]
|
||||||
|
- Sync share before action [[#1795](https://github.com/opencloud-eu/opencloud/pull/1795)]
|
||||||
|
- correct STORAGE_USERS_POSIX_WATCH_FS env typo in CI [[#1746](https://github.com/opencloud-eu/opencloud/pull/1746)]
|
||||||
|
|
||||||
|
### 📦️ Dependencies
|
||||||
|
|
||||||
|
- [full-ci] revaBump-v2.40.1 [[#1927](https://github.com/opencloud-eu/opencloud/pull/1927)]
|
||||||
|
- [full-ci] chore: bump web to v4.2.1 [[#1938](https://github.com/opencloud-eu/opencloud/pull/1938)]
|
||||||
|
- build(deps): bump google.golang.org/grpc from 1.76.0 to 1.77.0 [[#1923](https://github.com/opencloud-eu/opencloud/pull/1923)]
|
||||||
|
- build(deps): bump github.com/nats-io/nats-server/v2 from 2.12.1 to 2.12.2 [[#1922](https://github.com/opencloud-eu/opencloud/pull/1922)]
|
||||||
|
- build(deps): bump github.com/kovidgoyal/imaging from 1.7.2 to 1.8.17 [[#1912](https://github.com/opencloud-eu/opencloud/pull/1912)]
|
||||||
|
- build(deps): bump golang.org/x/crypto from 0.44.0 to 0.45.0 [[#1911](https://github.com/opencloud-eu/opencloud/pull/1911)]
|
||||||
|
- [decomposed]Update version 4.0.0 rc.2 [[#1917](https://github.com/opencloud-eu/opencloud/pull/1917)]
|
||||||
|
- chore: bump web to v4.2.1-rc.1 [[#1900](https://github.com/opencloud-eu/opencloud/pull/1900)]
|
||||||
|
- revaBump-getting#428 [[#1887](https://github.com/opencloud-eu/opencloud/pull/1887)]
|
||||||
|
- build(deps): bump github.com/blevesearch/bleve/v2 from 2.5.4 to 2.5.5 [[#1884](https://github.com/opencloud-eu/opencloud/pull/1884)]
|
||||||
|
- build(deps): bump github.com/olekukonko/tablewriter from 1.1.0 to 1.1.1 [[#1869](https://github.com/opencloud-eu/opencloud/pull/1869)]
|
||||||
|
- build(deps): bump golang.org/x/term from 0.36.0 to 0.37.0 [[#1845](https://github.com/opencloud-eu/opencloud/pull/1845)]
|
||||||
|
- reva-bump-2.39.2. update opencloud 4.0.0-rc.1 [[#1849](https://github.com/opencloud-eu/opencloud/pull/1849)]
|
||||||
|
- build(deps): bump golang.org/x/sync from 0.17.0 to 0.18.0 [[#1836](https://github.com/opencloud-eu/opencloud/pull/1836)]
|
||||||
|
- build(deps): bump golang.org/x/oauth2 from 0.32.0 to 0.33.0 [[#1828](https://github.com/opencloud-eu/opencloud/pull/1828)]
|
||||||
|
- build(deps): bump github.com/KimMachineGun/automemlimit from 0.7.4 to 0.7.5 [[#1787](https://github.com/opencloud-eu/opencloud/pull/1787)]
|
||||||
|
- build(deps): bump github.com/open-policy-agent/opa from 1.9.0 to 1.10.1 [[#1788](https://github.com/opencloud-eu/opencloud/pull/1788)]
|
||||||
|
- Bump reva [[#1786](https://github.com/opencloud-eu/opencloud/pull/1786)]
|
||||||
|
- build(deps): bump github.com/gabriel-vasile/mimetype from 1.4.10 to 1.4.11 [[#1775](https://github.com/opencloud-eu/opencloud/pull/1775)]
|
||||||
|
- build(deps): bump github.com/nats-io/nats-server/v2 from 2.12.0 to 2.12.1 [[#1706](https://github.com/opencloud-eu/opencloud/pull/1706)]
|
||||||
|
- build(deps): bump github.com/onsi/ginkgo/v2 from 2.27.1 to 2.27.2 [[#1754](https://github.com/opencloud-eu/opencloud/pull/1754)]
|
||||||
|
|
||||||
## [3.7.0](https://github.com/opencloud-eu/opencloud/releases/tag/v3.7.0) - 2025-11-03
|
## [3.7.0](https://github.com/opencloud-eu/opencloud/releases/tag/v3.7.0) - 2025-11-03
|
||||||
|
|
||||||
### ❤️ Thanks to all contributors! ❤️
|
### ❤️ Thanks to all contributors! ❤️
|
||||||
|
|||||||
9
Makefile
9
Makefile
@@ -27,6 +27,7 @@ OC_MODULES = \
|
|||||||
services/app-provider \
|
services/app-provider \
|
||||||
services/app-registry \
|
services/app-registry \
|
||||||
services/audit \
|
services/audit \
|
||||||
|
services/auth-api \
|
||||||
services/auth-app \
|
services/auth-app \
|
||||||
services/auth-basic \
|
services/auth-basic \
|
||||||
services/auth-bearer \
|
services/auth-bearer \
|
||||||
@@ -39,12 +40,12 @@ OC_MODULES = \
|
|||||||
services/gateway \
|
services/gateway \
|
||||||
services/graph \
|
services/graph \
|
||||||
services/groups \
|
services/groups \
|
||||||
|
services/groupware \
|
||||||
services/idm \
|
services/idm \
|
||||||
services/idp \
|
services/idp \
|
||||||
services/invitations \
|
services/invitations \
|
||||||
services/nats \
|
services/nats \
|
||||||
services/notifications \
|
services/notifications \
|
||||||
services/ocdav \
|
|
||||||
services/ocm \
|
services/ocm \
|
||||||
services/ocs \
|
services/ocs \
|
||||||
services/policies \
|
services/policies \
|
||||||
@@ -124,7 +125,7 @@ BEHAT_BIN=vendor-bin/behat/vendor/bin/behat
|
|||||||
|
|
||||||
.PHONY: test-acceptance-api
|
.PHONY: test-acceptance-api
|
||||||
test-acceptance-api: vendor-bin/behat/vendor
|
test-acceptance-api: vendor-bin/behat/vendor
|
||||||
BEHAT_BIN=$(BEHAT_BIN) tests/acceptance/run.sh
|
BEHAT_BIN=$(BEHAT_BIN) tests/acceptance/scripts/run.sh
|
||||||
|
|
||||||
vendor/bamarni/composer-bin-plugin: composer.lock
|
vendor/bamarni/composer-bin-plugin: composer.lock
|
||||||
composer install
|
composer install
|
||||||
@@ -198,6 +199,10 @@ go-mod-tidy:
|
|||||||
test:
|
test:
|
||||||
@go test -v -tags '$(TAGS)' -coverprofile coverage.out ./...
|
@go test -v -tags '$(TAGS)' -coverprofile coverage.out ./...
|
||||||
|
|
||||||
|
.PHONY: test-with-race
|
||||||
|
test-with-race:
|
||||||
|
@go test -race -v -tags '$(TAGS)' -coverprofile coverage.out ./...
|
||||||
|
|
||||||
.PHONY: go-coverage
|
.PHONY: go-coverage
|
||||||
go-coverage:
|
go-coverage:
|
||||||
@if [ ! -f coverage.out ]; then $(MAKE) test &>/dev/null; fi;
|
@if [ ! -f coverage.out ]; then $(MAKE) test &>/dev/null; fi;
|
||||||
|
|||||||
7
changelog/unreleased/add-ocm-wayf-configuration.md
Normal file
7
changelog/unreleased/add-ocm-wayf-configuration.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Enhancement: Add WAYF configuration for reva OCM service
|
||||||
|
|
||||||
|
Add WAYF configuration support for the Reva OCM service,
|
||||||
|
enabling federation discovery functionality for Open Cloud Mesh.
|
||||||
|
This includes configuration for federations file storage and invite accept dialog URL.
|
||||||
|
|
||||||
|
https://github.com/opencloud-eu/opencloud/pull/1714
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "opencloud-eu/opencloud",
|
"name": "opencloud-eu/opencloud",
|
||||||
"config" : {
|
"config": {
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "8.2"
|
"php": "8.3"
|
||||||
},
|
},
|
||||||
"vendor-dir": "./vendor-php",
|
"vendor-dir": "./vendor-php",
|
||||||
"allow-plugins": {
|
"allow-plugins": {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ set -euo pipefail
|
|||||||
# OC_VERSION: Version to download, e.g. OC_VERSION="1.2.0"
|
# OC_VERSION: Version to download, e.g. OC_VERSION="1.2.0"
|
||||||
|
|
||||||
# Call this script directly from opencloud:
|
# Call this script directly from opencloud:
|
||||||
# curl -L https://opencloud.eu/quickinstall.sh | /bin/bash
|
# curl -L https://opencloud.eu/install | /bin/bash
|
||||||
|
|
||||||
# This function is borrowed from openSUSEs /usr/bin/old, thanks.
|
# This function is borrowed from openSUSEs /usr/bin/old, thanks.
|
||||||
function backup_file () {
|
function backup_file () {
|
||||||
|
|||||||
161
devtools/deployments/multi-tenancy/.env.example
Normal file
161
devtools/deployments/multi-tenancy/.env.example
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
## Basic Settings ##
|
||||||
|
# Define the docker compose log driver used.
|
||||||
|
# Defaults to local
|
||||||
|
LOG_DRIVER=
|
||||||
|
# If you're on an internet facing server, comment out following line.
|
||||||
|
# It skips certificate validation for various parts of OpenCloud and is
|
||||||
|
# needed when self signed certificates are used.
|
||||||
|
INSECURE=true
|
||||||
|
|
||||||
|
## Features ##
|
||||||
|
COMPOSE_FILE=docker-compose.yml:traefik.yml:keycloak.yml:ldap-server.yml
|
||||||
|
|
||||||
|
## Traefik Settings ##
|
||||||
|
# Note: Traefik is always enabled and can't be disabled.
|
||||||
|
# Serve Traefik dashboard.
|
||||||
|
# Defaults to "false".
|
||||||
|
TRAEFIK_DASHBOARD=
|
||||||
|
# Domain of Traefik, where you can find the dashboard.
|
||||||
|
# Defaults to "traefik.opencloud.test"
|
||||||
|
TRAEFIK_DOMAIN=
|
||||||
|
# Basic authentication for the traefik dashboard.
|
||||||
|
# Defaults to user "admin" and password "admin" (written as: "admin:$2y$05$KDHu3xq92SPaO3G8Ybkc7edd51pPLJcG1nWk3lmlrIdANQ/B6r5pq").
|
||||||
|
# To create user:password pair, it's possible to use this command:
|
||||||
|
# echo $(htpasswd -nB user) | sed -e s/\\$/\\$\\$/g
|
||||||
|
TRAEFIK_BASIC_AUTH_USERS=
|
||||||
|
# Email address for obtaining LetsEncrypt certificates.
|
||||||
|
# Needs only be changed if this is a public facing server.
|
||||||
|
TRAEFIK_ACME_MAIL=
|
||||||
|
# Set to the following for testing to check the certificate process:
|
||||||
|
# "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||||
|
# With staging configured, there will be an SSL error in the browser.
|
||||||
|
# When certificates are displayed and are emitted by # "Fake LE Intermediate X1",
|
||||||
|
# the process went well and the envvar can be reset to empty to get valid certificates.
|
||||||
|
TRAEFIK_ACME_CASERVER=
|
||||||
|
# Enable the Traefik ACME (Automatic Certificate Management Environment) for automatic SSL certificate management.
|
||||||
|
TRAEFIK_SERVICES_TLS_CONFIG="tls.certresolver=letsencrypt"
|
||||||
|
# Enable Traefik to use local certificates.
|
||||||
|
#TRAEFIK_SERVICES_TLS_CONFIG="tls=true"
|
||||||
|
# You also need to provide a config file in ./config/traefik/dynamic/certs.yml
|
||||||
|
# Example:
|
||||||
|
# cat ./config/traefik/dynamic/certs.yml
|
||||||
|
# tls:
|
||||||
|
# certificates:
|
||||||
|
# - certFile: /certs/opencloud.test.crt
|
||||||
|
# keyFile: /certs/opencloud.test.key
|
||||||
|
# stores:
|
||||||
|
# - default
|
||||||
|
#
|
||||||
|
# The certificates need to copied into ./certs/, the absolute path inside the container is /certs/.
|
||||||
|
# You can also use TRAEFIK_CERTS_DIR=/path/on/host to set the path to the certificates directory.
|
||||||
|
# Enable the access log for Traefik by setting the following variable to true.
|
||||||
|
TRAEFIK_ACCESS_LOG=
|
||||||
|
# Configure the log level for Traefik.
|
||||||
|
# Possible values are "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" and "PANIC". Default is "ERROR".
|
||||||
|
TRAEFIK_LOG_LEVEL=
|
||||||
|
|
||||||
|
|
||||||
|
## OpenCloud Settings ##
|
||||||
|
# The opencloud container image.
|
||||||
|
# For production releases: "opencloudeu/opencloud"
|
||||||
|
# For rolling releases: "opencloudeu/opencloud-rolling"
|
||||||
|
# Defaults to production if not set otherwise
|
||||||
|
OC_DOCKER_IMAGE=opencloudeu/opencloud-rolling
|
||||||
|
# The openCloud container version.
|
||||||
|
# Defaults to "latest" and points to the latest stable tag.
|
||||||
|
OC_DOCKER_TAG=
|
||||||
|
# Domain of openCloud, where you can find the frontend.
|
||||||
|
# Defaults to "cloud.opencloud.test"
|
||||||
|
OC_DOMAIN=
|
||||||
|
# Demo users should not be created on a production instance,
|
||||||
|
# because their passwords are public. Defaults to "false".
|
||||||
|
# If demo users is set to "true", the following user accounts are created automatically:
|
||||||
|
# alan, mary, margaret, dennis and lynn - the password is 'demo' for all.
|
||||||
|
DEMO_USERS=
|
||||||
|
# Admin Password for the OpenCloud admin user.
|
||||||
|
# NOTE: This is only needed when using the built-in LDAP server (idm).
|
||||||
|
# If you are using an external LDAP server, the admin password is managed by the LDAP server.
|
||||||
|
# NOTE: This variable needs to be set before the first start of OpenCloud. Changes to this variable after the first start will be IGNORED.
|
||||||
|
# If not set, opencloud will not work properly. The container will be restarting.
|
||||||
|
# After the first initialization, the admin password can only be changed via the OpenCloud User Settings UI or by using the OpenCloud CLI.
|
||||||
|
# Documentation: https://docs.opencloud.eu/docs/admin/resources/common-issues#-change-admin-password-set-in-env
|
||||||
|
INITIAL_ADMIN_PASSWORD=
|
||||||
|
# Define the openCloud loglevel used.
|
||||||
|
#
|
||||||
|
LOG_LEVEL=
|
||||||
|
# Define the kind of logging.
|
||||||
|
# The default log can be read by machines.
|
||||||
|
# Set this to true to make the log human readable.
|
||||||
|
# LOG_PRETTY=true
|
||||||
|
#
|
||||||
|
# Define the openCloud storage location. Set the paths for config and data to a local path.
|
||||||
|
# Ensure that the configuration and data directories are owned by the user and group with ID 1000:1000.
|
||||||
|
# This matches the default user inside the container and avoids permission issues when accessing files.
|
||||||
|
# Note that especially the data directory can grow big.
|
||||||
|
# Leaving it default stores data in docker internal volumes.
|
||||||
|
# OC_CONFIG_DIR=/your/local/opencloud/config
|
||||||
|
# OC_DATA_DIR=/your/local/opencloud/data
|
||||||
|
|
||||||
|
### Compose Configuration ###
|
||||||
|
# Path separator for supplemental compose files specified in COMPOSE_FILE.
|
||||||
|
COMPOSE_PATH_SEPARATOR=:
|
||||||
|
|
||||||
|
### Ldap Settings ###
|
||||||
|
# LDAP is always needed for OpenCloud to store user data as there is no relational database.
|
||||||
|
# The built-in LDAP server should used for testing purposes or small installations only.
|
||||||
|
# For production installations, it is recommended to use an external LDAP server.
|
||||||
|
# We are using OpenLDAP as the default LDAP server because it is proven to be stable and reliable.
|
||||||
|
# This LDAP configuration is known to work with OpenCloud and provides a blueprint for
|
||||||
|
# configuring an external LDAP server based on other products like Microsoft Active Directory or other LDAP servers.
|
||||||
|
#
|
||||||
|
# Password of LDAP bind user "cn=admin,dc=opencloud,dc=eu". Defaults to "admin"
|
||||||
|
LDAP_BIND_PASSWORD=
|
||||||
|
# The LDAP server also creates an openCloud admin user dn: uid=admin,ou=users,dc=opencloud,dc=eu
|
||||||
|
# The initial password for this user is "admin"
|
||||||
|
# NOTE: This password can only be set once, if you want to change it later, you have to use the OpenCloud User Settings UI.
|
||||||
|
# If you changed the password and lost it, you need to execute the following LDAP query to reset it:
|
||||||
|
# enter the ldap-server container with `docker compose exec ldap-server sh`
|
||||||
|
# and run the following command to change the password:
|
||||||
|
# ldappasswd -H ldap://127.0.0.1:1389 -D "cn=admin,dc=opencloud,dc=eu" -W "uid=admin,ou=users,dc=opencloud,dc=eu"
|
||||||
|
# You will be prompted for the LDAP bind password.
|
||||||
|
# The output should provide you a new password for the admin user.
|
||||||
|
|
||||||
|
|
||||||
|
### Keycloak Settings ###
|
||||||
|
# Keycloak is an open-source identity and access management solution.
|
||||||
|
# We are using Keycloak as the default identity provider on production installations.
|
||||||
|
# It can be used to federate authentication with other identity providers like
|
||||||
|
# Microsoft Entra ID, ADFS or other SAML/OIDC providers.
|
||||||
|
# The use of Keycloak as bridge between OpenCloud and other identity providers creates more control over the
|
||||||
|
# authentication process, the allowed clients and the session management.
|
||||||
|
# Keycloak also manages the Role Based Access Control (RBAC) for OpenCloud.
|
||||||
|
# Keycloak can be used in two different modes:
|
||||||
|
# 1. Autoprovisioning: New users are automatically created in openCloud when they log in for the first time.
|
||||||
|
# 2. Shared User Directory: Users are created in Keycloak and can be used in OpenCloud immediately
|
||||||
|
# because the LDAP server is connected to both Keycloak and OpenCloud.
|
||||||
|
# Only use one of the two modes at a time.
|
||||||
|
|
||||||
|
## Autoprovisioning Mode ##
|
||||||
|
# Use together with idm/external-idp.yml
|
||||||
|
# If you want to use a keycloak for local testing, you can use testing/external-keycloak.yml and testing/ldap-manager.yml
|
||||||
|
# Domain of your Identity Provider.
|
||||||
|
IDP_DOMAIN=
|
||||||
|
# IdP Issuer URL, which is used to identify the Identity Provider.
|
||||||
|
# We need the complete URL, including the protocol (http or https) and the realm.
|
||||||
|
# Example: "https://keycloak.opencloud.test/realms/openCloud"
|
||||||
|
IDP_ISSUER_URL=
|
||||||
|
# Url of the account edit page from your Identity Provider.
|
||||||
|
IDP_ACCOUNT_URL=
|
||||||
|
|
||||||
|
## Shared User Directory Mode ##
|
||||||
|
# Use together with idm/ldap-keycloak.yml and traefik/ldap-keycloak.yml
|
||||||
|
# Domain for Keycloak. Defaults to "keycloak.opencloud.test".
|
||||||
|
KEYCLOAK_DOMAIN=
|
||||||
|
# Admin user login name. Defaults to "kcadmin".
|
||||||
|
KEYCLOAK_ADMIN=
|
||||||
|
# Admin user login password. Defaults to "admin".
|
||||||
|
KEYCLOAK_ADMIN_PASSWORD=
|
||||||
|
# Keycloak Database username. Defaults to "keycloak".
|
||||||
|
KC_DB_USERNAME=
|
||||||
|
# Keycloak Database password. Defaults to "keycloak".
|
||||||
|
KC_DB_PASSWORD=
|
||||||
49
devtools/deployments/multi-tenancy/README.md
Normal file
49
devtools/deployments/multi-tenancy/README.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Development/Test Deployment for a multi-tenacy setup
|
||||||
|
|
||||||
|
The docker compose files in this directory are derived from the
|
||||||
|
opencloud-compose project and can be used to deploy a Development or Testing
|
||||||
|
environment for a multi-tenancy setup of OpenCloud. It consists of the
|
||||||
|
following services:
|
||||||
|
|
||||||
|
* `provisioning`: The OpenCloud graph service deployed in a standalone mode. It
|
||||||
|
is configured to provide the libregraph education API for managing tenants
|
||||||
|
and users. The `ldap-server`service (see below) is used to store the tenants
|
||||||
|
and users.
|
||||||
|
* `ldap-server`: An OpenLDAP server that is used by the provisioning service to
|
||||||
|
store tenants and users. Used by the OpenCloud services as the user directory
|
||||||
|
(for looking up users and searching for sharees).
|
||||||
|
* `keycloak`: The OpenID Connect Provider used for authenticating users. The
|
||||||
|
pre-loaded realm is configured to add `tenantid` claim into the identity and
|
||||||
|
access tokens. It's also currently consuming user from the `ldap-server`
|
||||||
|
(this federation will likely go away in the future and is optional for future
|
||||||
|
configurations).
|
||||||
|
* `opencloud`: The OpenCloud configured so that is hides users from different
|
||||||
|
tenants from each other.
|
||||||
|
|
||||||
|
To deploy the setup, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.yml -f keycloak.yml -f ldap-server.yml -f traefik.yml up
|
||||||
|
```
|
||||||
|
|
||||||
|
Once deployed you can use the `initialize_users.go` to create a couple of example
|
||||||
|
tenants and some users in each tenant:
|
||||||
|
|
||||||
|
* Tenant `Famous Coders` with users `dennis` and `grace`
|
||||||
|
* Tenant `Scientists` with users `einstein` and `marie`
|
||||||
|
|
||||||
|
The passwords for the users is set to `demo` in keycloak
|
||||||
|
|
||||||
|
```
|
||||||
|
> go run initialize_users.go
|
||||||
|
Created tenant: Famous Coders with id fc58e19a-3a2a-4afc-90ec-8f94986db340
|
||||||
|
Created user: Dennis Ritchie with id ee1e14e7-b00b-4eec-8b03-a6bf0e29c77c
|
||||||
|
Created user: Grace Hopper with id a29f3afd-e4a3-4552-91e8-cc99e26bffce
|
||||||
|
Created tenant: Scientists with id 18406c53-e2d6-4e83-98b6-a55880eef195
|
||||||
|
Created user: Albert Einstein with id 12023d37-d6ce-4f19-a318-b70866f265ba
|
||||||
|
Created user: Marie Curie with id 30c3c825-c37d-4e85-8195-0142e4884872
|
||||||
|
Setting password for user: grace
|
||||||
|
Setting password for user: marie
|
||||||
|
Setting password for user: dennis
|
||||||
|
Setting password for user: einstein
|
||||||
|
```
|
||||||
0
devtools/deployments/multi-tenancy/certs/.gitkeep
Normal file
0
devtools/deployments/multi-tenancy/certs/.gitkeep
Normal file
0
devtools/deployments/multi-tenancy/certs/acme.json
Normal file
0
devtools/deployments/multi-tenancy/certs/acme.json
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"clientId": "OpenCloudAndroid",
|
||||||
|
"name": "OpenCloud Android App",
|
||||||
|
"surrogateAuthRequired": false,
|
||||||
|
"enabled": true,
|
||||||
|
"alwaysDisplayInConsole": false,
|
||||||
|
"clientAuthenticatorType": "client-secret",
|
||||||
|
"redirectUris": [
|
||||||
|
"oc://android.opencloud.eu"
|
||||||
|
],
|
||||||
|
"webOrigins": [],
|
||||||
|
"notBefore": 0,
|
||||||
|
"bearerOnly": false,
|
||||||
|
"consentRequired": false,
|
||||||
|
"standardFlowEnabled": true,
|
||||||
|
"implicitFlowEnabled": false,
|
||||||
|
"directAccessGrantsEnabled": true,
|
||||||
|
"serviceAccountsEnabled": false,
|
||||||
|
"publicClient": true,
|
||||||
|
"frontchannelLogout": false,
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"attributes": {
|
||||||
|
"saml.assertion.signature": "false",
|
||||||
|
"saml.force.post.binding": "false",
|
||||||
|
"saml.multivalued.roles": "false",
|
||||||
|
"saml.encrypt": "false",
|
||||||
|
"post.logout.redirect.uris": "oc://android.opencloud.eu",
|
||||||
|
"backchannel.logout.revoke.offline.tokens": "false",
|
||||||
|
"saml.server.signature": "false",
|
||||||
|
"saml.server.signature.keyinfo.ext": "false",
|
||||||
|
"exclude.session.state.from.auth.response": "false",
|
||||||
|
"backchannel.logout.session.required": "true",
|
||||||
|
"client_credentials.use_refresh_token": "false",
|
||||||
|
"saml_force_name_id_format": "false",
|
||||||
|
"saml.client.signature": "false",
|
||||||
|
"tls.client.certificate.bound.access.tokens": "false",
|
||||||
|
"saml.authnstatement": "false",
|
||||||
|
"display.on.consent.screen": "false",
|
||||||
|
"saml.onetimeuse.condition": "false"
|
||||||
|
},
|
||||||
|
"authenticationFlowBindingOverrides": {},
|
||||||
|
"fullScopeAllowed": true,
|
||||||
|
"nodeReRegistrationTimeout": -1,
|
||||||
|
"defaultClientScopes": [
|
||||||
|
"web-origins",
|
||||||
|
"profile",
|
||||||
|
"roles",
|
||||||
|
"groups",
|
||||||
|
"basic",
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"optionalClientScopes": [
|
||||||
|
"address",
|
||||||
|
"phone",
|
||||||
|
"offline_access",
|
||||||
|
"microprofile-jwt"
|
||||||
|
],
|
||||||
|
"access": {
|
||||||
|
"view": true,
|
||||||
|
"configure": true,
|
||||||
|
"manage": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
"clientId": "OpenCloudDesktop",
|
||||||
|
"name": "OpenCloud Desktop Client",
|
||||||
|
"surrogateAuthRequired": false,
|
||||||
|
"enabled": true,
|
||||||
|
"alwaysDisplayInConsole": false,
|
||||||
|
"clientAuthenticatorType": "client-secret",
|
||||||
|
"redirectUris": [
|
||||||
|
"http://127.0.0.1",
|
||||||
|
"http://localhost"
|
||||||
|
],
|
||||||
|
"webOrigins": [],
|
||||||
|
"notBefore": 0,
|
||||||
|
"bearerOnly": false,
|
||||||
|
"consentRequired": false,
|
||||||
|
"standardFlowEnabled": true,
|
||||||
|
"implicitFlowEnabled": false,
|
||||||
|
"directAccessGrantsEnabled": true,
|
||||||
|
"serviceAccountsEnabled": false,
|
||||||
|
"publicClient": true,
|
||||||
|
"frontchannelLogout": false,
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"attributes": {
|
||||||
|
"saml.assertion.signature": "false",
|
||||||
|
"saml.force.post.binding": "false",
|
||||||
|
"saml.multivalued.roles": "false",
|
||||||
|
"saml.encrypt": "false",
|
||||||
|
"post.logout.redirect.uris": "+",
|
||||||
|
"backchannel.logout.revoke.offline.tokens": "false",
|
||||||
|
"saml.server.signature": "false",
|
||||||
|
"saml.server.signature.keyinfo.ext": "false",
|
||||||
|
"exclude.session.state.from.auth.response": "false",
|
||||||
|
"backchannel.logout.session.required": "true",
|
||||||
|
"client_credentials.use_refresh_token": "false",
|
||||||
|
"saml_force_name_id_format": "false",
|
||||||
|
"saml.client.signature": "false",
|
||||||
|
"tls.client.certificate.bound.access.tokens": "false",
|
||||||
|
"saml.authnstatement": "false",
|
||||||
|
"display.on.consent.screen": "false",
|
||||||
|
"saml.onetimeuse.condition": "false"
|
||||||
|
},
|
||||||
|
"authenticationFlowBindingOverrides": {},
|
||||||
|
"fullScopeAllowed": true,
|
||||||
|
"nodeReRegistrationTimeout": -1,
|
||||||
|
"defaultClientScopes": [
|
||||||
|
"web-origins",
|
||||||
|
"profile",
|
||||||
|
"roles",
|
||||||
|
"groups",
|
||||||
|
"basic",
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"optionalClientScopes": [
|
||||||
|
"address",
|
||||||
|
"phone",
|
||||||
|
"offline_access",
|
||||||
|
"microprofile-jwt"
|
||||||
|
],
|
||||||
|
"access": {
|
||||||
|
"view": true,
|
||||||
|
"configure": true,
|
||||||
|
"manage": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"clientId": "OpenCloudIOS",
|
||||||
|
"name": "OpenCloud iOS App",
|
||||||
|
"surrogateAuthRequired": false,
|
||||||
|
"enabled": true,
|
||||||
|
"alwaysDisplayInConsole": false,
|
||||||
|
"clientAuthenticatorType": "client-secret",
|
||||||
|
"redirectUris": [
|
||||||
|
"oc://ios.opencloud.eu"
|
||||||
|
],
|
||||||
|
"webOrigins": [],
|
||||||
|
"notBefore": 0,
|
||||||
|
"bearerOnly": false,
|
||||||
|
"consentRequired": false,
|
||||||
|
"standardFlowEnabled": true,
|
||||||
|
"implicitFlowEnabled": false,
|
||||||
|
"directAccessGrantsEnabled": true,
|
||||||
|
"serviceAccountsEnabled": false,
|
||||||
|
"publicClient": true,
|
||||||
|
"frontchannelLogout": false,
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"attributes": {
|
||||||
|
"saml.assertion.signature": "false",
|
||||||
|
"saml.force.post.binding": "false",
|
||||||
|
"saml.multivalued.roles": "false",
|
||||||
|
"saml.encrypt": "false",
|
||||||
|
"post.logout.redirect.uris": "oc://ios.opencloud.eu",
|
||||||
|
"backchannel.logout.revoke.offline.tokens": "false",
|
||||||
|
"saml.server.signature": "false",
|
||||||
|
"saml.server.signature.keyinfo.ext": "false",
|
||||||
|
"exclude.session.state.from.auth.response": "false",
|
||||||
|
"backchannel.logout.session.required": "true",
|
||||||
|
"client_credentials.use_refresh_token": "false",
|
||||||
|
"saml_force_name_id_format": "false",
|
||||||
|
"saml.client.signature": "false",
|
||||||
|
"tls.client.certificate.bound.access.tokens": "false",
|
||||||
|
"saml.authnstatement": "false",
|
||||||
|
"display.on.consent.screen": "false",
|
||||||
|
"saml.onetimeuse.condition": "false"
|
||||||
|
},
|
||||||
|
"authenticationFlowBindingOverrides": {},
|
||||||
|
"fullScopeAllowed": true,
|
||||||
|
"nodeReRegistrationTimeout": -1,
|
||||||
|
"defaultClientScopes": [
|
||||||
|
"web-origins",
|
||||||
|
"profile",
|
||||||
|
"roles",
|
||||||
|
"groups",
|
||||||
|
"basic",
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"optionalClientScopes": [
|
||||||
|
"address",
|
||||||
|
"phone",
|
||||||
|
"offline_access",
|
||||||
|
"microprofile-jwt"
|
||||||
|
],
|
||||||
|
"access": {
|
||||||
|
"view": true,
|
||||||
|
"configure": true,
|
||||||
|
"manage": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"clientId": "Cyberduck",
|
||||||
|
"name": "Cyberduck",
|
||||||
|
"description": "File transfer utility client",
|
||||||
|
"surrogateAuthRequired": false,
|
||||||
|
"enabled": true,
|
||||||
|
"alwaysDisplayInConsole": false,
|
||||||
|
"clientAuthenticatorType": "client-secret",
|
||||||
|
"redirectUris": [
|
||||||
|
"x-cyberduck-action:oauth",
|
||||||
|
"x-mountainduck-action:oauth"
|
||||||
|
],
|
||||||
|
"webOrigins": [],
|
||||||
|
"notBefore": 0,
|
||||||
|
"bearerOnly": false,
|
||||||
|
"consentRequired": false,
|
||||||
|
"standardFlowEnabled": true,
|
||||||
|
"implicitFlowEnabled": false,
|
||||||
|
"directAccessGrantsEnabled": true,
|
||||||
|
"serviceAccountsEnabled": false,
|
||||||
|
"publicClient": true,
|
||||||
|
"frontchannelLogout": false,
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"attributes": {
|
||||||
|
"saml.assertion.signature": "false",
|
||||||
|
"saml.force.post.binding": "false",
|
||||||
|
"saml.multivalued.roles": "false",
|
||||||
|
"saml.encrypt": "false",
|
||||||
|
"oauth2.device.authorization.grant.enabled": "false",
|
||||||
|
"backchannel.logout.revoke.offline.tokens": "false",
|
||||||
|
"saml.server.signature": "false",
|
||||||
|
"saml.server.signature.keyinfo.ext": "false",
|
||||||
|
"exclude.session.state.from.auth.response": "false",
|
||||||
|
"oidc.ciba.grant.enabled": "false",
|
||||||
|
"backchannel.logout.session.required": "true",
|
||||||
|
"client_credentials.use_refresh_token": "false",
|
||||||
|
"saml_force_name_id_format": "false",
|
||||||
|
"saml.client.signature": "false",
|
||||||
|
"tls.client.certificate.bound.access.tokens": "false",
|
||||||
|
"saml.authnstatement": "false",
|
||||||
|
"display.on.consent.screen": "false",
|
||||||
|
"saml.onetimeuse.condition": "false"
|
||||||
|
},
|
||||||
|
"authenticationFlowBindingOverrides": {},
|
||||||
|
"fullScopeAllowed": true,
|
||||||
|
"nodeReRegistrationTimeout": -1,
|
||||||
|
"defaultClientScopes": [
|
||||||
|
"web-origins",
|
||||||
|
"profile",
|
||||||
|
"roles",
|
||||||
|
"groups",
|
||||||
|
"basic",
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"optionalClientScopes": [
|
||||||
|
"address",
|
||||||
|
"phone",
|
||||||
|
"offline_access",
|
||||||
|
"microprofile-jwt"
|
||||||
|
],
|
||||||
|
"access": {
|
||||||
|
"view": true,
|
||||||
|
"configure": true,
|
||||||
|
"manage": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"clientId": "web",
|
||||||
|
"name": "OpenCloud Web App",
|
||||||
|
"description": "",
|
||||||
|
"rootUrl": "{{OC_URL}}",
|
||||||
|
"adminUrl": "{{OC_URL}}",
|
||||||
|
"baseUrl": "",
|
||||||
|
"surrogateAuthRequired": false,
|
||||||
|
"enabled": true,
|
||||||
|
"alwaysDisplayInConsole": false,
|
||||||
|
"clientAuthenticatorType": "client-secret",
|
||||||
|
"redirectUris": [
|
||||||
|
"{{OC_URL}}/",
|
||||||
|
"{{OC_URL}}/oidc-callback.html",
|
||||||
|
"{{OC_URL}}/oidc-silent-redirect.html"
|
||||||
|
],
|
||||||
|
"webOrigins": [
|
||||||
|
"{{OC_URL}}"
|
||||||
|
],
|
||||||
|
"notBefore": 0,
|
||||||
|
"bearerOnly": false,
|
||||||
|
"consentRequired": false,
|
||||||
|
"standardFlowEnabled": true,
|
||||||
|
"implicitFlowEnabled": false,
|
||||||
|
"directAccessGrantsEnabled": true,
|
||||||
|
"serviceAccountsEnabled": false,
|
||||||
|
"publicClient": true,
|
||||||
|
"frontchannelLogout": false,
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"attributes": {
|
||||||
|
"saml.assertion.signature": "false",
|
||||||
|
"saml.force.post.binding": "false",
|
||||||
|
"saml.multivalued.roles": "false",
|
||||||
|
"saml.encrypt": "false",
|
||||||
|
"post.logout.redirect.uris": "+",
|
||||||
|
"oauth2.device.authorization.grant.enabled": "false",
|
||||||
|
"backchannel.logout.revoke.offline.tokens": "false",
|
||||||
|
"saml.server.signature": "false",
|
||||||
|
"saml.server.signature.keyinfo.ext": "false",
|
||||||
|
"exclude.session.state.from.auth.response": "false",
|
||||||
|
"oidc.ciba.grant.enabled": "false",
|
||||||
|
"backchannel.logout.url": "{{OC_URL}}/backchannel_logout",
|
||||||
|
"backchannel.logout.session.required": "true",
|
||||||
|
"client_credentials.use_refresh_token": "false",
|
||||||
|
"saml_force_name_id_format": "false",
|
||||||
|
"saml.client.signature": "false",
|
||||||
|
"tls.client.certificate.bound.access.tokens": "false",
|
||||||
|
"saml.authnstatement": "false",
|
||||||
|
"display.on.consent.screen": "false",
|
||||||
|
"saml.onetimeuse.condition": "false"
|
||||||
|
},
|
||||||
|
"authenticationFlowBindingOverrides": {},
|
||||||
|
"fullScopeAllowed": true,
|
||||||
|
"nodeReRegistrationTimeout": -1,
|
||||||
|
"defaultClientScopes": [
|
||||||
|
"web-origins",
|
||||||
|
"profile",
|
||||||
|
"roles",
|
||||||
|
"groups",
|
||||||
|
"basic",
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"optionalClientScopes": [
|
||||||
|
"address",
|
||||||
|
"phone",
|
||||||
|
"offline_access",
|
||||||
|
"microprofile-jwt"
|
||||||
|
],
|
||||||
|
"access": {
|
||||||
|
"view": true,
|
||||||
|
"configure": true,
|
||||||
|
"manage": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
printenv
|
||||||
|
# replace openCloud domain and LDAP password in keycloak realm import
|
||||||
|
mkdir /opt/keycloak/data/import
|
||||||
|
sed -e "s/cloud.opencloud.test/${OC_DOMAIN}/g" -e "s/ldap-admin-password/${LDAP_ADMIN_PASSWORD:-admin}/g" /opt/keycloak/data/import-dist/openCloud-realm.json > /opt/keycloak/data/import/openCloud-realm.json
|
||||||
|
|
||||||
|
# run original docker-entrypoint
|
||||||
|
/opt/keycloak/bin/kc.sh "$@"
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
|||||||
|
:root {
|
||||||
|
--pf-global--primary-color--100: #e2baff;
|
||||||
|
--pf-global--primary-color--200: #e2baff;
|
||||||
|
--pf-global--primary-color--dark-100: #e2baff;
|
||||||
|
--pf-global--Color--light-100: #20434f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: OpenCloud;
|
||||||
|
src: url('../fonts/OpenCloud500-Regular.woff2') format('woff2');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: OpenCloud;
|
||||||
|
src: url('../fonts/OpenCloud750-Bold.woff2') format('woff2');
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "OpenCloud", "Open Sans", Helvetica, Arial, sans-serif;
|
||||||
|
background: url(../img/background.png) no-repeat center !important;
|
||||||
|
background-size: cover !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kc-logo-text {
|
||||||
|
background-image: url(../img/logo.svg) !important;
|
||||||
|
background-size: contain;
|
||||||
|
width: 400px;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-header-wrapper{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,14 @@
|
|||||||
|
<svg width="170" height="35" viewBox="0 0 170 35" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M45.1928 23.7428C42.5766 22.2684 41.0547 19.5569 41.0547 16.1555C41.0547 14.4433 41.4115 12.921 42.1485 11.589C43.5753 8.92532 46.2869 7.35547 49.6879 7.35547C51.377 7.35547 52.8514 7.73604 54.1593 8.47339C56.7523 9.97188 58.2508 12.7307 58.2508 16.1555C58.2508 17.8443 57.894 19.3663 57.1801 20.6748C55.753 23.315 53.042 24.8605 49.6879 24.8605C47.9992 24.8605 46.501 24.504 45.1928 23.7428ZM49.6641 22.1254C52.9942 22.1254 55.1824 19.7947 55.1824 16.1555C55.1824 12.4215 52.8755 10.0667 49.6641 10.0667C46.4534 10.0667 44.1224 12.4215 44.1224 16.1555C44.1224 19.771 46.3345 22.1254 49.6641 22.1254Z" fill="#E2BAFF"/>
|
||||||
|
<path d="M62.0912 11.9934L63.6608 14.7522C65.0879 12.4929 66.967 11.9934 68.4176 11.9934C69.5828 11.9934 70.5821 12.255 71.4618 12.8259C72.3657 13.4202 73.0558 14.1814 73.5077 15.1328C74.0069 16.1318 74.2448 17.2259 74.2448 18.4387C74.2448 19.6518 74.0069 20.7697 73.5077 21.7687C73.0558 22.7201 72.3419 23.4813 71.4381 24.0283C70.5821 24.5989 69.5828 24.8605 68.4176 24.8605C67.6327 24.8605 66.8477 24.6943 66.0869 24.3613C65.3971 24.0283 64.7787 23.5526 64.2792 22.958V28.9992H61.3774V16.5599L59.5938 13.4443L62.0912 11.9934ZM64.2792 18.4387C64.2792 19.1764 64.4219 19.8658 64.7073 20.4605C65.0641 21.1027 65.4685 21.5546 65.9442 21.84C66.4913 22.1493 67.0856 22.292 67.7754 22.292C68.489 22.292 69.0836 22.1493 69.6069 21.84C70.1302 21.5308 70.5583 21.0789 70.8196 20.4605C71.1289 19.8658 71.2478 19.1764 71.2478 18.4387C71.2478 17.2497 70.9386 16.2983 70.3204 15.6323C69.6782 14.9187 68.8457 14.562 67.7516 14.562C66.7291 14.562 65.8728 14.9187 65.2306 15.6323C64.6122 16.2983 64.2792 17.2497 64.2792 18.4387Z" fill="#E2BAFF"/>
|
||||||
|
<path d="M76.5405 15.133C77.0162 14.1812 77.7297 13.3966 78.7049 12.7782C79.7039 12.2311 80.7981 11.9695 82.0587 11.9695C83.319 11.9695 84.3656 12.2311 85.1981 12.7306C86.1017 13.3015 86.768 14.0626 87.2437 15.0137C87.6715 15.9892 87.9094 17.1544 87.9094 18.4386L87.8621 19.1286H78.6098C78.7049 20.1987 79.0855 21.0077 79.7515 21.6261C80.4175 22.1491 81.2976 22.387 82.3438 22.387C83.1528 22.387 83.8661 22.2446 84.5318 21.9826C85.1981 21.721 85.7925 21.388 86.2685 20.9836C86.3398 21.0553 87.505 23.1005 87.505 23.1005C86.768 23.6476 85.9352 24.0758 85.0316 24.4084C84.1991 24.7177 83.2239 24.8604 82.1535 24.8604C80.8694 24.8604 79.7277 24.599 78.8001 24.052C77.8962 23.5287 77.1589 22.7675 76.5642 21.7689C76.0409 20.7696 75.7793 19.6516 75.7793 18.4386C75.7793 17.2496 76.0172 16.1317 76.5405 15.133ZM78.6811 17.1544H85.0316C84.9365 16.203 84.6273 15.5373 84.104 15.1089C83.5331 14.6097 82.8671 14.348 82.0587 14.348C81.2259 14.348 80.5126 14.6097 79.8704 15.0616C79.2996 15.5135 78.919 16.203 78.6811 17.1544Z" fill="#E2BAFF"/>
|
||||||
|
<path d="M102.054 17.0594V24.4799H99.1283V17.3211C99.1283 16.3459 98.9142 15.6561 98.4623 15.2042C98.0342 14.6809 97.3919 14.443 96.5121 14.443C95.9411 14.443 95.4656 14.5857 94.9899 14.895C94.538 15.1328 94.1812 15.5372 93.9433 16.0367C93.7293 16.5124 93.5866 17.0832 93.5866 17.773V24.4799H90.6371V16.5599L88.8535 13.4202L91.3745 11.9934L92.8492 14.5144C94.3477 12.2785 95.9648 11.9934 97.059 11.9934C98.2958 11.9934 99.0569 12.2072 99.5564 12.445C100.056 12.6832 100.508 12.9921 100.841 13.3727C101.649 14.2527 102.054 15.4896 102.054 17.0594Z" fill="#E2BAFF"/>
|
||||||
|
<path d="M117.538 23.838C117.015 24.0999 116.325 24.3613 115.469 24.5991C114.684 24.7656 113.851 24.8608 112.971 24.8608C111.259 24.8608 109.737 24.4802 108.429 23.7669C107.144 23.0531 106.145 22.0303 105.408 20.6748C104.694 19.3663 104.338 17.8443 104.338 16.1083C104.338 14.4195 104.694 12.8972 105.384 11.5414C106.074 10.2097 107.144 9.16318 108.405 8.47339C109.713 7.71225 111.283 7.35547 113.138 7.35547C114.066 7.35547 114.874 7.42683 115.564 7.61711C116.373 7.80739 117.038 8.04525 117.514 8.33068C118.014 8.56854 118.608 8.90153 119.298 9.35346L117.8 11.8982C117.062 11.3987 116.349 11.0185 115.659 10.733C114.85 10.4238 113.994 10.2573 113.066 10.2573C111.83 10.2573 110.807 10.4952 109.999 10.9944C109.118 11.5414 108.476 12.2312 108.048 13.0875C107.62 14.0151 107.382 15.0379 107.382 16.1555C107.382 17.2738 107.62 18.2725 108.048 19.1525C108.476 20.0088 109.118 20.6986 109.999 21.1981C110.831 21.6735 111.854 21.9117 113.043 21.9117C113.733 21.9117 114.351 21.84 114.922 21.6973C115.54 21.5308 116.064 21.3408 116.491 21.103C117.086 20.7937 117.538 20.5083 117.871 20.2467L119.346 22.8152C118.632 23.2434 118.037 23.6001 117.538 23.838Z" fill="#E2BAFF"/>
|
||||||
|
<rect x="121.127" y="7.23633" width="2.90154" height="17.2437" fill="#E2BAFF"/>
|
||||||
|
<path d="M126.195 18.4387C126.195 14.6809 128.859 11.9934 132.688 11.9934C136.494 11.9934 139.134 14.6571 139.134 18.4152C139.134 22.2206 136.494 24.8605 132.664 24.8605C129.002 24.8605 126.195 22.3633 126.195 18.4387ZM132.664 22.3633C134.71 22.3633 136.113 20.9124 136.113 18.4152C136.113 15.9891 134.71 14.4671 132.664 14.4671C130.548 14.4671 129.192 16.0604 129.192 18.4152C129.192 20.8411 130.572 22.3633 132.664 22.3633Z" fill="#E2BAFF"/>
|
||||||
|
<path d="M145.86 24.8606C144.456 24.8606 143.339 24.4324 142.482 23.5048C141.674 22.5774 141.27 21.3168 141.27 19.747V12.374H144.171V19.5329C144.171 20.4605 144.385 21.1741 144.837 21.6736C145.265 22.1493 145.931 22.3634 146.811 22.3634C147.382 22.3634 147.881 22.2444 148.334 21.9828C148.785 21.7212 149.118 21.3168 149.356 20.8173C149.618 20.294 149.737 19.6994 149.737 19.081V12.374H152.662V20.3654L154.422 23.4337L151.925 24.8606L150.522 22.4585C150.522 22.4585 149.974 23.1721 149.237 23.7905C148.334 24.5517 147.382 24.8606 145.86 24.8606Z" fill="#E2BAFF"/>
|
||||||
|
<path d="M156.104 15.1328C156.651 14.0624 157.293 13.2775 158.173 12.8259C159.053 12.2788 160.076 11.9696 161.17 11.9696C162.098 11.9696 162.859 12.1599 163.525 12.4929C164.191 12.8259 164.809 13.254 165.309 13.8959V7.23657H168.21V20.3415L169.947 23.4099L167.449 24.837L165.927 22.1968C165.927 22.1968 164.88 23.6712 163.525 24.3375C162.954 24.623 162.05 24.837 161.194 24.837C160.076 24.837 159.053 24.5751 158.173 24.0045C157.317 23.5526 156.651 22.7677 156.104 21.7687C155.604 20.7697 155.391 19.6993 155.391 18.4387C155.391 17.1546 155.604 16.0604 156.104 15.1328ZM158.363 18.4387C158.363 19.2474 158.506 19.8896 158.792 20.437C159.125 21.1027 159.553 21.5073 160.004 21.7925C160.528 22.1017 161.098 22.2682 161.812 22.2682C162.526 22.2682 163.144 22.1017 163.644 21.7925C164.143 21.5073 164.571 21.0789 164.88 20.437C165.166 19.8896 165.309 19.2474 165.309 18.4387C165.309 17.2497 164.999 16.2507 164.333 15.6323C163.763 14.9187 162.883 14.5385 161.836 14.5385C160.766 14.5385 159.933 14.9187 159.339 15.6323C158.673 16.2507 158.363 17.2497 158.363 18.4387Z" fill="#E2BAFF"/>
|
||||||
|
<path d="M13.4814 25.5141L14.9505 24.6659V18.5276L20.234 15.4772V13.785L18.7649 12.9368L13.4462 16.0076L8.20127 12.9794L6.73242 13.8273V15.5198L12.0159 18.5703V24.668L13.4814 25.5141Z" fill="#E2BAFF"/>
|
||||||
|
<path d="M26.9649 7.78377L13.4828 0L0 7.78408V11.1725L13.4824 3.38806L26.9649 11.1721V7.78377Z" fill="#E2BAFF"/>
|
||||||
|
<path d="M26.9646 23.8279L13.4821 31.612L0 23.8279V27.2163L13.4821 35L26.9646 27.2163V23.8279Z" fill="#E2BAFF"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.0 KiB |
@@ -0,0 +1,19 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const setLogoUrl = (url) => {
|
||||||
|
const logoTextSelector = document.querySelector(".kc-logo-text");
|
||||||
|
|
||||||
|
if (!logoTextSelector) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = url;
|
||||||
|
link.target = "_blank";
|
||||||
|
|
||||||
|
const parent = logoTextSelector.parentNode;
|
||||||
|
parent.insertBefore(link, logoTextSelector);
|
||||||
|
link.appendChild(logoTextSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLogoUrl('https://opencloud.eu')
|
||||||
|
});
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
parent=keycloak
|
||||||
|
import=common/keycloak
|
||||||
|
|
||||||
|
styles=css/login.css css/theme.css
|
||||||
|
scripts=js/script.js
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "Running custom LDAP entrypoint script..."
|
||||||
|
|
||||||
|
if [ ! -f /opt/bitnami/openldap/share/openldap.key ]
|
||||||
|
then
|
||||||
|
openssl req -x509 -newkey rsa:4096 -keyout /opt/bitnami/openldap/share/openldap.key -out /opt/bitnami/openldap/share/openldap.crt -sha256 -days 365 -batch -nodes
|
||||||
|
fi
|
||||||
|
# run original docker-entrypoint
|
||||||
|
/opt/bitnami/scripts/openldap/entrypoint.sh "$@"
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
dn: dc=opencloud,dc=eu
|
||||||
|
objectClass: organization
|
||||||
|
objectClass: dcObject
|
||||||
|
dc: opencloud
|
||||||
|
o: openCloud
|
||||||
|
|
||||||
|
dn: ou=users,dc=opencloud,dc=eu
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: users
|
||||||
|
|
||||||
|
dn: cn=admin,dc=opencloud,dc=eu
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
objectClass: person
|
||||||
|
cn: admin
|
||||||
|
sn: admin
|
||||||
|
uid: ldapadmin
|
||||||
|
|
||||||
|
dn: ou=tenants,dc=opencloud,dc=eu
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: tenants
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
dn: uid=admin,ou=users,dc=opencloud,dc=eu
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: person
|
||||||
|
objectClass: top
|
||||||
|
uid: admin
|
||||||
|
givenName: Admin
|
||||||
|
sn: Admin
|
||||||
|
cn: admin
|
||||||
|
displayName: Admin
|
||||||
|
description: An admin for this OpenCloud instance.
|
||||||
|
mail: admin@example.org
|
||||||
|
userPassword:: e1NTSEF9UWhmaFB3dERydTUydURoWFFObDRMbzVIckI3TkI5Nmo==
|
||||||
|
|
||||||
|
dn: cn=administrators,ou=groups,dc=opencloud,dc=eu
|
||||||
|
objectClass: groupOfNames
|
||||||
|
objectClass: top
|
||||||
|
cn: administrators
|
||||||
|
description: OpenCloud Administrators
|
||||||
|
member: uid=admin,ou=users,dc=opencloud,dc=eu
|
||||||
44
devtools/deployments/multi-tenancy/config/opencloud/csp.yaml
Normal file
44
devtools/deployments/multi-tenancy/config/opencloud/csp.yaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
directives:
|
||||||
|
child-src:
|
||||||
|
- '''self'''
|
||||||
|
connect-src:
|
||||||
|
- '''self'''
|
||||||
|
- 'blob:'
|
||||||
|
- 'https://${COMPANION_DOMAIN|companion.opencloud.test}/'
|
||||||
|
- 'wss://${COMPANION_DOMAIN|companion.opencloud.test}/'
|
||||||
|
- 'https://raw.githubusercontent.com/opencloud-eu/awesome-apps/'
|
||||||
|
- 'https://${IDP_DOMAIN|keycloak.opencloud.test}/'
|
||||||
|
default-src:
|
||||||
|
- '''none'''
|
||||||
|
font-src:
|
||||||
|
- '''self'''
|
||||||
|
frame-ancestors:
|
||||||
|
- '''self'''
|
||||||
|
frame-src:
|
||||||
|
- '''self'''
|
||||||
|
- 'blob:'
|
||||||
|
- 'https://embed.diagrams.net/'
|
||||||
|
# In contrary to bash and docker the default is given after the | character
|
||||||
|
- 'https://${COLLABORA_DOMAIN|collabora.opencloud.test}/'
|
||||||
|
# This is needed for the external-sites web extension when embedding sites
|
||||||
|
- 'https://docs.opencloud.eu'
|
||||||
|
img-src:
|
||||||
|
- '''self'''
|
||||||
|
- 'data:'
|
||||||
|
- 'blob:'
|
||||||
|
- 'https://raw.githubusercontent.com/opencloud-eu/awesome-apps/'
|
||||||
|
# In contrary to bash and docker the default is given after the | character
|
||||||
|
- 'https://${COLLABORA_DOMAIN|collabora.opencloud.test}/'
|
||||||
|
manifest-src:
|
||||||
|
- '''self'''
|
||||||
|
media-src:
|
||||||
|
- '''self'''
|
||||||
|
object-src:
|
||||||
|
- '''self'''
|
||||||
|
- 'blob:'
|
||||||
|
script-src:
|
||||||
|
- '''self'''
|
||||||
|
- '''unsafe-inline'''
|
||||||
|
style-src:
|
||||||
|
- '''self'''
|
||||||
|
- '''unsafe-inline'''
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# This adds four additional routes to the proxy. Forwarding
|
||||||
|
# request on '/carddav/', '/caldav/' and the respective '/.well-knwown'
|
||||||
|
# endpoints to the radicale container and setting the required headers.
|
||||||
|
additional_policies:
|
||||||
|
- name: default
|
||||||
|
routes:
|
||||||
|
- endpoint: /caldav/
|
||||||
|
backend: http://radicale:5232
|
||||||
|
remote_user_header: X-Remote-User
|
||||||
|
skip_x_access_token: true
|
||||||
|
additional_headers:
|
||||||
|
- X-Script-Name: /caldav
|
||||||
|
- endpoint: /.well-known/caldav
|
||||||
|
backend: http://radicale:5232
|
||||||
|
remote_user_header: X-Remote-User
|
||||||
|
skip_x_access_token: true
|
||||||
|
additional_headers:
|
||||||
|
- X-Script-Name: /caldav
|
||||||
|
- endpoint: /carddav/
|
||||||
|
backend: http://radicale:5232
|
||||||
|
remote_user_header: X-Remote-User
|
||||||
|
skip_x_access_token: true
|
||||||
|
additional_headers:
|
||||||
|
- X-Script-Name: /carddav
|
||||||
|
- endpoint: /.well-known/carddav
|
||||||
|
backend: http://radicale:5232
|
||||||
|
remote_user_header: X-Remote-User
|
||||||
|
skip_x_access_token: true
|
||||||
|
additional_headers:
|
||||||
|
- X-Script-Name: /carddav
|
||||||
|
# To enable the radicale web UI add this rule.
|
||||||
|
# "unprotected" is True because the Web UI itself ask for
|
||||||
|
# the password.
|
||||||
|
# Also set "type" to "internal" in the config/radicale/config
|
||||||
|
# - endpoint: /caldav/.web/
|
||||||
|
# backend: http://radicale:5232/
|
||||||
|
# unprotected: true
|
||||||
|
# skip_x_access_token: true
|
||||||
|
# additional_headers:
|
||||||
|
# - X-Script-Name: /caldav
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
set -e
|
||||||
|
|
||||||
|
printenv
|
||||||
|
# Function to add arguments to the command
|
||||||
|
add_arg() {
|
||||||
|
TRAEFIK_CMD="$TRAEFIK_CMD $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize the base command
|
||||||
|
TRAEFIK_CMD="traefik"
|
||||||
|
|
||||||
|
# Base Traefik arguments (from your existing configuration)
|
||||||
|
add_arg "--log.level=${TRAEFIK_LOG_LEVEL:-ERROR}"
|
||||||
|
# enable dashboard
|
||||||
|
add_arg "--api.dashboard=true"
|
||||||
|
# define entrypoints
|
||||||
|
add_arg "--entryPoints.http.address=:80"
|
||||||
|
add_arg "--entryPoints.http.http.redirections.entryPoint.to=https"
|
||||||
|
add_arg "--entryPoints.http.http.redirections.entryPoint.scheme=https"
|
||||||
|
add_arg "--entryPoints.https.address=:443"
|
||||||
|
# change default timeouts for long-running requests
|
||||||
|
# this is needed for webdav clients that do not support the TUS protocol
|
||||||
|
add_arg "--entryPoints.https.transport.respondingTimeouts.readTimeout=12h"
|
||||||
|
add_arg "--entryPoints.https.transport.respondingTimeouts.writeTimeout=12h"
|
||||||
|
add_arg "--entryPoints.https.transport.respondingTimeouts.idleTimeout=3m"
|
||||||
|
# docker provider (get configuration from container labels)
|
||||||
|
add_arg "--providers.docker.endpoint=unix:///var/run/docker.sock"
|
||||||
|
add_arg "--providers.docker.exposedByDefault=false"
|
||||||
|
# access log
|
||||||
|
add_arg "--accessLog=${TRAEFIK_ACCESS_LOG:-false}"
|
||||||
|
add_arg "--accessLog.format=json"
|
||||||
|
add_arg "--accessLog.fields.headers.names.X-Request-Id=keep"
|
||||||
|
|
||||||
|
# Add Let's Encrypt configuration if enabled
|
||||||
|
if [ "${TRAEFIK_SERVICES_TLS_CONFIG}" = "tls.certresolver=letsencrypt" ]; then
|
||||||
|
echo "Configuring Traefik with Let's Encrypt..."
|
||||||
|
add_arg "--certificatesResolvers.letsencrypt.acme.email=${TRAEFIK_ACME_MAIL:-example@example.org}"
|
||||||
|
add_arg "--certificatesResolvers.letsencrypt.acme.storage=/certs/acme.json"
|
||||||
|
add_arg "--certificatesResolvers.letsencrypt.acme.httpChallenge.entryPoint=http"
|
||||||
|
add_arg "--certificatesResolvers.letsencrypt.acme.caserver=${TRAEFIK_ACME_CASERVER:-https://acme-v02.api.letsencrypt.org/directory}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add local certificate configuration if enabled
|
||||||
|
if [ "${TRAEFIK_SERVICES_TLS_CONFIG}" = "tls=true" ]; then
|
||||||
|
echo "Configuring Traefik with local certificates..."
|
||||||
|
add_arg "--providers.file.directory=/etc/traefik/dynamic"
|
||||||
|
add_arg "--providers.file.watch=true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Warning if neither certificate method is enabled
|
||||||
|
if [ "${TRAEFIK_SERVICES_TLS_CONFIG}" != "tls=true" ] && [ "${TRAEFIK_SERVICES_TLS_CONFIG}" != "tls.certresolver=letsencrypt" ]; then
|
||||||
|
echo "WARNING: Neither Let's Encrypt nor local certificates are enabled."
|
||||||
|
echo "HTTPS will not work properly without certificate configuration."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add any custom arguments from environment variable
|
||||||
|
if [ -n "${TRAEFIK_CUSTOM_ARGS}" ]; then
|
||||||
|
echo "Adding custom Traefik arguments: ${TRAEFIK_CUSTOM_ARGS}"
|
||||||
|
TRAEFIK_CMD="$TRAEFIK_CMD $TRAEFIK_CUSTOM_ARGS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add any additional arguments passed to the script
|
||||||
|
for arg in "$@"; do
|
||||||
|
add_arg "$arg"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Print the final command for debugging
|
||||||
|
echo "Starting Traefik with command:"
|
||||||
|
echo "$TRAEFIK_CMD"
|
||||||
|
|
||||||
|
# Execute Traefik
|
||||||
|
exec $TRAEFIK_CMD
|
||||||
119
devtools/deployments/multi-tenancy/docker-compose.yml
Normal file
119
devtools/deployments/multi-tenancy/docker-compose.yml
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
# OpenCloud instance configured for multi-tenancy using keycloak as identity provider
|
||||||
|
# The graph service is setup to consume users via the CS3 API.
|
||||||
|
opencloud:
|
||||||
|
image: ${OC_DOCKER_IMAGE:-opencloudeu/opencloud-rolling}:${OC_DOCKER_TAG:-latest}
|
||||||
|
# changelog: https://github.com/opencloud-eu/opencloud/tree/main/changelog
|
||||||
|
# release notes: https://docs.opencloud.eu/opencloud_release_notes.html
|
||||||
|
networks:
|
||||||
|
opencloud-net:
|
||||||
|
entrypoint:
|
||||||
|
- /bin/sh
|
||||||
|
# run opencloud init to initialize a configuration file with random secrets
|
||||||
|
# it will fail on subsequent runs, because the config file already exists
|
||||||
|
# therefore we ignore the error and then start the opencloud server
|
||||||
|
command: ["-c", "opencloud init || true; opencloud server"]
|
||||||
|
environment:
|
||||||
|
OC_MULTI_TENANT_ENABLED: "true"
|
||||||
|
# enable services that are not started automatically
|
||||||
|
OC_URL: https://${OC_DOMAIN:-cloud.opencloud.test}
|
||||||
|
OC_LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||||
|
OC_LOG_COLOR: "${LOG_PRETTY:-false}"
|
||||||
|
OC_LOG_PRETTY: "${LOG_PRETTY:-false}"
|
||||||
|
OC_EXCLUDE_RUN_SERVICES: idm,idp
|
||||||
|
PROXY_ROLE_ASSIGNMENT_DRIVER: "oidc"
|
||||||
|
OC_OIDC_ISSUER: https://${KEYCLOAK_DOMAIN:-keycloak.opencloud.test}/realms/openCloud
|
||||||
|
PROXY_OIDC_REWRITE_WELLKNOWN: "true"
|
||||||
|
WEB_OIDC_CLIENT_ID: ${OC_OIDC_CLIENT_ID:-web}
|
||||||
|
PROXY_USER_OIDC_CLAIM: "uuid"
|
||||||
|
PROXY_USER_CS3_CLAIM: "userid"
|
||||||
|
WEB_OPTION_ACCOUNT_EDIT_LINK_HREF: "https://${KEYCLOAK_DOMAIN:-keycloak.opencloud.test}/realms/openCloud/account"
|
||||||
|
# admin and demo accounts must be created in Keycloak
|
||||||
|
OC_ADMIN_USER_ID: ""
|
||||||
|
SETTINGS_SETUP_DEFAULT_ASSIGNMENTS: "false"
|
||||||
|
GRAPH_ASSIGN_DEFAULT_USER_ROLE: "false"
|
||||||
|
GRAPH_USERNAME_MATCH: "none"
|
||||||
|
GROUPS_DRIVER: "null"
|
||||||
|
# This is needed to set the correct CSP rules for OpenCloud
|
||||||
|
IDP_DOMAIN: ${KEYCLOAK_DOMAIN:-keycloak.opencloud.test}
|
||||||
|
# do not use SSL between the reverse proxy and OpenCloud
|
||||||
|
PROXY_TLS: "false"
|
||||||
|
# INSECURE: needed if OpenCloud / reverse proxy is using self generated certificates
|
||||||
|
OC_INSECURE: "${INSECURE:-false}"
|
||||||
|
# basic auth (not recommended, but needed for eg. WebDav clients that do not support OpenID Connect)
|
||||||
|
PROXY_ENABLE_BASIC_AUTH: "false"
|
||||||
|
GRAPH_IDENTITY_BACKEND: "cs3"
|
||||||
|
PROXY_CSP_CONFIG_FILE_LOCATION: /etc/opencloud/csp.yaml
|
||||||
|
OC_LDAP_URI: ldaps://ldap-server:1636
|
||||||
|
OC_LDAP_INSECURE: "true"
|
||||||
|
OC_LDAP_BIND_DN: "cn=admin,dc=opencloud,dc=eu"
|
||||||
|
OC_LDAP_BIND_PASSWORD: ${LDAP_BIND_PASSWORD:-admin}
|
||||||
|
OC_LDAP_USER_BASE_DN: "ou=users,dc=opencloud,dc=eu"
|
||||||
|
OC_LDAP_USER_SCHEMA_TENANT_ID: "openCloudMemberOfSchool"
|
||||||
|
PROXY_LOG_LEVEL: "debug"
|
||||||
|
volumes:
|
||||||
|
- ./config/opencloud/csp.yaml:/etc/opencloud/csp.yaml
|
||||||
|
# configure the .env file to use own paths instead of docker internal volumes
|
||||||
|
- ${OC_CONFIG_DIR:-opencloud-config}:/etc/opencloud
|
||||||
|
- ${OC_DATA_DIR:-opencloud-data}:/var/lib/opencloud
|
||||||
|
logging:
|
||||||
|
driver: ${LOG_DRIVER:-local}
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.opencloud.entrypoints=https"
|
||||||
|
- "traefik.http.routers.opencloud.rule=Host(`${OC_DOMAIN:-cloud.opencloud.test}`)"
|
||||||
|
- "traefik.http.routers.opencloud.service=opencloud"
|
||||||
|
- "traefik.http.services.opencloud.loadbalancer.server.port=9200"
|
||||||
|
- "traefik.http.routers.opencloud.${TRAEFIK_SERVICES_TLS_CONFIG}"
|
||||||
|
# Stand-alone instance of the 'graph' service to serve the provisioning API
|
||||||
|
provsioning:
|
||||||
|
image: ${OC_DOCKER_IMAGE:-opencloudeu/opencloud-rolling}:${OC_DOCKER_TAG:-latest}
|
||||||
|
networks:
|
||||||
|
opencloud-net:
|
||||||
|
entrypoint:
|
||||||
|
- /bin/sh
|
||||||
|
# run opencloud init to initialize a configuration file with random secrets
|
||||||
|
# it will fail on subsequent runs, because the config file already exists
|
||||||
|
# therefore we ignore the error and then start the opencloud server
|
||||||
|
command: ["-c", "opencloud init || true; opencloud graph server"]
|
||||||
|
environment:
|
||||||
|
OC_LOG_LEVEL: "debug"
|
||||||
|
OC_LOG_COLOR: "${LOG_PRETTY:-false}"
|
||||||
|
OC_LOG_PRETTY: "${LOG_PRETTY:-false}"
|
||||||
|
# This just runs the standalone graph service we don't need access to the registry
|
||||||
|
MICRO_REGISTRY: "memory"
|
||||||
|
# INSECURE: needed if OpenCloud / reverse proxy is using self generated certificates
|
||||||
|
OC_INSECURE: "${INSECURE:-false}"
|
||||||
|
GRAPH_HTTP_ADDR: "0.0.0.0:9120"
|
||||||
|
GRAPH_HTTP_API_TOKEN: "${PROVISIONING_API_TOKEN:-changeme}"
|
||||||
|
# disable listening for events
|
||||||
|
GRAPH_EVENTS_ENDPOINT: ""
|
||||||
|
GRAPH_STORE_NODES: ""
|
||||||
|
GRAPH_ASSIGN_DEFAULT_USER_ROLE: "false"
|
||||||
|
GRAPH_USERNAME_MATCH: "none"
|
||||||
|
GRAPH_LDAP_EDUCATION_RESOURCES_ENABLED: "true"
|
||||||
|
GRAPH_LDAP_SCHOOL_BASE_DN: "ou=tenants,dc=opencloud,dc=eu"
|
||||||
|
OC_LDAP_URI: ldaps://ldap-server:1636
|
||||||
|
OC_LDAP_INSECURE: "true"
|
||||||
|
OC_LDAP_BIND_DN: "cn=admin,dc=opencloud,dc=eu"
|
||||||
|
OC_LDAP_BIND_PASSWORD: ${LDAP_BIND_PASSWORD:-admin}
|
||||||
|
OC_LDAP_USER_BASE_DN: "ou=users,dc=opencloud,dc=eu"
|
||||||
|
OC_LDAP_USER_FILTER: "(objectclass=inetOrgPerson)"
|
||||||
|
volumes:
|
||||||
|
# configure the .env file to use own paths instead of docker internal volumes
|
||||||
|
- ${PROVISIONING_CONFIG_DIR:-provisioning-config}:/etc/opencloud
|
||||||
|
logging:
|
||||||
|
driver: ${LOG_DRIVER:-local}
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "9120:9120"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
opencloud-config:
|
||||||
|
opencloud-data:
|
||||||
|
provisioning-config:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
opencloud-net:
|
||||||
169
devtools/deployments/multi-tenancy/initialize_users.go
Normal file
169
devtools/deployments/multi-tenancy/initialize_users.go
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Nerzal/gocloak/v13"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
provisioningAPIURL = "http://localhost:9120/graph"
|
||||||
|
provisioningAuthToken = "changeme"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tenantWithUsers struct {
|
||||||
|
tenant libregraph.EducationSchool
|
||||||
|
users []libregraph.EducationUser
|
||||||
|
}
|
||||||
|
|
||||||
|
var demoTenants = []tenantWithUsers{
|
||||||
|
{
|
||||||
|
tenant: libregraph.EducationSchool{
|
||||||
|
DisplayName: libregraph.PtrString("Famous Coders"),
|
||||||
|
},
|
||||||
|
users: []libregraph.EducationUser{
|
||||||
|
{
|
||||||
|
DisplayName: libregraph.PtrString("Dennis Ritchie"),
|
||||||
|
OnPremisesSamAccountName: libregraph.PtrString("dennis"),
|
||||||
|
Mail: libregraph.PtrString("dennis@example.org"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DisplayName: libregraph.PtrString("Grace Hopper"),
|
||||||
|
OnPremisesSamAccountName: libregraph.PtrString("grace"),
|
||||||
|
Mail: libregraph.PtrString("grace@example.org"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tenant: libregraph.EducationSchool{
|
||||||
|
DisplayName: libregraph.PtrString("Scientists"),
|
||||||
|
},
|
||||||
|
users: []libregraph.EducationUser{
|
||||||
|
{
|
||||||
|
DisplayName: libregraph.PtrString("Albert Einstein"),
|
||||||
|
OnPremisesSamAccountName: libregraph.PtrString("einstein"),
|
||||||
|
Mail: libregraph.PtrString("einstein@example.org"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DisplayName: libregraph.PtrString("Marie Curie"),
|
||||||
|
OnPremisesSamAccountName: libregraph.PtrString("marie"),
|
||||||
|
Mail: libregraph.PtrString("marie@example.org"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
lgconf := libregraph.NewConfiguration()
|
||||||
|
lgconf.Servers = libregraph.ServerConfigurations{
|
||||||
|
{
|
||||||
|
URL: provisioningAPIURL,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
lgconf.DefaultHeader = map[string]string{"Authorization": "Bearer " + provisioningAuthToken}
|
||||||
|
lgclient := libregraph.NewAPIClient(lgconf)
|
||||||
|
|
||||||
|
for _, tenant := range demoTenants {
|
||||||
|
tenantid, err := createTenant(lgclient, tenant.tenant)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to create tenant: %s\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, user := range tenant.users {
|
||||||
|
userid1, err := createUser(lgclient, user)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to create user: %s\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = lgclient.EducationSchoolApi.AddUserToSchool(context.TODO(), tenantid).EducationUserReference(libregraph.EducationUserReference{
|
||||||
|
OdataId: libregraph.PtrString(fmt.Sprintf("%s/education/users/%s", provisioningAPIURL, userid1)),
|
||||||
|
}).Execute()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to add user to tenant: %s\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resetAllUserPasswords()
|
||||||
|
setUserRoles()
|
||||||
|
}
|
||||||
|
|
||||||
|
func createUser(client *libregraph.APIClient, user libregraph.EducationUser) (string, error) {
|
||||||
|
newUser, _, err := client.EducationUserApi.CreateEducationUser(context.TODO()).EducationUser(user).Execute()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to create user: %s\n", err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
fmt.Printf("Created user: %s with id %s\n", newUser.GetDisplayName(), newUser.GetId())
|
||||||
|
return newUser.GetId(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTenant(client *libregraph.APIClient, tenant libregraph.EducationSchool) (string, error) {
|
||||||
|
newTenant, _, err := client.EducationSchoolApi.CreateSchool(context.TODO()).EducationSchool(tenant).Execute()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to create tenant: %s\n", err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
fmt.Printf("Created tenant: %s with id %s\n", newTenant.GetDisplayName(), newTenant.GetId())
|
||||||
|
return newTenant.GetId(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUserRoles() {
|
||||||
|
tls := tls.Config{InsecureSkipVerify: true}
|
||||||
|
restyClient := resty.New().SetTLSClientConfig(&tls)
|
||||||
|
client := gocloak.NewClient("https://keycloak.opencloud.test")
|
||||||
|
client.SetRestyClient(restyClient)
|
||||||
|
ctx := context.Background()
|
||||||
|
token, err := client.LoginAdmin(ctx, "kcadmin", "admin", "master")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to login: %s\n", err)
|
||||||
|
panic("Something wrong with the credentials or url")
|
||||||
|
}
|
||||||
|
|
||||||
|
role, _ := client.GetRealmRole(ctx, token.AccessToken, "openCloud", "opencloudUser")
|
||||||
|
users, err := client.GetUsers(ctx, token.AccessToken, "openCloud", gocloak.GetUsersParams{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", err)
|
||||||
|
panic("Oh no!, failed to list users :(")
|
||||||
|
}
|
||||||
|
for _, user := range users {
|
||||||
|
err := client.AddRealmRoleToUser(ctx, token.AccessToken, "openCloud", *user.ID, []gocloak.Role{
|
||||||
|
*role,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to assign role to user %s: %s\n", *user.Username, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetAllUserPasswords() {
|
||||||
|
tls := tls.Config{InsecureSkipVerify: true}
|
||||||
|
restyClient := resty.New().SetTLSClientConfig(&tls)
|
||||||
|
client := gocloak.NewClient("https://keycloak.opencloud.test")
|
||||||
|
client.SetRestyClient(restyClient)
|
||||||
|
ctx := context.Background()
|
||||||
|
token, err := client.LoginAdmin(ctx, "kcadmin", "admin", "master")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to login: %s\n", err)
|
||||||
|
panic("Something wrong with the credentials or url")
|
||||||
|
}
|
||||||
|
|
||||||
|
users, err := client.GetUsers(ctx, token.AccessToken, "openCloud", gocloak.GetUsersParams{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", err)
|
||||||
|
panic("Oh no!, failed to list users :(")
|
||||||
|
}
|
||||||
|
for _, user := range users {
|
||||||
|
fmt.Printf("Setting password for user: %s\n", *user.Username)
|
||||||
|
err = client.SetPassword(ctx, token.AccessToken, *user.ID, "openCloud", "demo", false)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to set password for user %s: %s\n", *user.Username, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
55
devtools/deployments/multi-tenancy/keycloak.yml
Normal file
55
devtools/deployments/multi-tenancy/keycloak.yml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
opencloud:
|
||||||
|
environment:
|
||||||
|
postgres:
|
||||||
|
image: postgres:alpine
|
||||||
|
networks:
|
||||||
|
opencloud-net:
|
||||||
|
volumes:
|
||||||
|
- keycloak_postgres_data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: keycloak
|
||||||
|
POSTGRES_USER: ${KC_DB_USERNAME:-keycloak}
|
||||||
|
POSTGRES_PASSWORD: ${KC_DB_PASSWORD:-keycloak}
|
||||||
|
logging:
|
||||||
|
driver: ${LOG_DRIVER:-local}
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
keycloak:
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.keycloak.entrypoints=https"
|
||||||
|
- "traefik.http.routers.keycloak.rule=Host(`${KEYCLOAK_DOMAIN:-keycloak.opencloud.test}`)"
|
||||||
|
- "traefik.http.routers.keycloak.${TRAEFIK_SERVICES_TLS_CONFIG}"
|
||||||
|
- "traefik.http.routers.keycloak.service=keycloak"
|
||||||
|
- "traefik.http.services.keycloak.loadbalancer.server.port=8080"
|
||||||
|
image: quay.io/keycloak/keycloak:26.4
|
||||||
|
networks:
|
||||||
|
opencloud-net:
|
||||||
|
command: [ "start", "--spi-connections-http-client-default-disable-trust-manager=${INSECURE:-false}", "--import-realm" ]
|
||||||
|
entrypoint: [ "/bin/sh", "/opt/keycloak/bin/docker-entrypoint-override.sh" ]
|
||||||
|
volumes:
|
||||||
|
- "./config/keycloak/docker-entrypoint-override.sh:/opt/keycloak/bin/docker-entrypoint-override.sh"
|
||||||
|
- "./config/keycloak/openCloud-realm.dist.json:/opt/keycloak/data/import-dist/openCloud-realm.json"
|
||||||
|
- "./config/keycloak/themes/opencloud:/opt/keycloak/themes/opencloud"
|
||||||
|
environment:
|
||||||
|
OC_DOMAIN: ${OC_DOMAIN:-cloud.opencloud.test}
|
||||||
|
KC_HOSTNAME: ${KEYCLOAK_DOMAIN:-keycloak.opencloud.test}
|
||||||
|
KC_DB: postgres
|
||||||
|
KC_DB_URL: "jdbc:postgresql://postgres:5432/keycloak"
|
||||||
|
KC_DB_USERNAME: ${KC_DB_USERNAME:-keycloak}
|
||||||
|
KC_DB_PASSWORD: ${KC_DB_PASSWORD:-keycloak}
|
||||||
|
KC_FEATURES: impersonation
|
||||||
|
KC_PROXY_HEADERS: xforwarded
|
||||||
|
KC_HTTP_ENABLED: true
|
||||||
|
KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN:-kcadmin}
|
||||||
|
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin}
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
logging:
|
||||||
|
driver: ${LOG_DRIVER:-local}
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
keycloak_postgres_data:
|
||||||
32
devtools/deployments/multi-tenancy/ldap-server.yml
Normal file
32
devtools/deployments/multi-tenancy/ldap-server.yml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
ldap-server:
|
||||||
|
image: bitnamilegacy/openldap:2.6
|
||||||
|
networks:
|
||||||
|
opencloud-net:
|
||||||
|
entrypoint: [ "/bin/sh", "/opt/bitnami/scripts/openldap/docker-entrypoint-override.sh", "/opt/bitnami/scripts/openldap/run.sh" ]
|
||||||
|
environment:
|
||||||
|
BITNAMI_DEBUG: true
|
||||||
|
LDAP_TLS_VERIFY_CLIENT: never
|
||||||
|
LDAP_ENABLE_TLS: "yes"
|
||||||
|
LDAP_TLS_CA_FILE: /opt/bitnami/openldap/share/openldap.crt
|
||||||
|
LDAP_TLS_CERT_FILE: /opt/bitnami/openldap/share/openldap.crt
|
||||||
|
LDAP_TLS_KEY_FILE: /opt/bitnami/openldap/share/openldap.key
|
||||||
|
LDAP_ROOT: "dc=opencloud,dc=eu"
|
||||||
|
LDAP_ADMIN_PASSWORD: ${LDAP_BIND_PASSWORD:-admin}
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:389:1389"
|
||||||
|
- "127.0.0.1:636:1636"
|
||||||
|
volumes:
|
||||||
|
# Only use the base ldif file to create the base structure
|
||||||
|
- ./config/ldap/ldif/10_base.ldif:/ldifs/10_base.ldif
|
||||||
|
# Use the custom schema from opencloud because we are in full control of the ldap server
|
||||||
|
- ../shared/config/ldap/schemas/10_opencloud_schema.ldif:/schemas/10_opencloud_schema.ldif
|
||||||
|
- ../shared/config/ldap/schemas/20_opencloud_education_schema.ldif:/schemas/20_opencloud_education_schema.ldif
|
||||||
|
- ./config/ldap/docker-entrypoint-override.sh:/opt/bitnami/scripts/openldap/docker-entrypoint-override.sh
|
||||||
|
- ${LDAP_CERTS_DIR:-ldap-certs}:/opt/bitnami/openldap/share
|
||||||
|
- ${LDAP_DATA_DIR:-ldap-data}:/bitnami/openldap
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
ldap-certs:
|
||||||
|
ldap-data:
|
||||||
24
devtools/deployments/multi-tenancy/testing/ldap-manager.yml
Normal file
24
devtools/deployments/multi-tenancy/testing/ldap-manager.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
# This file can be used to be added to the opencloud_full example
|
||||||
|
# to browse the LDAP server with a web interface.
|
||||||
|
# This is not a production ready setup.
|
||||||
|
services:
|
||||||
|
ldap-manager:
|
||||||
|
image: phpldapadmin/phpldapadmin:latest
|
||||||
|
networks:
|
||||||
|
opencloud-net:
|
||||||
|
environment:
|
||||||
|
LDAP_HOST: ldap-server
|
||||||
|
LDAP_PORT: 1389
|
||||||
|
LDAP_LOGIN_OBJECTCLASS: "inetOrgPerson"
|
||||||
|
APP_URL: "https://${LDAP_MANAGER_DOMAIN:-ldap.opencloud.test}"
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.ldap-manager.entrypoints=https"
|
||||||
|
- "traefik.http.routers.ldap-manager.rule=Host(`${LDAP_MANAGER_DOMAIN:-ldap.opencloud.test}`)"
|
||||||
|
- "traefik.http.routers.ldap-manager.${TRAEFIK_SERVICES_TLS_CONFIG}"
|
||||||
|
- "traefik.http.routers.ldap-manager.service=ldap-manager"
|
||||||
|
- "traefik.http.services.ldap-manager.loadbalancer.server.port=8080"
|
||||||
|
logging:
|
||||||
|
driver: ${LOG_DRIVER:-local}
|
||||||
|
restart: always
|
||||||
45
devtools/deployments/multi-tenancy/traefik.yml
Normal file
45
devtools/deployments/multi-tenancy/traefik.yml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
opencloud:
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.opencloud.entrypoints=https"
|
||||||
|
- "traefik.http.routers.opencloud.rule=Host(`${OC_DOMAIN:-cloud.opencloud.test}`)"
|
||||||
|
- "traefik.http.routers.opencloud.service=opencloud"
|
||||||
|
- "traefik.http.services.opencloud.loadbalancer.server.port=9200"
|
||||||
|
- "traefik.http.routers.opencloud.${TRAEFIK_SERVICES_TLS_CONFIG}"
|
||||||
|
traefik:
|
||||||
|
image: traefik:v3.3.1
|
||||||
|
# release notes: https://github.com/traefik/traefik/releases
|
||||||
|
networks:
|
||||||
|
opencloud-net:
|
||||||
|
aliases:
|
||||||
|
- ${OC_DOMAIN:-cloud.opencloud.test}
|
||||||
|
- ${KEYCLOAK_DOMAIN:-keycloak.opencloud.test}
|
||||||
|
entrypoint: [ "/bin/sh", "/opt/traefik/bin/docker-entrypoint-override.sh"]
|
||||||
|
environment:
|
||||||
|
- "TRAEFIK_SERVICES_TLS_CONFIG=${TRAEFIK_SERVICES_TLS_CONFIG:-tls.certresolver=letsencrypt}"
|
||||||
|
- "TRAEFIK_ACME_MAIL=${TRAEFIK_ACME_MAIL:-example@example.org}"
|
||||||
|
- "TRAEFIK_ACME_CASERVER=${TRAEFIK_ACME_CASERVER:-https://acme-v02.api.letsencrypt.org/directory}"
|
||||||
|
- "TRAEFIK_LOG_LEVEL=${TRAEFIK_LOG_LEVEL:-ERROR}"
|
||||||
|
- "TRAEFIK_ACCESS_LOG=${TRAEFIK_ACCESS_LOG:-false}"
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- "${DOCKER_SOCKET_PATH:-/var/run/docker.sock}:/var/run/docker.sock:ro"
|
||||||
|
- "./config/traefik/docker-entrypoint-override.sh:/opt/traefik/bin/docker-entrypoint-override.sh"
|
||||||
|
- "${TRAEFIK_CERTS_DIR:-./certs}:/certs"
|
||||||
|
- "./config/traefik/dynamic:/etc/traefik/dynamic"
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=${TRAEFIK_DASHBOARD:-false}"
|
||||||
|
# defaults to admin:admin
|
||||||
|
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}"
|
||||||
|
- "traefik.http.routers.traefik.entrypoints=https"
|
||||||
|
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.opencloud.test}`)"
|
||||||
|
- "traefik.http.routers.traefik.middlewares=traefik-auth"
|
||||||
|
- "traefik.http.routers.traefik.${TRAEFIK_SERVICES_TLS_CONFIG}"
|
||||||
|
- "traefik.http.routers.traefik.service=api@internal"
|
||||||
|
logging:
|
||||||
|
driver: ${LOG_DRIVER:-local}
|
||||||
|
restart: always
|
||||||
@@ -305,8 +305,15 @@ KEYCLOAK_ADMIN_PASSWORD=
|
|||||||
# Leaving it default stores data in docker internal volumes.
|
# Leaving it default stores data in docker internal volumes.
|
||||||
#RADICALE_DATA_DIR=/your/local/radicale/data
|
#RADICALE_DATA_DIR=/your/local/radicale/data
|
||||||
|
|
||||||
|
### Stalwart Settings ###
|
||||||
|
# Note: the leading colon is required to enable the service.
|
||||||
|
#STALWART=:stalwart.yml
|
||||||
|
# Domain of Stalwart
|
||||||
|
# Defaults to "stalwart.opencloud.test"
|
||||||
|
STALWART_DOMAIN=
|
||||||
|
|
||||||
## IMPORTANT ##
|
## IMPORTANT ##
|
||||||
# This MUST be the last line as it assembles the supplemental compose files to be used.
|
# This MUST be the last line as it assembles the supplemental compose files to be used.
|
||||||
# ALL supplemental configs must be added here, whether commented or not.
|
# ALL supplemental configs must be added here, whether commented or not.
|
||||||
# Each var must either be empty or contain :path/file.yml
|
# Each var must either be empty or contain :path/file.yml
|
||||||
COMPOSE_FILE=docker-compose.yml${OPENCLOUD:-}${TIKA:-}${DECOMPOSEDS3:-}${DECOMPOSEDS3_MINIO:-}${DECOMPOSED:-}${COLLABORA:-}${MONITORING:-}${IMPORTER:-}${CLAMAV:-}${INBUCKET:-}${EXTENSIONS:-}${UNZIP:-}${DRAWIO:-}${JSONVIEWER:-}${PROGRESSBARS:-}${EXTERNALSITES:-}${KEYCLOAK:-}${LDAP:-}${KEYCLOAK_AUTOPROVISIONING:-}${LDAP_MANAGER:-}${RADICALE:-}
|
COMPOSE_FILE=docker-compose.yml${OPENCLOUD:-}${TIKA:-}${DECOMPOSEDS3:-}${DECOMPOSEDS3_MINIO:-}${DECOMPOSED:-}${COLLABORA:-}${MONITORING:-}${IMPORTER:-}${CLAMAV:-}${INBUCKET:-}${EXTENSIONS:-}${UNZIP:-}${DRAWIO:-}${JSONVIEWER:-}${PROGRESSBARS:-}${EXTERNALSITES:-}${KEYCLOAK:-}${LDAP:-}${KEYCLOAK_AUTOPROVISIONING:-}${LDAP_MANAGER:-}${RADICALE:-}${STALWART:-}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"clientId": "groupware",
|
||||||
|
"name": "OpenCloud Groupware",
|
||||||
|
"description": "Used for authenticating automated HTTP clients of the OpenCloud Groupware API",
|
||||||
|
"rootUrl": "",
|
||||||
|
"adminUrl": "",
|
||||||
|
"baseUrl": "",
|
||||||
|
"surrogateAuthRequired": false,
|
||||||
|
"enabled": true,
|
||||||
|
"alwaysDisplayInConsole": false,
|
||||||
|
"clientAuthenticatorType": "client-secret",
|
||||||
|
"redirectUris": [
|
||||||
|
"/*"
|
||||||
|
],
|
||||||
|
"webOrigins": [
|
||||||
|
"/*"
|
||||||
|
],
|
||||||
|
"notBefore": 0,
|
||||||
|
"bearerOnly": false,
|
||||||
|
"consentRequired": false,
|
||||||
|
"standardFlowEnabled": true,
|
||||||
|
"implicitFlowEnabled": false,
|
||||||
|
"directAccessGrantsEnabled": true,
|
||||||
|
"serviceAccountsEnabled": false,
|
||||||
|
"publicClient": true,
|
||||||
|
"frontchannelLogout": true,
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"attributes": {
|
||||||
|
"oidc.ciba.grant.enabled": "false",
|
||||||
|
"backchannel.logout.session.required": "true",
|
||||||
|
"oauth2.device.authorization.grant.enabled": "false",
|
||||||
|
"backchannel.logout.revoke.offline.tokens": "false"
|
||||||
|
},
|
||||||
|
"authenticationFlowBindingOverrides": {},
|
||||||
|
"fullScopeAllowed": true,
|
||||||
|
"nodeReRegistrationTimeout": -1,
|
||||||
|
"defaultClientScopes": [
|
||||||
|
"web-origins",
|
||||||
|
"acr",
|
||||||
|
"profile",
|
||||||
|
"roles",
|
||||||
|
"groups",
|
||||||
|
"OpenCloudUnique_ID",
|
||||||
|
"basic",
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"optionalClientScopes": [
|
||||||
|
"address",
|
||||||
|
"phone",
|
||||||
|
"offline_access",
|
||||||
|
"microprofile-jwt"
|
||||||
|
],
|
||||||
|
"access": {
|
||||||
|
"view": true,
|
||||||
|
"configure": true,
|
||||||
|
"manage": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
dn: ou=policies,dc=opencloud,dc=eu
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
objectClass: top
|
||||||
|
ou: policies
|
||||||
|
|
||||||
|
dn: cn=default,ou=policies,dc=opencloud,dc=eu
|
||||||
|
cn: default
|
||||||
|
objectClass: pwdPolicy
|
||||||
|
objectClass: person
|
||||||
|
objectClass: top
|
||||||
|
pwdAllowUserChange: TRUE
|
||||||
|
pwdAttribute: userPassword
|
||||||
|
pwdCheckQuality: 0
|
||||||
|
pwdExpireWarning: 600
|
||||||
|
pwdFailureCountInterval: 30
|
||||||
|
pwdGraceAuthNLimit: 5
|
||||||
|
pwdInHistory: 5
|
||||||
|
pwdLockout: FALSE
|
||||||
|
pwdLockoutDuration: 0
|
||||||
|
pwdMaxAge: 0
|
||||||
|
pwdMaxFailure: 5
|
||||||
|
pwdMinAge: 0
|
||||||
|
pwdMinLength: 1
|
||||||
|
pwdMustChange: FALSE
|
||||||
|
pwdSafeModify: FALSE
|
||||||
|
sn: default
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Stalwart Configuration
|
||||||
|
|
||||||
|
The mechanics are currently to mount a different configuration file depending on the environment, as we support two scenarios that are described in [`services/groupware/DEVELOPER.md`](../../../../../services/groupware/DEVELOPER.md):
|
||||||
|
|
||||||
|
* «production» setup, with OpenLDAP and Keycloak containers
|
||||||
|
* «homelab» setup, with the built-in IDM (LDAP) and IDP that run as part of the `opencloud` container
|
||||||
|
|
||||||
|
The Docker Compose setup (in [`stalwart.yml`](../../stalwart.yml)) mounts either [`idmldap.toml`](./idmldap.toml) or [`ldap.toml`](./ldap.toml) depending on how the variable `STALWART_AUTH_DIRECTORY` is set, which is either `idmldap` for the homelab setup, or `ldap` for the production setup.
|
||||||
|
|
||||||
|
This is thus all done automatically, but whenever changes are performed to Stalwart configuration files, they must be reflected across those two files, to keep them in sync, as the only entry that should differ is this one:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
storage.directory = "ldap"
|
||||||
|
```
|
||||||
|
|
||||||
|
or this:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
storage.directory = "idmldap"
|
||||||
|
```
|
||||||
|
|
||||||
110
devtools/deployments/opencloud_full/config/stalwart/config.toml
Normal file
110
devtools/deployments/opencloud_full/config/stalwart/config.toml
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
authentication.fallback-admin.secret = "$6$4qPYDVhaUHkKcY7s$bB6qhcukb9oFNYRIvaDZgbwxrMa2RvF5dumCjkBFdX19lSNqrgKltf3aPrFMuQQKkZpK2YNuQ83hB1B3NiWzj."
|
||||||
|
authentication.fallback-admin.user = "mailadmin"
|
||||||
|
authentication.master.secret = "$6$4qPYDVhaUHkKcY7s$bB6qhcukb9oFNYRIvaDZgbwxrMa2RvF5dumCjkBFdX19lSNqrgKltf3aPrFMuQQKkZpK2YNuQ83hB1B3NiWzj."
|
||||||
|
authentication.master.user = "master"
|
||||||
|
directory.idmldap.attributes.class = "objectClass"
|
||||||
|
directory.idmldap.attributes.description = "displayName"
|
||||||
|
directory.idmldap.attributes.email = "mail"
|
||||||
|
directory.idmldap.attributes.groups = "memberOf"
|
||||||
|
directory.idmldap.attributes.name = "uid"
|
||||||
|
directory.idmldap.attributes.secret = "userPassword"
|
||||||
|
directory.idmldap.base-dn = "o=libregraph-idm"
|
||||||
|
directory.idmldap.bind.auth.method = "default"
|
||||||
|
directory.idmldap.bind.dn = "uid=reva,ou=sysusers,o=libregraph-idm"
|
||||||
|
directory.idmldap.bind.secret = "admin"
|
||||||
|
directory.idmldap.cache.size = 1048576
|
||||||
|
directory.idmldap.cache.ttl.negative = "10m"
|
||||||
|
directory.idmldap.cache.ttl.positive = "1h"
|
||||||
|
directory.idmldap.filter.email = "(&(|(objectClass=person)(objectClass=groupOfNames))(mail=?))"
|
||||||
|
directory.idmldap.filter.name = "(&(|(objectClass=person)(objectClass=groupOfNames))(uid=?))"
|
||||||
|
directory.idmldap.timeout = "15s"
|
||||||
|
directory.idmldap.tls.allow-invalid-certs = true
|
||||||
|
directory.idmldap.tls.enable = true
|
||||||
|
directory.idmldap.type = "ldap"
|
||||||
|
directory.idmldap.url = "ldaps://opencloud:9235"
|
||||||
|
directory.keycloak.auth.method = "user-token"
|
||||||
|
directory.keycloak.cache.size = 1048576
|
||||||
|
directory.keycloak.cache.ttl.negative = "10m"
|
||||||
|
directory.keycloak.cache.ttl.positive = "1h"
|
||||||
|
directory.keycloak.endpoint.method = "introspect"
|
||||||
|
directory.keycloak.endpoint.url = "http://keycloak:8080/realms/openCloud/protocol/openid-connect/userinfo"
|
||||||
|
directory.keycloak.fields.email = "email"
|
||||||
|
directory.keycloak.fields.full-name = "name"
|
||||||
|
directory.keycloak.fields.username = "preferred_username"
|
||||||
|
directory.keycloak.timeout = "15s"
|
||||||
|
directory.keycloak.type = "oidc"
|
||||||
|
directory.ldap.attributes.class = "objectClass"
|
||||||
|
directory.ldap.attributes.description = "displayName"
|
||||||
|
directory.ldap.attributes.email = "mail"
|
||||||
|
directory.ldap.attributes.email-alias = "mailAlias"
|
||||||
|
directory.ldap.attributes.groups = "memberOf"
|
||||||
|
directory.ldap.attributes.name = "uid"
|
||||||
|
directory.ldap.attributes.secret = "userPassword"
|
||||||
|
directory.ldap.attributes.secret-changed = "pwdChangedTime"
|
||||||
|
directory.ldap.base-dn = "dc=opencloud,dc=eu"
|
||||||
|
directory.ldap.bind.auth.dn = "cn=?,ou=users,dc=opencloud,dc=eu"
|
||||||
|
directory.ldap.bind.auth.enable = true
|
||||||
|
directory.ldap.bind.auth.search = true
|
||||||
|
directory.ldap.bind.dn = "cn=admin,dc=opencloud,dc=eu"
|
||||||
|
directory.ldap.bind.secret = "admin"
|
||||||
|
directory.ldap.cache.ttl.negative = "10m"
|
||||||
|
directory.ldap.cache.ttl.positive = "1h"
|
||||||
|
directory.ldap.filter.email = "(&(|(objectClass=person)(objectClass=groupOfNames))(|(uid=?)(mail=?)(mailAlias=?)(cn=?)))"
|
||||||
|
directory.ldap.filter.name = "(&(|(objectClass=person)(objectClass=groupOfNames))(|(uid=?)(cn=?)))"
|
||||||
|
directory.ldap.timeout = "5s"
|
||||||
|
directory.ldap.tls.allow-invalid-certs = true
|
||||||
|
directory.ldap.tls.enable = true
|
||||||
|
directory.ldap.type = "ldap"
|
||||||
|
directory.ldap.url = "ldap://ldap-server:1389"
|
||||||
|
http.allowed-endpoint = 200
|
||||||
|
http.hsts = true
|
||||||
|
http.permissive-cors = false
|
||||||
|
http.url = "'https://' + config_get('server.hostname')"
|
||||||
|
http.use-x-forwarded = true
|
||||||
|
metrics.prometheus.auth.secret = "secret"
|
||||||
|
metrics.prometheus.auth.username = "metrics"
|
||||||
|
metrics.prometheus.enable = true
|
||||||
|
server.listener.http.bind = "0.0.0.0:8080"
|
||||||
|
server.listener.http.protocol = "http"
|
||||||
|
server.listener.https.bind = "0.0.0.0:443"
|
||||||
|
server.listener.https.protocol = "http"
|
||||||
|
server.listener.https.tls.implicit = true
|
||||||
|
server.listener.imap.bind = "0.0.0.0:143"
|
||||||
|
server.listener.imap.protocol = "imap"
|
||||||
|
server.listener.imaptls.bind = "0.0.0.0:993"
|
||||||
|
server.listener.imaptls.protocol = "imap"
|
||||||
|
server.listener.imaptls.tls.implicit = true
|
||||||
|
server.listener.pop3.bind = "0.0.0.0:110"
|
||||||
|
server.listener.pop3.protocol = "pop3"
|
||||||
|
server.listener.pop3s.bind = "0.0.0.0:995"
|
||||||
|
server.listener.pop3s.protocol = "pop3"
|
||||||
|
server.listener.pop3s.tls.implicit = true
|
||||||
|
server.listener.sieve.bind = "0.0.0.0:4190"
|
||||||
|
server.listener.sieve.protocol = "managesieve"
|
||||||
|
server.listener.smtp.bind = "0.0.0.0:25"
|
||||||
|
server.listener.smtp.protocol = "smtp"
|
||||||
|
server.listener.submission.bind = "0.0.0.0:587"
|
||||||
|
server.listener.submission.protocol = "smtp"
|
||||||
|
server.listener.submissions.bind = "0.0.0.0:465"
|
||||||
|
server.listener.submissions.protocol = "smtp"
|
||||||
|
server.listener.submissions.tls.implicit = true
|
||||||
|
server.max-connections = 8192
|
||||||
|
server.socket.backlog = 1024
|
||||||
|
server.socket.nodelay = true
|
||||||
|
server.socket.reuse-addr = true
|
||||||
|
server.socket.reuse-port = true
|
||||||
|
storage.blob = "rocksdb"
|
||||||
|
storage.data = "rocksdb"
|
||||||
|
storage.directory = "%{env:STALWART_AUTH_DIRECTORY}%"
|
||||||
|
storage.fts = "rocksdb"
|
||||||
|
storage.lookup = "rocksdb"
|
||||||
|
store.rocksdb.compression = "lz4"
|
||||||
|
store.rocksdb.path = "/opt/stalwart/data"
|
||||||
|
store.rocksdb.type = "rocksdb"
|
||||||
|
tracer.console.ansi = true
|
||||||
|
tracer.console.buffered = true
|
||||||
|
tracer.console.enable = true
|
||||||
|
tracer.console.level = "trace"
|
||||||
|
tracer.console.lossy = false
|
||||||
|
tracer.console.multiline = false
|
||||||
|
tracer.console.type = "stdout"
|
||||||
111
devtools/deployments/opencloud_full/config/stalwart/idmldap.toml
Normal file
111
devtools/deployments/opencloud_full/config/stalwart/idmldap.toml
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
authentication.fallback-admin.secret = "$6$4qPYDVhaUHkKcY7s$bB6qhcukb9oFNYRIvaDZgbwxrMa2RvF5dumCjkBFdX19lSNqrgKltf3aPrFMuQQKkZpK2YNuQ83hB1B3NiWzj."
|
||||||
|
authentication.fallback-admin.user = "mailadmin"
|
||||||
|
authentication.master.secret = "$6$4qPYDVhaUHkKcY7s$bB6qhcukb9oFNYRIvaDZgbwxrMa2RvF5dumCjkBFdX19lSNqrgKltf3aPrFMuQQKkZpK2YNuQ83hB1B3NiWzj."
|
||||||
|
authentication.master.user = "master"
|
||||||
|
directory.idmldap.attributes.class = "objectClass"
|
||||||
|
directory.idmldap.attributes.description = "displayName"
|
||||||
|
directory.idmldap.attributes.email = "mail"
|
||||||
|
directory.idmldap.attributes.groups = "memberOf"
|
||||||
|
directory.idmldap.attributes.name = "cn"
|
||||||
|
directory.idmldap.attributes.secret = "userPassword"
|
||||||
|
directory.idmldap.base-dn = "o=libregraph-idm"
|
||||||
|
directory.idmldap.bind.auth.method = "default"
|
||||||
|
directory.idmldap.bind.dn = "uid=reva,ou=sysusers,o=libregraph-idm"
|
||||||
|
directory.idmldap.bind.secret = "admin"
|
||||||
|
directory.idmldap.cache.size = 1048576
|
||||||
|
directory.idmldap.cache.ttl.negative = "10m"
|
||||||
|
directory.idmldap.cache.ttl.positive = "1h"
|
||||||
|
directory.idmldap.filter.email = "(&(|(objectClass=person)(objectClass=groupOfNames))(mail=?))"
|
||||||
|
directory.idmldap.filter.name = "(&(|(objectClass=person)(objectClass=groupOfNames))(cn=?))"
|
||||||
|
directory.idmldap.timeout = "15s"
|
||||||
|
directory.idmldap.tls.allow-invalid-certs = true
|
||||||
|
directory.idmldap.tls.enable = true
|
||||||
|
directory.idmldap.type = "ldap"
|
||||||
|
directory.idmldap.url = "ldaps://opencloud:9235"
|
||||||
|
directory.keycloak.auth.method = "user-token"
|
||||||
|
directory.keycloak.cache.size = 1048576
|
||||||
|
directory.keycloak.cache.ttl.negative = "10m"
|
||||||
|
directory.keycloak.cache.ttl.positive = "1h"
|
||||||
|
directory.keycloak.endpoint.method = "introspect"
|
||||||
|
directory.keycloak.endpoint.url = "http://keycloak:8080/realms/openCloud/protocol/openid-connect/userinfo"
|
||||||
|
directory.keycloak.fields.email = "email"
|
||||||
|
directory.keycloak.fields.full-name = "name"
|
||||||
|
directory.keycloak.fields.username = "preferred_username"
|
||||||
|
directory.keycloak.timeout = "15s"
|
||||||
|
directory.keycloak.type = "oidc"
|
||||||
|
directory.ldap.attributes.class = "objectClass"
|
||||||
|
directory.ldap.attributes.description = "displayName"
|
||||||
|
directory.ldap.attributes.email = "mail"
|
||||||
|
directory.ldap.attributes.email-alias = "mailAlias"
|
||||||
|
directory.ldap.attributes.groups = "memberOf"
|
||||||
|
directory.ldap.attributes.name = "uid"
|
||||||
|
directory.ldap.attributes.secret = "userPassword"
|
||||||
|
directory.ldap.attributes.secret-changed = "pwdChangedTime"
|
||||||
|
directory.ldap.base-dn = "dc=opencloud,dc=eu"
|
||||||
|
directory.ldap.bind.auth.dn = "cn=?,ou=users,dc=opencloud,dc=eu"
|
||||||
|
directory.ldap.bind.auth.enable = true
|
||||||
|
directory.ldap.bind.auth.search = true
|
||||||
|
directory.ldap.bind.dn = "cn=admin,dc=opencloud,dc=eu"
|
||||||
|
directory.ldap.bind.secret = "admin"
|
||||||
|
directory.ldap.cache.ttl.negative = "10m"
|
||||||
|
directory.ldap.cache.ttl.positive = "1h"
|
||||||
|
directory.ldap.filter.email = "(&(|(objectClass=person)(objectClass=groupOfNames))(|(uid=?)(mail=?)(mailAlias=?)(cn=?)))"
|
||||||
|
directory.ldap.filter.name = "(&(|(objectClass=person)(objectClass=groupOfNames))(|(uid=?)(cn=?)))"
|
||||||
|
directory.ldap.timeout = "5s"
|
||||||
|
directory.ldap.tls.allow-invalid-certs = true
|
||||||
|
directory.ldap.tls.enable = true
|
||||||
|
directory.ldap.type = "ldap"
|
||||||
|
directory.ldap.url = "ldap://ldap-server:1389"
|
||||||
|
http.allowed-endpoint = 200
|
||||||
|
http.hsts = true
|
||||||
|
http.permissive-cors = false
|
||||||
|
http.url = "'https://' + config_get('server.hostname')"
|
||||||
|
http.use-x-forwarded = true
|
||||||
|
metrics.prometheus.auth.secret = "secret"
|
||||||
|
metrics.prometheus.auth.username = "metrics"
|
||||||
|
metrics.prometheus.enable = true
|
||||||
|
server.listener.http.bind = "0.0.0.0:8080"
|
||||||
|
server.listener.http.protocol = "http"
|
||||||
|
server.listener.https.bind = "0.0.0.0:443"
|
||||||
|
server.listener.https.protocol = "http"
|
||||||
|
server.listener.https.tls.implicit = true
|
||||||
|
server.listener.imap.bind = "0.0.0.0:143"
|
||||||
|
server.listener.imap.protocol = "imap"
|
||||||
|
server.listener.imaptls.bind = "0.0.0.0:993"
|
||||||
|
server.listener.imaptls.protocol = "imap"
|
||||||
|
server.listener.imaptls.tls.implicit = true
|
||||||
|
server.listener.pop3.bind = "0.0.0.0:110"
|
||||||
|
server.listener.pop3.protocol = "pop3"
|
||||||
|
server.listener.pop3s.bind = "0.0.0.0:995"
|
||||||
|
server.listener.pop3s.protocol = "pop3"
|
||||||
|
server.listener.pop3s.tls.implicit = true
|
||||||
|
server.listener.sieve.bind = "0.0.0.0:4190"
|
||||||
|
server.listener.sieve.protocol = "managesieve"
|
||||||
|
server.listener.smtp.bind = "0.0.0.0:25"
|
||||||
|
server.listener.smtp.protocol = "smtp"
|
||||||
|
server.listener.submission.bind = "0.0.0.0:587"
|
||||||
|
server.listener.submission.protocol = "smtp"
|
||||||
|
server.listener.submissions.bind = "0.0.0.0:465"
|
||||||
|
server.listener.submissions.protocol = "smtp"
|
||||||
|
server.listener.submissions.tls.implicit = true
|
||||||
|
server.max-connections = 8192
|
||||||
|
server.socket.backlog = 1024
|
||||||
|
server.socket.nodelay = true
|
||||||
|
server.socket.reuse-addr = true
|
||||||
|
server.socket.reuse-port = true
|
||||||
|
storage.blob = "rocksdb"
|
||||||
|
storage.data = "rocksdb"
|
||||||
|
storage.directory = "idmldap"
|
||||||
|
storage.fts = "rocksdb"
|
||||||
|
storage.lookup = "rocksdb"
|
||||||
|
store.rocksdb.compression = "lz4"
|
||||||
|
store.rocksdb.path = "/opt/stalwart/data"
|
||||||
|
store.rocksdb.type = "rocksdb"
|
||||||
|
tracer.console.ansi = true
|
||||||
|
tracer.console.buffered = true
|
||||||
|
tracer.console.enable = true
|
||||||
|
tracer.console.level = "trace"
|
||||||
|
tracer.console.lossy = false
|
||||||
|
tracer.console.multiline = false
|
||||||
|
tracer.console.type = "stdout"
|
||||||
|
sharing.allow-directory-query = false
|
||||||
110
devtools/deployments/opencloud_full/config/stalwart/ldap.toml
Normal file
110
devtools/deployments/opencloud_full/config/stalwart/ldap.toml
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
authentication.fallback-admin.secret = "$6$4qPYDVhaUHkKcY7s$bB6qhcukb9oFNYRIvaDZgbwxrMa2RvF5dumCjkBFdX19lSNqrgKltf3aPrFMuQQKkZpK2YNuQ83hB1B3NiWzj."
|
||||||
|
authentication.fallback-admin.user = "mailadmin"
|
||||||
|
authentication.master.secret = "$6$4qPYDVhaUHkKcY7s$bB6qhcukb9oFNYRIvaDZgbwxrMa2RvF5dumCjkBFdX19lSNqrgKltf3aPrFMuQQKkZpK2YNuQ83hB1B3NiWzj."
|
||||||
|
authentication.master.user = "master"
|
||||||
|
directory.idmldap.attributes.class = "objectClass"
|
||||||
|
directory.idmldap.attributes.description = "displayName"
|
||||||
|
directory.idmldap.attributes.email = "mail"
|
||||||
|
directory.idmldap.attributes.groups = "memberOf"
|
||||||
|
directory.idmldap.attributes.name = "uid"
|
||||||
|
directory.idmldap.attributes.secret = "userPassword"
|
||||||
|
directory.idmldap.base-dn = "o=libregraph-idm"
|
||||||
|
directory.idmldap.bind.auth.method = "default"
|
||||||
|
directory.idmldap.bind.dn = "uid=reva,ou=sysusers,o=libregraph-idm"
|
||||||
|
directory.idmldap.bind.secret = "admin"
|
||||||
|
directory.idmldap.cache.size = 1048576
|
||||||
|
directory.idmldap.cache.ttl.negative = "10m"
|
||||||
|
directory.idmldap.cache.ttl.positive = "1h"
|
||||||
|
directory.idmldap.filter.email = "(&(|(objectClass=person)(objectClass=groupOfNames))(mail=?))"
|
||||||
|
directory.idmldap.filter.name = "(&(|(objectClass=person)(objectClass=groupOfNames))(uid=?))"
|
||||||
|
directory.idmldap.timeout = "15s"
|
||||||
|
directory.idmldap.tls.allow-invalid-certs = true
|
||||||
|
directory.idmldap.tls.enable = true
|
||||||
|
directory.idmldap.type = "ldap"
|
||||||
|
directory.idmldap.url = "ldaps://opencloud:9235"
|
||||||
|
directory.keycloak.auth.method = "user-token"
|
||||||
|
directory.keycloak.cache.size = 1048576
|
||||||
|
directory.keycloak.cache.ttl.negative = "10m"
|
||||||
|
directory.keycloak.cache.ttl.positive = "1h"
|
||||||
|
directory.keycloak.endpoint.method = "introspect"
|
||||||
|
directory.keycloak.endpoint.url = "http://keycloak:8080/realms/openCloud/protocol/openid-connect/userinfo"
|
||||||
|
directory.keycloak.fields.email = "email"
|
||||||
|
directory.keycloak.fields.full-name = "name"
|
||||||
|
directory.keycloak.fields.username = "preferred_username"
|
||||||
|
directory.keycloak.timeout = "15s"
|
||||||
|
directory.keycloak.type = "oidc"
|
||||||
|
directory.ldap.attributes.class = "objectClass"
|
||||||
|
directory.ldap.attributes.description = "displayName"
|
||||||
|
directory.ldap.attributes.email = "mail"
|
||||||
|
directory.ldap.attributes.email-alias = "mailAlias"
|
||||||
|
directory.ldap.attributes.groups = "memberOf"
|
||||||
|
directory.ldap.attributes.name = "uid"
|
||||||
|
directory.ldap.attributes.secret = "userPassword"
|
||||||
|
directory.ldap.attributes.secret-changed = "pwdChangedTime"
|
||||||
|
directory.ldap.base-dn = "dc=opencloud,dc=eu"
|
||||||
|
directory.ldap.bind.auth.dn = "cn=?,ou=users,dc=opencloud,dc=eu"
|
||||||
|
directory.ldap.bind.auth.enable = true
|
||||||
|
directory.ldap.bind.auth.search = true
|
||||||
|
directory.ldap.bind.dn = "cn=admin,dc=opencloud,dc=eu"
|
||||||
|
directory.ldap.bind.secret = "admin"
|
||||||
|
directory.ldap.cache.ttl.negative = "10m"
|
||||||
|
directory.ldap.cache.ttl.positive = "1h"
|
||||||
|
directory.ldap.filter.email = "(&(|(objectClass=person)(objectClass=groupOfNames))(|(uid=?)(mail=?)(mailAlias=?)(cn=?)))"
|
||||||
|
directory.ldap.filter.name = "(&(|(objectClass=person)(objectClass=groupOfNames))(|(uid=?)(cn=?)))"
|
||||||
|
directory.ldap.timeout = "5s"
|
||||||
|
directory.ldap.tls.allow-invalid-certs = true
|
||||||
|
directory.ldap.tls.enable = true
|
||||||
|
directory.ldap.type = "ldap"
|
||||||
|
directory.ldap.url = "ldap://ldap-server:1389"
|
||||||
|
http.allowed-endpoint = 200
|
||||||
|
http.hsts = true
|
||||||
|
http.permissive-cors = false
|
||||||
|
http.url = "'https://' + config_get('server.hostname')"
|
||||||
|
http.use-x-forwarded = true
|
||||||
|
metrics.prometheus.auth.secret = "secret"
|
||||||
|
metrics.prometheus.auth.username = "metrics"
|
||||||
|
metrics.prometheus.enable = true
|
||||||
|
server.listener.http.bind = "0.0.0.0:8080"
|
||||||
|
server.listener.http.protocol = "http"
|
||||||
|
server.listener.https.bind = "0.0.0.0:443"
|
||||||
|
server.listener.https.protocol = "http"
|
||||||
|
server.listener.https.tls.implicit = true
|
||||||
|
server.listener.imap.bind = "0.0.0.0:143"
|
||||||
|
server.listener.imap.protocol = "imap"
|
||||||
|
server.listener.imaptls.bind = "0.0.0.0:993"
|
||||||
|
server.listener.imaptls.protocol = "imap"
|
||||||
|
server.listener.imaptls.tls.implicit = true
|
||||||
|
server.listener.pop3.bind = "0.0.0.0:110"
|
||||||
|
server.listener.pop3.protocol = "pop3"
|
||||||
|
server.listener.pop3s.bind = "0.0.0.0:995"
|
||||||
|
server.listener.pop3s.protocol = "pop3"
|
||||||
|
server.listener.pop3s.tls.implicit = true
|
||||||
|
server.listener.sieve.bind = "0.0.0.0:4190"
|
||||||
|
server.listener.sieve.protocol = "managesieve"
|
||||||
|
server.listener.smtp.bind = "0.0.0.0:25"
|
||||||
|
server.listener.smtp.protocol = "smtp"
|
||||||
|
server.listener.submission.bind = "0.0.0.0:587"
|
||||||
|
server.listener.submission.protocol = "smtp"
|
||||||
|
server.listener.submissions.bind = "0.0.0.0:465"
|
||||||
|
server.listener.submissions.protocol = "smtp"
|
||||||
|
server.listener.submissions.tls.implicit = true
|
||||||
|
server.max-connections = 8192
|
||||||
|
server.socket.backlog = 1024
|
||||||
|
server.socket.nodelay = true
|
||||||
|
server.socket.reuse-addr = true
|
||||||
|
server.socket.reuse-port = true
|
||||||
|
storage.blob = "rocksdb"
|
||||||
|
storage.data = "rocksdb"
|
||||||
|
storage.directory = "ldap"
|
||||||
|
storage.fts = "rocksdb"
|
||||||
|
storage.lookup = "rocksdb"
|
||||||
|
store.rocksdb.compression = "lz4"
|
||||||
|
store.rocksdb.path = "/opt/stalwart/data"
|
||||||
|
store.rocksdb.type = "rocksdb"
|
||||||
|
tracer.console.ansi = true
|
||||||
|
tracer.console.buffered = true
|
||||||
|
tracer.console.enable = true
|
||||||
|
tracer.console.level = "trace"
|
||||||
|
tracer.console.lossy = false
|
||||||
|
tracer.console.multiline = false
|
||||||
|
tracer.console.type = "stdout"
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
|
||||||
|
opencloud:
|
||||||
|
command: [ "-c", "opencloud init || true; dlv --listen=:40000 --headless=true --check-go-version=false --api-version=2 --accept-multiclient exec /usr/bin/opencloud server" ]
|
||||||
|
ports:
|
||||||
|
- 40000:40000
|
||||||
@@ -19,6 +19,11 @@ services:
|
|||||||
- "--entryPoints.http.http.redirections.entryPoint.to=https"
|
- "--entryPoints.http.http.redirections.entryPoint.to=https"
|
||||||
- "--entryPoints.http.http.redirections.entryPoint.scheme=https"
|
- "--entryPoints.http.http.redirections.entryPoint.scheme=https"
|
||||||
- "--entryPoints.https.address=:443"
|
- "--entryPoints.https.address=:443"
|
||||||
|
# http2 optimizations
|
||||||
|
- "--entryPoints.https.http2.maxConcurrentStreams=512"
|
||||||
|
- "--serversTransport.maxIdleConnsPerHost=100"
|
||||||
|
# allow self signed certificate from OpenCloud
|
||||||
|
- "--serversTransport.insecureSkipVerify=true"
|
||||||
# change default timeouts for long-running requests
|
# change default timeouts for long-running requests
|
||||||
# this is needed for webdav clients that do not support the TUS protocol
|
# this is needed for webdav clients that do not support the TUS protocol
|
||||||
- "--entryPoints.https.transport.respondingTimeouts.readTimeout=12h"
|
- "--entryPoints.https.transport.respondingTimeouts.readTimeout=12h"
|
||||||
@@ -31,6 +36,7 @@ services:
|
|||||||
- "--accessLog=true"
|
- "--accessLog=true"
|
||||||
- "--accessLog.format=json"
|
- "--accessLog.format=json"
|
||||||
- "--accessLog.fields.headers.names.X-Request-Id=keep"
|
- "--accessLog.fields.headers.names.X-Request-Id=keep"
|
||||||
|
- "--accessLog.fields.headers.names.Trace-Id=keep"
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
- "443:443"
|
- "443:443"
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ services:
|
|||||||
KC_FEATURES: impersonation
|
KC_FEATURES: impersonation
|
||||||
KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN_USER:-admin}
|
KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN_USER:-admin}
|
||||||
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin}
|
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin}
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.http.routers.keycloak.entrypoints=https"
|
- "traefik.http.routers.keycloak.entrypoints=https"
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ services:
|
|||||||
OC_LDAP_SERVER_WRITE_ENABLED: "false" # assuming the external ldap is not writable
|
OC_LDAP_SERVER_WRITE_ENABLED: "false" # assuming the external ldap is not writable
|
||||||
# OC_RUN_SERVICES specifies to start all services except glauth, idm and accounts. These are replaced by external services
|
# OC_RUN_SERVICES specifies to start all services except glauth, idm and accounts. These are replaced by external services
|
||||||
OC_EXCLUDE_RUN_SERVICES: idm
|
OC_EXCLUDE_RUN_SERVICES: idm
|
||||||
|
STALWART_AUTH_DIRECTORY: "ldap"
|
||||||
|
|
||||||
ldap-server:
|
ldap-server:
|
||||||
image: bitnamilegacy/openldap:2.6
|
image: bitnamilegacy/openldap:2.6
|
||||||
@@ -39,6 +40,9 @@ services:
|
|||||||
LDAP_TLS_KEY_FILE: /opt/bitnami/openldap/share/openldap.key
|
LDAP_TLS_KEY_FILE: /opt/bitnami/openldap/share/openldap.key
|
||||||
LDAP_ROOT: "dc=opencloud,dc=eu"
|
LDAP_ROOT: "dc=opencloud,dc=eu"
|
||||||
LDAP_ADMIN_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin}
|
LDAP_ADMIN_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin}
|
||||||
|
LDAP_CONFIGURE_PPOLICY: "yes"
|
||||||
|
LDAP_PPOLICY_USE_LOCKOUT: "no"
|
||||||
|
LDAP_PPOLICY_HASH_CLEARTEXT: "no"
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:389:1389"
|
- "127.0.0.1:389:1389"
|
||||||
- "127.0.0.1:636:1636"
|
- "127.0.0.1:636:1636"
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ services:
|
|||||||
OC_LOG_COLOR: "${LOG_PRETTY:-false}"
|
OC_LOG_COLOR: "${LOG_PRETTY:-false}"
|
||||||
OC_LOG_PRETTY: "${LOG_PRETTY:-false}"
|
OC_LOG_PRETTY: "${LOG_PRETTY:-false}"
|
||||||
# do not use SSL between Traefik and OpenCloud
|
# do not use SSL between Traefik and OpenCloud
|
||||||
PROXY_TLS: "false"
|
PROXY_TLS: "true"
|
||||||
# make the REVA gateway accessible to the app drivers
|
# make the REVA gateway accessible to the app drivers
|
||||||
GATEWAY_GRPC_ADDR: 0.0.0.0:9142
|
GATEWAY_GRPC_ADDR: 0.0.0.0:9142
|
||||||
# INSECURE: needed if OpenCloud / Traefik is using self generated certificates
|
# INSECURE: needed if OpenCloud / Traefik is using self generated certificates
|
||||||
@@ -58,6 +58,11 @@ services:
|
|||||||
COMPANION_DOMAIN: ${COMPANION_DOMAIN:-companion.opencloud.test}
|
COMPANION_DOMAIN: ${COMPANION_DOMAIN:-companion.opencloud.test}
|
||||||
# enable to allow using the banned passwords list
|
# enable to allow using the banned passwords list
|
||||||
OC_PASSWORD_POLICY_BANNED_PASSWORDS_LIST: banned-password-list.txt
|
OC_PASSWORD_POLICY_BANNED_PASSWORDS_LIST: banned-password-list.txt
|
||||||
|
IDM_REVASVC_PASSWORD: "admin"
|
||||||
|
AUTH_BASIC_LDAP_BIND_PASSWORD: "admin"
|
||||||
|
USERS_LDAP_BIND_PASSWORD: "admin"
|
||||||
|
GROUPS_LDAP_BIND_PASSWORD: "admin"
|
||||||
|
IDM_LDAPS_ADDR: 0.0.0.0:9235
|
||||||
volumes:
|
volumes:
|
||||||
- ./config/opencloud/app-registry.yaml:/etc/opencloud/app-registry.yaml
|
- ./config/opencloud/app-registry.yaml:/etc/opencloud/app-registry.yaml
|
||||||
- ./config/opencloud/csp.yaml:/etc/opencloud/csp.yaml
|
- ./config/opencloud/csp.yaml:/etc/opencloud/csp.yaml
|
||||||
@@ -72,6 +77,7 @@ services:
|
|||||||
- "traefik.http.routers.opencloud.tls.certresolver=http"
|
- "traefik.http.routers.opencloud.tls.certresolver=http"
|
||||||
- "traefik.http.routers.opencloud.service=opencloud"
|
- "traefik.http.routers.opencloud.service=opencloud"
|
||||||
- "traefik.http.services.opencloud.loadbalancer.server.port=9200"
|
- "traefik.http.services.opencloud.loadbalancer.server.port=9200"
|
||||||
|
- "traefik.http.services.opencloud.loadbalancer.server.scheme=https"
|
||||||
logging:
|
logging:
|
||||||
driver: ${LOG_DRIVER:-local}
|
driver: ${LOG_DRIVER:-local}
|
||||||
restart: always
|
restart: always
|
||||||
|
|||||||
36
devtools/deployments/opencloud_full/stalwart.yml
Normal file
36
devtools/deployments/opencloud_full/stalwart.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
traefik:
|
||||||
|
networks:
|
||||||
|
opencloud-net:
|
||||||
|
aliases:
|
||||||
|
- ${STALWART_DOMAIN:-stalwart.opencloud.test}
|
||||||
|
|
||||||
|
stalwart:
|
||||||
|
image: ghcr.io/stalwartlabs/stalwart:v0.15.0-alpine
|
||||||
|
hostname: ${STALWART_DOMAIN:-stalwart.opencloud.test}
|
||||||
|
networks:
|
||||||
|
- opencloud-net
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:143:143"
|
||||||
|
- "127.0.0.1:993:993"
|
||||||
|
- "127.0.0.1:1465:465"
|
||||||
|
volumes:
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
- "./config/stalwart/${STALWART_AUTH_DIRECTORY:-idmldap}.toml:/opt/stalwart/etc/config.toml"
|
||||||
|
- stalwart-data:/opt/stalwart/data
|
||||||
|
environment:
|
||||||
|
STALWART_AUTH_DIRECTORY: "${STALWART_AUTH_DIRECTORY:-idmldap}"
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.stalwart.entrypoints=https"
|
||||||
|
- "traefik.http.routers.stalwart.rule=Host(`${STALWART_DOMAIN:-stalwart.opencloud.test}`)"
|
||||||
|
- "traefik.http.routers.stalwart.tls.certresolver=http"
|
||||||
|
- "traefik.http.routers.stalwart.service=stalwart"
|
||||||
|
- "traefik.http.services.stalwart.loadbalancer.server.port=8080"
|
||||||
|
logging:
|
||||||
|
driver: ${LOG_DRIVER:-local}
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
stalwart-data:
|
||||||
343
docs/adr/0002-groupware-authentication-with-stalwart.md
Normal file
343
docs/adr/0002-groupware-authentication-with-stalwart.md
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
---
|
||||||
|
title: "Authentication with Stalwart"
|
||||||
|
---
|
||||||
|
|
||||||
|
* Status: draft
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
In a groupware environment, not every user will always use the OpenCloud UI to read their emails, some will resort to other [MUAs (Mail User Agents)](https://en.wikipedia.org/wiki/Email_client) that support a subset of features, use older protocols (IMAP, POP, SMTP, CalDAV, CardDAV) and lesser authentication methods (basic authentication). Those email clients will talk to Stalwart directly, as opposed to the OpenCloud UI which will make use of APIs of the OpenCloud Groupware service, since those protocols are provided by Stalwart and implementing them in OpenCloud would offer very little benefits, but definitely a lot of (almost completely) unnecessary effort.
|
||||||
|
|
||||||
|
Those protocols and operations that bypass the OpenCloud UI also need to be authenticated, this in and by Stalwart, and we need to find the best fitting approach that fulfills most or all of the following constraints:
|
||||||
|
|
||||||
|
### Single Provisioning
|
||||||
|
|
||||||
|
We want to avoid multiple provisioning of users, groups, passwords and other resources as much as possible.
|
||||||
|
While it is possible to have e.g. OpenCloud's user management also perform [Management API](https://stalw.art/docs/category/management-api/) calls, one still inevitably ends up in situations where users, user passwords, or other resources are not in sync, which becomes complex to debug and fix, and should thus be avoided if possible.
|
||||||
|
|
||||||
|
To do so, we should strive to have a single source of truth regarding users, their passwords, and similar resources and attributes such as groups, roles, application passwords, etc...
|
||||||
|
|
||||||
|
### Attack Detection
|
||||||
|
|
||||||
|
Coordinated attacks such as [denial of service](https://en.wikipedia.org/wiki/Denial-of-service_attack) attempts don't necessarily focus on a single protocol but are commonly multi-pronged, e.g. by brute forcing the [OIDC API](https://www.keycloak.org/docs/latest/authorization_services/index.html#token-endpoint), the OpenCloud Groupware API, IMAP and SMTP, \*DAV protocols, etc...
|
||||||
|
|
||||||
|
In order to detect those as well as to quickly react by blacklisting clients that are identified to attempt such attacks, it is useful to have a single authentication service for all the components of the system, all protocols, all clients (e.g. [PowerDNS Weakforced](https://github.com/PowerDNS/weakforced), [Nauthilus](https://nauthilus.org/), ...)
|
||||||
|
|
||||||
|
Furthermore, such services typically make use of [DNSBL/RBL services](https://en.wikipedia.org/wiki/Domain_Name_System_blocklist) that allow IP addresses of botnets to be blocked across many services of many providers as a shared defense mechanism.
|
||||||
|
|
||||||
|
As a bonus, a centralized authentication component can also provide metrics and observability capabilities across all those protocols.
|
||||||
|
|
||||||
|
### Custom Authentication Implementations
|
||||||
|
|
||||||
|
Some customers might want custom authentication implementations to integrate with their environment, in which case we would want those to be done once and in the technology stack we're all most familiar with (thus as a service in Go in the OpenCloud framework, and not e.g. a Lua script in Nauthilus, or a Rust plugin in Stalwart, etc...)
|
||||||
|
|
||||||
|
## Decision Drivers
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
First off, here is a brief explanation of each of the scenarios that we potentially or absolutely need to support, which we will explore for each implementation option:
|
||||||
|
|
||||||
|
* MUAs with basic authentication
|
||||||
|
* these are external mail clients (Thunderbird, Apple Mail, ...) with which users authenticate using legacy protocols (IMAP, POP3, SMTP) and their primary username and password in clear text (encrypted through the mandatory use of TLS)
|
||||||
|
* MUAs with application password authentication
|
||||||
|
* these are external mail clients (Thunderbird, Apple Mail, ...) with which users authenticate using legacy protocols (IMAP, POP3, SMTP) and one of the application passwords that they created in the OpenCloud UI, which is a useful security mechanism as it reduces the attack surface when one such password is leaked or discovered
|
||||||
|
* MUAs with SASL bearer token authentication
|
||||||
|
* these are more modern external mail clients (Thunderbird) with which users authenticate using legacy protocols (IMAP, POP3, SMTP) but more secure OIDC token based authentication (SASL OAUTHBEARER or SASL XOAUTH2), which closely resembles the OIDC authentication used by the OpenCloud UI towards the OpenCloud backends
|
||||||
|
* JMAP clients with basic authentication
|
||||||
|
* modern mail clients (Thunderbird) that speak the JMAP protocol over HTTP and authenticate using their primary username and password in clear text (encrypted through the use of HTTPS)
|
||||||
|
* JMAP clients with bearer token authentication
|
||||||
|
* modern mail clients (Thunderbird) that speak the JMAP protocol over HTTP and authenticate using an OIDC token (JWT) obtained from an IDP (typically KeyCloak)
|
||||||
|
* OpenCloud Groupware with master authentication
|
||||||
|
* the OpenCloud UI client uses APIs from the OpenCloud Groupware backend (and authenticates using OIDC)
|
||||||
|
* the OpenCloud Groupware backend, in turn, performs JMAP operations with Stalwart, and authenticates using Stalwart's shared secret master authentication protocol
|
||||||
|
* OpenCloud Groupware with generated token authentication
|
||||||
|
* the OpenCloud UI client uses APIs from the OpenCloud Groupware backend (and authenticates using OIDC)
|
||||||
|
* the OpenCloud Groupware backend, in turn, performs JMAP operations with Stalwart, and authenticates against Stalwart using bearer authentication with JWTs that it generates itself
|
||||||
|
* in the future, that JWT might also be the JWT that the OpenCloud UI used to authenticate against the OpenCloud Groupware in the first place
|
||||||
|
|
||||||
|
### Stalwart with the LDAP Directory
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
c(client)
|
||||||
|
s(Stalwart)
|
||||||
|
l(LDAP)
|
||||||
|
|
||||||
|
c -- IMAP/SMTP --> s
|
||||||
|
c -- JMAP --> s
|
||||||
|
s -- LDAP --> l
|
||||||
|
```
|
||||||
|
|
||||||
|
Clients authenticate directly against Stalwart, that is configured to use an LDAP authentication Directory.
|
||||||
|
An LDAP server (e.g. OpenLDAP) is needed as part of the infrastructure.
|
||||||
|
OpenCloud also has to make use of the same LDAP server.
|
||||||
|
|
||||||
|
* ✅ MUAs with basic authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's LDAP Directory plugin supports plain text authentication by looking up the userPassword attribute in the LDAP server
|
||||||
|
* ❌ MUAs with application password authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's LDAP Directory plugin does not support application password as it is hardwired to look up the password in the userPassword attribute in the LDAP server
|
||||||
|
* even if it did support looking up alternative passwords in LDAP, this would hardly be practical as the application passwords are currently created and stored in OpenCloud, which would need to be modified to store them in LDAP in the first place
|
||||||
|
* ❌ MUAs with SASL bearer token authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's LDAP Directory plugin does not support verifying OIDC tokens
|
||||||
|
* ✅ JMAP clients with basic authentication
|
||||||
|
* JMAP clients authenticate directly against Stalwart
|
||||||
|
* Stalwart's LDAP Directory plugin supports plain text authentication by looking up the userPassword attribute in the LDAP server
|
||||||
|
* ❌ JMAP clients with bearer token authentication
|
||||||
|
* JMAP clients authenticate directly against Stalwart
|
||||||
|
* Stalwart's LDAP Directory plugin does not support verifying OIDC tokens
|
||||||
|
* ✅ OpenCloud Groupware with master authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* Stalwart detects and supports clear text password master authentication regardless of the Directory that is being used, and verifies it against the shared secret password that is configured in the server
|
||||||
|
* ❌ OpenCloud Groupware with generated token authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* Stalwart's LDAP Directory plugin does not support verifying OIDC tokens
|
||||||
|
|
||||||
|
### Stalwart with the OIDC Directory
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
c(client)
|
||||||
|
s(Stalwart)
|
||||||
|
o(IDP)
|
||||||
|
|
||||||
|
c -- IMAP/SMTP --> s
|
||||||
|
c -- JMAP --> s
|
||||||
|
s -- OIDC HTTP --> o
|
||||||
|
```
|
||||||
|
|
||||||
|
Clients authenticate directly against Stalwart, that is configured to use an OIDC authentication Directory.
|
||||||
|
An OIDC IDP (server) is needed as part of the infrastructure, e.g. KeyCloak.
|
||||||
|
Optionally, an LDAP server (e.g. OpenLDAP) might be used as well, and KeyCloak would look up users and their credentials in LDAP.
|
||||||
|
|
||||||
|
OpenCloud also has to make use of the same LDAP server, or would need to be modified to be capable of only making use of an OIDC IDP (which would include limitations that are yet to be resolved, e.g. the option of using KeyCloak Admin APIs to retreieve groups, group members, ...)
|
||||||
|
|
||||||
|
* ❌ MUAs with basic authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's OIDC Directory plugin does not support plain text authentication
|
||||||
|
* ❌ MUAs with application password authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's OIDC Directory plugin does not support application passwords
|
||||||
|
* ❓ MUAs with SASL bearer token authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's OIDC Directory plugin does not currently support external IDPs, but is expected to in future versions
|
||||||
|
* as of Stalwart 0.12, this would only work if Stalwart itself is used as the IDP when acquiring a token
|
||||||
|
* ❌ JMAP clients with basic authentication
|
||||||
|
* JMAP clients authenticate directly against Stalwart
|
||||||
|
* Stalwart's OIDC Directory plugin does not support plain text authentication
|
||||||
|
* ❓ JMAP clients with bearer token authentication
|
||||||
|
* JMAP clients authenticate directly against Stalwart
|
||||||
|
* Stalwart's OIDC Directory plugin does not currently support external IDPs, but is expected to in future versions
|
||||||
|
* as of Stalwart 0.12, this would only work if Stalwart itself is used as the IDP when acquiring a token
|
||||||
|
* ✅ OpenCloud Groupware with master authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* Stalwart detects and supports clear text password master authentication regardless of the Directory that is being used, and verifies it against the shared secret password that is configured in the server
|
||||||
|
* ❓ OpenCloud Groupware with generated token authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* Stalwart's OIDC Directory plugin does not currently support external IDPs, but is expected to in future versions
|
||||||
|
* as of Stalwart 0.12, this would only work if Stalwart itself is used as the IDP when acquiring a token, which is not the case with this approach as the tokens are generated by the Groupware backend itself
|
||||||
|
|
||||||
|
### Stalwart with the Internal Directory
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
c(client)
|
||||||
|
s(Stalwart)
|
||||||
|
|
||||||
|
c -- IMAP/SMTP --> s
|
||||||
|
c -- JMAP --> s
|
||||||
|
```
|
||||||
|
|
||||||
|
Clients authenticate directly against Stalwart, that is configured to use an Internal authentication Directory.
|
||||||
|
Neither an OIDC IDP nor an LDAP server are needed as part of the infrastructure, as principal resources (users, groups) and their credentials exist in Stalwart's storage.
|
||||||
|
|
||||||
|
OpenCloud would not be capable of accessing those resources, which means that provisioning of groups, users, user passwords must be duplicated and kept in sync between Stalwart and OpenCloud.
|
||||||
|
|
||||||
|
* ✅ MUAs with basic authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's Internal Directory plugin supports plain text authentication
|
||||||
|
* ✅ MUAs with application password authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's Internal Directory plugin supports application passwords
|
||||||
|
* users are able to create those themselves using the self-service web UI of Stalwart
|
||||||
|
* they are not shared with the OpenCloud application passwords though and would need to be provisioned into Stalwart when created in OpenCloud to provide a single UI
|
||||||
|
* ❌ MUAs with SASL bearer token authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's Internal Directory plugin does not support OIDC token authentication
|
||||||
|
* ✅ JMAP clients with basic authentication
|
||||||
|
* JMAP clients authenticate directly against Stalwart
|
||||||
|
* Stalwart's Internal Directory plugin supports plain text authentication
|
||||||
|
* ❌ JMAP clients with bearer token authentication
|
||||||
|
* JMAP clients authenticate directly against Stalwart
|
||||||
|
* Stalwart's Internal Directory plugin does not support OIDC token authentication
|
||||||
|
* ✅ OpenCloud Groupware with master authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* Stalwart detects and supports clear text password master authentication regardless of the Directory that is being used, and verifies it against the shared secret password that is configured in the server
|
||||||
|
* ❌ OpenCloud Groupware with generated token authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* Stalwart's Internal Directory plugin does not support OIDC token authentication
|
||||||
|
|
||||||
|
### Stalwart with the OpenCloud Authentication API
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
c(client)
|
||||||
|
s(Stalwart)
|
||||||
|
o(OpenCloud)
|
||||||
|
l(LDAP)
|
||||||
|
|
||||||
|
c -- IMAP/SMTP --> s
|
||||||
|
c -- JMAP --> s
|
||||||
|
s -- REST --> o
|
||||||
|
o -- LDAP --> l
|
||||||
|
```
|
||||||
|
|
||||||
|
Clients authenticate directly against Stalwart, that is configured to use an "External" authentication Directory, that is yet to be developed. (warning)
|
||||||
|
Its protocol is currently not defined, but not particularly relevant at this time, as long as it supports accepting basic and bearer authentication in order to authenticate both username and password credentials as well as OIDC tokens.
|
||||||
|
|
||||||
|
That External Directory implementation forwards the basic or bearer credentials to an endpoint in the OpenCloud backend, that the responds with whether the authentication is successful or not, as well as with additional information that is needed for Stalwart (email address, display name, groups, roles, ...)
|
||||||
|
|
||||||
|
* ✅ MUAs with basic authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's External Directory supports plain text authentication by relaying the authentication operation to the OpenCloud backend, which can then authenticate users by username and password using an LDAP server
|
||||||
|
* note that this option requires having an LDAP server in the environment, including having it accessible by OpenCloud
|
||||||
|
* if that is not the case, then a viable option is also to support OIDC tokens and application passwords
|
||||||
|
* to clarify: this scenario is only about supporting authentication using the "primary" username and password
|
||||||
|
* ✅ MUAs with application password authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's External Directory supports application password authentication by relaying the authentication operation to the OpenCloud backend, which can then authenticate against its list of application passwords
|
||||||
|
* this is the ideal scenario for application passwords, since they are already supported by OpenCloud, and can be created and managed using the OpenCloud UI
|
||||||
|
* relaying the authentication operation to OpenCloud also prevents the need for duplicate provisioning of application passwords
|
||||||
|
* ✅ MUAs with SASL bearer token authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's External Directory supports OIDC token authentication by relaying the authentication operation to the OpenCloud backend, which can then either perform local token inspection and authentication by verifying the token's signature, or use the OIDC IDP's token introspection endpoint
|
||||||
|
* ✅ JMAP clients with basic authentication
|
||||||
|
* JMAP clients authenticate directly against Stalwart
|
||||||
|
* Stalwart's External Directory supports plain text authentication by relaying the authentication operation to the OpenCloud backend, which can then authenticate users by username and password using an LDAP server
|
||||||
|
* the same limitations/requirements as for the "MUAs with basic authentication" scenario apply here as well
|
||||||
|
* ✅ JMAP clients with bearer token authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's External Directory supports OIDC token authentication by relaying the authentication operation to the OpenCloud backend, which can then either perform local token inspection and authentication by verifying the token's signature, or use the OIDC IDP's token introspection endpoint
|
||||||
|
* ✅ OpenCloud Groupware with master authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* Stalwart detects and supports clear text password master authentication regardless of the Directory that is being used, and verifies it against the shared secret password that is configured in the server
|
||||||
|
* ✅ OpenCloud Groupware with generated token authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* in the worst case, the External Directory plugin in Stalwart would also perform a forwarding of the authentication operation to OpenCloud, which would obviously be able to verify a token it has created
|
||||||
|
* an optimization might be possible here, if the External Directory implementation permits for the configuration of specific issuers which should then be verifying against a JWK set directly, whereas the fallback behaviour would be to query the OpenCloud Authentication API
|
||||||
|
|
||||||
|
### Stalwart with Nauthilus and LDAP
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
c(client)
|
||||||
|
s(Stalwart)
|
||||||
|
n(Nauthilus)
|
||||||
|
l(LDAP)
|
||||||
|
|
||||||
|
c -- IMAP/SMTP --> s
|
||||||
|
c -- JMAP --> s
|
||||||
|
s -- REST --> n
|
||||||
|
n -- LDAP --> l
|
||||||
|
```
|
||||||
|
|
||||||
|
In this scenario, we introduce the [Nauthilus authentication service](https://nauthilus.org/), which has its own API but also a KeyCloak integration plugin.
|
||||||
|
It supports various backends and can also be scripted for more complex combinations.
|
||||||
|
|
||||||
|
⚠️ It would require the implementation of a Stalwart Nauthilus Directory, **that is yet to be developed**.
|
||||||
|
|
||||||
|
We do not make use of any OpenCloud Authentication API but, instead, attempt to have everything go through Nauthilus instead, backed by an LDAP server that then contains the users, groups, and user passwords.
|
||||||
|
|
||||||
|
The upside of using Nauthilus is that it does brute force attack detection and can provide metrics across multiple protocols and clients in a centralized fashion.
|
||||||
|
|
||||||
|
* ✅ MUAs with basic authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's Nauthilus Directory supports plain text authentication by relaying the authentication operation to Nauthilus, e.g. using its JSON API
|
||||||
|
* Nauthilus provides a response that contains user attributes from LDAP (display name, email addresses, ...)
|
||||||
|
* ❓ MUAs with application password authentication
|
||||||
|
* Nauthilus has no support for application passwords in itself
|
||||||
|
* a Lua plugin could potentially be used in Nauthilus to detect whether the clear text password matches a regular expression for application passwords and, if that is the case, first attempt to verify it through an API call (that does not exist yet) to the OpenCloud backend, but that would definitely be more complex and less elegant than having a single API
|
||||||
|
* ❓ MUAs with SASL bearer token authentication
|
||||||
|
* it is currently unclear whether Nauthilus supports OIDC token authentication
|
||||||
|
* ✅ JMAP clients with basic authentication
|
||||||
|
* Stalwart's Nauthilus Directory supports plain text authentication by relaying the authentication operation to Nauthilus, e.g. using its JSON API
|
||||||
|
* Nauthilus provides a response that contains user attributes from LDAP (display name, email addresses, ...)
|
||||||
|
* ❓ JMAP clients with bearer token authentication
|
||||||
|
* it is currently unclear whether Nauthilus supports OIDC token authentication
|
||||||
|
* ✅ OpenCloud Groupware with master authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* Stalwart detects and supports clear text password master authentication regardless of the Directory that is being used, and verifies it against the shared secret password that is configured in the server
|
||||||
|
* ❓ OpenCloud Groupware with generated token authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* it is currently unclear whether Nauthilus supports OIDC token authentication
|
||||||
|
* an optimization might be possible here, if the Nauthilus Directory implementation permits for the configuration of specific issuers which should then be verifying against a JWK set directly, whereas the fallback behaviour would be to query the Nauthilus API, but that does sound like a stretch to fit into the concept
|
||||||
|
|
||||||
|
### Stalwart with Nauthilus and an OpenCloud Authentication API
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
c(client)
|
||||||
|
j(client)
|
||||||
|
s(Stalwart)
|
||||||
|
n(Nauthilus)
|
||||||
|
o(OpenCloud)
|
||||||
|
l(LDAP)
|
||||||
|
k(Keycloak)
|
||||||
|
|
||||||
|
c -- IMAP/SMTP --> s
|
||||||
|
j -- JMAP --> s
|
||||||
|
s -- REST --> n
|
||||||
|
subgraph internal auth
|
||||||
|
n -- REST --> o
|
||||||
|
o -- LDAP --> l
|
||||||
|
o -- OIDC --> k
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
This option also makes use of the [Nauthilus authentication service](https://nauthilus.org/), but instead of it using LDAP to resolve users, we would either make use of its Lua scripting abilities to implement a backend that performs HTTP calls to an OpenCloud Authentication API, or implement an additional Nauthilus backend that uses the Nauthilus API to delegate to another instance, which would then be the OpenCloud Authentication API with support for the Nauthilus API.
|
||||||
|
|
||||||
|
⚠️ As with the previous option, it would require the implementation of a Stalwart Nauthilus Directory, **that is yet to be developed**.
|
||||||
|
|
||||||
|
Interestingly, if the OpenCloud Authentication API follows the Nauthilus API, this scenario can easily be degraded by dropping Nauthilus and, instead, having all services talk to the OpenCloud Authentication API directly.
|
||||||
|
|
||||||
|
* ✅ MUAs with basic authentication
|
||||||
|
* MUAs authenticate directly against Stalwart
|
||||||
|
* Stalwart's Nauthilus Directory supports plain text authentication by relaying the authentication operation to Nauthilus, e.g. using its JSON API
|
||||||
|
* Nauthilus provides a response that contains user attributes from LDAP (display name, email addresses, ...)
|
||||||
|
* ✅ MUAs with application password authentication
|
||||||
|
* Nauthilus would forward the authentication request to the OpenCloud Authentication API, which would support application passwords
|
||||||
|
* ❓ MUAs with SASL bearer token authentication
|
||||||
|
* it is currently unclear whether Nauthilus supports OIDC token authentication and whether it would be able to forward such requests to the OpenCloud Authentication API
|
||||||
|
* ✅ JMAP clients with basic authentication
|
||||||
|
* Stalwart's Nauthilus Directory supports plain text authentication by relaying the authentication operation to Nauthilus, e.g. using its JSON API
|
||||||
|
* Nauthilus then forwards that request to the OpenCloud Authentication API
|
||||||
|
* the OpenCloud Authentication API, and then Nauthilus, provides a response that contains user attributes from LDAP (display name, email addresses, ...) or claims from the JWT
|
||||||
|
* ❓ JMAP clients with bearer token authentication
|
||||||
|
* it is currently unclear whether Nauthilus supports OIDC token authentication and whether it would be able to forward such requests to the OpenCloud Authentication API
|
||||||
|
* ✅ OpenCloud Groupware with master authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* Stalwart detects and supports clear text password master authentication regardless of the Directory that is being used, and verifies it against the shared secret password that is configured in the server
|
||||||
|
* ❓ OpenCloud Groupware with generated token authentication
|
||||||
|
* the OpenCloud Groupware backend authenticates directly against Stalwart
|
||||||
|
* it is currently unclear whether Nauthilus supports OIDC token authentication and whether it would be able to forward such requests to the OpenCloud Authentication API
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> We need to clarify whether the Nauthilus API allows for a JWT to be submitted for the authentication request, and not only username and password – not to secure the request in itself, but to forward an OIDC token based authentication attempt as part of the payload.
|
||||||
|
|
||||||
|
### Comparing Options
|
||||||
|
|
||||||
|
| | MUA basic | MUA app password | MUA sasl | JMAP clients with basic auth | JMAP clients with JWT auth | Groupware Middleware with master auth | Groupware Middleware with JWT auth |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| Stalwart 0.12 with LDAP Directory | ✅ MUA → Stalwart | ❌ not supported with LDAP | ❌ not supported with LDAP | ✅ | ❌ | ✅ | ❌ |
|
||||||
|
| Stalwart 0.12 with OIDC Directory | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
|
||||||
|
| Stalwart 0.12 with Internal Directory | ✅ MUA → Stalwart, must be provisioned in Stalwart | ✅ MUA → Stalwart, must be provisioned in Stalwart | ❌ | ❌ | ❌ unless using Stalwart as IDP | ✅ | ❌ |
|
||||||
|
| Stalwart + OpenCloud Authentication API | ✅ MUA → Stalwart → OpenCloud | ✅ MUA → Stalwart → OpenCloud | ✅ MUA → Stalwart → OpenCloud | ✅ MUA → Stalwart → OpenCloud | ✅ MUA → Stalwart → OpenCloud | ✅ | ✅ |
|
||||||
|
| Stalwart + Nauthilus + LDAP | ✅ MUA → IMAP proxy → Nauthilus → LDAP | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ |
|
||||||
|
| Stalwart + Nauthilus + OpenCloud Authentication API | ✅ MUA → IMAP proxy → Nauthilus → OpenCloud | ✅ MUA → IMAP proxy → Nauthilus → OpenCloud | ✅ MUA → IMAP proxy → Nauthilus → OpenCloud | ✅ MUA → IMAP proxy → Nauthilus → OpenCloud | ✅ MUA → IMAP proxy → Nauthilus → OpenCloud | ✅ | ✅ |
|
||||||
|
| Stalwart + Nauthilus-like OpenCloud Authentication API | ✅ MUA → Stalwart → OpenCloud | ✅ MUA → Stalwart → OpenCloud | ✅ MUA → Stalwart → OpenCloud | ✅ MUA → Stalwart → OpenCloud | ✅ MUA → Stalwart → OpenCloud | ✅ | ✅ |
|
||||||
64
docs/adr/0003-groupware-microservice-vs-oc-integration.md
Normal file
64
docs/adr/0003-groupware-microservice-vs-oc-integration.md
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
status: proposed
|
||||||
|
date: 2025-06-24
|
||||||
|
author: Pascal Bleser <p.bleser@opencloud.eu>
|
||||||
|
decision-makers:
|
||||||
|
consulted:
|
||||||
|
informed:
|
||||||
|
title: "Implementing Groupware as a separate Microservice vs integrated in the OpenCloud Stack"
|
||||||
|
template: https://raw.githubusercontent.com/adr/madr/refs/tags/4.0.0/template/adr-template.md
|
||||||
|
---
|
||||||
|
|
||||||
|
* Status: draft
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Should the Groupware backend be an independent microservice or be part of the OpenCloud single binary framework?
|
||||||
|
|
||||||
|
The OpenCloud backend is built on a framework that
|
||||||
|
|
||||||
|
* implements token based authentication between services
|
||||||
|
* allows for a "single binary" deployment mode that runs all services within that one binary
|
||||||
|
* integrates services such as a NATS event bus
|
||||||
|
|
||||||
|
This decision is about whether the Groupware backend service should be implemented within that framework or, instead, be implemented as a standalone backend service.
|
||||||
|
|
||||||
|
## Decision Drivers
|
||||||
|
|
||||||
|
* single binary deployment strategy is potentially important (TODO how important is it really? stakeholders:?)
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
* have the Groupware Middleware as an independent microservice
|
||||||
|
* have the Groupware Middleware implemented within the existing OpenCloud framework
|
||||||
|
|
||||||
|
## Decision Outcome
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
### Consequences
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
### Confirmation
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## Pros and Cons of the Options
|
||||||
|
|
||||||
|
### Independent Microservice
|
||||||
|
|
||||||
|
* (potentially) good: be free from technical decisions made for the existing OpenCloud stack, to avoid carrying potential technical baggage
|
||||||
|
* (potentially) good: make use of a framework that is more fitting for the tasks the Groupware backend needs to accomplish
|
||||||
|
* bad: re-implement framework components that already exist, with the need to maintain those in two separate codebases, or the added complexity of a shared library repository
|
||||||
|
* bad: not have the ability to include the Groupware backend in the single binary deployment
|
||||||
|
* neutral: a separate code repository and delivery for the Groupware backend, which might or might not be of advantage
|
||||||
|
* neutral: may be implemented on a completely different technology stack, including the programming language
|
||||||
|
|
||||||
|
### Part of the framework
|
||||||
|
|
||||||
|
* good: fit into the opinionated choices that were made for the OpenCloud framework so far
|
||||||
|
* good: many aspects are already implemented in the current framework and can be made use of, potentially enhanced for the needs of the Groupware backend
|
||||||
|
* good: the ability to include the Groupware backend in the single binary deployment
|
||||||
|
* neutral: be in the same code repository and part of the same delivery as other services in OpenCloud
|
||||||
|
* neutral: must be implemented in Go on top of the same technology stack
|
||||||
294
docs/adr/0004-groupware-resource-linking.md
Normal file
294
docs/adr/0004-groupware-resource-linking.md
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
---
|
||||||
|
status: proposed
|
||||||
|
date: 2025-06-24
|
||||||
|
author: Pascal Bleser <p.bleser@opencloud.eu>
|
||||||
|
decision-makers:
|
||||||
|
consulted:
|
||||||
|
informed:
|
||||||
|
title: "Resource Linking"
|
||||||
|
template: https://raw.githubusercontent.com/adr/madr/refs/tags/4.0.0/template/adr-template.md
|
||||||
|
---
|
||||||
|
|
||||||
|
* Status: draft
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Which semantic and technical approach to take in order to provide strong integration of the various products and capabilities of OpenCloud, OpenTalk, and potentially other products as well?
|
||||||
|
|
||||||
|
## Decision Drivers
|
||||||
|
|
||||||
|
* a strong integration that allows users to access resources and relationships without having to switch views, which translates into a "mental switch" as well
|
||||||
|
* an innovative approach that differs from the traditional way groupware applications have been designed in the past
|
||||||
|
* TODO more decision drivers from PM
|
||||||
|
* a model that is open and generic enough to integrate many different types of resources and relationships
|
||||||
|
* a model that allows for independent and incremental upgrades to the resources and relationships that can be contributed by each service
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
* resource linking
|
||||||
|
* application launchers
|
||||||
|
* TODO? can we come up with more ideas?
|
||||||
|
|
||||||
|
## Decision Outcome
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
### Consequences
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
### Confirmation
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## Pros and Cons of the Options
|
||||||
|
|
||||||
|
### Resource Linking
|
||||||
|
|
||||||
|
This concept primarily resides on the idea of having resources, which have attributes, and relations between them, pretty much as [RDF (Resource Description Framework)](https://www.w3.org/RDF/) does, where the Groupware backend provides services to explore relations of a given resource.
|
||||||
|
|
||||||
|
* good: decoupling of UI, backends as well as other participants, as backends can gradually evolve the relationships and resources they understand and can contribute to over time, as well as for the UI that may just silently ignore resources it does not support yet or does not want to present to the user
|
||||||
|
* good: potential for an asynchronous architecture that would enable the UI to present some resources early without having to wait for those that require more processing time or are provided by services that happen to be under heavier load
|
||||||
|
* good: it should provide ammunition for a modern and original UI that is centered around resources and relationships rather than the usual visual paradigms
|
||||||
|
* bad: it might be a challenge to implement this approach in a performant way with rapid response times, as it could cause additional complexity and storage services (e.g. to denormalize reverse indexes, cache expensive resource graphs, etc...)
|
||||||
|
|
||||||
|
#### URNs
|
||||||
|
|
||||||
|
Each resource has a unique identifier, for which [URNs (Uniform Resource Names)](https://www.rfc-editor.org/rfc/rfc1737) seem the best representation.
|
||||||
|
|
||||||
|
URNs are composed of
|
||||||
|
|
||||||
|
* a namespace identifier
|
||||||
|
* a namespace-specific string
|
||||||
|
|
||||||
|
As a convention, we will use the following:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><code>urn:</code></th>
|
||||||
|
<th>ns</th>
|
||||||
|
<th colspan="2">namespace specific string</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><code>urn:</code></td>
|
||||||
|
<td><code>oc:</code></td>
|
||||||
|
<td><code><type>:</code></td>
|
||||||
|
<td><code><unique identifier>:</code></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
##### Examples
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><code>urn:</code></th>
|
||||||
|
<th>namespace</th>
|
||||||
|
<th>type</th>
|
||||||
|
<th>unique id</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><code>urn:</code></td>
|
||||||
|
<td><code>oc:</code></td>
|
||||||
|
<td><code>user:</code></td>
|
||||||
|
<td><code>camina.drummer</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>urn:</code></td>
|
||||||
|
<td><code>oc:</code></td>
|
||||||
|
<td><code>contact:</code></td>
|
||||||
|
<td><code>klaes.ashford</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>urn:</code></td>
|
||||||
|
<td><code>oc:</code></td>
|
||||||
|
<td><code>event:</code></td>
|
||||||
|
<td><code>dd4ea520-e414-41e1-b545-b1c7d4ce57e7</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>urn:</code></td>
|
||||||
|
<td><code>oc:</code></td>
|
||||||
|
<td><code>mail:</code></td>
|
||||||
|
<td><code><1e8074e8-cd56-4358-9f9e-f17cb701b950@opa.org></code></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
#### Exploration API
|
||||||
|
|
||||||
|
Whenever the user puts a resource into focus in the OpenCloud Groupware UI (i.e. by selecting/clicking that resource, e.g. the sender of an email), it may send a request to the Groupware service API to inquire about related resources.
|
||||||
|
|
||||||
|
What those related resources are still stands to be determined, but examples could be along the lines of
|
||||||
|
|
||||||
|
* unread emails from the same sender
|
||||||
|
* emails exchanged with that sender in the last 7 days
|
||||||
|
* files recently shared with that user
|
||||||
|
* spaces or groups in common with that user
|
||||||
|
* OpenTalk meetings planned within the next 3 days
|
||||||
|
|
||||||
|
In order to decouple the Groupware service from which resources and relations are supported,
|
||||||
|
|
||||||
|
* whenever such an exploration request is received, the Groupware service forwards it to all known services, in a "fan-out" model
|
||||||
|
* each service can understand the focused resource, or not, but if it does it may return related resources that it is capable of providing using its data model (e.g. OpenTalk providing related meeting resources, OpenCloud Groupware providing related calendar events, contacts, mails, etc...)
|
||||||
|
* ideally, that happens in an asynchronous fashion, using e.g. [SSE (Server Side Events)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) to push results to the OpenCloud UI to avoid having to wait for the slowest contributor, although that pushes the "reduce" part of this ["map-reduce" operation](https://en.wikipedia.org/wiki/MapReduce) to the client
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
c(client)
|
||||||
|
subgraph backend
|
||||||
|
a(opencloud api)
|
||||||
|
g(groupware)
|
||||||
|
ot(opentalk)
|
||||||
|
u(users)
|
||||||
|
s(stalwart)
|
||||||
|
k(keycloak)
|
||||||
|
end
|
||||||
|
subgraph storage
|
||||||
|
ots@{ shape: cyl, label: "opentalk\nstorage"}
|
||||||
|
ss@{ shape: cyl, label: "stalwart\nstorage"}
|
||||||
|
l@{ shape: cyl, label: "ldap"}
|
||||||
|
end
|
||||||
|
c-->|/related/urn:oc:user:camina.drummer|a
|
||||||
|
a-->|/related/urn:oc:user:camina.drummer|g
|
||||||
|
g-->s
|
||||||
|
s-->ss
|
||||||
|
a-->|/related/urn:oc:user:camina.drummer|ot
|
||||||
|
ot-->ots
|
||||||
|
a-->|/related/urn:oc:user:camina.drummer|u
|
||||||
|
u-->k
|
||||||
|
k-->l
|
||||||
|
|
||||||
|
ot-.->|urn:oc:meeting:232403bc-b98f-4643-a917-80bdcfc7aaba|a
|
||||||
|
g-.->|urn:oc:event:e5193ad3-8f1c-4162-8593-69fe659bcc08|a
|
||||||
|
```
|
||||||
|
|
||||||
|
This allows a decoupling of all the participants, enabling each service to add, remove or alter relationships that it is able to contribute for a given resource type.
|
||||||
|
|
||||||
|
Obviously, the UI needs to be able to understand resource types to know how to represent them, but if it silently ignores resource types that it does not know of, backends can evolve independently from the UI.
|
||||||
|
|
||||||
|
#### JSON-LD
|
||||||
|
|
||||||
|
[JSON-LD (JSON for Linking Data)](https://json-ld.org/) seems like a potent representation format for those relationships in a REST environment.
|
||||||
|
|
||||||
|
It could look something like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"@context": {
|
||||||
|
"@user": "https://schema.opencloud.eu/user.jsonld",
|
||||||
|
"link": "https://schema.opencloud.eu/linked.jsonld"
|
||||||
|
},
|
||||||
|
"@type": "urn:oc:type:user",
|
||||||
|
"@id": "urn:oc:user:cdrummer",
|
||||||
|
"name": "Camina Drummer",
|
||||||
|
"email": "camina@opa.org",
|
||||||
|
"roles": ["admin", "pirate"],
|
||||||
|
"link:rooms": [
|
||||||
|
{
|
||||||
|
"@context": {
|
||||||
|
"@room": "https://meta.opencloud.eu/room.jsonld",
|
||||||
|
"link": "https://schema.opencloud.eu/linked.jsonld"
|
||||||
|
},
|
||||||
|
"@id": "urn:oc:room:a3f19df6-6c7d-45fa-b16c-6e168e2a2a43",
|
||||||
|
"name": "OPA Leadership Standup 2355-02-27",
|
||||||
|
"start": "2355-02-27T10:58:15.918Z",
|
||||||
|
"end": "2355-02-27T13:52:59.010Z",
|
||||||
|
"started_by": {
|
||||||
|
"@context": "https://meta.opencloud.eu/user.jsonld",
|
||||||
|
"@type": "urn:oc:type:user",
|
||||||
|
"@id": "urn:oc:user:adawes",
|
||||||
|
"name": "Anderson Dawes",
|
||||||
|
"email": "anderson@opa.org"
|
||||||
|
},
|
||||||
|
"link:events": [
|
||||||
|
{
|
||||||
|
"@context": "https://meta.opencloud.eu/event.jsonld",
|
||||||
|
"@type": "urn:oc:type:event",
|
||||||
|
"@id": "urn:oc:event:3e041c88-088c-4015-a32e-5560561f6e26",
|
||||||
|
"start": "2355-02-27T11:09:15.918Z",
|
||||||
|
"end": "2355-02-27T13:52:59.010Z",
|
||||||
|
"status": "confirmed",
|
||||||
|
"invited": [
|
||||||
|
{
|
||||||
|
"@context": "https://meta.opencloud.eu/user.jsonld",
|
||||||
|
"@type": "urn:oc:type:user",
|
||||||
|
"@id": "urn:oc:user:adawes",
|
||||||
|
"name": "Anderson Dawes",
|
||||||
|
"email": "anderson@opa.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@context": "https://meta.opencloud.eu/user.jsonld",
|
||||||
|
"@type": "urn:oc:type:user",
|
||||||
|
"@id": "urn:oc:user:kashford",
|
||||||
|
"name": "Klaes Ashford",
|
||||||
|
"email": "klaes@opa.org"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"@context": "https://meta.opencloud.eu/contact.jsonld",
|
||||||
|
"@type": "urn:oc:type:contact",
|
||||||
|
"@id": "urn:oc:contact:9ccb247d-a728-4d8f-9259-c28cf6cef567",
|
||||||
|
"name": "Naomi Nagata",
|
||||||
|
"email": "naomo@opa.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@context": "https://meta.opencloud.eu/user.jsonld",
|
||||||
|
"@type": "urn:oc:type:user",
|
||||||
|
"@id": "urn:oc:user:adawes",
|
||||||
|
"name": "Anderson Dawes",
|
||||||
|
"email": "anderson@opa.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@context": "https://meta.opencloud.eu/user.jsonld",
|
||||||
|
"@type": "urn:oc:type:user",
|
||||||
|
"@id": "urn:oc:user:kashford",
|
||||||
|
"name": "Klaes Ashford",
|
||||||
|
"email": "klaes@opa.org"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"chat": {
|
||||||
|
"@context": "https://meta.opencloud.eu/file.jsonld",
|
||||||
|
"@type": "urn:oc:type:file",
|
||||||
|
"@id": "urn:oc:file:OPA:chatlogs/2355/02/27/a3f19df6-6c7d-45fa-b16c-6e168e2a2a43.md",
|
||||||
|
"href": "https://cloud.opencloud.eu/spaces/OPA/chatlogs/2355/02/27/a3f19df6-6c7d-45fa-b16c-6e168e2a2a43.md"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"link:mails": [
|
||||||
|
{
|
||||||
|
"@context": "https://meta.opencloud.eu/mail.jsonld",
|
||||||
|
"@type": "urn:oc:type:mail",
|
||||||
|
"@id": "583b9b66-c0b3-41ba-bf6c-a02ec5f4a638@smtp-07.opa.org",
|
||||||
|
"subject": "About bosmang Fred Johnson",
|
||||||
|
"date": "2355-01-03T09:39:44.919Z"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
],
|
||||||
|
"link:shares": [
|
||||||
|
{
|
||||||
|
"@context": "https://meta.opencloud.eu/share.jsonld",
|
||||||
|
"@type": "urn:oc:type:share",
|
||||||
|
"@id": "841ef259-584d-4ce6-827f-b53f900c988d",
|
||||||
|
"filename": "remember the cant.jpg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Application Launchers
|
||||||
|
|
||||||
|
Have a UI that is comprised of multiple more-or-less separate applications, with an application launcher bar, with each application being an icon in itself in that launcher.
|
||||||
|
|
||||||
|
Similar to what e.g. Google does, or Open-Xchange App Suite.
|
||||||
|
|
||||||
|
* bad: does not make for an integrated application paradigm since users still have to context switch between those applications/views to perform tasks
|
||||||
|
|
||||||
62
docs/adr/0005-groupware-software-stack.md
Normal file
62
docs/adr/0005-groupware-software-stack.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
status: proposed
|
||||||
|
date: 2025-06-25
|
||||||
|
author: Pascal Bleser <p.bleser@opencloud.eu>
|
||||||
|
decision-makers:
|
||||||
|
consulted:
|
||||||
|
informed:
|
||||||
|
title: "Groupware Software Stack"
|
||||||
|
template: https://raw.githubusercontent.com/adr/madr/refs/tags/4.0.0/template/adr-template.md
|
||||||
|
---
|
||||||
|
|
||||||
|
* Status: draft
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Which software stack to choose for the implementation of the OpenCloud Groupware service?
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
* [Go](https://go.dev/) with the OpenCloud framework, as it is used in OpenCloud
|
||||||
|
* Rust, as it is a similarly modern language, with know-how in Opentalk
|
||||||
|
* Java with an opinionated microservice framework (e.g. [Micronaut](https://micronaut.io/))
|
||||||
|
|
||||||
|
## Decision Outcome
|
||||||
|
|
||||||
|
The decision was taken to go with the existing Go technology stack used in OpenCloud, since it allows for
|
||||||
|
|
||||||
|
* everyone in the Groupware backend team to contribute
|
||||||
|
* having a single technology stack across all OpenCloud backend features
|
||||||
|
* having the option of a single binary deployment
|
||||||
|
|
||||||
|
### Consequences
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
### Confirmation
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## Pros and Cons of the Options
|
||||||
|
|
||||||
|
### Go
|
||||||
|
|
||||||
|
* good: established in the OpenCloud team, with expertise, potentially broadening the team that can contribute to Groupware development
|
||||||
|
* good: make use of the existing infrastructure and framework, including the single binary deployment option
|
||||||
|
* bad: less mature and capable technology stack, potentially problematic with regards to lack of asynchronous I/O and streamed HTTP processing
|
||||||
|
|
||||||
|
### Rust
|
||||||
|
|
||||||
|
* good: shared knowledge with the team of developers at OpenTalk
|
||||||
|
* bad: little to no experience in the current OpenCloud team
|
||||||
|
|
||||||
|
### Java
|
||||||
|
|
||||||
|
* bad: little to no experience in the current OpenCloud team, with exception of the Groupware members
|
||||||
|
* good: extensive experience with Micronaut with one OpenCloud developer
|
||||||
|
* good: opinionated and well documented
|
||||||
|
* good: cloud native
|
||||||
|
* good: mature technology stack
|
||||||
|
* good: asynchronous I/O and virtual threads make for efficient resource usage
|
||||||
|
* potentially bad: likely to not fit well into low resource environments (although native compilation using GraalVM is possible)
|
||||||
|
* potentially bad: prevents the single binary deployment option from including Groupware
|
||||||
73
docs/adr/0006-groupware-stalwart-as-backend.md
Normal file
73
docs/adr/0006-groupware-stalwart-as-backend.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
status: proposed
|
||||||
|
date: 2025-06-25
|
||||||
|
author: Pascal Bleser <p.bleser@opencloud.eu>
|
||||||
|
decision-makers:
|
||||||
|
consulted:
|
||||||
|
informed:
|
||||||
|
title: "Stalwart as Groupware Backend"
|
||||||
|
template: https://raw.githubusercontent.com/adr/madr/refs/tags/4.0.0/template/adr-template.md
|
||||||
|
---
|
||||||
|
|
||||||
|
* Status: draft
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Which Groupware backend should be used?
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
* [Stalwart](https://stalw.art/), contains not only mail but also collaborative features in an integrated package
|
||||||
|
* traditional IMAP/POP/SMTP stacks (e.g. [Dovecot](https://www.dovecot.org/) + [Postfix](https://www.postfix.org/))
|
||||||
|
|
||||||
|
## Decision Outcome
|
||||||
|
|
||||||
|
The decision was made to go with Stalwart, as it reduces the implementation effort on our end, allowing us for a much faster time-to-market with a significantly smaller team of developers.
|
||||||
|
|
||||||
|
### Consequences
|
||||||
|
|
||||||
|
We will most probably not need to develop much of a calendar or contact stack ourselves, as Stalwart is planning to implement those as part of the upcoming [JMAP](https://jmap.io/spec-core.html) specifications for [contacts](https://jmap.io/spec-contacts.html) and [calendars](https://jmap.io/spec-calendars.html).
|
||||||
|
|
||||||
|
The Groupware API will largely consist of a translation of high-level operations for the UI into JMAP operations sent to Stalwart.
|
||||||
|
|
||||||
|
#### Risks
|
||||||
|
|
||||||
|
On the flip side, there are a number of risks associated with that decision.
|
||||||
|
|
||||||
|
* Stalwart underdelivers on its promises
|
||||||
|
* calendaring provides insufficient features for our implementation (e.g. event series handling being too basic)
|
||||||
|
* not scaling for large deployments
|
||||||
|
* necessary adaptations (e.g. for authentication integration) are rejected upstream
|
||||||
|
* etc...
|
||||||
|
|
||||||
|
### Confirmation
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## Pros and Cons of the Options
|
||||||
|
|
||||||
|
### Stalwart
|
||||||
|
|
||||||
|
* good: integrated package that contains IMAP/POP, SMTP, anti-spam, AI, encryption at rest and many other features in one
|
||||||
|
* good: modern stack
|
||||||
|
* good: capable of fault tolerance in large deployments through its use of [FoundationDB](https://www.foundationdb.org/)
|
||||||
|
* bad: relatively new project with few to no large scale productive deployments (yet)
|
||||||
|
* bad: significant human [SPoF](https://en.wikipedia.org/wiki/Single_point_of_failure)/[bus factor](https://en.wikipedia.org/wiki/Bus_factor) issue as the development team currently consists of one
|
||||||
|
* good: supports and drives the JMAP protocol ([JMAP Core](https://jmap.io/spec-core.html), [JMAP Mail](https://jmap.io/spec-mail.html), [JMAP Contacts](https://jmap.io/spec-contacts.html), [JMAP Calendars](https://jmap.io/spec-calendars.html), [JMAP Tasks](https://jmap.io/spec-tasks.html), ...),
|
||||||
|
* which provides more high-level operations that we don't need to implement ourselves,
|
||||||
|
* as well as a much cleaner specification that reduces efforts too,
|
||||||
|
* and additionally can be implemented with an efficient stateless HTTP I/O stack
|
||||||
|
* bad: no viable broad JMAP implementation alternatives in case Stalwart does not deliver ([Apache James](https://james.apache.org/) only seems to support a basic subset of JMAP)
|
||||||
|
* good: implements a lot of Groupware "business logic" on its own, reducing the implementation effort on our end,
|
||||||
|
* most notably by not having to deal with IMAP extensions and quirks,
|
||||||
|
* or the complexity of calendar events
|
||||||
|
|
||||||
|
### IMAP/SMTP
|
||||||
|
|
||||||
|
* good: there are a number of alternatives in case a specific implementation does not deliver
|
||||||
|
* good: the best implementation candidates are well-established, used in large amounts of productive deployments, supported by teams of developers
|
||||||
|
* bad: more complex stack composed of numerous components as opposed to an all-in-one implementation
|
||||||
|
* bad: the effort and complexity of having to deal with IMAP,
|
||||||
|
* its complexity due to its extensions and its many quirks,
|
||||||
|
* as well as a significantly less efficient I/O stack that requires stateful session handling
|
||||||
|
* bad: requires the complete implementation of contacts, calendars and tasks in our own stack, as none of those services are provided by IMAP/SMTP backends
|
||||||
512
docs/adr/0007-groupware-webui-api.md
Normal file
512
docs/adr/0007-groupware-webui-api.md
Normal file
@@ -0,0 +1,512 @@
|
|||||||
|
---
|
||||||
|
status: accepted
|
||||||
|
date: 2025-07-22
|
||||||
|
author: pbleser-oc
|
||||||
|
consulted: AlexAndBear, butonic, dragotin, fschade, JammingBen, kulmann, martinherfurth, micbar, rhafer
|
||||||
|
title: "API for the Groupware Web UI"
|
||||||
|
---
|
||||||
|
<!-- markdownlint-disable-file MD024 MD033 -->
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
We need a comprehensive HTTP API for the OpenCloud Web UI to provide access to the following (upcoming) modules and Groupware functionalities:
|
||||||
|
|
||||||
|
* Mail
|
||||||
|
* Contacts
|
||||||
|
* Calendar
|
||||||
|
* Tasks
|
||||||
|
* Chat
|
||||||
|
* Configuration
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph clients
|
||||||
|
ui(OpenCloud UI)
|
||||||
|
muas(Other<br>MUAs)
|
||||||
|
end
|
||||||
|
subgraph Backend
|
||||||
|
subgraph OpenCloud
|
||||||
|
direction TB
|
||||||
|
groupware("OpenCloud<br>Groupware")
|
||||||
|
drive("OpenCloud<br>Drive")
|
||||||
|
end
|
||||||
|
stalwart(Stalwart)
|
||||||
|
end
|
||||||
|
subgraph Storage
|
||||||
|
drive_storage[(drive<br>storage)]
|
||||||
|
stalwart_metadata[(metadata<br>storage)]
|
||||||
|
stalwart_storage[(object<br>storage)]
|
||||||
|
end
|
||||||
|
ui x@==>|?|groupware
|
||||||
|
x@{ animate: true }
|
||||||
|
ui-->|Graph|drive
|
||||||
|
muas-->|IMAP,SMTP,*DAV|stalwart
|
||||||
|
groupware-->drive
|
||||||
|
groupware-->|JMAP|stalwart
|
||||||
|
drive-->drive_storage
|
||||||
|
stalwart-->stalwart_metadata
|
||||||
|
stalwart-->stalwart_storage
|
||||||
|
```
|
||||||
|
|
||||||
|
Additionally, the API must also be able to provide information about related resources and their relationships, as outlined in [the Resource Linking ADR](./0003-groupware-resource-linking.md).
|
||||||
|
|
||||||
|
For the OpenCloud Drive services, the communication between UI client and backend services is performed via the [LibreGraph API](https://github.com/opencloud-eu/libre-graph-api), which is based on [Microsoft Graph](https://developer.microsoft.com/en-us/graph). The goal of this ADR is **not** to question or change that decision, and the choice of an option is merely for the communication with the Groupware backend.
|
||||||
|
|
||||||
|
Communication between the OpenCloud Groupware and Stalwart will make use of the [JMAP (JSON Meta Application Protocol) protocol](https://jmap.io/spec-mail.html).
|
||||||
|
|
||||||
|
The API for the OpenCloud Web UI is **not** supposed to be an abstraction of that and thus may use JMAP data formats.
|
||||||
|
|
||||||
|
Other [MUAs (Mail User Agents)](https://en.wikipedia.org/wiki/Email_client) converse directly with Stalwart using [IMAP](https://en.wikipedia.org/wiki/Internet_Message_Access_Protocol) or [POP3](https://en.wikipedia.org/wiki/Post_Office_Protocol), [SMTP](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol), [CalDAV](https://en.wikipedia.org/wiki/CalDAV), [CardDAV](https://en.wikipedia.org/wiki/CardDAV), or JMAP itself.
|
||||||
|
|
||||||
|
This ADR concerns the decision regarding which API approach/process/technology/specification to use, not the details of the data model and such, which will need to be fleshed out following the requirements and priorities of the OpenCloud UI Client development, regardless of the selected approach.
|
||||||
|
|
||||||
|
## Decision Drivers
|
||||||
|
|
||||||
|
### UI Driven
|
||||||
|
|
||||||
|
The decision must be significantly driven by the OpenCloud UI Client developers, since they are the primary consumers of the API.
|
||||||
|
|
||||||
|
They will also be the sole consumers for a foreseeable while until the OpenCloud Groupware UI reaches a stable feature-complete milestone, which is the earliest point in time for the APIs to be considered stable as well and potentially be consumed by third parties.
|
||||||
|
|
||||||
|
Backend developers are stakeholders in that aspect as well though, as the choice of API approach has an impact on the complexity, costs and maintainability of the backend services as well.
|
||||||
|
|
||||||
|
### Economic Awareness
|
||||||
|
|
||||||
|
Reduction of complexity and implementation efforts, albeit not at all costs, and not only on the short run.
|
||||||
|
|
||||||
|
It is obviously of advantage when an option requires less implementation, or less complexity in its implementation.
|
||||||
|
|
||||||
|
### Efficiency
|
||||||
|
|
||||||
|
Regarding efficiency, the goal is to design an API that is tailored to providing responsiveness ([pagination](https://apisyouwonthate.com/blog/api-design-basics-pagination/), [SSEs (Server-Side Events)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events), ...) and good network performance.
|
||||||
|
|
||||||
|
The latter is achieved by minimizing the number of roundtrips between the client and the servers, which, in turn, is typically achieved through the use of higher level APIs as opposed to a granular API that provides more flexibility but also, by its very nature, requires the combination of multiple request-response roundtrips over the wire.
|
||||||
|
|
||||||
|
### Third Party Consumption
|
||||||
|
|
||||||
|
We are assuming that the APIs are public APIs (not just technically) and may be consumed by SDKs and third parties.
|
||||||
|
|
||||||
|
Implications are that care must be put into providing an API that is stable, versioned, has a changelog, and potentially provided as a product with [LTS (Long-term Support)](https://en.wikipedia.org/wiki/Long-term_support) options.
|
||||||
|
|
||||||
|
This also hints at the necessity of a capability exchange/discovery protocol between clients and the Groupware backend, as we will have different versions of clients and servers in the wild, and they need to be able to understand each other. Crucially, if locally running clients are developed, they can go a long time without being updated.
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
* [LibreGraph](#libregraph)
|
||||||
|
* [JMAP](#jmap)
|
||||||
|
* [custom REST API](#custom-rest-api) (albeit potentially based on standards, at least partially)
|
||||||
|
|
||||||
|
## Decision Outcome
|
||||||
|
|
||||||
|
The decision was made to go with the custom REST implementation option, mainly due to
|
||||||
|
|
||||||
|
* the use of LibreGraph providing little benefits
|
||||||
|
* if would provide us with a fleshed out API for groupware
|
||||||
|
* but we would not implement it fully
|
||||||
|
* and it is really an API for Outlook and Exchange, not a generic groupware standard
|
||||||
|
* furthermore, a significant blocker is that it does not provide for a way to support multiple accounts for a user
|
||||||
|
* the experience of implementing and using the LibreGraph API for the Drive components has made light of some challenges that we would not like to repeat
|
||||||
|
* using JMAP directly
|
||||||
|
* is a very interesting option in terms of standards, as it is an RFC,
|
||||||
|
* but we currently see that approach as too risky as per the potential complexity of parsing payloads of JMAP commands and their backreferences, plugging those across commands that must be forwarded as-is to Stalwart and others that need to be handled by the Groupware middleware itself, but also the potential need to reverse engineer the high-level meaning of chained low-level JMAP commands in order to implement enrichment, caches, reverse indexes, etc...
|
||||||
|
* however, it might be a better path forward in the future, especially if JMAP becomes a viable option for replacing the current use of LibreGraph as well
|
||||||
|
|
||||||
|
### Consequences
|
||||||
|
|
||||||
|
* we will need to design an API on our own, from scratch, albeit maximally making use of JMAP data structures
|
||||||
|
* that API will need to be maintained as a product, with documentation, versioning, LTS
|
||||||
|
|
||||||
|
## Pros and Cons of the Options
|
||||||
|
|
||||||
|
* [LibreGraph](#proscons-libregraph)
|
||||||
|
* [JMAP](#proscons-jmap)
|
||||||
|
* [Custom REST API](#proscons-custom)
|
||||||
|
|
||||||
|
### <a id="proscons-libregraph"/>LibreGraph
|
||||||
|
|
||||||
|
[LibreGraph](https://github.com/opencloud-eu/libre-graph-api) is an API specification that is heavily inspired by and based on [Microsoft Graph](https://developer.microsoft.com/en-us/graph), of which it is a partial implementation, but also with modifications where necessary.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /v1.0/me/messages?$select=sender,subject&$count=50&$orderby=received
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Good
|
||||||
|
|
||||||
|
* is already in use as the API for OpenCloud Drive operations, with a small stack to use it in the OpenCloud Web UI
|
||||||
|
* provides an API and data model that has already been thought out and used in production (albeit with only few different implementations)
|
||||||
|
|
||||||
|
#### Neutral
|
||||||
|
|
||||||
|
* does not have to follow the Microsoft Graph API, can be customized to our own needs, but in which case it becomes doubtful that there is any benefit in mimicking the Graph API in the first place if we diverge from it
|
||||||
|
* there is no compatibility benefit
|
||||||
|
* the only MUA that uses the Microsoft Graph API is Microsoft Outlook, and it is not a goal to support Microsoft Outlook as a MUA beyond standard IMAP/SMTP/CalDAV/CardDAV services (and that would be Microsoft Graph, not LibreGraph nor any customizations we would require)
|
||||||
|
* we will not implement all of the Microsoft Graph API
|
||||||
|
* we will not implement parts of the Microsoft Graph API as-is either, but will require to make modifications
|
||||||
|
* if there is a requirement for considering that API as a public API for third party integrators, then the API also needs to be documented, maintained, versioned, and kept stable as much as possible (this is neutral because it is a requirement that exists with every option)
|
||||||
|
|
||||||
|
#### Bad
|
||||||
|
|
||||||
|
* not an easy API to implement
|
||||||
|
* although we have libraries that take care of some of the more complex parts, such as parsing [OData](https://www.odata.org/) expressions
|
||||||
|
* really only easy to use when backed by a relational database and an object relational mapping framework using [ASP.NET](https://dotnet.microsoft.com/en-us/apps/aspnet) or [JPA](https://en.wikipedia.org/wiki/Jakarta_Persistence)/[Hibernate](https://hibernate.org/)
|
||||||
|
* its data model and peculiar interpretation of REST are really not [idomatic](https://en.wikipedia.org/wiki/HATEOAS) at all, and are clearly the result of reverse engineering the capabilities of Microsoft SQL Server and Exchange into a "standard" from the back, and then Microsoft Outlook's features and capabilities from the front
|
||||||
|
* not tailored to our needs
|
||||||
|
* we will most probably have a lot of cases in which we have to twist the Graph API to express what the UI needs
|
||||||
|
* will require using complex filters, which then require complex parsing in the backend in order to translate them into JMAP
|
||||||
|
* as opposed to directly using an expressive and maximally matching API in the first place
|
||||||
|
* we are likely to encounter use-cases that are not covered by the Graph API (especially due to our resource linking approach)
|
||||||
|
* does not support multiple accounts per user
|
||||||
|
* would require the addition of an account parameter, as a query parameter or as part of the path, which would make every URL in the API incompatible with Microsoft Graph
|
||||||
|
* more implementation effort than JMAP
|
||||||
|
* the JMAP RFCs already provides a data model, and we would end up converting between them all the time, with incompatibilities (Graph has attributes JMAP doesn't, and the other way around)
|
||||||
|
* possibly (probably?) more implementation effort than a custom REST API, due to its complexity
|
||||||
|
|
||||||
|
#### Decision Drivers
|
||||||
|
|
||||||
|
* UI Driven
|
||||||
|
* some members the OpenCloud Web Team strongly prefers not to use LibreGraph due to its complexity and to the fact that we would have to reftrofit operations into an existing API that was designed by a third party
|
||||||
|
* one upside is that there is already a client stack for performing LibreGraph operations, which could be reused to some degree for the Groupware APIs as well; it does not amount to all that much code though
|
||||||
|
* Economic Awareness
|
||||||
|
* more complexity and more effort as the other options due to the inherent complexity of the specification
|
||||||
|
* a data model is already specified in full, which might save us some time on that front
|
||||||
|
* although probably not really either since the actual data model we will work with on the backend is prescribed by JMAP, and we will only be looking to map attributes betsween JMAP and LibreGraph
|
||||||
|
* the data model is not necessarily thorougly documented either, which will leave room for interpretation, also due to incompatibilities between JMAP and Graph
|
||||||
|
* there will be attributes that are defined in JMAP and that we will receive from Stalwart that will not have a corresponding attribute in Graph (or be a list of values as opposed to a single value), and those will require to either lose some data by squashing it into the Graph data model, or extending the Graph data model which renders us incompatible with it
|
||||||
|
* Efficiency
|
||||||
|
* since the API is not tailored to our needs, we are much more likely to end up performing multiple roundtrips for single high level operations
|
||||||
|
* Third Party Consumption
|
||||||
|
* for some of the operations, we could point to the Microsoft Graph documentation, although that would not make for a great experience either, we would probably need to replicate it
|
||||||
|
* our deviations and extensions will have to be maintained just like the other options
|
||||||
|
* LibreGraph doesn't help with API stability either since
|
||||||
|
* we don't implement all of it, and need to document what we implement and what we don't,
|
||||||
|
* won't be compatible either due to modifications (additional parameters, unsupported parameters, different interpretations),
|
||||||
|
* and will just as equally need to evolve it as the other options, requiring the documentation of changes as well
|
||||||
|
* will be required to be maintained as a public API
|
||||||
|
* documentation
|
||||||
|
* LTS
|
||||||
|
* versioning
|
||||||
|
|
||||||
|
### <a id="proscons-jmap"/>JMAP
|
||||||
|
|
||||||
|
[JMAP (JSON Meta Application Protocol)](https://jmap.io/spec.html) is a set of specifications that are codified in RFCs:
|
||||||
|
|
||||||
|
* [RFC 8620](https://tools.ietf.org/html/rfc8620): core JMAP protocol
|
||||||
|
* [RFC 8261](https://tools.ietf.org/html/rfc8621): JMAP Mail
|
||||||
|
* [RFC 8887](https://www.rfc-editor.org/rfc/rfc8887.html): JMAP subprotocol for WebSocket
|
||||||
|
* [RFC 9404](https://www.rfc-editor.org/rfc/rfc9404.html): JMAP Blob Management Extension
|
||||||
|
* [RFC 9425](https://www.rfc-editor.org/rfc/rfc9425.html): JMAP Quotas
|
||||||
|
* [RFC 9553](https://www.rfc-editor.org/rfc/rfc9553.html): uses JSContact
|
||||||
|
* [RFC 8984](https://www.rfc-editor.org/rfc/rfc8984.html): uses JSCalendar
|
||||||
|
|
||||||
|
of which some are still in development at the time of writing:
|
||||||
|
|
||||||
|
* [JMAP Contacts](https://jmap.io/spec-contacts.html)
|
||||||
|
* [JMAP Calendars](https://jmap.io/spec-calendars.html)
|
||||||
|
* [JMAP Sharing](https://jmap.io/spec-sharing.html)
|
||||||
|
* [JMAP Tasks](https://jmap.io/spec-tasks.html)
|
||||||
|
|
||||||
|
To exemplify the JMAP protocol, the following code block is a JMAP request that
|
||||||
|
|
||||||
|
* fetches the 30 last received emails from a mailbox (folder)
|
||||||
|
* the threads of those emails
|
||||||
|
* email metadata of all of those threads, including a preview
|
||||||
|
|
||||||
|
<details open>
|
||||||
|
<summary>Click here to toggle the display of this example.</summary>
|
||||||
|
|
||||||
|
```json
|
||||||
|
[[ "Email/query", {
|
||||||
|
"accountId": "ue150411c",
|
||||||
|
"filter": {
|
||||||
|
"inMailbox": "fb666a55"
|
||||||
|
},
|
||||||
|
"sort": [{
|
||||||
|
"isAscending": false,
|
||||||
|
"property": "receivedAt"
|
||||||
|
}],
|
||||||
|
"collapseThreads": true,
|
||||||
|
"position": 0,
|
||||||
|
"limit": 30,
|
||||||
|
"calculateTotal": true
|
||||||
|
}, "0" ],
|
||||||
|
[ "Email/get", {
|
||||||
|
"accountId": "ue150411c",
|
||||||
|
"#ids": {
|
||||||
|
"resultOf": "0",
|
||||||
|
"name": "Email/query",
|
||||||
|
"path": "/ids"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
"threadId"
|
||||||
|
]
|
||||||
|
}, "1" ],
|
||||||
|
[ "Thread/get", {
|
||||||
|
"accountId": "ue150411c",
|
||||||
|
"#ids": {
|
||||||
|
"resultOf": "1",
|
||||||
|
"name": "Email/get",
|
||||||
|
"path": "/list/*/threadId"
|
||||||
|
}
|
||||||
|
}, "2" ],
|
||||||
|
[ "Email/get", {
|
||||||
|
"accountId": "ue150411c",
|
||||||
|
"#ids": {
|
||||||
|
"resultOf": "2",
|
||||||
|
"name": "Thread/get",
|
||||||
|
"path": "/list/*/emailIds"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
"threadId",
|
||||||
|
"mailboxIds",
|
||||||
|
"keywords",
|
||||||
|
"hasAttachment",
|
||||||
|
"from",
|
||||||
|
"subject",
|
||||||
|
"receivedAt",
|
||||||
|
"size",
|
||||||
|
"preview"
|
||||||
|
]
|
||||||
|
}, "3" ]]
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
#### Good
|
||||||
|
|
||||||
|
* flexible protocol that can easily be implemented by clients
|
||||||
|
* potentially does not require implementation efforts on the backend side
|
||||||
|
* would obviously support the full potential of JMAP and Stalwart
|
||||||
|
* we could potentially extend JMAP with our own data models and operations based on the [JMAP Core Protocol](https://jmap.io/spec-core.html), possibly even propose them as RFCs
|
||||||
|
* we can start with JMAP request objects that contain only a few or even only one JMAP methods (indicated by the [maxCallsInRequest capability](https://datatracker.ietf.org/doc/html/rfc8620#section-2)), allowing more calls as we need
|
||||||
|
* clients could implement the funtionality they need using multiple requests in the beginning, then we implement missing functionality on the server
|
||||||
|
* this would allow us to speed up requests that we need while at the same time giving clients the ability to make any necessary individual calls
|
||||||
|
* probably only a partially useful approach since chaining JMAP requests is necessary for even the most mundane operations, to avoid the inefficiency of multiple roundtrips
|
||||||
|
|
||||||
|
#### Neutral
|
||||||
|
|
||||||
|
* the [existing JMAP specifications](https://jmap.io/spec.html) will not cover 100% of the Web UI API needs (e.g. configuration settings[^config], [resource linking](./0003-groupware-resource-linking.md), ...), but that does not prevent us from implementing additional custom APIs, either as non-JMAP REST APIs, or as extensions of JMAP
|
||||||
|
* we would need to gauge whether JMAP communication
|
||||||
|
* should occur directly between the OpenCloud UI and Stalwart,
|
||||||
|
* or whether an OpenCloud Groupware service should be used as an intermediary and as an [anti-corruption layer](https://ddd-practitioners.com/home/glossary/bounded-context/bounded-context-relationship/anticorruption-layer/)
|
||||||
|
* if there is a requirement for considering that API as a public API for third party integrators, then the API also needs to be documented, maintained, versioned, and kept stable as much as possible (this is neutral because it is a requirement that exists with every option)
|
||||||
|
|
||||||
|
[^config]: although Stalwart will most likely have a [JMAP API for application configuration settings as well](https://matrix.to/#/!blIcSTIPwfKMtOEWcg:matrix.org/$CD9C6IZN28bbmN0Arb_Y-RapgsS4XqAqnDgf15yJahM?via=matrix.org&via=mozilla.org&via=chat.opencloud.eu)
|
||||||
|
> Message from [Mauro](https://github.com/mdecimus):
|
||||||
|
>
|
||||||
|
> Hi everyone, I'm curious what you think about standardizing a simple protocol/extension for users to easily manage certain account settings directly from their email clients. For instance, such a protocol could handle:
|
||||||
|
>
|
||||||
|
> * Passwords, app passwords, and MFA settings
|
||||||
|
> * Locale preferences
|
||||||
|
> * Timezone configuration
|
||||||
|
> * Basic email forwarding (without needing custom Sieve scripts)
|
||||||
|
> * Vacation/auto-responses
|
||||||
|
> * Blocking specific email addresses
|
||||||
|
> * Spam reporting (though not strictly a setting)
|
||||||
|
> * Calendar-related preferences
|
||||||
|
> * Encryption-at-rest settings
|
||||||
|
> * Mail auto-expunge policies
|
||||||
|
> * ... and potentially more.
|
||||||
|
>
|
||||||
|
> My initial thought is to implement this as a JMAP extension rather than inventing another protocol similar to ManageSieve, which feels somewhat like a "Frankenstein" IMAP extension.
|
||||||
|
>
|
||||||
|
> Many mailbox providers already offer some or all of these settings through their web interfaces, but a standardized JMAP-based extension could let users adjust these directly within their preferred email clients or via APIs.
|
||||||
|
|
||||||
|
#### Bad
|
||||||
|
|
||||||
|
* potentially bad: most probably too flexible for its own good, as it makes it difficult to reverse-engineer the high-level meaning of a set of JMAP requests in order to capture its semantics, e.g. to implement caching or reverse indexes for performance
|
||||||
|
* since the OpenCloud Drive backends use the LibreGraph API, using a JMAP based API for Groupware bears the risk of having multiple APIs to do the same thing, which we need to be careful about, and avoid if possible
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> This seems like a mild "bad" item, but the risk risk here is significant: if it turns out that we need to capture the semantics of API requests to perform additional operations (e.g. caching or indexing for performance reasons, or to decorate the data from Stalwart with information from other services), then we would have to re-implement the whole API as JMAP is too complex to parse to extract semantics from.
|
||||||
|
|
||||||
|
#### Two Approaches
|
||||||
|
|
||||||
|
There are two approaches as to how to implement our protocol based on JMAP:
|
||||||
|
|
||||||
|
* either our clients must split JMAP operations and send some to Stalwart, and others to the Groupware backend (depending on which endpoint is in charge of which API)
|
||||||
|
* or our clients send all the JMAP operations to the Groupware backend, which is then in charge to relay JMAP commands that are to be handled by Stalwart to Stalwart
|
||||||
|
|
||||||
|
##### Directly to Stalwart
|
||||||
|
|
||||||
|
If the OpenCloud UI Client communicates directly with Stalwart (using JMAP), then
|
||||||
|
|
||||||
|
* good: we don't need to implement any sort of "bridge" in the OpenCloud Groupware service (although the implementation effort is likely to be low)
|
||||||
|
* good: we avoid an additional hop in the network, gaining on performance and potentially on throughput
|
||||||
|
* bad: it will have to perform additional API requests for data and features that are not provided by Stalwart with the OpenCloud Groupware service (e.g. [Resource Linking](./0003-groupware-resource-linking.md)) as well, which is likely to lead to an increase in the number of network roundtrips
|
||||||
|
* bad: would be unable to extend the protocol with OpenCloud Groupware specific models and data
|
||||||
|
* bad: would be unable to implement caching or similar performance improvements if necessary
|
||||||
|
* bad: prevents us from implementing infrastructure features that are not present in Stalwart and might never be in the way we would need them, e.g. sharding across multi-site redundancy
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph clients
|
||||||
|
ui(OpenCloud UI)
|
||||||
|
muas(Other<br>MUAs)
|
||||||
|
end
|
||||||
|
subgraph Backend
|
||||||
|
subgraph OpenCloud
|
||||||
|
direction TB
|
||||||
|
groupware("OpenCloud<br>Groupware")
|
||||||
|
drive("OpenCloud<br>Drive")
|
||||||
|
end
|
||||||
|
stalwart(Stalwart)
|
||||||
|
end
|
||||||
|
subgraph Storage
|
||||||
|
drive_storage[(drive<br>storage)]
|
||||||
|
stalwart_metadata[(metadata<br>storage)]
|
||||||
|
stalwart_storage[(object<br>storage)]
|
||||||
|
end
|
||||||
|
ui x@==>|JMAP|stalwart
|
||||||
|
x@{ animate: true }
|
||||||
|
ui y@==>|JMAP or REST|groupware
|
||||||
|
y@{ animate: true }
|
||||||
|
ui-->|Graph|drive
|
||||||
|
muas-->|IMAP,SMTP,*DAV|stalwart
|
||||||
|
groupware-->drive
|
||||||
|
groupware-->|JMAP|stalwart
|
||||||
|
drive-->drive_storage
|
||||||
|
stalwart-->stalwart_metadata
|
||||||
|
stalwart-->stalwart_storage
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Groupware intermediary
|
||||||
|
|
||||||
|
Alternatively, if the OpenCloud UI Client exclusively communicates with the OpenCloud Groupware service (using JMAP), then
|
||||||
|
|
||||||
|
* good: the OpenCloud Groupware service acts as a anti-corruption layer, which would allow us to
|
||||||
|
* implement caching and similar performance improvement measures if necessary (e.g. reverse indexing of costly data)
|
||||||
|
* implement infrastructure features that are not present in Stalwart and might never be in the way we would need them, e.g. sharding across multi-site redundancy
|
||||||
|
* extend the JMAP protocol
|
||||||
|
* good: it enables us to minimize network roundtrips between the OpenCloud UI Client and the OpenCloud Groupware backend as there is no need to perform additional requests elsewhere
|
||||||
|
* bad: we have an additional intermediary hop that "just" relays operations to Stalwart most of the time
|
||||||
|
* due to Go HTTP stack limitations (lack of zero-copy asynchronous I/O),
|
||||||
|
* that might incur a cost of "needlessly" copying data in memory
|
||||||
|
* as well as performing blocking I/O (at the very least since JMAP requests first need to be read in full by te OpenCloud Groupware before they then can be sent to Stalwart more or less as-is, and the same applies to the responses)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph clients
|
||||||
|
ui(OpenCloud UI)
|
||||||
|
muas(Other<br>MUAs)
|
||||||
|
end
|
||||||
|
subgraph Backend
|
||||||
|
subgraph OpenCloud
|
||||||
|
direction TB
|
||||||
|
groupware("OpenCloud<br>Groupware")
|
||||||
|
drive("OpenCloud<br>Drive")
|
||||||
|
end
|
||||||
|
stalwart(Stalwart)
|
||||||
|
end
|
||||||
|
subgraph Storage
|
||||||
|
drive_storage[(drive<br>storage)]
|
||||||
|
stalwart_metadata[(metadata<br>storage)]
|
||||||
|
stalwart_storage[(object<br>storage)]
|
||||||
|
end
|
||||||
|
ui y@==>|JMAP|groupware
|
||||||
|
y@{ animate: true }
|
||||||
|
ui-->|Graph|drive
|
||||||
|
muas-->|IMAP,SMTP,*DAV|stalwart
|
||||||
|
groupware-->drive
|
||||||
|
groupware-->|JMAP|stalwart
|
||||||
|
drive-->drive_storage
|
||||||
|
stalwart-->stalwart_metadata
|
||||||
|
stalwart-->stalwart_storage
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Decision Drivers
|
||||||
|
|
||||||
|
* UI Driven
|
||||||
|
* the UI team did not express any particular preference for this option, but the JMAP protocol is simple to implement on any client
|
||||||
|
* Economic Awareness
|
||||||
|
* there would be less of a need to develop an API, but that doesn't put much into the balance
|
||||||
|
* developing a generic inbound JMAP command processing engine that is capable of resolving backreferences with requests that can be sent out to different backends (Stalwart, Drive, Groupware, OpenTalk, ...) seems risky in terms of complexity, also since Go doesn't have much of a [well-supported Reactive framework](https://github.com/ReactiveX/RxGo)
|
||||||
|
* Efficiency
|
||||||
|
* the ability of the JMAP protocol to chain multiple low-level commands provides for a very efficient way to compose higher-level operations without the need for multiple round-trips
|
||||||
|
* Third Party Consumption
|
||||||
|
* for some of the operations, we could point to the JMAP documentation and RFCs, although that would not make for a great experience either, we would probably need to replicate it
|
||||||
|
* our protocol extensions will have to be maintained just like the other options
|
||||||
|
* will be required to be maintained as a public API
|
||||||
|
* documentation
|
||||||
|
* LTS
|
||||||
|
* versioning
|
||||||
|
|
||||||
|
### <a id="proscons-custom"/>Custom REST API
|
||||||
|
|
||||||
|
A custom REST API would implement the resources and semantics as they are needed by the UI, and would be strongly if not fully UI-driven.
|
||||||
|
|
||||||
|
The data model should remain close or equal to JMAP's, to avoid data loss by converting back and forth.
|
||||||
|
|
||||||
|
We might look into existing specifications for formatting JSON payloads, such as [JSON:API](https://jsonapi.org/) or partial ones such as such as [JSON-LD](https://json-ld.org/) for relationships between resources, but this is currently outside of the scope of this ADR.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph clients
|
||||||
|
ui(OpenCloud UI)
|
||||||
|
muas(Other<br>MUAs)
|
||||||
|
end
|
||||||
|
subgraph Backend
|
||||||
|
subgraph OpenCloud
|
||||||
|
direction TB
|
||||||
|
groupware("OpenCloud<br>Groupware")
|
||||||
|
drive("OpenCloud<br>Drive")
|
||||||
|
end
|
||||||
|
stalwart(Stalwart)
|
||||||
|
end
|
||||||
|
subgraph Storage
|
||||||
|
drive_storage[(drive<br>storage)]
|
||||||
|
stalwart_metadata[(metadata<br>storage)]
|
||||||
|
stalwart_storage[(object<br>storage)]
|
||||||
|
end
|
||||||
|
ui y@==>|REST|groupware
|
||||||
|
y@{ animate: true }
|
||||||
|
ui-->|Graph|drive
|
||||||
|
muas-->|IMAP,SMTP,*DAV|stalwart
|
||||||
|
groupware-->drive
|
||||||
|
groupware-->|JMAP|stalwart
|
||||||
|
drive-->drive_storage
|
||||||
|
stalwart-->stalwart_metadata
|
||||||
|
stalwart-->stalwart_storage
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GET /groupware/startup/1/?mails=50
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Good
|
||||||
|
|
||||||
|
* completely tailored to the needs of the OpenCloud UI
|
||||||
|
* a higher-level API allows for easily understanding the semantic of each operation, which enables the potential for keeping track of data in order to implement reverse indexes and caching, if necessary to achieve functional or performance goals, as opposed to using a lower-level API such as JMAP which is maximally flexible and difficult to reverse-engineer the meaning of the operation and data
|
||||||
|
* can also be tailored to the capabilities of JMAP without exposing all of its flexibility
|
||||||
|
* provides the potential for expanding upon what JMAP provides
|
||||||
|
* would support the full potential of JMAP and Stalwart since the API would be designed accordingly
|
||||||
|
* allows learning how to use and cache individual JMAP method call responses, allowing to make a better decision in the future if JMAP should be used by clients
|
||||||
|
|
||||||
|
#### Neutral
|
||||||
|
|
||||||
|
* if there is a requirement for considering that API as a public API for third party integrators, then the API also needs to be documented, maintained, versioned, and kept stable as much as possible (this is neutral because it is a requirement that exists with every option)
|
||||||
|
|
||||||
|
#### Bad
|
||||||
|
|
||||||
|
* only partially follows any standards (REST, JSON, JMAP for data models)
|
||||||
|
* requires designing the API from scratch, as opposed to using the Graph API which already prescribes one
|
||||||
|
* although it probably makes sense to re-use the data model of JMAP, which is prescribed in RFCs, also to avoid data loss and copying things around needlessly
|
||||||
|
* since the OpenCloud Drive backends use the LibreGraph API, using a custom REST API for Groupware bears the risk of having multiple APIs to do the same thing, which we need to be careful about, and avoid if possible
|
||||||
|
|
||||||
|
#### Decision Drivers
|
||||||
|
|
||||||
|
* UI Driven
|
||||||
|
* favoured solution for the OpenCloud Web UI team
|
||||||
|
* Economic Awareness
|
||||||
|
* designing a new custom API is not much effort since it is UI requirements driven
|
||||||
|
* maintaining a new custom API or JMAP extensions is not more effort either, since the exact same thing needs to be done with LibreGraph, as it will have numerous exceptions and will require documenting those, as well as which parts of the Microsoft Graph API are implemented and which aren't
|
||||||
|
* Efficiency
|
||||||
|
* the most efficient approach since it is tailored to what is actually needed for the OpenCloud UI, which will allow us to reduce the roundtrips to a minimum
|
||||||
|
* Third Party Consumption
|
||||||
|
* a custom API will be required to be maintained as a public API
|
||||||
|
* documentation
|
||||||
|
* LTS
|
||||||
|
* versioning
|
||||||
52
docs/adr/0008-configuration-settings.md
Normal file
52
docs/adr/0008-configuration-settings.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
status: proposed
|
||||||
|
date: 2025-07-07
|
||||||
|
author: Pascal Bleser <p.bleser@opencloud.eu>
|
||||||
|
decision-makers:
|
||||||
|
consulted:
|
||||||
|
informed:
|
||||||
|
title: "Groupware Configuration Settings"
|
||||||
|
template: https://raw.githubusercontent.com/adr/madr/refs/tags/4.0.0/template/adr-template.md
|
||||||
|
---
|
||||||
|
|
||||||
|
* Status: draft
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
User Preferences need to be configurable through the UI and persisted in a backend service in order to be reliably available and backed up.
|
||||||
|
|
||||||
|
Such configuration options have default values that need to be set on multiple levels:
|
||||||
|
|
||||||
|
* globally
|
||||||
|
* by tenant
|
||||||
|
* by sub-tenant
|
||||||
|
* by group of users
|
||||||
|
* by user
|
||||||
|
|
||||||
|
Some options might even be client-specific, e.g. differ between the OpenCloud Web UI on desktop and the OpenCloud Web UI on mobile.
|
||||||
|
|
||||||
|
Furthermore, some options might be enforced and may not be overridden on every level (e.g. only globally or by tenant, by not modifiable by users.)
|
||||||
|
|
||||||
|
Ideally, the configuration settings have an architecture that permits pluggable sources.
|
||||||
|
|
||||||
|
This level of necessary complexity has a few drawbacks, the primary one being that it can become difficult to find out why a user sees this or that behavior in their UI, and thus to trace down where a given configuration setting is made (globally, on tenant level, etc...). It is thus critical to include tooling that allows to debug them.
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## Decision Outcome
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
### Consequences
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
### Confirmation
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## Pros and Cons of the Options
|
||||||
|
|
||||||
|
TODO
|
||||||
215
go.mod
215
go.mod
@@ -5,23 +5,29 @@ go 1.24.6
|
|||||||
require (
|
require (
|
||||||
dario.cat/mergo v1.0.2
|
dario.cat/mergo v1.0.2
|
||||||
github.com/CiscoM31/godata v1.0.11
|
github.com/CiscoM31/godata v1.0.11
|
||||||
github.com/KimMachineGun/automemlimit v0.7.4
|
github.com/KimMachineGun/automemlimit v0.7.5
|
||||||
github.com/Masterminds/semver v1.5.0
|
github.com/Masterminds/semver v1.5.0
|
||||||
|
github.com/MicahParks/jwkset v0.8.0
|
||||||
github.com/MicahParks/keyfunc/v2 v2.1.0
|
github.com/MicahParks/keyfunc/v2 v2.1.0
|
||||||
|
github.com/MicahParks/keyfunc/v3 v3.3.11
|
||||||
github.com/Nerzal/gocloak/v13 v13.9.0
|
github.com/Nerzal/gocloak/v13 v13.9.0
|
||||||
|
github.com/ProtonMail/go-crypto v1.1.5
|
||||||
github.com/bbalet/stopwords v1.0.0
|
github.com/bbalet/stopwords v1.0.0
|
||||||
github.com/beevik/etree v1.6.0
|
github.com/beevik/etree v1.6.0
|
||||||
github.com/blevesearch/bleve/v2 v2.5.4
|
github.com/blevesearch/bleve/v2 v2.5.7
|
||||||
|
github.com/brianvoe/gofakeit/v7 v7.7.3
|
||||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||||
github.com/coreos/go-oidc/v3 v3.16.0
|
github.com/coreos/go-oidc/v3 v3.17.0
|
||||||
github.com/cs3org/go-cs3apis v0.0.0-20250908152307-4ca807afe54e
|
github.com/cs3org/go-cs3apis v0.0.0-20250908152307-4ca807afe54e
|
||||||
github.com/davidbyttow/govips/v2 v2.16.0
|
github.com/davidbyttow/govips/v2 v2.16.0
|
||||||
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8
|
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8
|
||||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
||||||
github.com/gabriel-vasile/mimetype v1.4.11
|
github.com/emersion/go-imap/v2 v2.0.0-beta.5
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.12
|
||||||
github.com/ggwhite/go-masker v1.1.0
|
github.com/ggwhite/go-masker v1.1.0
|
||||||
github.com/go-chi/chi/v5 v5.2.3
|
github.com/go-chi/chi/v5 v5.2.4
|
||||||
github.com/go-chi/render v1.0.3
|
github.com/go-chi/render v1.0.3
|
||||||
|
github.com/go-crypt/crypt v0.4.5
|
||||||
github.com/go-jose/go-jose/v3 v3.0.4
|
github.com/go-jose/go-jose/v3 v3.0.4
|
||||||
github.com/go-ldap/ldap/v3 v3.4.12
|
github.com/go-ldap/ldap/v3 v3.4.12
|
||||||
github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3
|
github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3
|
||||||
@@ -33,8 +39,8 @@ require (
|
|||||||
github.com/go-micro/plugins/v4/store/nats-js-kv v0.0.0-20240726082623-6831adfdcdc4
|
github.com/go-micro/plugins/v4/store/nats-js-kv v0.0.0-20240726082623-6831adfdcdc4
|
||||||
github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus v1.2.0
|
github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus v1.2.0
|
||||||
github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry v1.2.0
|
github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry v1.2.0
|
||||||
github.com/go-playground/validator/v10 v10.28.0
|
github.com/go-playground/validator/v10 v10.30.1
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible
|
github.com/go-resty/resty/v2 v2.7.0
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||||
github.com/golang/protobuf v1.5.4
|
github.com/golang/protobuf v1.5.4
|
||||||
github.com/google/go-cmp v0.7.0
|
github.com/google/go-cmp v0.7.0
|
||||||
@@ -42,31 +48,35 @@ require (
|
|||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gookit/config/v2 v2.2.7
|
github.com/gookit/config/v2 v2.2.7
|
||||||
github.com/gorilla/mux v1.8.1
|
github.com/gorilla/mux v1.8.1
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4
|
||||||
github.com/invopop/validation v0.8.0
|
github.com/invopop/validation v0.8.0
|
||||||
github.com/jellydator/ttlcache/v2 v2.11.1
|
github.com/jellydator/ttlcache/v2 v2.11.1
|
||||||
github.com/jellydator/ttlcache/v3 v3.4.0
|
github.com/jellydator/ttlcache/v3 v3.4.0
|
||||||
|
github.com/jhillyerd/enmime/v2 v2.2.0
|
||||||
github.com/jinzhu/now v1.1.5
|
github.com/jinzhu/now v1.1.5
|
||||||
github.com/justinas/alice v1.2.0
|
github.com/justinas/alice v1.2.0
|
||||||
github.com/kovidgoyal/imaging v1.7.2
|
github.com/kovidgoyal/imaging v1.8.19
|
||||||
github.com/leonelquinteros/gotext v1.7.2
|
github.com/leonelquinteros/gotext v1.7.2
|
||||||
github.com/libregraph/idm v0.5.0
|
github.com/libregraph/idm v0.5.0
|
||||||
github.com/libregraph/lico v0.66.0
|
github.com/libregraph/lico v0.66.0
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.27
|
||||||
|
github.com/miekg/dns v1.1.57
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/mna/pigeon v1.3.0
|
github.com/mna/pigeon v1.3.0
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||||
github.com/nats-io/nats-server/v2 v2.12.1
|
github.com/nats-io/nats-server/v2 v2.12.3
|
||||||
github.com/nats-io/nats.go v1.47.0
|
github.com/nats-io/nats.go v1.48.0
|
||||||
github.com/oklog/run v1.2.0
|
github.com/oklog/run v1.2.0
|
||||||
github.com/olekukonko/tablewriter v1.1.0
|
github.com/olekukonko/tablewriter v1.1.2
|
||||||
github.com/onsi/ginkgo v1.16.5
|
github.com/onsi/ginkgo v1.16.5
|
||||||
github.com/onsi/ginkgo/v2 v2.27.2
|
github.com/onsi/ginkgo/v2 v2.27.5
|
||||||
github.com/onsi/gomega v1.38.2
|
github.com/onsi/gomega v1.39.0
|
||||||
github.com/open-policy-agent/opa v1.9.0
|
github.com/open-policy-agent/opa v1.12.3
|
||||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
|
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
|
||||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
|
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
|
||||||
github.com/opencloud-eu/reva/v2 v2.39.2-0.20251106122902-c13e27f55362
|
github.com/opencloud-eu/reva/v2 v2.41.1-0.20260120144836-2769c3c07a19
|
||||||
github.com/opensearch-project/opensearch-go/v4 v4.5.0
|
github.com/opensearch-project/opensearch-go/v4 v4.6.0
|
||||||
github.com/orcaman/concurrent-map v1.0.0
|
github.com/orcaman/concurrent-map v1.0.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pkg/xattr v0.4.12
|
github.com/pkg/xattr v0.4.12
|
||||||
@@ -76,44 +86,50 @@ require (
|
|||||||
github.com/rogpeppe/go-internal v1.14.1
|
github.com/rogpeppe/go-internal v1.14.1
|
||||||
github.com/rs/cors v1.11.1
|
github.com/rs/cors v1.11.1
|
||||||
github.com/rs/zerolog v1.34.0
|
github.com/rs/zerolog v1.34.0
|
||||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af
|
github.com/sethvargo/go-password v0.3.1
|
||||||
|
github.com/sirupsen/logrus v1.9.4
|
||||||
github.com/spf13/afero v1.15.0
|
github.com/spf13/afero v1.15.0
|
||||||
github.com/spf13/cobra v1.10.1
|
github.com/spf13/cobra v1.10.2
|
||||||
|
github.com/spf13/pflag v1.0.10
|
||||||
|
github.com/spf13/viper v1.21.0
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/test-go/testify v1.1.4
|
github.com/test-go/testify v1.1.4
|
||||||
github.com/testcontainers/testcontainers-go v0.39.0
|
github.com/testcontainers/testcontainers-go v0.40.0
|
||||||
github.com/testcontainers/testcontainers-go/modules/opensearch v0.39.0
|
github.com/testcontainers/testcontainers-go/modules/opensearch v0.40.0
|
||||||
github.com/theckman/yacspin v0.13.12
|
github.com/theckman/yacspin v0.13.12
|
||||||
github.com/thejerf/suture/v4 v4.0.6
|
github.com/thejerf/suture/v4 v4.0.6
|
||||||
github.com/tidwall/gjson v1.18.0
|
github.com/tidwall/gjson v1.18.0
|
||||||
|
github.com/tidwall/pretty v1.2.1
|
||||||
github.com/tidwall/sjson v1.2.5
|
github.com/tidwall/sjson v1.2.5
|
||||||
github.com/tus/tusd/v2 v2.8.0
|
github.com/tus/tusd/v2 v2.8.0
|
||||||
github.com/unrolled/secure v1.16.0
|
github.com/unrolled/secure v1.16.0
|
||||||
github.com/urfave/cli/v2 v2.27.7
|
github.com/urfave/cli/v2 v2.27.7
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||||
|
github.com/wk8/go-ordered-map v1.0.0
|
||||||
github.com/xhit/go-simple-mail/v2 v2.16.0
|
github.com/xhit/go-simple-mail/v2 v2.16.0
|
||||||
go-micro.dev/v4 v4.11.0
|
go-micro.dev/v4 v4.11.0
|
||||||
go.etcd.io/bbolt v1.4.3
|
go.etcd.io/bbolt v1.4.3
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0
|
||||||
go.opentelemetry.io/contrib/zpages v0.63.0
|
go.opentelemetry.io/contrib/zpages v0.64.0
|
||||||
go.opentelemetry.io/otel v1.38.0
|
go.opentelemetry.io/otel v1.39.0
|
||||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0
|
go.opentelemetry.io/otel/sdk v1.39.0
|
||||||
go.opentelemetry.io/otel/trace v1.38.0
|
go.opentelemetry.io/otel/trace v1.39.0
|
||||||
golang.org/x/crypto v0.43.0
|
golang.org/x/crypto v0.47.0
|
||||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
|
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
|
||||||
golang.org/x/image v0.32.0
|
golang.org/x/image v0.35.0
|
||||||
golang.org/x/net v0.46.0
|
golang.org/x/net v0.49.0
|
||||||
golang.org/x/oauth2 v0.32.0
|
golang.org/x/oauth2 v0.34.0
|
||||||
golang.org/x/sync v0.17.0
|
golang.org/x/sync v0.19.0
|
||||||
golang.org/x/term v0.36.0
|
golang.org/x/term v0.39.0
|
||||||
golang.org/x/text v0.30.0
|
golang.org/x/text v0.33.0
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4
|
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b
|
||||||
google.golang.org/grpc v1.76.0
|
google.golang.org/grpc v1.78.0
|
||||||
google.golang.org/protobuf v1.36.10
|
google.golang.org/protobuf v1.36.11
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gotest.tools/v3 v3.5.2
|
gotest.tools/v3 v3.5.2
|
||||||
stash.kopano.io/kgol/rndm v1.1.2
|
stash.kopano.io/kgol/rndm v1.1.2
|
||||||
)
|
)
|
||||||
@@ -123,30 +139,30 @@ require (
|
|||||||
filippo.io/edwards25519 v1.1.0 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
github.com/BurntSushi/toml v1.6.0 // indirect
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.4.0 // indirect
|
github.com/Masterminds/semver/v3 v3.4.0 // indirect
|
||||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.1.5 // indirect
|
|
||||||
github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect
|
github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect
|
||||||
github.com/agnivade/levenshtein v1.2.1 // indirect
|
github.com/agnivade/levenshtein v1.2.1 // indirect
|
||||||
github.com/ajg/form v1.5.1 // indirect
|
github.com/ajg/form v1.5.1 // indirect
|
||||||
github.com/alexedwards/argon2id v1.0.0 // indirect
|
github.com/alexedwards/argon2id v1.0.0 // indirect
|
||||||
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 // indirect
|
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 // indirect
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op // indirect
|
github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op // indirect
|
||||||
github.com/armon/go-radix v1.0.0 // indirect
|
github.com/armon/go-radix v1.0.0 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bitly/go-simplejson v0.5.0 // indirect
|
github.com/bitly/go-simplejson v0.5.0 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.22.0 // indirect
|
github.com/bits-and-blooms/bitset v1.22.0 // indirect
|
||||||
github.com/blevesearch/bleve_index_api v1.2.10 // indirect
|
github.com/blevesearch/bleve_index_api v1.2.11 // indirect
|
||||||
github.com/blevesearch/geo v0.2.4 // indirect
|
github.com/blevesearch/geo v0.2.4 // indirect
|
||||||
github.com/blevesearch/go-faiss v1.0.25 // indirect
|
github.com/blevesearch/go-faiss v1.0.26 // indirect
|
||||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||||
github.com/blevesearch/gtreap v0.1.1 // indirect
|
github.com/blevesearch/gtreap v0.1.1 // indirect
|
||||||
github.com/blevesearch/mmap-go v1.0.4 // indirect
|
github.com/blevesearch/mmap-go v1.0.4 // indirect
|
||||||
github.com/blevesearch/scorch_segment_api/v2 v2.3.12 // indirect
|
github.com/blevesearch/scorch_segment_api/v2 v2.3.13 // indirect
|
||||||
github.com/blevesearch/segment v0.9.1 // indirect
|
github.com/blevesearch/segment v0.9.1 // indirect
|
||||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||||
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
||||||
@@ -156,21 +172,25 @@ require (
|
|||||||
github.com/blevesearch/zapx/v13 v13.4.2 // indirect
|
github.com/blevesearch/zapx/v13 v13.4.2 // indirect
|
||||||
github.com/blevesearch/zapx/v14 v14.4.2 // indirect
|
github.com/blevesearch/zapx/v14 v14.4.2 // indirect
|
||||||
github.com/blevesearch/zapx/v15 v15.4.2 // indirect
|
github.com/blevesearch/zapx/v15 v15.4.2 // indirect
|
||||||
github.com/blevesearch/zapx/v16 v16.2.6 // indirect
|
github.com/blevesearch/zapx/v16 v16.2.8 // indirect
|
||||||
github.com/bluele/gcache v0.0.2 // indirect
|
github.com/bluele/gcache v0.0.2 // indirect
|
||||||
github.com/bombsimon/logrusr/v3 v3.1.0 // indirect
|
github.com/bombsimon/logrusr/v3 v3.1.0 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
github.com/ceph/go-ceph v0.36.0 // indirect
|
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||||
|
github.com/ceph/go-ceph v0.37.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cevaris/ordered_map v0.0.0-20190319150403-3adeae072e73 // indirect
|
github.com/cevaris/ordered_map v0.0.0-20190319150403-3adeae072e73 // indirect
|
||||||
|
github.com/clipperhouse/displaywidth v0.6.0 // indirect
|
||||||
|
github.com/clipperhouse/stringish v0.1.1 // indirect
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
|
||||||
github.com/cloudflare/circl v1.6.1 // indirect
|
github.com/cloudflare/circl v1.6.1 // indirect
|
||||||
github.com/containerd/errdefs v1.0.0 // indirect
|
github.com/containerd/errdefs v1.0.0 // indirect
|
||||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/containerd/platforms v1.0.0-rc.1 // indirect
|
github.com/containerd/platforms v1.0.0-rc.2 // indirect
|
||||||
github.com/coreos/go-semver v0.3.1 // indirect
|
github.com/coreos/go-semver v0.3.1 // indirect
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
github.com/coreos/go-systemd/v22 v22.6.0 // indirect
|
||||||
github.com/cornelk/hashmap v1.0.8 // indirect
|
github.com/cornelk/hashmap v1.0.8 // indirect
|
||||||
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||||
@@ -186,12 +206,14 @@ require (
|
|||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||||
github.com/docker/docker v28.3.3+incompatible // indirect
|
github.com/docker/docker v28.5.1+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.6.0 // indirect
|
github.com/docker/go-connections v0.6.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/ebitengine/purego v0.8.4 // indirect
|
github.com/ebitengine/purego v0.8.4 // indirect
|
||||||
github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc // indirect
|
github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc // indirect
|
||||||
|
github.com/emersion/go-message v0.18.1 // indirect
|
||||||
|
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/emvi/iso-639-1 v1.1.1 // indirect
|
github.com/emvi/iso-639-1 v1.1.1 // indirect
|
||||||
github.com/evanphx/json-patch/v5 v5.5.0 // indirect
|
github.com/evanphx/json-patch/v5 v5.5.0 // indirect
|
||||||
@@ -201,6 +223,7 @@ require (
|
|||||||
github.com/gdexlab/go-render v1.0.1 // indirect
|
github.com/gdexlab/go-render v1.0.1 // indirect
|
||||||
github.com/go-acme/lego/v4 v4.4.0 // indirect
|
github.com/go-acme/lego/v4 v4.4.0 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||||
|
github.com/go-crypt/x v0.4.7 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||||
github.com/go-git/go-git/v5 v5.13.2 // indirect
|
github.com/go-git/go-git/v5 v5.13.2 // indirect
|
||||||
@@ -217,11 +240,9 @@ require (
|
|||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||||
github.com/go-resty/resty/v2 v2.7.0 // indirect
|
|
||||||
github.com/go-sql-driver/mysql v1.9.3 // indirect
|
github.com/go-sql-driver/mysql v1.9.3 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||||
github.com/go-test/deep v1.1.0 // indirect
|
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/gobwas/httphead v0.1.0 // indirect
|
github.com/gobwas/httphead v0.1.0 // indirect
|
||||||
@@ -230,42 +251,48 @@ require (
|
|||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||||
github.com/gofrs/flock v0.13.0 // indirect
|
github.com/gofrs/flock v0.13.0 // indirect
|
||||||
|
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/gomodule/redigo v1.9.3 // indirect
|
github.com/gomodule/redigo v1.9.3 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/go-tpm v0.9.6 // indirect
|
github.com/google/go-tpm v0.9.7 // indirect
|
||||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||||
github.com/google/renameio/v2 v2.0.0 // indirect
|
github.com/google/renameio/v2 v2.0.1 // indirect
|
||||||
github.com/gookit/goutil v0.7.1 // indirect
|
github.com/gookit/goutil v0.7.1 // indirect
|
||||||
|
github.com/gorilla/css v1.0.1 // indirect
|
||||||
github.com/gorilla/handlers v1.5.1 // indirect
|
github.com/gorilla/handlers v1.5.1 // indirect
|
||||||
github.com/gorilla/schema v1.4.1 // indirect
|
github.com/gorilla/schema v1.4.1 // indirect
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||||
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
||||||
github.com/hashicorp/go-plugin v1.7.0 // indirect
|
github.com/hashicorp/go-plugin v1.7.0 // indirect
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/hashicorp/yamux v0.1.2 // indirect
|
github.com/hashicorp/yamux v0.1.2 // indirect
|
||||||
github.com/huandu/xstrings v1.5.0 // indirect
|
github.com/huandu/xstrings v1.5.0 // indirect
|
||||||
github.com/iancoleman/strcase v0.3.0 // indirect
|
github.com/iancoleman/strcase v0.3.0 // indirect
|
||||||
github.com/imdario/mergo v0.3.15 // indirect
|
github.com/imdario/mergo v0.3.15 // indirect
|
||||||
|
github.com/inbucket/html2text v0.9.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/jonboulle/clockwork v0.5.0 // indirect
|
github.com/jonboulle/clockwork v0.5.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/juliangruber/go-intersect v1.1.0 // indirect
|
github.com/juliangruber/go-intersect v1.1.0 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.2 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
|
||||||
github.com/klauspost/crc32 v1.3.0 // indirect
|
github.com/klauspost/crc32 v1.3.0 // indirect
|
||||||
github.com/kovidgoyal/go-parallel v1.0.1 // indirect
|
github.com/kovidgoyal/go-parallel v1.1.1 // indirect
|
||||||
|
github.com/kovidgoyal/go-shm v1.0.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
|
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
|
||||||
github.com/lestrrat-go/dsig v1.0.0 // indirect
|
github.com/lestrrat-go/dsig v1.0.0 // indirect
|
||||||
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect
|
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect
|
||||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||||
github.com/lestrrat-go/httprc/v3 v3.0.1 // indirect
|
github.com/lestrrat-go/httprc/v3 v3.0.1 // indirect
|
||||||
github.com/lestrrat-go/jwx/v3 v3.0.11 // indirect
|
github.com/lestrrat-go/jwx/v3 v3.0.12 // indirect
|
||||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||||
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
|
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
|
||||||
github.com/libregraph/oidc-go v1.1.0 // indirect
|
github.com/libregraph/oidc-go v1.1.0 // indirect
|
||||||
@@ -276,16 +303,15 @@ require (
|
|||||||
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
|
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.19 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.32 // indirect
|
github.com/mattn/go-sqlite3 v1.14.33 // indirect
|
||||||
github.com/maxymania/go-system v0.0.0-20170110133659-647cc364bf0b // indirect
|
github.com/maxymania/go-system v0.0.0-20170110133659-647cc364bf0b // indirect
|
||||||
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 // indirect
|
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 // indirect
|
||||||
github.com/miekg/dns v1.1.57 // indirect
|
|
||||||
github.com/mileusna/useragent v1.3.5 // indirect
|
github.com/mileusna/useragent v1.3.5 // indirect
|
||||||
github.com/minio/crc64nvme v1.1.0 // indirect
|
github.com/minio/crc64nvme v1.1.1 // indirect
|
||||||
github.com/minio/highwayhash v1.0.3 // indirect
|
github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 // indirect
|
||||||
github.com/minio/md5-simd v1.1.2 // indirect
|
github.com/minio/md5-simd v1.1.2 // indirect
|
||||||
github.com/minio/minio-go/v7 v7.0.97 // indirect
|
github.com/minio/minio-go/v7 v7.0.98 // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
@@ -296,16 +322,17 @@ require (
|
|||||||
github.com/moby/sys/userns v0.1.0 // indirect
|
github.com/moby/sys/userns v0.1.0 // indirect
|
||||||
github.com/moby/term v0.5.0 // indirect
|
github.com/moby/term v0.5.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/mschoch/smat v0.2.0 // indirect
|
github.com/mschoch/smat v0.2.0 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/nats-io/jwt/v2 v2.8.0 // indirect
|
github.com/nats-io/jwt/v2 v2.8.0 // indirect
|
||||||
github.com/nats-io/nkeys v0.4.11 // indirect
|
github.com/nats-io/nkeys v0.4.12 // indirect
|
||||||
github.com/nats-io/nuid v1.0.1 // indirect
|
github.com/nats-io/nuid v1.0.1 // indirect
|
||||||
github.com/nxadm/tail v1.4.8 // indirect
|
github.com/nxadm/tail v1.4.8 // indirect
|
||||||
|
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
|
||||||
github.com/olekukonko/errors v1.1.0 // indirect
|
github.com/olekukonko/errors v1.1.0 // indirect
|
||||||
github.com/olekukonko/ll v0.0.9 // indirect
|
github.com/olekukonko/ll v0.1.3 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||||
@@ -313,79 +340,82 @@ require (
|
|||||||
github.com/pablodz/inotifywaitgo v0.0.9 // indirect
|
github.com/pablodz/inotifywaitgo v0.0.9 // indirect
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/philhofer/fwd v1.2.0 // indirect
|
github.com/philhofer/fwd v1.2.0 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||||
github.com/pquerna/cachecontrol v0.2.0 // indirect
|
github.com/pquerna/cachecontrol v0.2.0 // indirect
|
||||||
github.com/prometheus/alertmanager v0.28.1 // indirect
|
github.com/prometheus/alertmanager v0.30.1 // indirect
|
||||||
github.com/prometheus/client_model v0.6.2 // indirect
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
github.com/prometheus/common v0.66.1 // indirect
|
github.com/prometheus/common v0.67.4 // indirect
|
||||||
github.com/prometheus/procfs v0.17.0 // indirect
|
github.com/prometheus/procfs v0.17.0 // indirect
|
||||||
github.com/prometheus/statsd_exporter v0.22.8 // indirect
|
github.com/prometheus/statsd_exporter v0.22.8 // indirect
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect
|
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
|
||||||
github.com/rs/xid v1.6.0 // indirect
|
github.com/rs/xid v1.6.0 // indirect
|
||||||
github.com/russellhaering/goxmldsig v1.5.0 // indirect
|
github.com/russellhaering/goxmldsig v1.5.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
|
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
|
||||||
github.com/segmentio/asm v1.2.0 // indirect
|
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||||
github.com/segmentio/kafka-go v0.4.49 // indirect
|
github.com/samber/lo v1.51.0 // indirect
|
||||||
|
github.com/samber/slog-common v0.19.0 // indirect
|
||||||
|
github.com/samber/slog-zerolog/v2 v2.9.0 // indirect
|
||||||
|
github.com/segmentio/asm v1.2.1 // indirect
|
||||||
|
github.com/segmentio/kafka-go v0.4.50 // indirect
|
||||||
github.com/segmentio/ksuid v1.0.4 // indirect
|
github.com/segmentio/ksuid v1.0.4 // indirect
|
||||||
github.com/sercand/kuberesolver/v5 v5.1.1 // indirect
|
github.com/sercand/kuberesolver/v5 v5.1.1 // indirect
|
||||||
github.com/sergi/go-diff v1.4.0 // indirect
|
github.com/sergi/go-diff v1.4.0 // indirect
|
||||||
github.com/sethvargo/go-diceware v0.5.0 // indirect
|
github.com/sethvargo/go-diceware v0.5.0 // indirect
|
||||||
github.com/sethvargo/go-password v0.3.1 // indirect
|
|
||||||
github.com/shamaton/msgpack/v2 v2.4.0 // indirect
|
github.com/shamaton/msgpack/v2 v2.4.0 // indirect
|
||||||
github.com/shirou/gopsutil/v4 v4.25.6 // indirect
|
github.com/shirou/gopsutil/v4 v4.25.6 // indirect
|
||||||
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
|
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
|
||||||
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect
|
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect
|
||||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||||
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect
|
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect
|
||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||||
github.com/stretchr/objx v0.5.2 // indirect
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/studio-b12/gowebdav v0.9.0 // indirect
|
github.com/studio-b12/gowebdav v0.9.0 // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/tchap/go-patricia/v2 v2.3.3 // indirect
|
github.com/tchap/go-patricia/v2 v2.3.3 // indirect
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.1 // indirect
|
github.com/tinylib/msgp v1.6.1 // indirect
|
||||||
github.com/tinylib/msgp v1.3.0 // indirect
|
|
||||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
|
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
|
||||||
github.com/trustelem/zxcvbn v1.0.1 // indirect
|
github.com/trustelem/zxcvbn v1.0.1 // indirect
|
||||||
github.com/valyala/fastjson v1.6.4 // indirect
|
github.com/valyala/fastjson v1.6.4 // indirect
|
||||||
github.com/vektah/gqlparser/v2 v2.5.30 // indirect
|
github.com/vektah/gqlparser/v2 v2.5.31 // indirect
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||||
github.com/wk8/go-ordered-map v1.0.0 // indirect
|
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||||
github.com/yashtewari/glob-intersection v0.2.0 // indirect
|
github.com/yashtewari/glob-intersection v0.2.0 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.etcd.io/etcd/api/v3 v3.6.5 // indirect
|
go.etcd.io/etcd/api/v3 v3.6.7 // indirect
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.6.5 // indirect
|
go.etcd.io/etcd/client/pkg/v3 v3.6.7 // indirect
|
||||||
go.etcd.io/etcd/client/v3 v3.6.5 // indirect
|
go.etcd.io/etcd/client/v3 v3.6.7 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/mod v0.28.0 // indirect
|
golang.org/x/mod v0.31.0 // indirect
|
||||||
golang.org/x/sys v0.37.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/time v0.14.0 // indirect
|
golang.org/x/time v0.14.0 // indirect
|
||||||
golang.org/x/tools v0.37.0 // indirect
|
golang.org/x/tools v0.40.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
|
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
|
||||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -400,3 +430,6 @@ replace go-micro.dev/v4 => github.com/butonic/go-micro/v4 v4.11.1-0.202411151126
|
|||||||
exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||||
|
|
||||||
replace github.com/go-micro/plugins/v4/store/nats-js-kv => github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a
|
replace github.com/go-micro/plugins/v4/store/nats-js-kv => github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a
|
||||||
|
|
||||||
|
// to get the logger injection (https://github.com/pablodz/inotifywaitgo/pull/11)
|
||||||
|
replace github.com/pablodz/inotifywaitgo v0.0.9 => github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9
|
||||||
|
|||||||
406
go.sum
406
go.sum
@@ -65,15 +65,15 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt
|
|||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/CiscoM31/godata v1.0.11 h1:w7y8twuW02LdH6mak3/GJ5i0GrCv2IoZUJVqa/g5Yeo=
|
github.com/CiscoM31/godata v1.0.11 h1:w7y8twuW02LdH6mak3/GJ5i0GrCv2IoZUJVqa/g5Yeo=
|
||||||
github.com/CiscoM31/godata v1.0.11/go.mod h1:ZMiT6JuD3Rm83HEtiTx4JEChsd25YCrxchKGag/sdTc=
|
github.com/CiscoM31/godata v1.0.11/go.mod h1:ZMiT6JuD3Rm83HEtiTx4JEChsd25YCrxchKGag/sdTc=
|
||||||
github.com/DeepDiver1975/secure v0.0.0-20240611112133-abc838fb797c h1:ocsNvQ2tNHme4v/lTs17HROamc7mFzZfzWcg4m+UXN0=
|
github.com/DeepDiver1975/secure v0.0.0-20240611112133-abc838fb797c h1:ocsNvQ2tNHme4v/lTs17HROamc7mFzZfzWcg4m+UXN0=
|
||||||
github.com/DeepDiver1975/secure v0.0.0-20240611112133-abc838fb797c/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
|
github.com/DeepDiver1975/secure v0.0.0-20240611112133-abc838fb797c/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
|
||||||
github.com/KimMachineGun/automemlimit v0.7.4 h1:UY7QYOIfrr3wjjOAqahFmC3IaQCLWvur9nmfIn6LnWk=
|
github.com/KimMachineGun/automemlimit v0.7.5 h1:RkbaC0MwhjL1ZuBKunGDjE/ggwAX43DwZrJqVwyveTk=
|
||||||
github.com/KimMachineGun/automemlimit v0.7.4/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
|
github.com/KimMachineGun/automemlimit v0.7.5/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
|
||||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||||
@@ -82,8 +82,12 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1
|
|||||||
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||||
|
github.com/MicahParks/jwkset v0.8.0 h1:jHtclI38Gibmu17XMI6+6/UB59srp58pQVxePHRK5o8=
|
||||||
|
github.com/MicahParks/jwkset v0.8.0/go.mod h1:fVrj6TmG1aKlJEeceAz7JsXGTXEn72zP1px3us53JrA=
|
||||||
github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k=
|
github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k=
|
||||||
github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k=
|
github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k=
|
||||||
|
github.com/MicahParks/keyfunc/v3 v3.3.11 h1:eA6wNltwdSRX2gtpTwZseBCC9nGeBkI9KxHtTyZbDbo=
|
||||||
|
github.com/MicahParks/keyfunc/v3 v3.3.11/go.mod h1:y6Ed3dMgNKTcpxbaQHD8mmrYDUZWJAxteddA6OQj+ag=
|
||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
@@ -119,8 +123,8 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNg
|
|||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op h1:+OSa/t11TFhqfrX0EOSqQBDJ0YlpmK0rDSiB19dg9M0=
|
github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op h1:Ucf+QxEKMbPogRO5guBNe5cgd9uZgfoJLOYs8WWhtjM=
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E=
|
github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E=
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||||
@@ -134,6 +138,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
|
|||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||||
github.com/aws/aws-sdk-go v1.37.27/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
github.com/aws/aws-sdk-go v1.37.27/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||||
|
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||||
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
github.com/bbalet/stopwords v1.0.0 h1:0TnGycCtY0zZi4ltKoOGRFIlZHv0WqpoIGUsObjztfo=
|
github.com/bbalet/stopwords v1.0.0 h1:0TnGycCtY0zZi4ltKoOGRFIlZHv0WqpoIGUsObjztfo=
|
||||||
github.com/bbalet/stopwords v1.0.0/go.mod h1:sAWrQoDMfqARGIn4s6dp7OW7ISrshUD8IP2q3KoqPjc=
|
github.com/bbalet/stopwords v1.0.0/go.mod h1:sAWrQoDMfqARGIn4s6dp7OW7ISrshUD8IP2q3KoqPjc=
|
||||||
github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE=
|
github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE=
|
||||||
@@ -151,22 +157,22 @@ github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6
|
|||||||
github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=
|
github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=
|
||||||
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||||
github.com/blevesearch/bleve/v2 v2.5.4 h1:1iur8e+PHsxtncV2xIVuqlQme/V8guEDO2uV6Wll3lQ=
|
github.com/blevesearch/bleve/v2 v2.5.7 h1:2d9YrL5zrX5EBBW++GOaEKjE+NPWeZGaX77IM26m1Z8=
|
||||||
github.com/blevesearch/bleve/v2 v2.5.4/go.mod h1:yB4PnV4N2q5rTEpB2ndG8N2ISexBQEFIYgwx4ztfvoo=
|
github.com/blevesearch/bleve/v2 v2.5.7/go.mod h1:yj0NlS7ocGC4VOSAedqDDMktdh2935v2CSWOCDMHdSA=
|
||||||
github.com/blevesearch/bleve_index_api v1.2.10 h1:FMFmZCmTX6PdoLLvwUnKF2RsmILFFwO3h0WPevXY9fE=
|
github.com/blevesearch/bleve_index_api v1.2.11 h1:bXQ54kVuwP8hdrXUSOnvTQfgK0KI1+f9A0ITJT8tX1s=
|
||||||
github.com/blevesearch/bleve_index_api v1.2.10/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0=
|
github.com/blevesearch/bleve_index_api v1.2.11/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0=
|
||||||
github.com/blevesearch/geo v0.2.4 h1:ECIGQhw+QALCZaDcogRTNSJYQXRtC8/m8IKiA706cqk=
|
github.com/blevesearch/geo v0.2.4 h1:ECIGQhw+QALCZaDcogRTNSJYQXRtC8/m8IKiA706cqk=
|
||||||
github.com/blevesearch/geo v0.2.4/go.mod h1:K56Q33AzXt2YExVHGObtmRSFYZKYGv0JEN5mdacJJR8=
|
github.com/blevesearch/geo v0.2.4/go.mod h1:K56Q33AzXt2YExVHGObtmRSFYZKYGv0JEN5mdacJJR8=
|
||||||
github.com/blevesearch/go-faiss v1.0.25 h1:lel1rkOUGbT1CJ0YgzKwC7k+XH0XVBHnCVWahdCXk4U=
|
github.com/blevesearch/go-faiss v1.0.26 h1:4dRLolFgjPyjkaXwff4NfbZFdE/dfywbzDqporeQvXI=
|
||||||
github.com/blevesearch/go-faiss v1.0.25/go.mod h1:OMGQwOaRRYxrmeNdMrXJPvVx8gBnvE5RYrr0BahNnkk=
|
github.com/blevesearch/go-faiss v1.0.26/go.mod h1:OMGQwOaRRYxrmeNdMrXJPvVx8gBnvE5RYrr0BahNnkk=
|
||||||
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
|
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
|
||||||
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
|
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
|
||||||
github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y=
|
github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y=
|
||||||
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
|
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
|
||||||
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
|
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
|
||||||
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
|
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
|
||||||
github.com/blevesearch/scorch_segment_api/v2 v2.3.12 h1:GGZc2qwbyRBwtckPPkHkLyXw64mmsLJxdturBI1cM+c=
|
github.com/blevesearch/scorch_segment_api/v2 v2.3.13 h1:ZPjv/4VwWvHJZKeMSgScCapOy8+DdmsmRyLmSB88UoY=
|
||||||
github.com/blevesearch/scorch_segment_api/v2 v2.3.12/go.mod h1:JBRGAneqgLSI2+jCNjtwMqp2B7EBF3/VUzgDPIU33MM=
|
github.com/blevesearch/scorch_segment_api/v2 v2.3.13/go.mod h1:ENk2LClTehOuMS8XzN3UxBEErYmtwkE7MAArFTXs9Vc=
|
||||||
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
|
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
|
||||||
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
|
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
|
||||||
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
|
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
|
||||||
@@ -185,8 +191,8 @@ github.com/blevesearch/zapx/v14 v14.4.2 h1:2SGHakVKd+TrtEqpfeq8X+So5PShQ5nW6GNxT
|
|||||||
github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8=
|
github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8=
|
||||||
github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k=
|
github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k=
|
||||||
github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw=
|
github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw=
|
||||||
github.com/blevesearch/zapx/v16 v16.2.6 h1:OHuUl2GhM+FpBq9RwNsJ4k/QodqbMMHoQEgn/IHYpu8=
|
github.com/blevesearch/zapx/v16 v16.2.8 h1:SlnzF0YGtSlrsOE3oE7EgEX6BIepGpeqxs1IjMbHLQI=
|
||||||
github.com/blevesearch/zapx/v16 v16.2.6/go.mod h1:cuAPB+YoIyRngNhno1S1GPr9SfMk+x/SgAHBLXSIq3k=
|
github.com/blevesearch/zapx/v16 v16.2.8/go.mod h1:murSoCJPCk25MqURrcJaBQ1RekuqSCSfMjXH4rHyA14=
|
||||||
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||||
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||||
@@ -194,12 +200,14 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR
|
|||||||
github.com/bombsimon/logrusr/v3 v3.1.0 h1:zORbLM943D+hDMGgyjMhSAz/iDz86ZV72qaak/CA0zQ=
|
github.com/bombsimon/logrusr/v3 v3.1.0 h1:zORbLM943D+hDMGgyjMhSAz/iDz86ZV72qaak/CA0zQ=
|
||||||
github.com/bombsimon/logrusr/v3 v3.1.0/go.mod h1:PksPPgSFEL2I52pla2glgCyyd2OqOHAnFF5E+g8Ixco=
|
github.com/bombsimon/logrusr/v3 v3.1.0/go.mod h1:PksPPgSFEL2I52pla2glgCyyd2OqOHAnFF5E+g8Ixco=
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
|
github.com/brianvoe/gofakeit/v7 v7.7.3 h1:RWOATEGpJ5EVg2nN8nlaEyaV/aB4d6c3GqYrbqQekss=
|
||||||
|
github.com/brianvoe/gofakeit/v7 v7.7.3/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA=
|
||||||
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
|
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
|
||||||
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
|
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
|
||||||
github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3 h1:h8Z0hBv5tg/uZMKu8V47+DKWYVQg0lYP8lXDQq7uRpE=
|
github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3 h1:h8Z0hBv5tg/uZMKu8V47+DKWYVQg0lYP8lXDQq7uRpE=
|
||||||
github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3/go.mod h1:eE/tD53n3KbVrzrWxKLxdkGw45Fg1qaNLWjpJMvIUF4=
|
github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3/go.mod h1:eE/tD53n3KbVrzrWxKLxdkGw45Fg1qaNLWjpJMvIUF4=
|
||||||
github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA=
|
github.com/bytecodealliance/wasmtime-go/v39 v39.0.1 h1:RibaT47yiyCRxMOj/l2cvL8cWiWBSqDXHyqsa9sGcCE=
|
||||||
github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q=
|
github.com/bytecodealliance/wasmtime-go/v39 v39.0.1/go.mod h1:miR4NYIEBXeDNamZIzpskhJ0z/p8al+lwMWylQ/ZJb4=
|
||||||
github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
|
github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
|
||||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||||
@@ -210,8 +218,10 @@ github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1x
|
|||||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/ceph/go-ceph v0.36.0 h1:IDE4vEF+4fmjve+CPjD1WStgfQ+Lh6vD+9PMUI712KI=
|
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI=
|
||||||
github.com/ceph/go-ceph v0.36.0/go.mod h1:fGCbndVDLuHW7q2954d6y+tgPFOBnRLqJRe2YXyngw4=
|
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8=
|
||||||
|
github.com/ceph/go-ceph v0.37.0 h1:KXliBe3ZDr3/AtfY7n9d1MG7ippYNCVhMPcAgm05CFI=
|
||||||
|
github.com/ceph/go-ceph v0.37.0/go.mod h1:3y2tOlITlyuVFhy8v6PpCEfjMwKPfXJiH0/2hKZZQRE=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
@@ -223,6 +233,12 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
|||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/clipperhouse/displaywidth v0.6.0 h1:k32vueaksef9WIKCNcoqRNyKbyvkvkysNYnAWz2fN4s=
|
||||||
|
github.com/clipperhouse/displaywidth v0.6.0/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o=
|
||||||
|
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
|
||||||
|
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
|
||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
||||||
@@ -233,18 +249,19 @@ github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151X
|
|||||||
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E=
|
github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4=
|
||||||
github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
|
github.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-oidc/v3 v3.16.0 h1:qRQUCFstKpXwmEjDQTIbyY/5jF00+asXzSkmkoa/mow=
|
github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc=
|
||||||
github.com/coreos/go-oidc/v3 v3.16.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
|
github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
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-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
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/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cornelk/hashmap v1.0.8 h1:nv0AWgw02n+iDcawr5It4CjQIAcdMMKRrs10HOJYlrc=
|
github.com/cornelk/hashmap v1.0.8 h1:nv0AWgw02n+iDcawr5It4CjQIAcdMMKRrs10HOJYlrc=
|
||||||
github.com/cornelk/hashmap v1.0.8/go.mod h1:RfZb7JO3RviW/rT6emczVuC/oxpdz4UsSB2LJSclR1k=
|
github.com/cornelk/hashmap v1.0.8/go.mod h1:RfZb7JO3RviW/rT6emczVuC/oxpdz4UsSB2LJSclR1k=
|
||||||
@@ -303,8 +320,8 @@ github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E
|
|||||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||||
github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
||||||
github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
|
github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
|
||||||
github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||||
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
@@ -322,6 +339,12 @@ github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc h1:6IxmRbXV8WXVkcYcTzk
|
|||||||
github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc/go.mod h1:FdVN2WHg7zOHhJ7kZQdDorfFhIfqZaHttjAzDDvAXHE=
|
github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc/go.mod h1:FdVN2WHg7zOHhJ7kZQdDorfFhIfqZaHttjAzDDvAXHE=
|
||||||
github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
|
github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
|
||||||
github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ=
|
github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ=
|
||||||
|
github.com/emersion/go-imap/v2 v2.0.0-beta.5 h1:H3858DNmBuXyMK1++YrQIRdpKE1MwBc+ywBtg3n+0wA=
|
||||||
|
github.com/emersion/go-imap/v2 v2.0.0-beta.5/go.mod h1:BZTFHsS1hmgBkFlHqbxGLXk2hnRqTItUgwjSSCsYNAk=
|
||||||
|
github.com/emersion/go-message v0.18.1 h1:tfTxIoXFSFRwWaZsgnqS1DSZuGpYGzSmCZD8SK3QA2E=
|
||||||
|
github.com/emersion/go-message v0.18.1/go.mod h1:XpJyL70LwRvq2a8rVbHXikPgKj8+aI0kGdHlg16ibYA=
|
||||||
|
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 h1:oP4q0fw+fOSWn3DfFi4EXdT+B+gTtzx8GC9xsc26Znk=
|
||||||
|
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/emvi/iso-639-1 v1.1.1 h1:7jrl1Sqw9ZYWmCOaH+cpQotLbGr/khwlLPXlBvE8WXU=
|
github.com/emvi/iso-639-1 v1.1.1 h1:7jrl1Sqw9ZYWmCOaH+cpQotLbGr/khwlLPXlBvE8WXU=
|
||||||
@@ -345,12 +368,14 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8
|
|||||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||||
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
|
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
|
||||||
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
|
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
|
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||||
github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U=
|
github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U=
|
||||||
github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM=
|
github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM=
|
||||||
github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
|
github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
|
||||||
@@ -372,11 +397,15 @@ github.com/go-asn1-ber/asn1-ber v1.4.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro
|
|||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||||
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
|
github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4=
|
||||||
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
|
||||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||||
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||||
|
github.com/go-crypt/crypt v0.4.5 h1:cCR5vVejGk1kurwoGfkLxGORY+Pc9GiE7xKCpyHZ3n4=
|
||||||
|
github.com/go-crypt/crypt v0.4.5/go.mod h1:cQijpCkqavdF52J1bE0PObWwqKKjQCHASHQ2dtLzOJs=
|
||||||
|
github.com/go-crypt/x v0.4.7 h1:hObjW67nhq/GI1jaD7XCv5RoiVKzF46XIbULgzH71oU=
|
||||||
|
github.com/go-crypt/x v0.4.7/go.mod h1:K3q7VmLC0U1QFAPn0SQvXjkAtu6FJuH0rN9LNqobX6k=
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
@@ -447,8 +476,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
|||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
|
github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
|
||||||
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
|
github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
|
||||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
|
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
|
||||||
@@ -462,8 +491,8 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe
|
|||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
|
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
||||||
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw=
|
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw=
|
||||||
@@ -485,13 +514,15 @@ github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8
|
|||||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gofrs/uuid/v5 v5.3.2 h1:2jfO8j3XgSwlz/wHqemAEugfnTlikAYHhnqQ8Xh4fE0=
|
github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0=
|
||||||
github.com/gofrs/uuid/v5 v5.3.2/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
|
||||||
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
||||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
@@ -502,8 +533,9 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er
|
|||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
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-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/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
@@ -565,8 +597,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
|
|||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/go-tika v0.3.1 h1:l+jr10hDhZjcgxFRfcQChRLo1bPXQeLFluMyvDhXTTA=
|
github.com/google/go-tika v0.3.1 h1:l+jr10hDhZjcgxFRfcQChRLo1bPXQeLFluMyvDhXTTA=
|
||||||
github.com/google/go-tika v0.3.1/go.mod h1:DJh5N8qxXIl85QkqmXknd+PeeRkUOTbvwyYf7ieDz6c=
|
github.com/google/go-tika v0.3.1/go.mod h1:DJh5N8qxXIl85QkqmXknd+PeeRkUOTbvwyYf7ieDz6c=
|
||||||
github.com/google/go-tpm v0.9.6 h1:Ku42PT4LmjDu1H5C5ISWLlpI1mj+Zq7sPGKoRw2XROA=
|
github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA=
|
||||||
github.com/google/go-tpm v0.9.6/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
@@ -580,8 +612,8 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
|||||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
||||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
|
github.com/google/renameio/v2 v2.0.1 h1:HyOM6qd9gF9sf15AvhbptGHUnaLTpEI9akAFFU3VyW0=
|
||||||
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
|
github.com/google/renameio/v2 v2.0.1/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
@@ -599,6 +631,8 @@ github.com/gophercloud/gophercloud v0.16.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075
|
|||||||
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae/go.mod h1:wx8HMD8oQD0Ryhz6+6ykq75PJ79iPyEqYHfwZ4l7OsA=
|
github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae/go.mod h1:wx8HMD8oQD0Ryhz6+6ykq75PJ79iPyEqYHfwZ4l7OsA=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
|
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
||||||
|
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
||||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
@@ -608,14 +642,16 @@ github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWS
|
|||||||
github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E=
|
github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E=
|
||||||
github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
|
github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 h1:kEISI/Gx67NzH3nJxAmY/dGac80kKZgZt134u7Y/k1s=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4/go.mod h1:6Nz966r3vQYCqIzWsuEl9d7cf7mRhtDmm++sOxlnfxI=
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
@@ -641,6 +677,8 @@ github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
|||||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||||
@@ -657,6 +695,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
|
|||||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
|
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
|
||||||
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
|
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
|
||||||
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||||
|
github.com/inbucket/html2text v0.9.0 h1:ULJmVcBEMAcmLE+/rN815KG1Fx6+a4HhbUxiDiN+qks=
|
||||||
|
github.com/inbucket/html2text v0.9.0/go.mod h1:QDaumzl+/OzlSVbNohhmg+yAy5pKjUjzCKW2BMvztKE=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
@@ -683,6 +723,8 @@ github.com/jellydator/ttlcache/v2 v2.11.1/go.mod h1:RtE5Snf0/57e+2cLWFYWCCsLas2H
|
|||||||
github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
|
github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
|
||||||
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
|
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
github.com/jhillyerd/enmime/v2 v2.2.0 h1:Pe35MB96eZK5Q0XjlvPftOgWypQpd1gcbfJKAt7rsB8=
|
||||||
|
github.com/jhillyerd/enmime/v2 v2.2.0/go.mod h1:SOBXlCemjhiV2DvHhAKnJiWrtJGS/Ffuw4Iy7NjBTaI=
|
||||||
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
|
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
|
||||||
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
|
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
@@ -718,8 +760,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF
|
|||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
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/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
|
github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
@@ -731,10 +773,12 @@ github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXH
|
|||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kovidgoyal/go-parallel v1.0.1 h1:nYUjN+EdpbmQjTg3N5eTUInuXTB3/1oD2vHdaMfuHoI=
|
github.com/kovidgoyal/go-parallel v1.1.1 h1:1OzpNjtrUkBPq3UaqrnvOoB2F9RttSt811uiUXyI7ok=
|
||||||
github.com/kovidgoyal/go-parallel v1.0.1/go.mod h1:BJNIbe6+hxyFWv7n6oEDPj3PA5qSw5OCtf0hcVxWJiw=
|
github.com/kovidgoyal/go-parallel v1.1.1/go.mod h1:BJNIbe6+hxyFWv7n6oEDPj3PA5qSw5OCtf0hcVxWJiw=
|
||||||
github.com/kovidgoyal/imaging v1.7.2 h1:mmT6k6Az3mC6dbqdZ6Q9KQCdZFWTAQ+q97NyGZgJ/2c=
|
github.com/kovidgoyal/go-shm v1.0.0 h1:HJEel9D1F9YhULvClEHJLawoRSj/1u/EDV7MJbBPgQo=
|
||||||
github.com/kovidgoyal/imaging v1.7.2/go.mod h1:GdkCORjfZMMGFY0Pb7TDmRhj7PDhxF/QShKukSCj0VU=
|
github.com/kovidgoyal/go-shm v1.0.0/go.mod h1:Yzb80Xf9L3kaoB2RGok9hHwMIt7Oif61kT6t3+VnZds=
|
||||||
|
github.com/kovidgoyal/imaging v1.8.19 h1:zWJdQqF2tfSKjvoB7XpLRhVGbYsze++M0iaqZ4ZkhNk=
|
||||||
|
github.com/kovidgoyal/imaging v1.8.19/go.mod h1:I0q8RdoEuyc4G8GFOF9CaluTUHQSf68d6TmsqpvfRI8=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -765,8 +809,8 @@ github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZ
|
|||||||
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
||||||
github.com/lestrrat-go/httprc/v3 v3.0.1 h1:3n7Es68YYGZb2Jf+k//llA4FTZMl3yCwIjFIk4ubevI=
|
github.com/lestrrat-go/httprc/v3 v3.0.1 h1:3n7Es68YYGZb2Jf+k//llA4FTZMl3yCwIjFIk4ubevI=
|
||||||
github.com/lestrrat-go/httprc/v3 v3.0.1/go.mod h1:2uAvmbXE4Xq8kAUjVrZOq1tZVYYYs5iP62Cmtru00xk=
|
github.com/lestrrat-go/httprc/v3 v3.0.1/go.mod h1:2uAvmbXE4Xq8kAUjVrZOq1tZVYYYs5iP62Cmtru00xk=
|
||||||
github.com/lestrrat-go/jwx/v3 v3.0.11 h1:yEeUGNUuNjcez/Voxvr7XPTYNraSQTENJgtVTfwvG/w=
|
github.com/lestrrat-go/jwx/v3 v3.0.12 h1:p25r68Y4KrbBdYjIsQweYxq794CtGCzcrc5dGzJIRjg=
|
||||||
github.com/lestrrat-go/jwx/v3 v3.0.11/go.mod h1:XSOAh2SiXm0QgRe3DulLZLyt+wUuEdFo81zuKTLcvgQ=
|
github.com/lestrrat-go/jwx/v3 v3.0.12/go.mod h1:HiUSaNmMLXgZ08OmGBaPVvoZQgJVOQphSrGr5zMamS8=
|
||||||
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
||||||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||||
github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
|
github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
|
||||||
@@ -820,10 +864,10 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
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.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
|
||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||||
github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
|
github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0=
|
||||||
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||||
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
@@ -833,20 +877,22 @@ github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 h1:Z/i1e+gTZrmcGeZy
|
|||||||
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE=
|
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE=
|
||||||
github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE=
|
github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE=
|
||||||
github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A=
|
github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A=
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||||
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||||
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||||
github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws=
|
github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws=
|
||||||
github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
|
github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
|
||||||
github.com/minio/crc64nvme v1.1.0 h1:e/tAguZ+4cw32D+IO/8GSf5UVr9y+3eJcxZI2WOO/7Q=
|
github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI=
|
||||||
github.com/minio/crc64nvme v1.1.0/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
github.com/minio/crc64nvme v1.1.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
||||||
github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q=
|
github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 h1:KGuD/pM2JpL9FAYvBrnBBeENKZNh6eNtjqytV6TYjnk=
|
||||||
github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
|
github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
|
||||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||||
github.com/minio/minio-go/v7 v7.0.97 h1:lqhREPyfgHTB/ciX8k2r8k0D93WaFqxbJX36UZq5occ=
|
github.com/minio/minio-go/v7 v7.0.98 h1:MeAVKjLVz+XJ28zFcuYyImNSAh8Mq725uNW4beRisi0=
|
||||||
github.com/minio/minio-go/v7 v7.0.97/go.mod h1:re5VXuo0pwEtoNLsNuSr0RrLfT/MBtohwdaSmPPSRSk=
|
github.com/minio/minio-go/v7 v7.0.98/go.mod h1:cY0Y+W7yozf0mdIclrttzo1Iiu7mEf9y7nk2uXqMOvM=
|
||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||||
@@ -886,8 +932,9 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
@@ -901,12 +948,12 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
|
|||||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
||||||
github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g=
|
github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g=
|
||||||
github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA=
|
github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA=
|
||||||
github.com/nats-io/nats-server/v2 v2.12.1 h1:0tRrc9bzyXEdBLcHr2XEjDzVpUxWx64aZBm7Rl1QDrA=
|
github.com/nats-io/nats-server/v2 v2.12.3 h1:KRv+1n7lddMVgkJPQer+pt36TcO0ENxjilBmeWdjcHs=
|
||||||
github.com/nats-io/nats-server/v2 v2.12.1/go.mod h1:OEaOLmu/2e6J9LzUt2OuGjgNem4EpYApO5Rpf26HDs8=
|
github.com/nats-io/nats-server/v2 v2.12.3/go.mod h1:MQXjG9WjyXKz9koWzUc3jYUMKD8x3CLmTNy91IQQz3Y=
|
||||||
github.com/nats-io/nats.go v1.47.0 h1:YQdADw6J/UfGUd2Oy6tn4Hq6YHxCaJrVKayxxFqYrgM=
|
github.com/nats-io/nats.go v1.48.0 h1:pSFyXApG+yWU/TgbKCjmm5K4wrHu86231/w84qRVR+U=
|
||||||
github.com/nats-io/nats.go v1.47.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
github.com/nats-io/nats.go v1.48.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||||
github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0=
|
github.com/nats-io/nkeys v0.4.12 h1:nssm7JKOG9/x4J8II47VWCL1Ds29avyiQDRn0ckMvDc=
|
||||||
github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE=
|
github.com/nats-io/nkeys v0.4.12/go.mod h1:MT59A1HYcjIcyQDJStTfaOY6vhy9XTUjOFo+SVsvpBg=
|
||||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||||
@@ -923,41 +970,45 @@ github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+
|
|||||||
github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E=
|
github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E=
|
||||||
github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk=
|
github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
|
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc=
|
||||||
|
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0=
|
||||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
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.1.3 h1:sV2jrhQGq5B3W0nENUISCR6azIPf7UBUpVq0x/y70Fg=
|
||||||
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
github.com/olekukonko/ll v0.1.3/go.mod h1:b52bVQRRPObe+yyBl0TxNfhesL0nedD4Cht0/zx55Ew=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
|
github.com/olekukonko/tablewriter v1.1.2 h1:L2kI1Y5tZBct/O/TyZK1zIE9GlBj/TVs+AY5tZDCDSc=
|
||||||
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
|
github.com/olekukonko/tablewriter v1.1.2/go.mod h1:z7SYPugVqGVavWoA2sGsFIoOVNmEHxUAAMrhXONtfkg=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=
|
github.com/onsi/ginkgo/v2 v2.27.5 h1:ZeVgZMx2PDMdJm/+w5fE/OyG6ILo1Y3e+QX4zSR0zTE=
|
||||||
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
|
github.com/onsi/ginkgo/v2 v2.27.5/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
|
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
|
||||||
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
|
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
|
||||||
github.com/open-policy-agent/opa v1.9.0 h1:QWFNwbcc29IRy0xwD3hRrMc/RtSersLY1Z6TaID3vgI=
|
github.com/open-policy-agent/opa v1.12.3 h1:qe3m/w52baKC/HJtippw+hYBUKCzuBCPjB+D5P9knfc=
|
||||||
github.com/open-policy-agent/opa v1.9.0/go.mod h1:72+lKmTda0O48m1VKAxxYl7MjP/EWFZu9fxHQK2xihs=
|
github.com/open-policy-agent/opa v1.12.3/go.mod h1:RnDgm04GA1RjEXJvrsG9uNT/+FyBNmozcPvA2qz60M4=
|
||||||
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a h1:Sakl76blJAaM6NxylVkgSzktjo2dS504iDotEFJsh3M=
|
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a h1:Sakl76blJAaM6NxylVkgSzktjo2dS504iDotEFJsh3M=
|
||||||
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY=
|
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY=
|
||||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+lP5lUUIzjRGDg93WrQfZJZCaV1ZP3KeyXi8bzY=
|
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+lP5lUUIzjRGDg93WrQfZJZCaV1ZP3KeyXi8bzY=
|
||||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89/go.mod h1:vigJkNss1N2QEceCuNw/ullDehncuJNFB6mEnzfq9UI=
|
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89/go.mod h1:vigJkNss1N2QEceCuNw/ullDehncuJNFB6mEnzfq9UI=
|
||||||
|
github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9 h1:dIftlX03Bzfbujhp9B54FbgER0VBDWJi/w8RBxJlzxU=
|
||||||
|
github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9/go.mod h1:JWyDC6H+5oZRdUJUgKuaye+8Ph5hEs6HVzVoPKzWSGI=
|
||||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 h1:vD/EdfDUrv4omSFjrinT8Mvf+8D7f9g4vgQ2oiDrVUI=
|
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 h1:vD/EdfDUrv4omSFjrinT8Mvf+8D7f9g4vgQ2oiDrVUI=
|
||||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
|
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
|
||||||
github.com/opencloud-eu/reva/v2 v2.39.2-0.20251106122902-c13e27f55362 h1:O9oHbqPnC+tAQTbaLD4Tj6I5jmSmTLaQCynTHkFP+cI=
|
github.com/opencloud-eu/reva/v2 v2.41.1-0.20260120144836-2769c3c07a19 h1:8loHHe7FYd7zgIcGTlbHwre+bU/AAwREEYVd4SWM9/s=
|
||||||
github.com/opencloud-eu/reva/v2 v2.39.2-0.20251106122902-c13e27f55362/go.mod h1:hOCR1OHAhGY8ecpq6sIS5Ru1ZOC/hBgNz+sYf6CrO9Y=
|
github.com/opencloud-eu/reva/v2 v2.41.1-0.20260120144836-2769c3c07a19/go.mod h1:pv+w23JG0/qJweZbTzNNev//YEvlUML1L/2iXgKGkkg=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
github.com/opensearch-project/opensearch-go/v4 v4.5.0 h1:26XckmmF6MhlXt91Bu1yY6R51jy1Ns/C3XgIfvyeTRo=
|
github.com/opensearch-project/opensearch-go/v4 v4.6.0 h1:Ac8aLtDSmLEyOmv0r1qhQLw3b4vcUhE42NE9k+Z4cRc=
|
||||||
github.com/opensearch-project/opensearch-go/v4 v4.5.0/go.mod h1:VmFc7dqOEM3ZtLhrpleOzeq+cqUgNabqQG5gX0xId64=
|
github.com/opensearch-project/opensearch-go/v4 v4.6.0/go.mod h1:3iZtb4SNt3IzaxavKq0dURh1AmtVgYW71E4XqmYnIiQ=
|
||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||||
@@ -968,8 +1019,6 @@ github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CF
|
|||||||
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
|
github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA=
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||||
github.com/pablodz/inotifywaitgo v0.0.9 h1:njquRbBU7fuwIe5rEvtaniVBjwWzcpdUVptSgzFqZsw=
|
|
||||||
github.com/pablodz/inotifywaitgo v0.0.9/go.mod h1:hAfx2oN+WKg8miwUKPs52trySpPignlRBRxWcXVHku0=
|
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
@@ -977,6 +1026,8 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2D
|
|||||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
|
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
|
||||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||||
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
|
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
|
||||||
@@ -1003,8 +1054,8 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om
|
|||||||
github.com/pquerna/cachecontrol v0.2.0 h1:vBXSNuE5MYP9IJ5kjsdo8uq+w41jSPgvba2DEnkRx9k=
|
github.com/pquerna/cachecontrol v0.2.0 h1:vBXSNuE5MYP9IJ5kjsdo8uq+w41jSPgvba2DEnkRx9k=
|
||||||
github.com/pquerna/cachecontrol v0.2.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI=
|
github.com/pquerna/cachecontrol v0.2.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI=
|
||||||
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||||
github.com/prometheus/alertmanager v0.28.1 h1:BK5pCoAtaKg01BYRUJhEDV1tqJMEtYBGzPw8QdvnnvA=
|
github.com/prometheus/alertmanager v0.30.1 h1:427prmCHuy1rMmV7fl/TVQFh5A/78XQ/Mp+TsswZNGM=
|
||||||
github.com/prometheus/alertmanager v0.28.1/go.mod h1:0StpPUDDHi1VXeM7p2yYfeZgLVi/PPlt39vo9LQUHxM=
|
github.com/prometheus/alertmanager v0.30.1/go.mod h1:93PBumcTLr/gNtNtM0m7BcCffbvYP5bKuLBWiOnISaA=
|
||||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
@@ -1037,8 +1088,8 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9
|
|||||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||||
github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||||
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
|
github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc=
|
||||||
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI=
|
||||||
github.com/prometheus/procfs v0.0.0-20170703101242-e645f4e5aaa8/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20170703101242-e645f4e5aaa8/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
@@ -1063,9 +1114,6 @@ github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8A
|
|||||||
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/riandyrn/otelchi v0.12.2 h1:6QhGv0LVw/dwjtPd12mnNrl0oEQF4ZAlmHcnlTYbeAg=
|
github.com/riandyrn/otelchi v0.12.2 h1:6QhGv0LVw/dwjtPd12mnNrl0oEQF4ZAlmHcnlTYbeAg=
|
||||||
github.com/riandyrn/otelchi v0.12.2/go.mod h1:weZZeUJURvtCcbWsdb7Y6F8KFZGedJlSrgUjq9VirV8=
|
github.com/riandyrn/otelchi v0.12.2/go.mod h1:weZZeUJURvtCcbWsdb7Y6F8KFZGedJlSrgUjq9VirV8=
|
||||||
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/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
@@ -1085,12 +1133,20 @@ github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK
|
|||||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
|
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
|
||||||
|
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||||
|
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||||
|
github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
|
||||||
|
github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
|
||||||
|
github.com/samber/slog-common v0.19.0 h1:fNcZb8B2uOLooeYwFpAlKjkQTUafdjfqKcwcC89G9YI=
|
||||||
|
github.com/samber/slog-common v0.19.0/go.mod h1:dTz+YOU76aH007YUU0DffsXNsGFQRQllPQh9XyNoA3M=
|
||||||
|
github.com/samber/slog-zerolog/v2 v2.9.0 h1:6LkOabJmZdNLaUWkTC3IVVA+dq7b/V0FM6lz6/7+THI=
|
||||||
|
github.com/samber/slog-zerolog/v2 v2.9.0/go.mod h1:gnQW9VnCfM34v2pRMUIGMsZOVbYLqY/v0Wxu6atSVGc=
|
||||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
|
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
|
||||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||||
github.com/segmentio/kafka-go v0.4.49 h1:GJiNX1d/g+kG6ljyJEoi9++PUMdXGAxb7JGPiDCuNmk=
|
github.com/segmentio/kafka-go v0.4.50 h1:mcyC3tT5WeyWzrFbd6O374t+hmcu1NKt2Pu1L3QaXmc=
|
||||||
github.com/segmentio/kafka-go v0.4.49/go.mod h1:Y1gn60kzLEEaW28YshXyk2+VCUKbJ3Qr6DrnT3i4+9E=
|
github.com/segmentio/kafka-go v0.4.50/go.mod h1:Y1gn60kzLEEaW28YshXyk2+VCUKbJ3Qr6DrnT3i4+9E=
|
||||||
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
|
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
|
||||||
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
|
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
|
||||||
github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY=
|
github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY=
|
||||||
@@ -1116,8 +1172,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
|||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0=
|
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||||
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
||||||
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
||||||
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||||
@@ -1128,6 +1184,8 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s
|
|||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/smartystreets/gunit v1.0.4/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ=
|
github.com/smartystreets/gunit v1.0.4/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||||
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||||
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 h1:0jjO3HdJfOn6gYHD/ZNZh0LLMxEAqkYX7xoDPQReEgs=
|
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 h1:0jjO3HdJfOn6gYHD/ZNZh0LLMxEAqkYX7xoDPQReEgs=
|
||||||
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784/go.mod h1:ff/5myEGgtsAwf26goQCO905GrEm5ugEZSd6OWTsrhM=
|
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784/go.mod h1:ff/5myEGgtsAwf26goQCO905GrEm5ugEZSd6OWTsrhM=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
@@ -1137,9 +1195,11 @@ github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
|||||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||||
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
|
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
|
||||||
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
|
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||||
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
|
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
@@ -1149,6 +1209,10 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
|||||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
|
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||||
|
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||||
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
|
||||||
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
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/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
@@ -1170,14 +1234,16 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
|
|||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
|
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc=
|
github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc=
|
||||||
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
|
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
|
||||||
github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
|
github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
|
||||||
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
|
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
|
||||||
github.com/testcontainers/testcontainers-go v0.39.0 h1:uCUJ5tA+fcxbFAB0uP3pIK3EJ2IjjDUHFSZ1H1UxAts=
|
github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU=
|
||||||
github.com/testcontainers/testcontainers-go v0.39.0/go.mod h1:qmHpkG7H5uPf/EvOORKvS6EuDkBUPE3zpVGaH9NL7f8=
|
github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
|
||||||
github.com/testcontainers/testcontainers-go/modules/opensearch v0.39.0 h1:IkJUhR8AigQxv7qHZho/OtTU6JtiSdBGVh76o175JGo=
|
github.com/testcontainers/testcontainers-go/modules/opensearch v0.40.0 h1:3TIrGk0zXyO9CG2N6APo7auwWIwAvhkwE1reISif8LM=
|
||||||
github.com/testcontainers/testcontainers-go/modules/opensearch v0.39.0/go.mod h1:B7AhrDmQ4QbpzA0BeWvqzaJ8vbwcdEQDzybr35sBRfw=
|
github.com/testcontainers/testcontainers-go/modules/opensearch v0.40.0/go.mod h1:VA0UCTPu+Gcs7MzdzBnSl0qDnxquuphv3ngSGdX97Xs=
|
||||||
github.com/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o=
|
github.com/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o=
|
||||||
github.com/thanhpk/randstr v1.0.6/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
|
github.com/thanhpk/randstr v1.0.6/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
|
||||||
github.com/theckman/yacspin v0.13.12 h1:CdZ57+n0U6JMuh2xqjnjRq5Haj6v1ner2djtLQRzJr4=
|
github.com/theckman/yacspin v0.13.12 h1:CdZ57+n0U6JMuh2xqjnjRq5Haj6v1ner2djtLQRzJr4=
|
||||||
@@ -1194,8 +1260,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
|||||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||||
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
|
github.com/tinylib/msgp v1.6.1 h1:ESRv8eL3u+DNHUoSAAQRE50Hm162zqAnBoGv9PzScPY=
|
||||||
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
|
github.com/tinylib/msgp v1.6.1/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
|
||||||
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||||
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||||
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||||
@@ -1218,8 +1284,8 @@ github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXV
|
|||||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE=
|
github.com/vektah/gqlparser/v2 v2.5.31 h1:YhWGA1mfTjID7qJhd1+Vxhpk5HTgydrGU9IgkWBTJ7k=
|
||||||
github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
|
github.com/vektah/gqlparser/v2 v2.5.31/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts=
|
||||||
github.com/vinyldns/go-vinyldns v0.0.0-20200917153823-148a5f6b8f14/go.mod h1:RWc47jtnVuQv6+lY3c768WtXCas/Xi+U5UFc5xULmYg=
|
github.com/vinyldns/go-vinyldns v0.0.0-20200917153823-148a5f6b8f14/go.mod h1:RWc47jtnVuQv6+lY3c768WtXCas/Xi+U5UFc5xULmYg=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||||
@@ -1261,12 +1327,12 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ
|
|||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
||||||
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
||||||
go.etcd.io/etcd/api/v3 v3.6.5 h1:pMMc42276sgR1j1raO/Qv3QI9Af/AuyQUW6CBAWuntA=
|
go.etcd.io/etcd/api/v3 v3.6.7 h1:7BNJ2gQmc3DNM+9cRkv7KkGQDayElg8x3X+tFDYS+E0=
|
||||||
go.etcd.io/etcd/api/v3 v3.6.5/go.mod h1:ob0/oWA/UQQlT1BmaEkWQzI0sJ1M0Et0mMpaABxguOQ=
|
go.etcd.io/etcd/api/v3 v3.6.7/go.mod h1:xJ81TLj9hxrYYEDmXTeKURMeY3qEDN24hqe+q7KhbnI=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.6.5 h1:Duz9fAzIZFhYWgRjp/FgNq2gO1jId9Yae/rLn3RrBP8=
|
go.etcd.io/etcd/client/pkg/v3 v3.6.7 h1:vvzgyozz46q+TyeGBuFzVuI53/yd133CHceNb/AhBVs=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.6.5/go.mod h1:8Wx3eGRPiy0qOFMZT/hfvdos+DjEaPxdIDiCDUv/FQk=
|
go.etcd.io/etcd/client/pkg/v3 v3.6.7/go.mod h1:2IVulJ3FZ/czIGl9T4lMF1uxzrhRahLqe+hSgy+Kh7Q=
|
||||||
go.etcd.io/etcd/client/v3 v3.6.5 h1:yRwZNFBx/35VKHTcLDeO7XVLbCBFbPi+XV4OC3QJf2U=
|
go.etcd.io/etcd/client/v3 v3.6.7 h1:9WqA5RpIBtdMxAy1ukXLAdtg2pAxNqW5NUoO2wQrE6U=
|
||||||
go.etcd.io/etcd/client/v3 v3.6.5/go.mod h1:ZqwG/7TAFZ0BJ0jXRPoJjKQJtbFo/9NIY8uoFFKcCyo=
|
go.etcd.io/etcd/client/v3 v3.6.7/go.mod h1:2XfROY56AXnUqGsvl+6k29wrwsSbEh1lAouQB1vHpeE=
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
@@ -1277,34 +1343,34 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ=
|
||||||
go.opentelemetry.io/contrib/zpages v0.63.0 h1:TppOKuZGbqXMgsfjqq3i09N5Vbo1JLtLImUqiTPGnX4=
|
go.opentelemetry.io/contrib/zpages v0.64.0 h1:iMybqKVR8AHHxFX4DuEWJ9dY75+9E7+IPwUK3Ll7NxM=
|
||||||
go.opentelemetry.io/contrib/zpages v0.63.0/go.mod h1:5F8uugz75ay/MMhRRhxAXY33FuaI8dl7jTxefrIy5qk=
|
go.opentelemetry.io/contrib/zpages v0.64.0/go.mod h1:DnkiyoQ7Yx/NmmKn10b6M2YBXreUqq0qhFa/kYgSZME=
|
||||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0=
|
||||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0 h1:8UPA4IbVZxpsD76ihGOQiFml99GPAEZLohDXvqHdi6U=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0/go.mod h1:MZ1T/+51uIVKlRzGw1Fo46KEWThjlCBZKl2LzY5nv4g=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
@@ -1320,8 +1386,8 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|||||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
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.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
@@ -1345,8 +1411,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
|
|||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
|
||||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -1362,8 +1428,8 @@ golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScy
|
|||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||||
golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ=
|
golang.org/x/image v0.35.0 h1:LKjiHdgMtO8z7Fh18nGY6KDcoEtVfsgLDPeLyguqb7I=
|
||||||
golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc=
|
golang.org/x/image v0.35.0/go.mod h1:MwPLTVgvxSASsxdLzKrl8BRFuyqMyGhLwmC+TO1Sybk=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
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=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@@ -1388,8 +1454,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
|
||||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -1443,8 +1509,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
|||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@@ -1452,8 +1518,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
|
|||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||||
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
||||||
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -1471,8 +1537,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -1556,8 +1622,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|||||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
@@ -1569,8 +1635,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
|||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
|
||||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -1585,8 +1651,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@@ -1649,8 +1715,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
|
||||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
|
||||||
golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
|
golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
|
||||||
golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg=
|
golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -1714,10 +1780,10 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
|
|||||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
|
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
|
||||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
|
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4 h1:8XJ4pajGwOlasW+L13MnEGA8W4115jJySQtVfS2/IBU=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4/go.mod h1:NnuHhy+bxcg30o7FnVAZbXsPHUDQ9qKWAQKCD7VxFtk=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 h1:i8QOKZfYg6AbGVZzUAY3LrNWCKF8O6zFisU9Wl9RER4=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
@@ -1733,8 +1799,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
|
|||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e h1:m7aQHHqd0q89mRwhwS9Bx2rjyl/hsFAeta+uGrHsQaU=
|
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e h1:m7aQHHqd0q89mRwhwS9Bx2rjyl/hsFAeta+uGrHsQaU=
|
||||||
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e/go.mod h1:gID3PKrg7pWKntu9Ss6zTLJ0ttC0X9IHgREOCZwbCVU=
|
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e/go.mod h1:gID3PKrg7pWKntu9Ss6zTLJ0ttC0X9IHgREOCZwbCVU=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
@@ -1751,8 +1817,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
|||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
|
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
|
||||||
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
|
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ include ../.make/docs.mk
|
|||||||
|
|
||||||
.PHONY: dev-docker
|
.PHONY: dev-docker
|
||||||
dev-docker:
|
dev-docker:
|
||||||
docker build -f docker/Dockerfile.multiarch -t opencloudeu/opencloud:dev ..
|
docker build -f docker/Dockerfile.multiarch -t opencloudeu/opencloud:dev ../..
|
||||||
|
|
||||||
.PHONY: dev-docker-multiarch
|
.PHONY: dev-docker-multiarch
|
||||||
dev-docker-multiarch:
|
dev-docker-multiarch:
|
||||||
@@ -28,7 +28,7 @@ dev-docker-multiarch:
|
|||||||
docker buildx rm opencloudbuilder || true
|
docker buildx rm opencloudbuilder || true
|
||||||
docker buildx create --platform linux/arm64,linux/amd64 --name opencloudbuilder
|
docker buildx create --platform linux/arm64,linux/amd64 --name opencloudbuilder
|
||||||
docker buildx use opencloudbuilder
|
docker buildx use opencloudbuilder
|
||||||
cd .. && docker buildx build --platform linux/arm64,linux/amd64 --output type=docker --file opencloud/docker/Dockerfile.multiarch --tag opencloudeu/opencloud:dev-multiarch .
|
docker buildx build --platform linux/arm64,linux/amd64 --output type=docker --file docker/Dockerfile.multiarch --tag opencloudeu/opencloud:dev-multiarch ../..
|
||||||
docker buildx rm opencloudbuilder
|
docker buildx rm opencloudbuilder
|
||||||
|
|
||||||
.PHONY: debug-docker
|
.PHONY: debug-docker
|
||||||
|
|||||||
1
opencloud/cmd/opencloud/.gitignore
vendored
Normal file
1
opencloud/cmd/opencloud/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/__debug_bin*
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
FROM golang:alpine3.21 AS build
|
FROM golang:alpine3.22 AS build
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
ARG STRING
|
ARG STRING
|
||||||
|
ARG EDITION="dev"
|
||||||
|
|
||||||
RUN apk add bash make git curl gcc musl-dev libc-dev binutils-gold inotify-tools vips-dev
|
RUN apk add bash make git curl gcc musl-dev libc-dev binutils-gold inotify-tools vips-dev
|
||||||
|
|
||||||
WORKDIR /opencloud
|
WORKDIR /build
|
||||||
RUN --mount=type=bind,target=/opencloud \
|
RUN --mount=type=bind,target=/build,rw \
|
||||||
--mount=type=cache,target=/go/pkg/mod \
|
--mount=type=cache,target=/go/pkg/mod \
|
||||||
--mount=type=cache,target=/root/.cache \
|
--mount=type=cache,target=/root/.cache \
|
||||||
GOOS="${TARGETOS:-linux}" GOARCH="${TARGETARCH:-amd64}" ; \
|
GOOS="${TARGETOS:-linux}" GOARCH="${TARGETARCH:-amd64}" ; \
|
||||||
make -C opencloud release-linux-docker-${TARGETARCH} ENABLE_VIPS=true DIST=/dist
|
make -C opencloud/opencloud release-linux-docker-${TARGETARCH} ENABLE_VIPS=true DIST=/dist
|
||||||
|
|
||||||
FROM alpine:3.21
|
FROM alpine:3.22
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
ARG REVISION
|
ARG REVISION
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/backup"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/backup"
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
@@ -11,62 +13,34 @@ import (
|
|||||||
"github.com/opencloud-eu/opencloud/pkg/config/parser"
|
"github.com/opencloud-eu/opencloud/pkg/config/parser"
|
||||||
decomposedbs "github.com/opencloud-eu/reva/v2/pkg/storage/fs/decomposed/blobstore"
|
decomposedbs "github.com/opencloud-eu/reva/v2/pkg/storage/fs/decomposed/blobstore"
|
||||||
decomposeds3bs "github.com/opencloud-eu/reva/v2/pkg/storage/fs/decomposeds3/blobstore"
|
decomposeds3bs "github.com/opencloud-eu/reva/v2/pkg/storage/fs/decomposeds3/blobstore"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// BackupCommand is the entrypoint for the backup command
|
// BackupCommand is the entrypoint for the backup command
|
||||||
func BackupCommand(cfg *config.Config) *cli.Command {
|
func BackupCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
bckCmd := &cobra.Command{
|
||||||
Name: "backup",
|
Use: "backup",
|
||||||
Usage: "OpenCloud backup functionality",
|
Short: "OpenCloud backup functionality",
|
||||||
Subcommands: []*cli.Command{
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
ConsistencyCommand(cfg),
|
|
||||||
},
|
|
||||||
Before: func(c *cli.Context) error {
|
|
||||||
return configlog.ReturnError(parser.ParseConfig(cfg, true))
|
return configlog.ReturnError(parser.ParseConfig(cfg, true))
|
||||||
},
|
},
|
||||||
Action: func(_ *cli.Context) error {
|
|
||||||
fmt.Println("Read the docs")
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
bckCmd.AddCommand(ConsistencyCommand(cfg))
|
||||||
|
return bckCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConsistencyCommand is the entrypoint for the consistency Command
|
// ConsistencyCommand is the entrypoint for the consistency Command
|
||||||
func ConsistencyCommand(cfg *config.Config) *cli.Command {
|
func ConsistencyCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
consCmd := &cobra.Command{
|
||||||
Name: "consistency",
|
Use: "consistency",
|
||||||
Usage: "check backup consistency",
|
Short: "check backup consistency",
|
||||||
Flags: []cli.Flag{
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "basepath",
|
|
||||||
Aliases: []string{"p"},
|
|
||||||
Usage: "the basepath of the decomposedfs (e.g. /var/tmp/opencloud/storage/users)",
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "blobstore",
|
|
||||||
Aliases: []string{"b"},
|
|
||||||
Usage: "the blobstore type. Can be (none, decomposed, decomposeds3). Default decomposed",
|
|
||||||
Value: "decomposed",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "fail",
|
|
||||||
Usage: "exit with non-zero status if consistency check fails",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
basePath := c.String("basepath")
|
|
||||||
if basePath == "" {
|
|
||||||
fmt.Println("basepath is required")
|
|
||||||
return cli.ShowCommandHelp(c, "consistency")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bs backup.ListBlobstore
|
bs backup.ListBlobstore
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
switch c.String("blobstore") {
|
basePath, _ := cmd.Flags().GetString("basepath")
|
||||||
|
blobstoreFlag, _ := cmd.Flags().GetString("blobstore")
|
||||||
|
switch blobstoreFlag {
|
||||||
case "decomposeds3":
|
case "decomposeds3":
|
||||||
bs, err = decomposeds3bs.New(
|
bs, err = decomposeds3bs.New(
|
||||||
cfg.StorageUsers.Drivers.DecomposedS3.Endpoint,
|
cfg.StorageUsers.Drivers.DecomposedS3.Endpoint,
|
||||||
@@ -87,7 +61,8 @@ func ConsistencyCommand(cfg *config.Config) *cli.Command {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := backup.CheckProviderConsistency(basePath, bs, c.Bool("fail")); err != nil {
|
fail, _ := cmd.Flags().GetBool("fail")
|
||||||
|
if err := backup.CheckProviderConsistency(basePath, bs, fail); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -95,6 +70,11 @@ func ConsistencyCommand(cfg *config.Config) *cli.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
consCmd.Flags().StringP("basepath", "p", "", "the basepath of the decomposedfs (e.g. /var/tmp/opencloud/storage/users)")
|
||||||
|
_ = consCmd.MarkFlagRequired("basepath")
|
||||||
|
consCmd.Flags().StringP("blobstore", "b", "decomposed", "the blobstore type. Can be (none, decomposed, decomposeds3). Default decomposed")
|
||||||
|
consCmd.Flags().Bool("fail", false, "exit with non-zero status if consistency check fails")
|
||||||
|
return consCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package command
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -10,8 +11,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
@@ -21,105 +24,118 @@ import (
|
|||||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||||
"github.com/pkg/xattr"
|
"github.com/pkg/xattr"
|
||||||
"github.com/rogpeppe/go-internal/lockedfile"
|
"github.com/rogpeppe/go-internal/lockedfile"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BenchmarkCommand is the entrypoint for the benchmark commands.
|
// BenchmarkCommand is the entrypoint for the benchmark commands.
|
||||||
func BenchmarkCommand(cfg *config.Config) *cli.Command {
|
func BenchmarkCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
benchCmd := &cobra.Command{
|
||||||
Name: "benchmark",
|
Use: "benchmark",
|
||||||
Usage: "cli tools to test low and high level performance",
|
Short: "cli tools to test low and high level performance",
|
||||||
Category: "benchmark",
|
|
||||||
Subcommands: []*cli.Command{BenchmarkClientCommand(cfg), BenchmarkSyscallsCommand(cfg)},
|
|
||||||
}
|
}
|
||||||
|
benchCmd.AddCommand(BenchmarkClientCommand(cfg), BenchmarkSyscallsCommand(cfg))
|
||||||
|
return benchCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// BenchmarkClientCommand is the entrypoint for the benchmark client command.
|
// BenchmarkClientCommand is the entrypoint for the benchmark client command.
|
||||||
func BenchmarkClientCommand(cfg *config.Config) *cli.Command {
|
func BenchmarkClientCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
benchClientCmd := &cobra.Command{
|
||||||
Name: "client",
|
Use: "client",
|
||||||
|
Short: "Start a client that continuously makes web requests and prints stats. The options mimic curl, but we default to PROPFIND requests.",
|
||||||
Usage: "Start a client that continuously makes web requests and prints stats. The options mimic curl, but URL must be at the end.",
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
Flags: []cli.Flag{
|
jobs, err := cmd.Flags().GetInt("jobs")
|
||||||
|
if err != nil {
|
||||||
// TODO with v3 'flag.Persistent: true' can be set to make the order of flags no longer relevant \o/
|
return err
|
||||||
// flags mimicing curl
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "request",
|
|
||||||
Aliases: []string{"X"},
|
|
||||||
Value: "PROPFIND",
|
|
||||||
Usage: "Specifies a custom request method to use when communicating with the HTTP server.",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "user",
|
|
||||||
Aliases: []string{"u"},
|
|
||||||
Value: "admin:admin",
|
|
||||||
Usage: "Specify the user name and password to use for server authentication.",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "insecure",
|
|
||||||
Aliases: []string{"k"},
|
|
||||||
Usage: "Skip the TLS verification step and proceed without checking.",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "data",
|
|
||||||
Aliases: []string{"d"},
|
|
||||||
Usage: "Sends the specified data in a request to the HTTP server.",
|
|
||||||
// TODE support multiple data flags, support data-binary, data-raw
|
|
||||||
},
|
|
||||||
&cli.StringSliceFlag{
|
|
||||||
Name: "header",
|
|
||||||
Aliases: []string{"H"},
|
|
||||||
Usage: "Extra header to include in information sent.",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "rate",
|
|
||||||
Usage: `Specify the maximum transfer frequency you allow a client to use - in number of transfer starts per time unit (sometimes called request rate).
|
|
||||||
The request rate is provided as "N/U" where N is an integer number and U is a time unit. Supported units are 's' (second), 'm' (minute), 'h' (hour) and 'd' /(day, as in a 24 hour unit). The default time unit, if no "/U" is provided, is number of transfers per hour.`,
|
|
||||||
},
|
|
||||||
/*
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "oauth2-bearer",
|
|
||||||
Usage: "Specify the Bearer Token for OAUTH 2.0 server authentication.",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "user-agent",
|
|
||||||
Aliases: []string{"A"},
|
|
||||||
Value: "admin:admin",
|
|
||||||
Usage: "Specify the User-Agent string to send to the HTTP server.",
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
// other flags
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "bearer-token-command",
|
|
||||||
Usage: "Command to execute for a bearer token, e.g. 'oidc-token opencloud'. When set, disables basic auth.",
|
|
||||||
},
|
|
||||||
&cli.IntFlag{
|
|
||||||
Name: "every",
|
|
||||||
Usage: "Aggregate stats every time this amount of seconds has passed.",
|
|
||||||
},
|
|
||||||
&cli.IntFlag{
|
|
||||||
Name: "jobs",
|
|
||||||
Aliases: []string{"j"},
|
|
||||||
Value: 1,
|
|
||||||
Usage: "Number of parallel clients to start.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Category: "benchmark",
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
opt := clientOptions{
|
|
||||||
request: c.String("request"),
|
|
||||||
url: c.Args().First(),
|
|
||||||
insecure: c.Bool("insecure"),
|
|
||||||
jobs: c.Int("jobs"),
|
|
||||||
headers: make(map[string]string),
|
|
||||||
data: []byte(c.String("data")),
|
|
||||||
}
|
}
|
||||||
|
insecure, _ := cmd.Flags().GetBool("insecure")
|
||||||
|
opt := clientOptions{
|
||||||
|
url: args[0],
|
||||||
|
insecure: insecure,
|
||||||
|
jobs: jobs,
|
||||||
|
headers: make(map[string]string),
|
||||||
|
}
|
||||||
|
|
||||||
|
if d, _ := cmd.Flags().GetString("data-raw"); d != "" {
|
||||||
|
opt.request = "POST"
|
||||||
|
opt.headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||||
|
opt.data = []byte(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
if d, _ := cmd.Flags().GetString("data"); d != "" {
|
||||||
|
opt.request = "POST"
|
||||||
|
opt.headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||||
|
if strings.HasPrefix(d, "@") {
|
||||||
|
filePath := strings.TrimPrefix(d, "@")
|
||||||
|
var data []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// read from file or stdin and trim trailing newlines
|
||||||
|
if filePath == "-" {
|
||||||
|
data, err = os.ReadFile("/dev/stdin")
|
||||||
|
} else {
|
||||||
|
data, err = os.ReadFile(filePath)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(errors.New("could not read data from file '" + filePath + "': " + err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean byte array similar to curl's --data parameter
|
||||||
|
// It removes leading/trailing whitespace and converts line breaks to spaces
|
||||||
|
|
||||||
|
// Trim leading and trailing whitespace
|
||||||
|
data = bytes.TrimSpace(data)
|
||||||
|
|
||||||
|
// Replace newlines and carriage returns with spaces
|
||||||
|
data = bytes.ReplaceAll(data, []byte("\r\n"), []byte(" "))
|
||||||
|
data = bytes.ReplaceAll(data, []byte("\n"), []byte(" "))
|
||||||
|
data = bytes.ReplaceAll(data, []byte("\r"), []byte(" "))
|
||||||
|
|
||||||
|
// Replace multiple spaces with single space
|
||||||
|
for bytes.Contains(data, []byte(" ")) {
|
||||||
|
data = bytes.ReplaceAll(data, []byte(" "), []byte(" "))
|
||||||
|
}
|
||||||
|
|
||||||
|
opt.data = data
|
||||||
|
} else {
|
||||||
|
opt.data = []byte(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d, _ := cmd.Flags().GetString("data-binary"); d != "" {
|
||||||
|
opt.request = "POST"
|
||||||
|
opt.headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||||
|
if strings.HasPrefix(d, "@") {
|
||||||
|
filePath := strings.TrimPrefix(d, "@")
|
||||||
|
var data []byte
|
||||||
|
var err error
|
||||||
|
if filePath == "-" {
|
||||||
|
data, err = os.ReadFile("/dev/stdin")
|
||||||
|
} else {
|
||||||
|
data, err = os.ReadFile(filePath)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(errors.New("could not read data from file '" + filePath + "': " + err.Error()))
|
||||||
|
}
|
||||||
|
opt.data = data
|
||||||
|
} else {
|
||||||
|
opt.data = []byte(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// override method if specified
|
||||||
|
if request, _ := cmd.Flags().GetString("request"); request != "" {
|
||||||
|
opt.request = request
|
||||||
|
}
|
||||||
|
|
||||||
if opt.url == "" {
|
if opt.url == "" {
|
||||||
log.Fatal(errors.New("no URL specified"))
|
log.Fatal(errors.New("no URL specified"))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, h := range c.StringSlice("headers") {
|
headersSlice, err := cmd.Flags().GetStringSlice("header")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, h := range headersSlice {
|
||||||
parts := strings.SplitN(h, ":", 2)
|
parts := strings.SplitN(h, ":", 2)
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
log.Fatal(errors.New("invalid header '" + h + "'"))
|
log.Fatal(errors.New("invalid header '" + h + "'"))
|
||||||
@@ -127,7 +143,7 @@ func BenchmarkClientCommand(cfg *config.Config) *cli.Command {
|
|||||||
opt.headers[parts[0]] = strings.TrimSpace(parts[1])
|
opt.headers[parts[0]] = strings.TrimSpace(parts[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
rate := c.String("rate")
|
rate, _ := cmd.Flags().GetString("rate")
|
||||||
if rate != "" {
|
if rate != "" {
|
||||||
parts := strings.SplitN(rate, "/", 2)
|
parts := strings.SplitN(rate, "/", 2)
|
||||||
num, err := strconv.Atoi(parts[0])
|
num, err := strconv.Atoi(parts[0])
|
||||||
@@ -150,12 +166,12 @@ func BenchmarkClientCommand(cfg *config.Config) *cli.Command {
|
|||||||
opt.rateDelay = unit / time.Duration(num)
|
opt.rateDelay = unit / time.Duration(num)
|
||||||
}
|
}
|
||||||
|
|
||||||
user := c.String("user")
|
user, _ := cmd.Flags().GetString("user")
|
||||||
opt.auth = func() string {
|
opt.auth = func() string {
|
||||||
return "Basic " + base64.StdEncoding.EncodeToString([]byte(user))
|
return "Basic " + base64.StdEncoding.EncodeToString([]byte(user))
|
||||||
}
|
}
|
||||||
|
|
||||||
btc := c.String("bearer-token-command")
|
btc, _ := cmd.Flags().GetString("bearer-token-command")
|
||||||
if btc != "" {
|
if btc != "" {
|
||||||
parts := strings.SplitN(btc, " ", 2)
|
parts := strings.SplitN(btc, " ", 2)
|
||||||
var cmd *exec.Cmd
|
var cmd *exec.Cmd
|
||||||
@@ -173,16 +189,47 @@ func BenchmarkClientCommand(cfg *config.Config) *cli.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
every := c.Int("every")
|
every, err := cmd.Flags().GetInt("every")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if every != 0 {
|
if every != 0 {
|
||||||
opt.ticker = time.NewTicker(time.Second * time.Duration(every))
|
opt.ticker = time.NewTicker(time.Second * time.Duration(every))
|
||||||
defer opt.ticker.Stop()
|
defer opt.ticker.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
return client(opt)
|
// Set up signal handling for Ctrl+C
|
||||||
|
ctx, cancel := context.WithCancel(cmd.Context())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
sigChan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-sigChan
|
||||||
|
fmt.Println("\nReceived interrupt signal, shutting down...")
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
return client(ctx, opt)
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// flags mimicing curl
|
||||||
|
benchClientCmd.Flags().StringP("request", "X", "PROPFIND", "Specifies a custom request method to use when communicating with the HTTP server.")
|
||||||
|
benchClientCmd.Flags().StringP("user", "u", "admin:admin", "Specify the user name and password to use for server authentication.")
|
||||||
|
benchClientCmd.Flags().BoolP("insecure", "k", false, "Skip the TLS verification step and proceed without checking.")
|
||||||
|
benchClientCmd.Flags().StringP("data", "d", "", "Sends the specified data in a POST request to the HTTP server, in the same way that a browser does when a user has filled in an HTML form and presses the submit button. If you start the data with the letter @, the rest should be a file name to read the data from, or - if you want to read the data from stdin. When -d, --data is told to read from a file like that, carriage returns and newlines are stripped out. If you do not want the @ character to have a special interpretation use --data-raw instead.")
|
||||||
|
benchClientCmd.Flags().StringP("data-raw", "", "", "Sends the specified data in a request to the HTTP server.")
|
||||||
|
benchClientCmd.Flags().StringP("data-binary", "", "", "This posts data exactly as specified with no extra processing whatsoever. If you start the data with the letter @, the rest should be a file name to read the data from, or - if you want to read the data from stdin.")
|
||||||
|
benchClientCmd.Flags().StringSliceP("headers", "H", []string{}, "Extra header to include in information sent.")
|
||||||
|
benchClientCmd.Flags().String("rate", "", "Specify the maximum transfer frequency you allow a client to use - in number of transfer starts per time unit (sometimes called request rate). The request rate is provided as \"N/U\" where N is an integer number and U is a time unit. Supported units are 's' (second), 'm' (minute), 'h' (hour) and 'd' /(day, as in a 24 hour unit). The default time unit, if no \"/U\" is provided, is number of transfers per hour.")
|
||||||
|
|
||||||
|
// other flags
|
||||||
|
benchClientCmd.Flags().IntP("jobs", "j", 1, "Number of parallel clients to start. Defaults to 1.")
|
||||||
|
benchClientCmd.Flags().Int("every", 0, "Aggregate stats every time this amount of seconds has passed.")
|
||||||
|
benchClientCmd.Flags().String("bearer-token-command", "", "Command to execute for a bearer token, e.g. 'oidc-token opencloud'. When set, disables basic auth.")
|
||||||
|
|
||||||
|
return benchClientCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
type clientOptions struct {
|
type clientOptions struct {
|
||||||
@@ -197,8 +244,7 @@ type clientOptions struct {
|
|||||||
jobs int
|
jobs int
|
||||||
}
|
}
|
||||||
|
|
||||||
func client(o clientOptions) error {
|
func client(ctx context.Context, o clientOptions) error {
|
||||||
|
|
||||||
type stat struct {
|
type stat struct {
|
||||||
job int
|
job int
|
||||||
duration time.Duration
|
duration time.Duration
|
||||||
@@ -217,6 +263,13 @@ func client(o clientOptions) error {
|
|||||||
|
|
||||||
cookies := map[string]*http.Cookie{}
|
cookies := map[string]*http.Cookie{}
|
||||||
for {
|
for {
|
||||||
|
// Check if context is cancelled
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest(o.request, o.url, bytes.NewReader(o.data))
|
req, err := http.NewRequest(o.request, o.url, bytes.NewReader(o.data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("client %d: could not create request: %s\n", i, err)
|
log.Printf("client %d: could not create request: %s\n", i, err)
|
||||||
@@ -234,20 +287,35 @@ func client(o clientOptions) error {
|
|||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
duration := -time.Until(start)
|
duration := -time.Until(start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Check if error is due to context cancellation
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
log.Printf("client %d: could not create request: %s\n", i, err)
|
log.Printf("client %d: could not create request: %s\n", i, err)
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
} else {
|
} else {
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
stats <- stat{
|
select {
|
||||||
|
case stats <- stat{
|
||||||
job: i,
|
job: i,
|
||||||
duration: duration,
|
duration: duration,
|
||||||
status: res.StatusCode,
|
status: res.StatusCode,
|
||||||
|
}:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
}
|
}
|
||||||
for _, c := range res.Cookies() {
|
for _, c := range res.Cookies() {
|
||||||
cookies[c.Name] = c
|
cookies[c.Name] = c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(o.rateDelay - duration)
|
// Sleep with context awareness
|
||||||
|
if o.rateDelay > duration {
|
||||||
|
select {
|
||||||
|
case <-time.After(o.rateDelay - duration):
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}(i)
|
}(i)
|
||||||
}
|
}
|
||||||
@@ -256,9 +324,14 @@ func client(o clientOptions) error {
|
|||||||
if o.ticker == nil {
|
if o.ticker == nil {
|
||||||
// no ticker, just write every request
|
// no ticker, just write every request
|
||||||
for {
|
for {
|
||||||
stat := <-stats
|
select {
|
||||||
numRequests++
|
case stat := <-stats:
|
||||||
fmt.Printf("req %d took %v and returned status %d\n", numRequests, stat.duration, stat.status)
|
numRequests++
|
||||||
|
fmt.Printf("req %d took %v and returned status %d\n", numRequests, stat.duration, stat.status)
|
||||||
|
case <-ctx.Done():
|
||||||
|
fmt.Println("\nShutting down...")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,31 +347,25 @@ func client(o clientOptions) error {
|
|||||||
numRequests = 0
|
numRequests = 0
|
||||||
duration = 0
|
duration = 0
|
||||||
}
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
if numRequests > 0 {
|
||||||
|
fmt.Printf("\n%d req at %v/req\n", numRequests, duration/time.Duration(numRequests))
|
||||||
|
}
|
||||||
|
fmt.Println("Shutting down...")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BenchmarkSyscallsCommand is the entrypoint for the benchmark syscalls command.
|
// BenchmarkSyscallsCommand is the entrypoint for the benchmark syscalls command.
|
||||||
func BenchmarkSyscallsCommand(cfg *config.Config) *cli.Command {
|
func BenchmarkSyscallsCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
benchSysCallCmd := &cobra.Command{
|
||||||
Name: "syscalls",
|
Use: "syscalls",
|
||||||
Usage: "test the performance of syscalls",
|
Short: "test the performance of syscalls",
|
||||||
Flags: []cli.Flag{
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "path",
|
|
||||||
Usage: "Path to test",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "iterations",
|
|
||||||
Value: "100",
|
|
||||||
Usage: "Number of iterations to execute",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Category: "benchmark",
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
|
|
||||||
path := c.String("path")
|
path, _ := cmd.Flags().GetString("path")
|
||||||
if path == "" {
|
if path == "" {
|
||||||
f, err := os.CreateTemp("", "opencloud-bench-temp-")
|
f, err := os.CreateTemp("", "opencloud-bench-temp-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -309,11 +376,16 @@ func BenchmarkSyscallsCommand(cfg *config.Config) *cli.Command {
|
|||||||
defer os.Remove(path)
|
defer os.Remove(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
iterations := c.Int("iterations")
|
iterations, err := cmd.Flags().GetInt("iterations")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return benchmark(iterations, path)
|
return benchmark(iterations, path)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
benchSysCallCmd.Flags().String("path", "", "Path to test")
|
||||||
|
benchSysCallCmd.Flags().Int("iterations", 100, "Number of iterations to execute")
|
||||||
|
return benchSysCallCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchmark(iterations int, path string) error {
|
func benchmark(iterations int, path string) error {
|
||||||
|
|||||||
7
opencloud/pkg/command/command.go
Normal file
7
opencloud/pkg/command/command.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
const (
|
||||||
|
CommandGroupServer = "Server"
|
||||||
|
CommandGroupServices = "Service"
|
||||||
|
CommandGroupStorage = "Storage"
|
||||||
|
)
|
||||||
@@ -9,8 +9,6 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
|
||||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||||
@@ -25,69 +23,57 @@ import (
|
|||||||
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree"
|
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree"
|
||||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||||
"github.com/opencloud-eu/reva/v2/pkg/store"
|
"github.com/opencloud-eu/reva/v2/pkg/store"
|
||||||
|
|
||||||
|
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||||
|
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DecomposedfsCommand is the entrypoint for the groups command.
|
// DecomposedfsCommand is the entrypoint for the groups command.
|
||||||
func DecomposedfsCommand(cfg *config.Config) *cli.Command {
|
func DecomposedfsCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
decomposedCmd := &cobra.Command{
|
||||||
Name: "decomposedfs",
|
Use: "decomposedfs",
|
||||||
Usage: `cli tools to inspect and manipulate a decomposedfs storage.`,
|
Short: `cli tools to inspect and manipulate a decomposedfs storage.`,
|
||||||
Category: "maintenance",
|
GroupID: CommandGroupStorage,
|
||||||
Subcommands: []*cli.Command{
|
|
||||||
metadataCmd(cfg),
|
|
||||||
checkCmd(cfg),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
decomposedCmd.AddCommand(metadataCmd(cfg), checkCmd(cfg))
|
||||||
|
return decomposedCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
register.AddCommand(DecomposedfsCommand)
|
register.AddCommand(DecomposedfsCommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkCmd(cfg *config.Config) *cli.Command {
|
func checkCmd(_ *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
cCmd := &cobra.Command{
|
||||||
Name: "check-treesize",
|
Use: "check-treesize",
|
||||||
Usage: `cli tool to check the treesize metadata of a Space`,
|
Short: `cli tool to check the treesize metadata of a Space`,
|
||||||
Flags: []cli.Flag{
|
RunE: check,
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "root",
|
|
||||||
Aliases: []string{"r"},
|
|
||||||
Required: true,
|
|
||||||
Usage: "Path to the root directory of the decomposedfs",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "node",
|
|
||||||
Required: true,
|
|
||||||
Aliases: []string{"n"},
|
|
||||||
Usage: "Space ID of the Space to inspect",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "repair",
|
|
||||||
Usage: "Try to repair nodes with incorrect treesize metadata. IMPORTANT: Only use this while OpenCloud is not running.",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "force",
|
|
||||||
Usage: "Do not prompt for confirmation when running in repair mode.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: check,
|
|
||||||
}
|
}
|
||||||
|
cCmd.Flags().StringP("root", "r", "", "Path to the root directory of the decomposedfs")
|
||||||
|
_ = cCmd.MarkFlagRequired("root")
|
||||||
|
cCmd.Flags().StringP("node", "n", "", "Space ID of the Space to inspect")
|
||||||
|
_ = cCmd.MarkFlagRequired("node")
|
||||||
|
cCmd.Flags().Bool("repair", false, "Try to repair nodes with incorrect treesize metadata. IMPORTANT: Only use this while OpenCloud is not running.")
|
||||||
|
cCmd.Flags().Bool("force", false, "Do not prompt for confirmation when running in repair mode.")
|
||||||
|
|
||||||
|
return cCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func check(c *cli.Context) error {
|
func check(cmd *cobra.Command, args []string) error {
|
||||||
rootFlag := c.String("root")
|
rootFlag, _ := cmd.Flags().GetString("root")
|
||||||
repairFlag := c.Bool("repair")
|
repairFlag, _ := cmd.Flags().GetBool("repair")
|
||||||
|
forceFlag, _ := cmd.Flags().GetBool("force")
|
||||||
|
|
||||||
if repairFlag && !c.Bool("force") {
|
if repairFlag && !forceFlag {
|
||||||
answer := strings.ToLower(stringPrompt("IMPORTANT: Only use '--repair' when OpenCloud is not running. Do you want to continue? [yes | no = default]"))
|
answer := strings.ToLower(stringPrompt("IMPORTANT: Only use '--repair' when OpenCloud is not running. Do you want to continue? [yes | no = default]"))
|
||||||
if answer != "yes" && answer != "y" {
|
if answer != "yes" && answer != "y" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lu, backend := getBackend(c)
|
lu, backend := getBackend(cmd)
|
||||||
o := &options.Options{
|
o := &options.Options{
|
||||||
MetadataBackend: backend.Name(),
|
MetadataBackend: backend.Name(),
|
||||||
MaxConcurrency: 100,
|
MaxConcurrency: 100,
|
||||||
@@ -100,7 +86,7 @@ func check(c *cli.Context) error {
|
|||||||
|
|
||||||
tree := tree.New(lu, bs, o, permissions.Permissions{}, store.Create(), &zerolog.Logger{})
|
tree := tree.New(lu, bs, o, permissions.Permissions{}, store.Create(), &zerolog.Logger{})
|
||||||
|
|
||||||
nId := c.String("node")
|
nId, _ := cmd.Flags().GetString("node")
|
||||||
n, err := lu.NodeFromSpaceID(context.Background(), nId)
|
n, err := lu.NodeFromSpaceID(context.Background(), nId)
|
||||||
if err != nil || !n.Exists {
|
if err != nil || !n.Exists {
|
||||||
fmt.Println("Can not find node '" + nId + "'")
|
fmt.Println("Can not find node '" + nId + "'")
|
||||||
@@ -116,7 +102,10 @@ func check(c *cli.Context) error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
treeSize, err := walkTree(ctx, tree, lu, n, repairFlag)
|
treeSize, err := walkTree(ctx, tree, lu, n, repairFlag)
|
||||||
treesizeFromMetadata, err := n.GetTreeSize(c.Context)
|
if err != nil {
|
||||||
|
fmt.Printf("failed to walk tree of node %s: %s\n", n.ID, err)
|
||||||
|
}
|
||||||
|
treesizeFromMetadata, err := n.GetTreeSize(cmd.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to read treesize of node: %s: %s\n", n.ID, err)
|
fmt.Printf("failed to read treesize of node: %s: %s\n", n.ID, err)
|
||||||
}
|
}
|
||||||
@@ -126,7 +115,7 @@ func check(c *cli.Context) error {
|
|||||||
if repairFlag {
|
if repairFlag {
|
||||||
fmt.Printf("Fixing tree size for node: %s. Calculated treesize: %d\n",
|
fmt.Printf("Fixing tree size for node: %s. Calculated treesize: %d\n",
|
||||||
n.ID, treeSize)
|
n.ID, treeSize)
|
||||||
n.SetTreeSize(c.Context, treeSize)
|
n.SetTreeSize(cmd.Context(), treeSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -185,105 +174,79 @@ func walkTree(ctx context.Context, tree *tree.Tree, lu *lookup.Lookup, root *nod
|
|||||||
return treesize, nil
|
return treesize, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func metadataCmd(cfg *config.Config) *cli.Command {
|
func metadataCmd(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
metaCmd := &cobra.Command{
|
||||||
Name: "metadata",
|
Use: "metadata",
|
||||||
Usage: `cli tools to inspect and manipulate node metadata`,
|
Short: `cli tools to inspect and manipulate node metadata`,
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "root",
|
|
||||||
Aliases: []string{"r"},
|
|
||||||
Required: true,
|
|
||||||
Usage: "Path to the decomposedfs",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "node",
|
|
||||||
Required: true,
|
|
||||||
Aliases: []string{"n"},
|
|
||||||
Usage: "Path to or ID of the node to inspect",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Subcommands: []*cli.Command{dumpCmd(cfg), getCmd(cfg), setCmd(cfg)},
|
|
||||||
}
|
}
|
||||||
|
metaCmd.AddCommand(dumpCmd(cfg), getCmd(cfg), setCmd(cfg))
|
||||||
|
metaCmd.Flags().StringP("root", "r", "", "Path to the root directory of the decomposedfs")
|
||||||
|
_ = metaCmd.MarkFlagRequired("root")
|
||||||
|
metaCmd.Flags().StringP("node", "n", "", "Path to or ID of the node to inspect")
|
||||||
|
_ = metaCmd.MarkFlagRequired("node")
|
||||||
|
return metaCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func dumpCmd(cfg *config.Config) *cli.Command {
|
func dumpCmd(_ *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
return &cobra.Command{
|
||||||
Name: "dump",
|
Use: "dump",
|
||||||
Usage: `print the metadata of the given node. String attributes will be enclosed in quotes. Binary attributes will be returned encoded as base64 with their value being prefixed with '0s'.`,
|
Short: `print the metadata of the given node. String attributes will be enclosed in quotes. Binary attributes will be returned encoded as base64 with their value being prefixed with '0s'.`,
|
||||||
Action: func(c *cli.Context) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
lu, backend := getBackend(c)
|
lu, backend := getBackend(cmd)
|
||||||
path, err := getNode(c, lu)
|
path, err := getNode(cmd, lu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
attribs, err := backend.All(c.Context, path)
|
attribs, err := backend.All(cmd.Context(), path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error reading attributes")
|
fmt.Println("Error reading attributes")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
printAttribs(attribs, c.String("attribute"))
|
attributeFlag, _ := cmd.Flags().GetString("attribute")
|
||||||
|
printAttribs(attribs, attributeFlag)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCmd(cfg *config.Config) *cli.Command {
|
func getCmd(_ *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
gCmd := &cobra.Command{
|
||||||
Name: "get",
|
Use: "get",
|
||||||
Usage: `print a specific attribute of the given node. String attributes will be enclosed in quotes. Binary attributes will be returned encoded as base64 with their value being prefixed with '0s'.`,
|
Short: `print a specific attribute of the given node. String attributes will be enclosed in quotes. Binary attributes will be returned encoded as base64 with their value being prefixed with '0s'.`,
|
||||||
Flags: []cli.Flag{
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
&cli.StringFlag{
|
lu, backend := getBackend(cmd)
|
||||||
Name: "attribute",
|
path, err := getNode(cmd, lu)
|
||||||
Aliases: []string{"a"},
|
|
||||||
Usage: "attribute to inspect",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
lu, backend := getBackend(c)
|
|
||||||
path, err := getNode(c, lu)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
attribs, err := backend.All(c.Context, path)
|
attribs, err := backend.All(cmd.Context(), path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error reading attributes")
|
fmt.Println("Error reading attributes")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
printAttribs(attribs, c.String("attribute"))
|
attributeFlag, _ := cmd.Flags().GetString("attribute")
|
||||||
|
printAttribs(attribs, attributeFlag)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
gCmd.Flags().StringP("attribute", "a", "", "attribute to inspect, can be a glob pattern (e.g. 'user.*' will match all attributes starting with 'user.').")
|
||||||
|
return gCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCmd(cfg *config.Config) *cli.Command {
|
func setCmd(_ *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
sCmd := &cobra.Command{
|
||||||
Name: "set",
|
Use: "set",
|
||||||
Usage: `manipulate metadata of the given node. Binary attributes can be given hex encoded (prefix by '0x') or base64 encoded (prefix by '0s').`,
|
Short: `manipulate metadata of the given node. Binary attributes can be given hex encoded (prefix by '0x') or base64 encoded (prefix by '0s').`,
|
||||||
Flags: []cli.Flag{
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
&cli.StringFlag{
|
lu, backend := getBackend(cmd)
|
||||||
Name: "attribute",
|
n, err := getNode(cmd, lu)
|
||||||
Required: true,
|
|
||||||
Aliases: []string{"a"},
|
|
||||||
Usage: "attribute to inspect",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "value",
|
|
||||||
Required: true,
|
|
||||||
Aliases: []string{"v"},
|
|
||||||
Usage: "value to set",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
lu, backend := getBackend(c)
|
|
||||||
n, err := getNode(c, lu)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
v := c.String("value")
|
v, _ := cmd.Flags().GetString("value")
|
||||||
if strings.HasPrefix(v, "0s") {
|
if strings.HasPrefix(v, "0s") {
|
||||||
b64, err := base64.StdEncoding.DecodeString(v[2:])
|
b64, err := base64.StdEncoding.DecodeString(v[2:])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -300,7 +263,8 @@ func setCmd(cfg *config.Config) *cli.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = backend.Set(c.Context, n, c.String("attribute"), []byte(v))
|
attributeFlag, _ := cmd.Flags().GetString("attribute")
|
||||||
|
err = backend.Set(cmd.Context(), n, attributeFlag, []byte(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error setting attribute")
|
fmt.Println("Error setting attribute")
|
||||||
return err
|
return err
|
||||||
@@ -308,9 +272,16 @@ func setCmd(cfg *config.Config) *cli.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
sCmd.Flags().StringP("attribute", "a", "", "attribute to inspect, can be a glob pattern (e.g. 'user.*' will match all attributes starting with 'user.').")
|
||||||
|
_ = sCmd.MarkFlagRequired("attribute")
|
||||||
|
|
||||||
|
sCmd.Flags().StringP("value", "v", "", "value to set")
|
||||||
|
_ = sCmd.MarkFlagRequired("value")
|
||||||
|
|
||||||
|
return sCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func backend(root, backend string) metadata.Backend {
|
func backend(backend string) metadata.Backend {
|
||||||
switch backend {
|
switch backend {
|
||||||
case "xattrs":
|
case "xattrs":
|
||||||
return metadata.NewXattrsBackend(cache.Config{})
|
return metadata.NewXattrsBackend(cache.Config{})
|
||||||
@@ -320,11 +291,11 @@ func backend(root, backend string) metadata.Backend {
|
|||||||
return metadata.NullBackend{}
|
return metadata.NullBackend{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBackend(c *cli.Context) (*lookup.Lookup, metadata.Backend) {
|
func getBackend(cmd *cobra.Command) (*lookup.Lookup, metadata.Backend) {
|
||||||
rootFlag := c.String("root")
|
rootFlag, _ := cmd.Flags().GetString("root")
|
||||||
|
|
||||||
bod := lookup.DetectBackendOnDisk(rootFlag)
|
bod := lookup.DetectBackendOnDisk(rootFlag)
|
||||||
backend := backend(rootFlag, bod)
|
backend := backend(bod)
|
||||||
lu := lookup.New(backend, &options.Options{
|
lu := lookup.New(backend, &options.Options{
|
||||||
Root: rootFlag,
|
Root: rootFlag,
|
||||||
MetadataBackend: bod,
|
MetadataBackend: bod,
|
||||||
@@ -332,8 +303,8 @@ func getBackend(c *cli.Context) (*lookup.Lookup, metadata.Backend) {
|
|||||||
return lu, backend
|
return lu, backend
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNode(c *cli.Context, lu *lookup.Lookup) (*node.Node, error) {
|
func getNode(cmd *cobra.Command, lu *lookup.Lookup) (*node.Node, error) {
|
||||||
nodeFlag := c.String("node")
|
nodeFlag, _ := cmd.Flags().GetString("node")
|
||||||
|
|
||||||
id, err := storagespace.ParseID(nodeFlag)
|
id, err := storagespace.ParseID(nodeFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
package helper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SubcommandDescription(serviceName string) string {
|
|
||||||
return fmt.Sprintf("%s service commands", serviceName)
|
|
||||||
}
|
|
||||||
@@ -11,49 +11,19 @@ import (
|
|||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config/defaults"
|
"github.com/opencloud-eu/opencloud/pkg/config/defaults"
|
||||||
cli "github.com/urfave/cli/v2"
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitCommand is the entrypoint for the init command
|
// InitCommand is the entrypoint for the init command
|
||||||
func InitCommand(cfg *config.Config) *cli.Command {
|
func InitCommand(_ *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
initCmd := &cobra.Command{
|
||||||
Name: "init",
|
Use: "init",
|
||||||
Usage: "initialise an OpenCloud config",
|
Short: "initialise an OpenCloud config",
|
||||||
Flags: []cli.Flag{
|
GroupID: CommandGroupServer,
|
||||||
&cli.StringFlag{
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
Name: "insecure",
|
insecureFlag := viper.GetString("insecure")
|
||||||
EnvVars: []string{"OC_INSECURE"},
|
|
||||||
Value: "ask",
|
|
||||||
Usage: "Allow insecure OpenCloud config",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "diff",
|
|
||||||
Aliases: []string{"d"},
|
|
||||||
Usage: "Show the difference between the current config and the new one",
|
|
||||||
Value: false,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "force-overwrite",
|
|
||||||
Aliases: []string{"f"},
|
|
||||||
EnvVars: []string{"OC_FORCE_CONFIG_OVERWRITE"},
|
|
||||||
Value: false,
|
|
||||||
Usage: "Force overwrite existing config file",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "config-path",
|
|
||||||
Value: defaults.BaseConfigPath(),
|
|
||||||
Usage: "Config path for the OpenCloud runtime",
|
|
||||||
EnvVars: []string{"OC_CONFIG_DIR", "OC_BASE_DATA_PATH"},
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "admin-password",
|
|
||||||
Aliases: []string{"ap"},
|
|
||||||
EnvVars: []string{"ADMIN_PASSWORD", "IDM_ADMIN_PASSWORD"},
|
|
||||||
Usage: "Set admin password instead of using a random generated one",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
insecureFlag := c.String("insecure")
|
|
||||||
insecure := false
|
insecure := false
|
||||||
if insecureFlag == "ask" {
|
if insecureFlag == "ask" {
|
||||||
answer := strings.ToLower(stringPrompt("Do you want to configure OpenCloud with certificate checking disabled?\n This is not recommended for public instances! [yes | no = default]"))
|
answer := strings.ToLower(stringPrompt("Do you want to configure OpenCloud with certificate checking disabled?\n This is not recommended for public instances! [yes | no = default]"))
|
||||||
@@ -63,13 +33,37 @@ func InitCommand(cfg *config.Config) *cli.Command {
|
|||||||
} else if insecureFlag == strings.ToLower("true") || insecureFlag == strings.ToLower("yes") || insecureFlag == strings.ToLower("y") {
|
} else if insecureFlag == strings.ToLower("true") || insecureFlag == strings.ToLower("yes") || insecureFlag == strings.ToLower("y") {
|
||||||
insecure = true
|
insecure = true
|
||||||
}
|
}
|
||||||
err := ocinit.CreateConfig(insecure, c.Bool("force-overwrite"), c.Bool("diff"), c.String("config-path"), c.String("admin-password"))
|
forceOverwriteFlag := viper.GetBool("force-overwrite")
|
||||||
|
diffFlag, _ := cmd.Flags().GetBool("diff")
|
||||||
|
configPathFlag := viper.GetString("config-path")
|
||||||
|
adminPasswordFlag := viper.GetString("admin-password")
|
||||||
|
err := ocinit.CreateConfig(insecure, forceOverwriteFlag, diffFlag, configPathFlag, adminPasswordFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Could not create config: %s", err)
|
log.Fatalf("Could not create config: %s", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
initCmd.Flags().String("insecure", "ask", "Allow insecure OpenCloud config")
|
||||||
|
_ = viper.BindEnv("insecure", "OC_INSECURE")
|
||||||
|
_ = viper.BindPFlag("insecure", initCmd.Flags().Lookup("insecure"))
|
||||||
|
|
||||||
|
initCmd.Flags().BoolP("diff", "d", false, "Show the difference between the current config and the new one")
|
||||||
|
|
||||||
|
initCmd.Flags().BoolP("force-overwrite", "f", false, "Force overwrite existing config file")
|
||||||
|
_ = viper.BindEnv("force-overwrite", "OC_FORCE_CONFIG_OVERWRITE")
|
||||||
|
_ = viper.BindPFlag("force-overwrite", initCmd.Flags().Lookup("force-overwrite"))
|
||||||
|
|
||||||
|
initCmd.Flags().String("config-path", defaults.BaseConfigPath(), "Config path for the OpenCloud runtime")
|
||||||
|
_ = viper.BindEnv("config-path", "OC_CONFIG_DIR")
|
||||||
|
_ = viper.BindEnv("config-path", "OC_BASE_DATA_PATH")
|
||||||
|
_ = viper.BindPFlag("config-path", initCmd.Flags().Lookup("config-path"))
|
||||||
|
|
||||||
|
initCmd.Flags().String("admin-password", "", "Set admin password instead of using a random generated one")
|
||||||
|
_ = viper.BindEnv("admin-password", "ADMIN_PASSWORD")
|
||||||
|
_ = viper.BindEnv("admin-password", "IDM_ADMIN_PASSWORD")
|
||||||
|
_ = viper.BindPFlag("admin-password", initCmd.Flags().Lookup("admin-password"))
|
||||||
|
return initCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -80,7 +74,7 @@ func stringPrompt(label string) string {
|
|||||||
input := ""
|
input := ""
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
for {
|
for {
|
||||||
fmt.Fprint(os.Stderr, label+" ")
|
_, _ = fmt.Fprint(os.Stderr, label+" ")
|
||||||
input, _ = reader.ReadString('\n')
|
input, _ = reader.ReadString('\n')
|
||||||
if input != "" {
|
if input != "" {
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -8,31 +8,26 @@ import (
|
|||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
||||||
|
"github.com/opencloud-eu/opencloud/pkg/config/parser"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListCommand is the entrypoint for the list command.
|
// ListCommand is the entrypoint for the list command.
|
||||||
func ListCommand(cfg *config.Config) *cli.Command {
|
func ListCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
listCmd := &cobra.Command{
|
||||||
Name: "list",
|
Use: "list",
|
||||||
Usage: "list OpenCloud services running in the runtime (supervised mode)",
|
Short: "list OpenCloud services running in the runtime (supervised mode)",
|
||||||
Category: "runtime",
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
Flags: []cli.Flag{
|
return configlog.ReturnError(parser.ParseConfig(cfg, true))
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "hostname",
|
|
||||||
Value: "localhost",
|
|
||||||
EnvVars: []string{"OC_RUNTIME_HOST"},
|
|
||||||
Destination: &cfg.Runtime.Host,
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "port",
|
|
||||||
Value: "9250",
|
|
||||||
EnvVars: []string{"OC_RUNTIME_PORT"},
|
|
||||||
Destination: &cfg.Runtime.Port,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
client, err := rpc.DialHTTP("tcp", net.JoinHostPort(cfg.Runtime.Host, cfg.Runtime.Port))
|
host := viper.GetString("hostname")
|
||||||
|
port := viper.GetString("port")
|
||||||
|
|
||||||
|
client, err := rpc.DialHTTP("tcp", net.JoinHostPort(host, port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to connect to the runtime. Has the runtime been started and did you configure the right runtime address (\"%s\")", cfg.Runtime.Host+":"+cfg.Runtime.Port)
|
log.Fatalf("Failed to connect to the runtime. Has the runtime been started and did you configure the right runtime address (\"%s\")", cfg.Runtime.Host+":"+cfg.Runtime.Port)
|
||||||
}
|
}
|
||||||
@@ -48,6 +43,15 @@ func ListCommand(cfg *config.Config) *cli.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listCmd.Flags().String("hostname", "localhost", "hostname of the runtime")
|
||||||
|
_ = viper.BindEnv("hostname", "OC_RUNTIME_HOST")
|
||||||
|
_ = viper.BindPFlag("hostname", listCmd.Flags().Lookup("hostname"))
|
||||||
|
|
||||||
|
listCmd.Flags().String("port", "9250", "port of the runtime")
|
||||||
|
_ = viper.BindEnv("port", "OC_RUNTIME_PORT")
|
||||||
|
_ = viper.BindPFlag("port", listCmd.Flags().Lookup("port"))
|
||||||
|
return listCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ import (
|
|||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
|
|
||||||
"github.com/pkg/xattr"
|
"github.com/pkg/xattr"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
"github.com/theckman/yacspin"
|
"github.com/theckman/yacspin"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
"github.com/vmihailenco/msgpack/v5"
|
"github.com/vmihailenco/msgpack/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,15 +38,16 @@ type EntryInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PosixfsCommand is the entrypoint for the posixfs command.
|
// PosixfsCommand is the entrypoint for the posixfs command.
|
||||||
func PosixfsCommand(cfg *config.Config) *cli.Command {
|
func PosixfsCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
posixCmd := &cobra.Command{
|
||||||
Name: "posixfs",
|
Use: "posixfs",
|
||||||
Usage: `cli tools to inspect and manipulate a posixfs storage.`,
|
Short: `cli tools to inspect and manipulate a posixfs storage.`,
|
||||||
Category: "maintenance",
|
GroupID: CommandGroupStorage,
|
||||||
Subcommands: []*cli.Command{
|
|
||||||
consistencyCmd(cfg),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
posixCmd.AddCommand(consistencyCmd(cfg))
|
||||||
|
|
||||||
|
return posixCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -53,27 +55,23 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// consistencyCmd returns a command to check the consistency of the posixfs storage.
|
// consistencyCmd returns a command to check the consistency of the posixfs storage.
|
||||||
func consistencyCmd(cfg *config.Config) *cli.Command {
|
func consistencyCmd(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
consCmd := &cobra.Command{
|
||||||
Name: "consistency",
|
Use: "consistency",
|
||||||
Usage: "check the consistency of the posixfs storage",
|
Short: "check the consistency of the posixfs storage",
|
||||||
Action: func(c *cli.Context) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return checkPosixfsConsistency(c, cfg)
|
return checkPosixfsConsistency(cmd, cfg)
|
||||||
},
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "root",
|
|
||||||
Aliases: []string{"r"},
|
|
||||||
Required: true,
|
|
||||||
Usage: "Path to the root directory of the posixfs storage",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
consCmd.Flags().StringP("root", "r", "", "Path to the root directory of the posixfs storage")
|
||||||
|
_ = consCmd.MarkFlagRequired("root")
|
||||||
|
|
||||||
|
return consCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkPosixfsConsistency checks the consistency of the posixfs storage.
|
// checkPosixfsConsistency checks the consistency of the posixfs storage.
|
||||||
func checkPosixfsConsistency(c *cli.Context, cfg *config.Config) error {
|
func checkPosixfsConsistency(cmd *cobra.Command, cfg *config.Config) error {
|
||||||
rootPath := c.String("root")
|
rootPath, _ := cmd.Flags().GetString("root")
|
||||||
indexesPath := filepath.Join(rootPath, "indexes")
|
indexesPath := filepath.Join(rootPath, "indexes")
|
||||||
|
|
||||||
_, err := os.Stat(indexesPath)
|
_, err := os.Stat(indexesPath)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/revisions"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/revisions"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
@@ -15,7 +16,8 @@ import (
|
|||||||
decomposeds3bs "github.com/opencloud-eu/reva/v2/pkg/storage/fs/decomposeds3/blobstore"
|
decomposeds3bs "github.com/opencloud-eu/reva/v2/pkg/storage/fs/decomposeds3/blobstore"
|
||||||
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup"
|
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup"
|
||||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -24,75 +26,33 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// RevisionsCommand is the entrypoint for the revisions command.
|
// RevisionsCommand is the entrypoint for the revisions command.
|
||||||
func RevisionsCommand(cfg *config.Config) *cli.Command {
|
func RevisionsCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
revCmd := &cobra.Command{
|
||||||
Name: "revisions",
|
Use: "revisions",
|
||||||
Usage: "OpenCloud revisions functionality",
|
Short: "OpenCloud revisions functionality",
|
||||||
Subcommands: []*cli.Command{
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
PurgeRevisionsCommand(cfg),
|
|
||||||
},
|
|
||||||
Before: func(_ *cli.Context) error {
|
|
||||||
return configlog.ReturnError(parser.ParseConfig(cfg, true))
|
return configlog.ReturnError(parser.ParseConfig(cfg, true))
|
||||||
},
|
},
|
||||||
Action: func(_ *cli.Context) error {
|
|
||||||
fmt.Println("Read the docs")
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
revCmd.AddCommand(PurgeRevisionsCommand(cfg))
|
||||||
|
|
||||||
|
return revCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// PurgeRevisionsCommand allows removing all revisions from a storage provider.
|
// PurgeRevisionsCommand allows removing all revisions from a storage provider.
|
||||||
func PurgeRevisionsCommand(cfg *config.Config) *cli.Command {
|
func PurgeRevisionsCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
revCmd := &cobra.Command{
|
||||||
Name: "purge",
|
Use: "purge",
|
||||||
Usage: "purge revisions",
|
Short: "purge revisions",
|
||||||
Flags: []cli.Flag{
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
&cli.StringFlag{
|
basePath, _ := cmd.Flags().GetString("basepath")
|
||||||
Name: "basepath",
|
|
||||||
Aliases: []string{"p"},
|
|
||||||
Usage: "the basepath of the decomposedfs (e.g. /var/tmp/opencloud/storage/metadata)",
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "blobstore",
|
|
||||||
Aliases: []string{"b"},
|
|
||||||
Usage: "the blobstore type. Can be (none, decomposed, decomposeds3). Default decomposed. Note: When using decomposeds3 this needs same configuration as the storage-users service",
|
|
||||||
Value: "decomposed",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "dry-run",
|
|
||||||
Usage: "do not delete anything, just print what would be deleted",
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "verbose",
|
|
||||||
Aliases: []string{"v"},
|
|
||||||
Usage: "print verbose output",
|
|
||||||
Value: false,
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "resource-id",
|
|
||||||
Aliases: []string{"r"},
|
|
||||||
Usage: "purge all revisions of this file/space. If not set, all revisions will be purged",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "glob-mechanism",
|
|
||||||
Usage: "the glob mechanism to find all nodes. Can be 'glob', 'list' or 'workers'. 'glob' uses globbing with a single worker. 'workers' spawns multiple go routines, accelatering the command drastically but causing high cpu and ram usage. 'list' looks for references by listing directories with multiple workers. Default is 'glob'",
|
|
||||||
Value: "glob",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
basePath := c.String("basepath")
|
|
||||||
if basePath == "" {
|
|
||||||
fmt.Println("basepath is required")
|
|
||||||
return cli.ShowCommandHelp(c, "revisions")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bs revisions.DelBlobstore
|
bs revisions.DelBlobstore
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
switch c.String("blobstore") {
|
blobstoreFlag, _ := cmd.Flags().GetString("blobstore")
|
||||||
|
switch blobstoreFlag {
|
||||||
case "decomposeds3":
|
case "decomposeds3":
|
||||||
bs, err = decomposeds3bs.New(
|
bs, err = decomposeds3bs.New(
|
||||||
cfg.StorageUsers.Drivers.DecomposedS3.Endpoint,
|
cfg.StorageUsers.Drivers.DecomposedS3.Endpoint,
|
||||||
@@ -115,12 +75,13 @@ func PurgeRevisionsCommand(cfg *config.Config) *cli.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var rid *provider.ResourceId
|
var rid *provider.ResourceId
|
||||||
resid, err := storagespace.ParseID(c.String("resource-id"))
|
resourceIDFlag, _ := cmd.Flags().GetString("resource-id")
|
||||||
|
resid, err := storagespace.ParseID(resourceIDFlag)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
rid = &resid
|
rid = &resid
|
||||||
}
|
}
|
||||||
|
|
||||||
mechanism := c.String("glob-mechanism")
|
mechanism, _ := cmd.Flags().GetString("glob-mechanism")
|
||||||
if rid.GetOpaqueId() != "" {
|
if rid.GetOpaqueId() != "" {
|
||||||
mechanism = "glob"
|
mechanism = "glob"
|
||||||
}
|
}
|
||||||
@@ -146,11 +107,30 @@ func PurgeRevisionsCommand(cfg *config.Config) *cli.Command {
|
|||||||
ch = revisions.List(p, 10)
|
ch = revisions.List(p, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
files, blobs, revisions := revisions.PurgeRevisions(ch, bs, c.Bool("dry-run"), c.Bool("verbose"))
|
flagDryRun, err := cmd.Flags().GetBool("dry-run")
|
||||||
printResults(files, blobs, revisions, c.Bool("dry-run"))
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
flagVerbose, err := cmd.Flags().GetBool("verbose")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
files, blobs, revisionResults := revisions.PurgeRevisions(ch, bs, flagDryRun, flagVerbose)
|
||||||
|
printResults(files, blobs, revisionResults, flagDryRun)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
revCmd.Flags().StringP("basepath", "p", "", "the basepath of the decomposedfs (e.g. /var/tmp/opencloud/storage/metadata)")
|
||||||
|
_ = revCmd.MarkFlagRequired("basepath")
|
||||||
|
revCmd.Flags().StringP("blobstore", "b", "decomposed", "the blobstore type. Can be (none, decomposed, decomposeds3). Default decomposed")
|
||||||
|
revCmd.Flags().Bool("dry-run", true, "do not delete anything, just print what would be deleted")
|
||||||
|
revCmd.Flags().BoolP("verbose", "v", false, "print verbose output")
|
||||||
|
revCmd.Flags().StringP("resource-id", "r", "", "purge all revisions of this file/space. If not set, all revisions will be purged")
|
||||||
|
revCmd.Flags().String("glob-mechanism", "glob", "the glob mechanism to find all nodes. Can be 'glob', 'list' or 'workers'. 'glob' uses globbing with a single worker. 'workers' spawns multiple go routines, accelatering the command drastically but causing high cpu and ram usage. 'list' looks for references by listing directories with multiple workers. Default is 'glob'")
|
||||||
|
|
||||||
|
return revCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func printResults(countFiles, countBlobs, countRevisions int, dryRun bool) {
|
func printResults(countFiles, countBlobs, countRevisions int, dryRun bool) {
|
||||||
|
|||||||
@@ -9,25 +9,32 @@ import (
|
|||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/clihelper"
|
"github.com/opencloud-eu/opencloud/pkg/clihelper"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Execute is the entry point for the opencloud command.
|
// Execute is the entry point for the opencloud command.
|
||||||
func Execute() error {
|
func Execute() error {
|
||||||
cfg := config.DefaultConfig()
|
cfg := config.DefaultConfig()
|
||||||
|
|
||||||
app := clihelper.DefaultApp(&cli.App{
|
app := clihelper.DefaultApp(&cobra.Command{
|
||||||
Name: "opencloud",
|
Use: "opencloud",
|
||||||
Usage: "opencloud",
|
Short: "opencloud",
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, fn := range register.Commands {
|
for _, commandFactory := range register.Commands {
|
||||||
app.Commands = append(
|
command := commandFactory(cfg)
|
||||||
app.Commands,
|
|
||||||
fn(cfg),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if command.GroupID != "" && !app.ContainsGroup(command.GroupID) {
|
||||||
|
app.AddGroup(&cobra.Group{
|
||||||
|
ID: command.GroupID,
|
||||||
|
Title: command.GroupID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
app.AddCommand(command)
|
||||||
|
}
|
||||||
|
app.SetArgs(os.Args[1:])
|
||||||
ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP)
|
ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP)
|
||||||
return app.RunContext(ctx, os.Args)
|
return app.ExecuteContext(ctx)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,22 +6,23 @@ import (
|
|||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config/parser"
|
"github.com/opencloud-eu/opencloud/pkg/config/parser"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server is the entrypoint for the server command.
|
// Server is the entrypoint for the server command.
|
||||||
func Server(cfg *config.Config) *cli.Command {
|
func Server(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
return &cobra.Command{
|
||||||
Name: "server",
|
Use: "server",
|
||||||
Usage: "start a fullstack server (runtime and all services in supervised mode)",
|
Short: "start a fullstack server (runtime and all services in supervised mode)",
|
||||||
Category: "fullstack",
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
Before: func(c *cli.Context) error {
|
|
||||||
return configlog.ReturnError(parser.ParseConfig(cfg, false))
|
return configlog.ReturnError(parser.ParseConfig(cfg, false))
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
GroupID: CommandGroupServer,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
// Prefer the in-memory registry as the default when running in single-binary mode
|
// Prefer the in-memory registry as the default when running in single-binary mode
|
||||||
r := runtime.New(cfg)
|
r := runtime.New(cfg)
|
||||||
return r.Start(c.Context)
|
return r.Start(cmd.Context())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"fmt"
|
||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/command/helper"
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
||||||
@@ -13,6 +12,7 @@ import (
|
|||||||
appprovider "github.com/opencloud-eu/opencloud/services/app-provider/pkg/command"
|
appprovider "github.com/opencloud-eu/opencloud/services/app-provider/pkg/command"
|
||||||
appregistry "github.com/opencloud-eu/opencloud/services/app-registry/pkg/command"
|
appregistry "github.com/opencloud-eu/opencloud/services/app-registry/pkg/command"
|
||||||
audit "github.com/opencloud-eu/opencloud/services/audit/pkg/command"
|
audit "github.com/opencloud-eu/opencloud/services/audit/pkg/command"
|
||||||
|
authapi "github.com/opencloud-eu/opencloud/services/auth-api/pkg/command"
|
||||||
authapp "github.com/opencloud-eu/opencloud/services/auth-app/pkg/command"
|
authapp "github.com/opencloud-eu/opencloud/services/auth-app/pkg/command"
|
||||||
authbasic "github.com/opencloud-eu/opencloud/services/auth-basic/pkg/command"
|
authbasic "github.com/opencloud-eu/opencloud/services/auth-basic/pkg/command"
|
||||||
authbearer "github.com/opencloud-eu/opencloud/services/auth-bearer/pkg/command"
|
authbearer "github.com/opencloud-eu/opencloud/services/auth-bearer/pkg/command"
|
||||||
@@ -25,12 +25,12 @@ import (
|
|||||||
gateway "github.com/opencloud-eu/opencloud/services/gateway/pkg/command"
|
gateway "github.com/opencloud-eu/opencloud/services/gateway/pkg/command"
|
||||||
graph "github.com/opencloud-eu/opencloud/services/graph/pkg/command"
|
graph "github.com/opencloud-eu/opencloud/services/graph/pkg/command"
|
||||||
groups "github.com/opencloud-eu/opencloud/services/groups/pkg/command"
|
groups "github.com/opencloud-eu/opencloud/services/groups/pkg/command"
|
||||||
|
groupware "github.com/opencloud-eu/opencloud/services/groupware/pkg/command"
|
||||||
idm "github.com/opencloud-eu/opencloud/services/idm/pkg/command"
|
idm "github.com/opencloud-eu/opencloud/services/idm/pkg/command"
|
||||||
idp "github.com/opencloud-eu/opencloud/services/idp/pkg/command"
|
idp "github.com/opencloud-eu/opencloud/services/idp/pkg/command"
|
||||||
invitations "github.com/opencloud-eu/opencloud/services/invitations/pkg/command"
|
invitations "github.com/opencloud-eu/opencloud/services/invitations/pkg/command"
|
||||||
nats "github.com/opencloud-eu/opencloud/services/nats/pkg/command"
|
nats "github.com/opencloud-eu/opencloud/services/nats/pkg/command"
|
||||||
notifications "github.com/opencloud-eu/opencloud/services/notifications/pkg/command"
|
notifications "github.com/opencloud-eu/opencloud/services/notifications/pkg/command"
|
||||||
ocdav "github.com/opencloud-eu/opencloud/services/ocdav/pkg/command"
|
|
||||||
ocm "github.com/opencloud-eu/opencloud/services/ocm/pkg/command"
|
ocm "github.com/opencloud-eu/opencloud/services/ocm/pkg/command"
|
||||||
ocs "github.com/opencloud-eu/opencloud/services/ocs/pkg/command"
|
ocs "github.com/opencloud-eu/opencloud/services/ocs/pkg/command"
|
||||||
policies "github.com/opencloud-eu/opencloud/services/policies/pkg/command"
|
policies "github.com/opencloud-eu/opencloud/services/policies/pkg/command"
|
||||||
@@ -50,238 +50,248 @@ import (
|
|||||||
web "github.com/opencloud-eu/opencloud/services/web/pkg/command"
|
web "github.com/opencloud-eu/opencloud/services/web/pkg/command"
|
||||||
webdav "github.com/opencloud-eu/opencloud/services/webdav/pkg/command"
|
webdav "github.com/opencloud-eu/opencloud/services/webdav/pkg/command"
|
||||||
webfinger "github.com/opencloud-eu/opencloud/services/webfinger/pkg/command"
|
webfinger "github.com/opencloud-eu/opencloud/services/webfinger/pkg/command"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var svccmds = []register.Command{
|
var serviceCommands = []register.Command{
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Activitylog.Service.Name, activitylog.GetCommands(cfg.Activitylog), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Activitylog.Service.Name, activitylog.GetCommands(cfg.Activitylog), func(c *config.Config) {
|
||||||
cfg.Activitylog.Commons = cfg.Commons
|
cfg.Activitylog.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Antivirus.Service.Name, antivirus.GetCommands(cfg.Antivirus), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Antivirus.Service.Name, antivirus.GetCommands(cfg.Antivirus), func(c *config.Config) {
|
||||||
// cfg.Antivirus.Commons = cfg.Commons // antivirus needs no commons atm
|
cfg.Antivirus.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.AppProvider.Service.Name, appprovider.GetCommands(cfg.AppProvider), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.AppProvider.Service.Name, appprovider.GetCommands(cfg.AppProvider), func(c *config.Config) {
|
||||||
cfg.AppProvider.Commons = cfg.Commons
|
cfg.AppProvider.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.AppRegistry.Service.Name, appregistry.GetCommands(cfg.AppRegistry), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.AppRegistry.Service.Name, appregistry.GetCommands(cfg.AppRegistry), func(c *config.Config) {
|
||||||
cfg.AppRegistry.Commons = cfg.Commons
|
cfg.AppRegistry.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Audit.Service.Name, audit.GetCommands(cfg.Audit), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Audit.Service.Name, audit.GetCommands(cfg.Audit), func(c *config.Config) {
|
||||||
cfg.Audit.Commons = cfg.Commons
|
cfg.Audit.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.AuthApp.Service.Name, authapp.GetCommands(cfg.AuthApp), func(_ *config.Config) {
|
return ServiceCommand(cfg, cfg.AuthApp.Service.Name, authapp.GetCommands(cfg.AuthApp), func(_ *config.Config) {
|
||||||
cfg.AuthApp.Commons = cfg.Commons
|
cfg.AuthApp.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.AuthBasic.Service.Name, authbasic.GetCommands(cfg.AuthBasic), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.AuthBasic.Service.Name, authbasic.GetCommands(cfg.AuthBasic), func(c *config.Config) {
|
||||||
cfg.AuthBasic.Commons = cfg.Commons
|
cfg.AuthBasic.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.AuthBearer.Service.Name, authbearer.GetCommands(cfg.AuthBearer), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.AuthBearer.Service.Name, authbearer.GetCommands(cfg.AuthBearer), func(c *config.Config) {
|
||||||
cfg.AuthBearer.Commons = cfg.Commons
|
cfg.AuthBearer.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.AuthMachine.Service.Name, authmachine.GetCommands(cfg.AuthMachine), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.AuthMachine.Service.Name, authmachine.GetCommands(cfg.AuthMachine), func(c *config.Config) {
|
||||||
cfg.AuthMachine.Commons = cfg.Commons
|
cfg.AuthMachine.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.AuthService.Service.Name, authservice.GetCommands(cfg.AuthService), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.AuthService.Service.Name, authservice.GetCommands(cfg.AuthService), func(c *config.Config) {
|
||||||
cfg.AuthService.Commons = cfg.Commons
|
cfg.AuthService.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Clientlog.Service.Name, clientlog.GetCommands(cfg.Clientlog), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Clientlog.Service.Name, clientlog.GetCommands(cfg.Clientlog), func(c *config.Config) {
|
||||||
cfg.Clientlog.Commons = cfg.Commons
|
cfg.Clientlog.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Collaboration.Service.Name, collaboration.GetCommands(cfg.Collaboration), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Collaboration.Service.Name, collaboration.GetCommands(cfg.Collaboration), func(c *config.Config) {
|
||||||
cfg.Collaboration.Commons = cfg.Commons
|
cfg.Collaboration.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.EventHistory.Service.Name, eventhistory.GetCommands(cfg.EventHistory), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.EventHistory.Service.Name, eventhistory.GetCommands(cfg.EventHistory), func(c *config.Config) {
|
||||||
cfg.EventHistory.Commons = cfg.Commons
|
cfg.EventHistory.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Frontend.Service.Name, frontend.GetCommands(cfg.Frontend), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Frontend.Service.Name, frontend.GetCommands(cfg.Frontend), func(c *config.Config) {
|
||||||
cfg.Frontend.Commons = cfg.Commons
|
cfg.Frontend.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Gateway.Service.Name, gateway.GetCommands(cfg.Gateway), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Gateway.Service.Name, gateway.GetCommands(cfg.Gateway), func(c *config.Config) {
|
||||||
cfg.Gateway.Commons = cfg.Commons
|
cfg.Gateway.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Graph.Service.Name, graph.GetCommands(cfg.Graph), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Graph.Service.Name, graph.GetCommands(cfg.Graph), func(c *config.Config) {
|
||||||
cfg.Graph.Commons = cfg.Commons
|
cfg.Graph.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Groups.Service.Name, groups.GetCommands(cfg.Groups), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Groups.Service.Name, groups.GetCommands(cfg.Groups), func(c *config.Config) {
|
||||||
cfg.Groups.Commons = cfg.Commons
|
cfg.Groups.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
|
return ServiceCommand(cfg, cfg.Groupware.Service.Name, groupware.GetCommands(cfg.Groupware), func(c *config.Config) {
|
||||||
|
cfg.Groupware.Commons = cfg.Commons
|
||||||
|
})
|
||||||
|
},
|
||||||
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.IDM.Service.Name, idm.GetCommands(cfg.IDM), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.IDM.Service.Name, idm.GetCommands(cfg.IDM), func(c *config.Config) {
|
||||||
cfg.IDM.Commons = cfg.Commons
|
cfg.IDM.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.IDP.Service.Name, idp.GetCommands(cfg.IDP), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.IDP.Service.Name, idp.GetCommands(cfg.IDP), func(c *config.Config) {
|
||||||
cfg.IDP.Commons = cfg.Commons
|
cfg.IDP.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Invitations.Service.Name, invitations.GetCommands(cfg.Invitations), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Invitations.Service.Name, invitations.GetCommands(cfg.Invitations), func(c *config.Config) {
|
||||||
cfg.Invitations.Commons = cfg.Commons
|
cfg.Invitations.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Nats.Service.Name, nats.GetCommands(cfg.Nats), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Nats.Service.Name, nats.GetCommands(cfg.Nats), func(c *config.Config) {
|
||||||
cfg.Nats.Commons = cfg.Commons
|
cfg.Nats.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Notifications.Service.Name, notifications.GetCommands(cfg.Notifications), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Notifications.Service.Name, notifications.GetCommands(cfg.Notifications), func(c *config.Config) {
|
||||||
cfg.Notifications.Commons = cfg.Commons
|
cfg.Notifications.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.OCDav.Service.Name, ocdav.GetCommands(cfg.OCDav), func(c *config.Config) {
|
|
||||||
cfg.OCDav.Commons = cfg.Commons
|
|
||||||
})
|
|
||||||
},
|
|
||||||
func(cfg *config.Config) *cli.Command {
|
|
||||||
return ServiceCommand(cfg, cfg.OCM.Service.Name, ocm.GetCommands(cfg.OCM), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.OCM.Service.Name, ocm.GetCommands(cfg.OCM), func(c *config.Config) {
|
||||||
cfg.OCM.Commons = cfg.Commons
|
cfg.OCM.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.OCS.Service.Name, ocs.GetCommands(cfg.OCS), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.OCS.Service.Name, ocs.GetCommands(cfg.OCS), func(c *config.Config) {
|
||||||
cfg.OCS.Commons = cfg.Commons
|
cfg.OCS.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Policies.Service.Name, policies.GetCommands(cfg.Policies), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Policies.Service.Name, policies.GetCommands(cfg.Policies), func(c *config.Config) {
|
||||||
cfg.Policies.Commons = cfg.Commons
|
cfg.Policies.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Postprocessing.Service.Name, postprocessing.GetCommands(cfg.Postprocessing), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Postprocessing.Service.Name, postprocessing.GetCommands(cfg.Postprocessing), func(c *config.Config) {
|
||||||
cfg.Postprocessing.Commons = cfg.Commons
|
cfg.Postprocessing.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Proxy.Service.Name, proxy.GetCommands(cfg.Proxy), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Proxy.Service.Name, proxy.GetCommands(cfg.Proxy), func(c *config.Config) {
|
||||||
cfg.Proxy.Commons = cfg.Commons
|
cfg.Proxy.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Search.Service.Name, search.GetCommands(cfg.Search), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Search.Service.Name, search.GetCommands(cfg.Search), func(c *config.Config) {
|
||||||
cfg.Search.Commons = cfg.Commons
|
cfg.Search.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Settings.Service.Name, settings.GetCommands(cfg.Settings), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Settings.Service.Name, settings.GetCommands(cfg.Settings), func(c *config.Config) {
|
||||||
cfg.Settings.Commons = cfg.Commons
|
cfg.Settings.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Sharing.Service.Name, sharing.GetCommands(cfg.Sharing), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Sharing.Service.Name, sharing.GetCommands(cfg.Sharing), func(c *config.Config) {
|
||||||
cfg.Sharing.Commons = cfg.Commons
|
cfg.Sharing.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.SSE.Service.Name, sse.GetCommands(cfg.SSE), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.SSE.Service.Name, sse.GetCommands(cfg.SSE), func(c *config.Config) {
|
||||||
cfg.SSE.Commons = cfg.Commons
|
cfg.SSE.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.StoragePublicLink.Service.Name, storagepubliclink.GetCommands(cfg.StoragePublicLink), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.StoragePublicLink.Service.Name, storagepubliclink.GetCommands(cfg.StoragePublicLink), func(c *config.Config) {
|
||||||
cfg.StoragePublicLink.Commons = cfg.Commons
|
cfg.StoragePublicLink.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.StorageShares.Service.Name, storageshares.GetCommands(cfg.StorageShares), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.StorageShares.Service.Name, storageshares.GetCommands(cfg.StorageShares), func(c *config.Config) {
|
||||||
cfg.StorageShares.Commons = cfg.Commons
|
cfg.StorageShares.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.StorageSystem.Service.Name, storagesystem.GetCommands(cfg.StorageSystem), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.StorageSystem.Service.Name, storagesystem.GetCommands(cfg.StorageSystem), func(c *config.Config) {
|
||||||
cfg.StorageSystem.Commons = cfg.Commons
|
cfg.StorageSystem.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.StorageUsers.Service.Name, storageusers.GetCommands(cfg.StorageUsers), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.StorageUsers.Service.Name, storageusers.GetCommands(cfg.StorageUsers), func(c *config.Config) {
|
||||||
cfg.StorageUsers.Commons = cfg.Commons
|
cfg.StorageUsers.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Thumbnails.Service.Name, thumbnails.GetCommands(cfg.Thumbnails), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Thumbnails.Service.Name, thumbnails.GetCommands(cfg.Thumbnails), func(c *config.Config) {
|
||||||
cfg.Thumbnails.Commons = cfg.Commons
|
cfg.Thumbnails.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Userlog.Service.Name, userlog.GetCommands(cfg.Userlog), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Userlog.Service.Name, userlog.GetCommands(cfg.Userlog), func(c *config.Config) {
|
||||||
cfg.Userlog.Commons = cfg.Commons
|
cfg.Userlog.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Users.Service.Name, users.GetCommands(cfg.Users), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Users.Service.Name, users.GetCommands(cfg.Users), func(c *config.Config) {
|
||||||
cfg.Users.Commons = cfg.Commons
|
cfg.Users.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Web.Service.Name, web.GetCommands(cfg.Web), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Web.Service.Name, web.GetCommands(cfg.Web), func(c *config.Config) {
|
||||||
cfg.Web.Commons = cfg.Commons
|
cfg.Web.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.WebDAV.Service.Name, webdav.GetCommands(cfg.WebDAV), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.WebDAV.Service.Name, webdav.GetCommands(cfg.WebDAV), func(c *config.Config) {
|
||||||
cfg.WebDAV.Commons = cfg.Commons
|
cfg.WebDAV.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
func(cfg *config.Config) *cli.Command {
|
func(cfg *config.Config) *cobra.Command {
|
||||||
return ServiceCommand(cfg, cfg.Webfinger.Service.Name, webfinger.GetCommands(cfg.Webfinger), func(c *config.Config) {
|
return ServiceCommand(cfg, cfg.Webfinger.Service.Name, webfinger.GetCommands(cfg.Webfinger), func(c *config.Config) {
|
||||||
cfg.Webfinger.Commons = cfg.Commons
|
cfg.Webfinger.Commons = cfg.Commons
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
func(cfg *config.Config) *cobra.Command {
|
||||||
|
return ServiceCommand(cfg, cfg.AuthApi.Service.Name, authapi.GetCommands(cfg.AuthApi), func(c *config.Config) {
|
||||||
|
cfg.AuthApi.Commons = cfg.Commons
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceCommand is the entry point for the all service commands.
|
// ServiceCommand composes a cobra command from the given inputs.
|
||||||
func ServiceCommand(cfg *config.Config, serviceName string, subcommands []*cli.Command, f func(*config.Config)) *cli.Command {
|
func ServiceCommand(cfg *config.Config, serviceName string, subCommands []*cobra.Command, f func(*config.Config)) *cobra.Command {
|
||||||
return &cli.Command{
|
command := &cobra.Command{
|
||||||
Name: serviceName,
|
Use: serviceName,
|
||||||
Usage: helper.SubcommandDescription(serviceName),
|
Short: fmt.Sprintf("%s service commands", serviceName),
|
||||||
Category: "services",
|
GroupID: CommandGroupServices,
|
||||||
Before: func(c *cli.Context) error {
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
configlog.Error(parser.ParseConfig(cfg, true))
|
configlog.Error(parser.ParseConfig(cfg, true))
|
||||||
f(cfg)
|
f(cfg)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Subcommands: subcommands,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
command.AddCommand(subCommands...)
|
||||||
|
|
||||||
|
return command
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
for _, c := range svccmds {
|
for _, c := range serviceCommands {
|
||||||
register.AddCommand(c)
|
register.AddCommand(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,7 @@ package command
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/spf13/viper"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
|
|
||||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
|
||||||
"github.com/opencloud-eu/reva/v2/pkg/share/manager/jsoncs3"
|
|
||||||
"github.com/opencloud-eu/reva/v2/pkg/share/manager/registry"
|
|
||||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
|
||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
@@ -19,15 +13,21 @@ import (
|
|||||||
mregistry "github.com/opencloud-eu/opencloud/pkg/registry"
|
mregistry "github.com/opencloud-eu/opencloud/pkg/registry"
|
||||||
sharing "github.com/opencloud-eu/opencloud/services/sharing/pkg/config"
|
sharing "github.com/opencloud-eu/opencloud/services/sharing/pkg/config"
|
||||||
sharingparser "github.com/opencloud-eu/opencloud/services/sharing/pkg/config/parser"
|
sharingparser "github.com/opencloud-eu/opencloud/services/sharing/pkg/config/parser"
|
||||||
|
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||||
|
"github.com/opencloud-eu/reva/v2/pkg/share/manager/jsoncs3"
|
||||||
|
"github.com/opencloud-eu/reva/v2/pkg/share/manager/registry"
|
||||||
|
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SharesCommand is the entrypoint for the groups command.
|
// SharesCommand is the entrypoint for the groups command.
|
||||||
func SharesCommand(cfg *config.Config) *cli.Command {
|
func SharesCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
sharesCmd := &cobra.Command{
|
||||||
Name: "shares",
|
Use: "shares",
|
||||||
Usage: `cli tools to manage entries in the share manager.`,
|
Short: `cli tools to manage entries in the share manager.`,
|
||||||
Category: "maintenance",
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
Before: func(c *cli.Context) error {
|
|
||||||
// Parse base config
|
// Parse base config
|
||||||
if err := parser.ParseConfig(cfg, true); err != nil {
|
if err := parser.ParseConfig(cfg, true); err != nil {
|
||||||
return configlog.ReturnError(err)
|
return configlog.ReturnError(err)
|
||||||
@@ -37,37 +37,21 @@ func SharesCommand(cfg *config.Config) *cli.Command {
|
|||||||
cfg.Sharing.Commons = cfg.Commons
|
cfg.Sharing.Commons = cfg.Commons
|
||||||
return configlog.ReturnError(sharingparser.ParseConfig(cfg.Sharing))
|
return configlog.ReturnError(sharingparser.ParseConfig(cfg.Sharing))
|
||||||
},
|
},
|
||||||
Subcommands: []*cli.Command{
|
|
||||||
cleanupCmd(cfg),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
sharesCmd.AddCommand(cleanupCmd(cfg))
|
||||||
|
|
||||||
|
return sharesCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
register.AddCommand(SharesCommand)
|
register.AddCommand(SharesCommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupCmd(cfg *config.Config) *cli.Command {
|
func cleanupCmd(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
cleanCmd := &cobra.Command{
|
||||||
Name: "cleanup",
|
Use: "cleanup",
|
||||||
Usage: `clean up stale entries in the share manager.`,
|
Short: `clean up stale entries in the share manager.`,
|
||||||
Flags: []cli.Flag{
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "service-account-id",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Name of the service account to use for the cleanup",
|
|
||||||
EnvVars: []string{"OC_SERVICE_ACCOUNT_ID"},
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "service-account-secret",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Secret for the service account",
|
|
||||||
EnvVars: []string{"OC_SERVICE_ACCOUNT_SECRET"},
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Before: func(c *cli.Context) error {
|
|
||||||
// Parse base config
|
// Parse base config
|
||||||
if err := parser.ParseConfig(cfg, true); err != nil {
|
if err := parser.ParseConfig(cfg, true); err != nil {
|
||||||
return configlog.ReturnError(err)
|
return configlog.ReturnError(err)
|
||||||
@@ -77,13 +61,24 @@ func cleanupCmd(cfg *config.Config) *cli.Command {
|
|||||||
cfg.Sharing.Commons = cfg.Commons
|
cfg.Sharing.Commons = cfg.Commons
|
||||||
return configlog.ReturnError(sharingparser.ParseConfig(cfg.Sharing))
|
return configlog.ReturnError(sharingparser.ParseConfig(cfg.Sharing))
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return cleanup(c, cfg)
|
return cleanup(cmd, cfg)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
cleanCmd.Flags().String("service-account-id", "", "Name of the service account to use for the cleanup")
|
||||||
|
_ = cleanCmd.MarkFlagRequired("service-account-id")
|
||||||
|
_ = viper.BindEnv("service-account-id", "OC_SERVICE_ACCOUNT_ID")
|
||||||
|
_ = viper.BindPFlag("service-account-id", cleanCmd.Flags().Lookup("service-account-id"))
|
||||||
|
|
||||||
|
cleanCmd.Flags().String("service-account-secret", "", "Secret for the service account")
|
||||||
|
_ = cleanCmd.MarkFlagRequired("service-account-secret")
|
||||||
|
_ = viper.BindEnv("service-account-secret", "OC_SERVICE_ACCOUNT_SECRET")
|
||||||
|
_ = viper.BindPFlag("service-account-secret", cleanCmd.Flags().Lookup("service-account-secret"))
|
||||||
|
|
||||||
|
return cleanCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanup(c *cli.Context, cfg *config.Config) error {
|
func cleanup(_ *cobra.Command, cfg *config.Config) error {
|
||||||
driver := cfg.Sharing.UserSharingDriver
|
driver := cfg.Sharing.UserSharingDriver
|
||||||
// cleanup is only implemented for the jsoncs3 share manager
|
// cleanup is only implemented for the jsoncs3 share manager
|
||||||
if driver != "jsoncs3" {
|
if driver != "jsoncs3" {
|
||||||
@@ -114,7 +109,9 @@ func cleanup(c *cli.Context, cfg *config.Config) error {
|
|||||||
return configlog.ReturnError(err)
|
return configlog.ReturnError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceUserCtx, err := utils.GetServiceUserContext(c.String("service-account-id"), client, c.String("service-account-secret"))
|
serviceAccountIDFlag := viper.GetString("service-account-id")
|
||||||
|
serviceAccountSecretFlag := viper.GetString("service-account-secret")
|
||||||
|
serviceUserCtx, err := utils.GetServiceUserContext(serviceAccountIDFlag, client, serviceAccountSecretFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return configlog.ReturnError(err)
|
return configlog.ReturnError(err)
|
||||||
}
|
}
|
||||||
@@ -171,39 +168,6 @@ func revaShareConfig(cfg *sharing.Config) map[string]interface{} {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func revaPublicShareConfig(cfg *sharing.Config) map[string]interface{} {
|
|
||||||
return map[string]interface{}{
|
|
||||||
"json": map[string]interface{}{
|
|
||||||
"file": cfg.PublicSharingDrivers.JSON.File,
|
|
||||||
"gateway_addr": cfg.Reva.Address,
|
|
||||||
},
|
|
||||||
"jsoncs3": map[string]interface{}{
|
|
||||||
"gateway_addr": cfg.Reva.Address,
|
|
||||||
"provider_addr": cfg.PublicSharingDrivers.JSONCS3.ProviderAddr,
|
|
||||||
"service_user_id": cfg.PublicSharingDrivers.JSONCS3.SystemUserID,
|
|
||||||
"service_user_idp": cfg.PublicSharingDrivers.JSONCS3.SystemUserIDP,
|
|
||||||
"machine_auth_apikey": cfg.PublicSharingDrivers.JSONCS3.SystemUserAPIKey,
|
|
||||||
},
|
|
||||||
"sql": map[string]interface{}{
|
|
||||||
"db_username": cfg.PublicSharingDrivers.SQL.DBUsername,
|
|
||||||
"db_password": cfg.PublicSharingDrivers.SQL.DBPassword,
|
|
||||||
"db_host": cfg.PublicSharingDrivers.SQL.DBHost,
|
|
||||||
"db_port": cfg.PublicSharingDrivers.SQL.DBPort,
|
|
||||||
"db_name": cfg.PublicSharingDrivers.SQL.DBName,
|
|
||||||
"password_hash_cost": cfg.PublicSharingDrivers.SQL.PasswordHashCost,
|
|
||||||
"enable_expired_shares_cleanup": cfg.PublicSharingDrivers.SQL.EnableExpiredSharesCleanup,
|
|
||||||
"janitor_run_interval": cfg.PublicSharingDrivers.SQL.JanitorRunInterval,
|
|
||||||
},
|
|
||||||
"cs3": map[string]interface{}{
|
|
||||||
"gateway_addr": cfg.PublicSharingDrivers.CS3.ProviderAddr,
|
|
||||||
"provider_addr": cfg.PublicSharingDrivers.CS3.ProviderAddr,
|
|
||||||
"service_user_id": cfg.PublicSharingDrivers.CS3.SystemUserID,
|
|
||||||
"service_user_idp": cfg.PublicSharingDrivers.CS3.SystemUserIDP,
|
|
||||||
"machine_auth_apikey": cfg.PublicSharingDrivers.CS3.SystemUserAPIKey,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func logger() *zerolog.Logger {
|
func logger() *zerolog.Logger {
|
||||||
log := oclog.NewLogger(
|
log := oclog.NewLogger(
|
||||||
oclog.Name("migrate"),
|
oclog.Name("migrate"),
|
||||||
|
|||||||
@@ -3,57 +3,40 @@ package command
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/trash"
|
|
||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/trash"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config/parser"
|
"github.com/opencloud-eu/opencloud/pkg/config/parser"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TrashCommand(cfg *config.Config) *cli.Command {
|
func TrashCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
trashCmd := &cobra.Command{
|
||||||
Name: "trash",
|
Use: "trash",
|
||||||
Usage: "OpenCloud trash functionality",
|
Short: "OpenCloud trash functionality",
|
||||||
Subcommands: []*cli.Command{
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
TrashPurgeEmptyDirsCommand(cfg),
|
|
||||||
},
|
|
||||||
Before: func(c *cli.Context) error {
|
|
||||||
return configlog.ReturnError(parser.ParseConfig(cfg, true))
|
return configlog.ReturnError(parser.ParseConfig(cfg, true))
|
||||||
},
|
},
|
||||||
Action: func(_ *cli.Context) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
fmt.Println("Read the docs")
|
fmt.Println("Read the docs")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
trashCmd.AddCommand(TrashPurgeEmptyDirsCommand(cfg))
|
||||||
|
|
||||||
|
return trashCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func TrashPurgeEmptyDirsCommand(cfg *config.Config) *cli.Command {
|
func TrashPurgeEmptyDirsCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
trashPurgeCmd := &cobra.Command{
|
||||||
Name: "purge-empty-dirs",
|
Use: "purge-empty-dirs",
|
||||||
Usage: "purge empty directories",
|
Short: "purge empty directories",
|
||||||
Flags: []cli.Flag{
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
&cli.StringFlag{
|
basePath, _ := cmd.Flags().GetString("basepath")
|
||||||
Name: "basepath",
|
dryRun, _ := cmd.Flags().GetBool("dry-run")
|
||||||
Aliases: []string{"p"},
|
if err := trash.PurgeTrashEmptyPaths(basePath, dryRun); err != nil {
|
||||||
Usage: "the basepath of the decomposedfs (e.g. /var/tmp/opencloud/storage/users)",
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "dry-run",
|
|
||||||
Usage: "do not delete anything, just print what would be deleted",
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
basePath := c.String("basepath")
|
|
||||||
if basePath == "" {
|
|
||||||
fmt.Println("basepath is required")
|
|
||||||
return cli.ShowCommandHelp(c, "trash")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := trash.PurgeTrashEmptyPaths(basePath, c.Bool("dry-run")); err != nil {
|
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -61,6 +44,12 @@ func TrashPurgeEmptyDirsCommand(cfg *config.Config) *cli.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
trashPurgeCmd.Flags().StringP("basepath", "p", "", "the basepath of the decomposedfs (e.g. /var/tmp/opencloud/storage/users)")
|
||||||
|
_ = trashPurgeCmd.MarkFlagRequired("basepath")
|
||||||
|
|
||||||
|
trashPurgeCmd.Flags().Bool("dry-run", true, "do not delete anything, just print what would be deleted")
|
||||||
|
|
||||||
|
return trashPurgeCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -4,15 +4,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/spf13/cobra"
|
||||||
"github.com/olekukonko/tablewriter/tw"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
mreg "go-micro.dev/v4/registry"
|
|
||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||||
|
|
||||||
|
"github.com/olekukonko/tablewriter"
|
||||||
|
"github.com/olekukonko/tablewriter/tw"
|
||||||
|
mreg "go-micro.dev/v4/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -20,22 +21,18 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// VersionCommand is the entrypoint for the version command.
|
// VersionCommand is the entrypoint for the version command.
|
||||||
func VersionCommand(cfg *config.Config) *cli.Command {
|
func VersionCommand(cfg *config.Config) *cobra.Command {
|
||||||
return &cli.Command{
|
versionCmd := &cobra.Command{
|
||||||
Name: "version",
|
Use: "version",
|
||||||
Usage: "print the version of this binary and all running service instances",
|
Short: "print the version of this binary and all running service instances",
|
||||||
Flags: []cli.Flag{
|
GroupID: CommandGroupServer,
|
||||||
&cli.BoolFlag{
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
Name: _skipServiceListingFlagName,
|
|
||||||
Usage: "skip service listing",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Category: "info",
|
|
||||||
Action: func(c *cli.Context) error {
|
|
||||||
fmt.Println("Version: " + version.GetString())
|
fmt.Println("Version: " + version.GetString())
|
||||||
|
fmt.Printf("Edition: %s\n", version.Edition)
|
||||||
fmt.Printf("Compiled: %s\n", version.Compiled())
|
fmt.Printf("Compiled: %s\n", version.Compiled())
|
||||||
|
|
||||||
if c.Bool(_skipServiceListingFlagName) {
|
skipServiceListing, _ := cmd.Flags().GetBool(_skipServiceListingFlagName)
|
||||||
|
if skipServiceListing {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +71,8 @@ func VersionCommand(cfg *config.Config) *cli.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
versionCmd.Flags().Bool(_skipServiceListingFlagName, false, "skip service listing")
|
||||||
|
return versionCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/gofrs/uuid"
|
"github.com/google/uuid"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/pkg/generators"
|
"github.com/opencloud-eu/opencloud/pkg/generators"
|
||||||
@@ -103,11 +103,11 @@ func CreateConfig(insecure, forceOverwrite, diff bool, configPath, adminPassword
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
systemUserID = uuid.Must(uuid.NewV4()).String()
|
systemUserID = uuid.NewString()
|
||||||
adminUserID = uuid.Must(uuid.NewV4()).String()
|
adminUserID = uuid.NewString()
|
||||||
graphApplicationID = uuid.Must(uuid.NewV4()).String()
|
graphApplicationID = uuid.NewString()
|
||||||
storageUsersMountID = uuid.Must(uuid.NewV4()).String()
|
storageUsersMountID = uuid.NewString()
|
||||||
serviceAccountID = uuid.Must(uuid.NewV4()).String()
|
serviceAccountID = uuid.NewString()
|
||||||
|
|
||||||
idmServicePassword, err = generators.GenerateRandomPassword(passwordLength)
|
idmServicePassword, err = generators.GenerateRandomPassword(passwordLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -281,6 +281,7 @@ func CreateConfig(insecure, forceOverwrite, diff bool, configPath, adminPassword
|
|||||||
cfg.Collaboration.App.Insecure = true
|
cfg.Collaboration.App.Insecure = true
|
||||||
cfg.Frontend.AppHandler = _insecureService
|
cfg.Frontend.AppHandler = _insecureService
|
||||||
cfg.Frontend.Archiver = _insecureService
|
cfg.Frontend.Archiver = _insecureService
|
||||||
|
cfg.Frontend.OCDav = _insecureService
|
||||||
cfg.Graph.Spaces = _insecureService
|
cfg.Graph.Spaces = _insecureService
|
||||||
cfg.Graph.Events = _insecureEvents
|
cfg.Graph.Events = _insecureEvents
|
||||||
cfg.Notifications.Notifications.Events = _insecureEvents
|
cfg.Notifications.Notifications.Events = _insecureEvents
|
||||||
@@ -289,7 +290,6 @@ func CreateConfig(insecure, forceOverwrite, diff bool, configPath, adminPassword
|
|||||||
cfg.Sharing.Events = _insecureEvents
|
cfg.Sharing.Events = _insecureEvents
|
||||||
cfg.StorageUsers.Events = _insecureEvents
|
cfg.StorageUsers.Events = _insecureEvents
|
||||||
cfg.Nats.Nats.TLSSkipVerifyClientCert = true
|
cfg.Nats.Nats.TLSSkipVerifyClientCert = true
|
||||||
cfg.Ocdav = _insecureService
|
|
||||||
cfg.Proxy = ProxyService{
|
cfg.Proxy = ProxyService{
|
||||||
InsecureBackends: true,
|
InsecureBackends: true,
|
||||||
OIDC: InsecureProxyOIDC{
|
OIDC: InsecureProxyOIDC{
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ type OpenCloudConfig struct {
|
|||||||
AuthBearer AuthbearerService `yaml:"auth_bearer"`
|
AuthBearer AuthbearerService `yaml:"auth_bearer"`
|
||||||
Users UsersAndGroupsService `yaml:"users"`
|
Users UsersAndGroupsService `yaml:"users"`
|
||||||
Groups UsersAndGroupsService `yaml:"groups"`
|
Groups UsersAndGroupsService `yaml:"groups"`
|
||||||
Ocdav InsecureService `yaml:"ocdav"`
|
Groupware GroupwareService `yaml:"groupware"`
|
||||||
Ocm OcmService `yaml:"ocm"`
|
Ocm OcmService `yaml:"ocm"`
|
||||||
Thumbnails ThumbnailService `yaml:"thumbnails"`
|
Thumbnails ThumbnailService `yaml:"thumbnails"`
|
||||||
Search Search `yaml:"search"`
|
Search Search `yaml:"search"`
|
||||||
@@ -105,6 +105,7 @@ type FrontendService struct {
|
|||||||
AppHandler InsecureService `yaml:"app_handler"`
|
AppHandler InsecureService `yaml:"app_handler"`
|
||||||
Archiver InsecureService
|
Archiver InsecureService
|
||||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||||
|
OCDav InsecureService
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gateway is the configuration for the gateway
|
// Gateway is the configuration for the gateway
|
||||||
@@ -126,6 +127,17 @@ type GraphService struct {
|
|||||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupwareSettings is the configuration for the groupware settings
|
||||||
|
type GroupwareSettings struct {
|
||||||
|
WebdavAllowInsecure bool `yaml:"webdav_allow_insecure"`
|
||||||
|
Cs3AllowInsecure bool `yaml:"cs3_allow_insecure"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupwareService is the configuration for the groupware service
|
||||||
|
type GroupwareService struct {
|
||||||
|
Groupware GroupwareSettings
|
||||||
|
}
|
||||||
|
|
||||||
// IdmService is the configuration for the IDM service
|
// IdmService is the configuration for the IDM service
|
||||||
type IdmService struct {
|
type IdmService struct {
|
||||||
ServiceUserPasswords ServiceUserPasswordsSettings `yaml:"service_user_passwords"`
|
ServiceUserPasswords ServiceUserPasswordsSettings `yaml:"service_user_passwords"`
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
package register
|
package register
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/pkg/config"
|
"github.com/opencloud-eu/opencloud/pkg/config"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Commands defines the slice of commands.
|
// Commands define the slice of commands.
|
||||||
Commands = []Command{}
|
Commands []Command
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command defines the register command.
|
// Command defines the register command.
|
||||||
type Command func(*config.Config) *cli.Command
|
type Command func(*config.Config) *cobra.Command
|
||||||
|
|
||||||
// AddCommand appends a command to Commands.
|
// AddCommand appends a command to Commands.
|
||||||
func AddCommand(cmd Command) {
|
func AddCommand(cmd Command) {
|
||||||
|
|||||||
@@ -2,14 +2,12 @@ package runtime
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options is a runtime option
|
// Options is a runtime option
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Services []string
|
Services []string
|
||||||
Logger log.Logger
|
Logger log.Logger
|
||||||
Context *cli.Context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option undocumented
|
// Option undocumented
|
||||||
@@ -21,10 +19,3 @@ func Services(s []string) Option {
|
|||||||
o.Services = append(o.Services, s...)
|
o.Services = append(o.Services, s...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context option
|
|
||||||
func Context(c *cli.Context) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Context = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/rpc"
|
"net/rpc"
|
||||||
@@ -25,6 +24,7 @@ import (
|
|||||||
appProvider "github.com/opencloud-eu/opencloud/services/app-provider/pkg/command"
|
appProvider "github.com/opencloud-eu/opencloud/services/app-provider/pkg/command"
|
||||||
appRegistry "github.com/opencloud-eu/opencloud/services/app-registry/pkg/command"
|
appRegistry "github.com/opencloud-eu/opencloud/services/app-registry/pkg/command"
|
||||||
audit "github.com/opencloud-eu/opencloud/services/audit/pkg/command"
|
audit "github.com/opencloud-eu/opencloud/services/audit/pkg/command"
|
||||||
|
authapi "github.com/opencloud-eu/opencloud/services/auth-api/pkg/command"
|
||||||
authapp "github.com/opencloud-eu/opencloud/services/auth-app/pkg/command"
|
authapp "github.com/opencloud-eu/opencloud/services/auth-app/pkg/command"
|
||||||
authbasic "github.com/opencloud-eu/opencloud/services/auth-basic/pkg/command"
|
authbasic "github.com/opencloud-eu/opencloud/services/auth-basic/pkg/command"
|
||||||
authmachine "github.com/opencloud-eu/opencloud/services/auth-machine/pkg/command"
|
authmachine "github.com/opencloud-eu/opencloud/services/auth-machine/pkg/command"
|
||||||
@@ -36,12 +36,12 @@ import (
|
|||||||
gateway "github.com/opencloud-eu/opencloud/services/gateway/pkg/command"
|
gateway "github.com/opencloud-eu/opencloud/services/gateway/pkg/command"
|
||||||
graph "github.com/opencloud-eu/opencloud/services/graph/pkg/command"
|
graph "github.com/opencloud-eu/opencloud/services/graph/pkg/command"
|
||||||
groups "github.com/opencloud-eu/opencloud/services/groups/pkg/command"
|
groups "github.com/opencloud-eu/opencloud/services/groups/pkg/command"
|
||||||
|
groupware "github.com/opencloud-eu/opencloud/services/groupware/pkg/command"
|
||||||
idm "github.com/opencloud-eu/opencloud/services/idm/pkg/command"
|
idm "github.com/opencloud-eu/opencloud/services/idm/pkg/command"
|
||||||
idp "github.com/opencloud-eu/opencloud/services/idp/pkg/command"
|
idp "github.com/opencloud-eu/opencloud/services/idp/pkg/command"
|
||||||
invitations "github.com/opencloud-eu/opencloud/services/invitations/pkg/command"
|
invitations "github.com/opencloud-eu/opencloud/services/invitations/pkg/command"
|
||||||
nats "github.com/opencloud-eu/opencloud/services/nats/pkg/command"
|
nats "github.com/opencloud-eu/opencloud/services/nats/pkg/command"
|
||||||
notifications "github.com/opencloud-eu/opencloud/services/notifications/pkg/command"
|
notifications "github.com/opencloud-eu/opencloud/services/notifications/pkg/command"
|
||||||
ocdav "github.com/opencloud-eu/opencloud/services/ocdav/pkg/command"
|
|
||||||
ocm "github.com/opencloud-eu/opencloud/services/ocm/pkg/command"
|
ocm "github.com/opencloud-eu/opencloud/services/ocm/pkg/command"
|
||||||
ocs "github.com/opencloud-eu/opencloud/services/ocs/pkg/command"
|
ocs "github.com/opencloud-eu/opencloud/services/ocs/pkg/command"
|
||||||
policies "github.com/opencloud-eu/opencloud/services/policies/pkg/command"
|
policies "github.com/opencloud-eu/opencloud/services/policies/pkg/command"
|
||||||
@@ -125,7 +125,7 @@ func NewService(ctx context.Context, options ...Option) (*Service, error) {
|
|||||||
if s.Services[priority] == nil {
|
if s.Services[priority] == nil {
|
||||||
s.Services[priority] = make(serviceFuncMap)
|
s.Services[priority] = make(serviceFuncMap)
|
||||||
}
|
}
|
||||||
s.Services[priority][name] = NewSutureServiceBuilder(exec)
|
s.Services[priority][name] = NewSutureServiceBuilder(name, exec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// nats is in priority group 0. It needs to start before all other services
|
// nats is in priority group 0. It needs to start before all other services
|
||||||
@@ -205,11 +205,6 @@ func NewService(ctx context.Context, options ...Option) (*Service, error) {
|
|||||||
cfg.IDM.Commons = cfg.Commons
|
cfg.IDM.Commons = cfg.Commons
|
||||||
return idm.Execute(cfg.IDM)
|
return idm.Execute(cfg.IDM)
|
||||||
})
|
})
|
||||||
reg(3, opts.Config.OCDav.Service.Name, func(ctx context.Context, cfg *occfg.Config) error {
|
|
||||||
cfg.OCDav.Context = ctx
|
|
||||||
cfg.OCDav.Commons = cfg.Commons
|
|
||||||
return ocdav.Execute(cfg.OCDav)
|
|
||||||
})
|
|
||||||
reg(3, opts.Config.OCS.Service.Name, func(ctx context.Context, cfg *occfg.Config) error {
|
reg(3, opts.Config.OCS.Service.Name, func(ctx context.Context, cfg *occfg.Config) error {
|
||||||
cfg.OCS.Context = ctx
|
cfg.OCS.Context = ctx
|
||||||
cfg.OCS.Commons = cfg.Commons
|
cfg.OCS.Commons = cfg.Commons
|
||||||
@@ -317,11 +312,11 @@ func NewService(ctx context.Context, options ...Option) (*Service, error) {
|
|||||||
|
|
||||||
// populate optional services
|
// populate optional services
|
||||||
areg := func(name string, exec func(context.Context, *occfg.Config) error) {
|
areg := func(name string, exec func(context.Context, *occfg.Config) error) {
|
||||||
s.Additional[name] = NewSutureServiceBuilder(exec)
|
s.Additional[name] = NewSutureServiceBuilder(name, exec)
|
||||||
}
|
}
|
||||||
areg(opts.Config.Antivirus.Service.Name, func(ctx context.Context, cfg *occfg.Config) error {
|
areg(opts.Config.Antivirus.Service.Name, func(ctx context.Context, cfg *occfg.Config) error {
|
||||||
cfg.Antivirus.Context = ctx
|
cfg.Antivirus.Context = ctx
|
||||||
// cfg.Antivirus.Commons = cfg.Commons // antivirus holds no Commons atm
|
cfg.Antivirus.Commons = cfg.Commons
|
||||||
return antivirus.Execute(cfg.Antivirus)
|
return antivirus.Execute(cfg.Antivirus)
|
||||||
})
|
})
|
||||||
areg(opts.Config.Audit.Service.Name, func(ctx context.Context, cfg *occfg.Config) error {
|
areg(opts.Config.Audit.Service.Name, func(ctx context.Context, cfg *occfg.Config) error {
|
||||||
@@ -349,6 +344,16 @@ func NewService(ctx context.Context, options ...Option) (*Service, error) {
|
|||||||
cfg.Notifications.Commons = cfg.Commons
|
cfg.Notifications.Commons = cfg.Commons
|
||||||
return notifications.Execute(cfg.Notifications)
|
return notifications.Execute(cfg.Notifications)
|
||||||
})
|
})
|
||||||
|
areg(opts.Config.AuthApi.Service.Name, func(ctx context.Context, cfg *occfg.Config) error {
|
||||||
|
cfg.AuthApi.Context = ctx
|
||||||
|
cfg.AuthApi.Commons = cfg.Commons
|
||||||
|
return authapi.Execute(cfg.AuthApi)
|
||||||
|
})
|
||||||
|
areg(opts.Config.Groupware.Service.Name, func(ctx context.Context, cfg *occfg.Config) error {
|
||||||
|
cfg.Groupware.Context = ctx
|
||||||
|
cfg.Groupware.Commons = cfg.Commons
|
||||||
|
return groupware.Execute(cfg.Groupware)
|
||||||
|
})
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
@@ -382,7 +387,32 @@ func Start(ctx context.Context, o ...Option) error {
|
|||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.Log.Info().Str("event", e.String()).Msg(fmt.Sprintf("supervisor: %v", e.Map()["supervisor_name"]))
|
switch ev := e.(type) {
|
||||||
|
case suture.EventServicePanic:
|
||||||
|
l := s.Log.Fatal()
|
||||||
|
if ev.Restarting {
|
||||||
|
l = s.Log.Error()
|
||||||
|
}
|
||||||
|
l.Str("event", e.String()).Str("service", ev.ServiceName).Str("supervisor", ev.SupervisorName).
|
||||||
|
Bool("restarting", ev.Restarting).Float64("failures", ev.CurrentFailures).Float64("threshold", ev.FailureThreshold).
|
||||||
|
Str("message", ev.PanicMsg).Msg("service panic")
|
||||||
|
case suture.EventServiceTerminate:
|
||||||
|
l := s.Log.Fatal()
|
||||||
|
if ev.Restarting {
|
||||||
|
l = s.Log.Error()
|
||||||
|
}
|
||||||
|
l.Str("event", e.String()).Str("service", ev.ServiceName).Str("supervisor", ev.SupervisorName).
|
||||||
|
Bool("restarting", ev.Restarting).Float64("failures", ev.CurrentFailures).Float64("threshold", ev.FailureThreshold).
|
||||||
|
Interface("error", ev.Err).Msg("service terminated")
|
||||||
|
case suture.EventBackoff:
|
||||||
|
s.Log.Warn().Str("event", e.String()).Str("supervisor", ev.SupervisorName).Msg("service backoff")
|
||||||
|
case suture.EventResume:
|
||||||
|
s.Log.Info().Str("event", e.String()).Str("supervisor", ev.SupervisorName).Msg("service resume")
|
||||||
|
case suture.EventStopTimeout:
|
||||||
|
s.Log.Warn().Str("event", e.String()).Str("service", ev.ServiceName).Str("supervisor", ev.SupervisorName).Msg("service resume")
|
||||||
|
default:
|
||||||
|
s.Log.Warn().Str("event", e.String()).Msgf("supervisor: %v", e.Map()["supervisor_name"])
|
||||||
|
}
|
||||||
},
|
},
|
||||||
FailureThreshold: 5,
|
FailureThreshold: 5,
|
||||||
FailureBackoff: 3 * time.Second,
|
FailureBackoff: 3 * time.Second,
|
||||||
|
|||||||
@@ -10,15 +10,17 @@ import (
|
|||||||
// SutureService allows for the settings command to be embedded and supervised by a suture supervisor tree.
|
// SutureService allows for the settings command to be embedded and supervised by a suture supervisor tree.
|
||||||
type SutureService struct {
|
type SutureService struct {
|
||||||
exec func(ctx context.Context) error
|
exec func(ctx context.Context) error
|
||||||
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSutureServiceBuilder creates a new suture service
|
// NewSutureServiceBuilder creates a new suture service
|
||||||
func NewSutureServiceBuilder(f func(context.Context, *occfg.Config) error) func(*occfg.Config) suture.Service {
|
func NewSutureServiceBuilder(name string, f func(context.Context, *occfg.Config) error) func(*occfg.Config) suture.Service {
|
||||||
return func(cfg *occfg.Config) suture.Service {
|
return func(cfg *occfg.Config) suture.Service {
|
||||||
return SutureService{
|
return SutureService{
|
||||||
exec: func(ctx context.Context) error {
|
exec: func(ctx context.Context) error {
|
||||||
return f(ctx, cfg)
|
return f(ctx, cfg)
|
||||||
},
|
},
|
||||||
|
name: name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,3 +29,8 @@ func NewSutureServiceBuilder(f func(context.Context, *occfg.Config) error) func(
|
|||||||
func (s SutureService) Serve(ctx context.Context) error {
|
func (s SutureService) Serve(ctx context.Context) error {
|
||||||
return s.exec(ctx)
|
return s.exec(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String to fullfil fmt.Stringer interface, used to log the service name
|
||||||
|
func (s SutureService) String() string {
|
||||||
|
return s.name
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,26 +1,18 @@
|
|||||||
package clihelper
|
package clihelper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/opencloud-eu/opencloud/pkg/version"
|
"github.com/opencloud-eu/opencloud/pkg/version"
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DefaultApp(app *cli.App) *cli.App {
|
// DefaultApp is a wrapper for DefaultApp that adds Cobra specific settings
|
||||||
|
func DefaultApp(app *cobra.Command) *cobra.Command {
|
||||||
|
// TODO: when migration is done this has to become DefaultApp
|
||||||
// version info
|
// version info
|
||||||
app.Version = version.String
|
app.Version = fmt.Sprintf("%s (%s <%s>) (%s)", version.String, "OpenCloud GmbH", "support@opencloud.eu", version.Compiled())
|
||||||
app.Compiled = version.Compiled()
|
|
||||||
|
|
||||||
// author info
|
|
||||||
app.Authors = []*cli.Author{
|
|
||||||
{
|
|
||||||
Name: "OpenCloud GmbH",
|
|
||||||
Email: "support@opencloud.eu",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable global version flag
|
|
||||||
// instead we provide the version command
|
|
||||||
app.HideVersion = true
|
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
appProvider "github.com/opencloud-eu/opencloud/services/app-provider/pkg/config"
|
appProvider "github.com/opencloud-eu/opencloud/services/app-provider/pkg/config"
|
||||||
appRegistry "github.com/opencloud-eu/opencloud/services/app-registry/pkg/config"
|
appRegistry "github.com/opencloud-eu/opencloud/services/app-registry/pkg/config"
|
||||||
audit "github.com/opencloud-eu/opencloud/services/audit/pkg/config"
|
audit "github.com/opencloud-eu/opencloud/services/audit/pkg/config"
|
||||||
|
authapi "github.com/opencloud-eu/opencloud/services/auth-api/pkg/config"
|
||||||
authapp "github.com/opencloud-eu/opencloud/services/auth-app/pkg/config"
|
authapp "github.com/opencloud-eu/opencloud/services/auth-app/pkg/config"
|
||||||
authbasic "github.com/opencloud-eu/opencloud/services/auth-basic/pkg/config"
|
authbasic "github.com/opencloud-eu/opencloud/services/auth-basic/pkg/config"
|
||||||
authbearer "github.com/opencloud-eu/opencloud/services/auth-bearer/pkg/config"
|
authbearer "github.com/opencloud-eu/opencloud/services/auth-bearer/pkg/config"
|
||||||
@@ -19,12 +20,12 @@ import (
|
|||||||
gateway "github.com/opencloud-eu/opencloud/services/gateway/pkg/config"
|
gateway "github.com/opencloud-eu/opencloud/services/gateway/pkg/config"
|
||||||
graph "github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
graph "github.com/opencloud-eu/opencloud/services/graph/pkg/config"
|
||||||
groups "github.com/opencloud-eu/opencloud/services/groups/pkg/config"
|
groups "github.com/opencloud-eu/opencloud/services/groups/pkg/config"
|
||||||
|
groupware "github.com/opencloud-eu/opencloud/services/groupware/pkg/config"
|
||||||
idm "github.com/opencloud-eu/opencloud/services/idm/pkg/config"
|
idm "github.com/opencloud-eu/opencloud/services/idm/pkg/config"
|
||||||
idp "github.com/opencloud-eu/opencloud/services/idp/pkg/config"
|
idp "github.com/opencloud-eu/opencloud/services/idp/pkg/config"
|
||||||
invitations "github.com/opencloud-eu/opencloud/services/invitations/pkg/config"
|
invitations "github.com/opencloud-eu/opencloud/services/invitations/pkg/config"
|
||||||
nats "github.com/opencloud-eu/opencloud/services/nats/pkg/config"
|
nats "github.com/opencloud-eu/opencloud/services/nats/pkg/config"
|
||||||
notifications "github.com/opencloud-eu/opencloud/services/notifications/pkg/config"
|
notifications "github.com/opencloud-eu/opencloud/services/notifications/pkg/config"
|
||||||
ocdav "github.com/opencloud-eu/opencloud/services/ocdav/pkg/config"
|
|
||||||
ocm "github.com/opencloud-eu/opencloud/services/ocm/pkg/config"
|
ocm "github.com/opencloud-eu/opencloud/services/ocm/pkg/config"
|
||||||
ocs "github.com/opencloud-eu/opencloud/services/ocs/pkg/config"
|
ocs "github.com/opencloud-eu/opencloud/services/ocs/pkg/config"
|
||||||
policies "github.com/opencloud-eu/opencloud/services/policies/pkg/config"
|
policies "github.com/opencloud-eu/opencloud/services/policies/pkg/config"
|
||||||
@@ -55,14 +56,13 @@ type Runtime struct {
|
|||||||
Services []string `yaml:"services" env:"OC_RUN_EXTENSIONS;OC_RUN_SERVICES" desc:"A comma-separated list of service names. Will start only the listed services." introductionVersion:"1.0.0"`
|
Services []string `yaml:"services" env:"OC_RUN_EXTENSIONS;OC_RUN_SERVICES" desc:"A comma-separated list of service names. Will start only the listed services." introductionVersion:"1.0.0"`
|
||||||
Disabled []string `yaml:"disabled_services" env:"OC_EXCLUDE_RUN_SERVICES" desc:"A comma-separated list of service names. Will start all default services except of the ones listed. Has no effect when OC_RUN_SERVICES is set." introductionVersion:"1.0.0"`
|
Disabled []string `yaml:"disabled_services" env:"OC_EXCLUDE_RUN_SERVICES" desc:"A comma-separated list of service names. Will start all default services except of the ones listed. Has no effect when OC_RUN_SERVICES is set." introductionVersion:"1.0.0"`
|
||||||
Additional []string `yaml:"add_services" env:"OC_ADD_RUN_SERVICES" desc:"A comma-separated list of service names. Will add the listed services to the default configuration. Has no effect when OC_RUN_SERVICES is set. Note that one can add services not started by the default list and exclude services from the default list by using both envvars at the same time." introductionVersion:"1.0.0"`
|
Additional []string `yaml:"add_services" env:"OC_ADD_RUN_SERVICES" desc:"A comma-separated list of service names. Will add the listed services to the default configuration. Has no effect when OC_RUN_SERVICES is set. Note that one can add services not started by the default list and exclude services from the default list by using both envvars at the same time." introductionVersion:"1.0.0"`
|
||||||
ShutdownOrder []string `yaml:"shutdown_order" env:"OC_SHUTDOWN_ORDER" desc:"A comma-separated list of service names defining the order in which services are shut down. Services not listed will be stopped after the listed ones in random order." introductionVersion:"%%NEXT%%"`
|
ShutdownOrder []string `yaml:"shutdown_order" env:"OC_SHUTDOWN_ORDER" desc:"A comma-separated list of service names defining the order in which services are shut down. Services not listed will be stopped after the listed ones in random order." introductionVersion:"4.0.0"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config combines all available configuration parts.
|
// Config combines all available configuration parts.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
*shared.Commons `yaml:"shared"`
|
*shared.Commons `yaml:"shared"`
|
||||||
|
|
||||||
Tracing *shared.Tracing `yaml:"tracing"`
|
|
||||||
Log *shared.Log `yaml:"log"`
|
Log *shared.Log `yaml:"log"`
|
||||||
Cache *shared.Cache `yaml:"cache"`
|
Cache *shared.Cache `yaml:"cache"`
|
||||||
GRPCClientTLS *shared.GRPCClientTLS `yaml:"grpc_client_tls"`
|
GRPCClientTLS *shared.GRPCClientTLS `yaml:"grpc_client_tls"`
|
||||||
@@ -78,7 +78,7 @@ type Config struct {
|
|||||||
TokenManager *shared.TokenManager `yaml:"token_manager"`
|
TokenManager *shared.TokenManager `yaml:"token_manager"`
|
||||||
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OC_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary for the access to resources from other services." introductionVersion:"1.0.0"`
|
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OC_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary for the access to resources from other services." introductionVersion:"1.0.0"`
|
||||||
TransferSecret string `yaml:"transfer_secret" env:"OC_TRANSFER_SECRET" desc:"Transfer secret for signing file up- and download requests." introductionVersion:"1.0.0"`
|
TransferSecret string `yaml:"transfer_secret" env:"OC_TRANSFER_SECRET" desc:"Transfer secret for signing file up- and download requests." introductionVersion:"1.0.0"`
|
||||||
URLSigningSecret string `yaml:"url_signing_secret" env:"OC_URL_SIGNING_SECRET" desc:"The shared secret used to sign URLs e.g. for image downloads by the web office suite." introductionVersion:"%%NEXT%%"`
|
URLSigningSecret string `yaml:"url_signing_secret" env:"OC_URL_SIGNING_SECRET" desc:"The shared secret used to sign URLs e.g. for image downloads by the web office suite." introductionVersion:"4.0.0"`
|
||||||
SystemUserID string `yaml:"system_user_id" env:"OC_SYSTEM_USER_ID" desc:"ID of the OpenCloud storage-system system user. Admins need to set the ID for the storage-system system user in this config option which is then used to reference the user. Any reasonable long string is possible, preferably this would be an UUIDv4 format." introductionVersion:"1.0.0"`
|
SystemUserID string `yaml:"system_user_id" env:"OC_SYSTEM_USER_ID" desc:"ID of the OpenCloud storage-system system user. Admins need to set the ID for the storage-system system user in this config option which is then used to reference the user. Any reasonable long string is possible, preferably this would be an UUIDv4 format." introductionVersion:"1.0.0"`
|
||||||
SystemUserAPIKey string `yaml:"system_user_api_key" env:"OC_SYSTEM_USER_API_KEY" desc:"API key for the storage-system system user." introductionVersion:"1.0.0"`
|
SystemUserAPIKey string `yaml:"system_user_api_key" env:"OC_SYSTEM_USER_API_KEY" desc:"API key for the storage-system system user." introductionVersion:"1.0.0"`
|
||||||
AdminUserID string `yaml:"admin_user_id" env:"OC_ADMIN_USER_ID" desc:"ID of a user, that should receive admin privileges. Consider that the UUID can be encoded in some LDAP deployment configurations like in .ldif files. These need to be decoded beforehand." introductionVersion:"1.0.0"`
|
AdminUserID string `yaml:"admin_user_id" env:"OC_ADMIN_USER_ID" desc:"ID of a user, that should receive admin privileges. Consider that the UUID can be encoded in some LDAP deployment configurations like in .ldif files. These need to be decoded beforehand." introductionVersion:"1.0.0"`
|
||||||
@@ -101,12 +101,12 @@ type Config struct {
|
|||||||
Gateway *gateway.Config `yaml:"gateway"`
|
Gateway *gateway.Config `yaml:"gateway"`
|
||||||
Graph *graph.Config `yaml:"graph"`
|
Graph *graph.Config `yaml:"graph"`
|
||||||
Groups *groups.Config `yaml:"groups"`
|
Groups *groups.Config `yaml:"groups"`
|
||||||
|
Groupware *groupware.Config `yaml:"groupware"`
|
||||||
IDM *idm.Config `yaml:"idm"`
|
IDM *idm.Config `yaml:"idm"`
|
||||||
IDP *idp.Config `yaml:"idp"`
|
IDP *idp.Config `yaml:"idp"`
|
||||||
Invitations *invitations.Config `yaml:"invitations"`
|
Invitations *invitations.Config `yaml:"invitations"`
|
||||||
Nats *nats.Config `yaml:"nats"`
|
Nats *nats.Config `yaml:"nats"`
|
||||||
Notifications *notifications.Config `yaml:"notifications"`
|
Notifications *notifications.Config `yaml:"notifications"`
|
||||||
OCDav *ocdav.Config `yaml:"ocdav"`
|
|
||||||
OCM *ocm.Config `yaml:"ocm"`
|
OCM *ocm.Config `yaml:"ocm"`
|
||||||
OCS *ocs.Config `yaml:"ocs"`
|
OCS *ocs.Config `yaml:"ocs"`
|
||||||
Postprocessing *postprocessing.Config `yaml:"postprocessing"`
|
Postprocessing *postprocessing.Config `yaml:"postprocessing"`
|
||||||
@@ -126,4 +126,5 @@ type Config struct {
|
|||||||
WebDAV *webdav.Config `yaml:"webdav"`
|
WebDAV *webdav.Config `yaml:"webdav"`
|
||||||
Webfinger *webfinger.Config `yaml:"webfinger"`
|
Webfinger *webfinger.Config `yaml:"webfinger"`
|
||||||
Search *search.Config `yaml:"search"`
|
Search *search.Config `yaml:"search"`
|
||||||
|
AuthApi *authapi.Config `yaml:"authapi"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
appProvider "github.com/opencloud-eu/opencloud/services/app-provider/pkg/config/defaults"
|
appProvider "github.com/opencloud-eu/opencloud/services/app-provider/pkg/config/defaults"
|
||||||
appRegistry "github.com/opencloud-eu/opencloud/services/app-registry/pkg/config/defaults"
|
appRegistry "github.com/opencloud-eu/opencloud/services/app-registry/pkg/config/defaults"
|
||||||
audit "github.com/opencloud-eu/opencloud/services/audit/pkg/config/defaults"
|
audit "github.com/opencloud-eu/opencloud/services/audit/pkg/config/defaults"
|
||||||
|
authapi "github.com/opencloud-eu/opencloud/services/auth-api/pkg/config/defaults"
|
||||||
authapp "github.com/opencloud-eu/opencloud/services/auth-app/pkg/config/defaults"
|
authapp "github.com/opencloud-eu/opencloud/services/auth-app/pkg/config/defaults"
|
||||||
authbasic "github.com/opencloud-eu/opencloud/services/auth-basic/pkg/config/defaults"
|
authbasic "github.com/opencloud-eu/opencloud/services/auth-basic/pkg/config/defaults"
|
||||||
authbearer "github.com/opencloud-eu/opencloud/services/auth-bearer/pkg/config/defaults"
|
authbearer "github.com/opencloud-eu/opencloud/services/auth-bearer/pkg/config/defaults"
|
||||||
@@ -19,12 +20,12 @@ import (
|
|||||||
gateway "github.com/opencloud-eu/opencloud/services/gateway/pkg/config/defaults"
|
gateway "github.com/opencloud-eu/opencloud/services/gateway/pkg/config/defaults"
|
||||||
graph "github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults"
|
graph "github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults"
|
||||||
groups "github.com/opencloud-eu/opencloud/services/groups/pkg/config/defaults"
|
groups "github.com/opencloud-eu/opencloud/services/groups/pkg/config/defaults"
|
||||||
|
groupware "github.com/opencloud-eu/opencloud/services/groupware/pkg/config/defaults"
|
||||||
idm "github.com/opencloud-eu/opencloud/services/idm/pkg/config/defaults"
|
idm "github.com/opencloud-eu/opencloud/services/idm/pkg/config/defaults"
|
||||||
idp "github.com/opencloud-eu/opencloud/services/idp/pkg/config/defaults"
|
idp "github.com/opencloud-eu/opencloud/services/idp/pkg/config/defaults"
|
||||||
invitations "github.com/opencloud-eu/opencloud/services/invitations/pkg/config/defaults"
|
invitations "github.com/opencloud-eu/opencloud/services/invitations/pkg/config/defaults"
|
||||||
nats "github.com/opencloud-eu/opencloud/services/nats/pkg/config/defaults"
|
nats "github.com/opencloud-eu/opencloud/services/nats/pkg/config/defaults"
|
||||||
notifications "github.com/opencloud-eu/opencloud/services/notifications/pkg/config/defaults"
|
notifications "github.com/opencloud-eu/opencloud/services/notifications/pkg/config/defaults"
|
||||||
ocdav "github.com/opencloud-eu/opencloud/services/ocdav/pkg/config/defaults"
|
|
||||||
ocm "github.com/opencloud-eu/opencloud/services/ocm/pkg/config/defaults"
|
ocm "github.com/opencloud-eu/opencloud/services/ocm/pkg/config/defaults"
|
||||||
ocs "github.com/opencloud-eu/opencloud/services/ocs/pkg/config/defaults"
|
ocs "github.com/opencloud-eu/opencloud/services/ocs/pkg/config/defaults"
|
||||||
policies "github.com/opencloud-eu/opencloud/services/policies/pkg/config/defaults"
|
policies "github.com/opencloud-eu/opencloud/services/policies/pkg/config/defaults"
|
||||||
@@ -63,6 +64,7 @@ func DefaultConfig() *Config {
|
|||||||
AppProvider: appProvider.DefaultConfig(),
|
AppProvider: appProvider.DefaultConfig(),
|
||||||
AppRegistry: appRegistry.DefaultConfig(),
|
AppRegistry: appRegistry.DefaultConfig(),
|
||||||
Audit: audit.DefaultConfig(),
|
Audit: audit.DefaultConfig(),
|
||||||
|
AuthApi: authapi.DefaultConfig(),
|
||||||
AuthApp: authapp.DefaultConfig(),
|
AuthApp: authapp.DefaultConfig(),
|
||||||
AuthBasic: authbasic.DefaultConfig(),
|
AuthBasic: authbasic.DefaultConfig(),
|
||||||
AuthBearer: authbearer.DefaultConfig(),
|
AuthBearer: authbearer.DefaultConfig(),
|
||||||
@@ -75,12 +77,12 @@ func DefaultConfig() *Config {
|
|||||||
Gateway: gateway.DefaultConfig(),
|
Gateway: gateway.DefaultConfig(),
|
||||||
Graph: graph.DefaultConfig(),
|
Graph: graph.DefaultConfig(),
|
||||||
Groups: groups.DefaultConfig(),
|
Groups: groups.DefaultConfig(),
|
||||||
|
Groupware: groupware.DefaultConfig(),
|
||||||
IDM: idm.DefaultConfig(),
|
IDM: idm.DefaultConfig(),
|
||||||
IDP: idp.DefaultConfig(),
|
IDP: idp.DefaultConfig(),
|
||||||
Invitations: invitations.DefaultConfig(),
|
Invitations: invitations.DefaultConfig(),
|
||||||
Nats: nats.DefaultConfig(),
|
Nats: nats.DefaultConfig(),
|
||||||
Notifications: notifications.DefaultConfig(),
|
Notifications: notifications.DefaultConfig(),
|
||||||
OCDav: ocdav.DefaultConfig(),
|
|
||||||
OCM: ocm.DefaultConfig(),
|
OCM: ocm.DefaultConfig(),
|
||||||
OCS: ocs.DefaultConfig(),
|
OCS: ocs.DefaultConfig(),
|
||||||
Postprocessing: postprocessing.DefaultConfig(),
|
Postprocessing: postprocessing.DefaultConfig(),
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
"testing"
|
"testing"
|
||||||
"testing/fstest"
|
"testing/fstest"
|
||||||
|
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestConfig struct {
|
type TestConfig struct {
|
||||||
@@ -98,6 +99,8 @@ frontend:
|
|||||||
service_account:
|
service_account:
|
||||||
service_account_id: c05389b2-d94c-4d01-a9b5-a2f97952cc14
|
service_account_id: c05389b2-d94c-4d01-a9b5-a2f97952cc14
|
||||||
service_account_secret: GW5.x1vDM&+NPRi++eV@.P7Tms4vj!=s
|
service_account_secret: GW5.x1vDM&+NPRi++eV@.P7Tms4vj!=s
|
||||||
|
ocdav:
|
||||||
|
insecure: true
|
||||||
auth_basic:
|
auth_basic:
|
||||||
auth_providers:
|
auth_providers:
|
||||||
ldap:
|
ldap:
|
||||||
@@ -114,8 +117,6 @@ groups:
|
|||||||
drivers:
|
drivers:
|
||||||
ldap:
|
ldap:
|
||||||
bind_password: c68JL=V$c@0GHs!%eSb8r&Ps3rgzKnXJ
|
bind_password: c68JL=V$c@0GHs!%eSb8r&Ps3rgzKnXJ
|
||||||
ocdav:
|
|
||||||
insecure: true
|
|
||||||
ocm:
|
ocm:
|
||||||
service_account:
|
service_account:
|
||||||
service_account_id: c05389b2-d94c-4d01-a9b5-a2f97952cc14
|
service_account_id: c05389b2-d94c-4d01-a9b5-a2f97952cc14
|
||||||
|
|||||||
@@ -40,9 +40,6 @@ func ParseConfig(cfg *config.Config, skipValidate bool) error {
|
|||||||
// EnsureDefaults ensures that all pointers in the
|
// EnsureDefaults ensures that all pointers in the
|
||||||
// OpenCloud config (not the services configs) are initialized
|
// OpenCloud config (not the services configs) are initialized
|
||||||
func EnsureDefaults(cfg *config.Config) {
|
func EnsureDefaults(cfg *config.Config) {
|
||||||
if cfg.Tracing == nil {
|
|
||||||
cfg.Tracing = &shared.Tracing{}
|
|
||||||
}
|
|
||||||
if cfg.Log == nil {
|
if cfg.Log == nil {
|
||||||
cfg.Log = &shared.Log{}
|
cfg.Log = &shared.Log{}
|
||||||
}
|
}
|
||||||
@@ -71,7 +68,6 @@ func EnsureCommons(cfg *config.Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cfg.Commons.Log = structs.CopyOrZeroValue(cfg.Log)
|
cfg.Commons.Log = structs.CopyOrZeroValue(cfg.Log)
|
||||||
cfg.Commons.Tracing = structs.CopyOrZeroValue(cfg.Tracing)
|
|
||||||
cfg.Commons.Cache = structs.CopyOrZeroValue(cfg.Cache)
|
cfg.Commons.Cache = structs.CopyOrZeroValue(cfg.Cache)
|
||||||
|
|
||||||
if cfg.GRPCClientTLS != nil {
|
if cfg.GRPCClientTLS != nil {
|
||||||
|
|||||||
1
pkg/jmap/.gitignore
vendored
Normal file
1
pkg/jmap/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/apidoc-examples.json
|
||||||
49
pkg/jmap/jmap_api.go
Normal file
49
pkg/jmap/jmap_api.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package jmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApiClient interface {
|
||||||
|
Command(ctx context.Context, logger *log.Logger, session *Session, request Request, acceptLanguage string) ([]byte, Language, Error)
|
||||||
|
io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
type WsPushListener interface {
|
||||||
|
OnNotification(username string, stateChange StateChange)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WsClient interface {
|
||||||
|
DisableNotifications() Error
|
||||||
|
io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
type WsClientFactory interface {
|
||||||
|
EnableNotifications(pushState State, sessionProvider func() (*Session, error), listener WsPushListener) (WsClient, Error)
|
||||||
|
io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionClient interface {
|
||||||
|
GetSession(baseurl *url.URL, username string, logger *log.Logger) (SessionResponse, Error)
|
||||||
|
io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlobClient interface {
|
||||||
|
UploadBinary(ctx context.Context, logger *log.Logger, session *Session, uploadUrl string, endpoint string, contentType string, acceptLanguage string, content io.Reader) (UploadedBlob, Language, Error)
|
||||||
|
DownloadBinary(ctx context.Context, logger *log.Logger, session *Session, downloadUrl string, endpoint string, acceptLanguage string) (*BlobDownload, Language, Error)
|
||||||
|
io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
logOperation = "operation"
|
||||||
|
logFetchBodies = "fetch-bodies"
|
||||||
|
logOffset = "offset"
|
||||||
|
logLimit = "limit"
|
||||||
|
logDownloadUrl = "download-url"
|
||||||
|
logBlobId = "blob-id"
|
||||||
|
logSinceState = "since-state"
|
||||||
|
)
|
||||||
137
pkg/jmap/jmap_api_blob.go
Normal file
137
pkg/jmap/jmap_api_blob.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package jmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (j *Client) GetBlobMetadata(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, id string) (*Blob, SessionState, State, Language, Error) {
|
||||||
|
cmd, jerr := j.request(session, logger,
|
||||||
|
invocation(CommandBlobGet, BlobGetCommand{
|
||||||
|
AccountId: accountId,
|
||||||
|
Ids: []string{id},
|
||||||
|
// add BlobPropertyData to retrieve the data
|
||||||
|
Properties: []string{BlobPropertyDigestSha256, BlobPropertyDigestSha512, BlobPropertySize},
|
||||||
|
}, "0"),
|
||||||
|
)
|
||||||
|
if jerr != nil {
|
||||||
|
return nil, "", "", "", jerr
|
||||||
|
}
|
||||||
|
|
||||||
|
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (*Blob, State, Error) {
|
||||||
|
var response BlobGetResponse
|
||||||
|
err := retrieveResponseMatchParameters(logger, body, CommandBlobGet, "0", &response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(response.List) != 1 {
|
||||||
|
logger.Error().Msgf("%T.List has %v entries instead of 1", response, len(response.List))
|
||||||
|
return nil, "", simpleError(err, JmapErrorInvalidJmapResponsePayload)
|
||||||
|
}
|
||||||
|
get := response.List[0]
|
||||||
|
return &get, response.State, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadedBlobWithHash struct {
|
||||||
|
BlobId string `json:"blobId"`
|
||||||
|
Size int `json:"size,omitzero"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Sha512 string `json:"sha:512,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *Client) UploadBlobStream(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, contentType string, body io.Reader) (UploadedBlob, Language, Error) {
|
||||||
|
logger = log.From(logger.With().Str(logEndpoint, session.UploadEndpoint))
|
||||||
|
// TODO(pbleser-oc) use a library for proper URL template parsing
|
||||||
|
uploadUrl := strings.ReplaceAll(session.UploadUrlTemplate, "{accountId}", accountId)
|
||||||
|
return j.blob.UploadBinary(ctx, logger, session, uploadUrl, session.UploadEndpoint, contentType, acceptLanguage, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *Client) DownloadBlobStream(accountId string, blobId string, name string, typ string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (*BlobDownload, Language, Error) {
|
||||||
|
logger = log.From(logger.With().Str(logEndpoint, session.DownloadEndpoint))
|
||||||
|
// TODO(pbleser-oc) use a library for proper URL template parsing
|
||||||
|
downloadUrl := session.DownloadUrlTemplate
|
||||||
|
downloadUrl = strings.ReplaceAll(downloadUrl, "{accountId}", accountId)
|
||||||
|
downloadUrl = strings.ReplaceAll(downloadUrl, "{blobId}", blobId)
|
||||||
|
downloadUrl = strings.ReplaceAll(downloadUrl, "{name}", name)
|
||||||
|
downloadUrl = strings.ReplaceAll(downloadUrl, "{type}", typ)
|
||||||
|
logger = log.From(logger.With().Str(logDownloadUrl, downloadUrl).Str(logBlobId, blobId))
|
||||||
|
return j.blob.DownloadBinary(ctx, logger, session, downloadUrl, session.DownloadEndpoint, acceptLanguage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *Client) UploadBlob(accountId string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string, data []byte, contentType string) (UploadedBlobWithHash, SessionState, State, Language, Error) {
|
||||||
|
encoded := base64.StdEncoding.EncodeToString(data)
|
||||||
|
|
||||||
|
upload := BlobUploadCommand{
|
||||||
|
AccountId: accountId,
|
||||||
|
Create: map[string]UploadObject{
|
||||||
|
"0": {
|
||||||
|
Data: []DataSourceObject{{
|
||||||
|
DataAsBase64: encoded,
|
||||||
|
}},
|
||||||
|
Type: contentType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
getHash := BlobGetRefCommand{
|
||||||
|
AccountId: accountId,
|
||||||
|
IdRef: &ResultReference{
|
||||||
|
ResultOf: "0",
|
||||||
|
Name: CommandBlobUpload,
|
||||||
|
Path: "/ids",
|
||||||
|
},
|
||||||
|
Properties: []string{BlobPropertyDigestSha512},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd, jerr := j.request(session, logger,
|
||||||
|
invocation(CommandBlobUpload, upload, "0"),
|
||||||
|
invocation(CommandBlobGet, getHash, "1"),
|
||||||
|
)
|
||||||
|
if jerr != nil {
|
||||||
|
return UploadedBlobWithHash{}, "", "", "", jerr
|
||||||
|
}
|
||||||
|
|
||||||
|
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (UploadedBlobWithHash, State, Error) {
|
||||||
|
var uploadResponse BlobUploadResponse
|
||||||
|
err := retrieveResponseMatchParameters(logger, body, CommandBlobUpload, "0", &uploadResponse)
|
||||||
|
if err != nil {
|
||||||
|
return UploadedBlobWithHash{}, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var getResponse BlobGetResponse
|
||||||
|
err = retrieveResponseMatchParameters(logger, body, CommandBlobGet, "1", &getResponse)
|
||||||
|
if err != nil {
|
||||||
|
return UploadedBlobWithHash{}, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(uploadResponse.Created) != 1 {
|
||||||
|
logger.Error().Msgf("%T.Created has %v entries instead of 1", uploadResponse, len(uploadResponse.Created))
|
||||||
|
return UploadedBlobWithHash{}, "", simpleError(err, JmapErrorInvalidJmapResponsePayload)
|
||||||
|
}
|
||||||
|
upload, ok := uploadResponse.Created["0"]
|
||||||
|
if !ok {
|
||||||
|
logger.Error().Msgf("%T.Created has no item '0'", uploadResponse)
|
||||||
|
return UploadedBlobWithHash{}, "", simpleError(err, JmapErrorInvalidJmapResponsePayload)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(getResponse.List) != 1 {
|
||||||
|
logger.Error().Msgf("%T.List has %v entries instead of 1", getResponse, len(getResponse.List))
|
||||||
|
return UploadedBlobWithHash{}, "", simpleError(err, JmapErrorInvalidJmapResponsePayload)
|
||||||
|
}
|
||||||
|
get := getResponse.List[0]
|
||||||
|
|
||||||
|
return UploadedBlobWithHash{
|
||||||
|
BlobId: upload.Id,
|
||||||
|
Size: upload.Size,
|
||||||
|
Type: upload.Type,
|
||||||
|
Sha512: get.DigestSha512,
|
||||||
|
}, getResponse.State, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
75
pkg/jmap/jmap_api_bootstrap.go
Normal file
75
pkg/jmap/jmap_api_bootstrap.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package jmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||||
|
"github.com/opencloud-eu/opencloud/pkg/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccountBootstrapResult struct {
|
||||||
|
Identities []Identity `json:"identities,omitempty"`
|
||||||
|
Quotas []Quota `json:"quotas,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *Client) GetBootstrap(accountIds []string, session *Session, ctx context.Context, logger *log.Logger, acceptLanguage string) (map[string]AccountBootstrapResult, SessionState, State, Language, Error) {
|
||||||
|
uniqueAccountIds := structs.Uniq(accountIds)
|
||||||
|
|
||||||
|
logger = j.logger("GetBootstrap", session, logger)
|
||||||
|
|
||||||
|
calls := make([]Invocation, len(uniqueAccountIds)*2)
|
||||||
|
for i, accountId := range uniqueAccountIds {
|
||||||
|
calls[i*2+0] = invocation(CommandIdentityGet, IdentityGetCommand{AccountId: accountId}, mcid(accountId, "I"))
|
||||||
|
calls[i*2+1] = invocation(CommandQuotaGet, QuotaGetCommand{AccountId: accountId}, mcid(accountId, "Q"))
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd, err := j.request(session, logger, calls...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", "", "", err
|
||||||
|
}
|
||||||
|
return command(j.api, logger, ctx, session, j.onSessionOutdated, cmd, acceptLanguage, func(body *Response) (map[string]AccountBootstrapResult, State, Error) {
|
||||||
|
identityPerAccount := map[string][]Identity{}
|
||||||
|
quotaPerAccount := map[string][]Quota{}
|
||||||
|
identityStatesPerAccount := map[string]State{}
|
||||||
|
quotaStatesPerAccount := map[string]State{}
|
||||||
|
for _, accountId := range uniqueAccountIds {
|
||||||
|
var identityResponse IdentityGetResponse
|
||||||
|
err = retrieveResponseMatchParameters(logger, body, CommandIdentityGet, mcid(accountId, "I"), &identityResponse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
} else {
|
||||||
|
identityPerAccount[accountId] = identityResponse.List
|
||||||
|
identityStatesPerAccount[accountId] = identityResponse.State
|
||||||
|
}
|
||||||
|
|
||||||
|
var quotaResponse QuotaGetResponse
|
||||||
|
err = retrieveResponseMatchParameters(logger, body, CommandQuotaGet, mcid(accountId, "Q"), "aResponse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
} else {
|
||||||
|
quotaPerAccount[accountId] = quotaResponse.List
|
||||||
|
quotaStatesPerAccount[accountId] = quotaResponse.State
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := map[string]AccountBootstrapResult{}
|
||||||
|
for accountId, value := range identityPerAccount {
|
||||||
|
r, ok := result[accountId]
|
||||||
|
if !ok {
|
||||||
|
r = AccountBootstrapResult{}
|
||||||
|
}
|
||||||
|
r.Identities = value
|
||||||
|
result[accountId] = r
|
||||||
|
}
|
||||||
|
for accountId, value := range quotaPerAccount {
|
||||||
|
r, ok := result[accountId]
|
||||||
|
if !ok {
|
||||||
|
r = AccountBootstrapResult{}
|
||||||
|
}
|
||||||
|
r.Quotas = value
|
||||||
|
result[accountId] = r
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, squashStateMaps(identityStatesPerAccount, quotaStatesPerAccount), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user