summaryrefslogtreecommitdiffstats
path: root/lib/puppet/metatype/evaluation.rb
blob: 36328c53795fd8259cd5f4e9e496b96999ef8b11 (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
class Puppet::Type
    # This method is responsible for collecting property changes we always
    # descend into the children before we evaluate our current properties.
    # This returns any changes resulting from testing, thus 'collect' rather
    # than 'each'.
    def evaluate
        #Puppet.err "Evaluating %s" % self.path.join(":")
        unless defined? @evalcount
            self.err "No evalcount defined on '%s' of type '%s'" %
                [self.title,self.class]
            @evalcount = 0
        end
        @evalcount += 1

        if p = self.provider and p.respond_to?(:prefetch)
            p.prefetch
        end

        # this only operates on properties, not properties + children
        # it's important that we call retrieve() on the type instance,
        # not directly on the property, because it allows the type to override
        # the method, like pfile does
        currentvalues = self.retrieve

        changes = propertychanges(currentvalues).flatten

        # now record how many changes we've resulted in
        if changes.length > 0
            self.debug "%s change(s)" %
                [changes.length]
        end

        # If we're in noop mode, we don't want to store the checked time,
        # because it will result in the resource not getting scheduled if
        # someone were to apply the catalog in non-noop mode.
        # We're going to go ahead and record that we checked if there were
        # no changes, since it's unlikely it will affect the scheduling.
        noop = noop?
        if ! noop or (noop && changes.length == 0)
            self.cache(:checked, Time.now)
        end
        return changes.flatten
    end

    # Flush the provider, if it supports it.  This is called by the
    # transaction.
    def flush
        if self.provider and self.provider.respond_to?(:flush)
            self.provider.flush
        end
    end

    # if all contained objects are in sync, then we're in sync
    # FIXME I don't think this is used on the type instances any more,
    # it's really only used for testing
    def insync?(is)
        insync = true
        
        if property = @parameters[:ensure]
            unless is.include? property
               raise Puppet::DevError,
                        "The is value is not in the is array for '%s'" %
                        [property.name]
            end
            ensureis = is[property]           
            if property.insync?(ensureis) and property.should == :absent
                return true
            end
        end

        properties.each { |property|
            unless is.include? property
               raise Puppet::DevError,
                        "The is value is not in the is array for '%s'" %
                        [property.name]
            end

            propis = is[property]
            unless property.insync?(propis)
                property.debug("Not in sync: %s vs %s" %
                    [propis.inspect, property.should.inspect])
                insync = false
            #else
            #    property.debug("In sync")
            end
        }

        #self.debug("%s sync status is %s" % [self,insync])
        return insync
    end
        
    # retrieve the current value of all contained properties
    def retrieve
         return currentpropvalues
    end
    
    # get a hash of the current properties.  
    def currentpropvalues(override_value = nil)
        # it's important to use the method here, as it follows the order
        # in which they're defined in the object
        return properties().inject({}) { | prophash, property|
                   prophash[property] = override_value.nil? ? 
                                          property.retrieve : 
                                             override_value
                   prophash
               }
    end

    # Are we running in noop mode?
    def noop?
        if defined?(@noop)
            @noop
        else
            Puppet[:noop]
        end
    end

    def noop
        noop?
    end
     
    # Retrieve the changes associated with all of the properties.
    def propertychanges(currentvalues)
        # If we are changing the existence of the object, then none of
        # the other properties matter.
        changes = []
        ensureparam = @parameters[:ensure]
        if @parameters.include?(:ensure) && !currentvalues.include?(ensureparam)
            raise Puppet::DevError, "Parameter ensure defined but missing from current values"
        end
        if @parameters.include?(:ensure) and ! ensureparam.insync?(currentvalues[ensureparam])
            changes << Puppet::PropertyChange.new(ensureparam, currentvalues[ensureparam])
        # Else, if the 'ensure' property is correctly absent, then do
        # nothing
        elsif @parameters.include?(:ensure) and currentvalues[ensureparam] == :absent
            return []
        else
            changes = properties().find_all { |property|
                currentvalues[property] ||= :absent
                ! property.insync?(currentvalues[property])
            }.collect { |property|
                Puppet::PropertyChange.new(property, currentvalues[property])
            }
        end

        if Puppet[:debug] and changes.length > 0
            self.debug("Changing " + changes.collect { |ch| ch.property.name }.join(","))
        end

        changes
    end
end