The following is a best practice guide to how to write a production quality plan. These best practices are reflected in the requirements for a user to contribute a plan to the Chef Habitat Core Plans.
If you haven’t already, a good first step is to read the Writing Plans documentation.
Each package plan should contain a value adhering to the guidelines for each of the following elements:
pkg_license(in SPDX format)
pkg_maintainerin the format of “The Chef Habitat Maintainers email@example.com”
pkg_namesee the section of this document on “Package Name Conventions”
pkg_originmust be set to
pkg_versionmust be the complete version number of the software
Package Name Conventions
Each package is identified by a unique string containing four sub-strings separated
by a forward slash (
/) called a PackageIdent.
version values of this identifier are user defined by
setting their corresponding variable in your
plan.ps1 file while the value of
release is generated at build-time.
The value of
name should exactly match the name of the project it represents and the plan file should be located within a directory of the same name in this repository.
Example: The plan for the bison project project contains setting
pkg_name=bisonand resides in
Managing Major Versions
There is one exception to this rule: Additional plans may be defined for projects for their past major versions by appending the major version number to its name. The plan file for this new package should be located within a directory of the same name.
Example: the bison project maintains the 2.x line along with their current major version (at time of writing: 3.x). A second plan is created as
bison2and placed within a directory of the same name in this repository.
Packages meeting this exception will always have their latest major version found in the package sharing the exact name of their project. A new package will be created for the previous major version following these conventions.
Example: the bison project releases the 4.x line and is continuing to support Bison 3.x. The
bisonpackage is copied to
bisonpackage is updated to build Bison 4.x.
Plan Basic Settings
You can read more about basic plan settings here. The minimum requirements for a core plan are:
- pkg_name is set
- pkg_origin is set
- pkg_shasum is set
- pkg_description is set
You can read more about callbacks here. The minimum requirement for a core plan are:
plan.ps1) is a good place to set environment variables and set the table to build the software. Think of it as a good place to do patches.
- If you clone a repo from git, you must override
return 0in a
plan.shor if you are authoring a
Invoke-Verifywith an empty implementation.
- Don’t call
exitwithin a build phase. In a
plan.sh, you should instead return an exit code such as
return 1for failure, and
return 0for success. In a
plan.ps1you should call
throwan exception upon failure.
- Don’t use
pkg_sourceunless you are downloading something as a third party.
- Don’t shell out to
habfrom inside of a callback. If you think you want to, you should use a utility function instead.
- Don’t call any functions or helper sthat begin with an underscore, for example
_dont_call_this_function(). Those are internal for internal builder functions and are not supported for external use. They will break your plan if you call them.
- Don’t run any code or run anything outside of a build phase or a function.
Application Lifecycle Hooks
The Supervisor dynamically invokes hooks at run-time, triggered by an application lifecycle event. You can read more about hooks here.
Lifecycle Hook Do’s
- Do redirect
exec 2>&1at the start of the hook)
- Do call the command to execute with
exec <command> <options>rather than running the command directly in a Linux targeted hook. This ensures the command is executed in the same process and that the service will restart correctly on configuration changes.
- You can write to the
/data/directories. Access these with your
runtime configuration settingvariable.
Lifecycle Hook Don’t’s
- Don’t call
sleepin a hook that is not the
runhook. You can only block the thread in a hook if it is in the
- Don’t shell out to
habfrom within a hook. If you think you want to, you should use a runtime configuration setting instead. If none of those will solve your problem, open an issue and tell the core team why.
- Don’t use
execif you’re running something with a pipe. It won’t work.
- Don’t execute commands as a
rootuser or try to
sudo hab pkg install.
- Don’t edit any of the Supervisor rendered templates.
- Don’t edit anything in
- Don’t write to anything in
All plans need a
README.md. Items to strongly consider including:
- Your name as maintainer and supporter of this plan.
- What Chef Habitat topology it uses (and the plan should have the correct topology for the technology).
- Step-by-step instructions for how to use the package.
- Describe the best update strategy for different deployments.
- Describe the configuration updates a user can make and if a full rebuild is required.
- Document how to scale the service.
- Instructions for monitoring the health of the service at the application layer.
- Describe how to call the package as an application dependency in an application.
- Describe how to integrate package into an application.
A repo of plans
The best practice is to place all plan files within a
habitat parent directory, which allows for a clean separation between your application source code and habitat specific files. However, if you maintain a separate repository solely for the purpose of storing habitat plans, then the use of a
habitat folder may not be necessary.