diff options
-rw-r--r-- | lib/chef/knife/core/status_presenter.rb | 156 | ||||
-rw-r--r-- | lib/chef/knife/status.rb | 69 | ||||
-rw-r--r-- | spec/unit/knife/status_spec.rb | 3 |
3 files changed, 168 insertions, 60 deletions
diff --git a/lib/chef/knife/core/status_presenter.rb b/lib/chef/knife/core/status_presenter.rb new file mode 100644 index 0000000000..3298d5e4ac --- /dev/null +++ b/lib/chef/knife/core/status_presenter.rb @@ -0,0 +1,156 @@ +# +# Author:: Nicolas DUPEUX (<nicolas.dupeux@arkea.com>) +# Copyright:: Copyright (c) 2011 Opscode, 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/core/text_formatter' +require 'chef/knife/core/generic_presenter' + +class Chef + class Knife + module Core + + # This module may be included into a knife subcommand class to automatically + # add configuration options used by the StatusPresenter + module StatusFormattingOptions + # :nodoc: + # Would prefer to do this in a rational way, but can't be done b/c of + # Mixlib::CLI's design :( + def self.included(includer) + includer.class_eval do + option :medium_output, + :short => '-m', + :long => '--medium', + :boolean => true, + :default => false, + :description => 'Include normal attributes in the output' + + option :long_output, + :short => '-l', + :long => '--long', + :boolean => true, + :default => false, + :description => 'Include all attributes in the output' + end + end + end + + #==Chef::Knife::Core::StatusPresenter + # A customized presenter for Chef::Node objects. Supports variable-length + # output formats for displaying node data + class StatusPresenter < GenericPresenter + + def format(data) + if parse_format_option == :json + summarize_json(data) + else + super + end + end + + def summarize_json(list) + result_list = [] + list.each do |node| + result = {} + + result["name"] = node.name + result["chef_environment"] = node.chef_environment + ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress] + fqdn = (node[:ec2] && node[:ec2][:public_hostname]) || node[:fqdn] + result["ip"] = ip if ip + result["fqdn"] = fqdn if fqdn + result["run_list"] = node.run_list if config[:run_list] + result["ohai_time"] = node[:ohai_time] + result["platform"] = node[:platform] if node[:platform] + result["platform_version"] = node[:platform_version] if node[:platform_version] + + if config[:long_output] + result["default"] = node.default_attrs + result["override"] = node.override_attrs + result["automatic"] = node.automatic_attrs + end + result_list << result + end + + Chef::JSONCompat.to_json_pretty(result_list) + end + + # Converts a Chef::Node object to a string suitable for output to a + # terminal. If config[:medium_output] or config[:long_output] are set + # the volume of output is adjusted accordingly. Uses colors if enabled + # in the ui object. + def summarize(list) + summarized='' + list.each do |data| + node = data + # special case ec2 with their split horizon whatsis. + ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress] + fqdn = (node[:ec2] && node[:ec2][:public_hostname]) || node[:fqdn] + + hours, minutes, seconds = 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 + else + color = :green + text = minutes_text + end + + line_parts = Array.new + line_parts << @ui.color(text, color) + ' ago' << node.name + line_parts << fqdn if fqdn + line_parts << ip if ip + line_parts << run_list if run_list + + if node['platform'] + platform = node['platform'] + if node['platform_version'] + platform << " #{node['platform_version']}" + end + line_parts << platform + end + + summarized=summarized + line_parts.join(', ') + ".\n" + end + summarized + end + + def key(key_text) + ui.color(key_text, :cyan) + end + + # :nodoc: + # TODO: this is duplicated from StatusHelper in the Webui. dedup. + def time_difference_in_hms(unix_time) + now = Time.now.to_i + difference = now - unix_time.to_i + hours = (difference / 3600).to_i + difference = difference % 3600 + minutes = (difference / 60).to_i + seconds = (difference % 60) + return [hours, minutes, seconds] + end + + end + end + end +end diff --git a/lib/chef/knife/status.rb b/lib/chef/knife/status.rb index 5906a4a624..93e81f8f03 100644 --- a/lib/chef/knife/status.rb +++ b/lib/chef/knife/status.rb @@ -17,13 +17,13 @@ # require 'chef/knife' +require 'chef/knife/core/status_presenter' class Chef class Knife class Status < Knife deps do - require 'highline' require 'chef/search/query' end @@ -44,74 +44,27 @@ class Chef :long => "--hide-healthy", :description => "Hide nodes that have run chef in the last hour" - def highline - @h ||= HighLine.new - end - def run + ui.use_presenter Knife::Core::StatusPresenter all_nodes = [] q = Chef::Search::Query.new - query = @name_args[0] || "*:*" + query = @name_args[0] ? @name_args[0].dup : '*:*' + if config[:hide_healthy] + time = Time.now.to_i + query_unhealthy = "NOT ohai_time:[" << (time - 60*60).to_s << " TO " << time.to_s << "]" + query << ' AND ' << query_unhealthy << @name_args[0] if @name_args[0] + query = query_unhealthy unless @name_args[0] + end q.search(:node, query) do |node| all_nodes << node end - all_nodes.sort { |n1, n2| + output(all_nodes.sort { |n1, n2| if (config[:sort_reverse] || Chef::Config[:knife][:sort_status_reverse]) (n2["ohai_time"] or 0) <=> (n1["ohai_time"] or 0) else (n1["ohai_time"] or 0) <=> (n2["ohai_time"] or 0) end - }.each do |node| - if node.has_key?("ec2") - fqdn = node['ec2']['public_hostname'] - ipaddress = node['ec2']['public_ipv4'] - else - fqdn = node['fqdn'] - ipaddress = node['ipaddress'] - end - hours, minutes, seconds = 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 - else - color = :green - text = minutes_text - end - - line_parts = Array.new - line_parts << @ui.color(text, color) + " ago" << node.name - line_parts << fqdn if fqdn - line_parts << ipaddress if ipaddress - line_parts << run_list if run_list - - if node['platform'] - platform = node['platform'] - if node['platform_version'] - platform << " #{node['platform_version']}" - end - line_parts << platform - end - highline.say(line_parts.join(', ') + '.') unless (config[:hide_healthy] && hours < 1) - end - - end - - # :nodoc: - # TODO: this is duplicated from StatusHelper in the Webui. dedup. - def time_difference_in_hms(unix_time) - now = Time.now.to_i - difference = now - unix_time.to_i - hours = (difference / 3600).to_i - difference = difference % 3600 - minutes = (difference / 60).to_i - seconds = (difference % 60) - return [hours, minutes, seconds] + }) end end diff --git a/spec/unit/knife/status_spec.rb b/spec/unit/knife/status_spec.rb index 6d8d9d5b25..bb43dd25e5 100644 --- a/spec/unit/knife/status_spec.rb +++ b/spec/unit/knife/status_spec.rb @@ -17,7 +17,6 @@ # require 'spec_helper' -require 'highline' describe Chef::Knife::Status do before(:each) do @@ -30,7 +29,7 @@ describe Chef::Knife::Status do Chef::Search::Query.stub(:new).and_return(query) @knife = Chef::Knife::Status.new @stdout = StringIO.new - @knife.stub(:highline).and_return(HighLine.new(StringIO.new, @stdout)) + @knife.ui.stub(:stdout).and_return(@stdout) end describe "run" do |