summaryrefslogtreecommitdiffstats
path: root/lib/puppet/propertychange.rb
blob: 35bbede1a2af7a49634cedbb0afe0341e9356e48 (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
# 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 properties and producing events.
	class PropertyChange
        attr_accessor :is, :should, :type, :path, :property, :transaction, :changed, :proxy
        
        # The log file generated when this object was changed.
        attr_reader :report
        
        # Switch the goals of the property, thus running the change in reverse.
        def backward
            @property.should = @is
            @is = @property.retrieve

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

        # Create our event object.
        def event(name)
            # default to a simple event type
            unless name.is_a?(Symbol)
                @property.warning("Property '%s' returned invalid event '%s'; resetting to default" %
                    [@property.class, name])

                event = @property.resource.class.name.id2name + "_changed"
            end
            
            Puppet::Event.new(
                :event => name,
                :transaction => @transaction,
                :source => self.source
            )
        end

        def initialize(property, currentvalue)
            unless property.is_a?(Puppet::Property)
                raise Puppet::DevError, "Got a %s instead of a property" %
                    property.class
            end
            @property = property
            @path = [property.path,"change"].flatten
            @is = currentvalue

            @should = property.should

            @changed = false
        end

        # Perform the actual change.  This method can go either forward or
        # backward, and produces an event.
        def go
            if skip?
                if self.noop
                    return [event(:noop)]
                else
                    return nil
                end
            end

            # The transaction catches any exceptions here.
            events = @property.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 { |name|
                @report = @property.log(@property.change_to_s(@is, @should))
                event(name)
            }
        end

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

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

            return self.go
        end
        
        def noop
            return @property.noop
        end
        
        def skip?
            if @property.insync?(@is)
                @property.info "Already in sync"
                return true
            end

            if @property.noop
                @property.log "is %s, should be %s (noop)" %
                    [property.is_to_s(@is), property.should_to_s(@should)]
                #@property.debug "%s is noop" % @property
                return true
            end
            return false
        end
        
        def source
            self.proxy || @property.resource
        end

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