summaryrefslogtreecommitdiff
path: root/lib/chef/knife
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chef/knife')
-rw-r--r--lib/chef/knife/bootstrap.rb54
-rw-r--r--lib/chef/knife/bootstrap/templates/chef-full.erb18
-rw-r--r--lib/chef/knife/client_delete.rb23
-rw-r--r--lib/chef/knife/client_key_create.rb3
-rw-r--r--lib/chef/knife/client_key_delete.rb1
-rw-r--r--lib/chef/knife/client_key_edit.rb1
-rw-r--r--lib/chef/knife/client_key_list.rb1
-rw-r--r--lib/chef/knife/client_key_show.rb1
-rw-r--r--lib/chef/knife/client_reregister.rb2
-rw-r--r--lib/chef/knife/configure.rb58
-rw-r--r--lib/chef/knife/configure_client.rb4
-rw-r--r--lib/chef/knife/cookbook_bulk_delete.rb2
-rw-r--r--lib/chef/knife/cookbook_create.rb431
-rw-r--r--lib/chef/knife/cookbook_download.rb11
-rw-r--r--lib/chef/knife/cookbook_metadata.rb6
-rw-r--r--lib/chef/knife/cookbook_show.rb24
-rw-r--r--lib/chef/knife/cookbook_site_download.rb18
-rw-r--r--lib/chef/knife/cookbook_site_install.rb26
-rw-r--r--lib/chef/knife/cookbook_site_list.rb9
-rw-r--r--lib/chef/knife/cookbook_site_search.rb9
-rw-r--r--lib/chef/knife/cookbook_site_share.rb37
-rw-r--r--lib/chef/knife/cookbook_site_show.rb17
-rw-r--r--lib/chef/knife/cookbook_site_unshare.rb9
-rw-r--r--lib/chef/knife/cookbook_test.rb6
-rw-r--r--lib/chef/knife/cookbook_upload.rb12
-rw-r--r--lib/chef/knife/core/bootstrap_context.rb62
-rw-r--r--lib/chef/knife/core/cookbook_scm_repo.rb6
-rw-r--r--lib/chef/knife/core/custom_manifest_loader.rb69
-rw-r--r--lib/chef/knife/core/gem_glob_loader.rb8
-rw-r--r--lib/chef/knife/core/generic_presenter.rb50
-rw-r--r--lib/chef/knife/core/status_presenter.rb39
-rw-r--r--lib/chef/knife/core/subcommand_loader.rb36
-rw-r--r--lib/chef/knife/core/ui.rb51
-rw-r--r--lib/chef/knife/data_bag_create.rb10
-rw-r--r--lib/chef/knife/data_bag_secret_options.rb4
-rw-r--r--lib/chef/knife/data_bag_show.rb2
-rw-r--r--lib/chef/knife/deps.rb66
-rw-r--r--lib/chef/knife/edit.rb4
-rw-r--r--lib/chef/knife/environment_compare.rb8
-rw-r--r--lib/chef/knife/exec.rb6
-rw-r--r--lib/chef/knife/help.rb101
-rw-r--r--lib/chef/knife/help_topics.rb4
-rw-r--r--lib/chef/knife/index_rebuild.rb133
-rw-r--r--lib/chef/knife/list.rb7
-rw-r--r--lib/chef/knife/node_delete.rb12
-rw-r--r--lib/chef/knife/node_policy_set.rb79
-rw-r--r--lib/chef/knife/node_run_list_add.rb2
-rw-r--r--lib/chef/knife/node_run_list_remove.rb2
-rw-r--r--lib/chef/knife/node_show.rb5
-rw-r--r--lib/chef/knife/osc_user_reregister.rb2
-rw-r--r--lib/chef/knife/osc_user_show.rb1
-rw-r--r--lib/chef/knife/role_env_run_list_add.rb2
-rw-r--r--lib/chef/knife/role_run_list_add.rb2
-rw-r--r--lib/chef/knife/search.rb37
-rw-r--r--lib/chef/knife/ssh.rb236
-rw-r--r--lib/chef/knife/ssl_check.rb11
-rw-r--r--lib/chef/knife/ssl_fetch.rb16
-rw-r--r--lib/chef/knife/status.rb4
-rw-r--r--lib/chef/knife/supermarket_download.rb33
-rw-r--r--lib/chef/knife/supermarket_install.rb (renamed from lib/chef/knife/cookbook_site_vendor.rb)35
-rw-r--r--lib/chef/knife/supermarket_list.rb33
-rw-r--r--lib/chef/knife/supermarket_search.rb33
-rw-r--r--lib/chef/knife/supermarket_share.rb33
-rw-r--r--lib/chef/knife/supermarket_show.rb33
-rw-r--r--lib/chef/knife/supermarket_unshare.rb33
-rw-r--r--lib/chef/knife/user_create.rb2
-rw-r--r--lib/chef/knife/user_delete.rb4
-rw-r--r--lib/chef/knife/user_edit.rb2
-rw-r--r--lib/chef/knife/user_key_create.rb1
-rw-r--r--lib/chef/knife/user_key_delete.rb1
-rw-r--r--lib/chef/knife/user_key_edit.rb1
-rw-r--r--lib/chef/knife/user_key_list.rb1
-rw-r--r--lib/chef/knife/user_key_show.rb1
-rw-r--r--lib/chef/knife/user_reregister.rb4
-rw-r--r--lib/chef/knife/user_show.rb2
-rw-r--r--lib/chef/knife/xargs.rb4
76 files changed, 879 insertions, 1237 deletions
diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb
index f5dc29371f..15d0f1be18 100644
--- a/lib/chef/knife/bootstrap.rb
+++ b/lib/chef/knife/bootstrap.rb
@@ -67,6 +67,11 @@ class Chef
:description => "The ssh gateway",
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key }
+ 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 }
+
option :forward_agent,
:short => "-A",
:long => "--forward-agent",
@@ -101,21 +106,19 @@ class Chef
:description => "The proxy server for the node being bootstrapped",
:proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p }
+ option :bootstrap_proxy_user,
+ :long => "--bootstrap-proxy-user PROXY_USER",
+ :description => "The proxy authentication username for the node being bootstrapped"
+
+ option :bootstrap_proxy_pass,
+ :long => "--bootstrap-proxy-pass PROXY_PASS",
+ :description => "The proxy authentication password for the node being bootstrapped"
+
option :bootstrap_no_proxy,
:long => "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]",
:description => "Do not proxy locations for the node being bootstrapped; this option is used internally by Opscode",
:proc => Proc.new { |np| Chef::Config[:knife][:bootstrap_no_proxy] = np }
- # DEPR: Remove this option in Chef 13
- option :distro,
- :short => "-d DISTRO",
- :long => "--distro DISTRO",
- :description => "Bootstrap a distro using a template. [DEPRECATED] Use -t / --bootstrap-template option instead.",
- :proc => Proc.new { |v|
- Chef::Log.warn("[DEPRECATED] -d / --distro option is deprecated. Use -t / --bootstrap-template option instead.")
- v
- }
-
option :bootstrap_template,
:short => "-t TEMPLATE",
:long => "--bootstrap-template TEMPLATE",
@@ -136,15 +139,6 @@ class Chef
:description => "Execute the bootstrap via sudo with password",
:boolean => false
- # DEPR: Remove this option in Chef 13
- option :template_file,
- :long => "--template-file TEMPLATE",
- :description => "Full path to location of template to use. [DEPRECATED] Use -t / --bootstrap-template option instead.",
- :proc => Proc.new { |v|
- Chef::Log.warn("[DEPRECATED] --template-file option is deprecated. Use -t / --bootstrap-template option instead.")
- v
- }
-
option :run_list,
:short => "-r RUN_LIST",
:long => "--run-list RUN_LIST",
@@ -206,6 +200,11 @@ class Chef
:description => "Custom command to install chef-client",
:proc => Proc.new { |ic| Chef::Config[:knife][:bootstrap_install_command] = ic }
+ option :bootstrap_preinstall_command,
+ :long => "--bootstrap-preinstall-command COMMANDS",
+ :description => "Custom commands to run before installing chef-client",
+ :proc => Proc.new { |preic| Chef::Config[:knife][:bootstrap_preinstall_command] = preic }
+
option :bootstrap_wget_options,
:long => "--bootstrap-wget-options OPTIONS",
:description => "Add options to wget when installing chef-client",
@@ -224,6 +223,7 @@ class Chef
unless valid_values.include?(v)
raise "Invalid value '#{v}' for --node-ssl-verify-mode. Valid values are: #{valid_values.join(", ")}"
end
+ v
}
option :node_verify_api_cert,
@@ -293,10 +293,9 @@ class Chef
end
def bootstrap_template
- # The order here is important. We want to check if we have the new Chef 12 option is set first.
- # Knife cloud plugins unfortunately all set a default option for the :distro so it should be at
- # the end.
- config[:bootstrap_template] || config[:template_file] || config[:distro] || default_bootstrap_template
+ # Allow passing a bootstrap template or use the default
+ # @return [String] The CLI specific bootstrap template or the default
+ config[:bootstrap_template] || default_bootstrap_template
end
def find_template
@@ -304,7 +303,7 @@ class Chef
# Use the template directly if it's a path to an actual file
if File.exists?(template)
- Chef::Log.debug("Using the specified bootstrap template: #{File.dirname(template)}")
+ Chef::Log.trace("Using the specified bootstrap template: #{File.dirname(template)}")
return template
end
@@ -317,7 +316,7 @@ class Chef
bootstrap_files.flatten!
template_file = Array(bootstrap_files).find do |bootstrap_template|
- Chef::Log.debug("Looking for bootstrap template in #{File.dirname(bootstrap_template)}")
+ Chef::Log.trace("Looking for bootstrap template in #{File.dirname(bootstrap_template)}")
File.exists?(bootstrap_template)
end
@@ -326,7 +325,7 @@ class Chef
raise Errno::ENOENT
end
- Chef::Log.debug("Found bootstrap template in #{File.dirname(template_file)}")
+ Chef::Log.trace("Found bootstrap template in #{File.dirname(template_file)}")
template_file
end
@@ -429,11 +428,12 @@ class Chef
ssh.config[:ssh_password] = config[:ssh_password]
ssh.config[:ssh_port] = config[:ssh_port]
ssh.config[:ssh_gateway] = config[:ssh_gateway]
+ ssh.config[:ssh_gateway_identity] = config[:ssh_gateway_identity]
ssh.config[:forward_agent] = config[:forward_agent]
ssh.config[:ssh_identity_file] = config[:ssh_identity_file] || config[:identity_file]
ssh.config[:manual] = true
ssh.config[:host_key_verify] = config[:host_key_verify]
- ssh.config[:on_error] = :raise
+ ssh.config[:on_error] = true
ssh
end
diff --git a/lib/chef/knife/bootstrap/templates/chef-full.erb b/lib/chef/knife/bootstrap/templates/chef-full.erb
index 6007ff9859..c80a3aa4ff 100644
--- a/lib/chef/knife/bootstrap/templates/chef-full.erb
+++ b/lib/chef/knife/bootstrap/templates/chef-full.erb
@@ -162,6 +162,12 @@ do_download() {
return 16
}
+<%# 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] %>
+<% end %>
+
<% if knife_config[:bootstrap_install_command] %>
<%= knife_config[:bootstrap_install_command] %>
<% else %>
@@ -182,21 +188,21 @@ fi
mkdir -p /etc/chef
<% if client_pem -%>
-cat > /etc/chef/client.pem <<EOP
+cat > /etc/chef/client.pem <<'EOP'
<%= ::File.read(::File.expand_path(client_pem)) %>
EOP
chmod 0600 /etc/chef/client.pem
<% end -%>
<% if validation_key -%>
-cat > /etc/chef/validation.pem <<EOP
+cat > /etc/chef/validation.pem <<'EOP'
<%= validation_key %>
EOP
chmod 0600 /etc/chef/validation.pem
<% end -%>
<% if encrypted_data_bag_secret -%>
-cat > /etc/chef/encrypted_data_bag_secret <<EOP
+cat > /etc/chef/encrypted_data_bag_secret <<'EOP'
<%= encrypted_data_bag_secret %>
EOP
chmod 0600 /etc/chef/encrypted_data_bag_secret
@@ -212,17 +218,17 @@ mkdir -p /etc/chef/trusted_certs
mkdir -p /etc/chef/ohai/hints
<% @chef_config[:knife][:hints].each do |name, hash| -%>
-cat > /etc/chef/ohai/hints/<%= name %>.json <<EOP
+cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP'
<%= Chef::JSONCompat.to_json(hash) %>
EOP
<% end -%>
<% end -%>
-cat > /etc/chef/client.rb <<EOP
+cat > /etc/chef/client.rb <<'EOP'
<%= config_content %>
EOP
-cat > /etc/chef/first-boot.json <<EOP
+cat > /etc/chef/first-boot.json <<'EOP'
<%= Chef::JSONCompat.to_json(first_boot) %>
EOP
diff --git a/lib/chef/knife/client_delete.rb b/lib/chef/knife/client_delete.rb
index e1b2365361..82b521c7d1 100644
--- a/lib/chef/knife/client_delete.rb
+++ b/lib/chef/knife/client_delete.rb
@@ -32,29 +32,32 @@ class Chef
:long => "--delete-validators",
:description => "Force deletion of client if it's a validator"
- banner "knife client delete CLIENT (options)"
+ banner "knife client delete [CLIENT [CLIENT]] (options)"
def run
- @client_name = @name_args[0]
-
- if @client_name.nil?
+ if @name_args.length == 0
show_usage
- ui.fatal("You must specify a client name")
+ ui.fatal("You must specify at least one client name")
exit 1
end
- delete_object(Chef::ApiClientV1, @client_name, "client") {
- object = Chef::ApiClientV1.load(@client_name)
+ @name_args.each do |client_name|
+ delete_client(client_name)
+ end
+ end
+
+ def delete_client(client_name)
+ delete_object(Chef::ApiClientV1, client_name, "client") do
+ object = Chef::ApiClientV1.load(client_name)
if object.validator
unless config[:delete_validators]
- ui.fatal("You must specify --delete-validators to delete the validator client #{@client_name}")
+ ui.fatal("You must specify --delete-validators to delete the validator client #{client_name}")
exit 2
end
end
object.destroy
- }
+ end
end
-
end
end
end
diff --git a/lib/chef/knife/client_key_create.rb b/lib/chef/knife/client_key_create.rb
index 68ad4d16d2..1f209ec879 100644
--- a/lib/chef/knife/client_key_create.rb
+++ b/lib/chef/knife/client_key_create.rb
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/knife/key_create"
require "chef/knife/key_create_base"
class Chef
@@ -30,6 +31,8 @@ class Chef
class ClientKeyCreate < Knife
include Chef::Knife::KeyCreateBase
+ banner "knife client key create CLIENT (options)"
+
attr_reader :actor
def initialize(argv = [])
diff --git a/lib/chef/knife/client_key_delete.rb b/lib/chef/knife/client_key_delete.rb
index 64eae2e27c..3463389a05 100644
--- a/lib/chef/knife/client_key_delete.rb
+++ b/lib/chef/knife/client_key_delete.rb
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/knife/key_delete"
class Chef
class Knife
diff --git a/lib/chef/knife/client_key_edit.rb b/lib/chef/knife/client_key_edit.rb
index 1dbd3c487b..1a685b7a56 100644
--- a/lib/chef/knife/client_key_edit.rb
+++ b/lib/chef/knife/client_key_edit.rb
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/knife/key_edit"
require "chef/knife/key_edit_base"
class Chef
diff --git a/lib/chef/knife/client_key_list.rb b/lib/chef/knife/client_key_list.rb
index 194ad42931..aa63c1196b 100644
--- a/lib/chef/knife/client_key_list.rb
+++ b/lib/chef/knife/client_key_list.rb
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/knife/key_list"
require "chef/knife/key_list_base"
class Chef
diff --git a/lib/chef/knife/client_key_show.rb b/lib/chef/knife/client_key_show.rb
index 77f9e96c5a..49bc9d3596 100644
--- a/lib/chef/knife/client_key_show.rb
+++ b/lib/chef/knife/client_key_show.rb
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/knife/key_show"
class Chef
class Knife
diff --git a/lib/chef/knife/client_reregister.rb b/lib/chef/knife/client_reregister.rb
index 5d9b2c0962..cc2b218e87 100644
--- a/lib/chef/knife/client_reregister.rb
+++ b/lib/chef/knife/client_reregister.rb
@@ -44,7 +44,7 @@ class Chef
end
client = Chef::ApiClientV1.reregister(@client_name)
- Chef::Log.debug("Updated client data: #{client.inspect}")
+ Chef::Log.trace("Updated client data: #{client.inspect}")
key = client.private_key
if config[:file]
File.open(config[:file], "w") do |f|
diff --git a/lib/chef/knife/configure.rb b/lib/chef/knife/configure.rb
index e726e32684..abde923788 100644
--- a/lib/chef/knife/configure.rb
+++ b/lib/chef/knife/configure.rb
@@ -1,6 +1,6 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
-# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/util/path_helper"
class Chef
class Knife
@@ -67,26 +68,22 @@ class Chef
end
def run
- ask_user_for_config_path
-
FileUtils.mkdir_p(chef_config_path)
+ config_file = File.join(chef_config_path, "credentials")
ask_user_for_config
- ::File.open(config[:config_file], "w") do |f|
+ config_file = File.expand_path(config_file)
+ if File.exist?(config_file)
+ confirm("Overwrite #{config_file}")
+ end
+ ::File.open(config_file, "w") do |f|
f.puts <<-EOH
-log_level :info
-log_location STDOUT
-node_name '#{new_client_name}'
-client_key '#{new_client_key}'
-validation_client_name '#{validation_client_name}'
-validation_key '#{validation_key}'
-chef_server_url '#{chef_server}'
-syntax_check_cache_path '#{File.join(chef_config_path, "syntax_check_cache")}'
+[default]
+client_name = '#{new_client_name}'
+client_key = '#{new_client_key}'
+chef_server_url = '#{chef_server}'
EOH
- unless chef_repo.empty?
- f.puts "cookbook_path [ '#{chef_repo}/cookbooks' ]"
- end
end
if config[:initial]
@@ -111,29 +108,14 @@ EOH
ui.msg("Before running commands with Knife")
ui.msg("")
ui.msg("*****")
- ui.msg("")
- ui.msg("You must place your validation key in:")
- ui.msg(" #{validation_key}")
- ui.msg("Before generating instance data with Knife")
- ui.msg("")
- ui.msg("*****")
end
ui.msg("Configuration file written to #{config[:config_file]}")
end
- def ask_user_for_config_path
- config[:config_file] ||= ask_question("Where should I put the config file? ", :default => "#{Chef::Config[:user_home]}/.chef/knife.rb")
- # have to use expand path to expand the tilde character to the user's home
- config[:config_file] = File.expand_path(config[:config_file])
- if File.exists?(config[:config_file])
- confirm("Overwrite #{config[:config_file]}")
- end
- end
-
def ask_user_for_config
server_name = guess_servername
- @chef_server = config[:chef_server_url] || ask_question("Please enter the chef server URL: ", :default => "https://#{server_name}:443")
+ @chef_server = config[:chef_server_url] || ask_question("Please enter the chef server URL: ", :default => "https://#{server_name}/organizations/myorg")
if config[:initial]
@new_client_name = config[:node_name] || ask_question("Please enter a name for the new user: ", :default => Etc.getlogin)
@admin_client_name = config[:admin_client_name] || ask_question("Please enter the existing admin name: ", :default => "admin")
@@ -142,10 +124,6 @@ EOH
else
@new_client_name = config[:node_name] || ask_question("Please enter an existing username or clientname for the API: ", :default => Etc.getlogin)
end
- @validation_client_name = config[:validation_client_name] || ask_question("Please enter the validation clientname: ", :default => "chef-validator")
- @validation_key = config[:validation_key] || ask_question("Please enter the location of the validation key: ", :default => "/etc/chef-server/chef-validator.pem")
- @validation_key = File.expand_path(@validation_key)
- @chef_repo = config[:repository] || ask_question("Please enter the path to a chef repository (or leave blank): ")
@new_client_key = config[:client_key] || File.join(chef_config_path, "#{@new_client_name}.pem")
@new_client_key = File.expand_path(@new_client_key)
@@ -153,18 +131,12 @@ EOH
def guess_servername
o = Ohai::System.new
- o.load_plugins
- o.require_plugin "os"
- o.require_plugin "hostname"
+ o.all_plugins(%w{ os hostname fqdn })
o[:fqdn] || o[:machinename] || o[:hostname] || "localhost"
end
- def config_file
- config[:config_file]
- end
-
def chef_config_path
- File.dirname(config_file)
+ Chef::Util::PathHelper.home(".chef")
end
end
end
diff --git a/lib/chef/knife/configure_client.rb b/lib/chef/knife/configure_client.rb
index 7d0b3d260d..c015687ac7 100644
--- a/lib/chef/knife/configure_client.rb
+++ b/lib/chef/knife/configure_client.rb
@@ -1,6 +1,6 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
-# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,8 +34,6 @@ class Chef
FileUtils.mkdir_p(@config_dir)
ui.info("Writing client.rb")
File.open(File.join(@config_dir, "client.rb"), "w") do |file|
- file.puts("log_level :info")
- file.puts("log_location STDOUT")
file.puts("chef_server_url '#{Chef::Config[:chef_server_url]}'")
file.puts("validation_client_name '#{Chef::Config[:validation_client_name]}'")
end
diff --git a/lib/chef/knife/cookbook_bulk_delete.rb b/lib/chef/knife/cookbook_bulk_delete.rb
index bd1c8a22cc..cdd1584e36 100644
--- a/lib/chef/knife/cookbook_bulk_delete.rb
+++ b/lib/chef/knife/cookbook_bulk_delete.rb
@@ -42,7 +42,7 @@ class Chef
all_cookbooks = Chef::CookbookVersion.list
cookbooks_names = all_cookbooks.keys.grep(regex)
- cookbooks_to_delete = cookbooks_names.inject({}) { |hash, name| hash[name] = all_cookbooks[name];hash }
+ cookbooks_to_delete = cookbooks_names.inject({}) { |hash, name| hash[name] = all_cookbooks[name]; hash }
ui.msg "All versions of the following cookbooks will be deleted:"
ui.msg ""
ui.msg ui.list(cookbooks_to_delete.keys.sort, :columns_down)
diff --git a/lib/chef/knife/cookbook_create.rb b/lib/chef/knife/cookbook_create.rb
index 950de380f8..6122fd52d3 100644
--- a/lib/chef/knife/cookbook_create.rb
+++ b/lib/chef/knife/cookbook_create.rb
@@ -21,438 +21,9 @@ require "chef/knife"
class Chef
class Knife
class CookbookCreate < Knife
-
- deps do
- require "chef/json_compat"
- require "uri"
- require "fileutils"
- end
-
- banner "knife cookbook create COOKBOOK (options)"
-
- option :cookbook_path,
- :short => "-o PATH",
- :long => "--cookbook-path PATH",
- :description => "The directory where the cookbook will be created"
-
- option :readme_format,
- :short => "-r FORMAT",
- :long => "--readme-format FORMAT",
- :description => "Format of the README file, supported formats are 'md' (markdown) and 'rdoc' (rdoc)"
-
- option :cookbook_license,
- :short => "-I LICENSE",
- :long => "--license LICENSE",
- :description => "License for cookbook, apachev2, gplv2, gplv3, mit or none"
-
- option :cookbook_copyright,
- :short => "-C COPYRIGHT",
- :long => "--copyright COPYRIGHT",
- :description => "Name of copyright holder"
-
- option :cookbook_email,
- :short => "-m EMAIL",
- :long => "--email EMAIL",
- :description => "Email address of cookbook maintainer"
-
def run
- self.config = Chef::Config.merge!(config)
- if @name_args.length < 1
- show_usage
- ui.fatal("You must specify a cookbook name")
- exit 1
- end
-
- if default_cookbook_path_empty? && parameter_empty?(config[:cookbook_path])
- raise ArgumentError, "Default cookbook_path is not specified in the knife.rb config file, and a value to -o is not provided. Nowhere to write the new cookbook to."
- end
-
- cookbook_path = File.expand_path(Array(config[:cookbook_path]).first)
- cookbook_name = @name_args.first
- copyright = config[:cookbook_copyright] || "YOUR_COMPANY_NAME"
- email = config[:cookbook_email] || "YOUR_EMAIL"
- license = ((config[:cookbook_license] != "false") && config[:cookbook_license]) || "none"
- readme_format = ((config[:readme_format] != "false") && config[:readme_format]) || "md"
- create_cookbook(cookbook_path, cookbook_name, copyright, license)
- create_readme(cookbook_path, cookbook_name, readme_format)
- create_changelog(cookbook_path, cookbook_name)
- create_metadata(cookbook_path, cookbook_name, copyright, email, license, readme_format)
- end
-
- def create_cookbook(dir, cookbook_name, copyright, license)
- msg("** Creating cookbook #{cookbook_name} in #{dir}")
- FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "attributes")}"
- FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "recipes")}"
- FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "definitions")}"
- FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "libraries")}"
- FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "resources")}"
- FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "providers")}"
- FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "files", "default")}"
- FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "templates", "default")}"
- unless File.exists?(File.join(dir, cookbook_name, "recipes", "default.rb"))
- open(File.join(dir, cookbook_name, "recipes", "default.rb"), "w") do |file|
- file.puts <<-EOH
-#
-# Cookbook Name:: #{cookbook_name}
-# Recipe:: default
-#
-# Copyright #{Time.now.year}, #{copyright}
-#
-EOH
- case license
- when "apachev2"
- file.puts <<-EOH
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-EOH
- when "gplv2"
- file.puts <<-EOH
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-EOH
- when "gplv3"
- file.puts <<-EOH
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-EOH
- when "mit"
- file.puts <<-EOH
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-EOH
- when "none"
- file.puts <<-EOH
-# All rights reserved - Do Not Redistribute
-#
-EOH
- end
- end
- end
- end
-
- def create_changelog(dir, cookbook_name)
- msg("** Creating CHANGELOG for cookbook: #{cookbook_name}")
- unless File.exists?(File.join(dir, cookbook_name, "CHANGELOG.md"))
- open(File.join(dir, cookbook_name, "CHANGELOG.md"), "w") do |file|
- file.puts <<-EOH
-# #{cookbook_name} CHANGELOG
-
-This file is used to list changes made in each version of the #{cookbook_name} cookbook.
-
-## 0.1.0
-- [your_name] - Initial release of #{cookbook_name}
-
-- - -
-Check the [Markdown Syntax Guide](http://daringfireball.net/projects/markdown/syntax) for help with Markdown.
-
-The [Github Flavored Markdown page](http://github.github.com/github-flavored-markdown/) describes the differences between markdown on github and standard markdown.
-EOH
- end
- end
+ Chef::Log.fatal("knife cookbook create has been removed. Please use `chef generate cookbook` from the ChefDK")
end
-
- def create_readme(dir, cookbook_name, readme_format)
- msg("** Creating README for cookbook: #{cookbook_name}")
- unless File.exist?(File.join(dir, cookbook_name, "README.#{readme_format}"))
- open(File.join(dir, cookbook_name, "README.#{readme_format}"), "w") do |file|
- case readme_format
- when "rdoc"
- file.puts <<-EOH
-= #{cookbook_name} Cookbook
-TODO: Enter the cookbook description here.
-
-e.g.
-This cookbook makes your favorite breakfast sandwich.
-
-== Requirements
-TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc.
-
-e.g.
-==== packages
-- +toaster+ - #{cookbook_name} needs toaster to brown your bagel.
-
-== Attributes
-TODO: List your cookbook attributes here.
-
-e.g.
-==== #{cookbook_name}::default
-<table>
- <tr>
- <th>Key</th>
- <th>Type</th>
- <th>Description</th>
- <th>Default</th>
- </tr>
- <tr>
- <td><tt>['#{cookbook_name}']['bacon']</tt></td>
- <td>Boolean</td>
- <td>whether to include bacon</td>
- <td><tt>true</tt></td>
- </tr>
-</table>
-
-== Usage
-==== #{cookbook_name}::default
-TODO: Write usage instructions for each cookbook.
-
-e.g.
-Just include +#{cookbook_name}+ in your node's +run_list+:
-
- {
- "name":"my_node",
- "run_list": [
- "recipe[#{cookbook_name}]"
- ]
- }
-
-== Contributing
-TODO: (optional) If this is a public cookbook, detail the process for contributing. If this is a private cookbook, remove this section.
-
-e.g.
-1. Fork the repository on Github
-2. Create a named feature branch (like `add_component_x`)
-3. Write your change
-4. Write tests for your change (if applicable)
-5. Run the tests, ensuring they all pass
-6. Submit a Pull Request using Github
-
-== License and Authors
-Authors: TODO: List authors
-EOH
- when "md", "mkd", "txt"
- file.puts <<-EOH
-# #{cookbook_name} Cookbook
-
-TODO: Enter the cookbook description here.
-
-e.g.
-This cookbook makes your favorite breakfast sandwich.
-
-## Requirements
-
-TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc.
-
-e.g.
-### Platforms
-
-- SandwichOS
-
-### Chef
-
-- Chef 12.0 or later
-
-### Cookbooks
-
-- `toaster` - #{cookbook_name} needs toaster to brown your bagel.
-
-## Attributes
-
-TODO: List your cookbook attributes here.
-
-e.g.
-### #{cookbook_name}::default
-
-<table>
- <tr>
- <th>Key</th>
- <th>Type</th>
- <th>Description</th>
- <th>Default</th>
- </tr>
- <tr>
- <td><tt>['#{cookbook_name}']['bacon']</tt></td>
- <td>Boolean</td>
- <td>whether to include bacon</td>
- <td><tt>true</tt></td>
- </tr>
-</table>
-
-## Usage
-
-### #{cookbook_name}::default
-
-TODO: Write usage instructions for each cookbook.
-
-e.g.
-Just include `#{cookbook_name}` in your node's `run_list`:
-
-```json
-{
- "name":"my_node",
- "run_list": [
- "recipe[#{cookbook_name}]"
- ]
-}
-```
-
-## Contributing
-
-TODO: (optional) If this is a public cookbook, detail the process for contributing. If this is a private cookbook, remove this section.
-
-e.g.
-1. Fork the repository on Github
-2. Create a named feature branch (like `add_component_x`)
-3. Write your change
-4. Write tests for your change (if applicable)
-5. Run the tests, ensuring they all pass
-6. Submit a Pull Request using Github
-
-## License and Authors
-
-Authors: TODO: List authors
-
-EOH
- else
- file.puts <<-EOH
-#{cookbook_name} Cookbook
-#{'=' * "#{cookbook_name} Cookbook".length}
- TODO: Enter the cookbook description here.
-
- e.g.
- This cookbook makes your favorite breakfast sandwich.
-
-Requirements
- TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc.
-
- e.g.
- toaster #{cookbook_name} needs toaster to brown your bagel.
-
-Attributes
- TODO: List your cookbook attributes here.
-
- #{cookbook_name}
- Key Type Description Default
- ['#{cookbook_name}']['bacon'] Boolean whether to include bacon true
-
-Usage
- #{cookbook_name}
- TODO: Write usage instructions for each cookbook.
-
- e.g.
- Just include `#{cookbook_name}` in your node's `run_list`:
-
- [code]
- {
- "name":"my_node",
- "run_list": [
- "recipe[#{cookbook_name}]"
- ]
- }
- [/code]
-
-Contributing
- TODO: (optional) If this is a public cookbook, detail the process for contributing. If this is a private cookbook, remove this section.
-
- e.g.
- 1. Fork the repository on Github
- 2. Create a named feature branch (like `add_component_x`)
- 3. Write your change
- 4. Write tests for your change (if applicable)
- 5. Run the tests, ensuring they all pass
- 6. Submit a Pull Request using Github
-
-License and Authors
- Authors: TODO: List authors
-EOH
- end
- end
- end
- end
-
- def create_metadata(dir, cookbook_name, copyright, email, license, readme_format)
- msg("** Creating metadata for cookbook: #{cookbook_name}")
-
- license_name = case license
- when "apachev2"
- "Apache 2.0"
- when "gplv2"
- "GNU Public License 2.0"
- when "gplv3"
- "GNU Public License 3.0"
- when "mit"
- "MIT"
- when "none"
- "All rights reserved"
- end
-
- unless File.exist?(File.join(dir, cookbook_name, "metadata.rb"))
- open(File.join(dir, cookbook_name, "metadata.rb"), "w") do |file|
- if File.exist?(File.join(dir, cookbook_name, "README.#{readme_format}"))
- long_description = "long_description IO.read(File.join(File.dirname(__FILE__), 'README.#{readme_format}'))"
- end
- file.puts <<-EOH
-name '#{cookbook_name}'
-maintainer '#{copyright}'
-maintainer_email '#{email}'
-license '#{license_name}'
-description 'Installs/Configures #{cookbook_name}'
-#{long_description}
-version '0.1.0'
-EOH
- end
- end
- end
-
- private
-
- def default_cookbook_path_empty?
- Chef::Config[:cookbook_path].nil? || Chef::Config[:cookbook_path].empty?
- end
-
- def parameter_empty?(parameter)
- parameter.nil? || parameter.empty?
- end
-
end
end
end
diff --git a/lib/chef/knife/cookbook_download.rb b/lib/chef/knife/cookbook_download.rb
index 741f444093..77e7aa0d09 100644
--- a/lib/chef/knife/cookbook_download.rb
+++ b/lib/chef/knife/cookbook_download.rb
@@ -70,12 +70,12 @@ class Chef
ui.info("Downloading #{@cookbook_name} cookbook version #{@version}")
cookbook = Chef::CookbookVersion.load(@cookbook_name, @version)
- manifest = cookbook.manifest
+ manifest = cookbook.cookbook_manifest
basedir = File.join(config[:download_directory], "#{@cookbook_name}-#{cookbook.version}")
if File.exists?(basedir)
if config[:force]
- Chef::Log.debug("Deleting #{basedir}")
+ Chef::Log.trace("Deleting #{basedir}")
FileUtils.rm_rf(basedir)
else
ui.fatal("Directory #{basedir} exists, use --force to overwrite")
@@ -83,12 +83,11 @@ class Chef
end
end
- Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
- next unless manifest.has_key?(segment)
+ manifest.by_parent_directory.each do |segment, files|
ui.info("Downloading #{segment}")
- manifest[segment].each do |segment_file|
+ files.each do |segment_file|
dest = File.join(basedir, segment_file["path"].gsub("/", File::SEPARATOR))
- Chef::Log.debug("Downloading #{segment_file['path']} to #{dest}")
+ Chef::Log.trace("Downloading #{segment_file['path']} to #{dest}")
FileUtils.mkdir_p(File.dirname(dest))
tempfile = rest.streaming_request(segment_file["url"])
FileUtils.mv(tempfile.path, dest)
diff --git a/lib/chef/knife/cookbook_metadata.rb b/lib/chef/knife/cookbook_metadata.rb
index 29eba6a36a..6f8f6db996 100644
--- a/lib/chef/knife/cookbook_metadata.rb
+++ b/lib/chef/knife/cookbook_metadata.rb
@@ -1,7 +1,7 @@
#
#
# Author:: Adam Jacob (<adam@chef.io>)
-# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -47,7 +47,7 @@ class Chef
if config[:all]
cl = Chef::CookbookLoader.new(config[:cookbook_path])
cl.load_cookbooks
- cl.each do |cname, cookbook|
+ cl.each_key do |cname|
generate_metadata(cname.to_s)
end
else
@@ -80,7 +80,7 @@ class Chef
File.open(json_file, "w") do |f|
f.write(Chef::JSONCompat.to_json_pretty(md))
end
- Chef::Log.debug("Generated #{json_file}")
+ Chef::Log.trace("Generated #{json_file}")
rescue Exceptions::ObsoleteDependencySyntax, Exceptions::InvalidVersionConstraint => e
ui.stderr.puts "ERROR: The cookbook '#{cookbook}' contains invalid or obsolete metadata syntax."
ui.stderr.puts "in #{file}:"
diff --git a/lib/chef/knife/cookbook_show.rb b/lib/chef/knife/cookbook_show.rb
index 5fab7c303f..1d9983632d 100644
--- a/lib/chef/knife/cookbook_show.rb
+++ b/lib/chef/knife/cookbook_show.rb
@@ -51,6 +51,10 @@ class Chef
:description => "Show corresponding URIs"
def run
+ cookbook_name, cookbook_version, segment, filename = @name_args
+
+ cookbook = Chef::CookbookVersion.load(cookbook_name, cookbook_version) unless cookbook_version.nil?
+
case @name_args.length
when 4 # We are showing a specific file
node = Hash.new
@@ -59,15 +63,11 @@ class Chef
node[:platform_version] = config[:platform_version] if config.has_key?(:platform_version)
class << node
- def attribute?(name)
+ def attribute?(name) # rubocop:disable Lint/NestedMethodDefinition
has_key?(name)
end
end
- cookbook_name, segment, filename = @name_args[0], @name_args[2], @name_args[3]
- cookbook_version = @name_args[1] == "latest" ? "_latest" : @name_args[1]
-
- cookbook = rest.get("cookbooks/#{cookbook_name}/#{cookbook_version}")
manifest_entry = cookbook.preferred_manifest_record(node, segment, filename)
temp_file = rest.streaming_request(manifest_entry[:url])
@@ -76,14 +76,14 @@ class Chef
pretty_print(temp_file.read)
when 3 # We are showing a specific part of the cookbook
- cookbook_version = @name_args[1] == "latest" ? "_latest" : @name_args[1]
- result = rest.get("cookbooks/#{@name_args[0]}/#{cookbook_version}")
- output(result.manifest[@name_args[2]])
- when 2 # We are showing the whole cookbook data
- cookbook_version = @name_args[1] == "latest" ? "_latest" : @name_args[1]
- output(rest.get("cookbooks/#{@name_args[0]}/#{cookbook_version}"))
+ if segment == "metadata"
+ output(cookbook.metadata)
+ else
+ output(cookbook.files_for(segment))
+ end
+ when 2 # We are showing the whole cookbook
+ output(cookbook.display)
when 1 # We are showing the cookbook versions (all of them)
- cookbook_name = @name_args[0]
env = config[:environment]
api_endpoint = env ? "environments/#{env}/cookbooks/#{cookbook_name}" : "cookbooks/#{cookbook_name}"
output(format_cookbook_list_for_display(rest.get(api_endpoint)))
diff --git a/lib/chef/knife/cookbook_site_download.rb b/lib/chef/knife/cookbook_site_download.rb
index 7d0e21791d..07e0037bd6 100644
--- a/lib/chef/knife/cookbook_site_download.rb
+++ b/lib/chef/knife/cookbook_site_download.rb
@@ -37,10 +37,22 @@ class Chef
:long => "--force",
:description => "Force download deprecated version"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
if current_cookbook_deprecated?
message = "DEPRECATION: This cookbook has been deprecated. "
- message << "It has been replaced by #{replacement_cookbook}."
+ replacement = replacement_cookbook
+ if !replacement.to_s.strip.empty?
+ message << "It has been replaced by #{replacement}."
+ else
+ message << "No replacement has been defined."
+ end
ui.warn message
unless config[:force]
@@ -59,7 +71,7 @@ class Chef
private
def cookbooks_api_url
- "https://supermarket.chef.io/api/v1/cookbooks"
+ "#{config[:supermarket_site]}/api/v1/cookbooks"
end
def current_cookbook_data
@@ -98,7 +110,7 @@ class Chef
end
def replacement_cookbook
- File.basename(current_cookbook_data["replacement"])
+ File.basename(current_cookbook_data["replacement"] || "")
end
def specific_cookbook_version_url
diff --git a/lib/chef/knife/cookbook_site_install.rb b/lib/chef/knife/cookbook_site_install.rb
index 802fdd792b..f4d692e13c 100644
--- a/lib/chef/knife/cookbook_site_install.rb
+++ b/lib/chef/knife/cookbook_site_install.rb
@@ -1,6 +1,6 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
-# Copyright:: Copyright 2010-2016, Chef Software Inc.
+# Copyright:: Copyright 2010-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +19,7 @@
require "chef/knife"
require "chef/exceptions"
require "shellwords"
+require "mixlib/archive"
class Chef
class Knife
@@ -59,6 +60,13 @@ class Chef
:boolean => true,
:default => false
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
attr_reader :cookbook_name
attr_reader :vendor_path
@@ -75,7 +83,7 @@ class Chef
# Check to ensure we have a valid source of cookbooks before continuing
#
@install_path = File.expand_path(Array(config[:cookbook_path]).first)
- ui.info "Installing #@cookbook_name to #{@install_path}"
+ ui.info "Installing #{@cookbook_name} to #{@install_path}"
@repo = CookbookSCMRepo.new(@install_path, ui, config)
#cookbook_path = File.join(vendor_path, name_args[0])
@@ -108,7 +116,7 @@ class Chef
end
unless config[:no_deps]
- preferred_metadata.dependencies.each do |cookbook, version_list|
+ preferred_metadata.dependencies.each_key do |cookbook|
# Doesn't do versions.. yet
nv = self.class.new
nv.config = config
@@ -134,6 +142,7 @@ class Chef
def download_cookbook_to(download_path)
downloader = Chef::Knife::CookbookSiteDownload.new
downloader.config[:file] = download_path
+ downloader.config[:supermarket_site] = config[:supermarket_site]
downloader.name_args = name_args
downloader.run
downloader
@@ -141,12 +150,7 @@ class Chef
def extract_cookbook(upstream_file, version)
ui.info("Uncompressing #{@cookbook_name} version #{version}.")
- # FIXME: Detect if we have the bad tar from git on Windows: https://github.com/opscode/chef/issues/1753
- extract_command = "tar zxvf \"#{convert_path upstream_file}\""
- if Chef::Platform.windows?
- extract_command << " --force-local"
- end
- shell_out!(extract_command, :cwd => @install_path)
+ Mixlib::Archive.new(convert_path(upstream_file)).extract(@install_path, perms: false)
end
def clear_existing_files(cookbook_path)
@@ -157,9 +161,9 @@ class Chef
def convert_path(upstream_file)
# converts a Windows path (C:\foo) to a mingw path (/c/foo)
if ENV["MSYSTEM"] == "MINGW32"
- return upstream_file.sub(/^([[:alpha:]]):/, '/\1')
+ upstream_file.sub(/^([[:alpha:]]):/, '/\1')
else
- return Shellwords.escape upstream_file
+ Shellwords.escape upstream_file
end
end
diff --git a/lib/chef/knife/cookbook_site_list.rb b/lib/chef/knife/cookbook_site_list.rb
index abe48bf340..3bdef8abe5 100644
--- a/lib/chef/knife/cookbook_site_list.rb
+++ b/lib/chef/knife/cookbook_site_list.rb
@@ -30,6 +30,13 @@ class Chef
:long => "--with-uri",
:description => "Show corresponding URIs"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
if config[:with_uri]
cookbooks = Hash.new
@@ -41,7 +48,7 @@ class Chef
end
def get_cookbook_list(items = 10, start = 0, cookbook_collection = {})
- cookbooks_url = "https://supermarket.chef.io/api/v1/cookbooks?items=#{items}&start=#{start}"
+ cookbooks_url = "#{config[:supermarket_site]}/api/v1/cookbooks?items=#{items}&start=#{start}"
cr = noauth_rest.get(cookbooks_url)
cr["items"].each do |cookbook|
cookbook_collection[cookbook["cookbook_name"]] = cookbook
diff --git a/lib/chef/knife/cookbook_site_search.rb b/lib/chef/knife/cookbook_site_search.rb
index ba4b873efc..d401844217 100644
--- a/lib/chef/knife/cookbook_site_search.rb
+++ b/lib/chef/knife/cookbook_site_search.rb
@@ -24,12 +24,19 @@ class Chef
banner "knife cookbook site search QUERY (options)"
category "cookbook site"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
output(search_cookbook(name_args[0]))
end
def search_cookbook(query, items = 10, start = 0, cookbook_collection = {})
- cookbooks_url = "https://supermarket.chef.io/api/v1/search?q=#{query}&items=#{items}&start=#{start}"
+ cookbooks_url = "#{config[:supermarket_site]}/api/v1/search?q=#{query}&items=#{items}&start=#{start}"
cr = noauth_rest.get(cookbooks_url)
cr["items"].each do |cookbook|
cookbook_collection[cookbook["cookbook_name"]] = cookbook
diff --git a/lib/chef/knife/cookbook_site_share.rb b/lib/chef/knife/cookbook_site_share.rb
index 6f37568f5f..e4d55276da 100644
--- a/lib/chef/knife/cookbook_site_share.rb
+++ b/lib/chef/knife/cookbook_site_share.rb
@@ -50,6 +50,13 @@ class Chef
:default => false,
:description => "Don't take action, only print what files will be uploaded to Supermarket."
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
config[:cookbook_path] ||= Chef::Config[:cookbook_path]
@@ -71,12 +78,12 @@ class Chef
Chef::CookbookUploader.new(cookbook).validate_cookbooks
tmp_cookbook_dir = Chef::CookbookSiteStreamingUploader.create_build_dir(cookbook)
begin
- Chef::Log.debug("Temp cookbook directory is #{tmp_cookbook_dir.inspect}")
+ Chef::Log.trace("Temp cookbook directory is #{tmp_cookbook_dir.inspect}")
ui.info("Making tarball #{cookbook_name}.tgz")
shell_out!("#{tar_cmd} -czf #{cookbook_name}.tgz #{cookbook_name}", :cwd => tmp_cookbook_dir)
rescue => e
ui.error("Error making tarball #{cookbook_name}.tgz: #{e.message}. Increase log verbosity (-VV) for more information.")
- Chef::Log.debug("\n#{e.backtrace.join("\n")}")
+ Chef::Log.trace("\n#{e.backtrace.join("\n")}")
exit(1)
end
@@ -91,11 +98,11 @@ class Chef
begin
do_upload("#{tmp_cookbook_dir}/#{cookbook_name}.tgz", category, Chef::Config[:node_name], Chef::Config[:client_key])
ui.info("Upload complete")
- Chef::Log.debug("Removing local staging directory at #{tmp_cookbook_dir}")
+ Chef::Log.trace("Removing local staging directory at #{tmp_cookbook_dir}")
FileUtils.rm_rf tmp_cookbook_dir
rescue => e
ui.error("Error uploading cookbook #{cookbook_name} to Supermarket: #{e.message}. Increase log verbosity (-VV) for more information.")
- Chef::Log.debug("\n#{e.backtrace.join("\n")}")
+ Chef::Log.trace("\n#{e.backtrace.join("\n")}")
exit(1)
end
@@ -106,23 +113,17 @@ class Chef
end
def get_category(cookbook_name)
- begin
- data = noauth_rest.get("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}")
- if !data["category"] && data["error_code"]
- ui.fatal("Received an error from Supermarket: #{data["error_code"]}. On the first time you upload it, you are required to specify the category you want to share this cookbook to.")
- exit(1)
- else
- data["category"]
- end
- rescue => e
- ui.fatal("Unable to reach Supermarket: #{e.message}. Increase log verbosity (-VV) for more information.")
- Chef::Log.debug("\n#{e.backtrace.join("\n")}")
- exit(1)
- end
+ data = noauth_rest.get("#{config[:supermarket_site]}/api/v1/cookbooks/#{@name_args[0]}")
+ data["category"]
+ rescue => e
+ return "Other" if e.kind_of?(Net::HTTPServerException) && e.response.code == "404"
+ ui.fatal("Unable to reach Supermarket: #{e.message}. Increase log verbosity (-VV) for more information.")
+ Chef::Log.trace("\n#{e.backtrace.join("\n")}")
+ exit(1)
end
def do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename)
- uri = "https://supermarket.chef.io/api/v1/cookbooks"
+ uri = "#{config[:supermarket_site]}/api/v1/cookbooks"
category_string = Chef::JSONCompat.to_json({ "category" => cookbook_category })
diff --git a/lib/chef/knife/cookbook_site_show.rb b/lib/chef/knife/cookbook_site_show.rb
index c0280cb318..ce153ca5a1 100644
--- a/lib/chef/knife/cookbook_site_show.rb
+++ b/lib/chef/knife/cookbook_site_show.rb
@@ -24,21 +24,32 @@ class Chef
banner "knife cookbook site show COOKBOOK [VERSION] (options)"
category "cookbook site"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
output(format_for_display(get_cookbook_data))
end
+ def supermarket_uri
+ "#{config[:supermarket_site]}/api/v1"
+ end
+
def get_cookbook_data
case @name_args.length
when 1
- noauth_rest.get("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}")
+ noauth_rest.get("#{supermarket_uri}/cookbooks/#{@name_args[0]}")
when 2
- noauth_rest.get("https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}/versions/#{name_args[1].tr('.', '_')}")
+ noauth_rest.get("#{supermarket_uri}/cookbooks/#{@name_args[0]}/versions/#{name_args[1].tr('.', '_')}")
end
end
def get_cookbook_list(items = 10, start = 0, cookbook_collection = {})
- cookbooks_url = "https://supermarket.chef.io/api/v1/cookbooks?items=#{items}&start=#{start}"
+ cookbooks_url = "#{supermarket_uri}/cookbooks?items=#{items}&start=#{start}"
cr = noauth_rest.get(cookbooks_url)
cr["items"].each do |cookbook|
cookbook_collection[cookbook["cookbook_name"]] = cookbook
diff --git a/lib/chef/knife/cookbook_site_unshare.rb b/lib/chef/knife/cookbook_site_unshare.rb
index 310f6ac41d..bdabff0b94 100644
--- a/lib/chef/knife/cookbook_site_unshare.rb
+++ b/lib/chef/knife/cookbook_site_unshare.rb
@@ -30,6 +30,13 @@ class Chef
banner "knife cookbook site unshare COOKBOOK"
category "cookbook site"
+ option :supermarket_site,
+ :short => "-m SUPERMARKET_SITE",
+ :long => "--supermarket-site SUPERMARKET_SITE",
+ :description => "Supermarket Site",
+ :default => "https://supermarket.chef.io",
+ :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
+
def run
@cookbook_name = @name_args[0]
if @cookbook_name.nil?
@@ -41,7 +48,7 @@ class Chef
confirm "Do you really want to unshare all versions of the cookbook #{@cookbook_name}"
begin
- rest.delete "https://supermarket.chef.io/api/v1/cookbooks/#{@name_args[0]}"
+ rest.delete "#{config[:supermarket_site]}/api/v1/cookbooks/#{@name_args[0]}"
rescue Net::HTTPServerException => e
raise e unless e.message =~ /Forbidden/
ui.error "Forbidden: You must be the maintainer of #{@cookbook_name} to unshare it."
diff --git a/lib/chef/knife/cookbook_test.rb b/lib/chef/knife/cookbook_test.rb
index 1a5c9df74e..f3a4981c95 100644
--- a/lib/chef/knife/cookbook_test.rb
+++ b/lib/chef/knife/cookbook_test.rb
@@ -2,7 +2,7 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Matthew Kent (<mkent@magoazul.com>)
-# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2018, Chef Software Inc.
# Copyright:: Copyright 2010-2016, Matthew Kent
# License:: Apache License, Version 2.0
#
@@ -43,14 +43,14 @@ class Chef
:description => "Test all cookbooks, rather than just a single cookbook"
def run
- ui.warn("DEPRECATED: Please use ChefSpec or Rubocop to syntax-check cookbooks.")
+ ui.warn("DEPRECATED: Please use ChefSpec or Cookstyle to syntax-check cookbooks.")
config[:cookbook_path] ||= Chef::Config[:cookbook_path]
checked_a_cookbook = false
if config[:all]
cl = cookbook_loader
cl.load_cookbooks
- cl.each do |key, cookbook|
+ cl.each_key do |key|
checked_a_cookbook = true
test_cookbook(key)
end
diff --git a/lib/chef/knife/cookbook_upload.rb b/lib/chef/knife/cookbook_upload.rb
index 6938ac280d..f67a26dc9a 100644
--- a/lib/chef/knife/cookbook_upload.rb
+++ b/lib/chef/knife/cookbook_upload.rb
@@ -2,7 +2,7 @@
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Christopher Walters (<cw@chef.io>)
# Author:: Nuo Yan (<yan.nuo@gmail.com>)
-# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -146,12 +146,12 @@ class Chef
end
if upload_failures == 0
- ui.info "Uploaded #{upload_ok} cookbook#{upload_ok > 1 ? "s" : ""}."
+ ui.info "Uploaded #{upload_ok} cookbook#{upload_ok == 1 ? "" : "s"}."
elsif upload_failures > 0 && upload_ok > 0
- ui.warn "Uploaded #{upload_ok} cookbook#{upload_ok > 1 ? "s" : ""} ok but #{upload_failures} " +
- "cookbook#{upload_failures > 1 ? "s" : ""} upload failed."
+ ui.warn "Uploaded #{upload_ok} cookbook#{upload_ok == 1 ? "" : "s"} ok but #{upload_failures} " +
+ "cookbook#{upload_failures == 1 ? "" : "s"} upload failed."
elsif upload_failures > 0 && upload_ok == 0
- ui.error "Failed to upload #{upload_failures} cookbook#{upload_failures > 1 ? "s" : ""}."
+ ui.error "Failed to upload #{upload_failures} cookbook#{upload_failures == 1 ? "" : "s"}."
exit 1
end
end
@@ -172,7 +172,7 @@ class Chef
if ! upload_set.has_key?(cookbook_name)
upload_set[cookbook_name] = cookbook_repo[cookbook_name]
if config[:depends]
- upload_set[cookbook_name].metadata.dependencies.each { |dep, ver| @name_args << dep }
+ upload_set[cookbook_name].metadata.dependencies.each_key { |dep| @name_args << dep }
end
end
rescue Exceptions::CookbookNotFoundInRepo => e
diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb
index 48d2cb9e77..deb7f8a3b4 100644
--- a/lib/chef/knife/core/bootstrap_context.rb
+++ b/lib/chef/knife/core/bootstrap_context.rb
@@ -54,7 +54,7 @@ class Chef
end
def client_d
- @cliend_d ||= client_d_content
+ @client_d ||= client_d_content
end
def encrypted_data_bag_secret
@@ -67,12 +67,36 @@ class Chef
@trusted_certs ||= trusted_certs_content
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?)
+ "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)
+ ":syslog"
+ elsif @chef_config[:config_log_location].equal?(STDOUT)
+ "STDOUT"
+ elsif @chef_config[:config_log_location].equal?(STDERR)
+ "STDERR"
+ elsif @chef_config[:config_log_location]
+ %Q{"#{@chef_config[:config_log_location]}"}
+ else
+ "STDOUT"
+ end
+ end
+
def config_content
client_rb = <<-CONFIG
-log_location STDOUT
chef_server_url "#{@chef_config[:chef_server_url]}"
validation_client_name "#{@chef_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}
+ end
+
+ client_rb << "log_location #{get_log_location}\n"
+
if @config[:chef_node_name]
client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n}
else
@@ -114,6 +138,16 @@ validation_client_name "#{@chef_config[:validation_client_name]}"
client_rb << %Q{https_proxy "#{knife_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}
+ 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}
+ end
+
if knife_config[:bootstrap_no_proxy]
client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n}
end
@@ -127,13 +161,14 @@ validation_client_name "#{@chef_config[:validation_client_name]}"
end
if Chef::Config[:fips]
- 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)
- raise "FIPS Mode requested but not supported by this client"
-end
-CONFIG
+ client_rb << <<-CONFIG.gsub(/^ {14}/, "")
+ 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)
+ raise "FIPS Mode requested but not supported by this client"
+ end
+ CONFIG
end
client_rb
@@ -143,7 +178,11 @@ CONFIG
# 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"
s = "#{client_path} -j /etc/chef/first-boot.json"
- s << " -l debug" if @config[:verbosity] && @config[:verbosity] >= 2
+ if @config[:verbosity] && @config[:verbosity] >= 3
+ s << " -l trace"
+ 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
@@ -188,6 +227,7 @@ CONFIG
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?
end
end
@@ -219,7 +259,7 @@ CONFIG
content << "mkdir #{file_on_node}\n"
else
content << "cat > #{file_on_node} <<'EOP'\n" +
- f.read + "\nEOP\n"
+ f.read.gsub("'", "'\\\\''") + "\nEOP\n"
end
end
end
diff --git a/lib/chef/knife/core/cookbook_scm_repo.rb b/lib/chef/knife/core/cookbook_scm_repo.rb
index e909066b02..38f432e5bb 100644
--- a/lib/chef/knife/core/cookbook_scm_repo.rb
+++ b/lib/chef/knife/core/cookbook_scm_repo.rb
@@ -122,7 +122,7 @@ class Chef
git("branch --no-color").stdout.lines.any? { |l| l =~ /\s#{Regexp.escape(branch_name)}(?:\s|$)/ }
end
- def get_current_branch()
+ def get_current_branch
ref = git("symbolic-ref HEAD").stdout
ref.chomp.split("/")[2]
end
@@ -131,9 +131,9 @@ class Chef
def git_repo?(directory)
if File.directory?(File.join(directory, ".git"))
- return true
+ true
elsif File.dirname(directory) == directory
- return false
+ false
else
git_repo?(File.dirname(directory))
end
diff --git a/lib/chef/knife/core/custom_manifest_loader.rb b/lib/chef/knife/core/custom_manifest_loader.rb
deleted file mode 100644
index 9fe51599af..0000000000
--- a/lib/chef/knife/core/custom_manifest_loader.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright:: Copyright 2015-2016, Chef Software, Inc
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require "chef/version"
-class Chef
- class Knife
- class SubcommandLoader
-
- #
- # Load a subcommand from a user-supplied
- # manifest file
- #
- class CustomManifestLoader < Chef::Knife::SubcommandLoader
- attr_accessor :manifest
- def initialize(chef_config_dir, plugin_manifest)
- super(chef_config_dir)
- @manifest = plugin_manifest
- end
-
- # If the user has created a ~/.chef/plugin_manifest.json file, we'll use
- # that instead of inspecting the on-system gems to find the plugins. The
- # file format is expected to look like:
- #
- # { "plugins": {
- # "knife-ec2": {
- # "paths": [
- # "/home/alice/.rubymanagerthing/gems/knife-ec2-x.y.z/lib/chef/knife/ec2_server_create.rb",
- # "/home/alice/.rubymanagerthing/gems/knife-ec2-x.y.z/lib/chef/knife/ec2_server_delete.rb"
- # ]
- # }
- # }
- # }
- #
- # Extraneous content in this file is ignored. This is intentional so that we
- # can adapt the file format for potential behavior changes to knife in
- # the future.
- def find_subcommands_via_manifest
- # Format of subcommand_files is "relative_path" (something you can
- # Kernel.require()) => full_path. The relative path isn't used
- # currently, so we just map full_path => full_path.
- subcommand_files = {}
- manifest["plugins"].each do |plugin_name, plugin_manifest|
- plugin_manifest["paths"].each do |cmd_path|
- subcommand_files[cmd_path] = cmd_path
- end
- end
- subcommand_files.merge(find_subcommands_via_dirglob)
- end
-
- def subcommand_files
- @subcommand_files ||= (find_subcommands_via_manifest.values + site_subcommands).flatten.uniq
- end
- end
- end
- end
-end
diff --git a/lib/chef/knife/core/gem_glob_loader.rb b/lib/chef/knife/core/gem_glob_loader.rb
index f5eff26903..c4523d69ad 100644
--- a/lib/chef/knife/core/gem_glob_loader.rb
+++ b/lib/chef/knife/core/gem_glob_loader.rb
@@ -81,9 +81,9 @@ class Chef
files = []
if check_load_path
- files = $LOAD_PATH.map { |load_path|
+ files = $LOAD_PATH.map do |load_path|
Dir["#{File.expand_path glob, Chef::Util::PathHelper.escape_glob_dir(load_path)}#{Gem.suffix_pattern}"]
- }.flatten.select { |file| File.file? file.untaint }
+ end.flatten.select { |file| File.file? file.untaint }
end
gem_files = latest_gem_specs.map do |spec|
@@ -98,7 +98,7 @@ class Chef
files.concat gem_files
files.uniq! if check_load_path
- return files
+ files
end
def latest_gem_specs
@@ -110,7 +110,7 @@ class Chef
end
def check_spec_for_glob(spec, glob)
- dirs = if spec.require_paths.size > 1 then
+ dirs = if spec.require_paths.size > 1
"{#{spec.require_paths.join(',')}}"
else
spec.require_paths.first
diff --git a/lib/chef/knife/core/generic_presenter.rb b/lib/chef/knife/core/generic_presenter.rb
index f273cb5bca..861bf1510d 100644
--- a/lib/chef/knife/core/generic_presenter.rb
+++ b/lib/chef/knife/core/generic_presenter.rb
@@ -28,12 +28,19 @@ class Chef
# :nodoc:
def self.included(includer)
includer.class_eval do
- @attrs_to_show = []
+ option :field_separator,
+ :short => "-S SEPARATOR",
+ :long => "--field-separator SEPARATOR",
+ :description => "Character separator used to delineate nesting in --attribute filters (default \".\")"
+
option :attribute,
:short => "-a ATTR1 [-a ATTR2]",
:long => "--attribute ATTR1 [--attribute ATTR2] ",
- :proc => lambda { |val| @attrs_to_show << val },
- :description => "Show one or more attributes"
+ :description => "Show one or more attributes",
+ :proc => Proc.new { |a|
+ Chef::Config[:knife][:attribute] ||= []
+ Chef::Config[:knife][:attribute].push(a)
+ }
end
end
end
@@ -173,25 +180,28 @@ class Chef
config[:attribute] || config[:run_list]
end
+ # GenericPresenter is used in contexts where MultiAttributeReturnOption
+ # is not, so we need to set the default value here rather than as part
+ # of the CLI option.
+ def attribute_field_separator
+ config[:field_separator] || "."
+ end
+
def extract_nested_value(data, nested_value_spec)
- nested_value_spec.split(".").each do |attr|
- if data.nil?
- nil # don't get no method error on nil
- # Must check :[] before attr because spec can include
- # `keys` - want the key named `keys`, not a list of
- # available keys.
- elsif data.respond_to?(:[]) && data.has_key?(attr)
- data = data[attr]
- elsif data.respond_to?(attr.to_sym)
- data = data.send(attr.to_sym)
- else
- data = begin
- data.send(attr.to_sym)
- rescue NoMethodError
- nil
- end
- end
+ nested_value_spec.split(attribute_field_separator).each do |attr|
+ data =
+ if data.is_a?(Array)
+ data[attr.to_i]
+ elsif data.respond_to?(:[], false) && data.key?(attr)
+ data[attr]
+ elsif data.respond_to?(attr.to_sym, false)
+ # handles -a chef_environment and other things that hang of the node and aren't really attributes
+ data.public_send(attr.to_sym)
+ else
+ nil
+ end
end
+ # necessary (?) for coercing objects (the run_list object?) to hashes
( !data.kind_of?(Array) && data.respond_to?(:to_hash) ) ? data.to_hash : data
end
diff --git a/lib/chef/knife/core/status_presenter.rb b/lib/chef/knife/core/status_presenter.rb
index 68c1acf4f1..1e2d9b41b6 100644
--- a/lib/chef/knife/core/status_presenter.rb
+++ b/lib/chef/knife/core/status_presenter.rb
@@ -101,29 +101,38 @@ class Chef
fqdn = (node[:ec2] && node[:ec2][:public_hostname]) || node[:fqdn]
name = node["name"] || node.name
- hours, minutes, = time_difference_in_hms(node["ohai_time"])
- hours_text = "#{hours} hour#{hours == 1 ? ' ' : 's'}"
- minutes_text = "#{minutes} minute#{minutes == 1 ? ' ' : 's'}"
run_list = "#{node['run_list']}" if config[:run_list]
- if hours > 24
- color = :red
- text = hours_text
- elsif hours >= 1
- color = :yellow
- text = hours_text
+ line_parts = Array.new
+
+ if node["ohai_time"]
+ hours, minutes, seconds = time_difference_in_hms(node["ohai_time"])
+ hours_text = "#{hours} hour#{hours == 1 ? ' ' : 's'}"
+ minutes_text = "#{minutes} minute#{minutes == 1 ? ' ' : 's'}"
+ seconds_text = "#{seconds} second#{seconds == 1 ? ' ' : 's'}"
+ if hours > 24
+ color = :red
+ text = hours_text
+ elsif hours >= 1
+ color = :yellow
+ text = hours_text
+ elsif minutes >= 1
+ color = :green
+ text = minutes_text
+ else
+ color = :green
+ text = seconds_text
+ end
+ line_parts << @ui.color(text, color) + " ago" << name
else
- color = :green
- text = minutes_text
+ line_parts << "Node #{name} has not yet converged"
end
- line_parts = Array.new
- line_parts << @ui.color(text, color) + " ago" << name
line_parts << fqdn if fqdn
line_parts << ip if ip
line_parts << run_list if run_list
if node["platform"]
- platform = node["platform"]
+ platform = node["platform"].dup
if node["platform_version"]
platform << " #{node['platform_version']}"
end
@@ -148,7 +157,7 @@ class Chef
difference = difference % 3600
minutes = (difference / 60).to_i
seconds = (difference % 60)
- return [hours, minutes, seconds]
+ [hours, minutes, seconds]
end
end
diff --git a/lib/chef/knife/core/subcommand_loader.rb b/lib/chef/knife/core/subcommand_loader.rb
index e617b39ded..026967d6ec 100644
--- a/lib/chef/knife/core/subcommand_loader.rb
+++ b/lib/chef/knife/core/subcommand_loader.rb
@@ -1,6 +1,6 @@
# Author:: Christopher Brown (<cb@chef.io>)
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,6 @@ require "chef/version"
require "chef/util/path_helper"
require "chef/knife/core/gem_glob_loader"
require "chef/knife/core/hashed_command_loader"
-require "chef/knife/core/custom_manifest_loader"
class Chef
class Knife
@@ -38,7 +37,6 @@ class Chef
#
class SubcommandLoader
attr_reader :chef_config_dir
- attr_reader :env
# A small factory method. Eventually, this is the only place
# where SubcommandLoader should know about its subclasses, but
@@ -48,11 +46,8 @@ class Chef
# or directly instantiate the appropriate subclass
def self.for_config(chef_config_dir)
if autogenerated_manifest?
- Chef::Log.debug("Using autogenerated hashed command manifest #{plugin_manifest_path}")
+ Chef::Log.trace("Using autogenerated hashed command manifest #{plugin_manifest_path}")
Knife::SubcommandLoader::HashedCommandLoader.new(chef_config_dir, plugin_manifest)
- elsif custom_manifest?
- Chef.log_deprecation("Using custom manifest #{plugin_manifest_path} is deprecated. Please use a `knife rehash` autogenerated manifest instead.")
- Knife::SubcommandLoader::CustomManifestLoader.new(chef_config_dir, plugin_manifest)
else
Knife::SubcommandLoader::GemGlobLoader.new(chef_config_dir)
end
@@ -72,10 +67,6 @@ class Chef
plugin_manifest? && plugin_manifest.key?(HashedCommandLoader::KEY)
end
- def self.custom_manifest?
- plugin_manifest? && plugin_manifest.key?("plugins")
- end
-
def self.plugin_manifest
Chef::JSONCompat.from_json(File.read(plugin_manifest_path))
end
@@ -84,14 +75,8 @@ class Chef
Chef::Util::PathHelper.home(".chef", "plugin_manifest.json")
end
- def initialize(chef_config_dir, env = nil)
+ def initialize(chef_config_dir)
@chef_config_dir = chef_config_dir
-
- # Deprecated and un-used instance variable.
- @env = env
- unless env.nil?
- Chef.log_deprecation("The env argument to Chef::Knife::SubcommandLoader is deprecated. If you are using env to inject/mock HOME, consider mocking Chef::Util::PathHelper.home instead.")
- end
end
# Load all the sub-commands
@@ -149,21 +134,6 @@ class Chef
end
#
- # Subclassses should define this themselves. Eventually, this will raise a
- # NotImplemented error, but for now, we mimic the behavior the user was likely
- # to get in the past.
- #
- def subcommand_files
- Chef.log_deprecation "Using Chef::Knife::SubcommandLoader directly is deprecated.
-Please use Chef::Knife::SubcommandLoader.for_config(chef_config_dir, env)"
- @subcommand_files ||= if Chef::Knife::SubcommandLoader.plugin_manifest?
- Chef::Knife::SubcommandLoader::CustomManifestLoader.new(chef_config_dir, env).subcommand_files
- else
- Chef::Knife::SubcommandLoader::GemGlobLoader.new(chef_config_dir, env).subcommand_files
- end
- end
-
- #
# Utility function for finding an element in a hash given an array
# of words and a separator. We find the the longest key in the
# hash composed of the given words joined by the separator.
diff --git a/lib/chef/knife/core/ui.rb b/lib/chef/knife/core/ui.rb
index 67e431f1a7..b2efbd8b8f 100644
--- a/lib/chef/knife/core/ui.rb
+++ b/lib/chef/knife/core/ui.rb
@@ -65,22 +65,18 @@ class Chef
# Prints a message to stdout. Aliased as +info+ for compatibility with
# the logger API.
def msg(message)
- begin
- stdout.puts message
- rescue Errno::EPIPE => e
- raise e if @config[:verbosity] >= 2
- exit 0
- end
+ stdout.puts message
+ rescue Errno::EPIPE => e
+ raise e if @config[:verbosity] >= 2
+ exit 0
end
# Prints a msg to stderr. Used for info, warn, error, and fatal.
def log(message)
- begin
- stderr.puts message
- rescue Errno::EPIPE => e
- raise e if @config[:verbosity] >= 2
- exit 0
- end
+ stderr.puts message
+ rescue Errno::EPIPE => e
+ raise e if @config[:verbosity] >= 2
+ exit 0
end
alias :info :log
@@ -138,7 +134,7 @@ class Chef
end
def ask_question(question, opts = {})
- question = question + "[#{opts[:default]}] " if opts[:default]
+ question += "[#{opts[:default]}] " if opts[:default]
if opts[:default] && config[:defaults]
opts[:default]
@@ -155,12 +151,10 @@ class Chef
end
def pretty_print(data)
- begin
- stdout.puts data
- rescue Errno::EPIPE => e
- raise e if @config[:verbosity] >= 2
- exit 0
- end
+ stdout.puts data
+ rescue Errno::EPIPE => e
+ raise e if @config[:verbosity] >= 2
+ exit 0
end
# Hash -> Hash
@@ -178,7 +172,7 @@ class Chef
tf.sync = true
tf.puts output
tf.close
- raise "Please set EDITOR environment variable" unless system("#{config[:editor]} #{tf.path}")
+ raise "Please set EDITOR environment variable. See https://docs.chef.io/knife_setup.html for details." unless system("#{config[:editor]} #{tf.path}")
output = IO.read(tf.path)
end
@@ -186,8 +180,7 @@ class Chef
if parse_output
if object_class.nil?
- Chef.log_deprecation("Auto inflation of JSON data is deprecated. Please pass in the class to inflate or use #edit_hash")
- Chef::JSONCompat.from_json(output)
+ raise ArgumentError, "Please pass in the object class to hydrate or use #edit_hash"
else
object_class.from_hash(Chef::JSONCompat.parse(output))
end
@@ -215,9 +208,9 @@ class Chef
output_parsed_again = Chef::JSONCompat.parse(Chef::JSONCompat.to_json(output))
if object_parsed_again != output_parsed_again
output.save
- self.msg("Saved #{output}")
+ msg("Saved #{output}")
else
- self.msg("Object unchanged, not saving")
+ msg("Object unchanged, not saving")
end
output(format_for_display(object)) if config[:print_after]
end
@@ -247,19 +240,19 @@ class Chef
when "Y", "y"
true
when "N", "n"
- self.msg("You said no, so I'm done here.")
+ msg("You said no, so I'm done here.")
false
when ""
unless default_choice.nil?
default_choice
else
- self.msg("I have no idea what to do with '#{answer}'")
- self.msg("Just say Y or N, please.")
+ msg("I have no idea what to do with '#{answer}'")
+ msg("Just say Y or N, please.")
confirm_without_exit(question, append_instructions, default_choice)
end
else
- self.msg("I have no idea what to do with '#{answer}'")
- self.msg("Just say Y or N, please.")
+ msg("I have no idea what to do with '#{answer}'")
+ msg("Just say Y or N, please.")
confirm_without_exit(question, append_instructions, default_choice)
end
end
diff --git a/lib/chef/knife/data_bag_create.rb b/lib/chef/knife/data_bag_create.rb
index 196278bb80..563e931dca 100644
--- a/lib/chef/knife/data_bag_create.rb
+++ b/lib/chef/knife/data_bag_create.rb
@@ -49,13 +49,15 @@ class Chef
exit(1)
end
- # create the data bag
+ # Verify if the data bag exists
begin
+ rest.get("data/#{@data_bag_name}")
+ ui.info("Data bag #{@data_bag_name} already exists")
+ rescue Net::HTTPServerException => e
+ raise unless e.to_s =~ /^404/
+ # if it doesn't exists, try to create it
rest.post("data", { "name" => @data_bag_name })
ui.info("Created data_bag[#{@data_bag_name}]")
- rescue Net::HTTPServerException => e
- raise unless e.to_s =~ /^409/
- ui.info("Data bag #{@data_bag_name} already exists")
end
# if an item is specified, create it, as well
diff --git a/lib/chef/knife/data_bag_secret_options.rb b/lib/chef/knife/data_bag_secret_options.rb
index b426cd442c..a612004e15 100644
--- a/lib/chef/knife/data_bag_secret_options.rb
+++ b/lib/chef/knife/data_bag_secret_options.rb
@@ -95,7 +95,7 @@ class Chef
##
# Determine if the user has specified an appropriate secret for encrypting data bag items.
- # @returns boolean
+ # @return boolean
def base_encryption_secret_provided?(need_encrypt_flag = true)
validate_secrets
@@ -114,7 +114,7 @@ class Chef
# Certain situations (show and bootstrap) don't need a --encrypt flag to use the config file secret
return true
end
- return false
+ false
end
def has_cl_secret?
diff --git a/lib/chef/knife/data_bag_show.rb b/lib/chef/knife/data_bag_show.rb
index ea9c390f19..5df0561276 100644
--- a/lib/chef/knife/data_bag_show.rb
+++ b/lib/chef/knife/data_bag_show.rb
@@ -51,7 +51,7 @@ class Chef
ui.warn("Encrypted data bag detected, but no secret provided for decoding. Displaying encrypted data.")
format_for_display(raw_data)
else
- ui.warn("Unencrypted data bag detected, ignoring any provided secret options.")
+ ui.warn("Unencrypted data bag detected, ignoring any provided secret options.") if secret
format_for_display(raw_data)
end
diff --git a/lib/chef/knife/deps.rb b/lib/chef/knife/deps.rb
index e773f65106..eec92cc9a3 100644
--- a/lib/chef/knife/deps.rb
+++ b/lib/chef/knife/deps.rb
@@ -72,49 +72,47 @@ class Chef
end
def get_dependencies(entry)
- begin
- if entry.parent && entry.parent.path == "/cookbooks"
- return entry.chef_object.metadata.dependencies.keys.map { |cookbook| "/cookbooks/#{cookbook}" }
+ if entry.parent && entry.parent.path == "/cookbooks"
+ entry.chef_object.metadata.dependencies.keys.map { |cookbook| "/cookbooks/#{cookbook}" }
- elsif entry.parent && entry.parent.path == "/nodes"
- node = Chef::JSONCompat.parse(entry.read)
- result = []
- if node["chef_environment"] && node["chef_environment"] != "_default"
- result << "/environments/#{node['chef_environment']}.json"
- end
- if node["run_list"]
- result += dependencies_from_runlist(node["run_list"])
- end
- result
+ elsif entry.parent && entry.parent.path == "/nodes"
+ node = Chef::JSONCompat.parse(entry.read)
+ result = []
+ if node["chef_environment"] && node["chef_environment"] != "_default"
+ result << "/environments/#{node['chef_environment']}.json"
+ end
+ if node["run_list"]
+ result += dependencies_from_runlist(node["run_list"])
+ end
+ result
- elsif entry.parent && entry.parent.path == "/roles"
- role = Chef::JSONCompat.parse(entry.read)
- result = []
- if role["run_list"]
- dependencies_from_runlist(role["run_list"]).each do |dependency|
- result << dependency if !result.include?(dependency)
- end
+ elsif entry.parent && entry.parent.path == "/roles"
+ role = Chef::JSONCompat.parse(entry.read)
+ result = []
+ if role["run_list"]
+ dependencies_from_runlist(role["run_list"]).each do |dependency|
+ result << dependency if !result.include?(dependency)
end
- if role["env_run_lists"]
- role["env_run_lists"].each_pair do |env, run_list|
- dependencies_from_runlist(run_list).each do |dependency|
- result << dependency if !result.include?(dependency)
- end
+ end
+ if role["env_run_lists"]
+ role["env_run_lists"].each_pair do |env, run_list|
+ dependencies_from_runlist(run_list).each do |dependency|
+ result << dependency if !result.include?(dependency)
end
end
- result
+ end
+ result
- elsif !entry.exists?
- raise Chef::ChefFS::FileSystem::NotFoundError.new(entry)
+ elsif !entry.exists?
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(entry)
- else
- []
- end
- rescue Chef::ChefFS::FileSystem::NotFoundError => e
- ui.error "#{format_path(e.entry)}: No such file or directory"
- self.exit_code = 2
+ else
[]
end
+ rescue Chef::ChefFS::FileSystem::NotFoundError => e
+ ui.error "#{format_path(e.entry)}: No such file or directory"
+ self.exit_code = 2
+ []
end
def dependencies_from_runlist(run_list)
diff --git a/lib/chef/knife/edit.rb b/lib/chef/knife/edit.rb
index 8489e4e179..4d7338f9f6 100644
--- a/lib/chef/knife/edit.rb
+++ b/lib/chef/knife/edit.rb
@@ -9,7 +9,7 @@ class Chef
deps do
require "chef/chef_fs/file_system"
- require "chef/chef_fs/file_system/not_found_error"
+ require "chef/chef_fs/file_system/exceptions"
end
option :local,
@@ -58,7 +58,7 @@ class Chef
# Let the user edit the temporary file
if !system("#{config[:editor]} #{file.path}")
- raise "Please set EDITOR environment variable. See https://docs.chef.io/knife_using.html for details."
+ raise "Please set EDITOR environment variable. See https://docs.chef.io/knife_setup.html for details."
end
result_text = IO.read(file.path)
diff --git a/lib/chef/knife/environment_compare.rb b/lib/chef/knife/environment_compare.rb
index 8a2ef853d3..9131f06068 100644
--- a/lib/chef/knife/environment_compare.rb
+++ b/lib/chef/knife/environment_compare.rb
@@ -81,7 +81,7 @@ class Chef
def constraint_list(environments)
constraints = {}
- environments.each do |env, url|
+ environments.each do |env, url| # rubocop:disable Performance/HashEachMethods
# Because you cannot modify the default environment I filter it out here.
unless env == "_default"
envdata = Chef::Environment.load(env)
@@ -94,17 +94,17 @@ class Chef
def cookbook_list(constraints)
result = {}
- constraints.each { |env, cb| result.merge!(cb) }
+ constraints.each_value { |cb| result.merge!(cb) }
result
end
def matrix_output(cookbooks, constraints)
rows = [ "" ]
environments = []
- constraints.each { |e, v| environments << e.to_s }
+ constraints.each_key { |e| environments << e.to_s }
columns = environments.count + 1
environments.each { |env| rows << ui.color(env, :bold) }
- cookbooks.each do |c, v|
+ cookbooks.each_key do |c|
total = []
environments.each { |n| total << constraints[n][c] }
if total.uniq.count == 1
diff --git a/lib/chef/knife/exec.rb b/lib/chef/knife/exec.rb
index 0aa8ea2ba8..7b27a51b85 100644
--- a/lib/chef/knife/exec.rb
+++ b/lib/chef/knife/exec.rb
@@ -68,15 +68,15 @@ class Chef::Knife::Exec < Chef::Knife
# Failing that, try searching the script path. If we can't find
# anything, fail gracefully.
- Chef::Log.debug("Searching script_path: #{config[:script_path].inspect}")
+ Chef::Log.trace("Searching script_path: #{config[:script_path].inspect}")
config[:script_path].each do |path|
path = File.expand_path(path)
test = File.join(path, x)
- Chef::Log.debug("Testing: #{test}")
+ Chef::Log.trace("Testing: #{test}")
if File.exists?(test)
script = test
- Chef::Log.debug("Found: #{test}")
+ Chef::Log.trace("Found: #{test}")
return script
end
end
diff --git a/lib/chef/knife/help.rb b/lib/chef/knife/help.rb
deleted file mode 100644
index e45b54eec8..0000000000
--- a/lib/chef/knife/help.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-#
-# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2011-2016, Chef Software Inc.
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-class Chef
- class Knife
- class Help < Chef::Knife
-
- banner "knife help [list|TOPIC]"
-
- def run
- if name_args.empty?
- ui.info "Usage: knife SUBCOMMAND (options)"
- ui.msg ""
- # This command is atypical, the user is likely not interested in usage of
- # this command, but knife in general. So hack the banner.
- opt_parser.banner = "General Knife Options:"
- ui.msg opt_parser.to_s
- ui.msg ""
- ui.info "For further help:"
- ui.info(<<-MOAR_HELP)
- knife help list list help topics
- knife help knife show general knife help
- knife help TOPIC display the manual for TOPIC
- knife SUBCOMMAND --help show the options for a command
-MOAR_HELP
- exit 1
- else
- @query = name_args.join("-")
- end
-
- case @query
- when "topics", "list"
- print_help_topics
- exit 1
- when "intro", "knife"
- @topic = "knife"
- else
- @topic = find_manpages_for_query(@query)
- end
-
- manpage_path = find_manpage_path(@topic)
- exec "man #{manpage_path}"
- end
-
- def help_topics
- # The list of help topics is generated by a rake task from the available man pages
- # This constant is provided in help_topics.rb which is automatically required/loaded by the knife subcommand loader.
- HELP_TOPICS
- end
-
- def print_help_topics
- ui.info "Available help topics are: "
- help_topics.collect { |t| t.gsub(/knife-/, "") }.sort.each do |topic|
- ui.msg " #{topic}"
- end
- end
-
- def find_manpages_for_query(query)
- possibilities = help_topics.select do |manpage|
- ::File.fnmatch("knife-#{query}*", manpage) || ::File.fnmatch("#{query}*", manpage)
- end
- if possibilities.empty?
- ui.error "No help found for '#{query}'"
- ui.msg ""
- print_help_topics
- exit 1
- elsif possibilities.size == 1
- possibilities.first
- else
- ui.info "Multiple help topics match your query. Pick one:"
- ui.highline.choose(*possibilities)
- end
- end
-
- def find_manpage_path(topic)
- if ::File.exists?(::File.expand_path("../distro/common/man/man1/#{topic}.1", CHEF_ROOT))
- # If we've provided the man page in the gem, give that
- return ::File.expand_path("../distro/common/man/man1/#{topic}.1", CHEF_ROOT)
- else
- # Otherwise, we'll just be using MANPATH
- topic
- end
- end
- end
- end
-end
diff --git a/lib/chef/knife/help_topics.rb b/lib/chef/knife/help_topics.rb
deleted file mode 100644
index a2aad65f55..0000000000
--- a/lib/chef/knife/help_topics.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# Do not edit this file by hand
-# This file is autogenerated by the docs:list rake task from the available manpages
-
-HELP_TOPICS = ["chef-shell", "knife-bootstrap", "knife-client", "knife-configure", "knife-cookbook-site", "knife-cookbook", "knife-data-bag", "knife-delete", "knife-deps", "knife-diff", "knife-download", "knife-edit", "knife-environment", "knife-exec", "knife-index-rebuild", "knife-list", "knife-node", "knife-raw", "knife-recipe-list", "knife-role", "knife-search", "knife-show", "knife-ssh", "knife-status", "knife-tag", "knife-upload", "knife-user", "knife-xargs", "knife"]
diff --git a/lib/chef/knife/index_rebuild.rb b/lib/chef/knife/index_rebuild.rb
deleted file mode 100644
index 206b7b0fbf..0000000000
--- a/lib/chef/knife/index_rebuild.rb
+++ /dev/null
@@ -1,133 +0,0 @@
-#
-# Author:: Daniel DeLeo (<dan@kallistec.com>)
-# Copyright:: Copyright 2009-2016, Daniel DeLeo
-# License:: Apache License, Version 2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require "chef/knife"
-
-class Chef
- class Knife
- class IndexRebuild < Knife
-
- banner "knife index rebuild (options)"
- option :yes,
- :short => "-y",
- :long => "--yes",
- :boolean => true,
- :description => "don't bother to ask if I'm sure"
-
- def run
- api_info = grab_api_info
-
- if unsupported_version?(api_info)
- unsupported_server_message(api_info)
- exit 1
- else
- deprecated_server_message
- nag
- output rest.post("/search/reindex", {})
- end
- end
-
- def grab_api_info
- # Since we don't yet have any endpoints that implement an
- # OPTIONS handler, we need to get our version header
- # information in a more roundabout way. We'll try to query
- # for a node we know won't exist; the 404 response that comes
- # back will give us what we want
- dummy_node = "knife_index_rebuild_test_#{rand(1000000)}"
- rest.get("/nodes/#{dummy_node}")
- rescue Net::HTTPServerException => exception
- r = exception.response
- parse_api_info(r)
- end
-
- # Only Chef 11+ servers will have version information in their
- # headers, and only those servers will lack an API endpoint for
- # index rebuilding.
- def unsupported_version?(api_info)
- !!api_info["version"]
- end
-
- def unsupported_server_message(api_info)
- ui.error("Rebuilding the index is not available via knife for #{server_type(api_info)}s version 11.0.0 and above.")
- ui.info("Instead, run the '#{ctl_command(api_info)} reindex' command on the server itself.")
- end
-
- def deprecated_server_message
- ui.warn("'knife index rebuild' has been removed for Chef 11+ servers. It will continue to work for prior versions, however.")
- end
-
- def nag
- ui.info("This operation is destructive. Rebuilding the index may take some time.")
- ui.confirm("Continue")
- end
-
- # Chef 11 (and above) servers return various pieces of
- # information about the server in an +x-ops-api-info+ header.
- # This is a +;+ delimited string of key / value pairs, separated
- # by +=+.
- #
- # Given a Net::HTTPResponse object, this method extracts this
- # information (if present), and returns it as a hash. If no
- # such header is found, an empty hash is returned.
- def parse_api_info(response)
- value = response["x-ops-api-info"]
- if value
- kv = value.split(";")
- kv.inject({}) do |acc, pair|
- k, v = pair.split("=")
- acc[k] = v
- acc
- end
- else
- {}
- end
- end
-
- # Given an API info hash (see +#parse_api_info(response)+),
- # return a string describing the kind of server we're
- # interacting with (based on the +flavor+ field)
- def server_type(api_info)
- case api_info["flavor"]
- when "osc"
- "Open Source Chef Server"
- when "opc"
- "Private Chef Server"
- else
- # Generic fallback
- "Chef Server"
- end
- end
-
- # Given an API info hash (see +#parse_api_info(response)+),
- # return the name of the "server-ctl" command for the kind of
- # server we're interacting with (based on the +flavor+ field)
- def ctl_command(api_info)
- case api_info["flavor"]
- when "osc"
- "chef-server-ctl"
- when "opc"
- "private-chef-ctl"
- else
- # Generic fallback
- "chef-server-ctl"
- end
- end
-
- end
- end
-end
diff --git a/lib/chef/knife/list.rb b/lib/chef/knife/list.rb
index 3d1583b270..e1a50b9360 100644
--- a/lib/chef/knife/list.rb
+++ b/lib/chef/knife/list.rb
@@ -44,7 +44,6 @@ class Chef
patterns = name_args.length == 0 ? [""] : name_args
# Get the top-level matches
- args = pattern_args_from(patterns)
all_results = parallelize(pattern_args_from(patterns)) do |pattern|
pattern_results = Chef::ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern).to_a
@@ -70,7 +69,7 @@ class Chef
# Flatten out directory results if necessary
if config[:flat]
- dir_results.each do |result, children|
+ dir_results.each do |result, children| # rubocop:disable Performance/HashEachMethods
results += children
end
dir_results = []
@@ -95,10 +94,10 @@ class Chef
printed_something = true
end
output "#{format_path(result)}:"
- print_results(children.map { |result| maybe_add_slash(result.name, result.dir?) }.sort, "")
+ print_results(children.map { |result| maybe_add_slash(result.display_name, result.dir?) }.sort, "")
end
- exit self.exit_code if self.exit_code
+ exit exit_code if exit_code
end
def add_dir_result(result)
diff --git a/lib/chef/knife/node_delete.rb b/lib/chef/knife/node_delete.rb
index 4dd7d764a1..52b8d122ca 100644
--- a/lib/chef/knife/node_delete.rb
+++ b/lib/chef/knife/node_delete.rb
@@ -27,18 +27,18 @@ class Chef
require "chef/json_compat"
end
- banner "knife node delete NODE (options)"
+ banner "knife node delete [NODE [NODE]] (options)"
def run
- @node_name = @name_args[0]
-
- if @node_name.nil?
+ if @name_args.length == 0
show_usage
- ui.fatal("You must specify a node name")
+ ui.fatal("You must specify at least one node name")
exit 1
end
- delete_object(Chef::Node, @node_name)
+ @name_args.each do |node_name|
+ delete_object(Chef::Node, node_name)
+ end
end
end
diff --git a/lib/chef/knife/node_policy_set.rb b/lib/chef/knife/node_policy_set.rb
new file mode 100644
index 0000000000..404446fe0e
--- /dev/null
+++ b/lib/chef/knife/node_policy_set.rb
@@ -0,0 +1,79 @@
+#
+# Author:: Piyush Awasthi (<piyush.awasthi@chef.io>)
+# Copyright:: Copyright 2017-2018, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License);
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+
+class Chef
+ class Knife
+ class NodePolicySet < Knife
+
+ deps do
+ require "chef/node"
+ require "chef/json_compat"
+ end
+
+ banner "knife node policy set NODE POLICY_GROUP POLICY_NAME (options)"
+
+ def run
+ validate_node!
+ validate_options!
+ node = Chef::Node.load(@name_args[0])
+ set_policy(node)
+ if node.save
+ ui.info "Successfully set the policy on node #{node.name}"
+ else
+ ui.info "Error in updating node #{node.name}"
+ end
+ end
+
+ private
+
+ # Set policy name and group to node
+ def set_policy(node)
+ policy_group, policy_name = @name_args[1..-1]
+ node.policy_name = policy_name
+ node.policy_group = policy_group
+ end
+
+ # Validate policy name and policy group
+ def validate_options!
+ if incomplete_policyfile_options?
+ ui.error("Policy group and name must be specified together")
+ exit 1
+ end
+ true
+ end
+
+ # Validate node pass in CLI
+ def validate_node!
+ if @name_args[0].nil?
+ ui.error("You must specify a node name")
+ show_usage
+ exit 1
+ end
+ end
+
+ # True if one of policy_name or policy_group was given, but not both
+ def incomplete_policyfile_options?
+ policy_group, policy_name = @name_args[1..-1]
+ (policy_group.nil? || policy_name.nil? || @name_args[1..-1].size > 2)
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/knife/node_run_list_add.rb b/lib/chef/knife/node_run_list_add.rb
index f8d40c8321..fb4ce3bc12 100644
--- a/lib/chef/knife/node_run_list_add.rb
+++ b/lib/chef/knife/node_run_list_add.rb
@@ -27,7 +27,7 @@ class Chef
require "chef/json_compat"
end
- banner "knife node run_list add [NODE] [ENTRY[,ENTRY]] (options)"
+ banner "knife node run_list add [NODE] [ENTRY [ENTRY]] (options)"
option :after,
:short => "-a ITEM",
diff --git a/lib/chef/knife/node_run_list_remove.rb b/lib/chef/knife/node_run_list_remove.rb
index 3f9cdabfff..df50818c23 100644
--- a/lib/chef/knife/node_run_list_remove.rb
+++ b/lib/chef/knife/node_run_list_remove.rb
@@ -27,7 +27,7 @@ class Chef
require "chef/json_compat"
end
- banner "knife node run_list remove [NODE] [ENTRY[,ENTRY]] (options)"
+ banner "knife node run_list remove [NODE] [ENTRY [ENTRY]] (options)"
def run
node = Chef::Node.load(@name_args[0])
diff --git a/lib/chef/knife/node_show.rb b/lib/chef/knife/node_show.rb
index c616b8ab72..3092b3fc27 100644
--- a/lib/chef/knife/node_show.rb
+++ b/lib/chef/knife/node_show.rb
@@ -55,11 +55,6 @@ class Chef
node = Chef::Node.load(@node_name)
output(format_for_display(node))
- self.class.attrs_to_show = []
- end
-
- def self.attrs_to_show=(attrs)
- @attrs_to_show = attrs
end
end
end
diff --git a/lib/chef/knife/osc_user_reregister.rb b/lib/chef/knife/osc_user_reregister.rb
index b513f31328..dee1cf41b1 100644
--- a/lib/chef/knife/osc_user_reregister.rb
+++ b/lib/chef/knife/osc_user_reregister.rb
@@ -49,7 +49,7 @@ class Chef
end
user = Chef::User.load(@user_name).reregister
- Chef::Log.debug("Updated user data: #{user.inspect}")
+ Chef::Log.trace("Updated user data: #{user.inspect}")
key = user.private_key
if config[:file]
File.open(config[:file], "w") do |f|
diff --git a/lib/chef/knife/osc_user_show.rb b/lib/chef/knife/osc_user_show.rb
index 22e9bf4dcd..5350837ad3 100644
--- a/lib/chef/knife/osc_user_show.rb
+++ b/lib/chef/knife/osc_user_show.rb
@@ -48,7 +48,6 @@ class Chef
user = Chef::User.load(@user_name)
output(format_for_display(user))
end
-
end
end
end
diff --git a/lib/chef/knife/role_env_run_list_add.rb b/lib/chef/knife/role_env_run_list_add.rb
index 61aec506a9..4a3bb70641 100644
--- a/lib/chef/knife/role_env_run_list_add.rb
+++ b/lib/chef/knife/role_env_run_list_add.rb
@@ -27,7 +27,7 @@ class Chef
require "chef/json_compat"
end
- banner "knife role env_run_list add [ROLE] [ENVIRONMENT] [ENTRY[,ENTRY]] (options)"
+ banner "knife role env_run_list add [ROLE] [ENVIRONMENT] [ENTRY [ENTRY]] (options)"
option :after,
:short => "-a ITEM",
diff --git a/lib/chef/knife/role_run_list_add.rb b/lib/chef/knife/role_run_list_add.rb
index 6aa92d37ba..7eaaa136bb 100644
--- a/lib/chef/knife/role_run_list_add.rb
+++ b/lib/chef/knife/role_run_list_add.rb
@@ -27,7 +27,7 @@ class Chef
require "chef/json_compat"
end
- banner "knife role run_list add [ROLE] [ENTRY[,ENTRY]] (options)"
+ banner "knife role run_list add [ROLE] [ENTRY [ENTRY]] (options)"
option :after,
:short => "-a ITEM",
diff --git a/lib/chef/knife/search.rb b/lib/chef/knife/search.rb
index 38d1ab3f42..94c33aa594 100644
--- a/lib/chef/knife/search.rb
+++ b/lib/chef/knife/search.rb
@@ -1,6 +1,6 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
-# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,6 +18,7 @@
require "chef/knife"
require "chef/knife/core/node_presenter"
+require "addressable/uri"
class Chef
class Knife
@@ -36,12 +37,6 @@ class Chef
banner "knife search INDEX QUERY (options)"
- option :sort,
- :short => "-o SORT",
- :long => "--sort SORT",
- :description => "The order to sort the results in",
- :default => nil
-
option :start,
:short => "-b ROW",
:long => "--start ROW",
@@ -78,33 +73,34 @@ class Chef
def run
read_cli_args
- fuzzify_query
if @type == "node"
ui.use_presenter Knife::Core::NodePresenter
end
q = Chef::Search::Query.new
- escaped_query = URI.escape(@query,
- Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
result_items = []
result_count = 0
search_args = Hash.new
- search_args[:sort] = config[:sort] if config[:sort]
+ search_args[:fuzz] = true
search_args[:start] = config[:start] if config[:start]
search_args[:rows] = config[:rows] if config[:rows]
if config[:filter_result]
search_args[:filter_result] = create_result_filter(config[:filter_result])
elsif (not ui.config[:attribute].nil?) && (not ui.config[:attribute].empty?)
search_args[:filter_result] = create_result_filter_from_attributes(ui.config[:attribute])
+ elsif config[:id_only]
+ search_args[:filter_result] = create_result_filter_from_attributes([])
end
begin
- q.search(@type, escaped_query, search_args) do |item|
+ q.search(@type, @query, search_args) do |item|
formatted_item = Hash.new
- if item.is_a?(Hash)
+ if config[:id_only]
+ formatted_item = format_for_display({ "id" => item["__display_name"] })
+ elsif item.is_a?(Hash)
# doing a little magic here to set the correct name
formatted_item[item["__display_name"]] = item.reject { |k| k == "__display_name" }
else
@@ -116,7 +112,7 @@ class Chef
rescue Net::HTTPServerException => e
msg = Chef::JSONCompat.from_json(e.response.body)["error"].first
ui.error("knife search failed: #{msg}")
- exit 1
+ exit 99
end
if ui.interchange?
@@ -131,6 +127,9 @@ class Chef
end
end
end
+
+ # return a "failure" code to the shell so that knife search can be used in pipes similar to grep
+ exit 1 if result_count == 0
end
def read_cli_args
@@ -158,12 +157,6 @@ class Chef
end
end
- def fuzzify_query
- if @query !~ /:/
- @query = "tags:*#{@query}* OR roles:*#{@query}* OR fqdn:*#{@query}* OR addresses:*#{@query}* OR policy_name:*#{@query}* OR policy_group:*#{@query}*"
- end
- end
-
# This method turns a set of key value pairs in a string into the appropriate data structure that the
# chef-server search api is expecting.
# expected input is in the form of:
@@ -183,7 +176,7 @@ class Chef
return_id, attr_path = f.split("=")
final_filter[return_id.to_sym] = attr_path.split(".")
end
- return final_filter
+ final_filter
end
def create_result_filter_from_attributes(filter_array)
@@ -193,7 +186,7 @@ class Chef
end
# adding magic filter so we can actually pull the name as before
final_filter["__display_name"] = [ "name" ]
- return final_filter
+ final_filter
end
end
diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb
index 2bbcbfc79e..c38dc43e74 100644
--- a/lib/chef/knife/ssh.rb
+++ b/lib/chef/knife/ssh.rb
@@ -1,6 +1,6 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
-# Copyright:: Copyright 2009-2016, Chef Software Inc.
+# Copyright:: Copyright 2009-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,7 +26,6 @@ class Chef
deps do
require "net/ssh"
require "net/ssh/multi"
- require "chef/monkey_patches/net-ssh-multi"
require "readline"
require "chef/exceptions"
require "chef/search/query"
@@ -47,11 +46,10 @@ class Chef
:default => nil,
:proc => lambda { |o| o.to_i }
- option :attribute,
+ option :ssh_attribute,
:short => "-a ATTR",
:long => "--attribute ATTR",
- :description => "The attribute to use for opening the connection - default depends on the context",
- :proc => Proc.new { |key| Chef::Config[:knife][:ssh_attribute] = key.strip }
+ :description => "The attribute to use for opening the connection - default depends on the context"
option :manual,
:short => "-m",
@@ -60,6 +58,10 @@ class Chef
:description => "QUERY is a space separated list of servers",
:default => false
+ option :prefix_attribute,
+ :long => "--prefix-attribute ATTR",
+ :description => "The attribute to use for prefixing the ouput - default depends on the context"
+
option :ssh_user,
:short => "-x USERNAME",
:long => "--ssh-user USERNAME",
@@ -93,16 +95,16 @@ class Chef
:description => "The ssh gateway",
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key.strip }
+ option :ssh_gateway_identity,
+ :long => "--ssh-gateway-identity SSH_GATEWAY_IDENTITY",
+ :description => "The SSH identity file used for gateway authentication"
+
option :forward_agent,
:short => "-A",
:long => "--forward-agent",
:description => "Enable SSH agent forwarding",
:boolean => true
- option :identity_file,
- :long => "--identity-file IDENTITY_FILE",
- :description => "The SSH identity file used for authentication. [DEPRECATED] Use --ssh-identity-file instead."
-
option :ssh_identity_file,
:short => "-i IDENTITY_FILE",
:long => "--ssh-identity-file IDENTITY_FILE",
@@ -119,7 +121,13 @@ class Chef
:long => "--exit-on-error",
:description => "Immediately exit if an error is encountered",
:boolean => true,
- :proc => Proc.new { :raise }
+ :default => false
+
+ 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 },
+ :default => :ignore
option :tmux_split,
:long => "--tmux-split",
@@ -128,15 +136,13 @@ class Chef
:default => false
def session
- config[:on_error] ||= :skip
ssh_error_handler = Proc.new do |server|
- case config[:on_error]
- when :skip
- ui.warn "Failed to connect to #{server.host} -- #{$!.class.name}: #{$!.message}"
- $!.backtrace.each { |l| Chef::Log.debug(l) }
- when :raise
+ if config[:on_error]
#Net::SSH::Multi magic to force exception to be re-raised.
throw :go, :raise
+ else
+ ui.warn "Failed to connect to #{server.host} -- #{$!.class.name}: #{$!.message}"
+ $!.backtrace.each { |l| Chef::Log.debug(l) }
end
end
@@ -148,7 +154,7 @@ class Chef
if config[:ssh_gateway]
gw_host, gw_user = config[:ssh_gateway].split("@").reverse
gw_host, gw_port = gw_host.split(":")
- gw_opts = session_options(gw_host, gw_port, gw_user)
+ gw_opts = session_options(gw_host, gw_port, gw_user, gateway: true)
user = gw_opts.delete(:user)
begin
@@ -164,63 +170,92 @@ class Chef
end
def configure_session
- list = config[:manual] ?
- @name_args[0].split(" ") :
- search_nodes
+ list = config[:manual] ? @name_args[0].split(" ") : search_nodes
if list.length == 0
- if @action_nodes.length == 0
+ if @search_count == 0
ui.fatal("No nodes returned from search")
else
- ui.fatal("#{@action_nodes.length} #{@action_nodes.length > 1 ? "nodes" : "node"} found, " +
+ ui.fatal("#{@search_count} #{@search_count > 1 ? "nodes" : "node"} found, " +
"but does not have the required attribute to establish the connection. " +
"Try setting another attribute to open the connection using --attribute.")
end
exit 10
end
+ if %i{warn fatal}.include?(config[:duplicated_fqdns])
+ fqdns = list.map { |v| v[0] }
+ if fqdns.count != fqdns.uniq.count
+ duplicated_fqdns = fqdns.uniq
+ ui.send(config[:duplicated_fqdns],
+ "SSH #{duplicated_fqdns.count > 1 ? 'nodes are' : 'node is'} " +
+ "duplicated: #{duplicated_fqdns.join(',')}")
+ exit 10 if config[:duplicated_fqdns] == :fatal
+ end
+ end
session_from_list(list)
end
- def get_ssh_attribute(node)
+ def get_prefix_attribute(item)
+ # Order of precedence for prefix
+ # 1) config value (cli or knife config)
+ # 2) nil
+ msg = "Using node attribute '%s' as the prefix: %s"
+ if item["prefix"]
+ Chef::Log.debug(sprintf(msg, config[:prefix_attribute], item["prefix"]))
+ item["prefix"]
+ else
+ nil
+ end
+ end
+
+ def get_ssh_attribute(item)
# Order of precedence for ssh target
- # 1) command line attribute
- # 2) configuration file
- # 3) cloud attribute
- # 4) fqdn
- if config[:attribute]
- Chef::Log.debug("Using node attribute '#{config[:attribute]}' as the ssh target")
- attribute = config[:attribute]
- elsif Chef::Config[:knife][:ssh_attribute]
- Chef::Log.debug("Using node attribute #{Chef::Config[:knife][:ssh_attribute]}")
- attribute = Chef::Config[:knife][:ssh_attribute]
- elsif node[:cloud] &&
- node[:cloud][:public_hostname] &&
- !node[:cloud][:public_hostname].empty?
- Chef::Log.debug("Using node attribute 'cloud[:public_hostname]' automatically as the ssh target")
- attribute = "cloud.public_hostname"
+ # 1) config value (cli or knife config)
+ # 2) cloud attribute
+ # 3) fqdn
+ msg = "Using node attribute '%s' as the ssh target: %s"
+ if item["target"]
+ Chef::Log.debug(sprintf(msg, config[:ssh_attribute], item["target"]))
+ item["target"]
+ elsif !item.dig("cloud", "public_hostname").to_s.empty?
+ Chef::Log.debug(sprintf(msg, "cloud.public_hostname", item["cloud"]["public_hostname"]))
+ item["cloud"]["public_hostname"]
else
- # falling back to default of fqdn
- Chef::Log.debug("Using node attribute 'fqdn' as the ssh target")
- attribute = "fqdn"
+ Chef::Log.debug(sprintf(msg, "fqdn", item["fqdn"]))
+ item["fqdn"]
end
- attribute
end
def search_nodes
list = Array.new
query = Chef::Search::Query.new
- @action_nodes = query.search(:node, @name_args[0])[0]
- @action_nodes.each do |item|
+ required_attributes = { fqdn: ["fqdn"], cloud: ["cloud"] }
+
+ separator = ui.presenter.attribute_field_separator
+
+ if config[:prefix_attribute]
+ required_attributes[:prefix] = config[:prefix_attribute].split(separator)
+ end
+
+ if config[:ssh_attribute]
+ required_attributes[:target] = config[:ssh_attribute].split(separator)
+ end
+
+ @search_count = 0
+ query.search(:node, @name_args[0], filter_result: required_attributes, fuzz: true) do |item|
+ @search_count += 1
# we should skip the loop to next iteration if the item
# returned by the search is nil
next if item.nil?
# next if we couldn't find the specified attribute in the
# returned node object
- host = extract_nested_value(item, get_ssh_attribute(item))
+ host = get_ssh_attribute(item)
next if host.nil?
- ssh_port = item[:cloud].nil? ? nil : item[:cloud][:public_ssh_port]
- srv = [host, ssh_port]
+ prefix = get_prefix_attribute(item)
+ ssh_port = item.dig("cloud", "public_ssh_port")
+ srv = [host, ssh_port, prefix]
list.push(srv)
end
+
list
end
@@ -232,15 +267,19 @@ class Chef
# @param host [String] Hostname for this session.
# @param port [String] SSH port for this session.
# @param user [String] Optional username for this session.
+ # @param gateway [Boolean] Flag: host or gateway key
# @return [Hash<Symbol, Object>]
- def session_options(host, port, user = nil)
- ssh_config = Net::SSH.configuration_for(host)
+ 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 config[:ssh_identity_file]
+ if !gateway && config[:ssh_identity_file]
opts[:keys] = File.expand_path(config[:ssh_identity_file])
opts[:keys_only] = true
+ elsif gateway && config[:ssh_gateway_identity]
+ opts[:keys] = File.expand_path(config[:ssh_gateway_identity])
+ opts[:keys_only] = true
elsif config[:ssh_password]
opts[:password] = config[:ssh_password]
end
@@ -249,38 +288,45 @@ class Chef
opts[:forward_agent] = forward_agent unless forward_agent.nil?
port ||= ssh_config[:port]
opts[:port] = port unless port.nil?
- opts[:logger] = Chef::Log.logger if Chef::Log.level == :debug
+ opts[:logger] = Chef::Log.with_child(subsystem: "net/ssh") if Chef::Log.level == :trace
if !config[:host_key_verify]
- opts[:paranoid] = false
+ opts[:verify_host_key] = false
opts[:user_known_hosts_file] = "/dev/null"
end
+ if ssh_config[:keepalive]
+ opts[:keepalive] = true
+ opts[:keepalive_interval] = ssh_config[:keepalive_interval]
+ end
end
end
def session_from_list(list)
list.each do |item|
- host, ssh_port = item
+ host, ssh_port, prefix = item
+ prefix = host unless prefix
Chef::Log.debug("Adding #{host}")
- session_opts = session_options(host, ssh_port)
+ 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 }
# Create the hostspec.
hostspec = session_opts[:user] ? "#{session_opts.delete(:user)}@#{host}" : host
# Connect a new session on the multi.
session.use(hostspec, session_opts)
- @longest = host.length if host.length > @longest
+ @longest = prefix.length if prefix.length > @longest
end
session
end
def fixup_sudo(command)
- command.sub(/^sudo/, 'sudo -p \'knife sudo password: \'')
+ command.sub(/^sudo/, "sudo -p 'knife sudo password: '")
end
def print_data(host, data)
@@ -311,19 +357,23 @@ class Chef
subsession ||= session
command = fixup_sudo(command)
command.force_encoding("binary") if command.respond_to?(:force_encoding)
- subsession.open_channel do |ch|
- ch.request_pty
- ch.exec command do |ch, success|
- raise ArgumentError, "Cannot execute #{command}" unless success
- ch.on_data do |ichannel, data|
- print_data(ichannel[:host], data)
- if data =~ /^knife sudo password: /
- print_data(ichannel[:host], "\n")
- ichannel.send_data("#{get_password}\n")
+ subsession.open_channel do |chan|
+ if config[:on_error] && exit_status != 0
+ chan.close()
+ else
+ chan.request_pty
+ chan.exec command do |ch, success|
+ raise ArgumentError, "Cannot execute #{command}" unless success
+ ch.on_data do |ichannel, data|
+ print_data(ichannel.connection[:prefix], data)
+ if data =~ /^knife sudo password: /
+ print_data(ichannel.connection[:prefix], "\n")
+ ichannel.send_data("#{get_password}\n")
+ end
+ end
+ ch.on_request "exit-status" do |ichannel, data|
+ exit_status = [exit_status, data.read_long].max
end
- end
- ch.on_request "exit-status" do |ichannel, data|
- exit_status = [exit_status, data.read_long].max
end
end
end
@@ -434,7 +484,7 @@ class Chef
end.join(" \\; ")
end
- tmux_name = "'knife ssh #{@name_args[0].tr(':', '=')}'"
+ tmux_name = "'knife ssh #{@name_args[0].tr(':.', '=-')}'"
begin
server = session.servers_for.first
cmd = ["tmux new-session -d -s #{tmux_name}",
@@ -530,12 +580,11 @@ class Chef
end
def configure_ssh_identity_file
- # config[:identity_file] is DEPRECATED in favor of :ssh_identity_file
- config[:ssh_identity_file] = get_stripped_unfrozen_value(config[:ssh_identity_file] || config[:identity_file] || Chef::Config[:knife][:ssh_identity_file])
+ config[:ssh_identity_file] = get_stripped_unfrozen_value(config[:ssh_identity_file] || Chef::Config[:knife][:ssh_identity_file])
end
- def extract_nested_value(data_structure, path_spec)
- ui.presenter.extract_nested_value(data_structure, path_spec)
+ def configure_ssh_gateway_identity
+ config[:ssh_gateway_identity] = get_stripped_unfrozen_value(config[:ssh_gateway_identity] || Chef::Config[:knife][:ssh_gateway_identity])
end
def run
@@ -543,29 +592,32 @@ class Chef
configure_user
configure_password
- configure_ssh_identity_file
+ @password = config[:ssh_password] if config[:ssh_password]
+
+ # If a password was not given, check for SSH identity file.
+ if !@password
+ configure_ssh_identity_file
+ configure_ssh_gateway_identity
+ end
+
configure_gateway
configure_session
exit_status =
- case @name_args[1]
- when "interactive"
- interactive
- when "screen"
- screen
- when "tmux"
- tmux
- when "macterm"
- macterm
- when "cssh"
- cssh
- when "csshx"
- Chef::Log.warn("knife ssh csshx will be deprecated in a future release")
- Chef::Log.warn("please use knife ssh cssh instead")
- cssh
- else
- ssh_command(@name_args[1..-1].join(" "))
- end
+ case @name_args[1]
+ when "interactive"
+ interactive
+ when "screen"
+ screen
+ when "tmux"
+ tmux
+ when "macterm"
+ macterm
+ when "cssh"
+ cssh
+ else
+ ssh_command(@name_args[1..-1].join(" "))
+ end
session.close
if exit_status != 0
diff --git a/lib/chef/knife/ssl_check.rb b/lib/chef/knife/ssl_check.rb
index 0c672f322e..c864ef52ec 100644
--- a/lib/chef/knife/ssl_check.rb
+++ b/lib/chef/knife/ssl_check.rb
@@ -44,7 +44,7 @@ class Chef
def uri
@uri ||= begin
- Chef::Log.debug("Checking SSL cert on #{given_uri}")
+ Chef::Log.trace("Checking SSL cert on #{given_uri}")
URI.parse(given_uri)
end
end
@@ -131,7 +131,7 @@ class Chef
true
rescue OpenSSL::SSL::SSLError => e
ui.error "The SSL certificate of #{host} could not be verified"
- Chef::Log.debug e.message
+ Chef::Log.trace e.message
debug_invalid_cert
false
end
@@ -141,7 +141,7 @@ class Chef
true
rescue OpenSSL::SSL::SSLError => e
ui.error "The SSL cert is signed by a trusted authority but is not valid for the given hostname"
- Chef::Log.debug(e)
+ Chef::Log.trace(e)
debug_invalid_host
false
end
@@ -257,7 +257,8 @@ ADVICE
def trusted_certificates
if configuration.trusted_certs_dir && Dir.exist?(configuration.trusted_certs_dir)
- Dir.glob(File.join(configuration.trusted_certs_dir, "*.{crt,pem}"))
+ glob_dir = ChefConfig::PathHelper.escape_glob_dir(configuration.trusted_certs_dir)
+ Dir.glob(File.join(glob_dir, "*.{crt,pem}"))
else
[]
end
@@ -275,7 +276,7 @@ ADVICE
rescue OpenSSL::X509::StoreError => e
return e.message
end
- return nil
+ nil
end
end
end
diff --git a/lib/chef/knife/ssl_fetch.rb b/lib/chef/knife/ssl_fetch.rb
index 5af1a905d5..98c98d06ae 100644
--- a/lib/chef/knife/ssl_fetch.rb
+++ b/lib/chef/knife/ssl_fetch.rb
@@ -41,7 +41,7 @@ class Chef
def uri
@uri ||= begin
- Chef::Log.debug("Checking SSL cert on #{given_uri}")
+ Chef::Log.trace("Checking SSL cert on #{given_uri}")
URI.parse(given_uri)
end
end
@@ -89,8 +89,11 @@ class Chef
def cn_of(certificate)
subject = certificate.subject
- cn_field_tuple = subject.to_a.find { |field| field[0] == "CN" }
- cn_field_tuple[1]
+ if cn_field_tuple = subject.to_a.find { |field| field[0] == "CN" }
+ cn_field_tuple[1]
+ else
+ nil
+ end
end
# Convert the CN of a certificate into something that will work well as a
@@ -117,9 +120,10 @@ class Chef
def write_cert(cert)
FileUtils.mkdir_p(trusted_certs_dir)
cn = cn_of(cert)
- filename = File.join(trusted_certs_dir, "#{normalize_cn(cn)}.crt")
- ui.msg("Adding certificate for #{cn} in #{filename}")
- File.open(filename, File::CREAT | File::TRUNC | File::RDWR, 0644) do |f|
+ filename = cn.nil? ? "#{host}_#{Time.new.to_i}" : normalize_cn(cn)
+ full_path = File.join(trusted_certs_dir, "#{filename}.crt")
+ ui.msg("Adding certificate for #{filename} in #{full_path}")
+ File.open(full_path, File::CREAT | File::TRUNC | File::RDWR, 0644) do |f|
f.print(cert.to_s)
end
end
diff --git a/lib/chef/knife/status.rb b/lib/chef/knife/status.rb
index 551d5addfc..0e3cd7e7d6 100644
--- a/lib/chef/knife/status.rb
+++ b/lib/chef/knife/status.rb
@@ -96,13 +96,13 @@ class Chef
all_nodes << node
end
- output(all_nodes.sort { |n1, n2|
+ output(all_nodes.sort do |n1, n2|
if config[:sort_reverse] || Chef::Config[:knife][:sort_status_reverse]
(n2["ohai_time"] || 0) <=> (n1["ohai_time"] || 0)
else
(n1["ohai_time"] || 0) <=> (n2["ohai_time"] || 0)
end
- })
+ end)
end
end
diff --git a/lib/chef/knife/supermarket_download.rb b/lib/chef/knife/supermarket_download.rb
new file mode 100644
index 0000000000..5657558591
--- /dev/null
+++ b/lib/chef/knife/supermarket_download.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_download"
+
+class Chef
+ class Knife
+ class SupermarketDownload < Knife::CookbookSiteDownload
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket download COOKBOOK [VERSION] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/cookbook_site_vendor.rb b/lib/chef/knife/supermarket_install.rb
index 291715cc0b..7642e68181 100644
--- a/lib/chef/knife/cookbook_site_vendor.rb
+++ b/lib/chef/knife/supermarket_install.rb
@@ -1,6 +1,6 @@
#
-# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2011-2016, Chef Software Inc.
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,28 +19,15 @@
require "chef/knife"
require "chef/knife/cookbook_site_install"
-class Chef::Knife::CookbookSiteVendor < Chef::Knife::CookbookSiteInstall
+class Chef
+ class Knife
+ class SupermarketInstall < Knife::CookbookSiteInstall
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
- def self.load_deps
- superclass.load_deps
+ banner "knife supermarket install COOKBOOK [VERSION] (options)"
+ category "supermarket"
+ end
end
-
- def self.options=(new_opts)
- superclass.options = new_opts
- end
-
- def self.options
- superclass.options
- end
-
- banner(<<-B)
-*************************************************
-DEPRECATED: please use knife cookbook site install
-*************************************************
-
-#{superclass.banner}
-B
-
- category "deprecated"
-
end
diff --git a/lib/chef/knife/supermarket_list.rb b/lib/chef/knife/supermarket_list.rb
new file mode 100644
index 0000000000..f2bc98bd0e
--- /dev/null
+++ b/lib/chef/knife/supermarket_list.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_list"
+
+class Chef
+ class Knife
+ class SupermarketList < Knife::CookbookSiteList
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket list (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_search.rb b/lib/chef/knife/supermarket_search.rb
new file mode 100644
index 0000000000..3206b0cb80
--- /dev/null
+++ b/lib/chef/knife/supermarket_search.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_search"
+
+class Chef
+ class Knife
+ class SupermarketSearch < Knife::CookbookSiteSearch
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket search QUERY (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_share.rb b/lib/chef/knife/supermarket_share.rb
new file mode 100644
index 0000000000..3109b9e794
--- /dev/null
+++ b/lib/chef/knife/supermarket_share.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_share"
+
+class Chef
+ class Knife
+ class SupermarketShare < Knife::CookbookSiteShare
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket share COOKBOOK [CATEGORY] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_show.rb b/lib/chef/knife/supermarket_show.rb
new file mode 100644
index 0000000000..2ad122143f
--- /dev/null
+++ b/lib/chef/knife/supermarket_show.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_show"
+
+class Chef
+ class Knife
+ class SupermarketShow < Knife::CookbookSiteShow
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket show COOKBOOK [VERSION] (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/supermarket_unshare.rb b/lib/chef/knife/supermarket_unshare.rb
new file mode 100644
index 0000000000..fd48e172ce
--- /dev/null
+++ b/lib/chef/knife/supermarket_unshare.rb
@@ -0,0 +1,33 @@
+#
+# Author:: Christopher Webber (<cwebber@chef.io>)
+# Copyright:: Copyright (c) 2014 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/knife"
+require "chef/knife/cookbook_site_unshare"
+
+class Chef
+ class Knife
+ class SupermarketUnshare < Knife::CookbookSiteUnshare
+ # Handle the subclassing (knife doesn't do this :()
+ dependency_loaders.concat(superclass.dependency_loaders)
+ options.merge!(superclass.options)
+
+ banner "knife supermarket unshare COOKBOOK (options)"
+ category "supermarket"
+ end
+ end
+end
diff --git a/lib/chef/knife/user_create.rb b/lib/chef/knife/user_create.rb
index d21afb1059..c4a89f3707 100644
--- a/lib/chef/knife/user_create.rb
+++ b/lib/chef/knife/user_create.rb
@@ -78,6 +78,8 @@ knife user create for Open Source 11 Server is being deprecated.
Open Source 11 Server user commands now live under the knife osc_user namespace.
For backwards compatibility, we will forward this request to knife osc_user create.
If you are using an Open Source 11 Server, please use that command to avoid this warning.
+NOTE: Backwards compatibility for Open Source 11 Server in these commands will be removed
+in Chef 15 which will be released April 2019.
EOF
end
diff --git a/lib/chef/knife/user_delete.rb b/lib/chef/knife/user_delete.rb
index ce4575ceab..abfb45253e 100644
--- a/lib/chef/knife/user_delete.rb
+++ b/lib/chef/knife/user_delete.rb
@@ -37,6 +37,8 @@ knife user delete for Open Source 11 Server is being deprecated.
Open Source 11 Server user commands now live under the knife osc_user namespace.
For backwards compatibility, we will forward this request to knife osc_user delete.
If you are using an Open Source 11 Server, please use that command to avoid this warning.
+NOTE: Backwards compatibility for Open Source 11 Server in these commands will be removed
+in Chef 15 which will be released April 2019.
EOF
end
@@ -60,7 +62,7 @@ EOF
end
output(format_for_display(object)) if config[:print_after]
- self.msg("Deleted #{user_name}")
+ msg("Deleted #{user_name}")
end
def run
diff --git a/lib/chef/knife/user_edit.rb b/lib/chef/knife/user_edit.rb
index bb80ede267..d184b85a6c 100644
--- a/lib/chef/knife/user_edit.rb
+++ b/lib/chef/knife/user_edit.rb
@@ -37,6 +37,8 @@ knife user edit for Open Source 11 Server is being deprecated.
Open Source 11 Server user commands now live under the knife oc_user namespace.
For backwards compatibility, we will forward this request to knife osc_user edit.
If you are using an Open Source 11 Server, please use that command to avoid this warning.
+NOTE: Backwards compatibility for Open Source 11 Server in these commands will be removed
+in Chef 15 which will be released April 2019.
EOF
end
diff --git a/lib/chef/knife/user_key_create.rb b/lib/chef/knife/user_key_create.rb
index 95a98a2f4f..1cceb886c4 100644
--- a/lib/chef/knife/user_key_create.rb
+++ b/lib/chef/knife/user_key_create.rb
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/knife/key_create"
require "chef/knife/key_create_base"
class Chef
diff --git a/lib/chef/knife/user_key_delete.rb b/lib/chef/knife/user_key_delete.rb
index 1c559f2ef0..2a0c958ed9 100644
--- a/lib/chef/knife/user_key_delete.rb
+++ b/lib/chef/knife/user_key_delete.rb
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/knife/key_delete"
class Chef
class Knife
diff --git a/lib/chef/knife/user_key_edit.rb b/lib/chef/knife/user_key_edit.rb
index 561af8edd0..ca056e3650 100644
--- a/lib/chef/knife/user_key_edit.rb
+++ b/lib/chef/knife/user_key_edit.rb
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/knife/key_edit"
require "chef/knife/key_edit_base"
class Chef
diff --git a/lib/chef/knife/user_key_list.rb b/lib/chef/knife/user_key_list.rb
index 799c069182..10583f4a3c 100644
--- a/lib/chef/knife/user_key_list.rb
+++ b/lib/chef/knife/user_key_list.rb
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/knife/key_list"
require "chef/knife/key_list_base"
class Chef
diff --git a/lib/chef/knife/user_key_show.rb b/lib/chef/knife/user_key_show.rb
index e09d5e04ed..b3a6ee73dc 100644
--- a/lib/chef/knife/user_key_show.rb
+++ b/lib/chef/knife/user_key_show.rb
@@ -17,6 +17,7 @@
#
require "chef/knife"
+require "chef/knife/key_show"
class Chef
class Knife
diff --git a/lib/chef/knife/user_reregister.rb b/lib/chef/knife/user_reregister.rb
index 8d2f2c1e73..fec6792134 100644
--- a/lib/chef/knife/user_reregister.rb
+++ b/lib/chef/knife/user_reregister.rb
@@ -37,6 +37,8 @@ knife user reregister for Open Source 11 Server is being deprecated.
Open Source 11 Server user commands now live under the knife osc_user namespace.
For backwards compatibility, we will forward this request to knife osc_user reregister.
If you are using an Open Source 11 Server, please use that command to avoid this warning.
+NOTE: Backwards compatibility for Open Source 11 Server in these commands will be removed
+in Chef 15 which will be released April 2019.
EOF
end
@@ -73,7 +75,7 @@ EOF
run_osc_11_user_reregister
else # EC / CS 12 case
user.reregister
- Chef::Log.debug("Updated user data: #{user.inspect}")
+ Chef::Log.trace("Updated user data: #{user.inspect}")
key = user.private_key
if config[:file]
File.open(config[:file], "w") do |f|
diff --git a/lib/chef/knife/user_show.rb b/lib/chef/knife/user_show.rb
index 04251c0863..6ba4ab5016 100644
--- a/lib/chef/knife/user_show.rb
+++ b/lib/chef/knife/user_show.rb
@@ -39,6 +39,8 @@ knife user show for Open Source 11 Server is being deprecated.
Open Source 11 Server user commands now live under the knife osc_user namespace.
For backwards compatibility, we will forward this request to knife osc_user show.
If you are using an Open Source 11 Server, please use that command to avoid this warning.
+NOTE: Backwards compatibility for Open Source 11 Server in these commands will be removed
+in Chef 15 which will be released April 2019.
EOF
end
diff --git a/lib/chef/knife/xargs.rb b/lib/chef/knife/xargs.rb
index 6559ca2e74..a316fb8cf7 100644
--- a/lib/chef/knife/xargs.rb
+++ b/lib/chef/knife/xargs.rb
@@ -9,7 +9,7 @@ class Chef
deps do
require "chef/chef_fs/file_system"
- require "chef/chef_fs/file_system/not_found_error"
+ require "chef/chef_fs/file_system/exceptions"
end
# TODO modify to remote-only / local-only pattern (more like delete)
@@ -181,7 +181,7 @@ class Chef
def destroy_tempfiles(tempfiles)
# Unlink the files now that we're done with them
- tempfiles.keys.each { |tempfile| tempfile.close! }
+ tempfiles.each_key { |tempfile| tempfile.close! }
end
def xargs_files(command, tempfiles)