diff options
author | Vivek Singh <vivek.singh@msystechnologies.com> | 2020-08-21 15:51:44 +0530 |
---|---|---|
committer | Vivek Singh <vivek.singh@msystechnologies.com> | 2020-08-25 16:31:47 +0530 |
commit | 03f822e5e1772f3ad7c7c5232f5c17f6263f6688 (patch) | |
tree | 78d9309e4014c5f44274155a84d933b9ffe0753d | |
parent | 894e9d4bf863d307c0090476df2ff551a9856fb9 (diff) | |
download | chef-03f822e5e1772f3ad7c7c5232f5c17f6263f6688.tar.gz |
Added config list use & show sub command
Signed-off-by: Vivek Singh <vivek.singh@msystechnologies.com>
-rw-r--r-- | lib/chef/knife/config_list.rb | 128 | ||||
-rw-r--r-- | lib/chef/knife/config_show.rb | 127 | ||||
-rw-r--r-- | lib/chef/knife/config_use.rb | 61 |
3 files changed, 316 insertions, 0 deletions
diff --git a/lib/chef/knife/config_list.rb b/lib/chef/knife/config_list.rb new file mode 100644 index 0000000000..9646178289 --- /dev/null +++ b/lib/chef/knife/config_list.rb @@ -0,0 +1,128 @@ +# +# Author:: Vivek Singh (<vsingh@chef.io>) +# Copyright:: Copyright (c) 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_relative "../knife" + +class Chef + class Knife + class ConfigList < Knife + banner "knife config list (options)" + + deps do + require_relative "../workstation_config_loader" + end + + option :ignore_knife_rb, + short: "-i", + long: "--ignore-knife-rb", + description: "Ignore the current config.rb/knife.rb configuration.", + default: false + + def configure_chef + apply_computed_config + end + + 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 + 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 = Array.new(table_data.first.length) 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 diff --git a/lib/chef/knife/config_show.rb b/lib/chef/knife/config_show.rb new file mode 100644 index 0000000000..b8b55e11f6 --- /dev/null +++ b/lib/chef/knife/config_show.rb @@ -0,0 +1,127 @@ +# +# Author:: Vivek Singh (<vsingh@chef.io>) +# Copyright:: Copyright (c) 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_relative "../knife" + +class Chef + class Knife + class ConfigShow < Knife + banner "knife config show [OPTION...] (options)\nDisplays the value of Chef::Config[OPTION] (or all config values)" + + option :all, + short: "-a", + long: "--all", + description: "Include options that are not set in the configuration.", + default: false + + option :raw, + short: "-r", + long: "--raw", + description: "Display a each value with no formatting.", + default: false + + def run + if config[:format] == "summary" && !config[:raw] + # If using the default, human-readable output, also show which config files are being loaded. + # Some of this is a bit hacky since it duplicates + wcl = self.class.config_loader + if wcl.credentials_found + loading_from("credentials", ChefConfig::PathHelper.home(".chef", "credentials")) + end + if wcl.config_location + loading_from("configuration", wcl.config_location) + end + + if Chef::Config[:config_d_dir] + wcl.find_dot_d(Chef::Config[:config_d_dir]).each do |path| + loading_from(".d/ configuration", path) + end + end + end + + # Dump the whole config, including defaults is --all was given. + config_data = Chef::Config.save(config[:all]) + # Two special cases, these are set during knife startup but we don't usually care about them. + unless config[:all] + config_data.delete(:color) + # Only keep these if true, false is much less important because it's the default. + config_data.delete(:local_mode) unless config_data[:local_mode] + config_data.delete(:enforce_default_paths) unless config_data[:enforce_default_paths] + config_data.delete(:enforce_path_sanity) unless config_data[:enforce_path_sanity] + end + + # Extract the data to show. + output_data = {} + if @name_args.empty? + output_data = config_data + else + @name_args.each do |filter| + if filter =~ %r{^/(.*)/(i?)$} + # It's a regex. + filter_re = Regexp.new($1, $2 ? Regexp::IGNORECASE : 0) + config_data.each do |key, value| + output_data[key] = value if key.to_s&.match?(filter_re) + end + else + # It's a dotted path string. + filter_parts = filter.split(/\./) + extract = lambda do |memo, filter_part| + memo.is_a?(Hash) ? memo[filter_part.to_sym] : nil + end + # Check against both config_data and all of the data, so that even + # in non-all mode, if you ask for a key that isn't in the non-all + # data, it will check against the broader set. + output_data[filter] = filter_parts.inject(config_data, &extract) || filter_parts.inject(Chef::Config.save(true), &extract) + end + end + end + + # Fix up some values. + output_data.each do |key, value| + if value == STDOUT + output_data[key] = "STDOUT" + elsif value == STDERR + output_data[key] = "STDERR" + end + end + + # Show the data. + if config[:raw] + output_data.each_value do |value| + ui.msg(value) + end + else + ui.output(output_data) + end + end + + private + + # Display a banner about loading from a config file. + # + # @api private + # @param type_of_file [String] Description of the file for the banner. + # @param path [String] Path of the file. + # @return [nil] + def loading_from(type_of_file, path) + path = Pathname.new(path).realpath + ui.msg(ui.color("Loading from #{type_of_file} file #{path}", :yellow)) + end + end + end +end diff --git a/lib/chef/knife/config_use.rb b/lib/chef/knife/config_use.rb new file mode 100644 index 0000000000..e944dc210b --- /dev/null +++ b/lib/chef/knife/config_use.rb @@ -0,0 +1,61 @@ +# +# Author:: Vivek Singh (<vsingh@chef.io>) +# Copyright:: Copyright (c) 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_relative "../knife" + +class Chef + class Knife + class ConfigUse < Knife + banner "knife config use [PROFILE]" + + deps do + require "fileutils" unless defined?(FileUtils) + end + + # Disable normal config loading since this shouldn't fail if the profile + # doesn't exist of the config is otherwise corrupted. + def configure_chef + apply_computed_config + end + + def run + profile = @name_args[0]&.strip + if profile.nil? || profile.empty? + ui.msg(self.class.config_loader.credentials_profile(config[:profile])) + else + credentials_data = self.class.config_loader.parse_credentials_file + context_file = ChefConfig::PathHelper.home(".chef", "context").freeze + + if credentials_data.nil? || credentials_data.empty? + ui.fatal("No profiles found, #{self.class.config_loader.credentials_file_path} does not exist or is empty") + exit 1 + end + + if credentials_data[profile].nil? + raise ChefConfig::ConfigurationError, "Profile #{profile} doesn't exist. Please add it to #{self.class.config_loader.credentials_file_path} and if it is profile with DNS name check that you are not missing single quotes around it as per docs https://docs.chef.io/workstation/knife_setup/#knife-profiles." + else + # Ensure the .chef/ folder exists. + FileUtils.mkdir_p(File.dirname(context_file)) + IO.write(context_file, "#{profile}\n") + ui.msg("Set default profile to #{profile}") + end + end + end + end + end +end |