Chef server provisioner
This commit is contained in:
parent
df648803dd
commit
df2e80140d
|
@ -6,11 +6,20 @@ module Vagrant
|
|||
class Chef < Base
|
||||
# This is the configuration which is available through `config.chef`
|
||||
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
|
||||
|
||||
# Shared config
|
||||
attr_accessor :provisioning_path
|
||||
attr_accessor :json
|
||||
|
||||
def initialize
|
||||
@validation_client_name = "chef-validator"
|
||||
@cookbooks_path = "cookbooks"
|
||||
@provisioning_path = "/tmp/vagrant-chef"
|
||||
@json = {
|
||||
|
@ -38,6 +47,7 @@ module Vagrant
|
|||
def chown_provisioning_folder
|
||||
logger.info "Setting permissions on chef provisioning folder..."
|
||||
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}")
|
||||
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'
|
||||
|
||||
# Chef
|
||||
config.chef.chef_server_url = "http://localhost:4000"
|
||||
config.chef.validation_key_path = "validation.pem"
|
||||
config.chef.cookbooks_path = "cookbooks"
|
||||
config.chef.provisioning_path = "/tmp/hobo-chef"
|
||||
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
|
||||
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
|
||||
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")
|
||||
|
|
|
@ -31,9 +31,11 @@ class ChefProvisionerTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
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.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)
|
||||
@action.chown_provisioning_folder
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue