Git Product home page Git Product logo

grafana-backup-tool's Introduction

Grafana Backup Tool

A Python-based application to backup Grafana settings using the Grafana API.

The aim of this tool is to:

  1. Easily backup and restore Grafana.
  2. Have versioned backups(date and time in file name) for restoring and saving to cloud storage providers. Currently support
    1. Amazon S3
    2. Azure Storage
    3. GCP Cloud Storage (Use service-account's credential file, see here)

Supported components

  • Folder
  • Folder Permissions
  • Library Elements (doesn't work with Grafana 8.0.0 but 8.4.3)
  • Dashboard (contains Alert)
  • Datasource
  • Alert Channel
  • Alert Rules (Supported in version 9.4.0 of grafana and up.)
  • Teams
  • Team Members (Needs Basic Authentication (username and password, see grafana doc)
    • You need to set Admin's account and password in grafanaSettings.json, or set the base64 encoded admin account and password in ENV GRAFANA_BASIC_AUTH. E.g export GRAFANA_BASIC_AUTH=YWRtaW46YWRtaW4=
    • Or Sets this ENV of the Grafana server GF_USERS_ALLOW_ORG_CREATE=true. see grafana doc
  • Organization (Needs Basic Authentication (username and password, see grafana doc)
    • You need to set Admin's account and password in grafanaSettings.json, or set the base64 encoded admin account and password in ENV GRAFANA_BASIC_AUTH. E.g export GRAFANA_BASIC_AUTH=YWRtaW46YWRtaW4=
    • Or Sets this ENV of the Grafana server GF_USERS_ALLOW_ORG_CREATE=true. see grafana doc
  • User (Needs Basic Authentication (username and password, see grafana doc)
    • You need to set Admin's account and password in grafanaSettings.json, or set the base64 encoded admin account and password in ENV GRAFANA_BASIC_AUTH. E.g export GRAFANA_BASIC_AUTH=YWRtaW46YWRtaW4=
    • Grafana's api doesn't provide user's password when backing up, so the default_user_password in grafanaSettings.json, or in ENV DEFAULT_USER_PASSWORD, E.g export DEFAULT_USER_PASSWORD=supersecret will be used when restoring.
  • Snapshots
  • Dashboard Versions (only backup, no restore)
  • Annotations

NOTE The only supported orgId right now is 1, the default organization will be backed up only!

Requirements

  • Bash
  • Python 2.7 or Python 3.x
  • Access to a Grafana API server.
  • A Token of an Admin role (see Configuration section below for more info)

Configuration

There are three ways to setup the configuration:

  1. Use environment variables to define the variables for connecting to a Grafana server.
  2. Use hard-coded settings in conf/grafanaSettings.json (this is the default settings file if not specified otherwise).
  3. Use ~/.grafana-backup.json to define variables in json format.

Example Config

  • Copy grafanaSettings.example.json and modify it for you to use, remove azure, aws, gcp, influxdb blocks (but keep the ones you used).
  • Check out the examples folder for more configuration details.

NOTE If you use environment variables, you need to add the following to your .bashrc or execute once before using the tool (please change variables according to your setup):

(GRAFANA_HEADERS is optional, use it if necessary. please see #45)

### Do not use a trailing slash on GRAFANA_URL
export GRAFANA_URL=http://some.host.org:3000
export GRAFANA_TOKEN=eyJrIjoidUhaU2ZQQndrWFN3RRVkUnVfrT56a1JoaG9KWFFObEgiLCJuIjoiYWRtaW4iLCJpZCI6MX0=

# GRAFANA_HEADERS is optional
export GRAFANA_HEADERS=Host:some.host.org

To create and obtain a Token for your Grafana server, please refer to the official documentation.

NOTE that you need to generate a Token with an Admin role for the backup to succeed, otherwise you will have potential permission issues.

Installation

Virtual environment (optional but recommended)

Create a virtualenv, you could using something like pyenv if you'd prefer

virtualenv -p $(which python3) venv
source venv/bin/activate

Installation using pypi

pip install grafana-backup

Installation using this repo

First clone this repo

git clone https://github.com/ysde/grafana-backup-tool.git
cd grafana-backup-tool

Installation works best using pip

pip install .

How to Use

  • First perform the Configuration and Installation sections as described above.
  • Use the grafana-backup save command to backup all your folders, dashboards, datasources and alert channels to the _OUTPUT_ subdirectory of the current directory.

Example:

$ grafana-backup save
$ tree _OUTPUT_
_OUTPUT_/
└── 202006272027.tar.gz
  • Use the grafana-backup restore <archive_file> command with a path to a previous backup to restore everything.

NOTE this may result in data loss, by overwriting data on the server.

Example:

$ grafana-backup restore _OUTPUT_/202006272027.tar.gz

Docker

Replace variables below to use the Docker version of this tool

  • {YOUR_GRAFANA_TOKEN}: Your Grafana site Token.
  • {YOUR_GRAFANA_URL}: Your Grafana site URL.
  • {YOUR_BACKUP_FOLDER_ON_THE_HOST}: The backup folder on the Grafana host machine.

Kubernetes

Check out the CronJob in examples for a simple example of how grafana-backup-tool can be ran within a Kubernetes environment

Backup

If you decide to use a volume (-v) then you'll need to create the volume first with 1337 uid/gid ownership first, example:

mkdir /tmp/backup
sudo chown 1337:1337 /tmp/backup
docker run --user $(id -u):$(id -g) --rm --name grafana-backup-tool \
           -e GRAFANA_TOKEN={YOUR_GRAFANA_TOKEN} \
           -e GRAFANA_URL={YOUR_GRAFANA_URL} \
           -e GRAFANA_ADMIN_ACCOUNT={YOUR_GRAFANA_ADMIN_ACCOUNT} \
           -e GRAFANA_ADMIN_PASSWORD={YOUR_GRAFANA_ADMIN_PASSWORD} \
           -e VERIFY_SSL={True/False} \
           -v {YOUR_BACKUP_FOLDER_ON_THE_HOST}:/opt/grafana-backup-tool/_OUTPUT_  \
           ysde/docker-grafana-backup-tool

Example:

docker run --user $(id -u):$(id -g) --rm --name grafana-backup-tool \
           -e GRAFANA_TOKEN="eyJrIjoiNGZqTDEyeXNaY0RsMXNhbkNTSnlKN2M3bE1VeHdqVTEiLCJuIjoiZ3JhZmFuYS1iYWNrdXAiLCJpZCI6MX0=" \
           -e GRAFANA_URL=http://192.168.0.79:3000 \
           -e GRAFANA_ADMIN_ACCOUNT=admin \
           -e GRAFANA_ADMIN_PASSWORD=adminpassword \
           -e VERIFY_SSL=False \
           -v /tmp/backup/:/opt/grafana-backup-tool/_OUTPUT_ \
           ysde/docker-grafana-backup-tool

S3 Example: Set S3 configurations in -e or grafanaSettings.json(example)

           -e AWS_S3_BUCKET_NAME="my-backups-bucket" \
           -e AWS_S3_BUCKET_KEY="grafana-backup-folder" \
           -e AWS_DEFAULT_REGION="us-east-1" \
           -e AWS_ACCESS_KEY_ID="secret" \
           -e AWS_SECRET_ACCESS_KEY="secret" \

Azure Example: Set Azure configurations in -e or grafanaSettings.json(example)

		   -e AZURE_STORAGE_CONTAINER_NAME="azure-storage-container-name" \
		   -e AZURE_STORAGE_CONNECTION_STRING="azure-storage-connection-string"

GCS Example: Set GCS configurations in -e or grafanaSettings.json(example)

		   -e GCS_BUCKET_NAME="backups-bucket-name" \
		   -e GCS_BUCKET_PATH="grafana-backup-folder" \
		   -e GCLOUD_PROJECT="gcp-project-name" \
		   -e GOOGLE_APPLICATION_CREDENTIALS="credential-file-path"

Restore

docker run --user $(id -u):$(id -g) --rm --name grafana-backup-tool \
           -e GRAFANA_TOKEN={YOUR_GRAFANA_TOKEN} \
           -e GRAFANA_URL={YOUR_GRAFANA_URL} \
           -e GRAFANA_ADMIN_ACCOUNT={YOUR_GRAFANA_ADMIN_ACCOUNT} \
           -e GRAFANA_ADMIN_PASSWORD={YOUR_GRAFANA_ADMIN_PASSWORD} \
           -e VERIFY_SSL={True/False} \
           -e RESTORE="true" \
           -e ARCHIVE_FILE={THE_ARCHIVED_FILE_NAME} \
           -v {YOUR_BACKUP_FOLDER_ON_THE_HOST}:/opt/grafana-backup-tool/_OUTPUT_  \
           ysde/docker-grafana-backup-tool

Example:

docker run --user $(id -u):$(id -g) --rm --name grafana-backup-tool \
           -e GRAFANA_TOKEN="eyJrIjoiNGZqTDEyeXNaY0RsMXNhbkNTSnlKN2M3bE1VeHdqVTEiLCJuIjoiZ3JhZmFuYS1iYWNrdXAiLCJpZCI6MX0=" \
           -e GRAFANA_URL=http://192.168.0.79:3000 \
           -e GRAFANA_ADMIN_ACCOUNT=admin \
           -e GRAFANA_ADMIN_PASSWORD=adminpassword \
           -e VERIFY_SSL=False \
           -e RESTORE="true" \
           -e ARCHIVE_FILE="202006280247.tar.gz" \
           -v /tmp/backup/:/opt/grafana-backup-tool/_OUTPUT_ \
           ysde/docker-grafana-backup-tool

Building

You can build the docker image simply by executing make in the root of this repo. The image will get tagged as ysde:grafana-backup

Monitoring

InfluxDB support has been added and Prometheus push gateway support will be added in the future.

In order to monitor successful backups with InfluxDB simply configure grafana-backup InfluxDB settings using this example configuration. Or if you prefer to use environment variables you can instead set INFLUXDB_HOST, INFLUXDB_PORT, INFLUXDB_MEASUREMENT, INFLUXDB_USERNAME and INFLUXDB_PASSWORD.

Once configured grafana-backup will automatically enter a 1 in your defined timeseries measurement upon each successful backup.

grafana-backup-tool's People

Contributors

abalalaev avatar acjohnson avatar aerickson avatar brandon-vargas avatar chriz-active avatar chtcvl avatar derektbrown avatar dfluff avatar diveflo avatar gkotian avatar ilveroluca avatar iwilltry42 avatar jartigag avatar keimille avatar lavirott avatar maglub avatar melouaer avatar mikey1993 avatar mt3593 avatar neallclark avatar nileger avatar peekjef72 avatar rdoering avatar suhlig avatar testsmith-io avatar thinrope avatar vindex10 avatar yg265 avatar ysde avatar zot24 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

grafana-backup-tool's Issues

Dashboard name vs. Dashboard uid

Hi,

What's the reason behind using the uid instead of the dashbaord title for the filename when saving the dashboard file?

Thanks

Restored datasources are "locked"

Hi,
Thank you for your work.

I have a strange problem but I don't know if it's a grafana or a backup-tool problem :

I'am running Grafana on a kubernetes cluster in a "prometheus" namespace. The backup phase works fine.

To test the restore, I create another grafana instance in a "test" namespace. The restore phase seems to work fine, but I need to update the "prometheus" datasource to make it point to the prometheus datasource. So I go in the datasource menu an I have this :

The datasource was added by config and cannot be modified using the UI

I cannot modify anything here and I cannot delete it. Is there something to do from the backup-tool?

Thank you

Pretty JSON

For those of us who prefer text/json output (for example to use with source control) it would be useful for JSON files be prettified (and perhaps sorted somehow?) when written to disk.

I'm not too familiar with Python but my work around right now is to apply the json.tool (module?) to each file via a bash script, but I presume that means this can be rolled into the backup tool itself.

Supporting Users and Orgs?

Is there any way this could be expanded to support backup/restore of users and orgs?
In my environment we have multiple organizations with different users/privileges per org.

Dashboard summary logfile only contains last dashboard saved instead of all

--- a/src/save_dashboards.py
+++ b/src/save_dashboards.py
@@ -42,8 +42,8 @@ def get_indivisual_dashboard_setting_and_save(dashboards):
                 content
             )
             file_path = folder_path + '/' + log_file
-            with open(u"{0}".format(file_path) , 'w+') as f:
-                f.write('{}\t{}'.format(board['uid'], to_python2_and_3_compatible_string(board['title'])))
+            with open(u"{0}".format(file_path) , 'a') as f:
+                f.write('{}\t{}\n'.format(board['uid'], to_python2_and_3_compatible_string(board['title'])))
 
 def save_dashboards_above_Ver6_2():
     limit = 5000 # limit is 5000 above V6.2+

ImportError: No module named ordered_dict

Hello,

I try to launch the backup_grafana.sh but I have the following error :

./backup_grafana.sh 
2019-01-28_14:10:33
Traceback (most recent call last):
  File "/opt/grafana-backup-tool/saveDashboards.py", line 2, in <module>
    from dashboardApi import *
  File "/opt/grafana-backup-tool/dashboardApi.py", line 1, in <module>
    import requests, json, re
  File "/usr/lib/python2.7/dist-packages/requests/__init__.py", line 80, in <module>
    from . import utils
  File "/usr/lib/python2.7/dist-packages/requests/utils.py", line 25, in <module>
    from .compat import parse_http_list as _parse_list_header
  File "/usr/lib/python2.7/dist-packages/requests/compat.py", line 94, in <module>
    from urllib3.packages.ordered_dict import OrderedDict
ImportError: No module named ordered_dict
Traceback (most recent call last):
  File "/opt/grafana-backup-tool/saveDatasources.py", line 2, in <module>
    from dashboardApi import *
  File "/opt/grafana-backup-tool/dashboardApi.py", line 1, in <module>
    import requests, json, re
  File "/usr/lib/python2.7/dist-packages/requests/__init__.py", line 80, in <module>
    from . import utils
  File "/usr/lib/python2.7/dist-packages/requests/utils.py", line 25, in <module>
    from .compat import parse_http_list as _parse_list_header
  File "/usr/lib/python2.7/dist-packages/requests/compat.py", line 94, in <module>
    from urllib3.packages.ordered_dict import OrderedDict
ImportError: No module named ordered_dict
Traceback (most recent call last):
  File "/opt/grafana-backup-tool/saveFolders.py", line 2, in <module>
    from dashboardApi import *
  File "/opt/grafana-backup-tool/dashboardApi.py", line 1, in <module>
    import requests, json, re
  File "/usr/lib/python2.7/dist-packages/requests/__init__.py", line 80, in <module>
    from . import utils
  File "/usr/lib/python2.7/dist-packages/requests/utils.py", line 25, in <module>
    from .compat import parse_http_list as _parse_list_header
  File "/usr/lib/python2.7/dist-packages/requests/compat.py", line 94, in <module>
    from urllib3.packages.ordered_dict import OrderedDict
ImportError: No module named ordered_dict
tar: Removing leading `/' from member names
/tmp/dashboards/2019-01-28_14:10:33/
tar: Removing leading `/' from member names
/tmp/datasources/2019-01-28_14:10:33/
tar: Removing leading `/' from member names
/tmp/folders/2019-01-28_14:10:33/

Did someone had the same issue and/or know what should I do ?

license?

Hello

thank you very much for awesome grafana-backup-tool

Can you please add a license file (example GPL, MIT,..) to your repo?

thanks

Fails to save dashboards with special characters

I saw PR #9 but I propose different solution: use the uri as filename, it should be filenamesafe on most filesystems...

Anyway, here is my suggestion, just in case:

diff --git a/saveDashboards.py b/saveDashboards.py
index 6e22071..2ce5d21 100644
--- a/saveDashboards.py
+++ b/saveDashboards.py
@@ -27,9 +27,10 @@ def save_dashboard_setting(file_name, dashboard_settings):
 def get_indivisual_dashboard_setting_and_save(dashboards):
     for board in dashboards:
         status_code_and_content = get_dashboard(board['uri'])
+        file_name = re.sub('^db/','',board['uri'])
         if status_code_and_content[0] == 200:
             # print(status_code_and_content[1])
-            save_dashboard_setting(board['title'], status_code_and_content[1])
+            save_dashboard_setting(file_name, status_code_and_content[1])
             # save_dashboard_setting(board['title'], json.dumps(status_code_and_content[1]))
 
 dashboards = get_all_dashboards_in_grafana()

There are some other errors with folders, so the above may not be the only thing that is needed.

Then I read about uid: http://docs.grafana.org/http_api/dashboard/ may be it is better to use that?

Restore example (from docker)

Hi,
I'am trying to use grafana-backup to backup and restore my grafana dashboards.

The backup works fine but I don't know how tu use the restore method.

I want to use it from docker.

For the backup I'am using this :

docker run --rm --name grafana-backup-tool \
   -e GRAFANA_TOKEN={YOUR_GRAFANA_TOKEN} \
   -e GRAFANA_URL={YOUR_GRAFANA_URL} \
   -v {YOUR_BACKUP_FOLDER_ON_THE_HOST}:/opt/grafana-backup-tool/_OUTPUT_  \
   ysde/docker-grafana-backup-tool

But for the restore I don't know what to do. When I look inside the Dockerfile I see that there is an ENTRYPOINT assigned to backup_grafana.sh.

thank you for your help

TypeError in dashboardApi.py

Thanks for such a fantastic tool! One issue that came up for me and stopped me from performing a full dashboard restoration was that in the get_folder_id_from_old_folder_url function, response[1] was deemed a dict on some instances rather than a string which caused the json.loads() call to throw a TypeError error for me regularly.

To fix it, I added the following if statement to replace line 45 (folder_data = json.loads(response[1]))

if isinstance(response[1],dict):
    folder_dict_to_str = json.dumps(response[1])
    # String to valid json
    folder_data = json.loads(folder_dict_to_str)   
else:
    folder_data = json.loads(response[1])

Are you able to implement this or something similar to the master branch, please?

Limit on dashboards backup

search dashboard in grafana:
/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py:851: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecureRequestWarning)
[debug] status: 422
[debug] body: {'message': 'Limit is above maximum allowed (5000), use page parameter to access hits beyond limit'}
get dashboards failed, status: 422, msg: {'message': 'Limit is above maximum allowed (5000), use page parameter to access hits beyond limit'}

directory name '2019-07-lOT07:33:06' with : not compatible with Windows

Hi

I run backup_grafana.sh which creates a tarball. When you unpack the tarball there are directories like 2019-07-lOT07:33:06 which is not compatible with windows. I upload the contents of tarball to Git repo.

Please replace : with -

During Git checkout of grafana-backup the Windows guys get:

fatal: cannot create directory at 'grafana-backup-tool/dashboards/2019-07-lOT07:33:06':
Invalid argument

thanks

Custom headers?

In my case, Grafana is sitting behind a load balancer which routes based on the Host header.

Basic auth failed

I ceated and added an API key as suggested in your documentation but cannot get the sript working due to authentication errors.

########################################

search dashboard in grafana:
get dashboards failed, status: 401, msg: {"message":"Basic auth failed"}

########################################

I'm using Grafana v6.1.3 (9504db8)

Any hints for me?

Regards

ValueError: No JSON object could be decoded

ubuntu@ip-172-17-0-146:~/git/grafana-backup-tool$ python
Python 2.7.12 (default, Nov 19 2016, 06:48:10)

ubuntu@ip-172-17-0-146:~/git/grafana-backup-tool$ printenv | grep GRAFANA
GRAFANA_URL=http://ip-172-17-0-146:3000/grafana
GRAFANA_TOKEN=***********************************

I can curl to ip-172-17-0-146:3000/grafana and get back data.

ubuntu@ip-172-17-0-146:~/git/grafana-backup-tool$ python saveDatasources.py ../dashboard_backup/
search datasources in grafana:
Traceback (most recent call last):
  File "saveDatasources.py", line 27, in <module>
    datasources = get_all_datasources_and_save()
  File "saveDatasources.py", line 19, in get_all_datasources_and_save
    datasources = json.loads(content_of_datasources)
  File "/usr/lib/python2.7/json/__init__.py", line 339, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python2.7/json/decoder.py", line 364, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python2.7/json/decoder.py", line 382, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

TypeError in saveDatasources.py

Not sure if this tool is supposed to work against grafana version 4 aswell. If not then please just close the ticket.

Python 2.7.9
Both grafana env variables are set and correct (I know because the saveDashboards.py works like a charm)
Grafana version: 4.1.0

user@server:/github/grafana-backup-tool$ python saveDatasources.py ~/tmp
search datasources in grafana:
There are 1 datasources:
Traceback (most recent call last):
  File "saveDatasources.py", line 27, in <module>
    datasources = get_all_datasources_and_save()
  File "saveDatasources.py", line 23, in get_all_datasources_and_save
    save_datasource(datasource['name'], datasource)
TypeError: string indices must be integers

The $datasource contains only u'message'

TypeError: health_check

(status, json_resp) = health_check(grafana_url, http_get_headers, verify_ssl, debug)

(status, json_resp) = health_check(grafana_url, http_get_headers, verify_ssl, debug)

leads to: TypeError: health_check() missing 1 required positional argument: 'debug'

see:
https://github.com/ysde/grafana-backup-tool/blob/master/grafana_backup/dashboardApi.py#L5
def health_check(grafana_url, http_get_headers, verify_ssl, client_cert, debug)

fix: call health_check with expected args

can't encode charecter u'xb0'

Getting this error. Let me know if you need more info.

Traceback (most recent call last):
File "/home/manderse/bin/grafana-backup-tool/saveDashboards.py", line 47, in
get_indivisual_dashboard_setting_and_save(dashboards)
File "/home/manderse/bin/grafana-backup-tool/saveDashboards.py", line 38, in get_indivisual_dashboard_setting_and_save
status_code_and_content = get_dashboard(board['uri'])
File "/home/manderse/bin/grafana-backup-tool/dashboardApi.py", line 11, in get_dashboard
r = send_grafana_get(grafana_url + "/api/dashboards/{0}".format(board_uri))
File "/home/manderse/bin/grafana-backup-tool/dashboardApi.py", line 67, in send_grafana_get
log_response(r)
File "/home/manderse/bin/grafana-backup-tool/commons.py", line 9, in log_response
print("body: {0}".format(resp.content.decode('utf8')))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xb0' in position 1206: ordinal not in range(128)

Don't include aws and grafana token configs when building pypi package

Just installed latest version from git, and found that when I use env vars instead of config files, the aws upload section always attempts an upload using the dummy config values in grafanaSettings.json (bucket_name, et. al). It's currently impossible to avoid the aws upload step when using env vars for conf because the conf directory is packaged up into the installation in setup.py. Also there's a default grafana token in there as well which seems not smart either?

I'm thinking maybe there needs to be an example conf in addition to the default conf, to showcase the aws configs? Not everyone (aka me) wants the tool to upload to aws (I'm uploading to backblaze b2).

All folders empty

Hello.
Thank you for your code. It works very well for me so far, except that the folders it creates when running a backup are empty. It does create a tar.gz file which has the folders inside which are not empty (the backup is working and reading my grafana), however the folders "alert_channels", "dashboards", "data_sources" and "folders" in the root OUTPUT folder are empty.
Is this supposed to be the case or should those folders have the files in them?
Thank you very much
Hamish

saveDashboards.py cannot write to file

Hi! I am using the current master of this project and while I can successfully export datasources and folders, the export of dashboards failes like so:

python saveDashboards.py /some-folder/
search dashboard in grafana:
There are 651 dashboards:
name: :: Bitbucket
name: :: Bot Traffic
...

########################################

query dashboard uri: db/bitbucket, status: 200
Traceback (most recent call last):
  File "saveDashboards.py", line 47, in <module>
    get_indivisual_dashboard_setting_and_save(dashboards)
  File "saveDashboards.py", line 40, in get_indivisual_dashboard_setting_and_save
    save_dashboard_setting(board['title'], board['uid'], status_code_and_content[1])
  File "saveDashboards.py", line 32, in save_dashboard_setting
    f.write(dashboard_settings.encode('utf-8'))
TypeError: write() argument must be str, not bytes

Grafana version is 5.4.2, os is Debian 9

Why archive and remove the output files?

Hi!

This is a nice tool and I really appreciate your work. I changed (quick and dirty) the bash script to simply not remove the files and changed the output directory from "OUTPUT" to "backup".
Similarly I removed the timestamp from the dashboards.txt file.

After a run of the script I add, commit, push ... why versioned tar archives and filenames when there's git?

Kind regards,
Patrick

Unable to backup Grafana 7.0.0 dashboards.

Hi, recently I've upgraded Grafana server to version 7.0, and backup tool cannot backup dashboards from it.

Here is traceback from the container:

Backing up grafana
/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py:986: InsecureRequestWarning: Unverified HTTPS request is being made to host 'beta-grafana.xyz.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning,
grafana health: https://beta-grafana.xyz.com:443//api/health
[DEBUG] status: 200
Traceback (most recent call last):
  File "./src/save_dashboards.py", line 75, in <module>
    (status, resp) = health_check()
  File "/opt/grafana-backup-tool/src/dashboardApi.py", line 29, in health_check
    return send_grafana_get(url)
  File "/opt/grafana-backup-tool/src/dashboardApi.py", line 106, in send_grafana_get
    log_response(r)
  File "/opt/grafana-backup-tool/src/commons.py", line 18, in log_response
    print("[DEBUG] body: {0}".format(resp.json()))
  File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 898, in json
    return complexjson.loads(self.text, **kwargs)
  File "/usr/local/lib/python3.7/json/__init__.py", line 348, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.7/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/lib/python3.7/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Polish and release

Dear @ysde,

first things first: Thanks for conceiving this excellent utility.

After taking a look, I recognized the module has not been added to PyPI yet. It would be cool to add an appropriate setup.py and - while being at it - to wrap the functionality of backup_grafana.sh/restore_grafana.sh within respective Python console script entrypoints.

With kind regards,
Andreas.

Support folders in Grafana 5

In grafana 5 when we execute backup, all folders are saved as a dashboard and when we try to restore this backup, folders are created as dashboards in the other instance.

Datasource passwords are not retrieved

The tool is saving the datasource without the password (encrypted or otherwise). Is it expected that the admin is supposed to manually insert the password into the datasource once it's been restored? Is anyone looking into the possibility of retrieving an encrypted password?

KeyError: 'uid' in saveDashboards.py

I am trying to use this perfectly suited backup script for me.
I have the requirements already.

python --version
Python 2.7.12
pip install requests
You are using pip version 6.1.1, however version 19.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Requirement already satisfied (use --upgrade to upgrade): requests in /usr/lib/python2.7/dist-packages

but still the script is facing with key error. Below is the error:

Traceback (most recent call last):
  File "/home/ec2-user/grafana-backup-tool/saveDashboards.py", line 52, in <module>
    get_indivisual_dashboard_setting_and_save(dashboards)
  File "/home/ec2-user/grafana-backup-tool/saveDashboards.py", line 43, in get_indivisual_dashboard_setting_and_save
    board['uid'],
KeyError: 'uid'

Handle API errors with exit code

Hi, I have recently noticed that tool doesn't handle Grafan API errors well.

In case of providing wrong Grafana Token, API replay with status 401 and following log is printed:

search alert channels in grafana: http://192.168.0.25:8081/api/alert-notifications
[DEBUG] status: 401
[DEBUG] body: {'message': 'Invalid API key'}
query alert channels failed, status: 401, msg: {'message': 'Invalid API key'}

But the tool works as usual, it creates empty archive and returns without errors.

Maybe it would be better to indicate such error (and probably other) with exit code and don't produce malformed archive files? It would be helpful especially when script is run automatically.

Kind regards,
Paweł

TypeError: get_folder() missing 4 required positional arguments

Restoring a dashboard fails with this error:

restoring dashboard: /tmp/tmp6drgimz0/_OUTPUT_/dashboards/202007301025/-xEOFu0Zz.dashboard
Traceback (most recent call last):
  File "/usr/bin/grafana-backup", line 11, in <module>
    load_entry_point('grafana-backup==1.0.0', 'console_scripts', 'grafana-backup')()
  File "/usr/lib/python3.8/site-packages/grafana_backup/cli.py", line 46, in main
    restore(args, settings)
  File "/usr/lib/python3.8/site-packages/grafana_backup/restore.py", line 43, in main
    restore_functions[ext](args, settings, file_path)
  File "/usr/lib/python3.8/site-packages/grafana_backup/create_dashboard.py", line 19, in main
    'folderId': get_folder_id_from_old_folder_url(content['meta']['folderUrl']),
  File "/usr/lib/python3.8/site-packages/grafana_backup/dashboardApi.py", line 70, in get_folder_id_from_old_folder_url
    response = get_folder(uid)
TypeError: get_folder() missing 4 required positional arguments: 'grafana_url', 'http_get_headers', 'verify_ssl', and 'debug'

Looks as if ab06386 changed get_folder to require four args, where the rest of the code seems to call it with just one.

Introduce some kind of DEBUG flag?

Now that everything works (tm), may be it is time to tidy out the default output and introduce some kind of debug/verbose flag...
I'd suggest "-d" and print a help message like:

echo "Please re-run with DEBUG enabled for troubleshooting:"
echo "$0 -d $*"
exit -1

upon error.

left_ver_newer_than_right_ver(resp['version'], "6.2.0")

Hello,
Thanks for the share.
I've the following error:

grafana health: https://monitoring.domain.com/api/health /home/florent/.local/lib/python2.7/site-packages/urllib3/connectionpool.py:1004: InsecureRequestWarning: Unverified HTTPS request is being made to host 'monitoring.domain.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings InsecureRequestWarning, [DEBUG] status: 200 [DEBUG] body: {u'commit': u'65dbd7cadc', u'version': u'7.0.0-c1fa1cd2pre', u'database': u'ok'} Traceback (most recent call last): File "/tmp/grafana-backup-tool/src/save_dashboards.py", line 70, in <module> is_api_support_page_param = left_ver_newer_than_right_ver(resp['version'], "6.2.0") File "/tmp/grafana-backup-tool/src/commons.py", line 6, in left_ver_newer_than_right_ver return convertVersion(current_version) > convertVersion(specefic_version) File "/tmp/grafana-backup-tool/src/commons.py", line 5, in convertVersion return int(''.join(ver.split("."))) ValueError: invalid literal for int() with base 10: '700-c1fa1cd2pre'

Any idea?
Thanks.
Florent

support python3

From http://docs.python-requests.org/en/master/

Note:

The use of Python 3 is highly preferred over Python 2. Consider upgrading your applications and infrastructure if you find yourself still using Python 2 in production today. If you are using Python 3, congratulations — you are indeed a person of excellent taste. —Kenneth Reitz

This tool is one of the few in my systems that still works only with python2.7, please upgrade it to support python3, as well.

It looks simple enough to do with futurize (looks like only 'print()' is used), let me know if you prefer PR, or you'd rather hand-check it yourself.

does not work with latest grafana version

Hi all,
wanted to try this but doesn't get it working.
Grafana URL is using https, grafana version is 6.0.2, Api got admin rights, when executing the backup script, I got:

2019-03-20_15:55:29
search dashboard in grafana:
Traceback (most recent call last):
File "/root/grafana-backup-tool/saveDashboards.py", line 45, in
dashboards = get_all_dashboards_in_grafana()
File "/root/grafana-backup-tool/saveDashboards.py", line 15, in get_all_dashboards_in_grafana
status_and_content_of_all_dashboards = search_dashboard()
File "/root/grafana-backup-tool/dashboardApi.py", line 7, in search_dashboard
r = send_grafana_get(grafana_url + '/api/search/?type=dash-db&limit=' + search_api_limit)
TypeError: cannot concatenate 'str' and 'int' objects

Thanks in advanced.
Cheers,
Marcus

Does the token have to exist after migration?

This is not an issue but a question.

So we generated an API token on one Grafana instance and used the script to migrate some dashboards. After that we accidentally deleted the API token on the instance, and keep getting unauthorized error. So I'm wondering if this token is required even after migration?

can't encode character u'\u2013'

Hi,
first of all, thank you for your work.

I ran into the following issue. Its working for most of my dashboards, but some encounter the following issue while saveDashboards.py exports it:

query dashboard uri: db/pxc-galera-graphs, status: 200
Traceback (most recent call last):
File "/grafana-backup-tool/saveDashboards.py", line 48, in
get_indivisual_dashboard_setting_and_save(dashboards)
File "grafana-backup-tool/saveDashboards.py", line 41, in get_indivisual_dashboard_setting_and_save
save_dashboard_setting(board['title'], board['uid'], status_code_and_content[1])
File "grafana-backup-tool/saveDashboards.py", line 33, in save_dashboard_setting
f.write(dashboard_settings)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2013' in position 21376: ordinal not in range(128)

I tried with python 2.7 and 3.6, same issue.

thanks a lot!

Backup tar file extraction fails

I've tried using the docker container to back up my grafana instance. Everything appears to work fine, but when I try extracting the resulting tar file I see the following error:

# tar xvzf 2019-06-21T16\:19\:59.tar.gz 
tar (child): Cannot connect to 2019-06-21T16: resolve failed

gzip: stdin: unexpected end of file
tar: Child returned status 128
tar: Error is not recoverable: exiting now

It seems that if I extract the tar file from a directory higher than it exists, it works, but if I try to extract it from its current directory, it does not.

root@8861f06da2eb:/opt/grafana-backup-tool/_OUTPUT_# tar xvzf 2019-06-21T16\:22\:39.tar.gz 
tar (child): Cannot connect to 2019-06-21T16: resolve failed

gzip: stdin: unexpected end of file
tar: Child returned status 128
tar: Error is not recoverable: exiting now
root@8861f06da2eb:/opt/grafana-backup-tool/_OUTPUT_# cd ..
root@8861f06da2eb:/opt/grafana-backup-tool# tar xvzf _OUTPUT_/2019-06-21T16\:22\:39.tar.gz 
_OUTPUT_/dashboards/2019-06-21T16:22:39/
_OUTPUT_/dashboards/2019-06-21T16:22:39/VLIFWnMWk.dashboard
_OUTPUT_/dashboards/2019-06-21T16:22:39/tnvBiR4Zk.dashboard
_OUTPUT_/dashboards/2019-06-21T16:22:39/77G4tjmWk.dashboard
_OUTPUT_/dashboards/2019-06-21T16:22:39/2co7gfmZk.dashboard
_OUTPUT_/dashboards/2019-06-21T16:22:39/dashboards_201906211622.txt
_OUTPUT_/datasources/2019-06-21T16:22:39/
_OUTPUT_/folders/2019-06-21T16:22:39/
_OUTPUT_/folders/2019-06-21T16:22:39/folders_201906211622.txt
_OUTPUT_/folders/2019-06-21T16:22:39/UWX_f8WZk.folder
_OUTPUT_/folders/2019-06-21T16:22:39/_CWXfUWWz.folder

GRAFANA_HEADERS enviroment variable is not optional as stated

Even though the README states the GRAFANA_HEADERS is an optional environment varible, when i do not include it i get this error: EXTRA_HEADERS = dict(h.split(':') for h in os.getenv('GRAFANA_HEADERS').split(',') if 'GRAFANA_HEADERS' in os.environ) AttributeError: 'NoneType' object has no attribute 'split'

I also attempted to setting GRAFANA_HEADERS equal to an empty string, i get a different error here: ValueError: dictionary update sequence element #0 has length 1; 2 is required

Below is a pull request to a solution for this error.
#47

Does this work with ssl and oauth integration?

I seem to be encountering errors, but I'm not sure if it is because my Grafana instance has SSO and SSL enabled.

Error with the real URL:

[DEBUG] status: 404
Traceback (most recent call last):
  File "/root/grafana-backups/scripts/src/save_dashboards.py", line 67, in <module>
    (status, resp) = health_check()
  File "/root/grafana-backups/scripts/src/dashboardApi.py", line 8, in health_check
    return send_grafana_get(url)
  File "/root/grafana-backups/scripts/src/dashboardApi.py", line 73, in send_grafana_get
    log_response(r)
  File "/root/grafana-backups/scripts/src/commons.py", line 16, in log_response
    print("[DEBUG] body: {0}".format(resp.json()))
  File "/usr/lib/python2.7/dist-packages/requests/models.py", line 651, in json
    return json.loads(self.text or self.content, **kwargs)
  File "/usr/lib64/python2.7/dist-packages/simplejson/__init__.py", line 505, in loads
    return _default_decoder.decode(s)
  File "/usr/lib64/python2.7/dist-packages/simplejson/decoder.py", line 370, in decode
    obj, end = self.raw_decode(s)
  File "/usr/lib64/python2.7/dist-packages/simplejson/decoder.py", line 400, in raw_decode
    return self.scan_once(s, idx=_w(s, idx).end())
simplejson.scanner.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

With localhost in grafanasettings.py

grafana health: http://localhost:3000/api/health
[DEBUG] status: 200
Traceback (most recent call last):
  File "/root/grafana-backups/scripts/src/save_dashboards.py", line 67, in <module>
    (status, resp) = health_check()
  File "/root/grafana-backups/scripts/src/dashboardApi.py", line 8, in health_check
    return send_grafana_get(url)
  File "/root/grafana-backups/scripts/src/dashboardApi.py", line 73, in send_grafana_get
    log_response(r)
  File "/root/grafana-backups/scripts/src/commons.py", line 16, in log_response
    print("[DEBUG] body: {0}".format(resp.json()))
  File "/usr/lib/python2.7/dist-packages/requests/models.py", line 651, in json
    return json.loads(self.text or self.content, **kwargs)
  File "/usr/lib64/python2.7/dist-packages/simplejson/__init__.py", line 505, in loads
    return _default_decoder.decode(s)
  File "/usr/lib64/python2.7/dist-packages/simplejson/decoder.py", line 370, in decode
    obj, end = self.raw_decode(s)
  File "/usr/lib64/python2.7/dist-packages/simplejson/decoder.py", line 400, in raw_decode
    return self.scan_once(s, idx=_w(s, idx).end())
simplejson.scanner.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.