summaryrefslogtreecommitdiffstats
path: root/lib/puppet/statechange.rb
blob: 4884026fe47861a5e2f9d0408cc6e8cbd47a1088 (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
# 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
        
        # The log file generated when this object was changed.
        attr_reader :report

        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 (noop)" %
                    [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]

            # The transaction catches any exceptions here.
            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,
                @report = @state.log(@state.change_to_s)
                Puppet::Event.new(
                    :event => event,
                    :change => self,
                    :transaction => @transaction,
                    :source => @state.parent,
                    :message => self.to_s
                )
            }
        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$