Converting a Kitchen YAML to Chef Attributes
This is an article that's been on the backlog for four and a half years, so I thought I should get around to actually writing it. Apologies if the context isn't quite right, as I'm trying to remember what I can for why we needed this.
You're hopefully testing your Chef cookbooks with Test Kitchen as part of a set of sufficient test coverage.
You may be finding that you've got your Test Kitchen's suites set up with a nice set of attributes that you want to move into your cookbook's attributes/
directory, but need some way to programmatically convert it, instead of doing it by hand.
(I won't recommend this (see also Chef Attributes and default.rb
- it's in the name), but this is what we were doing, and we needed a straightforward way to convert the two)
Let's take the following kitchen.yml
:
# ...
suites:
- name: default
run_list:
- recipe[cookbook-spectat::default]
attributes:
spectat:
authorized_keys: ['fake-ssh-public-key']
# ...
# more suites
# ...
- name: web-review-apps
run_list:
- recipe[cookbook-spectat::site]
provisioner:
client_rb:
environment: staging
attributes:
spectat:
site_fqdn: 'longfqdnwww.spectatdesigns.co.uk'
admin_user: 'root'
web_user: 'root'
review_apps: true
site_type: 'static'
dns:
api_key: 'fakeAPIkey'
tls:
strategy: 'self_signed'
- name: web-docker
run_list:
- recipe[cookbook-spectat::site]
attributes:
spectat:
site_fqdn: 'longfqdnwww.spectatdesigns.co.uk'
admin_user: 'root'
web_user: 'root'
docker: true
site_type: 'static'
dns:
api_key: 'fakeAPIkey'
tls:
strategy: 'self_signed'
not_set: null
Then with the following script:
require 'yaml'
def keys_to_attributes(keys)
acc = %w[default]
acc << keys.map { |k| "['#{k}']" }
acc.join ''
end
def output_hash(previous_keys, hash)
hash.each do |k, v|
keys = previous_keys.dup << k
if v.is_a? Hash
output_hash(keys, v)
else
puts "#{keys_to_attributes(keys)} = #{v.inspect}"
end
end
end
doc = YAML.load_file ARGV[0]
suite_name = ARGV[1] || 'default'
suite = doc['suites'].find { |s| s['name'] == suite_name }
raise "Suite `#{suite_name}` not found" if suite.nil?
output_hash([], suite['attributes'])
Which we can then execute like so:
# to use the `default` suite
$ ruby ktoa.rb kitchen.yml
# to use a specific suite
$ ruby ktoa.rb kitchen.yml web-docker
Which outputs the following when executing against web-docker
:
default['spectat']['site_fqdn'] = "longfqdnwww.spectatdesigns.co.uk"
default['spectat']['admin_user'] = "root"
default['spectat']['web_user'] = "root"
default['spectat']['docker'] = true
default['spectat']['site_type'] = "static"
default['spectat']['dns']['api_key'] = "fakeAPIkey"
default['spectat']['tls']['strategy'] = "self_signed"
default['spectat']['not_set'] = nil