Mocking data in Test Kitchen
This content is more than 4 years old and the cloud moves fast so some information may be slightly out of date.
The more complex your cookbooks, the bigger the need to supply some external information to your test machines. Passing specific attributes, values of databags or secrets for testing become necessary. We will go through these use cases and show how to mock the data in this post.
Attributes
This is the easiest use case and you have probably seen it on numerous tutorials: You have a cookbook which has different execution paths depending on some attribute value. A common one would be to specify the edition of an SQL Server you want to install. While the recipe might be the same, you can manage the distinction between Express, Standard and Enterprise by just changing an attribute.
So let’s say this is our hypothetical resource:
sql_server 'Install SQL Server' do
action :install
edition node['sql_server']['edition']
end
By setting the sql_server/edition
attribute we can influence if this is machine gets a Standard or Enterprise edition. Of course we want to test both. To do this, we can just add two suites to our Test Kitchen configuration file and supply the attribute1:
suites:
- name: standard
provider:
run_list:
- recipe[sql_server::configure]
attributes:
sql_server:
edition: standard
- name: enterprise
provider:
run_list:
- recipe[sql_server::configure]
attributes:
sql_server:
edition: enterprise
That’s everything needed. The Chef provisioners will automatically pull in those attributes and make them available to your cookbooks under test.
Data Bags
When it comes to central configuration, for example some values which multiple nodes need to access, Data Bags are the way to go. We could save some License Key in there:
licenses = data_bag_item('licenses', 'microsoft')
sql_server 'Install SQL Server' do
action :install
edition node['sql_server']['edition']
license licenses['sql_server']
end
In Test Kitchen we can mock this easily, as well:
suites:
- name: standard
provisioner:
run_list:
- recipe[sql_server::configure]
attributes:
sql_server:
edition: standard
data_bag_path: test/integration/data_bags/ # this is actually the default location
The directory test/integration/data_bags/
2 contains a subdirectory licenses
(the data bag name) and a file microsoft.json
(the item name) and this contains:
{
"sql_server": "..."
}
The most complicated thing about this is to remember the location of the databag and the databag/item.json
naming hierarchy.
Chef Vault
Of course we wouldn’t want our precious license keys (or passwords) out in the open like in the Data Bag example 3. The easiest way to avoid this is using Chef Vault. It automatically creates encrypted databags and you can assign privileges on which node may access which data bag.
As our Test Kitchen instances are not bootstrapped against a server and we don’t want to work with real data in our tests anyway, using Chef Vault here is no option. Outside of testing, accessing Vault is ok but in testing we should never interface with productions systems, right?
licenses = chef_vault_item('licenses', 'microsoft')
sql_server 'Install SQL Server' do
action :install
edition node['sql_server']['edition']
license licenses['sql_server']
end
Luckily, the developers of chef_vault
have implemented a fallback so we can use our Data Bag knowledge here:
suites:
- name: standard
provisioner:
run_list:
- recipe[sql_server::configure]
data_bag_path: test/integration/data_bags/
attributes:
chef_vault:
data_bag_fallback: true
We didn’t have to change our databag, only tell the helpers that a fallback is to be used. On a Chef Infra Server, we would still access the central data in the same way. It’s only the Kitchen configuration which makes the switch.
Don’t use Chef Vault in production
Chef Vault does not scale well, as it encrypts all secrets with a secret key per node. That leads to (#nodes) * (#secrets) different values and it’s easy to see that this won’t work beyond a handful of nodes.
For production setups, Hashicorp Vault is the recommended tool and is well-integrated with the Chef ecosysem.
-
Curious about why this is under provisioner? It’s the “new” style from 2013. I wrote a blog on Kitchen style ↩︎
-
Not sure about the default path? Definition in Chef base provisioner -> Lookup method -> Default test path ↩︎
-
It is worth mentioning that you can also use encrypted databags. The procedure for this is a bit more complicated and there are other blog entries like from atomic-penguin on setting it up. Test Kitchen has an integration for this, but be careful about accidentally committing secrets to GIT. ↩︎