Class: Cloudscaling::LDAPConfigUtils

Inherits:
Object
  • Object
show all
Defined in:
lib/cloudscaling/ldap.rb

Overview

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

Class Method Summary collapse

Class Method Details

.add_or_update_entry(dn, attrs) ⇒ Object

Add or update a cn=config entry



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/cloudscaling/ldap.rb', line 114

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) ⇒ Boolean

Check for existence of a cn=config entry

Returns:

  • (Boolean)


98
99
100
101
102
103
# File 'lib/cloudscaling/ldap.rb', line 98

def self.dn_exists?(dn)
  true unless ldapsearch(base: dn,
                         attributes: ['dn'],
                         scope: :base
                        ).empty?
end

.ldapadd(dn, attrs) ⇒ Object



105
106
107
108
109
110
111
# File 'lib/cloudscaling/ldap.rb', line 105

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) ⇒ Object

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



82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/cloudscaling/ldap.rb', line 82

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) ⇒ Object

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.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/cloudscaling/ldap.rb', line 43

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) ⇒ Object

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



32
33
34
35
36
37
38
# File 'lib/cloudscaling/ldap.rb', line 32

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