Chef server provisioner
This commit is contained in:
parent
df648803dd
commit
df2e80140d
|
@ -6,11 +6,20 @@ module Vagrant
|
||||||
class Chef < Base
|
class Chef < Base
|
||||||
# This is the configuration which is available through `config.chef`
|
# This is the configuration which is available through `config.chef`
|
||||||
class ChefConfig < Vagrant::Config::Base
|
class ChefConfig < Vagrant::Config::Base
|
||||||
|
# Chef server specific config
|
||||||
|
attr_accessor :chef_server_url
|
||||||
|
attr_accessor :validation_key_path
|
||||||
|
attr_accessor :validation_client_name
|
||||||
|
|
||||||
|
# Chef solo specific config
|
||||||
attr_accessor :cookbooks_path
|
attr_accessor :cookbooks_path
|
||||||
|
|
||||||
|
# Shared config
|
||||||
attr_accessor :provisioning_path
|
attr_accessor :provisioning_path
|
||||||
attr_accessor :json
|
attr_accessor :json
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
|
@validation_client_name = "chef-validator"
|
||||||
@cookbooks_path = "cookbooks"
|
@cookbooks_path = "cookbooks"
|
||||||
@provisioning_path = "/tmp/vagrant-chef"
|
@provisioning_path = "/tmp/vagrant-chef"
|
||||||
@json = {
|
@json = {
|
||||||
|
@ -38,6 +47,7 @@ module Vagrant
|
||||||
def chown_provisioning_folder
|
def chown_provisioning_folder
|
||||||
logger.info "Setting permissions on chef provisioning folder..."
|
logger.info "Setting permissions on chef provisioning folder..."
|
||||||
SSH.execute do |ssh|
|
SSH.execute do |ssh|
|
||||||
|
ssh.exec!("sudo mkdir -p #{Vagrant.config.chef.provisioning_path}")
|
||||||
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
module Vagrant
|
||||||
|
module Provisioners
|
||||||
|
# This class implements provisioning via chef-client, allowing provisioning
|
||||||
|
# with a chef server.
|
||||||
|
class ChefServer < Chef
|
||||||
|
def prepare
|
||||||
|
if Vagrant.config.chef.validation_key_path.nil?
|
||||||
|
raise Actions::ActionException.new(<<-msg)
|
||||||
|
Chef server provisioning requires that the `config.chef.validation_key_path` configuration
|
||||||
|
be set to a path on your local machine of the validation key used to register the
|
||||||
|
VM with the chef server.
|
||||||
|
msg
|
||||||
|
end
|
||||||
|
|
||||||
|
if Vagrant.config.chef.chef_server_url.nil?
|
||||||
|
raise Actions::ActionException.new(<<-msg)
|
||||||
|
Chef server provisioning requires that the `config.chef.chef_server_url` be set to the
|
||||||
|
URL of your chef server. Examples include "http://12.12.12.12:4000" and
|
||||||
|
"http://myserver.com:4000" (the port of course can be different, but 4000 is the default)
|
||||||
|
msg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def provision!
|
||||||
|
chown_provisioning_folder
|
||||||
|
upload_validation_key
|
||||||
|
setup_json
|
||||||
|
setup_config
|
||||||
|
run_chef_client
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_validation_key
|
||||||
|
logger.info "Uploading chef client validation key..."
|
||||||
|
SSH.upload!(Vagrant.config.chef.validation_key_path, guest_validation_key_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_config
|
||||||
|
solo_file = <<-solo
|
||||||
|
log_level :info
|
||||||
|
log_location STDOUT
|
||||||
|
ssl_verify_mode :verify_none
|
||||||
|
chef_server_url "#{Vagrant.config.chef.chef_server_url}"
|
||||||
|
|
||||||
|
validation_client_name "#{Vagrant.config.chef.validation_client_name}"
|
||||||
|
validation_key "#{guest_validation_key_path}"
|
||||||
|
client_key "/etc/chef/client.pem"
|
||||||
|
|
||||||
|
file_store_path "/srv/chef/file_store"
|
||||||
|
file_cache_path "/srv/chef/cache"
|
||||||
|
|
||||||
|
pid_file "/var/run/chef/chef-client.pid"
|
||||||
|
|
||||||
|
Mixlib::Log::Formatter.show_time = true
|
||||||
|
solo
|
||||||
|
|
||||||
|
logger.info "Uploading chef-client configuration script..."
|
||||||
|
SSH.upload!(StringIO.new(solo_file), File.join(Vagrant.config.chef.provisioning_path, "client.rb"))
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_chef_client
|
||||||
|
logger.info "Running chef-client..."
|
||||||
|
SSH.execute do |ssh|
|
||||||
|
ssh.exec!("cd #{Vagrant.config.chef.provisioning_path} && sudo chef-client -c client.rb -j dna.json") do |channel, data, stream|
|
||||||
|
# TODO: Very verbose. It would be easier to save the data and only show it during
|
||||||
|
# an error, or when verbosity level is set high
|
||||||
|
logger.info("#{stream}: #{data}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def guest_validation_key_path
|
||||||
|
File.join(Vagrant.config.chef.provisioning_path, "validation.pem")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -43,6 +43,8 @@ class Test::Unit::TestCase
|
||||||
config.package.extension = '.box'
|
config.package.extension = '.box'
|
||||||
|
|
||||||
# Chef
|
# Chef
|
||||||
|
config.chef.chef_server_url = "http://localhost:4000"
|
||||||
|
config.chef.validation_key_path = "validation.pem"
|
||||||
config.chef.cookbooks_path = "cookbooks"
|
config.chef.cookbooks_path = "cookbooks"
|
||||||
config.chef.provisioning_path = "/tmp/hobo-chef"
|
config.chef.provisioning_path = "/tmp/hobo-chef"
|
||||||
config.chef.json = {
|
config.chef.json = {
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||||
|
|
||||||
|
class ChefServerProvisionerTest < Test::Unit::TestCase
|
||||||
|
setup do
|
||||||
|
@action = Vagrant::Provisioners::ChefServer.new
|
||||||
|
|
||||||
|
Vagrant::SSH.stubs(:execute)
|
||||||
|
Vagrant::SSH.stubs(:upload!)
|
||||||
|
|
||||||
|
mock_config
|
||||||
|
end
|
||||||
|
|
||||||
|
context "provisioning" do
|
||||||
|
should "run the proper sequence of methods in order" do
|
||||||
|
prov_seq = sequence("prov_seq")
|
||||||
|
@action.expects(:chown_provisioning_folder).once.in_sequence(prov_seq)
|
||||||
|
@action.expects(:upload_validation_key).once.in_sequence(prov_seq)
|
||||||
|
@action.expects(:setup_json).once.in_sequence(prov_seq)
|
||||||
|
@action.expects(:setup_config).once.in_sequence(prov_seq)
|
||||||
|
@action.expects(:run_chef_client).once.in_sequence(prov_seq)
|
||||||
|
@action.provision!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "preparing" do
|
||||||
|
should "not raise an exception if validation_key_path is set" do
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.validation_key_path = "7"
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_nothing_raised { @action.prepare }
|
||||||
|
end
|
||||||
|
|
||||||
|
should "raise an exception if validation_key_path is nil" do
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.validation_key_path = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_raises(Vagrant::Actions::ActionException) {
|
||||||
|
@action.prepare
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not raise an exception if chef_server_url is set" do
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.chef_server_url = "7"
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_nothing_raised { @action.prepare }
|
||||||
|
end
|
||||||
|
|
||||||
|
should "raise an exception if chef_server_url is nil" do
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.chef_server_url = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_raises(Vagrant::Actions::ActionException) {
|
||||||
|
@action.prepare
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "uploading the validation key" do
|
||||||
|
should "upload the validation key to the provisioning path" do
|
||||||
|
@action.expects(:guest_validation_key_path).once.returns("bar")
|
||||||
|
Vagrant::SSH.expects(:upload!).with(Vagrant.config.chef.validation_key_path, "bar").once
|
||||||
|
@action.upload_validation_key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "the guest validation key path" do
|
||||||
|
should "be the provisioning path joined with validation.pem" do
|
||||||
|
result = mock("result")
|
||||||
|
File.expects(:join).with(Vagrant.config.chef.provisioning_path, "validation.pem").once.returns(result)
|
||||||
|
assert_equal result, @action.guest_validation_key_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "generating and uploading chef client configuration file" do
|
||||||
|
setup do
|
||||||
|
@action.stubs(:guest_validation_key_path).returns("foo")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "upload properly generate the configuration file using configuration data" do
|
||||||
|
expected_config = <<-config
|
||||||
|
log_level :info
|
||||||
|
log_location STDOUT
|
||||||
|
ssl_verify_mode :verify_none
|
||||||
|
chef_server_url "#{Vagrant.config.chef.chef_server_url}"
|
||||||
|
|
||||||
|
validation_client_name "#{Vagrant.config.chef.validation_client_name}"
|
||||||
|
validation_key "#{@action.guest_validation_key_path}"
|
||||||
|
client_key "/etc/chef/client.pem"
|
||||||
|
|
||||||
|
file_store_path "/srv/chef/file_store"
|
||||||
|
file_cache_path "/srv/chef/cache"
|
||||||
|
|
||||||
|
pid_file "/var/run/chef/chef-client.pid"
|
||||||
|
|
||||||
|
Mixlib::Log::Formatter.show_time = true
|
||||||
|
config
|
||||||
|
|
||||||
|
StringIO.expects(:new).with(expected_config).once
|
||||||
|
@action.setup_config
|
||||||
|
end
|
||||||
|
|
||||||
|
should "upload this file as client.rb to the provisioning folder" do
|
||||||
|
StringIO.expects(:new).returns("foo")
|
||||||
|
File.expects(:join).with(Vagrant.config.chef.provisioning_path, "client.rb").once.returns("bar")
|
||||||
|
Vagrant::SSH.expects(:upload!).with("foo", "bar").once
|
||||||
|
@action.setup_config
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "running chef client" do
|
||||||
|
should "cd into the provisioning directory and run chef client" do
|
||||||
|
ssh = mock("ssh")
|
||||||
|
ssh.expects(:exec!).with("cd #{Vagrant.config.chef.provisioning_path} && sudo chef-client -c client.rb -j dna.json").once
|
||||||
|
Vagrant::SSH.expects(:execute).yields(ssh)
|
||||||
|
@action.run_chef_client
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,6 +10,17 @@ class ChefSoloProvisionerTest < Test::Unit::TestCase
|
||||||
mock_config
|
mock_config
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "provisioning" do
|
||||||
|
should "run the proper sequence of methods in order" do
|
||||||
|
prov_seq = sequence("prov_seq")
|
||||||
|
@action.expects(:chown_provisioning_folder).once.in_sequence(prov_seq)
|
||||||
|
@action.expects(:setup_json).once.in_sequence(prov_seq)
|
||||||
|
@action.expects(:setup_solo_config).once.in_sequence(prov_seq)
|
||||||
|
@action.expects(:run_chef_solo).once.in_sequence(prov_seq)
|
||||||
|
@action.provision!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "shared folders" do
|
context "shared folders" do
|
||||||
should "setup shared folder on VM for the cookbooks" do
|
should "setup shared folder on VM for the cookbooks" do
|
||||||
File.expects(:expand_path).with(Vagrant.config.chef.cookbooks_path, Vagrant::Env.root_path).returns("foo")
|
File.expects(:expand_path).with(Vagrant.config.chef.cookbooks_path, Vagrant::Env.root_path).returns("foo")
|
||||||
|
|
|
@ -31,9 +31,11 @@ class ChefProvisionerTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
context "permissions on provisioning folder" do
|
context "permissions on provisioning folder" do
|
||||||
should "chown the folder to the ssh user" do
|
should "create and chown the folder to the ssh user" do
|
||||||
|
ssh_seq = sequence("ssh_seq")
|
||||||
ssh = mock("ssh")
|
ssh = mock("ssh")
|
||||||
ssh.expects(:exec!).with("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
ssh.expects(:exec!).with("sudo mkdir -p #{Vagrant.config.chef.provisioning_path}").once.in_sequence(ssh_seq)
|
||||||
|
ssh.expects(:exec!).with("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}").once.in_sequence(ssh_seq)
|
||||||
Vagrant::SSH.expects(:execute).yields(ssh)
|
Vagrant::SSH.expects(:execute).yields(ssh)
|
||||||
@action.chown_provisioning_folder
|
@action.chown_provisioning_folder
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue