Merge "Add import of json files"

This commit is contained in:
Zuul 2021-05-07 01:31:49 +00:00 committed by Gerrit Code Review
commit 39d8bd1d84
6 changed files with 182 additions and 17 deletions

View File

@ -52,6 +52,11 @@ For example, here is a minimal dashboard specification
environments. Users can specify their dashboards via a normal review
process and tests can validate their correctness.
The tool can also take JSON manually exported from the Grafana
interface and load it as a dashboard. This allows keeping dashboards
that have been edited with the inbuilt editor externally version
controlled.
A large number of examples are available in the OpenStack
`project-config
<https://git.openstack.org/cgit/openstack-infra/project-config/tree/grafana>`__

View File

@ -38,7 +38,8 @@ Update Command
``grafana-dashboard`` [options] update <path>
Updates each specified dashboard to the lastest layout from parsed yaml files.
Updates each specified dashboard to the lastest layout from parsed
yaml or json files.
FILES
=====

View File

@ -51,7 +51,8 @@ class Builder(object):
files_to_process.extend([os.path.join(path, f)
for f in os.listdir(path)
if (f.endswith('.yaml')
or f.endswith('.yml'))])
or f.endswith('.yml')
or f.endswith('.json'))])
else:
files_to_process.append(path)

View File

@ -50,21 +50,29 @@ class YamlParser(object):
def parse_fp(self, fp):
data = yaml.safe_load(fp)
result = self.validate(data)
for item in result.items():
group = self.data.get(item[0], {})
# Create slug to make it easier to find dashboards.
if item[0] == 'dashboard':
name = item[1]['title']
else:
name = item[1]['name']
slug = slugify(name)
if slug in group:
raise Exception(
"Duplicate {0} found in '{1}: '{2}' "
"already defined".format(item[0], fp.name, name))
group[slug] = item[1]
self.data[item[0]] = group
# Since a json file is valid YAML, we just pass through
# any JSON files
if fp.name.endswith('.json'):
slug = slugify(data['title'])
if not self.data.get('dashboard'):
self.data['dashboard'] = {}
self.data['dashboard'][slug] = data
else:
result = self.validate(data)
for item in result.items():
group = self.data.get(item[0], {})
# Create slug to make it easier to find dashboards.
if item[0] == 'dashboard':
name = item[1]['title']
else:
name = item[1]['name']
slug = slugify(name)
if slug in group:
raise Exception(
"Duplicate {0} found in '{1}: '{2}' "
"already defined".format(item[0], fp.name, name))
group[slug] = item[1]
self.data[item[0]] = group
def validate(self, data):
schema = Schema()

View File

@ -0,0 +1,141 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": 38,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": null,
"fieldConfig": {
"defaults": {
"custom": {}
},
"overrides": []
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 2,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"dataLinks": []
},
"percentage": false,
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"refId": "A",
"target": "stats.haproxy.balance_git_http.gitea01.opendev.org.bout"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Fresh update",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
}
],
"schemaVersion": 25,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
]
},
"timezone": "",
"title": "test json",
"uid": "M-GEcyWMk",
"version": 1
}

View File

@ -100,3 +100,12 @@ class TestCaseParser(TestCase):
def _get_empty_dashboard(self, name):
res, md5 = self.parser.get_dashboard(name)
self.assertEqual(res, None)
def test_parse_json(self):
path = os.path.join(
os.path.dirname(__file__),
'fixtures/parser/json-dashboard-0001.json')
self.parser.parse(path)
# Get parsed dashboard
res, md5 = self.parser.get_dashboard('test-json')
self.assertEqual(res['title'], 'test json')