Skip to content

Commit

Permalink
Add PowerShell/Windows support to ChefZero Provisioner.
Browse files Browse the repository at this point in the history
HTTP Proxy
==========

This commit also added more complete strategy for HTTP proxy variable
setting. If both `:http_proxy` and `:https_proxy` are set, then the
following Bourne shell environment variables are exported:

* `http_proxy`
* `HTTP_PROXY`
* `https_proxy`
* `HTTPS_PROXY`

And the following PowerShell environment variables are set:

* `$env:http_proxy`
* `$env:HTTP_PROXY`
* `$env:https_proxy`
* `$env:HTTPS_PROXY`

These environment variables will be set for every command excuted in the
Chef-related Provisioners.

The Bourne shell environment variable setting has also changed.
Previously they were set with an `env` prepended to the
`sh -c '...'` wrapped command. As of this commit, these environment
variables are set inside the `sh -c '...'` at the top and are exported.

For example running `wget "http://chef.io/chef/install.sh"` with
`:http_proxy` and `:https_proxy` set would generate a command
similar to:

    sh -c '
    http_proxy="http://proxy"; export http_proxy
    HTTP_PROXY="http://proxy"; export HTTP_PROXY
    https_proxy="https://proxy"; export https_proxy
    HTTPS_PROXY="https://proxy"; export HTTPS_PROXY

    wget "http://chef.io/chef/install.sh"
    '

Legacy Chef Zero Shim
=====================

As has always been the case, the chef-zero shim strategy for versions of
Chef older than 11.8.0 is best-effort, meaning it will work if your
base image has the needed requirements (which sometimes involve a
compiler).
  • Loading branch information
fnichol committed Mar 13, 2015
1 parent 55db014 commit a778878
Show file tree
Hide file tree
Showing 4 changed files with 618 additions and 310 deletions.
189 changes: 97 additions & 92 deletions lib/kitchen/provisioner/chef_zero.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,52 +55,48 @@ def create_sandbox
def prepare_command
return if modern?

ruby_bin = Pathname.new(config[:ruby_bindir])

# we are installing latest chef in order to get chef-zero and
# Chef::ChefFS only. The version of Chef that gets run will be
# the installed omnibus package. Yep, this is funky :)
cmd = <<-PREPARE.gsub(/^ {10}/, "")
#{chef_client_zero_env(:export)}
if ! #{sudo(ruby_bin.join("gem"))} list chef-zero -i >/dev/null; then
echo ">>>>>> Attempting to use chef-zero with old version of Chef"
echo "-----> Installing chef zero dependencies"
#{sudo(ruby_bin.join("gem"))} install chef --no-ri --no-rdoc --conservative
fi
PREPARE

Util.wrap_command(cmd)
gem_bin = remote_path_join(config[:ruby_bindir], "gem").
tap { |path| path.concat(".bat") if windows_os? }
vars = [
chef_client_zero_env,
shell_var("gem", sudo(gem_bin))
].join("\n").concat("\n")

shell_code_from_file(vars, "chef_zero_prepare_command_legacy")
end

# (see Base#run_command)
def run_command
cmd = modern? ? local_mode_command : shim_command

Util.wrap_command([cmd, *chef_client_args].join(" "))
wrap_shell_code([cmd, *chef_client_args].join(" "))
end

private

# Returns the command that will run chef client in local mode (a.k.a.
# chef zero mode).
# Adds optional flags to a chef-client command, depending on
# configuration data. Note that this method mutates the incoming Array.
#
# @return [String] the command string
# @param args [Array<String>] array of flags
# @api private
def local_mode_command
"#{sudo(config[:chef_client_path])} --local-mode"
end
def add_optional_chef_client_args!(args)
if config[:json_attributes]
json = remote_path_join(config[:root_path], "dna.json")
args << "--json-attributes #{json}"
end
if config[:log_file]
args << "--logfile #{config[:log_file]}"
end
return unless modern?

# Returns the command that will run a backwards compatible shim script
# that approximates local mode in a modern chef-client run.
#
# @return [String] the command string
# @api private
def shim_command
[
chef_client_zero_env,
sudo("#{config[:ruby_bindir]}/ruby"),
"#{config[:root_path]}/chef-client-zero.rb"
].join(" ")
# these flags are modern/chef-client local most only and will not work
# on older versions of chef-client
if config[:chef_zero_host]
args << "--chef-zero-host #{config[:chef_zero_host]}"
end
if config[:chef_zero_port]
args << "--chef-zero-port #{config[:chef_zero_port]}"
end
end

# Returns an Array of command line arguments for the chef client.
Expand All @@ -110,28 +106,66 @@ def shim_command
def chef_client_args
level = config[:log_level] == :info ? :auto : config[:log_level]
args = [
"--config #{config[:root_path]}/client.rb",
"--config #{remote_path_join(config[:root_path], "client.rb")}",
"--log_level #{level}",
"--force-formatter",
"--no-color"
]

