Экспорт дашбордов из grafana в Unix/Linux

Экспорт дашбордов из grafana в Unix/Linux

У меня на работе, установлена grafana и ее активно используют коллеги для снятия различных метрик по дашбордам. Как у нас частенько бывает — ложатся сервера и если нет бэкапов, то все печально! Руками бэкапить дашборды с графаны — это нормально, но я люблю автоматизацию. И решил написать скрипт для экспорта всех дашбордов из grafana себе на компьютер. Я совсем не много пишу на питон и по этому — хотел написать на нем (так и будет немного позже)….. но на скорую руку пришелся — bash.

Полезное чтиво:

Установка grafana в Unix/Linux

Настройка Grafana с Graphite/Zabbix/Prometheus/MySQL/InfluxDB/Elasticsearch/CloudWatch для сбора и отображения метрик в 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

Экспорт дашбордов из 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» завершена.

4 thoughts on “Экспорт дашбордов из grafana в Unix/Linux

  1. Добавлю свои 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
    
  2. Все настройки графаны, в том числе дашборды, храняться в .db файле рядом с местом установки графаны. Конкретно сами дашборды хранятся в таблице main.dashboard. Там в т.ч. хранятся json-шаблоны в поле data. Не проще было бы оттуда доставать?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.