Skip to content

Instantly share code, notes, and snippets.

@AndreLouisCaron
Created June 29, 2017 16:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndreLouisCaron/138f9b3447208a79345e9cb6f9d9b3e8 to your computer and use it in GitHub Desktop.
Save AndreLouisCaron/138f9b3447208a79345e9cb6f9d9b3e8 to your computer and use it in GitHub Desktop.
Grafana dashboard exchange
# -*- coding: utf-8 -*-
from __future__ import print_function
import errno
import glob
import json
import os
import requests
import sys
import time
from urlparse import urljoin
# Settings.
GRAFANA_URL = sys.argv[1]
GRAFANA_USERNAME = 'admin'
GRAFANA_PASSWORD = 'admin'
def get_json(url):
rep = requests.get(
urljoin(GRAFANA_URL, url),
auth=(GRAFANA_USERNAME, GRAFANA_PASSWORD),
)
rep.raise_for_status()
return rep.json()
def post_json(url, document, serialize=json.dumps):
rep = requests.post(
urljoin(GRAFANA_URL, url),
auth=(GRAFANA_USERNAME, GRAFANA_PASSWORD),
headers={
'Content-Type': 'application/json',
},
data=serialize(document),
)
rep.raise_for_status()
return rep.json()
def put_json(url, document, serialize=json.dumps):
rep = requests.put(
urljoin(GRAFANA_URL, url),
auth=(GRAFANA_USERNAME, GRAFANA_PASSWORD),
headers={
'Content-Type': 'application/json',
},
data=serialize(document),
)
rep.raise_for_status()
return rep.json()
def json_pp(doc):
"""Render JSON in normalized format."""
return json.dumps(doc, indent=2, sort_keys=True, separators=(',', ': '))
def ensure_dir(path):
"""Create a folder if it doesn't already exist."""
try:
os.mkdir(path)
except OSError as error:
if error.errno != errno.EEXIST:
raise
return path
def pull():
"""Pull Grafana configuration to disk."""
# Fetch all data sources.
ensure_dir('datasources')
for document in get_json('api/datasources'):
slug = document['name']
path = os.path.join('datasources', '%s.json' % (slug,))
print(path)
with open(path, 'wb') as stream:
stream.write(json_pp(document).encode('utf-8'))
stream.write(b'\n')
# Fetch all dashboards (except Home, which we can't edit).
ensure_dir('dashboards')
for document in get_json('api/search'):
if document['type'] != 'dash-db':
continue
slug = document['uri'].split('/', 1)[1]
dashboard = get_json('api/dashboards/db/%s' % (slug,))
path = os.path.join('dashboards', '%s.json' % (slug,))
print(path)
with open(path, 'wb') as stream:
stream.write(json_pp(dashboard).encode('utf-8'))
stream.write(b'\n')
def push():
"""Push on-disk configuration to Grafana."""
# Create/update data sources.
datasources = {
document['name']: document['id']
for document in get_json('api/datasources')
}
for path in glob.iglob(os.path.join('datasources', '*.json')):
print(path)
with open(path, 'rb') as stream:
document = json.loads(stream.read().decode('utf-8'))
# Create or update depending on whether it already exists.
document['id'] = datasources.get(document['name'], None)
if document['id']:
print('Updating data source "%s" with ID #%s.' % (
document['name'],
document['id'],
))
put_json(
'api/datasources/%s' % (document['id'],),
document,
)
else:
rep = post_json(
'api/datasources',
document,
)
print('Created data source "%s" with ID #%d.' % (
document['name'],
rep['id'],
))
print()
print('---')
# Create/update dashboards.
dashboards = {
document['uri'].split('/', 1)[1]: document['id']
for document in get_json('api/search')
}
for path in glob.iglob(os.path.join('dashboards', '*.json')):
print(path)
with open(path, 'rb') as stream:
document = json.loads(stream.read().decode('utf-8'))
slug = document['meta']['slug']
del document['meta']
document['dashboard']['id'] = dashboards.get(slug, None)
if 'id' in document:
print('Updating dashboard "%s" with slug "%s" and ID #%d.' % (
document['dashboard']['title'],
slug,
document['id'],
))
else:
print('Updating dashboard "%s" with slug "%s".' % (
document['dashboard']['title'],
slug,
))
try:
post_json(
'api/dashboards/db',
document,
)
except requests.exceptions.HTTPError as error:
# We'll get a version-mismatch error if Grafana already has the
# latest version (or a newer version).
if error.response.status_code != 412:
raise
print(error.response.json()['message'])
print()
def wait_until_responsive():
"""Poll Grafana until its API is repsonsive."""
while True:
print('Pinging Grafana...')
try:
rep = requests.get(
urljoin(GRAFANA_URL, 'api/admin/stats'),
auth=(GRAFANA_USERNAME, GRAFANA_PASSWORD),
)
except requests.exceptions.ConnectionError:
print(' not ready, retrying in 1 second...')
time.sleep(1.0)
continue
rep.raise_for_status()
print(' ready!')
break
if __name__ == '__main__':
wait_until_responsive()
#push()
pull()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment