Lightweight Resource Providers
This chapter discusses lightweight resource providers (LWRPs). They are a way to enhance the functionality of chef to provide new integrations which are not provided for out-of-box in chef.
Lightweight Resource Providers
A resource is something that defines the action that needs to be taken and a provider is something that executes that action.
To implement the functionality of a resource and provider in a recipe which is not an inbuilt resource provider, you can create your own LWRPs. You can use custom Ruby codes and inbuilt chef resources to create an LWRP.
LWRPs help in achieving the core objective of chef which is idempotence. One can achieve this state using scripts or recipes by leveraging “if”-type constructs to choose when to run the script; however, this process becomes fairly complex to manage.
LWRPs help us in achieving idempotence for complex and scalable infrastructure to provide reliable configuration management.
LWRPs are loaded from files that are saved in the following cookbook subdirectories:
Directory |
Description |
---|---|
providers/ |
The subdirectory in which lightweight providers are located. |
resources/ |
The subdirectory in which lightweight resources are located. |
The name of the cookbook and the name of the files in the resources/ and providers/ subdirectories determine the naming patterns of LWRPs.
For example, if a cookbook named example was downloaded to the chef repository, it would be located under /cookbooks/example/. If that cookbook contained two resources and two providers, the following files would be part of the resources/ directory:
Files |
Resource Name |
Generated Class |
---|---|---|
default.rb |
Example |
Chef::Resource::Example |
custom.rb |
Custom |
Chef::Resource::ExampleCustom |
And the following files would be part of the providers/ directory:
Files |
Provider Name |
Generated Class |
---|---|---|
default.rb |
Example |
Chef::Provider::Example |
custom.rb |
Custom |
Chef::Provider::ExampleCustom |
Chef-Maintained LWRPs
Chef maintains a number of LWRPs. We will discuss some of the important LWRPs maintained by the Opscode community. These are available in cookbooks. If we need to use them, we need to download the cookbook from the community, upload the cookbook to our chef server, and then use them in our custom recipes.
Cookbook |
Description |
---|---|
apt |
This cookbook is used to configure APT (Advanced Packaging Tool) for managing APT preferences and repositories. |
aws |
AWS refers to Amazon Web Services. This cookbook can be used to manage the resources that are running in AWS cloud. |
chef_handler |
This cookbook is used for exception handling. It distributes and enables the exception and report handlers. |
cron |
Cron is used to schedule something in Unix. This cookbook is used to install cron and start its service. |
daemontools |
Daemontools are used to manage Unix services. This cookbook is used to install and configure daemontools. |
firewall |
This cookbook is used to maintain the firewall rules. |
homebrew |
Homebrew is a package manager for Mac OS. This cookbook helps us to install and configure Homebrew. |
iis |
This is a Windows-based cookbook and can be used to install and configure IIS (Internet Information Services) server. |
lvm |
This cookbook is used to install the LVM2 package and then manage LVM. |
nginx |
This cookbook is used to install and configure Nginx from source code or package and then set up configuration handling. |
php |
This cookbook can be used to install and configure PHP and custom modules for PHP. |
postfix |
This cookbook can be used to install and configure Postfix. |
powershell |
This cookbook is used to install the Powershell module on Windows servers. |
rabbitmq |
This cookbook will install the RabbitMQ-server. |
squid |
This cookbook is used to install and configure Squid as a caching proxy server. |
sudo |
This cookbook is used install sudo and then configure the/etc/sudoers file. |
windows |
This cookbook can be used for the built-in Windows commands. |
yum |
This cookbook is used for the yum configuration file. |
Creating an LWRP
This section will demonstrate how to create an LWRP. We will create an LWRP to download Wordpress setup, extract it to the desired location, and then delete the downloaded file.
knife cookbook create wp_setup
Figure 10-1. Directory structure
actions :extract, :remove
attribute :wp_url, :kind_of=> String, default: "https://wordpress.org/latest.tar.gz"
attribute :wp_path, :kind_of=> String, default: "/var/www"
In this code sample, we are defining the following:
A default attribute is specified in the resource file so that if an attribute is not specified in the recipe or attribute file, chef client will take the default value from the resource file.
When the chef client identifies a custom resource, it will look for the related actions method in the provider.
Create a default.rb file under the folder named providers of wp_setup cookbook.
In this file, we define the actions to be performed.
Create methods for the custom actions specified in the resource file.
def whyrun_supported?
true
end
We use the whyrun method if we want chef client to tell the changes that would be applied to the node without actually applying them when it is run in whyrun mode. Its value can be true or false. For this example, we will set this value to true. To run the chef client in whyrun mode, run Chef-client –W.
Now we need to define the code that will be executed on calling of actions that we defined in the resources. First we will define the extract action. We will use Ruby and inbuilt chef resources to define the complete set of actions.
In this method we are using the File.exists? method to check if there is an existing Wordpress folder to achieve idempotency.
Chef::Log class is used to log entries in the log file.
A new_resource.updated_by_last_action method notifies the LWRP if the node has successfully updated. True or false is passed as an argument to this method to notify the execution of LWRP.
The converge_by is a wrapper method used when the chef client runs in whyrun mode and displays a message about that block of code.
if ::File.exists?("#{new_resource.wp_path}/wordpress")
Chef::Log.info "#{ @new_resource } already exists - nothing to do."
new_resource.updated_by_last_action(false)
else
converge_by("Downloading wordpress file") do
The remote_file is an inbuilt chef resource that downloads the file from a certain URL (uniform resource locator) to the node.
remote_file "#{new_resource.wp_path}/wordpress.tar.gz" do
source "#{new_resource.wp_url}"
action :create
end
Bash is also an inbuilt chef resource that is used to run bash scripts. We are using the bash resource to extract the downloaded Wordpress file.
bash "extracting wordpress" do
code <<-EOH
cd /var/www
mkdir wordpress
tar -xvf wordpres.tar.gz wordpress
EOH
end
The following snippet shows the whole code clubbed together:
action :extract do
if ::File.exists?("#{new_resource.wp_path}/wordpress")
Chef::Log.info "#{ @new_resource } already exists - nothing to do."
new_resource.updated_by_last_action(false)
else
converge_by("Downloading wordpress file") do
remote_file "#{new_resource.wp_path}/wordpress.tar.gz" do
source "#{new_resource.wp_url}"
action :create
end
bash "extracting wordpress" do
code <<-EOH
cd /var/www
mkdir wordpress
tar -xvf wordpres.tar.gz wordpress
EOH
end
end
new_resource.updated_by_last_action(true)
end
end
Action: remove: This method contains the inbuilt file resource which will delete the Wordpress installation file.
Chef::Log class is used to log entries in the log file.
The new_resource.updated_by_last_action method notifies the LWRP if the node has successfully updated. True or false is passed as argument to this method to notify the execution of LWRP.
converge_by is a wrapper method used when chef client runs in whyrun mode and displays a message about that block of code.
File is an inbuilt chef resource that has an action delete, which will delete any file.
action :remove do
unless ::File.exists?("#{new_resource.wp_path}/wordpress.tar.gz")
Chef::Log.info "#{ @new_resource } file deleted - nothing to do."
new_resource.updated_by_last_action(false)
else
converge_by("removing the compressed wordpress file") do
file "#{new_resource.wp_path}/wordpress.tar.gz" do
action :delete
end
directory "/root/chefdemo" do
action :create
end
end
new_resource.updated_by_last_action(true)
end
end
syntax: cookbookname_resourcename
wp_setup "extracting wordpress" do
wp_path node[:wordpress][:path]
wp_url node[:wordpress][:url]
action :extract
end
wp_setup "deleting the installation file" do
wp_path node[:wordpress][:path]
action :remove
end
default[:wordpress][:url] = "https://wordpress.org/latest.tar.gz"
default[:wordpress][:path] = "/var/www"
knife cookbook upload wp_setup
Figure 10-2. Uploading the cookbook
Figure 10-3. Running chef client
Figure 10-4. Verifying installation