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.
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