Pulling Strings With Puppet - James Turnbull [54]
The ParsedFile class, combined with the use of the ensurable helper method, tells Puppet that, depending on the setting of the ensure property, a particular shell should be present or absent.
The ensurable helper method also makes three methods available in your providers: create, destroy, exists?. The latter, exists?, allows logic to be added that determines whether the particular resource exists. The former methods, create and destroy, will contain the logic required to either create or destroy the resource, respectively. We're not using these methods as the ParsedFile class already provides this functionality, but you could also create a provider that utilized their functionality like so:
Here we have a provider that makes uses of the three ensureable methods to create, delete, and check for the existence of a file. Using these methods and some simple Ruby, you can perform a variety of useful functions that should allow you to develop basic types.
Back to our shells provider; we can see the record-line function takes the name of the shell from the name variable, in our case, the shell parameter in our resource type. In Listing 7-9, you can see an example of a resource that uses our shells resource type.
The resource in Listing 7-9 would add the /bin/bash shell to the /etc/shells file, if it wasn't already present. By changing the ensure attribute to absent, the resource would remove the shell from the file.
Tip - This is a very simple introduction to constructing providers. To find more about developing providers, refer to the documentation available on the Wiki at http://reductivelabs.com/trac/puppet/wiki/ProviderDevelopment.
Distributing Our New Type
Once we've created our new type and provider, we need to deploy it onto our master servers and clients. The master servers need it to be able to define resources in manifests, and the clients need it to be able to actually implement the resources on the client. To do this distribution, we could install our types and providers into the relevant type and provider directories in the Puppet package. But an easier and more effective method exists that makes use of a Puppet function called pluginsync.
The pluginsync function synchronizes the contents of a source, called pluginsource, to the libdir directory. This works in same way factsync synchronizes custom facts. The libdir directory is defined by default as $vardir/lib, usually /var/puppet/lib. The pluginsource option is usually a file mount called plugins.
To configure pluginsync, we need to configure both our master and client. In Listing 710, you can see the required master configuration.
In Listing 7-10, we've enabled the pluginsource as the plugins file mount. We've defined vardir to the default location of /var/puppet and finally specified the lib directory, where we will place our custom types and providers on the master. You should place your types in suitable directories. Usually this would be a type and a provider directory, and we would copy our type and provider into the directories. In Listing 7-11, we have created some directories and copied in the custom type and provider we have just created.
Next, we need to enable this file mount in the fileserver. conf configuration file on our master server as you can see in Listing 7-12.
In Listing 7-12, we've added a plugins mount and allowed access from all testing. com nodes.
Now on our client, we also need to configure pluginsync as you can see in Listing 7-13.
We enable the pluginsync option by setting it to true. We then set the libdir directory that will be the destination for our custom types and providers. Here we've defined the location as /var/puppet/lib. Next, we've specified where Puppet will find custom types, in our case on the plugins file mount on our Puppet master. Lastly, we set the plugindest option to tell Puppet to place our types and providers in this directory.
After configuration, we restart both the master and the client. When the client next connects to the master, pluginsync