vkhatri / chef-ddnsupdate

Chef cookbook to Manage Bind DDNS Records using nsupdate
https://supermarket.chef.io/cookbooks/ddnsupdate
Apache License 2.0
5 stars 2 forks source link

node['ddnsupdate']['resolv_conf']['nameservers'].first not being set when node['ddnsupdate']['use_resolv_conf'] is true #7

Closed bcorner13 closed 8 years ago

bcorner13 commented 8 years ago

line 26: node.default['ddnsupdate']['server'] = node['ddnsupdate']['resolv_conf']['nameservers'].first if node['ddnsupdate']['use_resolv_conf']

kitchen run:

   Recipe Compile Error in /tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/host.rb
   ================================================================================

   NoMethodError
   -------------
   undefined method `first' for nil:NilClass

   Cookbook Trace:
   ---------------
     /tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/default.rb:26:in `from_file'
     /tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/host.rb:20:in `from_file'

   Relevant File Content:
   ----------------------
   /tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/default.rb:

    19:  
    20:  temp_resolv_conf  = DDNSUpdate.resolv_conf
    21:  
    22:  node.default['ddnsupdate']['resolv_conf']['nameservers'] = temp_resolv_conf['nameservers']
    23:  node.default['ddnsupdate']['resolv_conf']['search'] = temp_resolv_conf['search']
    24:  node.default['ddnsupdate']['resolv_conf']['domain'] = temp_resolv_conf['search']
    25:  
    26>> node.default['ddnsupdate']['server'] = node['ddnsupdate']['resolv_conf']['nameservers'].first if node['ddnsupdate']['use_resolv_conf']
    27:  
    28:  fail "node['ddnsupdate']['server'] must be configured or enable node['ddnsupdate']['use_resolv_conf']" unless node['ddnsupdate']['server']
    29:  
vkhatri commented 8 years ago

@bcorner13 Are you overriding the value for node['ddnsupdate']['resolv_conf']['nameservers'] in a wrapper cookbook or role? it is defined as an array in the cookbook, i will try to reproduce it.

Perhaps for kitchen test it is better to set `node['ddnsupdate']['resolv_conf']['nameservers'] = ['127.0.0.1']'.

bcorner13 commented 8 years ago

These are the attributes I am setting in my kitchen.yml file:

      ddnsupdate:
        use_resolv_conf: true
        ttl: 300
        no_dnsec: true

and in the run_list section I am calling

      - recipe[ddnsupdate::host]

Its as if the library code:

  def self.resolv_conf(rc_file = '/etc/resolv.conf')
    rc = {
      :nameservers  => [],
      :domain       => nil,
      :search       => []
    }

    if File.exist?(rc_file)
      File.open(rc_file, 'r').each_line do |line|
        next if line =~ /^#|^;/
        case line
        when /domain/
          rc[:domain] = line.strip.split[1]
        when /search/
          rc[:search].push line.strip.split[1]
        when /nameserver/
          begin
            IPAddr.new(line.strip.split[1]).ipv4?
            rc[:nameservers].push line.strip.split[1]
          end
        end
      end
    end

is not actually reading the /etc/resolv.conf

bcorner13 commented 8 years ago

Added some debug to ddnsupdate.rb.

  def self.resolv_conf(rc_file = '/etc/resolv.conf')
    rc = {
      :nameservers  => [],
      :domain       => nil,
      :search       => []
    }
    Chef::Log.debug('About to read /etc/resolv.conf')
    if File.exist?(rc_file)
      File.open(rc_file, 'r').each_line do |line|
        Chef::Log.debug('reading file resolv.conf: ' + line)
        next if line =~ /^#|^;/
        case line
        when /domain/
          rc[:domain] = line.strip.split[1]
        when /search/
          rc[:search].push line.strip.split[1]
        when /nameserver/
          begin
            IPAddr.new(line.strip.split[1]).ipv4?
            rc[:nameservers].push line.strip.split[1]
          end
        end
      end
    else
    Chef::Log.debug('file /etc/resolv.conf doesnt exist')
    end
    rc
  end

and here is the output:

