Kondate
Kondate is yet another nodes management framework for Itamae/Serverspec.
Kondate provides nodes/roles/attributes/run_lists management feature for Itamae/Serverspec.
Installation
Add this line to your application's Gemfile:
gem 'kondate'
And then execute:
$ bundle
Or install it yourself as:
$ gem install kondate
Usage
Generate a template directory tree:
$ bundle exec kondate init .
Run itamae:
$ bundle exec kondate itamae <host>
Run serverspec:
$ bundle exec kondate serverspec <host>
Run itamae for multiple hosts of a given role in parallel:
$ bundle exec kondate itamae-role <role>
Run serverspec for multiple hosts of a given role in parallel:
$ bundle exec kondate serverspec-role <role>
Configuration
kondate init
provides a template directory tree such as:
.
├── .kondate.conf # kondate configuration
├── bootstrap.rb # itamae bootstrap
├── hosts.yml # manages hostnames and its roles
├── properties # manages run_lists and attributes
│ ├── nodes # host specific properties
│ ├── roles # role properties
│ └── environments # environment properties
├── recipes # itamae recipes
│ ├── middleware # middleware recipes
│ │ └── base
│ │ └── default.rb
│ └── roles # role recipes
└── spec # serverspec specs
├── middleware # middleware recipes specs
│ └── base_spec.rb
├─ roles # role recipes specs
└── spec_helper.rb
├── secrets # manages secrets attributes such as passwords
│ ├── properties
│ │ ├── environments
│ │ ├── nodes
│ │ └── roles
│ ├── recipes
│ │ ├── middleware
│ │ └── roles
│ └── spec
│ ├── middleware
│ └── roles
.kondate.conf
The default .kondate.conf looks like below:
middlware_recipes_dir: recipes/middleware
roles_recipes_dir: recipes/roles
middleware_recipes_serverspec_dir: spec/middleware
roles_recipes_serverspec_dir: spec/roles
nodes_properties_dir: properties/nodes
roles_properties_dir: properties/roles
environments_properties_dir: properties/environments
secret_middlware_recipes_dir: secrets/recipes/middleware
secret_roles_recipes_dir: secrets/recipes/roles
secret_middleware_recipes_serverspec_dir: secrets/spec/middleware
secret_roles_recipes_serverspec_dir: secrets/spec/roles
secret_nodes_properties_dir: secrets/properties/nodes
secret_roles_properties_dir: secrets/properties/roles
secret_environments_properties_dir: secrets/properties/environments
plugin_dir: lib
host_plugin:
type: file
path: hosts.yml
You can customize the directory tree with this conf.
Itamae options
You can configure itamae-kondate options on .kondate.conf, too as:
itamae_options:
shell: /bin/bash
See itamae-kondate --help
for option list.
Serverspec options
You can configure serversepc-kondate options on .kondate.conf, too as:
serverspec_options:
vagrant: true
See serverspec-kondate --help
for option list.
hosts.yml
The default uses file
host plugin, and hosts.yml
. The contents of hosts.yml
look like below:
localhost: [sample]
where keys are host names, and values are array of roles.
$ bundle exec kondate itamae <host>
works as follows:
- obtains a role list from
hosts.yml
- reads
properties/roles/#{role}.yml
, and find recipes and its attributes - runs recipes
You can create your own host plugin. See Host Plugin
section for more details.
properties
Property files are places to write recipes to run and attributes values.
├── properties # manages run_lists and attributes
│ ├── nodes # host specific properties
│ ├── roles # role properties
│ └── environments # environment properties
An example looks like below:
properties/roles/#{role}.yml
attributes:
ruby:
versions: [2.2.3]
gems:
2.2.3: [bundler]
node:
versions: [v0.12.2]
global: v0.12.2
nginx:
The attributes variables are accessible like attrs['ruby']['versions']
, which is equivalent and short version of node['attributes']['ruby']['versions']
in recipes.
You can also prepare host-specific property files such as:
properties/nodes/#{host}.yml
attributes:
nginx:
worker_processes: 8
In addition, you can also prepare environment property files such as:
properties/environments/#{ENV['ENVIRONMENT'] || 'development'}
.yml
global_attributes:
aws_region: ap-northeast-1
where global_attributes
is accessible like global_attrs['aws_region']
, which is equivalent and short version of node['global_attributes']['aws_region']
in recipes.
These files are merged on kondate execution in order of environment
+ role
+ node
(node
> role
> environment
in the strong order).
secret properties
Secret properties are places to write confidential attributes.
├── secrets # manages secrets attributes such as passwords
│ └── properties
│ ├── nodes
│ ├── roles
│ └── environments
An example looks like below:
secrets/properties/roles/sample.yml
attributes:
base:
password: xxxxxxxx
These files are merged with property files on kondate execution.
Hint: I manage secret property files on github private repository. ToDo: support encryption.
recipes
Put you itamae recipes:
├── recipes # itamae recipes
│ ├── middleware # middleware recipes
│ │ └── base
│ │ └── default.rb
│ └── roles # role recipes
middleware recipes
are usual recipes to write how to install middleware such as nginx
, mysql
.
role recipes
are places to write role-specific provisioning. I often write recipes to create log directories for my app (role), for example.
recipes/roles/myapp/default.rb
directory "/var/log/myapp" do
owner myapp
group myapp
mode 0755
end
spec
Put your serverspec specs.
└── spec # serverspec specs
├── middleware # middleware recipes specs
└── roles # role recipes specs
It is required that spec/spec_helper
has lines:
set :host, ENV['TARGET_HOST']
set :set_property, YAML.load_file(ENV['TARGET_NODE_FILE'])
because these ENVs are passed by kondate serverspec
.
Configuring following lines for vagrant is also recommended:
if ENV['TARGET_VAGRANT']
`vagrant up #{host}`
config = Tempfile.new('', Dir.tmpdir)
config.write(`vagrant ssh-config #{host}`)
config.close
Net::SSH::Config.for(host, [config.path])
else
ENV['TARGET_VAGRANT']
is turned on if kondate serverspec
is executed with --vagrant
option.
See templates/spec/spec_helper.rb for an example.
Exploring role files
Available version: >= v0.4.0
Assume role
is delimited with -
(you can configure the delimiter) such as myapp-web-staging
, this feature explores role files in order of:
- myapp-web-staging.yml
- myapp-web-base.yml
- myapp-web.yml
- myapp-base.yml
- myapp.yml
- base.yml
This makes it possible to share a property file, for example, myapp-web.yml
among myapp-web-staging
and myapp-web-production
roles.
To enable this feature, you need to configure .kondate.conf as:
explore_role_files: true # default is false
role_delimiter: "-" # default is -
Host Plugin
The default reads hosts.yml
to resolve roles of a host, but
you may want to resolve roles from AWS EC2 roles
tag, or
you may want to resolve roles from your own host resolver API application.
Thus, kondate
provides a plugin system to resolve hosts' roles.
Naming Convention
You must follow the below naming conventions:
- gem name: kondate-host_plugin-xxx (xxx_yyy) (if you want to make a gem)
- file name: lib/kondate/host_plugin/xxx.rb (xxx_yyy.rb)
- class name: Kondate::HostPlugin::Xxx (XxxYyy)
If you want to put your own host plugin locally without publishing a gem, you can configure the location with .kondate.conf as:
plugin_dir: lib
Interface
What you have to implement are #initialize
, #get_environment
, and #get_roles
methods.
get_hostinfo
method is an optional method to return arbitrary hostinfo of the host (available from kondate 0.2.0).
Here is an example of file plugin:
require 'yaml'
module Kondate
module HostPlugin
# YAML format
#
# host1: [role1, role2]
# host2: [role1, role2]
class File < Base
# @param [HashWithIndifferentAccess] config
def initialize(config)
super
raise ConfigError.new('file: path is not configured') unless config.path
@path = config.path
@roles_of_host = YAML.load_file(@path)
@hosts_of_role = {}
@roles_of_host.each do |host, roles|
roles.each do |role|
@hosts_of_role[role] ||= []
@hosts_of_role[role] << host
end
end
end
# @param [String] host hostname
# @return [String] environment name
def get_environment(host)
ENV['ENVIRONMENT'] || 'development'
end
# @param [String] host hostname
# @return [Array] array of roles
def get_roles(host)
@roles_of_host[host]
end
# @param [String] role role
# @return [Array] array of hosts
#
# Available from kondate >= 0.3.0
def get_hosts(role)
@hosts_of_role[role]
end
# Optional
#
# @param [String] host hostname
# @return [Hash] arbitrary hostinfo
def get_hostinfo(host)
{}
end
end
end
end
Config
config
parameter of #initialize
is created from the configuration file (.kondate.conf):
host_plugin:
type: file
path: hosts.yml
config.type
and config.path
is available in the above config.
See Also
Development
bundle exec exe/kondate init .
vagrant up
bundle exec exe/kondate itamae vagrant-centos --vagrant --role sample
bundle exec exe/kondate serverspec vagrant-centos --vagrant --role sample
ToDo
write tests
License
The gem is available as open source under the terms of the MIT License.