# class Node::Ldap

### Public Instance Methods

class_attributes() click to toggle source

The attributes that Puppet class information is stored in.

    # File lib/puppet/indirector/node/ldap.rb, line 11
    def class_attributes
      # LAK:NOTE See http://snurl.com/21zf8  [groups_google_com]
      x = Puppet[:ldapclassattrs].split(/\s*,\s*/)
    end

entry2hash(entry, fqdn = false) click to toggle source

Convert the found entry into a simple hash.

    # File lib/puppet/indirector/node/ldap.rb, line 84
    def entry2hash(entry, fqdn = false)
      result = {}

      cn  = entry.dn[     /cn\s*=\s*([^,\s]+)/i,1]
      dcs = entry.dn.scan(/dc\s*=\s*([^,\s]+)/i)
      result[:name]    = fqdn ? ([cn]+dcs).join('.') : cn
      result[:parent] = get_parent_from_entry(entry) if parent_attribute
      result[:classes] = get_classes_from_entry(entry)
      result[:stacked] = get_stacked_values_from_entry(entry)
      result[:parameters] = get_parameters_from_entry(entry)

      result[:environment] = result[:parameters]["environment"] if result[:parameters]["environment"]

      result[:stacked_parameters] = {}

      if result[:stacked]
        result[:stacked].each do |value|
          param = value.split('=', 2)
          result[:stacked_parameters][param[0]] = param[1]
        end
      end

      if result[:stacked_parameters]
        result[:stacked_parameters].each do |param, value|
          result[:parameters][param] = value unless result[:parameters].include?(param)
        end
      end

      result[:parameters] = convert_parameters(result[:parameters])

      result
    end

find(request) click to toggle source

Look for our node in ldap.

    # File lib/puppet/indirector/node/ldap.rb, line 29
    def find(request)
      names = [request.key]
      names << request.key.sub(/\..+/, '') if request.key.include?(".") # we assume it's an fqdn
      names << "default"

      node = nil
      names.each do |name|
        next unless info = name2hash(name)

        merge_parent(info) if info[:parent]
        info[:environment] ||= request.environment.to_s
        node = info2node(request.key, info)
        break
      end

      node
    end

name2hash(name) click to toggle source

Separate this out so it’s relatively atomic. It’s tempting to call process instead of name2hash() here, but it ends up being difficult to test because all exceptions get caught by ldapsearch. LAK:NOTE Unfortunately, the ldap support is too stupid to throw anything but LDAP::ResultError, even on bad connections, so we are rough handed with our error handling.

    # File lib/puppet/indirector/node/ldap.rb, line 22
    def name2hash(name)
      info = nil
      ldapsearch(search_filter(name)) { |entry| info = entry2hash(entry) }
      info
    end

parent_attribute() click to toggle source

The parent attribute, if we have one.

    # File lib/puppet/indirector/node/ldap.rb, line 69
    def parent_attribute
      if pattr = Puppet[:ldapparentattr] and ! pattr.empty?
        pattr
      else
        nil
      end
    end

search(request) click to toggle source

Find more than one node. LAK:NOTE This is a bit of a clumsy API, because the ‘search’ method currently requires a key. It seems appropriate in some cases but not others, and I don’t really know how to get rid of it as a requirement but allow it when desired.

    # File lib/puppet/indirector/node/ldap.rb, line 50
    def search(request)
      if classes = request.options[:class]
        classes = [classes] unless classes.is_a?(Array)
        filter = "(&(objectclass=puppetClient)(puppetclass=" + classes.join(")(puppetclass=") + "))"
      else
        filter = "(objectclass=puppetClient)"
      end

      infos = []
      ldapsearch(filter) { |entry| infos << entry2hash(entry, request.options[:fqdn]) }

      return infos.collect do |info|
        merge_parent(info) if info[:parent]
        info[:environment] ||= request.environment.to_s
        info2node(info[:name], info)
      end
    end

search_attributes() click to toggle source

Default to all attributes.

    # File lib/puppet/indirector/node/ldap.rb, line 118
    def search_attributes
      ldapattrs = Puppet[:ldapattrs]

      # results in everything getting returned
      return nil if ldapattrs == "all"

      search_attrs = class_attributes + ldapattrs.split(/\s*,\s*/)

      if pattr = parent_attribute
        search_attrs << pattr
      end

      search_attrs
    end

search_filter(name) click to toggle source

The ldap search filter to use.

    # File lib/puppet/indirector/node/ldap.rb, line 134
    def search_filter(name)
      filter = Puppet[:ldapstring]

      if filter.include? "%s"
        # Don't replace the string in-line, since that would hard-code our node
        # info.
        filter = filter.gsub('%s', name)
      end
      filter
    end

