Merge pull request #4761 from mitchellh/sethvargo/chef_omnibus

Automatically install Chef when provisioning with Chef
This commit is contained in:
Seth Vargo 2014-11-10 11:59:27 -05:00
commit 1c06da04e6
23 changed files with 866 additions and 380 deletions

1
.gitignore vendored
View File

@ -48,3 +48,4 @@ website/docs/Rakefile
website/www/.sass-cache
website/www/build
website/www/Rakefile
exec/

View File

@ -32,6 +32,7 @@ IMPROVEMENTS:
more easily. Vagrant will login for you if you specify auth. [GH-4042]
- providers/docker: `stop_timeout` can be used to modify the `docker stop`
timeout. [GH-4504]
- provisioners/chef: Automatically install Chef when using a Chef provisioner.
- synced\_folders/nfs: Won't use `sudo` to write to /etc/exports if there
are write privileges. [GH-2643]
- synced\_folders/smb: Credentials from one SMB will be copied to the rest. [GH-4675]

View File

@ -0,0 +1,19 @@
require_relative "../../omnibus"
module VagrantPlugins
module Chef
module Cap
module Debian
module ChefInstall
def self.chef_install(machine, version, prerelease)
machine.communicate.sudo("apt-get update -y -qq")
machine.communicate.sudo("apt-get install -y -qq curl")
command = Omnibus.build_command(version, prerelease)
machine.communicate.sudo(command)
end
end
end
end
end
end

View File

@ -0,0 +1,22 @@
module VagrantPlugins
module Chef
module Cap
module Linux
module ChefInstalled
# Check if Chef is installed at the given version.
# @return [true, false]
def self.chef_installed(machine, version)
knife = "/opt/chef/bin/knife"
command = "test -x #{knife}"
if version != :latest
command << "&& #{knife} --version | grep 'Chef: #{version}'"
end
machine.communicate.test(command, sudo: true)
end
end
end
end
end
end

View File

@ -0,0 +1,18 @@
require_relative "../../omnibus"
module VagrantPlugins
module Chef
module Cap
module Redhat
module ChefInstall
def self.chef_install(machine, version, prerelease)
machine.communicate.sudo("yum install -y -q curl")
command = Omnibus.build_command(version, prerelease)
machine.communicate.sudo(command)
end
end
end
end
end
end

View File

