Class: Puppet::Property

Inherits:
Parameter show all
Defined in:
lib/puppet/property.rb,
lib/puppet/type/zpool.rb,
lib/puppet/property/list.rb,
lib/puppet/property/keyvalue.rb,
lib/puppet/property/ordered_list.rb

Direct Known Subclasses

IniProperty, Ensure, KeyValue, List, VDev, SELFileContext

Defined Under Namespace

Classes: Ensure, KeyValue, List, MultiVDev, OrderedList, VDev

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes inherited from Parameter

#parent, #resource

Attributes included from Util::Docs

#doc, #nodoc

Attributes included from Util::Cacher::Expirer

#timestamp

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Parameter

aliasvalue, defaultto, desc, #devfail, doc, #expirer, #fail, initvars, isnamevar, isnamevar?, isrequired, #metaparam?, munge, newvalues, nodefault, #pathbuilder, #provider, proxymethods, #remove, required?, #tags, #to_s, unmunge, #unmunge, #unsafe_munge, #validate, validate

Methods included from Util::Docs

#desc, #dochook, #doctable, #nodoc?, #pad, scrub

Methods included from Util

activerecord_version, benchmark, chuser, classproxy, #execfail, #execpipe, execute, logmethods, memory, proxy, recmkdir, secure_open, symbolize, symbolizehash, symbolizehash!, synchronize_on, thinmark, #threadlock, which, withumask

Methods included from Util::POSIX

#get_posix_field, #gid, #idfield, #methodbyid, #methodbyname, #search_posix_field, #uid

Methods included from Util::Cacher

extended, included

Methods included from Util::Cacher::Expirer

#dependent_data_expired?, #expire

Methods included from Util::MethodHelper

#requiredopts, #set_options, #symbolize_options

Methods included from Util::Logging

#send_log

Methods included from Util::LogPaths

#path, #source_descriptors

Methods included from Util::Errors

#adderrorcontext, #devfail, #error_context, #exceptwrap, #fail

Constructor Details

#initialize(hash = {}) ⇒ Property

initialize our property



141
142
143
144
145
146
147
# File 'lib/puppet/property.rb', line 141

def initialize(hash = {})
  super

  if ! self.metaparam? and klass = Puppet::Type.metaparamclass(self.class.name)
    setup_shadow(klass)
  end
end

Class Attribute Details

.nameObject (readonly)

Returns the value of attribute name.



19
20
21
# File 'lib/puppet/property.rb', line 19

def name
  @name
end

.unmanagedObject

Returns the value of attribute unmanaged.



18
19
20
# File 'lib/puppet/property.rb', line 18

def unmanaged
  @unmanaged
end

Instance Attribute Details

#noopObject

for testing whether we should actually do anything



228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/puppet/property.rb', line 228

def noop
  # This is only here to make testing easier.
  if @resource.respond_to?(:noop?)
    @resource.noop?
  else
    if defined?(@noop)
      @noop
    else
      Puppet[:noop]
    end
  end
end

#shadowObject (readonly)

Returns the value of attribute shadow.



138
139
140
# File 'lib/puppet/property.rb', line 138

def shadow
  @shadow
end

#shouldorigObject (readonly)

Because ‘should’ uses an array, we have a special method for handling it. We also want to keep copies of the original values, so that they can be retrieved and compared later when merging.



13
14
15
# File 'lib/puppet/property.rb', line 13

def shouldorig
  @shouldorig
end

Class Method Details

.array_matchingObject

Return array matching info, defaulting to just matching the first value.



23
24
25
# File 'lib/puppet/property.rb', line 23

def array_matching
  @array_matching ||= :first
end

.array_matching=(value) ⇒ Object

Set whether properties should match all values or just the first one.

Raises:

  • (ArgumentError)


28
29
30
31
32
# File 'lib/puppet/property.rb', line 28

def array_matching=(value)
  value = value.intern if value.is_a?(String)
  raise ArgumentError, "Supported values for Property#array_matching are 'first' and 'all'" unless [:first, :all].include?(value)
  @array_matching = value
end

.method_added(sym) ⇒ Object



165
166
167
# File 'lib/puppet/property.rb', line 165

def self.method_added(sym)
  raise "Puppet::Property#safe_insync? shouldn't be overridden; please override insync? instead" if sym == :safe_insync?
end

.newvalue(name, options = {}, &block) ⇒ Object

Define a new valid value for a property. You must provide the value itself, usually as a symbol, or a regex to match the value.

