c69cfd18b6fa854e6e9330932a02fd31116a8ab2
[packages/precise/mcollective.git] / plugins / mcollective / application / rpc.rb
1 class MCollective::Application::Rpc<MCollective::Application
2   description "Generic RPC agent client application"
3
4   usage "mco rpc [options] [filters] --agent <agent> --action <action> [--argument <key=val> --argument ...]"
5   usage "mco rpc [options] [filters] <agent> <action> [<key=val> <key=val> ...]"
6
7   option :show_results,
8          :description    => "Do not process results, just send request",
9          :arguments      => ["--no-results", "--nr"],
10          :default        => true,
11          :type           => :bool
12
13   option :agent,
14          :description    => "Agent to call",
15          :arguments      => ["-a", "--agent AGENT"]
16
17   option :action,
18          :description    => "Action to call",
19          :arguments      => ["--action ACTION"]
20
21   option :arguments,
22          :description    => "Arguments to pass to agent",
23          :arguments      => ["--arg", "--argument ARGUMENT"],
24          :type           => :array,
25          :default        => [],
26          :validate       => Proc.new {|val| val.match(/^(.+?)=(.+)$/) ? true : "Could not parse --arg #{val} should be of the form key=val" }
27
28   def post_option_parser(configuration)
29     # handle the alternative format that optparse cant parse
30     unless (configuration.include?(:agent) && configuration.include?(:action))
31       if ARGV.length >= 2
32         configuration[:agent] = ARGV[0]
33         ARGV.delete_at(0)
34
35         configuration[:action] = ARGV[0]
36         ARGV.delete_at(0)
37
38         ARGV.each do |v|
39           if v =~ /^(.+?)=(.+)$/
40             configuration[:arguments] = [] unless configuration.include?(:arguments)
41             configuration[:arguments] << v
42           else
43             STDERR.puts("Could not parse --arg #{v}")
44             exit(1)
45           end
46         end
47       else
48         STDERR.puts("No agent, action and arguments specified")
49         exit(1)
50       end
51     end
52
53     # convert arguments to symbols for keys to comply with simplerpc conventions
54     args = configuration[:arguments].clone
55     configuration[:arguments] = {}
56
57     args.each do |v|
58       if v =~ /^(.+?)=(.+)$/
59         configuration[:arguments][$1.to_sym] = $2
60       end
61     end
62   end
63
64   def string_to_ddl_type(arguments, ddl)
65     return if ddl.empty?
66
67     arguments.keys.each do |key|
68       if ddl[:input].keys.include?(key)
69         case ddl[:input][key][:type]
70           when :boolean
71             arguments[key] = MCollective::DDL.string_to_boolean(arguments[key])
72
73           when :number, :integer, :float
74             arguments[key] = MCollective::DDL.string_to_number(arguments[key])
75         end
76       end
77     end
78   end
79
80   def main
81     mc = rpcclient(configuration[:agent])
82
83     mc.agent_filter(configuration[:agent])
84
85     string_to_ddl_type(configuration[:arguments], mc.ddl.action_interface(configuration[:action])) if mc.ddl
86
87     if mc.reply_to
88       configuration[:arguments][:process_results] = true
89
90       puts "Request sent with id: " + mc.send(configuration[:action], configuration[:arguments]) + " replies to #{mc.reply_to}"
91     elsif !configuration[:show_results]
92       configuration[:arguments][:process_results] = false
93
94       puts "Request sent with id: " + mc.send(configuration[:action], configuration[:arguments])
95     else
96       # if there's stuff on STDIN assume its JSON that came from another
97       # rpc or printrpc, we feed that in as discovery data
98       discover_args = {:verbose => true}
99
100       unless STDIN.tty?
101         discovery_data = STDIN.read.chomp
102         discover_args = {:json => discovery_data} unless discovery_data == ""
103       end
104
105       mc.discover discover_args
106
107       printrpc mc.send(configuration[:action], configuration[:arguments])
108
109       printrpcstats :summarize => true, :caption => "#{configuration[:agent]}##{configuration[:action]} call stats" if mc.discover.size > 0
110
111       halt mc.stats
112     end
113   end
114 end