diff options
Diffstat (limited to 'lib/puppet/util/ldap/manager.rb')
-rw-r--r-- | lib/puppet/util/ldap/manager.rb | 468 |
1 files changed, 234 insertions, 234 deletions
diff --git a/lib/puppet/util/ldap/manager.rb b/lib/puppet/util/ldap/manager.rb index 501a3cd4a..2ccd102bc 100644 --- a/lib/puppet/util/ldap/manager.rb +++ b/lib/puppet/util/ldap/manager.rb @@ -5,275 +5,275 @@ require 'puppet/util/ldap/generator' # The configuration class for LDAP providers, plus # connection handling for actually interacting with ldap. class Puppet::Util::Ldap::Manager - attr_reader :objectclasses, :puppet2ldap, :location, :rdn - - # A null-op that just returns the config. - def and - self + attr_reader :objectclasses, :puppet2ldap, :location, :rdn + + # A null-op that just returns the config. + def and + self + end + + # Set the offset from the search base and return the config. + def at(location) + @location = location + self + end + + # The basic search base. + def base + [location, Puppet[:ldapbase]].join(",") + end + + # Convert the name to a dn, then pass the args along to + # our connection. + 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 + + # Open, yield, and close the connection. Cannot be left + # open, at this point. + 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 - - # Set the offset from the search base and return the config. - def at(location) - @location = location - self + @connection.start + begin + yield @connection.connection + ensure + @connection.close end + nil + end - # The basic search base. - def base - [location, Puppet[:ldapbase]].join(",") - end + # Convert the name to a dn, then pass the args along to + # our connection. + def delete(name) + connect { |connection| connection.delete dn(name) } + end - # Convert the name to a dn, then pass the args along to - # our connection. - def create(name, attributes) - attributes = attributes.dup + # Calculate the dn for a given resource. + def dn(name) + ["#{rdn}=#{name}", base].join(",") + end - # Add the objectclasses - attributes["objectClass"] = objectclasses.collect { |o| o.to_s } - attributes["objectClass"] << "top" unless attributes["objectClass"].include?("top") + # Convert an ldap-style entry hash to a provider-style hash. + def entry2provider(entry) + raise ArgumentError, "Could not get dn from ldap entry" unless entry["dn"] - attributes[rdn.to_s] = [name] + # 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 - # Generate any new values we might need. - generate(attributes) + result = {:name => name} - # And create our resource. - connect { |conn| conn.add dn(name), attributes } + @ldap2puppet.each do |ldap, puppet| + result[puppet] = entry[ldap.to_s] || :absent end - # Open, yield, and close the connection. Cannot be left - # open, at this point. - 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) + result + end + + # Create our normal search filter. + def filter + return(objectclasses.length == 1 ? "objectclass=#{objectclasses[0]}" : "(&(objectclass=" + objectclasses.join(")(objectclass=") + "))") + end + + # Find the associated entry for a resource. Returns a hash, minus + # 'dn', or nil if the entry cannot be found. + 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 - @connection.start - begin - yield @connection.connection - ensure - @connection.close - end - nil + rescue => detail + return nil + end end + end - # Convert the name to a dn, then pass the args along to - # our connection. - def delete(name) - connect { |connection| connection.delete dn(name) } - end + # Declare a new attribute generator. + def generates(parameter) + @generators << Puppet::Util::Ldap::Generator.new(parameter) + @generators[-1] + end - # Calculate the dn for a given resource. - def dn(name) - ["#{rdn}=#{name}", base].join(",") - end + # Generate any extra values we need to make the ldap entry work. + def generate(values) + return unless @generators.length > 0 - # Convert an ldap-style entry hash to a provider-style hash. - def entry2provider(entry) - raise ArgumentError, "Could not get dn from ldap entry" unless entry["dn"] + @generators.each do |generator| + # Don't override any values that might exist. + next if values[generator.name] - # 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 + 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 - end - - # Create our normal search filter. - def filter - return(objectclasses.length == 1 ? "objectclass=#{objectclasses[0]}" : "(&(objectclass=" + objectclasses.join(")(objectclass=") + "))") - end - - # Find the associated entry for a resource. Returns a hash, minus - # 'dn', or nil if the entry cannot be found. - 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 + result = [result] unless result.is_a?(Array) + result = result.collect { |r| r.to_s } - # Declare a new attribute generator. - def generates(parameter) - @generators << Puppet::Util::Ldap::Generator.new(parameter) - @generators[-1] + values[generator.name] = result end - - # Generate any extra values we need to make the ldap entry work. - 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 + + def initialize + @rdn = :cn + @generators = [] + end + + # Specify what classes this provider models. + def manages(*classes) + @objectclasses = classes + self + end + + # 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. + 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 + + # Return the ldap name for a puppet attribute. + def ldap_name(attribute) + @puppet2ldap[attribute].to_s + end + + # Convert the name to a dn, then pass the args along to + # our connection. + def modify(name, mods) + connect { |connection| connection.modify dn(name), mods } + end + + # Specify the rdn that we use to build up our dn. + def named_by(attribute) + @rdn = attribute + self + end + + # Return the puppet name for an ldap attribute. + def puppet_name(attribute) + @ldap2puppet[attribute] + end + + # Search for all entries at our base. A potentially expensive search. + def search(sfilter = nil) + sfilter ||= filter + + result = [] + connect do |conn| + conn.search2(base, 1, sfilter) do |entry| + result << entry2provider(entry) + end end - - def initialize - @rdn = :cn - @generators = [] + return(result.empty? ? nil : result) + end + + # Update the ldap entry with the desired state. + def update(name, is, should) + if should[:ensure] == :absent + Puppet.info "Removing #{dn(name)} from ldap" + delete(name) + return end - # Specify what classes this provider models. - def manages(*classes) - @objectclasses = classes - self + # 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 - # 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. - 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 } + # We're modifying an existing entry. Yuck. - self - end - - # Return the ldap name for a puppet attribute. - def ldap_name(attribute) - @puppet2ldap[attribute].to_s - end + 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] - # Convert the name to a dn, then pass the args along to - # our connection. - def modify(name, mods) - connect { |connection| connection.modify dn(name), mods } - end + attributes = ldap_convert(should) - # Specify the rdn that we use to build up our dn. - def named_by(attribute) - @rdn = attribute - self - end + prop_name = ldap_name(property).to_s - # Return the puppet name for an ldap attribute. - def puppet_name(attribute) - @ldap2puppet[attribute] - end + # 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 - # Search for all entries at our base. A potentially expensive search. - def search(sfilter = nil) - sfilter ||= filter + # We're deleting it + if should[property] == :absent or should[property].nil? + mods << LDAP::Mod.new(LDAP::LDAP_MOD_DELETE, prop_name, []) + next + end - result = [] - connect do |conn| - conn.search2(base, 1, sfilter) do |entry| - result << entry2provider(entry) - end - end - return(result.empty? ? nil : result) + # We're replacing an existing value + mods << LDAP::Mod.new(LDAP::LDAP_MOD_REPLACE, prop_name, attributes[prop_name]) end - # Update the ldap entry with the desired state. - 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. + modify(name, mods) + end - 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] + # Is this a complete ldap configuration? + def valid? + location and objectclasses and ! objectclasses.empty? and puppet2ldap + end - attributes = ldap_convert(should) + private - 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 - - # Is this a complete ldap configuration? - def valid? - location and objectclasses and ! objectclasses.empty? and puppet2ldap - end - - private - - # Convert a hash of attributes to ldap-like forms. This mostly means - # getting rid of :ensure and making sure everything's an array of strings. - def ldap_convert(attributes) - attributes.reject { |param, value| value == :absent or param == :ensure }.inject({}) do |result, ary| - value = (ary[1].is_a?(Array) ? ary[1] : [ary[1]]).collect { |v| v.to_s } - result[ldap_name(ary[0])] = value - result - end + # Convert a hash of attributes to ldap-like forms. This mostly means + # getting rid of :ensure and making sure everything's an array of strings. + def ldap_convert(attributes) + attributes.reject { |param, value| value == :absent or param == :ensure }.inject({}) do |result, ary| + value = (ary[1].is_a?(Array) ? ary[1] : [ary[1]]).collect { |v| v.to_s } + result[ldap_name(ary[0])] = value + result end + end end |