# class Puppet::Util::Ldap::Manager

The configuration class for LDAP providers, plus connection handling for actually interacting with ldap.

### Attributes

location[R]
objectclasses[R]
puppet2ldap[R]
rdn[R]

### Public Class Methods

new() click to toggle source

    # File lib/puppet/util/ldap/manager.rb, line 155
    def initialize
      @rdn = :cn
      @generators = []
    end

### Public Instance Methods

and() click to toggle source

A null-op that just returns the config.

    # File lib/puppet/util/ldap/manager.rb, line 11
    def and
      self
    end

at(location) click to toggle source

Set the offset from the search base and return the config.

    # File lib/puppet/util/ldap/manager.rb, line 16
    def at(location)
      @location = location
      self
    end

base() click to toggle source

The basic search base.

    # File lib/puppet/util/ldap/manager.rb, line 22
    def base
      [location, Puppet[:ldapbase]].join(",")
    end

connect() { |connection| ... } click to toggle source

Open, yield, and close the connection. Cannot be left open, at this point.

    # File lib/puppet/util/ldap/manager.rb, line 46
    def connect
      raise ArgumentError, "You must pass a block to #connect" unless block_given?

      unless @connection
        if Puppet[:ldaptls]
          ssl = :tls
        elsif Puppet[:ldapssl]
          ssl = true
        else
          ssl = false
        end
        options = {:ssl => ssl}
        if user = Puppet[:ldapuser] and user != ""
          options[:user] = user
        end
        if password = Puppet[:ldappassword] and password != ""
          options[:password] = password
        end
        @connection = Puppet::Util::Ldap::Connection.new(Puppet[:ldapserver], Puppet[:ldapport], options)
      end
      @connection.start
      begin
        yield @connection.connection
      ensure
        @connection.close
      end
      nil
    end

create(name, attributes) click to toggle source

Convert the name to a dn, then pass the args along to our connection.

    # File lib/puppet/util/ldap/manager.rb, line 28
    def create(name, attributes)
      attributes = attributes.dup

      # Add the objectclasses
      attributes["objectClass"] = objectclasses.collect { |o| o.to_s }
      attributes["objectClass"] << "top" unless attributes["objectClass"].include?("top")

      attributes[rdn.to_s] = [name]

      # Generate any new values we might need.
      generate(attributes)

      # And create our resource.
      connect { |conn| conn.add dn(name), attributes }
    end

delete(name) click to toggle source

Convert the name to a dn, then pass the args along to our connection.

    # File lib/puppet/util/ldap/manager.rb, line 77
    def delete(name)
      connect { |connection| connection.delete dn(name) }
    end

dn(name) click to toggle source

Calculate the dn for a given resource.

    # File lib/puppet/util/ldap/manager.rb, line 82
    def dn(name)
      ["#{rdn}=#{name}", base].join(",")
    end

entry2provider(entry) click to toggle source

Convert an ldap-style entry hash to a provider-style hash.

    # File lib/puppet/util/ldap/manager.rb, line 87
    def entry2provider(entry)
      raise ArgumentError, "Could not get dn from ldap entry" unless entry["dn"]

      # DN is always a single-entry array.  Strip off the bits before the
      # first comma, then the bits after the remaining equal sign.  This is the
      # name.
      name = entry["dn"].dup.pop.split(",").shift.split("=").pop

      result = {:name => name}

      @ldap2puppet.each do |ldap, puppet|
        result[puppet] = entry[ldap.to_s] || :absent
      end

      result
    end

filter() click to toggle source

Create our normal search filter.

    # File lib/puppet/util/ldap/manager.rb, line 105
    def filter
      return(objectclasses.length == 1 ? "objectclass=#{objectclasses[0]}" : "(&(objectclass=" + objectclasses.join(")(objectclass=") + "))")
    end

find(name) click to toggle source

Find the associated entry for a resource. Returns a hash, minus ‘dn’, or nil if the entry cannot be found.

    # File lib/puppet/util/ldap/manager.rb, line 111
    def find(name)
      result = nil
      connect do |conn|
        begin
          conn.search2(dn(name), 0, "objectclass=*") do |result|
            # Convert to puppet-appropriate attributes
            return entry2provider(result)
          end
        rescue => detail
          return nil
        end
      end
    end

generate(values) click to toggle source

