A Test Kitchen provisioner for Habitat.
Test Kitchen builds a throwaway machine, applies your configuration to it, runs your tests, and destroys it. This provisioner makes the "apply your configuration" step install a Habitat supervisor on that machine and load a Habitat service into it — so you can test the package you just built, on a real operating system, before you promote it.
This documentation uses Cinc Workstation and the
cinccommands throughout. Everything here works identically with Chef Workstation — see Using with Chef.Note that the
habCLI itself is not renamed: Habitat is the upstream project, andhabis what you run on the instance either way.
- Requirements
- Installation
- Quick start
- How it works
- Configuration reference
- Examples
- Troubleshooting
- Using with Chef
- Contributing
- License
- Ruby 3.1 or newer (already satisfied if you use Cinc Workstation)
- A Test Kitchen driver to supply the machine — this gem only provisions. kitchen-vagrant, kitchen-docker, or any cloud driver will do.
- A Habitat package to test. That is either a package already in
Builder, or a local
.hartartifact you built withhab studio.
You do not need the hab CLI on the instance beforehand. The provisioner
installs it, then installs and starts a supervisor, as part of converge.
This provisioner ships with Cinc Workstation, which is the simplest way to get Test Kitchen and its plugins in one package. It also ships with Chef Workstation.
To install it yourself, add it to your Gemfile:
gem "kitchen-habitat"then bundle install. Or install the gem directly:
gem install kitchen-habitatThe smallest useful kitchen.yml names a driver for the machine, this
provisioner, and the package you want to run:
---
driver:
name: vagrant
provisioner:
name: habitat
hab_license: accept
package_origin: core
package_name: redis
verifier:
name: cinc_auditor
platforms:
- name: ubuntu-22.04
suites:
- name: defaultThen run the full cycle:
cinc kitchen testOr step through it:
cinc kitchen create # build the machine
cinc kitchen converge # install hab, start the supervisor, load the service
cinc kitchen verify # run your tests
cinc kitchen destroy # tear the machine down
hab_license: acceptis required for the supervisor to start on Linux. See the Chef license documentation.
A converge runs four steps in order:
- Install the
habCLI. Ifhabis already on the machine, this is skipped. Otherwise the official install script is downloaded and run —install.shon Linux,install.ps1on Windows. - Install and start a supervisor. On Linux a
hab-supsystemd unit is written and enabled. On Windows thecore/windows-servicepackage is installed and the Habitat service is started. Supervisor flags come from thehab_sup_*andevent_stream_*options. - Copy your local files into the sandbox. A
.hartartifact from your results directory, and auser.tomlplus any config files fromconfig_directory, are staged onto the machine. - Install and load the service. The package is installed with
hab pkg install, then loaded withhab svc loadif it has arunhook. The provisioner then waits for the service to appear inhab svc status, giving up afterservice_load_timeoutseconds.
Because step 4 only loads packages that ship a run hook, a package that is a
library or a build-time dependency converges successfully without a service
being started.
All options below are set under the provisioner: key in kitchen.yml, and
can be overridden per-platform or per-suite.
| Option | Default | Description |
|---|---|---|
hab_license |
nil |
Set to accept to accept the Habitat license. The supervisor will not start on Linux without it. |
hab_version |
"latest" |
Version of the hab CLI to install. On Linux, any value other than latest is passed to the install script as -v <version>. |
hab_channel |
"stable" |
Release channel the hab CLI is installed from. Windows only — the Linux install script does not take a channel. |
depot_url |
nil |
Habitat Builder (depot) URL to install packages from, exported to the supervisor as HAB_BLDR_URL. Linux only. When unset, the hab CLI's own default from ~/.hab/etc/cli.toml applies. |
These map to hab sup run flags on the supervisor the provisioner starts.
| Option | Default | Description |
|---|---|---|
hab_sup_peer |
[] |
List of supervisors to peer with to join a ring, as host or host:port, e.g. 192.168.1.86:9010. Each becomes a --peer. |
hab_sup_bind |
[] |
List of service bindings, as name:service.group, e.g. database:postgresql.default. Each becomes a --bind. |
hab_sup_group |
nil |
Service group the supervisor belongs to (--group). When unset the flag is not passed and Habitat's own default, default, applies. |
hab_sup_ring |
nil |
Ring key name (--ring). |
hab_sup_listen_gossip |
nil |
Address and port for gossip traffic (--listen-gossip), e.g. 0.0.0.0:9638. |
hab_sup_listen_ctl |
nil |
Address and port for the control gateway (--listen-ctl), e.g. 0.0.0.0:9632. |
hab_sup_listen_http |
nil |
Address and port for the HTTP gateway (--listen-http), e.g. 0.0.0.0:9631. |
| Option | Default | Description |
|---|---|---|
package_origin |
"core" |
Origin of the package to run. Overridden if artifact_name or a fully-qualified package_name is given. |
package_name |
nil |
Name of the package to run. Required unless it is supplied via artifact_name or install_latest_artifact. May be given as a full identifier — core/redis/4.0.14 is split into origin, name, and version for you. |
package_version |
nil |
Version of the package to run. |
package_release |
nil |
Release of the package to run. |
channel |
"stable" |
Channel the package is installed from and updated against (hab pkg install --channel, hab svc load --channel). Distinct from hab_channel, which is about the CLI. |
service_topology |
nil |
Service topology (--topology). Valid values are standalone and leader. Unset means standalone. |
service_update_strategy |
nil |
Update strategy (--strategy). Valid values are at-once and rolling. Unset means updates are not checked for. |
service_load_timeout |
300 |
Seconds to wait for the service to show up in hab svc status before failing the converge. |
| Option | Default | Description |
|---|---|---|
artifact_name |
nil |
Filename of a local .hart to upload and run, e.g. core-jq-static-1.5-20170127185151-x86_64-linux.hart. Origin, name, version, and release are parsed from the filename. The file must be in the results directory. |
install_latest_artifact |
false |
Upload and run the newest .hart in the results directory matching package_origin and package_name. Both of those must be set. package_version and package_release are ignored. |
results_directory |
auto-detected | Directory holding built .hart artifacts, relative to kitchen.yml. When unset, results, ../results, and ../../results are tried in that order, which covers the usual hab studio layouts. |
config_directory |
nil |
Directory holding a user.toml, and optionally default.toml, hooks, and config files, to ship to the service under test. Relative to kitchen.yml. |
user_toml_name |
"user.toml" |
Name of the file in config_directory to install as the service's user.toml. Lets one directory hold several, e.g. user-ha.toml. |
override_package_config |
false |
Load configuration and hooks from config_directory instead of the ones baked into the package, via the supervisor's --config-from. |
Reports supervisor and service events to a Chef Automate Application Dashboard.
| Option | Default | Description |
|---|---|---|
event_stream_application |
nil |
Application name to report under. |
event_stream_environment |
nil |
Application environment for this supervisor. |
event_stream_site |
nil |
Where the services are deployed — a datacenter, or a cloud region. |
event_stream_url |
nil |
Chef Automate URL including port 4222, e.g. automate.example.com:4222. |
event_stream_token |
nil |
Chef Automate API token. |
All five must be set for the supervisor to report to Automate. Setting only some of them passes incomplete flags and the supervisor will fail to start.
By default the stock supervisor that ships with the hab CLI is used, and
nothing extra is installed. Setting any of these makes the provisioner install
the supervisor you asked for before starting it.
| Option | Default | Description |
|---|---|---|
hab_sup_origin |
"core" |
Origin of the supervisor package. |
hab_sup_name |
"hab-sup" |
Name of the supervisor package. |
hab_sup_version |
nil |
Version of the supervisor package to pin. |
hab_sup_release |
nil |
Release of the supervisor package to pin. |
hab_sup_artifact_name |
nil |
Filename of a local supervisor .hart to upload and run, e.g. core-hab-sup-1.6.652-20240115194501-x86_64-linux.hart. Origin, name, version, and release are parsed from the filename, and the file must be in the results directory. |
These four identity options combine into a package identifier — core/hab-sup,
core/hab-sup/1.6.652, and so on — which is installed with hab pkg install.
When hab_sup_artifact_name is given instead, that artifact is uploaded
alongside your service artifact and installed from the path it lands at.
Leave all five unset and the converge is unchanged: no supervisor package is installed and the one bundled with the
habCLI is used, exactly as before.
---
driver:
name: vagrant
provisioner:
name: habitat
hab_license: accept
package_origin: core
package_name: redis
verifier:
name: cinc_auditor
platforms:
- name: ubuntu-22.04
suites:
- name: defaultAssumes you have already run a build in hab studio, so a .hart is sitting
in results/.
---
driver:
name: vagrant
customize:
memory: 2048
provisioner:
name: habitat
hab_license: accept
package_origin: mycompany
package_name: wildfly
results_directory: results
install_latest_artifact: true
verifier:
name: cinc_auditor
platforms:
- name: ubuntu-22.04
suites:
- name: default
verifier:
inspec_tests:
- testsTo pin an exact artifact instead of taking the newest, swap
install_latest_artifact for artifact_name:
provisioner:
name: habitat
hab_license: accept
results_directory: results
artifact_name: mycompany-wildfly-26.1.1-20240115194501-x86_64-linux.hartAssumes a configs/user.toml next to your kitchen.yml.
---
driver:
name: vagrant
provisioner:
name: habitat
hab_license: accept
package_origin: mycompany
package_name: wildfly
channel: unstable
config_directory: configs
verifier:
name: cinc_auditor
platforms:
- name: ubuntu-22.04
suites:
- name: defaultTo have the supervisor use the hooks and config files from that directory
rather than the ones inside the package, add override_package_config: true.
One suite per service, with the second peering to and binding against the first. This example uses the Docker driver so the containers can be linked.
---
driver:
name: docker
provisioner:
name: habitat
hab_license: accept
verifier:
name: cinc_auditor
platforms:
- name: ubuntu-22.04
suites:
- name: elasticsearch
provisioner:
package_origin: core
package_name: elasticsearch
driver:
instance_name: elastic
- name: kibana
provisioner:
package_origin: core
package_name: kibana
hab_sup_peer:
- elastic
hab_sup_bind:
- elasticsearch:elasticsearch.default
driver:
instance_name: kibana
links: elastic:elastic---
driver:
name: azurerm
driver_config:
subscription_id: <%= ENV["subscription_id"] %>
location: <%= ENV["region"] %>
machine_size: Standard_DS2_v2
provisioner:
name: habitat
hab_license: accept
hab_version: latest
event_stream_application: Effortless
event_stream_environment: stable
event_stream_site: <%= ENV["region"] %>
event_stream_url: automate.example.com:4222
event_stream_token: <%= ENV["automate_token"] %>
verifier:
name: cinc_auditor
platforms:
- name: windows
driver:
image_urn: MicrosoftWindowsServer:WindowsServer:2022-Datacenter:latest
vm_name: windows
provisioner:
package_origin: <%= ENV["package_origin"] %>
package_name: <%= ENV["package_name"] %>
suites:
- name: default
verifier:
inspec_tests:
- testsThe converge hangs, then fails after five minutes.
The service never appeared in hab svc status. Usually the package has no
run hook, or it crashed on startup. Run cinc kitchen login and check hab svc status and journalctl -u hab-sup (Linux) or the Habitat service's log
(Windows). Raise service_load_timeout only if the service is genuinely slow
to start.
Habitat license not accepted, and the supervisor never starts.
Set hab_license: accept in your provisioner config.
You must specify a 'package_origin' and 'package_name' to use the 'install_latest_artifact' option.
install_latest_artifact finds the newest .hart by matching
<package_origin>-<package_name>-*.hart, so it needs both to know what to look
for.
The .hart is not found, or the wrong one is uploaded.
Check results_directory. Auto-detection only looks in results,
../results, and ../../results relative to kitchen.yml; anywhere else must
be set explicitly.
My custom supervisor is not being used.
Check that hab_sup_artifact_name names a file that is actually in the results
directory — see results_directory. If you pinned a version or release
instead, confirm that identifier exists in the depot; the converge fails at
hab pkg install when it does not.
A bind fails with an unsatisfied service group.
hab_sup_bind entries are name:service.group. The bound service must already
be running and reachable — check that hab_sup_peer points at it and that the
network between the two machines allows the gossip port.
Everything above works unchanged with Chef Workstation. Substitute the commands:
| Cinc | Chef |
|---|---|
cinc kitchen test |
chef kitchen test (or plain kitchen test) |
cinc_auditor verifier |
inspec verifier |
The provisioner name is habitat either way, and the hab CLI is the same
program in both cases.
Bug reports and pull requests are welcome on GitHub.
For how to set up a development environment, run the tests, and generate the documentation, see CONTRIBUTING.md.
Licensed under the Apache License, Version 2.0. See LICENSE for details.