diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2020-04-09 13:28:17 -0700 |
---|---|---|
committer | Lamont Granquist <lamont@scriptkiddie.org> | 2020-04-17 10:20:31 -0700 |
commit | d7452360adb80e383b4886246990dbe46d3387c2 (patch) | |
tree | 1d4391bc389a25024fab40ea501745d3e5c8f9dc /lib/chef | |
parent | ac47427ab7090453a680c6c4cf6d32eb85cb270d (diff) | |
download | chef-d7452360adb80e383b4886246990dbe46d3387c2.tar.gz |
Knife bootstrap options cleanup
We have issue that are caused by old code before merging of hash values
were done correctly.
The `config` hash correctly merges all options and should always be
used.
Knife plugins should never touch Chef::Config[:knife] values (either
reading or writing from them).
The `knife_config` should be converted to the `config` hash since it
directly accesses Chef::Config[:knife] values.
The `config_value()` helper should no longer be used. Very clearly most
people started to use that when they should just use the config hash
directly. That was intended to be used only when a knife cli option
was being renamed and the former configuration value needed to be
used as well. It has been cargo culted around as the way to access
config values, and that should really stop.
The DataBagSecretOption mixin has been cleaned up so that the cli
options read+write only to the config[:cl_secret] and
config[:cl_secret_file] values. The config file values go into
config[:secret] and config[:secret_file]. The fact that those are
the merged values in the `config` hash doesn't matter since only
the cli should be writing to the first two and only the config
file should be writing to the latter two. I don't know why it was
made so complicated to begin with, but if there's some hidden
chef-11.early backcompat there, then chef-16 deliberately breaks that.
The use of `locate_config_value` helpers in all knife plugins is also
discouraged (but they all implement those themselves), just use the
config hash, which has the correct hash merge ordering. All of those
need to be deleted.
Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
Diffstat (limited to 'lib/chef')
-rw-r--r-- | lib/chef/deprecated.rb | 4 | ||||
-rw-r--r-- | lib/chef/knife.rb | 46 | ||||
-rw-r--r-- | lib/chef/knife/bootstrap.rb | 179 | ||||
-rw-r--r-- | lib/chef/knife/bootstrap/chef_vault_handler.rb | 20 | ||||
-rw-r--r-- | lib/chef/knife/bootstrap/client_builder.rb | 42 | ||||
-rw-r--r-- | lib/chef/knife/bootstrap/templates/chef-full.erb | 22 | ||||
-rw-r--r-- | lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb | 16 | ||||
-rw-r--r-- | lib/chef/knife/core/bootstrap_context.rb | 122 | ||||
-rw-r--r-- | lib/chef/knife/core/generic_presenter.rb | 7 | ||||
-rw-r--r-- | lib/chef/knife/core/windows_bootstrap_context.rb | 84 | ||||
-rw-r--r-- | lib/chef/knife/data_bag_secret_options.rb | 51 | ||||
-rw-r--r-- | lib/chef/knife/ssh.rb | 43 | ||||
-rw-r--r-- | lib/chef/knife/status.rb | 2 | ||||
-rw-r--r-- | lib/chef/knife/supermarket_download.rb | 3 | ||||
-rw-r--r-- | lib/chef/knife/supermarket_install.rb | 3 | ||||
-rw-r--r-- | lib/chef/knife/supermarket_list.rb | 3 | ||||
-rw-r--r-- | lib/chef/knife/supermarket_search.rb | 3 | ||||
-rw-r--r-- | lib/chef/knife/supermarket_share.rb | 3 | ||||
-rw-r--r-- | lib/chef/knife/supermarket_show.rb | 3 | ||||
-rw-r--r-- | lib/chef/knife/supermarket_unshare.rb | 3 |
20 files changed, 313 insertions, 346 deletions
diff --git a/lib/chef/deprecated.rb b/lib/chef/deprecated.rb index 7062e27aab..ecc589d263 100644 --- a/lib/chef/deprecated.rb +++ b/lib/chef/deprecated.rb @@ -233,6 +233,10 @@ class Chef target 28 end + class KnifeBootstrapApis < Base + target 29 + end + class Generic < Base def url "https://docs.chef.io/chef_deprecations_client/" diff --git a/lib/chef/knife.rb b/lib/chef/knife.rb index 1bf02df0df..bdab024579 100644 --- a/lib/chef/knife.rb +++ b/lib/chef/knife.rb @@ -343,31 +343,35 @@ class Chef exit(1) end - # keys from mixlib-cli options - def cli_keys - self.class.options.keys + # This is all set and default mixlib-config values. We only need the default + # values here (the set values are explicitly mixed in again later), but there is + # no mixlib-config API to get a Hash back with only the default values. + # + # Assumption: since config_file_defaults is the lowest precedence it doesn't matter + # that we include the set values here, but this is a hack and makes the name of the + # method a lie. FIXME: make the name not a lie by adding an API to mixlib-config. + # + # @api private + # + def config_file_defaults + Chef::Config[:knife].save(true) # this is like "dup" to a (real) Hash, and includes default values (and user set values) end - # extracts the settings from the Chef::Config[:knife] sub-hash that correspond - # to knife cli options -- in preparation for merging config values with cli values + # This is only the user-set mixlib-config values. We do not include the defaults + # here so that the config defaults do not override the cli defaults. + # + # @api private # - # NOTE: due to weirdness in mixlib-config #has_key? is only true if the value has - # been set by the user -- the Chef::Config defaults return #has_key?() of false and - # this code DEPENDS on that functionality since applying the default values in - # Chef::Config[:knife] would break the defaults in the cli that we would otherwise - # overwrite. def config_file_settings - cli_keys.each_with_object({}) do |key, memo| - if Chef::Config[:knife].key?(key) - memo[key] = Chef::Config[:knife][key] - end - end + Chef::Config[:knife].save(false) # this is like "dup" to a (real) Hash, and does not include default values (just user set values) end # config is merged in this order (inverse of precedence) - # default_config - mixlib-cli defaults (accessor from the mixin) - # config_file_settings - Chef::Config[:knife] sub-hash - # config - mixlib-cli settings (accessor from the mixin) + # config_file_defaults - Chef::Config[:knife] defaults from chef-config (XXX: this also includes the settings, but they get overwritten) + # default_config - mixlib-cli defaults (accessor from mixlib-cli) + # config_file_settings - Chef::Config[:knife] user settings from the client.rb file + # config - mixlib-cli settings (accessor from mixlib-cli) + # def merge_configs # Update our original_config - if someone has created a knife command # instance directly, they are likely ot have set cmd.config values directly @@ -375,7 +379,7 @@ class Chef @original_config = config.dup # other code may have a handle to the config object, so use Hash#replace to deliberately # update-in-place. - config.replace(default_config.merge(config_file_settings).merge(config)) + config.replace(config_file_defaults.merge(default_config).merge(config_file_settings).merge(config)) end # @@ -385,8 +389,9 @@ class Chef # @return [Symbol,NilClass] return the source of the config key, # one of: # - :cli - this was explicitly provided on the CLI - # - :config - this came from Chef::Config[:knife] + # - :config - this came from Chef::Config[:knife] explicitly being set # - :cli_default - came from a declared CLI `option`'s `default` value. + # - :config_default - this came from Chef::Config[:knife]'s defaults # - nil - if the key could not be found in any source. # This can happen when it is invalid, or has been # set directly into #config without then calling #merge_config @@ -394,6 +399,7 @@ class Chef return :cli if @original_config.include? key return :config if config_file_settings.key? key return :cli_default if default_config.include? key + return :config_default if config_file_defaults.key? key # must come after :config check nil end diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb index 3128dd4af9..bb6c5871c6 100644 --- a/lib/chef/knife/bootstrap.rb +++ b/lib/chef/knife/bootstrap.rb @@ -86,7 +86,6 @@ class Chef short: "-w AUTH-METHOD", long: "--winrm-auth-method AUTH-METHOD", description: "The WinRM authentication method to use.", - proc: Proc.new { |protocol| Chef::Config[:knife][:winrm_auth_method] = protocol }, in: WINRM_AUTH_PROTOCOL_LIST option :winrm_basic_auth_only, @@ -99,32 +98,27 @@ class Chef # option :kerberos_keytab_file, # :short => "-T KEYTAB_FILE", # :long => "--keytab-file KEYTAB_FILE", - # :description => "The Kerberos keytab file used for authentication", - # :proc => Proc.new { |keytab| Chef::Config[:knife][:kerberos_keytab_file] = keytab } + # :description => "The Kerberos keytab file used for authentication" option :kerberos_realm, short: "-R KERBEROS_REALM", long: "--kerberos-realm KERBEROS_REALM", - description: "The Kerberos realm used for authentication.", - proc: Proc.new { |protocol| Chef::Config[:knife][:kerberos_realm] = protocol } + description: "The Kerberos realm used for authentication." option :kerberos_service, short: "-S KERBEROS_SERVICE", long: "--kerberos-service KERBEROS_SERVICE", - description: "The Kerberos service used for authentication.", - proc: Proc.new { |protocol| Chef::Config[:knife][:kerberos_service] = protocol } + description: "The Kerberos service used for authentication." ## SSH Authentication option :ssh_gateway, short: "-G GATEWAY", long: "--ssh-gateway GATEWAY", - description: "The SSH gateway.", - proc: Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key } + description: "The SSH gateway." option :ssh_gateway_identity, long: "--ssh-gateway-identity SSH_GATEWAY_IDENTITY", - description: "The SSH identity file used for gateway authentication.", - proc: Proc.new { |key| Chef::Config[:knife][:ssh_gateway_identity] = key } + description: "The SSH identity file used for gateway authentication." option :ssh_forward_agent, short: "-A", @@ -140,7 +134,8 @@ class Chef option :ssh_verify_host_key, long: "--ssh-verify-host-key VALUE", description: "Verify host key. Default is 'always'.", - in: %w{always accept_new accept_new_or_local_tunnel never} + in: %w{always accept_new accept_new_or_local_tunnel never}, + default: "always" # # bootstrap options @@ -160,8 +155,7 @@ class Chef # client.rb content via chef-full/bootstrap_context option :bootstrap_proxy, long: "--bootstrap-proxy PROXY_URL", - description: "The proxy server for the node being bootstrapped.", - proc: Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p } + description: "The proxy server for the node being bootstrapped." # client.rb content via bootstrap_context option :bootstrap_proxy_user, @@ -176,8 +170,7 @@ class Chef # client.rb content via bootstrap_context option :bootstrap_no_proxy, long: "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]", - description: "Do not proxy locations for the node being bootstrapped", - proc: Proc.new { |np| Chef::Config[:knife][:bootstrap_no_proxy] = np } + description: "Do not proxy locations for the node being bootstrapped" # client.rb content via bootstrap_context option :bootstrap_template, @@ -270,21 +263,16 @@ class Chef proc: lambda { |o| Chef::JSONCompat.parse(File.read(o)) }, default: nil - # Note that several of the below options are used by bootstrap template, - # but only from the passed-in knife config; it does not use the - # config from the CLI for those values. We cannot always used the merged - # config, because in some cases the knife keys thIn those cases, the option - # will have a proc that assigns the value into Chef::Config[:knife] - # bootstrap template # Create ohai hints in /etc/chef/ohai/hints, fname=hintname, content=value - option :hint, + option :hints, long: "--hint HINT_NAME[=HINT_FILE]", description: "Specify an Ohai hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.", - proc: Proc.new { |h| - Chef::Config[:knife][:hints] ||= {} - name, path = h.split("=") - Chef::Config[:knife][:hints][name] = path ? Chef::JSONCompat.parse(::File.read(path)) : {} + proc: Proc.new { |hint, accumulator| + accumulator ||= {} + name, path = hint.split("=", 2) + accumulator[name] = path ? Chef::JSONCompat.parse(::File.read(path)) : {} + accumulator } # bootstrap override: url of a an installer shell script touse in place of omnitruck @@ -292,8 +280,7 @@ class Chef # the provided options to knife bootstrap, so we set the Chef::Config option here. option :bootstrap_url, long: "--bootstrap-url URL", - description: "URL to a custom installation script.", - proc: Proc.new { |u| Chef::Config[:knife][:bootstrap_url] = u } + description: "URL to a custom installation script." option :bootstrap_product, long: "--bootstrap-product PRODUCT", @@ -309,26 +296,22 @@ class Chef # bootstrap override: Do this instead of our own setup.sh from omnitruck. Causes bootstrap_url to be ignored. option :bootstrap_install_command, long: "--bootstrap-install-command COMMANDS", - description: "Custom command to install #{Chef::Dist::PRODUCT}.", - proc: Proc.new { |ic| Chef::Config[:knife][:bootstrap_install_command] = ic } + description: "Custom command to install #{Chef::Dist::PRODUCT}." # bootstrap template: Run this command first in the bootstrap script option :bootstrap_preinstall_command, long: "--bootstrap-preinstall-command COMMANDS", - description: "Custom commands to run before installing #{Chef::Dist::PRODUCT}.", - proc: Proc.new { |preic| Chef::Config[:knife][:bootstrap_preinstall_command] = preic } + description: "Custom commands to run before installing #{Chef::Dist::PRODUCT}." # bootstrap template option :bootstrap_wget_options, long: "--bootstrap-wget-options OPTIONS", - description: "Add options to wget when installing #{Chef::Dist::PRODUCT}.", - proc: Proc.new { |wo| Chef::Config[:knife][:bootstrap_wget_options] = wo } + description: "Add options to wget when installing #{Chef::Dist::PRODUCT}." # bootstrap template option :bootstrap_curl_options, long: "--bootstrap-curl-options OPTIONS", - description: "Add options to curl when install #{Chef::Dist::PRODUCT}.", - proc: Proc.new { |co| Chef::Config[:knife][:bootstrap_curl_options] = co } + description: "Add options to curl when install #{Chef::Dist::PRODUCT}." # chef_vault_handler option :bootstrap_vault_file, @@ -344,12 +327,12 @@ class Chef option :bootstrap_vault_item, long: "--bootstrap-vault-item VAULT_ITEM", description: 'A single vault and item to update as "vault:item".', - proc: Proc.new { |i| + proc: Proc.new { |i, accumulator| (vault, item) = i.split(/:/) - Chef::Config[:knife][:bootstrap_vault_item] ||= {} - Chef::Config[:knife][:bootstrap_vault_item][vault] ||= [] - Chef::Config[:knife][:bootstrap_vault_item][vault].push(item) - Chef::Config[:knife][:bootstrap_vault_item] + accumulator ||= {} + accumulator[vault] ||= [] + accumulator[vault].push(item) + accumulator } # Deprecated options. These must be declared after @@ -434,14 +417,14 @@ class Chef def client_builder @client_builder ||= Chef::Knife::Bootstrap::ClientBuilder.new( chef_config: Chef::Config, - knife_config: config, + config: config, ui: ui ) end def chef_vault_handler @chef_vault_handler ||= Chef::Knife::Bootstrap::ChefVaultHandler.new( - knife_config: config, + config: config, ui: ui ) end @@ -686,9 +669,8 @@ class Chef return @connection_protocol if @connection_protocol from_url = host_descriptor =~ %r{^(.*)://} ? $1 : nil - from_cli = config[:connection_protocol] - from_knife = Chef::Config[:knife][:connection_protocol] - @connection_protocol = from_url || from_cli || from_knife || "ssh" + from_knife = config[:connection_protocol] + @connection_protocol = from_url || from_knife || "ssh" end def do_connect(conn_options) @@ -724,6 +706,10 @@ class Chef true end + def winrm_auth_method + config_value(:winrm_auth_method, :winrm_authentication_protocol, "negotiate") + end + # Fail if using plaintext auth without ssl because # this can expose keys in plaintext on the wire. # TODO test for this method @@ -732,8 +718,8 @@ class Chef return true unless winrm? if Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])) - if config_value(:winrm_auth_method) == "plaintext" && - config_value(:winrm_ssl) != true + if winrm_auth_method == "plaintext" && + config[:winrm_ssl] != true ui.error <<~EOM Validatorless bootstrap over unsecure winrm channels could expose your key to network sniffing. @@ -857,9 +843,9 @@ class Chef # Reference: # https://github.com/chef/knife-windows/blob/92d151298142be4a4750c5b54bb264f8d5b81b8a/lib/chef/knife/winrm_knife_base.rb#L271-L273 # TODO Seems like we should also do a similar warning if ssh_verify_host == false - if config_value(:ca_trust_file).nil? && - config_value(:winrm_no_verify_cert) && - config_value(:winrm_ssl_peer_fingerprint).nil? + if config[:ca_trust_file].nil? && + config[:winrm_no_verify_cert] && + config[:winrm_ssl_peer_fingerprint].nil? ui.warn <<~WARN * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SSL validation of HTTPS requests for the WinRM transport is disabled. @@ -905,16 +891,13 @@ class Chef # Common configuration for all protocols def base_opts - port = config_value(:connection_port, - knife_key_for_protocol(connection_protocol, :port)) - user = config_value(:connection_user, - knife_key_for_protocol(connection_protocol, :user)) + port = config_for_protocol(:port) + user = config_for_protocol(:user) {}.tap do |opts| opts[:logger] = Chef::Log - # We do not store password in Chef::Config, so only use CLI `config` here opts[:password] = config[:connection_password] if config.key?(:connection_password) opts[:user] = user if user - opts[:max_wait_until_ready] = config_value(:max_wait).to_f unless config_value(:max_wait).nil? + opts[:max_wait_until_ready] = config[:max_wait].to_f unless config[:max_wait].nil? # TODO - when would we need to provide rdp_port vs port? Or are they not mutually exclusive? opts[:port] = port if port end @@ -922,7 +905,7 @@ class Chef def host_verify_opts if winrm? - { self_signed: config_value(:winrm_no_verify_cert) === true } + { self_signed: config[:winrm_no_verify_cert] === true } elsif ssh? # Fall back to the old knife config key name for back compat. { verify_host_key: config_value(:ssh_verify_host_key, :host_key_verify, "always") } @@ -936,7 +919,7 @@ class Chef return opts if winrm? opts[:non_interactive] = true # Prevent password prompts from underlying net/ssh - opts[:forward_agent] = (config_value(:ssh_forward_agent) === true) + opts[:forward_agent] = (config[:ssh_forward_agent] === true) opts[:connection_timeout] = session_timeout opts end @@ -945,7 +928,7 @@ class Chef opts = {} return opts if winrm? - identity_file = config_value(:ssh_identity_file) + identity_file = config[:ssh_identity_file] if identity_file opts[:key_files] = [identity_file] # We only set keys_only based on the explicit ssh_identity_file; @@ -965,7 +948,7 @@ class Chef opts[:keys_only] = false end - gateway_identity_file = config_value(:ssh_gateway) ? config_value(:ssh_gateway_identity) : nil + gateway_identity_file = config[:ssh_gateway] ? config[:ssh_gateway_identity] : nil unless gateway_identity_file.nil? opts[:key_files] << gateway_identity_file end @@ -975,8 +958,8 @@ class Chef def gateway_opts opts = {} - if config_value(:ssh_gateway) - split = config_value(:ssh_gateway).split("@", 2) + if config[:ssh_gateway] + split = config[:ssh_gateway].split("@", 2) if split.length == 1 gw_host = split[0] else @@ -1022,21 +1005,20 @@ class Chef def winrm_opts return {} unless winrm? - auth_method = config_value(:winrm_auth_method, :winrm_auth_method, "negotiate") opts = { - winrm_transport: auth_method, # winrm gem and train calls auth method 'transport' - winrm_basic_auth_only: config_value(:winrm_basic_auth_only) || false, - ssl: config_value(:winrm_ssl) === true, - ssl_peer_fingerprint: config_value(:winrm_ssl_peer_fingerprint), + winrm_transport: winrm_auth_method, # winrm gem and train calls auth method 'transport' + winrm_basic_auth_only: config[:winrm_basic_auth_only] || false, + ssl: config[:winrm_ssl] === true, + ssl_peer_fingerprint: config[:winrm_ssl_peer_fingerprint], } - if auth_method == "kerberos" - opts[:kerberos_service] = config_value(:kerberos_service) if config_value(:kerberos_service) - opts[:kerberos_realm] = config_value(:kerberos_realm) if config_value(:kerberos_service) + if winrm_auth_method == "kerberos" + opts[:kerberos_service] = config[:kerberos_service] if config[:kerberos_service] + opts[:kerberos_realm] = config[:kerberos_realm] if config[:kerberos_service] end - if config_value(:ca_trust_file) - opts[:ca_trust_path] = config_value(:ca_trust_file) + if config[:ca_trust_file] + opts[:ca_trust_path] = config[:ca_trust_file] end opts[:operation_timeout] = session_timeout @@ -1061,24 +1043,26 @@ class Chef } end - # Looks 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. + # This is for deprecating config options. The fallback_key can be used + # to pull an old knife config option out of the config file when the + # cli value has been renamed. This is different from the deprecated + # cli values, since these are for config options that have no corresponding + # cli value. # - # knife_config_key should be specified if the knife config lookup - # key is different from the CLI flag lookup key. + # DO NOT USE - this whole API is considered deprecated # - def config_value(key, knife_config_key = nil, default = nil) - if config.key? key + # @api deprecated + # + def config_value(key, fallback_key = nil, default = nil) + Chef.deprecated(:knife_bootstrap_apis, "Use of config_value without a fallback_key is deprecated. Knife plugin authors should access the config hash directly, which does correct merging of cli and config options.") if fallback_key.nil? + if config.key?(key) + # the first key is the primary key so we check the merged hash first config[key] + elsif config.key?(fallback_key) + # we get the old config option here (the deprecated cli option shouldn't exist) + config[fallback_key] else - lookup_key = knife_config_key || key - if Chef::Config[:knife].key?(lookup_key) || config.key?(lookup_key) - Chef::Config[:knife][lookup_key] || config[lookup_key] - else - default - end + default end end @@ -1099,6 +1083,8 @@ class Chef end end + private + # To avoid cluttering the CLI options, some flags (such as port and user) # are shared between protocols. However, there is still a need to allow the operator # to specify defaults separately, since they may not be the same values for different @@ -1107,11 +1093,20 @@ class Chef # These keys are available in Chef::Config, and are prefixed with the protocol name. # For example, :user CLI option will map to :winrm_user and :ssh_user Chef::Config keys, # based on the connection protocol in use. - def knife_key_for_protocol(protocol, option) - "#{connection_protocol}_#{option}".to_sym + + # @api private + def config_for_protocol(option) + if option == :port + config[:connection_port] || config[knife_key_for_protocol(option)] + else + config[:connection_user] || config[knife_key_for_protocol(option)] + end end - private + # @api private + def knife_key_for_protocol(option) + "#{connection_protocol}_#{option}".to_sym + end # True if policy_name and run_list are both given def policyfile_and_run_list_given? @@ -1134,7 +1129,7 @@ class Chef # session_timeout option has a default that may not arrive, particularly if # we're being invoked from a plugin that doesn't merge_config. def session_timeout - timeout = config_value(:session_timeout) + timeout = config[:session_timeout] return options[:session_timeout][:default] if timeout.nil? timeout.to_i diff --git a/lib/chef/knife/bootstrap/chef_vault_handler.rb b/lib/chef/knife/bootstrap/chef_vault_handler.rb index 7007e1403b..00f902d728 100644 --- a/lib/chef/knife/bootstrap/chef_vault_handler.rb +++ b/lib/chef/knife/bootstrap/chef_vault_handler.rb @@ -21,7 +21,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 @@ -29,11 +29,15 @@ 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: {}, knife_config: nil, ui: nil) + @config = config + unless knife_config.nil? + @config = knife_config + Chef.deprecated(:knife_bootstrap_apis, "The knife_config option to the Bootstrap::ClientBuilder object is deprecated and has been renamed to just 'config'") + end + @ui = ui end # Updates the chef vault items for the newly created client. @@ -85,17 +89,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 d557cc1feb..b2c07e8019 100644 --- a/lib/chef/knife/bootstrap/client_builder.rb +++ b/lib/chef/knife/bootstrap/client_builder.rb @@ -28,7 +28,7 @@ class Chef class ClientBuilder # @return [Hash] knife merged config, typically @config - attr_accessor :knife_config + attr_accessor :config # @return [Hash] chef config object attr_accessor :chef_config # @return [Chef::Knife::UI] ui object for output @@ -36,13 +36,17 @@ class Chef # @return [Chef::ApiClient] client saved on run attr_reader :client - # @param knife_config [Hash] Hash of knife config settings + # @param config [Hash] Hash of knife config settings # @param chef_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 - @ui = ui + def initialize(config: {}, knife_config: nil, chef_config: {}, ui: nil) + @config = config + unless knife_config.nil? + @config = knife_config + Chef.deprecated(:knife_bootstrap_apis, "The knife_config option to the Bootstrap::ClientBuilder object is deprecated and has been renamed to just 'config'") + end + @chef_config = chef_config + @ui = ui end # Main entry. Prompt the user to clean up any old client or node objects. Then create @@ -77,34 +81,34 @@ 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 @@ -154,7 +158,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 263203ca76..b4f75720ac 100644 --- a/lib/chef/knife/bootstrap/templates/chef-full.erb +++ b/lib/chef/knife/bootstrap/templates/chef-full.erb @@ -1,5 +1,5 @@ -<%= "https_proxy=\"#{knife_config[:bootstrap_proxy]}\" export https_proxy" if knife_config[:bootstrap_proxy] %> -<%= "no_proxy=\"#{knife_config[:bootstrap_no_proxy]}\" export no_proxy" if knife_config[:bootstrap_no_proxy] %> +<%= "https_proxy=\"#{@config[:bootstrap_proxy]}\" export https_proxy" if @config[:bootstrap_proxy] %> +<%= "no_proxy=\"#{@config[:bootstrap_no_proxy]}\" export no_proxy" if @config[:bootstrap_no_proxy] %> if test "x$TMPDIR" = "x"; then tmp="/tmp" @@ -37,7 +37,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 +57,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 +164,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::Dist::CLIENT %>; then echo "-----> Existing <%= Chef::Dist::PRODUCT %> installation detected" else @@ -214,10 +214,10 @@ mkdir -p <%= ChefConfig::Config.etc_chef_dir(false) %>/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 <%= ChefConfig::Config.etc_chef_dir(false) %>/ohai/hints -<% @chef_config[:knife][:hints].each do |name, hash| -%> +<% @config[:hints].each do |name, hash| -%> cat > <%= ChefConfig::Config.etc_chef_dir(false) %>/ohai/hints/<%= name %>.json <<'EOP' <%= Chef::JSONCompat.to_json(hash) %> EOP 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 b4da79e453..0b444e718c 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%"... @@ -92,10 +92,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" @@ -121,8 +121,8 @@ If !ERRORLEVEL!==0 ( :install @rem If user has provided the custom installation command, 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 the MSI installer @@ -244,12 +244,12 @@ echo Validation key written. <% end -%> <%# Generate Ohai Hints -%> -<% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> +<% unless @config[:hints].nil? || @config[:hints].empty? -%> @if NOT EXIST <%= bootstrap_directory %>\ohai\hints ( 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 85693d7bbd..7d99ea0d96 100644 --- a/lib/chef/knife/core/bootstrap_context.rb +++ b/lib/chef/knife/core/bootstrap_context.rb @@ -33,6 +33,8 @@ class Chef class BootstrapContext attr_accessor :client_pem + attr_accessor :config + attr_accessor :chef_config def initialize(config, run_list, chef_config, secret = nil) @config = config @@ -42,13 +44,13 @@ class Chef end def bootstrap_environment - @config[:environment] + config[:environment] 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 chef_config[:validation_key] && + File.exist?(File.expand_path(chef_config[:validation_key])) + IO.read(File.expand_path(chef_config[:validation_key])) else false end @@ -69,18 +71,18 @@ 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 !(chef_config[:config_log_location].class == IO ) && (chef_config[:config_log_location].nil? || chef_config[:config_log_location].to_s.empty?) "STDOUT" - elsif @chef_config[:config_log_location].equal?(:win_evt) + 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 chef_config[:config_log_location].equal?(:syslog) ":syslog" - elsif @chef_config[:config_log_location].equal?(STDOUT) + elsif chef_config[:config_log_location].equal?(STDOUT) "STDOUT" - elsif @chef_config[:config_log_location].equal?(STDERR) + elsif chef_config[:config_log_location].equal?(STDERR) "STDERR" - elsif @chef_config[:config_log_location] - %Q{"#{@chef_config[:config_log_location]}"} + elsif chef_config[:config_log_location] + %Q{"#{chef_config[:config_log_location]}"} else "STDOUT" end @@ -88,43 +90,43 @@ 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 "#{chef_config[:chef_server_url]}" + validation_client_name "#{chef_config[:validation_client_name]}" CONFIG - unless @chef_config[:chef_license].nil? - client_rb << "chef_license \"#{@chef_config[:chef_license]}\"\n" + unless chef_config[:chef_license].nil? + client_rb << "chef_license \"#{chef_config[:chef_license]}\"\n" end - unless @chef_config[:config_log_level].nil? || @chef_config[:config_log_level].empty? - client_rb << %Q{log_level :#{@chef_config[:config_log_level]}\n} + unless chef_config[:config_log_level].nil? || chef_config[:config_log_level].empty? + client_rb << %Q{log_level :#{chef_config[:config_log_level]}\n} end client_rb << "log_location #{get_log_location}\n" - 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 # 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 @@ -134,27 +136,27 @@ 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] - 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,16 +167,16 @@ class Chef client_rb << %Q{trusted_certs_dir "/etc/chef/trusted_certs"\n} end - if Chef::Config[:fips] + if chef_config[:fips] client_rb << "fips true\n" end - unless @chef_config[:file_cache_path].nil? - client_rb << "file_cache_path \"#{@chef_config[:file_cache_path]}\"\n" + unless chef_config[:file_cache_path].nil? + client_rb << "file_cache_path \"#{chef_config[:file_cache_path]}\"\n" end - unless @chef_config[:file_backup_path].nil? - client_rb << "file_backup_path \"#{@chef_config[:file_backup_path]}\"\n" + unless chef_config[:file_backup_path].nil? + client_rb << "file_backup_path \"#{chef_config[:file_backup_path]}\"\n" end client_rb @@ -182,32 +184,26 @@ class Chef 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::Dist::CLIENT}" + client_path = chef_config[:chef_client_path] || "#{Chef::Dist::CLIENT}" s = "#{client_path} -j /etc/chef/first-boot.json" - if @config[:verbosity] && @config[:verbosity] >= 3 + if config[:verbosity] && config[:verbosity] >= 3 s << " -l trace" - elsif @config[:verbosity] && @config[:verbosity] >= 2 + elsif config[:verbosity] && config[:verbosity] >= 2 s << " -l debug" end s << " -E #{bootstrap_environment}" unless bootstrap_environment.nil? - s << " --no-color" unless @config[:color] + s << " --no-color" unless config[:color] s end - # XXX: this reads values only out of the config file and is NOT merged with the CLI options, and it is most likely - # a bug to be using this accessor and we should be using config and not knife_config. - def knife_config - @chef_config.key?(:knife) ? @chef_config[:knife] : {} - end - # # Returns the version of Chef to install (as recognized by the Omnitruck API) # # @return [String] download version string def version_to_install - return @config[:bootstrap_version] if @config[:bootstrap_version] + return config[:bootstrap_version] if config[:bootstrap_version] - if @config[:channel] == "stable" + if config[:channel] == "stable" Chef::VERSION.split(".").first else "latest" @@ -215,15 +211,15 @@ class Chef end def first_boot - (@config[:first_boot_attributes] = Mash.new(@config[:first_boot_attributes]) || Mash.new).tap do |attributes| - if @config[:policy_name] && @config[:policy_group] - attributes[:policy_name] = @config[:policy_name] - attributes[:policy_group] = @config[:policy_group] + (config[:first_boot_attributes] = Mash.new(config[:first_boot_attributes]) || Mash.new).tap do |attributes| + if config[:policy_name] && config[:policy_group] + attributes[:policy_name] = config[:policy_name] + attributes[:policy_group] = config[:policy_group] else attributes[:run_list] = @run_list end attributes.delete(:run_list) if attributes[:policy_name] && !attributes[:policy_name].empty? - attributes.merge!(tags: @config[:tags]) if @config[:tags] && !@config[:tags].empty? + attributes.merge!(tags: config[:tags]) if config[:tags] && !config[:tags].empty? end end @@ -233,8 +229,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 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| content << "cat > /etc/chef/trusted_certs/#{File.basename(cert)} <<'EOP'\n" + IO.read(File.expand_path(cert)) + "\nEOP\n" end @@ -244,8 +240,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 chef_config[:client_d_dir] && File.exist?(chef_config[:client_d_dir]) + root = Pathname(chef_config[:client_d_dir]) root.find do |f| relative = f.relative_path_from(root) if f != root diff --git a/lib/chef/knife/core/generic_presenter.rb b/lib/chef/knife/core/generic_presenter.rb index 02d3a55595..bca5b5bfaf 100644 --- a/lib/chef/knife/core/generic_presenter.rb +++ b/lib/chef/knife/core/generic_presenter.rb @@ -37,9 +37,10 @@ class Chef short: "-a ATTR1 [-a ATTR2]", long: "--attribute ATTR1 [--attribute ATTR2] ", description: "Show one or more attributes", - proc: Proc.new { |a| - Chef::Config[:knife][:attribute] ||= [] - Chef::Config[:knife][:attribute].push(a) + proc: Proc.new { |arg, accumulator| + accumulator ||= [] + accumulator << arg + accumulator } end end diff --git a/lib/chef/knife/core/windows_bootstrap_context.rb b/lib/chef/knife/core/windows_bootstrap_context.rb index 5c4df857ae..e05409f6c4 100644 --- a/lib/chef/knife/core/windows_bootstrap_context.rb +++ b/lib/chef/knife/core/windows_bootstrap_context.rb @@ -30,6 +30,8 @@ class Chef # * @run_list - the run list for the node to boostrap # class WindowsBootstrapContext < BootstrapContext + attr_accessor :config + attr_accessor :chef_config def initialize(config, run_list, chef_config, secret = nil) @config = config @@ -40,15 +42,15 @@ class Chef 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(chef_config[:validation_key])) + IO.read(File.expand_path(chef_config[:validation_key])) else false end end def secret - escape_and_echo(@config[:secret]) + escape_and_echo(config[:secret]) end def trusted_certs_script @@ -57,25 +59,25 @@ 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 "#{chef_config[:chef_server_url]}" + validation_client_name "#{chef_config[:validation_client_name]}" file_cache_path "#{ChefConfig::Config.var_chef_dir(true)}/cache" file_backup_path "#{ChefConfig::Config.var_chef_dir(true)}/backup" cache_options ({:path => "#{ChefConfig::Config.etc_chef_dir(true)}/cache/checksums", :skip_expires => true}) CONFIG - unless @chef_config[:chef_license].nil? - client_rb << "chef_license \"#{@chef_config[:chef_license]}\"\n" + unless chef_config[:chef_license].nil? + client_rb << "chef_license \"#{chef_config[:chef_license]}\"\n" end - 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 chef_config[:config_log_level] + client_rb << %Q{log_level :#{chef_config[:config_log_level]}\n} else client_rb << "log_level :auto\n" end @@ -84,21 +86,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 @@ -108,22 +110,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 "#{ChefConfig::Config.etc_chef_dir(true)}/encrypted_data_bag_secret"\n} end @@ -131,7 +133,7 @@ class Chef client_rb << %Q{trusted_certs_dir "#{ChefConfig::Config.etc_chef_dir(true)}/trusted_certs"\n} end - if Chef::Config[:fips] + if chef_config[:fips] client_rb << "fips true\n" end @@ -139,18 +141,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 chef_config[:config_log_location].equal?(:win_evt) + %Q{:#{chef_config[:config_log_location]}\n} + elsif chef_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 chef_config[:config_log_location].equal?(STDOUT) "STDOUT\n" - elsif @chef_config[:config_log_location].equal?(STDERR) + elsif chef_config[:config_log_location].equal?(STDERR) "STDERR\n" - elsif @chef_config[:config_log_location].nil? || @chef_config[:config_log_location].empty? + elsif chef_config[:config_log_location].nil? || chef_config[:config_log_location].empty? "STDOUT\n" - elsif @chef_config[:config_log_location] - %Q{"#{@chef_config[:config_log_location]}"\n} + elsif chef_config[:config_log_location] + %Q{"#{chef_config[:config_log_location]}"\n} else "STDOUT\n" end @@ -270,15 +272,15 @@ class Chef # Build a URL to query www.chef.io that will redirect to the correct # Chef Infra msi download. def msi_url(machine_os = nil, machine_arch = nil, download_context = nil) - if @config[:msi_url].nil? || @config[:msi_url].empty? + if config[:msi_url].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 += "&channel=#{@config[:channel]}" + url += "&channel=#{config[:channel]}" url += "&v=#{version_to_install}" else - @config[:msi_url] + config[:msi_url] end end @@ -303,8 +305,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 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| content << "> #{bootstrap_directory}/trusted_certs/#{File.basename(cert)} (\n" + escape_and_echo(IO.read(File.expand_path(cert))) + "\n)\n" end @@ -314,8 +316,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 chef_config[:client_d_dir] && File.exist?(chef_config[:client_d_dir]) + root = Pathname(chef_config[:client_d_dir]) root.find do |f| relative = f.relative_path_from(root) if f != root diff --git a/lib/chef/knife/data_bag_secret_options.rb b/lib/chef/knife/data_bag_secret_options.rb index 213e02c376..8f9f96502f 100644 --- a/lib/chef/knife/data_bag_secret_options.rb +++ b/lib/chef/knife/data_bag_secret_options.rb @@ -34,17 +34,13 @@ class Chef # are provided. def self.included(base) - base.option :secret, + base.option :cl_secret, long: "--secret SECRET", - description: "The secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret'.", - # Need to store value from command line in separate variable - knife#merge_configs populates same keys - # on config object from - proc: Proc.new { |s| set_cl_secret(s) } + description: "The secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret'." - base.option :secret_file, + base.option :cl_secret_file, long: "--secret-file SECRET_FILE", - description: "A file containing the secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret_file'.", - proc: Proc.new { |sf| set_cl_secret_file(sf) } + description: "A file containing the secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret_file'." base.option :encrypt, long: "--encrypt", @@ -66,25 +62,25 @@ class Chef # IE, if we are not running 'knife data bag *' we don't need to load 'chef/encrypted_data_bag_item' require_relative "../encrypted_data_bag_item" - if has_cl_secret? - config[:secret] - elsif has_cl_secret_file? - Chef::EncryptedDataBagItem.load_secret(config[:secret_file]) - elsif secret = knife_config[:secret] + if config[:cl_secret] + config[:cl_secret] + elsif config[:cl_secret_file] + Chef::EncryptedDataBagItem.load_secret(config[:cl_secret_file]) + elsif secret = config[:secret] secret else - secret_file = knife_config[:secret_file] + secret_file = config[:secret_file] Chef::EncryptedDataBagItem.load_secret(secret_file) end end def validate_secrets - if has_cl_secret? && has_cl_secret_file? + if config[:cl_secret] && config[:cl_secret_file] ui.fatal("Please specify only one of --secret, --secret-file") exit(1) end - if knife_config[:secret] && knife_config[:secret_file] + if config[:secret] && config[:secret_file] ui.fatal("Please specify only one of 'secret' or 'secret_file' in your config file") exit(1) end @@ -98,41 +94,26 @@ class Chef def base_encryption_secret_provided?(need_encrypt_flag = true) validate_secrets - return true if has_cl_secret? || has_cl_secret_file? + return true if config[:cl_secret] || config[:cl_secret_file] if need_encrypt_flag if config[:encrypt] - unless knife_config[:secret] || knife_config[:secret_file] + unless config[:secret] || config[:secret_file] ui.fatal("No secret or secret_file specified in config, unable to encrypt item.") exit(1) end return true end return false - elsif knife_config[:secret] || knife_config[:secret_file] + elsif config[:secret] || config[:secret_file] # Certain situations (show and bootstrap) don't need a --encrypt flag to use the config file secret return true end false end - def has_cl_secret? - Chef::Config[:knife].key?(:cl_secret) - end - - def self.set_cl_secret(s) - Chef::Config[:knife][:cl_secret] = s - end - - def has_cl_secret_file? - Chef::Config[:knife].key?(:cl_secret_file) - end - - def self.set_cl_secret_file(sf) - Chef::Config[:knife][:cl_secret_file] = sf - end - def knife_config + Chef.deprecated(:knife_bootstrap_apis, "The `knife_config` bootstrap helper has been deprecated, use the properly merged `config` helper instead") Chef::Config.key?(:knife) ? Chef::Config[:knife] : {} end diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb index a959dc887d..837ba780f5 100644 --- a/lib/chef/knife/ssh.rb +++ b/lib/chef/knife/ssh.rb @@ -66,7 +66,7 @@ class Chef long: "--ssh-user USERNAME", description: "The ssh username." - option :ssh_password_ng, + option :ssh_password, short: "-P [PASSWORD]", long: "--ssh-password [PASSWORD]", description: "The ssh password - will prompt if flag is specified but no password is given.", @@ -79,20 +79,20 @@ class Chef short: "-p PORT", long: "--ssh-port PORT", description: "The ssh port.", - proc: Proc.new { |key| Chef::Config[:knife][:ssh_port] = key.strip } + proc: Proc.new { |key| key.strip } option :ssh_timeout, short: "-t SECONDS", long: "--ssh-timeout SECONDS", description: "The ssh connection timeout.", - proc: Proc.new { |key| Chef::Config[:knife][:ssh_timeout] = key.strip.to_i }, + proc: Proc.new { |key| key.strip.to_i }, default: 120 option :ssh_gateway, short: "-G GATEWAY", long: "--ssh-gateway GATEWAY", description: "The ssh gateway.", - proc: Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key.strip } + proc: Proc.new { |key| key.strip } option :ssh_gateway_identity, long: "--ssh-gateway-identity SSH_GATEWAY_IDENTITY", @@ -125,7 +125,7 @@ class Chef option :duplicated_fqdns, long: "--duplicated-fqdns", description: "Behavior if FQDNs are duplicated, ignored by default.", - proc: Proc.new { |key| Chef::Config[:knife][:duplicated_fqdns] = key.strip.to_sym }, + proc: Proc.new { |key| key.strip.to_sym }, default: :ignore option :tmux_split, @@ -149,7 +149,6 @@ class Chef end def configure_gateway - config[:ssh_gateway] ||= Chef::Config[:knife][:ssh_gateway] if config[:ssh_gateway] gw_host, gw_user = config[:ssh_gateway].split("@").reverse gw_host, gw_port = gw_host.split(":") @@ -273,7 +272,6 @@ class Chef def session_options(host, port, user = nil, gateway: false) ssh_config = Net::SSH.configuration_for(host, true) {}.tap do |opts| - # Chef::Config[:knife][:ssh_user] is parsed in #configure_user and written to config[:ssh_user] opts[:user] = user || config[:ssh_user] || ssh_config[:user] if !gateway && config[:ssh_identity_file] opts[:keys] = File.expand_path(config[:ssh_identity_file]) @@ -308,10 +306,8 @@ class Chef Chef::Log.debug("Adding #{host}") session_opts = session_options(host, ssh_port, gateway: false) # Handle port overrides for the main connection. - session_opts[:port] = Chef::Config[:knife][:ssh_port] if Chef::Config[:knife][:ssh_port] session_opts[:port] = config[:ssh_port] if config[:ssh_port] # Handle connection timeout - session_opts[:timeout] = Chef::Config[:knife][:ssh_timeout] if Chef::Config[:knife][:ssh_timeout] session_opts[:timeout] = config[:ssh_timeout] if config[:ssh_timeout] # Handle session prefix session_opts[:properties] = { prefix: prefix } @@ -547,7 +543,7 @@ class Chef end def get_stripped_unfrozen_value(value) - return nil if value.nil? + return nil unless value value.strip end @@ -557,37 +553,22 @@ class Chef Chef::Config[:knife][:ssh_user]) end - # This is a bit overly complicated because of the way we want knife ssh to work with -P causing a password prompt for - # the user, but we have to be conscious that this code gets included in knife bootstrap and knife * server create as - # well. We want to change the semantics so that the default is false and 'nil' means -P without an argument on the - # command line. But the other utilities expect nil to be the default and we can't prompt in that case. So we effectively - # use ssh_password_ng to determine if we're coming from knife ssh or from the other utilities. The other utilities can - # also be patched to use ssh_password_ng easily as long they follow the convention that the default is false. def configure_password - if config.key?(:ssh_password_ng) && config[:ssh_password_ng].nil? - # If the parameter is called on the command line with no value - # it will set :ssh_password_ng = nil - # This is where we want to trigger a prompt for password + if config.key?(:ssh_password) && config[:ssh_password].nil? + # if we have an actual nil that means someone called "--ssh-password" with no value, so we prompt for a password config[:ssh_password] = get_password else - # if ssh_password_ng is false then it has not been set at all, and we may be in knife ec2 and still - # using an old config[:ssh_password]. this is backwards compatibility. all knife cloud plugins should - # be updated to use ssh_password_ng with a default of false and ssh_password should be retired, (but - # we'll still need to use the ssh_password out of knife.rb if we find that). - ssh_password = config.key?(:ssh_password_ng) ? config[:ssh_password_ng] : config[:ssh_password] - # Otherwise, the password has either been specified on the command line, - # in knife.rb, or key based auth will be attempted - config[:ssh_password] = get_stripped_unfrozen_value(ssh_password || - Chef::Config[:knife][:ssh_password]) + # the false default of ssh_password results in a nil here + config[:ssh_password] = get_stripped_unfrozen_value(config[:ssh_password]) end end def configure_ssh_identity_file - config[:ssh_identity_file] = get_stripped_unfrozen_value(config[:ssh_identity_file] || Chef::Config[:knife][:ssh_identity_file]) + config[:ssh_identity_file] = get_stripped_unfrozen_value(config[:ssh_identity_file]) end def configure_ssh_gateway_identity - config[:ssh_gateway_identity] = get_stripped_unfrozen_value(config[:ssh_gateway_identity] || Chef::Config[:knife][:ssh_gateway_identity]) + config[:ssh_gateway_identity] = get_stripped_unfrozen_value(config[:ssh_gateway_identity]) end def run diff --git a/lib/chef/knife/status.rb b/lib/chef/knife/status.rb index f157c60b41..530cf791f7 100644 --- a/lib/chef/knife/status.rb +++ b/lib/chef/knife/status.rb @@ -85,7 +85,7 @@ class Chef end output(all_nodes.sort do |n1, n2| - if config[:sort_reverse] || Chef::Config[:knife][:sort_status_reverse] + if config[:sort_reverse] || config[:sort_status_reverse] (n2["ohai_time"] || 0) <=> (n1["ohai_time"] || 0) else (n1["ohai_time"] || 0) <=> (n2["ohai_time"] || 0) diff --git a/lib/chef/knife/supermarket_download.rb b/lib/chef/knife/supermarket_download.rb index 75dda0641e..5acd733b78 100644 --- a/lib/chef/knife/supermarket_download.rb +++ b/lib/chef/knife/supermarket_download.rb @@ -42,8 +42,7 @@ class Chef short: "-m SUPERMARKET_SITE", long: "--supermarket-site SUPERMARKET_SITE", description: "The URL of the Supermarket site.", - default: "https://supermarket.chef.io", - proc: Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket } + default: "https://supermarket.chef.io" def run if current_cookbook_deprecated? diff --git a/lib/chef/knife/supermarket_install.rb b/lib/chef/knife/supermarket_install.rb index 8813f3bf6e..55b32a1774 100644 --- a/lib/chef/knife/supermarket_install.rb +++ b/lib/chef/knife/supermarket_install.rb @@ -63,8 +63,7 @@ class Chef short: "-m SUPERMARKET_SITE", long: "--supermarket-site SUPERMARKET_SITE", description: "The URL of the Supermarket site.", - default: "https://supermarket.chef.io", - proc: Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket } + default: "https://supermarket.chef.io" attr_reader :cookbook_name attr_reader :vendor_path diff --git a/lib/chef/knife/supermarket_list.rb b/lib/chef/knife/supermarket_list.rb index 088f577457..7dca8d031b 100644 --- a/lib/chef/knife/supermarket_list.rb +++ b/lib/chef/knife/supermarket_list.rb @@ -34,8 +34,7 @@ class Chef short: "-m SUPERMARKET_SITE", long: "--supermarket-site SUPERMARKET_SITE", description: "The URL of the Supermarket site.", - default: "https://supermarket.chef.io", - proc: Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket } + default: "https://supermarket.chef.io" option :sort_by, long: "--sort-by SORT", diff --git a/lib/chef/knife/supermarket_search.rb b/lib/chef/knife/supermarket_search.rb index 227a0df456..57befaed35 100644 --- a/lib/chef/knife/supermarket_search.rb +++ b/lib/chef/knife/supermarket_search.rb @@ -28,8 +28,7 @@ class Chef short: "-m SUPERMARKET_SITE", long: "--supermarket-site SUPERMARKET_SITE", description: "The URL of the Supermarket site.", - default: "https://supermarket.chef.io", - proc: Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket } + default: "https://supermarket.chef.io" def run output(search_cookbook(name_args[0])) diff --git a/lib/chef/knife/supermarket_share.rb b/lib/chef/knife/supermarket_share.rb index 1082cd01d2..7d3523dfb8 100644 --- a/lib/chef/knife/supermarket_share.rb +++ b/lib/chef/knife/supermarket_share.rb @@ -51,8 +51,7 @@ class Chef short: "-m SUPERMARKET_SITE", long: "--supermarket-site SUPERMARKET_SITE", description: "The URL of the Supermarket site.", - default: "https://supermarket.chef.io", - proc: Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket } + default: "https://supermarket.chef.io" def run config[:cookbook_path] ||= Chef::Config[:cookbook_path] diff --git a/lib/chef/knife/supermarket_show.rb b/lib/chef/knife/supermarket_show.rb index 3db1f87fe7..7237cf0bc7 100644 --- a/lib/chef/knife/supermarket_show.rb +++ b/lib/chef/knife/supermarket_show.rb @@ -29,8 +29,7 @@ class Chef short: "-m SUPERMARKET_SITE", long: "--supermarket-site SUPERMARKET_SITE", description: "The URL of the Supermarket site.", - default: "https://supermarket.chef.io", - proc: Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket } + default: "https://supermarket.chef.io" def run output(format_for_display(get_cookbook_data)) diff --git a/lib/chef/knife/supermarket_unshare.rb b/lib/chef/knife/supermarket_unshare.rb index 1ae4d5108c..0904a70f57 100644 --- a/lib/chef/knife/supermarket_unshare.rb +++ b/lib/chef/knife/supermarket_unshare.rb @@ -33,8 +33,7 @@ class Chef short: "-m SUPERMARKET_SITE", long: "--supermarket-site SUPERMARKET_SITE", description: "The URL of the Supermarket site.", - default: "https://supermarket.chef.io", - proc: Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket } + default: "https://supermarket.chef.io" def run @cookbook_name = @name_args[0] |