Merge in 'flexible-provisioning' which supports abstracted provisioners, chef server, additional chef solo features, and better chef configuration overall. Also includes pluggable configuration keys.
This commit is contained in:
commit
9ba0647b64
|
@ -16,15 +16,8 @@ Vagrant::Config.run do |config|
|
||||||
config.vm.project_directory = "/vagrant"
|
config.vm.project_directory = "/vagrant"
|
||||||
config.vm.forward_port("ssh", 22, 2222)
|
config.vm.forward_port("ssh", 22, 2222)
|
||||||
config.vm.disk_image_format = 'VMDK'
|
config.vm.disk_image_format = 'VMDK'
|
||||||
|
config.vm.provisioner = nil
|
||||||
|
|
||||||
config.package.name = 'vagrant'
|
config.package.name = 'vagrant'
|
||||||
config.package.extension = '.box'
|
config.package.extension = '.box'
|
||||||
|
|
||||||
config.chef.enabled = false
|
|
||||||
config.chef.cookbooks_path = "cookbooks"
|
|
||||||
config.chef.provisioning_path = "/tmp/vagrant-chef"
|
|
||||||
config.chef.json = {
|
|
||||||
:instance_role => "vagrant",
|
|
||||||
:recipes => ["vagrant_main"]
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,8 @@ 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}.each do |f|
|
net/scp fileutils vagrant/util vagrant/actions/base vagrant/downloaders/base vagrant/actions/runner
|
||||||
|
vagrant/config vagrant/provisioners/base vagrant/provisioners/chef}.each do |f|
|
||||||
require f
|
require f
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,69 +2,47 @@ module Vagrant
|
||||||
module Actions
|
module Actions
|
||||||
module VM
|
module VM
|
||||||
class Provision < Base
|
class Provision < Base
|
||||||
|
attr_reader :provisioner
|
||||||
|
|
||||||
|
def intialize(*args)
|
||||||
|
super
|
||||||
|
|
||||||
|
@provisioner = nil
|
||||||
|
end
|
||||||
|
|
||||||
def prepare
|
def prepare
|
||||||
Vagrant.config.vm.share_folder("vagrant-provisioning", cookbooks_path, File.expand_path(Vagrant.config.chef.cookbooks_path, Env.root_path))
|
provisioner = Vagrant.config.vm.provisioner
|
||||||
|
|
||||||
|
if provisioner.nil?
|
||||||
|
logger.info("Provisioning not enabled, ignoring this step")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if provisioner.is_a?(Class)
|
||||||
|
@provisioner = provisioner.new
|
||||||
|
raise ActionException.new("Provisioners must be an instance of Vagrant::Provisioners::Base") unless @provisioner.is_a?(Provisioners::Base)
|
||||||
|
elsif provisioner.is_a?(Symbol)
|
||||||
|
# We have a few hard coded provisioners for built-ins
|
||||||
|
mapping = {
|
||||||
|
:chef_solo => Provisioners::ChefSolo,
|
||||||
|
:chef_server => Provisioners::ChefServer
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner_klass = mapping[provisioner]
|
||||||
|
raise ActionException.new("Unknown provisioner type: #{provisioner}") if provisioner_klass.nil?
|
||||||
|
@provisioner = provisioner_klass.new
|
||||||
|
end
|
||||||
|
|
||||||
|
logger.info "Provisioning enabled with #{@provisioner.class}"
|
||||||
|
@provisioner.prepare
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute!
|
def execute!
|
||||||
chown_provisioning_folder
|
if provisioner
|
||||||
setup_json
|
logger.info "Beginning provisioning process..."
|
||||||
setup_solo_config
|
provisioner.provision!
|
||||||
run_chef_solo
|
|
||||||
end
|
|
||||||
|
|
||||||
def chown_provisioning_folder
|
|
||||||
logger.info "Setting permissions on provisioning folder..."
|
|
||||||
SSH.execute do |ssh|
|
|
||||||
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_json
|
|
||||||
logger.info "Generating 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
|
|
||||||
|
|
||||||
def setup_solo_config
|
|
||||||
solo_file = <<-solo
|
|
||||||
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
|
|
||||||
cookbook_path "#{cookbooks_path}"
|
|
||||||
solo
|
|
||||||
|
|
||||||
logger.info "Uploading chef-solo configuration script..."
|
|
||||||
SSH.upload!(StringIO.new(solo_file), File.join(Vagrant.config.chef.provisioning_path, "solo.rb"))
|
|
||||||
end
|
|
||||||
|
|
||||||
def run_chef_solo
|
|
||||||
logger.info "Running chef recipes..."
|
|
||||||
SSH.execute do |ssh|
|
|
||||||
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
|
|
||||||
# an error, or when verbosity level is set high
|
|
||||||
logger.info("#{stream}: #{data}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def cookbooks_path
|
|
||||||
File.join(Vagrant.config.chef.provisioning_path, "cookbooks")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Vagrant
|
||||||
def prepare
|
def prepare
|
||||||
steps = [ForwardPorts, SharedFolders, Boot]
|
steps = [ForwardPorts, SharedFolders, Boot]
|
||||||
steps.unshift(Halt) if @runner.vm.running?
|
steps.unshift(Halt) if @runner.vm.running?
|
||||||
steps << Provision if Vagrant.config.chef.enabled
|
steps << Provision if !Vagrant.config.vm.provisioner.nil?
|
||||||
|
|
||||||
steps.each do |action_klass|
|
steps.each do |action_klass|
|
||||||
@runner.add_action(action_klass)
|
@runner.add_action(action_klass)
|
||||||
|
|
|
@ -17,7 +17,7 @@ msg
|
||||||
# Up is a "meta-action" so it really just queues up a bunch
|
# Up is a "meta-action" so it really just queues up a bunch
|
||||||
# of other actions in its place:
|
# of other actions in its place:
|
||||||
steps = [Import, ForwardPorts, SharedFolders, Boot]
|
steps = [Import, ForwardPorts, SharedFolders, Boot]
|
||||||
steps << Provision if Vagrant.config.chef.enabled
|
steps << Provision if !Vagrant.config.vm.provisioner.nil?
|
||||||
steps.insert(0, MoveHardDrive) if Vagrant.config.vm.hd_location
|
steps.insert(0, MoveHardDrive) if Vagrant.config.vm.hd_location
|
||||||
|
|
||||||
steps.each do |action_klass|
|
steps.each do |action_klass|
|
||||||
|
|
|
@ -14,7 +14,7 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
def configures(key, klass)
|
def configures(key, klass)
|
||||||
@@config.class.configures(key, klass)
|
config.class.configures(key, klass)
|
||||||
end
|
end
|
||||||
|
|
||||||
def config
|
def config
|
||||||
|
@ -75,11 +75,12 @@ module Vagrant
|
||||||
attr_reader :shared_folders
|
attr_reader :shared_folders
|
||||||
attr_accessor :hd_location
|
attr_accessor :hd_location
|
||||||
attr_accessor :disk_image_format
|
attr_accessor :disk_image_format
|
||||||
|
attr_accessor :provisioner
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@forwarded_ports = {}
|
@forwarded_ports = {}
|
||||||
@shared_folders = {}
|
@shared_folders = {}
|
||||||
|
@provisioner = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def forward_port(name, guestport, hostport, protocol="TCP")
|
def forward_port(name, guestport, hostport, protocol="TCP")
|
||||||
|
@ -112,25 +113,6 @@ module Vagrant
|
||||||
attr_accessor :extension
|
attr_accessor :extension
|
||||||
end
|
end
|
||||||
|
|
||||||
class ChefConfig < Base
|
|
||||||
attr_accessor :cookbooks_path
|
|
||||||
attr_accessor :provisioning_path
|
|
||||||
attr_accessor :json
|
|
||||||
attr_accessor :enabled
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@enabled = false
|
|
||||||
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
|
|
||||||
|
|
||||||
class VagrantConfig < Base
|
class VagrantConfig < Base
|
||||||
attr_accessor :dotfile_name
|
attr_accessor :dotfile_name
|
||||||
attr_accessor :log_output
|
attr_accessor :log_output
|
||||||
|
@ -159,7 +141,6 @@ module Vagrant
|
||||||
configures :package, PackageConfig
|
configures :package, PackageConfig
|
||||||
configures :ssh, SSHConfig
|
configures :ssh, SSHConfig
|
||||||
configures :vm, VMConfig
|
configures :vm, VMConfig
|
||||||
configures :chef, ChefConfig
|
|
||||||
configures :vagrant, VagrantConfig
|
configures :vagrant, VagrantConfig
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
module Vagrant
|
||||||
|
module Provisioners
|
||||||
|
# The base class for a "provisioner." A provisioner is responsible for
|
||||||
|
# provisioning a Vagrant system. This has been abstracted out to provide
|
||||||
|
# support for multiple solutions such as Chef Solo, Chef Client, and
|
||||||
|
# Puppet.
|
||||||
|
class Base
|
||||||
|
include Vagrant::Util
|
||||||
|
|
||||||
|
# This is the method called to "prepare" the provisioner. This is called
|
||||||
|
# before any actions are run by the action runner (see {Vagrant::Actions::Runner}).
|
||||||
|
# This can be used to setup shared folders, forward ports, etc. Whatever is
|
||||||
|
# necessary on a "meta" level.
|
||||||
|
def prepare; end
|
||||||
|
|
||||||
|
# This is the method called to provision the system. This method
|
||||||
|
# is expected to do whatever necessary to provision the system (create files,
|
||||||
|
# SSH, etc.)
|
||||||
|
def provision!; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,102 @@
|
||||||
|
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
|
||||||
|
# Chef server specific config
|
||||||
|
attr_accessor :chef_server_url
|
||||||
|
attr_accessor :validation_key_path
|
||||||
|
attr_accessor :validation_client_name
|
||||||
|
attr_accessor :client_key_path
|
||||||
|
|
||||||
|
# Chef solo specific config
|
||||||
|
attr_accessor :cookbooks_path
|
||||||
|
|
||||||
|
# Shared config
|
||||||
|
attr_accessor :provisioning_path
|
||||||
|
attr_accessor :json
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@validation_client_name = "chef-validator"
|
||||||
|
@client_key_path = "/etc/chef/client.pem"
|
||||||
|
|
||||||
|
@cookbooks_path = "cookbooks"
|
||||||
|
@provisioning_path = "/tmp/vagrant-chef"
|
||||||
|
@json = {
|
||||||
|
:instance_role => "vagrant",
|
||||||
|
:run_list => ["recipe[vagrant_main]"]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the run list for the provisioning
|
||||||
|
def run_list
|
||||||
|
json[:run_list]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Sets the run list to the specified value
|
||||||
|
def run_list=(value)
|
||||||
|
json[:run_list] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds a recipe to the run list
|
||||||
|
def add_recipe(name)
|
||||||
|
name = "recipe[#{name}]" unless name =~ /^recipe\[(.+?)\]$/
|
||||||
|
run_list << name
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds a role to the run list
|
||||||
|
def add_role(name)
|
||||||
|
name = "role[#{name}]" unless name =~ /^role\[(.+?)\]$/
|
||||||
|
run_list << name
|
||||||
|
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 mkdir -p #{Vagrant.config.chef.provisioning_path}")
|
||||||
|
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
|
|
@ -0,0 +1,96 @@
|
||||||
|
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
|
||||||
|
elsif !File.file?(Vagrant.config.chef.validation_key_path)
|
||||||
|
raise Actions::ActionException.new(<<-msg)
|
||||||
|
The validation key set for `config.chef.validation_key_path` does not exist! This
|
||||||
|
file needs to exist so it can be uploaded to the virtual machine. It is
|
||||||
|
currently set to "#{Vagrant.config.chef.validation_key_path}"
|
||||||
|
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
|
||||||
|
create_client_key_folder
|
||||||
|
upload_validation_key
|
||||||
|
setup_json
|
||||||
|
setup_config
|
||||||
|
run_chef_client
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_client_key_folder
|
||||||
|
logger.info "Creating folder to hold client key..."
|
||||||
|
path = Pathname.new(Vagrant.config.chef.client_key_path)
|
||||||
|
|
||||||
|
SSH.execute do |ssh|
|
||||||
|
ssh.exec!("sudo mkdir -p #{path.dirname}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_validation_key
|
||||||
|
logger.info "Uploading chef client validation key..."
|
||||||
|
SSH.upload!(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 "#{Vagrant.config.chef.client_key_path}"
|
||||||
|
|
||||||
|
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 validation_key_path
|
||||||
|
File.expand_path(Vagrant.config.chef.validation_key_path, Env.root_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def guest_validation_key_path
|
||||||
|
File.join(Vagrant.config.chef.provisioning_path, "validation.pem")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,67 @@
|
||||||
|
module Vagrant
|
||||||
|
module Provisioners
|
||||||
|
# This class implements provisioning via chef-solo.
|
||||||
|
class ChefSolo < Chef
|
||||||
|
def prepare
|
||||||
|
share_cookbook_folders
|
||||||
|
end
|
||||||
|
|
||||||
|
def provision!
|
||||||
|
chown_provisioning_folder
|
||||||
|
setup_json
|
||||||
|
setup_solo_config
|
||||||
|
run_chef_solo
|
||||||
|
end
|
||||||
|
|
||||||
|
def share_cookbook_folders
|
||||||
|
host_cookbook_paths.each_with_index do |cookbook, i|
|
||||||
|
Vagrant.config.vm.share_folder("vagrant-chef-solo-#{i}", cookbook_path(i), cookbook)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_solo_config
|
||||||
|
solo_file = <<-solo
|
||||||
|
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
|
||||||
|
cookbook_path #{cookbooks_path}
|
||||||
|
solo
|
||||||
|
|
||||||
|
logger.info "Uploading chef-solo configuration script..."
|
||||||
|
SSH.upload!(StringIO.new(solo_file), File.join(Vagrant.config.chef.provisioning_path, "solo.rb"))
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_chef_solo
|
||||||
|
logger.info "Running chef-solo..."
|
||||||
|
SSH.execute do |ssh|
|
||||||
|
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
|
||||||
|
# an error, or when verbosity level is set high
|
||||||
|
logger.info("#{stream}: #{data}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def host_cookbook_paths
|
||||||
|
cookbooks = Vagrant.config.chef.cookbooks_path
|
||||||
|
cookbooks = [cookbooks] unless cookbooks.is_a?(Array)
|
||||||
|
cookbooks.collect! { |cookbook| File.expand_path(cookbook, Env.root_path) }
|
||||||
|
return cookbooks
|
||||||
|
end
|
||||||
|
|
||||||
|
def cookbook_path(i)
|
||||||
|
File.join(Vagrant.config.chef.provisioning_path, "cookbooks-#{i}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def cookbooks_path
|
||||||
|
result = []
|
||||||
|
host_cookbook_paths.each_with_index do |host_path, i|
|
||||||
|
result << cookbook_path(i)
|
||||||
|
end
|
||||||
|
|
||||||
|
# We're lucky that ruby's string and array syntax for strings is the
|
||||||
|
# same as JSON, so we can just convert to JSON here and use that
|
||||||
|
result = result.to_s if result.length == 1
|
||||||
|
result.to_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -42,6 +42,10 @@ class Test::Unit::TestCase
|
||||||
config.package.name = 'vagrant'
|
config.package.name = 'vagrant'
|
||||||
config.package.extension = '.box'
|
config.package.extension = '.box'
|
||||||
|
|
||||||
|
# Chef
|
||||||
|
config.chef.chef_server_url = "http://localhost:4000"
|
||||||
|
config.chef.validation_key_path = "validation.pem"
|
||||||
|
config.chef.client_key_path = "/zoo/foo/bar.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 = {
|
||||||
|
|
|
@ -2,103 +2,107 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||||
|
|
||||||
class ProvisionActionTest < Test::Unit::TestCase
|
class ProvisionActionTest < Test::Unit::TestCase
|
||||||
setup do
|
setup do
|
||||||
@mock_vm, @vm, @action = mock_action(Vagrant::Actions::VM::Provision)
|
@runner, @vm, @action = mock_action(Vagrant::Actions::VM::Provision)
|
||||||
|
|
||||||
Vagrant::SSH.stubs(:execute)
|
|
||||||
Vagrant::SSH.stubs(:upload!)
|
|
||||||
|
|
||||||
mock_config
|
mock_config
|
||||||
end
|
end
|
||||||
|
|
||||||
context "shared folders" do
|
context "initialization" do
|
||||||
should "setup shared folder on VM for the cookbooks" do
|
should "have a nil provisioner by default" do
|
||||||
File.expects(:expand_path).with(Vagrant.config.chef.cookbooks_path, Vagrant::Env.root_path).returns("foo")
|
assert_nil @action.provisioner
|
||||||
@action.expects(:cookbooks_path).returns("bar")
|
|
||||||
Vagrant.config.vm.expects(:share_folder).with("vagrant-provisioning", "bar", "foo").once
|
|
||||||
@action.prepare
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "cookbooks path" do
|
context "executing" do
|
||||||
should "return the proper cookbook path" do
|
should "do nothing if the provisioner is nil" do
|
||||||
cookbooks_path = File.join(Vagrant.config.chef.provisioning_path, "cookbooks")
|
@action.expects(:provisioner).returns(nil)
|
||||||
assert_equal cookbooks_path, @action.cookbooks_path
|
assert_nothing_raised { @action.execute! }
|
||||||
|
end
|
||||||
|
|
||||||
|
should "call `provision!` on the provisioner" do
|
||||||
|
provisioner = mock("provisioner")
|
||||||
|
provisioner.expects(:provision!).once
|
||||||
|
@action.expects(:provisioner).twice.returns(provisioner)
|
||||||
|
@action.execute!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "permissions on provisioning folder" do
|
context "preparing" do
|
||||||
should "chown the folder to the ssh user" do
|
context "with a nil provisioner" do
|
||||||
ssh = mock("ssh")
|
setup do
|
||||||
ssh.expects(:exec!).with("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
mock_config do |config|
|
||||||
Vagrant::SSH.expects(:execute).yields(ssh)
|
config.vm.provisioner = nil
|
||||||
@action.chown_provisioning_folder
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
@action.setup_json
|
should "not set a provisioner if set to nil" do
|
||||||
end
|
@action.prepare
|
||||||
|
assert_nil @action.provisioner
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
||||||
should "add the directory as a special case to the JSON" do
|
context "with a Class provisioner" do
|
||||||
assert_json do |data|
|
setup do
|
||||||
assert_equal Vagrant.config.vm.project_directory, data["vagrant"]["directory"]
|
@instance = mock("instance")
|
||||||
|
@instance.stubs(:is_a?).with(Vagrant::Provisioners::Base).returns(true)
|
||||||
|
@instance.stubs(:prepare)
|
||||||
|
@klass = mock("klass")
|
||||||
|
@klass.stubs(:is_a?).with(Class).returns(true)
|
||||||
|
@klass.stubs(:new).returns(@instance)
|
||||||
|
|
||||||
|
mock_config do |config|
|
||||||
|
config.vm.provisioner = @klass
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "set the provisioner to an instantiation of the class" do
|
||||||
|
@klass.expects(:new).once.returns(@instance)
|
||||||
|
assert_nothing_raised { @action.prepare }
|
||||||
|
assert_equal @instance, @action.provisioner
|
||||||
|
end
|
||||||
|
|
||||||
|
should "call prepare on the instance" do
|
||||||
|
@instance.expects(:prepare).once
|
||||||
|
@action.prepare
|
||||||
|
end
|
||||||
|
|
||||||
|
should "raise an exception if the class is not a subclass of the provisioner base" do
|
||||||
|
@instance.expects(:is_a?).with(Vagrant::Provisioners::Base).returns(false)
|
||||||
|
assert_raises(Vagrant::Actions::ActionException) {
|
||||||
|
@action.prepare
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
should "add the config to the JSON" do
|
context "with a Symbol provisioner" do
|
||||||
assert_json do |data|
|
def provisioner_expectation(symbol, provisioner)
|
||||||
assert_equal Vagrant.config.vm.project_directory, data["vagrant"]["config"]["vm"]["project_directory"]
|
mock_config do |config|
|
||||||
|
config.vm.provisioner = symbol
|
||||||
|
end
|
||||||
|
|
||||||
|
instance = mock("instance")
|
||||||
|
instance.expects(:prepare).once
|
||||||
|
provisioner.expects(:new).returns(instance)
|
||||||
|
assert_nothing_raised { @action.prepare }
|
||||||
|
assert_equal instance, @action.provisioner
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
should "upload a StringIO to dna.json" do
|
should "raise an ActionException if its an unknown symbol" do
|
||||||
StringIO.expects(:new).with(anything).returns("bar")
|
mock_config do |config|
|
||||||
File.expects(:join).with(Vagrant.config.chef.provisioning_path, "dna.json").once.returns("baz")
|
config.vm.provisioner = :this_will_never_exist
|
||||||
Vagrant::SSH.expects(:upload!).with("bar", "baz").once
|
end
|
||||||
@action.setup_json
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "generating and uploading chef solo configuration file" do
|
assert_raises(Vagrant::Actions::ActionException) {
|
||||||
should "upload properly generate the configuration file using configuration data" do
|
@action.prepare
|
||||||
expected_config = <<-config
|
}
|
||||||
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
|
end
|
||||||
cookbook_path "#{@action.cookbooks_path}"
|
|
||||||
config
|
|
||||||
|
|
||||||
StringIO.expects(:new).with(expected_config).once
|
should "set :chef_solo to the ChefSolo provisioner" do
|
||||||
@action.setup_solo_config
|
provisioner_expectation(:chef_solo, Vagrant::Provisioners::ChefSolo)
|
||||||
end
|
end
|
||||||
|
|
||||||
should "upload this file as solo.rb to the provisioning folder" do
|
should "set :chef_server to the ChefServer provisioner" do
|
||||||
@action.expects(:cookbooks_path).returns("cookbooks")
|
provisioner_expectation(:chef_server, Vagrant::Provisioners::ChefServer)
|
||||||
StringIO.expects(:new).returns("foo")
|
end
|
||||||
File.expects(:join).with(Vagrant.config.chef.provisioning_path, "solo.rb").once.returns("bar")
|
|
||||||
Vagrant::SSH.expects(:upload!).with("foo", "bar").once
|
|
||||||
@action.setup_solo_config
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "running chef solo" do
|
|
||||||
should "cd into the provisioning directory and run chef solo" do
|
|
||||||
ssh = mock("ssh")
|
|
||||||
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)
|
|
||||||
@action.run_chef_solo
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,7 +33,8 @@ class ReloadActionTest < Test::Unit::TestCase
|
||||||
|
|
||||||
should "add in the provisioning step if enabled" do
|
should "add in the provisioning step if enabled" do
|
||||||
mock_config do |config|
|
mock_config do |config|
|
||||||
config.chef.enabled = true
|
# Dummy provisioner to test
|
||||||
|
config.vm.provisioner = "foo"
|
||||||
end
|
end
|
||||||
|
|
||||||
@default_order.push(Vagrant::Actions::VM::Provision)
|
@default_order.push(Vagrant::Actions::VM::Provision)
|
||||||
|
|
|
@ -47,7 +47,7 @@ class UpActionTest < Test::Unit::TestCase
|
||||||
|
|
||||||
should "add in the provisioning step if enabled" do
|
should "add in the provisioning step if enabled" do
|
||||||
mock_config do |config|
|
mock_config do |config|
|
||||||
config.chef.enabled = true
|
config.vm.provisioner = "foo"
|
||||||
end
|
end
|
||||||
|
|
||||||
@default_order.push(Vagrant::Actions::VM::Provision)
|
@default_order.push(Vagrant::Actions::VM::Provision)
|
||||||
|
|
|
@ -117,18 +117,6 @@ class ConfigTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "chef config" do
|
|
||||||
setup do
|
|
||||||
@config = Vagrant::Config::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 "top config class" do
|
context "top config class" do
|
||||||
setup do
|
setup do
|
||||||
@configures_list = []
|
@configures_list = []
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||||
|
|
||||||
|
class BaseProvisionerTest < Test::Unit::TestCase
|
||||||
|
should "include the util class so subclasses have access to it" do
|
||||||
|
assert Vagrant::Provisioners::Base.include?(Vagrant::Util)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "base instance" do
|
||||||
|
setup do
|
||||||
|
@base = Vagrant::Provisioners::Base.new
|
||||||
|
end
|
||||||
|
|
||||||
|
should "implement provision! which does nothing" do
|
||||||
|
assert_nothing_raised do
|
||||||
|
assert @base.respond_to?(:provision!)
|
||||||
|
@base.provision!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "implement prepare which does nothing" do
|
||||||
|
assert_nothing_raised do
|
||||||
|
assert @base.respond_to?(:prepare)
|
||||||
|
@base.prepare
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,175 @@
|
||||||
|
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(:create_client_key_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
|
||||||
|
setup do
|
||||||
|
File.stubs(:file?).returns(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
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 validation_key_path does exist" do
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.validation_key_path = "7"
|
||||||
|
end
|
||||||
|
|
||||||
|
File.expects(:file?).with(Vagrant.config.chef.validation_key_path).returns(true)
|
||||||
|
assert_nothing_raised { @action.prepare }
|
||||||
|
end
|
||||||
|
|
||||||
|
should "raise an exception if validation_key_path doesn't exist" do
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.validation_key_path = "7"
|
||||||
|
end
|
||||||
|
|
||||||
|
File.expects(:file?).with(Vagrant.config.chef.validation_key_path).returns(false)
|
||||||
|
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 "creating the client key folder" do
|
||||||
|
setup do
|
||||||
|
@raw_path = "/foo/bar/baz.pem"
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.client_key_path = @raw_path
|
||||||
|
end
|
||||||
|
|
||||||
|
@path = Pathname.new(@raw_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "create the folder using the dirname of the path" do
|
||||||
|
ssh = mock("ssh")
|
||||||
|
ssh.expects(:exec!).with("sudo mkdir -p #{@path.dirname}").once
|
||||||
|
Vagrant::SSH.expects(:execute).yields(ssh)
|
||||||
|
@action.create_client_key_folder
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "uploading the validation key" do
|
||||||
|
should "upload the validation key to the provisioning path" do
|
||||||
|
@action.expects(:validation_key_path).once.returns("foo")
|
||||||
|
@action.expects(:guest_validation_key_path).once.returns("bar")
|
||||||
|
Vagrant::SSH.expects(:upload!).with("foo", "bar").once
|
||||||
|
@action.upload_validation_key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "the validation key path" do
|
||||||
|
should "expand the configured key path" do
|
||||||
|
result = mock("result")
|
||||||
|
File.expects(:expand_path).with(Vagrant.config.chef.validation_key_path, Vagrant::Env.root_path).once.returns(result)
|
||||||
|
assert_equal result, @action.validation_key_path
|
||||||
|
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 "#{Vagrant.config.chef.client_key_path}"
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,142 @@
|
||||||
|
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||||
|
|
||||||
|
class ChefSoloProvisionerTest < Test::Unit::TestCase
|
||||||
|
setup do
|
||||||
|
@action = Vagrant::Provisioners::ChefSolo.new
|
||||||
|
|
||||||
|
Vagrant::SSH.stubs(:execute)
|
||||||
|
Vagrant::SSH.stubs(:upload!)
|
||||||
|
|
||||||
|
mock_config
|
||||||
|
end
|
||||||
|
|
||||||
|
context "preparing" do
|
||||||
|
should "share cookbook folders" do
|
||||||
|
@action.expects(:share_cookbook_folders).once
|
||||||
|
@action.prepare
|
||||||
|
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 "sharing cookbook folders" do
|
||||||
|
setup do
|
||||||
|
@host_cookbook_paths = ["foo", "bar"]
|
||||||
|
@action.stubs(:host_cookbook_paths).returns(@host_cookbook_paths)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "share each cookbook folder" do
|
||||||
|
share_seq = sequence("share_seq")
|
||||||
|
@host_cookbook_paths.each_with_index do |cookbook, i|
|
||||||
|
Vagrant.config.vm.expects(:share_folder).with("vagrant-chef-solo-#{i}", @action.cookbook_path(i), cookbook).in_sequence(share_seq)
|
||||||
|
end
|
||||||
|
|
||||||
|
@action.share_cookbook_folders
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "host cookbooks paths" do
|
||||||
|
should "expand the path of the cookbooks relative to the environment root path" do
|
||||||
|
@cookbook = "foo"
|
||||||
|
@expanded = "bar"
|
||||||
|
File.expects(:expand_path).with(@cookbook, Vagrant::Env.root_path).returns(@expanded)
|
||||||
|
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.cookbooks_path = @cookbook
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal [@expanded], @action.host_cookbook_paths
|
||||||
|
end
|
||||||
|
|
||||||
|
should "return as an array if was originally a string" do
|
||||||
|
File.stubs(:expand_path).returns("foo")
|
||||||
|
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.cookbooks_path = "foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal ["foo"], @action.host_cookbook_paths
|
||||||
|
end
|
||||||
|
|
||||||
|
should "return the array of cookbooks if its an array" do
|
||||||
|
cookbooks = ["foo", "bar"]
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.cookbooks_path = cookbooks
|
||||||
|
end
|
||||||
|
|
||||||
|
expand_seq = sequence('expand_seq')
|
||||||
|
cookbooks.each do |cookbook|
|
||||||
|
File.expects(:expand_path).with(cookbook, Vagrant::Env.root_path).returns(cookbook)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal cookbooks, @action.host_cookbook_paths
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "cookbooks path" do
|
||||||
|
should "return a proper path to a single cookbook" do
|
||||||
|
expected = File.join(Vagrant.config.chef.provisioning_path, "cookbooks-5")
|
||||||
|
assert_equal expected, @action.cookbook_path(5)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "return array-representation of cookbook paths if multiple" do
|
||||||
|
@cookbooks = (0..5).inject([]) do |acc, i|
|
||||||
|
acc << @action.cookbook_path(i)
|
||||||
|
end
|
||||||
|
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.cookbooks_path = @cookbooks
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal @cookbooks.to_json, @action.cookbooks_path
|
||||||
|
end
|
||||||
|
|
||||||
|
should "return a single string representation if cookbook paths is single" do
|
||||||
|
@cookbooks = @action.cookbook_path(0)
|
||||||
|
|
||||||
|
mock_config do |config|
|
||||||
|
config.chef.cookbooks_path = @cookbooks
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal @cookbooks.to_json, @action.cookbooks_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "generating and uploading chef solo configuration file" do
|
||||||
|
should "upload properly generate the configuration file using configuration data" do
|
||||||
|
expected_config = <<-config
|
||||||
|
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
|
||||||
|
cookbook_path #{@action.cookbooks_path}
|
||||||
|
config
|
||||||
|
|
||||||
|
StringIO.expects(:new).with(expected_config).once
|
||||||
|
@action.setup_solo_config
|
||||||
|
end
|
||||||
|
|
||||||
|
should "upload this file as solo.rb to the provisioning folder" do
|
||||||
|
@action.expects(:cookbooks_path).returns("cookbooks")
|
||||||
|
StringIO.expects(:new).returns("foo")
|
||||||
|
File.expects(:join).with(Vagrant.config.chef.provisioning_path, "solo.rb").once.returns("bar")
|
||||||
|
Vagrant::SSH.expects(:upload!).with("foo", "bar").once
|
||||||
|
@action.setup_solo_config
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "running chef solo" do
|
||||||
|
should "cd into the provisioning directory and run chef solo" do
|
||||||
|
ssh = mock("ssh")
|
||||||
|
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)
|
||||||
|
@action.run_chef_solo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,116 @@
|
||||||
|
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.run_list.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not include the 'json' key in the config dump" do
|
||||||
|
result = JSON.parse(@config.to_json)
|
||||||
|
assert !result.has_key?("json")
|
||||||
|
end
|
||||||
|
|
||||||
|
should "provide accessors to the run list" do
|
||||||
|
@config.run_list << "foo"
|
||||||
|
assert !@config.run_list.empty?
|
||||||
|
assert_equal ["foo"], @config.run_list
|
||||||
|
end
|
||||||
|
|
||||||
|
should "provide a writer for the run list" do
|
||||||
|
data = mock("data")
|
||||||
|
|
||||||
|
assert_nothing_raised {
|
||||||
|
@config.run_list = data
|
||||||
|
assert_equal data, @config.run_list
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
should "add a recipe to the run list" do
|
||||||
|
@config.add_recipe("foo")
|
||||||
|
assert_equal "recipe[foo]", @config.run_list[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not wrap the recipe in 'recipe[]' if it was in the name" do
|
||||||
|
@config.add_recipe("recipe[foo]")
|
||||||
|
assert_equal "recipe[foo]", @config.run_list[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
should "add a role to the run list" do
|
||||||
|
@config.add_role("user")
|
||||||
|
assert_equal "role[user]", @config.run_list[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
should "not wrap the role in 'role[]' if it was in the name" do
|
||||||
|
@config.add_role("role[user]")
|
||||||
|
assert_equal "role[user]", @config.run_list[0]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "permissions on provisioning folder" 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 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
|
||||||
|
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