@ -6,134 +6,98 @@ module VagrantPlugins
class Base < Vagrant.plugin("2", :config)
extend Vagrant::Util::Counter
attr_accessor :arguments
attr_accessor :attempts
# The path to Chef's bin/ directory.
# @return [String]
attr_accessor :binary_path
# Arbitrary environment variables to set before running the Chef
# provisioner command.
# @return [String]
attr_accessor :binary_env
attr_accessor :custom_config_path
attr_accessor :encrypted_data_bag_secret_key_path
attr_accessor :environment
attr_accessor :formatter
attr_accessor :http_proxy
attr_accessor :http_proxy_user
attr_accessor :http_proxy_pass
attr_accessor :https_proxy
attr_accessor :https_proxy_user
attr_accessor :https_proxy_pass
attr_accessor :json
# Install Chef on the system if it does not exist. Default is true.
# This is a trinary attribute (it can have three values):
#
# - true (bool) install Chef
# - false (bool) do not install Chef
# - "force" (string) install Chef, even if it is already installed at
# the proper version
#
# @return [true, false, String]
attr_accessor :install
# The Chef log level. See the Chef docs for acceptable values.
# @return [String, Symbol]
attr_accessor :log_level
attr_accessor :no_proxy
attr_accessor :node_name
attr_accessor :provisioning_path
attr_accessor :run_list
attr_accessor :file_cache_path
attr_accessor :file_backup_path
attr_accessor :verbose_logging
# Install a prerelease version of Chef.
# @return [true, false]
attr_accessor :prerelease
# The version of Chef to install. If Chef is already installed on the
# system, the installed version is compared with the requested version.
# If they match, no action is taken. If they do not match, version of
# the value specified in this attribute will be installed over top of
# the existing version (a warning will be displayed).
#
# You can also specify "latest" (default), which will install the latest
# version of Chef on the system. In this case, Chef will use whatever
# version is on the system. To force the newest version of Chef to be
# installed on every provision, set the {#install} option to "force".
#
# @return [String]
attr_accessor :version
def initialize
super
@arguments = UNSET_VALUE
@attempts = UNSET_VALUE
@binary_path = UNSET_VALUE
@binary_env = UNSET_VALUE
@custom_config_path = UNSET_VALUE
@encrypted_data_bag_secret_key_path = UNSET_VALUE
@environment = UNSET_VALUE
@formatter = UNSET_VALUE
@http_proxy = UNSET_VALUE
@http_proxy_user = UNSET_VALUE
@http_proxy_pass = UNSET_VALUE
@https_proxy = UNSET_VALUE
@https_proxy_user = UNSET_VALUE
@https_proxy_pass = UNSET_VALUE
@install = UNSET_VALUE
@log_level = UNSET_VALUE
@no_proxy = UNSET_VALUE
@node_name = UNSET_VALUE
@provisioning_path = UNSET_VALUE
@file_cache_path = UNSET_VALUE
@file_backup_path = UNSET_VALUE
@verbose_logging = UNSET_VALUE
@json = {}
@run_list = []
end
def encrypted_data_bag_secret=(value)
puts "DEPRECATION: Chef encrypted_data_bag_secret has no effect anymore."
puts "Remove this from your Vagrantfile since it'll be removed in the next"
puts "Vagrant version."
@prerelease = UNSET_VALUE
@version = UNSET_VALUE
end
def finalize!
@arguments = nil if @arguments == UNSET_VALUE
@attempts = 1 if @attempts == UNSET_VALUE
@binary_path = nil if @binary_path == UNSET_VALUE
@binary_env = nil if @binary_env == UNSET_VALUE
@custom_config_path = nil if @custom_config_path == UNSET_VALUE
@environment = nil if @environment == UNSET_VALUE
@formatter = nil if @formatter == UNSET_VALUE
@http_proxy = nil if @http_proxy == UNSET_VALUE
@http_proxy_user = nil if @http_proxy_user == UNSET_VALUE
@http_proxy_pass = nil if @http_proxy_pass == UNSET_VALUE
@https_proxy = nil if @https_proxy == UNSET_VALUE
@https_proxy_user = nil if @https_proxy_user == UNSET_VALUE
@https_proxy_pass = nil if @https_proxy_pass == UNSET_VALUE
@install = true if @install == UNSET_VALUE
@log_level = :info if @log_level == UNSET_VALUE
@no_proxy = nil if @no_proxy == UNSET_VALUE
@node_name = nil if @node_name == UNSET_VALUE
@provisioning_path = nil if @provisioning_path == UNSET_VALUE
@file_backup_path = "/var/chef/backup" if @file_backup_path == UNSET_VALUE
@file_cache_path = "/var/chef/cache" if @file_cache_path == UNSET_VALUE
@verbose_logging = false if @verbose_logging == UNSET_VALUE
@prerelease = false if @prerelease == UNSET_VALUE
@version = :latest if @version == UNSET_VALUE
if @encrypted_data_bag_secret_key_path == UNSET_VALUE
@encrypted_data_bag_secret_key_path = nil
# Make sure the install is a symbol if it's not a boolean
if @install.respond_to?(:to_sym)
@install = @install.to_sym
end
# Make sure the version is a symbol if it's not a boolean
if @version.respond_to?(:to_sym)
@version = @version.to_sym
end
# Make sure the log level is a symbol
@log_level = @log_level.to_sym
# Set the default provisioning path to be a unique path in /tmp
if !@provisioning_path
counter = self.class.get_and_update_counter(:chef_config)
@provisioning_path = "/tmp/vagrant-chef-#{counter}"
end
end
def merge(other)
super.tap do |result|
result.instance_variable_set(:@json, @json.merge(other.json))
result.instance_variable_set(:@run_list, (@run_list + other.run_list))
end
end
# Just like the normal configuration "validate" method except that
# it returns an array of errors that should be merged into some
# other error accumulator.
# Like validate, but returns a list of errors to append.
#
# @return [Array<String>]
def validate_base(machine)
errors = _detected_errors
if @custom_config_path
expanded = File.expand_path(@custom_config_path, machine.env.root_path)
if !File.file?(expanded)
errors << I18n.t("vagrant.config.chef.custom_config_path_missing")
end
if missing?(log_level)
errors << I18n.t("vagrant.provisioners.chef.log_level_empty")
end
errors
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
# Determine if the given string is "missing" (blank)
# @return [true, false]
def missing?(obj)
obj.to_s.strip.empty?
end
end
end

View File

