Showing with 452 additions and 431 deletions.
  1. +4 −0 .github/workflows/ci.yml
  2. +1 −1 .msync.yml
  3. +2 −0 .puppet-lint.rc
  4. +3 −0 .sync.yml
  5. +20 −0 CHANGELOG.md
  6. +2 −2 Gemfile
  7. +1 −1 README.md
  8. +1 −1 Rakefile
  9. +3 −3 lib/puppet/functions/grafana/deep_find_and_remove.rb
  10. +5 −2 lib/puppet/functions/grafana/get_sub_paths.rb
  11. +6 −8 lib/puppet/provider/grafana.rb
  12. +3 −3 lib/puppet/provider/grafana_conn_validator/net_http.rb
  13. +29 −37 lib/puppet/provider/grafana_dashboard/grafana.rb
  14. +2 −2 lib/puppet/provider/grafana_dashboard_permission/grafana.rb
  15. +21 −35 lib/puppet/provider/grafana_datasource/grafana.rb
  16. +22 −30 lib/puppet/provider/grafana_folder/grafana.rb
  17. +15 −21 lib/puppet/provider/grafana_notification/grafana.rb
  18. +11 −20 lib/puppet/provider/grafana_organization/grafana.rb
  19. +4 −1 lib/puppet/provider/grafana_plugin/grafana_cli.rb
  20. +1 −0 lib/puppet/provider/grafana_team/grafana.rb
  21. +14 −22 lib/puppet/provider/grafana_user/grafana.rb
  22. +4 −6 lib/puppet/type/grafana_conn_validator.rb
  23. +8 −13 lib/puppet/type/grafana_dashboard.rb
  24. +13 −19 lib/puppet/type/grafana_datasource.rb
  25. +4 −6 lib/puppet/type/grafana_folder.rb
  26. +21 −19 lib/puppet/type/grafana_ldap_config.rb
  27. +2 −0 lib/puppet/type/grafana_ldap_group_mapping.rb
  28. +5 −3 lib/puppet/type/grafana_ldap_server.rb
  29. +9 −13 lib/puppet/type/grafana_notification.rb
  30. +5 −9 lib/puppet/type/grafana_organization.rb
  31. +25 −27 lib/puppet/type/grafana_plugin.rb
  32. +2 −6 lib/puppet/type/grafana_team.rb
  33. +8 −10 lib/puppet/type/grafana_user.rb
  34. +5 −4 lib/puppet/util/grafana_conn_validator.rb
  35. +9 −7 metadata.json
  36. +3 −0 spec/acceptance/class_spec.rb
  37. +7 −1 spec/acceptance/grafana_folder_spec.rb
  38. +2 −0 spec/acceptance/grafana_plugin_spec.rb
  39. +5 −3 spec/acceptance/grafana_team_spec.rb
  40. +3 −0 spec/acceptance/grafana_user_spec.rb
  41. +67 −70 spec/classes/grafana_spec.rb
  42. +3 −1 spec/grafana_dashboard_permission_type_spec.rb
  43. +3 −1 spec/grafana_membership_type_spec.rb
  44. +5 −5 spec/spec_helper.rb
  45. +2 −0 spec/spec_helper_acceptance.rb
  46. +2 −0 spec/support/acceptance/prepare_host.rb
  47. +2 −0 spec/support/acceptance/supported_versions.rb
  48. +10 −10 spec/unit/puppet/provider/grafana_plugin/grafana_cli_spec.rb
  49. +6 −0 spec/unit/puppet/type/grafana_dashboard_type_spec.rb
  50. +6 −4 spec/unit/puppet/type/grafana_datasource_type_spec.rb
  51. +6 −0 spec/unit/puppet/type/grafana_folder_type_spec.rb
  52. +3 −0 spec/unit/puppet/type/grafana_ldap_config_spec.rb
  53. +3 −0 spec/unit/puppet/type/grafana_ldap_group_mapping_spec.rb
  54. +3 −0 spec/unit/puppet/type/grafana_ldap_server_spec.rb
  55. +5 −3 spec/unit/puppet/type/grafana_notification_type_spec.rb
  56. +3 −1 spec/unit/puppet/type/grafana_organization_type_spec.rb
  57. +4 −0 spec/unit/puppet/type/grafana_plugin_spec.rb
  58. +3 −1 spec/unit/puppet/type/grafana_team_type_spec.rb
  59. +6 −0 spec/unit/puppet/type/grafana_user_type_spec.rb
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ name: CI