[2015-10-29T18:51:57+00:00] DEBUG: Found recipe default in cookbook ddnsupdate
       [2015-10-29T18:51:57+00:00] DEBUG: About to read /etc/resolv.conf
       [2015-10-29T18:51:57+00:00] DEBUG: reading file resolv.conf: ; generated by /usr/sbin/dhclient-script

       [2015-10-29T18:51:57+00:00] DEBUG: reading file resolv.conf: search <domain>

       [2015-10-29T18:51:57+00:00] DEBUG: reading file resolv.conf: domain <domain>

       [2015-10-29T18:51:57+00:00] DEBUG: reading file resolv.conf: nameserver XX.XX.XX.XX

       [2015-10-29T18:51:57+00:00] DEBUG: reading file resolv.conf: nameserver XX.XX.XX.XX

       [2015-10-29T18:51:57+00:00] DEBUG: filtered backtrace of compile error: /tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/default.rb:26:in `from_file',/tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/host.rb:20:in `from_file'
       [2015-10-29T18:51:57+00:00] DEBUG: backtrace entry for compile error: '/tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/default.rb:26:in `from_file''
       [2015-10-29T18:51:57+00:00] DEBUG: Line number of compile error: '26'

       ================================================================================
       Recipe Compile Error in /tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/host.rb
       ================================================================================
bcorner13 commented 8 years ago

Fixed this issue. Problem boiled down to referencing the named hash. I am going to do another regression test to confirm, but my preliminary test is the feature works.

temp_resolv_conf  = DDNSUpdate.resolv_conf

node.default['ddnsupdate']['resolv_conf']['nameservers'] = temp_resolv_conf[:nameservers].first
node.default['ddnsupdate']['resolv_conf']['search'] = temp_resolv_conf[:search].first
node.default['ddnsupdate']['resolv_conf']['domain'] = temp_resolv_conf[:domain]

Found some additional issues now with

       ================================================================================
       Recipe Compile Error in /tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/host.rb
       ================================================================================

       TypeError
       ---------
       no implicit conversion of nil into String

       Cookbook Trace:
       ---------------
         /tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/host.rb:47:in `+'
         /tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/host.rb:47:in `from_file'

       Relevant File Content:
       ----------------------
       /tmp/kitchen/cache/cookbooks/ddnsupdate/recipes/host.rb:

        40:    group 'root'
        41:    source 'host_nsupdate_nodsec.erb'
        42:    notifies :run, 'execute[host_nsupdate]'
        43:    only_if { node['ddnsupdate']['no_ddnssec'] }
        44:  end
        45:  
        46:  node_domain = node['ddnsupdate']['host']['auto_fqdn_zone'] && node['domain'] ? node['domain'] : node['ddnsupdate']['host']['zone']
        47>> node_fqdn = node['ddnsupdate']['host']['auto_fqdn_zone'] && node['fqdn'] ? node['fqdn'] : (node['hostname'] + '.' + node['ddnsupdate']['host']['zone'])
        48:  
        49:  Chef::Log.warn('unable to determine node fqdn') unless node_fqdn
        50:  Chef::Log.warn('unable to determine node domain / zone') unless node_domain
        51:  
        52:  # host nsupdate config file
        53:  template node['ddnsupdate']['host']['config'] do
        54:    mode 0655
        55:    owner 'root'
        56:    group 'root'

I'll take a look at this tomorrow.

Next bit of improvement I am going to do is automate node['ddnsupdate']['host']['reverse_zone']. My reasoning is that depending on which VLC/subnet I am publishing two they could be different zones. This is something I don't think needs to be hardcoded as an attribute.

vkhatri commented 8 years ago

@bcorner13 Thank you for sharing your analysis. I think you need to set zone attribute default['ddnsupdate']['host']['zone'] for dns registration. Currently if attribute node['ddnsupdate']['host']['auto_fqdn_zone'] is set then node['domain'] will used as a domain, but that will only work if node has been registered with dns or ip fqdn entry is present in /etc/hosts.

I think cookbook can be updated to use domain from /etc/resolv.conf. I will also take a closer look today.

I also thought about assigning a default value to default['ddnsupdate']['host']['reverse_zone'], but you never know which subnet user has configured on the client and dns server. Like, in AWS a VPC subnet of 10.0.0.0/16 can have different subnets of 10.0.0.0/24 and dns server can have a 10.0.0.0/8 or something different.

But, i admit i did not try it further to make a technical guess. I have re opened this issue.

bcorner13 commented 8 years ago

My thought was that the DHCP on AWS provides the zone information. So pull the information from there instead of hard coding it.