Pull out common chef code into its own abstract provisioner
This commit is contained in:
parent
f6bc0ff5fc
commit
df648803dd
|
@ -5,7 +5,7 @@ PROJECT_ROOT = File.join(libdir, '..') unless defined?(PROJECT_ROOT)
|
||||||
# The libs which must be loaded prior to the rest
|
# The libs which must be loaded prior to the rest
|
||||||
%w{tempfile open-uri json pathname logger uri net/http virtualbox net/ssh archive/tar/minitar
|
%w{tempfile open-uri json pathname logger uri net/http virtualbox net/ssh archive/tar/minitar
|
||||||
net/scp fileutils vagrant/util vagrant/actions/base vagrant/downloaders/base vagrant/actions/runner
|
net/scp fileutils vagrant/util vagrant/actions/base vagrant/downloaders/base vagrant/actions/runner
|
||||||
vagrant/config vagrant/provisioners/base}.each do |f|
|
vagrant/config vagrant/provisioners/base vagrant/provisioners/chef}.each do |f|
|
||||||
require f
|
require f
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
module Vagrant
|
||||||
|
module Provisioners
|
||||||
|
# This class is a base class where the common functinality shared between
|
||||||
|
# chef-solo and chef-client provisioning are stored. This is **not an actual
|
||||||
|
# provisioner**. Instead, {ChefSolo} or {ChefServer} should be used.
|
||||||
|
class Chef < Base
|
||||||
|
# This is the configuration which is available through `config.chef`
|
||||||
|
class ChefConfig < Vagrant::Config::Base
|
||||||
|
attr_accessor :cookbooks_path
|
||||||
|
attr_accessor :provisioning_path
|
||||||
|
attr_accessor :json
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@cookbooks_path = "cookbooks"
|
||||||
|
@provisioning_path = "/tmp/vagrant-chef"
|
||||||
|
@json = {
|
||||||
|
:instance_role => "vagrant",
|
||||||
|
:run_list => ["recipe[vagrant_main]"]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_json
|
||||||
|
# Overridden so that the 'json' key could be removed, since its just
|
||||||
|
# merged into the config anyways
|
||||||
|
data = instance_variables_hash
|
||||||
|
data.delete(:json)
|
||||||
|
data.to_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Tell the Vagrant configure class about our custom configuration
|
||||||
|
Config.configures :chef, ChefConfig
|
||||||
|
|
||||||
|
def prepare
|
||||||
|
raise Actions::ActionException.new("Vagrant::Provisioners::Chef is not a valid provisioner! Use ChefSolo or ChefServer instead.")
|
||||||
|
end
|
||||||
|
|
||||||
|
def chown_provisioning_folder
|
||||||
|
logger.info "Setting permissions on chef provisioning folder..."
|
||||||
|
SSH.execute do |ssh|
|
||||||
|
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_json
|
||||||
|
logger.info "Generating chef JSON and uploading..."
|
||||||
|
|
||||||
|
# Set up initial configuration
|
||||||
|
data = {
|
||||||
|
:config => Vagrant.config,
|
||||||
|
:directory => Vagrant.config.vm.project_directory,
|
||||||
|
}
|
||||||
|
|
||||||
|
# And wrap it under the "vagrant" namespace
|
||||||
|
data = { :vagrant => data }
|
||||||
|
|
||||||
|
# Merge with the "extra data" which isn't put under the
|
||||||
|
# vagrant namespace by default
|
||||||
|
data.merge!(Vagrant.config.chef.json)
|
||||||
|
|
||||||
|
json = data.to_json
|
||||||
|
|
||||||
|
SSH.upload!(StringIO.new(json), File.join(Vagrant.config.chef.provisioning_path, "dna.json"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,36 +1,9 @@
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module Provisioners
|
module Provisioners
|
||||||
# This class implements provisioning via chef-solo.
|
# This class implements provisioning via chef-solo.
|
||||||
class ChefSolo < Base
|
class ChefSolo < Chef
|
||||||
# This is the configuration which is available through `config.chef_solo`
|
|
||||||
class CustomConfig < Vagrant::Config::Base
|
|
||||||
attr_accessor :cookbooks_path
|
|
||||||
attr_accessor :provisioning_path
|
|
||||||
attr_accessor :json
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@cookbooks_path = "cookbooks"
|
|
||||||
@provisioning_path = "/tmp/vagrant-chef"
|
|
||||||
@json = {
|
|
||||||
:instance_role => "vagrant",
|
|
||||||
:run_list => ["recipe[vagrant_main]"]
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_json
|
|
||||||
# Overridden so that the 'json' key could be removed, since its just
|
|
||||||
# merged into the config anyways
|
|
||||||
data = instance_variables_hash
|
|
||||||
data.delete(:json)
|
|
||||||
data.to_json
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Tell the Vagrant configure class about our custom configuration
|
|
||||||
Config.configures :chef_solo, CustomConfig
|
|
||||||
|
|
||||||
def prepare
|
def prepare
|
||||||
Vagrant.config.vm.share_folder("vagrant-chef-solo", cookbooks_path, File.expand_path(Vagrant.config.chef_solo.cookbooks_path, Env.root_path))
|
Vagrant.config.vm.share_folder("vagrant-chef-solo", cookbooks_path, File.expand_path(Vagrant.config.chef.cookbooks_path, Env.root_path))
|
||||||
end
|
end
|
||||||
|
|
||||||
def provision!
|
def provision!
|
||||||
|
@ -40,48 +13,20 @@ module Vagrant
|
||||||
run_chef_solo
|
run_chef_solo
|
||||||
end
|
end
|
||||||
|
|
||||||
def chown_provisioning_folder
|
|
||||||
logger.info "Setting permissions on chef solo provisioning folder..."
|
|
||||||
SSH.execute do |ssh|
|
|
||||||
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef_solo.provisioning_path}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def setup_json
|
|
||||||
logger.info "Generating chef solo JSON and uploading..."
|
|
||||||
|
|
||||||
# Set up initial configuration
|
|
||||||
data = {
|
|
||||||
:config => Vagrant.config,
|
|
||||||
:directory => Vagrant.config.vm.project_directory,
|
|
||||||
}
|
|
||||||
|
|
||||||
# And wrap it under the "vagrant" namespace
|
|
||||||
data = { :vagrant => data }
|
|
||||||
|
|
||||||
# Merge with the "extra data" which isn't put under the
|
|
||||||
# vagrant namespace by default
|
|
||||||
data.merge!(Vagrant.config.chef_solo.json)
|
|
||||||
|
|
||||||
json = data.to_json
|
|
||||||
|
|
||||||
SSH.upload!(StringIO.new(json), File.join(Vagrant.config.chef_solo.provisioning_path, "dna.json"))
|
|
||||||
end
|
|
||||||
|
|
||||||
def setup_solo_config
|
def setup_solo_config
|
||||||
solo_file = <<-solo
|
solo_file = <<-solo
|
||||||
file_cache_path "#{Vagrant.config.chef_solo.provisioning_path}"
|
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
|
||||||
cookbook_path "#{cookbooks_path}"
|
cookbook_path "#{cookbooks_path}"
|
||||||
solo
|
solo
|
||||||
|
|
||||||
logger.info "Uploading chef-solo configuration script..."
|
logger.info "Uploading chef-solo configuration script..."
|
||||||
SSH.upload!(StringIO.new(solo_file), File.join(Vagrant.config.chef_solo.provisioning_path, "solo.rb"))
|
SSH.upload!(StringIO.new(solo_file), File.join(Vagrant.config.chef.provisioning_path, "solo.rb"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_chef_solo
|
def run_chef_solo
|
||||||
logger.info "Running chef-solo..."
|
logger.info "Running chef-solo..."
|
||||||
SSH.execute do |ssh|
|
SSH.execute do |ssh|
|
||||||
ssh.exec!("cd #{Vagrant.config.chef_solo.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json") do |channel, data, stream|
|
ssh.exec!("cd #{Vagrant.config.chef.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json") do |channel, data, stream|
|
||||||
# TODO: Very verbose. It would be easier to save the data and only show it during
|
# 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
|
# an error, or when verbosity level is set high
|
||||||
logger.info("#{stream}: #{data}")
|
logger.info("#{stream}: #{data}")
|
||||||
|
@ -90,7 +35,7 @@ solo
|
||||||
end
|
end
|
||||||
|
|
||||||
def cookbooks_path
|
def cookbooks_path
|
||||||
File.join(Vagrant.config.chef_solo.provisioning_path, "cookbooks")
|
File.join(Vagrant.config.chef.provisioning_path, "cookbooks")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,10 +42,10 @@ class Test::Unit::TestCase
|
||||||
config.package.name = 'vagrant'
|
config.package.name = 'vagrant'
|
||||||
config.package.extension = '.box'
|
config.package.extension = '.box'
|
||||||
|
|
||||||
# Chef solo
|
# Chef
|
||||||
config.chef_solo.cookbooks_path = "cookbooks"
|
config.chef.cookbooks_path = "cookbooks"
|
||||||
config.chef_solo.provisioning_path = "/tmp/hobo-chef"
|
config.chef.provisioning_path = "/tmp/hobo-chef"
|
||||||
config.chef_solo.json = {
|
config.chef.json = {
|
||||||
:recipes => ["hobo_main"]
|
:recipes => ["hobo_main"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,9 @@ class ChefSoloProvisionerTest < Test::Unit::TestCase
|
||||||
mock_config
|
mock_config
|
||||||
end
|
end
|
||||||
|
|
||||||
context "config" do
|
|
||||||
setup do
|
|
||||||
@config = Vagrant::Provisioners::ChefSolo::CustomConfig.new
|
|
||||||
@config.json = "HEY"
|
|
||||||
end
|
|
||||||
|
|
||||||
should "not include the 'json' key in the config dump" do
|
|
||||||
result = JSON.parse(@config.to_json)
|
|
||||||
assert !result.has_key?("json")
|
|
||||||
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_solo.cookbooks_path, Vagrant::Env.root_path).returns("foo")
|
File.expects(:expand_path).with(Vagrant.config.chef.cookbooks_path, Vagrant::Env.root_path).returns("foo")
|
||||||
@action.expects(:cookbooks_path).returns("bar")
|
@action.expects(:cookbooks_path).returns("bar")
|
||||||
Vagrant.config.vm.expects(:share_folder).with("vagrant-chef-solo", "bar", "foo").once
|
Vagrant.config.vm.expects(:share_folder).with("vagrant-chef-solo", "bar", "foo").once
|
||||||
@action.prepare
|
@action.prepare
|
||||||
|
@ -33,62 +21,15 @@ class ChefSoloProvisionerTest < Test::Unit::TestCase
|
||||||
|
|
||||||
context "cookbooks path" do
|
context "cookbooks path" do
|
||||||
should "return the proper cookbook path" do
|
should "return the proper cookbook path" do
|
||||||
cookbooks_path = File.join(Vagrant.config.chef_solo.provisioning_path, "cookbooks")
|
cookbooks_path = File.join(Vagrant.config.chef.provisioning_path, "cookbooks")
|
||||||
assert_equal cookbooks_path, @action.cookbooks_path
|
assert_equal cookbooks_path, @action.cookbooks_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "permissions on provisioning folder" do
|
|
||||||
should "chown the folder to the ssh user" do
|
|
||||||
ssh = mock("ssh")
|
|
||||||
ssh.expects(:exec!).with("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef_solo.provisioning_path}")
|
|
||||||
Vagrant::SSH.expects(:execute).yields(ssh)
|
|
||||||
@action.chown_provisioning_folder
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "generating and uploading json" do
|
|
||||||
def assert_json
|
|
||||||
Vagrant::SSH.expects(:upload!).with do |json, path|
|
|
||||||
data = JSON.parse(json.read)
|
|
||||||
yield data
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
@action.setup_json
|
|
||||||
end
|
|
||||||
|
|
||||||
should "merge in the extra json specified in the config" do
|
|
||||||
Vagrant.config.chef_solo.json = { :foo => "BAR" }
|
|
||||||
assert_json do |data|
|
|
||||||
assert_equal "BAR", data["foo"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "add the directory as a special case to the JSON" do
|
|
||||||
assert_json do |data|
|
|
||||||
assert_equal Vagrant.config.vm.project_directory, data["vagrant"]["directory"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "add the config to the JSON" do
|
|
||||||
assert_json do |data|
|
|
||||||
assert_equal Vagrant.config.vm.project_directory, data["vagrant"]["config"]["vm"]["project_directory"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "upload a StringIO to dna.json" do
|
|
||||||
StringIO.expects(:new).with(anything).returns("bar")
|
|
||||||
File.expects(:join).with(Vagrant.config.chef_solo.provisioning_path, "dna.json").once.returns("baz")
|
|
||||||
Vagrant::SSH.expects(:upload!).with("bar", "baz").once
|
|
||||||
@action.setup_json
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "generating and uploading chef solo configuration file" do
|
context "generating and uploading chef solo configuration file" do
|
||||||
should "upload properly generate the configuration file using configuration data" do
|
should "upload properly generate the configuration file using configuration data" do
|
||||||
expected_config = <<-config
|
expected_config = <<-config
|
||||||
file_cache_path "#{Vagrant.config.chef_solo.provisioning_path}"
|
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
|
||||||
cookbook_path "#{@action.cookbooks_path}"
|
cookbook_path "#{@action.cookbooks_path}"
|
||||||
config
|
config
|
||||||
|
|
||||||
|
@ -99,7 +40,7 @@ config
|
||||||
should "upload this file as solo.rb to the provisioning folder" do
|
should "upload this file as solo.rb to the provisioning folder" do
|
||||||
@action.expects(:cookbooks_path).returns("cookbooks")
|
@action.expects(:cookbooks_path).returns("cookbooks")
|
||||||
StringIO.expects(:new).returns("foo")
|
StringIO.expects(:new).returns("foo")
|
||||||
File.expects(:join).with(Vagrant.config.chef_solo.provisioning_path, "solo.rb").once.returns("bar")
|
File.expects(:join).with(Vagrant.config.chef.provisioning_path, "solo.rb").once.returns("bar")
|
||||||
Vagrant::SSH.expects(:upload!).with("foo", "bar").once
|
Vagrant::SSH.expects(:upload!).with("foo", "bar").once
|
||||||
@action.setup_solo_config
|
@action.setup_solo_config
|
||||||
end
|
end
|
||||||
|
@ -108,7 +49,7 @@ config
|
||||||
context "running chef solo" do
|
context "running chef solo" do
|
||||||
should "cd into the provisioning directory and run chef solo" do
|
should "cd into the provisioning directory and run chef solo" do
|
||||||
ssh = mock("ssh")
|
ssh = mock("ssh")
|
||||||
ssh.expects(:exec!).with("cd #{Vagrant.config.chef_solo.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json").once
|
ssh.expects(:exec!).with("cd #{Vagrant.config.chef.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json").once
|
||||||
Vagrant::SSH.expects(:execute).yields(ssh)
|
Vagrant::SSH.expects(:execute).yields(ssh)
|
||||||
@action.run_chef_solo
|
@action.run_chef_solo
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||||
|
|
||||||
|
class ChefProvisionerTest < Test::Unit::TestCase
|
||||||
|
setup do
|
||||||
|
@action = Vagrant::Provisioners::Chef.new
|
||||||
|
|
||||||
|
Vagrant::SSH.stubs(:execute)
|
||||||
|
Vagrant::SSH.stubs(:upload!)
|
||||||
|
|
||||||
|
mock_config
|
||||||
|
end
|
||||||
|
|
||||||
|
context "preparing" do
|
||||||
|
should "raise an ActionException" do
|
||||||
|
assert_raises(Vagrant::Actions::ActionException) {
|
||||||
|
@action.prepare
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "config" do
|
||||||
|
setup do
|
||||||
|
@config = Vagrant::Provisioners::Chef::ChefConfig.new
|
||||||
|
@config.json = "HEY"
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not include the 'json' key in the config dump" do
|
||||||
|
result = JSON.parse(@config.to_json)
|
||||||
|
assert !result.has_key?("json")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "permissions on provisioning folder" do
|
||||||
|
should "chown the folder to the ssh user" do
|
||||||
|
ssh = mock("ssh")
|
||||||
|
ssh.expects(:exec!).with("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
||||||
|
Vagrant::SSH.expects(:execute).yields(ssh)
|
||||||
|
@action.chown_provisioning_folder
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "generating and uploading json" do
|
||||||
|
def assert_json
|
||||||
|
Vagrant::SSH.expects(:upload!).with do |json, path|
|
||||||
|
data = JSON.parse(json.read)
|
||||||
|
yield data
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
@action.setup_json
|
||||||
|
end
|
||||||
|
|
||||||
|
should "merge in the extra json specified in the config" do
|
||||||
|
Vagrant.config.chef.json = { :foo => "BAR" }
|
||||||
|
assert_json do |data|
|
||||||
|
assert_equal "BAR", data["foo"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "add the directory as a special case to the JSON" do
|
||||||
|
assert_json do |data|
|
||||||
|
assert_equal Vagrant.config.vm.project_directory, data["vagrant"]["directory"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "add the config to the JSON" do
|
||||||
|
assert_json do |data|
|
||||||
|
assert_equal Vagrant.config.vm.project_directory, data["vagrant"]["config"]["vm"]["project_directory"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "upload a StringIO to dna.json" do
|
||||||
|
StringIO.expects(:new).with(anything).returns("bar")
|
||||||
|
File.expects(:join).with(Vagrant.config.chef.provisioning_path, "dna.json").once.returns("baz")
|
||||||
|
Vagrant::SSH.expects(:upload!).with("bar", "baz").once
|
||||||
|
@action.setup_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue