Creating resources

You can write resource types and providers in the Puppet language. The following example shows you how to create resources in Puppet using the low-level types and provider method.

Note: The Puppet Resource API is a simpler and faster way to build types and providers.

Puppet’s property support has a helper method called ensurable that handles modeling creation and destruction; it creates an ensure property and adds absent and present values for it, which require three methods on the provider, create, destroy, and exists?.

The following example is a resource called file. The resource contains the type name (file), a documentation string, a parameter for the name of the file, and used the ensurable method to say that the file is both createable and destroyable.

Puppet::Type.newtype(:file) do
    @doc = "Manage a file (the simple version)."

    ensurable

    newparam(:name) do
        desc "The full path to the file."
    end
end

The following example is a provider. The provider contains the docs, the provider name, and the three methods that the ensure property requires. Note that it uses a desc instead of @doc = to specify the documentation. It also uses Ruby’s built-in file abilities to create an empty file, remove the file, or test whether the file exists.

Puppet::Type.type(:file).provide(:posix) do
    desc "Normal Unix-like POSIX support for file management."

    def create
        File.open(@resource[:name], "w") { |f| f.puts "" } # Create an empty file
    end

    def destroy
        File.unlink(@resource[:name])
    end

    def exists?
        File.exists?(@resource[:name])
    end
end
To manage the file mode, add the following code to your resource:
newproperty(:mode) do
    desc "Manage the file's mode."

    defaultto "640"
end

Note that the default value is specified, and it is a string instead of an integer (file modes are in octal). You can pass a lambda to defaultto instead of a value, if you don’t have a simple value.

To understand modes, add the following code to the provider:

def create
    File.open(@resource[:name], "w") { |f| f.puts "" } # Create an empty file
    # Make sure the mode is correct
    should_mode = @resource.should(:mode)
    unless self.mode == should_mode
        self.mode = should_mode
    end
end

# Return the mode as an octal string, not as an integer.
def mode
    if File.exists?(@resource[:name])
        "%o" % (File.stat(@resource[:name]).mode & 007777)
    else
        :absent
    end
end

# Set the file mode, converting from a string to an integer.
def mode=(value)
    File.chmod(Integer("0" + value), @resource[:name])
end

The getter method returns the value, but does not attempt to modify the resource itself. When the setter gets passed, the value it is supposed to set — it does not attempt to figure out the appropriate value to use.

Note that the ensure property, when created by the ensurable method, behaves differently because it uses methods for creation and destruction of the file, compared to normal properties that use getter and setter methods. When you create a resource, Puppet expects the create method to make any other necessary changes. This is because resources are already configured when created, so Puppet does not need to test them manually.

The absent and present values are defined by looking in the property.rb file:

newvalue(:present) do
    if @resource.provider and @resource.provider.respond_to?(:create)
        @resource.provider.create
    else
        @resource.create
    end
    nil # return nil so the event is autogenerated
end

newvalue(:absent) do
    if @resource.provider and @resource.provider.respond_to?(:destroy)
        @resource.provider.destroy
    else
        @resource.destroy
    end
    nil # return nil so the event is autogenerated
end