{"id":13586011,"url":"https://github.com/m110/grafcli","last_synced_at":"2025-10-06T02:36:48.570Z","repository":{"id":28889617,"uuid":"32414273","full_name":"m110/grafcli","owner":"m110","description":"Grafana CLI for quick and easy dashboards management.","archived":false,"fork":false,"pushed_at":"2022-07-25T18:41:11.000Z","size":154,"stargazers_count":168,"open_issues_count":13,"forks_count":20,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-09-29T13:58:31.670Z","etag":null,"topics":["backup","cli","dashboard","grafana","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/m110.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-17T19:08:15.000Z","updated_at":"2024-09-25T07:02:28.000Z","dependencies_parsed_at":"2022-07-27T17:18:38.284Z","dependency_job_id":null,"html_url":"https://github.com/m110/grafcli","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/m110/grafcli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m110%2Fgrafcli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m110%2Fgrafcli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m110%2Fgrafcli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m110%2Fgrafcli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/m110","download_url":"https://codeload.github.com/m110/grafcli/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m110%2Fgrafcli/sbom","scorecard":{"id":608249,"data":{"date":"2025-08-11","repo":{"name":"github.com/m110/grafcli","commit":"5c5ba2cec7454703345e6d2efc478d354827379b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.1,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 1/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:1: pin your Docker image by updating python:3.7-alpine to python:3.7-alpine@sha256:f3d31c8677d03f0b3c724446077f229a6ce9d3ac430f5c08cd7dff00292048c3","Warn: containerImage not pinned by hash: tests/integration/Dockerfile:1: pin your Docker image by updating python:3.7-alpine to python:3.7-alpine@sha256:f3d31c8677d03f0b3c724446077f229a6ce9d3ac430f5c08cd7dff00292048c3","Warn: pipCommand not pinned by hash: Dockerfile:7","Warn: pipCommand not pinned by hash: Dockerfile:8","Warn: pipCommand not pinned by hash: Dockerfile:9","Warn: pipCommand not pinned by hash: tests/integration/Dockerfile:8","Warn: pipCommand not pinned by hash: tests/integration/Dockerfile:9","Info:   0 out of   2 containerImage dependencies pinned","Info:   0 out of   5 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":4,"reason":"6 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2023-117 / GHSA-mrwq-x4v8-fh7p","Warn: Project is vulnerable to: PYSEC-2014-14 / GHSA-652x-xj99-gmcc","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2014-13 / GHSA-cfj3-7x9c-4p3h","Warn: Project is vulnerable to: PYSEC-2018-28 / GHSA-x84v-xcm2-53pg"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-21T02:05:32.689Z","repository_id":28889617,"created_at":"2025-08-21T02:05:32.689Z","updated_at":"2025-08-21T02:05:32.689Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278551039,"owners_count":26005385,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backup","cli","dashboard","grafana","python"],"created_at":"2024-08-01T15:05:16.406Z","updated_at":"2025-10-06T02:36:48.507Z","avatar_url":"https://github.com/m110.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# grafcli\n\n[![Build Status](https://travis-ci.org/m110/grafcli.svg?branch=master)](https://travis-ci.org/m110/grafcli)\n\n[Grafana](http://grafana.org) CLI for fast and easy dashboards management.\n\n**Please note** that grafcli has been tested for a while, but it still can have some minor defects. All help by contributions and suggestions is welcomed! Remember to back up your dashboards first.\n\nAlso note that grafcli was created when grafana itself lacked some features, like exports or API. Although it's still nice to have some of those in form of a CLI application.\n\nCredit goes to [b3niup](https://github.com/b3niup) for the original idea!\n\n## Featuring:\n\n* Dashboards backup and restore.\n* Easy rows and panels moving/copying between dashboards.\n* Editing dashboards/rows/panels in-place.\n* Templates of dashboards, rows and panels.\n* File export/import.\n* Interactive CLI with completions support.\n* Compatibility across older Grafana versions.\n* ...and more!\n\n## Why?\n\n* Lets you easily manage your dashboards using just your keyboard.\n* Provides convenient way to backup dashboards and restore them.\n* Can be used by any shell script with even more logic added.\n\n## How?\n\nGrafcli connects to Grafana HTTP API or directly to one of the backends (Elastic, SQLite, MySQL, PostgreSQL) and modifies the dashboards. This is all hidden behind an interface you already know well, similar to *nix filesystem.\n\n## Requirements\n\n* [Python 3](http://python.org)\n* [climb](https://github.com/m110/climb)\n* [pygments](http://pygments.org/)\n* Depending on which storage backends you use, you need to install as well:\n    * [requests](http://docs.python-requests.org/en/master/)\n        * `pip install requests`\n    * [elasticsearch-py](http://github.com/elastic/elasticsearch-py)\n        * `pip install elasticsearch`\n    * [psycopg2](http://initd.org/psycopg/)\n        * `pip install psycopg2`\n    * [MySQL Connector/Python](http://dev.mysql.com/downloads/connector/python/)\n        * `pip install mysql-connector-python-rf`\n\n## Installation\n\n```\npip3 install grafcli\n```\n\nor get the source and run:\n\n```\npython3 setup.py install\n```\n\nThen define your hosts in the config file (see below for details).\n```\ncp /etc/grafcli/grafcli.conf.example /etc/grafcli/grafcli.conf\n```\n\nYou will need at least one of the backend libraries listed above (except sqlite3, which comes with Python).\n\n## TODO\n\n* Improve confirmation prompt.\n* Improve completions.\n* Implement asterisk (*) handling.\n\n# Usage\n\n## Navigation\n\nUse `cd` and `ls` commands to list nodes and move around.\n\n```\n[/]\u003e cd templates\n[/templates]\u003e ls\ndashboards\nrows\npanels\n[/templates]\u003e ls dashboards\nexample_dashboard\nanother_dashboard\n[/templates]\u003e ls dashboards/example_dashboard\n1-Example-Row\n2-Another-Row\n3-Yet-Another-Row\n[/templates]\u003e ls dashboards/example_dashboard/1-Example-Row\n1-Example-Panel\n2-Another-Panel\n```\n\n## Directories\n\nIn the root directory, you will find three basic directories:\n\n* `backups` - for storing backups of your dashboards (surprised?).\n* `remote` - which lets you access remote hosts.\n* `templates` - that contains templates of dashboards, rows and panels.\n\n## Management\n\nMost of the arguments here are paths to a dashboard, row or panel.\n\n* `cat \u003cpath\u003e` - display JSON of given element.\n* `$EDITOR \u003cpath\u003e` - edit the JSON of given element in-place and update it afterwards. Editor name can be set in the config file.\n* `merge \u003cpaths\u003e` - merge documents together. Merge tool can be set in the config file.\n* `cp \u003csource\u003e \u003cdestination\u003e` - copies one element to another. Can be used to copy whole dashboards, rows or single panels.\n* `mv \u003csource\u003e \u003cdestination\u003e` - the same as `cp`, but moves (renames) the source.\n* `rm \u003cpath\u003e` - removes the element.\n* `template \u003cpath\u003e` - saves element as template.\n* `backup \u003cremote_host\u003e \u003csystem_path\u003e` - saves backup of all dashboards from remote host as .tgz archive.\n* `restore \u003csystem_path\u003e \u003cremote_host\u003e` - restores saved backup.\n* `export \u003cpath\u003e \u003csystem_path\u003e` - saves the JSON-encoded element to file.\n* `import \u003csystem_path\u003e \u003cpath\u003e` - loads the JSON-encoded element from file.\n* `pos \u003cpath\u003e \u003cindex\u003e` - change position of row in a dashboard or panel in a row.\n\n# Configuration\n\nGrafcli will attempt to read `./grafcli.conf`, `~/.grafcli.conf` and `/etc/grafcli/grafcli.conf` in that order.\n\nHere is the configuration file explained.\n```ini\n[grafcli]\n# Your favorite editor - this name will act as a command!\neditor = vim\n# Executable used as merge tool. Paths will be passed as arguments.\nmergetool = vimdiff\n# Commands history file. Leave empty to disable.\nhistory = ~/.grafcli_history\n# Additional verbosity, if needed.\nverbose = off\n# Answer 'yes' to all overwrite prompts.\nforce = on\n\n[resources]\n# Directory where all local data will be stored (including backups).\ndata-dir = ~/.grafcli\n\n# List of remote Grafana hosts.\n# The key names do not matter, as long as matching section exists.\n# Set the value to off to disable the host.\n[hosts]\nhost.example.com = on\n\n[host.example.com]\ntype = elastic\n# In case of more hosts, use comma-separated values.\nhosts = host1.example.com,host2.example.com\nport = 9200\nindex = grafana-dash\nssl = off\n# HTTP user and password, if any.\nuser =\npassword =\n```\n\nYou can use other backends as well.\n\nHTTP API:\n```ini\n[api.example.com]\ntype = api\nurl = http://localhost:3000/api\n# Use either user and password or just the token\nuser =\npassword =\n# token can also be stored in the GRAFANA_API_TOKEN environment variable\ntoken =\n```\n\nMySQL:\n```ini\n[mysql.example.com]\ntype = mysql\nhost = mysql.example.com\nport = 3306\nuser = grafana\npassword =\ndatabase = grafana\n```\n\nPostgreSQL:\n```ini\n[postgresql.example.com]\ntype = postgresql\nhost = postgresql.example.com\nport = 5432\nuser = grafana\npassword =\ndatabase = grafana\n```\n\nSQLite:\n```ini\n[sqlite.example.com]\ntype = sqlite\npath = /opt/grafana/data/grafana.db\n```\n\n# Tips\n\n## Batch mode\n\nAny command can be passed directly as arguments to grafcli, which will exit just after executing it. If you run it without arguments, you will get to interactive mode (preferable choice in most cases).\n\nBatch mode:\n```bash\n$ grafcli ls remote\nhost.example.com\nanother.example.com\n$ \n```\n\nInteractive mode:\n```bash\n$ grafcli\n[/]\u003e ls remote\nhost.example.com\nanother.example.com\n[/]\u003e \n```\n\n## Short names\n\nAll rows and panels names start with a number and it may seem that typing all that stuff gets boring soon. There are completions available (triggered by the `TAB` key) to help you with that.\n\nIt is enough to provide just the number of the row or panel. So instead of typing:\n```\n[/]\u003e cp /templates/dashboards/dashboard/1-Top-Row/1-Top-Panel /remote/example/dashboard/1-Top-Row\n```\nYou can just do:\n```\n[/]\u003e cp /templates/dashboards/dashboard/1/1 /remote/example/dashboard/1\n```\n\nBut then again, TAB-completions make it easy enough to type full names.\n\n# Examples\n\nSome of the common operations.\n\n* Store dashboard as template (saved to `templates/dashboards/main_dashboard`):\n\n```\n[/]\u003e template remote/example/main_dashboard\n```\n\n* Create the exact copy of dashboard's template:\n\n```\n[/templates/dashboards]\u003e cp main_dashboard new_dashboard\n```\n\n* Update remote dashboard with local template:\n\n```\n[/]\u003e cp templates/dashboards/new_dashboard remote/main_dashboard\n```\n\n* Move row from one dashboard to another (adds one more row to destination dashboard):\n\n```\n[/templates/dashboards]\u003e cp main_dashboard/1-Top-Row new_dashboard\n```\n\n* Move row from one dashboard to another and replace existing row:\n\n```\n[/templates/dashboards]\u003e cp main_dashboard/1-Top-Row new_dashboard/2-Some-Existing-Row\n```\n\n* Copy panel between rows (add one more panel to destination row).\n\n```\n[/templates/dashboards]\u003e cp main_dashboard/1-Top-Row/1-Top-Panel new_dashboard/1-Top-Row\n```\n\n* Copy panel between rows and replace existing panel.\n\n```\n[/templates/dashboards]\u003e cp main_dashboard/1-Top-Row/1-Top-Panel new_dashboard/1-Top-Row/2-Second-Panel\n```\n\n* Backup all dashboards.\n\n```\n[/] backup remote/example ~/backup.tgz\n```\n\n* Restore a backup.\n\n```\n[/] restore ~/backup.tgz remote/example\n```\n\n* Import dashboard from a file.\n\n```\n[/]\u003e import ~/dashboard.json templates/dashboards/dashboard\n```\n\n* Export dashboard to a file.\n\n```\n[/]\u003e export templates/dashboards/dashboard ~/dashboard.json\n```\n\n# Development\n\n## Running tests\n\nUnit tests can be run by:\n\n```\nmake unittests\n```\n\nTo run integration tests:\n\n```\nmake integration\n```\n\nThe first run of integration tests can take a bit longer, since images will be built and downloaded.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fm110%2Fgrafcli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fm110%2Fgrafcli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fm110%2Fgrafcli/lists"}