choria-mcorpc-support 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/bin/mco +64 -0
  3. data/lib/mcollective.rb +63 -0
  4. data/lib/mcollective/agent.rb +5 -0
  5. data/lib/mcollective/agents.rb +149 -0
  6. data/lib/mcollective/aggregate.rb +85 -0
  7. data/lib/mcollective/aggregate/average.ddl +33 -0
  8. data/lib/mcollective/aggregate/average.rb +29 -0
  9. data/lib/mcollective/aggregate/base.rb +40 -0
  10. data/lib/mcollective/aggregate/result.rb +9 -0
  11. data/lib/mcollective/aggregate/result/base.rb +25 -0
  12. data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
  13. data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
  14. data/lib/mcollective/aggregate/sum.ddl +33 -0
  15. data/lib/mcollective/aggregate/sum.rb +18 -0
  16. data/lib/mcollective/aggregate/summary.ddl +33 -0
  17. data/lib/mcollective/aggregate/summary.rb +53 -0
  18. data/lib/mcollective/application.rb +365 -0
  19. data/lib/mcollective/application/completion.rb +104 -0
  20. data/lib/mcollective/application/describe_filter.rb +87 -0
  21. data/lib/mcollective/application/facts.rb +62 -0
  22. data/lib/mcollective/application/find.rb +23 -0
  23. data/lib/mcollective/application/help.rb +28 -0
  24. data/lib/mcollective/application/inventory.rb +344 -0
  25. data/lib/mcollective/application/ping.rb +82 -0
  26. data/lib/mcollective/application/plugin.rb +369 -0
  27. data/lib/mcollective/application/rpc.rb +111 -0
  28. data/lib/mcollective/applications.rb +134 -0
  29. data/lib/mcollective/cache.rb +145 -0
  30. data/lib/mcollective/client.rb +353 -0
  31. data/lib/mcollective/config.rb +245 -0
  32. data/lib/mcollective/connector.rb +18 -0
  33. data/lib/mcollective/connector/base.rb +26 -0
  34. data/lib/mcollective/data.rb +91 -0
  35. data/lib/mcollective/data/agent_data.ddl +22 -0
  36. data/lib/mcollective/data/agent_data.rb +17 -0
  37. data/lib/mcollective/data/base.rb +67 -0
  38. data/lib/mcollective/data/collective_data.ddl +20 -0
  39. data/lib/mcollective/data/collective_data.rb +9 -0
  40. data/lib/mcollective/data/fact_data.ddl +28 -0
  41. data/lib/mcollective/data/fact_data.rb +55 -0
  42. data/lib/mcollective/data/fstat_data.ddl +89 -0
  43. data/lib/mcollective/data/fstat_data.rb +56 -0
  44. data/lib/mcollective/data/result.rb +45 -0
  45. data/lib/mcollective/ddl.rb +113 -0
  46. data/lib/mcollective/ddl/agentddl.rb +253 -0
  47. data/lib/mcollective/ddl/base.rb +217 -0
  48. data/lib/mcollective/ddl/dataddl.rb +56 -0
  49. data/lib/mcollective/ddl/discoveryddl.rb +52 -0
  50. data/lib/mcollective/ddl/validatorddl.rb +6 -0
  51. data/lib/mcollective/discovery.rb +143 -0
  52. data/lib/mcollective/discovery/flatfile.ddl +11 -0
  53. data/lib/mcollective/discovery/flatfile.rb +48 -0
  54. data/lib/mcollective/discovery/mc.ddl +11 -0
  55. data/lib/mcollective/discovery/mc.rb +30 -0
  56. data/lib/mcollective/discovery/stdin.ddl +11 -0
  57. data/lib/mcollective/discovery/stdin.rb +68 -0
  58. data/lib/mcollective/exceptions.rb +28 -0
  59. data/lib/mcollective/facts.rb +39 -0
  60. data/lib/mcollective/facts/base.rb +100 -0
  61. data/lib/mcollective/facts/yaml_facts.rb +65 -0
  62. data/lib/mcollective/generators.rb +7 -0
  63. data/lib/mcollective/generators/agent_generator.rb +51 -0
  64. data/lib/mcollective/generators/base.rb +46 -0
  65. data/lib/mcollective/generators/data_generator.rb +51 -0
  66. data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
  67. data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
  68. data/lib/mcollective/generators/templates/ddl.erb +8 -0
  69. data/lib/mcollective/generators/templates/plugin.erb +7 -0
  70. data/lib/mcollective/log.rb +118 -0
  71. data/lib/mcollective/logger.rb +5 -0
  72. data/lib/mcollective/logger/base.rb +77 -0
  73. data/lib/mcollective/logger/console_logger.rb +61 -0
  74. data/lib/mcollective/logger/file_logger.rb +53 -0
  75. data/lib/mcollective/logger/syslog_logger.rb +53 -0
  76. data/lib/mcollective/matcher.rb +224 -0
  77. data/lib/mcollective/matcher/parser.rb +128 -0
  78. data/lib/mcollective/matcher/scanner.rb +241 -0
  79. data/lib/mcollective/message.rb +248 -0
  80. data/lib/mcollective/monkey_patches.rb +152 -0
  81. data/lib/mcollective/optionparser.rb +197 -0
  82. data/lib/mcollective/pluginmanager.rb +180 -0
  83. data/lib/mcollective/pluginpackager.rb +98 -0
  84. data/lib/mcollective/pluginpackager/agent_definition.rb +94 -0
  85. data/lib/mcollective/pluginpackager/debpackage_packager.rb +237 -0
  86. data/lib/mcollective/pluginpackager/modulepackage_packager.rb +127 -0
  87. data/lib/mcollective/pluginpackager/ospackage_packager.rb +59 -0
  88. data/lib/mcollective/pluginpackager/rpmpackage_packager.rb +180 -0
  89. data/lib/mcollective/pluginpackager/standard_definition.rb +69 -0
  90. data/lib/mcollective/pluginpackager/templates/debian/Makefile.erb +7 -0
  91. data/lib/mcollective/pluginpackager/templates/debian/changelog.erb +5 -0
  92. data/lib/mcollective/pluginpackager/templates/debian/compat.erb +1 -0
  93. data/lib/mcollective/pluginpackager/templates/debian/control.erb +15 -0
  94. data/lib/mcollective/pluginpackager/templates/debian/copyright.erb +8 -0
  95. data/lib/mcollective/pluginpackager/templates/debian/rules.erb +6 -0
  96. data/lib/mcollective/pluginpackager/templates/module/Modulefile.erb +5 -0
  97. data/lib/mcollective/pluginpackager/templates/module/README.md.erb +37 -0
  98. data/lib/mcollective/pluginpackager/templates/module/_manifest.pp.erb +9 -0
  99. data/lib/mcollective/pluginpackager/templates/redhat/rpm_spec.erb +63 -0
  100. data/lib/mcollective/registration/base.rb +91 -0
  101. data/lib/mcollective/rpc.rb +182 -0
  102. data/lib/mcollective/rpc/actionrunner.rb +158 -0
  103. data/lib/mcollective/rpc/agent.rb +374 -0
  104. data/lib/mcollective/rpc/audit.rb +38 -0
  105. data/lib/mcollective/rpc/client.rb +1066 -0
  106. data/lib/mcollective/rpc/helpers.rb +321 -0
  107. data/lib/mcollective/rpc/progress.rb +63 -0
  108. data/lib/mcollective/rpc/reply.rb +87 -0
  109. data/lib/mcollective/rpc/request.rb +86 -0
  110. data/lib/mcollective/rpc/result.rb +90 -0
  111. data/lib/mcollective/rpc/stats.rb +294 -0
  112. data/lib/mcollective/runnerstats.rb +90 -0
  113. data/lib/mcollective/security.rb +26 -0
  114. data/lib/mcollective/security/base.rb +244 -0
  115. data/lib/mcollective/shell.rb +126 -0
  116. data/lib/mcollective/ssl.rb +285 -0
  117. data/lib/mcollective/util.rb +579 -0
  118. data/lib/mcollective/validator.rb +85 -0
  119. data/lib/mcollective/validator/array_validator.ddl +7 -0
  120. data/lib/mcollective/validator/array_validator.rb +9 -0
  121. data/lib/mcollective/validator/ipv4address_validator.ddl +7 -0
  122. data/lib/mcollective/validator/ipv4address_validator.rb +16 -0
  123. data/lib/mcollective/validator/ipv6address_validator.ddl +7 -0
  124. data/lib/mcollective/validator/ipv6address_validator.rb +16 -0
  125. data/lib/mcollective/validator/length_validator.ddl +7 -0
  126. data/lib/mcollective/validator/length_validator.rb +11 -0
  127. data/lib/mcollective/validator/regex_validator.ddl +7 -0
  128. data/lib/mcollective/validator/regex_validator.rb +9 -0
  129. data/lib/mcollective/validator/shellsafe_validator.ddl +7 -0
  130. data/lib/mcollective/validator/shellsafe_validator.rb +13 -0
  131. data/lib/mcollective/validator/typecheck_validator.ddl +7 -0
  132. data/lib/mcollective/validator/typecheck_validator.rb +28 -0
  133. 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