Converting a Kitchen YAML to Chef Attributes

Featured image for sharing metadata for article

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

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#blogumentation #chef #test-kitchen.

This blog post is 100% human-written, and has nothing derived from LLMs (be it code, editorial support or prose).

This post was filed under articles.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.