Skip to content

Commit b72e30b

Browse files
committed
Fix collect_datasource_items when hitting special templated datasource
The machinery croaked on `"value": ["$__all"]`. This will get skipped now, but a warning will be emitted.
1 parent 5d555fa commit b72e30b

File tree

4 files changed

+70
-13
lines changed

4 files changed

+70
-13
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ grafana-wtf changelog
55

66
in progress
77
===========
8+
- Fix ``collect_datasource_items`` when hitting special templated datasource.
9+
Thanks, @mauhiz.
810

911
2023-02-09 0.14.0
1012
=================

grafana_wtf/core.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
DatasourceItem,
2828
GrafanaDataModel,
2929
)
30-
from grafana_wtf.util import JsonPathFinder, as_bool
30+
from grafana_wtf.util import JsonPathFinder, as_bool, to_list
3131

3232
log = logging.getLogger(__name__)
3333

@@ -499,28 +499,40 @@ def index(self):
499499
def collect_datasource_items(self, element):
500500
element = element or []
501501
items = []
502+
503+
def add(item):
504+
if item is not None and item not in items:
505+
items.append(item)
506+
502507
for node in element:
503-
ds = None
504508

505509
# Directly defined datasources.
506510
if "datasource" in node and node["datasource"]:
507511
ds = node.datasource
508-
if isinstance(ds, Munch):
512+
if isinstance(ds, str):
513+
add(ds)
514+
elif isinstance(ds, Munch):
509515
ds = dict(ds)
516+
add(ds)
517+
continue
510518

511519
# Datasources defined as variables.
512520
if "type" in node and node["type"] == "datasource":
513-
ds_name = node.get("current", {}).get("value")
514-
datasource = self.datasource_by_name.get(ds_name, {})
515-
ds = dict(
516-
type=datasource.get("type"),
517-
uid=datasource.get("uid"),
518-
name=datasource.get("name"),
519-
url=datasource.get("url"),
520-
)
521+
values = to_list(node.get("current", {}).get("value"))
522+
for ds_name in values:
523+
datasource = self.datasource_by_name.get(ds_name)
524+
if datasource is None:
525+
log.warning(f"Data source '{ds_name}' not found")
526+
continue
527+
ds = dict(
528+
type=datasource.get("type"),
529+
uid=datasource.get("uid"),
530+
name=datasource.get("name"),
531+
url=datasource.get("url"),
532+
)
533+
add(ds)
534+
continue
521535

522-
if ds is not None and ds not in items:
523-
items.append(ds)
524536
return items
525537

526538
def index_dashboards(self):

grafana_wtf/util.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,9 @@ def format_dict(data) -> str:
165165
output.write(entry)
166166
output.seek(0)
167167
return output.read().rstrip()
168+
169+
170+
def to_list(value):
171+
if not isinstance(value, list):
172+
value = [value]
173+
return value

tests/test_core.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from unittest.mock import Mock
2+
3+
from munch import Munch
4+
5+
from grafana_wtf.core import Indexer
6+
7+
8+
def test_collect_datasource_items_variable_all():
9+
"""
10+
Verify fix for `TypeError: unhashable type: 'list'` in `collect_datasource_items`.
11+
12+
https://github.com/panodata/grafana-wtf/issues/62
13+
"""
14+
node = Munch(
15+
{
16+
"current": Munch({"selected": True, "text": ["All"], "value": ["$__all"]}),
17+
"hide": 0,
18+
"includeAll": True,
19+
"multi": True,
20+
"name": "datasource",
21+
"options": [],
22+
"query": "prometheus",
23+
"queryValue": "",
24+
"refresh": 1,
25+
"regex": "/.*-storage$/",
26+
"skipUrlSync": False,
27+
"type": "datasource",
28+
}
29+
)
30+
engine_mock = Mock(
31+
scan_datasources=Mock(return_value=[]),
32+
scan_dashboards=Mock(return_value=[]),
33+
dashboard_details=Mock(return_value=[]),
34+
)
35+
indexer = Indexer(engine=engine_mock)
36+
result = indexer.collect_datasource_items([node])
37+
assert result == []

0 commit comments

Comments
 (0)