The first argument to the method is either the value itself or a regex. The second argument is an option hash; valid options are:

  • :method: The name of the method to define. Defaults to ‘set_<value>’.

  • :required_features: A list of features this value requires.

  • :event: The event that should be returned when this value is set.

  • :call: When to call any associated block. The default value is ‘instead`, which means to call the value instead of calling the provider. You can also specify `before` or `after`, which will call both the block and the provider, according to the order you specify (the `first` refers to when the block is called, not the provider).



62
63
64
65
66
67
# File 'lib/puppet/property.rb', line 62

def self.newvalue(name, options = {}, &block)
  value = value_collection.newvalue(name, options, &block)

  define_method(value.method, &value.block) if value.method and value.block
  value
end

.value_name(name) ⇒ Object

Look up a value’s name, so we can find options and such.



36
37
38
39
40
# File 'lib/puppet/property.rb', line 36

def self.value_name(name)
  if value = value_collection.match?(name)
    value.name
  end
end

.value_option(name, option) ⇒ Object

Retrieve an option set when a value was defined.



43
44
45
46
47
# File 'lib/puppet/property.rb', line 43

def self.value_option(name, option)
  if value = value_collection.value(name)
    value.send(option)
  end
end

Instance Method Details

#call_provider(value) ⇒ Object

Call the provider method.



70
71
72
73
74
# File 'lib/puppet/property.rb', line 70

def call_provider(value)
    provider.send(self.class.name.to_s + "=", value)
rescue NoMethodError
    self.fail "The #{provider.class.name} provider can not handle attribute #{self.class.name}"
end

#call_valuemethod(name, value) ⇒ Object

Call the dynamically-created method associated with our value, if there is one.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/puppet/property.rb', line 78

def call_valuemethod(name, value)
  if method = self.class.value_option(name, :method) and self.respond_to?(method)
    begin
      event = self.send(method)
    rescue Puppet::Error
      raise
    rescue => detail
      puts detail.backtrace if Puppet[:trace]
      error = Puppet::Error.new("Could not set '#{value} on #{self.class.name}: #{detail}", @resource.line, @resource.file)
      error.set_backtrace detail.backtrace
      raise error
    end
  elsif block = self.class.value_option(name, :block)
    # FIXME It'd be better here to define a method, so that
    # the blocks could return values.
    self.instance_eval(&block)
  else
    devfail "Could not find method for value '#{name}'"
  end
end

#change_to_s(current_value, newvalue) ⇒ Object

How should a property change be printed as a string?



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/puppet/property.rb', line 100

def change_to_s(current_value, newvalue)
  begin
    if current_value == :absent
      return "defined '#{name}' as '#{should_to_s(newvalue)}'"
    elsif newvalue == :absent or newvalue == [:absent]
      return "undefined '#{name}' from '#{is_to_s(current_value)}'"
    else
      return "#{name} changed '#{is_to_s(current_value)}' to '#{should_to_s(newvalue)}'"
    end
  rescue Puppet::Error, Puppet::DevError
    raise
  rescue => detail
    puts detail.backtrace if Puppet[:trace]
    raise Puppet::DevError, "Could not convert change '#{name}' to string: #{detail}"
  end
end

#eventObject

Return a modified form of the resource event.



134
135
136
# File 'lib/puppet/property.rb', line 134

def event
  resource.event :name => event_name, :desired_value => should, :property => self, :source_description => path
end

#event_nameObject

Figure out which event to return.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/puppet/property.rb', line 118

def event_name
  value = self.should

  event_name = self.class.value_option(value, :event) and return event_name

  name == :ensure or return (name.to_s + "_changed").to_sym

  return (resource.type.to_s + case value
  when :present; "_created"
  when :absent; "_removed"
  else
    "_changed"
  end).to_sym
end

#insync?(is) ⇒ Boolean

This method should be overridden by derived classes if necessary to provide extra logic to determine whether the property is in sync.

Returns:

  • (Boolean)


172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/puppet/property.rb', line 172

def insync?(is)
  self.devfail "#{self.class.name}'s should is not array" unless @should.is_a?(Array)

  # an empty array is analogous to no should values
  return true if @should.empty?

  # Look for a matching value
  return (is == @should or is == @should.collect { |v| v.to_s }) if match_all?

  @should.each { |val| return true if is == val or is == val.to_s }

  # otherwise, return false
  false
end

#is_to_s(currentvalue) ⇒ Object

because the @should and @is vars might be in weird formats, we need to set up a mechanism for pretty printing of the values default to just the values, but this way individual properties can override these methods



191
192
193
# File 'lib/puppet/property.rb', line 191

def is_to_s(currentvalue)
  currentvalue
end

#log(msg) ⇒ Object

Send a log message.



196
197
198
199
200
201
202
203
204
205
# File 'lib/puppet/property.rb', line 196

def log(msg)

        Puppet::Util::Log.create(

    :level => resource[:loglevel],
    :message => msg,

    :source => self
  )
end

#match_all?Boolean

Should we match all values, or just the first?

Returns:

  • (Boolean)


208
209
210
# File 'lib/puppet/property.rb', line 208

def match_all?
  self.class.array_matching == :all
end

#munge(value) ⇒ Object

Execute our shadow’s munge code, too, if we have one.



213
214
215
216
217
# File 'lib/puppet/property.rb', line 213

def munge(value)
  self.shadow.munge(value) if self.shadow

  super
end

#nameObject

each property class must define the name method, and property instances do not change that name this implicitly means that a given object can only have one property instance of a given property class



223
224
225
# File 'lib/puppet/property.rb', line 223

def name
  self.class.name
end

#retrieveObject

By default, call the method associated with the property name on our provider. In other words, if the property name is ‘gid’, we’ll call ‘provider.gid’ to retrieve the current value.



244
245
246
# File 'lib/puppet/property.rb', line 244

def retrieve
  provider.send(self.class.name)
end

#safe_insync?(is) ⇒ Boolean

Determine whether the property is in-sync or not. If @should is not defined or is set to a non-true value, then we do not have a valid value for it and thus consider the property to be in-sync since we cannot fix it. Otherwise, we expect our should value to be an array, and if @is matches any of those values, then we consider it to be in-sync.

Don’t override this method.

Returns:

  • (Boolean)


157
158
159
160
161
162
163
# File 'lib/puppet/property.rb', line 157

def safe_insync?(is)
  # If there is no @should value, consider the property to be in sync.
  return true unless @should

  # Otherwise delegate to the (possibly derived) insync? method.
  insync?(is)
end

#set(value) ⇒ Object

Set our value, using the provider, an associated block, or both.



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/puppet/property.rb', line 249

def set(value)
  # Set a name for looking up associated options like the event.
  name = self.class.value_name(value)

  call = self.class.value_option(name, :call) || :none

  if call == :instead
    call_valuemethod(name, value)
  elsif call == :none
    # They haven't provided a block, and our parent does not have
    # a provider, so we have no idea how to handle this.
    self.fail "#{self.class.name} cannot handle values of type #{value.inspect}" unless @resource.provider
    call_provider(value)
  else
    # LAK:NOTE 20081031 This is a change in behaviour -- you could
    # previously specify :call => [;before|:after], which would call
    # the setter *in addition to* the block.  I'm convinced this
    # was never used, and it makes things unecessarily complicated.
    # If you want to specify a block and still call the setter, then
    # do so in the block.
    devfail "Cannot use obsolete :call value '#{call}' for property '#{self.class.name}'"
  end
end

#setup_shadow(klass) ⇒ Object

If there’s a shadowing metaparam, instantiate it now. This allows us to create a property or parameter with the same name as a metaparameter, and the metaparam will only be stored as a shadow.



277
278
279
# File 'lib/puppet/property.rb', line 277

def setup_shadow(klass)
  @shadow = klass.new(:resource => self.resource)
end

#shouldObject

Only return the first value



282
283
284
285
286
287
288
289
290
291
292
# File 'lib/puppet/property.rb', line 282

def should
  return nil unless defined?(@should)

  self.devfail "should for #{self.class.name} on #{resource.name} is not an array" unless @should.is_a?(Array)

  if match_all?
    return @should.collect { |val| self.unmunge(val) }
  else
    return self.unmunge(@should[0])
  end
end

#should=(values) ⇒ Object

Set the should value.



295
296
297
298
299
300
301
302
# File 'lib/puppet/property.rb', line 295

def should=(values)
  values = [values] unless values.is_a?(Array)

  @shouldorig = values

  values.each { |val| validate(val) }
  @should = values.collect { |val| self.munge(val) }
end

#should_to_s(newvalue) ⇒ Object



304
305
306
# File 'lib/puppet/property.rb', line 304

def should_to_s(newvalue)
  [newvalue].flatten.join(" ")
end

#syncObject



308
309
310
311
# File 'lib/puppet/property.rb', line 308

def sync
  devfail "Got a nil value for should" unless should
  set(should)
end

#unsafe_validate(value) ⇒ Object

Verify that the passed value is valid. If the developer uses a ‘validate’ hook, this method will get overridden.



315
316
317
318
# File 'lib/puppet/property.rb', line 315

def unsafe_validate(value)
  super
  validate_features_per_value(value)
end

#validate_features_per_value(value) ⇒ Object

Make sure that we’ve got all of the required features for a given value.



321
322
323
324
325
326
327
# File 'lib/puppet/property.rb', line 321

def validate_features_per_value(value)
  if features = self.class.value_option(self.class.value_name(value), :required_features)
    features = Array(features)
    needed_features = features.collect { |f| f.to_s }.join(", ")
    raise ArgumentError, "Provider must have features '#{needed_features}' to set '#{self.class.name}' to '#{value}'" unless provider.satisfies?(features)
  end
end

#valueObject

Just return any should value we might have.



330
331
332
# File 'lib/puppet/property.rb', line 330

def value
  self.should
end

#value=(value) ⇒ Object

Match the Parameter interface, but we really just use ‘should’ internally. Note that the should= method does all of the validation and such.



336
337
338
# File 'lib/puppet/property.rb', line 336

def value=(value)
  self.should = value
end