@ -0,0 +1,137 @@
require "vagrant/util/counter"
require_relative "base"
module VagrantPlugins
module Chef
module Config
# This is the config base for Chef provisioners that need a full Chef
# Runner object, like chef-solo or chef-client. For provisioners like
# chef-apply, these options are not valid
class BaseRunner < Base
attr_accessor :arguments
attr_accessor :attempts
attr_accessor :custom_config_path
attr_accessor :encrypted_data_bag_secret_key_path
attr_accessor :environment
attr_accessor :formatter
attr_accessor :http_proxy
attr_accessor :http_proxy_user
attr_accessor :http_proxy_pass
attr_accessor :https_proxy
attr_accessor :https_proxy_user
attr_accessor :https_proxy_pass
attr_accessor :json
attr_accessor :no_proxy
attr_accessor :node_name
attr_accessor :provisioning_path
attr_accessor :run_list
attr_accessor :file_cache_path
attr_accessor :file_backup_path
attr_accessor :verbose_logging
def initialize
super
@arguments = UNSET_VALUE
@attempts = UNSET_VALUE
@custom_config_path = UNSET_VALUE
# /etc/chef/client.rb config options
@encrypted_data_bag_secret_key_path = UNSET_VALUE
@environment = UNSET_VALUE
@formatter = UNSET_VALUE
@http_proxy = UNSET_VALUE
@http_proxy_user = UNSET_VALUE
@http_proxy_pass = UNSET_VALUE
@https_proxy = UNSET_VALUE
@https_proxy_user = UNSET_VALUE
@https_proxy_pass = UNSET_VALUE
@no_proxy = UNSET_VALUE
@node_name = UNSET_VALUE
@provisioning_path = UNSET_VALUE
@file_cache_path = UNSET_VALUE
@file_backup_path = UNSET_VALUE
@verbose_logging = UNSET_VALUE
# Runner options
@json = {}
@run_list = []
end
def encrypted_data_bag_secret=(value)
puts "DEPRECATION: Chef encrypted_data_bag_secret has no effect anymore."
puts "Remove this from your Vagrantfile since it'll be removed in the next"
puts "Vagrant version."
end
def finalize!
super
@arguments = nil if @arguments == UNSET_VALUE
@attempts = 1 if @attempts == UNSET_VALUE
@custom_config_path = nil if @custom_config_path == UNSET_VALUE
@environment = nil if @environment == UNSET_VALUE
@formatter = nil if @formatter == UNSET_VALUE
@http_proxy = nil if @http_proxy == UNSET_VALUE
@http_proxy_user = nil if @http_proxy_user == UNSET_VALUE
@http_proxy_pass = nil if @http_proxy_pass == UNSET_VALUE
@https_proxy = nil if @https_proxy == UNSET_VALUE
@https_proxy_user = nil if @https_proxy_user == UNSET_VALUE
@https_proxy_pass = nil if @https_proxy_pass == UNSET_VALUE
@no_proxy = nil if @no_proxy == UNSET_VALUE
@node_name = nil if @node_name == UNSET_VALUE
@provisioning_path = nil if @provisioning_path == UNSET_VALUE
@file_backup_path = "/var/chef/backup" if @file_backup_path == UNSET_VALUE
@file_cache_path = "/var/chef/cache" if @file_cache_path == UNSET_VALUE
@verbose_logging = false if @verbose_logging == UNSET_VALUE
if @encrypted_data_bag_secret_key_path == UNSET_VALUE
@encrypted_data_bag_secret_key_path = nil
end
# Set the default provisioning path to be a unique path in /tmp
if !@provisioning_path
counter = self.class.get_and_update_counter(:chef_config)
@provisioning_path = "/tmp/vagrant-chef-#{counter}"
end
end
def merge(other)
super.tap do |result|
result.instance_variable_set(:@json, @json.merge(other.json))
result.instance_variable_set(:@run_list, (@run_list + other.run_list))
end
end
# Just like the normal configuration "validate" method except that
# it returns an array of errors that should be merged into some
# other error accumulator.
def validate_base(machine)
errors = super
if @custom_config_path
expanded = File.expand_path(@custom_config_path, machine.env.root_path)
if !File.file?(expanded)
errors << I18n.t("vagrant.config.chef.custom_config_path_missing")
end
end
errors
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
end
end
end
end

View File

@ -1,9 +1,9 @@
require_relative "base"
module VagrantPlugins
module Chef
module Config
class ChefApply < Vagrant.plugin("2", :config)
extend Vagrant::Util::Counter
class ChefApply < Base
# The raw recipe text (as a string) to execute via chef-apply.
# @return [String]
attr_accessor :recipe
@ -13,25 +13,17 @@ module VagrantPlugins
# @return [String]
attr_accessor :upload_path
# The Chef log level.
# @return [String]
attr_accessor :log_level
def initialize
@recipe = UNSET_VALUE
super
@log_level = UNSET_VALUE
@recipe = UNSET_VALUE
@upload_path = UNSET_VALUE
end
def finalize!
@recipe = nil if @recipe == UNSET_VALUE
super
if @log_level == UNSET_VALUE
@log_level = :info
else
@log_level = @log_level.to_sym
end
@recipe = nil if @recipe == UNSET_VALUE
if @upload_path == UNSET_VALUE
counter = self.class.get_and_update_counter(:chef_apply)
@ -40,28 +32,18 @@ module VagrantPlugins
end
def validate(machine)
errors = _detected_errors
errors = validate_base(machine)
if missing(recipe)
if missing?(recipe)
errors << I18n.t("vagrant.provisioners.chef.recipe_empty")
end
if missing(log_level)
errors << I18n.t("vagrant.provisioners.chef.log_level_empty")
end
if missing(upload_path)
if missing?(upload_path)
errors << I18n.t("vagrant.provisioners.chef.upload_path_empty")
end
{ "chef apply provisioner" => errors }
end
# Determine if the given string is "missing" (blank)
# @return [true, false]
def missing(obj)
obj.to_s.strip.empty?
end
end
end
end

View File

@ -1,16 +1,33 @@
require "vagrant/util/which"
require_relative "base"
require_relative "base_runner"
module VagrantPlugins
module Chef
module Config
class ChefClient < Base
class ChefClient < BaseRunner
# The URL endpoint to the Chef Server.
# @return [String]
attr_accessor :chef_server_url
# The path on disk to the Chef client key,
# @return [String]
attr_accessor :client_key_path
# Delete the client key when the VM is destroyed. Default is false.
# @return [true, false]
attr_accessor :delete_client
# Delete the node when the VM is destroyed. Default is false.
# @return [true, false]
attr_accessor :delete_node
# The path to the validation key on disk.
# @return [String]
attr_accessor :validation_key_path
# The name of the validation client.
# @return [String]
attr_accessor :validation_client_name
def initialize
@ -36,8 +53,7 @@ module VagrantPlugins
end
def validate(machine)
errors = _detected_errors
errors.concat(validate_base(machine))
errors = validate_base(machine)
if chef_server_url.to_s.strip.empty?
errors << I18n.t("vagrant.config.chef.server_url_empty")

