sous-chefs / grafana

Development repository for the grafana cookbook
https://supermarket.chef.io/cookbooks/grafana
Other
76 stars 144 forks source link

grafana_config_ldap_servers resources error with "undefined method `[]' for nil:NilClass" #401

Closed Boy-Sittisak closed 1 year ago

Boy-Sittisak commented 3 years ago

:speaking_head: Foreword

:ghost: Brief Description

Hello I'm trying to deploy Gafana with LDAP config with grafana_config_ldap_servers Resources even with all default setting it will get error message with "undefined method `[]' for nil:NilClass" when run chef-client

:pancakes: Cookbook version

9.6.2

:woman_cook: Chef-Infra Version

16.13.16

:tophat: Platform details

CentOS Linux release 7.9.2009

Steps To Reproduce

Steps to reproduce the behavior:

grafana_config_ldap_servers 'grafana' do
  host '127.0.0.1'
  port 389
  use_ssl false
  start_tls false
  ssl_skip_verify false
  bind_dn 'cn=admin,dc=grafana,dc=org'
  bind_password 'SuperSecretPassword'
  search_filter '(cn=%s)'
  search_base_dns %w( dc=grafana,dc=org )
end

See this error message when run chef-client

    ================================================================================
    Error executing action `install` on resource 'grafana_config_ldap_servers[grafana]'
    ================================================================================

    NoMethodError
    -------------
    undefined method `[]' for nil:NilClass

    Cookbook Trace: (most recent call first)
    ----------------------------------------
    /home/user/.chef/cache/cookbooks/grafana/resources/config_ldap_servers.rb:41:in `block in class_from_file'

    Resource Declaration:
    ---------------------
    # In /home/user/.chef/cache/cookbooks/grafana/recipes/default.rb

     80: grafana_config_ldap_servers 'grafana' do
     81:   host '127.0.0.1'
     82:   port 389
     83:   use_ssl false
     84:   start_tls false
     85:   ssl_skip_verify false
     86:   bind_dn 'cn=admin,dc=grafana,dc=org'
     87:   bind_password 'SuperSecretPassword'
     88:   search_filter '(cn=%s)'
     89:   search_base_dns %w( dc=grafana,dc=org )
     90: end
     91: 

    Compiled Resource:
    ------------------
    # Declared in /home/user/.chef/cache/cookbooks/grafana/recipes/default.rb:80:in `from_file'

    grafana_config_ldap_servers("grafana") do
      action [:install]
      default_guard_interpreter :default
      declared_type :grafana_config_ldap_servers
      cookbook_name "grafana"
      recipe_name "cluster"
      host "127.0.0.1"
      port 389
      use_ssl false
      start_tls false
      ssl_skip_verify false
      bind_dn "cn=admin,dc=grafana,dc=org"
      bind_password "*sensitive value suppressed*"
      search_filter "(cn=%s)"
      search_base_dns ["dc=grafana,dc=org"]
      instance_name "grafana"
    end

    System Info:
    ------------
    chef_version=16.13.16
    platform=centos
    platform_version=7.9.2009
    ruby=ruby 2.7.3p183 (2021-04-05 revision 6847ee089d) [x86_64-linux]
    program_name=/usr/bin/chef-client
    executable=/opt/chef/bin/chef-client

