This post was spawned by some users asking questions about type and provider mechanics. Many (most?) people out there are not Ruby experts and therefore some of the usual ways of debugging type and provider code are not very illuminating. When searching there appeared to be a distinct lack of information on the Internet regarding Puppet type and provider execution. Specifically, where and when each part of the type and provider are executed and what you can access at each point.
If you need a VM upon which to try this code, take a look at the Free Learning Puppet VM.
This post hopes to illuminate the execution order of the various portions of a demonstration type and provider.
This is distinctly not going to cover the actual Ruby mechanics of why everything happens the way it does. If you want to delve that deeply, then I’d say to go ask the folks on the puppet-dev mailing list.
What executes on the server or client?
Now, I’ve occasionally taken some abuse for stating that types execute on the client.
This is, in fact, true.
The catalog is compiled on the server, but every part of the type and provider executes on the client against the compiled catalog. The upshot of this is that you can manipulate the catalog any way you choose if you do it in the appropriate place. But, that’s another post.
If you don’t believe me, try it for yourself! Add a file at ‘/tmp/foo’ to your client system with the content ‘client’ and add Puppet.warning(File.read(‘/tmp/foo’)) anywhere in your type methods to see what happens.
Basic Type Order
We will now walk through the basic execution order of the Puppet type.
Parameters and Properties
These execute In order of declaration inside the type. Each does the following when executed:
- Munging (Be careful! You can munge something into something else that isn’t valid at all.)
One thing to note is that, should you want to use the value of another parameter or property in one further down the line, you must declare it first. See parameters :foo and :bar in the example at the end to see what happens.
Properties and Provider Initialization
Just for extra fun, every time you run a property, you run initialize in the associated provider.
Remember that note above about declaration order? One place this doesn’t hold up is in provider initialization. You’ll see in the example below that we can see @resource[:name] but we can’t see @resource[:foo] or @resource[:bar] even though foo is declared before our property.
Yes, you heard that right, we run initialize after running through the properties and parameters. The benefit here is that you can access all values of the type post munging and validation. Therefore, you can do horrible, horrible, internal manipulation of the catalog if you so choose.
So, right after initialization we run finish. (I didn’t say this was going to make any sense.)
The finish method is run at the end of the type execution and can be used for multiple purposes. Usually, I use this to manipulate the catalog.
ALWAYS run super at the end of finish so that the autorequire methods will be called properly.
Now all of the autorequire methods calls are run. This isn’t too exciting and covered elsewhere in the Puppet documentation.
Ok, now we’re ready for the meat of our example. It’s time to run our providers!
Remember, once more, properties and parameters, and therefore, providers execute in the order that they are declared in the type.
In the provider, you can take a shortcut in declaring your getter and setter by simply declaring defines with the same name as the property in question. Unfortunately, if you want to change what insync? does, you have to re-declare it in the type. I’m hoping that they’ll add an equivalent ‘?’ define for the properties for consistency.
So, execution is with non-shortcut methods in parenthesis:
Get the current value of the property from the system.
Sync Check (insync?)
Check to see if the property is in sync with what the user provided in the Puppet code.
Set the system to match what the user expects.
This one is fun. The ‘flush‘ method is run if any provider in the resource is out of sync (if insync? returns ‘false‘). You can use this for all sorts of interesting things. See the previous post for an example.
Congratulations, you made it to the end of the run! As a prize, here’s a graphic of this process as well as some code to play with yourself.
All code can be found in the Onyx Point Github repository at http://git.io/_Bjamg
Trevor has worked in a variety of IT fields over the last
decade, including systems engineering, operating system
automation, security engineering, and various levels of
At OP his responsibilities include maintaining overall
technical oversight for Onyx Point solutions, providing
technical leadership and mentorship to the DevOps teams. He is
also responsible for leading OP’s solutions and intellectual
property development efforts, setting the technical focus of
the company, and managing OP products and related services. In
this regard, he oversees product development and delivery as
well as developing the strategic roadmap for OP’s product line.
At Onyx Point, our engineers focus on Security, System
Administration, Automation, Dataflow, and DevOps consulting for
government and commercial clients. We offer professional
services for Puppet, RedHat, SIMP, NiFi, GitLab, and the other
solutions in place that keep your systems running securely and
efficiently. We offer Open Source Software support and
Engineering and Consulting services through GSA IT Schedule 70.
As Open Source contributors and advocates, we encourage the use
of FOSS products in Government as part of an overarching IT
Efficiencies plan to reduce ongoing IT expenditures attributed
to software licensing. Our support and contributions to Open
Source, are just one of our many guiding principles
- Customer First.
- Security in All We Do.
- Pursue Innovation with Integrity.
- Communicate Openly and Respectfully.
- Offer Your Talents, and Appreciate the Talents of Others