summaryrefslogtreecommitdiffstats
path: root/lib/puppet/indirector/node/ldap.rb
blob: 73b5cdd7069bd6497db4ecb813df1a19a6d191bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
require 'puppet/node'
require 'puppet/indirector/ldap'

class Puppet::Node::Ldap < Puppet::Indirector::Ldap
    desc "Search in LDAP for node configuration information.  See
    the `LdapNodes`:trac: page for more information."

    # The attributes that Puppet class information is stored in.
    def class_attributes
        # LAK:NOTE See http://snurl.com/21zf8  [groups_google_com] 
        x = Puppet[:ldapclassattrs].split(/\s*,\s*/)
    end

    # Look for our node in ldap.
    def find(name)
        return nil unless information = super
        node = Puppet::Node.new(name)

        parent_info = nil
        parent = information[:parent]
        parents = [name]
        while parent
            if parents.include?(parent)
                raise ArgumentError, "Found loop in LDAP node parents; %s appears twice" % parent
            end
            parents << parent

            ldapsearch(parent) { |entry| parent_info = process(parent, entry) }

            unless parent_info
                raise Puppet::Error.new("Could not find parent node '%s'" % parent)
            end
            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 = parent_info[:parent]
        end

        node.classes = information[:classes].uniq unless information[:classes].empty?
        node.parameters = information[:parameters] unless information[:parameters].empty?
        node.environment = information[:environment] if information[:environment]
        node.fact_merge

        return node
    end

    # The parent attribute, if we have one.
    def parent_attribute
        if pattr = Puppet[:ldapparentattr] and ! pattr.empty?
            pattr
        else
            nil
        end
    end

    # Process the found entry.  We assume that we don't just want the
    # ldap object.
    def process(name, entry)
        result = {}
        if pattr = parent_attribute
            if values = entry.vals(pattr)
                if values.length > 1
                    raise Puppet::Error,
                        "Node %s has more than one parent: %s" % [name, values.inspect]
                end
                unless values.empty?
                    result[:parent] = values.shift
                end
            end
        end

        result[:classes] = []
        class_attributes.each { |attr|
            if values = entry.vals(attr)
                values.each do |v| result[:classes] << v end
            end
        }

        result[:parameters] = entry.to_hash.inject({}) do |hash, ary|
            if ary[1].length == 1
                hash[ary[0]] = ary[1].shift
            else
                hash[ary[0]] = ary[1]
            end
            hash
        end

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

        return result
    end

    # Default to all attributes.
    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

    # The ldap search filter to use.
    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

    def version(name)
        Puppet::Node::Facts.version(name)
    end
end