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,40 @@
1
+ module MCollective
2
+ class Aggregate
3
+ class Base
4
+ attr_accessor :name, :result, :output_name, :action, :aggregate_format, :arguments
5
+
6
+ def initialize(output_name, arguments, aggregate_format, action)
7
+ @name = self.class.to_s
8
+ @output_name = output_name
9
+
10
+ # Any additional arguments passed in the ddl after the output field will
11
+ # be stored in the arguments array which can be used in the function
12
+ @arguments = arguments
13
+ @aggregate_format = aggregate_format
14
+ @action = action
15
+ @result = {:value => nil, :type => nil, :output => output_name}
16
+
17
+ startup_hook
18
+ end
19
+
20
+ ['startup_hook', 'process_result'].each do |method|
21
+ define_method method do
22
+ raise RuntimeError, "'#{method}' method of function class #{@name} has not yet been implemented"
23
+ end
24
+ end
25
+
26
+ # Stops execution of the function and returns a specific ResultObject,
27
+ # aggregate functions will most likely override this but this is the simplest
28
+ # case so we might as well default to that
29
+ def summarize
30
+ raise "Result type is not set while trying to summarize aggregate function results" unless @result[:type]
31
+
32
+ result_class(@result[:type]).new(@result, @aggregate_format, @action)
33
+ end
34
+
35
+ def result_class(type)
36
+ Result.const_get("#{type.to_s.capitalize}Result")
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,9 @@
1
+ module MCollective
2
+ class Aggregate
3
+ module Result
4
+ require 'mcollective/aggregate/result/base'
5
+ require 'mcollective/aggregate/result/numeric_result'
6
+ require 'mcollective/aggregate/result/collection_result'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ module MCollective
2
+ class Aggregate
3
+ module Result
4
+ class Base
5
+ attr_accessor :result, :aggregate_format, :action
6
+
7
+ def initialize(result, aggregate_format, action)
8
+ raise "No aggregate_format defined in ddl or aggregate function" unless aggregate_format
9
+
10
+ @result = result
11
+ @aggregate_format = aggregate_format
12
+ @action = action
13
+ end
14
+
15
+ def to_s
16
+ raise "'to_s' method not implemented for result class '#{self.class}'"
17
+ end
18
+
19
+ def result_type
20
+ @result[:type]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module MCollective
2
+ class Aggregate
3
+ module Result
4
+ class CollectionResult<Base
5
+ def to_s
6
+ return "" if @result[:value].keys.include?(nil)
7
+
8
+ result = StringIO.new
9
+
10
+ @result[:value].sort{|x,y| x[1] <=> y[1]}.reverse.each do |value|
11
+ result.puts @aggregate_format % [value[0], value[1]]
12
+ end
13
+
14
+ result.string.chomp
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ module MCollective
2
+ class Aggregate
3
+ module Result
4
+ class NumericResult<Base
5
+ def to_s
6
+ return "" if @result[:value].nil?
7
+
8
+ return @aggregate_format % @result[:value]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ metadata :name => "Sum",
2
+ :description => "Determine the total added value of a set of values",
3
+ :author => "Pieter Loubser <pieter.loubser@puppetlabs.com>",
4
+ :license => "ASL 2.0",
5
+ :version => "1.0",
6
+ :url => "https://docs.puppetlabs.com/mcollective/plugin_directory/",
7
+ :timeout => 5
8
+
9
+ usage <<-USAGE
10
+
11
+ This aggregate plugin will determine the total added value of a set of values.
12
+
13
+ DDL Example:
14
+
15
+ summarize do
16
+ aggregate sum(:value)
17
+ end
18
+
19
+ Sample Output:
20
+
21
+ host1.example.com
22
+ Value: 10
23
+
24
+ host2.example.com
25
+ Value: 20
26
+
27
+
28
+ Summary of Value:
29
+
30
+ Sum of Value: 30
31
+
32
+ USAGE
33
+
@@ -0,0 +1,18 @@
1
+ module MCollective
2
+ class Aggregate
3
+ class Sum<Base
4
+ def startup_hook
5
+ @result[:value] = 0
6
+ @result[:type] = :numeric
7
+
8
+ # Set default aggregate_function if it is undefined
9
+ @aggregate_format = "Sum of #{@result[:output]}: %f" unless @aggregate_format
10
+ end
11
+
12
+ # Determines the average of a set of numerical values
13
+ def process_result(value, reply)
14
+ @result[:value] += value
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ metadata :name => "summary",
2
+ :description => "Displays the summary of a set of results",
3
+ :author => "Pieter Loubser <pieter.loubser@puppetlabs.com>",
4
+ :license => "ASL 2.0",
5
+ :version => "1.0",
6
+ :url => "https://docs.puppetlabs.com/mcollective/plugin_directory/",
7
+ :timeout => 5
8
+
9
+ usage <<-USAGE
10
+
11
+ This aggregate plugin will display the summary of a set of results.
12
+
13
+ DDL Example:
14
+
15
+ summarize do
16
+ aggregate summary(:value)
17
+ end
18
+
19
+ Sample Output:
20
+
21
+ host1.example.com
22
+ Property: collectives
23
+ Value: ["mcollective", "uk_collective"]
24
+
25
+ Summary of Value:
26
+
27
+ mcollective = 25
28
+ uk_collective = 15
29
+ fr_collective = 9
30
+ us_collective = 1
31
+
32
+ USAGE
33
+
@@ -0,0 +1,53 @@
1
+ module MCollective
2
+ class Aggregate
3
+ class Summary<Base
4
+ # Before function is run processing
5
+ def startup_hook
6
+ @result[:value] = {}
7
+ @result[:type] = :collection
8
+
9
+ # set default aggregate_format if it is undefined
10
+ @aggregate_format = :calculate unless @aggregate_format
11
+ end
12
+
13
+ # Increments the value field if value has been seen before
14
+ # Else create a new value field
15
+ def process_result(value, reply)
16
+ unless value.nil?
17
+ if value.is_a? Array
18
+ value.map{|val| add_value(val)}
19
+ else
20
+ add_value(value)
21
+ end
22
+ end
23
+ end
24
+
25
+ def add_value(value)
26
+ if @result[:value].keys.include?(value)
27
+ @result[:value][value] += 1
28
+ else
29
+ @result[:value][value] = 1
30
+ end
31
+ end
32
+
33
+ def summarize
34
+ if @aggregate_format == :calculate
35
+ max_key_length = @result[:value].keys.map do |k|
36
+
37
+ # Response values retain their types. Here we check
38
+ # if the response is a string and turn it into a string
39
+ # if it isn't one.
40
+ if k.respond_to?(:length)
41
+ k.length
42
+ elsif k.respond_to?(:to_s)
43
+ k.to_s.length
44
+ end
45
+ end.max
46
+ @aggregate_format = "%#{max_key_length}s = %s"
47
+ end
48
+
49
+ super
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,365 @@
1
+ require 'mcollective/rpc'
2
+
3
+ module MCollective
4
+ class Application
5
+ include RPC
6
+
7
+ class << self
8
+ # Intialize a blank set of options if its the first time used
9
+ # else returns active options
10
+ def application_options
11
+ intialize_application_options unless @application_options
12
+ @application_options
13
+ end
14
+
15
+ # set an option in the options hash
16
+ def []=(option, value)
17
+ intialize_application_options unless @application_options
18
+ @application_options[option] = value
19
+ end
20
+
21
+ # retrieves a specific option
22
+ def [](option)
23
+ intialize_application_options unless @application_options
24
+ @application_options[option]
25
+ end
26
+
27
+ # Sets the application description, there can be only one
28
+ # description per application so multiple calls will just
29
+ # change the description
30
+ def description(descr)
31
+ self[:description] = descr
32
+ end
33
+
34
+ # Supplies usage information, calling multiple times will
35
+ # create multiple usage lines in --help output
36
+ def usage(usage)
37
+ self[:usage] << usage
38
+ end
39
+
40
+ def exclude_argument_sections(*sections)
41
+ sections = [sections].flatten
42
+
43
+ sections.each do |s|
44
+ raise "Unknown CLI argument section #{s}" unless ["rpc", "common", "filter"].include?(s)
45
+ end
46
+
47
+ intialize_application_options unless @application_options
48
+ self[:exclude_arg_sections] = sections
49
+ end
50
+
51
+ # Wrapper to create command line options
52
+ #
53
+ # - name: varaible name that will be used to access the option value
54
+ # - description: textual info shown in --help
55
+ # - arguments: a list of possible arguments that can be used
56
+ # to activate this option
57
+ # - type: a data type that ObjectParser understand of :bool or :array
58
+ # - required: true or false if this option has to be supplied
59
+ # - validate: a proc that will be called with the value used to validate
60
+ # the supplied value
61
+ #
62
+ # option :foo,
63
+ # :description => "The foo option"
64
+ # :arguments => ["--foo ARG"]
65
+ #
66
+ # after this the value supplied will be in configuration[:foo]
67
+ def option(name, arguments)
68
+ opt = {:name => name,
69
+ :description => nil,
70
+ :arguments => [],
71
+ :type => String,
72
+ :required => false,
73
+ :validate => Proc.new { true }}
74
+
75
+ arguments.each_pair{|k,v| opt[k] = v}
76
+
77
+ self[:cli_arguments] << opt
78
+ end
79
+
80
+ # Creates an empty set of options
81
+ def intialize_application_options
82
+ @application_options = {:description => nil,
83
+ :usage => [],
84
+ :cli_arguments => [],
85
+ :exclude_arg_sections => []}
86
+ end
87
+ end
88
+
89
+ # The application configuration built from CLI arguments
90
+ def configuration
91
+ @application_configuration ||= {}
92
+ @application_configuration
93
+ end
94
+
95
+ # The active options hash used for MC::Client and other configuration
96
+ def options
97
+ @options
98
+ end
99
+
100
+ # Calls the supplied block in an option for validation, an error raised
101
+ # will log to STDERR and exit the application
102
+ def validate_option(blk, name, value)
103
+ validation_result = blk.call(value)
104
+
105
+ unless validation_result == true
106
+ STDERR.puts "Validation of #{name} failed: #{validation_result}"
107
+ exit 1
108
+ end
109
+ end
110
+
111
+ # Creates a standard options hash, pass in a block to add extra headings etc
112
+ # see Optionparser
113
+ def clioptions(help)
114
+ oparser = Optionparser.new({:verbose => false, :progress_bar => true}, "filter", application_options[:exclude_arg_sections])
115
+
116
+ options = oparser.parse do |parser, options|
117
+ if block_given?
118
+ yield(parser, options)
119
+ end
120
+
121
+ RPC::Helpers.add_simplerpc_options(parser, options) unless application_options[:exclude_arg_sections].include?("rpc")
122
+ end
123
+
124
+ return oparser.parser.help if help
125
+
126
+ validate_cli_options
127
+
128
+ post_option_parser(configuration) if respond_to?(:post_option_parser)
129
+
130
+ return options
131
+ rescue Exception => e
132
+ application_failure(e)
133
+ end
134
+
135
+ # Builds an ObjectParser config, parse the CLI options and validates based
136
+ # on the option config
137
+ def application_parse_options(help=false)
138
+ @options ||= {:verbose => false}
139
+
140
+ @options = clioptions(help) do |parser, options|
141
+ parser.define_head application_description if application_description
142
+ parser.banner = ""
143
+
144
+ if application_usage
145
+ parser.separator ""
146
+
147
+ application_usage.each do |u|
148
+ parser.separator "Usage: #{u}"
149
+ end
150
+
151
+ parser.separator ""
152
+ end
153
+
154
+ parser.separator "Application Options" unless application_cli_arguments.empty?
155
+
156
+ parser.define_tail ""
157
+ parser.define_tail "The Marionette Collective #{MCollective.version}"
158
+
159
+
160
+ application_cli_arguments.each do |carg|
161
+ opts_array = []
162
+
163
+ opts_array << :on
164
+
165
+ # if a default is set from the application set it up front
166
+ if carg.include?(:default)
167
+ configuration[carg[:name]] = carg[:default]
168
+ end
169
+
170
+ # :arguments are multiple possible ones
171
+ if carg[:arguments].is_a?(Array)
172
+ carg[:arguments].each {|a| opts_array << a}
173
+ else
174
+ opts_array << carg[:arguments]
175
+ end
176
+
177
+ # type was given and its not one of our special types, just pass it onto optparse
178
+ opts_array << carg[:type] if carg[:type] && ![:boolean, :bool, :array].include?(carg[:type])
179
+
180
+ opts_array << carg[:description]
181
+
182
+ # Handle our special types else just rely on the optparser to handle the types
183
+ if [:bool, :boolean].include?(carg[:type])
184
+ parser.send(*opts_array) do |v|
185
+ validate_option(carg[:validate], carg[:name], v)
186
+
187
+ configuration[carg[:name]] = v
188
+ end
189
+
190
+ elsif carg[:type] == :array
191
+ parser.send(*opts_array) do |v|
192
+ validate_option(carg[:validate], carg[:name], v)
193
+
194
+ configuration[carg[:name]] = [] unless configuration.include?(carg[:name])
195
+ configuration[carg[:name]] << v
196
+ end
197
+
198
+ else
199
+ parser.send(*opts_array) do |v|
200
+ validate_option(carg[:validate], carg[:name], v)
201
+
202
+ configuration[carg[:name]] = v
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ def validate_cli_options
210
+ # Check all required parameters were set
211
+ validation_passed = true
212
+ application_cli_arguments.each do |carg|
213
+ # Check for required arguments
214
+ if carg[:required]
215
+ unless configuration[ carg[:name] ]
216
+ validation_passed = false
217
+ STDERR.puts "The #{carg[:name]} option is mandatory"
218
+ end
219
+ end
220
+ end
221
+
222
+ unless validation_passed
223
+ STDERR.puts "\nPlease run with --help for detailed help"
224
+ exit 1
225
+ end
226
+
227
+
228
+ end
229
+
230
+ # Retrieves the full hash of application options
231
+ def application_options
232
+ self.class.application_options
233
+ end
234
+
235
+ # Retrieve the current application description
236
+ def application_description
237
+ application_options[:description]
238
+ end
239
+
240
+ # Return the current usage text false if nothing is set
241
+ def application_usage
242
+ usage = application_options[:usage]
243
+
244
+ usage.empty? ? false : usage
245
+ end
246
+
247
+ # Returns an array of all the arguments built using
248
+ # calls to optin
249
+ def application_cli_arguments
250
+ application_options[:cli_arguments]
251
+ end
252
+
253
+ # Handles failure, if we're far enough in the initialization
254
+ # phase it will log backtraces if its in verbose mode only
255
+ def application_failure(e, err_dest=STDERR)
256
+ # peole can use exit() anywhere and not get nasty backtraces as a result
257
+ if e.is_a?(SystemExit)
258
+ disconnect
259
+ raise(e)
260
+ end
261
+
262
+ if options[:verbose]
263
+ err_dest.puts "\nThe %s application failed to run: %s\n" % [ Util.colorize(:bold, $0), Util.colorize(:red, e.to_s)]
264
+ else
265
+ err_dest.puts "\nThe %s application failed to run, use -v for full error backtrace details: %s\n" % [ Util.colorize(:bold, $0), Util.colorize(:red, e.to_s)]
266
+ end
267
+
268
+ if options.nil? || options[:verbose]
269
+ e.backtrace.first << Util.colorize(:red, " <----")
270
+ err_dest.puts "\n%s %s" % [ Util.colorize(:red, e.to_s), Util.colorize(:bold, "(#{e.class.to_s})")]
271
+ e.backtrace.each{|l| err_dest.puts "\tfrom #{l}"}
272
+ end
273
+
274
+ disconnect
275
+
276
+ exit 1
277
+ end
278
+
279
+ def help
280
+ application_parse_options(true)
281
+ end
282
+
283
+ # The main logic loop, builds up the options, validate configuration and calls
284
+ # the main as supplied by the user. Disconnects when done and pass any exception
285
+ # onto the application_failure helper
286
+ def run
287
+ application_parse_options
288
+
289
+ validate_configuration(configuration) if respond_to?(:validate_configuration)
290
+
291
+ Util.setup_windows_sleeper if Util.windows?
292
+
293
+ main
294
+
295
+ disconnect
296
+
297
+ rescue Exception => e
298
+ application_failure(e)
299
+ end
300
+
301
+ def disconnect
302
+ MCollective::PluginManager["connector_plugin"].disconnect
303
+ rescue
304
+ end
305
+
306
+ # Fake abstract class that logs if the user tries to use an application without
307
+ # supplying a main override method.
308
+ def main
309
+ STDERR.puts "Applications need to supply a 'main' method"
310
+ exit 1
311
+ end
312
+
313
+ def halt_code(stats)
314
+ request_stats = {:discoverytime => 0,
315
+ :discovered => 0,
316
+ :okcount => 0,
317
+ :failcount => 0}.merge(stats.to_hash)
318
+
319
+ if (request_stats[:discoverytime] == 0 && request_stats[:responses] == 0)
320
+ return 4
321
+ end
322
+
323
+ if (request_stats[:discovered] > 0)
324
+ if (request_stats[:responses] == 0)
325
+ return 3
326
+ elsif (request_stats[:failcount] > 0)
327
+ return 2
328
+ end
329
+ end
330
+
331
+ if (request_stats[:discovered] == 0)
332
+ if (request_stats[:responses] && request_stats[:responses] > 0)
333
+ return 0
334
+ else
335
+ return 1
336
+ end
337
+ end
338
+
339
+ return 0
340
+ end
341
+
342
+ # A helper that creates a consistent exit code for applications by looking at an
343
+ # instance of MCollective::RPC::Stats
344
+ #
345
+ # Exit with 0 if nodes were discovered and all passed
346
+ # Exit with 0 if no discovery were done and > 0 responses were received, all ok
347
+ # Exit with 1 if no nodes were discovered
348
+ # Exit with 2 if nodes were discovered but some RPC requests failed
349
+ # Exit with 3 if nodes were discovered, but no responses received
350
+ # Exit with 4 if no discovery were done and no responses were received
351
+ def halt(stats)
352
+ exit(halt_code(stats))
353
+ end
354
+
355
+ # Wrapper around MC::RPC#rpcclient that forcably supplies our options hash
356
+ # if someone forgets to pass in options in an application the filters and other
357
+ # cli options wouldnt take effect which could have a disasterous outcome
358
+ def rpcclient(agent, flags = {})
359
+ flags[:options] = options unless flags.include?(:options)
360
+ flags[:exit_on_failure] = false
361
+
362
+ super
363
+ end
364
+ end
365
+ end