Advanced Chef: Writing Heavy Weight Resource Providers (HWRP)
The last in a short series of Chef related blog posts
Heavy Weight Resource Providers
This is a bit of a backwards term. When Chef first came out, there was no Light Weight Resource Provider (LWRP) syntax and any hardcore extension to Chef had to be written in Ruby. However, Opscode saw a need to be filled and created LWRP, making it easier to create your own Resources. The problem comes when LWRP cannot fulfill all of your needs. This means you need to fall back to writing pure ruby code. For lack of a better term, I’ll call this method a HWRP, or Heavy Weight Resource Provider.
While writing a LWRP is meant to be simple and elegant, writing a HWRP is meant to be flexible. It gives you the full power of ruby in exchange for elegance.
Let’s go over some interactions between LWRP and HWRP.
A few things you need to know
HWRPs and LWRPS are interchangeable
With LWRP you are taught to create a Resource and a Provider together. This is the simplest way. However, just because you need to convert a resource definition or a provider into a HWRP you do not need to convert both.
The LWRP syntax ’compiles’ into real ruby code, so Chef will not know the difference in how they were defined. A valid cookbook directory structure:
1 2 3 4 5 6 7 8 |
|
HWRPs live in library files
Anything you put in resources/
or providers/
Chef will attempt to parse at runtime. We don’t want Chef trying to read our HWRP as the Chef DSL, we want it to interpret it as code. Luckily, anything stored in the libraries/ folder Chef will try to import at runtime. A good example of this can be seen in the runit cookbook.
How to write a HWRP:
Let’s go through an example. We are going to create a HWRP that is very simple, it could easily be written as a LWRP. In fact, it will be. While we write the HWRP I will post examples of the analogous LWRP code when applicable.
- Cookbook Name:
cloud
- Resource Name:
magic
An example of calling this in a recipe:
1 2 3 4 5 |
|
Resources
Class Structure
We need to inherit from the appropriate Chef classes in our HWRP. Note the class hierarchy as well as the inheritance:
HWRP
1 2 3 4 5 6 7 8 9 10 11 |
|
LWRP
This has no counterpart in a LWRP as this part is done automagically by Chef when it reads your files.
Initialization Method
We need to override the initialize method to make sure we have some defaults. We aren’t defining all of our resource attributes here, just the ones that need defaults.
HWRP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Here is a similar LWRP although it actually defines a bit more than the HWRP due to the terseness of the syntax.
LWRP
1 2 3 4 5 |
|
Attribute Methods
Now lets set up some attribute methods in our HWRP. Make sure to read the code comments for an explanation of what is going on.
HWRP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
There are no more changes to our LWRP everything we just added with these two methods is already included in the LWRP syntax.
LWRP
1 2 3 4 5 |
|
Awesome, now we have defined our resource. Let’s move on to a basic provider.
Providers
Class Structure
Very similar to resources, here is the basic class structure for a provider.
HWRP
1 2 3 4 5 6 7 8 9 |
|
LWRP
Once again, this is pure boilerplate with no analogy in a LWRP.
Initialization Method
While we don’t need to write an initialize method (we can), we do need to override load_current_resource
.
HWRP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
LWRP
No LWRP changes yet, all we have done so far is set up some boilerplate for the HWRP.
Action Methods
Now it is time to define what we do in our actions, with our HWRP we need to define methods like action_create to define a :create
action. Chef will do some introspection to find these methods and hook them up.
HWRP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
For our LWRP, it is pretty simple
LWRP
1 2 3 4 5 6 7 |
|
Off into the wild blue yonder
At this point you should have a functioning HWRP. Sure, it doesn’t do anything, but it is best to start small.
Also take a look at the swap cookbook, a hybrid cookbook with a provider written as a HWRP.
Now that you can read these, you should be able to start picking apart definitions inside Chef core as they are very similar.
Andrew Gross is a Developer at Yipit, you can find him as @awgross on Twitter