diff options
author | Marc A. Paradise <marc.paradise@gmail.com> | 2019-04-06 15:34:02 -0400 |
---|---|---|
committer | Marc A. Paradise <marc.paradise@gmail.com> | 2019-04-06 15:34:02 -0400 |
commit | 129d0299061d54635720389cec4824f7516eaa31 (patch) | |
tree | d106ab1f7c65023060f8ea9333c3e0e4c020679f | |
parent | 37fbedb4216bb5d448c807a3de5fb9205f4580e6 (diff) | |
download | chef-mp/bootstrap-plus-consolidated-config.tar.gz |
Attempting to consolidate ocnfig. May not work because of how merge config excludes keys that are not explicitly declared as optionsmp/bootstrap-plus-consolidated-config
Signed-off-by: Marc A. Paradise <marc.paradise@gmail.com>
-rw-r--r-- | lib/chef/knife/bootstrap.rb | 47 | ||||
-rw-r--r-- | lib/chef/knife/bootstrap/chef_vault_handler.rb | 16 | ||||
-rw-r--r-- | lib/chef/knife/bootstrap/client_builder.rb | 44 | ||||
-rw-r--r-- | lib/chef/knife/bootstrap/templates/chef-full.erb | 23 | ||||
-rw-r--r-- | lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb | 18 | ||||
-rw-r--r-- | lib/chef/knife/core/bootstrap_context.rb | 121 | ||||
-rw-r--r-- | lib/chef/knife/core/windows_bootstrap_context.rb | 119 | ||||
-rw-r--r-- | spec/unit/knife/bootstrap_spec.rb | 33 | ||||
-rw-r--r-- | spec/unit/knife/core/bootstrap_context_spec.rb | 33 |
9 files changed, 214 insertions, 240 deletions
diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb index c6e214650b..4252cfdf7f 100644 --- a/lib/chef/knife/bootstrap.rb +++ b/lib/chef/knife/bootstrap.rb @@ -22,7 +22,6 @@ require "erubis" require "chef/knife/bootstrap/chef_vault_handler" require "chef/knife/bootstrap/client_builder" require "chef/util/path_helper" -require "chef/knife/bootstrap/options" class Chef class Knife @@ -32,9 +31,6 @@ class Chef WINRM_AUTH_PROTOCOL_LIST = %w{plaintext kerberos ssl negotiate}.freeze include DataBagSecretOptions - # Command line flags and options for bootstrap - there's a large number of them - # so we'll keep this file a little smaller by splitting them out. - include Bootstrap::Options # Common connectivity options option :connection_user, short: "-U USERNAME", @@ -352,14 +348,21 @@ class Chef banner "knife bootstrap [PROTOCOL://][USER@]FQDN (options)" def initialize(argv = []) + # These options need to be present in the CLI options hash + # in order for Knife#merge_config to merge them properly + # with Chef::Config[:knife]. + self.class.options[:ssh_user] = self.class.options[:connection_user] + self.class.options[:winrm_user] = self.class.options[:connection_user] + self.class.options[:ssh_port] = self.class.options[:connection_port] + self.class.options[:winrm_port] = self.class.options[:connection_port] + # knife config super @client_builder = Chef::Knife::Bootstrap::ClientBuilder.new( - chef_config: Chef::Config, - knife_config: config, + config: config, ui: ui ) @chef_vault_handler = Chef::Knife::Bootstrap::ChefVaultHandler.new( - knife_config: config, + config: config, ui: ui ) end @@ -440,19 +443,19 @@ class Chef @bootstrap_context ||= if target_host.base_os == :windows require "chef/knife/core/windows_bootstrap_context" - Knife::Core::WindowsBootstrapContext.new(config, config[:run_list], Chef::Config, secret) + Knife::Core::WindowsBootstrapContext.new(config, config[:run_list], secret) else require "chef/knife/core/bootstrap_context" - Knife::Core::BootstrapContext.new(config, config[:run_list], Chef::Config, secret) + Knife::Core::BootstrapContext.new(config, config[:run_list], secret) end end def first_boot_attributes - @config[:first_boot_attributes] || @config[:first_boot_attributes_from_file] || {} + config[:first_boot_attributes] || config[:first_boot_attributes_from_file] || {} end def render_template - @config[:first_boot_attributes] = first_boot_attributes + config[:first_boot_attributes] = first_boot_attributes template_file = find_template template = IO.read(template_file).chomp Erubis::Eruby.new(template).evaluate(bootstrap_context) @@ -574,7 +577,7 @@ class Chef # Fail if both first_boot_attributes and first_boot_attributes_from_file # are set. def validate_first_boot_attributes! - if @config[:first_boot_attributes] && @config[:first_boot_attributes_from_file] + if config[:first_boot_attributes] && config[:first_boot_attributes_from_file] raise Chef::Exceptions::BootstrapCommandInputError end true @@ -860,7 +863,14 @@ class Chef } end - # Looks up configuration entries, first in the class member + # + # Looks up configuration entries in the config field, + # which is a merge of cli config + defaults + knife config + # Because some keys can be kept in knife config under alternative + # names (eg -> connection_user -> winrm_user|ssh_user), + # we'll fall back to lookuping up under the provided alt_config_key + # + # merged 'config' fieldLooks up configuration entries, first in the class member # `config` which contains options populated from CLI flags. # If the entry is not found there, Chef::Config[:knife][KEY] # is checked. @@ -868,16 +878,13 @@ class Chef # knife_config_key should be specified if the knife config lookup # key is different from the CLI flag lookup key. # - def config_value(key, knife_config_key = nil, default = nil) + def config_value(key, alt_config_key = nil, default = nil) if config.key? key config[key] + elsif config.key? alt_config_key + config[alt_config_key] else - lookup_key = knife_config_key || key - if Chef::Config[:knife].key?(lookup_key) - Chef::Config[:knife][lookup_key] - else - default - end + default end end diff --git a/lib/chef/knife/bootstrap/chef_vault_handler.rb b/lib/chef/knife/bootstrap/chef_vault_handler.rb index 24ed0eb379..176315f2a0 100644 --- a/lib/chef/knife/bootstrap/chef_vault_handler.rb +++ b/lib/chef/knife/bootstrap/chef_vault_handler.rb @@ -23,7 +23,7 @@ class Chef class ChefVaultHandler # @return [Hash] knife merged config, typically @config - attr_accessor :knife_config + attr_accessor :config # @return [Chef::Knife::UI] ui object for output attr_accessor :ui @@ -31,11 +31,11 @@ class Chef # @return [Chef::ApiClient] vault client attr_reader :client - # @param knife_config [Hash] knife merged config, typically @config + # @param config [Hash] knife merged config, typically @config # @param ui [Chef::Knife::UI] ui object for output - def initialize(knife_config: {}, ui: nil) - @knife_config = knife_config - @ui = ui + def initialize(config: {}, ui: nil) + @config = config + @ui = ui end # Updates the chef vault items for the newly created client. @@ -87,17 +87,17 @@ class Chef # @return [String] string with serialized JSON representing the chef vault items def bootstrap_vault_json - knife_config[:bootstrap_vault_json] + config[:bootstrap_vault_json] end # @return [String] JSON text in a file representing the chef vault items def bootstrap_vault_file - knife_config[:bootstrap_vault_file] + config[:bootstrap_vault_file] end # @return [Hash] Ruby object representing the chef vault items to create def bootstrap_vault_item - knife_config[:bootstrap_vault_item] + config[:bootstrap_vault_item] end # Helper to return a ruby object represeting all the data bags and items diff --git a/lib/chef/knife/bootstrap/client_builder.rb b/lib/chef/knife/bootstrap/client_builder.rb index 5fb0edc31b..cc15791b9e 100644 --- a/lib/chef/knife/bootstrap/client_builder.rb +++ b/lib/chef/knife/bootstrap/client_builder.rb @@ -28,21 +28,19 @@ class Chef class Bootstrap < Knife class ClientBuilder - # @return [Hash] knife merged config, typically @config - attr_accessor :knife_config - # @return [Hash] chef config object - attr_accessor :chef_config + # @return [Hash] merged hash of CLI and knife config + attr_accessor :config # @return [Chef::Knife::UI] ui object for output attr_accessor :ui # @return [Chef::ApiClient] client saved on run attr_reader :client - # @param knife_config [Hash] Hash of knife config settings - # @param chef_config [Hash] Hash of chef config settings + # @param config [Hash] Hash of knife config settings + # @param config [Hash] Hash of chef config settings # @param ui [Chef::Knife::UI] UI object for output - def initialize(knife_config: {}, chef_config: {}, ui: nil) - @knife_config = knife_config - @chef_config = chef_config + def initialize(config: {}, ui: nil) + @config = config + @config = config @ui = ui end @@ -78,39 +76,39 @@ class Chef private - # @return [String] node name from the knife_config + # @return [String] node name from the config def node_name - knife_config[:chef_node_name] + config[:chef_node_name] end - # @return [String] enviroment from the knife_config + # @return [String] enviroment from the config def environment - knife_config[:environment] + config[:environment] end - # @return [String] run_list from the knife_config + # @return [String] run_list from the config def run_list - knife_config[:run_list] + config[:run_list] end - # @return [String] policy_name from the knife_config + # @return [String] policy_name from the config def policy_name - knife_config[:policy_name] + config[:policy_name] end - # @return [String] policy_group from the knife_config + # @return [String] policy_group from the config def policy_group - knife_config[:policy_group] + config[:policy_group] end - # @return [Hash,Array] Object representation of json first-boot attributes from the knife_config + # @return [Hash,Array] Object representation of json first-boot attributes from the config def first_boot_attributes - knife_config[:first_boot_attributes] + config[:first_boot_attributes] end # @return [String] chef server url from the Chef::Config def chef_server_url - chef_config[:chef_server_url] + config[:chef_server_url] end # Accesses the run_list and coerces it into an Array, changing nils into @@ -155,7 +153,7 @@ class Chef node.environment(environment) if environment node.policy_name = policy_name if policy_name node.policy_group = policy_group if policy_group - (knife_config[:tags] || []).each do |tag| + (config[:tags] || []).each do |tag| node.tags << tag end node diff --git a/lib/chef/knife/bootstrap/templates/chef-full.erb b/lib/chef/knife/bootstrap/templates/chef-full.erb index 094cca1c08..845bb03e22 100644 --- a/lib/chef/knife/bootstrap/templates/chef-full.erb +++ b/lib/chef/knife/bootstrap/templates/chef-full.erb @@ -1,5 +1,4 @@ -sh -c ' -<%= "export https_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%> +<%= "export https_proxy=\"#{config[:bootstrap_proxy]}\"" if config[:bootstrap_proxy] -%> if test "x$TMPDIR" = "x"; then tmp="/tmp" @@ -37,7 +36,7 @@ capture_tmp_stderr() { # do_wget URL FILENAME do_wget() { echo "trying wget..." - wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> <%= knife_config[:bootstrap_wget_options] %> -O "$2" "$1" 2>$tmp_dir/stderr + wget <%= "--proxy=on " if config[:bootstrap_proxy] %> <%= config[:bootstrap_wget_options] %> -O "$2" "$1" 2>$tmp_dir/stderr rc=$? # check for 404 grep "ERROR 404" $tmp_dir/stderr 2>&1 >/dev/null @@ -57,7 +56,7 @@ do_wget() { # do_curl URL FILENAME do_curl() { echo "trying curl..." - curl -sL <%= "--proxy \"#{knife_config[:bootstrap_proxy]}\" " if knife_config[:bootstrap_proxy] %> <%= knife_config[:bootstrap_curl_options] %> -D $tmp_dir/stderr -o "$2" "$1" 2>$tmp_dir/stderr + curl -sL <%= "--proxy \"#{config[:bootstrap_proxy]}\" " if config[:bootstrap_proxy] %> <%= config[:bootstrap_curl_options] %> -D $tmp_dir/stderr -o "$2" "$1" 2>$tmp_dir/stderr rc=$? # check for 404 grep "404 Not Found" $tmp_dir/stderr 2>&1 >/dev/null @@ -164,14 +163,14 @@ do_download() { <%# Run any custom commands before installing chef-client -%> <%# Ex. wait for cloud-init to complete -%> -<% if knife_config[:bootstrap_preinstall_command] %> - <%= knife_config[:bootstrap_preinstall_command] %> +<% if config[:bootstrap_preinstall_command] %> + <%= config[:bootstrap_preinstall_command] %> <% end %> -<% if knife_config[:bootstrap_install_command] %> - <%= knife_config[:bootstrap_install_command] %> +<% if config[:bootstrap_install_command] %> + <%= config[:bootstrap_install_command] %> <% else %> - install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://omnitruck.chef.io/chef/install.sh" %>" + install_sh="<%= config[:bootstrap_url] ? config[:bootstrap_url] : "https://omnitruck.chef.io/chef/install.sh" %>" if test -f /usr/bin/chef-client; then echo "-----> Existing Chef installation detected" else @@ -214,10 +213,10 @@ mkdir -p /etc/chef/trusted_certs <% end -%> <%# Generate Ohai Hints -%> -<% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> +<% unless config[:hints].nil? || config[:hints].empty? -%> mkdir -p /etc/chef/ohai/hints -<% @chef_config[:knife][:hints].each do |name, hash| -%> +<% config[:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' <%= Chef::JSONCompat.to_json(hash) %> EOP @@ -239,4 +238,4 @@ mkdir -p /etc/chef/client.d echo "Starting the first Chef Client run..." -<%= start_chef %>' +<%= start_chef %> diff --git a/lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb b/lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb index c30a22bd94..a85fb9947c 100644 --- a/lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb +++ b/lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb @@ -21,7 +21,7 @@ @rem the line is read. See help for the /E switch from cmd.exe /? . @setlocal ENABLEDELAYEDEXPANSION -<%= "SETX HTTP_PROXY \"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] %> +<%= "SETX HTTP_PROXY \"#{config[:bootstrap_proxy]}\"" if config[:bootstrap_proxy] %> @set BOOTSTRAP_DIRECTORY=<%= bootstrap_directory %> @echo Checking for existing directory "%BOOTSTRAP_DIRECTORY%"... @@ -96,10 +96,10 @@ goto architecture_select goto Version10.0 :architecture_select -<% if knife_config[:architecture] %> - @set MACHINE_ARCH=<%= knife_config[:architecture] %> +<% if config[:architecture] %> + @set MACHINE_ARCH=<%= config[:architecture] %> - <% if knife_config[:architecture] == "x86_64" %> + <% if config[:architecture] == "x86_64" %> IF "%PROCESSOR_ARCHITECTURE%"=="x86" IF not defined PROCESSOR_ARCHITEW6432 ( echo You specified bootstrap_architecture as x86_64 but the target machine is i386. A 64 bit program cannot run on a 32 bit machine. > "&2" echo Exiting without bootstrapping. > "&2" @@ -125,8 +125,8 @@ If !ERRORLEVEL!==0 ( :install @rem If user has provided the custom installation command for chef-client then execute it -<% if @chef_config[:knife][:bootstrap_install_command] %> - <%= @chef_config[:knife][:bootstrap_install_command] %> +<% if config[:bootstrap_install_command] %> + <%= config[:bootstrap_install_command] %> <% else %> @rem Install Chef using chef-client MSI installer @@ -232,7 +232,7 @@ echo Writing validation key... echo Validation key written. @echo on -<% if @config[:secret] -%> +<% if config[:secret] -%> > <%= bootstrap_directory %>\encrypted_data_bag_secret ( <%= secret %> ) @@ -244,10 +244,10 @@ mkdir <%= bootstrap_directory %>\trusted_certs <% end -%> <%# Generate Ohai Hints -%> -<% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> +<% unless config[:hints].nil? || config[:hints].empty? -%> mkdir <%= bootstrap_directory %>\ohai\hints -<% @chef_config[:knife][:hints].each do |name, hash| -%> +<% config[:hints].each do |name, hash| -%> > <%= bootstrap_directory %>\ohai\hints\<%= name %>.json ( <%= escape_and_echo(hash.to_json) %> ) diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb index 287fe0a50f..72a8ab1033 100644 --- a/lib/chef/knife/core/bootstrap_context.rb +++ b/lib/chef/knife/core/bootstrap_context.rb @@ -26,17 +26,17 @@ class Chef # Instances of BootstrapContext are the context objects (i.e., +self+) for # bootstrap templates. For backwards compatibility, they +must+ set the # following instance variables: - # * @config - a hash of knife's config values + # * @config - a hash of knife's @config values # * @run_list - the run list for the node to boostrap # class BootstrapContext attr_accessor :client_pem + attr_reader :config - def initialize(config, run_list, chef_config, secret = nil) + def initialize(config, run_list, secret = nil) @config = config @run_list = run_list - @chef_config = chef_config @secret = secret end @@ -45,9 +45,9 @@ class Chef end def validation_key - if @chef_config[:validation_key] && - File.exist?(File.expand_path(@chef_config[:validation_key])) - IO.read(File.expand_path(@chef_config[:validation_key])) + if @config[:validation_key] && + File.exist?(File.expand_path(@config[:validation_key])) + IO.read(File.expand_path(@config[:validation_key])) else false end @@ -68,31 +68,32 @@ class Chef end def get_log_location - if !(@chef_config[:config_log_location].class == IO ) && (@chef_config[:config_log_location].nil? || @chef_config[:config_log_location].to_s.empty?) + if !(@config[:config_log_location].class == IO ) && (@config[:config_log_location].nil? || @config[:config_log_location].to_s.empty?) "STDOUT" - elsif @chef_config[:config_log_location].equal?(:win_evt) - raise "The value :win_evt is not supported for config_log_location on Linux Platforms \n" - elsif @chef_config[:config_log_location].equal?(:syslog) + elsif @config[:config_log_location].equal?(:win_evt) + raise "The value :win_evt is not supported for @config_log_location on Linux Platforms \n" + elsif @config[:config_log_location].equal?(:syslog) ":syslog" - elsif @chef_config[:config_log_location].equal?(STDOUT) + elsif @config[:config_log_location].equal?(STDOUT) "STDOUT" - elsif @chef_config[:config_log_location].equal?(STDERR) + elsif @config[:config_log_location].equal?(STDERR) "STDERR" - elsif @chef_config[:config_log_location] - %Q{"#{@chef_config[:config_log_location]}"} + elsif @config[:config_log_location] + %Q{"#{@config[:config_log_location]}"} else "STDOUT" end end def config_content + require 'pry'; binding.pry client_rb = <<~CONFIG - chef_server_url "#{@chef_config[:chef_server_url]}" - validation_client_name "#{@chef_config[:validation_client_name]}" + chef_server_url "#{@config[:chef_server_url]}" + validation_client_name "#{@config[:validation_client_name]}" CONFIG - if !(@chef_config[:config_log_level].nil? || @chef_config[:config_log_level].empty?) - client_rb << %Q{log_level :#{@chef_config[:config_log_level]}\n} + if !(@config[:config_log_level].nil? || @config[:config_log_level].empty?) + client_rb << %Q{log_level :#{@config[:config_log_level]}\n} end client_rb << "log_location #{get_log_location}\n" @@ -103,23 +104,23 @@ class Chef client_rb << "# Using default node name (fqdn)\n" end - # We configure :verify_api_cert only when it's overridden on the CLI - # or when specified in the knife config. - if !@config[:node_verify_api_cert].nil? || knife_config.key?(:verify_api_cert) - value = @config[:node_verify_api_cert].nil? ? knife_config[:verify_api_cert] : @config[:node_verify_api_cert] + # We @configure :verify_api_cert only when it's overridden on the CLI + # or when specified in the knife @config. + if !@config[:node_verify_api_cert].nil? || @config.key?(:verify_api_cert) + value = @config[:node_verify_api_cert].nil? ? @config[:verify_api_cert] : @config[:node_verify_api_cert] client_rb << %Q{verify_api_cert #{value}\n} end - # We configure :ssl_verify_mode only when it's overridden on the CLI - # or when specified in the knife config. - if @config[:node_ssl_verify_mode] || knife_config.key?(:ssl_verify_mode) + # We @configure :ssl_verify_mode only when it's overridden on the CLI + # or when specified in the knife @config. + if @config[:node_ssl_verify_mode] || @config.key?(:ssl_verify_mode) value = case @config[:node_ssl_verify_mode] when "peer" :verify_peer when "none" :verify_none when nil - knife_config[:ssl_verify_mode] + @config[:ssl_verify_mode] else nil end @@ -130,26 +131,26 @@ class Chef end if @config[:ssl_verify_mode] - client_rb << %Q{ssl_verify_mode :#{knife_config[:ssl_verify_mode]}\n} + client_rb << %Q{ssl_verify_mode :#{@config[:ssl_verify_mode]}\n} end - if knife_config[:bootstrap_proxy] - client_rb << %Q{http_proxy "#{knife_config[:bootstrap_proxy]}"\n} - client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n} + if @config[:bootstrap_proxy] + client_rb << %Q{http_proxy "#{@config[:bootstrap_proxy]}"\n} + client_rb << %Q{https_proxy "#{@config[:bootstrap_proxy]}"\n} end - if knife_config[:bootstrap_proxy_user] - client_rb << %Q{http_proxy_user "#{knife_config[:bootstrap_proxy_user]}"\n} - client_rb << %Q{https_proxy_user "#{knife_config[:bootstrap_proxy_user]}"\n} + if @config[:bootstrap_proxy_user] + client_rb << %Q{http_proxy_user "#{@config[:bootstrap_proxy_user]}"\n} + client_rb << %Q{https_proxy_user "#{@config[:bootstrap_proxy_user]}"\n} end - if knife_config[:bootstrap_proxy_pass] - client_rb << %Q{http_proxy_pass "#{knife_config[:bootstrap_proxy_pass]}"\n} - client_rb << %Q{https_proxy_pass "#{knife_config[:bootstrap_proxy_pass]}"\n} + if @config[:bootstrap_proxy_pass] + client_rb << %Q{http_proxy_pass "#{@config[:bootstrap_proxy_pass]}"\n} + client_rb << %Q{https_proxy_pass "#{@config[:bootstrap_proxy_pass]}"\n} end - if knife_config[:bootstrap_no_proxy] - client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n} + if @config[:bootstrap_no_proxy] + client_rb << %Q{no_proxy "#{@config[:bootstrap_no_proxy]}"\n} end if encrypted_data_bag_secret @@ -165,7 +166,7 @@ class Chef fips true require "chef/version" chef_version = ::Chef::VERSION.split(".") - unless chef_version[0].to_i > 12 || (chef_version[0].to_i == 12 && chef_version[1].to_i >= 8) + unless chef_version[0].to_i > 12 || (chef_version[0].to_i == 12 && chef_version[1].to_i >= 20) raise "FIPS Mode requested but not supported by this client" end CONFIG @@ -175,8 +176,8 @@ class Chef end def start_chef - # If the user doesn't have a client path configure, let bash use the PATH for what it was designed for - client_path = @chef_config[:chef_client_path] || "chef-client" + # If the user doesn't have a client path @configure, let bash use the PATH for what it was designed for + client_path = @config[:chef_client_path] || "chef-client" s = "#{client_path} -j /etc/chef/first-boot.json" if @config[:verbosity] && @config[:verbosity] >= 3 s << " -l trace" @@ -188,34 +189,17 @@ class Chef s end - def knife_config - @chef_config.key?(:knife) ? @chef_config[:knife] : {} - end - # # chef version string to fetch the latest current version from omnitruck # If user is on X.Y.Z bootstrap will use the latest X release # X here can be 10 or 11 def latest_current_chef_version_string - installer_version_string = nil - if @config[:prerelease] - installer_version_string = ["-p"] - else - chef_version_string = if knife_config[:bootstrap_version] - knife_config[:bootstrap_version] - else - Chef::VERSION.split(".").first - end - - installer_version_string = ["-v", chef_version_string] - - # If bootstrapping a pre-release version add -p to the installer string - if chef_version_string.split(".").length > 3 - installer_version_string << "-p" - end - end - - installer_version_string.join(" ") + chef_version_string = if @config[:bootstrap_version] + @config[:bootstrap_version] + else + Chef::VERSION.split(".").first + end + "-v #{chef_version_string}" end def first_boot @@ -238,8 +222,8 @@ class Chef # This string should contain both the commands necessary to both create the files, as well as their content def trusted_certs_content content = "" - if @chef_config[:trusted_certs_dir] - Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert| + if @config[:trusted_certs_dir] + Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(@config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert| content << "cat > /etc/chef/trusted_certs/#{File.basename(cert)} <<'EOP'\n" + IO.read(File.expand_path(cert)) + "\nEOP\n" end @@ -249,8 +233,8 @@ class Chef def client_d_content content = "" - if @chef_config[:client_d_dir] && File.exist?(@chef_config[:client_d_dir]) - root = Pathname(@chef_config[:client_d_dir]) + if @config[:client_d_dir] && File.exist?(@config[:client_d_dir]) + root = Pathname(@config[:client_d_dir]) root.find do |f| relative = f.relative_path_from(root) if f != root @@ -266,7 +250,6 @@ class Chef end content end - end end end diff --git a/lib/chef/knife/core/windows_bootstrap_context.rb b/lib/chef/knife/core/windows_bootstrap_context.rb index 1993a68ea8..dbc7595c3d 100644 --- a/lib/chef/knife/core/windows_bootstrap_context.rb +++ b/lib/chef/knife/core/windows_bootstrap_context.rb @@ -25,36 +25,25 @@ class Chef # Instances of BootstrapContext are the context objects (i.e., +self+) for # bootstrap templates. For backwards compatability, they +must+ set the # following instance variables: - # * @config - a hash of knife's config values + # * config - a hash of knife's config values # * @run_list - the run list for the node to boostrap # class WindowsBootstrapContext < BootstrapContext - def initialize(config, run_list, chef_config, secret = nil) - @config = config - @run_list = run_list - @chef_config = chef_config - @secret = secret - # Compatibility with Chef 12 and Chef 11 versions - begin - # Pass along the secret parameter for Chef 12 - super(config, run_list, chef_config, secret) - rescue ArgumentError - # The Chef 11 base class only has parameters for initialize - super(config, run_list, chef_config) - end + def initialize(config, run_list, secret = nil) + super end def validation_key - if File.exist?(File.expand_path(@chef_config[:validation_key])) - IO.read(File.expand_path(@chef_config[:validation_key])) + if File.exist?(File.expand_path(config[:validation_key])) + IO.read(File.expand_path(config[:validation_key])) else false end end def secret - escape_and_echo(@config[:secret]) + escape_and_echo(config[:secret]) end def trusted_certs_script @@ -63,20 +52,20 @@ class Chef def config_content client_rb = <<~CONFIG - chef_server_url "#{@chef_config[:chef_server_url]}" - validation_client_name "#{@chef_config[:validation_client_name]}" + chef_server_url "#{config[:chef_server_url]}" + validation_client_name "#{config[:validation_client_name]}" file_cache_path "c:/chef/cache" file_backup_path "c:/chef/backup" cache_options ({:path => "c:/chef/cache/checksums", :skip_expires => true}) CONFIG - if @config[:chef_node_name] - client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n} + if config[:chef_node_name] + client_rb << %Q{node_name "#{config[:chef_node_name]}"\n} else client_rb << "# Using default node name (fqdn)\n" end - if @chef_config[:config_log_level] - client_rb << %Q{log_level :#{@chef_config[:config_log_level]}\n} + if config[:config_log_level] + client_rb << %Q{log_level :#{config[:config_log_level]}\n} else client_rb << "log_level :auto\n" end @@ -85,21 +74,21 @@ class Chef # We configure :verify_api_cert only when it's overridden on the CLI # or when specified in the knife config. - if !@config[:node_verify_api_cert].nil? || knife_config.key?(:verify_api_cert) - value = @config[:node_verify_api_cert].nil? ? knife_config[:verify_api_cert] : @config[:node_verify_api_cert] + if !config[:node_verify_api_cert].nil? || config.key?(:verify_api_cert) + value = config[:node_verify_api_cert].nil? ? config[:verify_api_cert] : config[:node_verify_api_cert] client_rb << %Q{verify_api_cert #{value}\n} end # We configure :ssl_verify_mode only when it's overridden on the CLI # or when specified in the knife config. - if @config[:node_ssl_verify_mode] || knife_config.key?(:ssl_verify_mode) - value = case @config[:node_ssl_verify_mode] + if config[:node_ssl_verify_mode] || config.key?(:ssl_verify_mode) + value = case config[:node_ssl_verify_mode] when "peer" :verify_peer when "none" :verify_none when nil - knife_config[:ssl_verify_mode] + config[:ssl_verify_mode] else nil end @@ -109,22 +98,22 @@ class Chef end end - if @config[:ssl_verify_mode] - client_rb << %Q{ssl_verify_mode :#{knife_config[:ssl_verify_mode]}\n} + if config[:ssl_verify_mode] + client_rb << %Q{ssl_verify_mode :#{config[:ssl_verify_mode]}\n} end - if knife_config[:bootstrap_proxy] + if config[:bootstrap_proxy] client_rb << "\n" - client_rb << %Q{http_proxy "#{knife_config[:bootstrap_proxy]}"\n} - client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n} - client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n} if knife_config[:bootstrap_no_proxy] + client_rb << %Q{http_proxy "#{config[:bootstrap_proxy]}"\n} + client_rb << %Q{https_proxy "#{config[:bootstrap_proxy]}"\n} + client_rb << %Q{no_proxy "#{config[:bootstrap_no_proxy]}"\n} if config[:bootstrap_no_proxy] end - if knife_config[:bootstrap_no_proxy] - client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n} + if config[:bootstrap_no_proxy] + client_rb << %Q{no_proxy "#{config[:bootstrap_no_proxy]}"\n} end - if @config[:secret] + if config[:secret] client_rb << %Q{encrypted_data_bag_secret "c:/chef/encrypted_data_bag_secret"\n} end @@ -136,7 +125,7 @@ class Chef client_rb << <<~CONFIG fips true chef_version = ::Chef::VERSION.split(".") - unless chef_version[0].to_i > 12 || (chef_version[0].to_i == 12 && chef_version[1].to_i >= 8) + unless chef_version[0].to_i > 12 || (chef_version[0].to_i == 12 && chef_version[1].to_i >= 20) raise "FIPS Mode requested but not supported by this client" end CONFIG @@ -146,18 +135,18 @@ class Chef end def get_log_location - if @chef_config[:config_log_location].equal?(:win_evt) - %Q{:#{@chef_config[:config_log_location]}\n} - elsif @chef_config[:config_log_location].equal?(:syslog) + if config[:config_log_location].equal?(:win_evt) + %Q{:#{config[:config_log_location]}\n} + elsif config[:config_log_location].equal?(:syslog) raise "syslog is not supported for log_location on Windows OS\n" - elsif @chef_config[:config_log_location].equal?(STDOUT) + elsif config[:config_log_location].equal?(STDOUT) "STDOUT\n" - elsif @chef_config[:config_log_location].equal?(STDERR) + elsif config[:config_log_location].equal?(STDERR) "STDERR\n" - elsif @chef_config[:config_log_location].nil? || @chef_config[:config_log_location].empty? + elsif config[:config_log_location].nil? || config[:config_log_location].empty? "STDOUT\n" - elsif @chef_config[:config_log_location] - %Q{"#{@chef_config[:config_log_location]}"\n} + elsif config[:config_log_location] + %Q{"#{config[:config_log_location]}"\n} else "STDOUT\n" end @@ -170,25 +159,13 @@ class Chef end def latest_current_windows_chef_version_query - installer_version_string = nil - if @config[:prerelease] - installer_version_string = "&prerelease=true" - else - chef_version_string = if knife_config[:bootstrap_version] - knife_config[:bootstrap_version] - else - Chef::VERSION.split(".").first - end - - installer_version_string = "&v=#{chef_version_string}" - - # If bootstrapping a pre-release version add the prerelease query string - if chef_version_string.split(".").length > 3 - installer_version_string << "&prerelease=true" - end - end + chef_version_string = if config[:bootstrap_version] + config[:bootstrap_version] + else + Chef::VERSION.split(".").first + end - installer_version_string + "&v=#{chef_version_string}" end def win_wget @@ -300,14 +277,14 @@ class Chef # The default msi path has a number of url query parameters - we attempt to substitute # such parameters in as long as they are provided by the template. - if @config[:install].nil? || @config[:msi_url].empty? + if config[:install].nil? || config[:msi_url].empty? url = "https://www.chef.io/chef/download?p=windows" url += "&pv=#{machine_os}" unless machine_os.nil? url += "&m=#{machine_arch}" unless machine_arch.nil? url += "&DownloadContext=#{download_context}" unless download_context.nil? url += latest_current_windows_chef_version_query else - @config[:msi_url] + config[:msi_url] end end @@ -325,7 +302,7 @@ class Chef private def install_command(executor_quote) - if @config[:install_as_service] + if config[:install_as_service] "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote} ADDLOCAL=#{executor_quote}ChefClientFeature,ChefServiceFeature#{executor_quote}" else "msiexec /qn /log #{executor_quote}%CHEF_CLIENT_MSI_LOG_PATH%#{executor_quote} /i #{executor_quote}%LOCAL_DESTINATION_MSI_PATH%#{executor_quote}" @@ -336,8 +313,8 @@ class Chef # This string should contain both the commands necessary to both create the files, as well as their content def trusted_certs_content content = "" - if @chef_config[:trusted_certs_dir] - Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert| + if config[:trusted_certs_dir] + Dir.glob(File.join(Chef::Util::PathHelper.escape_glob_dir(config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert| content << "> #{bootstrap_directory}/trusted_certs/#{File.basename(cert)} (\n" + escape_and_echo(IO.read(File.expand_path(cert))) + "\n)\n" end @@ -347,8 +324,8 @@ class Chef def client_d_content content = "" - if @chef_config[:client_d_dir] && File.exist?(@chef_config[:client_d_dir]) - root = Pathname(@chef_config[:client_d_dir]) + if config[:client_d_dir] && File.exist?(config[:client_d_dir]) + root = Pathname(config[:client_d_dir]) root.find do |f| relative = f.relative_path_from(root) if f != root diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb index 5be0999e37..1075e9dccc 100644 --- a/spec/unit/knife/bootstrap_spec.rb +++ b/spec/unit/knife/bootstrap_spec.rb @@ -51,13 +51,14 @@ describe Chef::Knife::Bootstrap do end end - context "#render_template - when using the chef-full default template" do + context "#render_template - when using the chef-full default template", :focus do let(:rendered_template) do knife.merge_configs knife.render_template end it "should render client.rb" do + puts rendered_template expect(rendered_template).to match("cat > /etc/chef/client.rb <<'EOP'") expect(rendered_template).to match("chef_server_url \"https://localhost:443\"") expect(rendered_template).to match("validation_client_name \"chef-validator\"") @@ -1777,27 +1778,37 @@ describe Chef::Knife::Bootstrap do describe "#config_value" do before do - knife.config[:test_key_a] = "a from cli" - knife.config[:test_key_b] = "b from cli" - Chef::Config[:knife][:test_key_a] = "a from Chef::Config" - Chef::Config[:knife][:test_key_c] = "c from Chef::Config" - Chef::Config[:knife][:alt_test_key_c] = "alt c from Chef::Config" + + # Make sure this is in classs.options, or else merge_configs won't see it + # since it's not a declared option + knife.class.options[:ssh_user] = knife.class.options[:connection_user] + knife.class.options[:winrm_user] = knife.class.options[:connection_user] + + knife.config[:connection_protocol] = "connection_protocol from CLI" + knife.config[:connection_user] = "connection_user_from CLI" + knife.config[:password] = "password from CLI" + + Chef::Config.knife.connection_protocol = "connection_protocol from Chef::Config" + Chef::Config.knife.ssh_user = "ssh user from Chef::Config" + Chef::Config.knife.winrm_user = "winrm user from Chef::Config" + knife.merge_configs + end it "returns CLI value when key is only provided by the CLI" do - expect(knife.config_value(:test_key_b)).to eq "b from cli" + expect(knife.config_value(:password)).to eq "password from CLI" end it "returns CLI value when key is provided by CLI and Chef::Config" do - expect(knife.config_value(:test_key_a)).to eq "a from cli" + expect(knife.config_value(:connection_protocol)).to eq "connection_protocol from CLI" end - it "returns Chef::Config value whent he key is only provided by Chef::Config" do - expect(knife.config_value(:test_key_c)).to eq "c from Chef::Config" + it "returns Chef::Config value when the key is only provided by Chef::Config" do + expect(knife.config_value(:ssh_user)).to eq "ssh user from Chef::Config" end it "returns the Chef::Config value from the alternative key when the CLI key is not set" do - expect(knife.config_value(:test_key_c, :alt_test_key_c)).to eq "alt c from Chef::Config" + expect(knife.config_value(:bad_key, :winrm_user)).to eq "winrm user from Chef::Config" end it "returns the default value when the key is not provided by CLI or Chef::Config" do diff --git a/spec/unit/knife/core/bootstrap_context_spec.rb b/spec/unit/knife/core/bootstrap_context_spec.rb index 5aa176557f..bc09fdf2d9 100644 --- a/spec/unit/knife/core/bootstrap_context_spec.rb +++ b/spec/unit/knife/core/bootstrap_context_spec.rb @@ -26,9 +26,8 @@ describe Chef::Knife::Core::BootstrapContext do Chef::Config[:fips] = false end - let(:config) { { foo: :bar, color: true } } let(:run_list) { Chef::RunList.new("recipe[tmux]", "role[base]") } - let(:chef_config) do + let(:config) do { config_log_level: "info", config_log_location: "/tmp/log", @@ -40,10 +39,10 @@ describe Chef::Knife::Core::BootstrapContext do let(:secret) { nil } - subject(:bootstrap_context) { described_class.new(config, run_list, chef_config, secret) } + subject(:bootstrap_context) { described_class.new(config, run_list, secret) } it "initializes with Chef 11 parameters" do - expect { described_class.new(config, run_list, chef_config) }.not_to raise_error + expect { described_class.new(config, run_list, config) }.not_to raise_error end it "runs chef with the first-boot.json with no environment specified" do @@ -80,14 +79,14 @@ describe Chef::Knife::Core::BootstrapContext do end describe "alternate chef-client path" do - let(:chef_config) { { chef_client_path: "/usr/local/bin/chef-client" } } + let(:config) { { chef_client_path: "/usr/local/bin/chef-client" } } it "runs chef-client from another path when specified" do expect(bootstrap_context.start_chef).to eq "/usr/local/bin/chef-client -j /etc/chef/first-boot.json" end end describe "validation key path that contains a ~" do - let(:chef_config) { { validation_key: "~/my.key" } } + let(:config) { { validation_key: "~/my.key" } } it "reads the validation key when it contains a ~" do expect(File).to receive(:exist?).with(File.expand_path("my.key", ENV["HOME"])).and_return(true) expect(IO).to receive(:read).with(File.expand_path("my.key", ENV["HOME"])) @@ -157,7 +156,7 @@ describe Chef::Knife::Core::BootstrapContext do end describe "when a bootstrap_version is specified" do - let(:chef_config) do + let(:config) do { knife: { bootstrap_version: "11.12.4" }, } @@ -169,7 +168,7 @@ describe Chef::Knife::Core::BootstrapContext do end describe "when a pre-release bootstrap_version is specified" do - let(:chef_config) do + let(:config) do { knife: { bootstrap_version: "11.12.4.rc.0" }, } @@ -193,7 +192,7 @@ describe Chef::Knife::Core::BootstrapContext do end describe "when configured in config" do - let(:chef_config) do + let(:config) do { knife: { ssl_verify_mode: :verify_peer }, } @@ -236,7 +235,7 @@ describe Chef::Knife::Core::BootstrapContext do end describe "when configured in config" do - let(:chef_config) do + let(:config) do { knife: { verify_api_cert: :false }, } @@ -272,49 +271,49 @@ describe Chef::Knife::Core::BootstrapContext do describe "#config_log_location" do context "when config_log_location is nil" do - let(:chef_config) { { config_log_location: nil } } + let(:config) { { config_log_location: nil } } it "sets the default config_log_location in the client.rb" do expect(bootstrap_context.get_log_location).to eq "STDOUT" end end context "when config_log_location is empty" do - let(:chef_config) { { config_log_location: "" } } + let(:config) { { config_log_location: "" } } it "sets the default config_log_location in the client.rb" do expect(bootstrap_context.get_log_location).to eq "STDOUT" end end context "when config_log_location is :win_evt" do - let(:chef_config) { { config_log_location: :win_evt } } + let(:config) { { config_log_location: :win_evt } } it "raise error when config_log_location is :win_evt " do expect { bootstrap_context.get_log_location }.to raise_error("The value :win_evt is not supported for config_log_location on Linux Platforms \n") end end context "when config_log_location is :syslog" do - let(:chef_config) { { config_log_location: :syslog } } + let(:config) { { config_log_location: :syslog } } it "sets the config_log_location value as :syslog in the client.rb" do expect(bootstrap_context.get_log_location).to eq ":syslog" end end context "When config_log_location is STDOUT" do - let(:chef_config) { { config_log_location: STDOUT } } + let(:config) { { config_log_location: STDOUT } } it "Sets the config_log_location value as STDOUT in the client.rb" do expect(bootstrap_context.get_log_location).to eq "STDOUT" end end context "when config_log_location is STDERR" do - let(:chef_config) { { config_log_location: STDERR } } + let(:config) { { config_log_location: STDERR } } it "sets the config_log_location value as STDERR in the client.rb" do expect(bootstrap_context.get_log_location).to eq "STDERR" end end context "when config_log_location is a path" do - let(:chef_config) { { config_log_location: "/tmp/ChefLogFile" } } + let(:config) { { config_log_location: "/tmp/ChefLogFile" } } it "sets the config_log_location path in the client.rb" do expect(bootstrap_context.get_log_location).to eq "\"/tmp/ChefLogFile\"" end |