Compare commits
591 Commits
renovate/r
...
docs/add-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e206ef01af | ||
|
|
06bbf043c0 | ||
|
|
079100b081 | ||
|
|
8e11703e94 | ||
|
|
03e9ffcc91 | ||
|
|
d7c75b8343 | ||
|
|
9ddd8a02c0 | ||
|
|
1601995fda | ||
|
|
af87c3d6f3 | ||
|
|
9f9b82f5cf | ||
|
|
04a9888a96 | ||
|
|
07a758d84a | ||
|
|
111af8b1a8 | ||
|
|
4c97e49fc5 | ||
|
|
10a291ec8b | ||
|
|
0e9fe9dc40 | ||
|
|
90ddd922ad | ||
|
|
1e1adafeec | ||
|
|
ecc9e9257e | ||
|
|
4fee8b34ad | ||
|
|
02464c19b8 | ||
|
|
62129bb91f | ||
|
|
3d8da61569 | ||
|
|
d7d296df8e | ||
|
|
305ed25896 | ||
|
|
8b6cc211e9 | ||
|
|
1ca95cda4a | ||
|
|
e5ed003fb2 | ||
|
|
176b0f8b48 | ||
|
|
33390a1483 | ||
|
|
e90759e5af | ||
|
|
8cb5f5646a | ||
|
|
c784de6ef5 | ||
|
|
589435b7c2 | ||
|
|
b4d2d1eaf5 | ||
|
|
36e28963d3 | ||
|
|
942b847952 | ||
|
|
488423abfc | ||
|
|
f75c853b90 | ||
|
|
4bbbd19049 | ||
|
|
f4b23253b1 | ||
|
|
06e1c83276 | ||
|
|
54041155bd | ||
|
|
b9b1028b91 | ||
|
|
f468597ad8 | ||
|
|
69060f5437 | ||
|
|
2ac4d0a13e | ||
|
|
e953e76006 | ||
|
|
c9e4c26c11 | ||
|
|
95ea758475 | ||
|
|
0931423259 | ||
|
|
75afc64dd0 | ||
|
|
67ca3c231a | ||
|
|
bcc2057456 | ||
|
|
720dfb65be | ||
|
|
7df3582237 | ||
|
|
2e0cf9bb61 | ||
|
|
0ed742cad7 | ||
|
|
6746207c36 | ||
|
|
4430699f2d | ||
|
|
acb0320796 | ||
|
|
95ffd1a55a | ||
|
|
ca5d898120 | ||
|
|
e3d73ddb81 | ||
|
|
e69f3c55f7 | ||
|
|
fbf1cdd0ce | ||
|
|
859865351d | ||
|
|
7b3145a3c1 | ||
|
|
fd14d4a5ed | ||
|
|
efd6b250d9 | ||
|
|
6bf5e3303e | ||
|
|
71d511abd8 | ||
|
|
1b278cc87e | ||
|
|
51c31e00a4 | ||
|
|
ff53276870 | ||
|
|
b739e4e802 | ||
|
|
7281bb7069 | ||
|
|
35ac04bad3 | ||
|
|
2411e78cd1 | ||
|
|
7236ba5fce | ||
|
|
612a0d1c7f | ||
|
|
06373ae47b | ||
|
|
daa28773d6 | ||
|
|
1830e2ce9d | ||
|
|
9a8d17a209 | ||
|
|
8149f586b3 | ||
|
|
c7dd159db1 | ||
|
|
a17d5a75fe | ||
|
|
2ccb7f618d | ||
|
|
b97fb638ad | ||
|
|
d9d227ec4d | ||
|
|
93f1c24b82 | ||
|
|
7c2f38641a | ||
|
|
6376484b13 | ||
|
|
d1334a6dff | ||
|
|
505e025d18 | ||
|
|
571e5c2e3c | ||
|
|
4ceb7eec52 | ||
|
|
2e507d5042 | ||
|
|
1bd5b29963 | ||
|
|
98ec655f33 | ||
|
|
1d38cf7f0d | ||
|
|
891ed6c4b7 | ||
|
|
e067b1de98 | ||
|
|
4cecab3185 | ||
|
|
867e8bb98f | ||
|
|
5abc0d0d91 | ||
|
|
3972046695 | ||
|
|
ffa5e41bec | ||
|
|
84bd99f1c1 | ||
|
|
de512fb02e | ||
|
|
3fca7cf952 | ||
|
|
8f8ed2bbec | ||
|
|
69e4b4667b | ||
|
|
0c016e210a | ||
|
|
769787ea40 | ||
|
|
b4312a220f | ||
|
|
c75a451b13 | ||
|
|
df816d00e4 | ||
|
|
782c819727 | ||
|
|
6fc82629d4 | ||
|
|
fc34b18122 | ||
|
|
ac162e203b | ||
|
|
ddeb970b4d | ||
|
|
a06905e2d3 | ||
|
|
07bf7b2ae1 | ||
|
|
0649635639 | ||
|
|
126e6dbcd8 | ||
|
|
f56fec2c10 | ||
|
|
ca5cf5fe7c | ||
|
|
06fb3fef43 | ||
|
|
414524e799 | ||
|
|
acf0da9b80 | ||
|
|
6f7c525213 | ||
|
|
684156fdf1 | ||
|
|
4cda8669a5 | ||
|
|
14c45b6db2 | ||
|
|
eeddc8cd18 | ||
|
|
99e4583cd1 | ||
|
|
cbd6b53182 | ||
|
|
259c7807cb | ||
|
|
d6fa822e89 | ||
|
|
a89377337b | ||
|
|
3b99370aac | ||
|
|
3c0409fe05 | ||
|
|
6d9e28a59f | ||
|
|
6c728f8dec | ||
|
|
445e88cb93 | ||
|
|
c98259f74a | ||
|
|
83e3b1fac7 | ||
|
|
16a0f6c86e | ||
|
|
10833172b9 | ||
|
|
d0ea82633f | ||
|
|
64da716a2e | ||
|
|
2d250ab364 | ||
|
|
b0ecc36fd6 | ||
|
|
d64cc987b8 | ||
|
|
ac7c1eed42 | ||
|
|
cfc8989d24 | ||
|
|
33b4d43248 | ||
|
|
92a6faeff2 | ||
|
|
a339a2dad3 | ||
|
|
ea90bdff9c | ||
|
|
f6e4dd9b0c | ||
|
|
460ed5b827 | ||
|
|
8010784322 | ||
|
|
f9c0924f0c | ||
|
|
4813256e0a | ||
|
|
28e8d7d56e | ||
|
|
3a6459cda3 | ||
|
|
03d738004d | ||
|
|
e3d1fc9c2c | ||
|
|
52d758dc93 | ||
|
|
452fc04d1d | ||
|
|
3e6a601fba | ||
|
|
e09deb6889 | ||
|
|
1070f94fbb | ||
|
|
137803a32a | ||
|
|
7648eac654 | ||
|
|
0a8d15dcac | ||
|
|
b5cf192331 | ||
|
|
f678f5a2cb | ||
|
|
ca5e7202b9 | ||
|
|
ce6523c5f6 | ||
|
|
83bed02a41 | ||
|
|
1759732d91 | ||
|
|
53aed34652 | ||
|
|
cf242def3a | ||
|
|
f61578a50f | ||
|
|
3965761168 | ||
|
|
f5ee26540b | ||
|
|
21b120cbae | ||
|
|
50932cbdab | ||
|
|
1f4720a0fd | ||
|
|
9cbdaef4be | ||
|
|
782b521c0f | ||
|
|
8d5e5e2ead | ||
|
|
1613d2815c | ||
|
|
7fbe2e5962 | ||
|
|
72e244c1e7 | ||
|
|
44beedd09a | ||
|
|
d6bcca2f7e | ||
|
|
20ec8ee61c | ||
|
|
1342858f36 | ||
|
|
63c5d8cb8f | ||
|
|
92375279f7 | ||
|
|
c3d7dbc258 | ||
|
|
c487952279 | ||
|
|
05dc9b2be1 | ||
|
|
d303746ff9 | ||
|
|
f185377c68 | ||
|
|
80d5cfa184 | ||
|
|
5f2074e84c | ||
|
|
bbfb8268d1 | ||
|
|
cb86be2e32 | ||
|
|
344fc5606f | ||
|
|
3cabc12f4c | ||
|
|
ee62a8d431 | ||
|
|
d399f116b8 | ||
|
|
8b31ec5040 | ||
|
|
58098f9339 | ||
|
|
f9ef1b6bd0 | ||
|
|
5dce711680 | ||
|
|
31a2d2aff4 | ||
|
|
209aa13ff7 | ||
|
|
84edc45dee | ||
|
|
0b56628622 | ||
|
|
4c8c32a1d4 | ||
|
|
c0c31afdde | ||
|
|
a4df6c8bb9 | ||
|
|
f2404361bf | ||
|
|
30bd4e7dba | ||
|
|
de88abafdd | ||
|
|
6a3e95913e | ||
|
|
0124aab805 | ||
|
|
af8d166b90 | ||
|
|
ec6e516e28 | ||
|
|
269c145051 | ||
|
|
3bfbbb1961 | ||
|
|
7eb8a9af99 | ||
|
|
51b39d8c6e | ||
|
|
284648df9e | ||
|
|
04ab552950 | ||
|
|
87794bec12 | ||
|
|
19826b5b26 | ||
|
|
2472555af0 | ||
|
|
7dbacddb18 | ||
|
|
c1808a00c2 | ||
|
|
edc7302c2f | ||
|
|
f533a5a6e5 | ||
|
|
ec0c14ac1a | ||
|
|
8bff09b88b | ||
|
|
86bf99aaaa | ||
|
|
1d0ab617e8 | ||
|
|
6093afddd4 | ||
|
|
c0b8fc6e6c | ||
|
|
86cb5d8af7 | ||
|
|
e75610ed03 | ||
|
|
c0ae0f437f | ||
|
|
2d5713e330 | ||
|
|
3176821ddc | ||
|
|
c7d77c6c64 | ||
|
|
5a031b370f | ||
|
|
25dd7e927f | ||
|
|
2c1aa65f2d | ||
|
|
1492db8ead | ||
|
|
9533cc4dbb | ||
|
|
d72e048bfe | ||
|
|
329d6a11fa | ||
|
|
7127b2538c | ||
|
|
237ab6c1b4 | ||
|
|
8263803e81 | ||
|
|
e5cf0e2086 | ||
|
|
6a3dfacc95 | ||
|
|
147ff4279b | ||
|
|
0973a44e6a | ||
|
|
75fb832826 | ||
|
|
f3e7576f0c | ||
|
|
8863ed9d6f | ||
|
|
437dcc875c | ||
|
|
3131a69f04 | ||
|
|
1cb66d86b0 | ||
|
|
79a5b024e1 | ||
|
|
238244fe5c | ||
|
|
2a5ce2f031 | ||
|
|
e1ddbda1bb | ||
|
|
5670f1c34c | ||
|
|
7df95261f3 | ||
|
|
68bc0f8076 | ||
|
|
b39708e439 | ||
|
|
74a9a288e2 | ||
|
|
7a7fd45bdd | ||
|
|
19d88de3cf | ||
|
|
fe9c21ebf8 | ||
|
|
a0180f8031 | ||
|
|
92fb6872f0 | ||
|
|
d4d8b2562e | ||
|
|
bee486be23 | ||
|
|
4bb91a7846 | ||
|
|
b77a99214a | ||
|
|
3dd4493d50 | ||
|
|
ce246936c4 | ||
|
|
555deb5d28 | ||
|
|
d216d75fbb | ||
|
|
edef69fdc8 | ||
|
|
bf65c43783 | ||
|
|
d25f5199c7 | ||
|
|
9c8a13c8c8 | ||
|
|
e91144950b | ||
|
|
5673d0b532 | ||
|
|
6783c7f998 | ||
|
|
f9fb2cfd50 | ||
|
|
7b2ea9a735 | ||
|
|
0e9a3881e7 | ||
|
|
bc9540fadb | ||
|
|
b53e3ac860 | ||
|
|
5a5aa18570 | ||
|
|
7cd3e5dc54 | ||
|
|
3c57a1880c | ||
|
|
4f2abe185c | ||
|
|
f76a4885ec | ||
|
|
5df4a3b9a3 | ||
|
|
6a15f40a85 | ||
|
|
cc4a6cff64 | ||
|
|
b9b0ff1219 | ||
|
|
815ced0f70 | ||
|
|
1bf0861738 | ||
|
|
5656f62cf4 | ||
|
|
eabb348152 | ||
|
|
f019d58a99 | ||
|
|
d2dbb816b2 | ||
|
|
e23ba8aa6c | ||
|
|
59bfb44a50 | ||
|
|
9b7c68c994 | ||
|
|
a7349af934 | ||
|
|
adcc634db6 | ||
|
|
e818234a4e | ||
|
|
81683d554d | ||
|
|
4cea71ee73 | ||
|
|
3f02f50cf9 | ||
|
|
f7eac7f7ba | ||
|
|
2362f9bd6b | ||
|
|
5ffff1e39d | ||
|
|
bda35611f1 | ||
|
|
681f27e6b3 | ||
|
|
2c6c564c18 | ||
|
|
c1e308f61e | ||
|
|
2f22073ad8 | ||
|
|
546d3ec313 | ||
|
|
466f1b8271 | ||
|
|
83ec5e6789 | ||
|
|
5ee636d47d | ||
|
|
be2944ea16 | ||
|
|
027eeb99e1 | ||
|
|
2a3b3c0003 | ||
|
|
dc77da11cf | ||
|
|
8b12bbcc55 | ||
|
|
e48eaa567e | ||
|
|
5b717af829 | ||
|
|
e21c0d4724 | ||
|
|
f03125279a | ||
|
|
bb6d7d02c7 | ||
|
|
71d10a3fa3 | ||
|
|
df4922ea78 | ||
|
|
e7a49fc472 | ||
|
|
4bdee91501 | ||
|
|
5f9ed73f82 | ||
|
|
0fe06800d5 | ||
|
|
6f82e44283 | ||
|
|
20a11e0bc0 | ||
|
|
52cd4d434f | ||
|
|
f7748676b3 | ||
|
|
df305c111e | ||
|
|
64f6bd5348 | ||
|
|
89ca1dd0e4 | ||
|
|
7ecb057414 | ||
|
|
34cf970b54 | ||
|
|
ddc5ae6f4d | ||
|
|
62c5df36d6 | ||
|
|
c74af4f3d4 | ||
|
|
87f40c65e4 | ||
|
|
8b7f119cad | ||
|
|
2b9c138d7e | ||
|
|
6b2b9bd7c2 | ||
|
|
9c676b3ae7 | ||
|
|
811ee99dac | ||
|
|
91b7ff2ece | ||
|
|
0ba040e866 | ||
|
|
51ad754d1e | ||
|
|
4ff6919731 | ||
|
|
4e296fa9ec | ||
|
|
2a0f149a63 | ||
|
|
a4aa3529c8 | ||
|
|
9021719437 | ||
|
|
913b303664 | ||
|
|
82e5b81a30 | ||
|
|
876bfeb9ad | ||
|
|
13c62a47a9 | ||
|
|
ad9d8098ef | ||
|
|
f191acf811 | ||
|
|
a53ce56bca | ||
|
|
31726e4a73 | ||
|
|
3076f7a9b9 | ||
|
|
24d3c88c09 | ||
|
|
043451685b | ||
|
|
f3eabbf588 | ||
|
|
2e1704b56f | ||
|
|
cd961af818 | ||
|
|
eb0824a881 | ||
|
|
15c6afafb3 | ||
|
|
c0391ad2ea | ||
|
|
04ea9eebd4 | ||
|
|
c9daec7b6d | ||
|
|
fbc81d2fd0 | ||
|
|
b1ddba9767 | ||
|
|
123e46c33b | ||
|
|
23726c7c90 | ||
|
|
4ae5c2ea84 | ||
|
|
638a1808f8 | ||
|
|
13f44336f2 | ||
|
|
9e0fe94e8d | ||
|
|
be1b18a3d6 | ||
|
|
a011ec29fe | ||
|
|
9587f9374b | ||
|
|
6cfcc32895 | ||
|
|
a38b210472 | ||
|
|
ae1a389f0f | ||
|
|
815e782ad0 | ||
|
|
e317e751d1 | ||
|
|
ab888c0435 | ||
|
|
ae65a9ae89 | ||
|
|
2bbba880cd | ||
|
|
9b72973293 | ||
|
|
f3cf17c069 | ||
|
|
1f6cb61941 | ||
|
|
df9b36292d | ||
|
|
3391163f9c | ||
|
|
1abb5aa0f9 | ||
|
|
b3d9fd677b | ||
|
|
8ab7a20265 | ||
|
|
0098a68983 | ||
|
|
fcf7aa5e2f | ||
|
|
5aef57af73 | ||
|
|
1ffe3cc486 | ||
|
|
069cc909ea | ||
|
|
f3cc62569b | ||
|
|
e5627bcc67 | ||
|
|
24751850c6 | ||
|
|
9a154ac15f | ||
|
|
def449293b | ||
|
|
05461b1455 | ||
|
|
fb5c5411f8 | ||
|
|
56b088aa2e | ||
|
|
c8664d303e | ||
|
|
590230f107 | ||
|
|
00652f1f96 | ||
|
|
545b7bf8ff | ||
|
|
7678fc9de1 | ||
|
|
5d82502535 | ||
|
|
27ac08dd51 | ||
|
|
5a798afb3f | ||
|
|
eca379e98e | ||
|
|
0a2564c4d5 | ||
|
|
59dedb387f | ||
|
|
451004d152 | ||
|
|
e930b3e6c4 | ||
|
|
5d8492d728 | ||
|
|
c83db36573 | ||
|
|
adf1224e82 | ||
|
|
12e294d8ab | ||
|
|
5f9a51418c | ||
|
|
6851ca2988 | ||
|
|
e8d4c63071 | ||
|
|
e51ec6a827 | ||
|
|
7d88b0130c | ||
|
|
a651fb1348 | ||
|
|
29f3a1f1b2 | ||
|
|
8ff11b57b3 | ||
|
|
11235e7153 | ||
|
|
6158167163 | ||
|
|
7be30abab0 | ||
|
|
a107e7db6b | ||
|
|
268f3ed0fb | ||
|
|
5e8294c9d3 | ||
|
|
4ac8063bda | ||
|
|
f7070b8ccc | ||
|
|
143ea45ea6 | ||
|
|
d1b9543189 | ||
|
|
5c97059d5c | ||
|
|
d2462a80f6 | ||
|
|
587e42d673 | ||
|
|
08518cc6c6 | ||
|
|
4959197e37 | ||
|
|
b7ef0df821 | ||
|
|
af2d5d98b5 | ||
|
|
7c7c9490fb | ||
|
|
ef2e62c852 | ||
|
|
232d211812 | ||
|
|
05dff2f7cb | ||
|
|
9573cd3395 | ||
|
|
bc1d3569ba | ||
|
|
7df537c9fc | ||
|
|
17771e0e1d | ||
|
|
0204bdab55 | ||
|
|
b1b7d81e0b | ||
|
|
0505507219 | ||
|
|
63c8fe287f | ||
|
|
05b8013a8e | ||
|
|
02dd1303c9 | ||
|
|
8c9624ba5f | ||
|
|
caac463427 | ||
|
|
4aa5fbbb20 | ||
|
|
0a0311a2b2 | ||
|
|
c95b057cdc | ||
|
|
dd6f9bcac9 | ||
|
|
1d23c6cf88 | ||
|
|
dacfa2afed | ||
|
|
212156289d | ||
|
|
93af167f9c | ||
|
|
bd7ee6d602 | ||
|
|
c04f6bedec | ||
|
|
b0acfd1189 | ||
|
|
a55e502aed | ||
|
|
0e4237b775 | ||
|
|
14750785b0 | ||
|
|
9e505ea2de | ||
|
|
7d6e91f0a6 | ||
|
|
5c5ecac6ee | ||
|
|
e478ee2e5f | ||
|
|
7604653fd8 | ||
|
|
891d5f0625 | ||
|
|
8b319086e7 | ||
|
|
a1e813bb0d | ||
|
|
69628baa9d | ||
|
|
626b799cff | ||
|
|
688248198e | ||
|
|
8512b219c5 | ||
|
|
bbb5322008 | ||
|
|
8c97ba4f08 | ||
|
|
7f99cce8c8 | ||
|
|
7c6afeabec | ||
|
|
4cf11b721a | ||
|
|
083f12d06e | ||
|
|
29c1e37ac2 | ||
|
|
4ed9af397d | ||
|
|
eb9c8e539c | ||
|
|
ea77062daf | ||
|
|
7756f2c416 | ||
|
|
8459fc2c4d | ||
|
|
1937f62c02 | ||
|
|
e014f1ba0c | ||
|
|
cfba349fdb | ||
|
|
e31e70d0c4 | ||
|
|
d746266b0d | ||
|
|
208ccd054b | ||
|
|
f63bdf4d09 | ||
|
|
1a372e2dec | ||
|
|
18e727ee7f | ||
|
|
b3f9dad044 | ||
|
|
075fa52190 | ||
|
|
2e115d0e93 | ||
|
|
bea45a94f0 | ||
|
|
bb08b2deea | ||
|
|
163a88056e | ||
|
|
aa8af6b798 | ||
|
|
bceeabd6c3 | ||
|
|
bb082f9490 | ||
|
|
30d79476cd | ||
|
|
26d36ec7ff | ||
|
|
8449a2e4fb | ||
|
|
3bc5cf4b5d | ||
|
|
8a19d663b0 | ||
|
|
bc9c42f5c2 | ||
|
|
a1a750d440 | ||
|
|
2223338e34 | ||
|
|
1fb7953a95 | ||
|
|
ac503c5194 | ||
|
|
77e571b079 | ||
|
|
16b02e86fa | ||
|
|
252ac75368 | ||
|
|
b762bdcaf7 | ||
|
|
b7eb566195 | ||
|
|
e281cb65f9 | ||
|
|
a00bcb0154 | ||
|
|
9fd0e767eb | ||
|
|
226c550d30 | ||
|
|
f8bb7549f4 | ||
|
|
985fc97a08 | ||
|
|
9ae4e3898c | ||
|
|
89e3fa7245 | ||
|
|
a30a71905e |
5
.gitattributes
vendored
5
.gitattributes
vendored
@@ -1 +1,6 @@
|
|||||||
* text=auto eol=lf
|
* text=auto eol=lf
|
||||||
|
*.gen.ts linguist-generated
|
||||||
|
*_gen.ts linguist-generated
|
||||||
|
*_gen.go linguist-generated
|
||||||
|
**/openapi_snapshots/*.json linguist-generated
|
||||||
|
apps/**/pkg/apis/*_manifest.go linguist-generated
|
||||||
|
|||||||
43
.github/CODEOWNERS
vendored
43
.github/CODEOWNERS
vendored
@@ -96,6 +96,9 @@
|
|||||||
/apps/iam/ @grafana/access-squad
|
/apps/iam/ @grafana/access-squad
|
||||||
/apps/sdk.mk @grafana/grafana-app-platform-squad
|
/apps/sdk.mk @grafana/grafana-app-platform-squad
|
||||||
/apps/correlations @grafana/datapro
|
/apps/correlations @grafana/datapro
|
||||||
|
/apps/example/ @grafana/grafana-app-platform-squad
|
||||||
|
/apps/logsdrilldown/ @grafana/observability-logs
|
||||||
|
/apps/annotation/ @grafana/grafana-backend-services-squad
|
||||||
/pkg/api/ @grafana/grafana-backend-group
|
/pkg/api/ @grafana/grafana-backend-group
|
||||||
/pkg/apis/ @grafana/grafana-app-platform-squad
|
/pkg/apis/ @grafana/grafana-app-platform-squad
|
||||||
/pkg/apis/query @grafana/grafana-datasources-core-services
|
/pkg/apis/query @grafana/grafana-datasources-core-services
|
||||||
@@ -149,7 +152,7 @@
|
|||||||
/pkg/promlib @grafana/oss-big-tent
|
/pkg/promlib @grafana/oss-big-tent
|
||||||
/pkg/storage/ @grafana/grafana-search-and-storage
|
/pkg/storage/ @grafana/grafana-search-and-storage
|
||||||
/pkg/storage/secret/ @grafana/grafana-operator-experience-squad
|
/pkg/storage/secret/ @grafana/grafana-operator-experience-squad
|
||||||
/pkg/services/annotations/ @grafana/grafana-search-and-storage
|
/pkg/services/annotations/ @grafana/grafana-backend-services-squad
|
||||||
/pkg/services/apikey/ @grafana/identity-squad
|
/pkg/services/apikey/ @grafana/identity-squad
|
||||||
/pkg/services/cleanup/ @grafana/grafana-backend-group
|
/pkg/services/cleanup/ @grafana/grafana-backend-group
|
||||||
/pkg/services/contexthandler/ @grafana/grafana-backend-group @grafana/grafana-app-platform-squad
|
/pkg/services/contexthandler/ @grafana/grafana-backend-group @grafana/grafana-app-platform-squad
|
||||||
@@ -165,7 +168,7 @@
|
|||||||
/pkg/services/kmsproviders/ @grafana/grafana-operator-experience-squad
|
/pkg/services/kmsproviders/ @grafana/grafana-operator-experience-squad
|
||||||
/pkg/services/licensing/ @grafana/grafana-operator-experience-squad
|
/pkg/services/licensing/ @grafana/grafana-operator-experience-squad
|
||||||
/pkg/services/dsquerierclient/ @grafana/grafana-datasources-core-services
|
/pkg/services/dsquerierclient/ @grafana/grafana-datasources-core-services
|
||||||
/pkg/services/navtree/ @grafana/grafana-backend-group
|
/pkg/services/navtree/ @grafana/grafana-backend-group @grafana/grafana-search-navigate-organise
|
||||||
/pkg/services/notifications/ @grafana/grafana-backend-group
|
/pkg/services/notifications/ @grafana/grafana-backend-group
|
||||||
/pkg/services/org/ @grafana/grafana-backend-group
|
/pkg/services/org/ @grafana/grafana-backend-group
|
||||||
/pkg/services/playlist/ @grafana/grafana-app-platform-squad
|
/pkg/services/playlist/ @grafana/grafana-app-platform-squad
|
||||||
@@ -179,7 +182,7 @@
|
|||||||
/pkg/services/search/ @grafana/grafana-search-and-storage
|
/pkg/services/search/ @grafana/grafana-search-and-storage
|
||||||
/pkg/services/searchusers/ @grafana/grafana-search-and-storage
|
/pkg/services/searchusers/ @grafana/grafana-search-and-storage
|
||||||
/pkg/services/secrets/ @grafana/grafana-operator-experience-squad
|
/pkg/services/secrets/ @grafana/grafana-operator-experience-squad
|
||||||
/pkg/services/shorturls/ @grafana/grafana-backend-group
|
/pkg/services/shorturls/ @grafana/sharing-squad
|
||||||
/pkg/services/sqlstore/ @grafana/grafana-search-and-storage
|
/pkg/services/sqlstore/ @grafana/grafana-search-and-storage
|
||||||
/pkg/services/ssosettings/ @grafana/identity-squad
|
/pkg/services/ssosettings/ @grafana/identity-squad
|
||||||
/pkg/services/star/ @grafana/grafana-search-and-storage
|
/pkg/services/star/ @grafana/grafana-search-and-storage
|
||||||
@@ -197,6 +200,7 @@
|
|||||||
/pkg/tests/apis/features @grafana/grafana-backend-services-squad
|
/pkg/tests/apis/features @grafana/grafana-backend-services-squad
|
||||||
/pkg/tests/apis/folder @grafana/grafana-search-and-storage
|
/pkg/tests/apis/folder @grafana/grafana-search-and-storage
|
||||||
/pkg/tests/apis/iam @grafana/identity-access-team
|
/pkg/tests/apis/iam @grafana/identity-access-team
|
||||||
|
/pkg/tests/apis/shorturl @grafana/sharing-squad
|
||||||
/pkg/tests/api/correlations/ @grafana/datapro
|
/pkg/tests/api/correlations/ @grafana/datapro
|
||||||
/pkg/tsdb/grafanads/ @grafana/grafana-backend-group
|
/pkg/tsdb/grafanads/ @grafana/grafana-backend-group
|
||||||
/pkg/tsdb/opentsdb/ @grafana/partner-datasources
|
/pkg/tsdb/opentsdb/ @grafana/partner-datasources
|
||||||
@@ -223,6 +227,7 @@
|
|||||||
/devenv/datasources.yaml @grafana/grafana-backend-group
|
/devenv/datasources.yaml @grafana/grafana-backend-group
|
||||||
/devenv/datasources_docker.yaml @grafana/grafana-backend-group
|
/devenv/datasources_docker.yaml @grafana/grafana-backend-group
|
||||||
/devenv/dev-dashboards-without-uid/ @grafana/dashboards-squad
|
/devenv/dev-dashboards-without-uid/ @grafana/dashboards-squad
|
||||||
|
/devenv/scopes/ @grafana/grafana-operator-experience-squad
|
||||||
|
|
||||||
/devenv/dev-dashboards/annotations @grafana/dataviz-squad
|
/devenv/dev-dashboards/annotations @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/migrations @grafana/dataviz-squad
|
/devenv/dev-dashboards/migrations @grafana/dataviz-squad
|
||||||
@@ -239,6 +244,7 @@
|
|||||||
/devenv/dev-dashboards/panel-library @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-library @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/panel-piechart @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-piechart @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/panel-stat @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-stat @grafana/dataviz-squad
|
||||||
|
/devenv/dev-dashboards/panel-status-history @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/panel-table @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-table @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/panel-timeline @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-timeline @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/panel-timeseries @grafana/dataviz-squad
|
/devenv/dev-dashboards/panel-timeseries @grafana/dataviz-squad
|
||||||
@@ -248,7 +254,6 @@
|
|||||||
/devenv/dev-dashboards/all-panels.json @grafana/dataviz-squad
|
/devenv/dev-dashboards/all-panels.json @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/dashboards.go @grafana/dataviz-squad
|
/devenv/dev-dashboards/dashboards.go @grafana/dataviz-squad
|
||||||
/devenv/dev-dashboards/home.json @grafana/dataviz-squad
|
/devenv/dev-dashboards/home.json @grafana/dataviz-squad
|
||||||
|
|
||||||
/devenv/dev-dashboards/datasource-elasticsearch/ @grafana/partner-datasources
|
/devenv/dev-dashboards/datasource-elasticsearch/ @grafana/partner-datasources
|
||||||
/devenv/dev-dashboards/datasource-opentsdb/ @grafana/partner-datasources
|
/devenv/dev-dashboards/datasource-opentsdb/ @grafana/partner-datasources
|
||||||
/devenv/dev-dashboards/datasource-influxdb/ @grafana/partner-datasources
|
/devenv/dev-dashboards/datasource-influxdb/ @grafana/partner-datasources
|
||||||
@@ -412,8 +417,8 @@
|
|||||||
|
|
||||||
/crowdin.yml @grafana/grafana-frontend-platform
|
/crowdin.yml @grafana/grafana-frontend-platform
|
||||||
/public/locales/ @grafanabot
|
/public/locales/ @grafanabot
|
||||||
/public/locales/i18next-parser.config.cjs @grafana/grafana-frontend-platform
|
i18next.config.ts @grafana/grafana-frontend-platform
|
||||||
/public/locales/i18next-parser-enterprise.config.cjs @grafana/grafana-frontend-platform
|
/public/locales/enterprise/i18next.config.ts @grafana/grafana-frontend-platform
|
||||||
/public/app/core/internationalization/ @grafana/grafana-frontend-platform
|
/public/app/core/internationalization/ @grafana/grafana-frontend-platform
|
||||||
/e2e/ @grafana/grafana-frontend-platform
|
/e2e/ @grafana/grafana-frontend-platform
|
||||||
/e2e-playwright/cloud-plugins-suite/ @grafana/partner-datasources
|
/e2e-playwright/cloud-plugins-suite/ @grafana/partner-datasources
|
||||||
@@ -470,22 +475,12 @@
|
|||||||
/e2e-playwright/fixtures/long-trace-response.json @grafana/observability-traces-and-profiling
|
/e2e-playwright/fixtures/long-trace-response.json @grafana/observability-traces-and-profiling
|
||||||
/e2e-playwright/fixtures/tempo-response.json @grafana/oss-big-tent
|
/e2e-playwright/fixtures/tempo-response.json @grafana/oss-big-tent
|
||||||
/e2e-playwright/fixtures/prometheus-response.json @grafana/datapro
|
/e2e-playwright/fixtures/prometheus-response.json @grafana/datapro
|
||||||
/e2e-playwright/panels-suite/canvas-scene.spec.ts @grafana/dataviz-squad
|
/e2e-playwright/panels-suite/ @grafana/dataviz-squad
|
||||||
/e2e-playwright/panels-suite/dashlist.spec.ts @grafana/grafana-search-navigate-organise
|
/e2e-playwright/panels-suite/dashlist.spec.ts @grafana/grafana-search-navigate-organise
|
||||||
/e2e-playwright/panels-suite/datagrid-data-change.spec.ts @grafana/dataviz-squad
|
|
||||||
/e2e-playwright/panels-suite/datagrid-editing-features.spec.ts @grafana/dataviz-squad
|
|
||||||
/e2e-playwright/panels-suite/frontend-sandbox-panel.spec.ts @grafana/plugins-platform-frontend
|
/e2e-playwright/panels-suite/frontend-sandbox-panel.spec.ts @grafana/plugins-platform-frontend
|
||||||
/e2e-playwright/panels-suite/geomap-layer-types.spec.ts @grafana/dataviz-squad
|
|
||||||
/e2e-playwright/panels-suite/geomap-map-controls.spec.ts @grafana/dataviz-squad
|
|
||||||
/e2e-playwright/panels-suite/geomap-spatial-operations-transform.spec.ts @grafana/dataviz-squad
|
|
||||||
/e2e-playwright/panels-suite/panelEdit_base.spec.ts @grafana/dashboards-squad
|
/e2e-playwright/panels-suite/panelEdit_base.spec.ts @grafana/dashboards-squad
|
||||||
/e2e-playwright/panels-suite/panelEdit_queries.spec.ts @grafana/dashboards-squad
|
/e2e-playwright/panels-suite/panelEdit_queries.spec.ts @grafana/dashboards-squad
|
||||||
/e2e-playwright/panels-suite/panelEdit_transforms.spec.ts @grafana/datapro
|
/e2e-playwright/panels-suite/panelEdit_transforms.spec.ts @grafana/datapro
|
||||||
/e2e-playwright/panels-suite/table-footer.spec.ts @grafana/dataviz-squad
|
|
||||||
/e2e-playwright/panels-suite/table-kitchenSink.spec.ts @grafana/dataviz-squad
|
|
||||||
/e2e-playwright/panels-suite/table-markdown.spec.ts @grafana/dataviz-squad
|
|
||||||
/e2e-playwright/panels-suite/table-sparkline.spec.ts @grafana/dataviz-squad
|
|
||||||
/e2e-playwright/panels-suite/table-utils.ts @grafana/dataviz-squad
|
|
||||||
/e2e-playwright/plugin-e2e/ @grafana/oss-big-tent @grafana/partner-datasources
|
/e2e-playwright/plugin-e2e/ @grafana/oss-big-tent @grafana/partner-datasources
|
||||||
/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/ @grafana/plugins-platform-frontend
|
/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/ @grafana/plugins-platform-frontend
|
||||||
/e2e-playwright/smoke-tests-suite/ @grafana/grafana-frontend-platform
|
/e2e-playwright/smoke-tests-suite/ @grafana/grafana-frontend-platform
|
||||||
@@ -502,6 +497,7 @@
|
|||||||
/e2e-playwright/various-suite/frontend-sandbox-app.spec.ts @grafana/plugins-platform-frontend
|
/e2e-playwright/various-suite/frontend-sandbox-app.spec.ts @grafana/plugins-platform-frontend
|
||||||
/e2e-playwright/various-suite/frontend-sandbox-datasource.spec.ts @grafana/plugins-platform-frontend
|
/e2e-playwright/various-suite/frontend-sandbox-datasource.spec.ts @grafana/plugins-platform-frontend
|
||||||
/e2e-playwright/various-suite/gauge.spec.ts @grafana/dataviz-squad
|
/e2e-playwright/various-suite/gauge.spec.ts @grafana/dataviz-squad
|
||||||
|
/e2e-playwright/various-suite/grafana-datasource-random-walk.spec.ts @grafana/grafana-frontend-platform
|
||||||
/e2e-playwright/various-suite/graph-auto-migrate.spec.ts @grafana/dataviz-squad
|
/e2e-playwright/various-suite/graph-auto-migrate.spec.ts @grafana/dataviz-squad
|
||||||
/e2e-playwright/various-suite/inspect-drawer.spec.ts @grafana/dashboards-squad
|
/e2e-playwright/various-suite/inspect-drawer.spec.ts @grafana/dashboards-squad
|
||||||
/e2e-playwright/various-suite/keybinds.spec.ts @grafana/grafana-frontend-platform
|
/e2e-playwright/various-suite/keybinds.spec.ts @grafana/grafana-frontend-platform
|
||||||
@@ -553,6 +549,7 @@
|
|||||||
/packages/grafana-data/src/geo/ @grafana/dataviz-squad
|
/packages/grafana-data/src/geo/ @grafana/dataviz-squad
|
||||||
/packages/grafana-data/src/monaco/ @grafana/partner-datasources
|
/packages/grafana-data/src/monaco/ @grafana/partner-datasources
|
||||||
/packages/grafana-data/src/panel/ @grafana/dashboards-squad
|
/packages/grafana-data/src/panel/ @grafana/dashboards-squad
|
||||||
|
/packages/grafana-data/src/panel/suggestions/ @grafana/dataviz-squad
|
||||||
/packages/grafana-data/src/query/ @grafana/grafana-datasources-core-services
|
/packages/grafana-data/src/query/ @grafana/grafana-datasources-core-services
|
||||||
/packages/grafana-data/src/rbac/ @grafana/access-squad
|
/packages/grafana-data/src/rbac/ @grafana/access-squad
|
||||||
/packages/grafana-data/src/table/ @grafana/dataviz-squad
|
/packages/grafana-data/src/table/ @grafana/dataviz-squad
|
||||||
@@ -560,6 +557,7 @@
|
|||||||
/packages/grafana-data/src/themes/ @grafana/grafana-frontend-platform
|
/packages/grafana-data/src/themes/ @grafana/grafana-frontend-platform
|
||||||
/packages/grafana-data/src/transformations/ @grafana/datapro
|
/packages/grafana-data/src/transformations/ @grafana/datapro
|
||||||
/packages/grafana-data/src/types/ @grafana/grafana-frontend-platform
|
/packages/grafana-data/src/types/ @grafana/grafana-frontend-platform
|
||||||
|
/packages/grafana-data/src/types/scopes.ts @grafana/grafana-operator-experience-squad
|
||||||
/packages/grafana-data/src/utils/__snapshots__/ @grafanabot
|
/packages/grafana-data/src/utils/__snapshots__/ @grafanabot
|
||||||
/packages/grafana-data/src/utils/anyToNumber.ts @grafana/grafana-frontend-platform
|
/packages/grafana-data/src/utils/anyToNumber.ts @grafana/grafana-frontend-platform
|
||||||
/packages/grafana-data/src/utils/arrayUtils* @grafana/grafana-frontend-platform
|
/packages/grafana-data/src/utils/arrayUtils* @grafana/grafana-frontend-platform
|
||||||
@@ -717,6 +715,7 @@
|
|||||||
/packages/grafana-ui/src/components/BarGauge/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/BarGauge/ @grafana/dataviz-squad
|
||||||
/packages/grafana-ui/src/components/DataLinks/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/DataLinks/ @grafana/dataviz-squad
|
||||||
/packages/grafana-ui/src/components/Gauge/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/Gauge/ @grafana/dataviz-squad
|
||||||
|
/packages/grafana-ui/src/components/RadialGauge/ @grafana/dataviz-squad
|
||||||
/packages/grafana-ui/src/components/PluginSignatureBadge/ @grafana/plugins-platform-frontend
|
/packages/grafana-ui/src/components/PluginSignatureBadge/ @grafana/plugins-platform-frontend
|
||||||
/packages/grafana-ui/src/components/Sparkline/ @grafana/grafana-frontend-platform @grafana/app-o11y-visualizations
|
/packages/grafana-ui/src/components/Sparkline/ @grafana/grafana-frontend-platform @grafana/app-o11y-visualizations
|
||||||
/packages/grafana-ui/src/components/Table/ @grafana/dataviz-squad
|
/packages/grafana-ui/src/components/Table/ @grafana/dataviz-squad
|
||||||
@@ -739,6 +738,9 @@
|
|||||||
# @grafana/test-utils
|
# @grafana/test-utils
|
||||||
/packages/grafana-test-utils @grafana/grafana-frontend-platform
|
/packages/grafana-test-utils @grafana/grafana-frontend-platform
|
||||||
|
|
||||||
|
# @grafana/api-clients
|
||||||
|
/packages/grafana-api-clients/ @grafana/grafana-frontend-platform @grafana/grafana-search-navigate-organise
|
||||||
|
|
||||||
# root files, mostly frontend
|
# root files, mostly frontend
|
||||||
/.browserslistrc @grafana/frontend-ops
|
/.browserslistrc @grafana/frontend-ops
|
||||||
/package.json @grafana/frontend-ops
|
/package.json @grafana/frontend-ops
|
||||||
@@ -789,7 +791,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||||||
/public/app/core/components/ColorScale/ @grafana/dataviz-squad
|
/public/app/core/components/ColorScale/ @grafana/dataviz-squad
|
||||||
/public/app/core/components/DynamicImports/ @grafana/grafana-search-navigate-organise
|
/public/app/core/components/DynamicImports/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/core/components/EmptyListCTA/ @grafana/grafana-frontend-platform
|
/public/app/core/components/EmptyListCTA/ @grafana/grafana-frontend-platform
|
||||||
/public/app/core/components/FolderFilter/ @grafana/sharing-squad
|
/public/app/core/components/FolderFilter/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/core/components/Footer/ @grafana/grafana-search-navigate-organise
|
/public/app/core/components/Footer/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/core/components/ForgottenPassword/ @grafana/grafana-search-navigate-organise
|
/public/app/core/components/ForgottenPassword/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/core/components/Form/ @grafana/grafana-frontend-platform
|
/public/app/core/components/Form/ @grafana/grafana-frontend-platform
|
||||||
@@ -957,7 +959,6 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||||||
/public/app/features/transformers/timeSeriesTable/ @grafana/dataviz-squad @grafana/app-o11y-visualizations
|
/public/app/features/transformers/timeSeriesTable/ @grafana/dataviz-squad @grafana/app-o11y-visualizations
|
||||||
/public/app/features/users/ @grafana/access-squad
|
/public/app/features/users/ @grafana/access-squad
|
||||||
/public/app/features/variables/ @grafana/dashboards-squad
|
/public/app/features/variables/ @grafana/dashboards-squad
|
||||||
/public/app/features/preferences/ @grafana/grafana-frontend-platform
|
|
||||||
/public/app/features/bookmarks/ @grafana/grafana-search-navigate-organise
|
/public/app/features/bookmarks/ @grafana/grafana-search-navigate-organise
|
||||||
/public/app/plugins/panel/* @grafana/dataviz-squad
|
/public/app/plugins/panel/* @grafana/dataviz-squad
|
||||||
/public/app/plugins/panel/alertlist/ @grafana/alerting-frontend
|
/public/app/plugins/panel/alertlist/ @grafana/alerting-frontend
|
||||||
@@ -1053,13 +1054,10 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform
|
|||||||
/scripts/trigger_windows_build.sh @grafana/grafana-developer-enablement-squad
|
/scripts/trigger_windows_build.sh @grafana/grafana-developer-enablement-squad
|
||||||
/scripts/cleanup-husky.sh @grafana/frontend-ops
|
/scripts/cleanup-husky.sh @grafana/frontend-ops
|
||||||
/scripts/verify-repo-update/ @grafana/grafana-developer-enablement-squad
|
/scripts/verify-repo-update/ @grafana/grafana-developer-enablement-squad
|
||||||
/scripts/generate-rtk-apis.ts @grafana/grafana-frontend-platform
|
|
||||||
/scripts/process-specs.ts @grafana/grafana-frontend-platform
|
|
||||||
/scripts/generate-alerting-rtk-apis.ts @grafana/alerting-frontend
|
/scripts/generate-alerting-rtk-apis.ts @grafana/alerting-frontend
|
||||||
/scripts/levitate-parse-json-report.js @grafana/plugins-platform-frontend
|
/scripts/levitate-parse-json-report.js @grafana/plugins-platform-frontend
|
||||||
/scripts/levitate-show-affected-plugins.js @grafana/plugins-platform-frontend
|
/scripts/levitate-show-affected-plugins.js @grafana/plugins-platform-frontend
|
||||||
/scripts/codemods/explicit-barrel-imports.cjs @grafana/frontend-ops
|
/scripts/codemods/explicit-barrel-imports.cjs @grafana/frontend-ops
|
||||||
/scripts/rtk-client-generator/ @grafana/grafana-search-navigate-organise
|
|
||||||
|
|
||||||
/scripts/codeowners-manifest/ @grafana/dataviz-squad
|
/scripts/codeowners-manifest/ @grafana/dataviz-squad
|
||||||
/scripts/test-coverage-by-codeowner.js @grafana/dataviz-squad
|
/scripts/test-coverage-by-codeowner.js @grafana/dataviz-squad
|
||||||
@@ -1170,6 +1168,7 @@ embed.go @grafana/grafana-as-code
|
|||||||
/pkg/registry/ @grafana/grafana-as-code
|
/pkg/registry/ @grafana/grafana-as-code
|
||||||
/pkg/registry/apis/ @grafana/grafana-app-platform-squad
|
/pkg/registry/apis/ @grafana/grafana-app-platform-squad
|
||||||
/pkg/registry/apis/folders @grafana/grafana-search-and-storage
|
/pkg/registry/apis/folders @grafana/grafana-search-and-storage
|
||||||
|
/pkg/registry/apis/datasource @grafana/grafana-datasources-core-services
|
||||||
/pkg/registry/apis/query @grafana/grafana-datasources-core-services
|
/pkg/registry/apis/query @grafana/grafana-datasources-core-services
|
||||||
/pkg/registry/apis/secret @grafana/grafana-operator-experience-squad
|
/pkg/registry/apis/secret @grafana/grafana-operator-experience-squad
|
||||||
/pkg/registry/apis/userstorage @grafana/grafana-app-platform-squad @grafana/plugins-platform-backend
|
/pkg/registry/apis/userstorage @grafana/grafana-app-platform-squad @grafana/plugins-platform-backend
|
||||||
|
|||||||
8
.github/actions/change-detection/action.yml
vendored
8
.github/actions/change-detection/action.yml
vendored
@@ -31,6 +31,9 @@ outputs:
|
|||||||
dockerfile:
|
dockerfile:
|
||||||
description: Whether the dockerfile or self have changed in any way
|
description: Whether the dockerfile or self have changed in any way
|
||||||
value: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}
|
value: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}
|
||||||
|
devenv:
|
||||||
|
description: Whether the devenv or self have changed in any way
|
||||||
|
value: ${{ steps.changed-files.outputs.devenv_any_changed || 'true' }}
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
@@ -136,6 +139,9 @@ runs:
|
|||||||
- '.vale.ini'
|
- '.vale.ini'
|
||||||
- '.github/actions/change-detection/**'
|
- '.github/actions/change-detection/**'
|
||||||
- '${{ inputs.self }}'
|
- '${{ inputs.self }}'
|
||||||
|
devenv:
|
||||||
|
- 'devenv/**'
|
||||||
|
- '${{ inputs.self }}'
|
||||||
- name: Print all change groups
|
- name: Print all change groups
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
@@ -157,3 +163,5 @@ runs:
|
|||||||
echo " --> ${{ steps.changed-files.outputs.docs_all_changed_files }}"
|
echo " --> ${{ steps.changed-files.outputs.docs_all_changed_files }}"
|
||||||
echo "Dockerfile: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}"
|
echo "Dockerfile: ${{ steps.changed-files.outputs.dockerfile_any_changed || 'true' }}"
|
||||||
echo " --> ${{ steps.changed-files.outputs.dockerfile_all_changed_files }}"
|
echo " --> ${{ steps.changed-files.outputs.dockerfile_all_changed_files }}"
|
||||||
|
echo "devenv: ${{ steps.changed-files.outputs.devenv_any_changed || 'true' }}"
|
||||||
|
echo " --> ${{ steps.changed-files.outputs.devenv_all_changed_files }}"
|
||||||
|
|||||||
4
.github/renovate.json5
vendored
4
.github/renovate.json5
vendored
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
extends: ["config:recommended"],
|
extends: ["config:recommended"],
|
||||||
enabledManagers: ["npm"],
|
enabledManagers: ["npm", "docker-compose"],
|
||||||
ignorePresets: [
|
ignorePresets: [
|
||||||
"github>grafana/grafana-renovate-config//presets/labels",
|
"github>grafana/grafana-renovate-config//presets/labels",
|
||||||
],
|
],
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"@types/slate-react", // we don't want to continue using this on the long run, use Monaco editor instead of Slate
|
"@types/slate-react", // we don't want to continue using this on the long run, use Monaco editor instead of Slate
|
||||||
"@types/slate", // we don't want to continue using this on the long run, use Monaco editor instead of Slate
|
"@types/slate", // we don't want to continue using this on the long run, use Monaco editor instead of Slate
|
||||||
],
|
],
|
||||||
includePaths: ["package.json", "packages/**", "public/app/plugins/**"],
|
includePaths: ["package.json", "packages/**", "public/app/plugins/**", "devenv/frontend-service/docker-compose.yaml"],
|
||||||
ignorePaths: ["emails/**", "**/mocks/**"],
|
ignorePaths: ["emails/**", "**/mocks/**"],
|
||||||
labels: ["area/frontend", "dependencies", "no-changelog"],
|
labels: ["area/frontend", "dependencies", "no-changelog"],
|
||||||
postUpdateOptions: ["yarnDedupeHighest"],
|
postUpdateOptions: ["yarnDedupeHighest"],
|
||||||
|
|||||||
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@@ -54,7 +54,7 @@ jobs:
|
|||||||
- name: Upload to GitHub security events
|
- name: Upload to GitHub security events
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
# If there are security problems, GitHub will automatically comment on the PR for us.
|
# If there are security problems, GitHub will automatically comment on the PR for us.
|
||||||
uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
category: actionlint
|
category: actionlint
|
||||||
|
|||||||
2
.github/workflows/alerting-swagger-gen.yml
vendored
2
.github/workflows/alerting-swagger-gen.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set go version
|
- name: Set go version
|
||||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
- name: Build swagger
|
- name: Build swagger
|
||||||
|
|||||||
2
.github/workflows/alerting-update-module.yml
vendored
2
.github/workflows/alerting-update-module.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # 5.5.0
|
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # 6.0.0
|
||||||
with:
|
with:
|
||||||
"go-version-file": "go.mod"
|
"go-version-file": "go.mod"
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
9
.github/workflows/backend-code-checks.yml
vendored
9
.github/workflows/backend-code-checks.yml
vendored
@@ -46,12 +46,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
# Explicitly set Go version to 1.24.1 to ensure consistent OpenAPI spec generation
|
go-version-file: go.mod
|
||||||
# The crypto/x509 package has additional fields in Go 1.24.1 that affect the generated specs
|
|
||||||
# This ensures the GHAs environment matches what we use in the Drone pipeline
|
|
||||||
go-version: 1.24.1
|
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
- name: Verify code generation
|
- name: Verify code generation
|
||||||
@@ -82,7 +79,7 @@ jobs:
|
|||||||
make swagger-clean && make openapi3-gen
|
make swagger-clean && make openapi3-gen
|
||||||
|
|
||||||
# Check if the generated specs differ from what's in the repository
|
# Check if the generated specs differ from what's in the repository
|
||||||
for f in public/api-merged.json public/openapi3.json; do git add $f; done
|
for f in public/api-merged.json public/openapi3.json public/api-enterprise-spec.json; do git add $f; done
|
||||||
if [ -z "$(git diff --name-only --cached)" ]; then
|
if [ -z "$(git diff --name-only --cached)" ]; then
|
||||||
echo "OpenAPI specs are up to date!"
|
echo "OpenAPI specs are up to date!"
|
||||||
else
|
else
|
||||||
|
|||||||
4
.github/workflows/backend-unit-tests.yml
vendored
4
.github/workflows/backend-unit-tests.yml
vendored
@@ -59,7 +59,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
@@ -94,7 +94,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
- name: Setup Enterprise
|
- name: Setup Enterprise
|
||||||
|
|||||||
2
.github/workflows/backport-trigger.yml
vendored
2
.github/workflows/backport-trigger.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
|||||||
}' "$GITHUB_EVENT_PATH" > /tmp/pr_info.json
|
}' "$GITHUB_EVENT_PATH" > /tmp/pr_info.json
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: pr_info
|
name: pr_info
|
||||||
path: /tmp/pr_info.json
|
path: /tmp/pr_info.json
|
||||||
|
|||||||
2
.github/workflows/backport-workflow.yml
vendored
2
.github/workflows/backport-workflow.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
|||||||
private_key: ${{ fromJSON(steps.secrets.outputs.secrets).APP_PEM }}
|
private_key: ${{ fromJSON(steps.secrets.outputs.secrets).APP_PEM }}
|
||||||
|
|
||||||
- name: Download PR info artifact
|
- name: Download PR info artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v6
|
||||||
id: download-pr-info
|
id: download-pr-info
|
||||||
with:
|
with:
|
||||||
github-token: ${{ github.token }}
|
github-token: ${{ github.token }}
|
||||||
|
|||||||
2
.github/workflows/changelog.yml
vendored
2
.github/workflows/changelog.yml
vendored
@@ -97,7 +97,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
fetch-tags: true
|
fetch-tags: true
|
||||||
- name: Setup nodejs environment
|
- name: Setup nodejs environment
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: .nvmrc
|
node-version-file: .nvmrc
|
||||||
- name: "Configure git user"
|
- name: "Configure git user"
|
||||||
|
|||||||
2
.github/workflows/cleanup-branches.yml
vendored
2
.github/workflows/cleanup-branches.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
|||||||
pull-requests: read
|
pull-requests: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
- uses: grafana/shared-workflows/actions/cleanup-branches@cleanup-branches/v1.0.0
|
- uses: grafana/shared-workflows/actions/cleanup-branches@cleanup-branches/v0.2.1
|
||||||
with:
|
with:
|
||||||
dry-run: true
|
dry-run: true
|
||||||
max-date: "1 month ago"
|
max-date: "1 month ago"
|
||||||
|
|||||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -72,14 +72,14 @@ jobs:
|
|||||||
|
|
||||||
- if: matrix.language == 'go' && needs.detect-changes.outputs.go == 'true'
|
- if: matrix.language == 'go' && needs.detect-changes.outputs.go == 'true'
|
||||||
name: Set go version
|
name: Set go version
|
||||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
if: needs.detect-changes.outputs[matrix.language] == 'true'
|
if: needs.detect-changes.outputs[matrix.language] == 'true'
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v4
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -94,4 +94,4 @@ jobs:
|
|||||||
make build-go
|
make build-go
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3
|
uses: github/codeql-action/analyze@v4
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
- name: 'Set up Cloud SDK'
|
- name: 'Set up Cloud SDK'
|
||||||
uses: 'google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db'
|
uses: 'google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db'
|
||||||
- name: Setup nodejs environment
|
- name: Setup nodejs environment
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: .nvmrc
|
node-version-file: .nvmrc
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -101,7 +101,7 @@ jobs:
|
|||||||
echo "has_backend=false" >> "$GITHUB_OUTPUT"
|
echo "has_backend=false" >> "$GITHUB_OUTPUT"
|
||||||
fi
|
fi
|
||||||
- name: Setup golang environment
|
- name: Setup golang environment
|
||||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
||||||
if: steps.check_backend.outputs.has_backend == 'true'
|
if: steps.check_backend.outputs.has_backend == 'true'
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
@@ -193,7 +193,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
- name: store build artifacts
|
- name: store build artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: build-artifacts
|
name: build-artifacts
|
||||||
path: ${{ steps.get_dir.outputs.dir }}/ci/packages/*.zip
|
path: ${{ steps.get_dir.outputs.dir }}/ci/packages/*.zip
|
||||||
|
|||||||
@@ -25,4 +25,5 @@ jobs:
|
|||||||
patch_ref: "${{ github.base_ref }}" # this is the target branch name, Ex: "main"
|
patch_ref: "${{ github.base_ref }}" # this is the target branch name, Ex: "main"
|
||||||
patch_repo: "grafana/grafana-security-patches"
|
patch_repo: "grafana/grafana-security-patches"
|
||||||
patch_prefix: "${{ github.event.pull_request.number }}"
|
patch_prefix: "${{ github.event.pull_request.number }}"
|
||||||
|
sender: "${{ github.event.pull_request.user.login }}"
|
||||||
secrets: inherit # zizmor: ignore[secrets-inherit]
|
secrets: inherit # zizmor: ignore[secrets-inherit]
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
path: './pr'
|
path: './pr'
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: './pr/.nvmrc'
|
node-version-file: './pr/.nvmrc'
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
run: zip -r ./pr_built_packages.zip ./packages/**/*.tgz
|
run: zip -r ./pr_built_packages.zip ./packages/**/*.tgz
|
||||||
|
|
||||||
- name: Upload build output as artifact
|
- name: Upload build output as artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: buildPr
|
name: buildPr
|
||||||
path: './pr/pr_built_packages.zip'
|
path: './pr/pr_built_packages.zip'
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
ref: ${{ github.event.pull_request.base.ref }}
|
ref: ${{ github.event.pull_request.base.ref }}
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: './base/.nvmrc'
|
node-version-file: './base/.nvmrc'
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ jobs:
|
|||||||
run: zip -r ./base_built_packages.zip ./packages/**/*.tgz
|
run: zip -r ./base_built_packages.zip ./packages/**/*.tgz
|
||||||
|
|
||||||
- name: Upload build output as artifact
|
- name: Upload build output as artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: buildBase
|
name: buildBase
|
||||||
path: './base/base_built_packages.zip'
|
path: './base/base_built_packages.zip'
|
||||||
@@ -136,17 +136,17 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
- name: Get built packages from pr
|
- name: Get built packages from pr
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: buildPr
|
name: buildPr
|
||||||
|
|
||||||
- name: Get built packages from base
|
- name: Get built packages from base
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: buildBase
|
name: buildBase
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ jobs:
|
|||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
|
|
||||||
- name: Upload check output as artifact
|
- name: Upload check output as artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: levitate
|
name: levitate
|
||||||
path: levitate/
|
path: levitate/
|
||||||
@@ -225,7 +225,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: 'Download artifact'
|
- name: 'Download artifact'
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: levitate
|
name: levitate
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/feature-toggles-ci.yml
vendored
2
.github/workflows/feature-toggles-ci.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: 'go.mod'
|
go-version-file: 'go.mod'
|
||||||
cache: true
|
cache: true
|
||||||
|
|||||||
12
.github/workflows/frontend-lint.yml
vendored
12
.github/workflows/frontend-lint.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -109,7 +109,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -133,7 +133,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
@@ -164,7 +164,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
4
.github/workflows/go-lint.yml
vendored
4
.github/workflows/go-lint.yml
vendored
@@ -41,7 +41,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-go@v5.5.0
|
- uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: ./go.mod
|
go-version-file: ./go.mod
|
||||||
- name: Run gofmt
|
- name: Run gofmt
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-go@v5.5.0
|
- uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: ./go.mod
|
go-version-file: ./go.mod
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
|
|||||||
6
.github/workflows/issue-opened.yml
vendored
6
.github/workflows/issue-opened.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
|||||||
|
|
||||||
- name: "Get vault secrets"
|
- name: "Get vault secrets"
|
||||||
id: vault-secrets
|
id: vault-secrets
|
||||||
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses]
|
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.3.0 # zizmor: ignore[unpinned-uses]
|
||||||
with:
|
with:
|
||||||
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault
|
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_commands_github_bot path in Vault
|
||||||
repo_secrets: |
|
repo_secrets: |
|
||||||
@@ -71,7 +71,7 @@ jobs:
|
|||||||
|
|
||||||
- name: "Get vault secrets"
|
- name: "Get vault secrets"
|
||||||
id: vault-secrets
|
id: vault-secrets
|
||||||
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses]
|
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.3.0 # zizmor: ignore[unpinned-uses]
|
||||||
with:
|
with:
|
||||||
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
|
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
|
||||||
repo_secrets: |
|
repo_secrets: |
|
||||||
@@ -139,7 +139,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: "Get vault secrets"
|
- name: "Get vault secrets"
|
||||||
id: vault-secrets
|
id: vault-secrets
|
||||||
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.2.1 # zizmor: ignore[unpinned-uses]
|
uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets/v1.3.0 # zizmor: ignore[unpinned-uses]
|
||||||
with:
|
with:
|
||||||
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
|
# Secrets placed in the ci/repo/grafana/grafana/plugins_platform_issue_triager path in Vault
|
||||||
repo_secrets: |
|
repo_secrets: |
|
||||||
|
|||||||
2
.github/workflows/lint-build-docs.yml
vendored
2
.github/workflows/lint-build-docs.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v4
|
||||||
with:
|
with:
|
||||||
languages: "javascript"
|
languages: "javascript"
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3
|
uses: github/codeql-action/analyze@v4
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ jobs:
|
|||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
if: steps.check-python.outputs.skip != 'true'
|
if: steps.check-python.outputs.skip != 'true'
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v4
|
||||||
with:
|
with:
|
||||||
languages: "python"
|
languages: "python"
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
if: steps.check-python.outputs.skip != 'true'
|
if: steps.check-python.outputs.skip != 'true'
|
||||||
uses: github/codeql-action/analyze@v3
|
uses: github/codeql-action/analyze@v4
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set go version
|
- name: Set go version
|
||||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
|||||||
38
.github/workflows/pr-e2e-tests.yml
vendored
38
.github/workflows/pr-e2e-tests.yml
vendored
@@ -94,14 +94,14 @@ jobs:
|
|||||||
id: artifact
|
id: artifact
|
||||||
|
|
||||||
- name: Upload grafana.tar.gz
|
- name: Upload grafana.tar.gz
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
name: grafana-tar-gz
|
name: grafana-tar-gz
|
||||||
path: build-dir/grafana.tar.gz
|
path: build-dir/grafana.tar.gz
|
||||||
|
|
||||||
- name: Upload grafana docker tarball
|
- name: Upload grafana docker tarball
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
name: grafana-docker-tar-gz
|
name: grafana-docker-tar-gz
|
||||||
@@ -122,7 +122,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: ${{ !github.event.pull_request.head.repo.fork }}
|
cache: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
@@ -133,7 +133,7 @@ jobs:
|
|||||||
# We want a static binary, so we need to set CGO_ENABLED=0
|
# We want a static binary, so we need to set CGO_ENABLED=0
|
||||||
CGO_ENABLED=0 go build -o ./e2e-runner ./e2e/
|
CGO_ENABLED=0 go build -o ./e2e-runner ./e2e/
|
||||||
echo "artifact=e2e-runner-${{github.run_number}}" >> "$GITHUB_OUTPUT"
|
echo "artifact=e2e-runner-${{github.run_number}}" >> "$GITHUB_OUTPUT"
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v5
|
||||||
id: upload
|
id: upload
|
||||||
with:
|
with:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
@@ -159,7 +159,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
registry: 'us-docker.pkg.dev'
|
registry: 'us-docker.pkg.dev'
|
||||||
environment: 'dev'
|
environment: 'dev'
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
||||||
with:
|
with:
|
||||||
name: grafana-docker-tar-gz
|
name: grafana-docker-tar-gz
|
||||||
path: .
|
path: .
|
||||||
@@ -221,10 +221,10 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: grafana-tar-gz
|
name: grafana-tar-gz
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.build-e2e-runner.outputs.artifact }}
|
name: ${{ needs.build-e2e-runner.outputs.artifact }}
|
||||||
- name: chmod +x
|
- name: chmod +x
|
||||||
@@ -245,7 +245,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
echo "suite=$(echo "$SUITE" | sed 's/\//-/g')" >> "$GITHUB_OUTPUT"
|
echo "suite=$(echo "$SUITE" | sed 's/\//-/g')" >> "$GITHUB_OUTPUT"
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v5
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.set-suite-name.outputs.suite }}-${{ github.run_number }}
|
name: ${{ steps.set-suite-name.outputs.suite }}-${{ github.run_number }}
|
||||||
@@ -267,7 +267,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
@@ -298,7 +298,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: grafana-tar-gz
|
name: grafana-tar-gz
|
||||||
- name: Run E2E tests
|
- name: Run E2E tests
|
||||||
@@ -307,7 +307,7 @@ jobs:
|
|||||||
version: 0.18.8
|
version: 0.18.8
|
||||||
verb: run
|
verb: run
|
||||||
args: go run ./pkg/build/e2e-playwright --package=grafana.tar.gz --shard=${{ matrix.shard }}/${{ matrix.shardTotal }} --blob-dir=./blob-report
|
args: go run ./pkg/build/e2e-playwright --package=grafana.tar.gz --shard=${{ matrix.shard }}/${{ matrix.shardTotal }} --blob-dir=./blob-report
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v5
|
||||||
if: success() || failure()
|
if: success() || failure()
|
||||||
with:
|
with:
|
||||||
name: playwright-blob-${{ github.run_number }}-${{ matrix.shard }}
|
name: playwright-blob-${{ github.run_number }}-${{ matrix.shard }}
|
||||||
@@ -360,7 +360,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
docker cp cpp-e2e-deploy:/outputs.json /tmp/outputs.json
|
docker cp cpp-e2e-deploy:/outputs.json /tmp/outputs.json
|
||||||
|
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: grafana-tar-gz
|
name: grafana-tar-gz
|
||||||
|
|
||||||
@@ -395,12 +395,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
- name: Download blob reports from GitHub Actions Artifacts
|
- name: Download blob reports from GitHub Actions Artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
path: blobs
|
path: blobs
|
||||||
pattern: playwright-blob-*
|
pattern: playwright-blob-*
|
||||||
@@ -439,7 +439,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload HTML report
|
- name: Upload HTML report
|
||||||
id: upload-html
|
id: upload-html
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
name: playwright-html-${{ github.run_number }}
|
name: playwright-html-${{ github.run_number }}
|
||||||
path: playwright-report
|
path: playwright-report
|
||||||
@@ -479,7 +479,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: grafana-tar-gz
|
name: grafana-tar-gz
|
||||||
- name: Run PR a11y test
|
- name: Run PR a11y test
|
||||||
@@ -498,7 +498,7 @@ jobs:
|
|||||||
args: go run ./pkg/build/a11y --package=grafana.tar.gz --no-threshold-fail --results=./pa11y-ci-results.json
|
args: go run ./pkg/build/a11y --package=grafana.tar.gz --no-threshold-fail --results=./pa11y-ci-results.json
|
||||||
- name: Upload pa11y results
|
- name: Upload pa11y results
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v5
|
||||||
with:
|
with:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
name: pa11y-ci-results
|
name: pa11y-ci-results
|
||||||
@@ -525,13 +525,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install --immutable
|
run: yarn install --immutable
|
||||||
- name: Get pa11y results
|
- name: Get pa11y results
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: pa11y-ci-results
|
name: pa11y-ci-results
|
||||||
- name: Extract and publish metrics
|
- name: Extract and publish metrics
|
||||||
|
|||||||
24
.github/workflows/pr-frontend-unit-tests.yml
vendored
24
.github/workflows/pr-frontend-unit-tests.yml
vendored
@@ -18,6 +18,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
outputs:
|
outputs:
|
||||||
changed: ${{ steps.detect-changes.outputs.frontend }}
|
changed: ${{ steps.detect-changes.outputs.frontend }}
|
||||||
|
devenv-changed: ${{ steps.detect-changes.outputs.devenv }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
@@ -169,3 +170,26 @@ jobs:
|
|||||||
needs: ${{ toJson(needs) }}
|
needs: ${{ toJson(needs) }}
|
||||||
failure-message: "One or more unit test jobs have failed"
|
failure-message: "One or more unit test jobs have failed"
|
||||||
success-message: "All unit tests completed successfully"
|
success-message: "All unit tests completed successfully"
|
||||||
|
|
||||||
|
devenv:
|
||||||
|
needs:
|
||||||
|
- detect-changes
|
||||||
|
if: needs.detect-changes.outputs.devenv-changed == 'true'
|
||||||
|
runs-on: ubuntu-x64-large
|
||||||
|
name: "Devenv frontend-service build"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Setup Docker
|
||||||
|
uses: docker/setup-docker-action@3fb92d6d9c634363128c8cce4bc3b2826526370a # v4
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: ./.github/actions/setup-node
|
||||||
|
- name: Install Tilt
|
||||||
|
run: curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash
|
||||||
|
- name: Create empty config files # TODO: the tiltfile should conditionally mount these only if they exist, like the enterprise license
|
||||||
|
run: |
|
||||||
|
touch devenv/frontend-service/configs/grafana-api.local.ini
|
||||||
|
touch devenv/frontend-service/configs/frontend-service.local.ini
|
||||||
|
- name: Test frontend-service Tiltfile
|
||||||
|
run: tilt ci --file devenv/frontend-service/Tiltfile
|
||||||
|
|||||||
4
.github/workflows/pr-go-workspace-check.yml
vendored
4
.github/workflows/pr-go-workspace-check.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set go version
|
- name: Set go version
|
||||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
||||||
with:
|
with:
|
||||||
cache: false
|
cache: false
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set go version
|
- name: Set go version
|
||||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
||||||
with:
|
with:
|
||||||
cache: false
|
cache: false
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|||||||
2
.github/workflows/pr-k8s-codegen-check.yml
vendored
2
.github/workflows/pr-k8s-codegen-check.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Set go version
|
- name: Set go version
|
||||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/pr-test-docker.yml
vendored
4
.github/workflows/pr-test-docker.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
id: detect-changes
|
id: detect-changes
|
||||||
uses: ./.github/actions/change-detection
|
uses: ./.github/actions/change-detection
|
||||||
with:
|
with:
|
||||||
self: .github/workflows/pr-test-integration.yml
|
self: .github/workflows/pr-test-docker.yml
|
||||||
|
|
||||||
build-dockerfile:
|
build-dockerfile:
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
@@ -34,6 +34,6 @@ jobs:
|
|||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: docker/setup-docker-action@b60f85385d03ac8acfca6d9996982511d8620a19 # v4
|
- uses: docker/setup-docker-action@3fb92d6d9c634363128c8cce4bc3b2826526370a # v4
|
||||||
- name: Build Dockerfile
|
- name: Build Dockerfile
|
||||||
run: make build-docker-full
|
run: make build-docker-full
|
||||||
|
|||||||
77
.github/workflows/pr-test-integration.yml
vendored
77
.github/workflows/pr-test-integration.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
@@ -68,7 +68,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)"
|
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)"
|
||||||
go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
|
go test -tags=sqlite -timeout=12m -run '^TestIntegration' "${PACKAGES[@]}"
|
||||||
|
|
||||||
sqlite_nocgo:
|
sqlite_nocgo:
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
@@ -78,6 +78,7 @@ jobs:
|
|||||||
# We don't need more than this since it has to wait for the other tests.
|
# We don't need more than this since it has to wait for the other tests.
|
||||||
shard: [
|
shard: [
|
||||||
1/4, 2/4, 3/4, 4/4,
|
1/4, 2/4, 3/4, 4/4,
|
||||||
|
profiled,
|
||||||
]
|
]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
@@ -91,17 +92,79 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
if: matrix.shard != 'profiled'
|
||||||
env:
|
env:
|
||||||
SHARD: ${{ matrix.shard }}
|
SHARD: ${{ matrix.shard }}
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
SKIP_PACKAGES: |-
|
||||||
|
pkg/tests/apis/folder
|
||||||
|
pkg/tests/apis/dashboard
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)"
|
# Build regex pattern like: pkg1$|pkg2$|pkg3$
|
||||||
CGO_ENABLED=0 go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}"
|
SKIP_PATTERN=$(echo "$SKIP_PACKAGES" | sed '/^$/d' | sed 's|.*|&$|' | paste -sd '|' -)
|
||||||
|
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N "$SHARD" -d - | grep -Ev "($SKIP_PATTERN)")"
|
||||||
|
go test -tags=sqlite -timeout=12m -run '^TestIntegration' "${PACKAGES[@]}"
|
||||||
|
- name: Run profiled tests
|
||||||
|
id: run-profiled-tests
|
||||||
|
if: matrix.shard == 'profiled'
|
||||||
|
env:
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
PROFILED_PACKAGES: |-
|
||||||
|
pkg/tests/apis/folder
|
||||||
|
pkg/tests/apis/dashboard
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
# Build regex pattern line: pkg1$|pkg2$|pkg3$
|
||||||
|
PROFILE_PATTERN=$(echo "$PROFILED_PACKAGES" | sed '/^$/d' | sed 's|.*|&$|' | paste -sd '|' -)
|
||||||
|
readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | grep -E "($PROFILE_PATTERN)")"
|
||||||
|
if [ ${#PACKAGES[@]} -eq 0 ]; then
|
||||||
|
echo "⚠️ No profiled packages found"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
mkdir -p profiles
|
||||||
|
EXIT_CODE=0
|
||||||
|
# Run each profiled package sequentially
|
||||||
|
for full_pkg in "${PACKAGES[@]}"; do
|
||||||
|
# Build valid file name
|
||||||
|
pkg_name=$(basename "$full_pkg" | tr '/' '_' | tr '.' '_')
|
||||||
|
echo "📦 Running $full_pkg"
|
||||||
|
set +e
|
||||||
|
go test -tags=sqlite -timeout=12m -run '^TestIntegration' \
|
||||||
|
-outputdir=profiles \
|
||||||
|
-cpuprofile="cpu_${pkg_name}.prof" \
|
||||||
|
-memprofile="mem_${pkg_name}.prof" \
|
||||||
|
-trace="trace_${pkg_name}.out" \
|
||||||
|
"$full_pkg" 2>&1 | tee "profiles/test_${pkg_name}.log"
|
||||||
|
TEST_EXIT=$?
|
||||||
|
set -e
|
||||||
|
if [ $TEST_EXIT -ne 0 ]; then
|
||||||
|
echo "❌ $full_pkg failed with exit code $TEST_EXIT"
|
||||||
|
EXIT_CODE=1
|
||||||
|
else
|
||||||
|
echo "✅ $full_pkg passed"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Set output for artifact upload
|
||||||
|
if [ $EXIT_CODE -ne 0 ]; then
|
||||||
|
echo "upload_artifacts=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "upload_artifacts=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
exit $EXIT_CODE
|
||||||
|
- name: Output test profiles and traces
|
||||||
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v4
|
||||||
|
if: matrix.shard == 'profiled' && !cancelled() && steps.run-profiled-tests.outputs.upload_artifacts == 'true'
|
||||||
|
with:
|
||||||
|
name: integration-test-profiles-sqlite-nocgo-${{ github.run_number }}
|
||||||
|
path: profiles/
|
||||||
|
retention-days: 7
|
||||||
|
if-no-files-found: ignore
|
||||||
mysql:
|
mysql:
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
if: needs.detect-changes.outputs.changed == 'true'
|
if: needs.detect-changes.outputs.changed == 'true'
|
||||||
@@ -139,7 +202,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
@@ -188,7 +251,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
cache: true
|
cache: true
|
||||||
|
|||||||
2
.github/workflows/publish-artifact.yml
vendored
2
.github/workflows/publish-artifact.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
||||||
with:
|
with:
|
||||||
name: ${{ inputs.name }}
|
name: ${{ inputs.name }}
|
||||||
pattern: ${{ inputs.pattern }}
|
pattern: ${{ inputs.pattern }}
|
||||||
|
|||||||
2
.github/workflows/publish-kinds-next.yml
vendored
2
.github/workflows/publish-kinds-next.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: "Setup Go"
|
- name: "Setup Go"
|
||||||
uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
|
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00"
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/publish-kinds-release.yml
vendored
2
.github/workflows/publish-kinds-release.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: "Setup Go"
|
- name: "Setup Go"
|
||||||
uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
|
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00"
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
|||||||
26
.github/workflows/release-build.yml
vendored
26
.github/workflows/release-build.yml
vendored
@@ -156,16 +156,16 @@ jobs:
|
|||||||
artifacts: targz:grafana:linux/arm/v6,deb:grafana:linux/arm/v6
|
artifacts: targz:grafana:linux/arm/v6,deb:grafana:linux/arm/v6
|
||||||
verify: true
|
verify: true
|
||||||
- name: windows-amd64
|
- name: windows-amd64
|
||||||
artifacts: targz:grafana:windows/amd64,zip:grafana:windows/amd64,msi:grafana:windows/amd64
|
artifacts: targz:grafana:windows/amd64:nocgo,zip:grafana:windows/amd64:nocgo,msi:grafana:windows/amd64:nocgo
|
||||||
verify: true
|
verify: true
|
||||||
- name: windows-arm64
|
- name: windows-arm64
|
||||||
artifacts: targz:grafana:windows/arm64,zip:grafana:windows/arm64
|
artifacts: targz:grafana:windows/arm64:nocgo,zip:grafana:windows/arm64:nocgo
|
||||||
verify: true
|
verify: true
|
||||||
- name: darwin-amd64
|
- name: darwin-amd64
|
||||||
artifacts: targz:grafana:darwin/amd64
|
artifacts: targz:grafana:darwin/amd64:nocgo
|
||||||
verify: true
|
verify: true
|
||||||
- name: darwin-arm64
|
- name: darwin-arm64
|
||||||
artifacts: targz:grafana:darwin/arm64
|
artifacts: targz:grafana:darwin/arm64:nocgo
|
||||||
verify: true
|
verify: true
|
||||||
steps:
|
steps:
|
||||||
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
|
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
|
||||||
@@ -187,12 +187,12 @@ jobs:
|
|||||||
output: artifacts-${{ matrix.name }}.txt
|
output: artifacts-${{ matrix.name }}.txt
|
||||||
verify: ${{ matrix.verify }}
|
verify: ${{ matrix.verify }}
|
||||||
build-id: ${{ github.run_id }}
|
build-id: ${{ github.run_id }}
|
||||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
|
||||||
with:
|
with:
|
||||||
name: artifacts-list-${{ matrix.name }}
|
name: artifacts-list-${{ matrix.name }}
|
||||||
path: ${{ steps.build.outputs.file }}
|
path: ${{ steps.build.outputs.file }}
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
|
||||||
with:
|
with:
|
||||||
name: artifacts-${{ matrix.name }}
|
name: artifacts-${{ matrix.name }}
|
||||||
path: ${{ steps.build.outputs.dist-dir }}
|
path: ${{ steps.build.outputs.dist-dir }}
|
||||||
@@ -224,27 +224,27 @@ jobs:
|
|||||||
- build
|
- build
|
||||||
steps:
|
steps:
|
||||||
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
|
- uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
||||||
with:
|
with:
|
||||||
name: artifacts-list-linux-amd64
|
name: artifacts-list-linux-amd64
|
||||||
path: .
|
path: .
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
||||||
with:
|
with:
|
||||||
name: artifacts-list-linux-arm64
|
name: artifacts-list-linux-arm64
|
||||||
path: .
|
path: .
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
||||||
with:
|
with:
|
||||||
name: artifacts-list-linux-armv7
|
name: artifacts-list-linux-armv7
|
||||||
path: .
|
path: .
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
||||||
with:
|
with:
|
||||||
name: artifacts-linux-amd64
|
name: artifacts-linux-amd64
|
||||||
path: dist
|
path: dist
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
||||||
with:
|
with:
|
||||||
name: artifacts-linux-arm64
|
name: artifacts-linux-arm64
|
||||||
path: dist
|
path: dist
|
||||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
|
||||||
with:
|
with:
|
||||||
name: artifacts-linux-armv7
|
name: artifacts-linux-armv7
|
||||||
path: dist
|
path: dist
|
||||||
@@ -333,7 +333,7 @@ jobs:
|
|||||||
body-includes: GitHub Actions Build
|
body-includes: GitHub Actions Build
|
||||||
token: ${{ steps.generate_token.outputs.token }}
|
token: ${{ steps.generate_token.outputs.token }}
|
||||||
- name: Create or update comment
|
- name: Create or update comment
|
||||||
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
|
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v4
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.generate_token.outputs.token }}
|
token: ${{ steps.generate_token.outputs.token }}
|
||||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||||
|
|||||||
9
.github/workflows/release-npm.yml
vendored
9
.github/workflows/release-npm.yml
vendored
@@ -60,7 +60,7 @@ jobs:
|
|||||||
echo "github.ref: $GITHUB_REF"
|
echo "github.ref: $GITHUB_REF"
|
||||||
|
|
||||||
- name: Checkout workflow ref
|
- name: Checkout workflow ref
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-depth: 100
|
fetch-depth: 100
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Checkout build commit
|
- name: Checkout build commit
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
ref: ${{ inputs.grafana_commit }}
|
ref: ${{ inputs.grafana_commit }}
|
||||||
@@ -123,11 +123,6 @@ jobs:
|
|||||||
- name: Validate packages
|
- name: Validate packages
|
||||||
run: ./scripts/validate-npm-packages.sh
|
run: ./scripts/validate-npm-packages.sh
|
||||||
|
|
||||||
- name: Debug OIDC Claims
|
|
||||||
uses: github/actions-oidc-debugger@2e9ba5d3f4bebaad1f91a2cede055115738b7ae8
|
|
||||||
with:
|
|
||||||
audience: '${{ github.server_url }}/${{ github.repository_owner }}'
|
|
||||||
|
|
||||||
- name: Publish packages
|
- name: Publish packages
|
||||||
env:
|
env:
|
||||||
NPM_TAG: ${{ steps.npm-tag.outputs.NPM_TAG }}
|
NPM_TAG: ${{ steps.npm-tag.outputs.NPM_TAG }}
|
||||||
|
|||||||
4
.github/workflows/release-pr.yml
vendored
4
.github/workflows/release-pr.yml
vendored
@@ -133,10 +133,10 @@ jobs:
|
|||||||
path: .grafana-main
|
path: .grafana-main
|
||||||
|
|
||||||
- name: Setup nodejs environment
|
- name: Setup nodejs environment
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: .nvmrc
|
node-version-file: .nvmrc
|
||||||
- uses: actions/setup-go@v5.5.0
|
- uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
- name: Configure git user
|
- name: Configure git user
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Pin Go version to mod file
|
- name: Pin Go version to mod file
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: 'go.mod'
|
go-version-file: 'go.mod'
|
||||||
cache: true
|
cache: true
|
||||||
- run: go version
|
- run: go version
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
4
.github/workflows/run-schema-v2-e2e.yml
vendored
4
.github/workflows/run-schema-v2-e2e.yml
vendored
@@ -22,11 +22,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Pin Go version to mod file
|
- name: Pin Go version to mod file
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: 'go.mod'
|
go-version-file: 'go.mod'
|
||||||
- run: go version
|
- run: go version
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
|
|||||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v9
|
- uses: actions/stale@v10
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
operations-per-run: 750
|
operations-per-run: 750
|
||||||
|
|||||||
8
.github/workflows/storybook-a11y.yml
vendored
8
.github/workflows/storybook-a11y.yml
vendored
@@ -34,12 +34,12 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
if: needs.detect-changes.outputs.changed == 'true'
|
if: needs.detect-changes.outputs.changed == 'true'
|
||||||
name: "Run Storybook a11y tests"
|
name: "Run Storybook a11y tests (light theme)"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v5
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
package-manager-cache: false # too large for GH's cache limits :-(
|
package-manager-cache: false # too large for GH's cache limits :-(
|
||||||
@@ -64,12 +64,12 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
if: needs.detect-changes.outputs.changed == 'true'
|
if: needs.detect-changes.outputs.changed == 'true'
|
||||||
name: "Run Storybook a11y tests"
|
name: "Run Storybook a11y tests (dark theme)"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-node@v5
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
package-manager-cache: false # too large for GH's cache limits :-(
|
package-manager-cache: false # too large for GH's cache limits :-(
|
||||||
|
|||||||
2
.github/workflows/swagger-gen.yml
vendored
2
.github/workflows/swagger-gen.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5.5.0
|
uses: actions/setup-go@v6.0.0
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
- name: Setup Enterprise
|
- name: Setup Enterprise
|
||||||
|
|||||||
4
.github/workflows/trivy-scan.yml
vendored
4
.github/workflows/trivy-scan.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install Trivy
|
- name: Install Trivy
|
||||||
uses: aquasecurity/setup-trivy@9ea583eb67910444b1f64abf338bd2e105a0a93d
|
uses: aquasecurity/setup-trivy@e6c2c5e321ed9123bda567646e2f96565e34abe1
|
||||||
with:
|
with:
|
||||||
version: v0.56.2
|
version: v0.56.2
|
||||||
cache: true
|
cache: true
|
||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
.
|
.
|
||||||
if: always() && github.repository == 'grafana/grafana'
|
if: always() && github.repository == 'grafana/grafana'
|
||||||
- name: Upload Trivy scan results to GitHub Security tab
|
- name: Upload Trivy scan results to GitHub Security tab
|
||||||
uses: github/codeql-action/upload-sarif@v3
|
uses: github/codeql-action/upload-sarif@v4
|
||||||
with:
|
with:
|
||||||
sarif_file: 'trivy-results.sarif'
|
sarif_file: 'trivy-results.sarif'
|
||||||
if: always() && github.repository == 'grafana/grafana'
|
if: always() && github.repository == 'grafana/grafana'
|
||||||
|
|||||||
2
.github/workflows/trufflehog.yml
vendored
2
.github/workflows/trufflehog.yml
vendored
@@ -31,6 +31,6 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-depth: ${{ steps.fetch_depth.outputs.fetch_depth }}
|
fetch-depth: ${{ steps.fetch_depth.outputs.fetch_depth }}
|
||||||
- name: Trufflehog
|
- name: Trufflehog
|
||||||
uses: trufflesecurity/trufflehog@e88e7d019eb84ca64f6b768c82eb6bf1a6271401 # v3.90.9
|
uses: trufflesecurity/trufflehog@b84c3d14d189e16da175e2c27fa8136603783ffc # v3.90.12
|
||||||
with:
|
with:
|
||||||
extra_args: --results=verified
|
extra_args: --results=verified
|
||||||
|
|||||||
2
.github/workflows/update-schema-types.yml
vendored
2
.github/workflows/update-schema-types.yml
vendored
@@ -17,6 +17,6 @@ jobs:
|
|||||||
bundle-schema-types:
|
bundle-schema-types:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- uses: grafana/plugin-actions/bundle-schema-types@main
|
- uses: grafana/plugin-actions/bundle-schema-types@main
|
||||||
|
|||||||
2
.github/workflows/verify-kinds.yml
vendored
2
.github/workflows/verify-kinds.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: "Setup Go"
|
- name: "Setup Go"
|
||||||
uses: "actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5"
|
uses: "actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00"
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -250,9 +250,12 @@ public/mockServiceWorker.js
|
|||||||
/e2e-playwright/test-plugins/*/dist
|
/e2e-playwright/test-plugins/*/dist
|
||||||
/apps/provisioning/cmd/job-controller/bin/
|
/apps/provisioning/cmd/job-controller/bin/
|
||||||
|
|
||||||
|
|
||||||
# Ignore unified storage kv store files
|
# Ignore unified storage kv store files
|
||||||
/grafana-kv-data
|
/grafana-kv-data
|
||||||
|
|
||||||
|
# Ignore debug output from test library
|
||||||
|
/pkg/storage/secret/metadata/testdata/rapid/TestStateMachine/
|
||||||
|
|
||||||
/codeowners-manifest/
|
/codeowners-manifest/
|
||||||
|
|
||||||
# Ignore grafana/hippocampus local cache folder
|
# Ignore grafana/hippocampus local cache folder
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ linters:
|
|||||||
deny:
|
deny:
|
||||||
- pkg: github.com/grafana/grafana/pkg
|
- pkg: github.com/grafana/grafana/pkg
|
||||||
desc: apps/playlist is not allowed to import grafana core
|
desc: apps/playlist is not allowed to import grafana core
|
||||||
apps-secret:
|
apps-secret:
|
||||||
list-mode: lax
|
list-mode: lax
|
||||||
files:
|
files:
|
||||||
- ./apps/secret/*
|
- ./apps/secret/*
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -25,6 +25,6 @@ plugins:
|
|||||||
path: .yarn/plugins/@yarnpkg/plugin-licenses.cjs
|
path: .yarn/plugins/@yarnpkg/plugin-licenses.cjs
|
||||||
spec: "https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.15.0/bundles/@yarnpkg/plugin-licenses.js"
|
spec: "https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.15.0/bundles/@yarnpkg/plugin-licenses.js"
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-4.9.4.cjs
|
yarnPath: .yarn/releases/yarn-4.10.3.cjs
|
||||||
|
|
||||||
enableScripts: false
|
enableScripts: false
|
||||||
|
|||||||
89
CHANGELOG.md
89
CHANGELOG.md
@@ -1,3 +1,92 @@
|
|||||||
|
<!-- 12.2.1 START -->
|
||||||
|
|
||||||
|
# 12.2.1 (2025-10-21)
|
||||||
|
|
||||||
|
### Features and enhancements
|
||||||
|
|
||||||
|
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112156](https://github.com/grafana/grafana/pull/112156), [@macabu](https://github.com/macabu)
|
||||||
|
- **Go:** Update to 1.25.3 [#112361](https://github.com/grafana/grafana/pull/112361), [@macabu](https://github.com/macabu)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
- **Auth:** Fix render user OAuth passthrough [#112092](https://github.com/grafana/grafana/pull/112092), [@mgyongyosi](https://github.com/mgyongyosi)
|
||||||
|
- **Dashboards:** Fix missing Ctrl+O keyboard shortcut for crosshair toggle [#111402](https://github.com/grafana/grafana/pull/111402), [@ivanortegaalba](https://github.com/ivanortegaalba)
|
||||||
|
- **Fix:** Fix redirection after login when Grafana is served from subpath [#111069](https://github.com/grafana/grafana/pull/111069), [@mgyongyosi](https://github.com/mgyongyosi)
|
||||||
|
- **FlameGraph:** Ensure total is only counted once for recursive function calls [#111606](https://github.com/grafana/grafana/pull/111606), [@simonswine](https://github.com/simonswine)
|
||||||
|
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111849](https://github.com/grafana/grafana/pull/111849), [@bradleypettit](https://github.com/bradleypettit)
|
||||||
|
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111769](https://github.com/grafana/grafana/pull/111769), [@wbrowne](https://github.com/wbrowne)
|
||||||
|
- **Table:** Backport the Safari 26 fixes to 12.2.1 [#111906](https://github.com/grafana/grafana/pull/111906), [@fastfrwrd](https://github.com/fastfrwrd)
|
||||||
|
|
||||||
|
<!-- 12.2.1 END -->
|
||||||
|
<!-- 12.1.3 START -->
|
||||||
|
|
||||||
|
# 12.1.3 (2025-10-21)
|
||||||
|
|
||||||
|
### Features and enhancements
|
||||||
|
|
||||||
|
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112159](https://github.com/grafana/grafana/pull/112159), [@macabu](https://github.com/macabu)
|
||||||
|
- **Go:** Update to 1.25.3 [#112362](https://github.com/grafana/grafana/pull/112362), [@macabu](https://github.com/macabu)
|
||||||
|
- **Table:** Avoid thrown error due to internal React issue [#111945](https://github.com/grafana/grafana/pull/111945), [@fastfrwrd](https://github.com/fastfrwrd)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
- **Auth:** Fix render user OAuth passthrough [#112097](https://github.com/grafana/grafana/pull/112097), [@mgyongyosi](https://github.com/mgyongyosi)
|
||||||
|
- **FlameGraph:** Ensure total is only counted once for recursive function calls [#111605](https://github.com/grafana/grafana/pull/111605), [@simonswine](https://github.com/simonswine)
|
||||||
|
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111848](https://github.com/grafana/grafana/pull/111848), [@bradleypettit](https://github.com/bradleypettit)
|
||||||
|
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111767](https://github.com/grafana/grafana/pull/111767), [@wbrowne](https://github.com/wbrowne)
|
||||||
|
|
||||||
|
<!-- 12.1.3 END -->
|
||||||
|
<!-- 12.0.6 START -->
|
||||||
|
|
||||||
|
# 12.0.6 (2025-10-21)
|
||||||
|
|
||||||
|
### Features and enhancements
|
||||||
|
|
||||||
|
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112161](https://github.com/grafana/grafana/pull/112161), [@macabu](https://github.com/macabu)
|
||||||
|
- **Go:** Update to 1.25.3 [#112364](https://github.com/grafana/grafana/pull/112364), [@macabu](https://github.com/macabu)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
- **Auth:** Fix render user OAuth passthrough [#112096](https://github.com/grafana/grafana/pull/112096), [@mgyongyosi](https://github.com/mgyongyosi)
|
||||||
|
- **FlameGraph:** Ensure total is only counted once for recursive function calls [#111604](https://github.com/grafana/grafana/pull/111604), [@simonswine](https://github.com/simonswine)
|
||||||
|
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111847](https://github.com/grafana/grafana/pull/111847), [@bradleypettit](https://github.com/bradleypettit)
|
||||||
|
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111766](https://github.com/grafana/grafana/pull/111766), [@wbrowne](https://github.com/wbrowne)
|
||||||
|
|
||||||
|
<!-- 12.0.6 END -->
|
||||||
|
<!-- 11.6.7 START -->
|
||||||
|
|
||||||
|
# 11.6.7 (2025-10-21)
|
||||||
|
|
||||||
|
### Features and enhancements
|
||||||
|
|
||||||
|
- **Analytics:** Apply proper batching to Loki exports and add configurable settings (Enterprise)
|
||||||
|
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112162](https://github.com/grafana/grafana/pull/112162), [@grambbledook](https://github.com/grambbledook)
|
||||||
|
- **Go:** Update to 1.25.3 [#112365](https://github.com/grafana/grafana/pull/112365), [@macabu](https://github.com/macabu)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
- **Auth:** Fix render user OAuth passthrough [#112094](https://github.com/grafana/grafana/pull/112094), [@mgyongyosi](https://github.com/mgyongyosi)
|
||||||
|
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111846](https://github.com/grafana/grafana/pull/111846), [@bradleypettit](https://github.com/bradleypettit)
|
||||||
|
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111801](https://github.com/grafana/grafana/pull/111801), [@wbrowne](https://github.com/wbrowne)
|
||||||
|
- **URLParams:** Stringify true values as key=true always (fixes issues with variables with true value) [#112045](https://github.com/grafana/grafana/pull/112045), [@torkelo](https://github.com/torkelo)
|
||||||
|
|
||||||
|
<!-- 11.6.7 END -->
|
||||||
|
<!-- 11.5.10 START -->
|
||||||
|
|
||||||
|
# 11.5.10 (2025-10-21)
|
||||||
|
|
||||||
|
### Features and enhancements
|
||||||
|
|
||||||
|
- **Go:** Update to 1.25.2 + golangci-lint v2.5.0 + golang.org/x/net v0.45.0 [#112163](https://github.com/grafana/grafana/pull/112163), [@macabu](https://github.com/macabu)
|
||||||
|
- **Go:** Update to 1.25.3 [#112366](https://github.com/grafana/grafana/pull/112366), [@macabu](https://github.com/macabu)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
- **Auth:** Fix render user OAuth passthrough [#112093](https://github.com/grafana/grafana/pull/112093), [@mgyongyosi](https://github.com/mgyongyosi)
|
||||||
|
- **LDAP Authentication:** Fix URL to propagate username context as parameter [#111845](https://github.com/grafana/grafana/pull/111845), [@bradleypettit](https://github.com/bradleypettit)
|
||||||
|
- **Plugins:** Dependencies do not inherit parent URL for preinstall [#111802](https://github.com/grafana/grafana/pull/111802), [@wbrowne](https://github.com/wbrowne)
|
||||||
|
|
||||||
|
<!-- 11.5.10 END -->
|
||||||
<!-- 12.2.0 START -->
|
<!-- 12.2.0 START -->
|
||||||
|
|
||||||
# 12.2.0 (2025-09-23)
|
# 12.2.0 (2025-09-23)
|
||||||
|
|||||||
@@ -2,51 +2,84 @@
|
|||||||
|
|
||||||
Thank you for your interest in contributing to Grafana! We welcome all people who want to contribute in a healthy and constructive manner within our community. To help us create a safe and positive community experience for all, we require all participants to adhere to the [Code of Conduct](CODE_OF_CONDUCT.md).
|
Thank you for your interest in contributing to Grafana! We welcome all people who want to contribute in a healthy and constructive manner within our community. To help us create a safe and positive community experience for all, we require all participants to adhere to the [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||||
|
|
||||||
This document is a guide to help you through the process of contributing to Grafana. Be sure to check out the [Grafana Champions program](https://grafana.com/community/champions/?src=github&camp=community-cross-platform-engagement) as you start to contribute- it’s designed to recognize and empower individuals who are actively contributing to the growth and success of the Grafana ecosystem.
|
This document is a guide to help you through the process of contributing to Grafana. Be sure to check out the [Grafana Champions program](https://grafana.com/community/champions/?src=github&camp=community-cross-platform-engagement) as you start to contribute. It's designed to recognize and empower individuals who are actively contributing to the growth and success of the Grafana ecosystem.
|
||||||
|
|
||||||
Whether you're a new contributer or a seasoned veteran we hope these resources help you connect with the community:
|
> **Help us improve!** We'd love to hear about your contributor experience. Take a moment to share your feedback in our [Open Source Contributor Experience Survey](https://gra.fan/ome). Your input helps us make contributing to Grafana better for everyone.
|
||||||
|
|
||||||
Interact and be heard:
|
Whether you're a new contributor or a seasoned veteran, we hope these resources help you connect with the community.
|
||||||
|
|
||||||
- Forums: Do you have a problem, question, or curiosity? Visit our [forums](https://gra.fan/fromgithubtoforums) for a reservoir of knowledge- submit your own questions and answers!
|
#### Interact and be heard
|
||||||
- Meetups: Craving in-person connections without the long journeys? [Join your local Grafana & Friends meetup group](https://gra.fan/githubtomeetup)!
|
|
||||||
- Community Slack: Eager for real-time connections with fellow users? Begin a conversation on [Slack](https://gra.fan/githubtoslack).
|
- **Forums:** Do you have a problem, question, or curiosity? Visit our [forums](https://gra.fan/fromgithubtoforums) for a reservoir of knowledge, submit your own questions and answers!
|
||||||
Learn:
|
- **Meetups:** Craving in-person connections without the long journeys? [Join your local Grafana & Friends meetup group](https://gra.fan/githubtomeetup)!
|
||||||
- YouTube: From getting started to exploring newer projects like Pyroscope and Beyla, the [Grafana YouTube channel](https://gra.fan/githubtoyoutube) has what you need to get started!
|
- **Community Slack:** Eager for real-time connections with fellow users? Begin a conversation on [Slack](https://gra.fan/githubtoslack).
|
||||||
- Meetups: Join a [group near you](https://gra.fan/githubtomeetup) to learn from local experts and ask questions in real time.
|
|
||||||
Share your story:
|
#### Learn
|
||||||
- Meetups and blogs: We’d love to feature your OSS Grafana Labs use case or story at an upcoming Grafana & Friends meetup or on the Grafana blog! Submit your idea [here](https://gra.fan/githubtocca) and we’ll connect with you on next steps if accepted.
|
|
||||||
|
- **YouTube:** From getting started to exploring newer projects like Pyroscope and Beyla, the [Grafana YouTube channel](https://gra.fan/githubtoyoutube) has what you need to get started!
|
||||||
|
- **Meetups:** Join a [group near you](https://gra.fan/githubtomeetup) to learn from local experts and ask questions in real time.
|
||||||
|
|
||||||
|
#### Make technical contributions
|
||||||
|
|
||||||
|
- You can make technical contributions with or without code. Scroll down to see how!
|
||||||
|
|
||||||
|
#### Share your story
|
||||||
|
|
||||||
|
- **Meetups and blogs:** We’d love to feature your OSS Grafana Labs use case or story at an upcoming Grafana & Friends meetup or on the Grafana blog! Submit your idea [here](https://gra.fan/githubtocca), and we’ll connect with you on next steps if accepted.
|
||||||
|
|
||||||
|
## Choose the right channel
|
||||||
|
|
||||||
|
Use the right place to ask questions, report problems, and propose changes.
|
||||||
|
|
||||||
|
- **[GitHub issues](https://github.com/grafana/grafana/issues) and [pull requests](https://github.com/grafana/grafana/pulls)**: Use for reproducible bugs in core Grafana and maintained plugins, small and actionable feature requests, and code or docs changes via pull requests. Avoid general “how do I” questions. For security issues, follow the [security policy](https://github.com/grafana/grafana/security/policy).
|
||||||
|
- **Grafana community forums**: Use for questions, troubleshooting, best practices, plugin development Q&A, and early idea discussion. Forums create a searchable public knowledge base that helps others with the same problems and questions. Start here if you are unsure: [Grafana community forums](https://community.grafana.com/).
|
||||||
|
- **Grafana Community Slack**: Use for quick, time-sensitive chats and networking. Do not rely on Slack for complex troubleshooting or decisions. Share outcomes back to a forum topic or GitHub issue/PR to keep a public record: [Grafana Community Slack](https://slack.grafana.com).
|
||||||
|
- **Not sure where to start?** Start with a forum topic. Maintainers and community members will redirect you if a GitHub issue or pull request is more appropriate.
|
||||||
|
|
||||||
## Make technical contributions
|
## Make technical contributions
|
||||||
|
|
||||||
We welcome your technical contributions! Here are some examples:
|
We welcome your technical contributions! You can contribute in several ways:
|
||||||
|
|
||||||
- Contribute to the Grafana codebase- check out these [help-wanted issues](<(https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)>)
|
### Contribute Code to Grafana
|
||||||
- Develop community [plugins](https://grafana.com/developers/plugin-tools)
|
|
||||||
- Report [bugs](https://github.com/grafana/grafana/issues/new?template=0-bug-report.yaml)
|
|
||||||
- [Triage issues](https://github.com/grafana/grafana/blob/4414b92e93440cc9ed0f281989ee71dc16216a15/contribute/triage-issues.md)
|
|
||||||
- Report [security vulnerabilities](https://github.com/grafana/grafana/security/policy)
|
|
||||||
- Submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md)
|
|
||||||
- Write [technical documentation](https://github.com/grafana/grafana/blob/4414b92e93440cc9ed0f281989ee71dc16216a15/contribute/documentation/README.md)
|
|
||||||
|
|
||||||
**Please note:** We do not currently accept contributions for translations. Please do not submit pull requests translating grafana.json files - they will be rejected. We do accept contributions to mark up phrases for translation. See [Internationalization](contribute/internationalization.md).
|
**What you will need:**
|
||||||
|
|
||||||
### Your first contribution
|
- Follow our [developer guide](contribute/developer-guide.md) to set up your environment.
|
||||||
|
- Adhere to our [frontend](contribute/style-guides/frontend.md) and [backend](contribute/backend/style-guide.md) style guides.
|
||||||
|
- Write or update tests ([testing guide](contribute/style-guides/testing.md)).
|
||||||
|
|
||||||
Unsure where to begin contributing to Grafana? Start by browsing issues labeled `beginner friendly` or `help wanted`.
|
**Step-by-step:**
|
||||||
|
|
||||||
- [Beginner-friendly](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22) issues are generally straightforward to complete.
|
1. Browse all [issues](https://github.com/grafana/grafana/issues) to find something to work on. You can also filter by [help wanted](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22).
|
||||||
- [Help wanted](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) issues are problems we would like the community to help us with regardless of complexity.
|
1. Prepare a clear, descriptive pull request ([how-to guide](contribute/create-pull-request.md)).
|
||||||
|
1. Ensure you include and run the appropriate tests as part of your pull request.
|
||||||
|
1. Commit and push your changes. If you encounter merge conflicts, you may rebase your branch onto the main branch.
|
||||||
|
|
||||||
If you're looking to make a code change, see how to set up your environment for [local development](contribute/developer-guide.md).
|
### Develop a Plugin
|
||||||
|
|
||||||
When you're ready to contribute, it's time to [create a pull request](/contribute/create-pull-request.md).
|
Grafana plugins let you extend the platform with new data sources, panels, and more. This is a great way to share your ideas and make a real impact on the Grafana ecosystem.
|
||||||
|
|
||||||
### Develop a plugin
|
**Step-by-step:**
|
||||||
|
|
||||||
Developing a Grafana plugin is a fantastic way to share your unique ideas with the community, extend the platform’s capabilities, and make a real impact on how people visualize and understand their data. Check out our guide to creating [plugins](https://grafana.com/developers/plugin-tools)
|
1. Read the [plugin development guide](https://grafana.com/developers/plugin-tools) to choose your plugin type and set up your environment.
|
||||||
|
2. Scaffold your plugin using the recommended tools.
|
||||||
|
3. Develop and test your plugin locally.
|
||||||
|
4. Follow best practices for code style, testing, and documentation.
|
||||||
|
5. Publish your plugin or submit it for review as described in the guide.
|
||||||
|
|
||||||
### Report bugs
|
### Contribute without code
|
||||||
|
|
||||||
|
You can help even if you don't write code:
|
||||||
|
|
||||||
|
- Report a bug with the [bug report template](https://github.com/grafana/grafana/issues/new?template=0-bug-report.yaml) and include steps to reproduce.
|
||||||
|
- Submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md) to propose improvements.
|
||||||
|
- Improve our docs with the [documentation contribution guide](https://github.com/grafana/grafana/blob/main/contribute/documentation).
|
||||||
|
- Help with [issue triage](https://github.com/grafana/grafana/blob/main/contribute/triage-issues.md) by reviewing, labeling, and clarifying open issues.
|
||||||
|
- Report security vulnerabilities following our [security policy](https://github.com/grafana/grafana/security/policy).
|
||||||
|
|
||||||
|
**Please note:** We do not currently accept contributions for translations. Please do not submit pull requests translating `grafana.json` files - they will be rejected. We do accept contributions to mark up phrases for translation. See [Internationalization](contribute/internationalization.md).
|
||||||
|
|
||||||
|
#### Reporting issues
|
||||||
|
|
||||||
Before submitting a new issue, try to make sure someone hasn't already reported the problem. Look through the [existing issues](https://github.com/grafana/grafana/issues) for similar issues.
|
Before submitting a new issue, try to make sure someone hasn't already reported the problem. Look through the [existing issues](https://github.com/grafana/grafana/issues) for similar issues.
|
||||||
|
|
||||||
@@ -59,11 +92,11 @@ For data visualization issues:
|
|||||||
- Query results from the inspect drawer (data tab & query inspector)
|
- Query results from the inspect drawer (data tab & query inspector)
|
||||||
- Panel settings can be extracted in the panel inspect drawer JSON tab
|
- Panel settings can be extracted in the panel inspect drawer JSON tab
|
||||||
|
|
||||||
For a dashboard related issues:
|
For dashboard related issues:
|
||||||
|
|
||||||
- Dashboard JSON can be found in the dashboard settings JSON model view
|
- Dashboard JSON can be found in the dashboard settings JSON model view. You can [send the panel JSON model](https://grafana.com/docs/grafana/latest/troubleshooting/send-panel-to-grafana-support/) to Grafana Labs Technical Support and request help with troubleshooting your issue.
|
||||||
|
|
||||||
For authentication and alerting Grafana server logs are useful.
|
For authentication and alerting, Grafana server logs are useful.
|
||||||
|
|
||||||
### Triage issues
|
### Triage issues
|
||||||
|
|
||||||
@@ -75,7 +108,7 @@ Read more about the ways you can [Triage issues](/contribute/triage-issues.md).
|
|||||||
|
|
||||||
If you believe you've found a security vulnerability, please read our [security policy](https://github.com/grafana/grafana/security/policy) for more details on reporting.
|
If you believe you've found a security vulnerability, please read our [security policy](https://github.com/grafana/grafana/security/policy) for more details on reporting.
|
||||||
|
|
||||||
### Suggest enhancements
|
### Suggest features
|
||||||
|
|
||||||
If you have an idea of how to improve Grafana, submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md).
|
If you have an idea of how to improve Grafana, submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md).
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ ARG JS_SRC=js-builder
|
|||||||
FROM alpine:3.22.2 AS alpine-base
|
FROM alpine:3.22.2 AS alpine-base
|
||||||
FROM ubuntu:22.04 AS ubuntu-base
|
FROM ubuntu:22.04 AS ubuntu-base
|
||||||
FROM golang:1.25.3-alpine AS go-builder-base
|
FROM golang:1.25.3-alpine AS go-builder-base
|
||||||
FROM --platform=${JS_PLATFORM} node:22-alpine AS js-builder-base
|
FROM --platform=${JS_PLATFORM} node:24-alpine AS js-builder-base
|
||||||
# Javascript build stage
|
# Javascript build stage
|
||||||
FROM --platform=${JS_PLATFORM} ${JS_IMAGE} AS js-builder
|
FROM --platform=${JS_PLATFORM} ${JS_IMAGE} AS js-builder
|
||||||
ARG JS_NODE_ENV=production
|
ARG JS_NODE_ENV=production
|
||||||
@@ -95,12 +95,14 @@ COPY pkg/aggregator pkg/aggregator
|
|||||||
COPY apps/playlist apps/playlist
|
COPY apps/playlist apps/playlist
|
||||||
COPY apps/plugins apps/plugins
|
COPY apps/plugins apps/plugins
|
||||||
COPY apps/shorturl apps/shorturl
|
COPY apps/shorturl apps/shorturl
|
||||||
|
COPY apps/annotation apps/annotation
|
||||||
COPY apps/correlations apps/correlations
|
COPY apps/correlations apps/correlations
|
||||||
COPY apps/preferences apps/preferences
|
COPY apps/preferences apps/preferences
|
||||||
COPY apps/provisioning apps/provisioning
|
COPY apps/provisioning apps/provisioning
|
||||||
COPY apps/secret apps/secret
|
COPY apps/secret apps/secret
|
||||||
COPY apps/scope apps/scope
|
COPY apps/scope apps/scope
|
||||||
COPY apps/investigations apps/investigations
|
COPY apps/investigations apps/investigations
|
||||||
|
COPY apps/logsdrilldown apps/logsdrilldown
|
||||||
COPY apps/advisor apps/advisor
|
COPY apps/advisor apps/advisor
|
||||||
COPY apps/dashboard apps/dashboard
|
COPY apps/dashboard apps/dashboard
|
||||||
COPY apps/folder apps/folder
|
COPY apps/folder apps/folder
|
||||||
@@ -113,6 +115,7 @@ COPY apps/alerting/notifications apps/alerting/notifications
|
|||||||
COPY apps/alerting/rules apps/alerting/rules
|
COPY apps/alerting/rules apps/alerting/rules
|
||||||
COPY pkg/codegen pkg/codegen
|
COPY pkg/codegen pkg/codegen
|
||||||
COPY pkg/plugins/codegen pkg/plugins/codegen
|
COPY pkg/plugins/codegen pkg/plugins/codegen
|
||||||
|
COPY apps/example apps/example
|
||||||
|
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
|
|||||||
8
Makefile
8
Makefile
@@ -135,14 +135,14 @@ i18n-extract-enterprise:
|
|||||||
@echo "Skipping i18n extract for Enterprise: not enabled"
|
@echo "Skipping i18n extract for Enterprise: not enabled"
|
||||||
else
|
else
|
||||||
i18n-extract-enterprise:
|
i18n-extract-enterprise:
|
||||||
@echo "Extracting i18n strings for Enterprise"
|
@echo "Extracting i18n strings for Enterprise"
|
||||||
yarn run i18next --config public/locales/i18next-parser-enterprise.config.cjs
|
cd public/locales/enterprise && yarn run i18next-cli extract --sync-primary
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: i18n-extract
|
.PHONY: i18n-extract
|
||||||
i18n-extract: i18n-extract-enterprise
|
i18n-extract: i18n-extract-enterprise
|
||||||
@echo "Extracting i18n strings for OSS"
|
@echo "Extracting i18n strings for OSS"
|
||||||
yarn run i18next --config public/locales/i18next-parser.config.cjs
|
yarn run i18next-cli extract --sync-primary
|
||||||
@echo "Extracting i18n strings for packages"
|
@echo "Extracting i18n strings for packages"
|
||||||
yarn run packages:i18n-extract
|
yarn run packages:i18n-extract
|
||||||
@echo "Extracting i18n strings for plugins"
|
@echo "Extracting i18n strings for plugins"
|
||||||
@@ -178,7 +178,7 @@ gen-apps: do-gen-apps gofmt ## Generate code for Grafana App SDK apps and run go
|
|||||||
@if [ -n "$$CODEGEN_VERIFY" ]; then \
|
@if [ -n "$$CODEGEN_VERIFY" ]; then \
|
||||||
echo "Verifying generated code is up to date..."; \
|
echo "Verifying generated code is up to date..."; \
|
||||||
if ! git diff --quiet; then \
|
if ! git diff --quiet; then \
|
||||||
echo "Error: Generated apps code is not up to date. Please run 'make gen-apps' to regenerate."; \
|
echo "Error: Generated code is not up to date. Please run 'make gen-apps', 'make gen-cue', and 'make gen-jsonnet' to regenerate."; \
|
||||||
git diff --name-only; \
|
git diff --name-only; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi; \
|
fi; \
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
The open-source platform for monitoring and observability
|
The open-source platform for monitoring and observability
|
||||||
|
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://drone.grafana.net/grafana/grafana)
|
|
||||||
[](https://goreportcard.com/report/github.com/grafana/grafana)
|
[](https://goreportcard.com/report/github.com/grafana/grafana)
|
||||||
|
|
||||||
Grafana allows you to query, visualize, alert on and understand your metrics no matter where they are stored. Create, explore, and share dashboards with your team and foster a data-driven culture:
|
Grafana allows you to query, visualize, alert on and understand your metrics no matter where they are stored. Create, explore, and share dashboards with your team and foster a data-driven culture:
|
||||||
@@ -36,6 +35,8 @@ If you're interested in contributing to the Grafana project:
|
|||||||
- Explore our [beginner-friendly issues](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22).
|
- Explore our [beginner-friendly issues](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22).
|
||||||
- Look through our [style guide and Storybook](https://developers.grafana.com/ui/latest/index.html).
|
- Look through our [style guide and Storybook](https://developers.grafana.com/ui/latest/index.html).
|
||||||
|
|
||||||
|
> Share your contributor experience in our [feedback survey](https://gra.fan/ome) to help us improve.
|
||||||
|
|
||||||
## Get involved
|
## Get involved
|
||||||
|
|
||||||
- Follow [@grafana on X (formerly Twitter)](https://x.com/grafana/).
|
- Follow [@grafana on X (formerly Twitter)](https://x.com/grafana/).
|
||||||
|
|||||||
@@ -1,5 +1,34 @@
|
|||||||
include ../sdk.mk
|
include ../sdk.mk
|
||||||
|
|
||||||
.PHONY: generate
|
.PHONY: etcd
|
||||||
|
etcd:
|
||||||
|
@docker run -d --name etcd --env ALLOW_NONE_AUTHENTICATION=yes -p 22379:2379 bitnamilegacy/etcd:latest
|
||||||
|
|
||||||
|
.PHONY: generate # Run Grafana App SDK code generation
|
||||||
generate: install-app-sdk update-app-sdk
|
generate: install-app-sdk update-app-sdk
|
||||||
@$(APP_SDK_BIN) generate -g ./pkg/apis --grouping=group --postprocess --defencoding=none --useoldmanifestkinds
|
@$(APP_SDK_BIN) generate \
|
||||||
|
--source=./kinds/ \
|
||||||
|
--gogenpath=./pkg/apis \
|
||||||
|
--grouping=group \
|
||||||
|
--defencoding=none
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run:
|
||||||
|
@go run ./pkg/standalone/server.go --etcd-servers=http://127.0.0.1:22379 --secure-port 7445
|
||||||
|
|
||||||
|
.PHONY: create-checks
|
||||||
|
create-checks:
|
||||||
|
@echo "Creating plugin check..."
|
||||||
|
@curl -k -X POST https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"kind":"Check","apiVersion":"advisor.grafana.app/v0alpha1","spec":{"data":{}},"metadata":{"generateName":"check-","labels":{"advisor.grafana.app/type":"plugin"},"namespace":"stacks-1"},"status":{"report":{"count":0,"failures":[]}}}' \
|
||||||
|
&& echo "Plugin check created successfully"
|
||||||
|
@echo "Creating datasource check..."
|
||||||
|
@curl -k -X POST https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"kind":"Check","apiVersion":"advisor.grafana.app/v0alpha1","spec":{"data":{}},"metadata":{"generateName":"check-","labels":{"advisor.grafana.app/type":"datasource"},"namespace":"stacks-1"},"status":{"report":{"count":0,"failures":[]}}}' \
|
||||||
|
&& echo "Datasource check created successfully"
|
||||||
|
|
||||||
|
delete-checks:
|
||||||
|
@curl -k -X DELETE https://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks \
|
||||||
|
&& echo "All checks deleted successfully"
|
||||||
|
|||||||
@@ -152,3 +152,28 @@ Check [`security_config_step.go`](./pkg/app/checks/configchecks/security_config_
|
|||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Create tests for your check and its steps to ensure they work as expected. Test both successful and failure scenarios.
|
Create tests for your check and its steps to ensure they work as expected. Test both successful and failure scenarios.
|
||||||
|
|
||||||
|
## Running the Standalone Mode
|
||||||
|
|
||||||
|
To run the standalone mode, you can use the `make run` command. This will start the advisor app in standalone mode, which means it will not be running in a Kubernetes cluster.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make etcd # Start etcd in a docker container
|
||||||
|
make run # Start the advisor app in standalone mode
|
||||||
|
```
|
||||||
|
|
||||||
|
This will start the advisor app on port 7445. You can then access the advisor app at `http://localhost:7445`.
|
||||||
|
|
||||||
|
To see some sample checks, you can run the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make create-checks
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can see list in the URL: `http://localhost:7445/apis/advisor.grafana.app/v0alpha1/namespaces/stacks-1/checks`
|
||||||
|
|
||||||
|
To delete all checks, you can run the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make delete-checks
|
||||||
|
```
|
||||||
|
|||||||
@@ -4,55 +4,78 @@ go 1.25.3
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/semver/v3 v3.4.0
|
github.com/Masterminds/semver/v3 v3.4.0
|
||||||
|
github.com/google/go-cmp v0.7.0
|
||||||
github.com/google/go-github/v70 v70.0.0
|
github.com/google/go-github/v70 v70.0.0
|
||||||
github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43
|
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37
|
||||||
github.com/grafana/grafana v0.0.0-00010101000000-000000000000
|
github.com/grafana/grafana v0.0.0-00010101000000-000000000000
|
||||||
github.com/grafana/grafana-app-sdk v0.40.2
|
github.com/grafana/grafana-app-sdk v0.48.1
|
||||||
github.com/grafana/grafana-app-sdk/logging v0.40.2
|
github.com/grafana/grafana-app-sdk/logging v0.48.1
|
||||||
github.com/grafana/grafana-plugin-sdk-go v0.278.0
|
github.com/grafana/grafana-plugin-sdk-go v0.281.0
|
||||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2
|
github.com/grafana/grafana/pkg/apimachinery v0.0.0
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.11.1
|
||||||
k8s.io/apimachinery v0.33.3
|
k8s.io/apimachinery v0.34.1
|
||||||
k8s.io/apiserver v0.33.3
|
k8s.io/apiserver v0.34.1
|
||||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
|
k8s.io/client-go v0.34.1
|
||||||
|
k8s.io/component-base v0.34.1
|
||||||
|
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||||
)
|
)
|
||||||
|
|
||||||
// transitive dependencies that need replaced
|
// transitive dependencies that need replaced
|
||||||
// TODO: stop depending on grafana core
|
// TODO: stop depending on grafana core
|
||||||
replace github.com/grafana/grafana => ../..
|
replace github.com/grafana/grafana => ../..
|
||||||
|
|
||||||
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6
|
replace github.com/grafana/grafana/apps/provisioning => ../provisioning
|
||||||
|
|
||||||
|
replace github.com/grafana/grafana/pkg/apimachinery => ../../pkg/apimachinery
|
||||||
|
|
||||||
|
replace github.com/grafana/grafana/pkg/apiserver => ../../pkg/apiserver
|
||||||
|
|
||||||
|
replace github.com/grafana/grafana/apps/dashboard => ../dashboard
|
||||||
|
|
||||||
|
replace github.com/grafana/grafana/pkg/aggregator => ../../pkg/aggregator
|
||||||
|
|
||||||
|
replace github.com/grafana/grafana/apps/folder => ../folder
|
||||||
|
|
||||||
|
replace github.com/grafana/grafana/apps/secret => ../secret
|
||||||
|
|
||||||
|
replace github.com/grafana/grafana/apps/iam => ../iam
|
||||||
|
|
||||||
|
replace github.com/grafana/grafana/apps/plugins => ../plugins
|
||||||
|
|
||||||
|
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
cel.dev/expr v0.24.0 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||||
dario.cat/mergo v1.0.2 // indirect
|
dario.cat/mergo v1.0.2 // indirect
|
||||||
filippo.io/edwards25519 v1.1.0 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
|
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect
|
||||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver v1.5.0 // indirect
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||||
|
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||||
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect
|
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect
|
||||||
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
|
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||||
github.com/apache/arrow-go/v18 v18.3.0 // indirect
|
github.com/apache/arrow-go/v18 v18.4.1 // indirect
|
||||||
github.com/armon/go-metrics v0.4.1 // indirect
|
github.com/armon/go-metrics v0.4.1 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
github.com/at-wat/mqtt-go v0.19.4 // indirect
|
github.com/at-wat/mqtt-go v0.19.4 // indirect
|
||||||
github.com/aws/aws-sdk-go v1.55.7 // indirect
|
github.com/aws/aws-sdk-go v1.55.7 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect
|
github.com/aws/aws-sdk-go-v2 v1.39.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.18.14 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 // indirect
|
||||||
github.com/aws/smithy-go v1.22.4 // indirect
|
github.com/aws/smithy-go v1.23.1 // indirect
|
||||||
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect
|
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect
|
||||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
@@ -62,13 +85,12 @@ require (
|
|||||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
||||||
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
github.com/bwmarrin/snowflake v0.3.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.2 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cheekybits/genny v1.0.0 // indirect
|
github.com/cheekybits/genny v1.0.0 // indirect
|
||||||
github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4 // indirect
|
|
||||||
github.com/cloudflare/circl v1.6.1 // indirect
|
github.com/cloudflare/circl v1.6.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.5.0 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect
|
github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect
|
||||||
@@ -78,102 +100,110 @@ require (
|
|||||||
github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect
|
github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect
|
||||||
github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect
|
github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect
|
||||||
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect
|
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect
|
||||||
github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // indirect
|
github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/elazarl/goproxy v1.7.2 // indirect
|
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||||
github.com/gchaincl/sqlhooks v1.3.0 // indirect
|
github.com/gchaincl/sqlhooks v1.3.0 // indirect
|
||||||
github.com/getkin/kin-openapi v0.132.0 // indirect
|
github.com/getkin/kin-openapi v0.133.0 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||||
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
|
github.com/go-jose/go-jose/v4 v4.1.2 // indirect
|
||||||
github.com/go-kit/log v0.2.1 // indirect
|
github.com/go-kit/log v0.2.1 // indirect
|
||||||
github.com/go-ldap/ldap/v3 v3.4.4 // indirect
|
github.com/go-ldap/ldap/v3 v3.4.4 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
github.com/go-logfmt/logfmt v0.6.1 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
github.com/go-openapi/analysis v0.24.0 // indirect
|
||||||
github.com/go-openapi/errors v0.22.0 // indirect
|
github.com/go-openapi/errors v0.22.3 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
github.com/go-openapi/jsonpointer v0.22.1 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
github.com/go-openapi/jsonreference v0.21.2 // indirect
|
||||||
github.com/go-openapi/loads v0.22.0 // indirect
|
github.com/go-openapi/loads v0.23.1 // indirect
|
||||||
github.com/go-openapi/runtime v0.28.0 // indirect
|
github.com/go-openapi/runtime v0.28.0 // indirect
|
||||||
github.com/go-openapi/spec v0.21.0 // indirect
|
github.com/go-openapi/spec v0.22.0 // indirect
|
||||||
github.com/go-openapi/strfmt v0.23.0 // indirect
|
github.com/go-openapi/strfmt v0.24.0 // indirect
|
||||||
github.com/go-openapi/swag v0.23.0 // indirect
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
github.com/go-openapi/validate v0.24.0 // indirect
|
github.com/go-openapi/swag/conv v0.25.1 // indirect
|
||||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
github.com/go-openapi/swag/fileutils v0.25.1 // indirect
|
||||||
|
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
|
||||||
|
github.com/go-openapi/swag/jsonutils v0.25.1 // indirect
|
||||||
|
github.com/go-openapi/swag/loading v0.25.1 // indirect
|
||||||
|
github.com/go-openapi/swag/mangling v0.25.1 // indirect
|
||||||
|
github.com/go-openapi/swag/stringutils v0.25.1 // indirect
|
||||||
|
github.com/go-openapi/swag/typeutils v0.25.1 // indirect
|
||||||
|
github.com/go-openapi/swag/yamlutils v0.25.1 // indirect
|
||||||
|
github.com/go-openapi/validate v0.25.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-stack/stack v1.8.1 // indirect
|
github.com/go-stack/stack v1.8.1 // 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/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||||
github.com/gogo/googleapis v1.4.1 // indirect
|
github.com/gogo/googleapis v1.4.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.3 // indirect
|
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||||
github.com/golang-migrate/migrate/v4 v4.7.0 // indirect
|
github.com/golang-migrate/migrate/v4 v4.7.0 // indirect
|
||||||
github.com/golang/mock v1.7.0-rc.1 // indirect
|
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/btree v1.1.3 // indirect
|
github.com/google/btree v1.1.3 // indirect
|
||||||
|
github.com/google/cel-go v0.26.1 // indirect
|
||||||
github.com/google/flatbuffers v25.2.10+incompatible // indirect
|
github.com/google/flatbuffers v25.2.10+incompatible // indirect
|
||||||
github.com/google/gnostic-models v0.6.9 // indirect
|
github.com/google/gnostic-models v0.7.0 // indirect
|
||||||
github.com/google/go-cmp v0.7.0 // indirect
|
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/google/wire v0.6.0 // indirect
|
github.com/google/wire v0.7.0 // indirect
|
||||||
github.com/gorilla/mux v1.8.1 // indirect
|
github.com/grafana/alerting v0.0.0-20251009192429-9427c24835ae // indirect
|
||||||
github.com/grafana/alerting v0.0.0-20250729175202-b4b881b7b263 // indirect
|
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
|
||||||
github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 // indirect
|
|
||||||
github.com/grafana/dataplane/sdata v0.0.9 // indirect
|
github.com/grafana/dataplane/sdata v0.0.9 // indirect
|
||||||
github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 // indirect
|
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
||||||
github.com/grafana/grafana-aws-sdk v1.1.0 // indirect
|
github.com/grafana/grafana-aws-sdk v1.3.0 // indirect
|
||||||
github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0 // indirect
|
github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 // indirect
|
||||||
github.com/grafana/grafana/apps/provisioning v0.0.0-20250804150913-990f1c69ecc2 // indirect
|
github.com/grafana/grafana/apps/plugins v0.0.0 // indirect
|
||||||
github.com/grafana/grafana/pkg/apiserver v0.0.0-20250804150913-990f1c69ecc2 // indirect
|
github.com/grafana/grafana/apps/provisioning v0.0.0 // indirect
|
||||||
|
github.com/grafana/grafana/pkg/apiserver v0.0.0 // indirect
|
||||||
github.com/grafana/otel-profiling-go v0.5.1 // indirect
|
github.com/grafana/otel-profiling-go v0.5.1 // indirect
|
||||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
|
github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect
|
||||||
github.com/grafana/sqlds/v4 v4.2.4 // indirect
|
github.com/grafana/sqlds/v4 v4.2.7 // indirect
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
|
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||||
github.com/hashicorp/go-metrics v0.5.4 // indirect
|
github.com/hashicorp/go-metrics v0.5.4 // indirect
|
||||||
github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect
|
github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-plugin v1.6.3 // indirect
|
github.com/hashicorp/go-plugin v1.7.0 // indirect
|
||||||
github.com/hashicorp/go-sockaddr v1.0.7 // indirect
|
github.com/hashicorp/go-sockaddr v1.0.7 // indirect
|
||||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/hashicorp/memberlist v0.5.2 // indirect
|
github.com/hashicorp/memberlist v0.5.2 // indirect
|
||||||
github.com/hashicorp/yamux v0.1.1 // 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/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jaegertracing/jaeger-idl v0.5.0 // indirect
|
github.com/jaegertracing/jaeger-idl v0.5.0 // indirect
|
||||||
github.com/jessevdk/go-flags v1.6.1 // indirect
|
github.com/jessevdk/go-flags v1.6.1 // indirect
|
||||||
github.com/jmespath-community/go-jmespath v1.1.1 // indirect
|
github.com/jmespath-community/go-jmespath v1.1.1 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/jmoiron/sqlx v1.3.5 // indirect
|
github.com/jmoiron/sqlx v1.4.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/jpillora/backoff v1.0.0 // indirect
|
github.com/jpillora/backoff v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect
|
github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/lestrrat-go/strftime v1.0.4 // indirect
|
github.com/lestrrat-go/strftime v1.0.4 // indirect
|
||||||
github.com/lib/pq v1.10.9 // indirect
|
github.com/lib/pq v1.10.9 // indirect
|
||||||
github.com/magefile/mage v1.15.0 // indirect
|
|
||||||
github.com/mailru/easyjson v0.9.0 // indirect
|
github.com/mailru/easyjson v0.9.0 // indirect
|
||||||
github.com/mattetti/filebuffer v1.0.1 // indirect
|
github.com/mattetti/filebuffer v1.0.1 // 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.16 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
github.com/mattn/go-sqlite3 v1.14.32 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
github.com/mdlayher/socket v0.4.1 // indirect
|
github.com/mdlayher/socket v0.4.1 // indirect
|
||||||
github.com/mdlayher/vsock v1.2.1 // indirect
|
github.com/mdlayher/vsock v1.2.1 // indirect
|
||||||
@@ -188,7 +218,7 @@ require (
|
|||||||
github.com/mithrandie/go-text v1.6.0 // indirect
|
github.com/mithrandie/go-text v1.6.0 // indirect
|
||||||
github.com/mithrandie/ternary v1.1.1 // indirect
|
github.com/mithrandie/ternary v1.1.1 // 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/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||||
@@ -199,9 +229,9 @@ require (
|
|||||||
github.com/oklog/run v1.1.0 // indirect
|
github.com/oklog/run v1.1.0 // indirect
|
||||||
github.com/oklog/ulid v1.3.1 // indirect
|
github.com/oklog/ulid v1.3.1 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/open-feature/go-sdk v1.14.1 // indirect
|
github.com/open-feature/go-sdk v1.16.0 // indirect
|
||||||
github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3 // indirect
|
github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.6 // indirect
|
||||||
github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 // indirect
|
github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.6 // indirect
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
||||||
@@ -209,41 +239,43 @@ require (
|
|||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // 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/prometheus/alertmanager v0.28.0 // indirect
|
github.com/prometheus/alertmanager v0.28.0 // indirect
|
||||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
github.com/prometheus/client_golang v1.23.2 // indirect
|
||||||
github.com/prometheus/client_model v0.6.2 // indirect
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
github.com/prometheus/common v0.65.0 // indirect
|
github.com/prometheus/common v0.67.1 // indirect
|
||||||
github.com/prometheus/common/sigv4 v0.1.0 // indirect
|
github.com/prometheus/common/sigv4 v0.1.0 // indirect
|
||||||
github.com/prometheus/exporter-toolkit v0.14.0 // indirect
|
github.com/prometheus/exporter-toolkit v0.14.0 // indirect
|
||||||
github.com/prometheus/procfs v0.16.1 // indirect
|
github.com/prometheus/procfs v0.16.1 // indirect
|
||||||
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
|
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
|
||||||
|
github.com/redis/go-redis/v9 v9.14.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/rs/cors v1.11.1 // indirect
|
github.com/rs/cors v1.11.1 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
||||||
github.com/shopspring/decimal v1.4.0 // indirect
|
github.com/shopspring/decimal v1.4.0 // 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-20200824052919-0d455de96546 // indirect
|
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/spf13/cast v1.7.1 // indirect
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.7 // indirect
|
github.com/spf13/cobra v1.10.1 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
|
github.com/stoewer/go-strcase v1.3.1 // indirect
|
||||||
github.com/stretchr/objx v0.5.2 // indirect
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/tetratelabs/wazero v1.8.2 // indirect
|
github.com/tetratelabs/wazero v1.8.2 // indirect
|
||||||
github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect
|
github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect
|
||||||
github.com/tjhop/slog-gokit v0.1.3 // indirect
|
github.com/tjhop/slog-gokit v0.1.5 // indirect
|
||||||
github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect
|
github.com/woodsbury/decimal128 v1.3.0 // indirect
|
||||||
github.com/unknwon/com v1.0.1 // indirect
|
|
||||||
github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect
|
|
||||||
github.com/urfave/cli v1.22.16 // indirect
|
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
github.com/zeebo/xxh3 v1.0.2 // indirect
|
github.com/zeebo/xxh3 v1.0.2 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.17.3 // indirect
|
go.etcd.io/etcd/api/v3 v3.6.4 // indirect
|
||||||
|
go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect
|
||||||
|
go.etcd.io/etcd/client/v3 v3.6.4 // indirect
|
||||||
|
go.mongodb.org/mongo-driver v1.17.4 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect
|
||||||
go.opentelemetry.io/contrib/propagators/jaeger v1.36.0 // indirect
|
go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 // indirect
|
||||||
go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0 // indirect
|
go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
|
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
||||||
@@ -252,48 +284,55 @@ require (
|
|||||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
go.uber.org/mock v0.6.0 // indirect
|
||||||
golang.org/x/crypto v0.40.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
golang.org/x/mod v0.26.0 // indirect
|
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||||
golang.org/x/net v0.42.0 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/oauth2 v0.30.0 // indirect
|
golang.org/x/crypto v0.43.0 // indirect
|
||||||
golang.org/x/sync v0.16.0 // indirect
|
golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect
|
||||||
golang.org/x/sys v0.34.0 // indirect
|
golang.org/x/mod v0.29.0 // indirect
|
||||||
golang.org/x/term v0.33.0 // indirect
|
golang.org/x/net v0.46.0 // indirect
|
||||||
golang.org/x/text v0.27.0 // indirect
|
golang.org/x/oauth2 v0.32.0 // indirect
|
||||||
golang.org/x/time v0.11.0 // indirect
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
golang.org/x/tools v0.35.0 // indirect
|
golang.org/x/sys v0.37.0 // indirect
|
||||||
|
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect
|
||||||
|
golang.org/x/term v0.36.0 // indirect
|
||||||
|
golang.org/x/text v0.30.0 // indirect
|
||||||
|
golang.org/x/time v0.14.0 // indirect
|
||||||
|
golang.org/x/tools v0.38.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||||
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
||||||
gonum.org/v1/gonum v0.16.0 // indirect
|
gonum.org/v1/gonum v0.16.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect
|
||||||
google.golang.org/grpc v1.74.2 // indirect
|
google.golang.org/grpc v1.76.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.6 // indirect
|
google.golang.org/protobuf v1.36.10 // indirect
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/mail.v2 v2.3.1 // indirect
|
gopkg.in/mail.v2 v2.3.1 // indirect
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
gopkg.in/src-d/go-errors.v1 v1.0.0 // indirect
|
gopkg.in/src-d/go-errors.v1 v1.0.0 // indirect
|
||||||
gopkg.in/telebot.v3 v3.2.1 // indirect
|
gopkg.in/telebot.v3 v3.3.8 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
k8s.io/api v0.33.3 // indirect
|
k8s.io/api v0.34.1 // indirect
|
||||||
k8s.io/apiextensions-apiserver v0.33.3 // indirect
|
k8s.io/apiextensions-apiserver v0.34.1 // indirect
|
||||||
k8s.io/client-go v0.33.3 // indirect
|
|
||||||
k8s.io/component-base v0.33.3 // indirect
|
|
||||||
k8s.io/klog/v2 v2.130.1 // indirect
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
k8s.io/kms v0.34.1 // indirect
|
||||||
modernc.org/libc v1.65.0 // indirect
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||||
|
modernc.org/libc v1.66.10 // indirect
|
||||||
modernc.org/mathutil v1.7.1 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/memory v1.10.0 // indirect
|
modernc.org/memory v1.11.0 // indirect
|
||||||
modernc.org/sqlite v1.38.0 // indirect
|
modernc.org/sqlite v1.39.1 // indirect
|
||||||
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
sigs.k8s.io/yaml v1.5.0 // indirect
|
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
|
||||||
xorm.io/builder v0.3.6 // indirect
|
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||||
|
xorm.io/builder v0.3.13 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,57 +1,49 @@
|
|||||||
package advisor
|
package advisor
|
||||||
|
|
||||||
check: {
|
checkv0alpha1: {
|
||||||
kind: "Check"
|
kind: "Check"
|
||||||
pluralName: "Checks"
|
plural: "checks"
|
||||||
current: "v0alpha1"
|
scope: "Namespaced"
|
||||||
validation: {
|
validation: {
|
||||||
operations: [
|
operations: [
|
||||||
"CREATE",
|
"CREATE",
|
||||||
"UPDATE",
|
"UPDATE",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
versions: {
|
schema: {
|
||||||
"v0alpha1": {
|
#Data: {
|
||||||
codegen: {
|
// Generic data input that a check can receive
|
||||||
ts: {enabled: false}
|
data?: [string]: string
|
||||||
go: {enabled: true}
|
}
|
||||||
}
|
#ErrorLink: {
|
||||||
schema: {
|
// URL to a page with more information about the error
|
||||||
#Data: {
|
url: string
|
||||||
// Generic data input that a check can receive
|
// Human readable error message
|
||||||
data?: [string]: string
|
message: string
|
||||||
}
|
}
|
||||||
#ErrorLink: {
|
#ReportFailure: {
|
||||||
// URL to a page with more information about the error
|
// Severity of the failure
|
||||||
url: string
|
severity: "high" | "low"
|
||||||
// Human readable error message
|
// Step ID that the failure is associated with
|
||||||
message: string
|
stepID: string
|
||||||
}
|
// Human readable identifier of the item that failed
|
||||||
#ReportFailure: {
|
item: string
|
||||||
// Severity of the failure
|
// ID of the item that failed
|
||||||
severity: "high" | "low"
|
itemID: string
|
||||||
// Step ID that the failure is associated with
|
// Links to actions that can be taken to resolve the failure
|
||||||
stepID: string
|
links: [...#ErrorLink]
|
||||||
// Human readable identifier of the item that failed
|
// More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.
|
||||||
item: string
|
moreInfo?: string
|
||||||
// ID of the item that failed
|
}
|
||||||
itemID: string
|
#Report: {
|
||||||
// Links to actions that can be taken to resolve the failure
|
// Number of elements analyzed
|
||||||
links: [...#ErrorLink]
|
count: int
|
||||||
// More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.
|
// List of failures
|
||||||
moreInfo?: string
|
failures: [...#ReportFailure]
|
||||||
}
|
}
|
||||||
#Report: {
|
spec: #Data
|
||||||
// Number of elements analyzed
|
status: {
|
||||||
count: int
|
report: #Report
|
||||||
// List of failures
|
|
||||||
failures: [...#ReportFailure]
|
|
||||||
}
|
|
||||||
spec: #Data
|
|
||||||
status: {
|
|
||||||
report: #Report
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,19 @@
|
|||||||
package advisor
|
package advisor
|
||||||
|
|
||||||
checktype: {
|
checktypev0alpha1: {
|
||||||
kind: "CheckType"
|
kind: "CheckType"
|
||||||
pluralName: "CheckTypes"
|
plural: "checktypes"
|
||||||
current: "v0alpha1"
|
scope: "Namespaced"
|
||||||
versions: {
|
schema: {
|
||||||
"v0alpha1": {
|
#Step: {
|
||||||
codegen: {
|
title: string
|
||||||
ts: {enabled: false}
|
description: string
|
||||||
go: {enabled: true}
|
stepID: string
|
||||||
}
|
resolution: string
|
||||||
schema: {
|
}
|
||||||
#Step: {
|
spec: {
|
||||||
title: string
|
name: string
|
||||||
description: string
|
steps: [...#Step]
|
||||||
stepID: string
|
|
||||||
resolution: string
|
|
||||||
}
|
|
||||||
spec: {
|
|
||||||
name: string
|
|
||||||
steps: [...#Step]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
package advisor
|
package advisor
|
||||||
|
|
||||||
manifest: {
|
manifest: {
|
||||||
appName: "advisor"
|
appName: "advisor"
|
||||||
groupOverride: "advisor.grafana.app"
|
groupOverride: "advisor.grafana.app"
|
||||||
kinds: [
|
versions: {
|
||||||
check,
|
"v0alpha1": {
|
||||||
checktype,
|
codegen: {
|
||||||
]
|
ts: {enabled: false}
|
||||||
|
go: {enabled: true}
|
||||||
|
}
|
||||||
|
kinds: [
|
||||||
|
checkv0alpha1,
|
||||||
|
checktypev0alpha1,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
99
apps/advisor/pkg/apis/advisor/v0alpha1/check_client_gen.go
generated
Normal file
99
apps/advisor/pkg/apis/advisor/v0alpha1/check_client_gen.go
generated
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package v0alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CheckClient struct {
|
||||||
|
client *resource.TypedClient[*Check, *CheckList]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCheckClient(client resource.Client) *CheckClient {
|
||||||
|
return &CheckClient{
|
||||||
|
client: resource.NewTypedClient[*Check, *CheckList](client, CheckKind()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCheckClientFromGenerator(generator resource.ClientGenerator) (*CheckClient, error) {
|
||||||
|
c, err := generator.ClientFor(CheckKind())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewCheckClient(c), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckClient) Get(ctx context.Context, identifier resource.Identifier) (*Check, error) {
|
||||||
|
return c.client.Get(ctx, identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckList, error) {
|
||||||
|
return c.client.List(ctx, namespace, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckList, error) {
|
||||||
|
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
|
||||||
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Limit: opts.Limit,
|
||||||
|
LabelFilters: opts.LabelFilters,
|
||||||
|
FieldSelectors: opts.FieldSelectors,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for resp.GetContinue() != "" {
|
||||||
|
page, err := c.client.List(ctx, namespace, resource.ListOptions{
|
||||||
|
Continue: resp.GetContinue(),
|
||||||
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Limit: opts.Limit,
|
||||||
|
LabelFilters: opts.LabelFilters,
|
||||||
|
FieldSelectors: opts.FieldSelectors,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp.SetContinue(page.GetContinue())
|
||||||
|
resp.SetResourceVersion(page.GetResourceVersion())
|
||||||
|
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckClient) Create(ctx context.Context, obj *Check, opts resource.CreateOptions) (*Check, error) {
|
||||||
|
// Make sure apiVersion and kind are set
|
||||||
|
obj.APIVersion = GroupVersion.Identifier()
|
||||||
|
obj.Kind = CheckKind().Kind()
|
||||||
|
return c.client.Create(ctx, obj, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckClient) Update(ctx context.Context, obj *Check, opts resource.UpdateOptions) (*Check, error) {
|
||||||
|
return c.client.Update(ctx, obj, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Check, error) {
|
||||||
|
return c.client.Patch(ctx, identifier, req, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus CheckStatus, opts resource.UpdateOptions) (*Check, error) {
|
||||||
|
return c.client.Update(ctx, &Check{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: CheckKind().Kind(),
|
||||||
|
APIVersion: GroupVersion.Identifier(),
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Namespace: identifier.Namespace,
|
||||||
|
Name: identifier.Name,
|
||||||
|
},
|
||||||
|
Status: newStatus,
|
||||||
|
}, resource.UpdateOptions{
|
||||||
|
Subresource: "status",
|
||||||
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||||
|
return c.client.Delete(ctx, identifier, opts)
|
||||||
|
}
|
||||||
99
apps/advisor/pkg/apis/advisor/v0alpha1/checktype_client_gen.go
generated
Normal file
99
apps/advisor/pkg/apis/advisor/v0alpha1/checktype_client_gen.go
generated
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package v0alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CheckTypeClient struct {
|
||||||
|
client *resource.TypedClient[*CheckType, *CheckTypeList]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCheckTypeClient(client resource.Client) *CheckTypeClient {
|
||||||
|
return &CheckTypeClient{
|
||||||
|
client: resource.NewTypedClient[*CheckType, *CheckTypeList](client, CheckTypeKind()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCheckTypeClientFromGenerator(generator resource.ClientGenerator) (*CheckTypeClient, error) {
|
||||||
|
c, err := generator.ClientFor(CheckTypeKind())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewCheckTypeClient(c), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckTypeClient) Get(ctx context.Context, identifier resource.Identifier) (*CheckType, error) {
|
||||||
|
return c.client.Get(ctx, identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckTypeClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckTypeList, error) {
|
||||||
|
return c.client.List(ctx, namespace, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckTypeClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckTypeList, error) {
|
||||||
|
resp, err := c.client.List(ctx, namespace, resource.ListOptions{
|
||||||
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Limit: opts.Limit,
|
||||||
|
LabelFilters: opts.LabelFilters,
|
||||||
|
FieldSelectors: opts.FieldSelectors,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for resp.GetContinue() != "" {
|
||||||
|
page, err := c.client.List(ctx, namespace, resource.ListOptions{
|
||||||
|
Continue: resp.GetContinue(),
|
||||||
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Limit: opts.Limit,
|
||||||
|
LabelFilters: opts.LabelFilters,
|
||||||
|
FieldSelectors: opts.FieldSelectors,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp.SetContinue(page.GetContinue())
|
||||||
|
resp.SetResourceVersion(page.GetResourceVersion())
|
||||||
|
resp.SetItems(append(resp.GetItems(), page.GetItems()...))
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckTypeClient) Create(ctx context.Context, obj *CheckType, opts resource.CreateOptions) (*CheckType, error) {
|
||||||
|
// Make sure apiVersion and kind are set
|
||||||
|
obj.APIVersion = GroupVersion.Identifier()
|
||||||
|
obj.Kind = CheckTypeKind().Kind()
|
||||||
|
return c.client.Create(ctx, obj, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckTypeClient) Update(ctx context.Context, obj *CheckType, opts resource.UpdateOptions) (*CheckType, error) {
|
||||||
|
return c.client.Update(ctx, obj, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckTypeClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*CheckType, error) {
|
||||||
|
return c.client.Patch(ctx, identifier, req, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckTypeClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus CheckTypeStatus, opts resource.UpdateOptions) (*CheckType, error) {
|
||||||
|
return c.client.Update(ctx, &CheckType{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: CheckTypeKind().Kind(),
|
||||||
|
APIVersion: GroupVersion.Identifier(),
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
Namespace: identifier.Namespace,
|
||||||
|
Name: identifier.Name,
|
||||||
|
},
|
||||||
|
Status: newStatus,
|
||||||
|
}, resource.UpdateOptions{
|
||||||
|
Subresource: "status",
|
||||||
|
ResourceVersion: opts.ResourceVersion,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CheckTypeClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||||
|
return c.client.Delete(ctx, identifier, opts)
|
||||||
|
}
|
||||||
57
apps/advisor/pkg/apis/advisor_manifest.go
generated
57
apps/advisor/pkg/apis/advisor_manifest.go
generated
@@ -12,22 +12,26 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/app"
|
"github.com/grafana/grafana-app-sdk/app"
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/kube-openapi/pkg/spec3"
|
||||||
|
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||||
|
|
||||||
v0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
v0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
rawSchemaCheckv0alpha1 = []byte(`{"spec":{"properties":{"data":{"additionalProperties":{"type":"string"},"description":"Generic data input that a check can receive","type":"object"}},"type":"object"},"status":{"properties":{"additionalFields":{"description":"additionalFields is reserved for future use","type":"object","x-kubernetes-preserve-unknown-fields":true},"operatorStates":{"additionalProperties":{"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"description":"details contains any extra information that is operator-specific","type":"object","x-kubernetes-preserve-unknown-fields":true},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"},"report":{"properties":{"count":{"description":"Number of elements analyzed","type":"integer"},"failures":{"description":"List of failures","items":{"properties":{"item":{"description":"Human readable identifier of the item that failed","type":"string"},"itemID":{"description":"ID of the item that failed","type":"string"},"links":{"description":"Links to actions that can be taken to resolve the failure","items":{"properties":{"message":{"description":"Human readable error message","type":"string"},"url":{"description":"URL to a page with more information about the error","type":"string"}},"required":["url","message"],"type":"object"},"type":"array"},"moreInfo":{"description":"More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.","type":"string"},"severity":{"description":"Severity of the failure","enum":["high","low"],"type":"string"},"stepID":{"description":"Step ID that the failure is associated with","type":"string"}},"required":["severity","stepID","item","itemID","links"],"type":"object"},"type":"array"}},"required":["count","failures"],"type":"object"}},"required":["report"],"type":"object"}}`)
|
rawSchemaCheckv0alpha1 = []byte(`{"Check":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"ErrorLink":{"additionalProperties":false,"properties":{"message":{"description":"Human readable error message","type":"string"},"url":{"description":"URL to a page with more information about the error","type":"string"}},"required":["url","message"],"type":"object"},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"Report":{"additionalProperties":false,"properties":{"count":{"description":"Number of elements analyzed","type":"integer"},"failures":{"description":"List of failures","items":{"$ref":"#/components/schemas/ReportFailure"},"type":"array"}},"required":["count","failures"],"type":"object"},"ReportFailure":{"additionalProperties":false,"properties":{"item":{"description":"Human readable identifier of the item that failed","type":"string"},"itemID":{"description":"ID of the item that failed","type":"string"},"links":{"description":"Links to actions that can be taken to resolve the failure","items":{"$ref":"#/components/schemas/ErrorLink"},"type":"array"},"moreInfo":{"description":"More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.","type":"string"},"severity":{"description":"Severity of the failure","enum":["high","low"],"type":"string"},"stepID":{"description":"Step ID that the failure is associated with","type":"string"}},"required":["severity","stepID","item","itemID","links"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"data":{"additionalProperties":{"type":"string"},"description":"Generic data input that a check can receive","type":"object"}},"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"},"report":{"$ref":"#/components/schemas/Report"}},"required":["report"],"type":"object"}}`)
|
||||||
versionSchemaCheckv0alpha1 app.VersionSchema
|
versionSchemaCheckv0alpha1 app.VersionSchema
|
||||||
_ = json.Unmarshal(rawSchemaCheckv0alpha1, &versionSchemaCheckv0alpha1)
|
_ = json.Unmarshal(rawSchemaCheckv0alpha1, &versionSchemaCheckv0alpha1)
|
||||||
rawSchemaCheckTypev0alpha1 = []byte(`{"spec":{"properties":{"name":{"type":"string"},"steps":{"items":{"properties":{"description":{"type":"string"},"resolution":{"type":"string"},"stepID":{"type":"string"},"title":{"type":"string"}},"required":["title","description","stepID","resolution"],"type":"object"},"type":"array"}},"required":["name","steps"],"type":"object"},"status":{"properties":{"additionalFields":{"description":"additionalFields is reserved for future use","type":"object","x-kubernetes-preserve-unknown-fields":true},"operatorStates":{"additionalProperties":{"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"description":"details contains any extra information that is operator-specific","type":"object","x-kubernetes-preserve-unknown-fields":true},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
|
rawSchemaCheckTypev0alpha1 = []byte(`{"CheckType":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"Step":{"additionalProperties":false,"properties":{"description":{"type":"string"},"resolution":{"type":"string"},"stepID":{"type":"string"},"title":{"type":"string"}},"required":["title","description","stepID","resolution"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"name":{"type":"string"},"steps":{"items":{"$ref":"#/components/schemas/Step"},"type":"array"}},"required":["name","steps"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`)
|
||||||
versionSchemaCheckTypev0alpha1 app.VersionSchema
|
versionSchemaCheckTypev0alpha1 app.VersionSchema
|
||||||
_ = json.Unmarshal(rawSchemaCheckTypev0alpha1, &versionSchemaCheckTypev0alpha1)
|
_ = json.Unmarshal(rawSchemaCheckTypev0alpha1, &versionSchemaCheckTypev0alpha1)
|
||||||
)
|
)
|
||||||
|
|
||||||
var appManifestData = app.ManifestData{
|
var appManifestData = app.ManifestData{
|
||||||
AppName: "advisor",
|
AppName: "advisor",
|
||||||
Group: "advisor.grafana.app",
|
Group: "advisor.grafana.app",
|
||||||
|
PreferredVersion: "v0alpha1",
|
||||||
Versions: []app.ManifestVersion{
|
Versions: []app.ManifestVersion{
|
||||||
{
|
{
|
||||||
Name: "v0alpha1",
|
Name: "v0alpha1",
|
||||||
@@ -57,6 +61,11 @@ var appManifestData = app.ManifestData{
|
|||||||
Schema: &versionSchemaCheckTypev0alpha1,
|
Schema: &versionSchemaCheckTypev0alpha1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Routes: app.ManifestVersionRoutes{
|
||||||
|
Namespaced: map[string]spec3.PathProps{},
|
||||||
|
Cluster: map[string]spec3.PathProps{},
|
||||||
|
Schemas: map[string]spec.Schema{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -86,6 +95,7 @@ var customRouteToGoResponseType = map[string]any{}
|
|||||||
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
|
// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists.
|
||||||
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
|
// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths.
|
||||||
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
|
// If there is no association for the provided kind, version, custom route path, and method, exists will return false.
|
||||||
|
// Resource routes (those without a kind) should prefix their route with "<namespace>/" if the route is namespaced (otherwise the route is assumed to be cluster-scope)
|
||||||
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
if len(path) > 0 && path[0] == '/' {
|
if len(path) > 0 && path[0] == '/' {
|
||||||
path = path[1:]
|
path = path[1:]
|
||||||
@@ -93,3 +103,42 @@ func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (g
|
|||||||
goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
||||||
return goType, exists
|
return goType, exists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var customRouteToGoParamsType = map[string]runtime.Object{}
|
||||||
|
|
||||||
|
func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goType runtime.Object, exists bool) {
|
||||||
|
if len(path) > 0 && path[0] == '/' {
|
||||||
|
path = path[1:]
|
||||||
|
}
|
||||||
|
goType, exists = customRouteToGoParamsType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
||||||
|
return goType, exists
|
||||||
|
}
|
||||||
|
|
||||||
|
var customRouteToGoRequestBodyType = map[string]any{}
|
||||||
|
|
||||||
|
func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
|
if len(path) > 0 && path[0] == '/' {
|
||||||
|
path = path[1:]
|
||||||
|
}
|
||||||
|
goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))]
|
||||||
|
return goType, exists
|
||||||
|
}
|
||||||
|
|
||||||
|
type GoTypeAssociator struct{}
|
||||||
|
|
||||||
|
func NewGoTypeAssociator() *GoTypeAssociator {
|
||||||
|
return &GoTypeAssociator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) {
|
||||||
|
return ManifestGoTypeAssociator(kind, version)
|
||||||
|
}
|
||||||
|
func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
|
return ManifestCustomRouteResponsesAssociator(kind, version, path, verb)
|
||||||
|
}
|
||||||
|
func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) {
|
||||||
|
return ManifestCustomRouteQueryAssociator(kind, version, path, verb)
|
||||||
|
}
|
||||||
|
func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) {
|
||||||
|
return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb)
|
||||||
|
}
|
||||||
|
|||||||
@@ -69,12 +69,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||||||
go func() {
|
go func() {
|
||||||
logger := log.WithContext(ctx).With("check", check.ID())
|
logger := log.WithContext(ctx).With("check", check.ID())
|
||||||
logger.Debug("Processing check", "namespace", req.Object.GetNamespace())
|
logger.Debug("Processing check", "namespace", req.Object.GetNamespace())
|
||||||
requester, err := identity.GetRequester(ctx)
|
orgID, err := getOrgIDFromNamespace(req.Object.GetNamespace())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error getting requester", "error", err)
|
logger.Error("Error getting org ID from namespace", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), requester.GetOrgID())
|
ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), orgID)
|
||||||
err = processCheck(ctx, logger, client, typesClient, req.Object, check)
|
err = processCheck(ctx, logger, client, typesClient, req.Object, check)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error processing check", "error", err)
|
logger.Error("Error processing check", "error", err)
|
||||||
@@ -85,12 +85,12 @@ func New(cfg app.Config) (app.App, error) {
|
|||||||
go func() {
|
go func() {
|
||||||
logger := log.WithContext(ctx).With("check", check.ID())
|
logger := log.WithContext(ctx).With("check", check.ID())
|
||||||
logger.Debug("Updating check", "namespace", req.Object.GetNamespace(), "name", req.Object.GetName())
|
logger.Debug("Updating check", "namespace", req.Object.GetNamespace(), "name", req.Object.GetName())
|
||||||
requester, err := identity.GetRequester(ctx)
|
orgID, err := getOrgIDFromNamespace(req.Object.GetNamespace())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error getting requester", "error", err)
|
logger.Error("Error getting org ID from namespace", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), requester.GetOrgID())
|
ctx = identity.WithServiceIdentityContext(context.WithoutCancel(ctx), orgID)
|
||||||
err = processCheckRetry(ctx, logger, client, typesClient, req.Object, check)
|
err = processCheckRetry(ctx, logger, client, typesClient, req.Object, check)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error processing check retry", "error", err)
|
logger.Error("Error processing check retry", "error", err)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/repo"
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/managedplugins"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||||
@@ -91,4 +92,5 @@ type AdvisorAppConfig struct {
|
|||||||
CheckRegistry CheckService
|
CheckRegistry CheckService
|
||||||
PluginConfig map[string]string
|
PluginConfig map[string]string
|
||||||
StackID string
|
StackID string
|
||||||
|
OrgService org.Service
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package mockchecks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry/mockchecks/mocksvcs"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks/datasourcecheck"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks/plugincheck"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||||
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginchecker"
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mockchecks.CheckRegistry is a mock implementation of the checkregistry.CheckService interface
|
||||||
|
// TODO: Add mocked checks here
|
||||||
|
type CheckRegistry struct {
|
||||||
|
datasourceSvc datasources.DataSourceService
|
||||||
|
pluginStore pluginstore.Store
|
||||||
|
pluginClient plugins.Client
|
||||||
|
pluginRepo repo.Service
|
||||||
|
GrafanaVersion string
|
||||||
|
pluginContextProvider datasourcecheck.PluginContextProvider
|
||||||
|
updateChecker pluginchecker.PluginUpdateChecker
|
||||||
|
pluginErrorResolver plugins.ErrorResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *CheckRegistry) Checks() []checks.Check {
|
||||||
|
return []checks.Check{
|
||||||
|
datasourcecheck.New(
|
||||||
|
m.datasourceSvc,
|
||||||
|
m.pluginStore,
|
||||||
|
m.pluginContextProvider,
|
||||||
|
m.pluginClient,
|
||||||
|
m.pluginRepo,
|
||||||
|
m.GrafanaVersion,
|
||||||
|
),
|
||||||
|
plugincheck.New(
|
||||||
|
m.pluginStore,
|
||||||
|
m.pluginRepo,
|
||||||
|
m.updateChecker,
|
||||||
|
m.pluginErrorResolver,
|
||||||
|
m.GrafanaVersion,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *CheckRegistry {
|
||||||
|
return &CheckRegistry{
|
||||||
|
datasourceSvc: &mocksvcs.DatasourceSvc{},
|
||||||
|
pluginStore: &mocksvcs.PluginStore{},
|
||||||
|
pluginClient: &mocksvcs.PluginClient{},
|
||||||
|
pluginRepo: &mocksvcs.PluginRepo{},
|
||||||
|
pluginContextProvider: &mocksvcs.PluginContextProvider{},
|
||||||
|
updateChecker: &mocksvcs.UpdateChecker{},
|
||||||
|
pluginErrorResolver: &mocksvcs.PluginErrorResolver{},
|
||||||
|
GrafanaVersion: "1.0.0",
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dss = map[string]*datasources.DataSource{
|
||||||
|
"prometheus-uid": {
|
||||||
|
ID: 1,
|
||||||
|
UID: "prometheus-uid",
|
||||||
|
Name: "Prometheus",
|
||||||
|
Type: "prometheus",
|
||||||
|
},
|
||||||
|
"mysql-uid": {
|
||||||
|
ID: 2,
|
||||||
|
UID: "mysql-uid",
|
||||||
|
Name: "MySQL",
|
||||||
|
Type: "mysql",
|
||||||
|
},
|
||||||
|
"unknown-uid": {
|
||||||
|
ID: 3,
|
||||||
|
UID: "unknown-uid",
|
||||||
|
Name: "Unknown",
|
||||||
|
Type: "unknown",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type DatasourceSvc struct {
|
||||||
|
datasources.DataSourceService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *DatasourceSvc) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) {
|
||||||
|
sources := make([]*datasources.DataSource, 0, len(dss))
|
||||||
|
for _, ds := range dss {
|
||||||
|
sources = append(sources, ds)
|
||||||
|
}
|
||||||
|
return sources, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *DatasourceSvc) GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) (*datasources.DataSource, error) {
|
||||||
|
return dss[query.UID], nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginClient struct {
|
||||||
|
plugins.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginClient) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
|
||||||
|
return &backend.CheckHealthResult{
|
||||||
|
Status: backend.HealthStatusOk,
|
||||||
|
Message: "Plugin is healthy",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginContextProvider struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACTUALLY USED by datasourcecheck
|
||||||
|
func (m *PluginContextProvider) GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error) {
|
||||||
|
// Create a plugin context with sample data based on the datasource
|
||||||
|
pluginContext := backend.PluginContext{
|
||||||
|
PluginID: pluginID,
|
||||||
|
PluginVersion: "1.0.0",
|
||||||
|
OrgID: 1,
|
||||||
|
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{
|
||||||
|
ID: ds.ID,
|
||||||
|
UID: ds.UID,
|
||||||
|
Name: ds.Name,
|
||||||
|
URL: ds.URL,
|
||||||
|
JSONData: []byte(`{
|
||||||
|
"httpMethod": "GET",
|
||||||
|
"timeout": "30s",
|
||||||
|
"keepCookies": []
|
||||||
|
}`),
|
||||||
|
DecryptedSecureJSONData: map[string]string{
|
||||||
|
"password": "sample-password",
|
||||||
|
"apiKey": "sample-api-key",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
GrafanaConfig: backend.NewGrafanaCfg(map[string]string{
|
||||||
|
"app_url": "http://localhost:3000",
|
||||||
|
"default_timezone": "UTC",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add user context if provided
|
||||||
|
if user != nil && !user.IsNil() {
|
||||||
|
pluginContext.User = &backend.User{
|
||||||
|
Login: user.GetLogin(),
|
||||||
|
Name: user.GetName(),
|
||||||
|
Email: user.GetEmail(),
|
||||||
|
Role: string(user.GetOrgRole()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pluginContext, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginErrorResolver struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume no plugin with errors
|
||||||
|
func (m *PluginErrorResolver) PluginErrors(ctx context.Context) []*plugins.Error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginErrorResolver) PluginError(ctx context.Context, pluginID string) *plugins.Error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginRepo struct {
|
||||||
|
repo.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PluginRepo) GetPluginsInfo(ctx context.Context, options repo.GetPluginsInfoOptions, compatOpts repo.CompatOpts) ([]repo.PluginInfo, error) {
|
||||||
|
return []repo.PluginInfo{
|
||||||
|
{
|
||||||
|
ID: 1,
|
||||||
|
Slug: "grafana-piechart-panel",
|
||||||
|
Version: "1.6.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: 2,
|
||||||
|
Slug: "prometheus",
|
||||||
|
Version: "10.0.0",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PluginStore struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
var ps = map[string]pluginstore.Plugin{
|
||||||
|
"prometheus": {
|
||||||
|
JSONData: plugins.JSONData{
|
||||||
|
ID: "prometheus",
|
||||||
|
Type: plugins.TypeDataSource,
|
||||||
|
Name: "Prometheus",
|
||||||
|
Info: plugins.Info{
|
||||||
|
Author: plugins.InfoLink{
|
||||||
|
Name: "Grafana Labs",
|
||||||
|
},
|
||||||
|
Version: "10.0.0",
|
||||||
|
},
|
||||||
|
Category: "Time series databases",
|
||||||
|
State: plugins.ReleaseStateAlpha,
|
||||||
|
Backend: true,
|
||||||
|
Metrics: true,
|
||||||
|
Logs: true,
|
||||||
|
Alerting: true,
|
||||||
|
Explore: true,
|
||||||
|
},
|
||||||
|
Class: plugins.ClassCore,
|
||||||
|
Signature: plugins.SignatureStatusInternal,
|
||||||
|
SignatureType: plugins.SignatureTypeGrafana,
|
||||||
|
SignatureOrg: "grafana.com",
|
||||||
|
},
|
||||||
|
"test-datasource": {
|
||||||
|
JSONData: plugins.JSONData{
|
||||||
|
ID: "grafana-piechart-panel",
|
||||||
|
Type: plugins.TypePanel,
|
||||||
|
Name: "Pie Chart",
|
||||||
|
Info: plugins.Info{
|
||||||
|
Author: plugins.InfoLink{
|
||||||
|
Name: "Grafana Labs",
|
||||||
|
},
|
||||||
|
Version: "1.6.0",
|
||||||
|
},
|
||||||
|
Category: "Visualization",
|
||||||
|
State: plugins.ReleaseStateAlpha,
|
||||||
|
},
|
||||||
|
Class: plugins.ClassCore,
|
||||||
|
Signature: plugins.SignatureStatusInternal,
|
||||||
|
SignatureType: plugins.SignatureTypeGrafana,
|
||||||
|
SignatureOrg: "grafana.com",
|
||||||
|
},
|
||||||
|
"grafana-piechart-panel": {
|
||||||
|
JSONData: plugins.JSONData{
|
||||||
|
ID: "prometheus",
|
||||||
|
Type: plugins.TypeDataSource,
|
||||||
|
Name: "Prometheus",
|
||||||
|
Info: plugins.Info{
|
||||||
|
Author: plugins.InfoLink{
|
||||||
|
Name: "Grafana Labs",
|
||||||
|
},
|
||||||
|
Version: "10.0.0",
|
||||||
|
},
|
||||||
|
Category: "Time series databases",
|
||||||
|
State: plugins.ReleaseStateAlpha,
|
||||||
|
Backend: true,
|
||||||
|
Metrics: true,
|
||||||
|
Logs: true,
|
||||||
|
Alerting: true,
|
||||||
|
Explore: true,
|
||||||
|
},
|
||||||
|
Class: plugins.ClassCore,
|
||||||
|
Signature: plugins.SignatureStatusInternal,
|
||||||
|
SignatureType: plugins.SignatureTypeGrafana,
|
||||||
|
SignatureOrg: "grafana.com",
|
||||||
|
},
|
||||||
|
"test-app": {
|
||||||
|
JSONData: plugins.JSONData{
|
||||||
|
ID: "test-app",
|
||||||
|
Type: plugins.TypeApp,
|
||||||
|
Name: "Test App",
|
||||||
|
Info: plugins.Info{
|
||||||
|
Author: plugins.InfoLink{
|
||||||
|
Name: "Test Author",
|
||||||
|
},
|
||||||
|
Version: "2.0.0",
|
||||||
|
},
|
||||||
|
Category: "Application",
|
||||||
|
State: plugins.ReleaseStateAlpha,
|
||||||
|
AutoEnabled: true,
|
||||||
|
},
|
||||||
|
Class: plugins.ClassExternal,
|
||||||
|
Signature: plugins.SignatureStatusValid,
|
||||||
|
SignatureType: plugins.SignatureTypeCommercial,
|
||||||
|
SignatureOrg: "test.com",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PluginStore) Plugin(ctx context.Context, pluginID string) (pluginstore.Plugin, bool) {
|
||||||
|
p, ok := ps[pluginID]
|
||||||
|
return p, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PluginStore) Plugins(ctx context.Context, pluginTypes ...plugins.Type) []pluginstore.Plugin {
|
||||||
|
plugins := make([]pluginstore.Plugin, 0, len(ps))
|
||||||
|
for _, p := range ps {
|
||||||
|
plugins = append(plugins, p)
|
||||||
|
}
|
||||||
|
return plugins
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package mocksvcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateChecker struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UpdateChecker) IsUpdatable(ctx context.Context, plugin pluginstore.Plugin) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UpdateChecker) CanUpdate(pluginId string, currentVersion string, targetVersion string, onlyMinor bool) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ package datasourcecheck
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
sysruntime "runtime"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
@@ -18,37 +20,47 @@ const (
|
|||||||
HealthCheckStepID = "health-check"
|
HealthCheckStepID = "health-check"
|
||||||
UIDValidationStepID = "uid-validation"
|
UIDValidationStepID = "uid-validation"
|
||||||
MissingPluginStepID = "missing-plugin"
|
MissingPluginStepID = "missing-plugin"
|
||||||
|
PromDepAuthStepID = "prom-dep-auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
type check struct {
|
type check struct {
|
||||||
DatasourceSvc datasources.DataSourceService
|
DatasourceSvc datasources.DataSourceService
|
||||||
PluginStore pluginstore.Store
|
PluginStore pluginstore.Store
|
||||||
PluginContextProvider pluginContextProvider
|
PluginContextProvider PluginContextProvider
|
||||||
PluginClient plugins.Client
|
PluginClient plugins.Client
|
||||||
PluginRepo repo.Service
|
PluginRepo repo.Service
|
||||||
GrafanaVersion string
|
GrafanaVersion string
|
||||||
|
pluginCanBeInstalledCache map[string]bool
|
||||||
|
pluginExistsCacheMu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
datasourceSvc datasources.DataSourceService,
|
datasourceSvc datasources.DataSourceService,
|
||||||
pluginStore pluginstore.Store,
|
pluginStore pluginstore.Store,
|
||||||
pluginContextProvider pluginContextProvider,
|
pluginContextProvider PluginContextProvider,
|
||||||
pluginClient plugins.Client,
|
pluginClient plugins.Client,
|
||||||
pluginRepo repo.Service,
|
pluginRepo repo.Service,
|
||||||
grafanaVersion string,
|
grafanaVersion string,
|
||||||
) checks.Check {
|
) checks.Check {
|
||||||
return &check{
|
return &check{
|
||||||
DatasourceSvc: datasourceSvc,
|
DatasourceSvc: datasourceSvc,
|
||||||
PluginStore: pluginStore,
|
PluginStore: pluginStore,
|
||||||
PluginContextProvider: pluginContextProvider,
|
PluginContextProvider: pluginContextProvider,
|
||||||
PluginClient: pluginClient,
|
PluginClient: pluginClient,
|
||||||
PluginRepo: pluginRepo,
|
PluginRepo: pluginRepo,
|
||||||
GrafanaVersion: grafanaVersion,
|
GrafanaVersion: grafanaVersion,
|
||||||
|
pluginCanBeInstalledCache: make(map[string]bool),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *check) Items(ctx context.Context) ([]any, error) {
|
func (c *check) Items(ctx context.Context) ([]any, error) {
|
||||||
dss, err := c.DatasourceSvc.GetAllDataSources(ctx, &datasources.GetAllDataSourcesQuery{})
|
requester, err := identity.GetRequester(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dss, err := c.DatasourceSvc.GetDataSources(ctx, &datasources.GetDataSourcesQuery{
|
||||||
|
OrgID: requester.GetOrgID(),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -87,6 +99,7 @@ func (c *check) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *check) Init(ctx context.Context) error {
|
func (c *check) Init(ctx context.Context) error {
|
||||||
|
c.pluginCanBeInstalledCache = make(map[string]bool)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +115,59 @@ func (c *check) Steps() []checks.Step {
|
|||||||
PluginRepo: c.PluginRepo,
|
PluginRepo: c.PluginRepo,
|
||||||
GrafanaVersion: c.GrafanaVersion,
|
GrafanaVersion: c.GrafanaVersion,
|
||||||
},
|
},
|
||||||
|
&promDepAuthStep{
|
||||||
|
canBeInstalled: c.canBeInstalled,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type pluginContextProvider interface {
|
// canBeInstalled checks if a plugin is already installed or if it's available in the plugin repository.
|
||||||
|
// Returns true if:
|
||||||
|
// - The plugin is NOT installed AND it IS available in the repository (can be installed)
|
||||||
|
// Returns false if:
|
||||||
|
// - The plugin is already installed, OR
|
||||||
|
// - The plugin is NOT available in the repository (nothing to install)
|
||||||
|
func (c *check) canBeInstalled(ctx context.Context, pluginType string) (bool, error) {
|
||||||
|
// Check cache first with read lock for performance
|
||||||
|
c.pluginExistsCacheMu.RLock()
|
||||||
|
if canBeInstalled, found := c.pluginCanBeInstalledCache[pluginType]; found {
|
||||||
|
c.pluginExistsCacheMu.RUnlock()
|
||||||
|
return canBeInstalled, nil
|
||||||
|
}
|
||||||
|
c.pluginExistsCacheMu.RUnlock()
|
||||||
|
|
||||||
|
// Cache miss - acquire write lock and check again (double-checked locking pattern)
|
||||||
|
c.pluginExistsCacheMu.Lock()
|
||||||
|
defer c.pluginExistsCacheMu.Unlock()
|
||||||
|
|
||||||
|
// Another goroutine may have populated the cache while we waited for the lock
|
||||||
|
if canBeInstalled, found := c.pluginCanBeInstalledCache[pluginType]; found {
|
||||||
|
return canBeInstalled, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if plugin is already installed
|
||||||
|
if _, isInstalled := c.PluginStore.Plugin(ctx, pluginType); isInstalled {
|
||||||
|
c.pluginCanBeInstalledCache[pluginType] = false
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin is not installed - check if it's available in the repository
|
||||||
|
availablePlugins, err := c.PluginRepo.GetPluginsInfo(ctx, repo.GetPluginsInfoOptions{
|
||||||
|
IncludeDeprecated: true,
|
||||||
|
Plugins: []string{pluginType},
|
||||||
|
}, repo.NewCompatOpts(c.GrafanaVersion, sysruntime.GOOS, sysruntime.GOARCH))
|
||||||
|
if err != nil {
|
||||||
|
// On error, assume plugin is installed/unavailable to avoid showing incorrect install links
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin is not installed but IS available - return false to show install link
|
||||||
|
// Plugin is not installed and NOT available in repo - return true (nothing to install)
|
||||||
|
isAvailableInRepo := len(availablePlugins) > 0
|
||||||
|
c.pluginCanBeInstalledCache[pluginType] = !isAvailableInRepo
|
||||||
|
return isAvailableInRepo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type PluginContextProvider interface {
|
||||||
GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error)
|
GetWithDataSource(ctx context.Context, pluginID string, user identity.Requester, ds *datasources.DataSource) (backend.PluginContext, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||||
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/repo"
|
"github.com/grafana/grafana/pkg/plugins/repo"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
@@ -230,6 +231,101 @@ func TestCheck_Run(t *testing.T) {
|
|||||||
assert.Equal(t, MissingPluginStepID, failures[0].StepID)
|
assert.Equal(t, MissingPluginStepID, failures[0].StepID)
|
||||||
assert.Len(t, failures[0].Links, 1)
|
assert.Len(t, failures[0].Links, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("should return failure when prometheus datasource uses SigV4 auth", func(t *testing.T) {
|
||||||
|
jsonData := simplejson.New()
|
||||||
|
jsonData.Set("sigV4Auth", true)
|
||||||
|
datasources := []*datasources.DataSource{
|
||||||
|
{UID: "valid-uid-1", Type: "prometheus", Name: "Prometheus", JsonData: jsonData},
|
||||||
|
}
|
||||||
|
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
|
||||||
|
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
|
||||||
|
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
|
||||||
|
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
|
||||||
|
{ID: 1, Slug: "prometheus", Status: "active"},
|
||||||
|
{ID: 2, Slug: "grafana-amazonprometheus-datasource", Status: "active"},
|
||||||
|
}}
|
||||||
|
mockPluginStore := &MockPluginStore{exists: true}
|
||||||
|
|
||||||
|
check := &check{
|
||||||
|
DatasourceSvc: mockDatasourceSvc,
|
||||||
|
PluginContextProvider: mockPluginContextProvider,
|
||||||
|
PluginClient: mockPluginClient,
|
||||||
|
PluginRepo: mockPluginRepo,
|
||||||
|
PluginStore: mockPluginStore,
|
||||||
|
GrafanaVersion: "11.0.0",
|
||||||
|
}
|
||||||
|
|
||||||
|
failures, err := runChecks(check)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, failures, 1)
|
||||||
|
assert.Equal(t, PromDepAuthStepID, failures[0].StepID)
|
||||||
|
assert.Contains(t, failures[0].Links, advisor.CheckErrorLink{
|
||||||
|
Message: "View SigV4 docs",
|
||||||
|
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/aws-authentication/",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should return failure when prometheus datasource uses Azure auth", func(t *testing.T) {
|
||||||
|
jsonData := simplejson.New()
|
||||||
|
jsonData.Set("azureCredentials", map[string]interface{}{"authType": "msi"})
|
||||||
|
datasources := []*datasources.DataSource{
|
||||||
|
{UID: "valid-uid-1", Type: "prometheus", Name: "Prometheus", JsonData: jsonData},
|
||||||
|
}
|
||||||
|
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
|
||||||
|
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
|
||||||
|
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
|
||||||
|
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
|
||||||
|
{ID: 1, Slug: "prometheus", Status: "active"},
|
||||||
|
{ID: 2, Slug: "grafana-azureprometheus-datasource", Status: "active"},
|
||||||
|
}}
|
||||||
|
mockPluginStore := &MockPluginStore{exists: true}
|
||||||
|
|
||||||
|
check := &check{
|
||||||
|
DatasourceSvc: mockDatasourceSvc,
|
||||||
|
PluginContextProvider: mockPluginContextProvider,
|
||||||
|
PluginClient: mockPluginClient,
|
||||||
|
PluginRepo: mockPluginRepo,
|
||||||
|
PluginStore: mockPluginStore,
|
||||||
|
GrafanaVersion: "11.0.0",
|
||||||
|
}
|
||||||
|
|
||||||
|
failures, err := runChecks(check)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, failures, 1)
|
||||||
|
assert.Equal(t, PromDepAuthStepID, failures[0].StepID)
|
||||||
|
assert.Contains(t, failures[0].Links, advisor.CheckErrorLink{
|
||||||
|
Message: "View Azure auth docs",
|
||||||
|
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/azure-authentication/",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should not return failure when prometheus datasource does not use deprecated auth", func(t *testing.T) {
|
||||||
|
jsonData := simplejson.New()
|
||||||
|
datasources := []*datasources.DataSource{
|
||||||
|
{UID: "valid-uid-1", Type: "prometheus", Name: "Prometheus", JsonData: jsonData},
|
||||||
|
}
|
||||||
|
mockDatasourceSvc := &MockDatasourceSvc{dss: datasources}
|
||||||
|
mockPluginContextProvider := &MockPluginContextProvider{pCtx: backend.PluginContext{}}
|
||||||
|
mockPluginClient := &MockPluginClient{res: &backend.CheckHealthResult{Status: backend.HealthStatusOk}}
|
||||||
|
mockPluginRepo := &MockPluginRepo{plugins: []repo.PluginInfo{
|
||||||
|
{ID: 1, Slug: "prometheus", Status: "active"},
|
||||||
|
}}
|
||||||
|
mockPluginStore := &MockPluginStore{exists: true}
|
||||||
|
|
||||||
|
check := &check{
|
||||||
|
DatasourceSvc: mockDatasourceSvc,
|
||||||
|
PluginContextProvider: mockPluginContextProvider,
|
||||||
|
PluginClient: mockPluginClient,
|
||||||
|
PluginRepo: mockPluginRepo,
|
||||||
|
PluginStore: mockPluginStore,
|
||||||
|
GrafanaVersion: "11.0.0",
|
||||||
|
}
|
||||||
|
|
||||||
|
failures, err := runChecks(check)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, failures)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheck_Item(t *testing.T) {
|
func TestCheck_Item(t *testing.T) {
|
||||||
@@ -251,7 +347,7 @@ type MockDatasourceSvc struct {
|
|||||||
dss []*datasources.DataSource
|
dss []*datasources.DataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockDatasourceSvc) GetAllDataSources(context.Context, *datasources.GetAllDataSourcesQuery) ([]*datasources.DataSource, error) {
|
func (m *MockDatasourceSvc) GetDataSources(context.Context, *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) {
|
||||||
return m.dss, nil
|
return m.dss, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type healthCheckStep struct {
|
type healthCheckStep struct {
|
||||||
PluginContextProvider pluginContextProvider
|
PluginContextProvider PluginContextProvider
|
||||||
PluginClient plugins.Client
|
PluginClient plugins.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
package datasourcecheck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-app-sdk/logging"
|
||||||
|
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
|
)
|
||||||
|
|
||||||
|
type promDepAuthStep struct {
|
||||||
|
canBeInstalled func(ctx context.Context, pluginType string) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *promDepAuthStep) Title() string {
|
||||||
|
return "Prometheus deprecated authentication check"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *promDepAuthStep) Description() string {
|
||||||
|
return "Check if Prometheus data sources are using deprecated authentication methods (Azure auth and SigV4)"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *promDepAuthStep) Resolution() string {
|
||||||
|
return fmt.Sprintf("Enable the feature toggle for 'prometheusTypeMigration'. If this feature toggle is already enabled, make sure that 'Azure Monitor Managed Service for Prometheus' and/or 'Amazon Managed Service for Prometheus' plugins are installed. If the data source is provisioned, edit data source type in the provisioning file to use '%s' or '%s'.", datasources.DS_AMAZON_PROMETHEUS, datasources.DS_AZURE_PROMETHEUS)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *promDepAuthStep) ID() string {
|
||||||
|
return PromDepAuthStepID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *promDepAuthStep) Run(ctx context.Context, log logging.Logger, obj *advisor.CheckSpec, item any) ([]advisor.CheckReportFailure, error) {
|
||||||
|
dataSource, ok := item.(*datasources.DataSource)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("invalid item type %T", item)
|
||||||
|
}
|
||||||
|
if dataSource.Type != datasources.DS_PROMETHEUS {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if dataSource.JsonData == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
awsAuthLinks, err := s.checkUsingAWSAuth(ctx, dataSource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
azureAuthLinks, err := s.checkUsingAzureAuth(ctx, dataSource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
errorLinks := append(awsAuthLinks, azureAuthLinks...)
|
||||||
|
|
||||||
|
if len(errorLinks) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []advisor.CheckReportFailure{checks.NewCheckReportFailureWithMoreInfo(
|
||||||
|
advisor.CheckReportFailureSeverityHigh,
|
||||||
|
s.ID(),
|
||||||
|
dataSource.Name,
|
||||||
|
dataSource.UID,
|
||||||
|
errorLinks,
|
||||||
|
fmt.Sprintf("Datasource %s (UID: %s) is of type %s but it's using a deprecated authentication method so it should be migrated", dataSource.Name, dataSource.UID, dataSource.Type),
|
||||||
|
)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *promDepAuthStep) checkUsingAWSAuth(ctx context.Context, dataSource *datasources.DataSource) ([]advisor.CheckErrorLink, error) {
|
||||||
|
var errorLinks []advisor.CheckErrorLink
|
||||||
|
if sigV4Auth, found := dataSource.JsonData.CheckGet("sigV4Auth"); found {
|
||||||
|
if enabled, err := sigV4Auth.Bool(); err != nil || !enabled {
|
||||||
|
// Disabled or not a valid boolean
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
readOnlyLink := checkReadOnly(dataSource)
|
||||||
|
|
||||||
|
if readOnlyLink != nil {
|
||||||
|
errorLinks = append(errorLinks, *readOnlyLink)
|
||||||
|
}
|
||||||
|
|
||||||
|
errorLinks = append(errorLinks,
|
||||||
|
advisor.CheckErrorLink{
|
||||||
|
Message: "View SigV4 docs",
|
||||||
|
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/aws-authentication/",
|
||||||
|
})
|
||||||
|
pluginLink := s.linkDataSource(ctx, datasources.DS_AMAZON_PROMETHEUS, "Amazon Managed Service for Prometheus")
|
||||||
|
if pluginLink != nil {
|
||||||
|
errorLinks = append(errorLinks, *pluginLink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errorLinks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *promDepAuthStep) checkUsingAzureAuth(ctx context.Context, dataSource *datasources.DataSource) ([]advisor.CheckErrorLink, error) {
|
||||||
|
var errorLinks []advisor.CheckErrorLink
|
||||||
|
if azureAuth, found := dataSource.JsonData.CheckGet("azureCredentials"); found {
|
||||||
|
if _, err := azureAuth.Value(); err != nil {
|
||||||
|
// azureAuth does not have a value
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
readOnlyLink := checkReadOnly(dataSource)
|
||||||
|
if readOnlyLink != nil {
|
||||||
|
errorLinks = append(errorLinks, *readOnlyLink)
|
||||||
|
}
|
||||||
|
errorLinks = append(errorLinks,
|
||||||
|
advisor.CheckErrorLink{
|
||||||
|
Message: "View Azure auth docs",
|
||||||
|
Url: "https://grafana.com/docs/grafana-cloud/connect-externally-hosted/data-sources/prometheus/configure/azure-authentication/",
|
||||||
|
})
|
||||||
|
pluginLink := s.linkDataSource(ctx, datasources.DS_AZURE_PROMETHEUS, "Azure Monitor Managed Service for Prometheus")
|
||||||
|
if pluginLink != nil {
|
||||||
|
errorLinks = append(errorLinks, *pluginLink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errorLinks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkReadOnly(dataSource *datasources.DataSource) *advisor.CheckErrorLink {
|
||||||
|
if readOnly, found := dataSource.JsonData.CheckGet("readonly"); found {
|
||||||
|
if enabled, err := readOnly.Bool(); err != nil || !enabled {
|
||||||
|
// Disabled or not a valid boolean
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &advisor.CheckErrorLink{
|
||||||
|
Message: "Change provisioning file",
|
||||||
|
Url: "https://grafana.com/docs/grafana/latest/administration/provisioning/#data-sources",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *promDepAuthStep) linkDataSource(ctx context.Context, pluginType string, pluginName string) *advisor.CheckErrorLink {
|
||||||
|
canBeInstalled, err := s.canBeInstalled(ctx, pluginType)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if canBeInstalled {
|
||||||
|
// Plugin is available in the repo
|
||||||
|
return &advisor.CheckErrorLink{
|
||||||
|
Message: fmt.Sprintf("Install %s", pluginName),
|
||||||
|
Url: fmt.Sprintf("/plugins/%s", pluginType),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/grafana/authlib/types"
|
"github.com/grafana/authlib/types"
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisor "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -57,15 +57,26 @@ func NewCheckReportFailureWithMoreInfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetNamespace(stackID string) (string, error) {
|
func GetNamespaces(ctx context.Context, stackID string, orgService org.Service) ([]string, error) {
|
||||||
if stackID == "" {
|
var namespaces []string
|
||||||
return metav1.NamespaceDefault, nil
|
if stackID != "" {
|
||||||
|
// Single namespace for cloud stack
|
||||||
|
stackId, err := strconv.ParseInt(stackID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid stack id: %s", stackID)
|
||||||
|
}
|
||||||
|
namespaces = []string{types.CloudNamespaceFormatter(stackId)}
|
||||||
|
} else {
|
||||||
|
// Multiple namespaces for each org
|
||||||
|
orgs, err := orgService.Search(ctx, &org.SearchOrgsQuery{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch orgs: %w", err)
|
||||||
|
}
|
||||||
|
for _, o := range orgs {
|
||||||
|
namespaces = append(namespaces, types.OrgNamespaceFormatter(o.ID))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stackId, err := strconv.ParseInt(stackID, 10, 64)
|
return namespaces, nil
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("invalid stack id: %s", stackID)
|
|
||||||
}
|
|
||||||
return types.CloudNamespaceFormatter(stackId), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetStatusAnnotation(obj resource.Object) string {
|
func GetStatusAnnotation(obj resource.Object) string {
|
||||||
|
|||||||
@@ -1,40 +1,61 @@
|
|||||||
package checks
|
package checks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetNamespace(t *testing.T) {
|
func TestGetNamespaces(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
input string
|
stackID string
|
||||||
expected string
|
orgs []string
|
||||||
|
expected []string
|
||||||
expectedErr string
|
expectedErr string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty stack ID",
|
name: "empty stack ID",
|
||||||
input: "",
|
stackID: "",
|
||||||
expected: metav1.NamespaceDefault,
|
orgs: []string{"default"},
|
||||||
|
expected: []string{metav1.NamespaceDefault},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "valid stack ID",
|
name: "valid stack ID",
|
||||||
input: "1234567890",
|
stackID: "1234567890",
|
||||||
expected: "stacks-1234567890",
|
orgs: []string{"default"},
|
||||||
|
expected: []string{"stacks-1234567890"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid stack ID",
|
name: "invalid stack ID",
|
||||||
input: "invalid",
|
stackID: "invalid",
|
||||||
expected: "",
|
orgs: []string{"default"},
|
||||||
|
expected: nil,
|
||||||
expectedErr: "invalid stack id: invalid",
|
expectedErr: "invalid stack id: invalid",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "multiple orgs and no stack ID",
|
||||||
|
stackID: "",
|
||||||
|
orgs: []string{"default", "org-2"},
|
||||||
|
expected: []string{"default", "org-2"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
result, err := GetNamespace(tt.input)
|
fakeOrgService := &mockOrgService{
|
||||||
|
SearchFunc: func(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
|
||||||
|
orgs := make([]*org.OrgDTO, len(tt.orgs))
|
||||||
|
for i, o := range tt.orgs {
|
||||||
|
orgs[i] = &org.OrgDTO{ID: int64(i + 1), Name: o}
|
||||||
|
}
|
||||||
|
return orgs, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
result, err := GetNamespaces(context.Background(), tt.stackID, fakeOrgService)
|
||||||
if tt.expectedErr != "" {
|
if tt.expectedErr != "" {
|
||||||
assert.EqualError(t, err, tt.expectedErr)
|
assert.EqualError(t, err, tt.expectedErr)
|
||||||
} else {
|
} else {
|
||||||
@@ -44,3 +65,12 @@ func TestGetNamespace(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockOrgService struct {
|
||||||
|
org.Service
|
||||||
|
SearchFunc func(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockOrgService) Search(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
|
||||||
|
return m.SearchFunc(ctx, query)
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,21 +24,23 @@ const defaultEvaluationInterval = 7 * 24 * time.Hour // 7 days
|
|||||||
const defaultMaxHistory = 10
|
const defaultMaxHistory = 10
|
||||||
|
|
||||||
var (
|
var (
|
||||||
waitInterval = 5 * time.Second
|
waitInterval = 5 * time.Second
|
||||||
waitMaxRetries = 3
|
waitMaxRetries = 3
|
||||||
|
evalIntervalRandomVariation = 1 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
// Runner is a "runnable" app used to be able to expose and API endpoint
|
// Runner is a "runnable" app used to be able to expose and API endpoint
|
||||||
// with the existing checks types. This does not need to be a CRUD resource, but it is
|
// with the existing checks types. This does not need to be a CRUD resource, but it is
|
||||||
// the only way existing at the moment to expose the check types.
|
// the only way existing at the moment to expose the check types.
|
||||||
type Runner struct {
|
type Runner struct {
|
||||||
checkRegistry checkregistry.CheckService
|
checkRegistry checkregistry.CheckService
|
||||||
client resource.Client
|
checksClient resource.Client
|
||||||
typesClient resource.Client
|
typesClient resource.Client
|
||||||
evaluationInterval time.Duration
|
defaultEvalInterval time.Duration
|
||||||
maxHistory int
|
maxHistory int
|
||||||
namespace string
|
log logging.Logger
|
||||||
log logging.Logger
|
orgService org.Service
|
||||||
|
stackID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRunner creates a new Runner.
|
// NewRunner creates a new Runner.
|
||||||
@@ -48,6 +51,7 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
|||||||
return nil, fmt.Errorf("invalid config type")
|
return nil, fmt.Errorf("invalid config type")
|
||||||
}
|
}
|
||||||
checkRegistry := specificConfig.CheckRegistry
|
checkRegistry := specificConfig.CheckRegistry
|
||||||
|
orgService := specificConfig.OrgService
|
||||||
evalInterval, err := getEvaluationInterval(specificConfig.PluginConfig)
|
evalInterval, err := getEvaluationInterval(specificConfig.PluginConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -56,10 +60,6 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
namespace, err := checks.GetNamespace(specificConfig.StackID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare storage client
|
// Prepare storage client
|
||||||
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
|
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
|
||||||
@@ -73,13 +73,14 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Runner{
|
return &Runner{
|
||||||
checkRegistry: checkRegistry,
|
checkRegistry: checkRegistry,
|
||||||
client: client,
|
checksClient: client,
|
||||||
typesClient: typesClient,
|
typesClient: typesClient,
|
||||||
evaluationInterval: evalInterval,
|
defaultEvalInterval: evalInterval,
|
||||||
maxHistory: maxHistory,
|
maxHistory: maxHistory,
|
||||||
namespace: namespace,
|
log: log.With("runner", "advisor.checkscheduler"),
|
||||||
log: log.With("runner", "advisor.checkscheduler"),
|
orgService: orgService,
|
||||||
|
stackID: specificConfig.StackID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,58 +89,91 @@ func (r *Runner) Run(ctx context.Context) error {
|
|||||||
// We still need the context to eventually be cancelled to exit this function
|
// We still need the context to eventually be cancelled to exit this function
|
||||||
// but we don't want the requests to fail because of it
|
// but we don't want the requests to fail because of it
|
||||||
ctxWithoutCancel := context.WithoutCancel(ctx)
|
ctxWithoutCancel := context.WithoutCancel(ctx)
|
||||||
lastCreated, err := r.checkLastCreated(ctxWithoutCancel, logger)
|
|
||||||
|
// Determine namespaces based on StackID or OrgID
|
||||||
|
namespaces, err := checks.GetNamespaces(ctxWithoutCancel, r.stackID, r.orgService)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get namespaces: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Scheduling checks", "namespaces", len(namespaces))
|
||||||
|
|
||||||
|
// Get the last created time for this specific namespace
|
||||||
|
lastCreatedMap, err := r.checkLastCreated(ctx, logger, namespaces)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error getting last check creation time", "error", err)
|
logger.Error("Error getting last check creation time", "error", err)
|
||||||
// Wait for interval to create the next scheduled check
|
return err
|
||||||
lastCreated = time.Now()
|
}
|
||||||
} else {
|
|
||||||
// do an initial creation if necessary
|
// If there are checks already created, run an initial cleanup
|
||||||
if lastCreated.IsZero() {
|
for _, namespace := range namespaces {
|
||||||
err = r.createChecks(ctxWithoutCancel, logger)
|
logger = logger.With("namespace", namespace)
|
||||||
if err != nil {
|
lastCreated := lastCreatedMap[namespace]
|
||||||
logger.Error("Error creating new check reports", "error", err)
|
|
||||||
} else {
|
if !lastCreated.IsZero() {
|
||||||
lastCreated = time.Now()
|
err = r.cleanupChecks(ctx, logger, namespace)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Run an initial cleanup to remove old checks
|
|
||||||
err = r.cleanupChecks(ctxWithoutCancel, logger)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error cleaning up old check reports", "error", err)
|
logger.Error("Error cleaning up old check reports", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = r.markUnprocessedChecks(ctx, logger, namespace)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error marking unprocessed checks", "error", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nextSendInterval := getNextSendInterval(lastCreated, r.evaluationInterval)
|
nextEvalTime := r.getNextEvalTime(r.defaultEvalInterval, lastCreatedMap)
|
||||||
ticker := time.NewTicker(nextSendInterval)
|
ticker := time.NewTicker(nextEvalTime)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
err = r.createChecks(ctxWithoutCancel, logger)
|
// Get the current last created time for this namespace
|
||||||
|
lastCreatedMap, err := r.checkLastCreated(ctx, logger, namespaces)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error creating new check reports", "error", err)
|
logger.Error("Error getting last check creation time", "error", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = r.cleanupChecks(ctxWithoutCancel, logger)
|
for _, namespace := range namespaces {
|
||||||
if err != nil {
|
logger = logger.With("namespace", namespace)
|
||||||
logger.Error("Error cleaning up old check reports", "error", err)
|
lastCreated := lastCreatedMap[namespace]
|
||||||
|
|
||||||
|
// If there are checks already created and they are older than the evaluation interval
|
||||||
|
// then we can automatically create more
|
||||||
|
if !lastCreated.IsZero() && lastCreated.Before(time.Now().Add(-r.defaultEvalInterval)) {
|
||||||
|
err = r.createChecks(ctx, logger, namespace)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error creating new check reports", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up old checks to avoid going over the limit
|
||||||
|
err = r.cleanupChecks(ctx, logger, namespace)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error cleaning up old check reports", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the last created time with the new created checks
|
||||||
|
lastCreatedMap[namespace] = time.Now()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if nextSendInterval != r.evaluationInterval {
|
// Reset the ticker to the next send interval
|
||||||
nextSendInterval = r.evaluationInterval
|
nextEvalTime = r.getNextEvalTime(r.defaultEvalInterval, lastCreatedMap)
|
||||||
}
|
ticker.Reset(nextEvalTime)
|
||||||
ticker.Reset(nextSendInterval)
|
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) listChecks(ctx context.Context, logger logging.Logger) ([]resource.Object, error) {
|
func (r *Runner) listChecks(ctx context.Context, logger logging.Logger, namespace string) ([]resource.Object, error) {
|
||||||
list, err := r.client.List(ctx, r.namespace, resource.ListOptions{
|
list, err := r.checksClient.List(ctx, namespace, resource.ListOptions{
|
||||||
Limit: 1000, // Avoid pagination for normal uses cases, which is a costly operation
|
Limit: 1000, // Avoid pagination for normal uses cases, which is a costly operation
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -149,7 +183,7 @@ func (r *Runner) listChecks(ctx context.Context, logger logging.Logger) ([]resou
|
|||||||
checks := list.GetItems()
|
checks := list.GetItems()
|
||||||
for list.GetContinue() != "" {
|
for list.GetContinue() != "" {
|
||||||
logger.Debug("List has continue token, listing next page", "continue", list.GetContinue())
|
logger.Debug("List has continue token, listing next page", "continue", list.GetContinue())
|
||||||
list, err = r.client.List(ctx, r.namespace, resource.ListOptions{Continue: list.GetContinue(), Limit: 1000})
|
list, err = r.checksClient.List(ctx, namespace, resource.ListOptions{Continue: list.GetContinue(), Limit: 1000})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -158,38 +192,48 @@ func (r *Runner) listChecks(ctx context.Context, logger logging.Logger) ([]resou
|
|||||||
return checks, nil
|
return checks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkLastCreated returns the creation time of the last check created
|
// checkLastCreated returns the creation time of the last check created for a specific namespace.
|
||||||
// regardless of its ID. This assumes that the checks are created in batches
|
// This assumes that the checks are created in batches so a batch will have a similar creation time.
|
||||||
// so a batch will have a similar creation time.
|
|
||||||
// In case it finds an unprocessed check from a previous run, it will set it to error.
|
// In case it finds an unprocessed check from a previous run, it will set it to error.
|
||||||
func (r *Runner) checkLastCreated(ctx context.Context, log logging.Logger) (time.Time, error) {
|
func (r *Runner) checkLastCreated(ctx context.Context, log logging.Logger, namespaces []string) (map[string]time.Time, error) {
|
||||||
checkList, err := r.listChecks(ctx, log)
|
lastCreated := map[string]time.Time{}
|
||||||
if err != nil {
|
for _, namespace := range namespaces {
|
||||||
return time.Time{}, err
|
checkList, err := r.listChecks(ctx, log, namespace)
|
||||||
}
|
if err != nil {
|
||||||
lastCreated := time.Time{}
|
return nil, err
|
||||||
for _, item := range checkList {
|
|
||||||
itemCreated := item.GetCreationTimestamp().Time
|
|
||||||
if itemCreated.After(lastCreated) {
|
|
||||||
lastCreated = itemCreated
|
|
||||||
}
|
}
|
||||||
|
for _, item := range checkList {
|
||||||
// If the check is unprocessed, set it to error
|
itemCreated := item.GetCreationTimestamp().Time
|
||||||
if checks.GetStatusAnnotation(item) == "" {
|
if itemCreated.After(lastCreated[namespace]) {
|
||||||
log.Info("Check is unprocessed, marking as error", "check", item.GetStaticMetadata().Identifier())
|
lastCreated[namespace] = itemCreated
|
||||||
err := checks.SetStatusAnnotation(ctx, r.client, item, checks.StatusAnnotationError)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Error setting check status to error", "error", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lastCreated, nil
|
return lastCreated, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Runner) markUnprocessedChecks(ctx context.Context, log logging.Logger, namespace string) error {
|
||||||
|
checkList, err := r.listChecks(ctx, log, namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, item := range checkList {
|
||||||
|
if checks.GetStatusAnnotation(item) == "" {
|
||||||
|
log.Info("Check is unprocessed, marking as error", "check", item.GetStaticMetadata().Identifier())
|
||||||
|
err := checks.SetStatusAnnotation(ctx, r.checksClient, item, checks.StatusAnnotationError)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error setting check status to error", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// createChecks creates a new check for each check type in the registry.
|
// createChecks creates a new check for each check type in the registry.
|
||||||
func (r *Runner) createChecks(ctx context.Context, logger logging.Logger) error {
|
func (r *Runner) createChecks(ctx context.Context, logger logging.Logger, namespace string) error {
|
||||||
// List existing CheckType objects
|
// List existing CheckType objects
|
||||||
list, err := r.typesClient.List(ctx, r.namespace, resource.ListOptions{})
|
list, err := r.typesClient.List(ctx, namespace, resource.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error listing check types: %w", err)
|
return fmt.Errorf("error listing check types: %w", err)
|
||||||
}
|
}
|
||||||
@@ -199,7 +243,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger) error
|
|||||||
for !allChecksRegistered && retryCount < waitMaxRetries {
|
for !allChecksRegistered && retryCount < waitMaxRetries {
|
||||||
logger.Info("Waiting for all check types to be registered", "retryCount", retryCount, "waitInterval", waitInterval)
|
logger.Info("Waiting for all check types to be registered", "retryCount", retryCount, "waitInterval", waitInterval)
|
||||||
time.Sleep(waitInterval)
|
time.Sleep(waitInterval)
|
||||||
list, err = r.typesClient.List(ctx, r.namespace, resource.ListOptions{})
|
list, err = r.typesClient.List(ctx, namespace, resource.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error listing check types: %w", err)
|
return fmt.Errorf("error listing check types: %w", err)
|
||||||
}
|
}
|
||||||
@@ -217,7 +261,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger) error
|
|||||||
obj := &advisorv0alpha1.Check{
|
obj := &advisorv0alpha1.Check{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
GenerateName: "check-",
|
GenerateName: "check-",
|
||||||
Namespace: r.namespace,
|
Namespace: namespace,
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
checks.TypeLabel: checkType.Spec.Name,
|
checks.TypeLabel: checkType.Spec.Name,
|
||||||
},
|
},
|
||||||
@@ -225,7 +269,7 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger) error
|
|||||||
Spec: advisorv0alpha1.CheckSpec{},
|
Spec: advisorv0alpha1.CheckSpec{},
|
||||||
}
|
}
|
||||||
id := obj.GetStaticMetadata().Identifier()
|
id := obj.GetStaticMetadata().Identifier()
|
||||||
_, err := r.client.Create(ctx, id, obj, resource.CreateOptions{})
|
_, err := r.checksClient.Create(ctx, id, obj, resource.CreateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating check: %w", err)
|
return fmt.Errorf("error creating check: %w", err)
|
||||||
}
|
}
|
||||||
@@ -234,13 +278,13 @@ func (r *Runner) createChecks(ctx context.Context, logger logging.Logger) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cleanupChecks deletes the olders checks if the number of checks exceeds the limit.
|
// cleanupChecks deletes the olders checks if the number of checks exceeds the limit.
|
||||||
func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger) error {
|
func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger, namespace string) error {
|
||||||
checkList, err := r.listChecks(ctx, logger)
|
checkList, err := r.listChecks(ctx, logger, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug("Cleaning up checks", "numChecks", len(checkList))
|
logger.Debug("Cleaning up checks", "namespace", namespace, "numChecks", len(checkList))
|
||||||
|
|
||||||
// organize checks by type
|
// organize checks by type
|
||||||
checksByType := map[string][]resource.Object{}
|
checksByType := map[string][]resource.Object{}
|
||||||
@@ -268,7 +312,7 @@ func (r *Runner) cleanupChecks(ctx context.Context, logger logging.Logger) error
|
|||||||
for i := 0; i < len(checks)-r.maxHistory; i++ {
|
for i := 0; i < len(checks)-r.maxHistory; i++ {
|
||||||
check := checks[i]
|
check := checks[i]
|
||||||
id := check.GetStaticMetadata().Identifier()
|
id := check.GetStaticMetadata().Identifier()
|
||||||
err := r.client.Delete(ctx, id, resource.DeleteOptions{})
|
err := r.checksClient.Delete(ctx, id, resource.DeleteOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error deleting check: %w", err)
|
return fmt.Errorf("error deleting check: %w", err)
|
||||||
}
|
}
|
||||||
@@ -293,15 +337,28 @@ func getEvaluationInterval(pluginConfig map[string]string) (time.Duration, error
|
|||||||
return evaluationInterval, nil
|
return evaluationInterval, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNextSendInterval(lastCreated time.Time, evaluationInterval time.Duration) time.Duration {
|
func (r *Runner) getNextEvalTime(defaultEvaluationInterval time.Duration, lastCreated map[string]time.Time) time.Duration {
|
||||||
nextSendInterval := time.Until(lastCreated.Add(evaluationInterval))
|
nextEvalTime := defaultEvaluationInterval
|
||||||
// Add random variation of one hour
|
|
||||||
randomVariation := time.Duration(rand.Int63n(time.Hour.Nanoseconds()))
|
// Get the oldest last created time
|
||||||
nextSendInterval += randomVariation
|
baseTime := time.Now()
|
||||||
if nextSendInterval < time.Minute {
|
for _, lastNamespacedCreated := range lastCreated {
|
||||||
nextSendInterval = 1 * time.Minute
|
if !lastNamespacedCreated.IsZero() && lastNamespacedCreated.Before(baseTime) {
|
||||||
|
baseTime = lastNamespacedCreated
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nextSendInterval
|
|
||||||
|
// Calculate the next evaluation time and add random variation
|
||||||
|
nextEvalTime = time.Until(baseTime.Add(nextEvalTime))
|
||||||
|
randomVariation := time.Duration(rand.Int63n(evalIntervalRandomVariation.Nanoseconds()))
|
||||||
|
nextEvalTime += randomVariation
|
||||||
|
|
||||||
|
// Ensure we always return a positive duration to avoid ticker panics
|
||||||
|
if nextEvalTime <= 0 {
|
||||||
|
nextEvalTime = 1 * time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextEvalTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMaxHistory(pluginConfig map[string]string) (int, error) {
|
func getMaxHistory(pluginConfig map[string]string) (int, error) {
|
||||||
|
|||||||
@@ -4,26 +4,50 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand/v2"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/logging"
|
"github.com/grafana/grafana-app-sdk/logging"
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
waitInterval = 1 * time.Millisecond
|
||||||
|
evalIntervalRandomVariation = 1 * time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestRunner_Run tests the main Run function with various scenarios
|
||||||
func TestRunner_Run(t *testing.T) {
|
func TestRunner_Run(t *testing.T) {
|
||||||
t.Run("does not crash when error on list", func(t *testing.T) {
|
t.Run("handles context cancellation gracefully", func(t *testing.T) {
|
||||||
|
runner := createTestRunner(&MockClient{}, &MockClient{})
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
cancel() // Cancel immediately
|
||||||
|
|
||||||
|
err := runner.Run(ctx)
|
||||||
|
assert.ErrorAs(t, err, &context.Canceled)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handles timeout gracefully", func(t *testing.T) {
|
||||||
|
runner := createTestRunner(&MockClient{}, &MockClient{})
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
err := runner.Run(ctx)
|
||||||
|
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handles check list error gracefully", func(t *testing.T) {
|
||||||
mockClient := &MockClient{
|
mockClient := &MockClient{
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
return nil, errors.New("list error")
|
return nil, errors.New("list checks error")
|
||||||
},
|
|
||||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
|
||||||
return &advisorv0alpha1.Check{}, nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,352 +57,289 @@ func TestRunner_Run(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
runner := &Runner{
|
runner := createTestRunner(mockClient, mockTypesClient)
|
||||||
client: mockClient,
|
err := runner.Run(context.Background())
|
||||||
typesClient: mockTypesClient,
|
assert.ErrorContains(t, err, "list checks error")
|
||||||
log: &logging.NoOpLogger{},
|
|
||||||
evaluationInterval: 1 * time.Hour,
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
cancel()
|
|
||||||
err := runner.Run(ctx)
|
|
||||||
assert.ErrorAs(t, err, &context.Canceled)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunner_checkLastCreated_ErrorOnList(t *testing.T) {
|
// TestRunner_Run_CheckCreation tests check creation scenarios
|
||||||
mockClient := &MockClient{
|
func TestRunner_Run_CheckCreation(t *testing.T) {
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
t.Run("does not create checks on first run when no previous checks exist", func(t *testing.T) {
|
||||||
return nil, errors.New("list error")
|
checksCreated := []string{}
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
runner := &Runner{
|
mockClient := &MockClient{
|
||||||
client: mockClient,
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
log: &logging.NoOpLogger{},
|
// Return empty list - no previous checks
|
||||||
}
|
return &advisorv0alpha1.CheckList{Items: []advisorv0alpha1.Check{}}, nil
|
||||||
|
},
|
||||||
|
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||||
|
checksCreated = append(checksCreated, id.Name)
|
||||||
|
return obj, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
|
mockTypesClient := &MockClient{
|
||||||
assert.Error(t, err)
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
assert.True(t, lastCreated.IsZero())
|
return &advisorv0alpha1.CheckTypeList{
|
||||||
}
|
Items: []advisorv0alpha1.CheckType{
|
||||||
|
{
|
||||||
func TestRunner_checkLastCreated_UnprocessedCheck(t *testing.T) {
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
patchOperation := resource.PatchOperation{}
|
Name: "test-check",
|
||||||
identifier := resource.Identifier{}
|
},
|
||||||
|
Spec: advisorv0alpha1.CheckTypeSpec{
|
||||||
mockClient := &MockClient{
|
Name: "test-check",
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
},
|
||||||
return &advisorv0alpha1.CheckList{
|
|
||||||
Items: []advisorv0alpha1.Check{
|
|
||||||
{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "check-1",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}, nil
|
||||||
}, nil
|
},
|
||||||
},
|
}
|
||||||
patchFunc: func(ctx context.Context, id resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions, into resource.Object) error {
|
|
||||||
patchOperation = patch.Operations[0]
|
|
||||||
identifier = id
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
runner := &Runner{
|
// Create a mock check service with one check to match the check type
|
||||||
client: mockClient,
|
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "test-check"}}}
|
||||||
log: &logging.NoOpLogger{},
|
runner := createTestRunnerWithRegistry(mockClient, mockTypesClient, mockCheckService)
|
||||||
}
|
|
||||||
|
|
||||||
lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
|
err := runAndTimeout(runner)
|
||||||
assert.NoError(t, err)
|
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
||||||
assert.True(t, lastCreated.IsZero())
|
// Should not create checks on first run when no previous checks exist
|
||||||
assert.Equal(t, "check-1", identifier.Name)
|
assert.Empty(t, checksCreated, "Should not create checks on first run when no previous checks exist")
|
||||||
assert.Equal(t, "/metadata/annotations", patchOperation.Path)
|
})
|
||||||
expectedAnnotations := map[string]string{
|
|
||||||
checks.StatusAnnotation: "error",
|
|
||||||
}
|
|
||||||
assert.Equal(t, expectedAnnotations, patchOperation.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunner_checkLastCreated_PaginatedResponse(t *testing.T) {
|
t.Run("creates checks when evaluation interval has passed", func(t *testing.T) {
|
||||||
// Create checks with different creation times
|
checksCreated := []string{}
|
||||||
past := time.Now().Add(-1 * time.Hour)
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
mockClient := &MockClient{
|
mockClient := &MockClient{
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
if options.Continue == "" {
|
// Return a check that was created long ago (past the evaluation interval)
|
||||||
// First page - return oldest and middle checks with continue token
|
|
||||||
return &advisorv0alpha1.CheckList{
|
return &advisorv0alpha1.CheckList{
|
||||||
ListMeta: metav1.ListMeta{
|
|
||||||
Continue: "continue-token-123",
|
|
||||||
},
|
|
||||||
Items: []advisorv0alpha1.Check{
|
Items: []advisorv0alpha1.Check{
|
||||||
{
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "check-1",
|
Name: "old-check",
|
||||||
CreationTimestamp: metav1.NewTime(past),
|
CreationTimestamp: metav1.NewTime(time.Now().Add(-15 * 24 * time.Hour)), // 15 days ago
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
checks.StatusAnnotation: "completed",
|
checks.StatusAnnotation: checks.StatusAnnotationProcessed,
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "check-2",
|
|
||||||
CreationTimestamp: metav1.NewTime(past),
|
|
||||||
Annotations: map[string]string{
|
|
||||||
checks.StatusAnnotation: "completed",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
},
|
||||||
// Second page - verify continue token is passed and return newest check
|
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||||
assert.Equal(t, "continue-token-123", options.Continue)
|
checksCreated = append(checksCreated, id.Name)
|
||||||
return &advisorv0alpha1.CheckList{
|
return obj, nil
|
||||||
Items: []advisorv0alpha1.Check{
|
},
|
||||||
{
|
}
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "check-3",
|
mockTypesClient := &MockClient{
|
||||||
CreationTimestamp: metav1.NewTime(now),
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
Annotations: map[string]string{
|
return &advisorv0alpha1.CheckTypeList{
|
||||||
checks.StatusAnnotation: "completed",
|
Items: []advisorv0alpha1.CheckType{
|
||||||
|
{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-check",
|
||||||
|
},
|
||||||
|
Spec: advisorv0alpha1.CheckTypeSpec{
|
||||||
|
Name: "test-check",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}, nil
|
||||||
}, nil
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
|
||||||
runner := &Runner{
|
// Create a mock check service with one check to match the check type
|
||||||
client: mockClient,
|
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "test-check"}}}
|
||||||
log: &logging.NoOpLogger{},
|
runner := createTestRunnerWithRegistry(mockClient, mockTypesClient, mockCheckService)
|
||||||
}
|
|
||||||
|
|
||||||
lastCreated, err := runner.checkLastCreated(context.Background(), &logging.NoOpLogger{})
|
err := runAndTimeout(runner)
|
||||||
assert.NoError(t, err)
|
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
||||||
assert.Equal(t, now.Truncate(time.Second), lastCreated.Truncate(time.Second))
|
// Should create checks when the evaluation interval has passed
|
||||||
|
assert.Greater(t, len(checksCreated), 0, "Should create checks when evaluation interval has passed")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunner_createChecks_ErrorOnCreate(t *testing.T) {
|
// TestRunner_Run_CheckCleanup tests check cleanup scenarios
|
||||||
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "check-1"}}}
|
func TestRunner_Run_CheckCleanup(t *testing.T) {
|
||||||
|
t.Run("cleans up old checks when limit exceeded", func(t *testing.T) {
|
||||||
|
checksDeleted := []string{}
|
||||||
|
|
||||||
mockClient := &MockClient{
|
// Create checks that exceed the max history limit
|
||||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
items := make([]advisorv0alpha1.Check, 0, defaultMaxHistory+2)
|
||||||
return nil, errors.New("create error")
|
for i := 0; i < defaultMaxHistory+2; i++ {
|
||||||
},
|
item := advisorv0alpha1.Check{}
|
||||||
}
|
item.SetName(fmt.Sprintf("check-%d", i))
|
||||||
|
item.SetLabels(map[string]string{
|
||||||
|
checks.TypeLabel: "test-type",
|
||||||
|
})
|
||||||
|
item.SetCreationTimestamp(metav1.NewTime(time.Now().Add(-time.Duration(i) * time.Hour)))
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
|
||||||
mockTypesClient := &MockClient{
|
mockClient := &MockClient{
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
checkType := &advisorv0alpha1.CheckType{}
|
return &advisorv0alpha1.CheckList{Items: items}, nil
|
||||||
checkType.Spec.Name = "check-1"
|
},
|
||||||
return &advisorv0alpha1.CheckTypeList{
|
deleteFunc: func(ctx context.Context, id resource.Identifier, opts resource.DeleteOptions) error {
|
||||||
Items: []advisorv0alpha1.CheckType{*checkType},
|
checksDeleted = append(checksDeleted, id.Name)
|
||||||
}, nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
runner := &Runner{
|
mockTypesClient := &MockClient{
|
||||||
checkRegistry: mockCheckService,
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
client: mockClient,
|
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
|
||||||
typesClient: mockTypesClient,
|
},
|
||||||
log: &logging.NoOpLogger{},
|
}
|
||||||
}
|
|
||||||
|
|
||||||
err := runner.createChecks(context.Background(), &logging.NoOpLogger{})
|
runner := createTestRunner(mockClient, mockTypesClient)
|
||||||
assert.Error(t, err)
|
|
||||||
|
err := runAndTimeout(runner)
|
||||||
|
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
||||||
|
// Should delete some checks due to cleanup
|
||||||
|
assert.Greater(t, len(checksDeleted), 0)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunner_createChecks_Success(t *testing.T) {
|
// TestRunner_Run_UnprocessedChecks tests handling of unprocessed checks
|
||||||
mockCheckService := &MockCheckService{checks: []checks.Check{&mockCheck{id: "check-1"}}}
|
func TestRunner_Run_UnprocessedChecks(t *testing.T) {
|
||||||
|
t.Run("marks unprocessed checks as error", func(t *testing.T) {
|
||||||
|
patchOperations := []resource.PatchOperation{}
|
||||||
|
|
||||||
mockClient := &MockClient{
|
mockClient := &MockClient{
|
||||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
return &advisorv0alpha1.Check{}, nil
|
return &advisorv0alpha1.CheckList{
|
||||||
},
|
Items: []advisorv0alpha1.Check{
|
||||||
}
|
{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "unprocessed-check",
|
||||||
|
CreationTimestamp: metav1.NewTime(time.Now().Add(-1 * time.Hour)),
|
||||||
|
// No status annotation - unprocessed
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
patchFunc: func(ctx context.Context, id resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions, into resource.Object) error {
|
||||||
|
patchOperations = append(patchOperations, patch.Operations...)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
mockTypesClient := &MockClient{
|
mockTypesClient := &MockClient{
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
checkType := &advisorv0alpha1.CheckType{}
|
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
|
||||||
checkType.Spec.Name = "check-1"
|
},
|
||||||
return &advisorv0alpha1.CheckTypeList{
|
}
|
||||||
Items: []advisorv0alpha1.CheckType{*checkType},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
runner := &Runner{
|
runner := createTestRunner(mockClient, mockTypesClient)
|
||||||
checkRegistry: mockCheckService,
|
|
||||||
client: mockClient,
|
|
||||||
typesClient: mockTypesClient,
|
|
||||||
log: &logging.NoOpLogger{},
|
|
||||||
}
|
|
||||||
|
|
||||||
err := runner.createChecks(context.Background(), &logging.NoOpLogger{})
|
err := runAndTimeout(runner)
|
||||||
assert.NoError(t, err)
|
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
||||||
|
// Should patch unprocessed check with error status
|
||||||
|
assert.Greater(t, len(patchOperations), 0)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunner_cleanupChecks_ErrorOnList(t *testing.T) {
|
// TestRunner_Run_Pagination tests pagination handling
|
||||||
mockClient := &MockClient{
|
func TestRunner_Run_Pagination(t *testing.T) {
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
t.Run("handles paginated check lists", func(t *testing.T) {
|
||||||
return nil, errors.New("list error")
|
callCount := 0
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
runner := &Runner{
|
mockClient := &MockClient{
|
||||||
client: mockClient,
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
log: &logging.NoOpLogger{},
|
callCount++
|
||||||
}
|
if callCount == 1 {
|
||||||
|
return &advisorv0alpha1.CheckList{
|
||||||
|
ListMeta: metav1.ListMeta{Continue: "continue-token"},
|
||||||
|
Items: []advisorv0alpha1.Check{
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "check-1"}},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return &advisorv0alpha1.CheckList{
|
||||||
|
Items: []advisorv0alpha1.Check{
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "check-2"}},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
|
mockTypesClient := &MockClient{
|
||||||
assert.Error(t, err)
|
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
|
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runner := createTestRunner(mockClient, mockTypesClient)
|
||||||
|
|
||||||
|
err := runAndTimeout(runner)
|
||||||
|
assert.ErrorAs(t, err, &context.DeadlineExceeded)
|
||||||
|
// Should handle pagination correctly
|
||||||
|
assert.GreaterOrEqual(t, callCount, 2)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunner_cleanupChecks_WithinMax(t *testing.T) {
|
// Helper functions
|
||||||
mockClient := &MockClient{
|
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
|
||||||
return &advisorv0alpha1.CheckList{
|
|
||||||
Items: []advisorv0alpha1.Check{{}, {}},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
deleteFunc: func(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
|
|
||||||
return fmt.Errorf("shouldn't be called")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
runner := &Runner{
|
// runAndTimeout runs a runner with a short timeout for testing purposes.
|
||||||
client: mockClient,
|
// This is used to terminate the runner's infinite loop in tests that don't specifically test timeout behavior.
|
||||||
log: &logging.NoOpLogger{},
|
func runAndTimeout(runner *Runner) error {
|
||||||
}
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond)
|
||||||
|
defer cancel()
|
||||||
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
|
return runner.Run(ctx)
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunner_cleanupChecks_ErrorOnDelete(t *testing.T) {
|
// createTestRunner creates a test runner with mock clients
|
||||||
mockClient := &MockClient{
|
func createTestRunner(checkClient, typesClient *MockClient) *Runner {
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
return createTestRunnerWithRegistry(checkClient, typesClient, &MockCheckService{checks: []checks.Check{}})
|
||||||
items := make([]advisorv0alpha1.Check, 0, defaultMaxHistory+1)
|
|
||||||
for i := 0; i < defaultMaxHistory+1; i++ {
|
|
||||||
item := advisorv0alpha1.Check{}
|
|
||||||
item.SetLabels(map[string]string{
|
|
||||||
checks.TypeLabel: "mock",
|
|
||||||
})
|
|
||||||
items = append(items, item)
|
|
||||||
}
|
|
||||||
return &advisorv0alpha1.CheckList{
|
|
||||||
Items: items,
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
deleteFunc: func(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
|
|
||||||
return errors.New("delete error")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
runner := &Runner{
|
|
||||||
client: mockClient,
|
|
||||||
maxHistory: defaultMaxHistory,
|
|
||||||
log: &logging.NoOpLogger{},
|
|
||||||
}
|
|
||||||
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
|
|
||||||
assert.ErrorContains(t, err, "delete error")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunner_cleanupChecks_Success(t *testing.T) {
|
// createTestRunnerWithRegistry creates a test runner with mock clients and custom registry
|
||||||
itemsDeleted := []string{}
|
func createTestRunnerWithRegistry(checkClient, typesClient *MockClient, checkRegistry checkregistry.CheckService) *Runner {
|
||||||
items := make([]advisorv0alpha1.Check, 0, defaultMaxHistory+1)
|
// Ensure mock clients have default implementations
|
||||||
for i := 0; i < defaultMaxHistory+1; i++ {
|
if checkClient.listFunc == nil {
|
||||||
item := advisorv0alpha1.Check{}
|
checkClient.listFunc = func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
item.SetName(fmt.Sprintf("check-%d", i))
|
return &advisorv0alpha1.CheckList{Items: []advisorv0alpha1.Check{}}, nil
|
||||||
item.SetLabels(map[string]string{
|
}
|
||||||
checks.TypeLabel: "mock",
|
|
||||||
})
|
|
||||||
item.SetCreationTimestamp(metav1.NewTime(time.Time{}.Add(time.Duration(i) * time.Hour)))
|
|
||||||
items = append(items, item)
|
|
||||||
}
|
}
|
||||||
// shuffle the items to ensure the oldest are deleted
|
if checkClient.createFunc == nil {
|
||||||
rand.Shuffle(len(items), func(i, j int) { items[i], items[j] = items[j], items[i] })
|
checkClient.createFunc = func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||||
|
return obj, nil
|
||||||
mockClient := &MockClient{
|
}
|
||||||
listFunc: func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
}
|
||||||
return &advisorv0alpha1.CheckList{
|
if checkClient.deleteFunc == nil {
|
||||||
Items: items,
|
checkClient.deleteFunc = func(ctx context.Context, id resource.Identifier, opts resource.DeleteOptions) error {
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
deleteFunc: func(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error {
|
|
||||||
itemsDeleted = append(itemsDeleted, identifier.Name)
|
|
||||||
return nil
|
return nil
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
if checkClient.patchFunc == nil {
|
||||||
|
checkClient.patchFunc = func(ctx context.Context, id resource.Identifier, patch resource.PatchRequest, opts resource.PatchOptions, into resource.Object) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runner := &Runner{
|
if typesClient.listFunc == nil {
|
||||||
client: mockClient,
|
typesClient.listFunc = func(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) {
|
||||||
maxHistory: defaultMaxHistory,
|
// Return empty list to match the empty MockCheckService
|
||||||
log: &logging.NoOpLogger{},
|
return &advisorv0alpha1.CheckTypeList{Items: []advisorv0alpha1.CheckType{}}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Runner{
|
||||||
|
checkRegistry: checkRegistry,
|
||||||
|
checksClient: checkClient,
|
||||||
|
typesClient: typesClient,
|
||||||
|
defaultEvalInterval: 5 * time.Millisecond,
|
||||||
|
maxHistory: defaultMaxHistory,
|
||||||
|
log: &logging.NoOpLogger{},
|
||||||
|
orgService: &mockOrgService{orgs: []*org.OrgDTO{{ID: 1}}},
|
||||||
|
stackID: "",
|
||||||
}
|
}
|
||||||
err := runner.cleanupChecks(context.Background(), &logging.NoOpLogger{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, []string{"check-0"}, itemsDeleted)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_getEvaluationInterval(t *testing.T) {
|
// Mock implementations
|
||||||
t.Run("default", func(t *testing.T) {
|
|
||||||
interval, err := getEvaluationInterval(map[string]string{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, 7*24*time.Hour, interval)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("invalid", func(t *testing.T) {
|
|
||||||
interval, err := getEvaluationInterval(map[string]string{"evaluation_interval": "invalid"})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Zero(t, interval)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("custom", func(t *testing.T) {
|
|
||||||
interval, err := getEvaluationInterval(map[string]string{"evaluation_interval": "1h"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, time.Hour, interval)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_getMaxHistory(t *testing.T) {
|
|
||||||
t.Run("default", func(t *testing.T) {
|
|
||||||
history, err := getMaxHistory(map[string]string{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, 10, history)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("invalid", func(t *testing.T) {
|
|
||||||
history, err := getMaxHistory(map[string]string{"max_history": "invalid"})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Zero(t, history)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("custom", func(t *testing.T) {
|
|
||||||
history, err := getMaxHistory(map[string]string{"max_history": "5"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, 5, history)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_getNextSendInterval(t *testing.T) {
|
|
||||||
lastCreated := time.Now().Add(-7 * 24 * time.Hour)
|
|
||||||
evaluationInterval := 7 * 24 * time.Hour
|
|
||||||
nextSendInterval := getNextSendInterval(lastCreated, evaluationInterval)
|
|
||||||
// The next send interval should be in < 1 hour
|
|
||||||
assert.True(t, nextSendInterval < time.Hour)
|
|
||||||
// Calculate the next send interval again and it should be different
|
|
||||||
nextSendInterval2 := getNextSendInterval(lastCreated, evaluationInterval)
|
|
||||||
assert.NotEqual(t, nextSendInterval, nextSendInterval2)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MockClient struct {
|
type MockClient struct {
|
||||||
resource.Client
|
resource.Client
|
||||||
@@ -414,7 +375,6 @@ func (m *MockCheckService) Checks() []checks.Check {
|
|||||||
|
|
||||||
type mockCheck struct {
|
type mockCheck struct {
|
||||||
checks.Check
|
checks.Check
|
||||||
|
|
||||||
id string
|
id string
|
||||||
steps []checks.Step
|
steps []checks.Step
|
||||||
}
|
}
|
||||||
@@ -426,3 +386,12 @@ func (m *mockCheck) ID() string {
|
|||||||
func (m *mockCheck) Steps() []checks.Step {
|
func (m *mockCheck) Steps() []checks.Step {
|
||||||
return m.steps
|
return m.steps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockOrgService struct {
|
||||||
|
org.Service
|
||||||
|
orgs []*org.OrgDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockOrgService) Search(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
|
||||||
|
return m.orgs, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
@@ -26,7 +27,8 @@ import (
|
|||||||
type Runner struct {
|
type Runner struct {
|
||||||
checkRegistry checkregistry.CheckService
|
checkRegistry checkregistry.CheckService
|
||||||
client resource.Client
|
client resource.Client
|
||||||
namespace string
|
orgService org.Service
|
||||||
|
stackID string
|
||||||
log logging.Logger
|
log logging.Logger
|
||||||
retryAttempts int
|
retryAttempts int
|
||||||
retryDelay time.Duration
|
retryDelay time.Duration
|
||||||
@@ -40,10 +42,7 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
|||||||
return nil, fmt.Errorf("invalid config type")
|
return nil, fmt.Errorf("invalid config type")
|
||||||
}
|
}
|
||||||
checkRegistry := specificConfig.CheckRegistry
|
checkRegistry := specificConfig.CheckRegistry
|
||||||
namespace, err := checks.GetNamespace(specificConfig.StackID)
|
orgService := specificConfig.OrgService
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare storage client
|
// Prepare storage client
|
||||||
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
|
clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.ClientConfig{})
|
||||||
@@ -55,7 +54,8 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
|||||||
return &Runner{
|
return &Runner{
|
||||||
checkRegistry: checkRegistry,
|
checkRegistry: checkRegistry,
|
||||||
client: client,
|
client: client,
|
||||||
namespace: namespace,
|
orgService: orgService,
|
||||||
|
stackID: specificConfig.StackID,
|
||||||
log: log.With("runner", "advisor.checktyperegisterer"),
|
log: log.With("runner", "advisor.checktyperegisterer"),
|
||||||
retryAttempts: 5,
|
retryAttempts: 5,
|
||||||
retryDelay: time.Second * 10,
|
retryDelay: time.Second * 10,
|
||||||
@@ -64,36 +64,47 @@ func New(cfg app.Config, log logging.Logger) (app.Runnable, error) {
|
|||||||
|
|
||||||
func (r *Runner) Run(ctx context.Context) error {
|
func (r *Runner) Run(ctx context.Context) error {
|
||||||
logger := r.log.WithContext(ctx)
|
logger := r.log.WithContext(ctx)
|
||||||
for _, t := range r.checkRegistry.Checks() {
|
|
||||||
steps := t.Steps()
|
// Determine namespaces based on StackID or OrgID
|
||||||
stepTypes := make([]advisorv0alpha1.CheckTypeStep, len(steps))
|
namespaces, err := checks.GetNamespaces(ctx, r.stackID, r.orgService)
|
||||||
for i, s := range steps {
|
if err != nil {
|
||||||
stepTypes[i] = advisorv0alpha1.CheckTypeStep{
|
return fmt.Errorf("failed to get namespaces: %w", err)
|
||||||
Title: s.Title(),
|
}
|
||||||
Description: s.Description(),
|
logger.Debug("Registering check types", "namespaces", len(namespaces))
|
||||||
StepID: s.ID(),
|
|
||||||
Resolution: s.Resolution(),
|
// Register check types in each namespace
|
||||||
|
for _, namespace := range namespaces {
|
||||||
|
for _, t := range r.checkRegistry.Checks() {
|
||||||
|
steps := t.Steps()
|
||||||
|
stepTypes := make([]advisorv0alpha1.CheckTypeStep, len(steps))
|
||||||
|
for i, s := range steps {
|
||||||
|
stepTypes[i] = advisorv0alpha1.CheckTypeStep{
|
||||||
|
Title: s.Title(),
|
||||||
|
Description: s.Description(),
|
||||||
|
StepID: s.ID(),
|
||||||
|
Resolution: s.Resolution(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
obj := &advisorv0alpha1.CheckType{
|
||||||
obj := &advisorv0alpha1.CheckType{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
Name: t.ID(),
|
||||||
Name: t.ID(),
|
Namespace: namespace,
|
||||||
Namespace: r.namespace,
|
Annotations: map[string]string{
|
||||||
Annotations: map[string]string{
|
checks.NameAnnotation: t.Name(),
|
||||||
checks.NameAnnotation: t.Name(),
|
// Flag to indicate feature availability
|
||||||
// Flag to indicate feature availability
|
checks.RetryAnnotation: "1",
|
||||||
checks.RetryAnnotation: "1",
|
checks.IgnoreStepsAnnotation: "1",
|
||||||
checks.IgnoreStepsAnnotation: "1",
|
},
|
||||||
},
|
},
|
||||||
},
|
Spec: advisorv0alpha1.CheckTypeSpec{
|
||||||
Spec: advisorv0alpha1.CheckTypeSpec{
|
Name: t.ID(),
|
||||||
Name: t.ID(),
|
Steps: stepTypes,
|
||||||
Steps: stepTypes,
|
},
|
||||||
},
|
}
|
||||||
}
|
err := r.registerCheckType(ctx, logger, t.ID(), obj)
|
||||||
err := r.registerCheckType(ctx, logger, t.ID(), obj)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checks"
|
||||||
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
k8sErrs "k8s.io/apimachinery/pkg/api/errors"
|
k8sErrs "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@@ -67,14 +68,17 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
checks []checks.Check
|
checks []checks.Check
|
||||||
|
stackID string
|
||||||
|
orgService org.Service
|
||||||
getFunc func(ctx context.Context, id resource.Identifier) (resource.Object, error)
|
getFunc func(ctx context.Context, id resource.Identifier) (resource.Object, error)
|
||||||
createFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error)
|
createFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error)
|
||||||
updateFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error)
|
updateFunc func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.UpdateOptions) (resource.Object, error)
|
||||||
expectedErr error
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "successful create",
|
name: "successful create",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
|
stackID: "123",
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
||||||
},
|
},
|
||||||
@@ -85,8 +89,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "resource exists with different annotations, should update",
|
name: "resource exists with different annotations, should update",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
|
stackID: "123",
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentAnnotations, nil
|
return existingObjectDifferentAnnotations, nil
|
||||||
},
|
},
|
||||||
@@ -96,8 +101,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "resource exists with different steps, should update",
|
name: "resource exists with different steps, should update",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
|
stackID: "123",
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentSteps, nil
|
return existingObjectDifferentSteps, nil
|
||||||
},
|
},
|
||||||
@@ -107,8 +113,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "resource exists with same annotations and steps, should not update",
|
name: "resource exists with same annotations and steps, should not update",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
|
stackID: "123",
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectSameContent, nil
|
return existingObjectSameContent, nil
|
||||||
},
|
},
|
||||||
@@ -118,8 +125,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "resource exists, with custom annotations preserved",
|
name: "resource exists, with custom annotations preserved",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
|
stackID: "123",
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentAnnotations, nil
|
return existingObjectDifferentAnnotations, nil
|
||||||
},
|
},
|
||||||
@@ -132,8 +140,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "create error",
|
name: "create error",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
|
stackID: "123",
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
||||||
},
|
},
|
||||||
@@ -144,8 +153,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: errors.New("create error"),
|
expectedErr: errors.New("create error"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "update error",
|
name: "update error",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
|
stackID: "123",
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentAnnotations, nil
|
return existingObjectDifferentAnnotations, nil
|
||||||
},
|
},
|
||||||
@@ -155,8 +165,9 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: errors.New("update error"),
|
expectedErr: errors.New("update error"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "shutting down error",
|
name: "shutting down error",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
|
stackID: "123",
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentAnnotations, nil
|
return existingObjectDifferentAnnotations, nil
|
||||||
},
|
},
|
||||||
@@ -166,14 +177,33 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "custom namespace",
|
name: "cloud stack namespace",
|
||||||
checks: []checks.Check{newMockCheck},
|
checks: []checks.Check{newMockCheck},
|
||||||
|
stackID: "456",
|
||||||
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
return existingObjectDifferentAnnotations, nil
|
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
||||||
},
|
},
|
||||||
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||||
if obj.GetNamespace() != "custom-namespace" {
|
if obj.GetNamespace() != "stack-456" {
|
||||||
return nil, fmt.Errorf("expected namespace %s, got %s", "custom-namespace", obj.GetNamespace())
|
return nil, fmt.Errorf("expected namespace %s, got %s", "stack-456", obj.GetNamespace())
|
||||||
|
}
|
||||||
|
return obj, nil
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple orgs",
|
||||||
|
checks: []checks.Check{newMockCheck},
|
||||||
|
stackID: "",
|
||||||
|
orgService: &mockOrgService{orgs: []*org.OrgDTO{{ID: 1, Name: "Org1"}, {ID: 2, Name: "Org2"}}},
|
||||||
|
getFunc: func(ctx context.Context, id resource.Identifier) (resource.Object, error) {
|
||||||
|
return nil, k8sErrs.NewNotFound(schema.GroupResource{}, id.Name)
|
||||||
|
},
|
||||||
|
createFunc: func(ctx context.Context, id resource.Identifier, obj resource.Object, opts resource.CreateOptions) (resource.Object, error) {
|
||||||
|
// Should create in both org-1 and org-2 namespaces
|
||||||
|
ns := obj.GetNamespace()
|
||||||
|
if ns != "org-1" && ns != "org-2" {
|
||||||
|
return nil, fmt.Errorf("expected namespace org-1 or org-2, got %s", ns)
|
||||||
}
|
}
|
||||||
return obj, nil
|
return obj, nil
|
||||||
},
|
},
|
||||||
@@ -183,6 +213,10 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
orgSvc := tt.orgService
|
||||||
|
if orgSvc == nil {
|
||||||
|
orgSvc = &mockOrgService{orgs: []*org.OrgDTO{}}
|
||||||
|
}
|
||||||
r := &Runner{
|
r := &Runner{
|
||||||
checkRegistry: &mockCheckRegistry{checks: tt.checks},
|
checkRegistry: &mockCheckRegistry{checks: tt.checks},
|
||||||
client: &mockClient{
|
client: &mockClient{
|
||||||
@@ -190,7 +224,8 @@ func TestCheckTypesRegisterer_Run(t *testing.T) {
|
|||||||
createFunc: tt.createFunc,
|
createFunc: tt.createFunc,
|
||||||
updateFunc: tt.updateFunc,
|
updateFunc: tt.updateFunc,
|
||||||
},
|
},
|
||||||
namespace: "custom-namespace",
|
orgService: orgSvc,
|
||||||
|
stackID: tt.stackID,
|
||||||
log: logging.DefaultLogger,
|
log: logging.DefaultLogger,
|
||||||
retryAttempts: 1,
|
retryAttempts: 1,
|
||||||
retryDelay: 0,
|
retryDelay: 0,
|
||||||
@@ -298,3 +333,12 @@ func (m *mockClient) Update(ctx context.Context, id resource.Identifier, obj res
|
|||||||
}
|
}
|
||||||
return nil, errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockOrgService struct {
|
||||||
|
org.Service
|
||||||
|
orgs []*org.OrgDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockOrgService) Search(ctx context.Context, query *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
|
||||||
|
return m.orgs, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/authlib/types"
|
||||||
"github.com/grafana/grafana-app-sdk/logging"
|
"github.com/grafana/grafana-app-sdk/logging"
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
advisorv0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1"
|
||||||
@@ -317,3 +318,12 @@ func waitForRetryAnnotation(ctx context.Context, log logging.Logger, client reso
|
|||||||
log.Debug("Retry annotation persisted", "check", obj.GetName(), "item", itemToRetry)
|
log.Debug("Retry annotation persisted", "check", obj.GetName(), "item", itemToRetry)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getOrgIDFromNamespace extracts the org ID from a namespace using the standard authlib parser.
|
||||||
|
func getOrgIDFromNamespace(namespace string) (int64, error) {
|
||||||
|
info, err := types.ParseNamespace(namespace)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to parse namespace %s: %w", namespace, err)
|
||||||
|
}
|
||||||
|
return info.OrgID, nil
|
||||||
|
}
|
||||||
|
|||||||
58
apps/advisor/pkg/standalone/server.go
Normal file
58
apps/advisor/pkg/standalone/server.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"k8s.io/apiserver/pkg/admission"
|
||||||
|
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
"k8s.io/component-base/cli"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-app-sdk/app"
|
||||||
|
"github.com/grafana/grafana-app-sdk/k8s/apiserver"
|
||||||
|
"github.com/grafana/grafana-app-sdk/k8s/apiserver/cmd/server"
|
||||||
|
"github.com/grafana/grafana-app-sdk/logging"
|
||||||
|
"github.com/grafana/grafana-app-sdk/simple"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/apis"
|
||||||
|
advisorapp "github.com/grafana/grafana/apps/advisor/pkg/app"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry"
|
||||||
|
"github.com/grafana/grafana/apps/advisor/pkg/app/checkregistry/mockchecks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
logging.DefaultLogger = logging.NewSLogLogger(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
||||||
|
Level: slog.LevelDebug,
|
||||||
|
}))
|
||||||
|
provider := simple.NewAppProvider(apis.LocalManifest(), nil, advisorapp.New)
|
||||||
|
config := app.Config{
|
||||||
|
KubeConfig: rest.Config{}, // this will be replaced by the apiserver loopback config
|
||||||
|
ManifestData: *apis.LocalManifest().ManifestData,
|
||||||
|
SpecificConfig: checkregistry.AdvisorAppConfig{
|
||||||
|
CheckRegistry: mockchecks.New(),
|
||||||
|
PluginConfig: map[string]string{},
|
||||||
|
StackID: "1", // Numeric stack ID for standalone mode
|
||||||
|
OrgService: nil, // Not needed when StackID is set
|
||||||
|
},
|
||||||
|
}
|
||||||
|
installer, err := apiserver.NewDefaultAppInstaller(provider, config, &apis.GoTypeAssociator{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ctx := genericapiserver.SetupSignalContext()
|
||||||
|
opts := apiserver.NewOptions([]apiserver.AppInstaller{installer})
|
||||||
|
opts.RecommendedOptions.Authentication = nil
|
||||||
|
opts.RecommendedOptions.Authorization = nil
|
||||||
|
opts.RecommendedOptions.CoreAPI = nil
|
||||||
|
opts.RecommendedOptions.EgressSelector = nil
|
||||||
|
opts.RecommendedOptions.Admission.Plugins = admission.NewPlugins()
|
||||||
|
opts.RecommendedOptions.Admission.RecommendedPluginOrder = []string{}
|
||||||
|
opts.RecommendedOptions.Admission.EnablePlugins = []string{}
|
||||||
|
opts.RecommendedOptions.Features.EnablePriorityAndFairness = false
|
||||||
|
opts.RecommendedOptions.ExtraAdmissionInitializers = func(_ *genericapiserver.RecommendedConfig) ([]admission.PluginInitializer, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
cmd := server.NewCommandStartServer(ctx, opts)
|
||||||
|
code := cli.Run(cmd)
|
||||||
|
os.Exit(code)
|
||||||
|
}
|
||||||
@@ -3,19 +3,20 @@ module github.com/grafana/grafana/apps/alerting/alertenrichment
|
|||||||
go 1.25.3
|
go 1.25.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/grafana/grafana-app-sdk v0.46.0
|
github.com/grafana/grafana-app-sdk v0.48.1
|
||||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28
|
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28
|
||||||
k8s.io/apimachinery v0.34.1
|
k8s.io/apimachinery v0.34.1
|
||||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
github.com/go-openapi/jsonpointer v0.22.1 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
github.com/go-openapi/jsonreference v0.21.2 // indirect
|
||||||
github.com/go-openapi/swag v0.23.0 // indirect
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
|
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/google/gnostic-models v0.7.0 // indirect
|
github.com/google/gnostic-models v0.7.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
@@ -24,11 +25,11 @@ require (
|
|||||||
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.3-0.20250322232337-35a7c28c31ee // indirect
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // 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/net v0.45.0 // indirect
|
golang.org/x/net v0.46.0 // indirect
|
||||||
golang.org/x/text v0.30.0 // indirect
|
golang.org/x/text v0.30.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.9 // indirect
|
google.golang.org/protobuf v1.36.10 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
k8s.io/klog/v2 v2.130.1 // indirect
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
|
|||||||
@@ -8,12 +8,14 @@ github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sa
|
|||||||
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk=
|
||||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM=
|
||||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU=
|
||||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ=
|
||||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
|
github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=
|
||||||
|
github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=
|
||||||
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/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
|
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
|
||||||
@@ -21,8 +23,8 @@ github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7O
|
|||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
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/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek=
|
||||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c=
|
||||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28 h1:PgMfX4OPENz/iXmtDDIW9+poZY4UD0hhmXm7flVclDo=
|
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28 h1:PgMfX4OPENz/iXmtDDIW9+poZY4UD0hhmXm7flVclDo=
|
||||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28/go.mod h1:av5N0Naq+8VV9MLF7zAkihy/mVq5UbS2EvRSJukDHlY=
|
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28/go.mod h1:av5N0Naq+8VV9MLF7zAkihy/mVq5UbS2EvRSJukDHlY=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
@@ -58,8 +60,8 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
|||||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
@@ -71,8 +73,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||||
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -91,8 +93,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
@@ -104,8 +106,8 @@ k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
|
|||||||
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
|
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
|
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
|
||||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
include ../../sdk.mk
|
include ../../sdk.mk
|
||||||
|
|
||||||
.PHONY: generate
|
.PHONY: generate # Run Grafana App SDK code generation
|
||||||
generate: do-generate ## Run Grafana App SDK code generation
|
generate: install-app-sdk update-app-sdk
|
||||||
|
@$(APP_SDK_BIN) generate \
|
||||||
.PHONY: do-generate
|
--source=./kinds/ \
|
||||||
do-generate: install-app-sdk update-app-sdk
|
--gogenpath=./pkg/apis \
|
||||||
@$(APP_SDK_BIN) generate --grouping=group --gogenpath=./pkg/apis --defencoding=yaml --postprocess
|
--grouping=group \
|
||||||
|
--genoperatorstate=false \
|
||||||
|
--defencoding=none
|
||||||
|
|
||||||
@@ -3,11 +3,11 @@ module github.com/grafana/grafana/apps/alerting/notifications
|
|||||||
go 1.25.3
|
go 1.25.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/grafana/grafana-app-sdk v0.46.0
|
github.com/grafana/grafana-app-sdk v0.48.1
|
||||||
github.com/grafana/grafana-app-sdk/logging v0.45.0
|
github.com/grafana/grafana-app-sdk/logging v0.48.1
|
||||||
k8s.io/apimachinery v0.34.1
|
k8s.io/apimachinery v0.34.1
|
||||||
k8s.io/apiserver v0.34.1
|
k8s.io/apiserver v0.34.1
|
||||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -26,9 +26,10 @@ require (
|
|||||||
github.com/getkin/kin-openapi v0.133.0 // indirect
|
github.com/getkin/kin-openapi v0.133.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
github.com/go-openapi/jsonpointer v0.22.1 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
github.com/go-openapi/jsonreference v0.21.2 // indirect
|
||||||
github.com/go-openapi/swag v0.23.0 // indirect
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
|
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
|
||||||
github.com/go-test/deep v1.1.1 // indirect
|
github.com/go-test/deep v1.1.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||||
@@ -58,7 +59,7 @@ require (
|
|||||||
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/prometheus/client_golang v1.23.2 // indirect
|
github.com/prometheus/client_golang v1.23.2 // 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.1 // indirect
|
||||||
github.com/prometheus/procfs v0.16.1 // indirect
|
github.com/prometheus/procfs v0.16.1 // indirect
|
||||||
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
|
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
@@ -81,20 +82,20 @@ require (
|
|||||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.7.1 // 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/net v0.45.0 // indirect
|
golang.org/x/net v0.46.0 // indirect
|
||||||
golang.org/x/oauth2 v0.30.0 // indirect
|
golang.org/x/oauth2 v0.32.0 // indirect
|
||||||
golang.org/x/sync v0.17.0 // indirect
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.36.0 // indirect
|
golang.org/x/sys v0.37.0 // indirect
|
||||||
golang.org/x/term v0.35.0 // indirect
|
golang.org/x/term v0.36.0 // indirect
|
||||||
golang.org/x/text v0.30.0 // indirect
|
golang.org/x/text v0.30.0 // indirect
|
||||||
golang.org/x/time v0.13.0 // indirect
|
golang.org/x/time v0.14.0 // indirect
|
||||||
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect
|
||||||
google.golang.org/grpc v1.75.1 // indirect
|
google.golang.org/grpc v1.76.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.9 // indirect
|
google.golang.org/protobuf v1.36.10 // indirect
|
||||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|||||||
@@ -36,12 +36,14 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
|||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk=
|
||||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM=
|
||||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU=
|
||||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ=
|
||||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
|
github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=
|
||||||
|
github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=
|
||||||
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.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
||||||
@@ -69,10 +71,10 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||||
github.com/grafana/grafana-app-sdk v0.46.0 h1:gvzQvCQgZJ/73BfAcbDt/6TAMhnVikVPxZt/UwDl+oc=
|
github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek=
|
||||||
github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc=
|
github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c=
|
||||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
|
github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng=
|
||||||
github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
|
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
|
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0=
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0=
|
||||||
@@ -138,8 +140,8 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
|
|||||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
|
github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI=
|
||||||
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q=
|
||||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||||
@@ -215,15 +217,15 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||||
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/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
@@ -234,11 +236,11 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM=
|
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||||
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||||
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.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
||||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
golang.org/x/oauth2 v0.32.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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -250,23 +252,23 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||||
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||||
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||||
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
|
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||||
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||||
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=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -279,13 +281,13 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
|||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1:d8Nakh1G+ur7+P3GcMjpRDEkoLUcLW2iU92XVqR+XMQ=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1:d8Nakh1G+ur7+P3GcMjpRDEkoLUcLW2iU92XVqR+XMQ=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw=
|
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
|
||||||
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
||||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
||||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
@@ -312,8 +314,8 @@ k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A=
|
|||||||
k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
|
k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
|
||||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
|
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
|
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
|
||||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
|
||||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReceiverClient struct {
|
type ReceiverClient struct {
|
||||||
@@ -76,24 +75,6 @@ func (c *ReceiverClient) Patch(ctx context.Context, identifier resource.Identifi
|
|||||||
return c.client.Patch(ctx, identifier, req, opts)
|
return c.client.Patch(ctx, identifier, req, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ReceiverClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus ReceiverStatus, opts resource.UpdateOptions) (*Receiver, error) {
|
|
||||||
return c.client.Update(ctx, &Receiver{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
Kind: ReceiverKind().Kind(),
|
|
||||||
APIVersion: GroupVersion.Identifier(),
|
|
||||||
},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
Namespace: identifier.Namespace,
|
|
||||||
Name: identifier.Name,
|
|
||||||
},
|
|
||||||
Status: newStatus,
|
|
||||||
}, resource.UpdateOptions{
|
|
||||||
Subresource: "status",
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ReceiverClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
func (c *ReceiverClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||||
return c.client.Delete(ctx, identifier, opts)
|
return c.client.Delete(ctx, identifier, opts)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ type Receiver struct {
|
|||||||
|
|
||||||
// Spec is the spec of the Receiver
|
// Spec is the spec of the Receiver
|
||||||
Spec ReceiverSpec `json:"spec" yaml:"spec"`
|
Spec ReceiverSpec `json:"spec" yaml:"spec"`
|
||||||
|
|
||||||
Status ReceiverStatus `json:"status" yaml:"status"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Receiver) GetSpec() any {
|
func (o *Receiver) GetSpec() any {
|
||||||
@@ -39,15 +37,11 @@ func (o *Receiver) SetSpec(spec any) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *Receiver) GetSubresources() map[string]any {
|
func (o *Receiver) GetSubresources() map[string]any {
|
||||||
return map[string]any{
|
return map[string]any{}
|
||||||
"status": o.Status,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Receiver) GetSubresource(name string) (any, bool) {
|
func (o *Receiver) GetSubresource(name string) (any, bool) {
|
||||||
switch name {
|
switch name {
|
||||||
case "status":
|
|
||||||
return o.Status, true
|
|
||||||
default:
|
default:
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@@ -55,13 +49,6 @@ func (o *Receiver) GetSubresource(name string) (any, bool) {
|
|||||||
|
|
||||||
func (o *Receiver) SetSubresource(name string, value any) error {
|
func (o *Receiver) SetSubresource(name string, value any) error {
|
||||||
switch name {
|
switch name {
|
||||||
case "status":
|
|
||||||
cast, ok := value.(ReceiverStatus)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("cannot set status type %#v, not of type ReceiverStatus", value)
|
|
||||||
}
|
|
||||||
o.Status = cast
|
|
||||||
return nil
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||||
}
|
}
|
||||||
@@ -233,7 +220,6 @@ func (o *Receiver) DeepCopyInto(dst *Receiver) {
|
|||||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||||
o.Spec.DeepCopyInto(&dst.Spec)
|
o.Spec.DeepCopyInto(&dst.Spec)
|
||||||
o.Status.DeepCopyInto(&dst.Status)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface compliance compile-time check
|
// Interface compliance compile-time check
|
||||||
@@ -305,15 +291,3 @@ func (s *ReceiverSpec) DeepCopy() *ReceiverSpec {
|
|||||||
func (s *ReceiverSpec) DeepCopyInto(dst *ReceiverSpec) {
|
func (s *ReceiverSpec) DeepCopyInto(dst *ReceiverSpec) {
|
||||||
resource.CopyObjectInto(dst, s)
|
resource.CopyObjectInto(dst, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy creates a full deep copy of ReceiverStatus
|
|
||||||
func (s *ReceiverStatus) DeepCopy() *ReceiverStatus {
|
|
||||||
cpy := &ReceiverStatus{}
|
|
||||||
s.DeepCopyInto(cpy)
|
|
||||||
return cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto deep copies ReceiverStatus into another ReceiverStatus object
|
|
||||||
func (s *ReceiverStatus) DeepCopyInto(dst *ReceiverStatus) {
|
|
||||||
resource.CopyObjectInto(dst, s)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type RoutingTreeClient struct {
|
type RoutingTreeClient struct {
|
||||||
@@ -76,24 +75,6 @@ func (c *RoutingTreeClient) Patch(ctx context.Context, identifier resource.Ident
|
|||||||
return c.client.Patch(ctx, identifier, req, opts)
|
return c.client.Patch(ctx, identifier, req, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RoutingTreeClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus RoutingTreeStatus, opts resource.UpdateOptions) (*RoutingTree, error) {
|
|
||||||
return c.client.Update(ctx, &RoutingTree{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
Kind: RoutingTreeKind().Kind(),
|
|
||||||
APIVersion: GroupVersion.Identifier(),
|
|
||||||
},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
Namespace: identifier.Namespace,
|
|
||||||
Name: identifier.Name,
|
|
||||||
},
|
|
||||||
Status: newStatus,
|
|
||||||
}, resource.UpdateOptions{
|
|
||||||
Subresource: "status",
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *RoutingTreeClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
func (c *RoutingTreeClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||||
return c.client.Delete(ctx, identifier, opts)
|
return c.client.Delete(ctx, identifier, opts)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ type RoutingTree struct {
|
|||||||
|
|
||||||
// Spec is the spec of the RoutingTree
|
// Spec is the spec of the RoutingTree
|
||||||
Spec RoutingTreeSpec `json:"spec" yaml:"spec"`
|
Spec RoutingTreeSpec `json:"spec" yaml:"spec"`
|
||||||
|
|
||||||
Status RoutingTreeStatus `json:"status" yaml:"status"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *RoutingTree) GetSpec() any {
|
func (o *RoutingTree) GetSpec() any {
|
||||||
@@ -39,15 +37,11 @@ func (o *RoutingTree) SetSpec(spec any) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *RoutingTree) GetSubresources() map[string]any {
|
func (o *RoutingTree) GetSubresources() map[string]any {
|
||||||
return map[string]any{
|
return map[string]any{}
|
||||||
"status": o.Status,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *RoutingTree) GetSubresource(name string) (any, bool) {
|
func (o *RoutingTree) GetSubresource(name string) (any, bool) {
|
||||||
switch name {
|
switch name {
|
||||||
case "status":
|
|
||||||
return o.Status, true
|
|
||||||
default:
|
default:
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@@ -55,13 +49,6 @@ func (o *RoutingTree) GetSubresource(name string) (any, bool) {
|
|||||||
|
|
||||||
func (o *RoutingTree) SetSubresource(name string, value any) error {
|
func (o *RoutingTree) SetSubresource(name string, value any) error {
|
||||||
switch name {
|
switch name {
|
||||||
case "status":
|
|
||||||
cast, ok := value.(RoutingTreeStatus)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("cannot set status type %#v, not of type RoutingTreeStatus", value)
|
|
||||||
}
|
|
||||||
o.Status = cast
|
|
||||||
return nil
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||||
}
|
}
|
||||||
@@ -233,7 +220,6 @@ func (o *RoutingTree) DeepCopyInto(dst *RoutingTree) {
|
|||||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||||
o.Spec.DeepCopyInto(&dst.Spec)
|
o.Spec.DeepCopyInto(&dst.Spec)
|
||||||
o.Status.DeepCopyInto(&dst.Status)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface compliance compile-time check
|
// Interface compliance compile-time check
|
||||||
@@ -305,15 +291,3 @@ func (s *RoutingTreeSpec) DeepCopy() *RoutingTreeSpec {
|
|||||||
func (s *RoutingTreeSpec) DeepCopyInto(dst *RoutingTreeSpec) {
|
func (s *RoutingTreeSpec) DeepCopyInto(dst *RoutingTreeSpec) {
|
||||||
resource.CopyObjectInto(dst, s)
|
resource.CopyObjectInto(dst, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy creates a full deep copy of RoutingTreeStatus
|
|
||||||
func (s *RoutingTreeStatus) DeepCopy() *RoutingTreeStatus {
|
|
||||||
cpy := &RoutingTreeStatus{}
|
|
||||||
s.DeepCopyInto(cpy)
|
|
||||||
return cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto deep copies RoutingTreeStatus into another RoutingTreeStatus object
|
|
||||||
func (s *RoutingTreeStatus) DeepCopyInto(dst *RoutingTreeStatus) {
|
|
||||||
resource.CopyObjectInto(dst, s)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/grafana/grafana-app-sdk/resource"
|
"github.com/grafana/grafana-app-sdk/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TemplateGroupClient struct {
|
type TemplateGroupClient struct {
|
||||||
@@ -76,24 +75,6 @@ func (c *TemplateGroupClient) Patch(ctx context.Context, identifier resource.Ide
|
|||||||
return c.client.Patch(ctx, identifier, req, opts)
|
return c.client.Patch(ctx, identifier, req, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TemplateGroupClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus TemplateGroupStatus, opts resource.UpdateOptions) (*TemplateGroup, error) {
|
|
||||||
return c.client.Update(ctx, &TemplateGroup{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
Kind: TemplateGroupKind().Kind(),
|
|
||||||
APIVersion: GroupVersion.Identifier(),
|
|
||||||
},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
Namespace: identifier.Namespace,
|
|
||||||
Name: identifier.Name,
|
|
||||||
},
|
|
||||||
Status: newStatus,
|
|
||||||
}, resource.UpdateOptions{
|
|
||||||
Subresource: "status",
|
|
||||||
ResourceVersion: opts.ResourceVersion,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TemplateGroupClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
func (c *TemplateGroupClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error {
|
||||||
return c.client.Delete(ctx, identifier, opts)
|
return c.client.Delete(ctx, identifier, opts)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ type TemplateGroup struct {
|
|||||||
|
|
||||||
// Spec is the spec of the TemplateGroup
|
// Spec is the spec of the TemplateGroup
|
||||||
Spec TemplateGroupSpec `json:"spec" yaml:"spec"`
|
Spec TemplateGroupSpec `json:"spec" yaml:"spec"`
|
||||||
|
|
||||||
Status TemplateGroupStatus `json:"status" yaml:"status"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *TemplateGroup) GetSpec() any {
|
func (o *TemplateGroup) GetSpec() any {
|
||||||
@@ -39,15 +37,11 @@ func (o *TemplateGroup) SetSpec(spec any) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *TemplateGroup) GetSubresources() map[string]any {
|
func (o *TemplateGroup) GetSubresources() map[string]any {
|
||||||
return map[string]any{
|
return map[string]any{}
|
||||||
"status": o.Status,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *TemplateGroup) GetSubresource(name string) (any, bool) {
|
func (o *TemplateGroup) GetSubresource(name string) (any, bool) {
|
||||||
switch name {
|
switch name {
|
||||||
case "status":
|
|
||||||
return o.Status, true
|
|
||||||
default:
|
default:
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@@ -55,13 +49,6 @@ func (o *TemplateGroup) GetSubresource(name string) (any, bool) {
|
|||||||
|
|
||||||
func (o *TemplateGroup) SetSubresource(name string, value any) error {
|
func (o *TemplateGroup) SetSubresource(name string, value any) error {
|
||||||
switch name {
|
switch name {
|
||||||
case "status":
|
|
||||||
cast, ok := value.(TemplateGroupStatus)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("cannot set status type %#v, not of type TemplateGroupStatus", value)
|
|
||||||
}
|
|
||||||
o.Status = cast
|
|
||||||
return nil
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("subresource '%s' does not exist", name)
|
return fmt.Errorf("subresource '%s' does not exist", name)
|
||||||
}
|
}
|
||||||
@@ -233,7 +220,6 @@ func (o *TemplateGroup) DeepCopyInto(dst *TemplateGroup) {
|
|||||||
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
dst.TypeMeta.Kind = o.TypeMeta.Kind
|
||||||
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta)
|
||||||
o.Spec.DeepCopyInto(&dst.Spec)
|
o.Spec.DeepCopyInto(&dst.Spec)
|
||||||
o.Status.DeepCopyInto(&dst.Status)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface compliance compile-time check
|
// Interface compliance compile-time check
|
||||||
@@ -305,15 +291,3 @@ func (s *TemplateGroupSpec) DeepCopy() *TemplateGroupSpec {
|
|||||||
func (s *TemplateGroupSpec) DeepCopyInto(dst *TemplateGroupSpec) {
|
func (s *TemplateGroupSpec) DeepCopyInto(dst *TemplateGroupSpec) {
|
||||||
resource.CopyObjectInto(dst, s)
|
resource.CopyObjectInto(dst, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy creates a full deep copy of TemplateGroupStatus
|
|
||||||
func (s *TemplateGroupStatus) DeepCopy() *TemplateGroupStatus {
|
|
||||||
cpy := &TemplateGroupStatus{}
|
|
||||||
s.DeepCopyInto(cpy)
|
|
||||||
return cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto deep copies TemplateGroupStatus into another TemplateGroupStatus object
|
|
||||||
func (s *TemplateGroupStatus) DeepCopyInto(dst *TemplateGroupStatus) {
|
|
||||||
resource.CopyObjectInto(dst, s)
|
|
||||||
}
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user