A Duct library that provides an Integrant key for managing dashboards and associated users and organizations in Grafana.
To use this library add the following key to your configuration:
:magnet.dashboard-manager/grafana
This key expects a configuration map with two mandatory keys, plus another three optional ones. These are the mandatory keys:
:uri
: The URI where Grafana's server is listening.:credentials
: A vector with two elements, a username and password, that are used for basic HTTP authentication.These are the optional keys:
:timeout
: Timeout value (in milli-seconds) for an connection attempt with Grafana.:max-retries
: If the connection attempt fails, how many retries we want to attempt before giving up.:backoff-ms
: This is a vector in the form [initial-delay-ms max-delay-ms multiplier] to control the delay between each retry. The delay for nth retry will be (max (* initial-delay-ms n multiplier) max-delay-ms). If multiplier is not specified (or if it is nil), a multiplier of 2 is used. All times are in milli-seconds.Key initialization returns a Grafana
record that can be used to perform the Grafana operations described below.
Basic configuration:
:magnet.dashboard-manager/grafana
{:uri #duct/env ["GRAFANA_URI" Str :or "http://localhost:3000"]
:credentials [#duct/env ["GRAFANA_USERNAME" Str :or "admin"]
#duct/env ["GRAFANA_TEST_PASSWORD" Str :or "admin"]]}
Configuration with custom request retry policy:
:magnet.dashboard-manager/grafana
{:uri #duct/env ["GRAFANA_URI" Str :or "http://localhost:3000"]
:credentials [#duct/env ["GRAFANA_USERNAME" Str :or "admin"]
#duct/env ["GRAFANA_TEST_PASSWORD" Str :or "admin"]]
:timeout 300
:max-retries 5
:backoff-ms [10 500]}
Grafana
recordIf you are using the library as part of a Duct-based project, adding any of the previous configurations to your config.edn
file will perform all the steps necessary to initialize the key and return a Grafana
record for the associated configuration. In order to show a few interactive usages of the library, we will do all the steps manually in the REPL.
First we require the relevant namespaces:
user> (require '[integrant.core :as ig]
'[magnet.dashboard-manager.core :as core])
nil
user>
Next we create the configuration var holding the Grafana integration configuration details:
user> (def config {:uri #duct/env ["GRAFANA_URI" Str :or "http://localhost:3000"]
:credentials [#duct/env ["GRAFANA_USERNAME" Str :or "admin"]
#duct/env ["GRAFANA_PASSWORD" Str :or "admin"]]})
#'user/config
user>
Now that we have all pieces in place, we can initialize the :magnet.dashboard-manager/grafana
Integrant key to get a Grafana
record. As we are doing all this from the REPL, we have to manually require magnet.dashboard-manager.grafana
namespace, where the init-key
multimethod for that key is defined (this is not needed when Duct takes care of initializing the key as part of the application start up):
user> (require '[magnet.dashboard-manager.grafana :as grafana])
nil
user>
And we finally initialize the key with the configuration defined above, to get our Grafana
record:
user> (def gf-record (->
config
(->> (ig/init-key :magnet.dashboard-manager/grafana))))
#'user/gf-record
user> gf-record
#magnet.dashboard_manager.grafana.Grafana{:uri "http://localhost:4000",
:credentials ["admin"
"admin"],
:timeout 200,
:max-retries 10,
:backoff-ms [500 1000 2.0]}
user>
Now that we have our Grafana
record, we are ready to use the methods defined by the protocols defined in magnet.dashboard-manager.core
namespace.
create-org
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
, :already-exists
:id
: ID assigned to the created organizationuser> (core/create-org gf-record "foo")
{:status :ok :id 2}
get-orgs
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
:orgs
: A vector of maps. Each map representing an existing organization.user> (core/get-orgs gf-record)
{:status :ok :orgs [{:id 1 :name "Main Org"}
{:id 2 :name "foo"}]}
update-org
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
, :already-exists
user> (core/update-org gf-record 2 "foo-bar")
{:status :ok}
delete-org
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
user> (core/delete-org gf-record 2)
{:status :ok}
add-org-user
Grafana
record:status
: :ok
,:access-denied
, :not-found
, :error
,:role-not-found
, :user-not-found
, :already-exists
user> (core/add-org-user gf-record 1 "foo-bar" "Editor")
{:status :ok}
get-org-users
Grafana
record:status
: :ok
,:access-denied
, :not-found
, :error
, :not-found
:users
: A vector of maps. Each map representing an existing user.user> (core/get-org-users gf-record 1)
{:status :ok :users [{:orgId 1, :userId 1, :email "admin@localhost", :avatarUrl "/avatar/46d229b033af06a191ff2267bca9ae56", :login "admin", :role "Admin", :lastSeenAt "2019-05-27T14:21:51Z", :lastSeenAtAge "< 1m"}
{:orgId 1, :userId 2, :email "foo-bar@email.com", :avatarUrl "/avatar/46d234t033af06a191ff2267bca9ae56", :login "foo-bar", :role "Editor", :lastSeenAt "2019-05-27T14:21:51Z", :lastSeenAtAge "< 1m"}]}
delete-org-user
Grafana
record:status
: :ok
,:access-denied
, :error
user> (core/delete-org-user gf-record 1 2)
{:status :ok}
create-user
Grafana
record:name
(OPTIONAL):email
(REQUIRED if login is not specified):login
(REQUIRED if email is not specified):password
(REQUIRED):status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
, :already-exists
, :invalid-data
:id
: The created user's ID.user> (core/create-user gf-record {:login "login" :password "password"})
{:status :ok :id 3}
update-user
Grafana
record:name
:email
(REQUIRED if login is not specified):login
(REQUIRED if email is not specified):status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
, :already-exists
, :missing-mandatory-data
:id
: The created user's ID.user> (core/update-user gf-record 3 {:name "fooo" :login "login"})
{:status :ok}
get-user
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
:user
: A map with the user information.user> (core/get-user gf-record "login")
{:status :ok :user {:id 3, :email "fooo@email.com", :name "fooo", :login "login", :theme "", :orgId 1, :isGrafanaAdmin false}}
get-user-orgs
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
, not-found
:orgs
: A vector of maps. Each map representing an organization.user> (core/get-user-orgs gf-record 1)
{:status :ok :orgs [{:orgId 1, :name "Main Org.", :role "Admin"}]}
delete-user
Grafana
record:status
: :ok
, :access-denied
, :unknown-host
, :connection-refused
, :error
user> (core/delete-user gf-record 2)
{:status :ok}
get-org-dashboards
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
:dashboards
: A list of maps. Each map representing a dashboard and it's panels.user> (core/get-org-dashboards gf-record 1)
{:status :ok, :dashboards ({:uid "yYtEB6WZz", :title "Example Dashboard", :url "/d/yYtEB6WZz/example-dashboard", :panels ({:id 2, :title "Panel Title\
", :ds-url "/d/yYtEB6WZz/example-dashboard"} {:id 4, :title "Panel Title", :ds-url "/d/yYtEB6WZz/example-dashboard"})})}
get-org-panels
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
:panels
: A list of maps. Each map representing a panel.user> (core/get-org-panels gf-record 1)
{:status :ok, :panels ({:id 2, :title "Panel Title", :ds-url "/d/yYtEB6WZz/example-dashboard"} {:id 4, :title "Panel Title", :ds-url "/d/yYtEB6WZz/ex\
ample-dashboard"})}
get-ds-panels
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
:panels
: A list of maps. Each map representing a panel.user> (core/get-org-panels gf-record 1)
{:status :ok, :panels ({:id 2, :title "Panel Title", :ds-url "/d/yYtEB6WZz/example-dashboard"} {:id 4, :title "Panel Title", :ds-url "/d/yYtEB6WZz/ex\
ample-dashboard"})}
create-datasource
Grafana
record:name
,:type
, and :access
key are mandatory, see the example, and Grafana's API documentation for more information.:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
, :already-exists
:id
: ID assigned to the created datasourceuser> (core/create-datasource gf-record 1 {:name "Name"
:type "postgres"
:url "postgres:5432"
:access "proxy"
:password "pass"
:user "postgres"
:database "hydrogen"
:isDefault true
:jsonData {:postgresVersion 906 :sslmode "disable"}})
{:status :ok :id 2}
get-datasource
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
:datasource
: A map with the datasource data.user> (core/get-datasource gf-record 1 2)
{:status :ok :datasource {:isDefault false,
:orgId 1,
:password "pass",
:name "b9db0015-e45f-4a81-80ef-c3b5225cbe39",
:secureJsonFields {},
:type "postgres",
:basicAuthUser "",
:typeLogoUrl "",
:readOnly false,
:basicAuthPassword "",
:id 2,
:basicAuth false,
:url "postgres:5432",
:database "hydrogen",
:access "proxy",
:jsonData {:postgresVersion 906, :sslmode "disable"},
:version 1,
:user "postgres",
:withCredentials false}}
get-datasources
Grafana
record:status
: :ok
, :access-denied
, :not-found
, :unknown-host
, :connection-refused
, :error
:datasources
: A vector of maps. Each map representing an existing datasource.user> (core/get-datasources gf-record 1)
{:status :ok :datasources [{:isDefault false,
:orgId 1,
:password "pass",
:name "00f70239-be39-4199-939c-d90fa625b41f",
:type "postgres",
:typeLogoUrl
"public/app/plugins/datasource/postgres/img/postgresql_logo.svg",
:readOnly false,
:id 32,
:basicAuth false,
:url "postgres:5432",
:database "hydrogen",
:access "proxy",
:jsonData {:postgresVersion 906, :sslmode "disable"},
:user "postgres"}
{:name "datasource2"
...}]
update-datasource
Grafana
record:name
,:type
, and :access
key are mandatory, see the example, and Grafana's API documentation for more information.:status
: :ok
, :access-denied
, :unknown-host
, :connection-refused
, :error
user> (core/update-datasource gf-record 1 2 {:name "new-name"})
{:status :ok
:datasource {:name "new-name" ...}}
delete-datasource
Grafana
record:status
: :ok
, :access-denied
, not-found
, :unknown-host
, :connection-refused
, :error
user> (core/delete-datasource gf-record 1 2)
{:status :ok}
Copyright (c) 2019 Magnet S Coop.
The source code for the library is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
Can you improve this documentation? These fine people already did:
lucassousaf, Bingen Galartza Iparragirre, Iñaki Arenaza, Lucas Sousa & Bingen GalartzaEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close