16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
Each new release typically also includes the latest modulesync defaults.
These should not affect the functionality of the module.

## [v4.2.0](https://github.com/voxpupuli/puppet-grafana/tree/v4.2.0) (2018-03-06)

[Full Changelog](https://github.com/voxpupuli/puppet-grafana/compare/v4.1.1...v4.2.0)

**Implemented enhancements:**

- Create organization [\#71](https://github.com/voxpupuli/puppet-grafana/issues/71)
- Expand organization property for dashboards [\#94](https://github.com/voxpupuli/puppet-grafana/pull/94) ([brandonrdn](https://github.com/brandonrdn))
- Add grafana\_api\_path to allow for API sub-paths [\#93](https://github.com/voxpupuli/puppet-grafana/pull/93) ([brandonrdn](https://github.com/brandonrdn))

## [v4.1.1](https://github.com/voxpupuli/puppet-grafana/tree/v4.1.1) (2018-02-21)

[Full Changelog](https://github.com/voxpupuli/puppet-grafana/compare/v4.1.0...v4.1.1)
Expand All @@ -15,6 +25,7 @@ These should not affect the functionality of the module.

**Merged pull requests:**

- release 4.1.1 [\#92](https://github.com/voxpupuli/puppet-grafana/pull/92) ([bastelfreak](https://github.com/bastelfreak))
- release 4.1.0 [\#88](https://github.com/voxpupuli/puppet-grafana/pull/88) ([bastelfreak](https://github.com/bastelfreak))

## [v4.1.0](https://github.com/voxpupuli/puppet-grafana/tree/v4.1.0) (2018-02-03)
Expand Down Expand Up @@ -114,9 +125,12 @@ These should not affect the functionality of the module.

[Full Changelog](https://github.com/voxpupuli/puppet-grafana/compare/v2.6.3...v3.0.0)

**Fixed bugs:**
**Implemented enhancements:**

- implement package\_ensure param for archlinux [\#34](https://github.com/voxpupuli/puppet-grafana/pull/34) ([bastelfreak](https://github.com/bastelfreak))

**Fixed bugs:**

- FIX configuration file ownership [\#30](https://github.com/voxpupuli/puppet-grafana/pull/30) ([cassianoleal](https://github.com/cassianoleal))

**Closed issues:**
Expand Down
28 changes: 23 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,20 @@ Example:
```


#### Using a sub-path for Grafana API

If you are using a sub-path for the Grafana API, you will need to set the `grafana_api_path` parameter for the following custom types:
- `grafana_dashboard`
- `grafana_datasource`
- `grafana_organization`
- `grafana_user`

For instance, if your sub-path is `/grafana`, the `grafana_api_path` must
be set to `/grafana/api`. Do not add a trailing `/` (slash) at the end of the value.

If you are not using sub-paths, you do not need to set this parameter.

#### Custom Types and Providers

The module includes several custom types:
Expand Down Expand Up @@ -367,13 +381,15 @@ grafana_dashboard { 'example_dashboard':
grafana_url => 'http://localhost:3000',
grafana_user => 'admin',
grafana_password => '5ecretPassw0rd',
grafana_api_path => '/grafana/api'
organization => 'NewOrg',
content => template('path/to/exported/file.json'),
}
```

`content` must be valid JSON, and is parsed before imported.
`grafana_user` and `grafana_password` are optional, and required when
authentication is enabled in Grafana.
authentication is enabled in Grafana. `grafana_api_path` is optional, and only used when using sub-paths for the API. `organization` is optional, and used when creating a dashboard for a specific organization.

Example:
Make sure the `grafana-server` service is up and running before creating the `grafana_dashboard` definition. One option is to use the `http_conn_validator` from the [healthcheck](https://forge.puppet.com/puppet/healthcheck) module
Expand Down Expand Up @@ -403,8 +419,9 @@ grafana_datasource { 'influxdb':
grafana_url => 'http://localhost:3000',
grafana_user => 'admin',
grafana_password => '5ecretPassw0rd',
grafana_api_path => '/grafana/api'
type => 'influxdb',
org_name => 'NewOrg',
organization => 'NewOrg',
url => 'http://localhost:8086',
user => 'admin',
password => '1nFlux5ecret',
Expand All @@ -417,15 +434,14 @@ grafana_datasource { 'influxdb':

Available types are: influxdb, elasticsearch, graphite, cloudwatch, mysql, opentsdb, and prometheus

`org_name` is used to set which organization a datasource will be created on. If this parameter is not set, it will default to organization ID 1 (Main Org. by default). If the default org is deleted, organizations will need to be specified.
`organization` is used to set which organization a datasource will be created on. If this parameter is not set, it will default to organization ID 1 (Main Org. by default). If the default org is deleted, organizations will need to be specified.

Access mode determines how Grafana connects to the datasource, either `direct`
from the browser, or `proxy` to send requests via grafana.

Setting `basic_auth` to `true` will allow use of the `basic_auth_user` and `basic_auth_password` params.

Authentication is optional, as is `database`; additional `json_data` can be
provided to allow custom configuration options.
Authentication is optional, as are `database` and `grafana_api_path`; additional `json_data` can be provided to allow custom configuration options.

Example:
Make sure the `grafana-server` service is up and running before creating the `grafana_datasource` definition. One option is to use the `http_conn_validator` from the [healthcheck](https://forge.puppet.com/puppet/healthcheck) module
Expand Down Expand Up @@ -561,13 +577,15 @@ Creates and manages a global grafana user via the API.
```puppet
grafana_user { 'username':
grafana_url => 'http://localhost:3000',
grafana_api_path => '/grafana/api'
grafana_user => 'admin',
grafana_password => '5ecretPassw0rd',
full_name => 'John Doe',
password => 'Us3r5ecret',
email => 'john@example.com',
}
```
`grafana_api_path` is only required if using sub-paths for the API

## Limitations

Expand Down
63 changes: 58 additions & 5 deletions lib/puppet/provider/grafana_dashboard/grafana.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,56 @@

defaultfor kernel: 'Linux'

def organization
resource[:organization]
end

def grafana_api_path
resource[:grafana_api_path]
end

def fetch_organizations
response = send_request('GET', format('%s/orgs', resource[:grafana_api_path]))
if response.code != '200'
raise format('Fail to retrieve organizations (HTTP response: %s/%s)', response.code, response.body)
end

begin
fetch_organizations = JSON.parse(response.body)

fetch_organizations.map { |x| x['id'] }.map do |id|
response = send_request 'GET', format('%s/orgs/%s', resource[:grafana_api_path], id)
if response.code != '200'
raise format('Failed to retrieve organization %d (HTTP response: %s/%s)', id, response.code, response.body)
end

fetch_organization = JSON.parse(response.body)

{
id: fetch_organization['id'],
name: fetch_organization['name']
}
end
rescue JSON::ParserError
raise format('Failed to parse response: %s', response.body)
end
end

def fetch_organization
unless @fetch_organization
@fetch_organization =
if resource[:organization].is_a?(Numeric) || resource[:organization].match(%r{^[0-9]*$})
fetch_organizations.find { |x| x[:id] == resource[:organization] }
else
fetch_organizations.find { |x| x[:name] == resource[:organization] }
end
end
@fetch_organization
end

# Return the list of dashboards
def dashboards
response = send_request('GET', '/api/search', nil, q: '', starred: false)
response = send_request('GET', format('%s/search', resource[:grafana_api_path]), nil, q: '', starred: false)
if response.code != '200'
raise format('Fail to retrieve the dashboards (HTTP response: %s/%s)', response.code, response.body)
end
Expand All @@ -30,7 +77,7 @@ def dashboards
def find_dashboard
return unless dashboards.find { |x| x['title'] == resource[:title] }

response = send_request('GET', format('/api/dashboards/db/%s', slug))
response = send_request('GET', format('%s/dashboards/db/%s', resource[:grafana_api_path], slug))
if response.code != '200'
raise format('Fail to retrieve dashboard %s (HTTP response: %s/%s)', resource[:title], response.code, response.body)
end
Expand All @@ -44,15 +91,21 @@ def find_dashboard
end

def save_dashboard(dashboard)
# change organizations
response = send_request 'POST', format('%s/user/using/%s', resource[:grafana_api_path], fetch_organization[:id])
unless response.code == '200'
raise format('Failed to switch to org %s (HTTP response: %s/%s)', fetch_organization[:id], response.code, response.body)
end

data = {
dashboard: dashboard.merge('title' => resource[:title],
'id' => @dashboard ? @dashboard['id'] : nil,
'version' => @dashboard ? @dashboard['version'] + 1 : 0),
overwrite: !@dashboard.nil?
}

response = send_request('POST', '/api/dashboards/db', data)
return unless response.code != '200'
response = send_request('POST', format('%s/dashboards/db', resource[:grafana_api_path]), data)
return unless (response.code != '200') && (response.code != '412')
raise format('Fail to save dashboard %s (HTTP response: %s/%s', resource[:name], response.code, response.body)
end

Expand All @@ -73,7 +126,7 @@ def create
end

def destroy
response = send_request('DELETE', format('/api/dashboards/db/%s', slug))
response = send_request('DELETE', format('%s/dashboards/db/%s', resource[:grafana_api_path], slug))

return unless response.code != '200'
raise Puppet::Error, format('Failed to delete dashboard %s (HTTP response: %s/%s', resource[:title], response.code, response.body)
Expand Down
43 changes: 21 additions & 22 deletions lib/puppet/provider/grafana_datasource/grafana.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ def organization
resource[:organization]
end

def grafana_api_path
resource[:grafana_api_path]
end

def fetch_organizations
response = send_request('GET', '/api/orgs')
response = send_request('GET', format('%s/orgs', resource[:grafana_api_path]))
if response.code != '200'
raise format('Fail to retrieve organizations (HTTP response: %s/%s)', response.code, response.body)
end

begin
fetch_organizations = JSON.parse(response.body)

fetch_organizations.map { |x| x['id'] }.map do |id|
response = send_request 'GET', format('/api/orgs/%s', id)
response = send_request 'GET', format('%s/orgs/%s', resource[:grafana_api_path], id)
if response.code != '200'
raise format('Failed to retrieve organization %d (HTTP response: %s/%s)', id, response.code, response.body)
end
Expand All @@ -42,13 +45,17 @@ def fetch_organizations

def fetch_organization
unless @fetch_organization
@fetch_organization = fetch_organizations.find { |x| x[:name] == resource[:organization] }
@fetch_organization = if resource[:organization].is_a?(Numeric) || resource[:organization].match(%r{^[0-9]*$})
fetch_organizations.find { |x| x[:id] == resource[:organization] }
else
fetch_organizations.find { |x| x[:name] == resource[:organization] }
end
end
@organization
@fetch_organization
end

def datasources
response = send_request('GET', '/api/datasources')
response = send_request('GET', format('%s/datasources', resource[:grafana_api_path]))
if response.code != '200'
raise format('Fail to retrieve datasources (HTTP response: %s/%s)', response.code, response.body)
end
Expand All @@ -57,7 +64,7 @@ def datasources
datasources = JSON.parse(response.body)

datasources.map { |x| x['id'] }.map do |id|
response = send_request 'GET', format('/api/datasources/%s', id)
response = send_request 'GET', format('%s/datasources/%s', resource[:grafana_api_path], id)
if response.code != '200'
raise format('Failed to retrieve datasource %d (HTTP response: %s/%s)', id, response.code, response.body)
end
Expand Down Expand Up @@ -206,17 +213,10 @@ def json_data=(value)
end

def save_datasource
if fetch_organization.nil?
response = send_request('POST', '/api/user/using/1')
if response.code != '200'
raise format('Failed to switch to org 1 (HTTP response: %s/%s)', response.code, response.body)
end
else
organization_id = fetch_organization[:id]
response = send_request 'POST', format('/api/user/using/%s', organization_id)
if response.code != '200'
raise format('Failed to switch to org %s (HTTP response: %s/%s)', organization_id, response.code, response.body)
end
# change organizations
response = send_request 'POST', format('%s/user/using/%s', resource[:grafana_api_path], fetch_organization[:id])
unless response.code == '200'
raise format('Failed to switch to org %s (HTTP response: %s/%s)', fetch_organization[:id], response.code, response.body)
end

data = {
Expand All @@ -236,20 +236,19 @@ def save_datasource
}

if datasource.nil?
response = send_request('POST', '/api/datasources', data)
response = send_request('POST', format('%s/datasources', resource[:grafana_api_path]), data)
else
data[:id] = datasource[:id]
response = send_request 'PUT', format('/api/datasources/%s', datasource[:id]), data
response = send_request 'PUT', format('%s/datasources/%s', resource[:grafana_api_path], datasource[:id]), data
end

if response.code != '200'
raise format('Failed to create save %s (HTTP response: %s/%s)', resource[:name], response.code, response.body)
end
self.datasource = nil
end

def delete_datasource
response = send_request 'DELETE', format('/api/datasources/%s', datasource[:id])
response = send_request 'DELETE', format('%s/datasources/%s', resource[:grafana_api_path], datasource[:id])

if response.code != '200'
raise format('Failed to delete datasource %s (HTTP response: %s/%s', resource[:name], response.code, response.body)
Expand Down
8 changes: 4 additions & 4 deletions lib/puppet/provider/grafana_organization/grafana.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
defaultfor kernel: 'Linux'

def organizations
response = send_request('GET', '/api/orgs')
response = send_request('GET', format('%s/orgs', resource[:grafana_api_path]))
if response.code != '200'
raise format('Failed to retrieve organizations (HTTP response: %s/%s)', response.code, response.body)
end
Expand All @@ -17,7 +17,7 @@ def organizations
organizations = JSON.parse(response.body)

organizations.map { |x| x['id'] }.map do |id|
response = send_request 'GET', format('/api/orgs/%s', id)
response = send_request 'GET', format('%s/orgs/%s', resource[:grafana_api_path], id)
if response.code != '200'
raise format('Failed to retrieve organization %d (HTTP response: %s/%s)', id, response.code, response.body)
end
Expand Down Expand Up @@ -71,7 +71,7 @@ def save_organization
address: resource[:address]
}

response = send_request('POST', '/api/orgs', data) if organization.nil?
response = send_request('POST', format('%s/orgs', resource[:grafana_api_path]), data) if organization.nil?

if response.code != '200'
raise format('Failed to create save %s (HTTP response: %s/%s)', resource[:name], response.code, response.body)
Expand All @@ -80,7 +80,7 @@ def save_organization
end

def delete_organization
response = send_request 'DELETE', format('/api/orgs/%s', organization[:id])
response = send_request 'DELETE', format('%s/orgs/%s', resource[:grafana_api_path], organization[:id])

if response.code != '200'
raise format('Failed to delete organization %s (HTTP response: %s/%s)', resource[:name], response.code, response.body)
Expand Down
Loading