View File

@ -1,14 +1,36 @@
require_relative "base"
require_relative "base_runner"
module VagrantPlugins
module Chef
module Config
class ChefSolo < Base
class ChefSolo < BaseRunner
# The path on disk where Chef cookbooks are stored.
# Default is "cookbooks".
# @return [String]
attr_accessor :cookbooks_path
# The path where data bags are stored on disk.
# @return [String]
attr_accessor :data_bags_path
# The path where environments are stored on disk.
# @return [String]
attr_accessor :environments_path
# A URL download a remote recipe from. Note: you should use chef-apply
# instead.
#
# @deprecated
#
# @return [String]
attr_accessor :recipe_url
# The path where roles are stored on disk.
# @return [String]
attr_accessor :roles_path
# The type of synced folders to use.
# @return [String]
attr_accessor :synced_folder_type
def initialize
@ -22,6 +44,19 @@ module VagrantPlugins
@synced_folder_type = UNSET_VALUE
end
# @deprecated This is deprecated in Chef and will be removed in Chef 12.
def recipe_url=(value)
puts "DEPRECATION: The 'recipe_url' setting for the Chef Solo"
puts "provisioner is deprecated. This value will be removed in"
puts "Chef 12. It is recommended you use the Chef Apply provisioner"
puts "instead. The 'recipe_url' setting will be removed in the next"
puts "version of Vagrant."
if value
@recipe_url = value
end
end
def nfs=(value)
puts "DEPRECATION: The 'nfs' setting for the Chef Solo provisioner is"
puts "deprecated. Please use the 'synced_folder_type' setting instead."
@ -63,8 +98,7 @@ module VagrantPlugins
end
def validate(machine)
errors = _detected_errors
errors.concat(validate_base(machine))
errors = validate_base(machine)
if [cookbooks_path].flatten.compact.empty?
errors << I18n.t("vagrant.config.chef.cookbooks_path_empty")

View File

@ -0,0 +1,45 @@
module VagrantPlugins
module Chef
class Installer
def initialize(machine, options = {})
@machine = machine
@version = options.fetch(:version, :latest)
@prerelease = options.fetch(:prerelease, :latest)
@force = options.fetch(:force, false)
end
# This handles verifying the Chef installation, installing it if it was
# requested, and so on. This method will raise exceptions if things are
# wrong.
def ensure_installed
# If the guest cannot check if Chef is installed, just exit printing a
# warning...
if !@machine.guest.capability?(:chef_installed)
@machine.ui.warn(I18n.t("vagrant.chef_cant_detect"))
return
end
if !should_install_chef?
@machine.ui.info(I18n.t("vagrant.chef_already_installed",
version: @version.to_s))
return
end
@machine.ui.detail(I18n.t("vagrant.chef_installing",
version: @version.to_s))
@machine.guest.capability(:chef_install, @version, @prerelease)
if !@machine.guest.capability(:chef_installed, @version)
raise Provisioner::Base::ChefError, :install_failed
end
end
# Determine if Chef should be installed. Chef is installed if the "force"
# option is given or if the guest does not have Chef installed at the
# proper version.
def should_install_chef?
@force || !@machine.guest.capability(:chef_installed, @version)
end
end
end
end

View File

@ -0,0 +1,28 @@
module VagrantPlugins
module Chef
module Omnibus
OMNITRUCK = "https://www.getchef.com/chef/install.sh".freeze
# Read more about the Omnibus installer here:
# https://docs.getchef.com/install_omnibus.html
def build_command(version, prerelease = false)
command = "curl -sL #{OMNITRUCK} | sudo bash"
if prerelease || version != :latest
command << " -s --"
end
if prerelease
command << " -p"
end
if version != :latest
command << " -v \"#{version}\""
end
command
end
module_function :build_command
end
end
end

View File

@ -52,6 +52,21 @@ module VagrantPlugins
require_relative "provisioner/chef_zero"
Provisioner::ChefZero
end
guest_capability(:linux, :chef_installed) do
require_relative "cap/linux/chef_installed"
Cap::Linux::ChefInstalled
end
guest_capability(:debian, :chef_install) do
require_relative "cap/debian/chef_install"
Cap::Debian::ChefInstall
end
guest_capability(:redhat, :chef_install) do
require_relative "cap/redhat/chef_install"
Cap::Redhat::ChefInstall
end
end
end
end

View File

