summaryrefslogtreecommitdiffstats
path: root/lib/puppet/statechange.rb
blob: c18cdd25cbb0a06ad687304dec35033002f42544 (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
# the class responsible for actually doing any work

# enables no-op and logging/rollback

module Puppet
    # Handle all of the work around performing an actual change,
    # including calling 'sync' on the states and producing events.
	class StateChange
        attr_accessor :is, :should, :type, :path, :state, :transaction, :changed

        def initialize(state)
            @state = state
            @path = [state.path,"change"].flatten
            @is = state.is

            if state.insync?
                raise Puppet::Error.new(
                    "Tried to create a change for in-sync state %s" % state.name
                )
            end
            @should = state.should

            @changed = false
        end

        # Perform the actual change.  This method can go either forward or
        # backward, and produces an event.
        def go
            if @state.insync?
                @state.info "Already in sync"
                return nil
            end

            if @state.noop
                @state.log "is %s, should be %s" %
                    [state.is_to_s, state.should_to_s]
                #@state.debug "%s is noop" % @state
                return nil
            end

            #@state.info "Is: %s, Should: %s" %
            #    [@state.is.inspect, @state.should.inspect]

            begin
                events = @state.sync
                if events.nil?
                    return nil
                end

                if events.is_a?(Array)
                    if events.empty?
                        return nil
                    end
                else
                    events = [events]
                end
                
                return events.collect { |event|
                    # default to a simple event type
                    if ! event.is_a?(Symbol)
                        @state.warning("State '%s' returned invalid event '%s'; resetting to default" %
                            [@state.class,event])

                        event = @state.parent.class.name.id2name + "_changed"
                    end

                    # i should maybe include object type, but the event type
                    # should basically point to that, right?
                        #:state => @state,
                        #:object => @state.parent,
                    @state.log @state.change_to_s
                    Puppet::Event.new(
                        :event => event,
                        :change => self,
                        :transaction => @transaction,
                        :source => @state.parent,
                        :message => self.to_s
                    )
                }
            rescue => detail
                #@state.err "%s failed: %s" % [self.to_s,detail]
                if Puppet[:debug]
                    puts detail.backtrace
                end
                raise
                # there should be a way to ask the state what type of event
                # it would have generated, but...
                pname = @state.parent.class.name.id2name
                #if pname.is_a?(Symbol)
                #    pname = pname.id2name
                #end
                    #:state => @state,
                @state.log "Failed: " + @state.change_to_s
                return Puppet::Event.new(
                    :event => pname + "_failed",
                    :change => self,
                    :source => @state.parent,
                    :transaction => @transaction,
                    :message => "Failed: " + self.to_s
                )
            end
        end

        def forward
            #@state.debug "moving change forward"

            unless defined? @transaction
                raise Puppet::Error,
                    "StateChange '%s' tried to be executed outside of transaction" %
                    self
            end

            return self.go
        end

        # Switch the goals of the state, thus running the change in reverse.
        def backward
            @state.should = @is
            @state.retrieve

            unless defined? @transaction
                raise Puppet::Error,
                    "StateChange '%s' tried to be executed outside of transaction" %
                    self
            end
            unless @state.insync?
                @state.info "Backing %s" % self
                return self.go
            else
                @state.debug "rollback is already in sync: %s vs. %s" %
                    [@state.is.inspect, @state.should.inspect]
                return nil
            end
        end
        
        def noop
            return @state.noop
        end

        def to_s
            return "change %s.%s(%s)" %
                [@transaction.object_id, self.object_id, @state.change_to_s]
            #return "change %s.%s" % [@transaction.object_id, self.object_id]
        end
	end
end

# $Id$