forked from choria-legacy/marionette-collective
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rpc.rb
136 lines (111 loc) · 4.6 KB
/
rpc.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
class MCollective::Application::Rpc<MCollective::Application
description "Generic RPC agent client application"
usage "mco rpc [options] [filters] --agent <agent> --action <action> [--argument <key=val> --argument ...]"
usage "mco rpc [options] [filters] <agent> <action> [<key=val> <key=val> ...]"
option :no_results,
:description => "Do not process results, just send request",
:arguments => ["--no-results", "--nr"],
:default => false,
:type => :bool
option :agent,
:description => "Agent to call",
:arguments => ["-a", "--agent AGENT"]
option :action,
:description => "Action to call",
:arguments => ["--action ACTION"]
option :arguments,
:description => "Arguments to pass to agent",
:arguments => ["--arg", "--argument ARGUMENT"],
:type => :array,
:default => [],
:validate => Proc.new {|val| val.match(/^(.+?)=(.+)$/) ? true : "Could not parse --arg #{val} should be of the form key=val" }
def post_option_parser(configuration)
# handle the alternative format that optparse cant parse
unless (configuration.include?(:agent) && configuration.include?(:action))
if ARGV.length >= 2
configuration[:agent] = ARGV[0]
ARGV.delete_at(0)
configuration[:action] = ARGV[0]
ARGV.delete_at(0)
ARGV.each do |v|
if v =~ /^(.+?)=(.+)$/
configuration[:arguments] = [] unless configuration.include?(:arguments)
configuration[:arguments] << v
else
STDERR.puts("Could not parse --arg #{v}")
end
end
else
STDERR.puts("No agent, action and arguments specified")
exit!
end
end
# convert arguments to symbols for keys to comply with simplerpc conventions
args = configuration[:arguments].clone
configuration[:arguments] = {}
args.each do |v|
if v =~ /^(.+?)=(.+)$/
configuration[:arguments][$1.to_sym] = $2
end
end
end
# As we're taking arguments on the command line we need a
# way to input booleans, true on the cli is a string so this
# method will take the ddl, find all arguments that are supposed
# to be boolean and if they are the strings "true"/"yes" or "false"/"no"
# turn them into the matching boolean
def string_to_boolean(val)
return true if ["true", "yes", "1"].include?(val)
return false if ["false", "no", "0"].include?(val)
raise "#{val} does not look like a boolean argument"
end
# a generic string to number function, if a number looks like a float
# it turns it into a float else an int. This is naive but should be sufficient
# for numbers typed on the cli in most cases
def string_to_number(val)
return val.to_f if val =~ /^\d+\.\d+$/
return val.to_i if val =~ /^\d+$/
raise "#{val} does not look like a number"
end
def string_to_ddl_type(arguments, ddl)
arguments.keys.each do |key|
if ddl[:input].keys.include?(key)
begin
case ddl[:input][key][:type]
when :boolean
arguments[key] = booleanish_to_boolean(arguments[key])
when :number, :integer, :float
arguments[key] = string_to_number(arguments[key])
end
rescue
# just go on to the next key, DDL validation will figure out
# any inconsistancies caused by exceptions when the request is made
end
end
end
end
def main
mc = rpcclient(configuration[:agent])
mc.agent_filter(configuration[:agent])
string_to_ddl_type(configuration[:arguments], mc.ddl.action_interface(configuration[:action])) unless mc.ddl.nil?
if mc.reply_to
configuration[:arguments][:process_results] = true
puts "Request sent with id: " + mc.send(configuration[:action], configuration[:arguments]) + " replies to #{mc.reply_to}"
elsif configuration[:no_results]
configuration[:arguments][:process_results] = false
puts "Request sent with id: " + mc.send(configuration[:action], configuration[:arguments])
else
# if there's stuff on STDIN assume its JSON that came from another
# rpc or printrpc, we feed that in as discovery data
unless STDIN.tty?
discovery_data = STDIN.read
mc.discover(:json => discovery_data)
else
mc.discover :verbose => true
end
printrpc mc.send(configuration[:action], configuration[:arguments])
printrpcstats :caption => "#{configuration[:agent]}##{configuration[:action]} call stats"
halt mc.stats
end
end
end