From a7788780745e4abf4559d708a0009343b380ee0d Mon Sep 17 00:00:00 2001 From: Fletcher Nichol Date: Fri, 13 Mar 2015 13:42:16 -0600 Subject: [PATCH] Add PowerShell/Windows support to ChefZero Provisioner. 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). --- lib/kitchen/provisioner/chef_zero.rb | 189 ++--- spec/kitchen/provisioner/chef_zero_spec.rb | 720 +++++++++++++------ support/chef_zero_prepare_command_legacy.ps1 | 9 + support/chef_zero_prepare_command_legacy.sh | 10 + 4 files changed, 618 insertions(+), 310 deletions(-) create mode 100644 support/chef_zero_prepare_command_legacy.ps1 create mode 100644 support/chef_zero_prepare_command_legacy.sh diff --git a/lib/kitchen/provisioner/chef_zero.rb b/lib/kitchen/provisioner/chef_zero.rb index 3600a0fef..1949e6e29 100644 --- a/lib/kitchen/provisioner/chef_zero.rb +++ b/lib/kitchen/provisioner/chef_zero.rb @@ -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] 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. @@ -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. @@ -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 @@ -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 diff --git a/spec/kitchen/provisioner/chef_zero_spec.rb b/spec/kitchen/provisioner/chef_zero_spec.rb index 6e97e7450..f7716eb4e 100644 --- a/spec/kitchen/provisioner/chef_zero_spec.rb +++ b/spec/kitchen/provisioner/chef_zero_spec.rb @@ -142,64 +142,104 @@ describe "defaults" do - before { provisioner.create_sandbox } - - it "sets node_name to the instance name" do - file.must_include %{node_name "#{instance.name}"} + # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + def self.common_client_rb_specs + it "sets node_name to the instance name" do + file.must_include %{node_name "#{instance.name}"} + end + + it "sets checksum_path" do + file.must_include %{checksum_path "#{base}checksums"} + end + + it "sets file_backup_path" do + file.must_include %{file_backup_path "#{base}backup"} + end + + it "sets cookbook_path" do + file.must_include %{cookbook_path } + + %{["#{base}cookbooks", "#{base}site-cookbooks"]} + end + + it "sets data_bag_path" do + file.must_include %{data_bag_path "#{base}data_bags"} + end + + it "sets environment_path" do + file.must_include %{environment_path "#{base}environments"} + end + + it "sets node_path" do + file.must_include %{node_path "#{base}nodes"} + end + + it "sets role_path" do + file.must_include %{role_path "#{base}roles"} + end + + it "sets client_path" do + file.must_include %{client_path "#{base}clients"} + end + + it "sets user_path" do + file.must_include %{user_path "#{base}users"} + end + + it "sets validation_key" do + file.must_include %{validation_key "#{base}validation.pem"} + end + + it "sets client_key" do + file.must_include %{client_key "#{base}client.pem"} + end + + it "sets chef_server_url" do + file.must_include %{chef_server_url "http://127.0.0.1:8889"} + end + + it "sets encrypted_data_bag_secret" do + file.must_include %{encrypted_data_bag_secret } + + %{"#{base}encrypted_data_bag_secret"} + end end + # rubocop:enable Metrics/MethodLength, Metrics/AbcSize - it "sets checksum_path" do - file.must_include %{checksum_path "/tmp/kitchen/checksums"} - end + describe "for unix os types" do - it "sets file_backup_path" do - file.must_include %{file_backup_path "/tmp/kitchen/backup"} - end + before do + platform.stubs(:os_type).returns("unix") + provisioner.create_sandbox + end - it "sets cookbook_path" do - file.must_include %{cookbook_path } + - %{["/tmp/kitchen/cookbooks", "/tmp/kitchen/site-cookbooks"]} - end + let(:base) { "/tmp/kitchen/" } - it "sets data_bag_path" do - file.must_include %{data_bag_path "/tmp/kitchen/data_bags"} + common_client_rb_specs end - it "sets environment_path" do - file.must_include %{environment_path "/tmp/kitchen/environments"} - end + describe "for windows os types with full path" do - it "sets node_path" do - file.must_include %{node_path "/tmp/kitchen/nodes"} - end + before do + platform.stubs(:os_type).returns("windows") + config[:root_path] = "\\a\\b" + provisioner.create_sandbox + end - it "sets role_path" do - file.must_include %{role_path "/tmp/kitchen/roles"} - end + let(:base) { "\\\\a\\\\b\\\\" } - it "sets client_path" do - file.must_include %{client_path "/tmp/kitchen/clients"} + common_client_rb_specs end - it "sets user_path" do - file.must_include %{user_path "/tmp/kitchen/users"} - end + describe "for windows os types with $env:TEMP prefixed paths" do - it "sets validation_key" do - file.must_include %{validation_key "/tmp/kitchen/validation.pem"} - end - - it "sets client_key" do - file.must_include %{client_key "/tmp/kitchen/client.pem"} - end + before do + platform.stubs(:os_type).returns("windows") + config[:root_path] = "$env:TEMP\\a" + provisioner.create_sandbox + end - it "sets chef_server_url" do - file.must_include %{chef_server_url "http://127.0.0.1:8889"} - end + let(:base) { "\#{ENV['TEMP']}\\\\a\\\\" } - it "sets encrypted_data_bag_secret" do - file.must_include %{encrypted_data_bag_secret } + - %{"/tmp/kitchen/encrypted_data_bag_secret"} + common_client_rb_specs end end @@ -345,101 +385,185 @@ def sandbox_path(path) describe "for old Chef versions" do - before do - config[:require_chef_omnibus] = "10.20" - config[:ruby_bindir] = "/rbd" - end + before { config[:require_chef_omnibus] = "10.20" } - it "uses bourne shell" do - cmd.must_match(/\Ash -c '$/) - cmd.must_match(/'\Z/) - end + describe "for bourne shells" do - it "sets the CHEF_REPO_PATH environment variable" do - config[:root_path] = "/r" + before do + platform.stubs(:shell_type).returns("bourne") + config[:ruby_bindir] = "/rbd" + end - cmd.must_match regexify(%{CHEF_REPO_PATH="/r" }, :partial_line) - end + it "uses bourne shell" do + cmd.must_match(/\Ash -c '$/) + cmd.must_match(/'\Z/) + end - it "sets the GEM_HOME environment variable" do - config[:root_path] = "/r" + it "ends with a single quote" do + cmd.must_match(/'\Z/) + end - cmd.must_match regexify( - %{GEM_HOME="/r/chef-client-zero-gems" }, :partial_line) - end + it "exports http_proxy & HTTP_PROXY when :http_proxy is set" do + config[:http_proxy] = "http://proxy" - it "sets the GEM_PATH environment variable" do - config[:root_path] = "/r" + cmd.lines[1..2].must_equal([ + %{http_proxy="http://proxy"; export http_proxy\n}, + %{HTTP_PROXY="http://proxy"; export HTTP_PROXY\n} + ]) + end - cmd.must_match regexify( - %{GEM_PATH="/r/chef-client-zero-gems" }, :partial_line) - end + it "exports https_proxy & HTTPS_PROXY when :https_proxy is set" do + config[:https_proxy] = "https://proxy" - it "sets the GEM_CACHE environment variable" do - config[:root_path] = "/r" + cmd.lines[1..2].must_equal([ + %{https_proxy="https://proxy"; export https_proxy\n}, + %{HTTPS_PROXY="https://proxy"; export HTTPS_PROXY\n} + ]) + end - cmd.must_match regexify( - %{GEM_CACHE="/r/chef-client-zero-gems/cache" }, :partial_line) - end + it "exports all http proxy variables when both are set" do + config[:http_proxy] = "http://proxy" + config[:https_proxy] = "https://proxy" - it "exports all the environment variables" do - cmd.must_match regexify( - "export CHEF_REPO_PATH GEM_HOME GEM_PATH GEM_CACHE;", :partial_line) - end + cmd.lines[1..4].must_equal([ + %{http_proxy="http://proxy"; export http_proxy\n}, + %{HTTP_PROXY="http://proxy"; export HTTP_PROXY\n}, + %{https_proxy="https://proxy"; export https_proxy\n}, + %{HTTPS_PROXY="https://proxy"; export HTTPS_PROXY\n} + ]) + end - it "checks if chef-zero is installed" do - cmd.must_match regexify( - %{if ! sudo -E /rbd/gem list chef-zero -i >/dev/null; then}) - end + it "sets the CHEF_REPO_PATH environment variable" do + config[:root_path] = "/r" - it "installs the chef gem" do - cmd.must_match regexify( - %{sudo -E /rbd/gem install chef --no-ri --no-rdoc --conservative}) - end - end - end + cmd.must_match regexify( + %{CHEF_REPO_PATH="/r"; export CHEF_REPO_PATH}) + end - describe "#run_command" do + it "sets the GEM_HOME environment variable" do + config[:root_path] = "/r" - let(:cmd) { provisioner.run_command } + cmd.must_match regexify( + %{GEM_HOME="/r/chef-client-zero-gems"; export GEM_HOME}) + end - describe "for modern Chef versions" do + it "sets the GEM_PATH environment variable" do + config[:root_path] = "/r" - before { config[:require_chef_omnibus] = "11.10" } + cmd.must_match regexify( + %{GEM_PATH="/r/chef-client-zero-gems"; export GEM_PATH}) + end - it "uses bourne shell" do - cmd.must_match(/\Ash -c '$/) - cmd.must_match(/'\Z/) - end + it "sets the GEM_CACHE environment variable" do + config[:root_path] = "/r" - it "uses sudo for chef-client when configured" do - config[:chef_omnibus_root] = "/c" - config[:sudo] = true + cmd.must_match regexify( + %{GEM_CACHE="/r/chef-client-zero-gems/cache"; export GEM_CACHE}) + end - cmd.must_match regexify("sudo -E /c/bin/chef-client ", :partial_line) - end + it "prepends sudo for gem command when :sudo is set" do + config[:sudo] = true - it "does not use sudo for chef-client when configured" do - config[:chef_omnibus_root] = "/c" - config[:sudo] = false + cmd.must_match regexify(%{gem="sudo -E /rbd/gem"}) + end + + it "does not sudo for gem commands when :sudo is falsey" do + config[:sudo] = false - cmd.must_match regexify("/c/bin/chef-client ", :partial_line) - cmd.wont_match regexify("sudo -E /c/bin/chef-client ", :partial_line) + cmd.must_match regexify(%{gem="/rbd/gem"}) + end end - it "sets local mode flag on chef-client" do - cmd.must_match regexify(" --local-mode", :partial_line) + describe "for powershell shells on windows os types" do + + before do + platform.stubs(:shell_type).returns("powershell") + platform.stubs(:os_type).returns("windows") + config[:root_path] = "\\r" + config[:ruby_bindir] = "\\rbd" + end + + it "exports http_proxy & HTTP_PROXY when :http_proxy is set" do + config[:http_proxy] = "http://proxy" + + cmd.lines[0..1].must_equal([ + %{$env:http_proxy = "http://proxy"\n}, + %{$env:HTTP_PROXY = "http://proxy"\n} + ]) + end + + it "exports https_proxy & HTTPS_PROXY when :https_proxy is set" do + config[:https_proxy] = "https://proxy" + + cmd.lines[0..1].must_equal([ + %{$env:https_proxy = "https://proxy"\n}, + %{$env:HTTPS_PROXY = "https://proxy"\n} + ]) + end + + it "exports all http proxy variables when both are set" do + config[:http_proxy] = "http://proxy" + config[:https_proxy] = "https://proxy" + + cmd.lines[0..3].must_equal([ + %{$env:http_proxy = "http://proxy"\n}, + %{$env:HTTP_PROXY = "http://proxy"\n}, + %{$env:https_proxy = "https://proxy"\n}, + %{$env:HTTPS_PROXY = "https://proxy"\n} + ]) + end + + it "sets the CHEF_REPO_PATH environment variable" do + config[:root_path] = "\\r" + + cmd.must_match regexify( + %{$env:CHEF_REPO_PATH = "\\r"}) + end + + it "sets the GEM_HOME environment variable" do + config[:root_path] = "\\r" + + cmd.must_match regexify( + %{$env:GEM_HOME = "\\r\\chef-client-zero-gems"}) + end + + it "sets the GEM_PATH environment variable" do + config[:root_path] = "\\r" + + cmd.must_match regexify( + %{$env:GEM_PATH = "\\r\\chef-client-zero-gems"}) + end + + it "sets the GEM_CACHE environment variable" do + config[:root_path] = "\\r" + + cmd.must_match regexify( + %{$env:GEM_CACHE = "\\r\\chef-client-zero-gems\\cache"}) + end + + it "sets the path to the gem command" do + cmd.must_match regexify(%{$gem = "\\rbd\\gem.bat"}) + end end + end + end + + describe "#run_command" do + let(:cmd) { provisioner.run_command } + + # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + def self.common_shell_specs it "sets config flag on chef-client" do cmd.must_match regexify( - " --config /tmp/kitchen/client.rb", :partial_line) + " --config #{base}client.rb", :partial_line) end it "sets config flag for custom root_path" do - config[:root_path] = "/a/b" + config[:root_path] = custom_root - cmd.must_match regexify(" --config /a/b/client.rb", :partial_line) + cmd.must_match regexify( + " --config #{custom_base}client.rb", :partial_line) end it "sets log level flag on chef-client to auto by default" do @@ -460,60 +584,192 @@ def sandbox_path(path) cmd.must_match regexify(" --no-color", :partial_line) end - it "sets chef zero port flag on chef-client" do - cmd.must_match regexify(" --chef-zero-port 8889", :partial_line) + it "sets json attributes flag on chef-client" do + cmd.must_match regexify( + " --json-attributes #{base}dna.json", :partial_line) end - it "sets chef zero host flag for custom host" do - config[:chef_zero_host] = "192.168.0.1" + it "sets json attribtes flag for custom root_path" do + config[:root_path] = custom_root - cmd.must_match regexify(" --chef-zero-host 192.168.0.1", :partial_line) + cmd.must_match regexify( + " --json-attributes #{custom_base}dna.json", :partial_line) end - it "sets chef zero port flag for custom port" do - config[:chef_zero_port] = 123 + it "does not set json attributes flag if config is falsey" do + config[:json_attributes] = false - cmd.must_match regexify(" --chef-zero-port 123", :partial_line) + cmd.wont_match regexify(" --json-attributes ", :partial_line) end - it "does not set chef zero host flag when value is falsey" do - config[:chef_zero_host] = nil + it "sets logfile flag for custom value" do + config[:log_file] = "#{custom_base}out.log" - cmd.wont_match regexify(" --chef-zero-host ", :partial_line) + cmd.must_match regexify( + " --logfile #{custom_base}out.log", :partial_line) end - it "does not set chef zero port flag when value is falsey" do - config[:chef_zero_port] = nil - - cmd.wont_match regexify(" --chef-zero-port ", :partial_line) + it "does not set logfile flag by default" do + cmd.wont_match regexify(" --logfile ", :partial_line) end + end + # rubocop:enable Metrics/MethodLength, Metrics/AbcSize - it "sets json attributes flag on chef-client" do - cmd.must_match regexify( - " --json-attributes /tmp/kitchen/dna.json", :partial_line) - end + describe "for modern Chef versions" do - it "sets json attribtes flag for custom root_path" do - config[:root_path] = "/booyah" + before { config[:require_chef_omnibus] = "11.10" } - cmd.must_match regexify( - " --json-attributes /booyah/dna.json", :partial_line) - end + # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + def self.common_modern_shell_specs + it "sets local mode flag on chef-client" do + cmd.must_match regexify(" --local-mode", :partial_line) + end - it "does not set json attributes flag if config is falsey" do - config[:json_attributes] = false + it "sets chef zero port flag on chef-client" do + cmd.must_match regexify(" --chef-zero-port 8889", :partial_line) + end - cmd.wont_match regexify(" --json-attributes ", :partial_line) + it "sets chef zero host flag for custom host" do + config[:chef_zero_host] = "192.168.0.1" + + cmd.must_match regexify(" --chef-zero-host 192.168.0.1", :partial_line) + end + + it "sets chef zero port flag for custom port" do + config[:chef_zero_port] = 123 + + cmd.must_match regexify(" --chef-zero-port 123", :partial_line) + end + + it "does not set chef zero host flag when value is falsey" do + config[:chef_zero_host] = nil + + cmd.wont_match regexify(" --chef-zero-host ", :partial_line) + end + + it "does not set chef zero port flag when value is falsey" do + config[:chef_zero_port] = nil + + cmd.wont_match regexify(" --chef-zero-port ", :partial_line) + end end + # rubocop:enable Metrics/MethodLength, Metrics/AbcSize - it "does not set logfile flag by default" do - cmd.wont_match regexify(" --logfile ", :partial_line) + describe "for bourne shells" do + + before { platform.stubs(:shell_type).returns("bourne") } + + let(:base) { "/tmp/kitchen/" } + let(:custom_base) { "/a/b/" } + let(:custom_root) { "/a/b" } + + common_shell_specs + common_modern_shell_specs + + it "uses bourne shell" do + cmd.must_match(/\Ash -c '$/) + cmd.must_match(/'\Z/) + end + + it "ends with a single quote" do + cmd.must_match(/'\Z/) + end + + it "exports http_proxy & HTTP_PROXY when :http_proxy is set" do + config[:http_proxy] = "http://proxy" + + cmd.lines[1..2].must_equal([ + %{http_proxy="http://proxy"; export http_proxy\n}, + %{HTTP_PROXY="http://proxy"; export HTTP_PROXY\n} + ]) + end + + it "exports https_proxy & HTTPS_PROXY when :https_proxy is set" do + config[:https_proxy] = "https://proxy" + + cmd.lines[1..2].must_equal([ + %{https_proxy="https://proxy"; export https_proxy\n}, + %{HTTPS_PROXY="https://proxy"; export HTTPS_PROXY\n} + ]) + end + + it "exports all http proxy variables when both are set" do + config[:http_proxy] = "http://proxy" + config[:https_proxy] = "https://proxy" + + cmd.lines[1..4].must_equal([ + %{http_proxy="http://proxy"; export http_proxy\n}, + %{HTTP_PROXY="http://proxy"; export HTTP_PROXY\n}, + %{https_proxy="https://proxy"; export https_proxy\n}, + %{HTTPS_PROXY="https://proxy"; export HTTPS_PROXY\n} + ]) + end + + it "uses sudo for chef-client when configured" do + config[:chef_omnibus_root] = "/c" + config[:sudo] = true + + cmd.must_match regexify("sudo -E /c/bin/chef-client ", :partial_line) + end + + it "does not use sudo for chef-client when configured" do + config[:chef_omnibus_root] = "/c" + config[:sudo] = false + + cmd.must_match regexify("/c/bin/chef-client ", :partial_line) + cmd.wont_match regexify("sudo -E /c/bin/chef-client ", :partial_line) + end end - it "sets logfile flag for custom value" do - config[:log_file] = "/a/out.log" + describe "for powershell shells on windows os types" do + + before do + platform.stubs(:shell_type).returns("powershell") + platform.stubs(:os_type).returns("windows") + end + + let(:base) { "$env:TEMP\\kitchen\\" } + let(:custom_base) { "\\a\\b\\" } + let(:custom_root) { "\\a\\b" } + + common_shell_specs + common_modern_shell_specs + + it "exports http_proxy & HTTP_PROXY when :http_proxy is set" do + config[:http_proxy] = "http://proxy" + + cmd.lines[0..1].must_equal([ + %{$env:http_proxy = "http://proxy"\n}, + %{$env:HTTP_PROXY = "http://proxy"\n} + ]) + end + + it "exports https_proxy & HTTPS_PROXY when :https_proxy is set" do + config[:https_proxy] = "https://proxy" + + cmd.lines[0..1].must_equal([ + %{$env:https_proxy = "https://proxy"\n}, + %{$env:HTTPS_PROXY = "https://proxy"\n} + ]) + end + + it "exports all http proxy variables when both are set" do + config[:http_proxy] = "http://proxy" + config[:https_proxy] = "https://proxy" + + cmd.lines[0..3].must_equal([ + %{$env:http_proxy = "http://proxy"\n}, + %{$env:HTTP_PROXY = "http://proxy"\n}, + %{$env:https_proxy = "https://proxy"\n}, + %{$env:HTTPS_PROXY = "https://proxy"\n} + ]) + end - cmd.must_match regexify(" --logfile /a/out.log", :partial_line) + it "calls the chef-client command from :chef_client_path" do + config[:chef_client_path] = "\\r\\chef-client.bat" + + cmd.must_match regexify("& \\r\\chef-client.bat ", :partial_line) + end end end @@ -521,118 +777,146 @@ def sandbox_path(path) before do config[:require_chef_omnibus] = "10.20" - config[:ruby_bindir] = "/r/bin" end - it "uses bourne shell" do - cmd.must_match(/\Ash -c '$/) - cmd.must_match(/'\Z/) - end + # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + def self.common_old_shell_specs + it "does not set local mode flag" do + cmd.wont_match regexify(" --local-mode", :partial_line) + end - it "uses sudo for ruby when configured" do - config[:root_path] = "/x" - config[:sudo] = true + it "does not set chef zero host flag for custom host" do + config[:chef_zero_host] = "192.168.0.1" - cmd.must_match regexify( - "sudo -E /r/bin/ruby /x/chef-client-zero.rb ", :partial_line) - end + cmd.wont_match regexify(" --chef-zero-host 192.168.0.1", :partial_line) + end - it "does not use sudo for ruby when configured" do - config[:root_path] = "/x" - config[:sudo] = false + it "does not set chef zero port flag for custom port" do + config[:chef_zero_port] = 123 - cmd.must_match regexify( - "/r/bin/ruby /x/chef-client-zero.rb ", :partial_line) - cmd.wont_match regexify( - "sudo -E /r/bin/ruby /x/chef-client-zero.rb ", :partial_line) + cmd.wont_match regexify(" --chef-zero-port 123", :partial_line) + end end - it "does not set local mode flag" do - cmd.wont_match regexify(" --local-mode", :partial_line) - end + describe "for bourne shells" do - it "sets config flag on chef-client" do - cmd.must_match regexify( - " --config /tmp/kitchen/client.rb", :partial_line) - end + before do + platform.stubs(:shell_type).returns("bourne") + config[:ruby_bindir] = "/r/bin" + end - it "sets config flag for custom root_path" do - config[:root_path] = "/a/b" + let(:base) { "/tmp/kitchen/" } + let(:custom_base) { "/a/b/" } + let(:custom_root) { "/a/b" } - cmd.must_match regexify(" --config /a/b/client.rb", :partial_line) - end + common_shell_specs + common_old_shell_specs - it "sets log level flag on chef-client to auto by default" do - cmd.must_match regexify(" --log_level auto", :partial_line) - end + it "uses bourne shell" do + cmd.must_match(/\Ash -c '$/) + cmd.must_match(/'\Z/) + end - it "set log level flag for custom level" do - config[:log_level] = :extreme + it "ends with a single quote" do + cmd.must_match(/'\Z/) + end - cmd.must_match regexify(" --log_level extreme", :partial_line) - end + it "uses sudo for ruby when configured" do + config[:root_path] = "/x" + config[:sudo] = true - it "sets force formatter flag on chef-solo" do - cmd.must_match regexify(" --force-formatter", :partial_line) - end + cmd.must_match regexify( + "sudo -E /r/bin/ruby /x/chef-client-zero.rb ", :partial_line) + end - it "sets no color flag on chef-solo" do - cmd.must_match regexify(" --no-color", :partial_line) - end + it "does not use sudo for ruby when configured" do + config[:root_path] = "/x" + config[:sudo] = false - it "sets json attributes flag on chef-client" do - cmd.must_match regexify( - " --json-attributes /tmp/kitchen/dna.json", :partial_line) - end + cmd.must_match regexify( + "/r/bin/ruby /x/chef-client-zero.rb ", :partial_line) + cmd.wont_match regexify( + "sudo -E /r/bin/ruby /x/chef-client-zero.rb ", :partial_line) + end - it "sets json attribtes flag for custom root_path" do - config[:root_path] = "/booyah" + it "sets the CHEF_REPO_PATH environment variable" do + config[:root_path] = "/r" - cmd.must_match regexify( - " --json-attributes /booyah/dna.json", :partial_line) - end + cmd.must_match regexify( + %{CHEF_REPO_PATH="/r"; export CHEF_REPO_PATH}) + end - it "does not set json attributes flag if config is falsey" do - config[:json_attributes] = false + it "sets the GEM_HOME environment variable" do + config[:root_path] = "/r" - cmd.wont_match regexify(" --json-attributes ", :partial_line) - end + cmd.must_match regexify( + %{GEM_HOME="/r/chef-client-zero-gems"; export GEM_HOME}) + end - it "does not set logfile flag by default" do - cmd.wont_match regexify(" --logfile ", :partial_line) - end + it "sets the GEM_PATH environment variable" do + config[:root_path] = "/r" - it "sets logfile flag for custom value" do - config[:log_file] = "/a/out.log" + cmd.must_match regexify( + %{GEM_PATH="/r/chef-client-zero-gems"; export GEM_PATH}) + end + + it "sets the GEM_CACHE environment variable" do + config[:root_path] = "/r" - cmd.must_match regexify(" --logfile /a/out.log", :partial_line) + cmd.must_match regexify( + %{GEM_CACHE="/r/chef-client-zero-gems/cache"; export GEM_CACHE}) + end end - it "sets the CHEF_REPO_PATH environment variable" do - config[:root_path] = "/r" + describe "for powershell shells on windows os types" do - cmd.must_match regexify(%{CHEF_REPO_PATH="/r" }, :partial_line) - end + before do + platform.stubs(:shell_type).returns("powershell") + platform.stubs(:os_type).returns("windows") + config[:ruby_bindir] = "\\r\\bin" + end - it "sets the GEM_HOME environment variable" do - config[:root_path] = "/r" + let(:base) { "$env:TEMP\\kitchen\\" } + let(:custom_base) { "\\a\\b\\" } + let(:custom_root) { "\\a\\b" } - cmd.must_match regexify( - %{GEM_HOME="/r/chef-client-zero-gems" }, :partial_line) - end + common_shell_specs + common_old_shell_specs - it "sets the GEM_PATH environment variable" do - config[:root_path] = "/r" + it "calls ruby from :ruby_bindir" do + config[:root_path] = "\\x" - cmd.must_match regexify( - %{GEM_PATH="/r/chef-client-zero-gems" }, :partial_line) - end + cmd.must_match regexify( + "\\r\\bin\\ruby.exe \\x\\chef-client-zero.rb ", :partial_line) + end - it "sets the GEM_CACHE environment variable" do - config[:root_path] = "/r" + it "sets the CHEF_REPO_PATH environment variable" do + config[:root_path] = "\\r" - cmd.must_match regexify( - %{GEM_CACHE="/r/chef-client-zero-gems/cache" }, :partial_line) + cmd.must_match regexify( + %{$env:CHEF_REPO_PATH = "\\r"}) + end + + it "sets the GEM_HOME environment variable" do + config[:root_path] = "\\r" + + cmd.must_match regexify( + %{$env:GEM_HOME = "\\r\\chef-client-zero-gems"}) + end + + it "sets the GEM_PATH environment variable" do + config[:root_path] = "\\r" + + cmd.must_match regexify( + %{$env:GEM_PATH = "\\r\\chef-client-zero-gems"}) + end + + it "sets the GEM_CACHE environment variable" do + config[:root_path] = "\\r" + + cmd.must_match regexify( + %{$env:GEM_CACHE = "\\r\\chef-client-zero-gems\\cache"}) + end end end end diff --git a/support/chef_zero_prepare_command_legacy.ps1 b/support/chef_zero_prepare_command_legacy.ps1 new file mode 100644 index 000000000..7910ef4d5 --- /dev/null +++ b/support/chef_zero_prepare_command_legacy.ps1 @@ -0,0 +1,9 @@ +# we are installing the first version of chef that bundled chef-zero 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 :) + +if ((& "$gem" list chef-zero i) -ne "true") { + Write-Host ">>>>>> Attempting to use chef-zero with old version of Chef`n" + Write-Host "-----> Installing chef zero dependencies`n" + & "$gem" install chef --version 11.8.0 --no-ri --no-rdoc --conservative +} diff --git a/support/chef_zero_prepare_command_legacy.sh b/support/chef_zero_prepare_command_legacy.sh new file mode 100644 index 000000000..586366401 --- /dev/null +++ b/support/chef_zero_prepare_command_legacy.sh @@ -0,0 +1,10 @@ +# we are installing the first version of chef that bundled chef-zero 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 :) + +$gem list chef-zero -i 2>&1 >/dev/null +if test $? -ne 0 ; then + echo ">>>>>> Attempting to use chef-zero with old version of Chef" + echo "-----> Installing chef zero dependencies" + $gem install chef --version 11.8.0 --no-ri --no-rdoc --conservative +fi