Puppet - Type and Provider


Advertisements

Puppet types are used for individual configuration management. Puppet has different types like a service type, package type, provider type, etc. Wherein each type has providers. The provider handles the configuration on different platforms or tools. For example, the package type has aptitude, yum, rpm, and DGM providers. There are a lot of types and Puppet covers a good spectrum configuration management item that needs to be managed.

Puppet uses Ruby as its base language. All Puppet types and providers present are written in Ruby language. As it follows the standard encoding format, one can simply create them as shown in the example for repo which manages repositories. Here, we will create type repo and providers’ svn and git. The first part of the repo type is type itself. The types are usually stored in lib/puppet/type. For this, we will create a file called repo.rb.

$ touch repo.rb

Add the following content in the file.

Puppet::Type.newtype(:repo) do  
@doc = "Manage repos"  
   Ensurable   
   newparam(:source) do 
      desc "The repo source"  
      
      validate do |value| 
         if value =~ /^git/ 
            resource[:provider] = :git 
         else 
            resource[:provider] = :svn 
         end 
      end 
      isnamevar 
   end  

   newparam(:path) do 
      desc "Destination path"  
      validate do |value| 
         unless value =~ /^\/[a-z0-9]+/ 
            raise ArgumentError , "%s is not a valid file path" % value 
         end 
      end 
   end 
end 

In the above script, we have created a block "Puppet::Type.newtype(:repo) do" which creates a new type with the name repo. Then, we have @doc which helps in adding whatever level of details one wants to add. The next statement is Ensurable; it creates a basic ensure property. Puppet type uses ensure property to determine the state of configuration item.

Example

service { "sshd": 
   ensure => present, 
} 

The ensure statement tells Puppet to except three method: create, destroy, and exist in the provider. These methods provide the following features −

  • A command to create a resource
  • A command to delete a resource
  • A command to check the existence of a resource

All we then need to do is specify these methods and their contents. Puppet creates the supporting infrastructure around them.

Next, we define a new parameter called source.

newparam(:source) do 
   desc "The repo source" 
   validate do |value| 
      if value =~ /^git/ 
         resource[:provider] = :git 
      else 
         resource[:provider] = :svn 
      end 
   end 
   isnamevar 
end

The source will tell the repo type where to retrieve/clone/checkout the source repository. In this, we are also using a hook called validate. In the provider section, we have defined git and svn which check for the validity of the repository we have defined.

Finally, in the code we have defined one more parameter called path.

newparam(:path) do 
   desc "Destination path" 
   validate do |value| 
      unless value =~ /^\/[a-z0-9]+/ 
         raise ArgumentError , "%s is not a valid file path" % value 
      end 

This is the value type which specifies where to put the new code that is retrieved. Here, again use the validate hook to create a block that checks the value of appropriateness.

Subversion Provider Use Case

Let’s start with the subversion provider using the above created type.

require 'fileutils' 
Puppet::Type.type(:repo).provide(:svn) do 
   desc "SVN Support"  
   
   commands :svncmd => "svn" 
   commands :svnadmin => "svnadmin"  
   
   def create 
      svncmd "checkout", resource[:name], resource[:path] 
   end  
   
   def destroy 
      FileUtils.rm_rf resource[:path] 
   end  
    
   def exists? 
      File.directory? resource[:path] 
   end 
end

In the above code, we have upfront defined that we need fileutils library, require 'fileutils' which we are going to use method from.

Next, we have defined the provider as block Puppet::Type.type(:repo).provide(:svn) do which tells Puppet that this is the provider for type called repo.

Then, we have added desc which allows to add some documentation to the provider. We have also defined the command that this provider will use. In the next line, we are checking the features of resource like create, delete, and exist.

Creating a Resource

Once all the above is done, we will create a resource which will be used in our classes and manifest files as shown in the following code.

repo { "wp": 
   source => "http://g01063908.git.brcl.org/trunk/", 
   path => "/var/www/wp", 
   ensure => present, 
}
Advertisements