diff --git a/lib/puppet/functions/grafana/deep_find_and_remove.rb b/lib/puppet/functions/grafana/deep_find_and_remove.rb index 6ff436c..20a1c2d 100644 --- a/lib/puppet/functions/grafana/deep_find_and_remove.rb +++ b/lib/puppet/functions/grafana/deep_find_and_remove.rb @@ -1,37 +1,37 @@ +# frozen_string_literal: true + # == Function: deep_find_and_remove # # This function takes a hash as input, along with a string # (key). Additionally, the optional removekey (defaults to # 'puppetsource') is a parameter. # # The purpose of this function is to extract the 'options' subhash # from the array of hashes given to provision dashboards. This options # subhash may contain a path and source which puppet will use for # provisioning: creating the path and applying the files from the # source. # # Additionally, if the key 'puppetsource' exists in the sub-hash, it # will be deleted from the structure. Thus the output of this function # may be used in yaml format for grafana's provisioning # configuration file for dashboards. Puppet::Functions.create_function(:'grafana::deep_find_and_remove') do dispatch :deep_find_and_remove do param 'String', :key param 'Hash', :object optional_param 'String', :removekey return_type 'Array' end def deep_find_and_remove(key, object, removekey = 'puppetsource') foundpaths = [] if object.respond_to?(:key?) && object.key?(key) 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 end diff --git a/lib/puppet/functions/grafana/get_sub_paths.rb b/lib/puppet/functions/grafana/get_sub_paths.rb index b2ff27f..78e0c7e 100644 --- a/lib/puppet/functions/grafana/get_sub_paths.rb +++ b/lib/puppet/functions/grafana/get_sub_paths.rb @@ -1,39 +1,42 @@ +# frozen_string_literal: true + # == Function get_sub_paths # # This function receives an input path as an input parameter, and # returns an array of the subpaths in the input, excluding the input # path itself. The function will attempt to ignore any extra slashes # in the path given. # # This function will only work on UNIX paths with forward slashes (/). # # Examples: # input = '/var/lib/grafana/dashboards' # output = [ '/var', '/var/lib', '/var/lib/grafana'/ ] # # input = '/opt' # output = [] # # input = '/first/second/' # output = [ '/first' ] Puppet::Functions.create_function(:'grafana::get_sub_paths') do dispatch :get_sub_paths do param 'String', :inputpath return_type 'Array' end def get_sub_paths(inputpath) ip = inputpath.gsub(%r{/+}, '/') allsubs = [] 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 end end diff --git a/lib/puppet/provider/grafana.rb b/lib/puppet/provider/grafana.rb index 6f198b5..1f0f60b 100644 --- a/lib/puppet/provider/grafana.rb +++ b/lib/puppet/provider/grafana.rb @@ -1,69 +1,67 @@ +# frozen_string_literal: true + # Copyright 2015 Mirantis, Inc. # require 'cgi' require 'json' require 'net/http' 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 # Return a Net::HTTP::Response object def send_request(operation = 'GET', path = '', data = nil, search_path = {}) request = nil encoded_search = '' if URI.respond_to?(:encode_www_form) encoded_search = URI.encode_www_form(search_path) else # Ideally we would have use URI.encode_www_form but it isn't # available with Ruby 1.8.x that ships with CentOS 6.5. encoded_search = search_path.to_a.map do |x| x.map { |y| CGI.escape(y.to_s) }.join('=') end encoded_search = encoded_search.join('&') end uri = URI.parse format('%s://%s:%d%s?%s', grafana_scheme, grafana_host, grafana_port, path, encoded_search) case operation.upcase when 'POST' request = Net::HTTP::Post.new(uri.request_uri) request.body = data.to_json when 'PUT' request = Net::HTTP::Put.new(uri.request_uri) request.body = data.to_json when 'GET' request = Net::HTTP::Get.new(uri.request_uri) when 'DELETE' request = Net::HTTP::Delete.new(uri.request_uri) else raise Puppet::Error, format('Unsupported HTTP operation %s', operation) 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', verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| http.request(request) end end end diff --git a/lib/puppet/provider/grafana_conn_validator/net_http.rb b/lib/puppet/provider/grafana_conn_validator/net_http.rb index 7799e84..6cfafc7 100644 --- a/lib/puppet/provider/grafana_conn_validator/net_http.rb +++ b/lib/puppet/provider/grafana_conn_validator/net_http.rb @@ -1,63 +1,63 @@ +# 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. $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', '..')) require 'puppet/util/grafana_conn_validator' # This file contains a provider for the resource type `grafana_conn_validator`, # which validates the Grafana API connection by attempting an http(s) connection. Puppet::Type.type(:grafana_conn_validator).provide(:net_http) do desc "A provider for the resource type `grafana_conn_validator`, which validates the Grafana API connection by attempting an http(s) connection to the Grafana server." # Test to see if the resource exists, returns true if it does, false if it # does not. # # Here we simply monopolize the resource API, to execute a test to see if the # database is connectable. When we return a state of `false` it triggers the # create method where we can return an error message. # # @return [bool] did the test succeed? def exists? start_time = Time.now timeout = resource[:timeout] success = validator.attempt_connection while success == false && ((Time.now - start_time) < timeout) # It can take several seconds for the Grafana server to start up; # especially on the first install. Therefore, our first connection attempt # may fail. Here we have somewhat arbitrarily chosen to retry every 2 # seconds until the configurable timeout has expired. Puppet.notice('Failed to connect to Grafana API; sleeping 2 seconds before retry') sleep 2 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 # This method is called when the exists? method returns false. # # @return [void] def create # If `#create` is called, that means that `#exists?` returned false, which # means that the connection could not be established... so we need to # cause a failure here. raise Puppet::Error, "Unable to connect to Grafana server! (#{@validator.grafana_url})" end # Returns the existing validator, if one exists otherwise creates a new object # from the class. # # @api private def validator @validator ||= Puppet::Util::GrafanaConnValidator.new(resource[:grafana_url], resource[:grafana_api_path]) end end diff --git a/lib/puppet/provider/grafana_dashboard/grafana.rb b/lib/puppet/provider/grafana_dashboard/grafana.rb index d01e892..cddeb1e 100644 --- a/lib/puppet/provider/grafana_dashboard/grafana.rb +++ b/lib/puppet/provider/grafana_dashboard/grafana.rb @@ -1,175 +1,164 @@ +# 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 desc 'Support for Grafana dashboards stored into Grafana' 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 + 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) { 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 ||= 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) rescue JSON::ParserError raise format('Fail to parse folders (HTTP response: %s/%s)', response.code, response.body) end end def find_folder folders unless @folders begin @folder = @folders.find { |folder| folder['title'] == resource[:folder] } raise format('Folder not found: %s', resource[:folder]) unless @folder rescue JSON::ParserError raise format('Fail to parse folder %s: %s', resource[:folder], response.body) end end # Return the list of dashboards 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) rescue JSON::ParserError raise format('Fail to parse dashboards (HTTP response: %s/%s)', response.code, response.body) end end # Return the dashboard matching with the resource's title def find_dashboard 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], db['uid'])) - if response.code != '200' - raise format('Fail to retrieve dashboard %s by uid %s (HTTP response: %s/%s)', resource[:title], db['uid'], 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 @dashboard = JSON.parse(response.body)['dashboard'] rescue JSON::ParserError raise format('Fail to parse dashboard %s: %s', resource[:title], response.body) end end def save_dashboard(dashboard) find_folder if resource[:folder] # 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' => @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) end def slug - resource[:title].downcase.gsub(%r{[ \+]+}, '-').gsub(%r{[^\w\- ]}, '') + resource[:title].downcase.gsub(%r{[ +]+}, '-').gsub(%r{[^\w\- ]}, '') end def content @dashboard.reject { |k, _| k =~ %r{^id|uid|version|title$} } end def content=(value) save_dashboard(value) end def create save_dashboard(resource[:content]) end def destroy 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) end def exists? find_dashboard end end diff --git a/lib/puppet/provider/grafana_dashboard_permission/grafana.rb b/lib/puppet/provider/grafana_dashboard_permission/grafana.rb index 0e1be74..829631a 100644 --- a/lib/puppet/provider/grafana_dashboard_permission/grafana.rb +++ b/lib/puppet/provider/grafana_dashboard_permission/grafana.rb @@ -1,249 +1,249 @@ # frozen_string_literal: true require 'json' require File.expand_path(File.join(File.dirname(__FILE__), '..', 'grafana')) Puppet::Type.type(:grafana_dashboard_permission).provide(:grafana, parent: Puppet::Provider::Grafana) do desc 'Support for Grafana dashboard permissions' defaultfor kernel: 'Linux' def grafana_api_path resource[:grafana_api_path] end def set_current_organization response = send_request 'POST', format('%s/user/using/%s', grafana_api_path, organization[:id]) return if response.code == '200' raise format('Failed to switch to org %s (HTTP response: %s/%s)', organization[:id], response.code, response.body) end def raise_on_error(code, message) raise message if code != '200' end def parse_response(data) JSON.parse(data) rescue JSON::ParserError raise format('Fail to parse response: %s', response.body) end def map_organizations(ids) ids.map do |id| response = send_request 'GET', format('%s/orgs/%s', grafana_api_path, id) raise_on_error(response.code, format('Failed to retrieve organization %d (HTTP response: %s/%s)', id, response.code, response.body)) organization = parse_response(response.body) { id: organization['id'], name: organization['name'] } end end def organizations response = send_request('GET', format('%s/orgs', grafana_api_path)) raise_on_error(response.code, format('Fail to retrieve organizations (HTTP response: %s/%s)', response.code, response.body)) organizations = JSON.parse(response.body) map_organizations(organizations.map { |x| x['id'] }) end def organization return @organization if @organization org = resource[:organization] key = org.is_a?(Numeric) || org.match(%r{/^[0-9]*$/}) ? :id : :name @organization = organizations.find { |x| x[key] == org } end def map_teams(teams) teams['teams'].map do |team| { id: team['id'], name: team['name'], organization: team['orgId'], membercount: team['membercount'], permission: team['permission'], email: team['email'] } end end def teams raise(format('Unknown Organization: %s', resource[:organization])) unless organization set_current_organization response = send_request('GET', format('%s/teams/search', grafana_api_path)) raise_on_error(response.code, format('Fail to retrieve teams (HTTP response: %s/%s)', response.code, response.body)) teams = parse_response(response.body) map_teams(teams) end def team @team ||= teams.find { |x| x[:name] == resource[:team] } end def send_users_request raise(format('Unknown Organization: %s', resource[:organization])) unless organization set_current_organization response = send_request('GET', format('%s/org/users', grafana_api_path)) raise_on_error(response.code, format('Fail to retrieve users (HTTP response: %s/%s)', response.code, response.body)) response.body end def users users = parse_response(send_users_request) users.map do |user| { id: user['userId'], name: user['login'], organization: user['orgId'], role: user['role'] } end end def user @user ||= users.find { |x| x[:name] == resource[:user] } end def dashboards set_current_organization search_path = { query: resource[:dashboard], type: 'dash-db' } response = send_request('GET', format('%s/search', grafana_api_path), nil, search_path) raise_on_error(response.code, format('Fail to retrieve dashboards (HTTP response: %s/%s)', response.code, response.body)) dashboards = parse_response(response.body) dashboards.map do |dashboard| { id: dashboard['id'], name: dashboard['title'] } end end def dashboard @dashboard ||= dashboards.find { |x| x[:name] == resource[:dashboard] } end def permissions return @permissions if @permissions raise(format('Unknown dashboard: %s', resource[:dashboard])) unless dashboard response = send_request('GET', format('%s/dashboards/id/%s/permissions', grafana_api_path, dashboard[:id])) raise_on_error(response.code, format('Failed to retrieve permissions on dashboard (HTTP response: %s/%s)', response.code, response.body)) permissions = parse_response(response.body) @permissions = permissions.map do |permission| { dashboardId: permission['dashboardId'], userId: permission['userId'], user: permission['userLogin'], teamId: permission['teamId'], team: permission['team'], permissionId: permission['permission'], permission: permission['permissionName'], dashboard: permission['title'], isFolder: permission['isFolder'], inherited: permission['inherited'] } end end def team_permission raise(format('Unknown team: %s for organaization: %s', resource[:team], resource[:organization])) unless team @team_permission ||= permissions.find { |x| x[:teamId] == team[:id] } end def user_permission raise(format('Unknown user: %s for organaization: %s', resource[:user], resource[:organization])) unless user @user_permission ||= permissions.find { |x| x[:userId] == user[:id] } end def permission resource[:user] ? user_permission[:permission] : team_permission[:permission] end def permission=(value) case value when 'View' resource[:permission] = 1 when 'Edit' resource[:permission] = 2 when 'Admin' resource[:permission] = 4 end save_permission end 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 2 when :Admin 4 end raise(format('User or Team must exist')) unless subject_id { key => subject_id, 'permission' => permission } end def remove_unneeded_permissions(obj) obj.delete_if { |k| k['dashboardId'] == -1 } new_target = resource[:user] || resource[:team] new_type = resource[:user] ? :user : :team obj.delete_if { |k| k[new_type] == new_target } obj.delete_if { |k| k[:teamId].zero? && k[:userId].zero? } end def existing_permissions perms = remove_unneeded_permissions(permissions) perms.map do |perm| target = perm[:userId].zero? ? perm[:teamId] : perm[:userId] type = perm[:userId].zero? ? :teamId : :userId { type => target, :permission => perm[:permissionId] } 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]) final_permissions = destroy ? { items: existing_permissions } : { items: existing_permissions + [new_permission] } ['POST', endpoint, final_permissions] end def save_permission response = send_request(*permission_data) raise_on_error(response.code, format('Failed to update membership %s, (HTTP response: %s/%s)', resource, response.code, response.body)) end def create save_permission end def destroy response = send_request(*permission_data(true)) raise_on_error(response.code, format('Failed to update membership %s, (HTTP response: %s/%s)', resource, response.code, response.body)) end def exists? raise('user or team parameter must be present') unless resource[:user] || resource[:team] resource[:user] ? user_permission : team_permission end end diff --git a/lib/puppet/provider/grafana_datasource/grafana.rb b/lib/puppet/provider/grafana_datasource/grafana.rb index 6688b30..d94a8b1 100644 --- a/lib/puppet/provider/grafana_datasource/grafana.rb +++ b/lib/puppet/provider/grafana_datasource/grafana.rb @@ -1,281 +1,267 @@ +# frozen_string_literal: true + # Copyright 2015 Mirantis, Inc. # require 'json' require File.expand_path(File.join(File.dirname(__FILE__), '..', 'grafana')) Puppet::Type.type(:grafana_datasource).provide(:grafana, parent: Puppet::Provider::Grafana) do desc 'Support for Grafana datasources' 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 + 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) { 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_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 def 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 + raise format('Fail to retrieve datasources (HTTP response: %s/%s)', response.code, response.body) if response.code != '200' begin datasources = JSON.parse(response.body) datasources.map { |x| x['id'] }.map do |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 + raise format('Failed to retrieve datasource %d (HTTP response: %s/%s)', id, response.code, response.body) if response.code != '200' datasource = JSON.parse(response.body) { id: datasource['id'], name: datasource['name'], url: datasource['url'], type: datasource['type'], user: datasource['user'], password: datasource['password'], database: datasource['database'], access_mode: datasource['access'], - is_default: datasource['isDefault'] ? :true : :false, - with_credentials: datasource['withCredentials'] ? :true : :false, - basic_auth: datasource['basicAuth'] ? :true : :false, + is_default: datasource['isDefault'] ? true : false, + with_credentials: datasource['withCredentials'] ? true : false, + basic_auth: datasource['basicAuth'] ? true : false, basic_auth_user: datasource['basicAuthUser'], basic_auth_password: datasource['basicAuthPassword'], json_data: datasource['jsonData'], secure_json_data: datasource['secureJsonData'] } end rescue JSON::ParserError raise format('Failed to parse response: %s', response.body) end end def datasource - unless @datasource - @datasource = datasources.find { |x| x[:name] == resource[:name] } - end + @datasource ||= datasources.find { |x| x[:name] == resource[:name] } @datasource end attr_writer :datasource def type datasource[:type] end def type=(value) resource[:type] = value save_datasource end def url datasource[:url] end def url=(value) resource[:url] = value save_datasource end def access_mode datasource[:access_mode] end def access_mode=(value) resource[:access_mode] = value save_datasource end def database datasource[:database] end def database=(value) resource[:database] = value save_datasource end def user datasource[:user] end def user=(value) resource[:user] = value save_datasource end def password datasource[:password] end def password=(value) resource[:password] = value save_datasource end - # rubocop:disable Style/PredicateName + # rubocop:disable Naming/PredicateName def is_default datasource[:is_default] end def is_default=(value) resource[:is_default] = value save_datasource end - # rubocop:enable Style/PredicateName + # rubocop:enable Naming/PredicateName def basic_auth datasource[:basic_auth] end def basic_auth=(value) resource[:basic_auth] = value save_datasource end def basic_auth_user datasource[:basic_auth_user] end def basic_auth_user=(value) resource[:basic_auth_user] = value save_datasource end def basic_auth_password datasource[:basic_auth_password] end def basic_auth_password=(value) resource[:basic_auth_password] = value save_datasource end def with_credentials datasource[:with_credentials] end def with_credentials=(value) resource[:with_credentials] = value save_datasource end def json_data datasource[:json_data] end def json_data=(value) resource[:json_data] = value save_datasource end def secure_json_data datasource[:secure_json_data] end def secure_json_data=(value) resource[:secure_json_data] = value save_datasource end def save_datasource # 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 = { name: resource[:name], type: resource[:type], url: resource[:url], access: resource[:access_mode], database: resource[:database], user: resource[:user], password: resource[:password], - isDefault: (resource[:is_default] == :true), - basicAuth: (resource[:basic_auth] == :true), + isDefault: (resource[:is_default] == true), + basicAuth: (resource[:basic_auth] == true), basicAuthUser: resource[:basic_auth_user], basicAuthPassword: resource[:basic_auth_password], - withCredentials: (resource[:with_credentials] == :true), + withCredentials: (resource[:with_credentials] == true), jsonData: resource[:json_data], secureJsonData: resource[:secure_json_data] } if datasource.nil? response = send_request('POST', format('%s/datasources', resource[:grafana_api_path]), data) else data[:id] = datasource[:id] 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 + raise format('Failed to create save %s (HTTP response: %s/%s)', resource[:name], response.code, response.body) if response.code != '200' + self.datasource = nil end def delete_datasource 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) - end + raise format('Failed to delete datasource %s (HTTP response: %s/%s', resource[:name], response.code, response.body) if response.code != '200' + self.datasource = nil end def create save_datasource end def destroy delete_datasource end def exists? datasource end end diff --git a/lib/puppet/provider/grafana_folder/grafana.rb b/lib/puppet/provider/grafana_folder/grafana.rb index 6e1f81d..7c5acbf 100644 --- a/lib/puppet/provider/grafana_folder/grafana.rb +++ b/lib/puppet/provider/grafana_folder/grafana.rb @@ -1,179 +1,171 @@ +# frozen_string_literal: true + require 'json' require File.expand_path(File.join(File.dirname(__FILE__), '..', 'grafana')) Puppet::Type.type(:grafana_folder).provide(:grafana, parent: Puppet::Provider::Grafana) do desc 'Support for Grafana folders stored into Grafana' defaultfor kernel: 'Linux' def organization resource[:organization] end def grafana_api_path resource[:grafana_api_path] end def permissions find_folder unless @folder response = send_request('GET', format('%s/folders/%s/permissions', resource[:grafana_api_path], @folder['uid'])) - if response.code != '200' - raise format('Failed to retrieve permissions %s (HTTP response: %s/%s)', resource[:title], response.code, response.body) - end + raise format('Failed to retrieve permissions %s (HTTP response: %s/%s)', resource[:title], response.code, response.body) if response.code != '200' + begin permissions = JSON.parse(response.body) rescue JSON::ParserError raise format('Fail to parse permissions (HTTP response: %s/%s)', response.code, response.body) end parsed_permissions = [] # These are the only configurable keys, many others are returned keep_keys = %w[permission role teamId userId] permissions.each do |permission| parsed_permission = {} permission.each_pair do |key, value| parsed_permission[key] = value if keep_keys.include?(key) && value != 0 end parsed_permissions << parsed_permission unless parsed_permission.empty? end parsed_permissions end def permissions=(value) save_permissions(value) 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 + 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) { 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 ||= 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) rescue JSON::ParserError raise format('Fail to parse folders (HTTP response: %s/%s)', response.code, response.body) end end def find_folder folders unless @folders @folders.each do |folder| @folder = folder if folder['title'] == resource[:title] end end def save_folder(folder) 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' # if folder exists, update object based on uid # else, create object if @folder.nil? data = { title: resource[:title], uid: resource[:uid] } response = send_request('POST', format('%s/folders', resource[:grafana_api_path]), data) - if (response.code != '200') && (response.code != '412') - raise format('Failed to create folder %s (HTTP response: %s/%s)', resource[:title], response.code, response.body) - end + raise format('Failed to create folder %s (HTTP response: %s/%s)', resource[:title], response.code, response.body) if (response.code != '200') && (response.code != '412') + folders find_folder save_permissions(resource[:permissions]) else data = { folder: folder.merge('title' => resource[:title], 'uid' => @folder['uid']), overwrite: !@folder.nil? } response = send_request('POST', format('%s/folders/%s', resource[:grafana_api_path], @folder['uid']), data) return unless (response.code != '200') && (response.code != '412') + raise format('Failed to update folder %s (HTTP response: %s/%s)', resource[:title], response.code, response.body) end end def save_permissions(value) return if value.nil? + 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' + find_folder unless @folder data = { 'items' => value } response = send_request 'POST', format('%s/folders/%s/permissions', resource[:grafana_api_path], @folder['uid']), data return if response.code == '200' + raise format('Failed to update permissions %s (HTTP response: %s/%s)', fetch_organization[:id], 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 create save_folder(resource) end def destroy find_folder unless @folder response = send_request('DELETE', format('%s/folders/%s', resource[:grafana_api_path], @folder['uid'])) return unless response.code != '200' + raise Puppet::Error, format('Failed to delete folder %s (HTTP response: %s/%s)', resource[:title], response.code, response.body) end def exists? folders unless @folders @folders.each do |folder| return true if folder['title'] == resource[:title] end false end end diff --git a/lib/puppet/provider/grafana_notification/grafana.rb b/lib/puppet/provider/grafana_notification/grafana.rb index 7777dfa..4714951 100644 --- a/lib/puppet/provider/grafana_notification/grafana.rb +++ b/lib/puppet/provider/grafana_notification/grafana.rb @@ -1,146 +1,140 @@ +# frozen_string_literal: true + # Copyright 2015 Mirantis, Inc. # require 'json' require File.expand_path(File.join(File.dirname(__FILE__), '..', 'grafana')) Puppet::Type.type(:grafana_notification).provide(:grafana, parent: Puppet::Provider::Grafana) do desc 'Support for Grafana notifications' defaultfor kernel: 'Linux' def grafana_api_path resource[:grafana_api_path] end def notifications response = send_request('GET', format('%s/alert-notifications', resource[:grafana_api_path])) - if response.code != '200' - raise format('Fail to retrieve notifications (HTTP response: %s/%s)', response.code, response.body) - end + raise format('Fail to retrieve notifications (HTTP response: %s/%s)', response.code, response.body) if response.code != '200' begin notifications = JSON.parse(response.body) notifications.map { |x| x['id'] }.map do |id| response = send_request 'GET', format('%s/alert-notifications/%s', resource[:grafana_api_path], id) - if response.code != '200' - raise format('Failed to retrieve notification %d (HTTP response: %s/%s)', id, response.code, response.body) - end + raise format('Failed to retrieve notification %d (HTTP response: %s/%s)', id, response.code, response.body) if response.code != '200' notification = JSON.parse(response.body) { id: notification['id'], name: notification['name'], type: notification['type'], - is_default: notification['isDefault'] ? :true : :false, - send_reminder: notification['sendReminder'] ? :true : :false, + is_default: notification['isDefault'] ? true : false, + send_reminder: notification['sendReminder'] ? true : false, frequency: notification['frequency'], settings: notification['settings'] } end rescue JSON::ParserError raise format('Failed to parse response: %s', response.body) end end def notification - unless @notification - @notification = notifications.find { |x| x[:name] == resource[:name] } - end + @notification ||= notifications.find { |x| x[:name] == resource[:name] } @notification end attr_writer :notification def type notification[:type] end def type=(value) resource[:type] = value save_notification end - # rubocop:disable Style/PredicateName + # rubocop:disable Naming/PredicateName def is_default notification[:is_default] end def is_default=(value) resource[:is_default] = value save_notification end def send_reminder notification[:send_reminder] end def send_reminder=(value) resource[:send_reminder] = value save_notification end - # rubocop:enable Style/PredicateName + # rubocop:enable Naming/PredicateName def frequency notification[:frequency] end def frequency=(value) resource[:frequency] = value save_notification end def settings notification[:settings] end def settings=(value) resource[:settings] = value save_notification end def save_notification data = { name: resource[:name], type: resource[:type], - isDefault: (resource[:is_default] == :true), - sendReminder: (resource[:send_reminder] == :true), + isDefault: (resource[:is_default] == true), + sendReminder: (resource[:send_reminder] == true), frequency: resource[:frequency], settings: resource[:settings] } if notification.nil? response = send_request('POST', format('%s/alert-notifications', resource[:grafana_api_path]), data) else data[:id] = notification[:id] response = send_request 'PUT', format('%s/alert-notifications/%s', resource[:grafana_api_path], notification[: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 + raise format('Failed to create save %s (HTTP response: %s/%s)', resource[:name], response.code, response.body) if response.code != '200' + self.notification = nil end def delete_notification response = send_request 'DELETE', format('%s/alert-notifications/%s', resource[:grafana_api_path], notification[:id]) - if response.code != '200' - raise format('Failed to delete notification %s (HTTP response: %s/%s', resource[:name], response.code, response.body) - end + raise format('Failed to delete notification %s (HTTP response: %s/%s', resource[:name], response.code, response.body) if response.code != '200' + self.notification = nil end def create save_notification end def destroy delete_notification end def exists? notification end end diff --git a/lib/puppet/provider/grafana_organization/grafana.rb b/lib/puppet/provider/grafana_organization/grafana.rb index 9cf0239..4b0377c 100644 --- a/lib/puppet/provider/grafana_organization/grafana.rb +++ b/lib/puppet/provider/grafana_organization/grafana.rb @@ -1,107 +1,98 @@ +# frozen_string_literal: true + require 'json' require File.expand_path(File.join(File.dirname(__FILE__), '..', 'grafana')) Puppet::Type.type(:grafana_organization).provide(:grafana, parent: Puppet::Provider::Grafana) do desc 'Support for Grafana organizations' defaultfor kernel: 'Linux' def organizations 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 + raise format('Failed to retrieve organizations (HTTP response: %s/%s)', response.code, response.body) if response.code != '200' begin organizations = JSON.parse(response.body) 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' organization = JSON.parse(response.body) { id: organization['id'], name: organization['name'], address: organization['address'] } end rescue JSON::ParserError raise format('Failed to parse response: %s', response.body) end end def organization - unless @organization - @organization = organizations.find { |x| x[:name] == resource[:name] } - end + @organization ||= organizations.find { |x| x[:name] == resource[:name] } @organization end attr_writer :organization - # rubocop:enable Style/PredicateName - def id organization[:id] end def id=(value) resource[:id] = value save_organization end def address organization[:json_data] end def address=(value) resource[:address] = value save_organization end def save_organization data = { id: resource[:id], name: resource[:name], address: resource[:address] } 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) - end + raise format('Failed to create save %s (HTTP response: %s/%s)', resource[:name], response.code, response.body) if response.code != '200' + self.organization = nil end def delete_organization 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) - end + raise format('Failed to delete organization %s (HTTP response: %s/%s)', resource[:name], response.code, response.body) if response.code != '200' + # change back to default organization response = send_request 'POST', format('%s/user/using/1', resource[:grafana_api_path]) - 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' + self.organization = nil end def create save_organization end def destroy delete_organization end def exists? organization end end diff --git a/lib/puppet/provider/grafana_plugin/grafana_cli.rb b/lib/puppet/provider/grafana_plugin/grafana_cli.rb index c84e547..34df6bc 100644 --- a/lib/puppet/provider/grafana_plugin/grafana_cli.rb +++ b/lib/puppet/provider/grafana_plugin/grafana_cli.rb @@ -1,63 +1,66 @@ +# frozen_string_literal: true + Puppet::Type.type(:grafana_plugin).provide(:grafana_cli) do has_command(:grafana_cli, 'grafana-cli') do is_optional end defaultfor feature: :posix mk_resource_methods def self.all_plugins plugins = [] grafana_cli('plugins', 'ls').split(%r{\n}).each do |line| next unless line =~ %r{^(\S+)\s+@\s+((?:\d\.).+)\s*$} + name = Regexp.last_match(1) version = Regexp.last_match(2) Puppet.debug("Found grafana plugin #{name} #{version}") plugins.push(name) end plugins.sort end def self.instances resources = [] all_plugins.each do |name| plugin = { ensure: :present, name: name } resources << new(plugin) if plugin[:name] end resources end def self.prefetch(resources) plugins = instances - resources.keys.each do |name| + resources.each_key do |name| if (provider = plugins.find { |plugin| plugin.name == name }) resources[name].provider = provider end end end def exists? @property_hash[:ensure] == :present end def create if resource[:repo] repo = "--repo #{resource[:repo]}" grafana_cli(repo, 'plugins', 'install', resource[:name]) elsif resource[:plugin_url] grafana_cli('--pluginUrl', resource[:plugin_url], 'plugins', 'install', resource[:name]) else grafana_cli('plugins', 'install', resource[:name]) end @property_hash[:ensure] = :present end def destroy grafana_cli('plugins', 'uninstall', resource[:name]) @property_hash[:ensure] = :absent end end diff --git a/lib/puppet/provider/grafana_team/grafana.rb b/lib/puppet/provider/grafana_team/grafana.rb index 223ef73..824e9c9 100644 --- a/lib/puppet/provider/grafana_team/grafana.rb +++ b/lib/puppet/provider/grafana_team/grafana.rb @@ -1,278 +1,279 @@ # frozen_string_literal: true require 'json' require File.expand_path(File.join(File.dirname(__FILE__), '..', 'grafana')) Puppet::Type.type(:grafana_team).provide(:grafana, parent: Puppet::Provider::Grafana) do desc 'Support for Grafana permissions' defaultfor kernel: 'Linux' def raise_on_error(code, message) raise message if code != '200' end def parse_response(data) JSON.parse(data) rescue JSON::ParserError raise format('Fail to parse response: %s', response.body) end def map_organizations(ids) ids.map do |id| response = send_request 'GET', format('%s/orgs/%s', resource[:grafana_api_path], id) raise_on_error(response.code, format('Failed to retrieve organization %d (HTTP response: %s/%s)', id, response.code, response.body)) organization = parse_response(response.body) { id: organization['id'], name: organization['name'] } end end def organizations response = send_request('GET', format('%s/orgs', resource[:grafana_api_path])) raise_on_error(response.code, format('Fail to retrieve organizations (HTTP response: %s/%s)', response.code, response.body)) organizations = JSON.parse(response.body) map_organizations(organizations.map { |x| x['id'] }) end def organization return @organization if @organization org = resource[:organization] key = org.is_a?(Numeric) || org.match(%r{/^[0-9]*$/}) ? :id : :name @organization = organizations.find { |x| x[key] == org } end def map_teams(teams) teams['teams'].map do |team| { id: team['id'], name: team['name'], organization: team['orgId'], membercount: team['membercount'], permission: team['permission'], email: team['email'] } end end def teams return [] unless organization set_current_organization response = send_request('GET', format('%s/teams/search', resource[:grafana_api_path])) raise_on_error(response.code, format('Fail to retrieve teams (HTTP response: %s/%s)', response.code, response.body)) teams = parse_response(response.body) map_teams(teams) end def team @team ||= teams.find { |x| x[:name] == resource[:name] } end def map_preferences(preferences) { theme: preferences['theme'], home_dashboard: preferences['homeDashboardId'], timezone: preferences['timezone'] } end def preferences team unless @team return if @preferences response = send_request('GET', format('%s/teams/%s/preferences', resource[:grafana_api_path], @team[:id])) raise_on_error(response.code, format('Fail to retrieve teams (HTTP response: %s/%s)', response.code, response.body)) preferences = parse_response(response.body) @preferences = map_preferences(preferences) end def setup_save_preferences_data endpoint = format('%s/teams/%s/preferences', resource[:grafana_api_path], @team[:id]) dash = get_dashboard(resource[:home_dashboard], resource[:home_dashboard_folder]) request_data = { theme: resource[:theme], homeDashboardId: dash[:id], timezone: resource[:timezone] } ['PUT', endpoint, request_data] end def save_preferences team unless @team set_current_organization setup_save_preferences_data response = send_request(*setup_save_preferences_data) # TODO: Raise on error? return if response.code == '200' || response.code == '412' raise format('Failed to update team %s, (HTTP response: %s/%s)', resource, response.code, response.body) end def set_current_organization response = send_request 'POST', format('%s/user/using/%s', resource[:grafana_api_path], organization[:id]) return if response.code == '200' raise format('Failed to switch to org %s (HTTP response: %s/%s)', organization[:id], response.code, response.body) end def home_dashboard_folder preferences unless @preferences dash = get_dashboard(@preferences[:home_dashboard]) return dash[:folder_name] if dash nil end def home_dashboard_folder=(value) resource[:home_dashboard_folder] = value save_preferences end def home_dashboard preferences unless @preferences dash = get_dashboard(@preferences[:home_dashboard]) return dash[:name] if dash nil end def home_dashboard=(value) resource[:home_dashboard] = value save_preferences end def setup_search_path(ident, folder_id = nil) query = if ident.is_a?(Numeric) || ident.match(%r{/^[0-9]*$/}) { dashboardIds: ident, type: 'dash-db' } else { query: ident, type: 'dash-db' } end query[:folderIds] = folder_id unless folder_id.nil? query end def get_dashboard(ident, folder = nil) set_current_organization return { id: 0, name: 'Default' } if ident == 0 # rubocop:disable Style/NumericPredicate folder_id = nil folder_id = get_dashboard_folder_id(folder) unless folder.nil? search_path = setup_search_path(ident, folder_id) response = send_request('GET', format('%s/search', resource[:grafana_api_path]), nil, search_path) raise_on_error(response.code, format('Fail to retrieve dashboars (HTTP response: %s/%s)', response.code, response.body)) dashboard = parse_response(response.body) format_dashboard(dashboard) end def format_dashboard(dashboard) return { id: 0, name: 'Default' } unless dashboard.first { id: dashboard.first['id'], name: dashboard.first['title'], folder_uid: dashboard.first['folderUid'], folder_name: dashboard.first['folderTitle'], } end def setup_folder_search_path(ident) if ident.is_a?(Numeric) || ident.match(%r{/^[0-9]*$/}) { folderIds: ident, type: 'dash-folder' } else { query: ident, type: 'dash-folder' } end end def get_dashboard_folder_id(ident) return nil if ident.nil? set_current_organization search_path = setup_folder_search_path(ident) response = send_request('GET', format('%s/search', resource[:grafana_api_path]), nil, search_path) raise_on_error(response.code, format('Fail to retrieve dashboars (HTTP response: %s/%s)', response.code, response.body)) dashboard = parse_response(response.body) return nil unless dashboard.first + dashboard.first['id'] end def theme preferences unless @preferences return @preferences[:theme] if @preferences nil end def theme=(value) resource[:theme] = value save_preferences end def timezone preferences unless @preferences return @preferences[:timezone] if @preferences nil end def timezone=(value) resource[:timezone] = value save_preferences end def setup_save_team_data verb = 'POST' endpoint = format('%s/teams', resource[:grafana_api_path]) request_data = { name: resource[:name], email: resource[:email] } if exists? verb = 'PUT' endpoint = format('%s/teams/%s', resource[:grafana_api_path], @team[:id]) end [verb, endpoint, request_data] end def save_team set_current_organization response = send_request(*setup_save_team_data) raise_on_error(response.code, format('Failed to update team %s, (HTTP response: %s/%s)', resource, response.code, response.body)) end def create save_team save_preferences end def destroy return unless team response = send_request('DELETE', format('%s/teams/%s', resource[:grafana_api_path], @team[:id])) raise_on_error(response.code, format('Failed to delete team %s (HTTP response: %s/%s)', resource, response.code, response.body)) end def exists? team return true if @team && @team[:name] == resource[:name] false end end diff --git a/lib/puppet/provider/grafana_user/grafana.rb b/lib/puppet/provider/grafana_user/grafana.rb index 9f01e1f..5892d5e 100644 --- a/lib/puppet/provider/grafana_user/grafana.rb +++ b/lib/puppet/provider/grafana_user/grafana.rb @@ -1,167 +1,159 @@ +# frozen_string_literal: true + require 'json' require File.expand_path(File.join(File.dirname(__FILE__), '..', 'grafana')) Puppet::Type.type(:grafana_user).provide(:grafana, parent: Puppet::Provider::Grafana) do desc 'Support for Grafana users' defaultfor kernel: 'Linux' def users response = send_request('GET', format('%s/users', resource[:grafana_api_path])) - if response.code != '200' - raise format('Fail to retrieve users (HTTP response: %s/%s)', response.code, response.body) - end + raise format('Fail to retrieve users (HTTP response: %s/%s)', response.code, response.body) if response.code != '200' begin users = JSON.parse(response.body) users.map { |x| x['id'] }.map do |id| response = send_request('GET', format('%s/users/%s', resource[:grafana_api_path], id)) - if response.code != '200' - raise format('Fail to retrieve user %d (HTTP response: %s/%s)', id, response.code, response.body) - end + raise format('Fail to retrieve user %d (HTTP response: %s/%s)', id, response.code, response.body) if response.code != '200' user = JSON.parse(response.body) { id: id, name: user['login'], full_name: user['name'], email: user['email'], theme: user['theme'], password: nil, - is_admin: user['isGrafanaAdmin'] ? :true : :false + is_admin: user['isGrafanaAdmin'] ? true : false } end rescue JSON::ParserError raise format('Fail to parse response: %s', response.body) end end def user - @user = users.find { |x| x[:name] == resource[:name] } unless @user + @user ||= users.find { |x| x[:name] == resource[:name] } @user end attr_writer :user def name user[:name] end def name=(value) resource[:name] = value save_user end def full_name user[:full_name] end def full_name=(value) resource[:full_name] = value save_user end def email user[:email] end def email=(value) resource[:email] = value save_user end def theme user[:theme] end def theme=(value) resource[:theme] = value save_user end def password nil end def password=(value) resource[:password] = value save_user end - # rubocop:disable Style/PredicateName + # rubocop:disable Naming/PredicateName def is_admin user[:is_admin] end def is_admin=(value) resource[:is_admin] = value save_user end - # rubocop:enable Style/PredicateName + # rubocop:enable Naming/PredicateName def save_user data = { login: resource[:name], name: resource[:full_name], email: resource[:email], password: resource[:password], theme: resource[:theme], - isGrafanaAdmin: (resource[:is_admin] == :true) + isGrafanaAdmin: (resource[:is_admin] == true) } if user.nil? response = send_request('POST', format('%s/admin/users', resource[:grafana_api_path]), data) else data[:id] = user[:id] send_request 'PUT', format('%s/admin/users/%s/password', resource[:grafana_api_path], user[:id]), password: data.delete(:password) send_request 'PUT', format('%s/admin/users/%s/permissions', resource[:grafana_api_path], user[:id]), isGrafanaAdmin: data.delete(:isGrafanaAdmin) response = send_request('PUT', format('%s/users/%s', resource[:grafana_api_path], user[:id]), data) end - if response.code != '200' - raise format('Failed to create user %s (HTTP response: %s/%s)', resource[:name], response.code, response.body) - end + raise format('Failed to create user %s (HTTP response: %s/%s)', resource[:name], response.code, response.body) if response.code != '200' + self.user = nil end def check_password uri = URI.parse format('%s://%s:%d%s/dashboards/home', grafana_scheme, grafana_host, grafana_port, resource[:grafana_api_path]) request = Net::HTTP::Get.new(uri.to_s) request.content_type = 'application/json' request.basic_auth resource[:name], resource[:password] response = Net::HTTP.start(grafana_host, grafana_port, use_ssl: grafana_scheme == 'https', verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| http.request(request) end - if response.code == '200' - true - else - false - end + response.code == '200' end def delete_user response = send_request('DELETE', format('%s/admin/users/%s', resource[:grafana_api_path], user[:id])) - if response.code != '200' - raise format('Failed to delete user %s (HTTP response: %s/%s', resource[:name], response.code, response.body) - end + raise format('Failed to delete user %s (HTTP response: %s/%s', resource[:name], response.code, response.body) if response.code != '200' + self.user = nil end def create save_user end def destroy delete_user end def exists? user end end diff --git a/lib/puppet/type/grafana_conn_validator.rb b/lib/puppet/type/grafana_conn_validator.rb index 7c659ed..cfed80f 100644 --- a/lib/puppet/type/grafana_conn_validator.rb +++ b/lib/puppet/type/grafana_conn_validator.rb @@ -1,42 +1,40 @@ +# frozen_string_literal: true + Puppet::Type.newtype(:grafana_conn_validator) do desc <<-DESC Verify connectivity to the Grafana API DESC ensurable newparam(:name, namevar: true) do desc 'Arbitrary name of this resource' end newparam(:grafana_url) do desc 'The URL of the Grafana server' defaultto 'http://localhost:3000' validate do |value| - unless value =~ %r{^https?://} - raise ArgumentError, format('%s is not a valid URL', value) - end + raise ArgumentError, format('%s is not a valid URL', value) unless value =~ %r{^https?://} end end newparam(:grafana_api_path) do desc 'The absolute path to the API endpoint' defaultto '/api/health' validate do |value| - unless value =~ %r{^/.*/?api/.*$} - raise ArgumentError, format('%s is not a valid API path', value) - end + raise ArgumentError, format('%s is not a valid API path', value) unless value =~ %r{^/.*/?api/.*$} end end newparam(:timeout) do desc 'How long to wait for the API to be available' defaultto(20) end autorequire(:service) do 'grafana-server' end end diff --git a/lib/puppet/type/grafana_dashboard.rb b/lib/puppet/type/grafana_dashboard.rb index b6cd648..87226d6 100644 --- a/lib/puppet/type/grafana_dashboard.rb +++ b/lib/puppet/type/grafana_dashboard.rb @@ -1,89 +1,84 @@ +# frozen_string_literal: true + # Copyright 2015 Mirantis, Inc. # require 'json' Puppet::Type.newtype(:grafana_dashboard) do @doc = 'Manage dashboards in Grafana' ensurable newparam(:title, namevar: true) do desc 'The title of the dashboard.' end newparam(:folder) do desc 'The folder to place the dashboard in (optional)' end newproperty(:content) do desc 'The JSON representation of the dashboard.' validate do |value| - begin - JSON.parse(value) - rescue JSON::ParserError - raise ArgumentError, 'Invalid JSON string for content' - end + JSON.parse(value) + rescue JSON::ParserError + raise ArgumentError, 'Invalid JSON string for content' end munge do |value| new_value = JSON.parse(value).reject { |k, _| k =~ %r{^id|version|title$} } new_value.sort.to_h end def should_to_s(value) if value.length > 12 "#{value.to_s.slice(0, 12)}..." else value end end end newparam(:grafana_url) do desc 'The URL of the Grafana server' defaultto '' validate do |value| - unless value =~ %r{^https?://} - raise ArgumentError, format('%s is not a valid URL', value) - end + raise ArgumentError, format('%s is not a valid URL', value) unless value =~ %r{^https?://} end end newparam(:grafana_user) do desc 'The username for the Grafana server (optional)' end newparam(:grafana_password) do desc 'The password for the Grafana server (optional)' end newparam(:grafana_api_path) do desc 'The absolute path to the API endpoint' defaultto '/api' validate do |value| - unless value =~ %r{^/.*/?api$} - raise ArgumentError, format('%s is not a valid API path', value) - end + raise ArgumentError, format('%s is not a valid API path', value) unless value =~ %r{^/.*/?api$} end end newparam(:organization) do desc 'The organization name to create the datasource on' defaultto 1 end - # rubocop:disable Style/SignalException validate do - fail('content is required when ensure is present') if self[:ensure] == :present && self[:content].nil? + fail('content is required when ensure is present') if self[:ensure] == :present && self[:content].nil? # rubocop:disable Style/SignalException end autorequire(:service) do 'grafana-server' end autorequire(:grafana_conn_validator) do 'grafana' end end diff --git a/lib/puppet/type/grafana_datasource.rb b/lib/puppet/type/grafana_datasource.rb index 35cffc2..4f4ec8e 100644 --- a/lib/puppet/type/grafana_datasource.rb +++ b/lib/puppet/type/grafana_datasource.rb @@ -1,136 +1,130 @@ +# frozen_string_literal: true + # Copyright 2015 Mirantis, Inc. # Puppet::Type.newtype(:grafana_datasource) do @doc = 'Manage datasources in Grafana' ensurable newparam(:name, namevar: true) do desc 'The name of the datasource.' end newparam(:grafana_api_path) do desc 'The absolute path to the API endpoint' defaultto '/api' validate do |value| - unless value =~ %r{^/.*/?api$} - raise ArgumentError, format('%s is not a valid API path', value) - end + raise ArgumentError, format('%s is not a valid API path', value) unless value =~ %r{^/.*/?api$} end end newparam(:grafana_url) do desc 'The URL of the Grafana server' defaultto '' validate do |value| - unless value =~ %r{^https?://} - raise ArgumentError, format('%s is not a valid URL', value) - end + raise ArgumentError, format('%s is not a valid URL', value) unless value =~ %r{^https?://} end end newparam(:grafana_user) do desc 'The username for the Grafana server' end newparam(:grafana_password) do desc 'The password for the Grafana server' end newproperty(:url) do desc 'The URL/Endpoint of the datasource' end newproperty(:type) do desc 'The datasource type' end newparam(:organization) do desc 'The organization name to create the datasource on' defaultto 1 end newproperty(:user) do desc 'The username for the datasource (optional)' end newproperty(:password) do desc 'The password for the datasource (optional)' sensitive true end newproperty(:database) do desc 'The name of the database (optional)' end newproperty(:access_mode) do desc 'Whether the datasource is accessed directly or not by the clients' newvalues(:direct, :proxy) defaultto :direct end newproperty(:is_default) do desc 'Whether the datasource is the default one' - newvalues(:true, :false) - defaultto :false + newvalues(true, false) + defaultto false end newproperty(:basic_auth) do desc 'Whether basic auth is enabled or not' - newvalues(:true, :false) - defaultto :false + newvalues(true, false) + defaultto false end newproperty(:basic_auth_user) do desc 'The username for basic auth if enabled' defaultto '' end newproperty(:basic_auth_password) do desc 'The password for basic auth if enabled' defaultto '' end newproperty(:with_credentials) do desc 'Whether credentials such as cookies or auth headers should be sent with cross-site requests' - newvalues(:true, :false) - defaultto :false + newvalues(true, false) + defaultto false end newproperty(:json_data) do desc 'Additional JSON data to configure the datasource (optional)' validate do |value| - unless value.nil? || value.is_a?(Hash) - raise ArgumentError, 'json_data should be a Hash!' - end + raise ArgumentError, 'json_data should be a Hash!' unless value.nil? || value.is_a?(Hash) end end newproperty(:secure_json_data) do desc 'Additional secure JSON data to configure the datasource (optional)' sensitive true validate do |value| - unless value.nil? || value.is_a?(Hash) - raise ArgumentError, 'secure_json_data should be a Hash!' - end + raise ArgumentError, 'secure_json_data should be a Hash!' unless value.nil? || value.is_a?(Hash) end end def set_sensitive_parameters(sensitive_parameters) # rubocop:disable Style/AccessorMethodName parameter(:password).sensitive = true if parameter(:password) parameter(:basic_auth_password).sensitive = true if parameter(:basic_auth_password) super(sensitive_parameters) end autorequire(:service) do 'grafana-server' end autorequire(:grafana_conn_validator) do 'grafana' end end diff --git a/lib/puppet/type/grafana_folder.rb b/lib/puppet/type/grafana_folder.rb index e8325a9..97a97d5 100644 --- a/lib/puppet/type/grafana_folder.rb +++ b/lib/puppet/type/grafana_folder.rb @@ -1,62 +1,60 @@ +# frozen_string_literal: true + require 'json' Puppet::Type.newtype(:grafana_folder) do @doc = 'Manage folders in Grafana' ensurable newparam(:title, namevar: true) do desc 'The title of the folder' end newparam(:uid) do desc 'UID of the folder' end newparam(:grafana_url) do desc 'The URL of the Grafana server' defaultto '' validate do |value| - unless value =~ %r{^https?://} - raise ArgumentError, format('%s is not a valid URL', value) - end + raise ArgumentError, format('%s is not a valid URL', value) unless value =~ %r{^https?://} end end newparam(:grafana_user) do desc 'The username for the Grafana server (optional)' end newparam(:grafana_password) do desc 'The password for the Grafana server (optional)' end newparam(:grafana_api_path) do desc 'The absolute path to the API endpoint' defaultto '/api' validate do |value| - unless value =~ %r{^/.*/?api$} - raise ArgumentError, format('%s is not a valid API path', value) - end + raise ArgumentError, format('%s is not a valid API path', value) unless value =~ %r{^/.*/?api$} end end newparam(:organization) do desc 'The organization name to create the folder on' defaultto 1 end newproperty(:permissions, array_matching: :all) do desc 'The permissions of the folder' end autorequire(:service) do 'grafana-server' end autorequire(:grafana_conn_validator) do 'grafana' end end diff --git a/lib/puppet/type/grafana_ldap_config.rb b/lib/puppet/type/grafana_ldap_config.rb index 23b4f04..ee52f46 100644 --- a/lib/puppet/type/grafana_ldap_config.rb +++ b/lib/puppet/type/grafana_ldap_config.rb @@ -1,185 +1,187 @@ +# frozen_string_literal: true + require 'toml' require 'puppet/parameter/boolean' Puppet::Type.newtype(:grafana_ldap_config) do @doc = 'Manage Grafana LDAP configuration' - @toml_header = <<-EOF -# -# Grafana LDAP configuration -# -# generated by Puppet module puppet-grafana -# https://github.com/voxpupuli/puppet-grafana -# -# *** Edit at your own peril *** -# -# ############################################# # -EOF + @toml_header = <<~EOF + # + # Grafana LDAP configuration + # + # generated by Puppet module puppet-grafana + # https://github.com/voxpupuli/puppet-grafana + # + # *** Edit at your own peril *** + # + # ############################################# # + EOF # currently not ensurable as we are not parsing the LDAP toml config. # ensurable newparam(:title, namevar: true) do desc 'Path to ldap.toml' validate do |value| raise ArgumentError, _('name/title must be a String') unless value.is_a?(String) end end newparam(:owner) do desc 'Owner of the LDAP configuration-file either as String or Integer (default: root)' defaultto 'root' validate do |value| raise ArgumentError, _('owner must be a String or Integer') unless value.is_a?(String) || value.is_a?(Integer) end end newparam(:group) do desc 'Group of the LDAP configuration file either as String or Integer (default: grafana)' defaultto 'grafana' validate do |value| raise ArgumentError, _('group must be a String or Integer') unless value.is_a?(String) || value.is_a?(Integer) end end newparam(:mode) do desc 'File-permissions mode of the LDAP configuration file as String' defaultto '0440' validate do |value| raise ArgumentError, _('file-permissions must be a String') unless value.is_a?(String) raise ArgumentError, _('file-permissions must be a String') if value.empty? # regex-pattern stolen from here - all credis to them! # https://github.com/puppetlabs/puppetlabs-stdlib/blob/master/types/filemode.pp # currently disabled, as it fails when implicitly called. # # raise ArgumentError, _('file-permissions is not valid') unless value.to_s.match(%r{/\A(([0-7]{1,4})|(([ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=][0-7]+)(,([ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=][0-7]+))*))\z/}) end end newparam(:replace, boolean: true, parent: Puppet::Parameter::Boolean) do desc 'Replace existing files' defaultto true end newparam(:backup, boolean: true, parent: Puppet::Parameter::Boolean) do desc 'Backup existing files before replacing them into the file-bucket' defaultto false end newparam(:validate_cmd) do desc 'A command to validate the new Grafana LDAP configuration before actually replacing it' validate do |value| raise ArgumentError, _('validate_cmd must be a String or undef') unless value.nil? || value.is_a?(String) end end def ldap_servers catalog.resources.each_with_object({}) do |resource, memo| next unless resource.is_a?(Puppet::Type.type(:grafana_ldap_server)) next unless resource[:name].is_a?(String) memo[resource[:name]] = resource memo end end def should_content return @generated_config if @generated_config @generated_config = {} ldap_servers.each do |server_k, server_v| # convert symbols to strings - server_params = Hash[server_v.original_parameters.map { |k, v| [k.to_s, v] }] + server_params = server_v.original_parameters.transform_keys(&:to_s) server_attributes = server_params['attributes'] server_params.delete('attributes') # grafana-syntax for multiple hosts is a space-separate list. server_params['host'] = server_params['hosts'].join(' ') server_params.delete('hosts') server_group_mappings = server_v.group_mappings server_block = { - 'servers' => [server_params], - 'servers.attributes' => server_attributes, + 'servers' => [server_params], + 'servers.attributes' => server_attributes, 'servers.group_mappings' => server_group_mappings }.compact @generated_config[server_k] = server_block end @generated_config.compact end def generate file_opts = {} # currently not ensurable # file_opts = { # ensure: (self[:ensure] == :absent) ? :absent : :file, # } [:name, :owner, :group, :mode, :replace, :backup, # this we have currently not implemented # :selinux_ignore_defaults, # :selrange, # :selrole, # :seltype, # :seluser, # :show_diff, :validate_cmd].each do |param| file_opts[param] = self[param] unless self[param].nil? end metaparams = Puppet::Type.metaparams excluded_metaparams = %w[before notify require subscribe tag] metaparams.reject! { |param| excluded_metaparams.include? param } metaparams.each do |metaparam| file_opts[metaparam] = self[metaparam] unless self[metaparam].nil? end [Puppet::Type.type(:file).new(file_opts)] end def eval_generate ldap_servers = should_content if !ldap_servers.nil? && !ldap_servers.empty? toml_contents = [] toml_contents << @toml_header toml_contents << ldap_servers.map do |k, v| str = [] str << "\n\n" - str << <<-EOF -# -# #{k} -# -EOF + str << <<~EOF + # + # #{k} + # + EOF str << TOML::Generator.new(v).body str.join end catalog.resource("File[#{self[:name]}]")[:content] = toml_contents.join end [catalog.resource("File[#{self[:name]}]")] end autonotify(:class) do 'grafana::service' end end diff --git a/lib/puppet/type/grafana_ldap_group_mapping.rb b/lib/puppet/type/grafana_ldap_group_mapping.rb index bcf5934..5d5ea8f 100644 --- a/lib/puppet/type/grafana_ldap_group_mapping.rb +++ b/lib/puppet/type/grafana_ldap_group_mapping.rb @@ -1,51 +1,53 @@ +# frozen_string_literal: true + require 'puppet/parameter/boolean' Puppet::Type.newtype(:grafana_ldap_group_mapping) do @doc = 'Map an LDAP group to a Grafana role.' def initialize(*args) @org_roles = %w[Admin Editor Viewer] super end validate do raise(_('grafana_ldap_group_mapping: title needs to be a non-empty string')) if self[:name].nil? || self[:name].empty? raise(_('grafana_ldap_group_mapping: ldap_server_name needs to be a non-empty string')) if self[:ldap_server_name].nil? || self[:ldap_server_name].empty? raise(_('grafana_ldap_group_mapping: group_dn needs to be a non-empty string')) if self[:group_dn].nil? || self[:group_dn].empty? raise(_("grafana_ldap_group_mapping: org_role needs to be a string of: #{@org_roles.join(', ')})")) if self[:org_role].nil? || self[:org_role].empty? end newparam(:title, namevar: true) do desc 'A unique identifier of the resource' validate do |value| raise ArgumentError, _('name/title must be a String') unless value.is_a?(String) end end newparam(:ldap_server_name) do desc 'The LDAP server config to apply the group-mappings on' validate do |value| raise ArgumentError, _('ldap_server_name must be a String') unless value.is_a?(String) end end newparam(:group_dn) do desc 'The LDAP distinguished-name of the group' validate do |value| raise ArgumentError, _('group_dn must be a String') unless value.is_a?(String) end end newparam(:org_role) do desc 'The Grafana role the shall be assigned to this group' newvalues(:Admin, :Editor, :Viewer) end newparam(:grafana_admin, boolean: true, parent: Puppet::Parameter::Boolean) do desc 'Additonal flag for Grafana > v5.3 to signal admin-role to Grafana' defaultto false end end diff --git a/lib/puppet/type/grafana_ldap_server.rb b/lib/puppet/type/grafana_ldap_server.rb index 638c5d1..39a68e9 100644 --- a/lib/puppet/type/grafana_ldap_server.rb +++ b/lib/puppet/type/grafana_ldap_server.rb @@ -1,177 +1,179 @@ +# frozen_string_literal: true + require 'puppet/parameter/boolean' Puppet::Type.newtype(:grafana_ldap_server) do @doc = 'Manage Grafana LDAP servers for LDAP authentication.' validate do raise(_('grafana_ldap_server: name must not be empty')) if self[:name].nil? || self[:name].empty? raise(_('grafana_ldap_server: hosts must not be empty')) if self[:hosts].nil? || self[:hosts].empty? raise(_('grafana_ldap_server: port must not be empty')) if self[:port].nil? raise(_('grafana_ldap_server: root_ca_cert must be set when SSL/TLS is enabled')) \ if !self[:ssl_skip_verify] && (self[:use_ssl] || self[:start_tls]) && self[:root_ca_cert].empty? raise(_('grafana_ldap_server: search_base_dns needs to contain at least one LDAP base-dn')) \ if self[:search_base_dns].empty? raise(_('grafana_ldap_server: group_search_base_dns needs to contain at least one LDAP base-dn')) \ if !self[:group_search_base_dns].nil? && self[:group_search_base_dns].empty? end newparam(:title, namevar: true) do desc 'A unique identified for this LDAP server.' validate do |value| raise ArgumentError, _('name/title must be a String') unless value.is_a?(String) end end newparam(:hosts) do desc 'The servers to perform LDAP authentication at' validate do |value| raise ArgumentError, _('hosts must be an Array') unless value.is_a?(Array) end end newparam(:port) do desc 'The port to connect at the LDAP servers (389 for TLS/plaintext, 636 for SSL [ldaps], optional)' defaultto 389 validate do |value| raise ArgumentError, _('port must be an Integer within the range 1-65535') unless value.is_a?(Integer) && value.between?(1, 65_535) # rubocop wants to have this weirdness end end newparam(:use_ssl, boolean: true, parent: Puppet::Parameter::Boolean) do desc 'Set to true if you want to perform LDAP via a SSL-connection (not meant to be for TLS, optional)' defaultto false end newparam(:start_tls, boolean: true, parent: Puppet::Parameter::Boolean) do desc 'Set to true if you want to perform LDAP via a TLS-connection (not meant to be for SSL, optional)' defaultto true end newparam(:ssl_skip_verify, boolean: true, parent: Puppet::Parameter::Boolean) do desc "Set to true to disable verification of the LDAP server's SSL certificate (for TLS and SSL, optional)" defaultto false end newparam(:root_ca_cert) do desc "The root ca-certificate to verify the LDAP server's SSL certificate against (for TLS and SSL, optional)" defaultto '/etc/ssl/certs/ca-certificates.crt' validate do |value| raise ArgumentError, _('root_ca_cert must be a String') unless value.is_a?(String) end end newparam(:client_cert) do desc "If the LDAP server requires certificate-based authentication, specify the client's certificate (for TLS and SSL, optional)" validate do |value| raise ArgumentError, _('client_cert must be a String') unless value.is_a?(String) end end newparam(:client_key) do desc "If the LDAP server requires certificate-based authentication, specify the client's certificate (for TLS and SSL, optional)" validate do |value| raise ArgumentError, _('client_key must be a String') unless value.is_a?(String) end end newparam(:bind_dn) do desc 'If the LDAP server requires authentication (i.e. non-anonymous), provide the distinguished-name (dn) here (optional)' validate do |value| raise ArgumentError, _('bind_dn must be a String') unless value.is_a?(String) end end newparam(:bind_password) do desc 'If the LDAP server requires authentication (i.e. non-anonymous), provide the password (optional)' validate do |value| raise ArgumentError, _('bind_password must be a String') unless value.is_a?(String) end end newparam(:search_filter) do desc 'A search-filter to be used when querying LDAP for user-accounts (optional)' validate do |value| raise ArgumentError, _('search_filter must be a String') unless value.is_a?(String) end end newparam(:search_base_dns) do desc 'The one or more base-dn to be used when querying LDAP for user-accounts (optional)' defaultto [] validate do |value| raise ArgumentError, _('search_base_dns must be an Array') unless value.is_a?(Array) value.each { |base_dn| raise ArgumentError, _('search_base_dns elements must be a String') unless base_dn.is_a?(String) } end end newparam(:group_search_filter) do desc 'A search-filter to be used when querying LDAP for group-accounts (optional)' validate do |value| raise ArgumentError, _('group_search_filter must be a String') unless value.is_a?(String) end end newparam(:group_search_filter_user_attribute) do desc 'The attribute to be used to locate matching user-accounts in the group (optional)' validate do |value| raise ArgumentError, _('group_search_filter_user_attribute must be a String') unless value.is_a?(String) end end newparam(:group_search_base_dns) do desc 'The base-dn to be used when querying LDAP for group-accounts (optional)' validate do |value| raise ArgumentError, _('search_base_dns must be an Array') unless value.is_a?(Array) value.each { |base_dn| raise ArgumentError, _('search_base_dns elements must be a String') unless base_dn.is_a?(String) } end end newparam(:attributes) do desc 'Mapping LDAP attributes to their Grafana user-account-properties (optional)' validate do |value| valid_attributes = %w[name surname username member_of email] raise ArgumentError, _('attributes must be a Hash') unless value.is_a?(Hash) value.each { |k, v| raise ArgumentError, _('attributes hash keys and values must be Strings') unless k.is_a?(String) && v.is_a?(String) } - raise ArgumentError, _("attributes contains an unknown key, allowed: #{valid_attributes.join(', ')}") if value.keys.reject { |key| valid_attributes.include?(key) }.count > 0 + raise ArgumentError, _("attributes contains an unknown key, allowed: #{valid_attributes.join(', ')}") if value.keys.reject { |key| valid_attributes.include?(key) }.count.positive? end end def set_sensitive_parameters(sensitive_parameters) # rubocop:disable Style/AccessorMethodName parameter(:bind_password).sensitive = true if parameter(:bind_password) super(sensitive_parameters) end def group_mappings catalog.resources.map do |resource| next unless resource.is_a?(Puppet::Type.type(:grafana_ldap_group_mapping)) next unless resource[:ldap_server_name] == self[:name] - group_mapping = Hash[resource.original_parameters.map { |k, v| [k.to_s, v] }] + group_mapping = resource.original_parameters.transform_keys(&:to_s) group_mapping.delete('ldap_server_name') group_mapping end.compact end end diff --git a/lib/puppet/type/grafana_notification.rb b/lib/puppet/type/grafana_notification.rb index 9cad69f..f50a927 100644 --- a/lib/puppet/type/grafana_notification.rb +++ b/lib/puppet/type/grafana_notification.rb @@ -1,79 +1,75 @@ +# frozen_string_literal: true + # Copyright 2015 Mirantis, Inc. # Puppet::Type.newtype(:grafana_notification) do @doc = 'Manage notification in Grafana' ensurable newparam(:name, namevar: true) do desc 'The name of the notification.' end newparam(:grafana_api_path) do desc 'The absolute path to the API endpoint' defaultto '/api' validate do |value| - unless value =~ %r{^/.*/?api$} - raise ArgumentError, format('%s is not a valid API path', value) - end + raise ArgumentError, format('%s is not a valid API path', value) unless value =~ %r{^/.*/?api$} end end newparam(:grafana_url) do desc 'The URL of the Grafana server' defaultto '' validate do |value| - unless value =~ %r{^https?://} - raise ArgumentError, format('%s is not a valid URL', value) - end + raise ArgumentError, format('%s is not a valid URL', value) unless value =~ %r{^https?://} end end newparam(:grafana_user) do desc 'The username for the Grafana server' end newparam(:grafana_password) do desc 'The password for the Grafana server' end newproperty(:type) do desc 'The notification type' end newproperty(:is_default) do desc 'Whether the notification is the default one' - newvalues(:true, :false) - defaultto :false + newvalues(true, false) + defaultto false end newproperty(:send_reminder) do desc 'Whether automatic message resending is enabled or not' - newvalues(:true, :false) - defaultto :false + newvalues(true, false) + defaultto false end newproperty(:frequency) do desc 'The notification reminder frequency' end newproperty(:settings) do desc 'Additional JSON data to configure the notification' validate do |value| - unless value.nil? || value.is_a?(Hash) - raise ArgumentError, 'settings should be a Hash!' - end + raise ArgumentError, 'settings should be a Hash!' unless value.nil? || value.is_a?(Hash) end end autorequire(:service) do 'grafana-server' end autorequire(:grafana_conn_validator) do 'grafana' end end diff --git a/lib/puppet/type/grafana_organization.rb b/lib/puppet/type/grafana_organization.rb index 146a765..cf8fbd2 100644 --- a/lib/puppet/type/grafana_organization.rb +++ b/lib/puppet/type/grafana_organization.rb @@ -1,64 +1,60 @@ +# frozen_string_literal: true + Puppet::Type.newtype(:grafana_organization) do @doc = 'Manage organizations in Grafana' ensurable newparam(:name, namevar: true) do desc 'The name of the organization.' validate do |value| raise ArgumentError, format('Unable to modify default organization') if value == 'Main Org.' end end newparam(:grafana_api_path) do desc 'The absolute path to the API endpoint' defaultto '/api' validate do |value| - unless value =~ %r{^/.*/?api$} - raise ArgumentError, format('%s is not a valid API path', value) - end + raise ArgumentError, format('%s is not a valid API path', value) unless value =~ %r{^/.*/?api$} end end newparam(:grafana_url) do desc 'The URL of the Grafana server' defaultto '' validate do |value| - unless value =~ %r{^https?://} - raise ArgumentError, format('%s is not a valid URL', value) - end + raise ArgumentError, format('%s is not a valid URL', value) unless value =~ %r{^https?://} end end newparam(:grafana_user) do desc 'The username for the Grafana server' end newparam(:grafana_password) do desc 'The password for the Grafana server' end newproperty(:id) do desc 'The ID of the organization' end newproperty(:address) do desc 'Additional JSON data to configure the organization address (optional)' validate do |value| - unless value.nil? || value.is_a?(Hash) - raise ArgumentError, 'address should be a Hash!' - end + raise ArgumentError, 'address should be a Hash!' unless value.nil? || value.is_a?(Hash) end end autorequire(:service) do 'grafana-server' end autorequire(:grafana_conn_validator) do 'grafana' end end diff --git a/lib/puppet/type/grafana_plugin.rb b/lib/puppet/type/grafana_plugin.rb index 6e92801..9e97019 100644 --- a/lib/puppet/type/grafana_plugin.rb +++ b/lib/puppet/type/grafana_plugin.rb @@ -1,61 +1,59 @@ +# frozen_string_literal: true + Puppet::Type.newtype(:grafana_plugin) do - desc <<-DESC -manages grafana plugins + desc <<~DESC + manages grafana plugins -@example Install a grafana plugin - grafana_plugin { 'grafana-simple-json-datasource': } + @example Install a grafana plugin + grafana_plugin { 'grafana-simple-json-datasource': } -@example Install a grafana plugin from different repo - grafana_plugin { 'grafana-simple-json-datasource': - ensure => 'present', - repo => 'https://nexus.company.com/grafana/plugins', - } + @example Install a grafana plugin from different repo + grafana_plugin { 'grafana-simple-json-datasource': + ensure => 'present', + repo => 'https://nexus.company.com/grafana/plugins', + } -@example Install a grafana plugin from a plugin url - grafana_plugin { 'grafana-example-custom-plugin': - ensure => 'present', - plugin_url => 'https://github.com/example/example-custom-plugin/zipball/v1.0.0' - } + @example Install a grafana plugin from a plugin url + grafana_plugin { 'grafana-example-custom-plugin': + ensure => 'present', + plugin_url => 'https://github.com/example/example-custom-plugin/zipball/v1.0.0' + } -@example Uninstall a grafana plugin - grafana_plugin { 'grafana-simple-json-datasource': - ensure => 'absent', - } + @example Uninstall a grafana plugin + grafana_plugin { 'grafana-simple-json-datasource': + ensure => 'absent', + } -@example Show resources - $ puppet resource grafana_plugin -DESC + @example Show resources + $ puppet resource grafana_plugin + DESC ensurable do defaultto(:present) newvalue(:present) do provider.create end newvalue(:absent) do provider.destroy end end newparam(:name, namevar: true) do desc 'The name of the plugin to enable' newvalues(%r{^\S+$}) end newparam(:repo) do desc 'The URL of an internal plugin server' validate do |value| - unless value =~ %r{^https?://} - raise ArgumentError, format('%s is not a valid URL', value) - end + raise ArgumentError, format('%s is not a valid URL', value) unless value =~ %r{^https?://} end end newparam(:plugin_url) do desc 'Full url to the plugin zip file' validate do |value| - unless value =~ %r{^https?://} - raise ArgumentError, format('%s is not a valid URL', value) - end + raise ArgumentError, format('%s is not a valid URL', value) unless value =~ %r{^https?://} end end end diff --git a/lib/puppet/type/grafana_team.rb b/lib/puppet/type/grafana_team.rb index 18209e8..ac9bb58 100644 --- a/lib/puppet/type/grafana_team.rb +++ b/lib/puppet/type/grafana_team.rb @@ -1,84 +1,80 @@ # frozen_string_literal: true Puppet::Type.newtype(:grafana_team) do @doc = 'Manage teams in Grafana' ensurable newparam(:name, namevar: true) do desc 'The name of the team' end newparam(:grafana_api_path) do desc 'The absolute path to the API endpoint' defaultto '/api' validate do |value| - unless value =~ %r{^/.*/?api$} - raise ArgumentError, format('%s is not a valid API path', value) - end + raise ArgumentError, format('%s is not a valid API path', value) unless value =~ %r{^/.*/?api$} end end newparam(:grafana_url) do desc 'The URL of the Grafana server' defaultto '' validate do |value| - unless value =~ %r{^https?://} - raise ArgumentError, format('%s is not a valid URL', value) - end + raise ArgumentError, format('%s is not a valid URL', value) unless value =~ %r{^https?://} end end newparam(:grafana_user) do desc 'The username for the Grafana server' end newparam(:grafana_password) do desc 'The password for the Grafana server' end newparam(:organization) do desc 'The organization the team belongs to' defaultto 'Main Org.' end newparam(:email) do desc 'The email for the team' defaultto '' end newproperty(:home_dashboard_folder) do desc 'The UID or name of the home dashboard folder' end newproperty(:home_dashboard) do desc 'The id or name of the home dashboard' defaultto 'Default' end newproperty(:theme) do desc 'The theme to use for the team' end newproperty(:timezone) do desc 'The timezone to use for the team' end autorequire(:service) do 'grafana-server' end autorequire(:grafana_dashboard) do catalog.resources.select { |r| r.is_a?(Puppet::Type.type(:grafana_dashboard)) } end autorequire(:grafana_organization) do catalog.resources.select { |r| r.is_a?(Puppet::Type.type(:grafana_organization)) } end autorequire(:grafana_conn_validator) do 'grafana' end end diff --git a/lib/puppet/type/grafana_user.rb b/lib/puppet/type/grafana_user.rb index 53beb6c..47b6d7c 100644 --- a/lib/puppet/type/grafana_user.rb +++ b/lib/puppet/type/grafana_user.rb @@ -1,77 +1,75 @@ +# frozen_string_literal: true + Puppet::Type.newtype(:grafana_user) do @doc = 'Manage users in Grafana' ensurable newparam(:name, namevar: true) do desc 'The username of the user.' end newparam(:grafana_api_path) do desc 'The absolute path to the API endpoint' defaultto '/api' validate do |value| - unless value =~ %r{^/.*/?api$} - raise ArgumentError, format('%s is not a valid API path', value) - end + raise ArgumentError, format('%s is not a valid API path', value) unless value =~ %r{^/.*/?api$} end end newparam(:grafana_url) do desc 'The URL of the Grafana server' defaultto '' validate do |value| - unless value =~ %r{^https?://} - raise ArgumentError, format('%s is not a valid URL', value) - end + raise ArgumentError, format('%s is not a valid URL', value) unless value =~ %r{^https?://} end end newparam(:grafana_user) do desc 'The username for the Grafana server' end newparam(:grafana_password) do desc 'The password for the Grafana server' end newparam(:full_name) do desc 'The full name of the user.' end newproperty(:password) do desc 'The password for the user' - def insync?(_is) + def insync?(_is) # rubocop:disable Naming/MethodParameterName provider.check_password end end newproperty(:email) do desc 'The email for the user' end newproperty(:theme) do desc 'The theme for the user' end newproperty(:is_admin) do desc 'Whether the user is a grafana admin' - newvalues(:true, :false) - defaultto :false + newvalues(true, false) + defaultto false end - def set_sensitive_parameters(sensitive_parameters) # rubocop:disable Style/AccessorMethodName + def set_sensitive_parameters(sensitive_parameters) # rubocop:disable Naming/AccessorMethodName parameter(:password).sensitive = true if parameter(:password) super(sensitive_parameters) end autorequire(:service) do 'grafana-server' end autorequire(:grafana_conn_validator) do 'grafana' end end diff --git a/lib/puppet/util/grafana_conn_validator.rb b/lib/puppet/util/grafana_conn_validator.rb index 2f8e97e..129b86d 100644 --- a/lib/puppet/util/grafana_conn_validator.rb +++ b/lib/puppet/util/grafana_conn_validator.rb @@ -1,45 +1,46 @@ +# frozen_string_literal: true + require 'net/http' module Puppet module Util # Validator class, for testing that Grafana is alive class GrafanaConnValidator - attr_reader :grafana_url - attr_reader :grafana_api_path + attr_reader :grafana_url, :grafana_api_path def initialize(grafana_url, grafana_api_path) @grafana_url = grafana_url @grafana_api_path = grafana_api_path end # Utility method; attempts to make an http/https connection to the Grafana server. # This is abstracted out into a method so that it can be called multiple times # for retry attempts. # # @return true if the connection is successful, false otherwise. def attempt_connection # All that we care about is that we are able to connect successfully via # http(s), so here we're simpling hitting a somewhat arbitrary low-impact URL # on the Grafana server. grafana_host = URI.parse(@grafana_url).host grafana_port = URI.parse(@grafana_url).port grafana_scheme = URI.parse(@grafana_url).scheme http = Net::HTTP.new(grafana_host, grafana_port) http.use_ssl = (grafana_scheme == 'https') http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(@grafana_api_path) request.add_field('Accept', 'application/json') response = http.request(request) unless response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPUnauthorized) Puppet.notice "Unable to connect to Grafana server (#{grafana_scheme}://#{grafana_host}:#{grafana_port}): [#{response.code}] #{response.msg}" return false end - return true + true rescue Exception => e # rubocop:disable Lint/RescueException Puppet.notice "Unable to connect to Grafana server (#{grafana_scheme}://#{grafana_host}:#{grafana_port}): #{e.message}" - return false + false end end end end diff --git a/spec/acceptance/class_spec.rb b/spec/acceptance/class_spec.rb index 57dd243..7f127d7 100644 --- a/spec/acceptance/class_spec.rb +++ b/spec/acceptance/class_spec.rb @@ -1,177 +1,180 @@ +# frozen_string_literal: true + require 'spec_helper_acceptance' supported_versions.each do |grafana_version| describe "grafana class with Grafana version #{grafana_version}" do # Create dummy module directorty shell('mkdir -p /etc/puppetlabs/code/environments/production/modules/my_custom_module/files/dashboards') context 'default parameters' do before do install_module_from_forge('puppetlabs/apt', '>= 7.5.0 < 9.0.0') end # Using puppet_apply as a helper + it 'works idempotently with no errors' do pp = <<-EOS class { 'grafana': version => "#{grafana_version}" } EOS prepare_host # Run it twice and test for idempotency apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end describe package('grafana') do it { is_expected.to be_installed } end describe service('grafana-server') do it { is_expected.to be_enabled } it { is_expected.to be_running } end end context 'with fancy dashboard config' do it 'works idempotently with no errors' do pp = <<-EOS class { 'grafana': version => "#{grafana_version}", provisioning_datasources => { apiVersion => 1, datasources => [ { name => 'Prometheus', type => 'prometheus', access => 'proxy', url => 'http://localhost:9090/prometheus', isDefault => false, }, ], }, provisioning_dashboards => { apiVersion => 1, providers => [ { name => 'default', orgId => 1, folder => '', type => 'file', disableDeletion => true, options => { path => '/var/lib/grafana/dashboards', puppetsource => 'puppet:///modules/my_custom_module/dashboards', }, }, ], } } EOS # Run it twice and test for idempotency apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end end context 'with fancy dashboard config and custom target file' do it 'works idempotently with no errors' do pp = <<-EOS class { 'grafana': version => "#{grafana_version}", provisioning_datasources => { apiVersion => 1, datasources => [ { name => 'Prometheus', type => 'prometheus', access => 'proxy', url => 'http://localhost:9090/prometheus', isDefault => false, }, ], }, provisioning_dashboards => { apiVersion => 1, providers => [ { name => 'default', orgId => 1, folder => '', type => 'file', disableDeletion => true, options => { path => '/var/lib/grafana/dashboards', puppetsource => 'puppet:///modules/my_custom_module/dashboards', }, }, ], }, provisioning_dashboards_file => '/etc/grafana/provisioning/dashboards/dashboard.yaml', provisioning_datasources_file => '/etc/grafana/provisioning/datasources/datasources.yaml' } EOS # Run it twice and test for idempotency apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end end end end describe 'grafana class with latest grafana version' do context 'update to beta release' do it 'works idempotently with no errors' do case fact('os.family') when 'Debian' pp = <<-EOS class { 'grafana': version => 'latest', repo_name => 'beta', } EOS when 'RedHat' pp = <<-EOS class { 'grafana': version => 'latest', repo_name => 'beta', } EOS end # Run it twice and test for idempotency apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end describe package('grafana') do it { is_expected.to be_installed } end end context 'revert back to stable' do it 'works idempotently with no errors' do case fact('os.family') when 'Debian' pp = <<-EOS class { 'grafana': version => 'latest', } EOS # Run it twice and test for idempotency apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) when 'RedHat' shell('/bin/rm /etc/yum.repos.d/grafana-beta.repo') shell('yum -y downgrade grafana') # No manifest to apply here end end describe package('grafana') do it { is_expected.to be_installed } end end end diff --git a/spec/acceptance/grafana_folder_spec.rb b/spec/acceptance/grafana_folder_spec.rb index bb951e1..3ab67fd 100644 --- a/spec/acceptance/grafana_folder_spec.rb +++ b/spec/acceptance/grafana_folder_spec.rb @@ -1,201 +1,207 @@ +# frozen_string_literal: true + require 'spec_helper_acceptance' supported_versions.each do |grafana_version| describe "grafana_folder with Grafana version #{grafana_version}" do context 'setup grafana server' do it 'runs successfully' do pp = <<-EOS class { 'grafana': version => "#{grafana_version}", cfg => { security => { admin_user => 'admin', admin_password => 'admin' } } } EOS prepare_host apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end end context 'create folder resource' do it 'creates the folders' do pp = <<-EOS include grafana::validator grafana_folder { 'example-folder': ensure => present, uid => 'example-folder', grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', permissions => [ {'permission' => 2, 'role' => 'Editor'}, {'permission' => 1, 'role' => 'Viewer'}, ], } grafana_folder { 'editor-folder': ensure => present, uid => 'editor-folder', grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', permissions => [ {'permission' => 1, 'role' => 'Editor'}, ], } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has created the example folder' do shell('curl --user admin:admin http://localhost:3000/api/folders') do |f| expect(f.stdout).to match(%r{example-folder}) end end + it 'has created the editor folder' do shell('curl --user admin:admin http://localhost:3000/api/folders') do |f| expect(f.stdout).to match(%r{editor-folder}) end end + it 'has created the example folder permissions' do shell('curl --user admin:admin http://localhost:3000/api/folders/example-folder/permissions') do |f| data = JSON.parse(f.stdout) expect(data).to include(hash_including('permission' => 2, 'role' => 'Editor'), hash_including('permission' => 1, 'role' => 'Viewer')) end end + it 'has created the editor folder permissions' do shell('curl --user admin:admin http://localhost:3000/api/folders/editor-folder/permissions') do |f| data = JSON.parse(f.stdout) expect(data).to include(hash_including('permission' => 1, 'role' => 'Editor')) end end end context 'updates folder resource' do it 'updates the folders' do pp = <<-EOS grafana_folder { 'example-folder': ensure => present, uid => 'example-folder', grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', permissions => [ {'permission' => 2, 'role' => 'Editor'}, ], } grafana_folder { 'editor-folder': ensure => present, uid => 'editor-folder', grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', permissions => [ {'permission' => 1, 'role' => 'Viewer'}, ], } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has updated the example folder permissions' do shell('curl --user admin:admin http://localhost:3000/api/folders/example-folder/permissions') do |f| data = JSON.parse(f.stdout) expect(data).to include(hash_including('permission' => 2, 'role' => 'Editor')) # expect(data.size).to eq(1) # expect(data[0]['permission']).to eq(2) # expect(data[0]['role']).to eq('Editor') end end + it 'has updated the editor folder permissions' do shell('curl --user admin:admin http://localhost:3000/api/folders/editor-folder/permissions') do |f| data = JSON.parse(f.stdout) expect(data).to include(hash_including('permission' => 1, 'role' => 'Viewer')) end end end context 'create folder containing dashboard' do it 'creates an example dashboard in the example folder' do pp = <<-EOS include grafana::validator grafana_dashboard { 'example-dashboard': ensure => present, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', content => '{"description": "example dashboard"}', folder => 'example-folder' } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'folder contains dashboard' do shell('curl --user admin:admin http://localhost:3000/api/search?query=example-dashboard') do |f| expect(f.stdout).to match(%r{"folderId":1}) end end end context 'destroy resources' do it 'destroys the folders and dashboard' do pp = <<-EOS include grafana::validator grafana_folder { 'example-folder': ensure => absent, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } grafana_folder { 'editor-folder': ensure => absent, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } grafana_folder { 'nomatch-folder': ensure => absent, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } grafana_dashboard { 'example-dashboard': ensure => absent, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has no example-folder' do shell('curl --user admin:admin http://localhost:3000/api/folders') do |f| expect(f.stdout).not_to match(%r{example-folder}) end end it 'has no editor-folder' do shell('curl --user admin:admin http://localhost:3000/api/folders') do |f| expect(f.stdout).not_to match(%r{editor-folder}) end end it 'has no nomatch-folder' do shell('curl --user admin:admin http://localhost:3000/api/folders') do |f| expect(f.stdout).not_to match(%r{nomatch-folder}) end end end end end diff --git a/spec/acceptance/grafana_plugin_spec.rb b/spec/acceptance/grafana_plugin_spec.rb index 38c081e..1a9ae12 100644 --- a/spec/acceptance/grafana_plugin_spec.rb +++ b/spec/acceptance/grafana_plugin_spec.rb @@ -1,97 +1,99 @@ +# frozen_string_literal: true + require 'spec_helper_acceptance' supported_versions.each do |grafana_version| describe "grafana_plugin with Grafana version #{grafana_version}" do context 'create plugin resource' do it 'runs successfully' do pp = <<-EOS class { 'grafana': version => "#{grafana_version}" } include grafana::validator grafana_plugin { 'grafana-simple-json-datasource': } EOS prepare_host apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has the plugin' do shell('grafana-cli plugins ls') do |r| expect(r.stdout).to match(%r{grafana-simple-json-datasource}) end end end context 'create plugin resource with repo' do it 'runs successfully' do pp = <<-EOS class { 'grafana': version => "#{grafana_version}" } include grafana::validator grafana_plugin { 'grafana-simple-json-datasource': ensure => present, repo => 'https://nexus.company.com/grafana/plugins', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has the plugin' do shell('grafana-cli plugins ls') do |r| expect(r.stdout).to match(%r{grafana-simple-json-datasource}) end end end context 'create plugin resource with url' do it 'runs successfully' do # Reset and reinstall the same plugin by URL shell('grafana-cli plugins uninstall grafana-simple-json-datasource') pp = <<-EOS class { 'grafana': version => "#{grafana_version}" } include grafana::validator grafana_plugin { 'grafana-simple-json-datasource': ensure => 'present', plugin_url => 'https://grafana.com/api/plugins/grafana-simple-json-datasource/versions/latest/download', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has the plugin' do shell('grafana-cli plugins ls') do |r| expect(r.stdout).to match(%r{grafana-simple-json-datasource}) end end end context 'destroy plugin resource' do it 'runs successfully' do pp = <<-EOS class { 'grafana': version => "#{grafana_version}" } include grafana::validator grafana_plugin { 'grafana-simple-json-datasource': ensure => absent, } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'does not have the plugin' do shell('grafana-cli plugins ls') do |r| expect(r.stdout).not_to match(%r{grafana-simple-json-datasource}) end end end end end diff --git a/spec/acceptance/grafana_team_spec.rb b/spec/acceptance/grafana_team_spec.rb index e066323..781e5b3 100644 --- a/spec/acceptance/grafana_team_spec.rb +++ b/spec/acceptance/grafana_team_spec.rb @@ -1,213 +1,215 @@ +# frozen_string_literal: true + require 'spec_helper_acceptance' supported_versions.each do |grafana_version| describe "grafana_team wth Grafana version #{grafana_version}" do context 'setup grafana server' do it 'runs successfully' do pp = <<-EOS class { 'grafana': version => "#{grafana_version}", cfg => { security => { admin_user => 'admin', admin_password => 'admin' } } } EOS prepare_host apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end end context 'create team resource on `Main Org.`' do it 'creates the team' do pp = <<-EOS include grafana::validator grafana_team { 'example-team': ensure => present, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has created the example team' do shell('curl --user admin:admin http://localhost:3000/api/teams/search?name=example-team') do |f| expect(f.stdout).to match(%r{example-team}) end end it 'has set default home dashboard' do shell('curl --user admin:admin http://localhost:3000/api/teams/1/preferences') do |f| data = JSON.parse(f.stdout) expect(data).to include('homeDashboardId' => 0) end end end context 'updates team resource' do it 'creates dashboard and sets team home dashboard' do pp = <<-EOS include grafana::validator grafana_dashboard { 'example-dashboard': ensure => present, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', content => '{"description": "example dashboard"}', } grafana_folder { 'example-folder': ensure => present, uid => 'example-folder', grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } -> grafana_dashboard { 'example-dashboard2': ensure => present, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', content => '{"description": "example dashboard2"}', folder => 'example-folder', } grafana_team { 'example-team': ensure => present, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', home_dashboard => 'example-dashboard', } grafana_team { 'example-team2': ensure => present, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', home_dashboard_folder => 'example-folder', home_dashboard => 'example-dashboard2', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has updated the example team home dashboard' do shell('curl --user admin:admin http://localhost:3000/api/teams/1/preferences') do |f| data = JSON.parse(f.stdout) expect(data['homeDashboardId']).not_to eq(0) end end it 'has updated the example team home dashboard with folder' do shell('curl --user admin:admin http://localhost:3000/api/teams/2/preferences') do |f| data = JSON.parse(f.stdout) expect(data['homeDashboardId']).not_to eq(0) end end end context 'create team resource on seperate organization' do it 'creates organization and team' do pp = <<-EOS include grafana::validator grafana_organization { 'example-organization': ensure => present, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } grafana_team { 'example-team-on-org': ensure => present, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', organization => 'example-organization', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'creates team on organization' do shell('curl --user admin:admin -X POST http://localhost:3000/api/user/using/2 && '\ - 'curl --user admin:admin http://localhost:3000/api/teams/search?name=example-team-on-org') do |f| + 'curl --user admin:admin http://localhost:3000/api/teams/search?name=example-team-on-org') do |f| expect(f.stdout).to match(%r{example-team-on-org}) end end end context 'destroy resources' do it 'destroys the teams, dashboard, and organization' do pp = <<-EOS include grafana::validator grafana_team { 'example-team': ensure => absent, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } grafana_team { 'example-team2': ensure => absent, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } grafana_team { 'example-team-on-org': ensure => absent, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', organization => 'example-organization', } grafana_dashboard { 'example-dashboard': ensure => absent, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } grafana_dashboard { 'example-dashboard2': ensure => absent, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } grafana_folder { 'example-folder': ensure => absent, uid => 'example-folder', grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } grafana_organization { 'example-organization': ensure => absent, grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end it 'has no example-team' do shell('curl --user admin:admin -X POST http://localhost:3000/api/user/using/1 && '\ - 'curl --user admin:admin http://localhost:3000/api/teams/search') do |f| + 'curl --user admin:admin http://localhost:3000/api/teams/search') do |f| expect(f.stdout).not_to match(%r{example-team}) end end it 'has no example-team-on-org' do shell('curl --user admin:admin -X POST http://localhost:3000/api/user/using/2 && '\ - 'curl --user admin:admin http://localhost:3000/api/teams') do |f| + 'curl --user admin:admin http://localhost:3000/api/teams') do |f| expect(f.stdout).not_to match(%r{example-team-on-org}) end end end end end diff --git a/spec/acceptance/grafana_user_spec.rb b/spec/acceptance/grafana_user_spec.rb index a094e34..a808ebd 100644 --- a/spec/acceptance/grafana_user_spec.rb +++ b/spec/acceptance/grafana_user_spec.rb @@ -1,40 +1,43 @@ +# frozen_string_literal: true + require 'spec_helper_acceptance' supported_versions.each do |grafana_version| describe "grafana_user with Grafana version #{grafana_version}" do prepare_host context 'setup grafana server' do it 'runs successfully' do pp = <<-EOS class { 'grafana': version => "#{grafana_version}", cfg => { security => { admin_user => 'admin', admin_password => 'admin' } } } EOS prepare_host apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end end + it 'runs successfully' do pp = <<-EOS grafana_user { 'user1': grafana_url => 'http://localhost:3000', grafana_user => 'admin', grafana_password => 'admin', full_name => 'John Doe', password => 'Us3r5ecret', email => 'john@example.com', } EOS apply_manifest(pp, catch_failures: true) apply_manifest(pp, catch_changes: true) end end end diff --git a/spec/classes/grafana_spec.rb b/spec/classes/grafana_spec.rb index aff6bde..934bee0 100644 --- a/spec/classes/grafana_spec.rb +++ b/spec/classes/grafana_spec.rb @@ -1,470 +1,467 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'grafana' do on_supported_os.each do |os, facts| context "on #{os}" do let(:facts) do facts end context 'with default values' do it { is_expected.to compile.with_all_deps } it { is_expected.to contain_class('grafana') } it { is_expected.to contain_class('grafana::install').that_comes_before('Class[grafana::config]') } it { is_expected.to contain_class('grafana::config').that_notifies('Class[grafana::service]') } it { is_expected.to contain_class('grafana::service') } end + # rubocop:disable RSpec/EmptyExampleGroup context 'with parameter install_method is set to package' do let(:params) do { install_method: 'package', version: '5.4.2' } end case facts[:osfamily] when 'Debian' download_location = '/tmp/grafana.deb' describe 'use archive to fetch the package to a temporary location' do it do - is_expected.to contain_archive('/tmp/grafana.deb').with_source( + expect(subject).to contain_archive('/tmp/grafana.deb').with_source( 'https://dl.grafana.com/oss/release/grafana_5.4.2_amd64.deb' ) end + it { is_expected.to contain_archive('/tmp/grafana.deb').that_comes_before('Package[grafana]') } end describe 'install dependencies first' do it { is_expected.to contain_package('libfontconfig1').with_ensure('present').that_comes_before('Package[grafana]') } end describe 'install the package' do it { is_expected.to contain_package('grafana').with_provider('dpkg') } it { is_expected.to contain_package('grafana').with_source(download_location) } end when 'RedHat' describe 'install dependencies first' do it { is_expected.to contain_package('fontconfig').with_ensure('present').that_comes_before('Package[grafana]') } end describe 'install the package' do it { is_expected.to contain_package('grafana').with_provider('rpm') } end end end context 'with some plugins passed in' do let(:params) do { plugins: { 'grafana-wizzle' => { 'ensure' => 'present' }, 'grafana-woozle' => { 'ensure' => 'absent' }, 'grafana-plugin' => { 'ensure' => 'present', 'repo' => 'https://nexus.company.com/grafana/plugins' }, 'grafana-plugin-url' => { 'ensure' => 'present', 'plugin_url' => 'https://grafana.com/api/plugins/grafana-simple-json-datasource/versions/latest/download' } } } end it { is_expected.to contain_grafana_plugin('grafana-wizzle').with(ensure: 'present') } it { is_expected.to contain_grafana_plugin('grafana-woozle').with(ensure: 'absent').that_notifies('Class[grafana::service]') } describe 'install plugin with plugin repo' do it { is_expected.to contain_grafana_plugin('grafana-plugin').with(ensure: 'present', repo: 'https://nexus.company.com/grafana/plugins') } end describe 'install plugin with plugin url' do it { is_expected.to contain_grafana_plugin('grafana-plugin-url').with(ensure: 'present', plugin_url: 'https://grafana.com/api/plugins/grafana-simple-json-datasource/versions/latest/download') } end end context 'with parameter install_method is set to repo' do let(:params) do { install_method: 'repo' } end case facts[:osfamily] when 'Debian' describe 'install apt repo dependencies first' do it { is_expected.to contain_class('apt') } it { is_expected.to contain_apt__source('grafana').with(release: 'stable', repos: 'main', location: 'https://packages.grafana.com/oss/deb') } it { is_expected.to contain_apt__source('grafana').that_comes_before('Package[grafana]') } end describe 'install dependencies first' do it { is_expected.to contain_package('libfontconfig1').with_ensure('present').that_comes_before('Package[grafana]') } end describe 'install the package' do it { is_expected.to contain_package('grafana').with_ensure('installed') } end when 'RedHat' describe 'yum repo dependencies first' do it { is_expected.to contain_yumrepo('grafana-stable').with(baseurl: 'https://packages.grafana.com/oss/rpm', gpgkey: 'https://packages.grafana.com/gpg.key', enabled: 1) } it { is_expected.to contain_yumrepo('grafana-stable').that_comes_before('Package[grafana]') } end describe 'install dependencies first' do it { is_expected.to contain_package('fontconfig').with_ensure('present').that_comes_before('Package[grafana]') } end describe 'install the package' do it { is_expected.to contain_package('grafana').with_ensure('installed') } end end end context 'with parameter install_method is set to repo and manage_package_repo is set to false' do let(:params) do { install_method: 'repo', manage_package_repo: false, version: 'present' } end case facts[:osfamily] when 'Debian' describe 'install dependencies first' do it { is_expected.to contain_package('libfontconfig1').with_ensure('present').that_comes_before('Package[grafana]') } end describe 'install the package' do it { is_expected.to contain_package('grafana').with_ensure('present') } end when 'RedHat' describe 'install dependencies first' do it { is_expected.to contain_package('fontconfig').with_ensure('present').that_comes_before('Package[grafana]') } end describe 'install the package' do it { is_expected.to contain_package('grafana').with_ensure('present') } end when 'Archlinux' describe 'install the package' do it { is_expected.to contain_package('grafana').with_ensure('present') } end end end context 'with parameter install_method is set to archive' do let(:params) do { install_method: 'archive', version: '5.4.2' } end install_dir = '/usr/share/grafana' service_config = '/usr/share/grafana/conf/custom.ini' archive_source = 'https://dl.grafana.com/oss/release/grafana-5.4.2.linux-amd64.tar.gz' describe 'extract archive to install_dir' do it { is_expected.to contain_archive('/tmp/grafana.tar.gz').with_ensure('present') } it { is_expected.to contain_archive('/tmp/grafana.tar.gz').with_source(archive_source) } it { is_expected.to contain_archive('/tmp/grafana.tar.gz').with_extract_path(install_dir) } end describe 'create grafana user' do it { is_expected.to contain_user('grafana').with_ensure('present').with_home(install_dir) } it { is_expected.to contain_user('grafana').that_comes_before('File[/usr/share/grafana]') } end case facts[:osfamily] - when 'Archlinux' - describe 'create data_dir' do - it { is_expected.to contain_file('/var/lib/grafana').with_ensure('directory') } - end - when 'Debian' + when 'Archlinux', 'Debian', 'RedHat' describe 'create data_dir' do it { is_expected.to contain_file('/var/lib/grafana').with_ensure('directory') } end when 'FreBSD' describe 'create data_dir' do it { is_expected.to contain_file('/var/db/grafana').with_ensure('directory') } end - when 'RedHat' - describe 'create data_dir' do - it { is_expected.to contain_file('/var/lib/grafana').with_ensure('directory') } - end end describe 'manage install_dir' do it { is_expected.to contain_file(install_dir).with_ensure('directory') } it { is_expected.to contain_file(install_dir).with_group('grafana').with_owner('grafana') } end describe 'configure grafana' do it { is_expected.to contain_file(service_config).with_ensure('file') } end describe 'run grafana as service' do it { is_expected.to contain_service('grafana').with_ensure('running').with_provider('base') } it { is_expected.to contain_service('grafana').with_hasrestart(false).with_hasstatus(false) } end context 'when user already defined' do let(:pre_condition) do 'user{"grafana": ensure => present, }' end describe 'do NOT create grafana user' do it { is_expected.not_to contain_user('grafana').with_ensure('present').with_home(install_dir) } end end context 'when service already defined' do let(:pre_condition) do 'service{"grafana": ensure => running, name => "grafana-server", hasrestart => true, hasstatus => true, }' end describe 'do NOT run service' do it { is_expected.not_to contain_service('grafana').with_hasrestart(false).with_hasstatus(false) } end end end context 'invalid parameters' do context 'cfg' do describe 'should not raise an error when cfg parameter is a hash' do let(:params) do { cfg: {} } end it { is_expected.to contain_package('grafana') } end end end context 'configuration file' do describe 'should not contain any configuration when cfg param is empty' do it { is_expected.to contain_file('grafana.ini').with_content("# This file is managed by Puppet, any changes will be overwritten\n\n") } end describe 'should correctly transform cfg param entries to Grafana configuration' do let(:params) do { cfg: { 'app_mode' => 'production', - 'section' => { - 'string' => 'production', - 'number' => 8080, + 'section' => { + 'string' => 'production', + 'number' => 8080, 'boolean' => false, - 'empty' => '' + 'empty' => '' } }, ldap_cfg: { 'servers' => [ { 'host' => 'server1', - 'use_ssl' => true, - 'search_filter' => '(sAMAccountName=%s)', + 'use_ssl' => true, + 'search_filter' => '(sAMAccountName=%s)', 'search_base_dns' => ['dc=domain1,dc=com'] } ], 'servers.attributes' => { - 'name' => 'givenName', - 'surname' => 'sn', - 'username' => 'sAMAccountName', + 'name' => 'givenName', + 'surname' => 'sn', + 'username' => 'sAMAccountName', 'member_of' => 'memberOf', - 'email' => 'email' + 'email' => 'email' } } } end expected = "# This file is managed by Puppet, any changes will be overwritten\n\n"\ "app_mode = production\n\n"\ "[section]\n"\ "boolean = false\n"\ "empty = \n"\ "number = 8080\n"\ "string = production\n" it { is_expected.to contain_file('grafana.ini').with_content(expected) } ldap_expected = "\n[[servers]]\n"\ - "host = \"server1\"\n"\ - "search_base_dns = [\"dc=domain1,dc=com\"]\n"\ - "search_filter = \"(sAMAccountName=%s)\"\n"\ - "use_ssl = true\n"\ - "\n"\ - "[servers.attributes]\n"\ - "email = \"email\"\n"\ - "member_of = \"memberOf\"\n"\ - "name = \"givenName\"\n"\ - "surname = \"sn\"\n"\ - "username = \"sAMAccountName\"\n"\ - "\n" + "host = \"server1\"\n"\ + "search_base_dns = [\"dc=domain1,dc=com\"]\n"\ + "search_filter = \"(sAMAccountName=%s)\"\n"\ + "use_ssl = true\n"\ + "\n"\ + "[servers.attributes]\n"\ + "email = \"email\"\n"\ + "member_of = \"memberOf\"\n"\ + "name = \"givenName\"\n"\ + "surname = \"sn\"\n"\ + "username = \"sAMAccountName\"\n"\ + "\n" it { is_expected.to contain_file('/etc/grafana/ldap.toml').with_content(ldap_expected) } end end context 'multiple ldap configuration' do describe 'should correctly transform ldap config param into Grafana ldap.toml' do let(:params) do { cfg: {}, ldap_cfg: [ { 'servers' => [ { 'host' => 'server1a server1b', - 'use_ssl' => true, - 'search_filter' => '(sAMAccountName=%s)', + 'use_ssl' => true, + 'search_filter' => '(sAMAccountName=%s)', 'search_base_dns' => ['dc=domain1,dc=com'] } ], 'servers.attributes' => { - 'name' => 'givenName', - 'surname' => 'sn', - 'username' => 'sAMAccountName', + 'name' => 'givenName', + 'surname' => 'sn', + 'username' => 'sAMAccountName', 'member_of' => 'memberOf', - 'email' => 'email' + 'email' => 'email' } }, { 'servers' => [ { 'host' => 'server2a server2b', - 'use_ssl' => true, - 'search_filter' => '(sAMAccountName=%s)', + 'use_ssl' => true, + 'search_filter' => '(sAMAccountName=%s)', 'search_base_dns' => ['dc=domain2,dc=com'] } ], 'servers.attributes' => { - 'name' => 'givenName', - 'surname' => 'sn', - 'username' => 'sAMAccountName', + 'name' => 'givenName', + 'surname' => 'sn', + 'username' => 'sAMAccountName', 'member_of' => 'memberOf', - 'email' => 'email' + 'email' => 'email' } } ] } end ldap_expected = "\n[[servers]]\n"\ - "host = \"server1a server1b\"\n"\ - "search_base_dns = [\"dc=domain1,dc=com\"]\n"\ - "search_filter = \"(sAMAccountName=%s)\"\n"\ - "use_ssl = true\n"\ - "\n"\ - "[servers.attributes]\n"\ - "email = \"email\"\n"\ - "member_of = \"memberOf\"\n"\ - "name = \"givenName\"\n"\ - "surname = \"sn\"\n"\ - "username = \"sAMAccountName\"\n"\ - "\n"\ - "\n[[servers]]\n"\ - "host = \"server2a server2b\"\n"\ - "search_base_dns = [\"dc=domain2,dc=com\"]\n"\ - "search_filter = \"(sAMAccountName=%s)\"\n"\ - "use_ssl = true\n"\ - "\n"\ - "[servers.attributes]\n"\ - "email = \"email\"\n"\ - "member_of = \"memberOf\"\n"\ - "name = \"givenName\"\n"\ - "surname = \"sn\"\n"\ - "username = \"sAMAccountName\"\n"\ - "\n" + "host = \"server1a server1b\"\n"\ + "search_base_dns = [\"dc=domain1,dc=com\"]\n"\ + "search_filter = \"(sAMAccountName=%s)\"\n"\ + "use_ssl = true\n"\ + "\n"\ + "[servers.attributes]\n"\ + "email = \"email\"\n"\ + "member_of = \"memberOf\"\n"\ + "name = \"givenName\"\n"\ + "surname = \"sn\"\n"\ + "username = \"sAMAccountName\"\n"\ + "\n"\ + "\n[[servers]]\n"\ + "host = \"server2a server2b\"\n"\ + "search_base_dns = [\"dc=domain2,dc=com\"]\n"\ + "search_filter = \"(sAMAccountName=%s)\"\n"\ + "use_ssl = true\n"\ + "\n"\ + "[servers.attributes]\n"\ + "email = \"email\"\n"\ + "member_of = \"memberOf\"\n"\ + "name = \"givenName\"\n"\ + "surname = \"sn\"\n"\ + "username = \"sAMAccountName\"\n"\ + "\n" it { is_expected.to contain_file('/etc/grafana/ldap.toml').with_content(ldap_expected) } end end context 'provisioning_dashboards defined' do let(:params) do { version: '6.0.0', provisioning_dashboards: { apiVersion: 1, providers: [ { name: 'default', orgId: 1, folder: '', type: 'file', disableDeletion: true, options: { path: '/var/lib/grafana/dashboards', puppetsource: 'puppet:///modules/my_custom_module/dashboards' } } ] } } end it do - is_expected.to contain_file('/var/lib/grafana/dashboards').with( + expect(subject).to contain_file('/var/lib/grafana/dashboards').with( ensure: 'directory', owner: 'grafana', group: 'grafana', mode: '0750', recurse: true, purge: true, source: 'puppet:///modules/my_custom_module/dashboards' ) end context 'without puppetsource defined' do let(:params) do { version: '6.0.0', provisioning_dashboards: { apiVersion: 1, providers: [ { name: 'default', orgId: 1, folder: '', type: 'file', disableDeletion: true, options: { path: '/var/lib/grafana/dashboards' } } ] } } end it { is_expected.not_to contain_file('/var/lib/grafana/dashboards') } end end context 'sysconfig environment variables' do let(:params) do { install_method: 'repo', sysconfig: { http_proxy: 'http://proxy.example.com/' } } end case facts[:osfamily] when 'Debian' describe 'Add the environment variable to the config file' do it { is_expected.to contain_augeas('sysconfig/grafana-server').with_context('/files/etc/default/grafana-server') } it { is_expected.to contain_augeas('sysconfig/grafana-server').with_changes(['set http_proxy http://proxy.example.com/']) } end when 'RedHat' describe 'Add the environment variable to the config file' do it { is_expected.to contain_augeas('sysconfig/grafana-server').with_context('/files/etc/sysconfig/grafana-server') } it { is_expected.to contain_augeas('sysconfig/grafana-server').with_changes(['set http_proxy http://proxy.example.com/']) } end end end + # rubocop:enable RSpec/EmptyExampleGroup end end end diff --git a/spec/grafana_dashboard_permission_type_spec.rb b/spec/grafana_dashboard_permission_type_spec.rb index ebb4fc6..9b35400 100644 --- a/spec/grafana_dashboard_permission_type_spec.rb +++ b/spec/grafana_dashboard_permission_type_spec.rb @@ -1,72 +1,74 @@ +# frozen_string_literal: true + require 'spec_helper' describe Puppet::Type.type(:grafana_dashboard_permission) do let(:gpermission) do described_class.new( title: 'foo_title', grafana_url: 'http://example.com/', grafana_api_path: '/api', user: 'foo_user', dashboard: 'foo_dashboard', permission: 'View', ensure: :present ) end context 'when setting parameters' do it "fails if grafana_url isn't HTTP-based" do expect do described_class.new title: 'foo_title', name: 'foo', grafana_url: 'example.com', ensure: :present end.to raise_error(Puppet::Error, %r{not a valid URL}) end it "fails if grafana_api_path isn't properly formed" do expect do described_class.new title: 'foo_title', grafana_url: 'http://example.com', grafana_api_path: '/invalidpath', ensure: :present end.to raise_error(Puppet::Error, %r{not a valid API path}) end it 'fails if both user and team set' do expect do described_class.new title: 'foo title', user: 'foo_user', team: 'foo_team' end.to raise_error(Puppet::Error, %r{Only user or team can be set, not both}) end + it 'accepts valid parameters' do expect(gpermission[:user]).to eq('foo_user') expect(gpermission[:grafana_api_path]).to eq('/api') expect(gpermission[:grafana_url]).to eq('http://example.com/') expect(gpermission[:dashboard]).to eq('foo_dashboard') end - # rubocop:enable RSpec/MultipleExpectations it 'autorequires the grafana-server for proper ordering' do catalog = Puppet::Resource::Catalog.new service = Puppet::Type.type(:service).new(name: 'grafana-server') catalog.add_resource service catalog.add_resource gpermission relationship = gpermission.autorequire.find do |rel| (rel.source.to_s == 'Service[grafana-server]') && (rel.target.to_s == gpermission.to_s) end expect(relationship).to be_a Puppet::Relationship end it 'does not autorequire the service it is not managed' do catalog = Puppet::Resource::Catalog.new catalog.add_resource gpermission expect(gpermission.autorequire).to be_empty end it 'autorequires grafana_conn_validator' do catalog = Puppet::Resource::Catalog.new validator = Puppet::Type.type(:grafana_conn_validator).new(name: 'grafana') catalog.add_resource validator catalog.add_resource gpermission relationship = gpermission.autorequire.find do |rel| (rel.source.to_s == 'Grafana_conn_validator[grafana]') && (rel.target.to_s == gpermission.to_s) end expect(relationship).to be_a Puppet::Relationship end end end diff --git a/spec/grafana_membership_type_spec.rb b/spec/grafana_membership_type_spec.rb index 4886757..718441d 100644 --- a/spec/grafana_membership_type_spec.rb +++ b/spec/grafana_membership_type_spec.rb @@ -1,74 +1,76 @@ +# frozen_string_literal: true + require 'spec_helper' describe Puppet::Type.type(:grafana_membership) do let(:gmembership) do described_class.new( title: 'foo_title', user_name: 'foo_user', target_name: 'foo_target', grafana_url: 'http://example.com/', grafana_api_path: '/api', membership_type: 'organization', role: 'Viewer', ensure: :present ) end context 'when setting parameters' do it "fails if grafana_url isn't HTTP-based" do expect do described_class.new title: 'foo_title', name: 'foo', grafana_url: 'example.com', ensure: :present end.to raise_error(Puppet::Error, %r{not a valid URL}) end it "fails if grafana_api_path isn't properly formed" do expect do described_class.new title: 'foo_title', grafana_url: 'http://example.com', grafana_api_path: '/invalidpath', ensure: :present end.to raise_error(Puppet::Error, %r{not a valid API path}) end it 'fails if membership type not valid' do expect do described_class.new title: 'foo title', membership_type: 'foo' end.to raise_error(Puppet::Error, %r{Invalid value "foo"}) end + it 'accepts valid parameters' do expect(gmembership[:user_name]).to eq('foo_user') expect(gmembership[:target_name]).to eq('foo_target') expect(gmembership[:grafana_api_path]).to eq('/api') expect(gmembership[:grafana_url]).to eq('http://example.com/') expect(gmembership[:membership_type]).to eq(:organization) end - # rubocop:enable RSpec/MultipleExpectations it 'autorequires the grafana-server for proper ordering' do catalog = Puppet::Resource::Catalog.new service = Puppet::Type.type(:service).new(name: 'grafana-server') catalog.add_resource service catalog.add_resource gmembership relationship = gmembership.autorequire.find do |rel| (rel.source.to_s == 'Service[grafana-server]') && (rel.target.to_s == gmembership.to_s) end expect(relationship).to be_a Puppet::Relationship end it 'does not autorequire the service it is not managed' do catalog = Puppet::Resource::Catalog.new catalog.add_resource gmembership expect(gmembership.autorequire).to be_empty end it 'autorequires grafana_conn_validator' do catalog = Puppet::Resource::Catalog.new validator = Puppet::Type.type(:grafana_conn_validator).new(name: 'grafana') catalog.add_resource validator catalog.add_resource gmembership relationship = gmembership.autorequire.find do |rel| (rel.source.to_s == 'Grafana_conn_validator[grafana]') && (rel.target.to_s == gmembership.to_s) end expect(relationship).to be_a Puppet::Relationship end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fb5f0cb..4d617f3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,17 +1,17 @@ +# frozen_string_literal: true + # Managed by modulesync - DO NOT EDIT # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ # puppetlabs_spec_helper will set up coverage if the env variable is set. # We want to do this if lib exists and it hasn't been explicitly set. -ENV['COVERAGE'] ||= 'yes' if Dir.exist?(File.expand_path('../../lib', __FILE__)) +ENV['COVERAGE'] ||= 'yes' if Dir.exist?(File.expand_path('../lib', __dir__)) require 'voxpupuli/test/spec_helper' if File.exist?(File.join(__dir__, 'default_module_facts.yml')) facts = YAML.safe_load(File.read(File.join(__dir__, 'default_module_facts.yml'))) - if facts - facts.each do |name, value| - add_custom_fact name.to_sym, value - end + facts&.each do |name, value| + add_custom_fact name.to_sym, value end end diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index d3b906b..d3a6e23 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + # Managed by modulesync - DO NOT EDIT # https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ require 'voxpupuli/acceptance/spec_helper_acceptance' configure_beaker Dir['./spec/support/acceptance/**/*.rb'].sort.each { |f| require f } diff --git a/spec/support/acceptance/prepare_host.rb b/spec/support/acceptance/prepare_host.rb index 996f5ae..420f554 100644 --- a/spec/support/acceptance/prepare_host.rb +++ b/spec/support/acceptance/prepare_host.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + def prepare_host cleanup_script = <<-SHELL /opt/puppetlabs/bin/puppet resource package grafana ensure=purged rm -rf /var/lib/grafana/ SHELL shell(cleanup_script) end diff --git a/spec/support/acceptance/supported_versions.rb b/spec/support/acceptance/supported_versions.rb index 71c754d..8ef388f 100644 --- a/spec/support/acceptance/supported_versions.rb +++ b/spec/support/acceptance/supported_versions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + def supported_versions %w[6.0.0 7.0.0 8.0.0] end diff --git a/spec/unit/puppet/provider/grafana_plugin/grafana_cli_spec.rb b/spec/unit/puppet/provider/grafana_plugin/grafana_cli_spec.rb index af34ab1..287f222 100644 --- a/spec/unit/puppet/provider/grafana_plugin/grafana_cli_spec.rb +++ b/spec/unit/puppet/provider/grafana_plugin/grafana_cli_spec.rb @@ -1,87 +1,87 @@ +# frozen_string_literal: true + require 'spec_helper' provider_class = Puppet::Type.type(:grafana_plugin).provider(:grafana_cli) describe provider_class do let(:resource) do Puppet::Type::Grafana_plugin.new( name: 'grafana-wizzle' ) end let(:provider) { provider_class.new(resource) } describe '#instances' do let(:plugins_ls_two) do - <<-PLUGINS -installed plugins: -grafana-simple-json-datasource @ 1.3.4 -jdbranham-diagram-panel @ 1.4.0 + <<~PLUGINS + installed plugins: + grafana-simple-json-datasource @ 1.3.4 + jdbranham-diagram-panel @ 1.4.0 -Restart grafana after installing plugins . + Restart grafana after installing plugins . PLUGINS - # rubocop:enable Layout/TrailingWhitespace end let(:plugins_ls_none) do - <<-PLUGINS + <<~PLUGINS -Restart grafana after installing plugins . + Restart grafana after installing plugins . PLUGINS end it 'has the correct names' do allow(provider_class).to receive(:grafana_cli).with('plugins', 'ls').and_return(plugins_ls_two) - expect(provider_class.instances.map(&:name)).to match_array(['grafana-simple-json-datasource', 'jdbranham-diagram-panel']) + expect(provider_class.instances.map(&:name)).to match_array(%w[grafana-simple-json-datasource jdbranham-diagram-panel]) expect(provider_class).to have_received(:grafana_cli) end it 'does not match if there are no plugins' do allow(provider_class).to receive(:grafana_cli).with('plugins', 'ls').and_return(plugins_ls_none) expect(provider_class.instances.size).to eq(0) expect(provider.exists?).to eq(false) expect(provider_class).to have_received(:grafana_cli) end - # rubocop:enable RSpec/MultipleExpectations end it '#create' do allow(provider).to receive(:grafana_cli) provider.create expect(provider).to have_received(:grafana_cli).with('plugins', 'install', 'grafana-wizzle') end it '#destroy' do allow(provider).to receive(:grafana_cli) provider.destroy expect(provider).to have_received(:grafana_cli).with('plugins', 'uninstall', 'grafana-wizzle') end describe 'create with repo' do let(:resource) do Puppet::Type::Grafana_plugin.new( name: 'grafana-plugin', repo: 'https://nexus.company.com/grafana/plugins' ) end it '#create with repo' do allow(provider).to receive(:grafana_cli) provider.create expect(provider).to have_received(:grafana_cli).with('--repo https://nexus.company.com/grafana/plugins', 'plugins', 'install', 'grafana-plugin') end end describe 'create with plugin url' do let(:resource) do Puppet::Type::Grafana_plugin.new( name: 'grafana-simple-json-datasource', plugin_url: 'https://grafana.com/api/plugins/grafana-simple-json-datasource/versions/latest/download' ) end it '#create with plugin url' do allow(provider).to receive(:grafana_cli) provider.create expect(provider).to have_received(:grafana_cli).with('--pluginUrl', 'https://grafana.com/api/plugins/grafana-simple-json-datasource/versions/latest/download', 'plugins', 'install', 'grafana-simple-json-datasource') end end end diff --git a/spec/unit/puppet/type/grafana_dashboard_type_spec.rb b/spec/unit/puppet/type/grafana_dashboard_type_spec.rb index 32b76e6..2114b17 100644 --- a/spec/unit/puppet/type/grafana_dashboard_type_spec.rb +++ b/spec/unit/puppet/type/grafana_dashboard_type_spec.rb @@ -1,72 +1,78 @@ +# frozen_string_literal: true + # Copyright 2015 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'spec_helper' describe Puppet::Type.type(:grafana_dashboard) do let(:gdashboard) do described_class.new name: 'foo', grafana_url: 'http://example.com/', content: '{}', ensure: :present end context 'when setting parameters' do it "fails if grafana_url isn't HTTP-based" do expect do described_class.new name: 'foo', grafana_url: 'example.com', content: '{}', ensure: :present end.to raise_error(Puppet::Error, %r{not a valid URL}) end it "fails if content isn't provided" do expect do described_class.new name: 'foo', grafana_url: 'http://example.com', ensure: :present end.to raise_error(Puppet::Error, %r{content is required}) end it "fails if content isn't JSON" do expect do described_class.new name: 'foo', grafana_url: 'http://example.com/', content: '{invalid', ensure: :present end.to raise_error(Puppet::Error, %r{Invalid JSON}) end + it 'accepts valid parameters' do expect(gdashboard[:name]).to eq('foo') expect(gdashboard[:grafana_url]).to eq('http://example.com/') expect(gdashboard[:content]).to eq({}) end + it 'autorequires the grafana-server for proper ordering' do catalog = Puppet::Resource::Catalog.new service = Puppet::Type.type(:service).new(name: 'grafana-server') catalog.add_resource service catalog.add_resource gdashboard relationship = gdashboard.autorequire.find do |rel| (rel.source.to_s == 'Service[grafana-server]') && (rel.target.to_s == gdashboard.to_s) end expect(relationship).to be_a Puppet::Relationship end + it 'does not autorequire the service it is not managed' do catalog = Puppet::Resource::Catalog.new catalog.add_resource gdashboard expect(gdashboard.autorequire).to be_empty end + it 'autorequires grafana_conn_validator' do catalog = Puppet::Resource::Catalog.new validator = Puppet::Type.type(:grafana_conn_validator).new(name: 'grafana') catalog.add_resource validator catalog.add_resource gdashboard relationship = gdashboard.autorequire.find do |rel| (rel.source.to_s == 'Grafana_conn_validator[grafana]') && (rel.target.to_s == gdashboard.to_s) end expect(relationship).to be_a Puppet::Relationship end end end diff --git a/spec/unit/puppet/type/grafana_datasource_type_spec.rb b/spec/unit/puppet/type/grafana_datasource_type_spec.rb index 80f75e3..ea1b4f7 100644 --- a/spec/unit/puppet/type/grafana_datasource_type_spec.rb +++ b/spec/unit/puppet/type/grafana_datasource_type_spec.rb @@ -1,94 +1,96 @@ +# frozen_string_literal: true + # Copyright 2015 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'spec_helper' describe Puppet::Type.type(:grafana_datasource) do let(:gdatasource) do described_class.new( name: 'foo', grafana_url: 'http://example.com', url: 'http://es.example.com', type: 'elasticsearch', organization: 'test_org', access_mode: 'proxy', is_default: true, basic_auth: true, basic_auth_user: 'user', basic_auth_password: 'password', with_credentials: true, database: 'test_db', user: 'db_user', password: 'db_password', json_data: { esVersion: 5, timeField: '@timestamp', timeInterval: '1m' }, secure_json_data: { password: '5ecretPassw0rd' } ) end context 'when setting parameters' do it "fails if grafana_url isn't HTTP-based" do expect do described_class.new name: 'foo', grafana_url: 'example.com', content: '{}', ensure: :present end.to raise_error(Puppet::Error, %r{not a valid URL}) end it "fails if json_data isn't valid" do expect do described_class.new name: 'foo', grafana_url: 'http://example.com', json_data: 'invalid', ensure: :present end.to raise_error(Puppet::Error, %r{json_data should be a Hash}) end it "fails if secure_json_data isn't valid" do expect do described_class.new name: 'foo', grafana_url: 'http://example.com', secure_json_data: 'invalid', ensure: :present end.to raise_error(Puppet::Error, %r{json_data should be a Hash}) end + it 'accepts valid parameters' do expect(gdatasource[:name]).to eq('foo') expect(gdatasource[:grafana_url]).to eq('http://example.com') expect(gdatasource[:url]).to eq('http://es.example.com') expect(gdatasource[:type]).to eq('elasticsearch') expect(gdatasource[:organization]).to eq('test_org') expect(gdatasource[:access_mode]).to eq(:proxy) - expect(gdatasource[:is_default]).to eq(:true) - expect(gdatasource[:basic_auth]).to eq(:true) + expect(gdatasource[:is_default]).to eq(:true) # rubocop:disable Lint/BooleanSymbol + expect(gdatasource[:basic_auth]).to eq(:true) # rubocop:disable Lint/BooleanSymbol expect(gdatasource[:basic_auth_user]).to eq('user') expect(gdatasource[:basic_auth_password]).to eq('password') - expect(gdatasource[:with_credentials]).to eq(:true) + expect(gdatasource[:with_credentials]).to eq(:true) # rubocop:disable Lint/BooleanSymbol expect(gdatasource[:database]).to eq('test_db') expect(gdatasource[:user]).to eq('db_user') expect(gdatasource[:password]).to eq('db_password') expect(gdatasource[:json_data]).to eq(esVersion: 5, timeField: '@timestamp', timeInterval: '1m') expect(gdatasource[:secure_json_data]).to eq(password: '5ecretPassw0rd') end - # rubocop:enable RSpec/MultipleExpectations it 'autorequires the grafana-server for proper ordering' do catalog = Puppet::Resource::Catalog.new service = Puppet::Type.type(:service).new(name: 'grafana-server') catalog.add_resource service catalog.add_resource gdatasource relationship = gdatasource.autorequire.find do |rel| (rel.source.to_s == 'Service[grafana-server]') && (rel.target.to_s == gdatasource.to_s) end expect(relationship).to be_a Puppet::Relationship end it 'does not autorequire the service it is not managed' do catalog = Puppet::Resource::Catalog.new catalog.add_resource gdatasource expect(gdatasource.autorequire).to be_empty end end end diff --git a/spec/unit/puppet/type/grafana_folder_type_spec.rb b/spec/unit/puppet/type/grafana_folder_type_spec.rb index f3ffa10..273664f 100644 --- a/spec/unit/puppet/type/grafana_folder_type_spec.rb +++ b/spec/unit/puppet/type/grafana_folder_type_spec.rb @@ -1,65 +1,71 @@ +# frozen_string_literal: true + # Copyright 2015 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'spec_helper' describe Puppet::Type.type(:grafana_folder) do let(:gfolder) do described_class.new name: 'foo', grafana_url: 'http://example.com/', ensure: :present end context 'when setting parameters' do it "fails if grafana_url isn't HTTP-based" do expect do described_class.new name: 'foo', grafana_url: 'example.com', ensure: :present end.to raise_error(Puppet::Error, %r{not a valid URL}) end it "fails if grafana_api_path isn't properly formed" do expect do described_class.new name: 'foo', grafana_url: 'http://example.com', grafana_api_path: '/invalidpath', ensure: :present end.to raise_error(Puppet::Error, %r{not a valid API path}) end + it 'accepts valid parameters' do expect(gfolder[:name]).to eq('foo') expect(gfolder[:grafana_url]).to eq('http://example.com/') end + it 'autorequires the grafana-server for proper ordering' do catalog = Puppet::Resource::Catalog.new service = Puppet::Type.type(:service).new(name: 'grafana-server') catalog.add_resource service catalog.add_resource gfolder relationship = gfolder.autorequire.find do |rel| (rel.source.to_s == 'Service[grafana-server]') && (rel.target.to_s == gfolder.to_s) end expect(relationship).to be_a Puppet::Relationship end + it 'does not autorequire the service it is not managed' do catalog = Puppet::Resource::Catalog.new catalog.add_resource gfolder expect(gfolder.autorequire).to be_empty end + it 'autorequires grafana_conn_validator' do catalog = Puppet::Resource::Catalog.new validator = Puppet::Type.type(:grafana_conn_validator).new(name: 'grafana') catalog.add_resource validator catalog.add_resource gfolder relationship = gfolder.autorequire.find do |rel| (rel.source.to_s == 'Grafana_conn_validator[grafana]') && (rel.target.to_s == gfolder.to_s) end expect(relationship).to be_a Puppet::Relationship end end end diff --git a/spec/unit/puppet/type/grafana_ldap_config_spec.rb b/spec/unit/puppet/type/grafana_ldap_config_spec.rb index c917c28..305e85c 100644 --- a/spec/unit/puppet/type/grafana_ldap_config_spec.rb +++ b/spec/unit/puppet/type/grafana_ldap_config_spec.rb @@ -1,164 +1,167 @@ +# frozen_string_literal: true + # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require 'spec_helper' # rubocop:disable RSpec/VoidExpect describe Puppet::Type.type(:grafana_ldap_config) do # resource title context 'validate resource title' do it 'fails if title is not set' do expect do described_class.new name: nil end.to raise_error(Puppet::Error, %r{Title or name must be provided}) end it 'fails if title is not a string' do expect do described_class.new name: 123 end.to raise_error(Puppet::ResourceError, %r{must be a String}) end end # owner context 'validate owner' do it 'fails if owner is wrong type' do expect do described_class.new name: 'foo_bar', owner: true end.to raise_error(Puppet::ResourceError, %r{must be a String or Integer}) end it 'succeeds if owner is string' do expect do described_class.new name: 'foo_bar', owner: 'foo' end end it 'succeeds if owner is numeric' do expect do described_class.new name: 'foo_bar', owner: 111 end end end # group context 'validate group' do it 'fails if group is wrong type' do expect do described_class.new name: 'foo_bar', group: true end.to raise_error(Puppet::ResourceError, %r{must be a String or Integer}) end it 'succeeds if group is string' do expect do described_class.new name: 'foo_bar', group: 'foo' end end it 'succeeds if group is numeric' do expect do described_class.new name: 'foo_bar', owner: 111 end end end # mode context 'validate mode' do it 'fails if mode is wrong type' do expect do described_class.new name: 'foo_bar', mode: 123 end.to raise_error(Puppet::ResourceError, %r{must be a String}) end it 'fails if mode is empty' do expect do described_class.new name: 'foo_bar', mode: '' end.to raise_error(Puppet::ResourceError, %r{must be a String}) end # currently disabled # it 'fails if mode is invalid' do # expect do # described_class.new name: 'foo_bar', mode: 'abcd' # end.to raise_error(Puppet::ResourceError, %r{is not valid}) # end it 'succeeds if mode is string' do expect do described_class.new name: 'foo_bar', mode: '0755' end end end # replace context 'validate replace' do it 'fails if replace is not a boolean' do expect do described_class.new name: 'foo_bar', replace: 'bla' end.to raise_error(Puppet::ResourceError, %r{Valid values are}) end it 'succeeds if replace' do expect do described_class.new name: 'foo_bar', replace: true end end end # backup context 'validate backup' do it 'fails if backup is not a boolean' do expect do described_class.new name: 'foo_bar', backup: 'bla' end.to raise_error(Puppet::ResourceError, %r{Valid values are}) end it 'succeeds if backup' do expect do described_class.new name: 'foo_bar', backup: true end end end # validate_cmd context 'validate validate_cmd' do it 'fails if validate_cmd is wrong type' do expect do described_class.new name: 'foo_bar', validate_cmd: 123 end.to raise_error(Puppet::Error, %r{must be a String}) end it 'succeeds if group is string' do expect do described_class.new name: 'foo_bar', validate_cmd: '0755' end end end # ldap_servers context 'validate ldap_servers' do it 'correctly returns the declared LDAP servers' do catalog = Puppet::Resource::Catalog.new server = Puppet::Type.type(:grafana_ldap_server).new( name: 'ldap.example.com', hosts: ['ldap.example.com'], search_base_dns: ['ou=auth'] ) config = Puppet::Type.type(:grafana_ldap_config).new name: 'ldap1' catalog.add_resource server catalog.add_resource config expect(config.ldap_servers.keys).to include('ldap.example.com') end end end +# rubocop:enable RSpec/VoidExpect diff --git a/spec/unit/puppet/type/grafana_ldap_group_mapping_spec.rb b/spec/unit/puppet/type/grafana_ldap_group_mapping_spec.rb index 81d33b4..a6c5204 100644 --- a/spec/unit/puppet/type/grafana_ldap_group_mapping_spec.rb +++ b/spec/unit/puppet/type/grafana_ldap_group_mapping_spec.rb @@ -1,151 +1,154 @@ +# frozen_string_literal: true + # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require 'spec_helper' # rubocop:disable RSpec/VoidExpect describe Puppet::Type.type(:grafana_ldap_group_mapping) do # resource title context 'validate resource title' do it 'fails if title is not set' do expect do described_class.new name: nil end.to raise_error(Puppet::Error, %r{Title or name must be provided}) end it 'fails if title is empty' do expect do described_class.new name: '' end.to raise_error(RuntimeError, %r{needs to be a non-empty string}) end it 'fails if title is not a string' do expect do described_class.new name: 123 end.to raise_error(Puppet::ResourceError, %r{must be a String}) end end # ldap_server_name context 'validate ldap_server_name' do it 'fails if ldap_server_name is not set' do expect do described_class.new name: 'foo_bar', ldap_server_name: nil, group_dn: 'bar' end.to raise_error(Puppet::Error, %r{Got nil value for}) end it 'fails if ldap_server_name is empty' do expect do described_class.new name: 'foo_bar', ldap_server_name: '', group_dn: 'bar' end.to raise_error(RuntimeError, %r{needs to be a non-empty string}) end it 'fails if ldap_server_name is not a string' do expect do described_class.new name: '123_bar', ldap_server_name: 123, group_dn: 'bar' end.to raise_error(Puppet::ResourceError, %r{must be a String}) end end # group_dn context 'validate group_dn' do it 'fails if group_dn is not set' do expect do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: nil end.to raise_error(Puppet::Error, %r{Got nil value for}) end it 'fails if group_dn is empty' do expect do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: '' end.to raise_error(RuntimeError, %r{needs to be a non-empty string}) end it 'fails if group_dn is not a string' do expect do described_class.new name: 'foo_123', ldap_server_name: 'foo', group_dn: 123 end.to raise_error(Puppet::ResourceError, %r{must be a String}) end end # org_role context 'validate org_role' do it 'fails if org_role is not set' do expect do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: nil end.to raise_error(Puppet::Error, %r{Got nil value for}) end it 'fails if org_role is not a string' do expect do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 123 end.to raise_error(Puppet::ResourceError, %r{Valid values are}) end it 'fails if org_role is an unknown role' do expect do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'bla' end.to raise_error(Puppet::Error, %r{Valid values are}) end it 'succeeds if all is correct' do expect do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Editor' end end end # grafana_admin context 'validate grafana_admin' do it 'fails if org_role is not a boolean' do expect do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Admin', grafana_admin: 'bla' end.to raise_error(Puppet::ResourceError, %r{Valid values are}) end it 'succeeds if grafana_admin' do expect do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Admin', grafana_admin: true end end end context 'valid viewer' do let(:group_mapping) do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Viewer', grafana_admin: false end it 'given all parameters' do expect(group_mapping[:org_role]).to eq(:Viewer) end end context 'valid editor' do let(:group_mapping) do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Editor', grafana_admin: false end it 'given all parameters' do expect(group_mapping[:org_role]).to eq(:Editor) end end context 'valid admin' do let(:group_mapping) do described_class.new name: 'foo_bar', ldap_server_name: 'foo', group_dn: 'bar', org_role: 'Admin', grafana_admin: true end it 'given all parameters' do expect(group_mapping[:org_role]).to eq(:Admin) end end end +# rubocop:enable RSpec/VoidExpect diff --git a/spec/unit/puppet/type/grafana_ldap_server_spec.rb b/spec/unit/puppet/type/grafana_ldap_server_spec.rb index 8cff019..2a812cd 100644 --- a/spec/unit/puppet/type/grafana_ldap_server_spec.rb +++ b/spec/unit/puppet/type/grafana_ldap_server_spec.rb @@ -1,337 +1,340 @@ +# frozen_string_literal: true + # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require 'spec_helper' # rubocop:disable RSpec/VoidExpect describe Puppet::Type.type(:grafana_ldap_server) do # resource title context 'validate resource title' do it 'fails if title is not set' do expect do described_class.new name: nil end.to raise_error(Puppet::Error, %r{Title or name must be provided}) end it 'fails if title is empty' do expect do described_class.new name: '' end.to raise_error(RuntimeError, %r{must not be empty}) end it 'fails if title is not a string' do expect do described_class.new name: 123 end.to raise_error(Puppet::ResourceError, %r{must be a String}) end end # hosts context 'validate hosts' do it 'fails if hosts is not set' do expect do described_class.new name: 'server1', hosts: nil end.to raise_error(Puppet::Error, %r{Got nil value for}) end it 'fails if hosts is not an array' do expect do described_class.new name: 'server1', hosts: '' end.to raise_error(RuntimeError, %r{must be an Array}) end it 'fails if hosts is empty' do expect do described_class.new name: 'server1', hosts: [] end.to raise_error(RuntimeError, %r{must not be empty}) end end # port context 'validate port' do it 'fails if port is empty' do expect do described_class.new name: 'server1', hosts: ['server1'], port: 0 end.to raise_error(RuntimeError, %r{must be an Integer within}) end it 'fails if port is a string' do expect do described_class.new name: 'server1', hosts: ['server1'], port: '123' end.to raise_error(Puppet::ResourceError, %r{must be an Integer within}) end it 'fails if port is greater than 65535' do expect do described_class.new name: 'server1', hosts: ['server1'], port: 123_456 end.to raise_error(Puppet::ResourceError, %r{must be an Integer within}) end end # use_ssl context 'validate use_ssl' do it 'fails if use_ssl is not boolean' do expect do described_class.new name: 'server1', hosts: ['server1'], use_ssl: 'foobar' end.to raise_error(Puppet::Error, %r{Valid values are true}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], use_ssl: true end end end # start_tls context 'validate start_tls' do it 'fails if start_tls is not boolean' do expect do described_class.new name: 'server1', hosts: ['server1'], start_tls: 'foobar' end.to raise_error(Puppet::Error, %r{Valid values are true}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], start_tls: true end end end # ssl_skip_verify context 'validate ssl_skip_verify' do it 'fails if ssl_skip_verify is not boolean' do expect do described_class.new name: 'server1', hosts: ['server1'], ssl_skip_verify: 'foobar' end.to raise_error(Puppet::Error, %r{Valid values are true}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], ssl_skip_verify: true end end end # root_ca_cert context 'validate root_ca_cert' do it 'fails if root_ca_cert is empty' do expect do described_class.new name: 'server1', hosts: ['server1'], root_ca_cert: '' end.to raise_error(RuntimeError, %r{must be set when SSL}) end it 'fails if root_ca_cert is not a string' do expect do described_class.new name: 'server1', hosts: ['server1'], root_ca_cert: 12_345 end.to raise_error(Puppet::Error, %r{must be a String}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], root_ca_cert: '/etc/ssl/certs/ca-certificate.crt' end end end # client_cert context 'validate client_cert' do it 'fails if client_cert is not a string' do expect do described_class.new name: 'server1', hosts: ['server1'], client_cert: 12_345 end.to raise_error(Puppet::Error, %r{must be a String}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], client_cert: '/etc/ssl/host.crt' end end end # client_key context 'validate client_key' do it 'fails if client_key is not a string' do expect do described_class.new name: 'server1', hosts: ['server1'], client_key: 12_345 end.to raise_error(Puppet::Error, %r{must be a String}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], client_key: '/etc/ssl/certs/ca-certificate.crt' end end end # bind_dn context 'validate bind_dn' do it 'fails if bind_dn is not a string' do expect do described_class.new name: 'server1', hosts: ['server1'], bind_dn: 12_345 end.to raise_error(Puppet::Error, %r{must be a String}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], bind_dn: 'cn=Admin', search_base_dns: ['ou=users'] end end end # bind_password context 'validate bind_password' do it 'fails if bind_password is not a string' do expect do described_class.new name: 'server1', hosts: ['server1'], bind_password: 12_345 end.to raise_error(Puppet::Error, %r{must be a String}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], bind_password: 'foobar', search_base_dns: ['ou=users'] end end end # search_filter context 'validate search_filter' do it 'fails if search_filter is not a string' do expect do described_class.new name: 'server1', hosts: ['server1'], search_filter: 12_345 end.to raise_error(Puppet::Error, %r{must be a String}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], search_filter: 'uid=%u', search_base_dns: ['ou=users'] end end end # search_base_dns context 'validate search_base_dns' do it 'fails if search_base_dns is not an array' do expect do described_class.new name: 'server1', hosts: ['server1'], search_base_dns: 12_345 end.to raise_error(Puppet::Error, %r{must be an Array}) end it 'fails if search_base_dns array members are not strings' do expect do described_class.new name: 'server1', hosts: ['server1'], search_base_dns: [12_345] end.to raise_error(Puppet::Error, %r{must be a String}) end it 'fails if search_base_dns array is empty' do expect do described_class.new name: 'server1', hosts: ['server1'], search_base_dns: [] end.to raise_error(RuntimeError, %r{needs to contain at least one LDAP base-dn}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], search_base_dns: ['ou=users'] end end end # group_search_filter context 'validate group_search_filter' do it 'fails if group_search_filter is not a string' do expect do described_class.new name: 'server1', hosts: ['server1'], group_search_filter: 12_345 end.to raise_error(Puppet::Error, %r{must be a String}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], group_search_filter: 'cn=adminsgroup', search_base_dns: ['ou=users'] end end end # group_search_filter_user_attribute context 'validate group_search_filter_user_attribute' do it 'fails if group_search_filter_user_attribute is not a string' do expect do described_class.new name: 'server1', hosts: ['server1'], group_search_filter_user_attribute: 12_345 end.to raise_error(Puppet::Error, %r{must be a String}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], group_search_filter_user_attribute: 'dn', search_base_dns: ['ou=users'] end end end # group_search_base_dns context 'validate group_search_base_dns' do it 'fails if group_search_base_dns is not an array' do expect do described_class.new name: 'server1', hosts: ['server1'], group_search_base_dns: 12_345 end.to raise_error(Puppet::Error, %r{must be an Array}) end it 'fails if group_search_base_dns array members are not strings' do expect do described_class.new name: 'server1', hosts: ['server1'], group_search_base_dns: [12_345] end.to raise_error(Puppet::Error, %r{must be a String}) end it 'fails if group_search_base_dns array is empty' do expect do described_class.new name: 'server1', hosts: ['server1'], group_search_base_dns: [], search_base_dns: ['ou=auth'] end.to raise_error(RuntimeError, %r{needs to contain at least one LDAP base-dn}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], group_search_base_dns: ['ou=users'] end end end # attributes context 'validate attributes' do it 'fails if attributes is not a hash' do expect do described_class.new name: 'server1', hosts: ['server1'], attributes: [12_345] end.to raise_error(Puppet::Error, %r{must be a Hash}) end it 'fails if unknown attribute' do expect do described_class.new name: 'server1', hosts: ['server1'], attributes: { 'foo' => 'bar' } end.to raise_error(Puppet::Error, %r{contains an unknown key}) end it 'fails if wrong key type' do expect do described_class.new name: 'server1', hosts: ['server1'], attributes: { 12_345 => 'bar' } end.to raise_error(Puppet::Error, %r{must be Strings}) end it 'fails if wrong value type' do expect do described_class.new name: 'server1', hosts: ['server1'], attributes: { 'surname' => {} } end.to raise_error(Puppet::Error, %r{must be Strings}) end it 'succeeds if all is correct' do expect do described_class.new name: 'server1', hosts: ['server1'], attributes: { 'username' => 'uid' } end end end end +# rubocop:enable RSpec/VoidExpect diff --git a/spec/unit/puppet/type/grafana_notification_type_spec.rb b/spec/unit/puppet/type/grafana_notification_type_spec.rb index e1b9953..ac5826f 100644 --- a/spec/unit/puppet/type/grafana_notification_type_spec.rb +++ b/spec/unit/puppet/type/grafana_notification_type_spec.rb @@ -1,70 +1,72 @@ +# frozen_string_literal: true + # Copyright 2015 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'spec_helper' describe Puppet::Type.type(:grafana_notification) do let(:gnotification) do described_class.new( name: 'foo', grafana_url: 'http://example.com', type: 'email', is_default: true, send_reminder: true, frequency: '20m', settings: { adresses: 'test@example.com' } ) end context 'when setting parameters' do it "fails if grafana_url isn't HTTP-based" do expect do described_class.new name: 'foo', grafana_url: 'example.com', content: '{}' end.to raise_error(Puppet::Error, %r{not a valid URL}) end it "fails if settings isn't valid" do expect do described_class.new name: 'foo', grafana_url: 'http://example.com', settings: 'invalid' end.to raise_error(Puppet::Error, %r{settings should be a Hash}) end + it 'accepts valid parameters' do expect(gnotification[:name]).to eq('foo') expect(gnotification[:grafana_url]).to eq('http://example.com') expect(gnotification[:type]).to eq('email') - expect(gnotification[:is_default]).to eq(:true) - expect(gnotification[:send_reminder]).to eq(:true) + expect(gnotification[:is_default]).to eq(:true) # rubocop:disable Lint/BooleanSymbol + expect(gnotification[:send_reminder]).to eq(:true) # rubocop:disable Lint/BooleanSymbol expect(gnotification[:frequency]).to eq('20m') expect(gnotification[:settings]).to eq(adresses: 'test@example.com') end - # rubocop:enable RSpec/MultipleExpectations it 'autorequires the grafana-server for proper ordering' do catalog = Puppet::Resource::Catalog.new service = Puppet::Type.type(:service).new(name: 'grafana-server') catalog.add_resource service catalog.add_resource gnotification relationship = gnotification.autorequire.find do |rel| (rel.source.to_s == 'Service[grafana-server]') && (rel.target.to_s == gnotification.to_s) end expect(relationship).to be_a Puppet::Relationship end it 'does not autorequire the service it is not managed' do catalog = Puppet::Resource::Catalog.new catalog.add_resource gnotification expect(gnotification.autorequire).to be_empty end end end diff --git a/spec/unit/puppet/type/grafana_organization_type_spec.rb b/spec/unit/puppet/type/grafana_organization_type_spec.rb index e195920..7700874 100644 --- a/spec/unit/puppet/type/grafana_organization_type_spec.rb +++ b/spec/unit/puppet/type/grafana_organization_type_spec.rb @@ -1,65 +1,67 @@ +# frozen_string_literal: true + require 'spec_helper' describe Puppet::Type.type(:grafana_organization) do let(:gorganization) do described_class.new( name: 'foo', grafana_url: 'http://example.com', grafana_user: 'admin', grafana_password: 'admin', address: { address1: 'test address1', address2: 'test address2', city: 'CityName', state: 'NewState', zipcode: '12345', country: 'USA' } ) end context 'when setting parameters' do it "fails if json_data isn't valid" do expect do described_class.new name: 'foo', address: 'invalid address' end.to raise_error(Puppet::Error, %r{address should be a Hash!}) end it "fails if grafana_url isn't HTTP-based" do expect do described_class.new name: 'foo', grafana_url: 'example.com', content: '{}', ensure: :present end.to raise_error(Puppet::Error, %r{not a valid URL}) end + it 'accepts valid parameters' do expect(gorganization[:name]).to eq('foo') expect(gorganization[:grafana_user]).to eq('admin') expect(gorganization[:grafana_password]).to eq('admin') expect(gorganization[:grafana_url]).to eq('http://example.com') expect(gorganization[:address]).to eq(address1: 'test address1', address2: 'test address2', city: 'CityName', state: 'NewState', zipcode: '12345', country: 'USA') end - # rubocop:enable RSpec/MultipleExpectations it 'autorequires the grafana-server for proper ordering' do catalog = Puppet::Resource::Catalog.new service = Puppet::Type.type(:service).new(name: 'grafana-server') catalog.add_resource service catalog.add_resource gorganization relationship = gorganization.autorequire.find do |rel| (rel.source.to_s == 'Service[grafana-server]') && (rel.target.to_s == gorganization.to_s) end expect(relationship).to be_a Puppet::Relationship end it 'does not autorequire the service it is not managed' do catalog = Puppet::Resource::Catalog.new catalog.add_resource gorganization expect(gorganization.autorequire).to be_empty end it 'autorequires grafana_conn_validator' do catalog = Puppet::Resource::Catalog.new validator = Puppet::Type.type(:grafana_conn_validator).new(name: 'grafana') catalog.add_resource validator catalog.add_resource gorganization relationship = gorganization.autorequire.find do |rel| (rel.source.to_s == 'Grafana_conn_validator[grafana]') && (rel.target.to_s == gorganization.to_s) end expect(relationship).to be_a Puppet::Relationship end end end diff --git a/spec/unit/puppet/type/grafana_plugin_spec.rb b/spec/unit/puppet/type/grafana_plugin_spec.rb index 7ba9114..00a100d 100644 --- a/spec/unit/puppet/type/grafana_plugin_spec.rb +++ b/spec/unit/puppet/type/grafana_plugin_spec.rb @@ -1,25 +1,29 @@ +# frozen_string_literal: true + require 'spec_helper' describe Puppet::Type.type(:grafana_plugin) do let(:plugin) do Puppet::Type.type(:grafana_plugin).new(name: 'grafana-whatsit') end it 'accepts a plugin name' do plugin[:name] = 'plugin-name' expect(plugin[:name]).to eq('plugin-name') end + it 'requires a name' do expect do Puppet::Type.type(:grafana_plugin).new({}) end.to raise_error(Puppet::Error, 'Title or name must be provided') end it 'accepts a plugin repo' do plugin[:repo] = 'https://nexus.company.com/grafana/plugins' expect(plugin[:repo]).to eq('https://nexus.company.com/grafana/plugins') end + it 'accepts a plugin url' do plugin[:plugin_url] = 'https://grafana.com/api/plugins/grafana-simple-json-datasource/versions/latest/download' expect(plugin[:plugin_url]).to eq('https://grafana.com/api/plugins/grafana-simple-json-datasource/versions/latest/download') end end diff --git a/spec/unit/puppet/type/grafana_team_type_spec.rb b/spec/unit/puppet/type/grafana_team_type_spec.rb index a714091..df4f0b6 100644 --- a/spec/unit/puppet/type/grafana_team_type_spec.rb +++ b/spec/unit/puppet/type/grafana_team_type_spec.rb @@ -1,63 +1,65 @@ +# frozen_string_literal: true + require 'spec_helper' describe Puppet::Type.type(:grafana_team) do let(:gteam) do described_class.new( name: 'foo', grafana_url: 'http://example.com', grafana_user: 'admin', grafana_password: 'admin', home_dashboard_folder: 'bar', home_dashboard: 'foo_dashboard', organization: 'foo_organization' ) end context 'when setting parameters' do it "fails if grafana_url isn't HTTP-based" do expect do described_class.new name: 'foo', grafana_url: 'example.com', content: '{}', ensure: :present end.to raise_error(Puppet::Error, %r{not a valid URL}) end + it 'accepts valid parameters' do expect(gteam[:name]).to eq('foo') expect(gteam[:grafana_user]).to eq('admin') expect(gteam[:grafana_password]).to eq('admin') expect(gteam[:grafana_url]).to eq('http://example.com') expect(gteam[:home_dashboard_folder]).to eq('bar') expect(gteam[:home_dashboard]).to eq('foo_dashboard') expect(gteam[:organization]).to eq('foo_organization') end - # rubocop:enable RSpec/MultipleExpectations it 'autorequires the grafana-server for proper ordering' do catalog = Puppet::Resource::Catalog.new service = Puppet::Type.type(:service).new(name: 'grafana-server') catalog.add_resource service catalog.add_resource gteam relationship = gteam.autorequire.find do |rel| (rel.source.to_s == 'Service[grafana-server]') && (rel.target.to_s == gteam.to_s) end expect(relationship).to be_a Puppet::Relationship end it 'does not autorequire the service it is not managed' do catalog = Puppet::Resource::Catalog.new catalog.add_resource gteam expect(gteam.autorequire).to be_empty end it 'autorequires grafana_conn_validator' do catalog = Puppet::Resource::Catalog.new validator = Puppet::Type.type(:grafana_conn_validator).new(name: 'grafana') catalog.add_resource validator catalog.add_resource gteam relationship = gteam.autorequire.find do |rel| (rel.source.to_s == 'Grafana_conn_validator[grafana]') && (rel.target.to_s == gteam.to_s) end expect(relationship).to be_a Puppet::Relationship end end end diff --git a/spec/unit/puppet/type/grafana_user_type_spec.rb b/spec/unit/puppet/type/grafana_user_type_spec.rb index c45aa90..ca83c66 100644 --- a/spec/unit/puppet/type/grafana_user_type_spec.rb +++ b/spec/unit/puppet/type/grafana_user_type_spec.rb @@ -1,59 +1,65 @@ +# frozen_string_literal: true + # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'spec_helper' describe Puppet::Type.type(:grafana_user) do let(:guser) do described_class.new name: 'test', full_name: 'Mr tester', password: 't3st', grafana_url: 'http://example.com/' end context 'when setting parameters' do it "fails if grafana_url isn't HTTP-based" do expect do described_class.new name: 'test', grafana_url: 'example.com' end.to raise_error(Puppet::Error, %r{not a valid URL}) end + it 'accepts valid parameters' do expect(guser[:name]).to eq('test') expect(guser[:full_name]).to eq('Mr tester') expect(guser[:password]).to eq('t3st') expect(guser[:grafana_url]).to eq('http://example.com/') end + it 'autorequires the grafana-server for proper ordering' do catalog = Puppet::Resource::Catalog.new service = Puppet::Type.type(:service).new(name: 'grafana-server') catalog.add_resource service catalog.add_resource guser relationship = guser.autorequire.find do |rel| (rel.source.to_s == 'Service[grafana-server]') && (rel.target.to_s == guser.to_s) end expect(relationship).to be_a Puppet::Relationship end + it 'does not autorequire the service it is not managed' do catalog = Puppet::Resource::Catalog.new catalog.add_resource guser expect(guser.autorequire).to be_empty end + it 'autorequires grafana_conn_validator' do catalog = Puppet::Resource::Catalog.new validator = Puppet::Type.type(:grafana_conn_validator).new(name: 'grafana') catalog.add_resource validator catalog.add_resource guser relationship = guser.autorequire.find do |rel| (rel.source.to_s == 'Grafana_conn_validator[grafana]') && (rel.target.to_s == guser.to_s) end expect(relationship).to be_a Puppet::Relationship end end end