if config[:chef_zero_host]
args << "--chef-zero-host #{config[:chef_zero_host]}"
end
if config[:chef_zero_port]
args << "--chef-zero-port #{config[:chef_zero_port]}"
end
if config[:json_attributes]
args << "--json-attributes #{config[:root_path]}/dna.json"
end
if config[:log_file]
args << "--logfile #{config[:log_file]}"
end
add_optional_chef_client_args!(args)

args
end

# Generates a string of shell environment variables needed for the
# chef-client-zero.rb shim script to properly function.
#
# @return [String] a shell script string
# @api private
def chef_client_zero_env
root = config[:root_path]
gem_home = gem_path = remote_path_join(root, "chef-client-zero-gems")
gem_cache = remote_path_join(gem_home, "cache")

[
env_var("CHEF_REPO_PATH", root),
env_var("GEM_HOME", gem_home),
env_var("GEM_PATH", gem_path),
env_var("GEM_CACHE", gem_cache)
].join("\n").concat("\n")
end

# Returns the command that will run chef client in local mode (a.k.a.
# chef zero mode).
#
# @return [String] the command string
# @api private
def local_mode_command
"#{sudo(config[:chef_client_path])} --local-mode".
tap { |str| str.insert(0, "& ") if powershell_shell? }
end

# Determines whether or not local mode (a.k.a chef zero mode) is
# supported in the version of Chef as determined by inspecting the
# require_chef_omnibus config variable.
#
# The only way this method returns false is if require_chef_omnibus has
# an explicit version set to less than 11.8.0, when chef zero mode was
# introduced. Otherwise a modern Chef installation is assumed.
#
# @return [true,false] whether or not the desired version of Chef
# supports local mode
# @api private
def modern?
version = config[:require_chef_omnibus]

case version
when nil, false, true, "latest"
true
else
Gem::Version.new(version) >= Gem::Version.new("11.8.0") ? true : false
end
end

# Writes a chef-client local-mode shim script to the sandbox directory
# only if the desired version of Chef is old enough. The version of Chef
# is determined using the `config[:require_chef_omnibus]` value.
Expand All @@ -148,18 +182,6 @@ def prepare_chef_client_zero_rb
FileUtils.cp(source, File.join(sandbox_path, "chef-client-zero.rb"))
end

# Writes a fake (but valid) validation.pem into the sandbox directory.
#
# @api private
def prepare_validation_pem
info("Preparing validation.pem")
debug("Using a dummy validation.pem")

source = File.join(File.dirname(__FILE__),
%w[.. .. .. support dummy-validation.pem])
FileUtils.cp(source, File.join(sandbox_path, "validation.pem"))
end

# Writes a client.rb configuration file to the sandbox directory.
#
# @api private
Expand All @@ -174,46 +196,29 @@ def prepare_client_rb
end
end

# Generates a string of shell environment variables needed for the
# chef-client-zero.rb shim script to properly function.
# Writes a fake (but valid) validation.pem into the sandbox directory.
#
# @param extra [Symbol] whether or not the environment variables need to
# be exported, using the `:export` symbol (default: `nil`)
# @return [String] a shell script string
# @api private
def chef_client_zero_env(extra = nil)
args = [
%{CHEF_REPO_PATH="#{config[:root_path]}"},
%{GEM_HOME="#{config[:root_path]}/chef-client-zero-gems"},
%{GEM_PATH="#{config[:root_path]}/chef-client-zero-gems"},
%{GEM_CACHE="#{config[:root_path]}/chef-client-zero-gems/cache"}
]
if extra == :export
args << %{; export CHEF_REPO_PATH GEM_HOME GEM_PATH GEM_CACHE;}
end
args.join(" ")
def prepare_validation_pem
info("Preparing validation.pem")
debug("Using a dummy validation.pem")

source = File.join(File.dirname(__FILE__),
%w[.. .. .. support dummy-validation.pem])
FileUtils.cp(source, File.join(sandbox_path, "validation.pem"))
end

# Determines whether or not local mode (a.k.a chef zero mode) is
# supported in the version of Chef as determined by inspecting the
# require_chef_omnibus config variable.
#
# The only way this method returns false is if require_chef_omnibus has
# an explicit version set to less than 11.8.0, when chef zero mode was
# introduced. Otherwise a modern Chef installation is assumed.
# Returns the command that will run a backwards compatible shim script
# that approximates local mode in a modern chef-client run.
#
# @return [true,false] whether or not the desired version of Chef
# supports local mode
# @return [String] the command string
# @api private
def modern?
version = config[:require_chef_omnibus]
def shim_command
ruby = remote_path_join(config[:ruby_bindir], "ruby").
tap { |path| path.concat(".exe") if windows_os? }
shim = remote_path_join(config[:root_path], "chef-client-zero.rb")

case version
when nil, false, true, "latest"
true
else
Gem::Version.new(version) >= Gem::Version.new("11.8.0") ? true : false
end
"#{chef_client_zero_env}\n#{sudo(ruby)} #{shim}"
end
end
end
Expand Down
Loading

0 comments on commit a778878

Please sign in to comment.