Running handlers:
[2021-06-23T15:41:53+07:00] ERROR: Running exception handlers
Running handlers complete
[2021-06-23T15:41:53+07:00] ERROR: Exception handlers complete
Chef Infra Client failed. 0 resources updated in 20 seconds
[2021-06-23T15:41:54+07:00] FATAL: Stacktrace dumped to /home/user/.chef/cache/chef-stacktrace.out
[2021-06-23T15:41:54+07:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report
[2021-06-23T15:41:54+07:00] FATAL: NoMethodError: grafana_config_ldap_servers[grafana] (grafana line 80) had an error: NoMethodError: undefined method `[]' for nil:NilClass

:police_car: Expected behavior

Write ldap servers config to /etc/grafana/ldap.toml file

:heavy_plus_sign: Additional context

I'm not sure if I do something wrong or not but I tested with minimal required setting like below still the got same result

grafana_config_ldap_servers 'grafana' do
  host '127.0.0.1'
end
ramereth commented 3 years ago

@Boy-Sittisak what resources are you running before you use this resource? I believe you need a few other resources before using it which might be part of the problem. If you can provide a full example, that would be great.

Boy-Sittisak commented 3 years ago

@ramereth Thank for reply Here is cookbook recipe that I try to deploy with chef-client This cookbook able to run without problem until I add grafana_config_ldap_servers resource maybe I missed something and need to add before grafana_config_ldap_servers resource? I'm new to chef and grafana as well.

grafana_install 'grafana'

service 'grafana-server' do
  action [:enable, :start]
  subscribes :restart, ['template[/etc/grafana/grafana.ini]', 'template[/etc/grafana/ldap.toml]'], :delayed
end

grafana_config 'grafana' do
  restart_on_upgrade true
end

grafana_config_server 'grafana' do
  http_addr 'localhost'
  http_port 3000
  protocol :http
  enable_gzip true
end

grafana_config_database 'grafana' do
  type :mysql
  host 'localhost:3306'
  user 'grafana'
  password '090CE11ce'
  max_idle_conn 10
  max_open_conn 30
  ssl_mode false
  action :install
end

grafana_config_auth 'grafana' do
  ldap_enabled true
  ldap_config_file '/etc/grafana/ldap.toml'
  ldap_allow_sign_up true
end

grafana_config_ldap_servers 'grafana' do
  host '127.0.0.1'
  port 389
  use_ssl false
  start_tls false
  ssl_skip_verify false
  bind_dn 'cn=admin,dc=grafana,dc=org'
  bind_password 'SuperSecretPassword'
  search_filter '(cn=%s)'
  search_base_dns %w( dc=grafana,dc=org )
end

grafana_config_ldap 'grafana' do
  servers_attributes_name 'givenName'
  servers_attributes_surname 'sn'
  servers_attributes_username 'cn'
  servers_attributes_member_of 'memberOf'
  servers_attributes_email 'mail'
end

grafana_config_ldap_group_mappings 'grafana' do
  group_dn 'cn=admins,dc=grafana,dc=org'
  org_role 'Admin'
  grafana_admin true
  org_id 1
end

grafana_config_writer 'grafana'
ramereth commented 3 years ago

@Boy-Sittisak I confirmed if you move grafana_config_ldap before grafana_config_ldap_servers, the issue goes away. It now complains about not having access to mysql but I assume you already have that setup in your environment. Can you please confirm this is works now for you?

Boy-Sittisak commented 3 years ago

@ramereth Thank you very much it work. I was confuse by original ldap.toml file as I see [[servers]] section come first so I through maybe I should put grafana_config_ldap_servers first.

xorima commented 3 years ago

If the documentation is not clear on this for our cookbook could you drop in a pr to make it easier to comprehend?

Thanks!

bmhughes commented 3 years ago

I'll open myself up here and say that unless there's a reason that I can't see right now, there's no reason that the grafana_config_ldap_servers can't lazy create the parent ldap hash either I don't think which would make these work either way around.

xorima commented 3 years ago

I'll open myself up here and say that unless there's a reason that I can't see right now, there's no reason that the grafana_config_ldap_servers can't lazy create the parent ldap hash either I don't think which would make these work either way around.

Go for it and issue a PR? ;)

bmhughes commented 3 years ago

I did have a quick look yesterday but it turned into a big job as almost all of the config resources want changes making to them as it's obviously been done by someone that didn't appreciate the difference between a Chef::Mash and a normal ruby Hash.

I think the way to go is a helper to set the values to make sure the parent Hashes exist so that the resources can be used in any order. The nil and concat things is just weird to me as well.

I'll probably have a pop at it soon as it'll eat away at me 😬

bmhughes commented 3 years ago

Only a quick attempt but thinking of something like this for setting values:

def run_state_config_set(hash, key, value, *path)
  raise ArgumentError unless hash.is_a?(Hash)

  hash['sous-chefs'] ||= {}

  config_hash = hash['sous-chefs']
  path.each do |pn|
    config_hash[pn] ||= {}
    config_hash = config_hash[pn]
  end

  config_hash[key] = value
end

So you pass the top level node.run_state in along with the setting and its value then walk down the path lazy creating the sub-hashes if they don't exist then set the final key/value at the bottom. Also the resources can then use a loop to set the values using property_is_set? to skip if they property isn't set instead of all the unless and concat stuff.

Thoughts?