├── .gitignore ├── lib ├── grafana.rb └── grafana │ ├── version.rb │ ├── login.rb │ ├── frontend.rb │ ├── snapshot.rb │ ├── organization.rb │ ├── user.rb │ ├── users.rb │ ├── organizations.rb │ ├── datasource.rb │ ├── http_request.rb │ ├── dashboard.rb │ ├── admin.rb │ ├── client.rb │ └── dashboard_template.rb ├── docs ├── LOGIN.md ├── FRONTEND.md ├── ORGANIZATION.md ├── USERS.md ├── SNAPSHOT.md ├── ADMIN.md ├── ORGANIZATIONS.md ├── USER.md ├── DATASOURCE.md └── DASHBOARD.md ├── grafana-api.gemspec ├── CHANGELOG.md ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | -------------------------------------------------------------------------------- /lib/grafana.rb: -------------------------------------------------------------------------------- 1 | 2 | require 'grafana/client.rb' 3 | -------------------------------------------------------------------------------- /lib/grafana/version.rb: -------------------------------------------------------------------------------- 1 | module Grafana 2 | VERSION = "0.1.0" 3 | end 4 | -------------------------------------------------------------------------------- /docs/LOGIN.md: -------------------------------------------------------------------------------- 1 | ## Login Related API Methods 2 | 3 | The following methods are all relating to login api opperations 4 | 5 | ##### Ping the current login session: 6 | ```ruby 7 | g.ping_session() 8 | ``` 9 | -------------------------------------------------------------------------------- /docs/FRONTEND.md: -------------------------------------------------------------------------------- 1 | 2 | ## Frontend Related API Methods 3 | --- 4 | 5 | The following methods are all relating to the front-end settings 6 | 7 | 8 | ##### Get all current front-end settings: 9 | ```ruby 10 | g.get_frontend_settings() 11 | ``` 12 | -------------------------------------------------------------------------------- /lib/grafana/login.rb: -------------------------------------------------------------------------------- 1 | module Grafana 2 | 3 | module Login 4 | 5 | def ping_session() 6 | endpoint = "/api/login/ping" 7 | @logger.info("Pingning current session (GET #{endpoint})") if @debug 8 | return get_request(endpoint) 9 | 10 | end 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /lib/grafana/frontend.rb: -------------------------------------------------------------------------------- 1 | module Grafana 2 | 3 | module Frontend 4 | 5 | def get_frontend_settings() 6 | endpoint = "/api/frontend/settings" 7 | @logger.info("Getting frontend settings (GET #{endpoint})") if @debug 8 | return get_request(endpoint) 9 | end 10 | 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /grafana-api.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = 'grafana-api' 3 | s.version = '0.2.0' 4 | s.date = '2017-07-20' 5 | s.summary = "Grafana HTTP API Wrapper" 6 | s.description = "A simple wrapper for the Grafana HTTP API" 7 | s.authors = ["Alain Lefebvre"] 8 | s.email = 'alain.lefebvre@gmail.com' 9 | s.files = ["lib/grafana.rb"] + Dir["lib/grafana/*"] 10 | s.homepage = 'http://github.com/hartfordfive/ruby-grafana-api' 11 | s.license = 'MIT' 12 | s.add_runtime_dependency 'json', '~> 1.7' 13 | s.add_runtime_dependency 'rest-client', '~> 1.8' 14 | end 15 | -------------------------------------------------------------------------------- /docs/ORGANIZATION.md: -------------------------------------------------------------------------------- 1 | ## Organization Related API Methods 2 | --- 3 | 4 | The following methods are all relating to Grafana administration 5 | 6 | 7 | ##### Get ognaization for current user: 8 | ```ruby 9 | g.get_current_org() 10 | ``` 11 | 12 | ##### Update properties of the current organization: 13 | ```ruby 14 | g.update_current_org({ 15 | "name": "Main Org." 16 | }) 17 | ``` 18 | 19 | ##### Get users in current organizations: 20 | ```ruby 21 | g.get_current_org_users() 22 | ``` 23 | 24 | ##### Add a global user to the current orgnaization: 25 | ```ruby 26 | g.add_user_to_current_org({ 27 | "role": "Admin", 28 | "loginOrEmail": "jdoe" 29 | }) 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/USERS.md: -------------------------------------------------------------------------------- 1 | ## Users API Methods 2 | --- 3 | The following methods are all relating to global users 4 | 5 | ##### Get all users: 6 | ```ruby 7 | g.get_all_users() 8 | ``` 9 | 10 | ##### Get a user by ID: 11 | ```ruby 12 | g.get_user_by_id(USER_ID) 13 | ``` 14 | 15 | ##### Search for users by a given property: 16 | ```ruby 17 | # Example, search for user by username: 18 | g.search_for_users_by({"login" => "jdoe"}) 19 | # or by email: 20 | g.search_for_users_by({"email" => "johndoe@youremail.com"}) 21 | ``` 22 | 23 | ##### Updating user info: 24 | ```ruby 25 | g.update_user_info(USER_ID, {"email" => "anewemail@yourdomain.com"}) 26 | ``` 27 | 28 | ##### Getting a given user's organizations: 29 | ```ruby 30 | g.get_user_orgs(USER_ID) 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /lib/grafana/snapshot.rb: -------------------------------------------------------------------------------- 1 | module Grafana 2 | 3 | module Snapshot 4 | 5 | def get_snapshot(key) 6 | endpoint = "/api/snapshot/#{key}" 7 | @logger.info("Getting frontend settings (GET #{endpoint})") if @debug 8 | return get_request(endpoint) 9 | end 10 | 11 | def create_snapshot(dashboard={}) 12 | endpoint = "/api/snapshot" 13 | @logger.info("Creating dashboard snapshot (POST #{endpoint})") if @debug 14 | return post_request(endpoint, dashboard) 15 | end 16 | 17 | def delete_snapshot(key) 18 | endpoint = "/api/snapshots-delete/#{key}" 19 | @logger.info("Deleting snapshot ID #{key} (GET #{endpoint})") if @debug 20 | return delete_request(endpoint) 21 | end 22 | 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /docs/SNAPSHOT.md: -------------------------------------------------------------------------------- 1 | 2 | ## Snapshot Methods 3 | --- 4 | 5 | ##### Create a snapshot for a given dahsboard: 6 | ```ruby 7 | g.create_snapshot({ 8 | "dashboard": { 9 | "editable":false, 10 | "hideControls":true, 11 | "nav":[ 12 | { 13 | "enable":false, 14 | "type":"timepicker" 15 | } 16 | ], 17 | "rows": [ 18 | { 19 | 20 | } 21 | ], 22 | "style":"dark", 23 | "tags":[], 24 | "templating":{ 25 | "list":[ 26 | ] 27 | }, 28 | "time":{ 29 | }, 30 | "timezone":"browser", 31 | "title":"Home", 32 | "version":5 33 | }, 34 | "expires": 3600 35 | }) 36 | ``` 37 | 38 | ##### Get snapshot: 39 | ```ruby 40 | g.get_snapshot('snapshot-key') 41 | ``` 42 | 43 | ##### Delete snapshot: 44 | ```ruby 45 | g.delete_snapshot('snapshot-key') 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/ADMIN.md: -------------------------------------------------------------------------------- 1 | ## Admin Related API Methods 2 | --- 3 | 4 | The following methods are all relating to Grafana administration 5 | 6 | 7 | ##### Get current admin settings: 8 | ```ruby 9 | g.get_admin_settings() 10 | ``` 11 | 12 | ##### Update a user's permissions: 13 | ```ruby 14 | # Give user global admin privilege in Grafana 15 | g.update_user_permissions(6, {"isGrafanaAdmin" => false}) 16 | 17 | # Give user admin privilege in their current organization 18 | g.update_user_permissions(6, "Admin") 19 | ``` 20 | 21 | ##### Deleting a user: 22 | ```ruby 23 | g.delete_user(6) 24 | ``` 25 | 26 | ##### Creating a user: 27 | ```ruby 28 | g.create_user({ 29 | "name": "User", 30 | "email": "user@graf.com", 31 | "login": "user", 32 | "password": "userpassword" 33 | }) 34 | ``` 35 | 36 | ##### Updating user password: 37 | ```ruby 38 | g.update_user_pass(6, 'VerySecretPassword') 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## Grafana API CHANGELOG 3 | 4 | Version 0.2.0 5 | ---------- 6 | - Fixed parenthesis issue in Dashboard module (nicolasbrechet, Issue #18) 7 | - Added functionality to fetch grafana dashboard list (shukla-praveen, Issue #16) 8 | - Fixed current user log when debugging on (sebastienluquet, Issue #15) 9 | - Enable an API Request, when grafana is located behind a proxy or the uri_path has changed (bodsch, Issue #12) 10 | - Add APIkey auth capability using headers (BarthV, Issue #11) 11 | 12 | Version 0.1.2 13 | ---------- 14 | * Fixed issue in http_request wrapper where patch method was being used where it should have been the correct POST/PUT/DELETE methods 15 | 16 | Version 0.1.0 17 | ---------- 18 | * Implemented the rest of the HTTP API methods and updated documentation 19 | 20 | 21 | Version 0.0.1 22 | ---------- 23 | * Initial version with very limitted set of methods implemented 24 | -------------------------------------------------------------------------------- /docs/ORGANIZATIONS.md: -------------------------------------------------------------------------------- 1 | ## Organizations Related API Methods 2 | --- 3 | 4 | The following methods are all relating to Grafana organizations 5 | 6 | 7 | ##### Get all orgnaizations: 8 | ```ruby 9 | g.get_all_orgs() 10 | ``` 11 | 12 | ##### Update a given organization: 13 | ```ruby 14 | g.update_org(ORG_ID, { 15 | "name": "Main Org 2." 16 | }) 17 | ``` 18 | 19 | ##### Get all users in a specific orgnaization: 20 | ```ruby 21 | g.get_org_users(ORG_ID) 22 | ``` 23 | 24 | ##### Add a user to given orgnaization: 25 | ```ruby 26 | g.add_user_to_org(ORG_ID, { 27 | "loginOrEmail": "testuser", 28 | "role": "Viewer" 29 | }) 30 | ``` 31 | 32 | ##### Update a user property within a specific organization: 33 | ```ruby 34 | g.update_org_user(ORG_ID, USER_ID, { 35 | "role":"Admin" 36 | }) 37 | ``` 38 | 39 | ##### Remove a user from a given orgnaization: 40 | ```ruby 41 | g.delete_user_from_org(ORG_ID, USER_ID) 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/USER.md: -------------------------------------------------------------------------------- 1 | 2 | ## User API Methods 3 | --- 4 | The following methods are all relating to the active user 5 | 6 | ##### Get the current user: 7 | ```ruby 8 | g.get_current_user() 9 | ``` 10 | 11 | ##### Update current user's password: 12 | ```ruby 13 | g.upate_current_user_pass({ 14 | "oldPassword": "old_password", 15 | "newPassword": "new_password", 16 | "confirmNew": "confirm_new_password" 17 | }) 18 | ``` 19 | 20 | ##### Switch user to a given org in the current session: 21 | ```ruby 22 | g.switch_current_user_org(2) 23 | ``` 24 | 25 | ##### Getting all organizations a user belongs to: 26 | ```ruby 27 | g.get_current_user_orgs() 28 | ``` 29 | 30 | ##### Adding a given dashboard for the current user's favorites: 31 | ```ruby 32 | g.add_dashboard_star(DASHBOARD_ID) 33 | ``` 34 | 35 | ##### Removing a given dashboard for the current user's favorites: 36 | ```ruby 37 | g.remove_dashboard_star(DASHBOARD_ID) 38 | ``` 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /lib/grafana/organization.rb: -------------------------------------------------------------------------------- 1 | 2 | module Grafana 3 | 4 | module Organization 5 | 6 | def get_current_org() 7 | endpoint = "/api/org" 8 | @logger.info("Getting current organization (GET #{endpoint})") if @debug 9 | return get_request(endpoint) 10 | end 11 | 12 | def update_current_org(properties={}) 13 | endpoint = "/api/org" 14 | @logger.info("Updating current organization (PUT #{endpoint})") if @debug 15 | return put_request(endpoint, properties) 16 | end 17 | 18 | def get_current_org_users() 19 | endpoint = "/api/org/users" 20 | @logger.info("Getting organization users (GET #{endpoint})") if @debug 21 | return get_request(endpoint) 22 | end 23 | 24 | def add_user_to_current_org(properties={}) 25 | endpoint = "/api/org/users" 26 | @logger.info("Adding user to current organization (POST #{endpoint})") if @debug 27 | return post_request(endpoint, properties) 28 | end 29 | 30 | 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Lightspeed POS Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /docs/DATASOURCE.md: -------------------------------------------------------------------------------- 1 | 2 | ## Datasource Related API Methods 3 | --- 4 | 5 | The following methods are all relating to data sources 6 | 7 | 8 | ##### Get all current data sources: 9 | ```ruby 10 | g.get_data_sources() 11 | ``` 12 | 13 | ##### Get the CloudWatch namespaces for a given CloudWatch data source id: 14 | ```ruby 15 | g.get_cw_namespaces(23) 16 | ``` 17 | 18 | ##### Create a data source: 19 | ```ruby 20 | g.create_data_source( 21 | { 22 | "access" => "proxy", 23 | "name" => "cloudwatch_metrics_us-east-1", 24 | "database" => "metrics_us-east-1", 25 | "type" => "cloudwatch", 26 | "jsonData" => { "defaultRegion" => "us-east-1"} 27 | } 28 | ) 29 | ``` 30 | 31 | ##### Get available data source types: 32 | ```ruby 33 | g.get_available_data_source_types() 34 | ``` 35 | 36 | ##### Update a data source: 37 | ```ruby 38 | g.update_data_source({ 39 | "id": 1, 40 | "orgId": 1, 41 | "name": "test_datasource", 42 | "type": "graphite", 43 | "access": "proxy", 44 | "url": "http://mydatasource.com", 45 | "password": "", 46 | "user": "", 47 | "database": "", 48 | "basicAuth": true, 49 | "basicAuthUser": "basicuser", 50 | "basicAuthPassword": "basicuser", 51 | "isDefault": false, 52 | "jsonData": null 53 | }) 54 | ``` 55 | 56 | ##### Delete a data source: 57 | ```ruby 58 | g.delete_data_source(23) 59 | ``` 60 | -------------------------------------------------------------------------------- /lib/grafana/user.rb: -------------------------------------------------------------------------------- 1 | 2 | module Grafana 3 | 4 | module User 5 | 6 | def get_current_user() 7 | endpoint = "/api/user" 8 | @logger.info("Getting user current user (GET #{endpoint})") if @debug 9 | return get_request(endpoint) 10 | end 11 | 12 | def update_current_user_pass(properties={}) 13 | endpoint = "/api/user/password" 14 | @logger.info("Updating current user password (PUT #{endpoint})") if @debug 15 | return put_request(endpoint,properties) 16 | end 17 | 18 | def switch_current_user_org(org_id) 19 | endpoint = "/api/user/using/#{org_id}" 20 | @logger.info("Switching current user to Org ID #{org_id} (GET #{endpoint})") if @debug 21 | return post_request(endpoint, {}) 22 | end 23 | 24 | def get_current_user_orgs() 25 | endpoint = "/api/user/orgs" 26 | @logger.info("Getting current user organizations (GET #{endpoint})") if @debug 27 | return get_request(endpoint) 28 | end 29 | 30 | def add_dashboard_star(dashboard_id) 31 | endpoint = "/api/user/stars/dashboard/#{dashboard_id}" 32 | @logger.info("Adding start to dashboard ID #{dashboard_id} (GET #{endpoint})") if @debug 33 | return post_request(endpoint, {}) 34 | end 35 | 36 | def remove_dashboard_star(dashboard_id) 37 | endpoint = "/api/user/stars/dashboard/#{dashboard_id}" 38 | @logger.info("Deleting start on dashboard ID #{dashboard_id} (GET #{endpoint})") if @debug 39 | return delete_request(endpoint) 40 | end 41 | 42 | end 43 | 44 | end 45 | -------------------------------------------------------------------------------- /lib/grafana/users.rb: -------------------------------------------------------------------------------- 1 | 2 | module Grafana 3 | 4 | module Users 5 | 6 | def get_all_users() 7 | endpoint = "/api/users" 8 | @logger.info("Getting all users (GET #{endpoint})") if @debug 9 | return get_request(endpoint) 10 | end 11 | 12 | def get_user_by_id(id) 13 | endpoint = "/api/users/#{id}" 14 | @logger.info("Getting user ID #{id} (GET #{endpoint})") if @debug 15 | return get_request(endpoint) 16 | end 17 | 18 | def search_for_users_by(search={}) 19 | all_users = self.get_all_users() 20 | key, value = search.first 21 | @logger.info("Searching for users matching #{key} = #{value}") if @debug 22 | users = [] 23 | all_users.each do |u| 24 | if u[key] && u[key] == value 25 | users.push(u) 26 | end 27 | end 28 | return (users.length >= 1 ? users : false) 29 | end 30 | 31 | def update_user_info(id, properties={}) 32 | endpoint = "/api/users/#{id}" 33 | @logger.info("Updating user ID #{id}") if @debug 34 | existing_user = self.get_user(id) 35 | if !existing_user 36 | @logger.error("User #{id} does not exist") if @debug 37 | return false 38 | end 39 | properties = existing_user.merge(properties) 40 | return put_request(endpoint,properties.to_json) 41 | end 42 | 43 | def get_user_orgs(userid) 44 | endpoint = "/api/users/#{userid}/orgs" 45 | @logger.info("Getting organizations for user #{userid} (GET #{endpoint})") if @debug 46 | return get_request(endpoint) 47 | end 48 | 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /lib/grafana/organizations.rb: -------------------------------------------------------------------------------- 1 | 2 | module Grafana 3 | 4 | module Organizations 5 | 6 | def get_all_orgs() 7 | endpoint = "/api/orgs" 8 | @logger.info("Getting all organizations (GET #{endpoint})") if @debug 9 | return get_request(endpoint) 10 | end 11 | 12 | 13 | def update_org(org_id, properties={}) 14 | endpoint = "/api/orgs/#{org_id}" 15 | @logger.info("Updating orgnaization ID #{org_id} (POST #{endpoint})") if @debug 16 | return post_request(endpoint, properties) 17 | end 18 | 19 | def get_org_users(org_id) 20 | endpoint = "/api/orgs/#{org_id}/users" 21 | @logger.info("Getting users in orgnaization ID #{org_id} (GET #{endpoint})") if @debug 22 | return get_request(endpoint) 23 | end 24 | 25 | 26 | def add_user_to_org(org_id, user={}) 27 | endpoint = "/api/orgs/#{org_id}/users" 28 | @logger.info("Adding user to orgnaization ID #{org_id} (POST #{endpoint})") if @debug 29 | return post_request(endpoint, user) 30 | end 31 | 32 | def update_org_user(org_id, user_id, properties={}) 33 | endpoint = "/api/orgs/#{org_id}/users/#{user_id}" 34 | @logger.info("Updating user #{user_id} in organization #{org_id} (PATCH #{endpoint})") if @debug 35 | return patch_request(endpoint, properties) 36 | end 37 | 38 | def delete_user_from_org(org_id, user_id) 39 | endpoint = "/api/orgs/#{org_id}/users/#{user_id}" 40 | @logger.info("Deleting user #{user_id} in organization #{org_id} (DELETE #{endpoint})") if @debug 41 | return delete_request(endpoint) 42 | end 43 | 44 | end 45 | 46 | end 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ruby-grafana-api 2 | 3 | [![Gem Version](https://badge.fury.io/rb/grafana-api.svg)](https://badge.fury.io/rb/grafana-api) 4 | 5 | ## Description 6 | 7 | A simple Ruby wrapper for the [Grafana](http://docs.grafana.org/reference/http_api/) HTTP API. To include in your project, simply require the grafana library: 8 | 9 | ```ruby 10 | require 'grafana' 11 | ``` 12 | 13 | ## Comments/Notes 14 | 15 | If you come across a bug or if you have a request for a new feature, please open an issue. 16 | 17 | 18 | ## Methods & Usage Examples 19 | 20 | #### Creating an instance of the grafana api client: 21 | ```ruby 22 | options = { 23 | "debug" => false, 24 | "timeout" => 3, 25 | "ssl" => false 26 | } 27 | g = Grafana::Client.new('[GRAFANA_HOST]', [GRAFANA_PORT], '[GRAFANA_USER]', '[GRAFANA_PASS]', options) 28 | ``` 29 | 30 | #### Connecting to Grafana using an API key: 31 | ```ruby 32 | options = { 33 | "debug" => false, 34 | "timeout" => 3, 35 | "ssl" => false, 36 | "headers" => { 37 | "Authorization" => "Bearer eiJrIjoidTBsQWpicGR0SzFXD29aclExTjk1cVliMWREUVp0alAiLCJuIjoiR8JhZGFzaG3yFiwiawQIOjE2" 38 | } 39 | } 40 | g = Grafana::Client.new('[GRAFANA_HOST]', [GRAFANA_PORT], nil, nil, options) 41 | ``` 42 | *user and pass attributes are ignored when specifying Authorization header* 43 | 44 | #### Individual Module Documentation 45 | 46 | * [Admin](docs/ADMIN.md) 47 | * [Dashboard](docs/DASHBOARD.md) 48 | * [Datasource](docs/DATASOURCE.md) 49 | * [Frontend](docs/FRONTEND.md) 50 | * [Login](docs/LOGIN.md) 51 | * [Organization](docs/ORGANIZATION.md) 52 | * [Organizations](docs/ORGANIZATIONS.md) 53 | * [Snapshot](docs/SNAPSHOT.md) 54 | * [User](docs/USER.md) 55 | * [Users](docs/USERS.md) 56 | 57 | 58 | ## License 59 | 60 | Covered by the MIT [license](LICENSE). 61 | -------------------------------------------------------------------------------- /docs/DASHBOARD.md: -------------------------------------------------------------------------------- 1 | 2 | ## Dashboard Related API Methods 3 | --- 4 | 5 | The following methods are all relating to dashboards 6 | 7 | 8 | ##### Get a dashboard: 9 | ```ruby 10 | g.get_dashboard('Main Dashboard') # converted to 'main-dashboard' automatically 11 | ``` 12 | 13 | ##### Get a dashboard list: 14 | ```ruby 15 | g.get_dashboard_list() # No parameter is required 16 | ``` 17 | 18 | ##### Creating a dashboard: 19 | ```ruby 20 | g.create_dashboard({ 21 | "title" => "API Created Dashboard", 22 | "from" => "now-30m", 23 | "to" => "now", 24 | "panels" => [ 25 | { 26 | "datasource" => "cloudwatch_production_us-east-1", 27 | "graph_title" => "EC2 Instance CPU", 28 | "targets" => [ 29 | { 30 | "metric_name" => "CPUUtilization", 31 | "namespace" => "AWS/EC2", 32 | "dimension_name" => "InstanceId", 33 | "dimension_value" => "i-07abc123", 34 | "region" => "us-east-1", 35 | "legend_alias" => "Instance #1 {{metric}} {{stat}}" 36 | }, 37 | { 38 | "metric_name" => "CPUUtilization", 39 | "namespace" => "AWS/EC2", 40 | "dimension_name" => "InstanceId", 41 | "dimension_value" => "i-07abc124", 42 | "region" => "us-east-1", 43 | "legend_alias" => "Instance #2 {{metric}} {{stat}}" 44 | }, 45 | { 46 | "metric_name" => "CPUUtilization", 47 | "namespace" => "AWS/EC2", 48 | "dimension_name" => "InstanceId", 49 | "dimension_value" => "i-07abc125", 50 | "region" => "us-east-1", 51 | "legend_alias" => "Instance #3 {{metric}} {{stat}}" 52 | } 53 | ] 54 | } 55 | ] 56 | }) 57 | ``` 58 | 59 | ##### Delete a dashboard: 60 | ```ruby 61 | g.delete_dashboard('Main Dashboard') 62 | ``` 63 | 64 | ##### Get the home dashboard: 65 | ```ruby 66 | g.get_home_dashboard() 67 | ``` 68 | 69 | ##### Get dashboard tags: 70 | ```ruby 71 | g.get_dashboard_tags() 72 | ``` 73 | 74 | ##### Search for dashboard: 75 | ```ruby 76 | g.search_dashboards({"query" => "My Dashboard", "tags" => 'test'}) 77 | ``` 78 | -------------------------------------------------------------------------------- /lib/grafana/datasource.rb: -------------------------------------------------------------------------------- 1 | 2 | module Grafana 3 | 4 | module Datasource 5 | 6 | def get_cw_namespaces(datasource_id) 7 | endpoint = "/api/datasources/proxy/#{datasource_id}" 8 | @logger.info("Getting data source namespaces (POST /api/datasources/proxy/#{datasource_id})") if @debug 9 | return post_request(endpoint, {"action" => "__GetNamespaces"}.to_json) 10 | end 11 | 12 | def get_data_sources() 13 | endpoint = "/api/datasources" 14 | @logger.info("Attempting to get existing data sources (GET #{endpoint})") if @debug 15 | data_sources = get_request(endpoint) 16 | if !data_sources 17 | return false 18 | end 19 | data_source_map = {} 20 | data_sources.each { |ds| 21 | data_source_map[ds['id']] = ds 22 | } 23 | return data_source_map 24 | end 25 | 26 | def get_data_source(id) 27 | endpoint = "/api/datasources/#{id}" 28 | @logger.info("Attempting to get existing data source ID #{id}") if @debug 29 | return get_request(endpoint) 30 | end 31 | 32 | def update_data_source(id, ds={}) 33 | existing_ds = self.get_data_source(id) 34 | ds = existing_ds.merge(ds) 35 | endpoint = "/api/datasources/#{id}" 36 | @logger.info("Updating data source ID #{id}") if @debug 37 | return put_request(endpoint, ds.to_json) 38 | end 39 | 40 | def create_data_source(ds={}) 41 | if ds == {} || !ds.has_key?('name') || !ds.has_key?('database') 42 | @logger.error("Error: missing 'name' and 'database' values!") if @debug 43 | return false 44 | end 45 | endpoint = "/api/datasources" 46 | @logger.info("Creating data source: #{ds['name']} (database: #{ds['database']})") if @debug 47 | return post_request(endpoint, ds.to_json) 48 | end 49 | 50 | def delete_data_source(id) 51 | endpoint = "/api/datasources/#{id}" 52 | @logger.info("Deleting data source #{id} (DELETE #{endpoint})") if @debug 53 | return delete_request(endpoint) 54 | end 55 | 56 | def get_available_data_source_types() 57 | endpoint = '/api/datasources/plugins' 58 | @logger.info("Attempting to get existing data source types (GET #{endpoint})") if @debug 59 | return get_request(endpoint) 60 | end 61 | 62 | end 63 | 64 | end 65 | -------------------------------------------------------------------------------- /lib/grafana/http_request.rb: -------------------------------------------------------------------------------- 1 | module Grafana 2 | 3 | module HttpRequest 4 | 5 | def get_request(endpoint) 6 | @logger.info("Running: Grafana::HttpRequest::#{__method__} on #{endpoint}") if @debug 7 | return _issue_request('GET', endpoint) 8 | end 9 | 10 | def post_request(endpoint, postdata={}) 11 | @logger.info("Running: Grafana::HttpRequest::#{__method__} on #{endpoint}") if @debug 12 | return _issue_request('POST', endpoint, postdata) 13 | end 14 | 15 | def put_request(endpoint, putdata={}) 16 | @logger.info("Running: Grafana::HttpRequest::#{__method__} on #{endpoint}") if @debug 17 | return _issue_request('PUT', endpoint, putdata) 18 | end 19 | 20 | def delete_request(endpoint) 21 | @logger.info("Running: Grafana::HttpRequest::#{__method__} on #{endpoint}") if @debug 22 | return _issue_request('DELETE', endpoint) 23 | end 24 | 25 | def patch_request(endpoint, patchdata={}) 26 | @logger.info("Running: Grafana::HttpRequest::#{__method__} on #{endpoint}") if @debug 27 | return _issue_request('PATCH', endpoint, patchdata) 28 | end 29 | 30 | def _issue_request(method_type='GET', endpoint='/', data={}) 31 | 32 | begin 33 | resp = nil 34 | case method_type.upcase 35 | when 'GET' 36 | resp = @api_instance[endpoint].get(@headers) 37 | when 'POST' 38 | resp = @api_instance[endpoint].post(data,@headers) 39 | when 'PATCH' 40 | resp = @api_instance[endpoint].patch(data,@headers) 41 | when 'PUT' 42 | resp = @api_instance[endpoint].put(data,@headers) 43 | when 'DELETE' 44 | resp = @api_instance[endpoint].delete(@headers) 45 | else 46 | @logger.error("Error: #{__method__} is not a valid request method.") if @debug 47 | return false 48 | end 49 | 50 | if (resp.code.to_i >= 200 && resp.code.to_i <= 299) || (resp.code.to_i >= 400 && resp.code.to_i <= 499) 51 | return JSON.parse(resp.body) 52 | else 53 | @logger.error("#{__method__} on #{endpoint} failed: HTTP #{resp.code} - #{resp.body}") if @debug 54 | return false 55 | end 56 | 57 | rescue => e 58 | @logger.error("Error: #{__method__} #{endpoint} error: #{e}") if @debug 59 | return false 60 | end 61 | 62 | end 63 | 64 | end 65 | 66 | end 67 | -------------------------------------------------------------------------------- /lib/grafana/dashboard.rb: -------------------------------------------------------------------------------- 1 | module Grafana 2 | 3 | module Dashboard 4 | 5 | def create_slug(text) 6 | text.gsub!(/[()]/, "") 7 | if text =~ /\s/ 8 | if text =~ /-/ 9 | text = text.gsub(/\s+/, "").downcase 10 | else 11 | text = text.gsub(/\s+/, "-").downcase 12 | end 13 | end 14 | return text 15 | end 16 | 17 | def get_dashboard_list() 18 | endpoint = "/api/search" 19 | @logger.info("Attempting to get dashboard list (GET /api/search)") if @debug 20 | return get_request(endpoint) 21 | end 22 | 23 | def get_dashboard(name='') 24 | name = self.create_slug(name) 25 | endpoint = "/api/dashboards/db/#{name}" 26 | @logger.info("Attempting to get dashboard (GET /api/dashboards/db/#{name})") if @debug 27 | return get_request(endpoint) 28 | end 29 | 30 | def create_dashboard(properties={}) 31 | endpoint = "/api/dashboards/db" 32 | dashboard = self.build_template(properties) 33 | @logger.info("Creating dashboard: #{properties['title']} (POST /api/dashboards/db)") if @debug 34 | return post_request(endpoint, dashboard) 35 | end 36 | 37 | def delete_dashboard(name) 38 | name = self.create_slug(name) 39 | data = self.get_dashboard( name ) 40 | id = data['dashboard']['id'] ? data['dashboard']['id'] : nil 41 | 42 | endpoint = "/api/dashboards/db/#{name}" 43 | @logger.info("Deleting dahsboard ID #{id} (DELETE #{endpoint})") if @debug 44 | return delete_request(endpoint) 45 | end 46 | 47 | def get_home_dashboard() 48 | endpoint = "/api/dashboards/home" 49 | @logger.info("Attempting to get home dashboard (GET #{endpoint})") if @debug 50 | return get_request(endpoint) 51 | end 52 | 53 | def get_dashboard_tags() 54 | endpoint = "/api/dashboards/tags" 55 | @logger.info("Attempting to get dashboard tags(GET #{endpoint})") if @debug 56 | return get_request(endpoint) 57 | end 58 | 59 | def search_dashboards(params={}) 60 | params['query'] = (params['query'].length >= 1 ? CGI::escape(params['query']) : '' ) 61 | params['starred'] = (params['starred'] ? 'true' : 'false') 62 | endpoint = "/api/search/?query=#{params['query']}&starred=#{params['starred']}&tag=#{params['tags']}" 63 | @logger.info("Attempting to search for dashboards (GET #{endpoint})") if @debug 64 | return get_request(endpoint) 65 | end 66 | 67 | end 68 | 69 | end 70 | -------------------------------------------------------------------------------- /lib/grafana/admin.rb: -------------------------------------------------------------------------------- 1 | 2 | module Grafana 3 | 4 | module Admin 5 | 6 | def get_admin_settings() 7 | endpoint = "/api/admin/settings" 8 | @logger.info("Getting admin settings (GET #{endpoint})") if @debug 9 | return get_request(endpoint) 10 | end 11 | 12 | def update_user_permissions(id, perm) 13 | 14 | valid_perms = ['Viewer','Editor','Read Only Editor','Admin'] 15 | 16 | if perm.class.to_s == "String" && !valid_perms.include?(perm) 17 | @logger.warn("Basic user permissions include: #{valid_perms.join(',')}") if @debug 18 | return false 19 | elsif perm.class.to_s == "Hash" && 20 | ( !perm.has_key?('isGrafanaAdmin') || ![true,false].include?(perm['isGrafanaAdmin']) ) 21 | @logger.warn("Grafana admin permission must be either true or false") if @debug 22 | return false 23 | end 24 | 25 | @logger.info("Updating user ID #{id} permissions") if @debug 26 | 27 | if perm.class.to_s == 'Hash' 28 | endpoint = "/api/admin/users/#{id}/permissions" 29 | @logger.info("Updating user ID #{id} permissions (PUT #{endpoint})") if @debug 30 | return put_request(endpoint, {"isGrafanaAdmin" => perm['isGrafanaAdmin']}.to_json) 31 | else 32 | org = self.get_current_org() 33 | endpoint = "/api/orgs/#{org['id']}/users/#{id}" 34 | @logger.info("Updating user ID #{id} permissions (PUT #{endpoint})") if @debug 35 | user = { 36 | 'name' => org['name'], 37 | 'orgId' => org['id'], 38 | 'role' => perm.downcase.capitalize 39 | } 40 | return patch_request(endpoint, user.to_json) 41 | end 42 | end 43 | 44 | def delete_user(user_id) 45 | if user_id == 1 46 | @logger.warn("Can't delete user ID #{user_id} (admin user)") if @debug 47 | return false 48 | end 49 | endpoint = "/api/admin/users/#{user_id}" 50 | @logger.info("Deleting user ID #{user_id} (DELETE #{endpoint})") if @debug 51 | return delete_request(endpoint) 52 | end 53 | 54 | def create_user(properties={}) 55 | endpoint = "/api/admin/users" 56 | @logger.info("Creating user: #{properties['name']}") if @debug 57 | @logger.info("Data: #{properties.to_s}") if @debug 58 | return post_request(endpoint, properties.to_json) 59 | end 60 | 61 | def update_user_pass(user_id,password) 62 | endpoint = " /api/admin/users/#{user_id}/#{password}" 63 | @logger.info("Updating password for user ID #{user_id} (PUT #{endpoint})") if @debug 64 | return put_request(endpoint,properties) 65 | end 66 | 67 | 68 | end 69 | 70 | end 71 | -------------------------------------------------------------------------------- /lib/grafana/client.rb: -------------------------------------------------------------------------------- 1 | 2 | require 'rest-client' 3 | require 'json' 4 | require 'logger' 5 | 6 | module Grafana 7 | 8 | require_relative 'http_request' 9 | require_relative 'user' 10 | require_relative 'users' 11 | require_relative 'datasource' 12 | require_relative 'organization' 13 | require_relative 'organizations' 14 | require_relative 'dashboard' 15 | require_relative 'dashboard_template' 16 | require_relative 'snapshot' 17 | require_relative 'frontend' 18 | require_relative 'login' 19 | require_relative 'admin' 20 | require_relative 'version' 21 | 22 | class Client 23 | 24 | attr_reader :debug, :session_cookies, :headers, :logger, :api_instance 25 | 26 | include Grafana::HttpRequest 27 | include Grafana::User 28 | include Grafana::Users 29 | include Grafana::Datasource 30 | include Grafana::Organization 31 | include Grafana::Organizations 32 | include Grafana::Dashboard 33 | include Grafana::DashboardTemplate 34 | include Grafana::Snapshot 35 | include Grafana::Frontend 36 | include Grafana::Login 37 | include Grafana::Admin 38 | 39 | def initialize(host="localhost", port=3000, user='admin', pass='', settings={}) 40 | 41 | if settings.has_key?('timeout') && settings['timeout'].to_i <= 0 42 | settings['timeout'] = 5 43 | end 44 | 45 | if settings.has_key?('open_timeout') && settings['open_timeout'].to_i <= 0 46 | settings['open_timeout'] = 5 47 | end 48 | 49 | if settings.has_key?('headers') && settings['headers'].class.to_s != 'Hash' 50 | settings['headers'] = {} 51 | end 52 | 53 | if settings.has_key?('url_path') && settings['url_path'].class.to_s != 'String' 54 | settings['url_path'] = '' 55 | end 56 | 57 | proto = ( settings.has_key?('ssl') && settings['ssl'] == true ? 'https' : 'http') 58 | url = sprintf( '%s://%s:%s%s', proto, host, port, settings['url_path'] ) 59 | 60 | @logger.info("Initializing API client #{url}") if @debug 61 | @logger.info("Options: #{settings}") if @debug 62 | 63 | @api_instance = RestClient::Resource.new( 64 | "#{url}", 65 | :timeout => settings['timeout'], 66 | :open_timeout => settings['open_timeout'], 67 | :headers => settings['headers'] 68 | ) 69 | @debug = (settings['debug'] ? true : false) 70 | @logger = Logger.new(STDOUT) 71 | @headers = nil 72 | 73 | if settings['headers'].key?('Authorization') 74 | # API key Auth 75 | @headers = { 76 | :content_type => 'application/json; charset=UTF-8', 77 | :Authorization => settings['headers']['Authorization'] 78 | } 79 | else 80 | # Regular login Auth 81 | self.login(user, pass) 82 | end 83 | return self 84 | end 85 | 86 | def login(user='admin',pass='admin') 87 | @logger.info("Attempting to establish user session") if @debug 88 | request_data = {'User' => user, 'Password' => pass} 89 | begin 90 | resp = @api_instance['/login'].post( 91 | request_data.to_json, 92 | {:content_type => 'application/json; charset=UTF-8'} 93 | ) 94 | @session_cookies = resp.cookies 95 | if resp.code.to_i == 200 96 | @headers = { 97 | :content_type => 'application/json; charset=UTF-8', 98 | :cookies => @session_cookies 99 | } 100 | return true 101 | else 102 | return false 103 | end 104 | rescue => e 105 | @logger.error("Error running POST request on /login: #{e}") if @debug 106 | @logger.error("Request data: #{request_data.to_json}") if @debug 107 | return false 108 | end 109 | @logger.info("User session initiated") if @debug 110 | end 111 | 112 | end # End of Client class 113 | 114 | end # End of GrafanaApi module 115 | -------------------------------------------------------------------------------- /lib/grafana/dashboard_template.rb: -------------------------------------------------------------------------------- 1 | 2 | module Grafana 3 | 4 | module DashboardTemplate 5 | 6 | # CloudWatch Namespaces, Dimensions and Metrics Reference: 7 | # http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/CW_Support_For_AWS.html 8 | @@cw_dimensions = [] 9 | 10 | 11 | def build_template(params={}) 12 | 13 | if !params.has_key?('from') 14 | params['from'] = 'now-2h' 15 | end 16 | if !params.has_key?('to') 17 | params['to'] = 'now' 18 | end 19 | if params['title'] == '' 20 | return false 21 | end 22 | 23 | rows = [] 24 | params['panels'].each do |panel| 25 | rows.push(self.build_panel(panel)) 26 | end 27 | 28 | tpl = %q[ 29 | { 30 | "dashboard": { 31 | "id": null, 32 | "title": "%{title}", 33 | "originalTitle": "%{title}", 34 | "annotations": { 35 | "list": [] 36 | }, 37 | "hideControls": false, 38 | "timezone": "browser", 39 | "editable": true, 40 | "rows": [ 41 | %{rows} 42 | ], 43 | "time": { 44 | "from": "%{from}", 45 | "to": "%{to}" 46 | }, 47 | "timepicker": { 48 | "collapse": false, 49 | "enable": true, 50 | "notice": false, 51 | "now": true, 52 | "refresh_intervals": [ 53 | "5s", 54 | "10s", 55 | "30s", 56 | "1m", 57 | "5m", 58 | "15m", 59 | "30m", 60 | "1h", 61 | "2h", 62 | "1d" 63 | ], 64 | "status": "Stable", 65 | "time_options": [ 66 | "5m", 67 | "15m", 68 | "1h", 69 | "6h", 70 | "12h", 71 | "24h", 72 | "2d", 73 | "7d", 74 | "30d" 75 | ], 76 | "type": "timepicker" 77 | }, 78 | "tags": ["api-templated"], 79 | "templating": { 80 | "list": [] 81 | }, 82 | "schemaVersion": 7, 83 | "sharedCrosshair": false, 84 | "style": "dark", 85 | "version": 1, 86 | "links": [] 87 | }, 88 | "overwrite": false 89 | } 90 | ] 91 | 92 | return tpl % { 93 | title: params['title'], 94 | from: params['from'], 95 | to: params['to'], 96 | rows: rows.join(',') 97 | } 98 | 99 | end 100 | 101 | 102 | def build_panel(params={}) 103 | 104 | panel = %q[ 105 | { 106 | "collapse": false, 107 | "editable": true, 108 | "height": "250px", 109 | "panels": [ 110 | { 111 | "aliasColors": {}, 112 | "bars": false, 113 | "datasource": "%{datasource}", 114 | "editable": true, 115 | "error": false, 116 | "fill": 1, 117 | "grid": { 118 | "leftLogBase": 1, 119 | "leftMax": null, 120 | "leftMin": null, 121 | "rightLogBase": 1, 122 | "rightMax": null, 123 | "rightMin": null, 124 | "threshold1": null, 125 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 126 | "threshold2": null, 127 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 128 | }, 129 | "legend": { 130 | "avg": false, 131 | "current": false, 132 | "max": false, 133 | "min": false, 134 | "show": true, 135 | "total": false, 136 | "values": false 137 | }, 138 | "lines": true, 139 | "linewidth": 2, 140 | "links": [], 141 | "nullPointMode": "connected", 142 | "percentage": false, 143 | "pointradius": 5, 144 | "points": false, 145 | "renderer": "flot", 146 | "seriesOverrides": [], 147 | "span": 12, 148 | "stack": false, 149 | "steppedLine": false, 150 | "targets": [ 151 | %{targets} 152 | ], 153 | "timeFrom": null, 154 | "timeShift": null, 155 | "title": "%{graph_title}", 156 | "tooltip": { 157 | "shared": true, 158 | "value_type": "cumulative" 159 | }, 160 | "type": "graph", 161 | "x-axis": true, 162 | "y-axis": true, 163 | "y_formats": [ 164 | "short", 165 | "short" 166 | ] 167 | } 168 | ], 169 | "title": "Row" 170 | } 171 | ] 172 | 173 | targets = [] 174 | params['targets'].each do |t| 175 | targets.push(self.build_target(t)) 176 | end 177 | 178 | 179 | return panel % { 180 | datasource: params['datasource'], 181 | graph_title: params['graph_title'], 182 | targets: targets.join(',') 183 | } 184 | 185 | 186 | end 187 | 188 | 189 | def build_target(params={}) 190 | 191 | target = %q[ 192 | { 193 | "alias": "%{legend_alias}", 194 | "dimensions": { 195 | "%{dimension_name}": "%{dimension_value}" 196 | }, 197 | "metricName": "%{metric_name}", 198 | "namespace": "%{namespace}", 199 | "period": 60, 200 | "query": "", 201 | "refId": "A", 202 | "region": "%{region}", 203 | "statistics": [ 204 | "Maximum" 205 | ], 206 | "timeField": "@timestamp" 207 | } 208 | ] 209 | 210 | return target % { 211 | metric_name: params['metric_name'], 212 | namespace: params['namespace'], 213 | dimension_name: params['dimension_name'], 214 | dimension_value: params['dimension_value'], 215 | region: params['region'], 216 | legend_alias: params['legend_alias'], 217 | } 218 | 219 | end 220 | 221 | end 222 | 223 | end 224 | 225 | --------------------------------------------------------------------------------