Compare commits
705 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf4c090fe2 | ||
|
|
1440e77bea | ||
|
|
df83bf10a2 | ||
|
|
aeaf7b23a6 | ||
|
|
0ff4aa80ed | ||
|
|
020ecfdf56 | ||
|
|
e70a9de45a | ||
|
|
a6fc391583 | ||
|
|
534ba6d805 | ||
|
|
2bd1a19169 | ||
|
|
a996dd25d6 | ||
|
|
4d108007fe | ||
|
|
4df07b4e25 | ||
|
|
2040f61c56 | ||
|
|
aa94f7ebfe | ||
|
|
855b570878 | ||
|
|
1713f7f01d | ||
|
|
2b7d124be8 | ||
|
|
ad4d71740a | ||
|
|
77312d3a9c | ||
|
|
3565fe7105 | ||
|
|
df62c6a197 | ||
|
|
f929bd51db | ||
|
|
381f3da30e | ||
|
|
f48ea5eea6 | ||
|
|
3c2cb7715b | ||
|
|
90132770fa | ||
|
|
30c882c18d | ||
|
|
e5836064ce | ||
|
|
f7cb827944 | ||
|
|
f76cafa68e | ||
|
|
cdae9126ed | ||
|
|
b4c1df11f6 | ||
|
|
7c94d5cd1a | ||
|
|
74d6b5fc1c | ||
|
|
af42e0836a | ||
|
|
f453fbe8ef | ||
|
|
8d635efda0 | ||
|
|
0f2e879339 | ||
|
|
e51dd88260 | ||
|
|
984293cc52 | ||
|
|
9a1a9584b7 | ||
|
|
8a69ffb007 | ||
|
|
ab9f0e8edd | ||
|
|
18167f1c18 | ||
|
|
a2ff7629e0 | ||
|
|
6782be80fd | ||
|
|
e2adb4ced5 | ||
|
|
c02dd7462a | ||
|
|
b418e14bd9 | ||
|
|
4be6ef4ab3 | ||
|
|
e33d18701d | ||
|
|
f0254c201a | ||
|
|
a02306bc75 | ||
|
|
10d840b1cc | ||
|
|
551957fc4d | ||
|
|
2d1f59a9cc | ||
|
|
5f78ad583f | ||
|
|
22c7c741eb | ||
|
|
b62322b128 | ||
|
|
96287a9061 | ||
|
|
c8becf57fa | ||
|
|
d5196ab322 | ||
|
|
2765afc830 | ||
|
|
c63533f004 | ||
|
|
bf4ee9bcc6 | ||
|
|
56628996b7 | ||
|
|
0107491195 | ||
|
|
81d34137a8 | ||
|
|
e6135ffd4f | ||
|
|
9dd38031e4 | ||
|
|
dbbd6b9b66 | ||
|
|
1626a66bab | ||
|
|
25e1d723c6 | ||
|
|
23abf044ff | ||
|
|
5ec7d60e5f | ||
|
|
ef0586acab | ||
|
|
284045748c | ||
|
|
99c188f626 | ||
|
|
10d30f0b73 | ||
|
|
283b39c397 | ||
|
|
eb686c06f2 | ||
|
|
155ff06cbe | ||
|
|
2465f53324 | ||
|
|
a911d36dea | ||
|
|
04029a94cd | ||
|
|
71b0326769 | ||
|
|
8345e83bd6 | ||
|
|
9802d86783 | ||
|
|
a3552a60e1 | ||
|
|
a0aa0b55e7 | ||
|
|
4dd9b8f324 | ||
|
|
94b8cbdc6a | ||
|
|
0cc8ccdaa5 | ||
|
|
ff3db60e2e | ||
|
|
2288e01752 | ||
|
|
c39979a557 | ||
|
|
25504e84ed | ||
|
|
c650b50c37 | ||
|
|
d3a3e7cfd1 | ||
|
|
3b824a5e00 | ||
|
|
110522307a | ||
|
|
719ebdc24d | ||
|
|
610a90b79a | ||
|
|
72ecf72c45 | ||
|
|
8155ce9804 | ||
|
|
d91e9ddd22 | ||
|
|
d8f269954a | ||
|
|
0bb30b146c | ||
|
|
da9a28f37d | ||
|
|
c92874875c | ||
|
|
dbaa45e51e | ||
|
|
0a3ec93347 | ||
|
|
ab76864e61 | ||
|
|
5ed2880a8b | ||
|
|
38864d74bd | ||
|
|
484d9e3f9d | ||
|
|
77403b0dc1 | ||
|
|
c0830e9cde | ||
|
|
7d508df1b4 | ||
|
|
25f2960717 | ||
|
|
1f32871f70 | ||
|
|
3fb4eb7322 | ||
|
|
09dbb52423 | ||
|
|
82ae7c6eee | ||
|
|
17a2ce13f0 | ||
|
|
415ad8fbf3 | ||
|
|
c71608aae8 | ||
|
|
37c45a81a9 | ||
|
|
f93d83befe | ||
|
|
9db964bf35 | ||
|
|
cdba2bd184 | ||
|
|
8fd3015e52 | ||
|
|
2c86484e54 | ||
|
|
c47f40d99c | ||
|
|
9460063ab5 | ||
|
|
3bd58446d6 | ||
|
|
661503f828 | ||
|
|
56fc82151b | ||
|
|
681326140d | ||
|
|
4ff4ac1d5f | ||
|
|
393f41cd14 | ||
|
|
4063ae37a4 | ||
|
|
d7379912c1 | ||
|
|
45a156577c | ||
|
|
9e7651a1b3 | ||
|
|
64f5874778 | ||
|
|
1d587450b3 | ||
|
|
eb66266629 | ||
|
|
faa5e699d2 | ||
|
|
cb9fc3f6b4 | ||
|
|
6d27c3d0c5 | ||
|
|
962f996799 | ||
|
|
d09749eaaa | ||
|
|
9b29a19609 | ||
|
|
58406707f9 | ||
|
|
38c94bb633 | ||
|
|
9e59751c07 | ||
|
|
ae82112c2e | ||
|
|
95aef8241c | ||
|
|
d650dc94c9 | ||
|
|
09a0a49c52 | ||
|
|
937b26f3fd | ||
|
|
89238b4a04 | ||
|
|
b122f53085 | ||
|
|
609b0fa498 | ||
|
|
5e484e8393 | ||
|
|
6281910591 | ||
|
|
9680a3d44d | ||
|
|
b5c53aae97 | ||
|
|
cb6c6c8172 | ||
|
|
574e92e1d8 | ||
|
|
7214ee9024 | ||
|
|
829af9425f | ||
|
|
cd4026da6b | ||
|
|
d089b5e05d | ||
|
|
33ee1fba30 | ||
|
|
c138ff2c90 | ||
|
|
38906acda9 | ||
|
|
49d9235433 | ||
|
|
0d5579b4c0 | ||
|
|
08ee1da6b1 | ||
|
|
7453df2662 | ||
|
|
e258f30704 | ||
|
|
e562ae753b | ||
|
|
13c6f37ea5 | ||
|
|
feb5e20779 | ||
|
|
f606654c50 | ||
|
|
3f5078339c | ||
|
|
75ee1e9208 | ||
|
|
f5cf926364 | ||
|
|
b6afe5f2e8 | ||
|
|
b67872bc35 | ||
|
|
0c269d64d0 | ||
|
|
ce75afa413 | ||
|
|
13a9701581 | ||
|
|
333af6fd9b | ||
|
|
c817aecd66 | ||
|
|
b8ff3b1e3f | ||
|
|
dcac63936b | ||
|
|
28f0acd854 | ||
|
|
a2cd05f6db | ||
|
|
67410f7a4d | ||
|
|
37f9bdfc8c | ||
|
|
938deae4b4 | ||
|
|
a1b20bf69a | ||
|
|
44f5b92fbc | ||
|
|
0c45ee63a9 | ||
|
|
2bd4c14e5f | ||
|
|
47d3884377 | ||
|
|
d5aeae3a90 | ||
|
|
5c30643f6e | ||
|
|
82ba27b5f2 | ||
|
|
d2296d332e | ||
|
|
a4b1dd036d | ||
|
|
b894b5e669 | ||
|
|
b379b28337 | ||
|
|
e33b17fac6 | ||
|
|
50d1519a91 | ||
|
|
827fb7e8de | ||
|
|
21ecaae6ff | ||
|
|
7224ca6c62 | ||
|
|
f69654fcd5 | ||
|
|
7a3c1e162c | ||
|
|
ac1dda3b3a | ||
|
|
40844614bf | ||
|
|
f2942d94a5 | ||
|
|
48fc5edda1 | ||
|
|
c7acbcdaf5 | ||
|
|
f32e3a2960 | ||
|
|
813a9a975f | ||
|
|
b253284acc | ||
|
|
1411709db1 | ||
|
|
9b9e3962c5 | ||
|
|
048ac3089b | ||
|
|
79575ea124 | ||
|
|
3ba3fd9a59 | ||
|
|
6e145ad32d | ||
|
|
4c9b146bda | ||
|
|
2c8571a686 | ||
|
|
249e682511 | ||
|
|
be34417b3a | ||
|
|
a1e6c31ec1 | ||
|
|
634a26d2eb | ||
|
|
ddd5e5ae70 | ||
|
|
c67d72db63 | ||
|
|
8bcd55d221 | ||
|
|
6a82098ddf | ||
|
|
e80f54c243 | ||
|
|
fb41048dd7 | ||
|
|
2d5ec9b9e4 | ||
|
|
1bc94c7d5a | ||
|
|
e6f2811b21 | ||
|
|
7c3e8afd82 | ||
|
|
01f80950de | ||
|
|
83b7bbd60b | ||
|
|
add791b2cc | ||
|
|
d7b5fb4604 | ||
|
|
bafe25fbd9 | ||
|
|
7548d6f6d1 | ||
|
|
e708e9ac3c | ||
|
|
6d8d6cdb57 | ||
|
|
b487aa3e6a | ||
|
|
7cb0403faa | ||
|
|
e5e1683840 | ||
|
|
8d400b8f7b | ||
|
|
17b9609209 | ||
|
|
7b09dfe9a0 | ||
|
|
ebe8e62bd5 | ||
|
|
ced8c5f0e4 | ||
|
|
5a96863eed | ||
|
|
519e58a267 | ||
|
|
a2ed0b15da | ||
|
|
c9e9f25699 | ||
|
|
6c259eb04d | ||
|
|
de295af231 | ||
|
|
a5e6cb9a02 | ||
|
|
750ea9bbdd | ||
|
|
238139fad6 | ||
|
|
fbc44025dc | ||
|
|
27e7a28b37 | ||
|
|
2ea5b6fe33 | ||
|
|
a6a12d36d7 | ||
|
|
448b1cbc15 | ||
|
|
4752d7884a | ||
|
|
21ade3f64f | ||
|
|
94ee9c63a8 | ||
|
|
fac0333f47 | ||
|
|
80d694d205 | ||
|
|
ca7bbc44c0 | ||
|
|
4c5e1cacfe | ||
|
|
f80810081b | ||
|
|
f5e351af8b | ||
|
|
23c9da6162 | ||
|
|
eadaff6191 | ||
|
|
0d3f24ce54 | ||
|
|
7a30f72902 | ||
|
|
417db13efb | ||
|
|
22638db532 | ||
|
|
16c3566a87 | ||
|
|
688f5b830c | ||
|
|
4436b8da12 | ||
|
|
8870e3e85b | ||
|
|
ed110bc312 | ||
|
|
61b296afad | ||
|
|
0bfbb1c161 | ||
|
|
242689abe2 | ||
|
|
bea4741a12 | ||
|
|
dce59ccff2 | ||
|
|
4840adff00 | ||
|
|
e171ed8910 | ||
|
|
77400cef08 | ||
|
|
1324a67cbd | ||
|
|
64053e1954 | ||
|
|
1b85b2fca7 | ||
|
|
6d6b509d27 | ||
|
|
68bc9dd9dc | ||
|
|
5f98982a09 | ||
|
|
de7a880d66 | ||
|
|
80f8fb1e02 | ||
|
|
067ceb178e | ||
|
|
12ace5ab65 | ||
|
|
8ddcd67080 | ||
|
|
a376de56f2 | ||
|
|
7b1e41abc6 | ||
|
|
cebae40468 | ||
|
|
0cfdd726f7 | ||
|
|
2e67e3ba63 | ||
|
|
c40b0ea1df | ||
|
|
dd8c50e140 | ||
|
|
7ca346e9f0 | ||
|
|
3933cb6bf6 | ||
|
|
803694f41b | ||
|
|
9123e0fca8 | ||
|
|
5de2c99c32 | ||
|
|
f565800a51 | ||
|
|
a73365c3fe | ||
|
|
d0c17100cb | ||
|
|
6c0752473a | ||
|
|
f7c9fe6abc | ||
|
|
78e837cf39 | ||
|
|
f15919555b | ||
|
|
1ab2928f9d | ||
|
|
75993971c6 | ||
|
|
66c4a04dec | ||
|
|
b086981e15 | ||
|
|
574baa7151 | ||
|
|
3305ac1f36 | ||
|
|
50026fad2e | ||
|
|
87c9c47579 | ||
|
|
fe301142ba | ||
|
|
567fec402e | ||
|
|
0841e67da8 | ||
|
|
214b9af5a3 | ||
|
|
4533f22871 | ||
|
|
c09c00a1f5 | ||
|
|
295169b94f | ||
|
|
2dd40eb4e4 | ||
|
|
b8c4aa3936 | ||
|
|
65f9970a3e | ||
|
|
a1b92369db | ||
|
|
e731c248d7 | ||
|
|
dd66cbc847 | ||
|
|
ca25a25386 | ||
|
|
d3f516f1c4 | ||
|
|
95285aa09f | ||
|
|
8ed856c64f | ||
|
|
26e1b3a3fa | ||
|
|
1157542f70 | ||
|
|
1dfff74da9 | ||
|
|
27e1c67453 | ||
|
|
bc64754364 | ||
|
|
486aaca109 | ||
|
|
4dfaab4c5b | ||
|
|
2c3b8bb035 | ||
|
|
377b78102d | ||
|
|
4565676233 | ||
|
|
fa9a95f645 | ||
|
|
ef60d89742 | ||
|
|
c79b1bef15 | ||
|
|
cde347bd3d | ||
|
|
77421531d0 | ||
|
|
5377b82612 | ||
|
|
ef0b7bda6f | ||
|
|
e52aceeaba | ||
|
|
10f934d287 | ||
|
|
3095dabe3c | ||
|
|
1888708ca5 | ||
|
|
bdb736a9ee | ||
|
|
219118ef4a | ||
|
|
869d8e6f0e | ||
|
|
06aca5e8b5 | ||
|
|
65352dccc0 | ||
|
|
b649358734 | ||
|
|
e1b9d361ed | ||
|
|
3d9ea3f1fa | ||
|
|
4aae3c6c05 | ||
|
|
cec783ca2c | ||
|
|
00454b32f5 | ||
|
|
1c886940ff | ||
|
|
eb3aa7b193 | ||
|
|
6a5ce09b08 | ||
|
|
7e9a10a5fb | ||
|
|
93a8d8a25b | ||
|
|
a2b864dd6b | ||
|
|
f84534adea | ||
|
|
4b61c7cd55 | ||
|
|
8ed79d614b | ||
|
|
8d13276844 | ||
|
|
b894a5ff16 | ||
|
|
8f0c8005af | ||
|
|
34133671b9 | ||
|
|
ed067e8d35 | ||
|
|
4c6e4e2aa6 | ||
|
|
23738ad4ac | ||
|
|
1236b7b918 | ||
|
|
b170bde74f | ||
|
|
c46a3c8646 | ||
|
|
e5e8b9800c | ||
|
|
23c88a3b3f | ||
|
|
29c9d3f74c | ||
|
|
b804f6d999 | ||
|
|
249c1e8d3d | ||
|
|
c3cc60b080 | ||
|
|
afec9ec5be | ||
|
|
543c7fe587 | ||
|
|
b4ad044044 | ||
|
|
5d54bc00e1 | ||
|
|
871b85f199 | ||
|
|
ec7703bad7 | ||
|
|
217d43e512 | ||
|
|
06623506d3 | ||
|
|
fb7db147ed | ||
|
|
1fbac909cb | ||
|
|
2ee59ccad8 | ||
|
|
e078e2733f | ||
|
|
ed4dc241cc | ||
|
|
8523b1e410 | ||
|
|
d0753949bc | ||
|
|
515eab2405 | ||
|
|
c897485958 | ||
|
|
4d2e6b4a34 | ||
|
|
6eba9c2438 | ||
|
|
a806f542c6 | ||
|
|
8a9da4ba66 | ||
|
|
da8f6c150b | ||
|
|
d518ed5330 | ||
|
|
2c10f29b0f | ||
|
|
7db9cc3bf0 | ||
|
|
99257eb048 | ||
|
|
83d599670d | ||
|
|
fc0a4b34a1 | ||
|
|
f52920aa01 | ||
|
|
7f8dacd087 | ||
|
|
fc7d876158 | ||
|
|
764fa15e24 | ||
|
|
c40a50829d | ||
|
|
b5e70d4607 | ||
|
|
e3ea6c683c | ||
|
|
23655315b8 | ||
|
|
d04ad835e2 | ||
|
|
053c2039bb | ||
|
|
14bb7832af | ||
|
|
04d071aaa3 | ||
|
|
de0d409a23 | ||
|
|
64283408ee | ||
|
|
6dcb9e696d | ||
|
|
f17100e98e | ||
|
|
1f21b3e23b | ||
|
|
3dd073f98d | ||
|
|
6ed69e3d93 | ||
|
|
2b93cbbf04 | ||
|
|
13e015fe3f | ||
|
|
253b2cc081 | ||
|
|
8a53ec610b | ||
|
|
05b0bfafe4 | ||
|
|
0fc4da810f | ||
|
|
b0349bc795 | ||
|
|
fa7d7ed5df | ||
|
|
fc718b8a9a | ||
|
|
b16626c3b5 | ||
|
|
5c57c7cff5 | ||
|
|
770acee56a | ||
|
|
3d9b7a5892 | ||
|
|
4f7791b9fa | ||
|
|
893a91af3a | ||
|
|
c5419ba885 | ||
|
|
de8696d5d3 | ||
|
|
b7adf28501 | ||
|
|
b3531362ca | ||
|
|
7e2fb5e92e | ||
|
|
cc74f6c6a0 | ||
|
|
ec23816df6 | ||
|
|
c902ec1808 | ||
|
|
2cc855a131 | ||
|
|
0cbeb56af1 | ||
|
|
d8abfe6a7d | ||
|
|
949e3d29e8 | ||
|
|
25d3ec5bbf | ||
|
|
a8eed9d344 | ||
|
|
44b0f15a61 | ||
|
|
df71fe33fd | ||
|
|
8f29d28572 | ||
|
|
28f7b6dad1 | ||
|
|
138c8c348e | ||
|
|
c2b720835b | ||
|
|
d338b7ea7b | ||
|
|
1e6e89121c | ||
|
|
afce0feb05 | ||
|
|
8e9b3507c5 | ||
|
|
034f5921cc | ||
|
|
f1220fd2a4 | ||
|
|
0459261d19 | ||
|
|
97fd66db2e | ||
|
|
7aaa188471 | ||
|
|
b53a57610b | ||
|
|
6fa7ffc23f | ||
|
|
914071993d | ||
|
|
44a61a6db3 | ||
|
|
28781e7dfd | ||
|
|
ddeba41638 | ||
|
|
1dd4f03100 | ||
|
|
375816106e | ||
|
|
fff5d7154e | ||
|
|
4b73f67703 | ||
|
|
3000a2a43b | ||
|
|
f112e38266 | ||
|
|
6687409efb | ||
|
|
6836268f3e | ||
|
|
99aa9a46bc | ||
|
|
1290087b78 | ||
|
|
c99d6bd505 | ||
|
|
f2b5b6f299 | ||
|
|
7626775491 | ||
|
|
1452634a2a | ||
|
|
cf43007531 | ||
|
|
346577b664 | ||
|
|
76bd2aea44 | ||
|
|
a40314022b | ||
|
|
7992897418 | ||
|
|
707700ac7d | ||
|
|
85ccefdb84 | ||
|
|
d36efddcf7 | ||
|
|
005556632f | ||
|
|
006286ac05 | ||
|
|
0695e431ea | ||
|
|
38a4a2dc60 | ||
|
|
1446f54447 | ||
|
|
2e927a1053 | ||
|
|
b02a860e66 | ||
|
|
15f11effa0 | ||
|
|
bc570bb140 | ||
|
|
6eb00000fe | ||
|
|
45e6d9fcc4 | ||
|
|
3eaaa5d32d | ||
|
|
3a48ea8dde | ||
|
|
affd3d15a0 | ||
|
|
d14ac54af6 | ||
|
|
1dea5cb34b | ||
|
|
28ce71253f | ||
|
|
3cca45dd88 | ||
|
|
c2cc77fa08 | ||
|
|
1cc4c0c1f0 | ||
|
|
079346917f | ||
|
|
d86ed679b1 | ||
|
|
6315142d00 | ||
|
|
7e089314f7 | ||
|
|
9d5ccaef54 | ||
|
|
556219b192 | ||
|
|
fd20aa7c03 | ||
|
|
6b5854936d | ||
|
|
b5a54c535b | ||
|
|
eb994ad72e | ||
|
|
3451f9a9db | ||
|
|
53817b7429 | ||
|
|
8f9d9ed35d | ||
|
|
f4f12c1e84 | ||
|
|
bde0136317 | ||
|
|
2b3c547589 | ||
|
|
ba2e43f547 | ||
|
|
492f842c53 | ||
|
|
3a99148315 | ||
|
|
e168bfe03e | ||
|
|
71dcafebb8 | ||
|
|
c10359dd5b | ||
|
|
177220e2fe | ||
|
|
d7f58d74d3 | ||
|
|
cdbd4e0fc0 | ||
|
|
c2064781a0 | ||
|
|
7cc3d0c34e | ||
|
|
5076f9304b | ||
|
|
048cecdab5 | ||
|
|
9fc59cc212 | ||
|
|
727a7bf27a | ||
|
|
886c8b823a | ||
|
|
b5820d930c | ||
|
|
ffb1db833c | ||
|
|
540bde269e | ||
|
|
cc3418f6a3 | ||
|
|
b4a77d49b4 | ||
|
|
601a1d9b92 | ||
|
|
6737f79331 | ||
|
|
250f85b9bd | ||
|
|
cc5d7002b0 | ||
|
|
ba9c3f60c4 | ||
|
|
cec9634f4a | ||
|
|
ab4f8c273d | ||
|
|
120a86ecf9 | ||
|
|
24ae9cef36 | ||
|
|
7e8bd8d004 | ||
|
|
e794951087 | ||
|
|
d30835f648 | ||
|
|
b142d6a037 | ||
|
|
ad22e20ecd | ||
|
|
979f2d79fb | ||
|
|
abed9c055f | ||
|
|
c9f5568332 | ||
|
|
92ac1fbb5b | ||
|
|
48143d6caf | ||
|
|
9c492bd774 | ||
|
|
428d4b0dbf | ||
|
|
f2c5417ee4 | ||
|
|
aa59843902 | ||
|
|
fa95297e6a | ||
|
|
80e4a9dc55 | ||
|
|
bff174dba9 | ||
|
|
1232745e89 | ||
|
|
fe4cfbeb73 | ||
|
|
d39dac10a6 | ||
|
|
5ca972542b | ||
|
|
56679ac80f | ||
|
|
60816f5fc2 | ||
|
|
39f37ff8aa | ||
|
|
92e5968f91 | ||
|
|
a101177b55 | ||
|
|
fbed72c89c | ||
|
|
c4b57a2562 | ||
|
|
cfd1f5c072 | ||
|
|
697a3eaa43 | ||
|
|
30f048965c | ||
|
|
dc11f1da81 | ||
|
|
4cc80efee6 | ||
|
|
66d020eb7e | ||
|
|
392c47f39b | ||
|
|
64c16eb912 | ||
|
|
51b078fb65 | ||
|
|
4050fce220 | ||
|
|
828dd34507 | ||
|
|
06f7332156 | ||
|
|
c9cdb4cda0 | ||
|
|
41ff37f0a1 | ||
|
|
2c7040c246 | ||
|
|
4042e4b225 | ||
|
|
b97cede054 | ||
|
|
a21afbe9a6 | ||
|
|
63a200686e | ||
|
|
d6cdc2497c | ||
|
|
1e275d0cd1 | ||
|
|
71ef9b6db5 | ||
|
|
eabcbcda88 | ||
|
|
bc5b59737c | ||
|
|
8e7d23cdeb | ||
|
|
bd7964d549 | ||
|
|
fa72c4fea4 | ||
|
|
13d0bd5815 | ||
|
|
0a487c484d | ||
|
|
403c64ab20 | ||
|
|
c318f7bb31 | ||
|
|
1b8103f0ea | ||
|
|
7defb1adf5 | ||
|
|
e92ea79524 | ||
|
|
2116152295 | ||
|
|
a58b4ff2d6 | ||
|
|
14b737e662 | ||
|
|
b39fb7fdd5 | ||
|
|
a0a6fa6fa5 | ||
|
|
a5588b6957 | ||
|
|
4ed1ec5174 | ||
|
|
db92a96067 | ||
|
|
1d515bb52c | ||
|
|
164ddb16c9 | ||
|
|
0c7294593c | ||
|
|
d554c6f9be | ||
|
|
fa021b547a | ||
|
|
db91033b6e | ||
|
|
20353db966 | ||
|
|
a2bbd89a9e | ||
|
|
df94b380f4 | ||
|
|
3898ea02e6 | ||
|
|
fe293718a2 | ||
|
|
e5df179c7c | ||
|
|
74c3f732c1 | ||
|
|
1f8a2a67bf | ||
|
|
08461408a2 | ||
|
|
af63a26be0 | ||
|
|
abef722265 | ||
|
|
380aa26ea3 | ||
|
|
0e54c474aa | ||
|
|
8a1bd2ee22 | ||
|
|
2e86985d44 | ||
|
|
f9fb315dbd | ||
|
|
61e6f63b32 | ||
|
|
5b926cc102 | ||
|
|
1bf982439b | ||
|
|
5f3b7eaa45 |
@@ -1,6 +1,56 @@
|
||||
aliases:
|
||||
# Workflow filters
|
||||
- &filter-only-release
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: /^v[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)$/
|
||||
- &filter-not-release
|
||||
tags:
|
||||
ignore: /^v[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)$/
|
||||
|
||||
version: 2
|
||||
|
||||
jobs:
|
||||
mysql-integration-test:
|
||||
docker:
|
||||
- image: circleci/golang:1.10
|
||||
- image: circleci/mysql:5.6-ram
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: rootpass
|
||||
MYSQL_DATABASE: grafana_tests
|
||||
MYSQL_USER: grafana
|
||||
MYSQL_PASSWORD: password
|
||||
working_directory: /go/src/github.com/grafana/grafana
|
||||
steps:
|
||||
- checkout
|
||||
- run: sudo apt update
|
||||
- run: sudo apt install -y mysql-client
|
||||
- run: dockerize -wait tcp://127.0.0.1:3306 -timeout 120s
|
||||
- run: cat docker/blocks/mysql_tests/setup.sql | mysql -h 127.0.0.1 -P 3306 -u root -prootpass
|
||||
- run:
|
||||
name: mysql integration tests
|
||||
command: 'GRAFANA_TEST_DB=mysql go test ./pkg/services/sqlstore/... ./pkg/tsdb/mysql/... '
|
||||
|
||||
postgres-integration-test:
|
||||
docker:
|
||||
- image: circleci/golang:1.10
|
||||
- image: circleci/postgres:9.3-ram
|
||||
environment:
|
||||
POSTGRES_USER: grafanatest
|
||||
POSTGRES_PASSWORD: grafanatest
|
||||
POSTGRES_DB: grafanatest
|
||||
working_directory: /go/src/github.com/grafana/grafana
|
||||
steps:
|
||||
- checkout
|
||||
- run: sudo apt update
|
||||
- run: sudo apt install -y postgresql-client
|
||||
- run: dockerize -wait tcp://127.0.0.1:5432 -timeout 120s
|
||||
- run: 'PGPASSWORD=grafanatest psql -p 5432 -h 127.0.0.1 -U grafanatest -d grafanatest -f docker/blocks/postgres_tests/setup.sql'
|
||||
- run:
|
||||
name: postgres integration tests
|
||||
command: 'GRAFANA_TEST_DB=postgres go test ./pkg/services/sqlstore/... ./pkg/tsdb/postgres/...'
|
||||
|
||||
codespell:
|
||||
docker:
|
||||
- image: circleci/python
|
||||
@@ -20,18 +70,21 @@ jobs:
|
||||
gometalinter:
|
||||
docker:
|
||||
- image: circleci/golang:1.10
|
||||
environment:
|
||||
# we need CGO because of go-sqlite3
|
||||
CGO_ENABLED: 1
|
||||
working_directory: /go/src/github.com/grafana/grafana
|
||||
steps:
|
||||
- checkout
|
||||
- run: 'go get -u gopkg.in/alecthomas/gometalinter.v2'
|
||||
- run: 'go get -u github.com/tsenart/deadcode'
|
||||
- run: 'go get -u github.com/gordonklaus/ineffassign'
|
||||
- run: 'go get -u github.com/opennota/check/cmd/structcheck'
|
||||
- run: 'go get -u github.com/mdempsky/unconvert'
|
||||
- run: 'go get -u github.com/opennota/check/cmd/varcheck'
|
||||
- run:
|
||||
name: install gometalinter tool
|
||||
command: 'go get -u github.com/alecthomas/gometalinter'
|
||||
- run:
|
||||
name: install linters
|
||||
command: 'gometalinter --install'
|
||||
- run:
|
||||
name: run some linters
|
||||
command: 'gometalinter --vendor --deadline 6m --disable-all --enable=structcheck --enable=unconvert --enable=varcheck ./pkg/...'
|
||||
name: run linters
|
||||
command: 'gometalinter.v2 --enable-gc --vendor --deadline 10m --disable-all --enable=deadcode --enable=ineffassign --enable=structcheck --enable=unconvert --enable=varcheck ./...'
|
||||
|
||||
test-frontend:
|
||||
docker:
|
||||
@@ -43,7 +96,6 @@ jobs:
|
||||
command: 'sudo npm install -g yarn --quiet'
|
||||
- restore_cache:
|
||||
key: dependency-cache-{{ checksum "yarn.lock" }}
|
||||
# Could we skip this step if the cache has been restored? `[ -d node_modules ] || yarn install ...` should be able to apply to build step as well
|
||||
- run:
|
||||
name: yarn install
|
||||
command: 'yarn install --pure-lockfile --no-progress'
|
||||
@@ -65,15 +117,27 @@ jobs:
|
||||
name: build backend and run go tests
|
||||
command: './scripts/circle-test-backend.sh'
|
||||
|
||||
build:
|
||||
build-all:
|
||||
docker:
|
||||
- image: grafana/build-container:v0.1
|
||||
- image: grafana/build-container:1.0.0
|
||||
working_directory: /go/src/github.com/grafana/grafana
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: prepare build tools
|
||||
command: '/tmp/bootstrap.sh'
|
||||
- restore_cache:
|
||||
key: phantomjs-binaries-{{ checksum "scripts/build/download-phantomjs.sh" }}
|
||||
- run:
|
||||
name: download phantomjs binaries
|
||||
command: './scripts/build/download-phantomjs.sh'
|
||||
- save_cache:
|
||||
key: phantomjs-binaries-{{ checksum "scripts/build/download-phantomjs.sh" }}
|
||||
paths:
|
||||
- /tmp/phantomjs
|
||||
- run:
|
||||
name: build and package grafana
|
||||
command: './scripts/build/build.sh'
|
||||
command: './scripts/build/build-all.sh'
|
||||
- run:
|
||||
name: sign packages
|
||||
command: './scripts/build/sign_packages.sh'
|
||||
@@ -89,6 +153,24 @@ jobs:
|
||||
- dist/grafana*
|
||||
- scripts/*.sh
|
||||
- scripts/publish
|
||||
- store_artifacts:
|
||||
path: dist
|
||||
|
||||
build-enterprise:
|
||||
docker:
|
||||
- image: grafana/build-container:v0.1
|
||||
working_directory: /go/src/github.com/grafana/grafana
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: build and package grafana
|
||||
command: './scripts/build/build_enterprise.sh'
|
||||
- run:
|
||||
name: sign packages
|
||||
command: './scripts/build/sign_packages.sh'
|
||||
- run:
|
||||
name: sha-sum packages
|
||||
command: 'go run build.go sha-dist'
|
||||
|
||||
deploy-master:
|
||||
docker:
|
||||
@@ -101,23 +183,28 @@ jobs:
|
||||
command: 'sudo pip install awscli'
|
||||
- run:
|
||||
name: deploy to s3
|
||||
command: 'aws s3 sync ./dist s3://$BUCKET_NAME/master'
|
||||
command: |
|
||||
# Also
|
||||
cp dist/grafana-latest.linux-x64.tar.gz dist/grafana-master-$(echo "${CIRCLE_SHA1}" | cut -b1-7).linux-x64.tar.gz
|
||||
aws s3 sync ./dist s3://$BUCKET_NAME/master
|
||||
- run:
|
||||
name: Trigger Windows build
|
||||
command: './scripts/trigger_windows_build.sh ${APPVEYOR_TOKEN} ${CIRCLE_SHA1} master'
|
||||
- run:
|
||||
name: Trigger Docker build
|
||||
command: './scripts/trigger_docker_build.sh ${TRIGGER_GRAFANA_PACKER_CIRCLECI_TOKEN}'
|
||||
command: './scripts/trigger_docker_build.sh ${TRIGGER_GRAFANA_PACKER_CIRCLECI_TOKEN} master-$(echo "${CIRCLE_SHA1}" | cut -b1-7)'
|
||||
- run:
|
||||
name: Publish to Grafana.com
|
||||
command: './scripts/publish -apiKey ${GRAFANA_COM_API_KEY}'
|
||||
command: |
|
||||
rm dist/grafana-master-$(echo "${CIRCLE_SHA1}" | cut -b1-7).linux-x64.tar.gz
|
||||
./scripts/publish -apiKey ${GRAFANA_COM_API_KEY}
|
||||
|
||||
deploy-release:
|
||||
docker:
|
||||
- image: circleci/python:2.7-stretch
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: dist
|
||||
at: .
|
||||
- run:
|
||||
name: install awscli
|
||||
command: 'sudo pip install awscli'
|
||||
@@ -135,37 +222,55 @@ workflows:
|
||||
version: 2
|
||||
test-and-build:
|
||||
jobs:
|
||||
- build-all:
|
||||
filters: *filter-not-release
|
||||
- codespell:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
- build:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
filters: *filter-not-release
|
||||
- gometalinter:
|
||||
filters: *filter-not-release
|
||||
- test-frontend:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
filters: *filter-not-release
|
||||
- test-backend:
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
filters: *filter-not-release
|
||||
- mysql-integration-test:
|
||||
filters: *filter-not-release
|
||||
- postgres-integration-test:
|
||||
filters: *filter-not-release
|
||||
- deploy-master:
|
||||
requires:
|
||||
- build-all
|
||||
- test-backend
|
||||
- test-frontend
|
||||
- build
|
||||
- codespell
|
||||
- gometalinter
|
||||
- mysql-integration-test
|
||||
- postgres-integration-test
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
branches:
|
||||
only: master
|
||||
release:
|
||||
jobs:
|
||||
- build-all:
|
||||
filters: *filter-only-release
|
||||
- codespell:
|
||||
filters: *filter-only-release
|
||||
- gometalinter:
|
||||
filters: *filter-only-release
|
||||
- test-frontend:
|
||||
filters: *filter-only-release
|
||||
- test-backend:
|
||||
filters: *filter-only-release
|
||||
- mysql-integration-test:
|
||||
filters: *filter-only-release
|
||||
- postgres-integration-test:
|
||||
filters: *filter-only-release
|
||||
- deploy-release:
|
||||
requires:
|
||||
- build-all
|
||||
- test-backend
|
||||
- test-frontend
|
||||
- build
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: /^v[0-9]+(\.[0-9]+){2}(-.+|[^-.]*)$/
|
||||
- codespell
|
||||
- gometalinter
|
||||
- mysql-integration-test
|
||||
- postgres-integration-test
|
||||
filters: *filter-only-release
|
||||
|
||||
15
.dockerignore
Normal file
15
.dockerignore
Normal file
@@ -0,0 +1,15 @@
|
||||
.awcache
|
||||
.dockerignore
|
||||
.git
|
||||
.gitignore
|
||||
.github
|
||||
data*
|
||||
dist
|
||||
docker
|
||||
docs
|
||||
dump.rdb
|
||||
node_modules
|
||||
/local
|
||||
/tmp
|
||||
*.yml
|
||||
*.md
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,8 +1,10 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
coverage/
|
||||
.aws-config.json
|
||||
awsconfig
|
||||
/.awcache
|
||||
/dist
|
||||
/public/build
|
||||
/public/views/index.html
|
||||
@@ -42,10 +44,13 @@ docker-compose.yaml
|
||||
/conf/provisioning/**/custom.yaml
|
||||
profile.cov
|
||||
/grafana
|
||||
/local
|
||||
.notouch
|
||||
/Makefile.local
|
||||
/pkg/cmd/grafana-cli/grafana-cli
|
||||
/pkg/cmd/grafana-server/grafana-server
|
||||
/pkg/cmd/grafana-server/debug
|
||||
/pkg/extensions
|
||||
debug.test
|
||||
/examples/*/dist
|
||||
/packaging/**/*.rpm
|
||||
@@ -60,4 +65,6 @@ debug.test
|
||||
/vendor/**/*_test.go
|
||||
/vendor/**/.editorconfig
|
||||
/vendor/**/appengine*
|
||||
*.orig
|
||||
*.orig
|
||||
|
||||
/devenv/dashboards/bulk-testing/*.json
|
||||
|
||||
90
CHANGELOG.md
90
CHANGELOG.md
@@ -1,4 +1,86 @@
|
||||
# 5.1.0 (unreleased)
|
||||
# 5.2.0 (unreleased)
|
||||
|
||||
### New Features
|
||||
|
||||
* **Dashboard**: Import dashboard to folder [#10796](https://github.com/grafana/grafana/issues/10796)
|
||||
|
||||
### Minor
|
||||
|
||||
* **Dashboard**: Fix so panel titles doesn't wrap [#11074](https://github.com/grafana/grafana/issues/11074)
|
||||
* **Dashboard**: Prevent double-click when saving dashboard [#11963](https://github.com/grafana/grafana/issues/11963)
|
||||
* **Dashboard**: AutoFocus the add-panel search filter [#12189](https://github.com/grafana/grafana/pull/12189) thx [@ryantxu](https://github.com/ryantxu)
|
||||
* **Units**: W/m2 (energy), l/h (flow) and kPa (pressure) [#11233](https://github.com/grafana/grafana/pull/11233), thx [@flopp999](https://github.com/flopp999)
|
||||
* **Units**: Litre/min (flow) and milliLitre/min (flow) [#12282](https://github.com/grafana/grafana/pull/12282), thx [@flopp999](https://github.com/flopp999)
|
||||
* **Alerting**: Fix mobile notifications for Microsoft Teams alert notifier [#11484](https://github.com/grafana/grafana/pull/11484), thx [@manacker](https://github.com/manacker)
|
||||
* **Influxdb**: Add support for mode function [#12286](https://github.com/grafana/grafana/issues/12286)
|
||||
* **Cloudwatch**: Fixes panic caused by bad timerange settings [#12199](https://github.com/grafana/grafana/issues/12199)
|
||||
* **Auth Proxy**: Whitelist proxy IP address instead of client IP address [#10707](https://github.com/grafana/grafana/issues/10707)
|
||||
|
||||
# 5.2.0-beta1 (2018-06-05)
|
||||
|
||||
### New Features
|
||||
|
||||
* **Elasticsearch**: Alerting support [#5893](https://github.com/grafana/grafana/issues/5893), thx [@WPH95](https://github.com/WPH95)
|
||||
* **Login**: Change admin password after first login [#11882](https://github.com/grafana/grafana/issues/11882)
|
||||
* **Alert list panel**: Updated to support filtering alerts by name, dashboard title, folder, tags [#11500](https://github.com/grafana/grafana/issues/11500), [#8168](https://github.com/grafana/grafana/issues/8168), [#6541](https://github.com/grafana/grafana/issues/6541)
|
||||
|
||||
### Minor
|
||||
|
||||
* **Dashboard**: Modified time range and variables are now not saved by default [#10748](https://github.com/grafana/grafana/issues/10748), [#8805](https://github.com/grafana/grafana/issues/8805)
|
||||
* **Graph**: Show invisible highest value bucket in histogram [#11498](https://github.com/grafana/grafana/issues/11498)
|
||||
* **Dashboard**: Enable "Save As..." if user has edit permission [#11625](https://github.com/grafana/grafana/issues/11625)
|
||||
* **Prometheus**: Query dates are now step-aligned [#10434](https://github.com/grafana/grafana/pull/10434)
|
||||
* **Prometheus**: Table columns order now changes when rearrange queries [#11690](https://github.com/grafana/grafana/issues/11690), thx [@mtanda](https://github.com/mtanda)
|
||||
* **Variables**: Fix variable interpolation when using multiple formatting types [#11800](https://github.com/grafana/grafana/issues/11800), thx [@svenklemm](https://github.com/svenklemm)
|
||||
* **Dashboard**: Fix date selector styling for dark/light theme in time picker control [#11616](https://github.com/grafana/grafana/issues/11616)
|
||||
* **Discord**: Alert notification channel type for Discord, [#7964](https://github.com/grafana/grafana/issues/7964) thx [@jereksel](https://github.com/jereksel),
|
||||
* **InfluxDB**: Support SELECT queries in templating query, [#5013](https://github.com/grafana/grafana/issues/5013)
|
||||
* **InfluxDB**: Support count distinct aggregation [#11645](https://github.com/grafana/grafana/issues/11645), thx [@kichristensen](https://github.com/kichristensen)
|
||||
* **Dashboard**: JSON Model under dashboard settings can now be updated & changes saved, [#1429](https://github.com/grafana/grafana/issues/1429), thx [@jereksel](https://github.com/jereksel)
|
||||
* **Security**: Fix XSS vulnerabilities in dashboard links [#11813](https://github.com/grafana/grafana/pull/11813)
|
||||
* **Singlestat**: Fix "time of last point" shows local time when dashboard timezone set to UTC [#10338](https://github.com/grafana/grafana/issues/10338)
|
||||
* **Prometheus**: Add support for passing timeout parameter to Prometheus [#11788](https://github.com/grafana/grafana/pull/11788), thx [@mtanda](https://github.com/mtanda)
|
||||
* **Login**: Add optional option sign out url for generic oauth [#9847](https://github.com/grafana/grafana/issues/9847), thx [@roidelapluie](https://github.com/roidelapluie)
|
||||
* **Login**: Use proxy server from environment variable if available [#9703](https://github.com/grafana/grafana/issues/9703), thx [@iyeonok](https://github.com/iyeonok)
|
||||
* **Invite users**: Friendlier error message when smtp is not configured [#12087](https://github.com/grafana/grafana/issues/12087), thx [@thurt](https://github.com/thurt)
|
||||
* **Graphite**: Don't send distributed tracing headers when using direct/browser access mode [#11494](https://github.com/grafana/grafana/issues/11494)
|
||||
* **Sidenav**: Show create dashboard link for viewers if at least editor in one folder [#11858](https://github.com/grafana/grafana/issues/11858)
|
||||
* **SQL**: Second epochs are now correctly converted to ms. [#12085](https://github.com/grafana/grafana/pull/12085)
|
||||
* **Singlestat**: Fix singlestat threshold tooltip [#11971](https://github.com/grafana/grafana/issues/11971)
|
||||
* **Dashboard**: Hide grid controls in fullscreen/low-activity views [#11771](https://github.com/grafana/grafana/issues/11771)
|
||||
* **Dashboard**: Validate uid when importing dashboards [#11515](https://github.com/grafana/grafana/issues/11515)
|
||||
* **Docker**: Support for env variables ending with _FILE [grafana-docker #166](https://github.com/grafana/grafana-docker/pull/166), thx [@efrecon](https://github.com/efrecon)
|
||||
* **Alert list panel**: Show alerts for user with viewer role [#11167](https://github.com/grafana/grafana/issues/11167)
|
||||
* **Provisioning**: Verify checksum of dashboards before updating to reduce load on database [#11670](https://github.com/grafana/grafana/issues/11670)
|
||||
* **Provisioning**: Support symlinked files in dashboard provisioning config files [#11958](https://github.com/grafana/grafana/issues/11958)
|
||||
* **Dashboard list panel**: Search dashboards by folder [#11525](https://github.com/grafana/grafana/issues/11525)
|
||||
* **Sidenav**: Always show server admin link in sidenav if grafana admin [#11657](https://github.com/grafana/grafana/issues/11657)
|
||||
|
||||
# 5.1.3 (2018-05-16)
|
||||
|
||||
* **Scroll**: Graph panel / legend texts shifts on the left each time we move scrollbar on firefox [#11830](https://github.com/grafana/grafana/issues/11830)
|
||||
|
||||
# 5.1.2 (2018-05-09)
|
||||
|
||||
* **Database**: Fix MySql migration issue [#11862](https://github.com/grafana/grafana/issues/11862)
|
||||
* **Google Analytics**: Enable Google Analytics anonymizeIP setting for GDPR [#11656](https://github.com/grafana/grafana/pull/11656)
|
||||
|
||||
# 5.1.1 (2018-05-07)
|
||||
|
||||
* **LDAP**: LDAP login with MariaDB/MySQL database and dn>100 chars not possible [#11754](https://github.com/grafana/grafana/issues/11754)
|
||||
* **Build**: AppVeyor Windows build missing version and commit info [#11758](https://github.com/grafana/grafana/issues/11758)
|
||||
* **Scroll**: Scroll can't start in graphs on Chrome mobile [#11710](https://github.com/grafana/grafana/issues/11710)
|
||||
* **Units**: Revert renaming of unit key ppm [#11743](https://github.com/grafana/grafana/issues/11743)
|
||||
|
||||
# 5.1.0 (2018-04-26)
|
||||
|
||||
* **Folders**: Default permissions on folder are not shown as inherited in its dashboards [#11668](https://github.com/grafana/grafana/issues/11668)
|
||||
* **Templating**: Allow more than 20 previews when creating a variable [#11508](https://github.com/grafana/grafana/issues/11508)
|
||||
* **Dashboard**: Row edit icon not shown [#11466](https://github.com/grafana/grafana/issues/11466)
|
||||
* **SQL**: Unsupported data types for value column using time series query [#11703](https://github.com/grafana/grafana/issues/11703)
|
||||
* **Prometheus**: Prometheus query inspector expands to be very large on autocomplete queries [#11673](https://github.com/grafana/grafana/issues/11673)
|
||||
|
||||
# 5.1.0-beta1 (2018-04-20)
|
||||
|
||||
* **MSSQL**: New Microsoft SQL Server data source [#10093](https://github.com/grafana/grafana/pull/10093), [#11298](https://github.com/grafana/grafana/pull/11298), thx [@linuxchips](https://github.com/linuxchips)
|
||||
* **Prometheus**: The heatmap panel now support Prometheus histograms [#10009](https://github.com/grafana/grafana/issues/10009)
|
||||
@@ -43,13 +125,13 @@
|
||||
* **Units**: Use B/s instead Bps for Bytes per second [#9342](https://github.com/grafana/grafana/pull/9342), thx [@mayli](https://github.com/mayli)
|
||||
* **Units**: Radiation units [#11001](https://github.com/grafana/grafana/issues/11001), thx [@victorclaessen](https://github.com/victorclaessen)
|
||||
* **Units**: Timeticks unit [#11183](https://github.com/grafana/grafana/pull/11183), thx [@jtyr](https://github.com/jtyr)
|
||||
* **Units**: Concentration units and "Normal cubic metre" [#11211](https://github.com/grafana/grafana/issues/11211), thx [@flopp999](https://github.com/flopp999)
|
||||
* **Units**: Concentration units and "Normal cubic metre" [#11211](https://github.com/grafana/grafana/issues/11211), thx [@flopp999](https://github.com/flopp999)
|
||||
* **Units**: New currency - Czech koruna [#11384](https://github.com/grafana/grafana/pull/11384), thx [@Rohlik](https://github.com/Rohlik)
|
||||
* **Avatar**: Fix DISABLE_GRAVATAR option [#11095](https://github.com/grafana/grafana/issues/11095)
|
||||
* **Heatmap**: Disable log scale when using time time series buckets [#10792](https://github.com/grafana/grafana/issues/10792)
|
||||
* **Provisioning**: Remove `id` from json when provisioning dashboards, [#11138](https://github.com/grafana/grafana/issues/11138)
|
||||
* **Prometheus**: tooltip for legend format not showing properly [#11516](https://github.com/grafana/grafana/issues/11516), thx [@svenklemm](https://github.com/svenklemm)
|
||||
* **Playlist**: Empty playlists cannot be deleted [#11133](https://github.com/grafana/grafana/issues/11133), thx [@kichristensen](https://github.com/kichristensen)
|
||||
* **Prometheus**: tooltip for legend format not showing properly [#11516](https://github.com/grafana/grafana/issues/11516), thx [@svenklemm](https://github.com/svenklemm)
|
||||
* **Playlist**: Empty playlists cannot be deleted [#11133](https://github.com/grafana/grafana/issues/11133), thx [@kichristensen](https://github.com/kichristensen)
|
||||
* **Switch Orgs**: Alphabetic order in Switch Organization modal [#11556](https://github.com/grafana/grafana/issues/11556)
|
||||
* **Postgres**: improve `$__timeFilter` macro [#11578](https://github.com/grafana/grafana/issues/11578), thx [@svenklemm](https://github.com/svenklemm)
|
||||
* **Permission list**: Improved ux [#10747](https://github.com/grafana/grafana/issues/10747)
|
||||
|
||||
348
Gopkg.lock
generated
348
Gopkg.lock
generated
@@ -4,8 +4,8 @@
|
||||
[[projects]]
|
||||
name = "cloud.google.com/go"
|
||||
packages = ["compute/metadata"]
|
||||
revision = "767c40d6a2e058483c25fa193e963a22da17236d"
|
||||
version = "v0.18.0"
|
||||
revision = "056a55f54a6cc77b440b31a56a5e7c3982d32811"
|
||||
version = "v0.22.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/BurntSushi/toml"
|
||||
@@ -19,17 +19,43 @@
|
||||
packages = ["."]
|
||||
revision = "7677a1d7c1137cd3dd5ba7a076d0c898a1ef4520"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/apache/thrift"
|
||||
packages = ["lib/go/thrift"]
|
||||
revision = "b2a4d4ae21c789b689dd162deb819665567f481c"
|
||||
version = "0.10.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/aws/aws-sdk-go"
|
||||
packages = ["aws","aws/awserr","aws/awsutil","aws/client","aws/client/metadata","aws/corehandlers","aws/credentials","aws/credentials/ec2rolecreds","aws/credentials/endpointcreds","aws/credentials/stscreds","aws/defaults","aws/ec2metadata","aws/endpoints","aws/request","aws/session","aws/signer/v4","internal/shareddefaults","private/protocol","private/protocol/ec2query","private/protocol/query","private/protocol/query/queryutil","private/protocol/rest","private/protocol/restxml","private/protocol/xml/xmlutil","service/cloudwatch","service/ec2","service/ec2/ec2iface","service/s3","service/sts"]
|
||||
revision = "decd990ddc5dcdf2f73309cbcab90d06b996ca28"
|
||||
version = "v1.12.67"
|
||||
packages = [
|
||||
"aws",
|
||||
"aws/awserr",
|
||||
"aws/awsutil",
|
||||
"aws/client",
|
||||
"aws/client/metadata",
|
||||
"aws/corehandlers",
|
||||
"aws/credentials",
|
||||
"aws/credentials/ec2rolecreds",
|
||||
"aws/credentials/endpointcreds",
|
||||
"aws/credentials/stscreds",
|
||||
"aws/defaults",
|
||||
"aws/ec2metadata",
|
||||
"aws/endpoints",
|
||||
"aws/request",
|
||||
"aws/session",
|
||||
"aws/signer/v4",
|
||||
"internal/sdkio",
|
||||
"internal/sdkrand",
|
||||
"internal/shareddefaults",
|
||||
"private/protocol",
|
||||
"private/protocol/ec2query",
|
||||
"private/protocol/query",
|
||||
"private/protocol/query/queryutil",
|
||||
"private/protocol/rest",
|
||||
"private/protocol/restxml",
|
||||
"private/protocol/xml/xmlutil",
|
||||
"service/cloudwatch",
|
||||
"service/ec2",
|
||||
"service/ec2/ec2iface",
|
||||
"service/s3",
|
||||
"service/sts"
|
||||
]
|
||||
revision = "c7cd1ebe87257cde9b65112fc876b0339ea0ac30"
|
||||
version = "v1.13.49"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -41,7 +67,7 @@
|
||||
branch = "master"
|
||||
name = "github.com/beorn7/perks"
|
||||
packages = ["quantile"]
|
||||
revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9"
|
||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -75,20 +101,35 @@
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/denisenkom/go-mssqldb"
|
||||
packages = [".","internal/cp"]
|
||||
packages = [
|
||||
".",
|
||||
"internal/cp"
|
||||
]
|
||||
revision = "270bc3860bb94dd3a3ffd047377d746c5e276726"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/facebookgo/inject"
|
||||
packages = ["."]
|
||||
revision = "cc1aa653e50f6a9893bcaef89e673e5b24e1e97b"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/facebookgo/structtag"
|
||||
packages = ["."]
|
||||
revision = "217e25fb96916cc60332e399c9aa63f5c422ceed"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fatih/color"
|
||||
packages = ["."]
|
||||
revision = "570b54cabe6b8eb0bc2dfce68d964677d63b5260"
|
||||
version = "v1.5.0"
|
||||
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-ini/ini"
|
||||
packages = ["."]
|
||||
revision = "32e4c1e6bc4e7d0d8451aa6b75200d19e37a536a"
|
||||
version = "v1.32.0"
|
||||
revision = "6529cf7c58879c08d927016dde4477f18a0634cb"
|
||||
version = "v1.36.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-ldap/ldap"
|
||||
@@ -117,7 +158,12 @@
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/go-macaron/session"
|
||||
packages = [".","memcache","postgres","redis"]
|
||||
packages = [
|
||||
".",
|
||||
"memcache",
|
||||
"postgres",
|
||||
"redis"
|
||||
]
|
||||
revision = "b8e286a0dba8f4999042d6b258daf51b31d08938"
|
||||
|
||||
[[projects]]
|
||||
@@ -132,10 +178,10 @@
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/go-xorm/builder"
|
||||
packages = ["."]
|
||||
revision = "488224409dd8aa2ce7a5baf8d10d55764a913738"
|
||||
revision = "bad0a612f0d6277b953910822ab5dfb30dd18237"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-xorm/core"
|
||||
@@ -152,14 +198,20 @@
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = ["proto","ptypes","ptypes/any","ptypes/duration","ptypes/timestamp"]
|
||||
revision = "c65a0412e71e8b9b3bfd22925720d23c0f054237"
|
||||
packages = [
|
||||
"proto",
|
||||
"ptypes",
|
||||
"ptypes/any",
|
||||
"ptypes/duration",
|
||||
"ptypes/timestamp"
|
||||
]
|
||||
revision = "927b65914520a8b7d44f5c9057611cfec6b2e2d0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/gopherjs/gopherjs"
|
||||
packages = ["js"]
|
||||
revision = "178c176a91fe05e3e6c58fa5c989bad19e6cdcb3"
|
||||
revision = "8dffc02ea1cb8398bb73f30424697c60fcf8d4c5"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
@@ -175,32 +227,35 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/grafana/grafana_plugin_model"
|
||||
packages = ["go/datasource"]
|
||||
revision = "dfe5dc0a6ce05825ba7fe2d0323d92e631bffa89"
|
||||
name = "github.com/grafana/grafana-plugin-model"
|
||||
packages = [
|
||||
"go/datasource",
|
||||
"go/renderer"
|
||||
]
|
||||
revision = "84176c64269d8060f99e750ee8aba6f062753336"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/go-hclog"
|
||||
packages = ["."]
|
||||
revision = "5bcb0f17e36442247290887cc914a6e507afa5c4"
|
||||
revision = "69ff559dc25f3b435631604f573a5fa1efdb6433"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/hashicorp/go-plugin"
|
||||
packages = ["."]
|
||||
revision = "3e6d191694b5a3a2b99755f31b47fa209e4bcd09"
|
||||
revision = "e8d22c780116115ae5624720c9af0c97afe4f551"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/go-version"
|
||||
packages = ["."]
|
||||
revision = "4fe82ae3040f80a03d04d2cccb5606a626b8e1ee"
|
||||
revision = "23480c0665776210b5fbbac6eaaee40e3e6a96b7"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/yamux"
|
||||
packages = ["."]
|
||||
revision = "683f49123a33db61abfb241b7ac5e4af4dc54d55"
|
||||
revision = "2658be15c5f05e76244154714161f17e3e77de2e"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/inconshreveable/log15"
|
||||
@@ -221,7 +276,10 @@
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/klauspost/compress"
|
||||
packages = ["flate","gzip"]
|
||||
packages = [
|
||||
"flate",
|
||||
"gzip"
|
||||
]
|
||||
revision = "6c8db69c4b49dd4df1fff66996cf556176d0b9bf"
|
||||
version = "v1.2.1"
|
||||
|
||||
@@ -238,22 +296,25 @@
|
||||
version = "v1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/kr/pretty"
|
||||
packages = ["."]
|
||||
revision = "cfb55aafdaf3ec08f0db22699ab822c50091b1c4"
|
||||
revision = "73f6ac0b30a98e433b289500d779f50c1a6f0712"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/kr/text"
|
||||
packages = ["."]
|
||||
revision = "7cafcd837844e784b526369c9bce262804aebc60"
|
||||
revision = "e2ffdb16a802fe2bb95e2e35ff34f0e53aeef34f"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/lib/pq"
|
||||
packages = [".","oid"]
|
||||
revision = "61fe37aa2ee24fabcdbe5c4ac1d4ac566f88f345"
|
||||
packages = [
|
||||
".",
|
||||
"oid"
|
||||
]
|
||||
revision = "d34b9ff171c21ad295489235aec8b6626023cd04"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
@@ -270,8 +331,8 @@
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-sqlite3"
|
||||
packages = ["."]
|
||||
revision = "6c771bb9887719704b210e87e934f08be014bdb1"
|
||||
version = "v1.6.0"
|
||||
revision = "323a32be5a2421b8c7087225079c6c900ec397cd"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
@@ -285,9 +346,19 @@
|
||||
packages = ["."]
|
||||
revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/oklog/run"
|
||||
packages = ["."]
|
||||
revision = "4dadeb3030eda0273a12382bb2348ffc7c9d1a39"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/opentracing/opentracing-go"
|
||||
packages = [".","ext","log"]
|
||||
packages = [
|
||||
".",
|
||||
"ext",
|
||||
"log"
|
||||
]
|
||||
revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38"
|
||||
version = "v1.0.2"
|
||||
|
||||
@@ -297,9 +368,20 @@
|
||||
revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0"
|
||||
version = "v2.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/prometheus/client_golang"
|
||||
packages = ["api","api/prometheus/v1","prometheus","prometheus/promhttp"]
|
||||
packages = [
|
||||
"api",
|
||||
"api/prometheus/v1",
|
||||
"prometheus",
|
||||
"prometheus/promhttp"
|
||||
]
|
||||
revision = "967789050ba94deca04a5e84cce8ad472ce313c1"
|
||||
version = "v0.9.0-pre1"
|
||||
|
||||
@@ -312,14 +394,23 @@
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/prometheus/common"
|
||||
packages = ["expfmt","internal/bitbucket.org/ww/goautoneg","model"]
|
||||
revision = "89604d197083d4781071d3c65855d24ecfb0a563"
|
||||
packages = [
|
||||
"expfmt",
|
||||
"internal/bitbucket.org/ww/goautoneg",
|
||||
"model"
|
||||
]
|
||||
revision = "d811d2e9bf898806ecfb6ef6296774b13ffc314c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/prometheus/procfs"
|
||||
packages = [".","internal/util","nfsd","xfs"]
|
||||
revision = "85fadb6e89903ef7cca6f6a804474cd5ea85b6e1"
|
||||
packages = [
|
||||
".",
|
||||
"internal/util",
|
||||
"nfs",
|
||||
"xfs"
|
||||
]
|
||||
revision = "8b1c2da0d56deffdbb9e48d4414b4e674bd8083e"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -328,20 +419,28 @@
|
||||
revision = "cb7f23ec59bec0d61b19c56cd88cee3d0cc1870c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/sergi/go-diff"
|
||||
packages = ["diffmatchpatch"]
|
||||
revision = "1744e2970ca51c86172c8190fadad617561ed6e7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/smartystreets/assertions"
|
||||
packages = [".","internal/go-render/render","internal/oglematchers"]
|
||||
revision = "0b37b35ec7434b77e77a4bb29b79677cced992ea"
|
||||
version = "1.8.1"
|
||||
packages = [
|
||||
".",
|
||||
"internal/go-render/render",
|
||||
"internal/oglematchers"
|
||||
]
|
||||
revision = "7678a5452ebea5b7090a6b163f844c133f523da2"
|
||||
version = "1.8.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/smartystreets/goconvey"
|
||||
packages = ["convey","convey/gotest","convey/reporting"]
|
||||
packages = [
|
||||
"convey",
|
||||
"convey/gotest",
|
||||
"convey/reporting"
|
||||
]
|
||||
revision = "9e8dc3f972df6c8fcc0375ef492c24d0bb204857"
|
||||
version = "1.6.3"
|
||||
|
||||
@@ -353,19 +452,39 @@
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/uber/jaeger-client-go"
|
||||
packages = [".","config","internal/baggage","internal/baggage/remote","internal/spanlog","log","rpcmetrics","thrift-gen/agent","thrift-gen/baggage","thrift-gen/jaeger","thrift-gen/sampling","thrift-gen/zipkincore","utils"]
|
||||
revision = "3ac96c6e679cb60a74589b0d0aa7c70a906183f7"
|
||||
version = "v2.11.2"
|
||||
packages = [
|
||||
".",
|
||||
"config",
|
||||
"internal/baggage",
|
||||
"internal/baggage/remote",
|
||||
"internal/spanlog",
|
||||
"internal/throttler",
|
||||
"internal/throttler/remote",
|
||||
"log",
|
||||
"rpcmetrics",
|
||||
"thrift",
|
||||
"thrift-gen/agent",
|
||||
"thrift-gen/baggage",
|
||||
"thrift-gen/jaeger",
|
||||
"thrift-gen/sampling",
|
||||
"thrift-gen/zipkincore",
|
||||
"utils"
|
||||
]
|
||||
revision = "b043381d944715b469fd6b37addfd30145ca1758"
|
||||
version = "v2.14.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/uber/jaeger-lib"
|
||||
packages = ["metrics"]
|
||||
revision = "7f95f4f7e80028096410abddaae2556e4c61b59f"
|
||||
version = "v1.3.1"
|
||||
revision = "ed3a127ec5fef7ae9ea95b01b542c47fbd999ce5"
|
||||
version = "v1.5.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/yudai/gojsondiff"
|
||||
packages = [".","formatter"]
|
||||
packages = [
|
||||
".",
|
||||
"formatter"
|
||||
]
|
||||
revision = "7b1b7adf999dab73a6eb02669c3d82dbb27a3dd6"
|
||||
version = "1.0.0"
|
||||
|
||||
@@ -378,42 +497,87 @@
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["md4","pbkdf2"]
|
||||
revision = "3d37316aaa6bd9929127ac9a527abf408178ea7b"
|
||||
packages = [
|
||||
"md4",
|
||||
"pbkdf2"
|
||||
]
|
||||
revision = "1a580b3eff7814fc9b40602fd35256c63b50f491"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
packages = ["context","context/ctxhttp","http2","http2/hpack","idna","internal/timeseries","lex/httplex","trace"]
|
||||
revision = "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
packages = [
|
||||
"context",
|
||||
"context/ctxhttp",
|
||||
"http/httpguts",
|
||||
"http2",
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
"internal/timeseries",
|
||||
"trace"
|
||||
]
|
||||
revision = "2491c5de3490fced2f6cff376127c667efeed857"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/oauth2"
|
||||
packages = [".","google","internal","jws","jwt"]
|
||||
revision = "b28fcf2b08a19742b43084fb40ab78ac6c3d8067"
|
||||
packages = [
|
||||
".",
|
||||
"google",
|
||||
"internal",
|
||||
"jws",
|
||||
"jwt"
|
||||
]
|
||||
revision = "cdc340f7c179dbbfa4afd43b7614e8fcadde4269"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["errgroup"]
|
||||
revision = "fd80eb99c8f653c847d294a001bdf2a3a6f768f5"
|
||||
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "af50095a40f9041b3b38960738837185c26e9419"
|
||||
revision = "7c87d13f8e835d2fb3a70a2912c811ed0c1d241b"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/text"
|
||||
packages = ["collate","collate/build","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
|
||||
revision = "e19ae1496984b1c655b8044a65c0300a3c878dd3"
|
||||
packages = [
|
||||
"collate",
|
||||
"collate/build",
|
||||
"internal/colltab",
|
||||
"internal/gen",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"language",
|
||||
"secure/bidirule",
|
||||
"transform",
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable"
|
||||
]
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/appengine"
|
||||
packages = [".","cloudsql","internal","internal/app_identity","internal/base","internal/datastore","internal/log","internal/modules","internal/remote_api","internal/urlfetch","urlfetch"]
|
||||
packages = [
|
||||
".",
|
||||
"cloudsql",
|
||||
"internal",
|
||||
"internal/app_identity",
|
||||
"internal/base",
|
||||
"internal/datastore",
|
||||
"internal/log",
|
||||
"internal/modules",
|
||||
"internal/remote_api",
|
||||
"internal/urlfetch",
|
||||
"urlfetch"
|
||||
]
|
||||
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
|
||||
version = "v1.0.0"
|
||||
|
||||
@@ -421,13 +585,39 @@
|
||||
branch = "master"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
revision = "a8101f21cf983e773d0c1133ebc5424792003214"
|
||||
revision = "7bb2a897381c9c5ab2aeb8614f758d7766af68ff"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [".","balancer","balancer/base","balancer/roundrobin","codes","connectivity","credentials","encoding","grpclb/grpc_lb_v1/messages","grpclog","health","health/grpc_health_v1","internal","keepalive","metadata","naming","peer","resolver","resolver/dns","resolver/passthrough","stats","status","tap","transport"]
|
||||
revision = "6b51017f791ae1cfbec89c52efdf444b13b550ef"
|
||||
version = "v1.9.2"
|
||||
packages = [
|
||||
".",
|
||||
"balancer",
|
||||
"balancer/base",
|
||||
"balancer/roundrobin",
|
||||
"codes",
|
||||
"connectivity",
|
||||
"credentials",
|
||||
"encoding",
|
||||
"encoding/proto",
|
||||
"grpclb/grpc_lb_v1/messages",
|
||||
"grpclog",
|
||||
"health",
|
||||
"health/grpc_health_v1",
|
||||
"internal",
|
||||
"keepalive",
|
||||
"metadata",
|
||||
"naming",
|
||||
"peer",
|
||||
"resolver",
|
||||
"resolver/dns",
|
||||
"resolver/passthrough",
|
||||
"stats",
|
||||
"status",
|
||||
"tap",
|
||||
"transport"
|
||||
]
|
||||
revision = "1e2570b1b19ade82d8dbb31bba4e65e9f9ef5b34"
|
||||
version = "v1.11.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "v3"
|
||||
@@ -450,14 +640,14 @@
|
||||
[[projects]]
|
||||
name = "gopkg.in/ini.v1"
|
||||
packages = ["."]
|
||||
revision = "32e4c1e6bc4e7d0d8451aa6b75200d19e37a536a"
|
||||
version = "v1.32.0"
|
||||
revision = "6529cf7c58879c08d927016dde4477f18a0634cb"
|
||||
version = "v1.36.0"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/macaron.v1"
|
||||
packages = ["."]
|
||||
revision = "75f2e9b42e99652f0d82b28ccb73648f44615faa"
|
||||
version = "v1.2.4"
|
||||
revision = "c1be95e6d21e769e44e1ec33cec9da5837861c10"
|
||||
version = "v1.3.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
@@ -472,14 +662,14 @@
|
||||
version = "v2.3.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4"
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "ad3c71fd3244369c313978e9e7464c7116faee764386439a17de0707a08103aa"
|
||||
inputs-digest = "85cc057e0cc074ab5b43bd620772d63d51e07b04e8782fcfe55e6929d2fc40f7"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
12
Gopkg.toml
12
Gopkg.toml
@@ -85,11 +85,11 @@ ignored = [
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-xorm/core"
|
||||
version = "0.5.7"
|
||||
version = "=0.5.7"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-xorm/xorm"
|
||||
version = "0.6.4"
|
||||
version = "=0.6.4"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
@@ -101,12 +101,16 @@ ignored = [
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/grafana/grafana_plugin_model"
|
||||
name = "github.com/grafana/grafana-plugin-model"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/go-hclog"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/hashicorp/go-plugin"
|
||||
revision = "e8d22c780116115ae5624720c9af0c97afe4f551"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/go-version"
|
||||
@@ -125,7 +129,7 @@ ignored = [
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mattn/go-sqlite3"
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/opentracing/opentracing-go"
|
||||
|
||||
@@ -12,6 +12,10 @@ module.exports = function (grunt) {
|
||||
platform: process.platform.replace('win32', 'windows'),
|
||||
};
|
||||
|
||||
if (grunt.option('platform')) {
|
||||
config.platform = grunt.option('platform');
|
||||
}
|
||||
|
||||
if (grunt.option('arch')) {
|
||||
config.arch = grunt.option('arch');
|
||||
} else {
|
||||
|
||||
@@ -39,12 +39,21 @@ go run build.go build
|
||||
|
||||
For this you need nodejs (v.6+).
|
||||
|
||||
To build the assets, rebuild on file change, and serve them by Grafana's webserver (http://localhost:3000):
|
||||
```bash
|
||||
npm install -g yarn
|
||||
yarn install --pure-lockfile
|
||||
npm run watch
|
||||
```
|
||||
|
||||
Build the assets, rebuild on file change with Hot Module Replacement (HMR), and serve them by webpack-dev-server (http://localhost:3333):
|
||||
```bash
|
||||
yarn start
|
||||
# OR set a theme
|
||||
env GRAFANA_THEME=light yarn start
|
||||
```
|
||||
Note: HMR for Angular is not supported. If you edit files in the Angular part of the app, the whole page will reload.
|
||||
|
||||
Run tests
|
||||
```bash
|
||||
npm run jest
|
||||
|
||||
26
ROADMAP.md
26
ROADMAP.md
@@ -1,26 +1,20 @@
|
||||
# Roadmap (2018-02-22)
|
||||
# Roadmap (2018-05-06)
|
||||
|
||||
This roadmap is a tentative plan for the core development team. Things change constantly as PRs come in and priorities change.
|
||||
But it will give you an idea of our current vision and plan.
|
||||
|
||||
|
||||
### Short term (1-2 months)
|
||||
|
||||
- v5.1
|
||||
- Build speed improvements & integration test execution
|
||||
- Kubernetes friendly docker container
|
||||
- Enterprise LDAP
|
||||
- Provisioning workflow
|
||||
- MSSQL datasource
|
||||
- Elasticsearch alerting
|
||||
- Crossplatform builds
|
||||
- Backend service refactorings
|
||||
- Explore UI
|
||||
- First login registration view
|
||||
|
||||
### Mid term (2-4 months)
|
||||
|
||||
- v5.2
|
||||
- Azure monitor backend rewrite
|
||||
- Elasticsearch alerting
|
||||
- First login registration view
|
||||
- Backend plugins? (alert notifiers, auth)
|
||||
- Crossplatform builds
|
||||
- IFQL Initial support
|
||||
- Multi-Stat panel
|
||||
- React Panels
|
||||
- Templating Query Editor UI Plugin hook
|
||||
|
||||
### Long term (4 - 8 months)
|
||||
|
||||
|
||||
15
appveyor.yml
15
appveyor.yml
@@ -6,7 +6,7 @@ clone_folder: c:\gopath\src\github.com\grafana\grafana
|
||||
|
||||
environment:
|
||||
nodejs_version: "6"
|
||||
GOPATH: c:\gopath
|
||||
GOPATH: C:\gopath
|
||||
GOVERSION: 1.10
|
||||
|
||||
install:
|
||||
@@ -38,16 +38,3 @@ artifacts:
|
||||
- path: grafana-*windows-*.*
|
||||
name: binzip
|
||||
type: zip
|
||||
|
||||
deploy:
|
||||
- provider: Environment
|
||||
name: GrafanaReleaseMaster
|
||||
on:
|
||||
buildType: master
|
||||
|
||||
- provider: Environment
|
||||
name: GrafanaReleaseRelease
|
||||
on:
|
||||
buildType: release
|
||||
|
||||
|
||||
|
||||
152
build.go
152
build.go
@@ -16,7 +16,6 @@ import (
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -24,14 +23,13 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`)
|
||||
goarch string
|
||||
goos string
|
||||
gocc string
|
||||
gocxx string
|
||||
cgo string
|
||||
pkgArch string
|
||||
version string = "v1"
|
||||
//versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`)
|
||||
goarch string
|
||||
goos string
|
||||
gocc string
|
||||
cgo bool
|
||||
pkgArch string
|
||||
version string = "v1"
|
||||
// deb & rpm does not support semver so have to handle their version a little differently
|
||||
linuxPackageVersion string = "v1"
|
||||
linuxPackageIteration string = ""
|
||||
@@ -42,10 +40,9 @@ var (
|
||||
buildNumber int = 0
|
||||
binaries []string = []string{"grafana-server", "grafana-cli"}
|
||||
isDev bool = false
|
||||
enterprise bool = false
|
||||
)
|
||||
|
||||
const minGoVersion = 1.8
|
||||
|
||||
func main() {
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetFlags(0)
|
||||
@@ -55,12 +52,12 @@ func main() {
|
||||
flag.StringVar(&goarch, "goarch", runtime.GOARCH, "GOARCH")
|
||||
flag.StringVar(&goos, "goos", runtime.GOOS, "GOOS")
|
||||
flag.StringVar(&gocc, "cc", "", "CC")
|
||||
flag.StringVar(&gocxx, "cxx", "", "CXX")
|
||||
flag.StringVar(&cgo, "cgo-enabled", "", "CGO_ENABLED")
|
||||
flag.BoolVar(&cgo, "cgo-enabled", cgo, "Enable cgo")
|
||||
flag.StringVar(&pkgArch, "pkg-arch", "", "PKG ARCH")
|
||||
flag.StringVar(&phjsToRelease, "phjs", "", "PhantomJS binary")
|
||||
flag.BoolVar(&race, "race", race, "Use race detector")
|
||||
flag.BoolVar(&includeBuildNumber, "includeBuildNumber", includeBuildNumber, "IncludeBuildNumber in package name")
|
||||
flag.BoolVar(&enterprise, "enterprise", enterprise, "Build enterprise version of Grafana")
|
||||
flag.IntVar(&buildNumber, "buildNumber", 0, "Build number from CI system")
|
||||
flag.BoolVar(&isDev, "dev", isDev, "optimal for development, skips certain steps")
|
||||
flag.Parse()
|
||||
@@ -94,20 +91,24 @@ func main() {
|
||||
build("grafana-server", "./pkg/cmd/grafana-server", []string{})
|
||||
|
||||
case "build":
|
||||
clean()
|
||||
//clean()
|
||||
for _, binary := range binaries {
|
||||
build(binary, "./pkg/cmd/"+binary, []string{})
|
||||
}
|
||||
|
||||
case "build-frontend":
|
||||
grunt(gruntBuildArg("build")...)
|
||||
|
||||
case "test":
|
||||
test("./pkg/...")
|
||||
grunt("test")
|
||||
|
||||
case "package":
|
||||
grunt(gruntBuildArg("release")...)
|
||||
if runtime.GOOS != "windows" {
|
||||
createLinuxPackages()
|
||||
}
|
||||
grunt(gruntBuildArg("build")...)
|
||||
packageGrafana()
|
||||
|
||||
case "package-only":
|
||||
packageGrafana()
|
||||
|
||||
case "pkg-rpm":
|
||||
grunt(gruntBuildArg("release")...)
|
||||
@@ -132,6 +133,22 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func packageGrafana() {
|
||||
platformArg := fmt.Sprintf("--platform=%v", goos)
|
||||
previousPkgArch := pkgArch
|
||||
if pkgArch == "" {
|
||||
pkgArch = goarch
|
||||
}
|
||||
postProcessArgs := gruntBuildArg("package")
|
||||
postProcessArgs = append(postProcessArgs, platformArg)
|
||||
grunt(postProcessArgs...)
|
||||
pkgArch = previousPkgArch
|
||||
|
||||
if goos == "linux" {
|
||||
createLinuxPackages()
|
||||
}
|
||||
}
|
||||
|
||||
func makeLatestDistCopies() {
|
||||
files, err := ioutil.ReadDir("dist")
|
||||
if err != nil {
|
||||
@@ -139,9 +156,9 @@ func makeLatestDistCopies() {
|
||||
}
|
||||
|
||||
latestMapping := map[string]string{
|
||||
".deb": "dist/grafana_latest_amd64.deb",
|
||||
".rpm": "dist/grafana-latest-1.x86_64.rpm",
|
||||
".tar.gz": "dist/grafana-latest.linux-x64.tar.gz",
|
||||
"_amd64.deb": "dist/grafana_latest_amd64.deb",
|
||||
".x86_64.rpm": "dist/grafana-latest-1.x86_64.rpm",
|
||||
".linux-amd64.tar.gz": "dist/grafana-latest.linux-x64.tar.gz",
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
@@ -212,6 +229,10 @@ type linuxPackageOptions struct {
|
||||
}
|
||||
|
||||
func createDebPackages() {
|
||||
previousPkgArch := pkgArch
|
||||
if pkgArch == "armv7" {
|
||||
pkgArch = "armhf"
|
||||
}
|
||||
createPackage(linuxPackageOptions{
|
||||
packageType: "deb",
|
||||
homeDir: "/usr/share/grafana",
|
||||
@@ -229,9 +250,17 @@ func createDebPackages() {
|
||||
|
||||
depends: []string{"adduser", "libfontconfig"},
|
||||
})
|
||||
pkgArch = previousPkgArch
|
||||
}
|
||||
|
||||
func createRpmPackages() {
|
||||
previousPkgArch := pkgArch
|
||||
switch {
|
||||
case pkgArch == "armv7":
|
||||
pkgArch = "armhfp"
|
||||
case pkgArch == "arm64":
|
||||
pkgArch = "aarch64"
|
||||
}
|
||||
createPackage(linuxPackageOptions{
|
||||
packageType: "rpm",
|
||||
homeDir: "/usr/share/grafana",
|
||||
@@ -249,6 +278,7 @@ func createRpmPackages() {
|
||||
|
||||
depends: []string{"/sbin/service", "fontconfig", "freetype", "urw-fonts"},
|
||||
})
|
||||
pkgArch = previousPkgArch
|
||||
}
|
||||
|
||||
func createLinuxPackages() {
|
||||
@@ -286,19 +316,33 @@ func createPackage(options linuxPackageOptions) {
|
||||
"-s", "dir",
|
||||
"--description", "Grafana",
|
||||
"-C", packageRoot,
|
||||
"--vendor", "Grafana",
|
||||
"--url", "https://grafana.com",
|
||||
"--license", "\"Apache 2.0\"",
|
||||
"--maintainer", "contact@grafana.com",
|
||||
"--config-files", options.initdScriptFilePath,
|
||||
"--config-files", options.etcDefaultFilePath,
|
||||
"--config-files", options.systemdServiceFilePath,
|
||||
"--after-install", options.postinstSrc,
|
||||
"--name", "grafana",
|
||||
|
||||
"--version", linuxPackageVersion,
|
||||
"-p", "./dist",
|
||||
}
|
||||
|
||||
name := "grafana"
|
||||
if enterprise {
|
||||
name += "-enterprise"
|
||||
}
|
||||
args = append(args, "--name", name)
|
||||
|
||||
description := "Grafana"
|
||||
if enterprise {
|
||||
description += " Enterprise"
|
||||
}
|
||||
args = append(args, "--vendor", description)
|
||||
|
||||
if !enterprise {
|
||||
args = append(args, "--license", "\"Apache 2.0\"")
|
||||
}
|
||||
|
||||
if options.packageType == "rpm" {
|
||||
args = append(args, "--rpm-posttrans", "packaging/rpm/control/posttrans")
|
||||
}
|
||||
@@ -326,20 +370,6 @@ func createPackage(options linuxPackageOptions) {
|
||||
runPrint("fpm", append([]string{"-t", options.packageType}, args...)...)
|
||||
}
|
||||
|
||||
func verifyGitRepoIsClean() {
|
||||
rs, err := runError("git", "ls-files", "--modified")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to check if git tree was clean, %v, %v\n", string(rs), err)
|
||||
return
|
||||
}
|
||||
count := len(string(rs))
|
||||
if count > 0 {
|
||||
log.Fatalf("Git repository has modified files, aborting")
|
||||
}
|
||||
|
||||
log.Println("Git repository is clean")
|
||||
}
|
||||
|
||||
func ensureGoPath() {
|
||||
if os.Getenv("GOPATH") == "" {
|
||||
cwd, err := os.Getwd()
|
||||
@@ -352,10 +382,6 @@ func ensureGoPath() {
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeWorkingDir(dir string) {
|
||||
os.Chdir(dir)
|
||||
}
|
||||
|
||||
func grunt(params ...string) {
|
||||
if runtime.GOOS == "windows" {
|
||||
runPrint(`.\node_modules\.bin\grunt`, params...)
|
||||
@@ -391,7 +417,12 @@ func test(pkg string) {
|
||||
}
|
||||
|
||||
func build(binaryName, pkg string, tags []string) {
|
||||
binary := "./bin/" + binaryName
|
||||
binary := fmt.Sprintf("./bin/%s-%s/%s", goos, goarch, binaryName)
|
||||
if isDev {
|
||||
//dont include os and arch in output path in dev environment
|
||||
binary = fmt.Sprintf("./bin/%s", binaryName)
|
||||
}
|
||||
|
||||
if goos == "windows" {
|
||||
binary += ".exe"
|
||||
}
|
||||
@@ -413,6 +444,7 @@ func build(binaryName, pkg string, tags []string) {
|
||||
if !isDev {
|
||||
setBuildEnv()
|
||||
runPrint("go", "version")
|
||||
fmt.Printf("Targeting %s/%s\n", goos, goarch)
|
||||
}
|
||||
|
||||
runPrint("go", args...)
|
||||
@@ -433,6 +465,7 @@ func ldflags() string {
|
||||
b.WriteString(fmt.Sprintf(" -X main.version=%s", version))
|
||||
b.WriteString(fmt.Sprintf(" -X main.commit=%s", getGitSha()))
|
||||
b.WriteString(fmt.Sprintf(" -X main.buildstamp=%d", buildStamp()))
|
||||
b.WriteString(fmt.Sprintf(" -X main.enterprise=%t", enterprise))
|
||||
return b.String()
|
||||
}
|
||||
|
||||
@@ -455,6 +488,14 @@ func clean() {
|
||||
|
||||
func setBuildEnv() {
|
||||
os.Setenv("GOOS", goos)
|
||||
if goos == "windows" {
|
||||
// require windows >=7
|
||||
os.Setenv("CGO_CFLAGS", "-D_WIN32_WINNT=0x0601")
|
||||
}
|
||||
if goarch != "amd64" || goos != "linux" {
|
||||
// needed for all other archs
|
||||
cgo = true
|
||||
}
|
||||
if strings.HasPrefix(goarch, "armv") {
|
||||
os.Setenv("GOARCH", "arm")
|
||||
os.Setenv("GOARM", goarch[4:])
|
||||
@@ -464,15 +505,12 @@ func setBuildEnv() {
|
||||
if goarch == "386" {
|
||||
os.Setenv("GO386", "387")
|
||||
}
|
||||
if cgo != "" {
|
||||
os.Setenv("CGO_ENABLED", cgo)
|
||||
if cgo {
|
||||
os.Setenv("CGO_ENABLED", "1")
|
||||
}
|
||||
if gocc != "" {
|
||||
os.Setenv("CC", gocc)
|
||||
}
|
||||
if gocxx != "" {
|
||||
os.Setenv("CXX", gocxx)
|
||||
}
|
||||
}
|
||||
|
||||
func getGitSha() string {
|
||||
@@ -492,24 +530,6 @@ func buildStamp() int64 {
|
||||
return s
|
||||
}
|
||||
|
||||
func buildArch() string {
|
||||
os := goos
|
||||
if os == "darwin" {
|
||||
os = "macosx"
|
||||
}
|
||||
return fmt.Sprintf("%s-%s", os, goarch)
|
||||
}
|
||||
|
||||
func run(cmd string, args ...string) []byte {
|
||||
bs, err := runError(cmd, args...)
|
||||
if err != nil {
|
||||
log.Println(cmd, strings.Join(args, " "))
|
||||
log.Println(string(bs))
|
||||
log.Fatal(err)
|
||||
}
|
||||
return bytes.TrimSpace(bs)
|
||||
}
|
||||
|
||||
func runError(cmd string, args ...string) ([]byte, error) {
|
||||
ecmd := exec.Command(cmd, args...)
|
||||
bs, err := ecmd.CombinedOutput()
|
||||
|
||||
@@ -237,6 +237,9 @@ disable_login_form = false
|
||||
# Set to true to disable the signout link in the side menu. useful if you use auth.proxy
|
||||
disable_signout_menu = false
|
||||
|
||||
# URL to redirect the user to after sign out
|
||||
signout_redirect_url =
|
||||
|
||||
#################################### Anonymous Auth ######################
|
||||
[auth.anonymous]
|
||||
# enable anonymous access
|
||||
@@ -442,6 +445,11 @@ enabled = true
|
||||
# Makes it possible to turn off alert rule execution but alerting UI is visible
|
||||
execute_alerts = true
|
||||
|
||||
#################################### Explore #############################
|
||||
[explore]
|
||||
# Enable the Explore section
|
||||
enabled = false
|
||||
|
||||
#################################### Internal Grafana Metrics ############
|
||||
# Metrics available at HTTP API Url /metrics
|
||||
[metrics]
|
||||
|
||||
@@ -217,6 +217,9 @@ log_queries =
|
||||
# Set to true to disable the signout link in the side menu. useful if you use auth.proxy, defaults to false
|
||||
;disable_signout_menu = false
|
||||
|
||||
# URL to redirect the user to after sign out
|
||||
;signout_redirect_url =
|
||||
|
||||
#################################### Anonymous Auth ##########################
|
||||
[auth.anonymous]
|
||||
# enable anonymous access
|
||||
@@ -377,6 +380,11 @@ log_queries =
|
||||
# Makes it possible to turn off alert rule execution but alerting UI is visible
|
||||
;execute_alerts = true
|
||||
|
||||
#################################### Explore #############################
|
||||
[explore]
|
||||
# Enable the Explore section
|
||||
;enabled = false
|
||||
|
||||
#################################### Internal Grafana Metrics ##########################
|
||||
# Metrics available at HTTP API Url /metrics
|
||||
[metrics]
|
||||
|
||||
11
devenv/README.md
Normal file
11
devenv/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
This folder contains useful scripts and configuration for...
|
||||
|
||||
* Configuring datasources in Grafana
|
||||
* Provision example dashboards in Grafana
|
||||
* Run preconfiured datasources as docker containers
|
||||
|
||||
want to know more? run setup!
|
||||
|
||||
```bash
|
||||
./setup.sh
|
||||
```
|
||||
9
devenv/dashboards/bulk-testing/bulk-dashboards.yaml
Normal file
9
devenv/dashboards/bulk-testing/bulk-dashboards.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
apiVersion: 1
|
||||
|
||||
providers:
|
||||
- name: 'Bulk dashboards'
|
||||
folder: 'Bulk dashboards'
|
||||
type: file
|
||||
options:
|
||||
path: devenv/dashboards/bulk-testing
|
||||
|
||||
1140
devenv/dashboards/bulk-testing/bulkdash.jsonnet
Normal file
1140
devenv/dashboards/bulk-testing/bulkdash.jsonnet
Normal file
File diff suppressed because it is too large
Load Diff
75
devenv/datasources/default/default.yaml
Normal file
75
devenv/datasources/default/default.yaml
Normal file
@@ -0,0 +1,75 @@
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Graphite
|
||||
type: graphite
|
||||
access: proxy
|
||||
url: http://localhost:8080
|
||||
jsonData:
|
||||
graphiteVersion: "1.1"
|
||||
|
||||
- name: Prometheus
|
||||
type: prometheus
|
||||
access: proxy
|
||||
isDefault: true
|
||||
url: http://localhost:9090
|
||||
|
||||
- name: InfluxDB
|
||||
type: influxdb
|
||||
access: proxy
|
||||
database: site
|
||||
user: grafana
|
||||
password: grafana
|
||||
url: http://localhost:8086
|
||||
jsonData:
|
||||
timeInterval: "15s"
|
||||
|
||||
- name: OpenTsdb
|
||||
type: opentsdb
|
||||
access: proxy
|
||||
url: http://localhost:4242
|
||||
jsonData:
|
||||
tsdbResolution: 1
|
||||
tsdbVersion: 1
|
||||
|
||||
- name: Elastic
|
||||
type: elasticsearch
|
||||
access: proxy
|
||||
database: "[metrics-]YYYY.MM.DD"
|
||||
url: http://localhost:9200
|
||||
jsonData:
|
||||
interval: Daily
|
||||
timeField: "@timestamp"
|
||||
|
||||
- name: MySQL
|
||||
type: mysql
|
||||
url: localhost:3306
|
||||
database: grafana
|
||||
user: grafana
|
||||
password: password
|
||||
|
||||
- name: MSSQL
|
||||
type: mssql
|
||||
url: localhost:1433
|
||||
database: grafana
|
||||
user: grafana
|
||||
password: "Password!"
|
||||
|
||||
- name: Postgres
|
||||
type: postgres
|
||||
url: localhost:5432
|
||||
database: grafana
|
||||
user: grafana
|
||||
secureJsonData:
|
||||
password: password
|
||||
jsonData:
|
||||
sslmode: "disable"
|
||||
|
||||
- name: Cloudwatch
|
||||
type: cloudwatch
|
||||
editable: true
|
||||
jsonData:
|
||||
authType: credentials
|
||||
defaultRegion: eu-west-2
|
||||
|
||||
|
||||
61
devenv/setup.sh
Executable file
61
devenv/setup.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#/bin/bash
|
||||
|
||||
bulkDashboard() {
|
||||
|
||||
requiresJsonnet
|
||||
|
||||
COUNTER=0
|
||||
MAX=400
|
||||
while [ $COUNTER -lt $MAX ]; do
|
||||
jsonnet -o "dashboards/bulk-testing/dashboard${COUNTER}.json" -e "local bulkDash = import 'dashboards/bulk-testing/bulkdash.jsonnet'; bulkDash + { uid: 'uid-${COUNTER}', title: 'title-${COUNTER}' }"
|
||||
let COUNTER=COUNTER+1
|
||||
done
|
||||
|
||||
ln -s -f -r ./dashboards/bulk-testing/bulk-dashboards.yaml ../conf/provisioning/dashboards/custom.yaml
|
||||
}
|
||||
|
||||
requiresJsonnet() {
|
||||
if ! type "jsonnet" > /dev/null; then
|
||||
echo "you need you install jsonnet to run this script"
|
||||
echo "follow the instructions on https://github.com/google/jsonnet"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
defaultDashboards() {
|
||||
echo "not implemented yet"
|
||||
}
|
||||
|
||||
defaultDatasources() {
|
||||
echo "setting up all default datasources using provisioning"
|
||||
|
||||
ln -s -f -r ./datasources/default/default.yaml ../conf/provisioning/datasources/custom.yaml
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo -e "install.sh\n\tThis script installs my basic setup for a debian laptop\n"
|
||||
echo "Usage:"
|
||||
echo " bulk-dashboards - create and provisioning 400 dashboards"
|
||||
echo " default-datasources - provisiong all core datasources"
|
||||
}
|
||||
|
||||
main() {
|
||||
local cmd=$1
|
||||
|
||||
if [[ -z "$cmd" ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $cmd == "bulk-dashboards" ]]; then
|
||||
bulkDashboard
|
||||
elif [[ $cmd == "default-datasources" ]]; then
|
||||
defaultDatasources
|
||||
elif [[ $cmd == "default-dashboards" ]]; then
|
||||
bulkDashboard
|
||||
else
|
||||
usage
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -2,7 +2,7 @@
|
||||
# http://localhost:3000 (Grafana running locally)
|
||||
#
|
||||
# Please note that you'll need to change the root_url in the Grafana configuration:
|
||||
# root_url = %(protocol)s://%(domain)s:/grafana/
|
||||
# root_url = %(protocol)s://%(domain)s:10081/grafana/
|
||||
|
||||
apacheproxy:
|
||||
build: blocks/apache_proxy
|
||||
|
||||
15
docker/blocks/elastic6/docker-compose.yaml
Normal file
15
docker/blocks/elastic6/docker-compose.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
# You need to run 'sysctl -w vm.max_map_count=262144' on the host machine
|
||||
|
||||
elasticsearch6:
|
||||
image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4
|
||||
command: elasticsearch
|
||||
ports:
|
||||
- "11200:9200"
|
||||
- "11300:9300"
|
||||
|
||||
fake-elastic6-data:
|
||||
image: grafana/fake-data-gen
|
||||
network_mode: bridge
|
||||
environment:
|
||||
FD_DATASOURCE: elasticsearch6
|
||||
FD_PORT: 11200
|
||||
2
docker/blocks/elastic6/elasticsearch.yml
Normal file
2
docker/blocks/elastic6/elasticsearch.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
script.inline: on
|
||||
script.indexed: on
|
||||
@@ -1,7 +1,19 @@
|
||||
CREATE LOGIN %%USER%% WITH PASSWORD = '%%PWD%%'
|
||||
GO
|
||||
|
||||
CREATE DATABASE %%DB%%;
|
||||
CREATE DATABASE %%DB%%
|
||||
ON
|
||||
( NAME = %%DB%%,
|
||||
FILENAME = '/var/opt/mssql/data/%%DB%%.mdf',
|
||||
SIZE = 500MB,
|
||||
MAXSIZE = 1000MB,
|
||||
FILEGROWTH = 100MB )
|
||||
LOG ON
|
||||
( NAME = %%DB%%_log,
|
||||
FILENAME = '/var/opt/mssql/data/%%DB%%_log.ldf',
|
||||
SIZE = 500MB,
|
||||
MAXSIZE = 1000MB,
|
||||
FILEGROWTH = 100MB );
|
||||
GO
|
||||
|
||||
USE %%DB%%;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
environment:
|
||||
ACCEPT_EULA: Y
|
||||
MSSQL_SA_PASSWORD: Password!
|
||||
MSSQL_PID: Express
|
||||
MSSQL_PID: Developer
|
||||
MSSQL_DATABASE: grafana
|
||||
MSSQL_USER: grafana
|
||||
MSSQL_PASSWORD: Password!
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mysql:
|
||||
image: mysql:latest
|
||||
image: mysql:5.6
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: rootpass
|
||||
MYSQL_DATABASE: grafana
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
FROM mysql:latest
|
||||
FROM mysql:5.6
|
||||
ADD setup.sql /docker-entrypoint-initdb.d
|
||||
CMD ["mysqld"]
|
||||
CMD ["mysqld"]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# http://localhost:3000 (Grafana running locally)
|
||||
#
|
||||
# Please note that you'll need to change the root_url in the Grafana configuration:
|
||||
# root_url = %(protocol)s://%(domain)s:/grafana/
|
||||
# root_url = %(protocol)s://%(domain)s:10080/grafana/
|
||||
|
||||
nginxproxy:
|
||||
build: blocks/nginx_proxy
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
postgrestest:
|
||||
image: postgres:latest
|
||||
image: postgres:9.3
|
||||
environment:
|
||||
POSTGRES_USER: grafana
|
||||
POSTGRES_PASSWORD: password
|
||||
@@ -13,4 +13,4 @@
|
||||
network_mode: bridge
|
||||
environment:
|
||||
FD_DATASOURCE: postgres
|
||||
FD_PORT: 5432
|
||||
FD_PORT: 5432
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
FROM postgres:latest
|
||||
FROM postgres:9.3
|
||||
ADD setup.sql /docker-entrypoint-initdb.d
|
||||
CMD ["postgres"]
|
||||
CMD ["postgres"]
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
CREATE DATABASE grafanadstest;
|
||||
REVOKE CONNECT ON DATABASE grafanadstest FROM PUBLIC;
|
||||
GRANT CONNECT ON DATABASE grafanadstest TO grafanatest;
|
||||
GRANT CONNECT ON DATABASE grafanadstest TO grafanatest;
|
||||
|
||||
3
docker/blocks/prometheus_mac/Dockerfile
Normal file
3
docker/blocks/prometheus_mac/Dockerfile
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM prom/prometheus:v1.8.2
|
||||
ADD prometheus.yml /etc/prometheus/
|
||||
ADD alert.rules /etc/prometheus/
|
||||
10
docker/blocks/prometheus_mac/alert.rules
Normal file
10
docker/blocks/prometheus_mac/alert.rules
Normal file
@@ -0,0 +1,10 @@
|
||||
# Alert Rules
|
||||
|
||||
ALERT AppCrash
|
||||
IF process_open_fds > 0
|
||||
FOR 15s
|
||||
LABELS { severity="critical" }
|
||||
ANNOTATIONS {
|
||||
summary = "Number of open fds > 0",
|
||||
description = "Just testing"
|
||||
}
|
||||
26
docker/blocks/prometheus_mac/docker-compose.yaml
Normal file
26
docker/blocks/prometheus_mac/docker-compose.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
prometheus:
|
||||
build: blocks/prometheus_mac
|
||||
ports:
|
||||
- "9090:9090"
|
||||
|
||||
node_exporter:
|
||||
image: prom/node-exporter
|
||||
ports:
|
||||
- "9100:9100"
|
||||
|
||||
fake-prometheus-data:
|
||||
image: grafana/fake-data-gen
|
||||
ports:
|
||||
- "9091:9091"
|
||||
environment:
|
||||
FD_DATASOURCE: prom
|
||||
|
||||
alertmanager:
|
||||
image: quay.io/prometheus/alertmanager
|
||||
ports:
|
||||
- "9093:9093"
|
||||
|
||||
prometheus-random-data:
|
||||
build: blocks/prometheus_random_data
|
||||
ports:
|
||||
- "8081:8080"
|
||||
39
docker/blocks/prometheus_mac/prometheus.yml
Normal file
39
docker/blocks/prometheus_mac/prometheus.yml
Normal file
@@ -0,0 +1,39 @@
|
||||
# my global config
|
||||
global:
|
||||
scrape_interval: 10s # By default, scrape targets every 15 seconds.
|
||||
evaluation_interval: 10s # By default, scrape targets every 15 seconds.
|
||||
# scrape_timeout is set to the global default (10s).
|
||||
|
||||
# Load and evaluate rules in this file every 'evaluation_interval' seconds.
|
||||
rule_files:
|
||||
- "alert.rules"
|
||||
# - "first.rules"
|
||||
# - "second.rules"
|
||||
|
||||
alerting:
|
||||
alertmanagers:
|
||||
- scheme: http
|
||||
static_configs:
|
||||
- targets:
|
||||
- "alertmanager:9093"
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'prometheus'
|
||||
static_configs:
|
||||
- targets: ['localhost:9090']
|
||||
|
||||
- job_name: 'node_exporter'
|
||||
static_configs:
|
||||
- targets: ['node_exporter:9100']
|
||||
|
||||
- job_name: 'fake-data-gen'
|
||||
static_configs:
|
||||
- targets: ['fake-prometheus-data:9091']
|
||||
|
||||
- job_name: 'grafana'
|
||||
static_configs:
|
||||
- targets: ['host.docker.internal:3000']
|
||||
|
||||
- job_name: 'prometheus-random-data'
|
||||
static_configs:
|
||||
- targets: ['prometheus-random-data:8080']
|
||||
@@ -76,7 +76,7 @@ Saltstack | [https://github.com/salt-formulas/salt-formula-grafana](https://gith
|
||||
|
||||
> This feature is available from v5.0
|
||||
|
||||
It's possible to manage datasources in Grafana by adding one or more yaml config files in the [`provisioning/datasources`](/installation/configuration/#provisioning) directory. Each config file can contain a list of `datasources` that will be added or updated during start up. If the datasource already exists, Grafana will update it to match the configuration file. The config file can also contain a list of datasources that should be deleted. That list is called `delete_datasources`. Grafana will delete datasources listed in `delete_datasources` before inserting/updating those in the `datasource` list.
|
||||
It's possible to manage datasources in Grafana by adding one or more yaml config files in the [`provisioning/datasources`](/installation/configuration/#provisioning) directory. Each config file can contain a list of `datasources` that will be added or updated during start up. If the datasource already exists, Grafana will update it to match the configuration file. The config file can also contain a list of datasources that should be deleted. That list is called `deleteDatasources`. Grafana will delete datasources listed in `deleteDatasources` before inserting/updating those in the `datasource` list.
|
||||
|
||||
### Running Multiple Grafana Instances
|
||||
|
||||
@@ -94,13 +94,13 @@ deleteDatasources:
|
||||
orgId: 1
|
||||
|
||||
# list of datasources to insert/update depending
|
||||
# whats available in the database
|
||||
# what's available in the database
|
||||
datasources:
|
||||
# <string, required> name of the datasource. Required
|
||||
- name: Graphite
|
||||
# <string, required> datasource type. Required
|
||||
type: graphite
|
||||
# <string, required> access mode. direct or proxy. Required
|
||||
# <string, required> access mode. proxy or direct (Server or Browser in the UI). Required
|
||||
access: proxy
|
||||
# <int> org id. will default to orgId 1 if not specified
|
||||
orgId: 1
|
||||
@@ -154,7 +154,7 @@ Since not all datasources have the same configuration settings we only have the
|
||||
| tlsAuthWithCACert | boolean | *All* | Enable TLS authentication using CA cert |
|
||||
| tlsSkipVerify | boolean | *All* | Controls whether a client verifies the server's certificate chain and host name. |
|
||||
| graphiteVersion | string | Graphite | Graphite version |
|
||||
| timeInterval | string | Elastic, Influxdb & Prometheus | Lowest interval/step value that should be used for this data source |
|
||||
| timeInterval | string | Elastic, InfluxDB & Prometheus | Lowest interval/step value that should be used for this data source |
|
||||
| esVersion | string | Elastic | Elasticsearch version as an number (2/5/56) |
|
||||
| timeField | string | Elastic | Which field that should be used as timestamp |
|
||||
| interval | string | Elastic | Index date time format |
|
||||
@@ -162,9 +162,9 @@ Since not all datasources have the same configuration settings we only have the
|
||||
| assumeRoleArn | string | Cloudwatch | ARN of Assume Role |
|
||||
| defaultRegion | string | Cloudwatch | AWS region |
|
||||
| customMetricsNamespaces | string | Cloudwatch | Namespaces of Custom Metrics |
|
||||
| tsdbVersion | string | OpenTsdb | Version |
|
||||
| tsdbResolution | string | OpenTsdb | Resolution |
|
||||
| sslmode | string | Postgre | SSLmode. 'disable', 'require', 'verify-ca' or 'verify-full' |
|
||||
| tsdbVersion | string | OpenTSDB | Version |
|
||||
| tsdbResolution | string | OpenTSDB | Resolution |
|
||||
| sslmode | string | PostgreSQL | SSLmode. 'disable', 'require', 'verify-ca' or 'verify-full' |
|
||||
|
||||
#### Secure Json Data
|
||||
|
||||
@@ -177,8 +177,8 @@ Secure json data is a map of settings that will be encrypted with [secret key](/
|
||||
| tlsCACert | string | *All* |CA cert for out going requests |
|
||||
| tlsClientCert | string | *All* |TLS Client cert for outgoing requests |
|
||||
| tlsClientKey | string | *All* |TLS Client key for outgoing requests |
|
||||
| password | string | Postgre | password |
|
||||
| user | string | Postgre | user |
|
||||
| password | string | PostgreSQL | password |
|
||||
| user | string | PostgreSQL | user |
|
||||
| accessKey | string | Cloudwatch | Access key for connecting to Cloudwatch |
|
||||
| secretKey | string | Cloudwatch | Secret key for connecting to Cloudwatch |
|
||||
|
||||
@@ -197,13 +197,23 @@ providers:
|
||||
folder: ''
|
||||
type: file
|
||||
disableDeletion: false
|
||||
editable: false
|
||||
updateIntervalSeconds: 3 #how often Grafana will scan for changed dashboards
|
||||
options:
|
||||
path: /var/lib/grafana/dashboards
|
||||
```
|
||||
|
||||
When Grafana starts, it will update/insert all dashboards available in the configured path. Then later on poll that path and look for updated json files and insert those update/insert those into the database.
|
||||
|
||||
#### Making changes to a provisioned dashboard
|
||||
|
||||
It's possible to make changes to a provisioned dashboard in Grafana UI, but there's currently no possibility to automatically save the changes back to the provisioning source.
|
||||
However, if you make changes to a provisioned dashboard you can `Save` the dashboard which will bring up a *Cannot save provisioned dashboard* dialog like seen in the screenshot below.
|
||||
Here available options will let you `Copy JSON to Clipboard` and/or `Save JSON to file` which can help you synchronize your dashboard changes back to the provisioning source.
|
||||
|
||||
Note: The JSON shown in input field and when using `Copy JSON to Clipboard` and/or `Save JSON to file` will have the `id` field automatically removed to aid the provisioning workflow.
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/provisioning_cannot_save_dashboard.png" max-width="500px" class="docs-image--no-shadow" >}}
|
||||
|
||||
### Reuseable Dashboard Urls
|
||||
|
||||
If the dashboard in the json file contains an [uid](/reference/dashboard/#json-fields), Grafana will force insert/update on that uid. This allows you to migrate dashboards betweens Grafana instances and provisioning Grafana from configuration without breaking the urls given since the new dashboard url uses the uid as identifier.
|
||||
|
||||
@@ -27,7 +27,9 @@ and the conditions that need to be met for the alert to change state and trigger
|
||||
## Execution
|
||||
|
||||
The alert rules are evaluated in the Grafana backend in a scheduler and query execution engine that is part
|
||||
of core Grafana. Only some data sources are supported right now. They include `Graphite`, `Prometheus`, `InfluxDB`, `OpenTSDB`, `MySQL`, `Postgres` and `Cloudwatch`.
|
||||
of core Grafana. Only some data sources are supported right now. They include `Graphite`, `Prometheus`, `Elasticsearch`, `InfluxDB`, `OpenTSDB`, `MySQL`, `Postgres` and `Cloudwatch`.
|
||||
|
||||
> Alerting support for Elasticsearch is only available in Grafana v5.2 and above.
|
||||
|
||||
### Clustering
|
||||
|
||||
@@ -152,6 +154,8 @@ filters = alerting.scheduler:debug \
|
||||
tsdb.prometheus:debug \
|
||||
tsdb.opentsdb:debug \
|
||||
tsdb.influxdb:debug \
|
||||
tsdb.elasticsearch:debug \
|
||||
tsdb.elasticsearch.client:debug \
|
||||
```
|
||||
|
||||
If you want to log raw query sent to your TSDB and raw response in log you also have to set grafana.ini option `app_mode` to
|
||||
|
||||
@@ -208,9 +208,9 @@ it costs $0.01 per 1,000 GetMetricStatistics or ListMetrics requests. For each q
|
||||
issue a GetMetricStatistics request and every time you pick a dimension in the query editor
|
||||
Grafana will issue a ListMetrics request.
|
||||
|
||||
## Configure datasource with provisioning
|
||||
## Configure the Datasource with Provisioning
|
||||
|
||||
It's now possible to configure datasources using config files with Grafanas provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
It's now possible to configure datasources using config files with Grafana's provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
|
||||
Here are some provisioning examples for this datasource.
|
||||
|
||||
|
||||
@@ -29,13 +29,19 @@ Name | Description
|
||||
*Name* | The data source name. This is how you refer to the data source in panels & queries.
|
||||
*Default* | Default data source means that it will be pre-selected for new panels.
|
||||
*Url* | The HTTP protocol, IP, and port of your Elasticsearch server.
|
||||
*Access* | Proxy = access via Grafana backend, Direct = access directly from browser.
|
||||
*Access* | Server (default) = URL needs to be accessible from the Grafana backend/server, Browser = URL needs to be accessible from the browser.
|
||||
|
||||
Proxy access means that the Grafana backend will proxy all requests from the browser, and send them on to the Data Source. This is useful because it can eliminate CORS (Cross Origin Site Resource) issues, as well as eliminate the need to disseminate authentication to the browser.
|
||||
Access mode controls how requests to the data source will be handled. Server should be the preferred way if nothing else stated.
|
||||
|
||||
### Direct access
|
||||
### Server access mode (Default)
|
||||
|
||||
If you select direct access you must update your Elasticsearch configuration to allow other domains to access
|
||||
All requests will be made from the browser to Grafana backend/server which in turn will forward the requests to the data source and by that circumvent possible Cross-Origin Resource Sharing (CORS) requirements. The URL needs to be accessible from the grafana backend/server if you select this access mode.
|
||||
|
||||
### Browser (Direct) access
|
||||
|
||||
All requests will be made from the browser directly to the data source and may be subject to Cross-Origin Resource Sharing (CORS) requirements. The URL needs to be accessible from the browser if you select this access mode.
|
||||
|
||||
If you select Browser access you must update your Elasticsearch configuration to allow other domains to access
|
||||
Elasticsearch from the browser. You do this by specifying these to options in your **elasticsearch.yml** config file.
|
||||
|
||||
```bash
|
||||
@@ -45,7 +51,7 @@ http.cors.allow-origin: "*"
|
||||
|
||||
### Index settings
|
||||
|
||||

|
||||

|
||||
|
||||
Here you can specify a default for the `time field` and specify the name of your Elasticsearch index. You can use
|
||||
a time pattern for the index name or a wildcard.
|
||||
@@ -73,7 +79,7 @@ Identifier | Description
|
||||
|
||||
## Metric Query editor
|
||||
|
||||

|
||||

|
||||
|
||||
The Elasticsearch query editor allows you to select multiple metrics and group by multiple terms or filters. Use the plus and minus icons to the right to add/remove
|
||||
metrics or group by clauses. Some metrics and group by clauses haves options, click the option text to expand the row to view and edit metric or group by options.
|
||||
@@ -154,9 +160,9 @@ Time | The name of the time field, needs to be date field.
|
||||
Text | Event description field.
|
||||
Tags | Optional field name to use for event tags (can be an array or a CSV string).
|
||||
|
||||
## Configure datasource with provisioning
|
||||
## Configure the Datasource with Provisioning
|
||||
|
||||
It's now possible to configure datasources using config files with Grafanas provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
It's now possible to configure datasources using config files with Grafana's provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
|
||||
Here are some provisioning examples for this datasource.
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ queries through the use of query references.
|
||||
## Adding the data source
|
||||
|
||||
1. Open the side menu by clicking the Grafana icon in the top header.
|
||||
2. In the side menu under the `Dashboards` link you should find a link named `Data Sources`.
|
||||
2. In the side menu under the `Configuration` link you should find a link named `Data Sources`.
|
||||
3. Click the `+ Add data source` button in the top header.
|
||||
4. Select `Graphite` from the *Type* dropdown.
|
||||
|
||||
@@ -31,20 +31,28 @@ Name | Description
|
||||
*Name* | The data source name. This is how you refer to the data source in panels & queries.
|
||||
*Default* | Default data source means that it will be pre-selected for new panels.
|
||||
*Url* | The HTTP protocol, IP, and port of your graphite-web or graphite-api install.
|
||||
*Access* | Proxy = access via Grafana backend, Direct = access directly from browser.
|
||||
*Access* | Server (default) = URL needs to be accessible from the Grafana backend/server, Browser = URL needs to be accessible from the browser.
|
||||
|
||||
Proxy access means that the Grafana backend will proxy all requests from the browser, and send them on to the Data Source. This is useful because it can eliminate CORS (Cross Origin Site Resource) issues, as well as eliminate the need to disseminate authentication details to the browser.
|
||||
Access mode controls how requests to the data source will be handled. Server should be the preferred way if nothing else stated.
|
||||
|
||||
### Server access mode (Default)
|
||||
|
||||
All requests will be made from the browser to Grafana backend/server which in turn will forward the requests to the data source and by that circumvent possible Cross-Origin Resource Sharing (CORS) requirements. The URL needs to be accessible from the grafana backend/server if you select this access mode.
|
||||
|
||||
### Browser access mode
|
||||
|
||||
All requests will be made from the browser directly to the data source and may be subject to Cross-Origin Resource Sharing (CORS) requirements. The URL needs to be accessible from the browser if you select this access mode.
|
||||
|
||||
## Metric editor
|
||||
|
||||
### Navigate metric segments
|
||||
|
||||
Click the ``Select metric`` link to start navigating the metric space. One you start you can continue using the mouse
|
||||
or keyboard arrow keys. You can select a wildcard and still continue.
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v45/graphite_query1_still.png"
|
||||
animated-gif="/img/docs/v45/graphite_query1.gif" >}}
|
||||
|
||||
|
||||
### Functions
|
||||
|
||||
Click the plus icon to the right to add a function. You can search for the function or select it from the menu. Once
|
||||
@@ -55,7 +63,6 @@ by the x icon.
|
||||
{{< docs-imagebox img="/img/docs/v45/graphite_query2_still.png"
|
||||
animated-gif="/img/docs/v45/graphite_query2.gif" >}}
|
||||
|
||||
|
||||
### Optional parameters
|
||||
|
||||
Some functions like aliasByNode support an optional second argument. To add this parameter specify for example 3,-2 as the first parameter and the function editor will adapt and move the -2 to a second parameter. To remove the second optional parameter just click on it and leave it blank and the editor will remove it.
|
||||
@@ -63,7 +70,6 @@ Some functions like aliasByNode support an optional second argument. To add this
|
||||
{{< docs-imagebox img="/img/docs/v45/graphite_query3_still.png"
|
||||
animated-gif="/img/docs/v45/graphite_query3.gif" >}}
|
||||
|
||||
|
||||
### Nested Queries
|
||||
|
||||
You can reference queries by the row “letter” that they’re on (similar to Microsoft Excel). If you add a second query to a graph, you can reference the first query simply by typing in #A. This provides an easy and convenient way to build compounded queries.
|
||||
@@ -71,7 +77,6 @@ You can reference queries by the row “letter” that they’re on (similar to
|
||||
{{< docs-imagebox img="/img/docs/v45/graphite_nested_queries_still.png"
|
||||
animated-gif="/img/docs/v45/graphite_nested_queries.gif" >}}
|
||||
|
||||
|
||||
## Point consolidation
|
||||
|
||||
All Graphite metrics are consolidated so that Graphite doesn't return more data points than there are pixels in the graph. By default,
|
||||
@@ -89,6 +94,18 @@ being displayed in your dashboard.
|
||||
Checkout the [Templating]({{< relref "reference/templating.md" >}}) documentation for an introduction to the templating feature and the different
|
||||
types of template variables.
|
||||
|
||||
Graphite 1.1 introduced tags and Grafana added support for Graphite queries with tags in version 5.0. To create a variable using tag values, then you need to use the Grafana functions `tags` and `tag_values`.
|
||||
|
||||
Query | Description
|
||||
------------ | -------------
|
||||
*tags()* | Returns all tags.
|
||||
*tags(server=~backend\*)* | Returns only tags that occur in series matching the filter expression.
|
||||
*tag_values(server)* | Return tag values for the specified tag.
|
||||
*tag_values(server, server=~backend\*)* | Returns filtered tag values that occur for the specified tag in series matching those expressions.
|
||||
*tag_values(server, server=~backend\*, app=~${apps:regex})* | Multiple filter expressions and expressions can contain other variables.
|
||||
|
||||
For more details, see the [Graphite docs on the autocomplete api for tags](http://graphite.readthedocs.io/en/latest/tags.html#auto-complete-support).
|
||||
|
||||
### Query variable
|
||||
|
||||
The query you specify in the query field should be a metric find type of query. For example, a query like `prod.servers.*` will fill the
|
||||
@@ -97,10 +114,10 @@ variable with all possible values that exist in the wildcard position.
|
||||
You can also create nested variables that use other variables in their definition. For example
|
||||
`apps.$app.servers.*` uses the variable `$app` in its query definition.
|
||||
|
||||
### Variable usage
|
||||
### Variable Usage
|
||||
|
||||
You can use a variable in a metric node path or as a parameter to a function.
|
||||

|
||||

|
||||
|
||||
There are two syntaxes:
|
||||
|
||||
@@ -113,6 +130,18 @@ the second syntax in expressions like `my.server[[serverNumber]].count`.
|
||||
Example:
|
||||
[Graphite Templated Dashboard](http://play.grafana.org/dashboard/db/graphite-templated-nested)
|
||||
|
||||
### Variable Usage in Tag Queries
|
||||
|
||||
Multi-value variables in tag queries use the advanced formatting syntax introduced in Grafana 5.0 for variables: `{var:regex}`. Non-tag queries will use the default glob formatting for multi-value variables.
|
||||
|
||||
Example of a tag expression with regex formatting and using the Equal Tilde operator, `=~`:
|
||||
|
||||
```text
|
||||
server=~${servers:regex}
|
||||
```
|
||||
|
||||
Checkout the [Advanced Formatting Options section in the Variables]({{< relref "reference/templating.md#advanced-formatting-options" >}}) documentation for examples and details.
|
||||
|
||||
## Annotations
|
||||
|
||||
[Annotations]({{< relref "reference/annotations.md" >}}) allows you to overlay rich event information on top of graphs. You add annotation
|
||||
@@ -121,9 +150,9 @@ queries via the Dashboard menu / Annotations view.
|
||||
Graphite supports two ways to query annotations. A regular metric query, for this you use the `Graphite query` textbox. A Graphite events query, use the `Graphite event tags` textbox,
|
||||
specify a tag or wildcard (leave empty should also work)
|
||||
|
||||
## Configure datasource with provisioning
|
||||
## Configure the Datasource with Provisioning
|
||||
|
||||
It's now possible to configure datasources using config files with Grafanas provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
It's now possible to configure datasources using config files with Grafana's provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
|
||||
Here are some provisioning examples for this datasource.
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ The following datasources are officially supported:
|
||||
* [Prometheus]({{< relref "prometheus.md" >}})
|
||||
* [MySQL]({{< relref "mysql.md" >}})
|
||||
* [Postgres]({{< relref "postgres.md" >}})
|
||||
* [Microsoft SQL Server (MSSQL)]({{< relref "mssql.md" >}})
|
||||
|
||||
## Data source plugins
|
||||
|
||||
|
||||
@@ -28,16 +28,20 @@ Name | Description
|
||||
*Name* | The data source name. This is how you refer to the data source in panels & queries.
|
||||
*Default* | Default data source means that it will be pre-selected for new panels.
|
||||
*Url* | The http protocol, ip and port of you influxdb api (influxdb api port is by default 8086)
|
||||
*Access* | Proxy = access via Grafana backend, Direct = access directly from browser.
|
||||
*Access* | Server (default) = URL needs to be accessible from the Grafana backend/server, Browser = URL needs to be accessible from the browser.
|
||||
*Database* | Name of your influxdb database
|
||||
*User* | Name of your database user
|
||||
*Password* | Database user's password
|
||||
|
||||
### Proxy vs Direct access
|
||||
Access mode controls how requests to the data source will be handled. Server should be the preferred way if nothing else stated.
|
||||
|
||||
Proxy access means that the Grafana backend will proxy all requests from the browser. So requests to InfluxDB will be channeled through
|
||||
`grafana-server`. This means that the URL you specify needs to be accessible from the server you are running Grafana on. Proxy access
|
||||
mode is also more secure as the username & password will never reach the browser.
|
||||
### Server access mode (Default)
|
||||
|
||||
All requests will be made from the browser to Grafana backend/server which in turn will forward the requests to the data source and by that circumvent possible Cross-Origin Resource Sharing (CORS) requirements. The URL needs to be accessible from the grafana backend/server if you select this access mode.
|
||||
|
||||
### Browser access mode
|
||||
|
||||
All requests will be made from the browser directly to the data source and may be subject to Cross-Origin Resource Sharing (CORS) requirements. The URL needs to be accessible from the browser if you select this access mode.
|
||||
|
||||
### Min time interval
|
||||
A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example `1m` if your data is written every minute.
|
||||
@@ -191,9 +195,9 @@ For InfluxDB you need to enter a query like in the above example. You need to ha
|
||||
part. If you only select one column you will not need to enter anything in the column mapping fields. The
|
||||
Tags field can be a comma separated string.
|
||||
|
||||
## Configure datasource with provisioning
|
||||
## Configure the Datasource with Provisioning
|
||||
|
||||
It's now possible to configure datasources using config files with Grafanas provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
It's now possible to configure datasources using config files with Grafana's provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
|
||||
Here are some provisioning examples for this datasource.
|
||||
|
||||
|
||||
565
docs/sources/features/datasources/mssql.md
Normal file
565
docs/sources/features/datasources/mssql.md
Normal file
@@ -0,0 +1,565 @@
|
||||
+++
|
||||
title = "Using Microsoft SQL Server in Grafana"
|
||||
description = "Guide for using Microsoft SQL Server in Grafana"
|
||||
keywords = ["grafana", "MSSQL", "Microsoft", "SQL", "guide", "Azure SQL Database"]
|
||||
type = "docs"
|
||||
[menu.docs]
|
||||
name = "Microsoft SQL Server"
|
||||
parent = "datasources"
|
||||
weight = 7
|
||||
+++
|
||||
|
||||
# Using Microsoft SQL Server in Grafana
|
||||
|
||||
> Only available in Grafana v5.1+.
|
||||
|
||||
Grafana ships with a built-in Microsoft SQL Server (MSSQL) data source plugin that allows you to query and visualize data from any Microsoft SQL Server 2005 or newer, including Microsoft Azure SQL Database.
|
||||
|
||||
## Adding the data source
|
||||
|
||||
1. Open the side menu by clicking the Grafana icon in the top header.
|
||||
2. In the side menu under the `Configuration` link you should find a link named `Data Sources`.
|
||||
3. Click the `+ Add data source` button in the top header.
|
||||
4. Select *Microsoft SQL Server* from the *Type* dropdown.
|
||||
|
||||
### Data source options
|
||||
|
||||
Name | Description
|
||||
------------ | -------------
|
||||
*Name* | The data source name. This is how you refer to the data source in panels & queries.
|
||||
*Default* | Default data source means that it will be pre-selected for new panels.
|
||||
*Host* | The IP address/hostname and optional port of your MSSQL instance. If port is omitted, default 1433 will be used.
|
||||
*Database* | Name of your MSSQL database.
|
||||
*User* | Database user's login/username
|
||||
*Password* | Database user's password
|
||||
|
||||
### Database User Permissions (Important!)
|
||||
|
||||
The database user you specify when you add the data source should only be granted SELECT permissions on
|
||||
the specified database & tables you want to query. Grafana does not validate that the query is safe. The query
|
||||
could include any SQL statement. For example, statements like `DELETE FROM user;` and `DROP TABLE user;` would be
|
||||
executed. To protect against this we **Highly** recommend you create a specific MSSQL user with restricted permissions.
|
||||
|
||||
Example:
|
||||
|
||||
```sql
|
||||
CREATE USER grafanareader WITH PASSWORD 'password'
|
||||
GRANT SELECT ON dbo.YourTable3 TO grafanareader
|
||||
```
|
||||
|
||||
Make sure the user does not get any unwanted privileges from the public role.
|
||||
|
||||
### Known Issues
|
||||
|
||||
MSSQL 2008 and 2008 R2 engine cannot handle login records when SSL encryption is not disabled. Due to this you may receive an `Login error: EOF` error when trying to create your datasource.
|
||||
To fix MSSQL 2008 R2 issue, install MSSQL 2008 R2 Service Pack 2. To fix MSSQL 2008 issue, install Microsoft MSSQL 2008 Service Pack 3 and Cumulative update package 3 for MSSQL 2008 SP3.
|
||||
|
||||
## Query Editor
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/mssql_query_editor.png" class="docs-image--no-shadow" >}}
|
||||
|
||||
You find the MSSQL query editor in the metrics tab in Graph, Singlestat or Table panel's edit mode. You enter edit mode by clicking the
|
||||
panel title, then edit. The editor allows you to define a SQL query to select data to be visualized.
|
||||
|
||||
1. Select *Format as* `Time series` (for use in Graph or Singlestat panel's among others) or `Table` (for use in Table panel among others).
|
||||
2. This is the actual editor where you write your SQL queries.
|
||||
3. Show help section for MSSQL below the query editor.
|
||||
4. Show actual executed SQL query. Will be available first after a successful query has been executed.
|
||||
5. Add an additional query where an additional query editor will be displayed.
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
## Macros
|
||||
|
||||
To simplify syntax and to allow for dynamic parts, like date range filters, the query can contain macros.
|
||||
|
||||
Macro example | Description
|
||||
------------ | -------------
|
||||
*$__time(dateColumn)* | Will be replaced by an expression to rename the column to *time*. For example, *dateColumn as time*
|
||||
*$__timeEpoch(dateColumn)* | Will be replaced by an expression to convert a DATETIME column type to unix timestamp and rename it to *time*. <br/>For example, *DATEDIFF(second, '1970-01-01', dateColumn) AS time*
|
||||
*$__timeFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name. <br/>For example, *dateColumn >= DATEADD(s, 1494410783, '1970-01-01') AND dateColumn <= DATEADD(s, 1494410783, '1970-01-01')*
|
||||
*$__timeFrom()* | Will be replaced by the start of the currently active time selection. For example, *DATEADD(second, 1494410783, '1970-01-01')*
|
||||
*$__timeTo()* | Will be replaced by the end of the currently active time selection. For example, *DATEADD(second, 1494410783, '1970-01-01')*
|
||||
*$__timeGroup(dateColumn,'5m'[, fillvalue])* | Will be replaced by an expression usable in GROUP BY clause. Providing a *fillValue* of *NULL* or *floating value* will automatically fill empty series in timerange with that value. <br/>For example, *CAST(ROUND(DATEDIFF(second, '1970-01-01', time_column)/300.0, 0) as bigint)\*300*.
|
||||
*$__timeGroup(dateColumn,'5m', 0)* | Same as above but with a fill parameter so all null values will be converted to the fill value (all null values would be set to zero using this example).
|
||||
*$__unixEpochFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name with times represented as unix timestamp. For example, *dateColumn > 1494410783 AND dateColumn < 1494497183*
|
||||
*$__unixEpochFrom()* | Will be replaced by the start of the currently active time selection as unix timestamp. For example, *1494410783*
|
||||
*$__unixEpochTo()* | Will be replaced by the end of the currently active time selection as unix timestamp. For example, *1494497183*
|
||||
|
||||
We plan to add many more macros. If you have suggestions for what macros you would like to see, please [open an issue](https://github.com/grafana/grafana) in our GitHub repo.
|
||||
|
||||
The query editor has a link named `Generated SQL` that shows up after a query has been executed, while in panel edit mode. Click on it and it will expand and show the raw interpolated SQL string that was executed.
|
||||
|
||||
## Table queries
|
||||
|
||||
If the `Format as` query option is set to `Table` then you can basically do any type of SQL query. The table panel will automatically show the results of whatever columns & rows your query returns.
|
||||
|
||||
**Example database table:**
|
||||
|
||||
```sql
|
||||
CREATE TABLE [event] (
|
||||
time_sec bigint,
|
||||
description nvarchar(100),
|
||||
tags nvarchar(100),
|
||||
)
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE [mssql_types] (
|
||||
c_bit bit, c_tinyint tinyint, c_smallint smallint, c_int int, c_bigint bigint, c_money money, c_smallmoney smallmoney, c_numeric numeric(10,5),
|
||||
c_real real, c_decimal decimal(10,2), c_float float,
|
||||
c_char char(10), c_varchar varchar(10), c_text text,
|
||||
c_nchar nchar(12), c_nvarchar nvarchar(12), c_ntext ntext,
|
||||
c_datetime datetime, c_datetime2 datetime2, c_smalldatetime smalldatetime, c_date date, c_time time, c_datetimeoffset datetimeoffset
|
||||
)
|
||||
|
||||
INSERT INTO [mssql_types]
|
||||
SELECT
|
||||
1, 5, 20020, 980300, 1420070400, '$20000.15', '£2.15', 12345.12,
|
||||
1.11, 2.22, 3.33,
|
||||
'char10', 'varchar10', 'text',
|
||||
N'☺nchar12☺', N'☺nvarchar12☺', N'☺text☺',
|
||||
GETDATE(), CAST(GETDATE() AS DATETIME2), CAST(GETDATE() AS SMALLDATETIME), CAST(GETDATE() AS DATE), CAST(GETDATE() AS TIME), SWITCHOFFSET(CAST(GETDATE() AS DATETIMEOFFSET), '-07:00'))
|
||||
```
|
||||
|
||||
Query editor with example query:
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/mssql_table_query.png" max-width="500px" class="docs-image--no-shadow" >}}
|
||||
|
||||
|
||||
The query:
|
||||
|
||||
```sql
|
||||
SELECT * FROM [mssql_types]
|
||||
```
|
||||
|
||||
You can control the name of the Table panel columns by using regular `AS ` SQL column selection syntax. Example:
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
c_bit as [column1], c_tinyint as [column2]
|
||||
FROM
|
||||
[mssql_types]
|
||||
```
|
||||
|
||||
The resulting table panel:
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/mssql_table_result.png" max-width="1489px" class="docs-image--no-shadow" >}}
|
||||
|
||||
## Time series queries
|
||||
|
||||
If you set `Format as` to `Time series`, for use in Graph panel for example, then the query must must have a column named `time` that returns either a sql datetime or any numeric datatype representing unix epoch in seconds. You may return a column named `metric` that is used as metric name for the value column. Any column except `time` and `metric` is treated as a value column. If you omit the `metric` column, tha name of the value column will be the metric name. You may select multiple value columns, each will have its name as metric.
|
||||
|
||||
**Example database table:**
|
||||
|
||||
```sql
|
||||
CREATE TABLE [event] (
|
||||
time_sec bigint,
|
||||
description nvarchar(100),
|
||||
tags nvarchar(100),
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
```sql
|
||||
CREATE TABLE metric_values (
|
||||
time datetime,
|
||||
measurement nvarchar(100),
|
||||
valueOne int,
|
||||
valueTwo int,
|
||||
)
|
||||
|
||||
INSERT metric_values (time, measurement, valueOne, valueTwo) VALUES('2018-03-15 12:30:00', 'Metric A', 62, 6)
|
||||
INSERT metric_values (time, measurement, valueOne, valueTwo) VALUES('2018-03-15 12:30:00', 'Metric B', 49, 11)
|
||||
...
|
||||
INSERT metric_values (time, measurement, valueOne, valueTwo) VALUES('2018-03-15 13:55:00', 'Metric A', 14, 25)
|
||||
INSERT metric_values (time, measurement, valueOne, valueTwo) VALUES('2018-03-15 13:55:00', 'Metric B', 48, 10)
|
||||
|
||||
```
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/mssql_time_series_one.png" class="docs-image--no-shadow docs-image--right" >}}
|
||||
|
||||
**Example with one `value` and one `metric` column.**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
time,
|
||||
valueOne,
|
||||
measurement as metric
|
||||
FROM
|
||||
metric_values
|
||||
WHERE
|
||||
$__timeFilter(time)
|
||||
ORDER BY 1
|
||||
```
|
||||
|
||||
When above query are used in a graph panel the result will be two series named `Metric A` and `Metric B` with value of `valueOne` and `valueTwo` plotted over `time`.
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/mssql_time_series_two.png" class="docs-image--no-shadow docs-image--right" >}}
|
||||
|
||||
**Example with multiple `value` culumns:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
time,
|
||||
valueOne,
|
||||
valueTwo
|
||||
FROM
|
||||
metric_values
|
||||
WHERE
|
||||
$__timeFilter(time)
|
||||
ORDER BY 1
|
||||
```
|
||||
|
||||
When above query are used in a graph panel the result will be two series named `valueOne` and `valueTwo` with value of `valueOne` and `valueTwo` plotted over `time`.
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/mssql_time_series_three.png" class="docs-image--no-shadow docs-image--right" >}}
|
||||
|
||||
**Example using the $__timeGroup macro:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
$__timeGroup(time, '3m') as time,
|
||||
measurement as metric,
|
||||
avg(valueOne)
|
||||
FROM
|
||||
metric_values
|
||||
WHERE
|
||||
$__timeFilter(time)
|
||||
GROUP BY
|
||||
$__timeGroup(time, '3m'),
|
||||
measurement
|
||||
ORDER BY 1
|
||||
```
|
||||
|
||||
When above query are used in a graph panel the result will be two series named `Metric A` and `Metric B` with an average of `valueOne` plotted over `time`.
|
||||
Any two series lacking a value in a 3 minute window will render a line between those two lines. You'll notice that the graph to the right never goes down to zero.
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/mssql_time_series_four.png" class="docs-image--no-shadow docs-image--right" >}}
|
||||
|
||||
**Example using the $__timeGroup macro with fill parameter set to zero:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
$__timeGroup(time, '3m', 0) as time,
|
||||
measurement as metric,
|
||||
sum(valueTwo)
|
||||
FROM
|
||||
metric_values
|
||||
WHERE
|
||||
$__timeFilter(time)
|
||||
GROUP BY
|
||||
$__timeGroup(time, '3m'),
|
||||
measurement
|
||||
ORDER BY 1
|
||||
```
|
||||
|
||||
When above query are used in a graph panel the result will be two series named `Metric A` and `Metric B` with a sum of `valueTwo` plotted over `time`.
|
||||
Any series lacking a value in a 3 minute window will have a value of zero which you'll see rendered in the graph to the right.
|
||||
|
||||
## Templating
|
||||
|
||||
Instead of hard-coding things like server, application and sensor name in you metric queries you can use variables in their place. Variables are shown as dropdown select boxes at the top of the dashboard. These dropdowns makes it easy to change the data being displayed in your dashboard.
|
||||
|
||||
Checkout the [Templating]({{< relref "reference/templating.md" >}}) documentation for an introduction to the templating feature and the different types of template variables.
|
||||
|
||||
### Query Variable
|
||||
|
||||
If you add a template variable of the type `Query`, you can write a MSSQL query that can
|
||||
return things like measurement names, key names or key values that are shown as a dropdown select box.
|
||||
|
||||
For example, you can have a variable that contains all values for the `hostname` column in a table if you specify a query like this in the templating variable *Query* setting.
|
||||
|
||||
```sql
|
||||
SELECT hostname FROM host
|
||||
```
|
||||
|
||||
A query can return multiple columns and Grafana will automatically create a list from them. For example, the query below will return a list with values from `hostname` and `hostname2`.
|
||||
|
||||
```sql
|
||||
SELECT [host].[hostname], [other_host].[hostname2] FROM host JOIN other_host ON [host].[city] = [other_host].[city]
|
||||
```
|
||||
|
||||
Another option is a query that can create a key/value variable. The query should return two columns that are named `__text` and `__value`. The `__text` column value should be unique (if it is not unique then the first value is used). The options in the dropdown will have a text and value that allows you to have a friendly name as text and an id as the value. An example query with `hostname` as the text and `id` as the value:
|
||||
|
||||
```sql
|
||||
SELECT hostname __text, id __value FROM host
|
||||
```
|
||||
|
||||
You can also create nested variables. For example if you had another variable named `region`. Then you could have
|
||||
the hosts variable only show hosts from the current selected region with a query like this (if `region` is a multi-value variable then use the `IN` comparison operator rather than `=` to match against multiple values):
|
||||
|
||||
```sql
|
||||
SELECT hostname FROM host WHERE region IN ($region)
|
||||
```
|
||||
|
||||
### Using Variables in Queries
|
||||
|
||||
> From Grafana 4.3.0 to 4.6.0, template variables are always quoted automatically so if it is a string value do not wrap them in quotes in where clauses.
|
||||
>
|
||||
> From Grafana 5.0.0, template variable values are only quoted when the template variable is a `multi-value`.
|
||||
|
||||
If the variable is a multi-value variable then use the `IN` comparison operator rather than `=` to match against multiple values.
|
||||
|
||||
There are two syntaxes:
|
||||
|
||||
`$<varname>` Example with a template variable named `hostname`:
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
atimestamp time,
|
||||
aint value
|
||||
FROM table
|
||||
WHERE $__timeFilter(atimestamp) and hostname in($hostname)
|
||||
ORDER BY atimestamp
|
||||
```
|
||||
|
||||
`[[varname]]` Example with a template variable named `hostname`:
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
atimestamp as time,
|
||||
aint as value
|
||||
FROM table
|
||||
WHERE $__timeFilter(atimestamp) and hostname in([[hostname]])
|
||||
ORDER BY atimestamp
|
||||
```
|
||||
|
||||
#### Disabling Quoting for Multi-value Variables
|
||||
|
||||
Grafana automatically creates a quoted, comma-separated string for multi-value variables. For example: if `server01` and `server02` are selected then it will be formatted as: `'server01', 'server02'`. Do disable quoting, use the csv formatting option for variables:
|
||||
|
||||
`${servers:csv}`
|
||||
|
||||
Read more about variable formatting options in the [Variables]({{< relref "reference/templating.md#advanced-formatting-options" >}}) documentation.
|
||||
|
||||
## Annotations
|
||||
|
||||
[Annotations]({{< relref "reference/annotations.md" >}}) allows you to overlay rich event information on top of graphs. You add annotation queries via the Dashboard menu / Annotations view.
|
||||
|
||||
**Columns:**
|
||||
|
||||
Name | Description
|
||||
------------ | -------------
|
||||
time | The name of the date/time field. Could be a column with a native sql date/time data type or epoch value.
|
||||
text | Event description field.
|
||||
tags | Optional field name to use for event tags as a comma separated string.
|
||||
|
||||
**Example database tables:**
|
||||
|
||||
```sql
|
||||
CREATE TABLE [events] (
|
||||
time_sec bigint,
|
||||
description nvarchar(100),
|
||||
tags nvarchar(100),
|
||||
)
|
||||
```
|
||||
|
||||
We also use the database table defined in [Time series queries](#time-series-queries).
|
||||
|
||||
**Example query using time column with epoch values:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
time_sec as time,
|
||||
description as [text],
|
||||
tags
|
||||
FROM
|
||||
[events]
|
||||
WHERE
|
||||
$__unixEpochFilter(time_sec)
|
||||
ORDER BY 1
|
||||
```
|
||||
|
||||
**Example query using time column of native sql date/time data type:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
time,
|
||||
measurement as text,
|
||||
convert(varchar, valueOne) + ',' + convert(varchar, valueTwo) as tags
|
||||
FROM
|
||||
metric_values
|
||||
WHERE
|
||||
$__timeFilter(time_column)
|
||||
ORDER BY 1
|
||||
```
|
||||
|
||||
## Stored procedure support
|
||||
|
||||
Stored procedures have been verified to work. However, please note that we haven't done anything special to support this why there may exist edge cases where it won't work as you would expect.
|
||||
Stored procedures should be supported in table, time series and annotation queries as long as you use the same naming of columns and return data in the same format as describe above under respective section.
|
||||
|
||||
Please note that any macro function will not work inside a stored procedure.
|
||||
|
||||
### Examples
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/mssql_metrics_graph.png" class="docs-image--no-shadow docs-image--right" >}}
|
||||
For the following examples the database table defined in [Time series queries](#time-series-queries). Let's say that we want to visualize 4 series in a graph panel, i.e. all combinations of columns `valueOne`, `valueTwo` and `measurement`. Graph panel to the right visualizes what we want to achieve. To solve this we actually need to use two queries:
|
||||
|
||||
**First query:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
$__timeGroup(time, '5m') as time,
|
||||
measurement + ' - value one' as metric,
|
||||
avg(valueOne) as valueOne
|
||||
FROM
|
||||
metric_values
|
||||
WHERE
|
||||
$__timeFilter(time)
|
||||
GROUP BY
|
||||
$__timeGroup(time, '5m'),
|
||||
measurement
|
||||
ORDER BY 1
|
||||
```
|
||||
|
||||
**Second query:**
|
||||
```sql
|
||||
SELECT
|
||||
$__timeGroup(time, '5m') as time,
|
||||
measurement + ' - value two' as metric,
|
||||
avg(valueTwo) as valueTwo
|
||||
FROM
|
||||
metric_values
|
||||
GROUP BY
|
||||
$__timeGroup(time, '5m'),
|
||||
measurement
|
||||
ORDER BY 1
|
||||
```
|
||||
|
||||
#### Stored procedure using time in epoch format
|
||||
|
||||
We can define a stored procedure that will return all data we need to render 4 series in a graph panel like above.
|
||||
In this case the stored procedure accepts two parameters `@from` and `@to` of `int` data types which should be a timerange (from-to) in epoch format
|
||||
which will be used to filter the data to return from the stored procedure.
|
||||
|
||||
We're mimicking the `$__timeGroup(time, '5m')` in the select and group by expressions and that's why there's a lot of lengthy expressions needed -
|
||||
these could be extracted to MSSQL functions, if wanted.
|
||||
|
||||
```sql
|
||||
CREATE PROCEDURE sp_test_epoch(
|
||||
@from int,
|
||||
@to int
|
||||
) AS
|
||||
BEGIN
|
||||
SELECT
|
||||
cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int) as time,
|
||||
measurement + ' - value one' as metric,
|
||||
avg(valueOne) as value
|
||||
FROM
|
||||
metric_values
|
||||
WHERE
|
||||
time >= DATEADD(s, @from, '1970-01-01') AND time <= DATEADD(s, @to, '1970-01-01')
|
||||
GROUP BY
|
||||
cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int),
|
||||
measurement
|
||||
UNION ALL
|
||||
SELECT
|
||||
cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int) as time,
|
||||
measurement + ' - value two' as metric,
|
||||
avg(valueTwo) as value
|
||||
FROM
|
||||
metric_values
|
||||
WHERE
|
||||
time >= DATEADD(s, @from, '1970-01-01') AND time <= DATEADD(s, @to, '1970-01-01')
|
||||
GROUP BY
|
||||
cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int),
|
||||
measurement
|
||||
ORDER BY 1
|
||||
END
|
||||
```
|
||||
|
||||
Then we can use the following query for our graph panel.
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
@from int = $__unixEpochFrom(),
|
||||
@to int = $__unixEpochTo()
|
||||
|
||||
EXEC dbo.sp_test_epoch @from, @to
|
||||
```
|
||||
|
||||
#### Stored procedure using time in datetime format
|
||||
|
||||
We can define a stored procedure that will return all data we need to render 4 series in a graph panel like above.
|
||||
In this case the stored procedure accepts two parameters `@from` and `@to` of `datetime` data types which should be a timerange (from-to)
|
||||
which will be used to filter the data to return from the stored procedure.
|
||||
|
||||
We're mimicking the `$__timeGroup(time, '5m')` in the select and group by expressions and that's why there's a lot of lengthy expressions needed -
|
||||
these could be extracted to MSSQL functions, if wanted.
|
||||
|
||||
```sql
|
||||
CREATE PROCEDURE sp_test_datetime(
|
||||
@from datetime,
|
||||
@to datetime
|
||||
) AS
|
||||
BEGIN
|
||||
SELECT
|
||||
cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int) as time,
|
||||
measurement + ' - value one' as metric,
|
||||
avg(valueOne) as value
|
||||
FROM
|
||||
metric_values
|
||||
WHERE
|
||||
time >= @from AND time <= @to
|
||||
GROUP BY
|
||||
cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int),
|
||||
measurement
|
||||
UNION ALL
|
||||
SELECT
|
||||
cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int) as time,
|
||||
measurement + ' - value two' as metric,
|
||||
avg(valueTwo) as value
|
||||
FROM
|
||||
metric_values
|
||||
WHERE
|
||||
time >= @from AND time <= @to
|
||||
GROUP BY
|
||||
cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int),
|
||||
measurement
|
||||
ORDER BY 1
|
||||
END
|
||||
|
||||
```
|
||||
|
||||
Then we can use the following query for our graph panel.
|
||||
|
||||
```sql
|
||||
DECLARE
|
||||
@from datetime = $__timeFrom(),
|
||||
@to datetime = $__timeTo()
|
||||
|
||||
EXEC dbo.sp_test_datetime @from, @to
|
||||
```
|
||||
|
||||
## Alerting
|
||||
|
||||
Time series queries should work in alerting conditions. Table formatted queries are not yet supported in alert rule
|
||||
conditions.
|
||||
|
||||
## Configure the Datasource with Provisioning
|
||||
|
||||
It's now possible to configure datasources using config files with Grafana's provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
|
||||
Here are some provisioning examples for this datasource.
|
||||
|
||||
```yaml
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: MSSQL
|
||||
type: mssql
|
||||
url: localhost:1433
|
||||
database: grafana
|
||||
user: grafana
|
||||
secureJsonData:
|
||||
password: "Password!"
|
||||
|
||||
```
|
||||
@@ -12,6 +12,8 @@ weight = 7
|
||||
# Using MySQL in Grafana
|
||||
|
||||
> Only available in Grafana v4.3+.
|
||||
>
|
||||
> Starting from Grafana v5.1 you can name the time column *time* in addition to earlier supported *time_sec*. Usage of *time_sec* will eventually be deprecated.
|
||||
|
||||
Grafana ships with a built-in MySQL data source plugin that allow you to query any visualize
|
||||
data from a MySQL compatible database.
|
||||
@@ -23,6 +25,17 @@ data from a MySQL compatible database.
|
||||
3. Click the `+ Add data source` button in the top header.
|
||||
4. Select *MySQL* from the *Type* dropdown.
|
||||
|
||||
### Data source options
|
||||
|
||||
Name | Description
|
||||
------------ | -------------
|
||||
*Name* | The data source name. This is how you refer to the data source in panels & queries.
|
||||
*Default* | Default data source means that it will be pre-selected for new panels.
|
||||
*Host* | The IP address/hostname and optional port of your MySQL instance.
|
||||
*Database* | Name of your MySQL database.
|
||||
*User* | Database user's login/username
|
||||
*Password* | Database user's password
|
||||
|
||||
### Database User Permissions (Important!)
|
||||
|
||||
The database user you specify when you add the data source should only be granted SELECT permissions on
|
||||
@@ -46,10 +59,12 @@ To simplify syntax and to allow for dynamic parts, like date range filters, the
|
||||
Macro example | Description
|
||||
------------ | -------------
|
||||
*$__time(dateColumn)* | Will be replaced by an expression to convert to a UNIX timestamp and rename the column to `time_sec`. For example, *UNIX_TIMESTAMP(dateColumn) as time_sec*
|
||||
*$__timeEpoch(dateColumn)* | Will be replaced by an expression to convert to a UNIX timestamp and rename the column to `time_sec`. For example, *UNIX_TIMESTAMP(dateColumn) as time_sec*
|
||||
*$__timeFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name. For example, *dateColumn > FROM_UNIXTIME(1494410783) AND dateColumn < FROM_UNIXTIME(1494497183)*
|
||||
*$__timeFrom()* | Will be replaced by the start of the currently active time selection. For example, *FROM_UNIXTIME(1494410783)*
|
||||
*$__timeTo()* | Will be replaced by the end of the currently active time selection. For example, *FROM_UNIXTIME(1494497183)*
|
||||
*$__timeGroup(dateColumn,'5m')* | Will be replaced by an expression usable in GROUP BY clause. For example, *cast(cast(UNIX_TIMESTAMP(dateColumn)/(300) as signed)*300 as signed) as time_sec,*
|
||||
*$__timeGroup(dateColumn,'5m')* | Will be replaced by an expression usable in GROUP BY clause. For example, *cast(cast(UNIX_TIMESTAMP(dateColumn)/(300) as signed)*300 as signed),*
|
||||
*$__timeGroup(dateColumn,'5m',0)* | Same as above but with a fill parameter so all null values will be converted to the fill value (all null values would be set to zero using this example).
|
||||
*$__unixEpochFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name with times represented as unix timestamp. For example, *dateColumn > 1494410783 AND dateColumn < 1494497183*
|
||||
*$__unixEpochFrom()* | Will be replaced by the start of the currently active time selection as unix timestamp. For example, *1494410783*
|
||||
*$__unixEpochTo()* | Will be replaced by the end of the currently active time selection as unix timestamp. For example, *1494497183*
|
||||
@@ -84,39 +99,50 @@ The resulting table panel:
|
||||
|
||||

|
||||
|
||||
### Time series queries
|
||||
## Time series queries
|
||||
|
||||
If you set `Format as` to `Time series`, for use in Graph panel for example, then there are some requirements for
|
||||
what your query returns.
|
||||
If you set `Format as` to `Time series`, for use in Graph panel for example, then the query must return a column named `time` that returns either a sql datetime or any numeric datatype representing unix epoch.
|
||||
Any column except `time` and `metric` is treated as a value column.
|
||||
You may return a column named `metric` that is used as metric name for the value column.
|
||||
|
||||
- Must be a column named `time_sec` representing a unix epoch in seconds.
|
||||
- Must be a column named `value` representing the time series value.
|
||||
- Must be a column named `metric` representing the time series name.
|
||||
|
||||
Example:
|
||||
**Example with `metric` column:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
min(UNIX_TIMESTAMP(time_date_time)) as time_sec,
|
||||
max(value_double) as value,
|
||||
metric1 as metric
|
||||
FROM test_data
|
||||
WHERE $__timeFilter(time_date_time)
|
||||
GROUP BY metric1, UNIX_TIMESTAMP(time_date_time) DIV 300
|
||||
ORDER BY time_sec asc
|
||||
```
|
||||
|
||||
Example with $__timeGroup macro:
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
$__timeGroup(time_date_time,'5m') as time_sec,
|
||||
min(value_double) as value,
|
||||
metric_name as metric
|
||||
$__timeGroup(time_date_time,'5m'),
|
||||
min(value_double),
|
||||
'min' as metric
|
||||
FROM test_data
|
||||
WHERE $__timeFilter(time_date_time)
|
||||
GROUP BY 1, metric_name
|
||||
ORDER BY 1
|
||||
GROUP BY time
|
||||
ORDER BY time
|
||||
```
|
||||
|
||||
**Example using the fill parameter in the $__timeGroup macro to convert null values to be zero instead:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
$__timeGroup(createdAt,'5m',0),
|
||||
sum(value_double) as value,
|
||||
measurement
|
||||
FROM test_data
|
||||
WHERE
|
||||
$__timeFilter(createdAt)
|
||||
GROUP BY time, measurement
|
||||
ORDER BY time
|
||||
```
|
||||
|
||||
**Example with multiple columns:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
$__timeGroup(time_date_time,'5m'),
|
||||
min(value_double) as min_value,
|
||||
max(value_double) as max_value
|
||||
FROM test_data
|
||||
WHERE $__timeFilter(time_date_time)
|
||||
GROUP BY time
|
||||
ORDER BY time
|
||||
```
|
||||
|
||||
Currently, there is no support for a dynamic group by time based on time range & panel width.
|
||||
@@ -180,7 +206,7 @@ There are two syntaxes:
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
UNIX_TIMESTAMP(atimestamp) as time_sec,
|
||||
UNIX_TIMESTAMP(atimestamp) as time,
|
||||
aint as value,
|
||||
avarchar as metric
|
||||
FROM my_table
|
||||
@@ -192,7 +218,7 @@ ORDER BY atimestamp ASC
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
UNIX_TIMESTAMP(atimestamp) as time_sec,
|
||||
UNIX_TIMESTAMP(atimestamp) as time,
|
||||
aint as value,
|
||||
avarchar as metric
|
||||
FROM my_table
|
||||
@@ -200,25 +226,47 @@ WHERE $__timeFilter(atimestamp) and hostname in([[hostname]])
|
||||
ORDER BY atimestamp ASC
|
||||
```
|
||||
|
||||
#### Disabling Quoting for Multi-value Variables
|
||||
|
||||
Grafana automatically creates a quoted, comma-separated string for multi-value variables. For example: if `server01` and `server02` are selected then it will be formatted as: `'server01', 'server02'`. Do disable quoting, use the csv formatting option for variables:
|
||||
|
||||
`${servers:csv}`
|
||||
|
||||
Read more about variable formatting options in the [Variables]({{< relref "reference/templating.md#advanced-formatting-options" >}}) documentation.
|
||||
|
||||
## Annotations
|
||||
|
||||
[Annotations]({{< relref "reference/annotations.md" >}}) allows you to overlay rich event information on top of graphs. You add annotation queries via the Dashboard menu / Annotations view.
|
||||
[Annotations]({{< relref "reference/annotations.md" >}}) allow you to overlay rich event information on top of graphs. You add annotation queries via the Dashboard menu / Annotations view.
|
||||
|
||||
An example query:
|
||||
**Example query using time column with epoch values:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
UNIX_TIMESTAMP(atimestamp) as time_sec,
|
||||
value as text,
|
||||
epoch_time as time,
|
||||
metric1 as text,
|
||||
CONCAT(tag1, ',', tag2) as tags
|
||||
FROM my_table
|
||||
WHERE $__timeFilter(atimestamp)
|
||||
ORDER BY atimestamp ASC
|
||||
FROM
|
||||
public.test_data
|
||||
WHERE
|
||||
$__unixEpochFilter(epoch_time)
|
||||
```
|
||||
|
||||
**Example query using time column of native sql date/time data type:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
native_date_time as time,
|
||||
metric1 as text,
|
||||
CONCAT(tag1, ',', tag2) as tags
|
||||
FROM
|
||||
public.test_data
|
||||
WHERE
|
||||
$__timeFilter(native_date_time)
|
||||
```
|
||||
|
||||
Name | Description
|
||||
------------ | -------------
|
||||
time_sec | The name of the date/time field.
|
||||
time | The name of the date/time field. Could be a column with a native sql date/time data type or epoch value.
|
||||
text | Event description field.
|
||||
tags | Optional field name to use for event tags as a comma separated string.
|
||||
|
||||
@@ -226,9 +274,9 @@ tags | Optional field name to use for event tags as a comma separated string.
|
||||
|
||||
Time series queries should work in alerting conditions. Table formatted queries is not yet supported in alert rule conditions.
|
||||
|
||||
## Configure datasource with provisioning
|
||||
## Configure the Datasource with Provisioning
|
||||
|
||||
It's now possible to configure datasources using config files with Grafanas provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
It's now possible to configure datasources using config files with Grafana's provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
|
||||
Here are some provisioning examples for this datasource.
|
||||
|
||||
@@ -242,4 +290,4 @@ datasources:
|
||||
database: grafana
|
||||
user: grafana
|
||||
password: password
|
||||
```
|
||||
```
|
||||
|
||||
@@ -28,11 +28,10 @@ Name | Description
|
||||
*Name* | The data source name. This is how you refer to the data source in panels & queries.
|
||||
*Default* | Default data source means that it will be pre-selected for new panels.
|
||||
*Url* | The http protocol, ip and port of you opentsdb server (default port is usually 4242)
|
||||
*Access* | Proxy = access via Grafana backend, Direct = access directly from browser.
|
||||
*Access* | Server (default) = URL needs to be accessible from the Grafana backend/server, Browser = URL needs to be accessible from the browser.
|
||||
*Version* | Version = opentsdb version, either <=2.1 or 2.2
|
||||
*Resolution* | Metrics from opentsdb may have datapoints with either second or millisecond resolution.
|
||||
|
||||
|
||||
## Query editor
|
||||
|
||||
Open a graph in edit mode by click the title. Query editor will differ if the datasource has version <=2.1 or = 2.2.
|
||||
@@ -89,9 +88,9 @@ Query | Description
|
||||
|
||||
For details on OpenTSDB metric queries checkout the official [OpenTSDB documentation](http://opentsdb.net/docs/build/html/index.html)
|
||||
|
||||
## Configure datasource with provisioning
|
||||
## Configure the Datasource with Provisioning
|
||||
|
||||
It's now possible to configure datasources using config files with Grafanas provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
It's now possible to configure datasources using config files with Grafana's provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
|
||||
Here are some provisioning examples for this datasource.
|
||||
|
||||
|
||||
@@ -20,6 +20,18 @@ Grafana ships with a built-in PostgreSQL data source plugin that allows you to q
|
||||
3. Click the `+ Add data source` button in the top header.
|
||||
4. Select *PostgreSQL* from the *Type* dropdown.
|
||||
|
||||
### Data source options
|
||||
|
||||
Name | Description
|
||||
------------ | -------------
|
||||
*Name* | The data source name. This is how you refer to the data source in panels & queries.
|
||||
*Default* | Default data source means that it will be pre-selected for new panels.
|
||||
*Host* | The IP address/hostname and optional port of your PostgreSQL instance.
|
||||
*Database* | Name of your PostgreSQL database.
|
||||
*User* | Database user's login/username
|
||||
*Password* | Database user's password
|
||||
*SSL Mode* | This option determines whether or with what priority a secure SSL TCP/IP connection will be negotiated with the server.
|
||||
|
||||
### Database User Permissions (Important!)
|
||||
|
||||
The database user you specify when you add the data source should only be granted SELECT permissions on
|
||||
@@ -45,11 +57,12 @@ Macro example | Description
|
||||
------------ | -------------
|
||||
*$__time(dateColumn)* | Will be replaced by an expression to rename the column to `time`. For example, *dateColumn as time*
|
||||
*$__timeSec(dateColumn)* | Will be replaced by an expression to rename the column to `time` and converting the value to unix timestamp. For example, *extract(epoch from dateColumn) as time*
|
||||
*$__timeFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name. For example, *extract(epoch from dateColumn) BETWEEN 1494410783 AND 1494497183*
|
||||
*$__timeFrom()* | Will be replaced by the start of the currently active time selection. For example, *to_timestamp(1494410783)*
|
||||
*$__timeTo()* | Will be replaced by the end of the currently active time selection. For example, *to_timestamp(1494497183)*
|
||||
*$__timeFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name. For example, *dateColumn BETWEEN '2017-04-21T05:01:17Z' AND '2017-04-21T05:06:17Z'*
|
||||
*$__timeFrom()* | Will be replaced by the start of the currently active time selection. For example, *'2017-04-21T05:01:17Z'*
|
||||
*$__timeTo()* | Will be replaced by the end of the currently active time selection. For example, *'2017-04-21T05:06:17Z'*
|
||||
*$__timeGroup(dateColumn,'5m')* | Will be replaced by an expression usable in GROUP BY clause. For example, *(extract(epoch from dateColumn)/300)::bigint*300 AS time*
|
||||
*$__unixEpochFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name with times represented as unix timestamp. For example, *dateColumn > 1494410783 AND dateColumn < 1494497183*
|
||||
*$__timeGroup(dateColumn,'5m', 0)* | Same as above but with a fill parameter so all null values will be converted to the fill value (all null values would be set to zero using this example).
|
||||
*$__unixEpochFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name with times represented as unix timestamp. For example, *dateColumn >= 1494410783 AND dateColumn <= 1494497183*
|
||||
*$__unixEpochFrom()* | Will be replaced by the start of the currently active time selection as unix timestamp. For example, *1494410783*
|
||||
*$__unixEpochTo()* | Will be replaced by the end of the currently active time selection as unix timestamp. For example, *1494497183*
|
||||
|
||||
@@ -82,36 +95,50 @@ You can control the name of the Table panel columns by using regular `as ` SQL c
|
||||
|
||||
The resulting table panel:
|
||||
|
||||

|
||||

|
||||
|
||||
### Time series queries
|
||||
## Time series queries
|
||||
|
||||
If you set `Format as` to `Time series`, for use in Graph panel for example, then the query must return a column named `time` that returns either a sql datetime or any numeric datatype representing unix epoch in seconds.
|
||||
If you set `Format as` to `Time series`, for use in Graph panel for example, then the query must return a column named `time` that returns either a sql datetime or any numeric datatype representing unix epoch.
|
||||
Any column except `time` and `metric` is treated as a value column.
|
||||
You may return a column named `metric` that is used as metric name for the value column.
|
||||
|
||||
Example with `metric` column
|
||||
**Example with `metric` column:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
$__timeGroup(time_date_time,'5m'),
|
||||
min(value_double),
|
||||
$__timeGroup("time_date_time",'5m'),
|
||||
min("value_double"),
|
||||
'min' as metric
|
||||
FROM test_data
|
||||
WHERE $__timeFilter(time_date_time)
|
||||
WHERE $__timeFilter("time_date_time")
|
||||
GROUP BY time
|
||||
ORDER BY time
|
||||
```
|
||||
|
||||
Example with multiple columns:
|
||||
**Example using the fill parameter in the $__timeGroup macro to convert null values to be zero instead:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
$__timeGroup(time_date_time,'5m'),
|
||||
min(value_double) as min_value,
|
||||
max(value_double) as max_value
|
||||
$__timeGroup("createdAt",'5m',0),
|
||||
sum(value) as value,
|
||||
measurement
|
||||
FROM test_data
|
||||
WHERE $__timeFilter(time_date_time)
|
||||
WHERE
|
||||
$__timeFilter("createdAt")
|
||||
GROUP BY time, measurement
|
||||
ORDER BY time
|
||||
```
|
||||
|
||||
**Example with multiple columns:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
$__timeGroup("time_date_time",'5m'),
|
||||
min("value_double") as "min_value",
|
||||
max("value_double") as "max_value"
|
||||
FROM test_data
|
||||
WHERE $__timeFilter("time_date_time")
|
||||
GROUP BY time
|
||||
ORDER BY time
|
||||
```
|
||||
@@ -190,26 +217,47 @@ WHERE $__timeFilter(atimestamp) and hostname in([[hostname]])
|
||||
ORDER BY atimestamp ASC
|
||||
```
|
||||
|
||||
#### Disabling Quoting for Multi-value Variables
|
||||
|
||||
Grafana automatically creates a quoted, comma-separated string for multi-value variables. For example: if `server01` and `server02` are selected then it will be formatted as: `'server01', 'server02'`. Do disable quoting, use the csv formatting option for variables:
|
||||
|
||||
`${servers:csv}`
|
||||
|
||||
Read more about variable formatting options in the [Variables]({{< relref "reference/templating.md#advanced-formatting-options" >}}) documentation.
|
||||
|
||||
## Annotations
|
||||
|
||||
[Annotations]({{< relref "reference/annotations.md" >}}) allow you to overlay rich event information on top of graphs. You add annotation queries via the Dashboard menu / Annotations view.
|
||||
|
||||
An example query:
|
||||
**Example query using time column with epoch values:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
extract(epoch from time_date_time) AS time,
|
||||
metric1 as text,
|
||||
epoch_time as time,
|
||||
metric1 as text,
|
||||
concat_ws(', ', metric1::text, metric2::text) as tags
|
||||
FROM
|
||||
public.test_data
|
||||
WHERE
|
||||
$__timeFilter(time_date_time)
|
||||
$__unixEpochFilter(epoch_time)
|
||||
```
|
||||
|
||||
**Example query using time column of native sql date/time data type:**
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
native_date_time as time,
|
||||
metric1 as text,
|
||||
concat_ws(', ', metric1::text, metric2::text) as tags
|
||||
FROM
|
||||
public.test_data
|
||||
WHERE
|
||||
$__timeFilter(native_date_time)
|
||||
```
|
||||
|
||||
Name | Description
|
||||
------------ | -------------
|
||||
time | The name of the date/time field.
|
||||
time | The name of the date/time field. Could be a column with a native sql date/time data type or epoch value.
|
||||
text | Event description field.
|
||||
tags | Optional field name to use for event tags as a comma separated string.
|
||||
|
||||
@@ -218,9 +266,9 @@ tags | Optional field name to use for event tags as a comma separated string.
|
||||
Time series queries should work in alerting conditions. Table formatted queries is not yet supported in alert rule
|
||||
conditions.
|
||||
|
||||
## Configure datasource with provisioning
|
||||
## Configure the Datasource with Provisioning
|
||||
|
||||
It's now possible to configure datasources using config files with Grafanas provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
It's now possible to configure datasources using config files with Grafana's provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
|
||||
Here are some provisioning examples for this datasource.
|
||||
|
||||
@@ -237,5 +285,4 @@ datasources:
|
||||
password: "Password!"
|
||||
jsonData:
|
||||
sslmode: "disable" # disable/require/verify-ca/verify-full
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
@@ -30,7 +30,7 @@ Name | Description
|
||||
*Name* | The data source name. This is how you refer to the data source in panels & queries.
|
||||
*Default* | Default data source means that it will be pre-selected for new panels.
|
||||
*Url* | The http protocol, ip and port of you Prometheus server (default port is usually 9090)
|
||||
*Access* | Proxy = access via Grafana backend, Direct = access directly from browser.
|
||||
*Access* | Server (default) = URL needs to be accessible from the Grafana backend/server, Browser = URL needs to be accessible from the browser.
|
||||
*Basic Auth* | Enable basic authentication to the Prometheus data source.
|
||||
*User* | Name of your Prometheus user
|
||||
*Password* | Database user's password
|
||||
@@ -50,7 +50,7 @@ Name | Description
|
||||
*Min step* | Set a lower limit for the Prometheus step option. Step controls how big the jumps are when the Prometheus query engine performs range queries. Sadly there is no official prometheus documentation to link to for this very important option.
|
||||
*Resolution* | Controls the step option. Small steps create high-resolution graphs but can be slow over larger time ranges, lowering the resolution can speed things up. `1/2` will try to set step option to generate 1 data point for every other pixel. A value of `1/10` will try to set step option so there is a data point every 10 pixels.
|
||||
*Metric lookup* | Search for metric names in this input field.
|
||||
*Format as* | **(New in v4.3)** Switch between Table & Time series. Table format will only work in the Table panel.
|
||||
*Format as* | Switch between Table, Time series or Heatmap. Table format will only work in the Table panel. Heatmap format is suitable for displaying metrics having histogram type on Heatmap panel. Under the hood, it converts cumulative histogram to regular and sorts series by the bucket bound.
|
||||
|
||||
## Templating
|
||||
|
||||
@@ -101,9 +101,9 @@ The step option is useful to limit the number of events returned from your query
|
||||
|
||||
Since 4.6.0 Grafana exposes metrics for Prometheus on the `/metrics` endpoint. We also bundle a dashboard within Grafana so you can get started viewing your metrics faster. You can import the bundled dashboard by going to the data source edit page and click the dashboard tab. There you can find a dashboard for Grafana and one for Prometheus. Import and start viewing all the metrics!
|
||||
|
||||
## Configure datasource with provisioning
|
||||
## Configure the Datasource with Provisioning
|
||||
|
||||
It's now possible to configure datasources using config files with Grafanas provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
It's now possible to configure datasources using config files with Grafana's provisioning system. You can read more about how it works and all the settings you can set for datasources on the [provisioning docs page](/administration/provisioning/#datasources)
|
||||
|
||||
Here are some provisioning examples for this datasource.
|
||||
|
||||
@@ -115,4 +115,4 @@ datasources:
|
||||
type: prometheus
|
||||
access: proxy
|
||||
url: http://localhost:9090
|
||||
```
|
||||
```
|
||||
|
||||
@@ -22,15 +22,18 @@ options for the panel.
|
||||
|
||||
## General
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v43/graph_general.png" max-width= "900px" >}}
|
||||
{{< docs-imagebox img="/img/docs/v51/graph_general.png" max-width= "800px" >}}
|
||||
|
||||
The general tab allows customization of a panel's appearance and menu options.
|
||||
|
||||
### General Options
|
||||
### Info
|
||||
|
||||
- **Title** - The panel title on the dashboard
|
||||
- **Span** - The panel width in columns
|
||||
- **Height** - The panel contents height in pixels
|
||||
- **Title** - The panel title of the dashboard, displayed at the top.
|
||||
- **Description** - The panel description, displayed on hover of info icon in the upper left corner of the panel.
|
||||
- **Transparent** - If checked, removes the solid background of the panel (default not checked).
|
||||
|
||||
### Repeat
|
||||
Repeat a panel for each value of a variable. Repeating panels are described in more detail [here]({{< relref "reference/templating.md#repeating-panels" >}}).
|
||||
|
||||
### Drilldown / detail link
|
||||
|
||||
@@ -54,47 +57,65 @@ options.
|
||||
|
||||
## Axes
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v43/graph_axes_grid_options.png" max-width= "900px" >}}
|
||||
{{< docs-imagebox img="/img/docs/v51/graph_axes_grid_options.png" max-width= "800px" >}}
|
||||
|
||||
The Axes tab controls the display of axes, grids and legend. The **Left Y** and **Right Y** can be customized using:
|
||||
The Axes tab controls the display of axes.
|
||||
|
||||
### Left Y/Right Y
|
||||
|
||||
The **Left Y** and **Right Y** can be customized using:
|
||||
|
||||
- **Unit** - The display unit for the Y value
|
||||
- **Scale** -
|
||||
- **Scale** - The scale to use for the Y value, linear or logarithmic. (default linear)
|
||||
- **Y-Min** - The minimum Y value. (default auto)
|
||||
- **Y-Max** - The maximum Y value. (default auto)
|
||||
- **Decimals** - Controls how many decimals are displayed for Y value (default auto)
|
||||
- **Label** - The Y axis label (default "")
|
||||
|
||||
Axes can also be hidden by unchecking the appropriate box from **Show**.
|
||||
|
||||
### X-Axis Mode
|
||||
### X-Axis
|
||||
|
||||
There are three options:
|
||||
Axis can be hidden by unchecking **Show**.
|
||||
|
||||
For **Mode** there are three options:
|
||||
|
||||
- The default option is **Time** and means the x-axis represents time and that the data is grouped by time (for example, by hour or by minute).
|
||||
|
||||
- The **Series** option means that the data is grouped by series and not by time. The y-axis still represents the value.
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v45/graph-x-axis-mode-series.png" max-width="700px">}}
|
||||
{{< docs-imagebox img="/img/docs/v51/graph-x-axis-mode-series.png" max-width="800px">}}
|
||||
|
||||
- The **Histogram** option converts the graph into a histogram. A Histogram is a kind of bar chart that groups numbers into ranges, often called buckets or bins. Taller bars show that more data falls in that range. Histograms and buckets are described in more detail [here](http://docs.grafana.org/features/panels/heatmap/#histograms-and-buckets).
|
||||
|
||||
<img src="/img/docs/v43/heatmap_histogram.png" class="no-shadow">
|
||||
|
||||
### Legend
|
||||
|
||||
The legend hand be hidden by checking the **Show** checkbox. If it's shown, it can be
|
||||
displayed as a table of values by checking the **Table** checkbox. Series with no
|
||||
values can be hidden from the legend using the **Hide empty** checkbox.
|
||||
### Y-Axes
|
||||
|
||||
### Legend Values
|
||||
- **Align** - Check to align left and right Y-axes by value (default unchecked/false)
|
||||
- **Level** - Available when *Align* is checked. Value to use for alignment of left and right Y-axes, starting from Y=0 (default 0)
|
||||
|
||||
## Legend
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/graph-legend.png" max-width= "800px" >}}
|
||||
|
||||
### Options
|
||||
|
||||
- **Show** - Uncheck to hide the legend (default checked/true)
|
||||
- **Table** - Check to display legend in table (default unchecked/false)
|
||||
- **To the right** - Check to display legend to the right (default unchecked/false)
|
||||
- **Width** - Available when *To the right* is checked. Value to control the minimum width for the legend (default 0)
|
||||
|
||||
### Values
|
||||
|
||||
Additional values can be shown along-side the legend names:
|
||||
|
||||
- **Total** - Sum of all values returned from metric query
|
||||
- **Current** - Last value returned from the metric query
|
||||
- **Min** - Minimum of all values returned from metric query
|
||||
- **Max** - Maximum of all values returned from the metric query
|
||||
- **Avg** - Average of all values returned from metric query
|
||||
- **Current** - Last value returned from the metric query
|
||||
- **Total** - Sum of all values returned from metric query
|
||||
- **Decimals** - Controls how many decimals are displayed for legend values (and graph hover tooltips)
|
||||
|
||||
The legend values are calculated client side by Grafana and depend on what type of
|
||||
@@ -103,63 +124,72 @@ be correct at the same time. For example if you plot a rate like requests/second
|
||||
using average as aggregator, then the Total in the legend will not represent the total number of requests.
|
||||
It is just the sum of all data points received by Grafana.
|
||||
|
||||
### Hide series
|
||||
|
||||
Hide series when all values of a series from a metric query are of a specific value:
|
||||
|
||||
- **With only nulls** - Value=*null* (default unchecked)
|
||||
- **With only zeros** - Value=*zero* (default unchecked)
|
||||
|
||||
## Display styles
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v43/graph_display_styles.png" max-width= "900px" >}}
|
||||
{{< docs-imagebox img="/img/docs/v51/graph_display_styles.png" max-width= "800px" >}}
|
||||
|
||||
Display styles control visual properties of the graph.
|
||||
|
||||
### Thresholds
|
||||
### Draw Options
|
||||
|
||||
Thresholds allow you to add arbitrary lines or sections to the graph to make it easier to see when
|
||||
the graph crosses a particular threshold.
|
||||
|
||||
|
||||
### Chart Options
|
||||
#### Draw Modes
|
||||
|
||||
- **Bar** - Display values as a bar chart
|
||||
- **Lines** - Display values as a line graph
|
||||
- **Points** - Display points for values
|
||||
|
||||
### Line Options
|
||||
#### Mode Options
|
||||
|
||||
- **Line Fill** - Amount of color fill for a series. 0 is none.
|
||||
- **Line Width** - The width of the line for a series.
|
||||
- **Null point mode** - How null values are displayed
|
||||
- **Staircase line** - Draws adjacent points as staircase
|
||||
- **Fill** - Amount of color fill for a series (default 1). 0 is none.
|
||||
- **Line Width** - The width of the line for a series (default 1).
|
||||
- **Staircase** - Draws adjacent points as staircase
|
||||
- **Points Radius** - Adjust the size of points when *Points* are selected as *Draw Mode*.
|
||||
|
||||
### Multiple Series
|
||||
#### Hover tooltip
|
||||
|
||||
- **Mode** - Controls how many series to display in the tooltip when hover over a point in time, All series or single (default All series).
|
||||
- **Sort order** - Controls how series displayed in tooltip are sorted, None, Ascending or Descending (default None).
|
||||
- **Stacked value** - Available when *Stack* are checked and controls how stacked values are displayed in tooltip (default Individual).
|
||||
- Individual: the value for the series you hover over
|
||||
- Cumulative - sum of series below plus the series you hover over
|
||||
|
||||
#### Stacking & Null value
|
||||
|
||||
If there are multiple series, they can be displayed as a group.
|
||||
|
||||
- **Stack** - Each series is stacked on top of another
|
||||
- **Percent** - Each series is drawn as a percentage of the total of all series
|
||||
- **Percent** - Available when *Stack* are checked. Each series is drawn as a percentage of the total of all series
|
||||
- **Null value** - How null values are displayed
|
||||
|
||||
If you have stack enabled, you can select what the mouse hover feature should show.
|
||||
### Series overrides
|
||||
|
||||
- Cumulative - Sum of series below plus the series you hover over
|
||||
- Individual - Just the value for the series you hover over
|
||||
|
||||
### Rendering
|
||||
|
||||
- **Flot** - Render the graphs in the browser using Flot (default)
|
||||
- **Graphite PNG** - Render the graph on the server using graphite's render API.
|
||||
|
||||
### Tooltip
|
||||
|
||||
- **All series** - Show all series on the same tooltip and a x crosshairs to help follow all series
|
||||
|
||||
### Series Specific Overrides
|
||||
{{< docs-imagebox img="/img/docs/v51/graph_display_overrides.png" max-width= "800px" >}}
|
||||
|
||||
The section allows a series to be rendered differently from the others. For example, one series can be given
|
||||
a thicker line width to make it stand out.
|
||||
a thicker line width to make it stand out and/or be moved to the right Y-axis.
|
||||
|
||||
#### Dashes Drawing Style
|
||||
|
||||
There is an option under Series overrides to draw lines as dashes. Set Dashes to the value True to override the line draw setting for a specific series.
|
||||
|
||||
### Thresholds
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/graph_display_thresholds.png" max-width= "800px" >}}
|
||||
|
||||
Thresholds allow you to add arbitrary lines or sections to the graph to make it easier to see when
|
||||
the graph crosses a particular threshold.
|
||||
|
||||
## Time Range
|
||||
|
||||
The time range tab allows you to override the dashboard time range and specify a panel specific time. Either through a relative from now time option or through a timeshift.
|
||||
{{< docs-imagebox img="/img/docs/v51/graph-time-range.png" max-width= "900px" >}}
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v45/graph-time-range.png" max-width= "900px" >}}
|
||||
The time range tab allows you to override the dashboard time range and specify a panel specific time.
|
||||
Either through a relative from now time option or through a timeshift.
|
||||
Panel time overrides & timeshift are described in more detail [here]({{< relref "reference/timerange.md#panel-time-overrides-timeshift" >}}).
|
||||
|
||||
@@ -56,26 +56,39 @@ Data and bucket options can be found in the `Axes` tab.
|
||||
Data format | Description
|
||||
------------ | -------------
|
||||
*Time series* | Grafana does the bucketing by going through all time series values. The bucket sizes & intervals will be determined using the Buckets options.
|
||||
*Time series buckets* | Each time series already represents a Y-Axis bucket. The time series name (alias) needs to be a numeric value representing the upper interval for the bucket. Grafana does no bucketing so the bucket size options are hidden.
|
||||
*Time series buckets* | Each time series already represents a Y-Axis bucket. The time series name (alias) needs to be a numeric value representing the upper or lower interval for the bucket. Grafana does no bucketing so the bucket size options are hidden.
|
||||
|
||||
### Bucket bound
|
||||
|
||||
When Data format is *Time series buckets* datasource returns series with names representing bucket bound. But depending
|
||||
on datasource, a bound may be *upper* or *lower*. This option allows to adjust a bound type. If *Auto* is set, a bound
|
||||
option will be chosen based on panels' datasource type.
|
||||
|
||||
### Bucket Size
|
||||
|
||||
The Bucket count & size options are used by Grafana to calculate how big each cell in the heatmap is. You can
|
||||
define the bucket size either by count (the first input box) or by specifying a size interval. For the Y-Axis
|
||||
the size interval is just a value but for the X-bucket you can specify a time range in the *Size* input, for example,
|
||||
the time range `1h`. This will make the cells 1h wide on the X-axis.
|
||||
the time range `1h`. This will make the cells 1h wide on the X-axis.
|
||||
|
||||
### Pre-bucketed data
|
||||
|
||||
If you have a data that is already organized into buckets you can use the `Time series buckets` data format. This format requires that your metric query return regular time series and that each time series has a numeric name
|
||||
that represent the upper or lower bound of the interval.
|
||||
If you have a data that is already organized into buckets you can use the `Time series buckets` data format. This format
|
||||
requires that your metric query return regular time series and that each time series has a numeric name that represent
|
||||
the upper or lower bound of the interval.
|
||||
|
||||
The only data source that supports histograms over time is Elasticsearch. You do this by adding a *Histogram*
|
||||
bucket aggregation before the *Date Histogram*.
|
||||
There are a number of datasources supporting histogram over time like Elasticsearch (by using a Histogram bucket
|
||||
aggregation) or Prometheus (with [histogram](https://prometheus.io/docs/concepts/metric_types/#histogram) metric type
|
||||
and *Format as* option set to Heatmap). But generally, any datasource could be used if it meets the requirements:
|
||||
returns series with names representing bucket bound or returns sereis sorted by the bound in ascending order.
|
||||
|
||||

|
||||
With Elasticsearch you control the size of the buckets using the Histogram interval (Y-Axis) and the Date Histogram interval (X-axis).
|
||||
|
||||
You control the size of the buckets using the Histogram interval (Y-Axis) and the Date Histogram interval (X-axis).
|
||||

|
||||
|
||||
With Prometheus you can only control X-axis by adjusting *Min step* and *Resolution* options.
|
||||
|
||||

|
||||
|
||||
## Display Options
|
||||
|
||||
@@ -100,8 +113,8 @@ but include a group by time interval or maxDataPoints limit coupled with an aggr
|
||||
|
||||
This all depends on the time range of your query of course. But the important point is to know that the Histogram bucketing
|
||||
that Grafana performs may be done on already aggregated and averaged data. To get more accurate heatmaps it is better
|
||||
to do the bucketing during metric collection or store the data in Elasticsearch, which currently is the only data source
|
||||
data supports doing Histogram bucketing on the raw data.
|
||||
to do the bucketing during metric collection or store the data in Elasticsearch, or in the other data source which
|
||||
supports doing Histogram bucketing on the raw data.
|
||||
|
||||
If you remove or lower the group by time (or raise maxDataPoints) in your query to return more data points your heatmap will be
|
||||
more accurate but this can also be very CPU & Memory taxing for your browser and could cause hangs and crashes if the number of
|
||||
|
||||
@@ -77,11 +77,11 @@ Gauges gives a clear picture of how high a value is in it's context. It's a grea
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
### Value to text mapping
|
||||
### Value/Range to text mapping
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v45/singlestat-value-mapping.png" class="docs-image--right docs-image--no-shadow">}}
|
||||
|
||||
Value to text mapping allows you to translate the value of the summary stat into explicit text. The text will respect all styling, thresholds and customization defined for the value. This can be useful to translate the number of the main Singlestat value into a context-specific human-readable word or message.
|
||||
Value/Range to text mapping allows you to translate the value of the summary stat into explicit text. The text will respect all styling, thresholds and customization defined for the value. This can be useful to translate the number of the main Singlestat value into a context-specific human-readable word or message.
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
|
||||
@@ -14,11 +14,53 @@ weight = 2
|
||||
|
||||
<img class="screenshot" src="/assets/img/features/table-panel.png">
|
||||
|
||||
The new table panel is very flexible, supporting both multiple modes for time series as well as for
|
||||
The table panel is very flexible, supporting both multiple modes for time series as well as for
|
||||
table, annotation and raw JSON data. It also provides date formatting and value formatting and coloring options.
|
||||
|
||||
To view table panels in action and test different configurations with sample data, check out the [Table Panel Showcase in the Grafana Playground](http://play.grafana.org/dashboard/db/table-panel-showcase).
|
||||
|
||||
## Querying Data
|
||||
|
||||
The table panel displays the results of a query specified in the **Metrics** tab.
|
||||
The result being displayed depends on the datasource and the query, but generally there is one row per datapoint, with extra columns for associated keys and values, as well as one column for the numeric value of the datapoint.
|
||||
You can change the behavior in the section **Data to Table** below.
|
||||
|
||||
### Merge Multiple Queries per Table
|
||||
|
||||
> Only available in Grafana v5.0+.
|
||||
|
||||
Sometimes it is useful to display the results of multiple queries in the same table on corresponding rows, e.g., when comparing capacity and actual usage of resources.
|
||||
In this example usage and capacity are metrics that will have corresponding datapoints, while their associated keys and values can be used to match them.
|
||||
(This matching is only available with the **Table Transform** set to **Table**.)
|
||||
|
||||
In its simplest case, both queries return time-series data with a numeric value and a timestamp.
|
||||
If the timestamps are the same, datapoints will be matched and rendered on the same row.
|
||||
Some datasources return keys and values (labels, tags) associated with the datapoint.
|
||||
These are being matched as well if they are present in both results and have the same value.
|
||||
The following datapoints will end up on the same row with one time column, two label columns ("host" and "job") and two value columns:
|
||||
|
||||
```
|
||||
Datapoint for query A: {time: 1, host: "node-2", job: "job-8", value: 3}
|
||||
Datapoint for query B: {time: 1, host: "node-2", value: 4}
|
||||
```
|
||||
|
||||
The following two results cannot be matched and will be rendered on separate rows:
|
||||
|
||||
```
|
||||
Different time
|
||||
Datapoint for query A: {time: 1, host: "node-2", job: "job-8", value: 3}
|
||||
Datapoint for query B: {time: 2, host: "node-2", value: 4}
|
||||
|
||||
Different label "host"
|
||||
Datapoint for query A: {time: 1, host: "node-2", job: "job-8", value: 3}
|
||||
Datapoint for query B: {time: 1, host: "node-9", value: 4}
|
||||
```
|
||||
|
||||
You can still merge both of the above cases by changing the conflicting column's **Type** to **hidden** in the **Column Styles**.
|
||||
|
||||
Note that if each datapoint of your query results have multiple value fields like max, min, mean, etc., they will likely have different values and therefore will not match and render on separate rows.
|
||||
If you intend for rows to be merged but see them rendered on separate rows, check the query results in the **Query Inspector** for field values being identical across datapoints that should be merged into a row.
|
||||
|
||||
## Options overview
|
||||
|
||||
The table panel has many ways to manipulate your data for optimal presentation.
|
||||
@@ -97,3 +139,14 @@ The column styles allow you control how dates and numbers are formatted.
|
||||
4. **Thresholds and Coloring**: Specify color mode and thresholds limits.
|
||||
5. **Type**: The three supported types of types are **Number**, **String** and **Date**. **Unit** and **Decimals**: Specify unit and decimal precision for numbers. **Format**: Specify date format for dates.
|
||||
|
||||
|
||||
### String
|
||||
#### Value/Range to text mapping
|
||||
|
||||
> Only available in Grafana v5.1+.
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/table-value-mapping.png" class="docs-image--right docs-image--no-shadow">}}
|
||||
|
||||
Value/range to text mapping allows you to translate numeric values into explicit text. The text will respect all styling, thresholds and customization defined for the value. This can be useful to translate the numeric values into a context-specific human-readable word or message.
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
@@ -11,7 +11,7 @@ weight = 3
|
||||
+++
|
||||
|
||||
|
||||
## Whats new in Grafana v4.1
|
||||
## What's new in Grafana v4.1
|
||||
- **Graph**: Support for shared tooltip on all graphs as you hover over one graph. [#1578](https://github.com/grafana/grafana/pull/1578), [#6274](https://github.com/grafana/grafana/pull/6274)
|
||||
- **Victorops**: Add VictorOps notification integration [#6411](https://github.com/grafana/grafana/issues/6411), thx [@ichekrygin](https://github.com/ichekrygin)
|
||||
- **Opsgenie**: Add OpsGenie notification integratiion [#6687](https://github.com/grafana/grafana/issues/6687), thx [@kylemcc](https://github.com/kylemcc)
|
||||
@@ -24,7 +24,7 @@ weight = 3
|
||||
|
||||
{{< imgbox max-width="60%" img="/img/docs/v41/shared_tooltip.gif" caption="Shared tooltip" >}}
|
||||
|
||||
Showing the tooltip on all panels at the same time has been a long standing request in Grafana and we are really happy to finally be able to release it.
|
||||
Showing the tooltip on all panels at the same time has been a long standing request in Grafana and we are really happy to finally be able to release it.
|
||||
You can enable/disable the shared tooltip from the dashboard settings menu or cycle between default, shared tooltip and shared crosshair by pressing `CTRL + O` or `CMD + O`.
|
||||
|
||||
<div class="clearfix"></div>
|
||||
@@ -50,7 +50,7 @@ Panels with a help text available have a little indicator in the top left corner
|
||||
In Grafana 4.1.0 you can configure your Cloudwatch data source with `access key` and `secret key` directly in the data source configuration page.
|
||||
This enables people to use the Cloudwatch data source without having access to the filesystem where Grafana is running.
|
||||
|
||||
Once the `access key` and `secret key` have been saved the user will no longer be able to view them.
|
||||
Once the `access key` and `secret key` have been saved the user will no longer be able to view them.
|
||||
<div class="clearfix"></div>
|
||||
|
||||
## Upgrade & Breaking changes
|
||||
|
||||
@@ -10,7 +10,7 @@ parent = "whatsnew"
|
||||
weight = -1
|
||||
+++
|
||||
|
||||
## Whats new in Grafana v4.2
|
||||
## What's new in Grafana v4.2
|
||||
|
||||
Grafana v4.2 Beta is now [available for download](https://grafana.com/grafana/download/4.2.0).
|
||||
Just like the last release this one contains lots bug fixes and minor improvements.
|
||||
|
||||
@@ -64,7 +64,7 @@ This makes exploring and filtering Prometheus data much easier.
|
||||
* **Dataproxy**: Allow grafan to renegotiate tls connection [#9250](https://github.com/grafana/grafana/issues/9250)
|
||||
* **HTTP**: set net.Dialer.DualStack to true for all http clients [#9367](https://github.com/grafana/grafana/pull/9367)
|
||||
* **Alerting**: Add diff and percent diff as series reducers [#9386](https://github.com/grafana/grafana/pull/9386), thx [@shanhuhai5739](https://github.com/shanhuhai5739)
|
||||
* **Slack**: Allow images to be uploaded to slack when Token is precent [#7175](https://github.com/grafana/grafana/issues/7175), thx [@xginn8](https://github.com/xginn8)
|
||||
* **Slack**: Allow images to be uploaded to slack when Token is present [#7175](https://github.com/grafana/grafana/issues/7175), thx [@xginn8](https://github.com/xginn8)
|
||||
* **Opsgenie**: Use their latest API instead of old version [#9399](https://github.com/grafana/grafana/pull/9399), thx [@cglrkn](https://github.com/cglrkn)
|
||||
* **Table**: Add support for displaying the timestamp with milliseconds [#9429](https://github.com/grafana/grafana/pull/9429), thx [@s1061123](https://github.com/s1061123)
|
||||
* **Hipchat**: Add metrics, message and image to hipchat notifications [#9110](https://github.com/grafana/grafana/issues/9110), thx [@eloo](https://github.com/eloo)
|
||||
|
||||
125
docs/sources/guides/whats-new-in-v5-1.md
Normal file
125
docs/sources/guides/whats-new-in-v5-1.md
Normal file
@@ -0,0 +1,125 @@
|
||||
+++
|
||||
title = "What's New in Grafana v5.1"
|
||||
description = "Feature & improvement highlights for Grafana v5.1"
|
||||
keywords = ["grafana", "new", "documentation", "5.1"]
|
||||
type = "docs"
|
||||
[menu.docs]
|
||||
name = "Version 5.1"
|
||||
identifier = "v5.1"
|
||||
parent = "whatsnew"
|
||||
weight = -7
|
||||
+++
|
||||
|
||||
# What's New in Grafana v5.1
|
||||
|
||||
Grafana v5.1 brings new features, many enhancements and bug fixes. This article will detail the major new features and enhancements.
|
||||
|
||||
* [Improved scrolling experience]({{< relref "#improved-scrolling-experience" >}})
|
||||
* [Improved docker image]({{< relref "#improved-docker-image-breaking-change" >}}) with a breaking change!
|
||||
* [Heatmap support for Prometheus]({{< relref "#prometheus" >}})
|
||||
* [Microsoft SQL Server]({{< relref "#microsoft-sql-server" >}}) as metric & table datasource!
|
||||
* [Dashboards & Panels]({{< relref "#dashboards-panels" >}}) Improved adding panels to dashboards and enhancements to Graph and Table panels.
|
||||
* [New variable interpolation syntax]({{< relref "#new-variable-interpolation-syntax" >}})
|
||||
* [Improved workflow for provisioned dashboards]({{< relref "#improved-workflow-for-provisioned-dashboards" >}})
|
||||
|
||||
## Improved scrolling experience
|
||||
|
||||
In Grafana v5.0 we introduced a new scrollbar component. Unfortunately this introduced a lot of issues and in some scenarios removed
|
||||
the native scrolling functionality. Grafana v5.1 ships with a native scrollbar for all pages together with a scrollbar component for
|
||||
the dashboard grid and panels that's not overriding the native scrolling functionality. We hope that these changes and improvements should
|
||||
make the Grafana user experience much better!
|
||||
|
||||
## Improved docker image (breaking change)
|
||||
|
||||
Grafana v5.1 brings an improved official docker image which should make it easier to run and use the Grafana docker image and at the same time give more control to the user how to use/run it.
|
||||
|
||||
We've switched the id of the grafana user running Grafana inside a docker container. Unfortunately this means that files created prior to 5.1 won't have the correct permissions for later versions and thereby this introduces a breaking change.
|
||||
We made this change so that it would be easier for you to control what user Grafana is executed as (see examples below).
|
||||
|
||||
Version | User | User ID
|
||||
--------|---------|---------
|
||||
< 5.1 | grafana | 104
|
||||
>= 5.1 | grafana | 472
|
||||
|
||||
Please read the [updated documentation](/installation/docker/#migration-from-a-previous-version-of-the-docker-container-to-5-1-or-later) which includes migration instructions and more information.
|
||||
|
||||
## Prometheus
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/prometheus_heatmap.png" max-width="800px" class="docs-image--right" >}}
|
||||
|
||||
The Prometheus datasource now support transforming Prometheus histograms to the heatmap panel. Prometheus histogram is a powerful feature, and we're
|
||||
really happy to finally allow our users to render those as heatmaps. Please read [Heatmap panel documentation](/features/panels/heatmap/#pre-bucketed-data)
|
||||
for more information on how to use it.
|
||||
|
||||
Prometheus query editor also got support for autocomplete of template variables. More information in the [Prometheus data source documentation](/features/datasources/prometheus/).
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
## Microsoft SQL Server
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/mssql_query_editor_showcase.png" max-width= "800px" class="docs-image--right" >}}
|
||||
|
||||
Grafana v5.1 now ships with a built-in Microsoft SQL Server (MSSQL) data source plugin that allows you to query and visualize data from any
|
||||
Microsoft SQL Server 2005 or newer, including Microsoft Azure SQL Database. Do you have metric or log data in MSSQL? You can now visualize
|
||||
that data and define alert rules on it like with any of Grafana's other core datasources.
|
||||
|
||||
Please read [Using Microsoft SQL Server in Grafana documentation](/features/datasources/mssql/) for more detailed information on how to get started and use it.
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
## Dashboards & Panels
|
||||
|
||||
### Adding new panels to dashboards
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/dashboard_add_panel.png" max-width= "800px" class="docs-image--right" >}}
|
||||
|
||||
The control for adding new panels to dashboards have got some enhancements and now includes functionality to search for the type of panel
|
||||
you want to add. Further, the control has tabs separating functionality for adding new panels and pasting
|
||||
copied panels.
|
||||
|
||||
By copying a panel in a dashboard it will be displayed in the `Paste` tab in *any* dashboard and allows you to paste the
|
||||
copied panel into the current dashboard.
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/dashboard_panel_copy.png" max-width= "300px" >}}
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
### Graph Panel
|
||||
|
||||
New enhancements includes support for multiple series stacking in histogram mode, thresholds for right Y axis, aligning left and right Y-axes to one level and additional units. More information in the [Graph panel documentation](/features/panels/graph/).
|
||||
|
||||
### Table Panel
|
||||
|
||||
New enhancements includes support for mapping a numeric value/range to text and additional units. More information in the [Table panel documentation](/features/panels/table_panel/#string).
|
||||
|
||||
## New variable interpolation syntax
|
||||
|
||||
We now support a new option for rendering variables that gives the user full control of how the value(s) should be rendered.
|
||||
In the table below you can see some examples and you can find all different options in the [Variables documentation](http://docs.grafana.org/reference/templating/#advanced-formatting-options).
|
||||
|
||||
Filter Option | Example | Raw | Interpolated | Description
|
||||
------------ | ------------- | ------------- | ------------- | -------------
|
||||
`glob` | ${servers:glob} | `'test1', 'test2'` | `{test1,test2}` | Formats multi-value variable into a glob
|
||||
`regex` | ${servers:regex} | `'test.', 'test2'` | <code>(test\.|test2)</code> | Formats multi-value variable into a regex string
|
||||
`pipe` | ${servers:pipe} | `'test.', 'test2'` | <code>test.|test2</code> | Formats multi-value variable into a pipe-separated string
|
||||
`csv`| ${servers:csv} | `'test1', 'test2'` | `test1,test2` | Formats multi-value variable as a comma-separated string
|
||||
|
||||
## Improved workflow for provisioned dashboards
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v51/provisioning_cannot_save_dashboard.png" max-width="800px" class="docs-image--right" >}}
|
||||
|
||||
Grafana v5.1 brings an improved workflow for provisioned dashboards:
|
||||
|
||||
* A populated `id` property in JSON is now automatically removed when provisioning dashboards.
|
||||
* When making changes to a provisioned dashboard you can `Save` the dashboard which now will bring up a *Cannot save provisioned dashboard* dialog like seen in the screenshot to the right.
|
||||
|
||||
|
||||
Available options in the dialog will let you `Copy JSON to Clipboard` and/or `Save JSON to file` which can help you synchronize your dashboard changes back to the provisioning source.
|
||||
More information in the [Provisioning documentation](/administration/provisioning/).
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
## Changelog
|
||||
|
||||
Checkout the [CHANGELOG.md](https://github.com/grafana/grafana/blob/master/CHANGELOG.md) file for a complete list
|
||||
of new features, changes, and bug fixes.
|
||||
70
docs/sources/guides/whats-new-in-v5-2.md
Normal file
70
docs/sources/guides/whats-new-in-v5-2.md
Normal file
@@ -0,0 +1,70 @@
|
||||
+++
|
||||
title = "What's New in Grafana v5.2"
|
||||
description = "Feature & improvement highlights for Grafana v5.2"
|
||||
keywords = ["grafana", "new", "documentation", "5.2"]
|
||||
type = "docs"
|
||||
[menu.docs]
|
||||
name = "Version 5.2"
|
||||
identifier = "v5.2"
|
||||
parent = "whatsnew"
|
||||
weight = -8
|
||||
+++
|
||||
|
||||
# What's New in Grafana v5.2
|
||||
|
||||
Grafana v5.2 brings new features, many enhancements and bug fixes. This article will detail the major new features and enhancements.
|
||||
|
||||
* [Elasticsearch alerting]({{< relref "#elasticsearch-alerting" >}}) it's finally here!
|
||||
* [Cross platform build support]({{< relref "#cross-platform-build-support" >}}) enables native builds of Grafana for many more platforms!
|
||||
* [Improved Docker image]({{< relref "#improved-docker-image" >}}) with support for docker secrets
|
||||
* [Prometheus]({{< relref "#prometheus" >}}) with alignment enhancements
|
||||
* [Alerting]({{< relref "#alerting" >}}) with alert notification channel type for Discord
|
||||
* [Dashboards & Panels]({{< relref "#dashboards-panels" >}})
|
||||
|
||||
## Elasticsearch alerting
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v52/elasticsearch_alerting.png" max-width="800px" class="docs-image--right" >}}
|
||||
|
||||
Grafana v5.2 ships with an updated Elasticsearch datasource with support for alerting. Alerting support for Elasticsearch has been one of
|
||||
the most requested features by our community and now it's finally here. Please try it out and let us know what you think.
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
## Cross platform build support
|
||||
|
||||
Grafana v5.2 brings an improved build pipeline with cross platform support. This enables native builds of Grafana for ARMv7 (x32), ARM64 (x64),
|
||||
MacOS/Darwin (x64) and Windows (x64) in both stable and nightly builds.
|
||||
|
||||
We've been longing for native ARM build support for a long time. With the help from our amazing community this is now finally available.
|
||||
|
||||
## Improved Docker image
|
||||
|
||||
The Grafana docker image now includes support for Docker secrets which enables you to supply Grafana with configuration through files. More
|
||||
information in the [Installing using Docker documentation](/installation/docker/#reading-secrets-from-files-support-for-docker-secrets).
|
||||
|
||||
## Prometheus
|
||||
|
||||
The Prometheus datasource now aligns the start/end of the query sent to Prometheus with the step, which ensures PromQL expressions with *rate*
|
||||
functions get consistent results, and thus avoid graphs jumping around on reload.
|
||||
|
||||
## Alerting
|
||||
|
||||
By popular demand Grafana now includes support for an alert notification channel type for [Discord](https://discordapp.com/).
|
||||
|
||||
## Dashboards & Panels
|
||||
|
||||
### Modified time range and variables are no longer saved by default
|
||||
|
||||
{{< docs-imagebox img="/img/docs/v52/dashboard_save_modal.png" max-width="800px" class="docs-image--right" >}}
|
||||
|
||||
Starting from Grafana v5.2 a modified time range or variable are no longer saved by default. To save a modified
|
||||
time range or variable you'll need to actively select that when saving a dashboard, see screenshot.
|
||||
This should hopefully make it easier to have sane defaults of time and variables in dashboards and make it more explicit
|
||||
when you actually want to overwrite those settings.
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
## Changelog
|
||||
|
||||
Checkout the [CHANGELOG.md](https://github.com/grafana/grafana/blob/master/CHANGELOG.md) file for a complete list
|
||||
of new features, changes, and bug fixes.
|
||||
@@ -35,10 +35,15 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
`/api/alerts?dashboardId=1`
|
||||
|
||||
- **dashboardId** – Return alerts for a specified dashboard.
|
||||
- **panelId** – Return alerts for a specified panel on a dashboard.
|
||||
- **limit** - Limit response to x number of alerts.
|
||||
- **dashboardId** – Limit response to alerts in specified dashboard(s). You can specify multiple dashboards, e.g. dashboardId=23&dashboardId=35.
|
||||
- **panelId** – Limit response to alert for a specified panel on a dashboard.
|
||||
- **query** - Limit response to alerts having a name like this value.
|
||||
- **state** - Return alerts with one or more of the following alert states: `ALL`,`no_data`, `paused`, `alerting`, `ok`, `pending`. To specify multiple states use the following format: `?state=paused&state=alerting`
|
||||
- **limit** - Limit response to *X* number of alerts.
|
||||
- **folderId** – Limit response to alerts of dashboards in specified folder(s). You can specify multiple folders, e.g. folderId=23&folderId=35.
|
||||
- **dashboardQuery** - Limit response to alerts having a dashboard name like this value.
|
||||
- **dashboardTag** - Limit response to alerts of dashboards with specified tags. To do an "AND" filtering with multiple tags, specify the tags parameter multiple times e.g. dashboardTag=tag1&dashboardTag=tag2.
|
||||
|
||||
|
||||
**Example Response**:
|
||||
|
||||
@@ -49,18 +54,15 @@ Content-Type: application/json
|
||||
```
|
||||
|
||||
## Get one alert
|
||||
|
||||
`GET /api/alerts/:id`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
|
||||
```http
|
||||
GET /api/alerts/1 HTTP/1.1
|
||||
Accept: application/json
|
||||
```http
|
||||
GET /api/alerts/1 HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
```
|
||||
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
```
|
||||
|
||||
@@ -88,16 +90,35 @@ Content-Type: application/json
|
||||
```http
|
||||
POST /api/alerts/1/pause HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
```
|
||||
|
||||
|
||||
HTTP/1.1 200
|
||||
The :id query parameter is the id of the alert to be paused or unpaused.
|
||||
|
||||
JSON Body Schema:
|
||||
|
||||
- **paused** – Can be `true` or `false`. True to pause an alert. False to unpause an alert.
|
||||
|
||||
**Example Response**:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
{
|
||||
```
|
||||
|
||||
## Pause all alerts
|
||||
|
||||
`POST /api/admin/pause-all-alerts`
|
||||
|
||||
```http
|
||||
POST /api/admin/pause-all-alerts HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
```
|
||||
|
||||
JSON Body Schema:
|
||||
|
||||
@@ -32,10 +32,12 @@ Query Parameters:
|
||||
|
||||
- `from`: epoch datetime in milliseconds. Optional.
|
||||
- `to`: epoch datetime in milliseconds. Optional.
|
||||
- `limit`: number. Optional - default is 10. Max limit for results returned.
|
||||
- `limit`: number. Optional - default is 100. Max limit for results returned.
|
||||
- `alertId`: number. Optional. Find annotations for a specified alert.
|
||||
- `dashboardId`: number. Optional. Find annotations that are scoped to a specific dashboard
|
||||
- `panelId`: number. Optional. Find annotations that are scoped to a specific panel
|
||||
- `userId`: number. Optional. Find annotations created by a specific user
|
||||
- `type`: string. Optional. `alert`|`annotation` Return alerts or user created annotations
|
||||
- `tags`: string. Optional. Use this to filter global annotations. Global annotations are annotations from an annotation data source that are not connected specifically to a dashboard or panel. To do an "AND" filtering with multiple tags, specify the tags parameter multiple times e.g. `tags=tag1&tags=tag2`.
|
||||
|
||||
**Example Response**:
|
||||
|
||||
@@ -106,6 +106,7 @@ Accept: application/json
|
||||
- **200** - Ok
|
||||
- **401** - Unauthorized
|
||||
- **403** - Access denied
|
||||
- **404** - Dashboard not found
|
||||
"items": [
|
||||
{
|
||||
"role": "Viewer",
|
||||
|
||||
@@ -331,6 +331,27 @@ Content-Type: application/json
|
||||
|
||||
```
|
||||
|
||||
## Update Users in Organisation
|
||||
|
||||
`PATCH /api/orgs/:orgId/users/:userId`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
```http
|
||||
PATCH /api/orgs/1/users/2 HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
```
|
||||
|
||||
**Example Response**:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
|
||||
```
|
||||
|
||||
## Delete User in Organisation
|
||||
|
||||
@@ -380,6 +401,8 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
"role":"Viewer"
|
||||
}
|
||||
```
|
||||
Note: The api will only work when you pass the admin name and password
|
||||
to the request http url, like http://admin:admin@localhost:3000/api/orgs/1/users
|
||||
|
||||
**Example Response**:
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ JSON Body schema:
|
||||
Content-Type: application/json
|
||||
{
|
||||
"deleteKey":"XXXXXXX",
|
||||
"deleteUrl":"myurl/dashboard/snapshot/XXXXXXX",
|
||||
"deleteUrl":"myurl/api/snapshots-delete/XXXXXXX",
|
||||
"key":"YYYYYYY",
|
||||
"url":"myurl/dashboard/snapshot/YYYYYYY"
|
||||
}
|
||||
@@ -81,7 +81,46 @@ Keys:
|
||||
- **deleteKey** – Key generated to delete the snapshot
|
||||
- **key** – Key generated to share the dashboard
|
||||
|
||||
## Get Snapshot by Id
|
||||
## Get list of Snapshots
|
||||
|
||||
`GET /api/dashboard/snapshots`
|
||||
|
||||
Query parameters:
|
||||
|
||||
- **query** – Search Query
|
||||
- **limit** – Limit the number of returned results
|
||||
|
||||
**Example Request**:
|
||||
|
||||
```http
|
||||
GET /api/dashboard/snapshots HTTP/1.1
|
||||
Accept: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
```
|
||||
|
||||
**Example Response**:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
|
||||
```
|
||||
|
||||
## Get Snapshot by Key
|
||||
|
||||
`GET /api/snapshots/:key`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
```http
|
||||
GET /api/snapshots/YYYYYYY HTTP/1.1
|
||||
Accept: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
```
|
||||
|
||||
**Example Response**:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
|
||||
@@ -90,7 +129,6 @@ Keys:
|
||||
## Delete Snapshot by Key
|
||||
|
||||
`DELETE /api/snapshots/:key`
|
||||
Content-Type: application/json
|
||||
|
||||
**Example Request**:
|
||||
|
||||
@@ -140,16 +178,15 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Snapshot by deleteKey
|
||||
## Delete Snapshot by Key
|
||||
|
||||
`GET /api/snapshots-delete/:deleteKey`
|
||||
`DELETE /api/snapshots/:key`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
```http
|
||||
GET /api/snapshots/YYYYYYY HTTP/1.1
|
||||
DELETE /api/snapshots/YYYYYYY HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
```
|
||||
|
||||
@@ -159,5 +196,27 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
|
||||
{"message":"Snapshot deleted. It might take an hour before it's cleared from a CDN cache."}
|
||||
{"message":"Snapshot deleted. It might take an hour before it's cleared from any CDN caches."}
|
||||
```
|
||||
|
||||
## Delete Snapshot by deleteKey
|
||||
|
||||
This API call can be used without authentication by using the secret delete key for the snapshot.
|
||||
|
||||
`GET /api/snapshots-delete/:deleteKey`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
```http
|
||||
GET /api/snapshots-delete/XXXXXXX HTTP/1.1
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
**Example Response**:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
|
||||
{"message":"Snapshot deleted. It might take an hour before it's cleared from any CDN caches."}
|
||||
```
|
||||
@@ -53,7 +53,7 @@ server {
|
||||
```bash
|
||||
[server]
|
||||
domain = foo.bar
|
||||
root_url = %(protocol)s://%(domain)s:/grafana
|
||||
root_url = %(protocol)s://%(domain)s/grafana/
|
||||
```
|
||||
|
||||
#### Nginx configuration with sub path
|
||||
@@ -98,7 +98,7 @@ Given:
|
||||
```bash
|
||||
[server]
|
||||
domain = localhost:8080
|
||||
root_url = %(protocol)s://%(domain)s:/grafana
|
||||
root_url = %(protocol)s://%(domain)s/grafana/
|
||||
```
|
||||
|
||||
Create an Inbound Rule for the parent website (localhost:8080 in this example) in IIS Manager with the following settings:
|
||||
|
||||
@@ -93,8 +93,6 @@ Directory where grafana will automatically scan and look for plugins
|
||||
|
||||
### provisioning
|
||||
|
||||
> This feature is available in 5.0+
|
||||
|
||||
Folder that contains [provisioning](/administration/provisioning) config files that grafana will apply on startup. Dashboards will be reloaded when the json files changes
|
||||
|
||||
## [server]
|
||||
@@ -421,25 +419,33 @@ allowed_organizations = github google
|
||||
|
||||
## [auth.google]
|
||||
|
||||
You need to create a Google project. You can do this in the [Google
|
||||
Developer Console](https://console.developers.google.com/project). When
|
||||
you create the project you will need to specify a callback URL. Specify
|
||||
this as callback:
|
||||
First, you need to create a Google OAuth Client:
|
||||
|
||||
```bash
|
||||
http://<my_grafana_server_name_or_ip>:<grafana_server_port>/login/google
|
||||
```
|
||||
1. Go to https://console.developers.google.com/apis/credentials
|
||||
|
||||
This callback URL must match the full HTTP address that you use in your
|
||||
browser to access Grafana, but with the prefix path of `/login/google`.
|
||||
When the Google project is created you will get a Client ID and a Client
|
||||
Secret. Specify these in the Grafana configuration file. For example:
|
||||
2. Click the 'Create Credentials' button, then click 'OAuth Client ID' in the
|
||||
menu that drops down
|
||||
|
||||
3. Enter the following:
|
||||
|
||||
- Application Type: Web Application
|
||||
- Name: Grafana
|
||||
- Authorized Javascript Origins: https://grafana.mycompany.com
|
||||
- Authorized Redirect URLs: https://grafana.mycompany.com/login/google
|
||||
|
||||
Replace https://grafana.mycompany.com with the URL of your Grafana instance.
|
||||
|
||||
4. Click Create
|
||||
|
||||
5. Copy the Client ID and Client Secret from the 'OAuth Client' modal
|
||||
|
||||
Specify the Client ID and Secret in the Grafana configuration file. For example:
|
||||
|
||||
```bash
|
||||
[auth.google]
|
||||
enabled = true
|
||||
client_id = YOUR_GOOGLE_APP_CLIENT_ID
|
||||
client_secret = YOUR_GOOGLE_APP_CLIENT_SECRET
|
||||
client_id = CLIENT_ID
|
||||
client_secret = CLIENT_SECRET
|
||||
scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
|
||||
auth_url = https://accounts.google.com/o/oauth2/auth
|
||||
token_url = https://accounts.google.com/o/oauth2/token
|
||||
@@ -659,6 +665,10 @@ Set to `true` to enable auto sign up of users who do not exist in Grafana DB. De
|
||||
|
||||
Limit where auth proxy requests come from by configuring a list of IP addresses. This can be used to prevent users spoofing the X-WEBAUTH-USER header.
|
||||
|
||||
### headers
|
||||
|
||||
Used to define additional headers for `Name`, `Email` and/or `Login`, for example if the user's name is sent in the X-WEBAUTH-NAME header and their email address in the X-WEBAUTH-EMAIL header, set `headers = Name:X-WEBAUTH-NAME Email:X-WEBAUTH-EMAIL`.
|
||||
|
||||
<hr>
|
||||
|
||||
## [session]
|
||||
@@ -713,7 +723,7 @@ Analytics ID here. By default this feature is disabled.
|
||||
|
||||
## [dashboards]
|
||||
|
||||
### versions_to_keep (introduced in v5.0)
|
||||
### versions_to_keep
|
||||
|
||||
Number dashboard versions to keep (per dashboard). Default: 20, Minimum: 1.
|
||||
|
||||
|
||||
@@ -15,7 +15,10 @@ weight = 1
|
||||
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable for Debian-based Linux | [grafana_5.0.4_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.4_amd64.deb)
|
||||
Stable for Debian-based Linux | [grafana_5.1.3_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.1.3_amd64.deb)
|
||||
<!--
|
||||
Beta for Debian-based Linux | [grafana_5.1.0-beta1_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.1.0-beta1_amd64.deb)
|
||||
-->
|
||||
|
||||
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
|
||||
installation.
|
||||
@@ -24,11 +27,18 @@ installation.
|
||||
|
||||
|
||||
```bash
|
||||
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.4_amd64.deb
|
||||
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.1.3_amd64.deb
|
||||
sudo apt-get install -y adduser libfontconfig
|
||||
sudo dpkg -i grafana_5.0.4_amd64.deb
|
||||
sudo dpkg -i grafana_5.1.3_amd64.deb
|
||||
```
|
||||
|
||||
<!-- ## Install Latest Beta
|
||||
```bash
|
||||
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.1.0-beta1_amd64.deb
|
||||
sudo apt-get install -y adduser libfontconfig
|
||||
sudo dpkg -i grafana_5.1.0-beta1_amd64.deb
|
||||
``` -->
|
||||
|
||||
## APT Repository
|
||||
|
||||
Add the following line to your `/etc/apt/sources.list` file.
|
||||
|
||||
@@ -18,28 +18,6 @@ Grafana is very easy to install and run using the official docker container.
|
||||
$ docker run -d -p 3000:3000 grafana/grafana
|
||||
```
|
||||
|
||||
All Grafana configuration settings can be defined using environment
|
||||
variables, this is especially useful when using the above container.
|
||||
|
||||
## Docker volumes & ENV config
|
||||
|
||||
The Docker container exposes two volumes, the sqlite3 database in the
|
||||
folder `/var/lib/grafana` and configuration files is in `/etc/grafana/`
|
||||
folder. You can map these volumes to host folders when you start the
|
||||
container:
|
||||
|
||||
```bash
|
||||
$ docker run -d -p 3000:3000 \
|
||||
-v /var/lib/grafana:/var/lib/grafana \
|
||||
-e "GF_SECURITY_ADMIN_PASSWORD=secret" \
|
||||
grafana/grafana
|
||||
```
|
||||
|
||||
In the above example I map the data folder and sets a configuration option via
|
||||
an `ENV` instruction.
|
||||
|
||||
See the [docker volumes documentation](https://docs.docker.com/engine/admin/volumes/volumes/) if you want to create a volume to use with the Grafana docker image instead of a bind mount (binding to a directory in the host system).
|
||||
|
||||
## Configuration
|
||||
|
||||
All options defined in conf/grafana.ini can be overridden using environment
|
||||
@@ -56,15 +34,29 @@ $ docker run \
|
||||
grafana/grafana
|
||||
```
|
||||
|
||||
You can use your own grafana.ini file by using environment variable `GF_PATHS_CONFIG`.
|
||||
|
||||
The back-end web server has a number of configuration options. Go to the
|
||||
[Configuration]({{< relref "configuration.md" >}}) page for details on all
|
||||
those options.
|
||||
|
||||
## Running a Specific Version of Grafana
|
||||
|
||||
```bash
|
||||
# specify right tag, e.g. 5.1.0 - see Docker Hub for available tags
|
||||
$ docker run \
|
||||
-d \
|
||||
-p 3000:3000 \
|
||||
--name grafana \
|
||||
grafana/grafana:5.1.0
|
||||
```
|
||||
|
||||
## Running of the master branch
|
||||
|
||||
For every successful commit we publish a Grafana container to [`grafana/grafana`](https://hub.docker.com/r/grafana/grafana/tags/) and [`grafana/grafana-dev`](https://hub.docker.com/r/grafana/grafana-dev/tags/). In `grafana/grafana` container we will always overwrite the `master` tag with the latest version. In `grafana/grafana-dev` we will include
|
||||
the git commit in the tag. If you run Grafana master in production we **strongly** recommend that you use the later since different machines might run different version of grafana if they pull the master tag at different times.
|
||||
|
||||
## Installing Plugins for Grafana
|
||||
|
||||
Pass the plugins you want installed to docker with the `GF_INSTALL_PLUGINS` environment variable as a comma separated list. This will pass each plugin name to `grafana-cli plugins install ${plugin}`.
|
||||
Pass the plugins you want installed to docker with the `GF_INSTALL_PLUGINS` environment variable as a comma separated list. This will pass each plugin name to `grafana-cli plugins install ${plugin}` and install them when Grafana starts.
|
||||
|
||||
```bash
|
||||
docker run \
|
||||
@@ -75,15 +67,22 @@ docker run \
|
||||
grafana/grafana
|
||||
```
|
||||
|
||||
## Running a Specific Version of Grafana
|
||||
## Building a custom Grafana image with pre-installed plugins
|
||||
|
||||
In the [grafana-docker](https://github.com/grafana/grafana-docker/) there is a folder called `custom/` which includes a `Dockerfile` that can be used to build a custom Grafana image. It accepts `GRAFANA_VERSION` and `GF_INSTALL_PLUGINS` as build arguments.
|
||||
|
||||
Example of how to build and run:
|
||||
```bash
|
||||
# specify right tag, e.g. 4.5.2 - see Docker Hub for available tags
|
||||
$ docker run \
|
||||
cd custom
|
||||
docker build -t grafana:latest-with-plugins \
|
||||
--build-arg "GRAFANA_VERSION=latest" \
|
||||
--build-arg "GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource" .
|
||||
|
||||
docker run \
|
||||
-d \
|
||||
-p 3000:3000 \
|
||||
--name grafana \
|
||||
grafana/grafana:5.0.2
|
||||
--name=grafana \
|
||||
grafana:latest-with-plugins
|
||||
```
|
||||
|
||||
## Configuring AWS Credentials for CloudWatch Support
|
||||
@@ -108,3 +107,108 @@ Supported variables:
|
||||
- `GF_AWS_${profile}_ACCESS_KEY_ID`: AWS access key ID (required).
|
||||
- `GF_AWS_${profile}_SECRET_ACCESS_KEY`: AWS secret access key (required).
|
||||
- `GF_AWS_${profile}_REGION`: AWS region (optional).
|
||||
|
||||
## Grafana container with persistent storage (recommended)
|
||||
|
||||
```bash
|
||||
# create a persistent volume for your data in /var/lib/grafana (database and plugins)
|
||||
docker volume create grafana-storage
|
||||
|
||||
# start grafana
|
||||
docker run \
|
||||
-d \
|
||||
-p 3000:3000 \
|
||||
--name=grafana \
|
||||
-v grafana-storage:/var/lib/grafana \
|
||||
grafana/grafana
|
||||
```
|
||||
|
||||
## Grafana container using bind mounts
|
||||
|
||||
You may want to run Grafana in Docker but use folders on your host for the database or configuration. When doing so it becomes important to start the container with a user that is able to access and write to the folder you map into the container.
|
||||
|
||||
```bash
|
||||
mkdir data # creates a folder for your data
|
||||
ID=$(id -u) # saves your user id in the ID variable
|
||||
|
||||
# starts grafana with your user id and using the data folder
|
||||
docker run -d --user $ID --volume "$PWD/data:/var/lib/grafana" -p 3000:3000 grafana/grafana:5.1.0
|
||||
```
|
||||
|
||||
## Reading secrets from files (support for Docker Secrets)
|
||||
|
||||
> Available in v5.2.0 and later
|
||||
|
||||
It's possible to supply Grafana with configuration through files. This works well with [Docker Secrets](https://docs.docker.com/engine/swarm/secrets/) as the secrets by default gets mapped into `/run/secrets/<name of secret>` of the container.
|
||||
|
||||
You can do this with any of the configuration options in conf/grafana.ini by setting `GF_<SectionName>_<KeyName>_FILE` to the path of the file holding the secret.
|
||||
|
||||
Let's say you want to set the admin password this way.
|
||||
|
||||
- Admin password secret: `/run/secrets/admin_password`
|
||||
- Environment variable: `GF_SECURITY_ADMIN_PASSWORD_FILE=/run/secrets/admin_password`
|
||||
|
||||
|
||||
## Migration from a previous version of the docker container to 5.1 or later
|
||||
|
||||
The docker container for Grafana has seen a major rewrite for 5.1.
|
||||
|
||||
**Important changes**
|
||||
|
||||
* file ownership is no longer modified during startup with `chown`
|
||||
* default user id `472` instead of `104`
|
||||
* no more implicit volumes
|
||||
- `/var/lib/grafana`
|
||||
- `/etc/grafana`
|
||||
- `/var/log/grafana`
|
||||
|
||||
### Removal of implicit volumes
|
||||
|
||||
Previously `/var/lib/grafana`, `/etc/grafana` and `/var/log/grafana` were defined as volumes in the `Dockerfile`. This led to the creation of three volumes each time a new instance of the Grafana container started, whether you wanted it or not.
|
||||
|
||||
You should always be careful to define your own named volume for storage, but if you depended on these volumes you should be aware that an upgraded container will no longer have them.
|
||||
|
||||
**Warning**: when migrating from an earlier version to 5.1 or later using docker compose and implicit volumes you need to use `docker inspect` to find out which volumes your container is mapped to so that you can map them to the upgraded container as well. You will also have to change file ownership (or user) as documented below.
|
||||
|
||||
### User ID changes
|
||||
|
||||
In 5.1 we switched the id of the grafana user. Unfortunately this means that files created prior to 5.1 won't have the correct permissions for later versions. We made this change so that it would be more likely that the grafana users id would be unique to Grafana. For example, on Ubuntu 16.04 `104` is already in use by the syslog user.
|
||||
|
||||
Version | User | User ID
|
||||
--------|---------|---------
|
||||
< 5.1 | grafana | 104
|
||||
>= 5.1 | grafana | 472
|
||||
|
||||
There are two possible solutions to this problem. Either you start the new container as the root user and change ownership from `104` to `472` or you start the upgraded container as user `104`.
|
||||
|
||||
#### Running docker as a different user
|
||||
|
||||
```bash
|
||||
docker run --user 104 --volume "<your volume mapping here>" grafana/grafana:5.1.0
|
||||
```
|
||||
|
||||
##### Specifying a user in docker-compose.yml
|
||||
```yaml
|
||||
version: "2"
|
||||
|
||||
services:
|
||||
grafana:
|
||||
image: grafana/grafana:5.1.0
|
||||
ports:
|
||||
- 3000:3000
|
||||
user: "104"
|
||||
```
|
||||
|
||||
#### Modifying permissions
|
||||
|
||||
The commands below will run bash inside the Grafana container with your volume mapped in. This makes it possible to modify the file ownership to match the new container. Always be careful when modifying permissions.
|
||||
|
||||
```bash
|
||||
$ docker run -ti --user root --volume "<your volume mapping here>" --entrypoint bash grafana/grafana:5.1.0
|
||||
|
||||
# in the container you just started:
|
||||
chown -R root:root /etc/grafana && \
|
||||
chmod -R a+r /etc/grafana && \
|
||||
chown -R grafana:grafana /var/lib/grafana && \
|
||||
chown -R grafana:grafana /usr/share/grafana
|
||||
```
|
||||
|
||||
@@ -15,8 +15,10 @@ weight = 2
|
||||
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [5.0.4 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.4-1.x86_64.rpm)
|
||||
|
||||
Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [5.1.3 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.1.3-1.x86_64.rpm)
|
||||
<!--
|
||||
Latest Beta for CentOS / Fedora / OpenSuse / Redhat Linux | [5.1.0-beta1 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.1.0-beta1.x86_64.rpm)
|
||||
-->
|
||||
|
||||
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
|
||||
installation.
|
||||
@@ -26,23 +28,29 @@ installation.
|
||||
You can install Grafana using Yum directly.
|
||||
|
||||
```bash
|
||||
$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.4-1.x86_64.rpm
|
||||
$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.1.3-1.x86_64.rpm
|
||||
```
|
||||
|
||||
<!-- ## Install Beta
|
||||
|
||||
```bash
|
||||
$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.1.0-beta1.x86_64.rpm
|
||||
``` -->
|
||||
|
||||
Or install manually using `rpm`.
|
||||
|
||||
#### On CentOS / Fedora / Redhat:
|
||||
|
||||
```bash
|
||||
$ wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.4-1.x86_64.rpm
|
||||
$ wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.1.3-1.x86_64.rpm
|
||||
$ sudo yum install initscripts fontconfig
|
||||
$ sudo rpm -Uvh grafana-5.0.4-1.x86_64.rpm
|
||||
$ sudo rpm -Uvh grafana-5.1.3-1.x86_64.rpm
|
||||
```
|
||||
|
||||
#### On OpenSuse:
|
||||
|
||||
```bash
|
||||
$ sudo rpm -i --nodeps grafana-5.0.4-1.x86_64.rpm
|
||||
$ sudo rpm -i --nodeps grafana-5.1.3-1.x86_64.rpm
|
||||
```
|
||||
|
||||
## Install via YUM Repository
|
||||
|
||||
@@ -12,7 +12,11 @@ weight = 3
|
||||
|
||||
Description | Download
|
||||
------------ | -------------
|
||||
Latest stable package for Windows | [grafana-5.0.4.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.4.windows-x64.zip)
|
||||
Latest stable package for Windows | [grafana-5.1.3.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.1.3.windows-x64.zip)
|
||||
|
||||
<!--
|
||||
Latest beta package for Windows | [grafana.5.1.0-beta1.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.0-beta5.windows-x64.zip)
|
||||
-->
|
||||
|
||||
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
|
||||
installation.
|
||||
|
||||
@@ -5,7 +5,7 @@ type = "docs"
|
||||
[menu.docs]
|
||||
name = "Developing App Plugins"
|
||||
parent = "developing"
|
||||
weight = 6
|
||||
weight = 4
|
||||
+++
|
||||
|
||||
# Grafana Apps
|
||||
|
||||
@@ -5,7 +5,7 @@ type = "docs"
|
||||
[menu.docs]
|
||||
name = "Developing Datasource Plugins"
|
||||
parent = "developing"
|
||||
weight = 6
|
||||
weight = 5
|
||||
+++
|
||||
|
||||
# Datasources
|
||||
@@ -25,7 +25,6 @@ To interact with the rest of grafana the plugins module file can export 5 differ
|
||||
- Datasource (Required)
|
||||
- QueryCtrl (Required)
|
||||
- ConfigCtrl (Required)
|
||||
- QueryOptionsCtrl
|
||||
- AnnotationsQueryCtrl
|
||||
|
||||
## Plugin json
|
||||
@@ -182,12 +181,6 @@ A JavaScript class that will be instantiated and treated as an Angular controlle
|
||||
|
||||
Requires a static template or templateUrl variable which will be rendered as the view for this controller.
|
||||
|
||||
## QueryOptionsCtrl
|
||||
|
||||
A JavaScript class that will be instantiated and treated as an Angular controller when the user edits metrics in a panel. This controller is responsible for handling panel wide settings for the datasource, such as interval, rate and aggregations if needed.
|
||||
|
||||
Requires a static template or templateUrl variable which will be rendered as the view for this controller.
|
||||
|
||||
## AnnotationsQueryCtrl
|
||||
|
||||
A JavaScript class that will be instantiated and treated as an Angular controller when the user choose this type of datasource in the templating menu in the dashboard.
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
---
|
||||
page_title: Plugin panel
|
||||
page_description: Panel plugins for Grafana
|
||||
page_keywords: grafana, plugins, documentation
|
||||
---
|
||||
|
||||
|
||||
+++
|
||||
title = "Installing Plugins"
|
||||
title = "Developing Panel Plugins"
|
||||
keywords = ["grafana", "plugins", "panel", "documentation"]
|
||||
type = "docs"
|
||||
[menu.docs]
|
||||
name = "Developing Panel Plugins"
|
||||
parent = "developing"
|
||||
weight = 1
|
||||
weight = 4
|
||||
+++
|
||||
|
||||
|
||||
@@ -20,7 +15,21 @@ Panels are the main building blocks of dashboards.
|
||||
|
||||
## Panel development
|
||||
|
||||
Examples
|
||||
|
||||
### Scrolling
|
||||
The grafana dashboard framework controls the panel height. To enable a scrollbar within the panel the PanelCtrl needs to set the scrollable static variable:
|
||||
|
||||
```javascript
|
||||
export class MyPanelCtrl extends PanelCtrl {
|
||||
static scrollable = true;
|
||||
...
|
||||
```
|
||||
|
||||
In this case, make sure the template has a single `<div>...</div>` root. The plugin loader will modify that element adding a scrollbar.
|
||||
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
- [clock-panel](https://github.com/grafana/clock-panel)
|
||||
- [singlestat-panel](https://github.com/grafana/grafana/blob/master/public/app/plugins/panel/singlestat/module.ts)
|
||||
|
||||
@@ -5,7 +5,7 @@ type = "docs"
|
||||
[menu.docs]
|
||||
name = "plugin.json Schema"
|
||||
parent = "developing"
|
||||
weight = 6
|
||||
weight = 8
|
||||
+++
|
||||
|
||||
# Plugin.json
|
||||
|
||||
@@ -13,7 +13,7 @@ dev environment. Grafana ships with its own required backend server; also comple
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [Go 1.9.2](https://golang.org/dl/)
|
||||
- [Go 1.10](https://golang.org/dl/)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
- [NodeJS LTS](https://nodejs.org/download/)
|
||||
- node-gyp is the Node.js native addon build tool and it requires extra dependencies: python 2.7, make and GCC. These are already installed for most Linux distros and MacOS. See the Building On Windows section or the [node-gyp installation instructions](https://github.com/nodejs/node-gyp#installation) for more details.
|
||||
@@ -66,13 +66,13 @@ You can run a local instance of Grafana by running:
|
||||
```bash
|
||||
./bin/grafana-server
|
||||
```
|
||||
If you built the binary with `go run build.go build`, run `./bin/grafana-server`
|
||||
Or, if you built the binary with `go run build.go build`, run `./bin/<os>-<architecture>/grafana-server`
|
||||
|
||||
If you built it with `go build .`, run `./grafana`
|
||||
|
||||
Open grafana in your browser (default [http://localhost:3000](http://localhost:3000)) and login with admin user (default user/pass = admin/admin).
|
||||
|
||||
## Developing Grafana
|
||||
# Developing Grafana
|
||||
|
||||
To add features, customize your config, etc, you'll need to rebuild the backend when you change the source code. We use a tool named `bra` that
|
||||
does this.
|
||||
@@ -124,7 +124,7 @@ Learn more about Grafana config options in the [Configuration section](/installa
|
||||
## Create a pull requests
|
||||
Please contribute to the Grafana project and submit a pull request! Build new features, write or update documentation, fix bugs and generally make Grafana even more awesome.
|
||||
|
||||
## Troubleshooting
|
||||
# Troubleshooting
|
||||
|
||||
**Problem**: PhantomJS or node-sass errors when running grunt
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ When a user creates a new dashboard, a new dashboard JSON object is initialized
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"refresh": "5s",
|
||||
"schemaVersion": 16,
|
||||
"version": 0,
|
||||
"links": []
|
||||
@@ -71,6 +72,7 @@ Each field in the dashboard JSON is explained below with its usage:
|
||||
| **timepicker** | timepicker metadata, see [timepicker section](#timepicker) for details |
|
||||
| **templating** | templating metadata, see [templating section](#templating) for details |
|
||||
| **annotations** | annotations metadata, see [annotations section](#annotations) for details |
|
||||
| **refresh** | auto-refresh interval
|
||||
| **schemaVersion** | version of the JSON schema (integer), incremented each time a Grafana update brings changes to said schema |
|
||||
| **version** | version of the dashboard (integer), incremented each time the dashboard is updated |
|
||||
| **panels** | panels array, see below for detail. |
|
||||
|
||||
@@ -36,6 +36,29 @@ interpolation the variable value might be **escaped** in order to conform to the
|
||||
For example, a variable used in a regex expression in an InfluxDB or Prometheus query will be regex escaped. Read the data source specific
|
||||
documentation article for details on value escaping during interpolation.
|
||||
|
||||
### Advanced Formatting Options
|
||||
|
||||
> Only available in Grafana v5.1+.
|
||||
|
||||
The formatting of the variable interpolation depends on the data source but there are some situations where you might want to change the default formatting. For example, the default for the MySql datasource is to join multiple values as comma-separated with quotes: `'server01','server02'`. In some cases you might want to have a comma-separated string without quotes: `server01,server02`. This is now possible with the advanced formatting options.
|
||||
|
||||
Syntax: `${var_name:option}`
|
||||
|
||||
Filter Option | Example | Raw | Interpolated | Description
|
||||
------------ | ------------- | ------------- | ------------- | -------------
|
||||
`glob` | ${servers:glob} | `'test1', 'test2'` | `{test1,test2}` | (Default) Formats multi-value variable into a glob (for Graphite queries)
|
||||
`regex` | ${servers:regex} | `'test.', 'test2'` | <code>(test\.|test2)</code> | Formats multi-value variable into a regex string
|
||||
`pipe` | ${servers:pipe} | `'test.', 'test2'` | <code>test.|test2</code> | Formats multi-value variable into a pipe-separated string
|
||||
`csv`| ${servers:csv} | `'test1', 'test2'` | `test1,test2` | Formats multi-value variable as a comma-separated string
|
||||
`distributed`| ${servers:distributed} | `'test1', 'test2'` | `test1,servers=test2` | Formats multi-value variable in custom format for OpenTSDB.
|
||||
`lucene`| ${servers:lucene} | `'test', 'test2'` | `("test" OR "test2")` | Formats multi-value variable as a lucene expression.
|
||||
|
||||
Test the formatting options on the [Grafana Play site](http://play.grafana.org/d/cJtIfcWiz/template-variable-formatting-options?orgId=1).
|
||||
|
||||
If any invalid formatting option is specified, then `glob` is the default/fallback option.
|
||||
|
||||
An alternative syntax (that might be deprecated in the future) is `[[var_name:option]]`.
|
||||
|
||||
### Variable options
|
||||
|
||||
A variable is presented as a dropdown select box at the top of the dashboard. It has a current value and a set of **options**. The **options**
|
||||
@@ -166,7 +189,7 @@ Option | Description
|
||||
------- | --------
|
||||
*Multi-value* | If enabled, the variable will support the selection of multiple options at the same time.
|
||||
*Include All option* | Add a special `All` option whose value includes all options.
|
||||
*Custom all value* | By default the `All` value will include all options in combined expression. This can become very long and can have performance problems. Many times it can be better to specify a custom all value, like a wildcard regex. To make it possible to have custom regex, globs or lucene syntax in the **Custom all value** option it is never escaped so you will have to think avbout what is a valid value for your data source.
|
||||
*Custom all value* | By default the `All` value will include all options in combined expression. This can become very long and can have performance problems. Many times it can be better to specify a custom all value, like a wildcard regex. To make it possible to have custom regex, globs or lucene syntax in the **Custom all value** option it is never escaped so you will have to think about what is a valid value for your data source.
|
||||
|
||||
### Formatting multiple values
|
||||
|
||||
@@ -277,4 +300,3 @@ Variable values are always synced to the URL using the syntax `var-<varname>=val
|
||||
- [Graphite Templated Dashboard](http://play.grafana.org/dashboard/db/graphite-templated-nested)
|
||||
- [Elasticsearch Templated Dashboard](http://play.grafana.org/dashboard/db/elasticsearch-templated)
|
||||
- [InfluxDB Templated Dashboard](http://play.grafana.org/dashboard/db/influxdb-templated-queries)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Example:
|
||||
- Parent site: http://localhost:8080
|
||||
- Grafana: http://localhost:3000
|
||||
|
||||
Grafana as a subpath: http://localhost:8080/grafana
|
||||
Grafana as a subpath: http://localhost:8080/grafana
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -33,7 +33,7 @@ Given that the subpath should be `grafana` and the parent site is `localhost:808
|
||||
```bash
|
||||
[server]
|
||||
domain = localhost:8080
|
||||
root_url = %(protocol)s://%(domain)s:/grafana
|
||||
root_url = %(protocol)s://%(domain)s/grafana/
|
||||
```
|
||||
|
||||
Restart the Grafana server after changing the config file.
|
||||
@@ -74,11 +74,11 @@ When navigating to the grafana url (`http://localhost:8080/grafana` in the examp
|
||||
|
||||
1. The `root_url` setting in the Grafana config file does not match the parent url with subpath. This could happen if the root_url is commented out by mistake (`;` is used for commenting out a line in .ini files):
|
||||
|
||||
`; root_url = %(protocol)s://%(domain)s:/grafana`
|
||||
`; root_url = %(protocol)s://%(domain)s/grafana/`
|
||||
|
||||
2. or if the subpath in the `root_url` setting does not match the subpath used in the pattern in the Inbound Rule in IIS:
|
||||
|
||||
`root_url = %(protocol)s://%(domain)s:/grafana`
|
||||
`root_url = %(protocol)s://%(domain)s/grafana/`
|
||||
|
||||
pattern in Inbound Rule: `wrongsubpath(/)?(.*)`
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ weight = 10
|
||||
</a>
|
||||
<figcaption>
|
||||
<a href="https://youtu.be/FC13uhFRsVw?list=PLDGkOdUX1Ujo3wHw9-z5Vo12YLqXRjzg2" target="_blank" rel="noopener noreferrer">
|
||||
#3 Whats New In Grafana 2.0
|
||||
#3 What's New In Grafana 2.0
|
||||
</a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[
|
||||
{ "version": "v5.1", "path": "/v5.1", "archived": false },
|
||||
{ "version": "v5.0", "path": "/", "archived": false, "current": true },
|
||||
{ "version": "v5.1", "path": "/", "archived": false, "current": true },
|
||||
{ "version": "v5.0", "path": "/v5.0", "archived": true },
|
||||
{ "version": "v4.6", "path": "/v4.6", "archived": true },
|
||||
{ "version": "v4.5", "path": "/v4.5", "archived": true },
|
||||
{ "version": "v4.4", "path": "/v4.4", "archived": true },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"stable": "5.0.0",
|
||||
"testing": "5.0.0"
|
||||
"stable": "5.2.0",
|
||||
"testing": "5.2.0"
|
||||
}
|
||||
|
||||
34
package.json
34
package.json
@@ -4,7 +4,7 @@
|
||||
"company": "Grafana Labs"
|
||||
},
|
||||
"name": "grafana",
|
||||
"version": "5.1.0-pre1",
|
||||
"version": "5.2.3",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/grafana/grafana.git"
|
||||
@@ -18,11 +18,12 @@
|
||||
"@types/react-dom": "^16.0.3",
|
||||
"angular-mocks": "^1.6.6",
|
||||
"autoprefixer": "^6.4.0",
|
||||
"awesome-typescript-loader": "^3.2.3",
|
||||
"awesome-typescript-loader": "^4.0.0",
|
||||
"axios": "^0.17.1",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"clean-webpack-plugin": "^0.1.19",
|
||||
"css-loader": "^0.28.7",
|
||||
"enzyme": "^3.1.0",
|
||||
"enzyme-adapter-react-16": "^1.0.1",
|
||||
@@ -32,7 +33,7 @@
|
||||
"expect.js": "~0.2.0",
|
||||
"expose-loader": "^0.7.3",
|
||||
"extract-text-webpack-plugin": "^3.0.0",
|
||||
"file-loader": "^0.11.2",
|
||||
"file-loader": "^1.1.11",
|
||||
"gaze": "^1.1.2",
|
||||
"glob": "~7.0.0",
|
||||
"grunt": "1.0.1",
|
||||
@@ -54,11 +55,11 @@
|
||||
"grunt-usemin": "3.1.1",
|
||||
"grunt-webpack": "^3.0.2",
|
||||
"html-loader": "^0.5.1",
|
||||
"html-webpack-harddisk-plugin": "^0.2.0",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"husky": "^0.14.3",
|
||||
"jest": "^22.0.4",
|
||||
"jshint-stylish": "~2.2.1",
|
||||
"json-loader": "^0.5.7",
|
||||
"karma": "1.7.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-expect": "~1.1.3",
|
||||
@@ -80,25 +81,28 @@
|
||||
"postcss-loader": "^2.0.6",
|
||||
"postcss-reporter": "^5.0.0",
|
||||
"prettier": "1.9.2",
|
||||
"react-hot-loader": "^4.2.0",
|
||||
"react-test-renderer": "^16.0.0",
|
||||
"sass-lint": "^1.10.2",
|
||||
"sass-loader": "^6.0.6",
|
||||
"sass-loader": "^7.0.1",
|
||||
"sinon": "1.17.6",
|
||||
"style-loader": "^0.21.0",
|
||||
"systemjs": "0.20.19",
|
||||
"systemjs-plugin-css": "^0.1.36",
|
||||
"ts-jest": "^22.0.0",
|
||||
"ts-loader": "^3.2.0",
|
||||
"tslint": "^5.8.0",
|
||||
"tslint-loader": "^3.5.3",
|
||||
"typescript": "^2.6.2",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-bundle-analyzer": "^2.9.0",
|
||||
"webpack-cleanup-plugin": "^0.5.1",
|
||||
"webpack-dev-server": "2.11.1",
|
||||
"webpack-merge": "^4.1.0",
|
||||
"zone.js": "^0.7.2"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "webpack --progress --colors --config scripts/webpack/webpack.dev.js",
|
||||
"start": "webpack-dev-server --progress --colors --config scripts/webpack/webpack.hot.js",
|
||||
"watch": "webpack --progress --colors --watch --config scripts/webpack/webpack.dev.js",
|
||||
"build": "grunt build",
|
||||
"test": "grunt test",
|
||||
@@ -130,11 +134,11 @@
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"angular": "^1.6.6",
|
||||
"angular": "1.6.6",
|
||||
"angular-bindonce": "^0.3.1",
|
||||
"angular-native-dragdrop": "^1.2.2",
|
||||
"angular-route": "^1.6.6",
|
||||
"angular-sanitize": "^1.6.6",
|
||||
"angular-route": "1.6.6",
|
||||
"angular-sanitize": "1.6.6",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"baron": "^3.0.3",
|
||||
"brace": "^0.10.0",
|
||||
@@ -144,6 +148,7 @@
|
||||
"d3-scale-chromatic": "^1.1.1",
|
||||
"eventemitter3": "^2.0.3",
|
||||
"file-saver": "^1.3.3",
|
||||
"immutable": "^3.8.2",
|
||||
"jquery": "^3.2.1",
|
||||
"lodash": "^4.17.4",
|
||||
"mobx": "^3.4.1",
|
||||
@@ -152,10 +157,11 @@
|
||||
"moment": "^2.18.1",
|
||||
"mousetrap": "^1.6.0",
|
||||
"mousetrap-global-bind": "^1.1.0",
|
||||
"prismjs": "^1.6.0",
|
||||
"prop-types": "^15.6.0",
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-grid-layout-grafana": "0.16.0",
|
||||
"react-grid-layout": "0.16.6",
|
||||
"react-highlight-words": "^0.10.0",
|
||||
"react-popper": "^0.7.5",
|
||||
"react-select": "^1.1.0",
|
||||
@@ -164,8 +170,14 @@
|
||||
"remarkable": "^1.7.1",
|
||||
"rst2html": "github:thoward/rst2html#990cb89",
|
||||
"rxjs": "^5.4.3",
|
||||
"slate": "^0.33.4",
|
||||
"slate-plain-serializer": "^0.5.10",
|
||||
"slate-react": "^0.12.4",
|
||||
"tether": "^1.4.0",
|
||||
"tether-drop": "https://github.com/torkelo/drop/tarball/master",
|
||||
"tinycolor2": "^1.4.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"caniuse-db": "1.0.30000772"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /usr/bin/env bash
|
||||
deb_ver=5.0.0-beta5
|
||||
rpm_ver=5.0.0-beta5
|
||||
deb_ver=5.1.0-beta1
|
||||
rpm_ver=5.1.0-beta1
|
||||
|
||||
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${deb_ver}_amd64.deb
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
func AdminGetSettings(c *m.ReqContext) {
|
||||
settings := make(map[string]interface{})
|
||||
|
||||
for _, section := range setting.Cfg.Sections() {
|
||||
for _, section := range setting.Raw.Sections() {
|
||||
jsonSec := make(map[string]interface{})
|
||||
settings[section.Name()] = jsonSec
|
||||
|
||||
|
||||
@@ -2,12 +2,14 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/search"
|
||||
)
|
||||
|
||||
func ValidateOrgAlert(c *m.ReqContext) {
|
||||
@@ -46,12 +48,64 @@ func GetAlertStatesForDashboard(c *m.ReqContext) Response {
|
||||
|
||||
// GET /api/alerts
|
||||
func GetAlerts(c *m.ReqContext) Response {
|
||||
dashboardQuery := c.Query("dashboardQuery")
|
||||
dashboardTags := c.QueryStrings("dashboardTag")
|
||||
stringDashboardIDs := c.QueryStrings("dashboardId")
|
||||
stringFolderIDs := c.QueryStrings("folderId")
|
||||
|
||||
dashboardIDs := make([]int64, 0)
|
||||
for _, id := range stringDashboardIDs {
|
||||
dashboardID, err := strconv.ParseInt(id, 10, 64)
|
||||
if err == nil {
|
||||
dashboardIDs = append(dashboardIDs, dashboardID)
|
||||
}
|
||||
}
|
||||
|
||||
if dashboardQuery != "" || len(dashboardTags) > 0 || len(stringFolderIDs) > 0 {
|
||||
folderIDs := make([]int64, 0)
|
||||
for _, id := range stringFolderIDs {
|
||||
folderID, err := strconv.ParseInt(id, 10, 64)
|
||||
if err == nil {
|
||||
folderIDs = append(folderIDs, folderID)
|
||||
}
|
||||
}
|
||||
|
||||
searchQuery := search.Query{
|
||||
Title: dashboardQuery,
|
||||
Tags: dashboardTags,
|
||||
SignedInUser: c.SignedInUser,
|
||||
Limit: 1000,
|
||||
OrgId: c.OrgId,
|
||||
DashboardIds: dashboardIDs,
|
||||
Type: string(search.DashHitDB),
|
||||
FolderIds: folderIDs,
|
||||
Permission: m.PERMISSION_VIEW,
|
||||
}
|
||||
|
||||
err := bus.Dispatch(&searchQuery)
|
||||
if err != nil {
|
||||
return Error(500, "List alerts failed", err)
|
||||
}
|
||||
|
||||
for _, d := range searchQuery.Result {
|
||||
if d.Type == search.DashHitDB && d.Id > 0 {
|
||||
dashboardIDs = append(dashboardIDs, d.Id)
|
||||
}
|
||||
}
|
||||
|
||||
// if we didn't find any dashboards, return empty result
|
||||
if len(dashboardIDs) == 0 {
|
||||
return JSON(200, []*m.AlertListItemDTO{})
|
||||
}
|
||||
}
|
||||
|
||||
query := m.GetAlertsQuery{
|
||||
OrgId: c.OrgId,
|
||||
DashboardId: c.QueryInt64("dashboardId"),
|
||||
PanelId: c.QueryInt64("panelId"),
|
||||
Limit: c.QueryInt64("limit"),
|
||||
User: c.SignedInUser,
|
||||
OrgId: c.OrgId,
|
||||
DashboardIDs: dashboardIDs,
|
||||
PanelId: c.QueryInt64("panelId"),
|
||||
Limit: c.QueryInt64("limit"),
|
||||
User: c.SignedInUser,
|
||||
Query: c.Query("query"),
|
||||
}
|
||||
|
||||
states := c.QueryStrings("state")
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/search"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
@@ -64,6 +65,60 @@ func TestAlertingApiEndpoint(t *testing.T) {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alerts?dashboardId=1", "/api/alerts", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
var searchQuery *search.Query
|
||||
bus.AddHandler("test", func(query *search.Query) error {
|
||||
searchQuery = query
|
||||
return nil
|
||||
})
|
||||
|
||||
var getAlertsQuery *m.GetAlertsQuery
|
||||
bus.AddHandler("test", func(query *m.GetAlertsQuery) error {
|
||||
getAlertsQuery = query
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.handlerFunc = GetAlerts
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(searchQuery, ShouldBeNil)
|
||||
So(getAlertsQuery, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alerts?dashboardId=1&dashboardId=2&folderId=3&dashboardTag=abc&dashboardQuery=dbQuery&limit=5&query=alertQuery", "/api/alerts", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
var searchQuery *search.Query
|
||||
bus.AddHandler("test", func(query *search.Query) error {
|
||||
searchQuery = query
|
||||
query.Result = search.HitList{
|
||||
&search.Hit{Id: 1},
|
||||
&search.Hit{Id: 2},
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
var getAlertsQuery *m.GetAlertsQuery
|
||||
bus.AddHandler("test", func(query *m.GetAlertsQuery) error {
|
||||
getAlertsQuery = query
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.handlerFunc = GetAlerts
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(searchQuery, ShouldNotBeNil)
|
||||
So(searchQuery.DashboardIds[0], ShouldEqual, 1)
|
||||
So(searchQuery.DashboardIds[1], ShouldEqual, 2)
|
||||
So(searchQuery.FolderIds[0], ShouldEqual, 3)
|
||||
So(searchQuery.Tags[0], ShouldEqual, "abc")
|
||||
So(searchQuery.Title, ShouldEqual, "dbQuery")
|
||||
|
||||
So(getAlertsQuery, ShouldNotBeNil)
|
||||
So(getAlertsQuery.DashboardIDs[0], ShouldEqual, 1)
|
||||
So(getAlertsQuery.DashboardIDs[1], ShouldEqual, 2)
|
||||
So(getAlertsQuery.Limit, ShouldEqual, 5)
|
||||
So(getAlertsQuery.Query, ShouldEqual, "alertQuery")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package api
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
@@ -15,9 +14,10 @@ import (
|
||||
func GetAnnotations(c *m.ReqContext) Response {
|
||||
|
||||
query := &annotations.ItemQuery{
|
||||
From: c.QueryInt64("from") / 1000,
|
||||
To: c.QueryInt64("to") / 1000,
|
||||
From: c.QueryInt64("from"),
|
||||
To: c.QueryInt64("to"),
|
||||
OrgId: c.OrgId,
|
||||
UserId: c.QueryInt64("userId"),
|
||||
AlertId: c.QueryInt64("alertId"),
|
||||
DashboardId: c.QueryInt64("dashboardId"),
|
||||
PanelId: c.QueryInt64("panelId"),
|
||||
@@ -37,7 +37,7 @@ func GetAnnotations(c *m.ReqContext) Response {
|
||||
if item.Email != "" {
|
||||
item.AvatarUrl = dtos.GetGravatarUrl(item.Email)
|
||||
}
|
||||
item.Time = item.Time * 1000
|
||||
item.Time = item.Time
|
||||
}
|
||||
|
||||
return JSON(200, items)
|
||||
@@ -68,16 +68,12 @@ func PostAnnotation(c *m.ReqContext, cmd dtos.PostAnnotationsCmd) Response {
|
||||
UserId: c.UserId,
|
||||
DashboardId: cmd.DashboardId,
|
||||
PanelId: cmd.PanelId,
|
||||
Epoch: cmd.Time / 1000,
|
||||
Epoch: cmd.Time,
|
||||
Text: cmd.Text,
|
||||
Data: cmd.Data,
|
||||
Tags: cmd.Tags,
|
||||
}
|
||||
|
||||
if item.Epoch == 0 {
|
||||
item.Epoch = time.Now().Unix()
|
||||
}
|
||||
|
||||
if err := repo.Save(&item); err != nil {
|
||||
return Error(500, "Failed to save annotation", err)
|
||||
}
|
||||
@@ -97,7 +93,7 @@ func PostAnnotation(c *m.ReqContext, cmd dtos.PostAnnotationsCmd) Response {
|
||||
}
|
||||
|
||||
item.Id = 0
|
||||
item.Epoch = cmd.TimeEnd / 1000
|
||||
item.Epoch = cmd.TimeEnd
|
||||
|
||||
if err := repo.Save(&item); err != nil {
|
||||
return Error(500, "Failed save annotation for region end time", err)
|
||||
@@ -132,9 +128,6 @@ func PostGraphiteAnnotation(c *m.ReqContext, cmd dtos.PostGraphiteAnnotationsCmd
|
||||
return Error(500, "Failed to save Graphite annotation", err)
|
||||
}
|
||||
|
||||
if cmd.When == 0 {
|
||||
cmd.When = time.Now().Unix()
|
||||
}
|
||||
text := formatGraphiteAnnotation(cmd.What, cmd.Data)
|
||||
|
||||
// Support tags in prior to Graphite 0.10.0 format (string of tags separated by space)
|
||||
@@ -163,7 +156,7 @@ func PostGraphiteAnnotation(c *m.ReqContext, cmd dtos.PostGraphiteAnnotationsCmd
|
||||
item := annotations.Item{
|
||||
OrgId: c.OrgId,
|
||||
UserId: c.UserId,
|
||||
Epoch: cmd.When,
|
||||
Epoch: cmd.When * 1000,
|
||||
Text: text,
|
||||
Tags: tagsArray,
|
||||
}
|
||||
@@ -191,7 +184,7 @@ func UpdateAnnotation(c *m.ReqContext, cmd dtos.UpdateAnnotationsCmd) Response {
|
||||
OrgId: c.OrgId,
|
||||
UserId: c.UserId,
|
||||
Id: annotationID,
|
||||
Epoch: cmd.Time / 1000,
|
||||
Epoch: cmd.Time,
|
||||
Text: cmd.Text,
|
||||
Tags: cmd.Tags,
|
||||
}
|
||||
@@ -203,7 +196,7 @@ func UpdateAnnotation(c *m.ReqContext, cmd dtos.UpdateAnnotationsCmd) Response {
|
||||
if cmd.IsRegion {
|
||||
itemRight := item
|
||||
itemRight.RegionId = item.Id
|
||||
itemRight.Epoch = cmd.TimeEnd / 1000
|
||||
itemRight.Epoch = cmd.TimeEnd
|
||||
|
||||
// We don't know id of region right event, so set it to 0 and find then using query like
|
||||
// ... WHERE region_id = <item.RegionId> AND id != <item.RegionId> ...
|
||||
@@ -301,19 +294,3 @@ func canSave(c *m.ReqContext, repo annotations.Repository, annotationID int64) R
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func canSaveByRegionID(c *m.ReqContext, repo annotations.Repository, regionID int64) Response {
|
||||
items, err := repo.Find(&annotations.ItemQuery{RegionId: regionID, OrgId: c.OrgId})
|
||||
|
||||
if err != nil || len(items) == 0 {
|
||||
return Error(500, "Could not find annotation to update", err)
|
||||
}
|
||||
|
||||
dashboardID := items[0].DashboardId
|
||||
|
||||
if canSave, err := canSaveByDashboardID(c, dashboardID); err != nil || !canSave {
|
||||
return dashboardGuardianResponse(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
// automatically set HEAD for every GET
|
||||
macaronR.SetAutoHead(true)
|
||||
|
||||
r := newRouteRegister(middleware.RequestMetrics, middleware.RequestTracing)
|
||||
r := hs.RouteRegister
|
||||
|
||||
// not logged in views
|
||||
r.Get("/", reqSignedIn, Index)
|
||||
@@ -77,6 +77,9 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
r.Get("/dashboards/", reqSignedIn, Index)
|
||||
r.Get("/dashboards/*", reqSignedIn, Index)
|
||||
|
||||
r.Get("/explore/", reqEditorRole, Index)
|
||||
r.Get("/explore/*", reqEditorRole, Index)
|
||||
|
||||
r.Get("/playlists/", reqSignedIn, Index)
|
||||
r.Get("/playlists/*", reqSignedIn, Index)
|
||||
r.Get("/alerting/", reqSignedIn, Index)
|
||||
@@ -107,7 +110,8 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot)
|
||||
r.Get("/api/snapshot/shared-options/", GetSharingOptions)
|
||||
r.Get("/api/snapshots/:key", GetDashboardSnapshot)
|
||||
r.Get("/api/snapshots-delete/:key", reqEditorRole, wrap(DeleteDashboardSnapshot))
|
||||
r.Get("/api/snapshots-delete/:deleteKey", wrap(DeleteDashboardSnapshotByDeleteKey))
|
||||
r.Delete("/api/snapshots/:key", reqEditorRole, wrap(DeleteDashboardSnapshot))
|
||||
|
||||
// api renew session based on remember cookie
|
||||
r.Get("/api/login/ping", quota("session"), LoginAPIPing)
|
||||
@@ -374,7 +378,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
}, reqGrafanaAdmin)
|
||||
|
||||
// rendering
|
||||
r.Get("/render/*", reqSignedIn, RenderToPng)
|
||||
r.Get("/render/*", reqSignedIn, hs.RenderToPng)
|
||||
|
||||
// grafana.net proxy
|
||||
r.Any("/api/gnet/*", reqSignedIn, ProxyGnetRequest)
|
||||
|
||||
@@ -226,7 +226,7 @@ func (this *thunderTask) Fetch() {
|
||||
this.Done()
|
||||
}
|
||||
|
||||
var client *http.Client = &http.Client{
|
||||
var client = &http.Client{
|
||||
Timeout: time.Second * 2,
|
||||
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
|
||||
}
|
||||
|
||||
@@ -46,6 +46,31 @@ func loggedInUserScenarioWithRole(desc string, method string, url string, routeP
|
||||
})
|
||||
}
|
||||
|
||||
func anonymousUserScenario(desc string, method string, url string, routePattern string, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc.defaultHandler = wrap(func(c *m.ReqContext) Response {
|
||||
sc.context = c
|
||||
if sc.handlerFunc != nil {
|
||||
return sc.handlerFunc(sc.context)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
switch method {
|
||||
case "GET":
|
||||
sc.m.Get(routePattern, sc.defaultHandler)
|
||||
case "DELETE":
|
||||
sc.m.Delete(routePattern, sc.defaultHandler)
|
||||
}
|
||||
|
||||
fn(sc)
|
||||
})
|
||||
}
|
||||
|
||||
func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext {
|
||||
sc.resp = httptest.NewRecorder()
|
||||
req, err := http.NewRequest(method, url, nil)
|
||||
|
||||
@@ -91,11 +91,31 @@ func GetDashboardSnapshot(c *m.ReqContext) {
|
||||
c.JSON(200, dto)
|
||||
}
|
||||
|
||||
// GET /api/snapshots-delete/:key
|
||||
// GET /api/snapshots-delete/:deleteKey
|
||||
func DeleteDashboardSnapshotByDeleteKey(c *m.ReqContext) Response {
|
||||
key := c.Params(":deleteKey")
|
||||
|
||||
query := &m.GetDashboardSnapshotQuery{DeleteKey: key}
|
||||
|
||||
err := bus.Dispatch(query)
|
||||
if err != nil {
|
||||
return Error(500, "Failed to get dashboard snapshot", err)
|
||||
}
|
||||
|
||||
cmd := &m.DeleteDashboardSnapshotCommand{DeleteKey: query.Result.DeleteKey}
|
||||
|
||||
if err := bus.Dispatch(cmd); err != nil {
|
||||
return Error(500, "Failed to delete dashboard snapshot", err)
|
||||
}
|
||||
|
||||
return JSON(200, util.DynMap{"message": "Snapshot deleted. It might take an hour before it's cleared from any CDN caches."})
|
||||
}
|
||||
|
||||
// DELETE /api/snapshots/:key
|
||||
func DeleteDashboardSnapshot(c *m.ReqContext) Response {
|
||||
key := c.Params(":key")
|
||||
|
||||
query := &m.GetDashboardSnapshotQuery{DeleteKey: key}
|
||||
query := &m.GetDashboardSnapshotQuery{Key: key}
|
||||
|
||||
err := bus.Dispatch(query)
|
||||
if err != nil {
|
||||
@@ -118,13 +138,13 @@ func DeleteDashboardSnapshot(c *m.ReqContext) Response {
|
||||
return Error(403, "Access denied to this snapshot", nil)
|
||||
}
|
||||
|
||||
cmd := &m.DeleteDashboardSnapshotCommand{DeleteKey: key}
|
||||
cmd := &m.DeleteDashboardSnapshotCommand{DeleteKey: query.Result.DeleteKey}
|
||||
|
||||
if err := bus.Dispatch(cmd); err != nil {
|
||||
return Error(500, "Failed to delete dashboard snapshot", err)
|
||||
}
|
||||
|
||||
return JSON(200, util.DynMap{"message": "Snapshot deleted. It might take an hour before it's cleared from a CDN cache."})
|
||||
return JSON(200, util.DynMap{"message": "Snapshot deleted. It might take an hour before it's cleared from any CDN caches."})
|
||||
}
|
||||
|
||||
// GET /api/dashboard/snapshots
|
||||
@@ -154,7 +174,6 @@ func SearchDashboardSnapshots(c *m.ReqContext) Response {
|
||||
Id: snapshot.Id,
|
||||
Name: snapshot.Name,
|
||||
Key: snapshot.Key,
|
||||
DeleteKey: snapshot.DeleteKey,
|
||||
OrgId: snapshot.OrgId,
|
||||
UserId: snapshot.UserId,
|
||||
External: snapshot.External,
|
||||
|
||||
@@ -47,15 +47,30 @@ func TestDashboardSnapshotApiEndpoint(t *testing.T) {
|
||||
|
||||
Convey("When user has editor role and is not in the ACL", func() {
|
||||
Convey("Should not be able to delete snapshot", func() {
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/snapshots-delete/12345", "/api/snapshots-delete/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is anonymous", func() {
|
||||
Convey("Should be able to delete snapshot by deleteKey", func() {
|
||||
anonymousUserScenario("When calling GET on", "GET", "/api/snapshots-delete/12345", "/api/snapshots-delete/:deleteKey", func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteDashboardSnapshotByDeleteKey
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"deleteKey": "12345"}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(respJSON.Get("message").MustString(), ShouldStartWith, "Snapshot deleted")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is editor and dashboard has default ACL", func() {
|
||||
aclMockResp = []*m.DashboardAclInfoDTO{
|
||||
{Role: &viewerRole, Permission: m.PERMISSION_VIEW},
|
||||
@@ -63,9 +78,9 @@ func TestDashboardSnapshotApiEndpoint(t *testing.T) {
|
||||
}
|
||||
|
||||
Convey("Should be able to delete a snapshot", func() {
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/snapshots-delete/12345", "/api/snapshots-delete/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
@@ -81,9 +96,9 @@ func TestDashboardSnapshotApiEndpoint(t *testing.T) {
|
||||
mockSnapshotResult.UserId = TestUserID
|
||||
|
||||
Convey("Should be able to delete a snapshot", func() {
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/snapshots-delete/12345", "/api/snapshots-delete/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", m.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
|
||||
@@ -22,21 +22,22 @@ type LoginCommand struct {
|
||||
}
|
||||
|
||||
type CurrentUser struct {
|
||||
IsSignedIn bool `json:"isSignedIn"`
|
||||
Id int64 `json:"id"`
|
||||
Login string `json:"login"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
LightTheme bool `json:"lightTheme"`
|
||||
OrgCount int `json:"orgCount"`
|
||||
OrgId int64 `json:"orgId"`
|
||||
OrgName string `json:"orgName"`
|
||||
OrgRole m.RoleType `json:"orgRole"`
|
||||
IsGrafanaAdmin bool `json:"isGrafanaAdmin"`
|
||||
GravatarUrl string `json:"gravatarUrl"`
|
||||
Timezone string `json:"timezone"`
|
||||
Locale string `json:"locale"`
|
||||
HelpFlags1 m.HelpFlags1 `json:"helpFlags1"`
|
||||
IsSignedIn bool `json:"isSignedIn"`
|
||||
Id int64 `json:"id"`
|
||||
Login string `json:"login"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
LightTheme bool `json:"lightTheme"`
|
||||
OrgCount int `json:"orgCount"`
|
||||
OrgId int64 `json:"orgId"`
|
||||
OrgName string `json:"orgName"`
|
||||
OrgRole m.RoleType `json:"orgRole"`
|
||||
IsGrafanaAdmin bool `json:"isGrafanaAdmin"`
|
||||
GravatarUrl string `json:"gravatarUrl"`
|
||||
Timezone string `json:"timezone"`
|
||||
Locale string `json:"locale"`
|
||||
HelpFlags1 m.HelpFlags1 `json:"helpFlags1"`
|
||||
HasEditPermissionInFolders bool `json:"hasEditPermissionInFolders"`
|
||||
}
|
||||
|
||||
type MetricRequest struct {
|
||||
@@ -51,7 +52,7 @@ type UserStars struct {
|
||||
|
||||
func GetGravatarUrl(text string) string {
|
||||
if setting.DisableGravatar {
|
||||
return "/public/img/user_profile.png"
|
||||
return setting.AppSubUrl + "/public/img/user_profile.png"
|
||||
}
|
||||
|
||||
if text == "" {
|
||||
|
||||
@@ -57,4 +57,5 @@ type ImportDashboardCommand struct {
|
||||
Overwrite bool `json:"overwrite"`
|
||||
Dashboard *simplejson.Json `json:"dashboard"`
|
||||
Inputs []plugins.ImportDashboardInput `json:"inputs"`
|
||||
FolderId int64 `json:"folderId"`
|
||||
}
|
||||
|
||||
@@ -140,6 +140,7 @@ func getFrontendSettingsMap(c *m.ReqContext) (map[string]interface{}, error) {
|
||||
"authProxyEnabled": setting.AuthProxyEnabled,
|
||||
"ldapEnabled": setting.LdapEnabled,
|
||||
"alertingEnabled": setting.AlertingEnabled,
|
||||
"exploreEnabled": setting.ExploreEnabled,
|
||||
"googleAnalyticsId": setting.GoogleAnalyticsId,
|
||||
"disableLoginForm": setting.DisableLoginForm,
|
||||
"externalUserMngInfo": setting.ExternalUserMngInfo,
|
||||
|
||||
@@ -26,27 +26,37 @@ import (
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/services/rendering"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.RegisterService(&HTTPServer{})
|
||||
}
|
||||
|
||||
type HTTPServer struct {
|
||||
log log.Logger
|
||||
macaron *macaron.Macaron
|
||||
context context.Context
|
||||
streamManager *live.StreamManager
|
||||
cache *gocache.Cache
|
||||
httpSrv *http.Server
|
||||
|
||||
httpSrv *http.Server
|
||||
RouteRegister RouteRegister `inject:""`
|
||||
Bus bus.Bus `inject:""`
|
||||
RenderService rendering.Service `inject:""`
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
}
|
||||
|
||||
func NewHTTPServer() *HTTPServer {
|
||||
return &HTTPServer{
|
||||
log: log.New("http.server"),
|
||||
cache: gocache.New(5*time.Minute, 10*time.Minute),
|
||||
}
|
||||
func (hs *HTTPServer) Init() error {
|
||||
hs.log = log.New("http.server")
|
||||
hs.cache = gocache.New(5*time.Minute, 10*time.Minute)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) Start(ctx context.Context) error {
|
||||
func (hs *HTTPServer) Run(ctx context.Context) error {
|
||||
var err error
|
||||
|
||||
hs.context = ctx
|
||||
@@ -57,9 +67,20 @@ func (hs *HTTPServer) Start(ctx context.Context) error {
|
||||
hs.streamManager.Run(ctx)
|
||||
|
||||
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
|
||||
hs.log.Info("Initializing HTTP Server", "address", listenAddr, "protocol", setting.Protocol, "subUrl", setting.AppSubUrl, "socket", setting.SocketPath)
|
||||
hs.log.Info("HTTP Server Listen", "address", listenAddr, "protocol", setting.Protocol, "subUrl", setting.AppSubUrl, "socket", setting.SocketPath)
|
||||
|
||||
hs.httpSrv = &http.Server{Addr: listenAddr, Handler: hs.macaron}
|
||||
|
||||
// handle http shutdown on server context done
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
// Hacky fix for race condition between ListenAndServe and Shutdown
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
if err := hs.httpSrv.Shutdown(context.Background()); err != nil {
|
||||
hs.log.Error("Failed to shutdown server", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
switch setting.Protocol {
|
||||
case setting.HTTP:
|
||||
err = hs.httpSrv.ListenAndServe()
|
||||
@@ -96,12 +117,6 @@ func (hs *HTTPServer) Start(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) Shutdown(ctx context.Context) error {
|
||||
err := hs.httpSrv.Shutdown(ctx)
|
||||
hs.log.Info("Stopped HTTP server")
|
||||
return err
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) listenAndServeTLS(certfile, keyfile string) error {
|
||||
if certfile == "" {
|
||||
return fmt.Errorf("cert_file cannot be empty when using HTTPS")
|
||||
@@ -162,11 +177,12 @@ func (hs *HTTPServer) newMacaron() *macaron.Macaron {
|
||||
hs.mapStatic(m, route.Directory, "", pluginRoute)
|
||||
}
|
||||
|
||||
hs.mapStatic(m, setting.StaticRootPath, "build", "public/build")
|
||||
hs.mapStatic(m, setting.StaticRootPath, "", "public")
|
||||
hs.mapStatic(m, setting.StaticRootPath, "robots.txt", "robots.txt")
|
||||
|
||||
if setting.ImageUploadProvider == "local" {
|
||||
hs.mapStatic(m, setting.ImagesDir, "", "/public/img/attachments")
|
||||
hs.mapStatic(m, hs.Cfg.ImagesDir, "", "/public/img/attachments")
|
||||
}
|
||||
|
||||
m.Use(macaron.Renderer(macaron.RenderOptions{
|
||||
@@ -229,6 +245,12 @@ func (hs *HTTPServer) mapStatic(m *macaron.Macaron, rootDir string, dir string,
|
||||
c.Resp.Header().Set("Cache-Control", "public, max-age=3600")
|
||||
}
|
||||
|
||||
if prefix == "public/build" {
|
||||
headers = func(c *macaron.Context) {
|
||||
c.Resp.Header().Set("Cache-Control", "public, max-age=31536000")
|
||||
}
|
||||
}
|
||||
|
||||
if setting.Env == setting.DEV {
|
||||
headers = func(c *macaron.Context) {
|
||||
c.Resp.Header().Set("Cache-Control", "max-age=0, must-revalidate, no-cache")
|
||||
|
||||
@@ -42,23 +42,29 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
|
||||
settings["appSubUrl"] = ""
|
||||
}
|
||||
|
||||
hasEditPermissionInFoldersQuery := m.HasEditPermissionInFoldersQuery{SignedInUser: c.SignedInUser}
|
||||
if err := bus.Dispatch(&hasEditPermissionInFoldersQuery); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var data = dtos.IndexViewData{
|
||||
User: &dtos.CurrentUser{
|
||||
Id: c.UserId,
|
||||
IsSignedIn: c.IsSignedIn,
|
||||
Login: c.Login,
|
||||
Email: c.Email,
|
||||
Name: c.Name,
|
||||
OrgCount: c.OrgCount,
|
||||
OrgId: c.OrgId,
|
||||
OrgName: c.OrgName,
|
||||
OrgRole: c.OrgRole,
|
||||
GravatarUrl: dtos.GetGravatarUrl(c.Email),
|
||||
IsGrafanaAdmin: c.IsGrafanaAdmin,
|
||||
LightTheme: prefs.Theme == "light",
|
||||
Timezone: prefs.Timezone,
|
||||
Locale: locale,
|
||||
HelpFlags1: c.HelpFlags1,
|
||||
Id: c.UserId,
|
||||
IsSignedIn: c.IsSignedIn,
|
||||
Login: c.Login,
|
||||
Email: c.Email,
|
||||
Name: c.Name,
|
||||
OrgCount: c.OrgCount,
|
||||
OrgId: c.OrgId,
|
||||
OrgName: c.OrgName,
|
||||
OrgRole: c.OrgRole,
|
||||
GravatarUrl: dtos.GetGravatarUrl(c.Email),
|
||||
IsGrafanaAdmin: c.IsGrafanaAdmin,
|
||||
LightTheme: prefs.Theme == "light",
|
||||
Timezone: prefs.Timezone,
|
||||
Locale: locale,
|
||||
HelpFlags1: c.HelpFlags1,
|
||||
HasEditPermissionInFolders: hasEditPermissionInFoldersQuery.Result,
|
||||
},
|
||||
Settings: settings,
|
||||
Theme: prefs.Theme,
|
||||
@@ -86,17 +92,23 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
|
||||
data.Theme = "light"
|
||||
}
|
||||
|
||||
if c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR {
|
||||
if hasEditPermissionInFoldersQuery.Result {
|
||||
children := []*dtos.NavLink{
|
||||
{Text: "Dashboard", Icon: "gicon gicon-dashboard-new", Url: setting.AppSubUrl + "/dashboard/new"},
|
||||
}
|
||||
|
||||
if c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR {
|
||||
children = append(children, &dtos.NavLink{Text: "Folder", SubTitle: "Create a new folder to organize your dashboards", Id: "folder", Icon: "gicon gicon-folder-new", Url: setting.AppSubUrl + "/dashboards/folder/new"})
|
||||
}
|
||||
|
||||
children = append(children, &dtos.NavLink{Text: "Import", SubTitle: "Import dashboard from file or Grafana.com", Id: "import", Icon: "gicon gicon-dashboard-import", Url: setting.AppSubUrl + "/dashboard/import"})
|
||||
|
||||
data.NavTree = append(data.NavTree, &dtos.NavLink{
|
||||
Text: "Create",
|
||||
Id: "create",
|
||||
Icon: "fa fa-fw fa-plus",
|
||||
Url: setting.AppSubUrl + "/dashboard/new",
|
||||
Children: []*dtos.NavLink{
|
||||
{Text: "Dashboard", Icon: "gicon gicon-dashboard-new", Url: setting.AppSubUrl + "/dashboard/new"},
|
||||
{Text: "Folder", SubTitle: "Create a new folder to organize your dashboards", Id: "folder", Icon: "gicon gicon-folder-new", Url: setting.AppSubUrl + "/dashboards/folder/new"},
|
||||
{Text: "Import", SubTitle: "Import dashboard from file or Grafana.com", Id: "import", Icon: "gicon gicon-dashboard-import", Url: setting.AppSubUrl + "/dashboard/import"},
|
||||
},
|
||||
Text: "Create",
|
||||
Id: "create",
|
||||
Icon: "fa fa-fw fa-plus",
|
||||
Url: setting.AppSubUrl + "/dashboard/new",
|
||||
Children: children,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -117,6 +129,19 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
|
||||
Children: dashboardChildNavs,
|
||||
})
|
||||
|
||||
if setting.ExploreEnabled && (c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR) {
|
||||
data.NavTree = append(data.NavTree, &dtos.NavLink{
|
||||
Text: "Explore",
|
||||
Id: "explore",
|
||||
SubTitle: "Explore your data",
|
||||
Icon: "fa fa-rocket",
|
||||
Url: setting.AppSubUrl + "/explore",
|
||||
Children: []*dtos.NavLink{
|
||||
{Text: "New tab", Icon: "gicon gicon-dashboard-new", Url: setting.AppSubUrl + "/explore"},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if c.IsSignedIn {
|
||||
// Only set login if it's different from the name
|
||||
var login string
|
||||
@@ -209,7 +234,7 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if c.OrgRole == m.ROLE_ADMIN {
|
||||
if c.IsGrafanaAdmin || c.OrgRole == m.ROLE_ADMIN {
|
||||
cfgNode := &dtos.NavLink{
|
||||
Id: "cfg",
|
||||
Text: "Configuration",
|
||||
@@ -263,10 +288,24 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
|
||||
},
|
||||
}
|
||||
|
||||
if c.IsGrafanaAdmin {
|
||||
if c.OrgRole != m.ROLE_ADMIN {
|
||||
cfgNode = &dtos.NavLink{
|
||||
Id: "cfg",
|
||||
Text: "Configuration",
|
||||
SubTitle: "Organization: " + c.OrgName,
|
||||
Icon: "gicon gicon-cog",
|
||||
Url: setting.AppSubUrl + "/admin/users",
|
||||
Children: make([]*dtos.NavLink, 0),
|
||||
}
|
||||
}
|
||||
|
||||
if c.OrgRole == m.ROLE_ADMIN && c.IsGrafanaAdmin {
|
||||
cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{
|
||||
Divider: true, HideFromTabs: true, Id: "admin-divider", Text: "Text",
|
||||
})
|
||||
}
|
||||
|
||||
if c.IsGrafanaAdmin {
|
||||
cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{
|
||||
Text: "Server Admin",
|
||||
HideFromTabs: true,
|
||||
@@ -289,7 +328,7 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
|
||||
|
||||
data.NavTree = append(data.NavTree, &dtos.NavLink{
|
||||
Text: "Help",
|
||||
SubTitle: fmt.Sprintf(`Grafana v%s (%s)`, setting.BuildVersion, setting.BuildCommit),
|
||||
SubTitle: fmt.Sprintf(`%s v%s (%s)`, setting.ApplicationName, setting.BuildVersion, setting.BuildCommit),
|
||||
Id: "help",
|
||||
Url: "#",
|
||||
Icon: "gicon gicon-question",
|
||||
|
||||
@@ -78,7 +78,13 @@ func tryLoginUsingRememberCookie(c *m.ReqContext) bool {
|
||||
user := userQuery.Result
|
||||
|
||||
// validate remember me cookie
|
||||
if val, _ := c.GetSuperSecureCookie(user.Rands+user.Password, setting.CookieRememberName); val != user.Login {
|
||||
signingKey := user.Rands + user.Password
|
||||
if len(signingKey) < 10 {
|
||||
c.Logger.Error("Invalid user signingKey")
|
||||
return false
|
||||
}
|
||||
|
||||
if val, _ := c.GetSuperSecureCookie(signingKey, setting.CookieRememberName); val != user.Login {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -155,5 +161,9 @@ func Logout(c *m.ReqContext) {
|
||||
c.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl+"/")
|
||||
c.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl+"/")
|
||||
c.Session.Destory(c.Context)
|
||||
c.Redirect(setting.AppSubUrl + "/login")
|
||||
if setting.SignoutRedirectUrl != "" {
|
||||
c.Redirect(setting.SignoutRedirectUrl)
|
||||
} else {
|
||||
c.Redirect(setting.AppSubUrl + "/login")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ func OAuthLogin(ctx *m.ReqContext) {
|
||||
|
||||
// handle call back
|
||||
tr := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: setting.OAuthService.OAuthInfos[name].TlsSkipVerify,
|
||||
},
|
||||
|
||||
@@ -74,6 +74,9 @@ func AddOrgInvite(c *m.ReqContext, inviteDto dtos.AddInviteForm) Response {
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&emailCmd); err != nil {
|
||||
if err == m.ErrSmtpNotEnabled {
|
||||
return Error(412, err.Error(), err)
|
||||
}
|
||||
return Error(500, "Failed to send email invite", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
logger = log.New("data-proxy-log")
|
||||
client = &http.Client{
|
||||
Timeout: time.Second * 30,
|
||||
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
|
||||
}
|
||||
tokenCache = map[int64]*jwtToken{}
|
||||
logger = log.New("data-proxy-log")
|
||||
tokenCache = map[string]*jwtToken{}
|
||||
client = newHTTPClient()
|
||||
)
|
||||
|
||||
type jwtToken struct {
|
||||
@@ -48,6 +45,10 @@ type DataSourceProxy struct {
|
||||
plugin *plugins.DataSourcePlugin
|
||||
}
|
||||
|
||||
type httpClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
func NewDataSourceProxy(ds *m.DataSource, plugin *plugins.DataSourcePlugin, ctx *m.ReqContext, proxyPath string) *DataSourceProxy {
|
||||
targetURL, _ := url.Parse(ds.Url)
|
||||
|
||||
@@ -60,6 +61,13 @@ func NewDataSourceProxy(ds *m.DataSource, plugin *plugins.DataSourcePlugin, ctx
|
||||
}
|
||||
}
|
||||
|
||||
func newHTTPClient() httpClient {
|
||||
return &http.Client{
|
||||
Timeout: time.Second * 30,
|
||||
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
|
||||
}
|
||||
}
|
||||
|
||||
func (proxy *DataSourceProxy) HandleRequest() {
|
||||
if err := proxy.validateRequest(); err != nil {
|
||||
proxy.ctx.JsonApiErr(403, err.Error(), nil)
|
||||
@@ -311,7 +319,7 @@ func (proxy *DataSourceProxy) applyRoute(req *http.Request) {
|
||||
}
|
||||
|
||||
func (proxy *DataSourceProxy) getAccessToken(data templateData) (string, error) {
|
||||
if cachedToken, found := tokenCache[proxy.ds.Id]; found {
|
||||
if cachedToken, found := tokenCache[proxy.getAccessTokenCacheKey()]; found {
|
||||
if cachedToken.ExpiresOn.After(time.Now().Add(time.Second * 10)) {
|
||||
logger.Info("Using token from cache")
|
||||
return cachedToken.AccessToken, nil
|
||||
@@ -350,12 +358,16 @@ func (proxy *DataSourceProxy) getAccessToken(data templateData) (string, error)
|
||||
|
||||
expiresOnEpoch, _ := strconv.ParseInt(token.ExpiresOnString, 10, 64)
|
||||
token.ExpiresOn = time.Unix(expiresOnEpoch, 0)
|
||||
tokenCache[proxy.ds.Id] = &token
|
||||
tokenCache[proxy.getAccessTokenCacheKey()] = &token
|
||||
|
||||
logger.Info("Got new access token", "ExpiresOn", token.ExpiresOn)
|
||||
return token.AccessToken, nil
|
||||
}
|
||||
|
||||
func (proxy *DataSourceProxy) getAccessTokenCacheKey() string {
|
||||
return fmt.Sprintf("%v_%v_%v", proxy.ds.Id, proxy.route.Path, proxy.route.Method)
|
||||
}
|
||||
|
||||
func interpolateString(text string, data templateData) (string, error) {
|
||||
t, err := template.New("content").Parse(text)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package pluginproxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
|
||||
@@ -100,6 +104,112 @@ func TestDSRouteRule(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Plugin with multiple routes for token auth", func() {
|
||||
plugin := &plugins.DataSourcePlugin{
|
||||
Routes: []*plugins.AppPluginRoute{
|
||||
{
|
||||
Path: "pathwithtoken1",
|
||||
Url: "https://api.nr1.io/some/path",
|
||||
TokenAuth: &plugins.JwtTokenAuth{
|
||||
Url: "https://login.server.com/{{.JsonData.tenantId}}/oauth2/token",
|
||||
Params: map[string]string{
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": "{{.JsonData.clientId}}",
|
||||
"client_secret": "{{.SecureJsonData.clientSecret}}",
|
||||
"resource": "https://api.nr1.io",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "pathwithtoken2",
|
||||
Url: "https://api.nr2.io/some/path",
|
||||
TokenAuth: &plugins.JwtTokenAuth{
|
||||
Url: "https://login.server.com/{{.JsonData.tenantId}}/oauth2/token",
|
||||
Params: map[string]string{
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": "{{.JsonData.clientId}}",
|
||||
"client_secret": "{{.SecureJsonData.clientSecret}}",
|
||||
"resource": "https://api.nr2.io",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
setting.SecretKey = "password"
|
||||
key, _ := util.Encrypt([]byte("123"), "password")
|
||||
|
||||
ds := &m.DataSource{
|
||||
JsonData: simplejson.NewFromAny(map[string]interface{}{
|
||||
"clientId": "asd",
|
||||
"tenantId": "mytenantId",
|
||||
}),
|
||||
SecureJsonData: map[string][]byte{
|
||||
"clientSecret": key,
|
||||
},
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest("GET", "http://localhost/asd", nil)
|
||||
ctx := &m.ReqContext{
|
||||
Context: &macaron.Context{
|
||||
Req: macaron.Request{Request: req},
|
||||
},
|
||||
SignedInUser: &m.SignedInUser{OrgRole: m.ROLE_EDITOR},
|
||||
}
|
||||
|
||||
Convey("When creating and caching access tokens", func() {
|
||||
var authorizationHeaderCall1 string
|
||||
var authorizationHeaderCall2 string
|
||||
|
||||
Convey("first call should add authorization header with access token", func() {
|
||||
json, err := ioutil.ReadFile("./test-data/access-token-1.json")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
client = newFakeHTTPClient(json)
|
||||
proxy1 := NewDataSourceProxy(ds, plugin, ctx, "pathwithtoken1")
|
||||
proxy1.route = plugin.Routes[0]
|
||||
proxy1.applyRoute(req)
|
||||
|
||||
authorizationHeaderCall1 = req.Header.Get("Authorization")
|
||||
So(req.URL.String(), ShouldEqual, "https://api.nr1.io/some/path")
|
||||
So(authorizationHeaderCall1, ShouldStartWith, "Bearer eyJ0e")
|
||||
|
||||
Convey("second call to another route should add a different access token", func() {
|
||||
json2, err := ioutil.ReadFile("./test-data/access-token-2.json")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
req, _ := http.NewRequest("GET", "http://localhost/asd", nil)
|
||||
client = newFakeHTTPClient(json2)
|
||||
proxy2 := NewDataSourceProxy(ds, plugin, ctx, "pathwithtoken2")
|
||||
proxy2.route = plugin.Routes[1]
|
||||
proxy2.applyRoute(req)
|
||||
|
||||
authorizationHeaderCall2 = req.Header.Get("Authorization")
|
||||
|
||||
So(req.URL.String(), ShouldEqual, "https://api.nr2.io/some/path")
|
||||
So(authorizationHeaderCall1, ShouldStartWith, "Bearer eyJ0e")
|
||||
So(authorizationHeaderCall2, ShouldStartWith, "Bearer eyJ0e")
|
||||
So(authorizationHeaderCall2, ShouldNotEqual, authorizationHeaderCall1)
|
||||
|
||||
Convey("third call to first route should add cached access token", func() {
|
||||
req, _ := http.NewRequest("GET", "http://localhost/asd", nil)
|
||||
|
||||
client = newFakeHTTPClient([]byte{})
|
||||
proxy3 := NewDataSourceProxy(ds, plugin, ctx, "pathwithtoken1")
|
||||
proxy3.route = plugin.Routes[0]
|
||||
proxy3.applyRoute(req)
|
||||
|
||||
authorizationHeaderCall3 := req.Header.Get("Authorization")
|
||||
So(req.URL.String(), ShouldEqual, "https://api.nr1.io/some/path")
|
||||
So(authorizationHeaderCall1, ShouldStartWith, "Bearer eyJ0e")
|
||||
So(authorizationHeaderCall3, ShouldStartWith, "Bearer eyJ0e")
|
||||
So(authorizationHeaderCall3, ShouldEqual, authorizationHeaderCall1)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When proxying graphite", func() {
|
||||
plugin := &plugins.DataSourcePlugin{}
|
||||
ds := &m.DataSource{Url: "htttp://graphite:8080", Type: m.DS_GRAPHITE}
|
||||
@@ -214,3 +324,27 @@ func TestDSRouteRule(t *testing.T) {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
type httpClientStub struct {
|
||||
fakeBody []byte
|
||||
}
|
||||
|
||||
func (c *httpClientStub) Do(req *http.Request) (*http.Response, error) {
|
||||
bodyJSON, _ := simplejson.NewJson(c.fakeBody)
|
||||
_, passedTokenCacheTest := bodyJSON.CheckGet("expires_on")
|
||||
So(passedTokenCacheTest, ShouldBeTrue)
|
||||
|
||||
bodyJSON.Set("expires_on", fmt.Sprint(time.Now().Add(time.Second*60).Unix()))
|
||||
body, _ := bodyJSON.MarshalJSON()
|
||||
resp := &http.Response{
|
||||
Body: ioutil.NopCloser(bytes.NewReader(body)),
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func newFakeHTTPClient(fakeBody []byte) httpClient {
|
||||
return &httpClientStub{
|
||||
fakeBody: fakeBody,
|
||||
}
|
||||
}
|
||||
|
||||
9
pkg/api/pluginproxy/test-data/access-token-1.json
Normal file
9
pkg/api/pluginproxy/test-data/access-token-1.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"token_type": "Bearer",
|
||||
"expires_in": "3599",
|
||||
"ext_expires_in": "0",
|
||||
"expires_on": "1528740417",
|
||||
"not_before": "1528736517",
|
||||
"resource": "https://api.nr1.io",
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImlCakwxUmNxemhpeTRmcHhJeGRacW9oTTJZayIsImtpZCI6ImlCakwxUmNxemhpeTRmcHhJeGRacW9oTTJZayJ9.eyJhdWQiOiJodHRwczovL2FwaS5sb2dhbmFseXRpY3MuaW8iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9lN2YzZjY2MS1hOTMzLTRiM2YtODE3Ni01MWM0Zjk4MmVjNDgvIiwiaWF0IjoxNTI4NzM2NTE3LCJuYmYiOjE1Mjg3MzY1MTcsImV4cCI6MTUyODc0MDQxNywiYWlvIjoiWTJkZ1lBaStzaWRsT3NmQ2JicGhLMSsremttN0NBQT0iLCJhcHBpZCI6IjdmMzJkYjdjLTZmNmYtNGU4OC05M2Q5LTlhZTEyNmMwYTU1ZiIsImFwcGlkYWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2U3ZjNmNjYxLWE5MzMtNGIzZi04MTc2LTUxYzRmOTgyZWM0OC8iLCJvaWQiOiI1NDQ5ZmJjOS1mYWJhLTRkNjItODE2Yy05ZmMwMzZkMWViN2UiLCJzdWIiOiI1NDQ5ZmJjOS1mYWJhLTRkNjItODE2Yy05ZmMwMzZkMWViN2UiLCJ0aWQiOiJlN2YzZjY2MS1hOTMzLTRiM2YtODE3Ni01MWM0Zjk4MmVjNDgiLCJ1dGkiOiJZQTlQa2lxUy1VV1hMQjhIRnU0U0FBIiwidmVyIjoiMS4wIn0.ga5qudt4LDMKTStAxUmzjyZH8UFBAaFirJqpTdmYny4NtkH6JT2EILvjTjYxlKeTQisvwx9gof0PyicZIab9d6wlMa2xiLzr2nmaOonYClY8fqBaRTgc1xVjrKFw5SCgpx3FnEyJhIWvVPIfaWaogSHcQbIpe4kdk4tz-ccmrx0D1jsziSI4BZcJcX04aJuHZGz9k4mQZ_AA5sQSeQaNuojIng6rYoIifAXFYBZPTbeeeqmiGq8v0IOLeNKbC0POeQCJC_KKBG6Z_MV2KgPxFEzQuX2ZFmRD_wGPteV5TUBxh1kARdqexA3e0zAKSawR9kmrAiZ21lPr4tX2Br_HDg"
|
||||
}
|
||||
9
pkg/api/pluginproxy/test-data/access-token-2.json
Normal file
9
pkg/api/pluginproxy/test-data/access-token-2.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"token_type": "Bearer",
|
||||
"expires_in": "3599",
|
||||
"ext_expires_in": "0",
|
||||
"expires_on": "1528662059",
|
||||
"not_before": "1528658159",
|
||||
"resource": "https://api.nr2.io",
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImlCakwxUmNxemhpeTRmcHhJeGRacW9oTTJZayIsImtpZCI6ImlCakwxUmNxemhpeTRmcHhJeGRacW9oTTJZayJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2U3ZjNmNjYxLWE5MzMtNGIzZi04MTc2LTUxYzRmOTgyZWM0OC8iLCJpYXQiOjE1Mjg2NTgxNTksIm5iZiI6MTUyODY1ODE1OSwiZXhwIjoxNTI4NjYyMDU5LCJhaW8iOiJZMmRnWUFpK3NpZGxPc2ZDYmJwaEsxKyt6a203Q0FBPSIsImFwcGlkIjoiODg5YjdlZDgtMWFlZC00ODZlLTk3ODktODE5NzcwYmJiNjFhIiwiYXBwaWRhY3IiOiIxIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvZTdmM2Y2NjEtYTkzMy00YjNmLTgxNzYtNTFjNGY5ODJlYzQ4LyIsIm9pZCI6IjY0YzQxNjMyLTliOWUtNDczNy05MTYwLTBlNjAzZTg3NjljYyIsInN1YiI6IjY0YzQxNjMyLTliOWUtNDczNy05MTYwLTBlNjAzZTg3NjljYyIsInRpZCI6ImU3ZjNmNjYxLWE5MzMtNGIzZi04MTc2LTUxYzRmOTgyZWM0OCIsInV0aSI6IkQ1ODZHSGUySDBPd0ptOU0xeVlKQUEiLCJ2ZXIiOiIxLjAifQ.Pw8c8gpoZptw3lGreQoHQaMVOozSaTE5D38Vm2aCHRB3DvD3N-Qcm1x0ZCakUEV2sJd7jvx4XtPFuW7063T0V1deExL4rzzvIo0ZfMmURf9tCTiKFKYibqf8_PtfPSz0t9eNDEUGmWDh1Wgssb4W_H-wPqgl9VPMT7T6ynkfIm0-ODPZTBzgSHiY8C_L1-DkhsK7XiqbUlSDgx9FpfChZS3ah8QhA8geqnb_HVuSktg7WhpxmogSpK5QdrwSE3jsbItpzOfLJ4iBd2ExzS2C0y8H_Coluk3Y1YA07tAxJ6Y7oBv-XwGqNfZhveOCQOzX-U3dFod3fXXysjB0UB89WQ"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user