Chef guidelines with Managed services
The following is a general advice and guidance on how to integrate Chef Cookbooks with Managed services and the essential structural elements of Chef as used within CAM.
Fundamentals
Role based orchestration
The most important aspect of integrating existing Chef cookbooks with Managed services is that all orchestration from the template is based upon the Chef Role. Chef Roles are the primary artifact for orchestration.
When you examine the Terraform Resource responsible for calling Chef through the Pattern Manager, you notice that the Chef Role is mentioned as the runlist. Subsequent calls to Chef appends the Role to the RunList in order.
resource "camc_softwaredeploy" "centralnode_liberty_install" {
depends_on = ["camc_bootstrap.centralnode_chef_bootstrap_comp","camc_bootstrap.libertynode_chef_bootstrap_comp"]
name = "centralnode_liberty_install"
camc_endpoint = "${var.ibm_pm_service}/v1/software_deployment/chef"
access_token = "${var.ibm_pm_access_token}"
skip_ssl_verify = true
trace = true
data = <<EOT
{
"os_admin_user": "${var.centralnode-os_admin_user}",
"stack_id": "${random_id.stack_id.hex}",
"environment_name": "_default",
"host_ip": "${vsphere_virtual_machine.centralnode.network_interface.0.ipv4_address}",
"node_name": "${var.centralnode-name}",
"runlist": "role[liberty_install]",
"node_attributes": {
"ibm": {
"im_repo": "${var.ibm_im_repo}",
"im_repo_user": "${var.ibm_im_repo_user}",
"sw_repo": "${var.ibm_sw_repo}",
"sw_repo_user": "${var.ibm_sw_repo_user}"
},
"ibm_internal": {
"roles": "[liberty_install]"
},
"was_liberty": {
"base_version": "${var.centralnode_was_liberty_base_version}",
"edition": "${var.centralnode_was_liberty_edition}",
"im_install_dir": "${var.centralnode_was_liberty_im_install_dir}",
"install_dir": "${var.centralnode_was_liberty_install_dir}",
"install_grp": "${var.centralnode_was_liberty_install_grp}",
"install_user": "${var.centralnode_was_liberty_install_user}",
"java_version": "${var.centralnode_was_liberty_java_version}",
"wlp_user_dir": "${var.centralnode_was_liberty_wlp_user_dir}"
}
},
"vault_content": {
"item": "secrets",
"values": {
"ibm": {
"im_repo_password": "${var.ibm_im_repo_password}",
"sw_repo_password": "${var.ibm_sw_repo_password}"
}
},
"vault": "${random_id.stack_id.hex}"
}
}
EOT
}
In this example, the roles field is populated with the role to be run. The Pattern Manager appends the role to the runlist of the node and runs the chef-client to complete the execution of the component.
Chef Cookbooks must therefore be designed in such a way as to be orchestrated by the running and subsequent running of Chef Roles. It is important to note the relationship between Attributes passed from Managed services and the Chef Role. As a general rule, hide all attributes that are not to be changed within a Role and expose only Node based attributes to Managed services.
Chef Client and Server version
When a Content Runtime is deployed, a pre-approved version of the Chef Client and Server are deployed. As Chef is an open source tool, only specific versions of the Chef Client and server are approved for deployment. The current versions are as follows:
- Chef Server: v12.11.1
- Chef Client: v12.12.13
Language linting
IBM provided Chef Cookbooks use the following tools to standardize on the language and structure of Chef Cookbooks:
-Rubocop -FoodCritic
Testing tooling
IBM tests all cookbooks with the following tools that are automated as part of a Devops Toolchain.
- ChefSpec
- Test Kitchen
README generation
All Chef Cookbook README.md files are generated with the knife readme plugin that is located at Chef.
Structural elements
The following section is a summary of the structural elements of standard IBM provided cookbooks. It is not necessary for customer provided cookbooks to follow these standards, they are included as a reference only.
Standard Chef attributes
Chef Node Attributes are commonly used to define cross-cookbook attributes, which may be used to describe common features. A single Chef Node might consume multiple cookbooks, so standardize those standard variables that affect all cookbooks.
The following is the list of standard Chef Attributes used in IBM provided cookbooks. These may be referenced in a customer provided cookbook only if there is a need to re-use these standard variables.
Note: This is not mandatory but required only for consistency and simplicity.
Attribute | Definition |
---|---|
default['ibm']['expand_area'] | Home directory for Open Patterns unfold directory, this is a global variable that may be set in the Environment. This path is absolute and all other paths are relative to it. |
force_override[
|
Cookbook based ExpandArea which will be relative to the global expandArea. This value will be set in the internal.rb file. |
default['ibm']['sw_repo_root'] | URL location of the Repository Server. |
force_override['
|
The correct version attribute name to describe the archive to install a product from is ['
|
force_override['
|
ARRAY of file names of the installer. |
force_override[ibm][evidence_path]['windows'] | Root path for the Evidence files on Windows systems, this variable will be defined in a role on the customer chef server. |
force_override[ibm][evidence_path]['unix'] | Root path for the Evidence files on Unix systems, this variable will be defined in a role on the customer chef server. |
default[
|
ZIP File which contains the evidence. |
default['
|
Identifier for the fix pack to be applied. This attribute is necessary for all products that support the notion of applying fix packs. The precise fix pack must never be hard-coded in the Recipe. |
force_override['
|
The data structure should include a hash for every operating system user including related settings such as username, home directory, password, ldap_user etc. |
Base directory for a product to be installed into. | Home directory for Open Patterns unfold directory, this is a global variable that may be set in the Environment. This path is absolute and all other paths are relative to it. |
force_override['
|
One or more attributes defining the relative location of product related files on the software repository (such as default['ibm']['sw_repo_root']). |
force_override['
|
One or more attributes defining the relative location of fix pack related files on the software repository (such as default['ibm']['sw_repo_root']). |
force_override['
|
The value should contain a list of operating system libraries to install. |
default['ibm']['temp_dir'] | An absolute path to a temporary location on the filesystem to store any temporary files. |
default['ibm']['log_dir'] | Any logfiles that should persist on the system should be written to this location. |
Avoiding namespace clashes
As a node might run one or more cookbooks, seperate similar attributes from different cookbooks. The following rule applies when naming attributes.
['<cookbookName>']['<attribute>']
Internal.rb vs Default.rb
IBM categorizes Chef variables based on whether they are to be exposed in CAM or not, the general structure applies.
|- chef
| |- cookbooks
| | |- <cookbook_name>
| |- attributes
| - default.rb # All product attributes
| - internal.rb # force_override attributes that may never be changed.
Attribute Precedence
Chef supports a wide variety of attribute precedence, the following is a summary of the supported and the relevant use cases.
Standard Chef Recipes
The following is the set of standard recipes that should exist in all IBM provided cookbooks. Product specific cookbooks to configure and control are added separately.
Receipe Name | Definition |
---|---|
prereq | OS Pre-requisite provisioning. |
prereq-check | Recipe to ensure that pre-requisites are in place for a cookbook to run. |
fixpack | Product un-installation only. (Not necessary by default, however, should it be required, then use this name) |
uninstall | OS Pre-requisite provisioning. |
harden | Product hardening only. Note, this is inherently customer specific and must therefore be separated from other recipes. |
install | Product installation only. |
gather_evidence | Recipe to gather artifacts to prove an installation has occurred successfully. These artifacts are to be packed in a single archive. |
cleanup | Recipe to remove all unwanted files such as install media and temp files. |
default | Standard default recipe which will implement the minimal functionality to stand up the cookbook. |
Chef Cookbook Principles
The following is a list of principles used in the construction of Chef Cookbooks.
The Granularity Principle
Granularity in the CHEF context refers to the care taken to expose recipes in a granular enough fashion to ensure Orchestration and Pattern designers can assemble the component pieces in such a way as to gain the desired result. There are no hard and fast rules here, the general principal to apply is this:
Recipes should seek to encapsulate a single software function.
Recipes represent the lowest representation of functionality provided by the Chef Cookbook and as such should contain with them a single operation that may be combined into a Role as a Pattern is defined based on these recipes. Standard CHEF Recipes represent both a minimal default and also encapsulate this principle.
Configuration of software products is in general difficult to generalize, however, consider a similar principle when deciding on Recipes that seek to implement software configuration. As a general rule, a single recipe should implement a single configuration concept.
When evaluating a Software Product to try to find the correct level of Granularity, it is important to be aware of the following general principles.
-
How Recipes relate to Roles.
-
How Roles are used in Pattern definition.
-
How Roles are used in Pattern Orchestration.
-
An understanding of the standard Recipes required for any software product.
An understanding of where Recipes sit in relation to the overall Open Pattern construct is essential to an understanding of the best way to find the correct level of granularity.
The Idempotency Principle
The Idempotency principal is in essence the practice of running an action more than once producing the same result. From a CHEF perspective, assume that a recipe will fail at some point and needs to be re-run.
All CHEF Cookbook's and Recipe's must be inherently idempotent.
Recipes must be designed with re-entry in mind. This can be as a result of failure, or as a result of the chef client being run at unexpected times. Cookbooks should make no assumption's as to the start state of the system and always check that an action can be run before it is run.
Touch points include:
- Only download files where necessary, for example, do not download installer files if the installation is already complete.
- Only execute configuration changes.
- All LWRP and other CHEF artefacts for example Recipes must be inherently idempotent.
- Cookbooks should never produce errors based on a state of the running software.
Data Driven Principle
Data Driven refers to the exposing as many options as CHEF variables as possible and therefore reducing the number of hard coded values. The general principle is as follows: CHEF Cookbooks should be highly dependent on attributes when executing, changing the outcome should be driven by modifying the attributes through the use of Roles and Node Attributes. The following generalizations apply:
- Maximize CHEF Attributes.
- Minimize hard coding.
- CHEF Attributes should be represented as arrays where possible.
Maximizing Attributes / Minimize Hard Coding As a general rule, values that are consumed by a cookbook should be represented as Attributes. Attribute definition and consumption by CHEF should follow the guidelines set out in the Attribute Precedence section of this document. As a general Rule all attributes are changeable, however, there are circumstances where certain variables are to remain fixed, these are given the force_override operator and defined in the internal.rb file.
Standard Attributes Attributes that implement standardized concepts should be named as per the Naming Standards described in this guide. Standard Attributes are defined to maximize readability of our Chef Cookbooks, but also to allow for attributes to be standardized across an environment.
Attribute Arrays Software products that implement multiple configuration items of the same type should be represented in an Array from a definition perspective. A reasonable example of this is the definition of database, which may be described in terms of 1..n databases. It is best practice in these cases to define the attributes in an array rather than singleton attributes, for example:
default['was']['os_users'] = {
'wasadmin' => {
'name' => 'wasadmin',
'gid' => 'wasgrp',
'comment' => 'WAS administrative user',
'home' => "/home/wasadmin",
'shell' => '/bin/bash'
},
'wasowner' => {
'name' => 'wasowner',
'gid' => 'wasgrp',
'comment' => 'WAS owner',
'home' => "/home/wasowner",
'shell' => '/bin/bash'
}
}
The previous example defines the os_users attribute as an Hash Table rather than as singleton attributes. It is therefore possible to add or remove users based on data alone, without the need to define any new attributes or change the code in general.
Modularity Principle
The principle of Modularity relates to creating re-usable components that may be utilized within a single cookbook, or to external cookbooks.
CHEF Cookbooks should be modular in nature and take advantage where possible of Libraries, LWRP and other CHEF Cookbooks.
An important consideration when designing a cookbook is whether to use an LWRP or not. A Chef Lightweight Resource Provider can be created to encapsulate the functionality of Software Configuration items to be treated as an object. A clear identifier of an object that should be represented as an LWRP is that it may be modified, exhibits internal state, applies across Operating Systems and is in general version independent. As a guide, consider existing CHEF Resources, each of these are in fact an implementation of a LWRP.
Never attempt to re-create an existing Chef Resource if one already exists. Open Patterns should maximize the use of LWRP for the following situations.
- Fix pack installation.
- State control (For example, stop/start) Software configuration.
LWRP should exhibit the following characteristics.
- Operating System neutral.
- Software version neutral.
- State neutral. (For example, start a Software Product that is already started will not cause an error)
- Idempotent.