stacked_attributes(dummy_argument=:work_arround_for_ruby_GC_bug) click to toggle source

The attributes that Puppet will stack as array over the full hierarchy.

    # File lib/puppet/indirector/node/ldap.rb, line 79
    def stacked_attributes(dummy_argument=:work_arround_for_ruby_GC_bug)
      Puppet[:ldapstackedattrs].split(/\s*,\s*/)
    end

### Private Instance Methods

add_to_node(node, information) click to toggle source

Add our hash of ldap information to the node instance.

    # File lib/puppet/indirector/node/ldap.rb, line 148
    def add_to_node(node, information)
      node.classes = information[:classes].uniq unless information[:classes].nil? or information[:classes].empty?
      node.parameters = information[:parameters] unless information[:parameters].nil? or information[:parameters].empty?
      node.environment = information[:environment] if information[:environment]
    end

convert(value) click to toggle source

Convert any values if necessary.

    # File lib/puppet/indirector/node/ldap.rb, line 167
    def convert(value)
      case value
      when Integer, Fixnum, Bignum; value
      when "true"; true
      when "false"; false
      else
        value
      end
    end

convert_parameters(parameters) click to toggle source

    # File lib/puppet/indirector/node/ldap.rb, line 154
    def convert_parameters(parameters)
      result = {}
      parameters.each do |param, value|
        if value.is_a?(Array)
          result[param] = value.collect { |v| convert(v) }
        else
          result[param] = convert(value)
        end
      end
      result
    end

find_and_merge_parent(parent, information) click to toggle source

Find information for our parent and merge it into the current info.

    # File lib/puppet/indirector/node/ldap.rb, line 178
    def find_and_merge_parent(parent, information)
      parent_info = name2hash(parent) || raise(Puppet::Error.new("Could not find parent node '#{parent}'"))
      information[:classes] += parent_info[:classes]
      parent_info[:parameters].each do |param, value|
        # Specifically test for whether it's set, so false values are handled correctly.
        information[:parameters][param] = value unless information[:parameters].include?(param)
      end
      information[:environment] ||= parent_info[:environment]
      parent_info[:parent]
    end

get_classes_from_entry(entry) click to toggle source

    # File lib/puppet/indirector/node/ldap.rb, line 215
    def get_classes_from_entry(entry)
      result = class_attributes.inject([]) do |array, attr|
        if values = entry.vals(attr)
          values.each do |v| array << v end
        end
        array
      end
      result.uniq
    end

get_parameters_from_entry(entry) click to toggle source

    # File lib/puppet/indirector/node/ldap.rb, line 225
    def get_parameters_from_entry(entry)
      stacked_params = stacked_attributes
      entry.to_hash.inject({}) do |hash, ary|
        unless stacked_params.include?(ary[0]) # don't add our stacked parameters to the main param list
          if ary[1].length == 1
            hash[ary[0]] = ary[1].shift
          else
            hash[ary[0]] = ary[1]
          end
        end
        hash
      end
    end

get_parent_from_entry(entry) click to toggle source

    # File lib/puppet/indirector/node/ldap.rb, line 239
    def get_parent_from_entry(entry)
      pattr = parent_attribute

      return nil unless values = entry.vals(pattr)

      if values.length > 1
        raise Puppet::Error,
          "Node entry #{entry.dn} specifies more than one parent: #{values.inspect}"
      end
      return(values.empty? ? nil : values.shift)
    end

get_stacked_values_from_entry(entry) click to toggle source

    # File lib/puppet/indirector/node/ldap.rb, line 251
    def get_stacked_values_from_entry(entry)
      stacked_attributes.inject([]) do |result, attr|
        if values = entry.vals(attr)
          result += values
        end
        result
      end
    end

info2node(name, info) click to toggle source

Take a name and a hash, and return a node instance.

    # File lib/puppet/indirector/node/ldap.rb, line 190
    def info2node(name, info)
      node = Puppet::Node.new(name)

      add_to_node(node, info)

      node.fact_merge

      node
    end

merge_parent(info) click to toggle source

    # File lib/puppet/indirector/node/ldap.rb, line 200
    def merge_parent(info)
      parent_info = nil
      parent = info[:parent]

      # Preload the parent array with the node name.
      parents = [info[:name]]
      while parent
        raise ArgumentError, "Found loop in LDAP node parents; #{parent} appears twice" if parents.include?(parent)
        parents << parent
        parent = find_and_merge_parent(parent, info)
      end

      info
    end