summaryrefslogtreecommitdiffstats
path: root/lib/puppet/transportable.rb
blob: 9d1373024240ac973fc322e1b2334cfbef2fb146 (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/usr/local/bin/ruby -w

# $Id$

require 'puppet'

module Puppet
    #------------------------------------------------------------
    class TransObject < Hash
        attr_accessor :type

        @@ohash = {}
        @@oarray = []

        def TransObject.add(object)
            @@oarray.push object

            # this is just so we can check, at parse time, whether a required
            # object has already been mentioned when it is listed as required
            # because we're ordered, as long as an object gets made before its
            # dependent objects will get synced later
            @@ohash[object.longname] = object
        end

        def TransObject.clear
            @@oarray.clear
        end

        def TransObject.list
            return @@oarray
        end

        def initialize(name,type)
            self[:name] = name
            @type = type
            self.class.add(self)
        end

        def longname
            return [self.type,self[:name]].join('--')
        end

        def name
            return self[:name]
        end

        def to_s
            return "%s(%s) => %s" % [@type,self[:name],super]
        end

        def to_type
            retobj = nil
            if type = Puppet::Type.type(self.type)
                begin
                    # this will fail if the type already exists
                    # which may or may not be a good thing...
                    retobj = type.new(self)
                rescue => detail
                    Puppet.err "Failed to create %s: %s" % [type.name,detail]
                    return nil
                end
            else
                raise "Could not find object type %s" % self.type
            end

            return retobj
        end
    end
    #------------------------------------------------------------

    #------------------------------------------------------------
    class TransSetting
        attr_accessor :type, :name, :args, :evalcount

        def initialize
            @evalcount = 0
        end

        def evaluate
            @evalcount += 0
            if type = Puppet::Type.type(self.type)
                # call the settings
                name = self.name
                unless name.is_a?(Symbol)
                    name = name.intern
                end
                if type.allowedmethod(name)
                    type.send(self.name,self.args)
                else
                    Puppet.err("%s does not respond to %s" % [self.type,self.name])
                end
            else
                raise "Could not find object type %s" % setting.type
            end
        end
    end
    #------------------------------------------------------------

    #------------------------------------------------------------
    # just a linear container for objects
    class TransBucket < Array
        attr_accessor :name, :type

        def push(*args)
            args.each { |arg|
                case arg
                when Puppet::TransBucket, Puppet::TransObject, Puppet::TransSetting
                    # nada
                else
                    raise "TransBuckets cannot handle objects of type %s" %
                        arg.class
                end
            }
            super
        end

        def to_type
            # this container will contain the equivalent of all objects at
            # this level
            #container = Puppet::Component.new(:name => @name, :type => @type)
            unless defined? @name
                raise "TransBuckets must have names"
            end
            unless defined? @type
                Puppet.debug "TransBucket '%s' has no type" % @name
            end
            hash = {
                :name => @name,
                :type => @type
            }
            if defined? @parameters
                @parameters.each { |param,value|
                    Puppet.debug "Defining %s on %s of type %s" %
                        [param,@name,@type]
                    hash[param] = value
                }
            else
                Puppet.debug "%s has no parameters" % @name
            end
            container = Puppet::Component.new(hash)
            nametable = {}

            self.each { |child|
                # the fact that we descend here means that we are
                # always going to execute depth-first
                # which is _probably_ a good thing, but one never knows...
                if child.is_a?(Puppet::TransBucket)
                    # just perform the same operation on any children
                    container.push(child.to_type)
                elsif child.is_a?(Puppet::TransSetting)
                    # XXX this is wrong, but for now just evaluate the settings
                    child.evaluate
                elsif child.is_a?(Puppet::TransObject)
                    # do a simple little naming hack to see if the object already
                    # exists in our scope
                    # this assumes that type/name combinations are globally
                    # unique
                    name = [child[:name],child.type].join("--")

                    if nametable.include?(name)
                        object = nametable[name]
                        child.each { |var,value|
                            # don't rename; this shouldn't be possible anyway
                            next if var == :name

                            Puppet.debug "Adding %s to %s" % [var,name]
                            # override any existing values
                            object[var] = value
                        }
                    else # the object does not exist yet in our scope
                        # now we have the object instantiated, in our scope
                        object = child.to_type
                        nametable[name] = object

                        # this sets the order of the object
                        container.push object
                    end
                else
                    raise "TransBucket#to_type cannot handle objects of type %s" %
                        child.class
                end
            }

            # at this point, no objects at are level are still Transportable
            # objects
            return container
        end

        def param(param,value)
            unless defined? @parameters
                @parameters = {}
            end
            @parameters[param] = value
        end

    end
    #------------------------------------------------------------
end