Generate any extra values we need to make the ldap entry work.

    # File lib/puppet/util/ldap/manager.rb, line 132
    def generate(values)
      return unless @generators.length > 0

      @generators.each do |generator|
        # Don't override any values that might exist.
        next if values[generator.name]

        if generator.source
          unless value = values[generator.source]
            raise ArgumentError, "#{generator.source} must be defined to generate #{generator.name}"
          end
          result = generator.generate(value)
        else
          result = generator.generate
        end

        result = [result] unless result.is_a?(Array)
        result = result.collect { |r| r.to_s }

        values[generator.name] = result
      end
    end

generates(parameter) click to toggle source

Declare a new attribute generator.

    # File lib/puppet/util/ldap/manager.rb, line 126
    def generates(parameter)
      @generators << Puppet::Util::Ldap::Generator.new(parameter)
      @generators[-1]
    end

ldap_name(attribute) click to toggle source

Return the ldap name for a puppet attribute.

    # File lib/puppet/util/ldap/manager.rb, line 180
    def ldap_name(attribute)
      @puppet2ldap[attribute].to_s
    end

manages(*classes) click to toggle source

Specify what classes this provider models.

    # File lib/puppet/util/ldap/manager.rb, line 161
    def manages(*classes)
      @objectclasses = classes
      self
    end

maps(attributes) click to toggle source

Specify the attribute map. Assumes the keys are the puppet attributes, and the values are the ldap attributes, and creates a map for each direction.

    # File lib/puppet/util/ldap/manager.rb, line 169
    def maps(attributes)
      # The map with the puppet attributes as the keys
      @puppet2ldap = attributes

      # and the ldap attributes as the keys.
      @ldap2puppet = attributes.inject({}) { |map, ary| map[ary[1]] = ary[0]; map }

      self
    end

modify(name, mods) click to toggle source

Convert the name to a dn, then pass the args along to our connection.

    # File lib/puppet/util/ldap/manager.rb, line 186
    def modify(name, mods)
      connect { |connection| connection.modify dn(name), mods }
    end

named_by(attribute) click to toggle source

Specify the rdn that we use to build up our dn.

    # File lib/puppet/util/ldap/manager.rb, line 191
    def named_by(attribute)
      @rdn = attribute
      self
    end

puppet_name(attribute) click to toggle source

Return the puppet name for an ldap attribute.

    # File lib/puppet/util/ldap/manager.rb, line 197
    def puppet_name(attribute)
      @ldap2puppet[attribute]
    end

search(sfilter = nil) click to toggle source

Search for all entries at our base. A potentially expensive search.

    # File lib/puppet/util/ldap/manager.rb, line 202
    def search(sfilter = nil)
      sfilter ||= filter

      result = []
      connect do |conn|
        conn.search2(base, 1, sfilter) do |entry|
          result << entry2provider(entry)
        end
      end
      return(result.empty? ? nil : result)
    end

update(name, is, should) click to toggle source

Update the ldap entry with the desired state.

    # File lib/puppet/util/ldap/manager.rb, line 215
    def update(name, is, should)
      if should[:ensure] == :absent
        Puppet.info "Removing #{dn(name)} from ldap"
        delete(name)
        return
      end

      # We're creating a new entry
      if is.empty? or is[:ensure] == :absent
        Puppet.info "Creating #{dn(name)} in ldap"
        # Remove any :absent params and :ensure, then convert the names to ldap names.
        attrs = ldap_convert(should)
        create(name, attrs)
        return
      end

      # We're modifying an existing entry.  Yuck.

      mods = []
      # For each attribute we're deleting that is present, create a
      # modify instance for deletion.
      [is.keys, should.keys].flatten.uniq.each do |property|
        # They're equal, so do nothing.
        next if is[property] == should[property]

        attributes = ldap_convert(should)

        prop_name = ldap_name(property).to_s

        # We're creating it.
        if is[property] == :absent or is[property].nil?
          mods << LDAP::Mod.new(LDAP::LDAP_MOD_ADD, prop_name, attributes[prop_name])
          next
        end

        # We're deleting it
        if should[property] == :absent or should[property].nil?
          mods << LDAP::Mod.new(LDAP::LDAP_MOD_DELETE, prop_name, [])
          next
        end

        # We're replacing an existing value
        mods << LDAP::Mod.new(LDAP::LDAP_MOD_REPLACE, prop_name, attributes[prop_name])
      end

      modify(name, mods)
    end

valid?() click to toggle source

Is this a complete ldap configuration?

    # File lib/puppet/util/ldap/manager.rb, line 264
    def valid?
      location and objectclasses and ! objectclasses.empty? and puppet2ldap
    end