summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan McLellan <btm@loftninjas.org>2019-05-06 12:42:28 -0400
committerGitHub <noreply@github.com>2019-05-06 12:42:28 -0400
commit4e9dddc3a7667c22a5f76217f2ea6195574cccba (patch)
treef090f616249128cf3a325c8d79b646a1775118c6
parent3f8efb05853364bcff846e9f98bb6fbf6773fe58 (diff)
parenta1c438aa2b15b310ecccd062ae714026f39d3f12 (diff)
downloadchef-4e9dddc3a7667c22a5f76217f2ea6195574cccba.tar.gz
Merge pull request #8442 from chef/mp/bootstrap/restore-prerelease
Restore bootstrap pre-release support
-rw-r--r--RELEASE_NOTES.md4
-rw-r--r--lib/chef/knife.rb25
-rw-r--r--lib/chef/knife/bootstrap.rb85
-rw-r--r--lib/chef/knife/bootstrap/templates/chef-full.erb4
-rw-r--r--lib/chef/knife/core/bootstrap_context.rb21
-rw-r--r--lib/chef/knife/core/windows_bootstrap_context.rb18
-rw-r--r--spec/unit/knife/bootstrap_spec.rb22
-rw-r--r--spec/unit/knife/core/bootstrap_context_spec.rb43
-rw-r--r--spec/unit/knife/core/windows_bootstrap_context_spec.rb25
-rw-r--r--spec/unit/knife_spec.rb21
10 files changed, 137 insertions, 131 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index b0913a2a2f..ea1871d677 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -114,10 +114,11 @@ Using removed options will cause the command to fail.
| --ssh-port | --connection-port | `knife[:ssh_port]` config setting remains available.
| --ssh-user | --connection-user | `knife[:ssh_user]` config setting remains available.
| --ssl-peer-fingerprint | --winrm-ssl-peer-fingerprint | |
+| --prerelease |--channel CHANNEL | This now allows you to specify the channel that Chef Infra Client gets installed from. Valid values are _stable_, current, and unstable. 'current' has the same effect as using the old --prerelease. |
| --winrm-authentication-protocol=PROTO | --winrm-auth-method=AUTH-METHOD | Valid values: plaintext, kerberos, ssl, _negotiate_|
| --winrm-password| --connection-password | |
| --winrm-port| --connection-port | `knife[:winrm_port]` config setting remains available.|
-| --winrm-ssl-verify-mode MODE | --winrm-no-verify-cert | [1] Mode is not accepted. When flag is present, SSL cert will not be verified. Same as original mode of 'verify_none'. |
+| --winrm-ssl-verify-mode MODE | --winrm-no-verify-cert | [1] Mode is not accepted. When flag is present, SSL cert will not be verified. Same as original mode of 'verify\_none'. |
| --winrm-transport TRANSPORT | --winrm-ssl | [1] Use this flag if the target host is accepts WinRM connections over SSL.
| --winrm-user | --connection-user | `knife[:winrm_user]` config setting remains available.|
@@ -131,7 +132,6 @@ Using removed options will cause the command to fail.
|--kerberos-keytab-file| This option existed but was not implemented.|
|--winrm-codepage| This was used under knife-windows because bootstrapping was performed over a `cmd` shell. It is now invoked from `powershell`, so this option is no longer used.|
|--winrm-shell|This option was ignored for bootstrap.|
-|--prerelease|Chef now releases all development builds to our current channel and does not perform pre-release gem releases.|
|--install-as-service|Installing Chef client as a service is not supported|
#### Usage Changes
diff --git a/lib/chef/knife.rb b/lib/chef/knife.rb
index da9c1ab1e9..4cd7cdb73c 100644
--- a/lib/chef/knife.rb
+++ b/lib/chef/knife.rb
@@ -344,13 +344,8 @@ class Chef
# Chef::Config[:knife] would break the defaults in the cli that we would otherwise
# overwrite.
def config_file_settings
- @key_sources = { cli: [], config: [] }
cli_keys.each_with_object({}) do |key, memo|
- if config.key?(key)
- @key_sources[:cli] << key
- end
if Chef::Config[:knife].key?(key)
- @key_sources[:config] << key
memo[key] = Chef::Config[:knife][key]
end
end
@@ -361,16 +356,28 @@ class Chef
# config_file_settings - Chef::Config[:knife] sub-hash
# config - mixlib-cli settings (accessor from the mixin)
def merge_configs
+ # This is the config after user CLI options have been evaluated, and it contains only
+ # user-supplied values.
+ @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))
end
- # Return where a config key has been sourced,
- # :cli, :config, or nil if the key is not set.
+ #
+ # Determine the source of a given configuration key
+ #
+ # @argument key [Symbol] a configuration key
+ # @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]
+ # - :cli_default - came from a declared CLI `option`'s `default` value.
+ # - nil - if they key does not exist
def config_source(key)
- return :cli if @key_sources[:cli].include? key
- return :config if @key_sources[:config].include? key
+ return :cli if @original_config.include? key
+ return :config if config_file_settings.key? key
+ return :cli_default if default_config.include? key
nil
end
diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb
index 69d9ffb8c0..5d76736e06 100644
--- a/lib/chef/knife/bootstrap.rb
+++ b/lib/chef/knife/bootstrap.rb
@@ -86,7 +86,8 @@ class Chef
short: "-w AUTH-METHOD",
long: "--winrm-auth-method AUTH-METHOD",
description: "The WinRM authentication method to use. Valid choices are #{friendly_opt_list(WINRM_AUTH_PROTOCOL_LIST)}.",
- proc: Proc.new { |protocol| Chef::Config[:knife][:winrm_auth_method] = protocol }
+ proc: Proc.new { |protocol| Chef::Config[:knife][:winrm_auth_method] = protocol },
+ in: WINRM_AUTH_PROTOCOL_LIST
option :winrm_basic_auth_only,
long: "--winrm-basic-auth-only",
@@ -156,6 +157,12 @@ class Chef
description: "The version of #{Chef::Dist::PRODUCT} to install.",
proc: lambda { |v| Chef::Config[:knife][:bootstrap_version] = v }
+ option :channel,
+ long: "--channel CHANNEL",
+ description: "Install from the given channel. Valid values are 'stable, 'current', and 'unstable'. Default is 'stable'",
+ default: "stable",
+ in: %w{stable current unstable}
+
# client.rb content via chef-full/bootstrap_context
option :bootstrap_proxy,
long: "--bootstrap-proxy PROXY_URL",
@@ -347,42 +354,45 @@ class Chef
DEPRECATED_FLAGS = {
# deprecated_key: [new_key, deprecated_long]
- auth_timeout: [:max_wait, "--max-wait SECONDS"],
- host_key_verify: [:ssh_verify_host_key,
- "--[no-]host-key-verify",
- ],
- ssh_user: [:connection_user,
- "--ssh-user USER",
- ],
- ssh_password: [:connection_password,
- "--ssh-password PASSWORD",
- ],
- ssh_port: [:connection_port,
- "-ssh-port",
- ],
- ssl_peer_fingerprint: [:winrm_ssl_peer_fingerprint,
- "--ssl-peer-fingerprint FINGERPRINT",
- ],
- winrm_user: [:connection_user,
- "--winrm-user USER",
- ],
- winrm_password: [:connection_password,
- "--winrm-password",
- ],
- winrm_port: [:connection_port,
- "--winrm-port",
- ],
- winrm_authentication_protocol: [:winrm_auth_method,
- "--winrm-authentication-protocol PROTOCOL",
- ],
+ # optional third element: replacement_value - if converting from bool
+ # (--bool-option) to valued flag (--new-option VALUE)
+ # this will be the value that is assigned the new flag when the old flag is used.
+ auth_timeout: [:max_wait, "--max-wait SECONDS" ],
+ host_key_verify:
+ [:ssh_verify_host_key, "--[no-]host-key-verify"],
+ prerelease:
+ [:channel, "--prerelease", "current"],
+ ssh_user:
+ [:connection_user, "--ssh-user USER"],
+ ssh_password:
+ [:connection_password, "--ssh-password PASSWORD"],
+ ssh_port:
+ [:connection_port, "-ssh-port" ],
+ ssl_peer_fingerprint:
+ [:winrm_ssl_peer_fingerprint, "--ssl-peer-fingerprint FINGERPRINT"],
+ winrm_user:
+ [:connection_user, "--winrm-user USER"],
+ winrm_password:
+ [:connection_password, "--winrm-password"],
+ winrm_port:
+ [:connection_port, "--winrm-port"],
+ winrm_authentication_protocol:
+ [:winrm_auth_method, "--winrm-authentication-protocol PROTOCOL"],
}.freeze
DEPRECATED_FLAGS.each do |deprecated_key, deprecation_entry|
- new_key, deprecated_long = deprecation_entry
+ new_key, deprecated_long, replacement_value = deprecation_entry
new_long = options[new_key][:long]
+ new_long_desc = if replacement_value.nil?
+ new_long
+ else
+ "#{new_long.split(" ").first} #{replacement_value}"
+ end
option(deprecated_key, long: deprecated_long,
- description: "#{deprecated_long} is deprecated. Use #{new_long} instead.",
- boolean: options[new_key][:boolean])
+ description: "This flag is deprecated. Please use '#{new_long_desc}' instead.",
+ boolean: options[new_key][:boolean] || !replacement_value.nil?,
+ # Put deprecated options at the end of the options list
+ on: :tail)
end
attr_accessor :client_builder
@@ -638,12 +648,13 @@ class Chef
end
# If any deprecated flags are used, let the user know and
- # update config[new-key] to the value given to the deprecated flag.
+ # update config[new-key] to the value given to the deprecated flag,
+ # or to the mapped value in case of changing flag type.
# If a deprecated flag and its corresponding replacement
- # are both used, raise an error.
+ # are both used, exit
def verify_deprecated_flags!
DEPRECATED_FLAGS.each do |deprecated_key, deprecation_entry|
- new_key, deprecated_long = deprecation_entry
+ new_key, deprecated_long, replacement_value = deprecation_entry
if config.key?(deprecated_key) && config_source(deprecated_key) == :cli
if config.key?(new_key) && config_source(new_key) == :cli
new_long = options[new_key][:long].split(" ").first
@@ -656,9 +667,9 @@ class Chef
EOM
exit 1
else
- config[new_key] = config[deprecated_key]
+ config[new_key] = replacement_value || config[deprecated_key]
unless Chef::Config[:silence_deprecation_warnings] == true
- ui.warn options[deprecated_key][:description]
+ ui.warn "You provided #{deprecated_long.split(" ").first}. #{options[deprecated_key][:description]}"
end
end
end
diff --git a/lib/chef/knife/bootstrap/templates/chef-full.erb b/lib/chef/knife/bootstrap/templates/chef-full.erb
index 58a64a23b8..54fa3a61d1 100644
--- a/lib/chef/knife/bootstrap/templates/chef-full.erb
+++ b/lib/chef/knife/bootstrap/templates/chef-full.erb
@@ -175,9 +175,9 @@ do_download() {
if test -f /usr/bin/<%= Chef::Dist::CLIENT %>}; then
echo "-----> Existing <%= Chef::Dist::PRODUCT %> installation detected"
else
- echo "-----> Installing Chef Omnibus (<%= latest_current_chef_version_string %>)"
+ echo "-----> Installing Chef Omnibus (<%= @config[:channel] %>/<%= version_to_install %>)"
do_download ${install_sh} $tmp_dir/install.sh
- sh $tmp_dir/install.sh -P chef <%= latest_current_chef_version_string %>
+ sh $tmp_dir/install.sh -P chef -c <%= @config[:channel] %> -v <%= version_to_install %>
fi
<% end %>
diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb
index dcca7b8a69..5a27836da8 100644
--- a/lib/chef/knife/core/bootstrap_context.rb
+++ b/lib/chef/knife/core/bootstrap_context.rb
@@ -187,16 +187,17 @@ class Chef
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
- def latest_current_chef_version_string
- chef_version_string = if knife_config[:bootstrap_version]
- knife_config[:bootstrap_version]
- else
- Chef::VERSION.split(".").first
- end
-
- "-v #{chef_version_string}"
+ # Returns the version of Chef to install (as recognized by the Omnitruck API)
+ #
+ # @return [String] download version string
+ def version_to_install
+ return knife_config[:bootstrap_version] if knife_config[:bootstrap_version]
+
+ if @config[:channel] == "stable"
+ Chef::VERSION.split(".").first
+ else
+ "latest"
+ end
end
def first_boot
diff --git a/lib/chef/knife/core/windows_bootstrap_context.rb b/lib/chef/knife/core/windows_bootstrap_context.rb
index 6054743106..109f8e6f37 100644
--- a/lib/chef/knife/core/windows_bootstrap_context.rb
+++ b/lib/chef/knife/core/windows_bootstrap_context.rb
@@ -158,16 +158,6 @@ class Chef
start_chef << "chef-client -c c:/chef/client.rb -j c:/chef/first-boot.json#{bootstrap_environment_option}\n"
end
- def latest_current_windows_chef_version_query
- chef_version_string = if knife_config[:bootstrap_version]
- knife_config[:bootstrap_version]
- else
- Chef::VERSION.split(".").first
- end
-
- "&v=#{chef_version_string}"
- end
-
def win_wget
# I tried my best to figure out how to properly url decode and switch / to \
# but this is VBScript - so I don't really care that badly.
@@ -273,16 +263,16 @@ class Chef
"%TEMP%\\#{Chef::Dist::CLIENT}-latest.msi"
end
+ # 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)
- # 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[: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 += latest_current_windows_chef_version_query
+ url += "&channel=#{@config[:channel]}"
+ url += "&v=#{version_to_install}"
else
@config[:msi_url]
end
diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb
index 995a2ef4c9..4261a3a166 100644
--- a/spec/unit/knife/bootstrap_spec.rb
+++ b/spec/unit/knife/bootstrap_spec.rb
@@ -1603,29 +1603,31 @@ describe Chef::Knife::Bootstrap do
end
context "when a deprecated CLI flag is given on the CLI" do
- before do
- knife.config[:ssh_user] = "sshuser"
- knife.merge_configs
- end
+ let(:bootstrap_cli_options) { %w{--ssh-user sshuser} }
it "maps the key value to the new key and points the human to the new flag" do
- expect(knife.ui).to receive(:warn).with(/--ssh-user USER is deprecated. Use --connection-user USERNAME instead./)
+ expect(knife.ui).to receive(:warn).with(/You provided --ssh-user. This flag is deprecated. Please use '--connection-user USERNAME' instead./)
knife.verify_deprecated_flags!
expect(knife.config[:connection_user]).to eq "sshuser"
end
end
context "when a deprecated CLI flag is given on the CLI, along with its replacement" do
- before do
- knife.config[:ssh_user] = "sshuser"
- knife.config[:connection_user] = "real-user"
- knife.merge_configs
- end
+ let(:bootstrap_cli_options) { %w{--connection-user a --ssh-user b} }
it "informs the human that both are provided and exits" do
expect(knife.ui).to receive(:error).with(/You provided both --connection-user and --ssh-user.*Please use.*/m)
expect { knife.verify_deprecated_flags! }.to raise_error SystemExit
end
end
+
+ context "when a deprecated boolean CLI flag is given on the CLI, and its non-boolean replacement is used" do
+ let(:bootstrap_cli_options) { %w{--prerelease} }
+ it "correctly maps the old boolean value to the new value" do
+ expect(knife.ui).to receive(:warn)
+ knife.verify_deprecated_flags!
+ expect(knife.config[:channel]).to eq "current"
+ end
+ end
end
describe "#register_client" do
diff --git a/spec/unit/knife/core/bootstrap_context_spec.rb b/spec/unit/knife/core/bootstrap_context_spec.rb
index 2ed8b6bc51..d57e254793 100644
--- a/spec/unit/knife/core/bootstrap_context_spec.rb
+++ b/spec/unit/knife/core/bootstrap_context_spec.rb
@@ -156,25 +156,6 @@ describe Chef::Knife::Core::BootstrapContext do
end
end
- describe "when a bootstrap_version is specified" do
- let(:chef_config) do
- {
- knife: { bootstrap_version: "11.12.4" },
- }
- end
-
- it "should send the full version to the installer" do
- expect(bootstrap_context.latest_current_chef_version_string).to eq("-v 11.12.4")
- end
- end
-
- describe "when a bootstrap_version is not specified" do
- it "should send the latest current to the installer" do
- # Intentionally hard coded in order not to replicate the logic.
- expect(bootstrap_context.latest_current_chef_version_string).to eq("-v #{Chef::VERSION.to_i}")
- end
- end
-
describe "ssl_verify_mode" do
it "isn't set in the config_content by default" do
expect(bootstrap_context.config_content).not_to include("ssl_verify_mode")
@@ -292,4 +273,28 @@ describe Chef::Knife::Core::BootstrapContext do
end
end
+
+ describe "#version_to_install" do
+ context "when bootstrap_version is provided" do
+ let(:chef_config) { { knife: { bootstrap_version: "awesome" } } }
+
+ it "returns bootstrap_version" do
+ expect(bootstrap_context.version_to_install).to eq "awesome"
+ end
+ end
+
+ context "when bootstrap_version is not provided" do
+ let(:config) { { channel: "stable" } }
+ it "returns the currently running major version out of Chef::VERSION" do
+ expect(bootstrap_context.version_to_install).to eq Chef::VERSION.split(".").first
+ end
+ end
+
+ context "and channel is other than stable" do
+ let(:config) { { channel: "unstable" } }
+ it "returns the version string 'latest'" do
+ expect(bootstrap_context.version_to_install).to eq "latest"
+ end
+ end
+ end
end
diff --git a/spec/unit/knife/core/windows_bootstrap_context_spec.rb b/spec/unit/knife/core/windows_bootstrap_context_spec.rb
index a19ad11247..7bc73c113a 100644
--- a/spec/unit/knife/core/windows_bootstrap_context_spec.rb
+++ b/spec/unit/knife/core/windows_bootstrap_context_spec.rb
@@ -176,29 +176,30 @@ describe Chef::Knife::Core::WindowsBootstrapContext do
end
end
- describe "latest_current_windows_chef_version_query" do
- it "returns the major version of the current version of Chef" do
- stub_const("Chef::VERSION", "15.1.2")
- expect(bootstrap_context.latest_current_windows_chef_version_query).to eq("&v=15")
- end
-
- end
-
describe "msi_url" do
- context "when config option is not set" do
+ context "when msi_url config option is not set" do
+ let(:config) { { channel: "stable" } }
before do
- expect(bootstrap_context).to receive(:latest_current_windows_chef_version_query).and_return("&v=something")
+ expect(bootstrap_context).to receive(:version_to_install).and_return("something")
end
it "returns a chef.io msi url with minimal url parameters" do
- reference_url = "https://www.chef.io/chef/download?p=windows&v=something"
+ reference_url = "https://www.chef.io/chef/download?p=windows&channel=stable&v=something"
expect(bootstrap_context.msi_url).to eq(reference_url)
end
it "returns a chef.io msi url with provided url parameters substituted" do
- reference_url = "https://www.chef.io/chef/download?p=windows&pv=machine&m=arch&DownloadContext=ctx&v=something"
+ reference_url = "https://www.chef.io/chef/download?p=windows&pv=machine&m=arch&DownloadContext=ctx&channel=stable&v=something"
expect(bootstrap_context.msi_url("machine", "arch", "ctx")).to eq(reference_url)
end
+
+ context "when a channel is provided in config" do
+ let(:config) { { channel: "current" } }
+ it "returns a chef.io msi url with the requested channel" do
+ reference_url = "https://www.chef.io/chef/download?p=windows&channel=current&v=something"
+ expect(bootstrap_context.msi_url).to eq(reference_url)
+ end
+ end
end
context "when msi_url config option is set" do
diff --git a/spec/unit/knife_spec.rb b/spec/unit/knife_spec.rb
index 7e05bec8f7..6fcb831531 100644
--- a/spec/unit/knife_spec.rb
+++ b/spec/unit/knife_spec.rb
@@ -299,37 +299,26 @@ describe Chef::Knife do
expect(Chef::Config[:log_level]).to eql(:warn)
end
- it "prefers the default value if no config or command line value is present and reports the source as default" do
+ it "prefers the default value from option definition if no config or command line value is present and reports the source as default" do
knife_command = KnifeSpecs::TestYourself.new([]) # empty argv
knife_command.configure_chef
expect(knife_command.config[:opt_with_default]).to eq("default-value")
+ expect(knife_command.config_source(:opt_with_default)).to eq(:cli_default)
end
- it "prefers a value in Chef::Config[:knife] to the default" do
+ it "prefers a value in Chef::Config[:knife] to the default and reports the source as config" do
Chef::Config[:knife][:opt_with_default] = "from-knife-config"
knife_command = KnifeSpecs::TestYourself.new([]) # empty argv
knife_command.configure_chef
expect(knife_command.config[:opt_with_default]).to eq("from-knife-config")
- expect(knife_command.config_source(:opt_with_default)).to eq (:config)
- end
-
- it "correctly reports Chef::Config as the source when a a config entry comes from there" do
- Chef::Config[:knife][:opt_with_default] = "from-knife-config"
- knife_command = KnifeSpecs::TestYourself.new([]) # empty argv
- knife_command.configure_chef
- expect(knife_command.config_source(:opt_with_default)).to eq (:config)
+ expect(knife_command.config_source(:opt_with_default)).to eq(:config)
end
it "prefers a value from command line over Chef::Config and the default and reports the source as CLI" do
knife_command = KnifeSpecs::TestYourself.new(["-D", "from-cli"])
knife_command.configure_chef
expect(knife_command.config[:opt_with_default]).to eq("from-cli")
- expect(knife_command.config_source(:opt_with_default)).to eq (:cli)
- end
- it "correctly reports CLI as the source when a config entry comes from the CLI" do
- knife_command = KnifeSpecs::TestYourself.new(["-D", "from-cli"])
- knife_command.configure_chef
- expect(knife_command.config_source(:opt_with_default)).to eq (:cli)
+ expect(knife_command.config_source(:opt_with_default)).to eq(:cli)
end
it "merges `listen` config to Chef::Config" do