summaryrefslogtreecommitdiffstats
path: root/lib/puppet/event.rb
blob: 86205591d3ea1877fcfb5304b795c9d103dddfe4 (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
199
200
201
#!/usr/local/bin/ruby -w

# $Id$

# included so we can test object types
require 'puppet'
require 'puppet/type'

module Puppet
    # events are transient packets of information; they result in one or more (or none)
    # subscriptions getting triggered, and then they get cleared
    # eventually, these will be passed on to some central event system
	class Event
        # subscriptions are permanent associations determining how different
        # objects react to an event
        class Subscription
            attr_accessor :source, :event, :target, :method

            def initialize(hash)
                @triggered = false

                hash.each { |method,value|
                    # assign each value appropriately
                    # this is probably wicked-slow
                    self.send(method.to_s + "=",value)
                }
                Puppet.warning "New Subscription: '%s' => '%s'" %
                    [@source,@event]
            end

            # the transaction is passed in so that we can notify it if
            # something fails
            def trigger(transaction)
                # this is potentially incomplete, because refreshing an object
                # could theoretically kick off an event, which would not get run
                # or, because we're executing the first subscription rather than
                # the last, a later-refreshed object could somehow be connected
                # to the "old" object rather than "new"
                # but we're pretty far from that being a problem
                if transaction.triggercount(self) > 0
                    Puppet.debug "%s has already run" % self
                else
                    Puppet.debug "'%s' matched '%s'; triggering '%s' on '%s'" %
                        [@source,@event,@method,@target]
                    begin
                        if @target.respond_to?(@method)
                            @target.send(@method)
                        else
                            Puppet.debug "'%s' of type '%s' does not respond to '%s'" %
                                [@target,@target.class,@method.inspect]
                        end
                    rescue => detail
                        # um, what the heck do i do when an object fails to refresh?
                        # shouldn't that result in the transaction rolling back?
                        # XXX yeah, it should
                        Puppet.err "'%s' failed to %s: '%s'" %
                            [@target,@method,detail]
                        raise
                        #raise "We need to roll '%s' transaction back" %
                            #transaction
                    end
                    transaction.triggered(self)
                end
            end
        end

		attr_accessor :event, :object, :transaction

        @@events = []

        @@subscriptions = []

        def Event.process
            Puppet.warning "Processing events"
            @@events.each { |event|
                @@subscriptions.find_all { |sub|
                    #Puppet.warning "Sub source: '%s'; event object: '%s'" %
                    #    [sub.source.inspect,event.object.inspect]
                    sub.source == event.object and
                        (sub.event == event.event or
                         sub.event == :ALL_EVENTS)
                }.each { |sub|
                    Puppet.notice "Found sub"
                    sub.trigger(event.transaction)
                }
            }

            @@events.clear
        end

        def Event.subscribe(hash)
            if hash[:event] == '*'
                hash[:event] = :ALL_EVENTS
            end
            sub = Subscription.new(hash)

            # add to the correct area
            @@subscriptions.push sub
        end

		def initialize(args)
            unless args.include?(:event) and args.include?(:object)
				raise "Event.new called incorrectly"
			end

			@event = args[:event]
			@object = args[:object]
			@transaction = args[:transaction]

            Puppet.info "%s: %s" %
                [@object,@event]

            # initially, just stuff all instances into a central bucket
            # to be handled as a batch
            @@events.push self
		end
	end
end


#---------------------------------------------------------------
# here i'm separating out the methods dealing with handling events
# currently not in use, so...

class Puppet::NotUsed
    #---------------------------------------------------------------
    # return action array
    # these are actions to use for responding to events
    # no, this probably isn't the best way, because we're providing
    # access to the actual hash, which is silly
    def action
        if not defined? @actions
            puts "defining action hash"
            @actions = Hash.new
        end
        @actions
    end
    #---------------------------------------------------------------

    #---------------------------------------------------------------
    # call an event
    # this is called on subscribers by the trigger method from the obj
    # which sent the event
    # event handling should probably be taking place in a central process,
    # but....
    def event(event,obj)
        Puppet.debug "#{self} got event #{event} from #{obj}"
        if @actions.key?(event)
            Puppet.debug "calling it"
            @actions[event].call(self,obj,event)
        else
            p @actions
        end
    end
    #---------------------------------------------------------------

    #---------------------------------------------------------------
    # subscribe to an event or all events
    # this entire event system is a hack job and needs to
    # be replaced with a central event handler
    def subscribe(args,&block)
        obj = args[:object]
        event = args[:event] || '*'.intern
        if obj.nil? or event.nil?
            raise "subscribe was called wrongly; #{obj} #{event}"
        end
        obj.action[event] = block
        #events.each { |event|
            unless @notify.key?(event)
                @notify[event] = Array.new
            end
            unless @notify[event].include?(obj)
                Puppet.debug "pushing event '%s' for object '%s'" % [event,obj]
                @notify[event].push(obj)
            end
        #	}
        #else
        #	@notify['*'.intern].push(obj)
    end
    #---------------------------------------------------------------

    #---------------------------------------------------------------
    # initiate a response to an event
    def trigger(event)
        subscribers = Array.new
        if @notify.include?('*') and @notify['*'].length > 0
            @notify['*'].each { |obj| subscribers.push(obj) }
        end
        if (@notify.include?(event) and (! @notify[event].empty?) )
            @notify[event].each { |obj| subscribers.push(obj) }
        end
        Puppet.debug "triggering #{event}"
        subscribers.each { |obj|
            Puppet.debug "calling #{event} on #{obj}"
            obj.event(event,self)
        }
    end
    #---------------------------------------------------------------

    #---------------------------------------------------------------
end # Puppet::Type