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?
So, this is "primarily opinion based", but I'll answer it anyway. There are 4 distinct choices here:
Definition
LWRP
HWRP
"Library"
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:
LWRPs
HWRPs
Libraries
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:
Move the code into a resources file
Wrap the code with an action
Add a provides line for the name of the resource
Change the include_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
Related
How can I create a recipe that will populate its attributes using the fiels from an instance of an object in a generic way?
As an example, consider the following recipe:
component = $auth_docker
docker_image component.name do
registry component.registry
tag component.tag
action :pull
end
When you have 50s of recipes that look like this, maintaining them really gets overwhelming.
In Python, i would probably implement a solution that would look a bit like this:
docker_image = DockerImage(**$auth_docker)
Or, I would create some sort of helper function to build it for me:
def generate_docker_image_lwrp(attributes):
lwrp = DockerImage()
lwrp.registry = attributes.registry
lwrp.tag = attributes.tag
return lwrp
The goal is to reduce maintenance on the recipes. For instance this morning I wanted to add Chef's "retries" attribute on all recipes that pull an image. I had to edit all of them - I don't want that. I should've been able to a) add the attribute to the stack's JSON b) edit the Ruby wrapper class so that instances of it (i.e.: $auth_docker) get the "retries" field, then c) add the retries attribute to the lwrp-generator. Since all recipes would use the same generator, recipes wouldn't need to be edited at all.
Is this possible using Chef, in a way that 'notifies' still work?
Quoting the Documentation
A definition is code that is reused across recipes, similar to a
compile-time macro. A definition is created using arbitrary code
wrapped around built-in chef-client resources—file, execute, template,
and so on—by declaring those resources into the definition as if they
were declared in a recipe. A definition is then used in one (or more)
recipes as if it were a resource.
Though a definition behaves like a resource, some key differences
exist. A definition:
Is not a resource or a lightweight resource Is defined from within the
/definitions directory of a cookbook Is loaded before resources during
the chef-client run; this ensures the definition is available to all
of the resources that may need it May not notify resources in the
resource collection because a definition is loaded before the resource
collection itself is created; however, a resource in a definition may
notify a resource that exists within the same definition Automatically
supports why-run mode, unlike lightweight resources Use a defintion
when repeating patterns exist across resources and/or when a simple,
direct approach is desired. There is no limit to the number of
resources that may be included in a definition: use as many built-in
chef-client resources as necessary.
I.e: you can create a definition for this in a library cookbook used solely for this.
docker_library/defintions/default.rb
define :my_docker_image, :component => nil do
component = params[:component]
docker_image component.name do
registry component.registry
tag component.tag
action :pull
end
end
in your recipes (need to have a depends on the docker_library cookbook in the metadata.rb):
my_component = $auth_docker
my_docker_image my_component.name do
component my_component
end
A more complete exemple of definition is available in the logrotate cookbook
I'm quite new to Prism. I'm studying QuickStarts shipped with it as well as other examples on the net. Almost all of them make modules aware of what region their view(s) get dropped into. Typically, the method Initalize of a module has a line like the the following.
RegionManager.Regions["LeftRegion"].Add(fundView);
I feel quite uncomfortable with that. There's a similar discussion but I think that it should be the responsibility of the shell component to define such mapping. However, I cannot find any example of such approach and I'm not sure whether the bootstrapper is the right place to put such mapping in.
Is this approach completely wrong?
Nothing is completely wrong. But it makes no sense to have the shell/bootstrapper (that by design doesn't know anything about the application it will host) knows what view goes into which region.
Consider an application that can be extended by simply adding modules into a given folder. When you follow the approach that the module knows where it's views want to reside (the mapping is done in Initialize()), this is no problem. I designed my first Prism application that way.
But if your mapping is done in your shell you always have to update your shell (which is part of the base application, not any module) when you want to add another module. This runs contrary to the loosely coupling paradigm. Besides that you have to create one base application for every module constellation. And there are (2^number of modules) permutations you have to cover. That results in loosing your flexibility you gained by using Prism.
Say I am writing a Ruby gem. I want to design classes and modules going to be used.
How to identify them?
Where do I need classes and where do I need modules?
Your question is about one of the main design feature of the Ruby language.
Basically, you can see module as collection of tools, and class as collection of objects which are able to mix with those tools.
Ruby faq says about modules :
Modules are collections of methods and constants. They cannot generate instances.
When you want to provide something, you'll need a class. You can do a MyClass.new, you cannot with a module : MyModule.new won't work.
On the other hand :
Classes may generate instances (objects), and have per-instance state (instance variables).
When you want to provide a way of doing something, you'll a need a module. You can do a MyModule.doSomething(SomeParams). You can also do that with a class methods, but you won't be able to do some mix-in with it.
See this faq for a more detailed answer.
This is a object oriented design task, if you are really new to that I would recommend to study a book like Head First Object-Oriented Analysis and Design. I usually try to identify the core actors/concepts in the business model to discover which classes I need.
A basic rule is to use classes when you need to maintain some states, and modules when there is no need of maintaining states. Ruby has several uses for modules Ruby, there are several articles about this topic in the Practicing Ruby blog: part 1, part 2, part 3, part 4
I use to think of Modules stricly as as behaviour capsules and Classes as state and behaviour capsules (from encapsulation).
So, if you want to encapsulate a behaviour use a module. Otherwise use a class.
After developing in CodeIgniter for awhile, I find it difficult to make decisions when to create a custom library and when to create a custom helper.
I do understand that both allow having business logic in it and are reusable across the framework (calling from different controller etc.)
But I strongly believe that the fact that CI core developers are separating libraries from helpers, there has to be a reason behind it and I guess, this is the reason waiting for me to discover and get enlightened.
CI developers out there, pls advise.
i think it's better to include an example.
I could have a
class notification_lib {
function set_message() { /*...*/}
function get_message() {/*...*/}
function update_message() {/*...*/}
}
Alternatively, i could also include all the functions into a helper.
In a notification_helper.php file, i will include set_message(), get_message(), update_message()..
Where either way, it still can be reused. So this got me thinking about the decision making point about when exactly do we create a library and a helper particularly in CI.
In a normal (framework-less) php app, the choice is clear as there is no helper, you will just need to create a library in order to reuse codes. But here, in CI, I would like to understand the core developers seperation of libraries and helpers
Well the choice comes down to set of functions or class. The choice is almost the same as a instance class verses a static class.
If you have just a simply group of functions then you only need to make a group of functions. If these group of functions share a lot of data, then you need to make a class that has an instance to store this data in between the method (class function) calls.
Do you have many public or private properties to store relating to your notification messages?
If you use a class, you could set multiple messages through the system then get_messages() could return a private array of messages. That would make it perfect for being a library.
There is a question I ask myself when deciding this that I think will help you as well. The question is: Am I providing a feature to my framework or am I consolidating?
If you have a feature that you are adding to your framework, then you'll want to create a library for that. Form validation, for example, is a feature that you are adding to a framework. Even though you can do form validation without this library, you're creating a standard system for validation which is a feature.
However, there is also a form helper which helps you create the HTML of forms. The big difference from the form validation library is that the form helper isn't creating a new feature, its just a set of related functions that help you write the HTML of forms properly.
Hopefully this differentiation will help you as it has me.
First of all, you should be sure that you understand the difference between CI library and helper class. Helper class is anything that helps any pre-made thing such as array, string, uri, etc; they are there and PHP already provides functions for them but you still create a helper to add more functionality to them.
On the other hand, library can be anything like something you are creating for the first time, any solution which might not be necessarily already out there.
Once you understand this difference fully, taking decision must not be that difficult.
Helper contains a group of functions to help you do a particular task.
Available helpers in CI
Libraries usually contain non-CI specific functionality. Like an image library. Something which is portable between applications.
Available libraries in CI
Source link
If someone ask me what the way you follow when time comes to create Helpers or Libraries.
I think these differences:
Class : In a nutshell, a Class is a blueprint for an object. And an object encapsulates conceptually related State and Responsibility of something in your Application and usually offers an programming interface with which to interact with these. This fosters code reuse and improves maintainability.
Functions : A function is a piece of code which takes one more input in the form of parameter and does some processing and returns a value. You already have seen many functions like fopen() and fread() etc. They are built-in functions but PHP gives you option to create your own functions as well.
So go for Class i.e. libraries if any one point matches
global variable need to use in two or more functions or even one, I hate using Global keyword
default initialization as per each time call or load
some tasks are private to entity not publicly open, think of functions never have public modifiers why?
function to function dependencies i.e. tasks are separated but two or more tasks needs it. Think of validate_email check only for email sending script for to,cc,bcc,etc. all of these needs validate_email.
And Lastly not least all related tasks i.e. functions should be placed in single object or file, it's easier for reference and remembrance.
For Helpers : any point which not matches with libraries
Personally I use libraries for big things, say an FTP-library I built that is a lot faster than CodeIgniters shipped library. This is a class with a lot of methods that share data with each other.
I use helpers for smaller tasks that are not related to a lot of other functionality. Small functions like decorating strings might be an example. Or copying a directory recursively to another location.
What are some defining characteristics of a Ruby DSL that separate it from just a regular API?
When you use an API you instantiate objects and call methods in an imperative manner. On the other hand a good DSL should be declarative, representing rules and relationships in your problem domain, not instructions to be executed. Moreover ideally DSL should be readable and modifiable by somebody who is not a programmer (which is not the case with APIs).
Also please keep in mind the distinction between internal and external DSLs.
Internal domain specific language is embedded in a programming language (eg. Ruby). It's easy to implement, but the structure of the DSL is dependent on the parent language it is embedded in.
External domain specific language is a separate language designed with the particular domain in mind. It gives you a greater flexibility when it comes to syntax, but you have to implement the code to interpret it. It's also more secure, as the person editing domain rules doesn't have access to all the power of the parent language.
DSL (domain specific language) is an over-hyped term. If you are simply using a sub-set of a language (say Ruby), how is it a different language than the original? The answer is, it isn't.
However, if you do some preprocessing of the source text to introduce new syntax or new semantics not found in the core language then you indeed have a new language, which may be domain-specific.
The combination of Ruby's poetry mode and operator overloading does present the possibility of having something that is at the same time legal Ruby syntax and a reasonable DSL.
And the continued aggravation that is XML does show that perhaps the simple DSL built into all those config files wasn't completely misguided..
Creating a DSL:
Adding new methods to the Object class so that you can just call them as if they were built-in language constructs. (see rake)
Creating methods on a custom object or set of objects, and then having script files run the statements in the context of a top-level object. (see capistrano)
API design:
Creating methods on a custom object or set of objects, so the user creates an object to use the methods.
Creating methods as class methods, so that the user prefixes the classname in front of all the methods.
Creating methods as a mixin that users include or extend to use the methods in their custom objects.
So yes, the line is thin between them. It's trivial to turn a custom set of objects into a DSL by adding one method that runs a script file in the right context.
The difference between a DSL and an API to me is that a DSL could be at least understood (and verified) if not written as a sub-language of Ruby by someone in that domain.
For example, you could have financial analysts writing rules for a stock trading application in a Ruby DSL and they would never have to know they were using Ruby.
They are, in fact, the same thing. DSLs are generally implemented via the normal language mechanisms in Ruby, so technically they're all APIs.
However, for people to recognize something as a DSL, it usually ends up adding what look like declarative statements to existing classes. Something like the validators and relationship declarations in ActiveRecord.
class Foo << ActiveRecord::Base
validates_uniqueness_of :name
validates_numericality_of :number, :integer_only => true
end
looks like a DSL, while the following doesn't:
class Foo <<ActiveRecord::BAse
def validate
unless unique? name
errors.add(:name, "must be unique")
end
unless number.to_s.match?(/^[-]?\d$/)
errors.add(:number, "must be an integer")
end
end
end
They're both going to be implemented by normal Ruby code. It's just that one looks like you've got cool new language constructs, while the other seems rather pedestrian (and overly verbose, etc. etc.)