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
|
# 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
# Switch the goals of the state, thus running the change in reverse.
def backward
@state.should = @is
@should = @is
@is = @state.retrieve
@state.is = @is
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 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
# Generate an appropriate event from the is/should values.
def genevent
tail = if @state.name == :ensure
if @should == :present
"created"
elsif @should == :absent
"deleted"
else
@should.to_s
end
else
"changed"
end
[state.parent.class.name.to_s, tail].join("_").intern
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.
if @state.method(:sync).arity == 0
@state.warnstamp :syncwoutvalue, "sync() should accept a value"
events = @state.sync
else
events = @state.sync(@should)
end
unless events.is_a? Array
events = [events]
end
events = events.collect do |e|
if e.nil?
genevent()
else
if ! e.is_a?(Symbol)
@state.warning(
"State '%s' returned invalid event '%s'; resetting" %
[@state.class,e]
)
genevent()
else
e
end
end
end.reject { |e| e == :nochange }
if events.empty?
return nil
end
return events.collect { |event|
# 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 initialize(state, is = nil)
@state = state
@path = [state.path,"change"].flatten
if is
@is = is
else
state.warning "did not pass 'is' to statechange"
@is = state.is
end
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
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$
|