Last time I described a general approach I used to decrease the amount of duplication across the recipes I developed in different cookbooks. The goals of these latter is to handle the deploy of specific PHP application via OpsWorks.
The PHP application I’m talking about are based in particular on WordPress (WP) and PrestaShop (PS).
Last time I also cited a “mysterious” recipe upon which I relied for setting the default attributes to specialize its behavior.
Actually there are two recipes that I use to this purpose but to describe the concept at their base I’m going to present here just one of them, i.e. phpapps::set_config_files
.
If you read the last article of mine (if you don’t go for it! 😉 ) you can guess that the above mentioned recipe resides in the general cookbook phpapps
. Or better its implementation.
As a matter of fact the actual recipe that I select and associate to the deploy phase of a PHP layer in OpsWorks isn’t the one residing in the phpapps cookbook but the one defined inside the application specific cookbooks, i.e. wordpress
and prestashop
.
Inside these cookbooks there is indeed a set_config_files
recipe that does nothing more than include the recipe of the “parent” cookbook phpapps
.
The purpose of these recipes is to properly create the config files needed by WordPress and PrestaShop applications. These are respectively the wp_config.php
and the defines.inc.php
and settings.inc.php
.
The creation of these files is handled, as shown below, inside the “parent” recipe phpapps::set_config_files
:
node['deploy'].each do |application, deploy|
next if deploy['application_type'] != 'php' or deploy['application'] != application
deploy['config_files'].to_h.each do |config_file, vars|
template vars['file'] do
only_if do
Chef::Log.info "Set config file #{vars['file']}..."
end
cookbook deploy['type']
source vars['template']
mode 00660
owner deploy['user']
group deploy['group']
variables vars.merge(deploy['environment'])
end
end
end
The recipe does nothing more than loop on the config_files
data structure and rely on the template
resource provided by the Chef DSL.
There are two peculiarities here to note. The first one is represented by the config_files
data structure. As many other data needed by the recipes it is stored as a default attribute inside the specific application cookbook. In particular it is implemented as an hash. Here there is an excerpt of the default.rb
file representing the config_files
inside the wordpress
cookbook:
node['deploy'].each do |application, deploy|
...
default['deploy'][application]['config_files'] = {
'wp_config' => {
'file' => ::File.join(deploy['absolute_document_root'], 'wp-config.php'),
'template' => 'wp-config.php.erb',
'db_name' => deploy['database']['database'],
'db_user' => deploy['database']['username'],
'db_password' => deploy['database']['password'],
'db_host' => deploy['database']['host'],
'auth_key' => '',
'secure_auth_key' => '',
'logged_in_key' => '',
'nonce_key' => '',
'auth_salt' => '',
'secure_auth_salt' => '',
'logged_in_salt' => '',
'nonce_salt' => '',
'table_prefix' => 'wp_',
'aws_access_key_id' => nil,
'aws_secret_access_key' => nil,
'wplang' => 'en-US',
'wp_cache' => false,
'force_secure_logins' => false,
'disable_wp_cron' => false,
'wp_siteurl' => domain,
'wp_home' => domain,
'wp_allow_multisite' => false,
'wp_uploads' => ::File.join('wp-content', 'uploads')
}
}
...
end
...
All the data needed to create the configuration files are handled inside the default.rb
file and gets passed to the over mentioned template
resource inside the general phpapps::set_config_files
recipe.
The second peculiarity of the general set_config_files
recipe is cookbook deploy['type']
. This attribute is used to tell Chef (and OspWorks) to pickup the correct default attributes and template files, i.e. the ones related to the deployed application type.
The cookbook deploy['type']
together with the default attributes allowed us to refactor the specific application set_config_files
recipes by moving their common implementation inside a more general cookbook and recipe.
All the specific aspects related to the application configuration files are handled by the default attributes defined inside the specific application cookbook. The implementation of the recipe resides instead inside the general cookbook phpapps
.
The key takehome message of this post is that it is possible to avoid code duplication across different cookbooks by leveraging upon the logic of the default attributes, the coobook
attribute of the template
resource and the inclusion of the recipes (include cookbook_name::recipe
).
Next time I’ll discuss another recipe, conceptually similar to the one I briefly presented here, in which I use another feature of Chef to add a little bit of “magic” to the recipes 😉
Cheers!
Leave a Reply