Экспорт дашбордов из grafana в Unix/Linux
У меня на работе, установлена grafana и ее активно используют коллеги для снятия различных метрик по дашбордам. Как у нас частенько бывает — ложатся сервера и если нет бэкапов, то все печально! Руками бэкапить дашборды с графаны — это нормально, но я люблю автоматизацию. И решил написать скрипт для экспорта всех дашбордов из grafana себе на компьютер. Я совсем не много пишу на питон и по этому — хотел написать на нем (так и будет немного позже)….. но на скорую руку пришелся — bash.
Полезное чтиво:
Установка grafana в Unix/Linux
-=== СПОСОБ 1 — Использование BASH===-
Предположим, скрипт у меня лежит прям в текущей директории:
# cat get_grafana_dashes.sh
Собственно, вот сие чудо:
#!/bin/bash -x
#
# Vitaliy Natarov
#
# Set some colors for status OK, FAIL and titles
SETCOLOR_SUCCESS="echo -en \\033[1;32m"
SETCOLOR_FAILURE="echo -en \\033[1;31m"
SETCOLOR_NORMAL="echo -en \\033[0;39m"
SETCOLOR_TITLE="echo -en \\033[1;36m" #Fuscia
SETCOLOR_TITLE_GREEN="echo -en \\033[0;32m" #green
SETCOLOR_TITLE_PURPLE="echo -en \\033[0;35m" #purple
SETCOLOR_NUMBERS="echo -en \\033[0;34m" #BLUE
KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
HOST="http://graffana-server.local"
DASH_DIR="/home/captain/Grafana/dashboards"
if [ ! -d "$DASH_DIR" ]; then
mkdir -p dashboards
else
$SETCOLOR_TITLE_PURPLE
echo "|-------------------------------------------------------------------------------|";
echo "| A $DASH_DIR directory is already exist! |";
echo "|-------------------------------------------------------------------------------|";
$SETCOLOR_NORMAL
fi
#curl -sS -k -H "Authorization: Bearer $KEY" $HOST/api/search\?query\=\& |tr ']{' '\n'| cut -d ':' -f4| cut -d ',' -f1| cut -d '"' -f2 | grep -Ev "(^$|\[)"| cut -c 4-
for dash in $(curl -sS -k -H "Authorization: Bearer $KEY" $HOST/api/search\?query\=\& |tr ']{' '\n'| cut -d ':' -f4| cut -d ',' -f1| cut -d '"' -f2 | grep -Ev "(^$|\[)"| cut -c 4-); do
curl -sS -k -H "Authorization: Bearer $KEY" $HOST/api/dashboards/db/$dash > dashboards/$dash.json
$SETCOLOR_TITLE_GREEN
echo "The [ $dash ] dashboard has been exported"
$SETCOLOR_NORMAL
done
$SETCOLOR_TITLE
echo "|-------------------------------------------------------------------------------|";
echo "|----------------------------------FINISHED-------------------------------------|";
echo "|-------------------------------------------------------------------------------|";
$SETCOLOR_NORMAL
Где:
- KEY=»XXXXXXXXXXXXXXXXXXXXXXXX» — Ключ для использования API. Можно сгенерировать в админ-панеле самой графаны.
- HOST=»http://graffana-server.local» — УРЛ где находится графана-сервер.
- DASH_DIR=»/home/captain/Grafana/dashboards» — Путь где будут лежать все шаблоны (дашборды) после экспорта.
Запускаем:
$ bash Get_grafana_dashes.sh
Получаем:

