Class: Puppet::Property

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

Direct Known Subclasses

IniProperty, Ensure, KeyValue, List, VDev, SELFileContext

Defined Under Namespace

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

Constant Summary

Constants included from Util::Docs

Util::Docs::HEADER_LEVELS

Constants included from Util

Util::AbsolutePathPosix, Util::AbsolutePathWindows

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes inherited from Parameter

#parent, #resource

Attributes included from Util::Docs

#doc, #nodoc

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Parameter

aliasvalue, defaultto, desc, #devfail, doc, #fail, format_value_for_display, 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, #markdown_definitionlist, #markdown_header, #nodoc?, #pad, scrub

Methods included from Util

absolute_path?, activerecord_version, benchmark, binread, chuser, classproxy, #execfail, #execpipe, execute, execute_posix, execute_windows, logmethods, memory, path_to_uri, proxy, replace_file, safe_posix_fork, symbolize, symbolizehash, symbolizehash!, synchronize_on, thinmark, #threadlock, uri_to_path, wait_for_output, which, withumask

Methods included from Util::POSIX

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

Methods included from Util::MethodHelper

#requiredopts, #set_options, #symbolize_options

Methods included from Util::Logging

#clear_deprecation_warnings, #deprecation_warning, #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



143
144
145
146
147
148
149
# File 'lib/vendor/puppet/property.rb', line 143

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/vendor/puppet/property.rb', line 19

def name
  @name
end

.unmanagedObject

Returns the value of attribute unmanaged.



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

def unmanaged
  @unmanaged
end

Instance Attribute Details

#noopObject

for testing whether we should actually do anything



262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/vendor/puppet/property.rb', line 262

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.



140
141
142
# File 'lib/vendor/puppet/property.rb', line 140

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/vendor/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/vendor/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/vendor/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



167
168
169
# File 'lib/vendor/puppet/property.rb', line 167

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/vendor/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/vendor/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/vendor/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
75
76
# File 'lib/vendor/puppet/property.rb', line 70

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

#call_valuemethod(name, value) ⇒ Object

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



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

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?



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

def change_to_s(current_value, newvalue)
  begin
    if current_value == :absent
      return "defined '#{name}' as #{self.class.format_value_for_display should_to_s(newvalue)}"
    elsif newvalue == :absent or newvalue == [:absent]
      return "undefined '#{name}' from #{self.class.format_value_for_display is_to_s(current_value)}"
    else
      return "#{name} changed #{self.class.format_value_for_display is_to_s(current_value)} to #{self.class.format_value_for_display 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.



136
137
138
# File 'lib/vendor/puppet/property.rb', line 136

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

#event_nameObject

Figure out which event to return.



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

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 may be overridden by derived classes if necessary to provide extra logic to determine whether the property is in sync. In most cases, however, only ‘property_matches?` needs to be overridden to give the correct outcome - without reproducing all the array matching logic, etc, found here.

Returns:

  • (Boolean)


176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/vendor/puppet/property.rb', line 176

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, either for all the @should values, or any of
  # them, depending on the configuration of this property.
  if match_all? then
    # Emulate Array#== using our own comparison function.
    # A non-array was not equal to an array, which @should always is.
    return false unless is.is_a? Array

    # If they were different lengths, they are not equal.
    return false unless is.length == @should.length

    # Finally, are all the elements equal?  In order to preserve the
    # behaviour of previous 2.7.x releases, we need to impose some fun rules
    # on "equality" here.
    #
    # Specifically, we need to implement *this* comparison: the two arrays
    # are identical if the is values are == the should values, or if the is
    # values are == the should values, stringified.
    #
    # This does mean that property equality is not commutative, and will not
    # work unless the `is` value is carefully arranged to match the should.
    return (is == @should or is == @should.map(&:to_s))

    # When we stop being idiots about this, and actually have meaningful
    # semantics, this version is the thing we actually want to do.
    #
    # return is.zip(@should).all? {|a, b| property_matches?(a, b) }
  else
    return @should.any? {|want| property_matches?(is, want) }
  end
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



228
229
230
# File 'lib/vendor/puppet/property.rb', line 228

def is_to_s(currentvalue)
  currentvalue
end

#log(msg) ⇒ Object

Send a log message.



233
234
235
236
237
238
239
# File 'lib/vendor/puppet/property.rb', line 233

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)


242
243
244
# File 'lib/vendor/puppet/property.rb', line 242

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

#munge(value) ⇒ Object

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



247
248
249
250
251
# File 'lib/vendor/puppet/property.rb', line 247

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



257
258
259
# File 'lib/vendor/puppet/property.rb', line 257

def name
  self.class.name
end

#property_matches?(current, desired) ⇒ Boolean

Compare the current and desired value of a property in a property-specific way. Invoked by ‘insync?`; this should be overridden if your property has a different comparison type but does not actually differentiate the overall insync? logic.

Returns:

  • (Boolean)


217
218
219
220
221
222
# File 'lib/vendor/puppet/property.rb', line 217

def property_matches?(current, desired)
  # This preserves the older Puppet behaviour of doing raw and string
  # equality comparisons for all equality.  I am not clear this is globally
  # desirable, but at least it is not a breaking change. --daniel 2011-11-11
  current == desired or current == desired.to_s
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.



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

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)


159
160
161
162
163
164
165
# File 'lib/vendor/puppet/property.rb', line 159

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.



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/vendor/puppet/property.rb', line 283

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.



311
312
313
# File 'lib/vendor/puppet/property.rb', line 311

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

#shouldObject

Only return the first value



316
317
318
319
320
321
322
323
324
325
326
# File 'lib/vendor/puppet/property.rb', line 316

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.



329
330
331
332
333
334
335
336
# File 'lib/vendor/puppet/property.rb', line 329

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



338
339
340
# File 'lib/vendor/puppet/property.rb', line 338

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

#syncObject



342
343
344
345
# File 'lib/vendor/puppet/property.rb', line 342

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.



349
350
351
352
# File 'lib/vendor/puppet/property.rb', line 349

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.



355
356
357
358
359
360
361
# File 'lib/vendor/puppet/property.rb', line 355

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.



364
365
366
# File 'lib/vendor/puppet/property.rb', line 364

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.



370
371
372
# File 'lib/vendor/puppet/property.rb', line 370

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