on: pull_request

concurrency:
group: ${{ github.head_ref }}
cancel-in-progress: true

jobs:
setup_matrix:
name: 'Setup Test Matrix'
Expand Down
2 changes: 1 addition & 1 deletion .msync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
# Managed by modulesync - DO NOT EDIT
# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/

modulesync_config_version: '4.2.0'
modulesync_config_version: '5.1.0'
2 changes: 2 additions & 0 deletions .puppet-lint.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--fail-on-warnings
--no-parameter_documentation-check
3 changes: 3 additions & 0 deletions .sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ Gemfile:
- gem: 'toml'
spec/spec_helper_acceptance.rb:
unmanaged: false
.puppet-lint.rc:
enabled_lint_checks:
- parameter_types
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ 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.

## [v10.0.0](https://github.com/voxpupuli/puppet-grafana/tree/v10.0.0) (2021-11-26)

[Full Changelog](https://github.com/voxpupuli/puppet-grafana/compare/v9.0.1...v10.0.0)

**Breaking changes:**

- Drop support for Debian 9, Ubuntu 16.04 \(EOL\) [\#262](https://github.com/voxpupuli/puppet-grafana/pull/262) ([smortex](https://github.com/smortex))

**Implemented enhancements:**

- Add support for Debian 11, CentOS 8, RedHat 8 and FreeBSD 13 [\#255](https://github.com/voxpupuli/puppet-grafana/pull/255) ([smortex](https://github.com/smortex))

**Fixed bugs:**

- Fix dashboard api call in grafana\_dashboard [\#267](https://github.com/voxpupuli/puppet-grafana/pull/267) ([joernott](https://github.com/joernott))

**Closed issues:**

- grafana\_dashboards ov version 9.0.1 does not work with Grafana 6.7.6 [\#261](https://github.com/voxpupuli/puppet-grafana/issues/261)

## [v9.0.1](https://github.com/voxpupuli/puppet-grafana/tree/v9.0.1) (2021-08-26)

[Full Changelog](https://github.com/voxpupuli/puppet-grafana/compare/v9.0.0...v9.0.1)
Expand Down
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
source ENV['GEM_SOURCE'] || "https://rubygems.org"

group :test do
gem 'voxpupuli-test', '~> 2.5', :require => false
gem 'voxpupuli-test', '~> 5.0', :require => false
gem 'coveralls', :require => false
gem 'simplecov-console', :require => false
gem 'puppet_metadata', '~> 1.0', :require => false
Expand All @@ -22,7 +22,7 @@ end

group :release do
gem 'github_changelog_generator', '>= 1.16.1', :require => false if RUBY_VERSION >= '2.5'
gem 'voxpupuli-release', '>= 1.0.2', :require => false
gem 'voxpupuli-release', '>= 1.2.0', :require => false
gem 'puppet-strings', '>= 2.2', :require => false
end

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ grafana_dashboard { 'example_dashboard':
}
```

`content` must be valid JSON, and is parsed before imported.
`content` must be valid JSON, and is parsed before imported. You can use the JSON generated with the share/export functionality or from the API call to /dashboards/uid but must remove the fields "id", "uid", "title" and "version" to make the resource call idempotent.
`grafana_user` and `grafana_password` are optional, and required when
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.
`folder` is an optional parameter, but the folder resource must exist.
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Managed by modulesync - DO NOT EDIT
# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/

# Attempt to load voxupuli-test (which pulls in puppetlabs_spec_helper),
# Attempt to load voxpupuli-test (which pulls in puppetlabs_spec_helper),
# otherwise attempt to load it directly.
begin
require 'voxpupuli/test/rake'
Expand Down
6 changes: 3 additions & 3 deletions lib/puppet/functions/grafana/deep_find_and_remove.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

# == Function: deep_find_and_remove
#
# This function takes a hash as input, along with a string
Expand Down Expand Up @@ -28,9 +30,7 @@ def deep_find_and_remove(key, object, removekey = 'puppetsource')
foundpaths << object[key].dup
object[key].delete(removekey)
end
if object.is_a? Enumerable
foundpaths << object.map { |*a| deep_find_and_remove(key, a.last) }
end
foundpaths << object.map { |*a| deep_find_and_remove(key, a.last) } if object.is_a? Enumerable
foundpaths.flatten.compact
foundpaths
end
Expand Down
7 changes: 5 additions & 2 deletions lib/puppet/functions/grafana/get_sub_paths.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

# == Function get_sub_paths
#
# This function receives an input path as an input parameter, and
Expand Down Expand Up @@ -28,10 +30,11 @@ def get_sub_paths(inputpath)
parts = ip.split('/')
parts.each_with_index do |value, index|
next if index.zero? || index == (parts.length - 1)

allsubs << if index == 1
'/' + value
"/#{value}"
else
allsubs[index - 2] + '/' + value
"#{allsubs[index - 2]}/#{value}"
end
end
allsubs
Expand Down
14 changes: 6 additions & 8 deletions lib/puppet/provider/grafana.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

# Copyright 2015 Mirantis, Inc.
#
require 'cgi'
Expand All @@ -7,19 +9,17 @@
class Puppet::Provider::Grafana < Puppet::Provider
# Helper methods
def grafana_host
@grafana_host = URI.parse(resource[:grafana_url]).host unless @grafana_host
@grafana_host ||= URI.parse(resource[:grafana_url]).host
@grafana_host
end

def grafana_port
@grafana_port = URI.parse(resource[:grafana_url]).port unless @grafana_port
@grafana_port ||= URI.parse(resource[:grafana_url]).port
@grafana_port
end

def grafana_scheme
unless @grafana_scheme
@grafana_scheme = URI.parse(resource[:grafana_url]).scheme
end
@grafana_scheme ||= URI.parse(resource[:grafana_url]).scheme
@grafana_scheme
end

Expand Down Expand Up @@ -56,9 +56,7 @@ def send_request(operation = 'GET', path = '', data = nil, search_path = {})
end

request.content_type = 'application/json'
if resource[:grafana_user] && resource[:grafana_password]
request.basic_auth resource[:grafana_user], resource[:grafana_password]
end
request.basic_auth resource[:grafana_user], resource[:grafana_password] if resource[:grafana_user] && resource[:grafana_password]

Net::HTTP.start(grafana_host, grafana_port,
use_ssl: grafana_scheme == 'https',
Expand Down
6 changes: 3 additions & 3 deletions lib/puppet/provider/grafana_conn_validator/net_http.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

# In this case I'm trying the relative path first, then falling back to normal
# mechanisms. This should be fixed in future versions of puppet but it looks
# like we'll need to maintain this for some time perhaps.
Expand Down Expand Up @@ -36,9 +38,7 @@ def exists?
success = validator.attempt_connection
end

unless success
Puppet.notice("Failed to connect to Grafana within timeout window of #{timeout} seconds; giving up.")
end
Puppet.notice("Failed to connect to Grafana within timeout window of #{timeout} seconds; giving up.") unless success

success
end
Expand Down
66 changes: 29 additions & 37 deletions lib/puppet/provider/grafana_dashboard/grafana.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# frozen_string_literal: true

# Copyright 2015 Mirantis, Inc.
#
require 'json'

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'grafana'))

# Note: this class doesn't implement the self.instances and self.prefetch
# NOTE: this class doesn't implement the self.instances and self.prefetch
# methods because the Grafana API doesn't allow to retrieve the dashboards and
# all their properties in a single call.
Puppet::Type.type(:grafana_dashboard).provide(:grafana, parent: Puppet::Provider::Grafana) do
Expand All @@ -22,18 +24,14 @@ def grafana_api_path

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
raise format('Fail to retrieve organizations (HTTP response: %s/%s)', response.code, response.body) if response.code != '200'

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
raise format('Failed to retrieve organization %d (HTTP response: %s/%s)', id, response.code, response.body) if response.code != '200'

fetch_organization = JSON.parse(response.body)

Expand All @@ -48,22 +46,17 @@ def fetch_organizations
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 ||= 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
@fetch_organization
end

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

begin
@folders = JSON.parse(response.body)
Expand All @@ -87,13 +80,10 @@ def find_folder
def dashboards
# 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
raise format('Failed to switch to org %s (HTTP response: %s/%s)', fetch_organization[:id], response.code, response.body) unless response.code == '200'

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
raise format('Fail to retrieve the dashboards (HTTP response: %s/%s)', response.code, response.body) if response.code != '200'

begin
JSON.parse(response.body)
Expand All @@ -104,13 +94,12 @@ def dashboards

# Return the dashboard matching with the resource's title
def find_dashboard
return unless dashboards.find { |x| x['title'] == resource[:title] }
db = dashboards.find { |x| x['title'] == resource[:title] }
return if db.nil?

response = send_request('GET', format('%s/dashboards/uid/%s', resource[:grafana_api_path], slug))
response = send_request('GET', format('%s/dashboards/uid/%s', resource[:grafana_api_path], db['uid']))

if response.code != '200'
raise format('Fail to retrieve dashboard %s (HTTP response: %s/%s)', resource[:title], response.code, response.body)
end
raise format('Fail to retrieve dashboard %s by uid %s (HTTP response: %s/%s)', resource[:title], db['uid'], response.code, response.body) if response.code != '200'

begin
# Cache the dashboard's content
Expand All @@ -125,26 +114,25 @@ 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
raise format('Failed to switch to org %s (HTTP response: %s/%s)', fetch_organization[:id], response.code, response.body) unless response.code == '200'

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

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)

raise format('Fail to save dashboard %s (HTTP response: %s/%s)', resource[:name], response.code, response.body)
end

def slug
resource[:title].downcase.gsub(%r{[ \+]+}, '-').gsub(%r{[^\w\- ]}, '')
resource[:title].downcase.gsub(%r{[ +]+}, '-').gsub(%r{[^\w\- ]}, '')
end

def content
Expand All @@ -160,10 +148,14 @@ def create
end

def destroy
response = send_request('DELETE', format('%s/dashboards/uid/%s', resource[:grafana_api_path], slug))
db = dashboards.find { |x| x['title'] == resource[:title] }
raise Puppet::Error, format('Failed to delete dashboard %s, dashboard not found', resource[:title]) if db.nil?

response = send_request('DELETE', format('%s/dashboards/uid/%s', resource[:grafana_api_path], db['uid']))

return unless response.code != '200'
raise Puppet::Error, format('Failed to delete dashboard %s (HTTP response: %s/%s', resource[:title], response.code, response.body)

raise Puppet::Error, format('Failed to delete dashboard %s (HTTP response: %s/%s)', resource[:title], response.code, response.body)
end

def exists?
Expand Down
4 changes: 2 additions & 2 deletions lib/puppet/provider/grafana_dashboard_permission/grafana.rb
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def permission=(value)
def new_permission
key = resource[:user] ? :userId : :teamId
subject_id = resource[:user] ? user[:id] : team[:id]
permission = case resource[:permission]
permission = case resource[:permission] # rubocop:disable Style/HashLikeCase
when :View
1
when :Edit
Expand Down Expand Up @@ -218,7 +218,7 @@ def existing_permissions
end
end

def permission_data(destroy = false)
def permission_data(destroy = false) # rubocop:disable Style/OptionalBooleanParameter
raise format('Unknown dashboard: %s', resource[:dashboard]) unless dashboard

endpoint = format('%s/dashboards/id/%s/permissions', grafana_api_path, dashboard[:id])
Expand Down
Loading