diff --git a/lib/puppet/provider/grafana_user/grafana.rb b/lib/puppet/provider/grafana_user/grafana.rb index 47e418d..9f01e1f 100644 --- a/lib/puppet/provider/grafana_user/grafana.rb +++ b/lib/puppet/provider/grafana_user/grafana.rb @@ -1,149 +1,167 @@ 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 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 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 } 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 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 - user[:password] + nil end def password=(value) resource[:password] = value save_user end # rubocop:disable Style/PredicateName def is_admin user[:is_admin] end def is_admin=(value) resource[:is_admin] = value save_user end # rubocop:enable Style/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) } 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 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 + 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 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_user.rb b/lib/puppet/type/grafana_user.rb index 61d8ac3..1be077b 100644 --- a/lib/puppet/type/grafana_user.rb +++ b/lib/puppet/type/grafana_user.rb @@ -1,70 +1,73 @@ 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 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 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) + 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 end def set_sensitive_parameters(sensitive_parameters) # rubocop:disable Style/AccessorMethodName parameter(:password).sensitive = true if parameter(:password) super(sensitive_parameters) end autorequire(:service) do 'grafana-server' end end diff --git a/spec/acceptance/grafana_user_spec.rb b/spec/acceptance/grafana_user_spec.rb new file mode 100644 index 0000000..73a142a --- /dev/null +++ b/spec/acceptance/grafana_user_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper_acceptance' + +describe 'grafana_user' do + context 'setup grafana server' do + it 'runs successfully' do + pp = <<-EOS + class { 'grafana': + cfg => { + security => { + admin_user => 'admin', + admin_password => 'admin' + } + } + } + EOS + 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