Экспорт дашбордов из grafana в Unix/Linux
Вроде бы все нормально. Кому режит глаза, могут убрать расскраску 🙂
-=== СПОСОБ 2 — Использование PYTHON===-
Будет скоро, постараюсь написать на днях. Возможно после выходных….
Так вот, прошло несколько дней и мой скрипт — готов.
Открываю его:
$ vim grafana_dashboards.py
Он имеет следующее содержание:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
import time
import os
import argparse
import json
import glob
# from datetime import datetime
from requests.packages.urllib3.exceptions import InsecureRequestWarning
class Bgcolors:
def __init__(self):
self.get = {
'HEADER': '\033[95m',
'OKBLUE': '\033[94m',
'OKGREEN': '\033[92m',
'WARNING': '\033[93m',
'FAIL': '\033[91m',
'ENDC': '\033[0m',
'BOLD': '\033[1m',
'UNDERLINE': '\033[4m'
}
def get_grafana_dashboards(g_url, g_token):
dashboards_array = []
headers = {'Authorization': str('Bearer ' + g_token), 'Content-type': 'application/json'}
get_data_req = requests.get(g_url + '/api/search?query=&', headers=headers)
pars_json = json.loads(get_data_req.text)
for dash in pars_json:
# print(dash['uri'][3::])
dashboards_array.append(dash['uri'][3::])
return dashboards_array
def export_grafana_dashboards(g_token, g_url, dir_path, e_dash):
headers = {'Authorization': str('Bearer ' + g_token),
'Content-type': 'application/json'
}
if not os.path.exists(dir_path):
os.makedirs(dir_path)
print(dir_path, 'has been created')
dashboard_names = get_grafana_dashboards(g_url, g_token)
dash_count = 1
if e_dash == 'all':
# print('I will export ALL DASHes!')
for d in dashboard_names:
dashboard_name_out = dir_path + '/' + d + '.json'
get_dashboard = requests.get(g_url + '/api/dashboards/db/' + d, headers=headers)
try:
f = open(dashboard_name_out, 'w')
f.write(json.dumps(get_dashboard.json(), indent=4))
f.close()
print('[', dash_count, ']', d)
dash_count += 1
except EOFError:
print('I cant write to file: ', EOFError)
else:
# print('I will export %s dashbourd(s)!' % e_dash)
for d in dashboard_names:
for dd in e_dash:
if d == dd:
dashboard_name_out = dir_path + '/' + d + '.json'
get_dashboard = requests.get(g_url + '/api/dashboards/db/' + d, headers=headers)
try:
f = open(dashboard_name_out, 'w+')
f.write(json.dumps(get_dashboard.json(), indent=4))
f.close()
print('[', dash_count, ']', d)
dash_count += 1
except ValueError:
print('I cant write to file: ', ValueError)
#
return export_grafana_dashboards
def import_grafana_dashboards(g_token, g_url, dir_path, i_dash):
headers = {'Authorization': str('Bearer ' + g_token),
'Content-type': 'application/json',
'Accept': 'application/json'
}
dash_count = 1
if i_dash == 'all':
# print('I will import ALL DASHes!')
files = glob.glob(dir_path + "/" + "*.json")
else:
# print('I will import %s dashbourd(s)!' % i_dash)
for d in i_dash:
files = glob.glob(str(dir_path) + "/" + str(d) + ".json")
for f in files:
d = f.split('.')[0].split('/')[1]
with open(f, 'r') as file:
dashboard = file.read()
try:
print('[%s] Need to create an import to grafana [%s]' % (dash_count, f))
datas = json.loads(dashboard)
protocol = g_url.split(':')[0]
if protocol == "http":
i__dash = requests.post(g_url + '/api/dashboards/db/', headers=headers, json=datas)
elif protocol == "https":
verify = False
if not verify:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
i__dash = requests.post(g_url + '/api/dashboards/db/', headers=headers, json=datas, verify=verify)
if i__dash.status_code != 200:
print(i__dash.status_code)
exit(0)
else:
print('Incorrect URL! Use url with http|https protocol')
exit(0)
print(i__dash)
except EOFError as e:
print(e)
dash_count += 1
return import_grafana_dashboards
def main():
start__time = time.time()
parser = argparse.ArgumentParser(prog='python3 script_name.py -h',
usage='python3 script_name.py {ARGS}',
add_help=True,
prefix_chars='--/',
epilog='''created by Vitalii Natarov''')
parser.add_argument('--version', action='version', version='v1.0.0')
parser.add_argument('--dash', '--dashboard', nargs='+', dest='dashboard', help='Indicate a dashboard(s)',
default='all')
parser.add_argument('--gtoken', '--token', dest='gtoken', help='Token of grafana server', default=None)
parser.add_argument('--gurl', '--url', dest='gurl', help='URL from grafana', default=None)
parser.add_argument('--dir', '--directory', dest='dashboards_dir', help='Indicate a folder for dashboard(s)',
default='CM-Shared_Grafana', metavar='folder')
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument('--i', dest='imports', help='Import function', action='store_true')
group.add_argument('--import', dest='imports', help='Import function', action='store_true')
group2 = parser.add_mutually_exclusive_group(required=False)
group2.add_argument('--e', dest='exports', help='Export function', action='store_true', default=argparse.SUPPRESS)
group2.add_argument('--export', dest='exports', help='Export function', action='store_true')
results = parser.parse_args()
dashboards_dir = results.dashboards_dir
dashboard = results.dashboard
grafana_token = results.gtoken
grafana_url = results.gurl
if (grafana_token is not None) and (grafana_url is not None):
if results.exports:
print('EXPORT function!')
export_grafana_dashboards(grafana_token, grafana_url, dashboards_dir, dashboard)
elif results.imports:
print('IMPORT function')
import_grafana_dashboards(grafana_token, grafana_url, dashboards_dir, dashboard)
else:
print('Please add [--gurl] and/or [--gtoken] option(s).Use "--e" to export, "--i" to import dashboards as well')
print('For help, use: script_name.py -h')
exit(0)
end__time = round(time.time() - start__time, 2)
print("--- %s seconds ---" % end__time)
print(
Bgcolors().get['OKGREEN'], "============================================================",
Bgcolors().get['ENDC'])
print(
Bgcolors().get['OKGREEN'], "==========================FINISHED==========================",
Bgcolors().get['ENDC'])
print(
Bgcolors().get['OKGREEN'], "============================================================",
Bgcolors().get['ENDC'])
if __name__ == '__main__':
main()
Для помощи можно использовать:
$ python3 grafana_dashboards.py -h
usage: python3 script_name.py {ARGS}
optional arguments:
-h, --help show this help message and exit
--version show program's version number and exit
--dash DASHBOARD [DASHBOARD ...], --dashboard DASHBOARD [DASHBOARD ...]
Indicate a dashboard(s)
--dir folder, --directory folder
Indicate a folder for dashboard(s)
--i Import function
--import Import function
--e Export function
--export Export function
created by Vitalii Natarov
Чтобы выполнить экспорт шалонов, выполняем:
$ python3 grafana_dashboards.py --e --gurl GRAFANA_URL_HERE --gtoken GRAFANA_TOKEN_HERE
Можно указать другую директорию:
$ python3 grafana_dashboards.py --e --dir some_another_dir --gurl GRAFANA_URL_HERE --gtoken GRAFANA_TOKEN_HERE
Или, можно экспортировать не все шаблоны, а только выбранные, — например:
$ python3 grafana_dashboards.py --e --dir --dash some_dashboard --gurl GRAFANA_URL_HERE --gtoken GRAFANA_TOKEN_HERE
Для импортирования, служит другая команда:
$ python3 grafana_dashboards.py --i
-=== СПОСОБ 3 — Использование модуля для grafana===-
Для начала, потребуется python3 + pip3:
Установка pip/setuptools/wheel в Unix/Linux
Ставим нужный пакет:
$ pip3 install grafcli
Теперь создайте конфигурационный файл grafcli.conf. Пока это в вашем рабочем каталоге в порядке:
[grafcli] editor = vim verbose = off [hosts] $GRAFANA_URL = on [$GRAFANA_URL] type = api url = https://$GRAFANA_URL:$PORT ssl = on user = admin password = $GRAFANA_ADMIN_PASSWORD #token = $GRAFANA_TOKEN [resources] data-dir = ~/.grafcli
Если вы используете token, то вам не нужно прописывать user/password. Чтобы проверить, действительно ли ваш файл конфигурации настроен корректно, попробуйте выполнить:
$ grafcli ls remote
Он должен показать URL-адрес Grafana, который вы прописали. Чтобы создать резервную копию всех дашбордов, используйте команду:
$ grafcli backup remote/$GRAFANA_URL/ backup.tgz
Восстановление из резервной копии также простое:
$ grafcli restore backup.tgz remote/$GRAFANA_URL/
Вот и все, статья «Экспорт дашбордов из grafana в Unix/Linux» завершена.
Добавлю свои 5 копеек. В баш скрипте немного проще, плюс архив:
#!/bin/bash KEY="" URL="" b_dir="/opt/bkup/grafana/dash" dt=$(date +%d%m%Y) dashs=$(curl -sS -k -H "Authorization: Bearer $KEY" $URL/api/search\?query\=\& | jq '.[] | .uri' | sed 's/"//g' | cut -d '/' -f2) for d in $dashs do curl -sS -k -H "Authorization: Bearer $KEY" $URL/api/dashboards/db/$d > $b_dir/$d.json done zip -jm $b_dir/grafana_dash_$dt.zip $b_dir/*.json >> /dev/nullДа, все верно. Но мне нужно было именно на питоне 🙂
Все настройки графаны, в том числе дашборды, храняться в .db файле рядом с местом установки графаны. Конкретно сами дашборды хранятся в таблице main.dashboard. Там в т.ч. хранятся json-шаблоны в поле data. Не проще было бы оттуда доставать?
Коллеги, а как же рассказать про импорт обратно? =)