Being relatively new to Chef, I am required to create libraries or definitions from existing recipes.
There recipes use bash resource, ruby block resource (which notifies another ruby block resource with delayed timing), template resource again which notifies a ruby block etc.
What would be the best approach to this? Library or definition?
I have read that if I use definition, I won't be able to notify a resource within the definition, does that mean I can notify a resource in a different definition file?
I also read that in libraries you cant use the resources directly. If this is true, how can I use a resource within my library?
The most common use case for a library is to provide helper methods to your cookbook, either to reduce code duplication, or simply to make recipe code more understandable by hiding implementation logic. Consider a trivial example: suppose I only want to have my user account created on a system if it has bacon.
Because a library is built using Ruby, anything that can be done with Ruby can be done in a library file, including advanced functionality such as extending built-in Chef classes. The syntax for a library varies because library files are created using Ruby and are designed to handle custom situations. See the Examples section below for samples.
These libraries are often no more than a few lines long, but can also be as simple or as sophisticated as you want. Once written, the methods in the library can be re-used by recipes within any cookbook that depends on it.
Once we open the chef::recipe class, there are changes that it gets polluted. As a best practice, it is always a better way to introduce a new sub class inside the library and define a method as class method. This avoids pulling the chef::recipe namespace.
So, this is "primarily opinion based", but I'll answer it anyway. There are 4 distinct choices here:
A definition is just a wrapper around one or more resources with some parameterization. However, definitions are not added to the resource collection. Meaning you can't "notify" or trigger events on a definition. They are solely for wrapping and naming a series of repeatable steps found in a recipe.
An LWRP (Light-weight resource and provider) is a Chef-specific DSL that actually compiles into an HWRP (Heavy-weight resource and provider) at runtime. Both LWRPs and HWRPs are Chef extensions. In addition to wrapping a series of repeatable tasks, *WRPs will create a top-level resource in Chef (like template
or package
) that's available for use in your recipe and other cookbook's recipes as well.
The difference between and LWRP and HWRP is really the Ruby. HWRPs use full-blown Ruby classes. If you aren't a Ruby developer, they may be a bit intimidating. Nonetheless, you should give it a try before writing and LWRP. LWRPs use a Chef-specific DSL for creating resources. At the end of the day, they compile to (roughly) the same code as the Heavy-weight counterpart. I'll link some references at the end. You have access to Chef resources inside either implementation, as well as the run_context.
Finally, "libraries" (notice the quotes) are often misunderstood and abused. They are Ruby code, evaluated as Ruby, so they can do pretty much anything. HWRPs are actually a form of a library. Sometimes people use libraries as "helpers". They will create a helper module with methods like best_ip_for
or aggregate_some_data
and then "mix" (Rubyism) that library into their recipes or resources to DRY things up. Other times, libraries can be use to "hack" Chef itself. The partial-search cookbook is a good example of this. Facebook talked about how they limited the number of attributes sent back to the server last year at ChefConf too. Libraries are really an undefined territory because they are the keys to the kingdom.
So, while I haven't actually answered your question (because it's opinion-based), I hope I've given you enough information about the best direction moving forward. Keep in mind that every infrastructure is a special snowflake and there is no right answer; there's only a best answer. I'd suggest sharing this information with your team and weighing the pros and cons of each approach. You can also try the Chef mailing list, on which people will give you many opinions.
Resources:
Modern Chef terminology has rebranded "LWRPs" as "Custom Resources" and the "Provider" that is the "P" of the "LWRP" has melted into the background and users just run actions now (the action_class
is the way to access the old provider
class).
Definitions still exist, are still discouraged, and still have known bugs which will never be fixed. There is no reason to use them.
Custom Resources are what everyone should use. More people should move recipe code into custom resources for reusability. The basic steps are simple:
provides
line for the name of the resourceinclude_recipe
call in recipes into a call to the custom resource.That's all that is necessary for simple cases. Once that is done the resource can now be extended by adding properties, or existing node attributes can be converted into properties (the node attributes can be pushed back into the call to the resource from recipe mode).
For modern resources on Chef-15/16 consider setting unified_mode true
to remove the compile/converge phase from the custom resource and simplify writing the resource.
For an example of the conversion of a simple recipe to a custom resource see this answer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With