class Cloudscaling::LDAPConfigUtils

Tools for manipulating slapd using a ldapi:/// connection

Public Class Methods

add_or_update_entry(dn, attrs) click to toggle source

Add or update a cn=config entry

# File lib/cloudscaling/ldap.rb, line 113
def self.add_or_update_entry(dn, attrs)
  unless dn_exists?(dn)
    ldapadd(dn, attrs)
    return
  end
  ldif = ["dn: #{dn}",
          'changeType: modify']
  attrs.each do |attr, value|
    ldif << "replace: #{attr}"
    case value
    when Array
      value.each { |vvv| ldif << "#{attr}: #{vvv}" }
    else
      ldif << "#{attr}: #{value}"
    end
    ldif << '-'
  end
  ldapmodify_ldif(ldif)
end
dn_exists?(dn) click to toggle source

Check for existence of a cn=config entry

# File lib/cloudscaling/ldap.rb, line 97
def self.dn_exists?(dn)
  true unless ldapsearch(base: dn,
                         attributes: ['dn'],
                         scope: :base
                        ).empty?
end
ldapadd(dn, attrs) click to toggle source
# File lib/cloudscaling/ldap.rb, line 104
def self.ldapadd(dn, attrs)
  ldif = ["dn: #{dn}"]
  attrs.each do |attr, value|
    ldif << "#{attr}: #{value}"
  end
  ldapmodify_ldif(ldif, :add)
end
ldapmodify_ldif(ldif, op = :modify) click to toggle source

Use this to modify anything in cn=config ldif: String or Array of Strings op: :modify (default) or :add

# File lib/cloudscaling/ldap.rb, line 81
def self.ldapmodify_ldif(ldif, op = :modify)
  ldif = ldif.join("\n") if ldif.is_a?(Array)
  extraargs = []
  case op
  when :add
    extraargs << '-a'
  end
  # Chef::Log.info("applying ldif: #{ldif}")
  lmod = Mixlib::ShellOut.new(
    'ldapmodify', *extraargs, '-Q', '-Y', 'EXTERNAL', '-H', 'ldapi:///',
    input: ldif)
  lmod.run_command
  lmod.error!
end
ldapsearch(args) click to toggle source

Mimic Net::LDAP#search using ldapsearch subprocess so we can use things like -Y EXTERNAL -H ldapi:/// Returns a Net::LDAP::Dataset object representing the result.

# File lib/cloudscaling/ldap.rb, line 42
def self.ldapsearch(args)
  cmdargs = %w(ldapsearch -LLLQ -Y EXTERNAL -H ldapi:/// -o ldif-wrap=no)
  filter = attributes = nil
  args.each do |arg, val|
    case arg.to_s
    when 'base'
      cmdargs += ['-b', val]
    when 'scope'
      unless [:base, :one, :sub, :children].include? val
        fail "Unrecognized scope: #{val}"
      end
      cmdargs += ['-s', String(val)]
    when 'filter'
      filter = val
    when 'attributes'
      case val
      when Array
        attributes = val
      when String
        attributes = [val]
      else
        fail("attributes must be an Array, not #{val.class}")
      end
    else
      fail "Unrecognized option: #{arg}"
    end
  end
  cmdargs << filter if filter
  cmdargs += attributes if attributes
  lsearch = Mixlib::ShellOut.new(*cmdargs, returns: [0, 32])
  # exit 32 --> noSuchObject
  lsearch.run_command
  lsearch.error!
  Net::LDAP::Dataset.read_ldif(StringIO.new(lsearch.stdout))
end
slapcat(subtree_dn, filter) click to toggle source

Read directly from an on-disk database, even if slapd is not running.

# File lib/cloudscaling/ldap.rb, line 31
def self.slapcat(subtree_dn, filter)
  scat = Mixlib::ShellOut.new('slapcat', '-o', 'ldif-wrap=no',
                              '-H', "ldap:///#{subtree_dn}???#{filter}")
  scat.run_command
  scat.error!
  scat.stdout
end