Chef 12 has an awesome new feature called ‘organizations’ that allows you to split your chef server into logical units. Perfect if you have a hard divide between production and lab.
Organizations have separate cookbooks, users, roles and environments. That also means that you need to have separate knife.rb config files.
While you could try and use a tool like knife block to manage multiple knife config files, it currently is very buggy and doesn’t work well with RVM on Mac OSX
This github gist shows an elegant solution
Variables inside the knife.rb
~/.chef/knife.rb
require 'yaml'
CHEF_ENV = ENV['CHEF_ENV'] || "your_environment"
current_dir = File.dirname(__FILE__)
env_config = YAML.load_file("#{current_dir}/#{CHEF_ENV}/config.yml")
log_level :info
log_location STDOUT
node_name env_config["node_name"]
client_key "#{current_dir}/#{CHEF_ENV}/#{env_config["node_name"]}.pem"
validation_client_name env_config["validator"] || "chef-validator"
validation_key "#{current_dir}/#{env_config["validator"]}.pem"
chef_server_url env_config["server"]
cache_type 'BasicFile'
cache_options( :path => "#{current_dir}/#{CHEF_ENV}/checksums" )
Then create as many folders as you want
$ tree ~/.chef
/Users/spuder/.chef
├── azure-prod
│ └── knife.rb
├── foo-lab
│ ├── chef-foo-lab-validator.pem
│ ├── config.yml
│ ├── knife.rb
│ └── spuder.pem
├── foo-prod
│ ├── chef-foo-prod-validator.pem
│ ├── config.yml
│ ├── knife.rb
│ └── spuder.pem
├── knife.rb
├── bar-lab
│ ├── chef-bar-lab-validator.pem
│ ├── config.yml
│ ├── knife.rb
│ └── spuder.pem
├── bar-prod
│ ├── chef-bar-prod-validator.pem
│ ├── config.yml
│ └── spuder.pem
Here is an example for the foo chef server with the lab environment
foo-lab/config.yml
node_name: "bacon"
server: "https://chef.example.com/organizations/lab"
validator: "chef-foo-lab-validator"
foo-lab/knife.rb
current_dir = File.dirname(__FILE__)
log_level :info
log_location STDOUT
node_name "spuder"
client_key "#{current_dir}/spuder.pem"
validation_client_name "lab-validator"
validation_key "#{current_dir}/chef-foo-lab-validator.pem"
chef_server_url "https://chef.example.com/organizations/lab"
cookbook_path ["#{current_dir}/../cookbooks"]
Usage
To switch between environments, simply set the environment variable CHEF_ENV
where CHEF_ENV
is the name of the folder that contains the knife.rb file you want.
CHEF_ENV=foo-lab knife node list
CHEF_ENV=foo-prod knife node edit
CHEF_ENV=bar-prod knife cookbook list
This makes it easy to automate with jenkins / gitlab-ci by creating automated upload of cookbooks to the correct chef servers, simply by changing an environment variable.
Caveats
The only downside to this is if you use test kitchen
and berkshelf
, they for some reason need to query the knife.rb . You’ll need to get in the habit of setting this environment variable with them too.
CHEF_ENV=foo-lab berks install
CHEF_ENV=foo-lab berks upload
CHEF_ENV=bar-prod kitchen setup
CHEF_ENV=bar-prod kitchen converge
Alternatives
If you don’t like this solution, there is another tool that looks promising called chefvm (like RVM)