Here’s where we define how the resource really works. In most cases, it’s the properties that interact with your resource’s providers. If you define a property named owner, then when you are retrieving the state of your resource, then the owner property will call the owner method on the provider. In turn, when you are setting the state (because the resource is out of sync), then the owner property will call the owner= method to set the state on disk.
There’s one common exception to this: The ensure property is special because it’s used to create and destroy resources. You can set this property up on your resource type just by calling the ensurable method in your type definition:
Puppet::Type.newtype(:database) do
ensurable
...
endThis property uses three methods on the provider: create, destroy, and exists?. The last method, somewhat obviously, is a boolean to determine if the resource current exists. If a resource’s ensure property is out of sync, then no other properties will be checked or modified.
You can modify how ensure behaves, such as by adding other valid values and determining what methods get called as a result; see existing types like package for examples.
The rest of the properties are defined a lot like you define the types, with the newproperty method, which should be called on the type:
Puppet::Type.newtype(:database) do
ensurable
newproperty(:owner) do
desc "The owner of the database."
...
end
endNote the call to desc; this sets the documentation string for this property, and for Puppet types that get distributed with Puppet, it is extracted as part of the Type reference.
When Puppet was first developed, there would normally be a lot of code in this property definition. Now, however, you normally only define valid values or set up validation and munging. If you specify valid values, then Puppet will only accept those values, and it will automatically handle accepting either strings or symbols. In most cases, you only define allowed values for ensure, but it works for other properties, too:
newproperty(:enable) do
newvalue(:true)
newvalue(:false)
endYou can attach code to the value definitions (this code would be called instead of the property= method), but it’s normally unnecessary.
For most properties, though, it is sufficient to set up validation:
newproperty(:owner) do
validate do |value|
unless value =~ /^\w+/
raise ArgumentError, "%s is not a valid user name" % value
end
end
endNote that the order in which you define your properties can be important: Puppet keeps track of the definition order, and it always checks and fixes properties in the order they are defined.
By default, if a property is assigned multiple values in an array:
It is considered in sync if any of those values matches the current value. If none of those values match, the first one will be used when syncing the property. If, instead, the property should only be in sync if all values match the current value (e.g., a list of times in a cron job), you can declare this:
newproperty(:minute, :array_matching => :all) do # :array_matching defaults to :first
...
endYou can also customize how information about your property gets logged. You can create an is_to_s method to change how the current values are described, should_to_s to change how the desired values are logged, and change_to_s to change the overall log message for changes. See current types for examples.
Handling values set on properties is currently somewhat confusing, and will hopefully be fixed in the future. When a resource is created with a list of desired values, those values are stored in each property in its @should instance variable. You can retrieve those values directly by calling should on your resource (although note that when :array_matching is set to :first you get the first value in the array, otherwise you get the whole array):
myval = should(:color)When you’re not sure (or don’t care) whether you’re dealing with a property or parameter, it’s best to use value:
myvalue = value(:color)