Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

8280 - RPC::Helpers#rpcresults should support JSON

Add the ability for the printrpc helper to return JSON data.
Any application that is using the printrpc helper to display
data will now be able to just add -j to the command line and
return JSON instead.

If STDOUT is a tty the JSON will be pretty formatted else it
will just be a big blob of machine friendly JSON.

The basic use case is to eventually allow piping RPC results
from one query into the following query - perhaps with some
grep like filtering - thus avoiding discovery and allowing
totally arbitrary actions on arbitrary sets of hosts.

This also adjusts the progress bar and the stats to only display
if STDOUT is a tty.
  • Loading branch information...
commit d3b3e8f275672965ae23f694c4f1803b855f8381 1 parent 814becf
@ripienaar ripienaar authored
View
7 lib/mcollective/rpc.rb
@@ -107,6 +107,8 @@ def self.discovered(discovered)
# This will use "Foo" as the caption to the stats in verbose
# mode
def printrpcstats(flags={})
+ return unless @options[:output_format] == :console
+
verbose = @options[:verbose] rescue verbose = false
caption = flags[:caption] || "rpc stats"
@@ -131,10 +133,11 @@ def printrpc(result, flags = {})
verbose = @options[:verbose] rescue verbose = false
verbose = flags[:verbose] || verbose
flatten = flags[:flatten] || false
+ format = @options[:output_format]
- result_text = Helpers.rpcresults(result, {:verbose => verbose, :flatten => flatten})
+ result_text = Helpers.rpcresults(result, {:verbose => verbose, :flatten => flatten, :format => format})
- if result.is_a?(Array)
+ if result.is_a?(Array) && format == :console
puts "\n%s\n" % [ result_text ]
else
# when we get just one result to print dont pad them all with
View
6 lib/mcollective/rpc/client.rb
@@ -4,7 +4,7 @@ module RPC
# and just brings in a lot of convention and standard approached.
class Client
attr_accessor :discovery_timeout, :timeout, :verbose, :filter, :config, :progress
- attr_reader :client, :stats, :ddl, :agent, :limit_targets
+ attr_reader :client, :stats, :ddl, :agent, :limit_targets, :output_format
@@initial_options = nil
@@ -47,6 +47,7 @@ def initialize(agent, flags = {})
@discovered_agents = nil
@progress = options[:progress_bar]
@limit_targets = options[:mcollective_limit_targets]
+ @output_format = options[:output_format] || :console
agent_filter agent
@@ -324,6 +325,8 @@ def reset_filter
def discover(flags={})
flags.include?(:verbose) ? verbose = flags[:verbose] : verbose = @verbose
+ verbose = false unless @output_format == :console
+
if @discovered_agents == nil
@stats.time_discovery :start
@@ -349,6 +352,7 @@ def options
:verbose => @verbose,
:filter => @filter,
:collective => @collective,
+ :output_format => @output_format,
:config => @config}
end
View
77 lib/mcollective/rpc/helpers.rb
@@ -76,49 +76,57 @@ def self.colorize(code, msg)
# hostnames, it will just print the result as if it's one huge result,
# handy for things like showing a combined mailq.
def self.rpcresults(result, flags = {})
- flags = {:verbose => false, :flatten => false}.merge(flags)
+ flags = {:verbose => false, :flatten => false, :format => :console}.merge(flags)
result_text = ""
ddl = nil
# if running in verbose mode, just use the old style print
# no need for all the DDL helpers obfuscating the result
- if flags[:verbose]
- result_text = old_rpcresults(result, flags)
+ if flags[:format] == :json
+ if STDOUT.tty?
+ result_text = JSON.pretty_generate(result)
+ else
+ result_text = result.to_json
+ end
else
- [result].flatten.each do |r|
- begin
- ddl ||= DDL.new(r.agent).action_interface(r.action.to_s)
-
- sender = r[:sender]
- status = r[:statuscode]
- message = r[:statusmsg]
- display = ddl[:display]
- result = r[:data]
-
- # appand the results only according to what the DDL says
- case display
- when :ok
- if status == 0
- result_text << text_for_result(sender, status, message, result, ddl)
- end
-
- when :failed
- if status > 0
+ if flags[:verbose]
+ result_text = old_rpcresults(result, flags)
+ else
+ [result].flatten.each do |r|
+ begin
+ ddl ||= DDL.new(r.agent).action_interface(r.action.to_s)
+
+ sender = r[:sender]
+ status = r[:statuscode]
+ message = r[:statusmsg]
+ display = ddl[:display]
+ result = r[:data]
+
+ # appand the results only according to what the DDL says
+ case display
+ when :ok
+ if status == 0
+ result_text << text_for_result(sender, status, message, result, ddl)
+ end
+
+ when :failed
+ if status > 0
+ result_text << text_for_result(sender, status, message, result, ddl)
+ end
+
+ when :always
result_text << text_for_result(sender, status, message, result, ddl)
- end
-
- when :always
- result_text << text_for_result(sender, status, message, result, ddl)
- when :flatten
- result_text << text_for_flattened_result(status, result)
+ when :flatten
+ result_text << text_for_flattened_result(status, result)
+ end
+ rescue Exception => e
+ # no DDL so just do the old style print unchanged for
+ # backward compat
+ result_text = old_rpcresults(result, flags)
end
- rescue Exception => e
- # no DDL so just do the old style print unchanged for
- # backward compat
- result_text = old_rpcresults(result, flags)
end
end
end
@@ -263,6 +271,11 @@ def self.add_simplerpc_options(parser, options)
parser.on('--limit-nodes [COUNT]', '--ln [COUNT]', 'Send request to only a subset of nodes, can be a percentage') do |v|
options[:mcollective_limit_targets] = v
end
+
+ parser.on('--json', '-j', 'Produce JSON output') do |v|
+ options[:progress_bar] = false
+ options[:output_format] = :json
+ end
end
end
end
View
9 lib/mcollective/rpc/result.rb
@@ -27,6 +27,15 @@ def []=(idx, item)
def each
@results.each_pair {|k,v| yield(k,v) }
end
+
+ def to_json(*a)
+ {:agent => @agent,
+ :action => @action,
+ :sender => @results[:sender],
+ :statuscode => @results[:statuscode],
+ :statusmsg => @results[:statusmsg],
+ :data => @results[:data]}.to_json(*a)
+ end
end
end
end
View
9 spec/unit/rpc/result_spec.rb
@@ -44,7 +44,7 @@ module RPC
end
end
- describe "each" do
+ describe "#each" do
it "should itterate all the pairs" do
data = {}
@@ -54,6 +54,13 @@ module RPC
data[:bar].should == "baz"
end
end
+
+ describe "#to_json" do
+ it "should correctly json encode teh data" do
+ result = Result.new("tester", "test", {:statuscode => 0, :statusmsg => "OK", :sender => "rspec", :data => {:foo => "bar", :bar => "baz"}})
+ JSON.load(result.to_json).should == {"agent" => "tester", "action" => "test", "statuscode" => 0, "statusmsg" => "OK", "sender" => "rspec", "data" => {"foo" => "bar", "bar" => "baz"}}
+ end
+ end
end
end
end
View
1  website/changelog.md
@@ -11,6 +11,7 @@ title: Changelog
|Date|Description|Ticket|
|----|-----------|------|
+|2011/07/07|Add a -j argument to all SimpleRPC clients that causes printrpc to produce JSON data|8280|
|2011/06/30|Add the ability to do point to point comms for requests affecting small numbers of hosts|7988|
|2011/06/21|Add support for Stomp Gem version 1.1.9 callback based logging|7960|
|2011/06/21|On the server side log missing DDL files at debug and not warning level|7961|
Please sign in to comment.
Something went wrong with that request. Please try again.