@ -2,6 +2,8 @@ require 'tempfile'
require "vagrant/util/template_renderer"
require_relative "../installer"
module VagrantPlugins
module Chef
module Provisioner
@ -13,6 +15,24 @@ module VagrantPlugins
error_namespace("vagrant.provisioners.chef")
end
def initialize(machine, config)
super
@logger = Log4r::Logger.new("vagrant::provisioners::chef")
end
def install_chef
return if !config.install
@logger.info("Checking for Chef installation...")
installer = Installer.new(@machine,
force: config.install == :force,
version: config.version,
prerelease: config.prerelease,
)
installer.ensure_installed
end
def verify_binary(binary)
# Checks for the existence of chef binary and error if it
# doesn't exist.
@ -20,7 +40,8 @@ module VagrantPlugins
"which #{binary}",
error_class: ChefError,
error_key: :chef_not_detected,
binary: binary)
binary: binary,
)
end
# This returns the command to run Chef for the given client

View File

@ -1,13 +1,18 @@
require "tempfile"
require_relative "base"
module VagrantPlugins
module Chef
module Provisioner
class ChefApply < Vagrant.plugin("2", :provisioner)
class ChefApply < Base
def provision
install_chef
verify_binary(chef_binary_path("chef-apply"))
command = "chef-apply"
command << " --log-level #{config.log_level}"
command << " #{config.upload_path}"
command << " \"#{target_recipe_path}\""
command << " --log_level #{config.log_level}"
user = @machine.ssh_info[:username]
@ -18,7 +23,7 @@ module VagrantPlugins
# Upload the recipe
upload_recipe
@machine.ui.info(I18n.t("vagrant.provisioners.chef.running_chef_apply",
@machine.ui.info(I18n.t("vagrant.provisioners.chef.running_apply",
script: config.path)
)
@ -34,6 +39,12 @@ module VagrantPlugins
end
end
# The destination (on the guest) where the recipe will live
# @return [String]
def target_recipe_path
File.join(config.upload_path, "recipe.rb")
end
# Write the raw recipe contents to a tempfile and upload that to the
# machine.
def upload_recipe
@ -43,8 +54,7 @@ module VagrantPlugins
file.rewind
# Upload the tempfile to the guest
destination = File.join(config.upload_path, "recipe.rb")
@machine.communicate.upload(file.path, destination)
@machine.communicate.upload(file.path, target_recipe_path)
ensure
# Delete our template
file.close

View File

@ -18,6 +18,7 @@ module VagrantPlugins
end
def provision
install_chef
verify_binary(chef_binary_path("chef-client"))
chown_provisioning_folder
create_client_key_folder

View File

@ -35,6 +35,7 @@ module VagrantPlugins
end
def provision
install_chef
# Verify that the proper shared folders exist.
check = []
@shared_folders.each do |type, local_path, remote_path|

View File

@ -89,14 +89,42 @@ Vagrant.configure(2) do |config|
# puppet.manifest_file = "default.pp"
# end
# Enable provisioning with chef solo, specifying a cookbooks path, roles
# Enable provisioning with Chef Solo, specifying a cookbooks path, roles
# path, and data_bags path (all relative to this Vagrantfile), and adding
# some recipes and/or roles.
#
# config.vm.provision "chef_solo" do |chef|
# chef.cookbooks_path = "../my-recipes/cookbooks"
# chef.roles_path = "../my-recipes/roles"
# chef.data_bags_path = "../my-recipes/data_bags"
# chef.cookbooks_path = "~/chef/cookbooks"
# chef.roles_path = "~/chef/roles"
# chef.data_bags_path = "~/chef/data_bags"
#
# chef.add_recipe "mysql"
# chef.add_role "web"
#
# chef.json = { mysql_password: "foo" }
# end
#
# Chef Solo will automatically install the latest version of Chef for you.
# This can be configured in the provisioner block:
#
# config.vm.provision "chef_solo" do |chef|
# chef.version = "11.16.4"
# end
#
# Alternative you can disable the installation of Chef entirely:
#
# config.vm.provision "chef_solo" do |chef|
# chef.install = false
# end
# Enable provisioning with Chef Zero. The Chef Zero provisioner accepts the
# exact same parameter as the Chef Solo provisioner:
#
# config.vm.provision "chef_zero" do |chef|
# chef.cookbooks_path = "~/chef/cookbooks"
# chef.roles_path = "~/chef/roles"
# chef.data_bags_path = "~/chef/data_bags"
#
# chef.add_recipe "mysql"
# chef.add_role "web"
#
@ -104,10 +132,10 @@ Vagrant.configure(2) do |config|
# chef.json = { mysql_password: "foo" }
# end
# Enable provisioning with chef server, specifying the chef server URL,
# Enable provisioning with Chef Server, specifying the chef server URL,
# and the path to the validation key (relative to this Vagrantfile).
#
# The Opscode Platform uses HTTPS. Substitute your organization for
# The Hosted Chef platform uses HTTPS. Substitute your organization for
# ORGNAME in the URL and validation key.
#
# If you have your own Chef Server, use the appropriate URL, which may be
@ -119,11 +147,40 @@ Vagrant.configure(2) do |config|
# chef.validation_key_path = "ORGNAME-validator.pem"
# end
#
# If you're using the Opscode platform, your validator client is
# If you're using the Hosted Chef platform, your validator client is
# ORGNAME-validator, replacing ORGNAME with your organization name.
#
# If you have your own Chef Server, the default validation client name is
# chef-validator, unless you changed the configuration.
#
# chef.validation_client_name = "ORGNAME-validator"
#
# Chef Client will automatically install the latest version of Chef for you.
# This can be configured in the provisioner block:
#
# config.vm.provision "chef_client" do |chef|
# chef.version = "11.16.4"
# end
#
# Alternative you can disable the installation of Chef entirely:
#
# config.vm.provision "chef_client" do |chef|
# chef.install = false
# end
# Enable provisioning with Chef Apply, specifying an inline recipe to execute
# on the target system.
#
# config.vm.provision "chef_apply" do |chef|
# chef.recipe = <<-RECIPE
# package "curl"
# RECIPE
# end
#
# Chef Apply will automatically install the latest version of Chef for you.
# This can be configured in the provisioner block:
#
# config.vm.provision "chef_apply" do |chef|
# chef.version = "11.16.4"
# end
end

View File

@ -87,6 +87,14 @@ en:
CFEngine running in "single run" mode. Will execute one file.
cfengine_single_run_execute: |-
Executing run file for CFEngine...
chef_cant_detect: |-
Vagrant does not support detecting whether Chef is installed
for the guest OS running in the machine. Vagrant will assume it is
installed and attempt to continue.
chef_already_installed: |-
Detected Chef (%{version}) is already installed
chef_installing: |-
Installing Chef (%{version})...
chef_client_cleanup_failed: |-
Cleaning up the '%{deletable}' for Chef failed. The stdout and
stderr are shown below. Vagrant will continue destroying the machine,
@ -1754,6 +1762,16 @@ en:
"The cookbook path '%{path}' doesn't exist. Ignoring..."
json: "Generating chef JSON and uploading..."
client_key_folder: "Creating folder to hold client key..."
install_failed: |-
Vagrant could not detect Chef on the guest! Even after Vagrant
attempted to install Chef, it could still not find Chef on the system.
Please make sure you are connected to the Internet and can access
Chef's package distribution servers. If you already have Chef
installed on this guest, you can disable the automatic Chef detection
by setting the 'install' option in the Chef configuration section of
your Vagrantfile:
chef.install = false
log_level_empty: |-
The Chef provisioner requires a log level. If you did not set a
log level, this is probably a bug and should be reported.
@ -1765,7 +1783,7 @@ en:
guest.
running_client: "Running chef-client..."
running_client_again: "Running chef-client again (failed to converge)..."
running_client_apply: "Running chef-apply..."
running_apply: "Running chef-apply..."
running_solo: "Running chef-solo..."
running_solo_again: "Running chef-solo again (failed to converge)..."
missing_shared_folders: |-

View File

@ -0,0 +1,255 @@
require_relative "../../../../base"
require Vagrant.source_root.join("plugins/provisioners/chef/config/base_runner")
describe VagrantPlugins::Chef::Config::BaseRunner do
include_context "unit"
subject { described_class.new }
let(:machine) { double("machine") }
describe "#arguments" do
it "defaults to nil" do
subject.finalize!
expect(subject.arguments).to be(nil)
end
end
describe "#attempts" do
it "defaults to 1" do
subject.finalize!
expect(subject.attempts).to eq(1)
end
end
describe "#custom_config_path" do
it "defaults to nil" do
subject.finalize!
expect(subject.custom_config_path).to be(nil)
end
end
describe "#environment" do
it "defaults to nil" do
subject.finalize!
expect(subject.environment).to be(nil)
end
end
describe "#encrypted_data_bag_secret_key_path" do
it "defaults to nil" do
subject.finalize!
expect(subject.encrypted_data_bag_secret_key_path).to be(nil)
end
end
describe "#formatter" do
it "defaults to nil" do
subject.finalize!
expect(subject.formatter).to be(nil)
end
end
describe "#http_proxy" do
it "defaults to nil" do
subject.finalize!
expect(subject.http_proxy).to be(nil)
end
end
describe "#http_proxy_user" do
it "defaults to nil" do
subject.finalize!
expect(subject.http_proxy_user).to be(nil)
end
end
describe "#http_proxy_pass" do
it "defaults to nil" do
subject.finalize!
expect(subject.http_proxy_pass).to be(nil)
end
end
describe "#https_proxy" do
it "defaults to nil" do
subject.finalize!
expect(subject.https_proxy).to be(nil)
end
end
describe "#https_proxy_user" do
it "defaults to nil" do
subject.finalize!
expect(subject.https_proxy_user).to be(nil)
end
end
describe "#https_proxy_pass" do
it "defaults to nil" do
subject.finalize!
expect(subject.https_proxy_pass).to be(nil)
end
end
describe "#log_level" do
it "defaults to :info" do
subject.finalize!
expect(subject.log_level).to be(:info)
end
it "is converted to a symbol" do
subject.log_level = "foo"
subject.finalize!
expect(subject.log_level).to eq(:foo)
end
end
describe "#no_proxy" do
it "defaults to nil" do
subject.finalize!
expect(subject.no_proxy).to be(nil)
end
end
describe "#node_name" do
it "defaults to nil" do
subject.finalize!
expect(subject.node_name).to be(nil)
end
end
describe "#provisioning_path" do
it "defaults to a tmp_path" do
subject.finalize!
expect(subject.provisioning_path).to match(%r{/tmp/vagrant-chef-\d+})
end
end
describe "#file_backup_path" do
it "defaults to /var/chef/backup" do
subject.finalize!
expect(subject.file_backup_path).to eq("/var/chef/backup")
end
end
describe "#file_cache_path" do
it "defaults to /var/chef/cache" do
subject.finalize!
expect(subject.file_cache_path).to eq("/var/chef/cache")
end
end
describe "#verbose_logging" do
it "defaults to false" do
subject.finalize!
expect(subject.verbose_logging).to be(false)
end
end
describe "#run_list" do
it "defaults to an empty array" do
subject.finalize!
expect(subject.run_list).to be_a(Array)
expect(subject.run_list).to be_empty
end
end
describe "#json" do
it "defaults to an empty hash" do
subject.finalize!
expect(subject.json).to be_a(Hash)
expect(subject.json).to be_empty
end
end
describe "#add_recipe" do
context "when the prefix is given" do
it "adds the value to the run_list" do
subject.add_recipe("recipe[foo::bar]")
expect(subject.run_list).to eq %w(recipe[foo::bar])
end
end
context "when the prefix is not given" do
it "adds the prefixed value to the run_list" do
subject.add_recipe("foo::bar")
expect(subject.run_list).to eq %w(recipe[foo::bar])
end
end
end
describe "#add_role" do
context "when the prefix is given" do
it "adds the value to the run_list" do
subject.add_role("role[foo]")
expect(subject.run_list).to eq %w(role[foo])
end
end
context "when the prefix is not given" do
it "adds the prefixed value to the run_list" do
subject.add_role("foo")
expect(subject.run_list).to eq %w(role[foo])
end
end
end
describe "#validate_base" do
context "when #custom_config_path does not exist" do
let(:path) { "/path/to/file" }
before do
allow(File).to receive(:file?)
.with(path)
.and_return(false)
allow(machine).to receive(:env)
.and_return(double("env",
root_path: "",
))
end
it "returns an error" do
subject.custom_config_path = path
subject.finalize!
expect(subject.validate_base(machine))
.to eq ['Path specified for "custom_config_path" does not exist.']
end
end
end
describe "#merge" do
it "merges the json hash" do
a = described_class.new.tap do |i|
i.json = { "foo" => "bar" }
end
b = described_class.new.tap do |i|
i.json = { "zip" => "zap" }
end
result = a.merge(b)
expect(result.json).to eq(
"foo" => "bar",
"zip" => "zap",
)
end
it "appends the run_list array" do
a = described_class.new.tap do |i|
i.run_list = ["recipe[foo::bar]"]
end
b = described_class.new.tap do |i|
i.run_list = ["recipe[zip::zap]"]
end
result = a.merge(b)
expect(result.run_list).to eq %w(
recipe[foo::bar]
recipe[zip::zap]
)
end
end
end

View File

@ -9,20 +9,6 @@ describe VagrantPlugins::Chef::Config::Base do
let(:machine) { double("machine") }
describe "#arguments" do
it "defaults to nil" do
subject.finalize!
expect(subject.arguments).to be(nil)
end
end
describe "#attempts" do
it "defaults to 1" do
subject.finalize!
expect(subject.attempts).to eq(1)
end
end
describe "#binary_path" do
it "defaults to nil" do
subject.finalize!
@ -37,66 +23,16 @@ describe VagrantPlugins::Chef::Config::Base do
end
end
describe "#custom_config_path" do
it "defaults to nil" do
describe "#install" do
it "defaults to true" do
subject.finalize!
expect(subject.custom_config_path).to be(nil)
end
expect(subject.install).to be(true)
end
describe "#environment" do
it "defaults to nil" do
it "is converted to a symbol" do
subject.install = "force"
subject.finalize!
expect(subject.environment).to be(nil)
end
end
describe "#formatter" do
it "defaults to nil" do
subject.finalize!
expect(subject.formatter).to be(nil)
end
end
describe "#http_proxy" do
it "defaults to nil" do
subject.finalize!
expect(subject.http_proxy).to be(nil)
end
end
describe "#http_proxy_user" do
it "defaults to nil" do
subject.finalize!
expect(subject.http_proxy_user).to be(nil)
end
end
describe "#http_proxy_pass" do
it "defaults to nil" do
subject.finalize!
expect(subject.http_proxy_pass).to be(nil)
end
end
describe "#https_proxy" do
it "defaults to nil" do
subject.finalize!
expect(subject.https_proxy).to be(nil)
end
end
describe "#https_proxy_user" do
it "defaults to nil" do
subject.finalize!
expect(subject.https_proxy_user).to be(nil)
end
end
describe "#https_proxy_pass" do
it "defaults to nil" do
subject.finalize!
expect(subject.https_proxy_pass).to be(nil)
expect(subject.install).to eq(:force)
end
end
@ -113,150 +49,23 @@ describe VagrantPlugins::Chef::Config::Base do
end
end
describe "#no_proxy" do
it "defaults to nil" do
describe "#prerelease" do
it "defaults to true" do
subject.finalize!
expect(subject.no_proxy).to be(nil)
expect(subject.prerelease).to be(false)
end
end
describe "#node_name" do
it "defaults to nil" do
describe "#version" do
it "defaults to :latest" do
subject.finalize!
expect(subject.node_name).to be(nil)
end
expect(subject.version).to eq(:latest)
end
describe "#provisioning_path" do
it "defaults to a tmp_path" do
it "converts the string 'latest' to a symbol" do
subject.version = "latest"
subject.finalize!
expect(subject.provisioning_path).to match(%r{/tmp/vagrant-chef-\d+})
end
end
describe "#file_backup_path" do
it "defaults to /var/chef/backup" do
subject.finalize!
expect(subject.file_backup_path).to eq("/var/chef/backup")
end
end
describe "#file_cache_path" do
it "defaults to /var/chef/cache" do
subject.finalize!
expect(subject.file_cache_path).to eq("/var/chef/cache")
end
end
describe "#verbose_logging" do
it "defaults to false" do
subject.finalize!
expect(subject.verbose_logging).to be(false)
end
end
describe "#run_list" do
it "defaults to an empty array" do
subject.finalize!
expect(subject.run_list).to be_a(Array)
expect(subject.run_list).to be_empty
end
end
describe "#json" do
it "defaults to an empty hash" do
subject.finalize!
expect(subject.json).to be_a(Hash)
expect(subject.json).to be_empty
end
end
describe "#add_recipe" do
context "when the prefix is given" do
it "adds the value to the run_list" do
subject.add_recipe("recipe[foo::bar]")
expect(subject.run_list).to eq %w(recipe[foo::bar])
end
end
context "when the prefix is not given" do
it "adds the prefixed value to the run_list" do
subject.add_recipe("foo::bar")
expect(subject.run_list).to eq %w(recipe[foo::bar])
end
end
end
describe "#add_role" do
context "when the prefix is given" do
it "adds the value to the run_list" do
subject.add_role("role[foo]")
expect(subject.run_list).to eq %w(role[foo])
end
end
context "when the prefix is not given" do
it "adds the prefixed value to the run_list" do
subject.add_role("foo")
expect(subject.run_list).to eq %w(role[foo])
end
end
end
describe "#validate_base" do
context "when #custom_config_path does not exist" do
let(:path) { "/path/to/file" }
before do
allow(File).to receive(:file?)
.with(path)
.and_return(false)
allow(machine).to receive(:env)
.and_return(double("env",
root_path: "",
))
end
it "returns an error" do
subject.custom_config_path = path
subject.finalize!
expect(subject.validate_base(machine))
.to eq ['Path specified for "custom_config_path" does not exist.']
end
end
end
describe "#merge" do
it "merges the json hash" do
a = described_class.new.tap do |i|
i.json = { "foo" => "bar" }
end
b = described_class.new.tap do |i|
i.json = { "zip" => "zap" }
end
result = a.merge(b)
expect(result.json).to eq(
"foo" => "bar",
"zip" => "zap",
)
end
it "appends the run_list array" do
a = described_class.new.tap do |i|
i.run_list = ["recipe[foo::bar]"]
end
b = described_class.new.tap do |i|
i.run_list = ["recipe[zip::zap]"]
end
result = a.merge(b)
expect(result.run_list).to eq %w(
recipe[foo::bar]
recipe[zip::zap]
)
expect(subject.version).to eq(:latest)
end
end
end

View File

@ -20,19 +20,6 @@ describe VagrantPlugins::Chef::Config::ChefApply do
end
end
describe "#log_level" do
it "defaults to :info" do
subject.finalize!
expect(subject.log_level).to be(:info)
end
it "is converted to a symbol" do
subject.log_level = "foo"
subject.finalize!
expect(subject.log_level).to eq(:foo)
end
end
describe "#upload_path" do
it "defaults to /tmp/vagrant-chef-apply.rb" do
subject.finalize!

View File

@ -0,0 +1,45 @@
require_relative "../../../base"
require Vagrant.source_root.join("plugins/provisioners/chef/omnibus")
describe VagrantPlugins::Chef::Omnibus, :focus do
let(:prefix) { "curl -sL #{described_class.const_get(:OMNITRUCK)}" }
let(:version) { :latest }
let(:prerelease) { false }
let(:build_command) { described_class.build_command(version, prerelease) }
context "when prerelease is given" do
let(:prerelease) { true }
it "returns the correct command" do
expect(build_command).to eq("#{prefix} | sudo bash -s -- -p")
end
end
context "when version is :latest" do
let(:version) { :latest }
it "returns the correct command" do
expect(build_command).to eq("#{prefix} | sudo bash")
end
end
context "when version is a string" do
let(:version) { "1.2.3" }
it "returns the correct command" do
expect(build_command).to eq("#{prefix} | sudo bash -s -- -v \"1.2.3\"")
end
end
context "when prerelease and version are given" do
let(:version) { "1.2.3" }
let(:prerelease) { true }
it "returns the correct command" do
expect(build_command).to eq("#{prefix} | sudo bash -s -- -p -v \"1.2.3\"")
end
end
end