summaryrefslogtreecommitdiff
path: root/lib/chef/knife
diff options
context:
space:
mode:
authorNoah Kantrowitz <noah@coderanger.net>2018-07-11 12:55:18 -0700
committerNoah Kantrowitz <noah@coderanger.net>2018-07-11 12:55:18 -0700
commitd730505bb0d53d14c7b005c756ed4993b95fdf94 (patch)
tree5c66f3c25001fdcd654580dff3e2b195dc2135a0 /lib/chef/knife
parentac977e9494d516fbc44d6012bb157254c28c0a05 (diff)
downloadchef-d730505bb0d53d14c7b005c756ed4993b95fdf94.tar.gz
New `knife config list-profiles` command to show available profiles.
Signed-off-by: Noah Kantrowitz <noah@coderanger.net>
Diffstat (limited to 'lib/chef/knife')
-rw-r--r--lib/chef/knife/config_list_profiles.rb121
1 files changed, 121 insertions, 0 deletions
diff --git a/lib/chef/knife/config_list_profiles.rb b/lib/chef/knife/config_list_profiles.rb
new file mode 100644
index 0000000000..8780f5824a
--- /dev/null
+++ b/lib/chef/knife/config_list_profiles.rb
@@ -0,0 +1,121 @@
+#
+# Copyright:: Copyright (c) 2018, Noah Kantrowitz
+# 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/workstation_config_loader"
+
+class Chef
+ class Knife
+ class ConfigListProfiles < Knife
+ banner "knife config list-profiles"
+
+ option :ignore_knife_rb,
+ short: "-i",
+ long: "--ignore-knife-rb",
+ description: "Ignore the current knife.rb configuration",
+ default: false
+
+ def run
+ credentials_data = self.class.config_loader.parse_credentials_file
+ if credentials_data.nil? || credentials_data.empty?
+ # Should this just show the ambient knife.rb config as "default" instead?
+ ui.fatal("No profiles found, #{self.class.config_loader.credentials_file_path} does not exist or is empty")
+ exit 1
+ end
+
+ current_profile = self.class.config_loader.credentials_profile(config[:profile])
+ profiles = credentials_data.keys.map do |profile|
+ if config[:ignore_knife_rb]
+ # Don't do any fancy loading nonsense, just the raw data.
+ profile_data = credentials_data[profile]
+ {
+ profile: profile,
+ active: profile == current_profile,
+ client_name: profile_data["client_name"] || profile_data["node_name"],
+ client_key: profile_data["client_key"],
+ server_url: profile_data["chef_server_url"],
+ }
+ else
+ # Fancy loading nonsense so we get what the actual config would be.
+ # Note that this modifies the global config, after this, all bets are
+ # off as to whats in the config.
+ Chef::Config.reset
+ wcl = Chef::WorkstationConfigLoader.new(nil, Chef::Log, profile: profile)
+ wcl.load
+ {
+ profile: profile,
+ active: profile == current_profile,
+ client_name: Chef::Config[:node_name],
+ client_key: Chef::Config[:client_key],
+ server_url: Chef::Config[:chef_server_url],
+ }
+ end
+ end
+
+ # Try to reset the config.
+ unless config[:ignore_knife_rb]
+ Chef::Config.reset
+ Chef::WorkstationConfigLoader.new(config[:config_file], Chef::Log, profile: config[:profile]).load
+ apply_computed_config
+ end
+
+ if ui.interchange?
+ # Machine-readable output.
+ ui.output(profiles)
+ else
+ # Table output.
+ ui.output(render_table(profiles))
+ end
+ end
+
+ private
+
+ def render_table(profiles, padding: 2)
+ # Replace the home dir in the client key path with ~.
+ profiles.each do |profile|
+ profile[:client_key] = profile[:client_key].to_s.gsub(/^#{Regexp.escape(Dir.home)}/, '~') if profile[:client_key]
+ end
+ # Render the data to a 2D array that will be used for the table.
+ table_data = [['', 'Profile', 'Client', 'Key', 'Server']] + profiles.map do |profile|
+ [profile[:active] ? '*' : ''] + profile.values_at(:profile, :client_name, :client_key, :server_url).map(&:to_s)
+ end
+ # Compute column widths.
+ column_widths = table_data.first.length.times.map do |i|
+ table_data.map { |row| row[i].length + padding }.max
+ end
+ # Special case, the first col gets no padding (because indicator) and last
+ # get no padding because last.
+ column_widths[0] -= padding
+ column_widths[-1] -= padding
+ # Build the format string for each row.
+ format_string = column_widths.map { |w| "%-#{w}.#{w}s" }.join('')
+ format_string << "\n"
+ # Print the header row and a separator.
+ table = ui.color(format_string % table_data.first, :green)
+ table << "-" * column_widths.sum
+ table << "\n"
+ # Print the rest of the table.
+ table_data.drop(1).each do |row|
+ table << format_string % row
+ end
+ # Trim the last newline because ui.output adds one.
+ table.chomp!
+ end
+
+ end
+ end
+end