choria-mcorpc-support 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/mco +64 -0
- data/lib/mcollective.rb +63 -0
- data/lib/mcollective/agent.rb +5 -0
- data/lib/mcollective/agents.rb +149 -0
- data/lib/mcollective/aggregate.rb +85 -0
- data/lib/mcollective/aggregate/average.ddl +33 -0
- data/lib/mcollective/aggregate/average.rb +29 -0
- data/lib/mcollective/aggregate/base.rb +40 -0
- data/lib/mcollective/aggregate/result.rb +9 -0
- data/lib/mcollective/aggregate/result/base.rb +25 -0
- data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
- data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
- data/lib/mcollective/aggregate/sum.ddl +33 -0
- data/lib/mcollective/aggregate/sum.rb +18 -0
- data/lib/mcollective/aggregate/summary.ddl +33 -0
- data/lib/mcollective/aggregate/summary.rb +53 -0
- data/lib/mcollective/application.rb +365 -0
- data/lib/mcollective/application/completion.rb +104 -0
- data/lib/mcollective/application/describe_filter.rb +87 -0
- data/lib/mcollective/application/facts.rb +62 -0
- data/lib/mcollective/application/find.rb +23 -0
- data/lib/mcollective/application/help.rb +28 -0
- data/lib/mcollective/application/inventory.rb +344 -0
- data/lib/mcollective/application/ping.rb +82 -0
- data/lib/mcollective/application/plugin.rb +369 -0
- data/lib/mcollective/application/rpc.rb +111 -0
- data/lib/mcollective/applications.rb +134 -0
- data/lib/mcollective/cache.rb +145 -0
- data/lib/mcollective/client.rb +353 -0
- data/lib/mcollective/config.rb +245 -0
- data/lib/mcollective/connector.rb +18 -0
- data/lib/mcollective/connector/base.rb +26 -0
- data/lib/mcollective/data.rb +91 -0
- data/lib/mcollective/data/agent_data.ddl +22 -0
- data/lib/mcollective/data/agent_data.rb +17 -0
- data/lib/mcollective/data/base.rb +67 -0
- data/lib/mcollective/data/collective_data.ddl +20 -0
- data/lib/mcollective/data/collective_data.rb +9 -0
- data/lib/mcollective/data/fact_data.ddl +28 -0
- data/lib/mcollective/data/fact_data.rb +55 -0
- data/lib/mcollective/data/fstat_data.ddl +89 -0
- data/lib/mcollective/data/fstat_data.rb +56 -0
- data/lib/mcollective/data/result.rb +45 -0
- data/lib/mcollective/ddl.rb +113 -0
- data/lib/mcollective/ddl/agentddl.rb +253 -0
- data/lib/mcollective/ddl/base.rb +217 -0
- data/lib/mcollective/ddl/dataddl.rb +56 -0
- data/lib/mcollective/ddl/discoveryddl.rb +52 -0
- data/lib/mcollective/ddl/validatorddl.rb +6 -0
- data/lib/mcollective/discovery.rb +143 -0
- data/lib/mcollective/discovery/flatfile.ddl +11 -0
- data/lib/mcollective/discovery/flatfile.rb +48 -0
- data/lib/mcollective/discovery/mc.ddl +11 -0
- data/lib/mcollective/discovery/mc.rb +30 -0
- data/lib/mcollective/discovery/stdin.ddl +11 -0
- data/lib/mcollective/discovery/stdin.rb +68 -0
- data/lib/mcollective/exceptions.rb +28 -0
- data/lib/mcollective/facts.rb +39 -0
- data/lib/mcollective/facts/base.rb +100 -0
- data/lib/mcollective/facts/yaml_facts.rb +65 -0
- data/lib/mcollective/generators.rb +7 -0
- data/lib/mcollective/generators/agent_generator.rb +51 -0
- data/lib/mcollective/generators/base.rb +46 -0
- data/lib/mcollective/generators/data_generator.rb +51 -0
- data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
- data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
- data/lib/mcollective/generators/templates/ddl.erb +8 -0
- data/lib/mcollective/generators/templates/plugin.erb +7 -0
- data/lib/mcollective/log.rb +118 -0
- data/lib/mcollective/logger.rb +5 -0
- data/lib/mcollective/logger/base.rb +77 -0
- data/lib/mcollective/logger/console_logger.rb +61 -0
- data/lib/mcollective/logger/file_logger.rb +53 -0
- data/lib/mcollective/logger/syslog_logger.rb +53 -0
- data/lib/mcollective/matcher.rb +224 -0
- data/lib/mcollective/matcher/parser.rb +128 -0
- data/lib/mcollective/matcher/scanner.rb +241 -0
- data/lib/mcollective/message.rb +248 -0
- data/lib/mcollective/monkey_patches.rb +152 -0
- data/lib/mcollective/optionparser.rb +197 -0
- data/lib/mcollective/pluginmanager.rb +180 -0
- data/lib/mcollective/pluginpackager.rb +98 -0
- data/lib/mcollective/pluginpackager/agent_definition.rb +94 -0
- data/lib/mcollective/pluginpackager/debpackage_packager.rb +237 -0
- data/lib/mcollective/pluginpackager/modulepackage_packager.rb +127 -0
- data/lib/mcollective/pluginpackager/ospackage_packager.rb +59 -0
- data/lib/mcollective/pluginpackager/rpmpackage_packager.rb +180 -0
- data/lib/mcollective/pluginpackager/standard_definition.rb +69 -0
- data/lib/mcollective/pluginpackager/templates/debian/Makefile.erb +7 -0
- data/lib/mcollective/pluginpackager/templates/debian/changelog.erb +5 -0
- data/lib/mcollective/pluginpackager/templates/debian/compat.erb +1 -0
- data/lib/mcollective/pluginpackager/templates/debian/control.erb +15 -0
- data/lib/mcollective/pluginpackager/templates/debian/copyright.erb +8 -0
- data/lib/mcollective/pluginpackager/templates/debian/rules.erb +6 -0
- data/lib/mcollective/pluginpackager/templates/module/Modulefile.erb +5 -0
- data/lib/mcollective/pluginpackager/templates/module/README.md.erb +37 -0
- data/lib/mcollective/pluginpackager/templates/module/_manifest.pp.erb +9 -0
- data/lib/mcollective/pluginpackager/templates/redhat/rpm_spec.erb +63 -0
- data/lib/mcollective/registration/base.rb +91 -0
- data/lib/mcollective/rpc.rb +182 -0
- data/lib/mcollective/rpc/actionrunner.rb +158 -0
- data/lib/mcollective/rpc/agent.rb +374 -0
- data/lib/mcollective/rpc/audit.rb +38 -0
- data/lib/mcollective/rpc/client.rb +1066 -0
- data/lib/mcollective/rpc/helpers.rb +321 -0
- data/lib/mcollective/rpc/progress.rb +63 -0
- data/lib/mcollective/rpc/reply.rb +87 -0
- data/lib/mcollective/rpc/request.rb +86 -0
- data/lib/mcollective/rpc/result.rb +90 -0
- data/lib/mcollective/rpc/stats.rb +294 -0
- data/lib/mcollective/runnerstats.rb +90 -0
- data/lib/mcollective/security.rb +26 -0
- data/lib/mcollective/security/base.rb +244 -0
- data/lib/mcollective/shell.rb +126 -0
- data/lib/mcollective/ssl.rb +285 -0
- data/lib/mcollective/util.rb +579 -0
- data/lib/mcollective/validator.rb +85 -0
- data/lib/mcollective/validator/array_validator.ddl +7 -0
- data/lib/mcollective/validator/array_validator.rb +9 -0
- data/lib/mcollective/validator/ipv4address_validator.ddl +7 -0
- data/lib/mcollective/validator/ipv4address_validator.rb +16 -0
- data/lib/mcollective/validator/ipv6address_validator.ddl +7 -0
- data/lib/mcollective/validator/ipv6address_validator.rb +16 -0
- data/lib/mcollective/validator/length_validator.ddl +7 -0
- data/lib/mcollective/validator/length_validator.rb +11 -0
- data/lib/mcollective/validator/regex_validator.ddl +7 -0
- data/lib/mcollective/validator/regex_validator.rb +9 -0
- data/lib/mcollective/validator/shellsafe_validator.ddl +7 -0
- data/lib/mcollective/validator/shellsafe_validator.rb +13 -0
- data/lib/mcollective/validator/typecheck_validator.ddl +7 -0
- data/lib/mcollective/validator/typecheck_validator.rb +28 -0
- metadata +215 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
class Application::Completion<MCollective::Application
|
|
3
|
+
description "Helper for shell completion systems"
|
|
4
|
+
|
|
5
|
+
exclude_argument_sections "common", "filter", "rpc"
|
|
6
|
+
|
|
7
|
+
option :list_agents,
|
|
8
|
+
:description => "List all known agents",
|
|
9
|
+
:arguments => "--list-agents",
|
|
10
|
+
:required => false,
|
|
11
|
+
:type => :boolean
|
|
12
|
+
|
|
13
|
+
option :list_actions,
|
|
14
|
+
:description => "List all actions for an agent",
|
|
15
|
+
:arguments => "--list-actions",
|
|
16
|
+
:required => false,
|
|
17
|
+
:type => :boolean
|
|
18
|
+
|
|
19
|
+
option :list_inputs,
|
|
20
|
+
:description => "List all inputs for an action",
|
|
21
|
+
:arguments => "--list-inputs",
|
|
22
|
+
:required => false,
|
|
23
|
+
:type => :boolean
|
|
24
|
+
|
|
25
|
+
option :list_applications,
|
|
26
|
+
:description => "List all known applications",
|
|
27
|
+
:arguments => "--list-applications",
|
|
28
|
+
:required => false,
|
|
29
|
+
:type => :boolean
|
|
30
|
+
|
|
31
|
+
option :agent,
|
|
32
|
+
:description => "The agent to operate on",
|
|
33
|
+
:arguments => "--agent AGENT",
|
|
34
|
+
:required => false
|
|
35
|
+
|
|
36
|
+
option :action,
|
|
37
|
+
:description => "The action to operate on",
|
|
38
|
+
:arguments => "--action ACTION",
|
|
39
|
+
:required => false
|
|
40
|
+
|
|
41
|
+
def list_agents
|
|
42
|
+
if options[:verbose]
|
|
43
|
+
PluginManager.find(:agent, "ddl").each do |agent|
|
|
44
|
+
begin
|
|
45
|
+
ddl = DDL.new(agent)
|
|
46
|
+
puts "%s:%s" % [ agent, ddl.meta[:description] ]
|
|
47
|
+
rescue
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
PluginManager.find(:agent, "ddl").each {|p| puts p}
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def list_actions
|
|
56
|
+
abort "Please specify an agent to list actions for" unless configuration[:agent]
|
|
57
|
+
|
|
58
|
+
if options[:verbose]
|
|
59
|
+
ddl = DDL.new(configuration[:agent], :agent)
|
|
60
|
+
|
|
61
|
+
ddl.actions.sort.each do |action|
|
|
62
|
+
puts "%s:%s" % [action, ddl.action_interface(action)[:description]]
|
|
63
|
+
end
|
|
64
|
+
else
|
|
65
|
+
DDL.new(configuration[:agent], :agent).actions.sort.each {|a| puts a}
|
|
66
|
+
end
|
|
67
|
+
rescue
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def list_inputs
|
|
71
|
+
abort "Please specify an action and agent to list inputs for" unless configuration[:agent] && configuration[:action]
|
|
72
|
+
|
|
73
|
+
if options[:verbose]
|
|
74
|
+
ddl = DDL.new(configuration[:agent], :agent)
|
|
75
|
+
action = ddl.action_interface(configuration[:action])
|
|
76
|
+
action[:input].keys.sort.each do |input|
|
|
77
|
+
puts "%s:%s" % [input, action[:input][input][:description]]
|
|
78
|
+
end
|
|
79
|
+
else
|
|
80
|
+
DDL.new(configuration[:agent], :agent).action_interface(configuration[:action])[:input].keys.sort.each {|i| puts i}
|
|
81
|
+
end
|
|
82
|
+
rescue
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def list_applications
|
|
86
|
+
if options[:verbose]
|
|
87
|
+
Applications.list.each do |app|
|
|
88
|
+
puts "%s:%s" % [app, Applications[app].application_description]
|
|
89
|
+
end
|
|
90
|
+
else
|
|
91
|
+
Applications.list.each {|a| puts a}
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def main
|
|
96
|
+
actions = configuration.keys.map{|k| k.to_s}.grep(/^list_/)
|
|
97
|
+
|
|
98
|
+
abort "Please choose either --list-[agents|actions|inputs|applications]" if actions.empty?
|
|
99
|
+
abort "Please choose only one of --list-[agents|actions|inputs|applications]" if actions.size > 1
|
|
100
|
+
|
|
101
|
+
send actions.first
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
class Application::Describe_filter<Application
|
|
3
|
+
exclude_argument_sections "common", "rpc"
|
|
4
|
+
|
|
5
|
+
description "Display human readable interpretation of filters"
|
|
6
|
+
|
|
7
|
+
usage "mco describe_filter -S <filter> -F <filter> -C <filter>"
|
|
8
|
+
|
|
9
|
+
def describe_s_filter(stack)
|
|
10
|
+
indent = " "
|
|
11
|
+
old_indent = " "
|
|
12
|
+
puts "-S Query expands to the following instructions:"
|
|
13
|
+
puts
|
|
14
|
+
stack.each do |token|
|
|
15
|
+
if token.keys[0] == "statement"
|
|
16
|
+
if token.values[0] =~ /(<=|>=|=|=~|=)/
|
|
17
|
+
op = $1
|
|
18
|
+
k,v = token.values[0].split(op)
|
|
19
|
+
puts indent + get_fact_string(k, v, op)
|
|
20
|
+
else
|
|
21
|
+
puts indent + get_class_string(token.values[0])
|
|
22
|
+
end
|
|
23
|
+
elsif token.keys[0] == "fstatement"
|
|
24
|
+
v = token.values[0]
|
|
25
|
+
result_string = indent + "Execute the Data Query '#{v["name"]}'"
|
|
26
|
+
if v["params"]
|
|
27
|
+
result_string += " with parameters (#{v["params"]})"
|
|
28
|
+
end
|
|
29
|
+
result_string += ". "
|
|
30
|
+
result_string += "Check if the query's '#{v["value"]}' value #{v["operator"]} '#{v["r_compare"]}' "
|
|
31
|
+
puts result_string
|
|
32
|
+
elsif token.keys[0] == "("
|
|
33
|
+
puts indent + "("
|
|
34
|
+
old_indent = indent
|
|
35
|
+
indent *= 2
|
|
36
|
+
elsif token.keys[0] == ")"
|
|
37
|
+
indent = old_indent
|
|
38
|
+
puts indent + ")"
|
|
39
|
+
else
|
|
40
|
+
puts indent + token.keys[0].upcase
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def describe_f_filter(facts)
|
|
46
|
+
puts "-F filter expands to the following fact comparisons:"
|
|
47
|
+
puts
|
|
48
|
+
facts.each do |f|
|
|
49
|
+
puts " " + get_fact_string(f[:fact], f[:value], f[:operator])
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def describe_c_filter(classes)
|
|
54
|
+
puts "-C filter expands to the following class checks:"
|
|
55
|
+
puts
|
|
56
|
+
classes.each do |c|
|
|
57
|
+
puts " " + get_class_string(c)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def main
|
|
62
|
+
if !(@options[:filter]["fact"].empty?)
|
|
63
|
+
describe_f_filter(@options[:filter]["fact"])
|
|
64
|
+
puts
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if !(@options[:filter]["cf_class"].empty?)
|
|
68
|
+
describe_c_filter(@options[:filter]["cf_class"])
|
|
69
|
+
puts
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if !(@options[:filter]["compound"].empty?)
|
|
73
|
+
describe_s_filter(@options[:filter]["compound"][0])
|
|
74
|
+
puts
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
def get_fact_string(fact, value, op)
|
|
80
|
+
"Check if fact '#{fact}' #{op} '#{value}'"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def get_class_string(classname)
|
|
84
|
+
"Check if class '#{classname}' is present on the host"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
class MCollective::Application::Facts<MCollective::Application
|
|
2
|
+
description "Reports on usage for a specific fact"
|
|
3
|
+
|
|
4
|
+
def post_option_parser(configuration)
|
|
5
|
+
configuration[:fact] = ARGV.shift if ARGV.size > 0
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def validate_configuration(configuration)
|
|
9
|
+
raise "Please specify a fact to report for" unless configuration.include?(:fact)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def show_single_fact_report(fact, facts, verbose=false)
|
|
13
|
+
puts("Report for fact: #{fact}\n\n")
|
|
14
|
+
|
|
15
|
+
field_size = MCollective::Util.field_size(facts.keys)
|
|
16
|
+
facts.keys.sort.each do |k|
|
|
17
|
+
printf(" %-#{field_size}s found %d times\n", k, facts[k].size)
|
|
18
|
+
|
|
19
|
+
if verbose
|
|
20
|
+
puts
|
|
21
|
+
|
|
22
|
+
facts[k].sort.each do |f|
|
|
23
|
+
puts(" #{f}")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
puts
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def main
|
|
32
|
+
rpcutil = rpcclient("rpcutil")
|
|
33
|
+
rpcutil.progress = false
|
|
34
|
+
|
|
35
|
+
facts = {}
|
|
36
|
+
|
|
37
|
+
rpcutil.get_fact(:fact => configuration[:fact]) do |resp|
|
|
38
|
+
begin
|
|
39
|
+
value = resp[:body][:data][:value]
|
|
40
|
+
if value
|
|
41
|
+
if facts.include?(value)
|
|
42
|
+
facts[value] << resp[:senderid]
|
|
43
|
+
else
|
|
44
|
+
facts[value] = [ resp[:senderid] ]
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
rescue Exception => e
|
|
48
|
+
STDERR.puts "Could not parse facts for #{resp[:senderid]}: #{e.class}: #{e}"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if facts.empty?
|
|
53
|
+
puts "No values found for fact #{configuration[:fact]}\n"
|
|
54
|
+
else
|
|
55
|
+
show_single_fact_report(configuration[:fact], facts, options[:verbose])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
printrpcstats
|
|
59
|
+
|
|
60
|
+
halt rpcutil.stats
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class MCollective::Application::Find<MCollective::Application
|
|
2
|
+
description "Find hosts using the discovery system matching filter criteria"
|
|
3
|
+
|
|
4
|
+
def main
|
|
5
|
+
mc = rpcclient("rpcutil")
|
|
6
|
+
|
|
7
|
+
starttime = Time.now
|
|
8
|
+
|
|
9
|
+
mc.detect_and_set_stdin_discovery
|
|
10
|
+
|
|
11
|
+
nodes = mc.discover
|
|
12
|
+
|
|
13
|
+
discoverytime = Time.now - starttime
|
|
14
|
+
|
|
15
|
+
STDERR.puts if options[:verbose]
|
|
16
|
+
|
|
17
|
+
nodes.each {|c| puts c}
|
|
18
|
+
|
|
19
|
+
STDERR.puts "\nDiscovered %s nodes in %.2f seconds using the %s discovery plugin" % [nodes.size, discoverytime, mc.client.discoverer.discovery_method] if options[:verbose]
|
|
20
|
+
|
|
21
|
+
nodes.size > 0 ? exit(0) : exit(1)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
class Application::Help<Application
|
|
3
|
+
description "Application list and help"
|
|
4
|
+
usage "rpc help [application name]"
|
|
5
|
+
|
|
6
|
+
def post_option_parser(configuration)
|
|
7
|
+
configuration[:application] = ARGV.shift if ARGV.size > 0
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def main
|
|
11
|
+
if configuration.include?(:application)
|
|
12
|
+
puts Applications[configuration[:application]].help
|
|
13
|
+
else
|
|
14
|
+
puts "The Marionette Collective version #{MCollective.version}"
|
|
15
|
+
puts
|
|
16
|
+
|
|
17
|
+
Applications.list.sort.each do |app|
|
|
18
|
+
begin
|
|
19
|
+
puts " %-15s %s" % [app, Applications[app].application_description]
|
|
20
|
+
rescue
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
puts
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
class MCollective::Application::Inventory<MCollective::Application
|
|
2
|
+
description "General reporting tool for nodes, collectives and subcollectives"
|
|
3
|
+
|
|
4
|
+
option :script,
|
|
5
|
+
:description => "Script to run",
|
|
6
|
+
:arguments => ["--script SCRIPT"]
|
|
7
|
+
|
|
8
|
+
option :collectives,
|
|
9
|
+
:description => "List all known collectives",
|
|
10
|
+
:arguments => ["--list-collectives", "--lc"],
|
|
11
|
+
:default => false,
|
|
12
|
+
:type => :bool
|
|
13
|
+
|
|
14
|
+
option :collectivemap,
|
|
15
|
+
:description => "Create a DOT graph of all collectives",
|
|
16
|
+
:arguments => ["--collective-graph MAP", "--cg MAP", "--map MAP"]
|
|
17
|
+
|
|
18
|
+
def post_option_parser(configuration)
|
|
19
|
+
configuration[:node] = ARGV.shift if ARGV.size > 0
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def validate_configuration(configuration)
|
|
23
|
+
unless configuration[:node] || configuration[:script] || configuration[:collectives] || configuration[:collectivemap]
|
|
24
|
+
raise "Need to specify either a node name, script to run or other options"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get all the known collectives and nodes that belong to them
|
|
29
|
+
def get_collectives
|
|
30
|
+
util = rpcclient("rpcutil")
|
|
31
|
+
util.progress = false
|
|
32
|
+
|
|
33
|
+
collectives = {}
|
|
34
|
+
nodes = 0
|
|
35
|
+
total = 0
|
|
36
|
+
|
|
37
|
+
util.collective_info do |r, cinfo|
|
|
38
|
+
begin
|
|
39
|
+
if cinfo[:data] && cinfo[:data][:collectives]
|
|
40
|
+
cinfo[:data][:collectives].each do |collective|
|
|
41
|
+
collectives[collective] ||= []
|
|
42
|
+
collectives[collective] << cinfo[:sender]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
nodes += 1
|
|
46
|
+
total += 1
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
{:collectives => collectives, :nodes => nodes, :total_nodes => total}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Writes a crude DOT graph to a file
|
|
55
|
+
def collectives_map(file)
|
|
56
|
+
File.open(file, "w") do |graph|
|
|
57
|
+
puts "Retrieving collective info...."
|
|
58
|
+
collectives = get_collectives
|
|
59
|
+
|
|
60
|
+
graph.puts 'graph {'
|
|
61
|
+
|
|
62
|
+
collectives[:collectives].keys.sort.each do |collective|
|
|
63
|
+
graph.puts ' subgraph "%s" {' % [ collective ]
|
|
64
|
+
|
|
65
|
+
collectives[:collectives][collective].each do |member|
|
|
66
|
+
graph.puts ' "%s" -- "%s"' % [ member, collective ]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
graph.puts ' }'
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
graph.puts '}'
|
|
73
|
+
|
|
74
|
+
puts "Graph of #{collectives[:total_nodes]} nodes has been written to #{file}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Prints a report of all known sub collectives
|
|
79
|
+
def collectives_report
|
|
80
|
+
collectives = get_collectives
|
|
81
|
+
|
|
82
|
+
puts " %-30s %s" % [ "Collective", "Nodes" ]
|
|
83
|
+
puts " %-30s %s" % [ "==========", "=====" ]
|
|
84
|
+
|
|
85
|
+
collectives[:collectives].sort_by {|key,count| count.size}.each do |collective|
|
|
86
|
+
puts " %-30s %d" % [ collective[0], collective[1].size ]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
puts
|
|
90
|
+
puts " %30s %d" % [ "Total nodes:", collectives[:nodes] ]
|
|
91
|
+
puts
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def node_inventory
|
|
95
|
+
node = configuration[:node]
|
|
96
|
+
|
|
97
|
+
util = rpcclient("rpcutil")
|
|
98
|
+
util.identity_filter node
|
|
99
|
+
util.progress = false
|
|
100
|
+
|
|
101
|
+
nodestats = util.custom_request("daemon_stats", {}, node, {"identity" => node}).first
|
|
102
|
+
|
|
103
|
+
unless nodestats
|
|
104
|
+
STDERR.puts "Did not receive any results from node #{node}"
|
|
105
|
+
exit 1
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
unless nodestats[:statuscode] == 0
|
|
109
|
+
STDERR.puts "Failed to retrieve daemon_stats from #{node}: #{nodestats[:statusmsg]}"
|
|
110
|
+
else
|
|
111
|
+
util.custom_request("inventory", {}, node, {"identity" => node}).each do |resp|
|
|
112
|
+
unless resp[:statuscode] == 0
|
|
113
|
+
STDERR.puts "Failed to retrieve inventory for #{node}: #{resp[:statusmsg]}"
|
|
114
|
+
next
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
data = resp[:data]
|
|
118
|
+
|
|
119
|
+
begin
|
|
120
|
+
puts "Inventory for #{resp[:sender]}:"
|
|
121
|
+
puts
|
|
122
|
+
|
|
123
|
+
nodestats = nodestats[:data]
|
|
124
|
+
|
|
125
|
+
puts " Server Statistics:"
|
|
126
|
+
puts " Version: #{nodestats[:version]}"
|
|
127
|
+
puts " Start Time: #{Time.at(nodestats[:starttime])}"
|
|
128
|
+
puts " Config File: #{nodestats[:configfile]}"
|
|
129
|
+
puts " Collectives: #{data[:collectives].join(', ')}" if data.include?(:collectives)
|
|
130
|
+
puts " Main Collective: #{data[:main_collective]}" if data.include?(:main_collective)
|
|
131
|
+
puts " Process ID: #{nodestats[:pid]}"
|
|
132
|
+
puts " Total Messages: #{nodestats[:total]}"
|
|
133
|
+
puts " Messages Passed Filters: #{nodestats[:passed]}"
|
|
134
|
+
puts " Messages Filtered: #{nodestats[:filtered]}"
|
|
135
|
+
puts " Expired Messages: #{nodestats[:ttlexpired]}"
|
|
136
|
+
puts " Replies Sent: #{nodestats[:replies]}"
|
|
137
|
+
puts " Total Processor Time: #{nodestats[:times][:utime]} seconds"
|
|
138
|
+
puts " System Time: #{nodestats[:times][:stime]} seconds"
|
|
139
|
+
|
|
140
|
+
puts
|
|
141
|
+
|
|
142
|
+
puts " Agents:"
|
|
143
|
+
if data[:agents].size > 0
|
|
144
|
+
data[:agents].sort.in_groups_of(3, "") do |agents|
|
|
145
|
+
puts " %-15s %-15s %-15s" % agents
|
|
146
|
+
end
|
|
147
|
+
else
|
|
148
|
+
puts " No agents installed"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
puts
|
|
152
|
+
|
|
153
|
+
puts " Data Plugins:"
|
|
154
|
+
if data[:data_plugins].size > 0
|
|
155
|
+
data[:data_plugins].sort.in_groups_of(3, "") do |plugins|
|
|
156
|
+
puts " %-15s %-15s %-15s" % plugins.map{|p| p.gsub("_data", "")}
|
|
157
|
+
end
|
|
158
|
+
else
|
|
159
|
+
puts " No data plugins installed"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
puts
|
|
163
|
+
|
|
164
|
+
puts " Configuration Management Classes:"
|
|
165
|
+
if data[:classes].size > 0
|
|
166
|
+
field_size = MCollective::Util.field_size(data[:classes], 30)
|
|
167
|
+
fields_num = MCollective::Util.field_number(field_size)
|
|
168
|
+
format = " " + (" %-#{field_size}s" * fields_num)
|
|
169
|
+
|
|
170
|
+
data[:classes].sort.in_groups_of(fields_num, "") do |klasses|
|
|
171
|
+
puts format % klasses
|
|
172
|
+
end
|
|
173
|
+
else
|
|
174
|
+
puts " No classes applied"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
puts
|
|
178
|
+
|
|
179
|
+
puts " Facts:"
|
|
180
|
+
if data[:facts].size > 0
|
|
181
|
+
data[:facts].sort_by{|f| f[0]}.each do |f|
|
|
182
|
+
puts " #{f[0]} => #{f[1]}"
|
|
183
|
+
end
|
|
184
|
+
else
|
|
185
|
+
puts " No facts known"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
break
|
|
189
|
+
rescue Exception => e
|
|
190
|
+
STDERR.puts "Failed to display node inventory: #{e.class}: #{e}"
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
halt util.stats
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Helpers to create a simple DSL for scriptlets
|
|
199
|
+
def format(fmt)
|
|
200
|
+
@fmt = fmt
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def fields(&blk)
|
|
204
|
+
@flds = blk
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def identity
|
|
208
|
+
@node[:identity]
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def facts
|
|
212
|
+
@node[:facts]
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def classes
|
|
216
|
+
@node[:classes]
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def agents
|
|
220
|
+
@node[:agents]
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def page_length(len)
|
|
224
|
+
@page_length = len
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def page_heading(fmt)
|
|
228
|
+
@page_heading = fmt
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def page_body(fmt)
|
|
232
|
+
@page_body = fmt
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Expects a simple printf style format and apply it to
|
|
236
|
+
# each node:
|
|
237
|
+
#
|
|
238
|
+
# inventory do
|
|
239
|
+
# format "%s:\t\t%s\t\t%s"
|
|
240
|
+
#
|
|
241
|
+
# fields { [ identity, facts["serialnumber"], facts["productname"] ] }
|
|
242
|
+
# end
|
|
243
|
+
def inventory(&blk)
|
|
244
|
+
raise "Need to give a block to inventory" unless block_given?
|
|
245
|
+
|
|
246
|
+
blk.call if block_given?
|
|
247
|
+
|
|
248
|
+
raise "Need to define a format" if @fmt.nil?
|
|
249
|
+
raise "Need to define inventory fields" if @flds.nil?
|
|
250
|
+
|
|
251
|
+
util = rpcclient("rpcutil")
|
|
252
|
+
util.progress = false
|
|
253
|
+
|
|
254
|
+
util.inventory do |t, resp|
|
|
255
|
+
@node = {:identity => resp[:sender],
|
|
256
|
+
:facts => resp[:data][:facts],
|
|
257
|
+
:classes => resp[:data][:classes],
|
|
258
|
+
:agents => resp[:data][:agents]}
|
|
259
|
+
|
|
260
|
+
puts @fmt % @flds.call
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Use the ruby formatr gem to build reports using Perls formats
|
|
265
|
+
#
|
|
266
|
+
# It is kind of ugly but brings a lot of flexibility in report
|
|
267
|
+
# writing without building an entire reporting language.
|
|
268
|
+
#
|
|
269
|
+
# You need to have formatr installed to enable reports like:
|
|
270
|
+
#
|
|
271
|
+
# formatted_inventory do
|
|
272
|
+
# page_length 20
|
|
273
|
+
#
|
|
274
|
+
# page_heading <<TOP
|
|
275
|
+
#
|
|
276
|
+
# Node Report @<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
277
|
+
# time
|
|
278
|
+
#
|
|
279
|
+
# Hostname: Customer: Distribution:
|
|
280
|
+
# -------------------------------------------------------------------------
|
|
281
|
+
# TOP
|
|
282
|
+
#
|
|
283
|
+
# page_body <<BODY
|
|
284
|
+
#
|
|
285
|
+
# @<<<<<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
286
|
+
# identity, facts["customer"], facts["lsbdistdescription"]
|
|
287
|
+
# @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
288
|
+
# facts["processor0"]
|
|
289
|
+
# BODY
|
|
290
|
+
# end
|
|
291
|
+
def formatted_inventory(&blk)
|
|
292
|
+
require 'formatr'
|
|
293
|
+
|
|
294
|
+
raise "Need to give a block to formatted_inventory" unless block_given?
|
|
295
|
+
|
|
296
|
+
blk.call if block_given?
|
|
297
|
+
|
|
298
|
+
raise "Need to define page body format" if @page_body.nil?
|
|
299
|
+
|
|
300
|
+
body_fmt = FormatR::Format.new(@page_heading, @page_body)
|
|
301
|
+
body_fmt.setPageLength(@page_length)
|
|
302
|
+
time = Time.now
|
|
303
|
+
|
|
304
|
+
util = rpcclient("rpcutil")
|
|
305
|
+
util.progress = false
|
|
306
|
+
|
|
307
|
+
util.inventory do |t, resp|
|
|
308
|
+
@node = {:identity => resp[:sender],
|
|
309
|
+
:facts => resp[:data][:facts],
|
|
310
|
+
:classes => resp[:data][:classes],
|
|
311
|
+
:agents => resp[:data][:agents]}
|
|
312
|
+
|
|
313
|
+
body_fmt.printFormat(binding)
|
|
314
|
+
end
|
|
315
|
+
rescue Exception => e
|
|
316
|
+
STDERR.puts "Could not create report: #{e.class}: #{e}"
|
|
317
|
+
exit 1
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
@fmt = nil
|
|
321
|
+
@flds = nil
|
|
322
|
+
@page_heading = nil
|
|
323
|
+
@page_body = nil
|
|
324
|
+
@page_length = 40
|
|
325
|
+
|
|
326
|
+
def main
|
|
327
|
+
if configuration[:script]
|
|
328
|
+
if File.exist?(configuration[:script])
|
|
329
|
+
eval(File.read(configuration[:script]))
|
|
330
|
+
else
|
|
331
|
+
raise "Could not find script to run: #{configuration[:script]}"
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
elsif configuration[:collectivemap]
|
|
335
|
+
collectives_map(configuration[:collectivemap])
|
|
336
|
+
|
|
337
|
+
elsif configuration[:collectives]
|
|
338
|
+
collectives_report
|
|
339
|
+
|
|
340
|
+
else
|
|
341
|
+
node_inventory
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
end
|