choria-mcorpc-support 2.21.1 → 2.23.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 (145) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mcollective.rb +1 -2
  3. data/lib/mcollective/agent/bolt_tasks.ddl +253 -0
  4. data/lib/mcollective/agent/bolt_tasks.json +365 -0
  5. data/lib/mcollective/agent/bolt_tasks.rb +178 -0
  6. data/lib/mcollective/agent/choria_util.ddl +152 -0
  7. data/lib/mcollective/agent/choria_util.json +244 -0
  8. data/lib/mcollective/agent/rpcutil.ddl +8 -4
  9. data/lib/mcollective/agent/rpcutil.json +333 -0
  10. data/lib/mcollective/agent/scout.ddl +169 -0
  11. data/lib/mcollective/agent/scout.json +224 -0
  12. data/lib/mcollective/agents.rb +7 -6
  13. data/lib/mcollective/aggregate.rb +4 -4
  14. data/lib/mcollective/aggregate/average.rb +2 -2
  15. data/lib/mcollective/aggregate/base.rb +2 -2
  16. data/lib/mcollective/aggregate/result.rb +3 -3
  17. data/lib/mcollective/aggregate/result/collection_result.rb +2 -2
  18. data/lib/mcollective/aggregate/result/numeric_result.rb +2 -2
  19. data/lib/mcollective/aggregate/sum.rb +2 -2
  20. data/lib/mcollective/aggregate/summary.rb +3 -4
  21. data/lib/mcollective/application.rb +57 -21
  22. data/lib/mcollective/application/choria.rb +189 -0
  23. data/lib/mcollective/application/completion.rb +6 -6
  24. data/lib/mcollective/application/facts.rb +11 -11
  25. data/lib/mcollective/application/federation.rb +237 -0
  26. data/lib/mcollective/application/find.rb +4 -4
  27. data/lib/mcollective/application/help.rb +3 -3
  28. data/lib/mcollective/application/inventory.rb +3 -341
  29. data/lib/mcollective/application/ping.rb +5 -51
  30. data/lib/mcollective/application/playbook.rb +207 -0
  31. data/lib/mcollective/application/plugin.rb +106 -106
  32. data/lib/mcollective/application/rpc.rb +3 -108
  33. data/lib/mcollective/application/tasks.rb +425 -0
  34. data/lib/mcollective/applications.rb +11 -10
  35. data/lib/mcollective/audit/choria.rb +33 -0
  36. data/lib/mcollective/cache.rb +2 -4
  37. data/lib/mcollective/client.rb +11 -10
  38. data/lib/mcollective/config.rb +21 -34
  39. data/lib/mcollective/connector/base.rb +2 -1
  40. data/lib/mcollective/connector/nats.ddl +9 -0
  41. data/lib/mcollective/connector/nats.rb +450 -0
  42. data/lib/mcollective/data.rb +8 -3
  43. data/lib/mcollective/data/agent_data.rb +1 -1
  44. data/lib/mcollective/data/base.rb +6 -5
  45. data/lib/mcollective/data/bolt_task_data.ddl +90 -0
  46. data/lib/mcollective/data/bolt_task_data.rb +32 -0
  47. data/lib/mcollective/data/collective_data.rb +1 -1
  48. data/lib/mcollective/data/fact_data.rb +6 -6
  49. data/lib/mcollective/data/fstat_data.rb +2 -4
  50. data/lib/mcollective/data/result.rb +7 -2
  51. data/lib/mcollective/ddl/agentddl.rb +5 -17
  52. data/lib/mcollective/ddl/base.rb +10 -13
  53. data/lib/mcollective/discovery.rb +24 -39
  54. data/lib/mcollective/discovery/choria.ddl +11 -0
  55. data/lib/mcollective/discovery/choria.rb +223 -0
  56. data/lib/mcollective/discovery/flatfile.rb +7 -8
  57. data/lib/mcollective/discovery/mc.rb +2 -2
  58. data/lib/mcollective/discovery/stdin.rb +17 -18
  59. data/lib/mcollective/exceptions.rb +13 -0
  60. data/lib/mcollective/facts/base.rb +9 -9
  61. data/lib/mcollective/facts/yaml_facts.rb +12 -12
  62. data/lib/mcollective/generators.rb +3 -3
  63. data/lib/mcollective/generators/agent_generator.rb +3 -4
  64. data/lib/mcollective/generators/base.rb +14 -15
  65. data/lib/mcollective/generators/data_generator.rb +5 -6
  66. data/lib/mcollective/log.rb +2 -2
  67. data/lib/mcollective/logger/base.rb +3 -2
  68. data/lib/mcollective/logger/console_logger.rb +10 -10
  69. data/lib/mcollective/logger/file_logger.rb +7 -7
  70. data/lib/mcollective/logger/syslog_logger.rb +11 -15
  71. data/lib/mcollective/message.rb +8 -39
  72. data/lib/mcollective/monkey_patches.rb +2 -4
  73. data/lib/mcollective/optionparser.rb +2 -1
  74. data/lib/mcollective/pluginmanager.rb +3 -5
  75. data/lib/mcollective/pluginpackager.rb +1 -3
  76. data/lib/mcollective/pluginpackager/agent_definition.rb +3 -8
  77. data/lib/mcollective/pluginpackager/forge_packager.rb +7 -9
  78. data/lib/mcollective/pluginpackager/standard_definition.rb +1 -2
  79. data/lib/mcollective/registration/base.rb +18 -16
  80. data/lib/mcollective/rpc.rb +2 -4
  81. data/lib/mcollective/rpc/actionrunner.rb +16 -18
  82. data/lib/mcollective/rpc/agent.rb +26 -43
  83. data/lib/mcollective/rpc/audit.rb +1 -0
  84. data/lib/mcollective/rpc/client.rb +67 -85
  85. data/lib/mcollective/rpc/helpers.rb +55 -62
  86. data/lib/mcollective/rpc/progress.rb +2 -2
  87. data/lib/mcollective/rpc/reply.rb +17 -19
  88. data/lib/mcollective/rpc/request.rb +7 -5
  89. data/lib/mcollective/rpc/result.rb +6 -8
  90. data/lib/mcollective/rpc/stats.rb +49 -58
  91. data/lib/mcollective/security/base.rb +13 -56
  92. data/lib/mcollective/security/choria.rb +765 -0
  93. data/lib/mcollective/shell.rb +9 -4
  94. data/lib/mcollective/signer/base.rb +28 -0
  95. data/lib/mcollective/signer/choria.rb +185 -0
  96. data/lib/mcollective/ssl.rb +8 -6
  97. data/lib/mcollective/util.rb +58 -55
  98. data/lib/mcollective/util/bolt_support.rb +176 -0
  99. data/lib/mcollective/util/bolt_support/plan_runner.rb +167 -0
  100. data/lib/mcollective/util/bolt_support/task_result.rb +94 -0
  101. data/lib/mcollective/util/bolt_support/task_results.rb +128 -0
  102. data/lib/mcollective/util/choria.rb +946 -0
  103. data/lib/mcollective/util/indifferent_hash.rb +12 -0
  104. data/lib/mcollective/util/natswrapper.rb +242 -0
  105. data/lib/mcollective/util/playbook.rb +435 -0
  106. data/lib/mcollective/util/playbook/data_stores.rb +201 -0
  107. data/lib/mcollective/util/playbook/data_stores/base.rb +99 -0
  108. data/lib/mcollective/util/playbook/data_stores/consul_data_store.rb +88 -0
  109. data/lib/mcollective/util/playbook/data_stores/environment_data_store.rb +33 -0
  110. data/lib/mcollective/util/playbook/data_stores/etcd_data_store.rb +42 -0
  111. data/lib/mcollective/util/playbook/data_stores/file_data_store.rb +106 -0
  112. data/lib/mcollective/util/playbook/data_stores/shell_data_store.rb +103 -0
  113. data/lib/mcollective/util/playbook/inputs.rb +265 -0
  114. data/lib/mcollective/util/playbook/nodes.rb +207 -0
  115. data/lib/mcollective/util/playbook/nodes/mcollective_nodes.rb +86 -0
  116. data/lib/mcollective/util/playbook/nodes/pql_nodes.rb +40 -0
  117. data/lib/mcollective/util/playbook/nodes/shell_nodes.rb +55 -0
  118. data/lib/mcollective/util/playbook/nodes/terraform_nodes.rb +65 -0
  119. data/lib/mcollective/util/playbook/nodes/yaml_nodes.rb +47 -0
  120. data/lib/mcollective/util/playbook/playbook_logger.rb +47 -0
  121. data/lib/mcollective/util/playbook/puppet_logger.rb +51 -0
  122. data/lib/mcollective/util/playbook/report.rb +152 -0
  123. data/lib/mcollective/util/playbook/task_result.rb +55 -0
  124. data/lib/mcollective/util/playbook/tasks.rb +196 -0
  125. data/lib/mcollective/util/playbook/tasks/base.rb +45 -0
  126. data/lib/mcollective/util/playbook/tasks/graphite_event_task.rb +64 -0
  127. data/lib/mcollective/util/playbook/tasks/mcollective_task.rb +356 -0
  128. data/lib/mcollective/util/playbook/tasks/shell_task.rb +93 -0
  129. data/lib/mcollective/util/playbook/tasks/slack_task.rb +105 -0
  130. data/lib/mcollective/util/playbook/tasks/webhook_task.rb +136 -0
  131. data/lib/mcollective/util/playbook/template_util.rb +98 -0
  132. data/lib/mcollective/util/playbook/uses.rb +169 -0
  133. data/lib/mcollective/util/tasks_support.rb +751 -0
  134. data/lib/mcollective/util/tasks_support/cli.rb +260 -0
  135. data/lib/mcollective/util/tasks_support/default_formatter.rb +138 -0
  136. data/lib/mcollective/util/tasks_support/json_formatter.rb +108 -0
  137. data/lib/mcollective/validator.rb +6 -1
  138. data/lib/mcollective/validator/bolt_task_name_validator.ddl +7 -0
  139. data/lib/mcollective/validator/bolt_task_name_validator.rb +11 -0
  140. data/lib/mcollective/validator/length_validator.rb +1 -3
  141. metadata +65 -6
  142. data/lib/mcollective/application/describe_filter.rb +0 -87
  143. data/lib/mcollective/matcher.rb +0 -220
  144. data/lib/mcollective/matcher/parser.rb +0 -128
  145. data/lib/mcollective/matcher/scanner.rb +0 -241
@@ -0,0 +1,224 @@
1
+ {
2
+ "$schema": "https://choria.io/schemas/mcorpc/ddl/v1/agent.json",
3
+ "metadata": {
4
+ "name": "scout",
5
+ "description": "Choria Scout Agent Management API",
6
+ "author": "R.I.Pienaar <rip@devco.net>",
7
+ "license": "Apache-2.0",
8
+ "version": "0.0.1",
9
+ "url": "https://choria.io",
10
+ "provider": "golang",
11
+ "timeout": 5
12
+ },
13
+ "actions": [
14
+ {
15
+ "action": "checks",
16
+ "input": {
17
+ },
18
+ "output": {
19
+ "checks": {
20
+ "description": "Details about each check",
21
+ "display_as": "Checks",
22
+ "default": null,
23
+ "type": "array"
24
+ }
25
+ },
26
+ "display": "ok",
27
+ "description": "Obtain a list of checks and their current status"
28
+ },
29
+ {
30
+ "action": "goss_validate",
31
+ "input": {
32
+ "file": {
33
+ "prompt": "Goss File",
34
+ "description": "Path to the Goss validation specification",
35
+ "type": "string",
36
+ "default": null,
37
+ "optional": false,
38
+ "validation": ".+",
39
+ "maxlength": 256
40
+ },
41
+ "vars": {
42
+ "prompt": "Vars File",
43
+ "description": "Path to a file to use as template variables",
44
+ "type": "string",
45
+ "default": null,
46
+ "optional": true,
47
+ "validation": ".+",
48
+ "maxlength": 256
49
+ }
50
+ },
51
+ "output": {
52
+ "failures": {
53
+ "description": "The number of tests that failed",
54
+ "display_as": "Failed Tests",
55
+ "default": null,
56
+ "type": "integer"
57
+ },
58
+ "results": {
59
+ "description": "The full test results",
60
+ "display_as": "Results",
61
+ "default": null,
62
+ "type": "array"
63
+ },
64
+ "runtime": {
65
+ "description": "The time it took to run the tests, in seconds",
66
+ "display_as": "Runtime",
67
+ "default": null,
68
+ "type": "integer"
69
+ },
70
+ "success": {
71
+ "description": "Indicates if the test passed",
72
+ "display_as": "Success",
73
+ "default": null,
74
+ "type": "string"
75
+ },
76
+ "summary": {
77
+ "description": "A human friendly test result",
78
+ "display_as": "Summary",
79
+ "default": null,
80
+ "type": "string"
81
+ },
82
+ "tests": {
83
+ "description": "The number of tests that were run",
84
+ "display_as": "Tests",
85
+ "default": null,
86
+ "type": "integer"
87
+ }
88
+ },
89
+ "display": "failed",
90
+ "description": "Performs a Goss validation using a specific file",
91
+ "aggregate": [
92
+ {
93
+ "function": "summary",
94
+ "args": [
95
+ "tests",
96
+ {
97
+ "format": "%s Test Cases on %d node(s)"
98
+ }
99
+ ]
100
+ },
101
+ {
102
+ "function": "summary",
103
+ "args": [
104
+ "failures",
105
+ {
106
+ "format": "%s Failed Cases on %d node(s)"
107
+ }
108
+ ]
109
+ },
110
+ {
111
+ "function": "summary",
112
+ "args": [
113
+ "success",
114
+ {
115
+ "format": "%s Passed Cases on %d node(s)"
116
+ }
117
+ ]
118
+ }
119
+ ]
120
+ },
121
+ {
122
+ "action": "maintenance",
123
+ "input": {
124
+ "checks": {
125
+ "prompt": "Checks",
126
+ "description": "Check to pause, empty means all",
127
+ "type": "array",
128
+ "default": null,
129
+ "optional": true
130
+ }
131
+ },
132
+ "output": {
133
+ "failed": {
134
+ "description": "List of checks that could not be paused",
135
+ "display_as": "Failed",
136
+ "default": null,
137
+ "type": "array"
138
+ },
139
+ "skipped": {
140
+ "description": "List of checks that was skipped",
141
+ "display_as": "Skipped",
142
+ "default": null,
143
+ "type": "array"
144
+ },
145
+ "transitioned": {
146
+ "description": "List of checks that were paused",
147
+ "display_as": "Triggered",
148
+ "default": null,
149
+ "type": "array"
150
+ }
151
+ },
152
+ "display": "failed",
153
+ "description": "Pause checking of one or more checks"
154
+ },
155
+ {
156
+ "action": "resume",
157
+ "input": {
158
+ "checks": {
159
+ "prompt": "Checks",
160
+ "description": "Check to resume, empty means all",
161
+ "type": "array",
162
+ "default": null,
163
+ "optional": true
164
+ }
165
+ },
166
+ "output": {
167
+ "failed": {
168
+ "description": "List of checks that could not be resumed",
169
+ "display_as": "Failed",
170
+ "default": null,
171
+ "type": "array"
172
+ },
173
+ "skipped": {
174
+ "description": "List of checks that was skipped",
175
+ "display_as": "Skipped",
176
+ "default": null,
177
+ "type": "array"
178
+ },
179
+ "transitioned": {
180
+ "description": "List of checks that were resumed",
181
+ "display_as": "Triggered",
182
+ "default": null,
183
+ "type": "array"
184
+ }
185
+ },
186
+ "display": "failed",
187
+ "description": "Resume active checking of one or more checks"
188
+ },
189
+ {
190
+ "action": "trigger",
191
+ "input": {
192
+ "checks": {
193
+ "prompt": "Checks",
194
+ "description": "Check to trigger, empty means all",
195
+ "type": "array",
196
+ "default": null,
197
+ "optional": true
198
+ }
199
+ },
200
+ "output": {
201
+ "failed": {
202
+ "description": "List of checks that could not be triggered",
203
+ "display_as": "Failed",
204
+ "default": null,
205
+ "type": "array"
206
+ },
207
+ "skipped": {
208
+ "description": "List of checks that was skipped",
209
+ "display_as": "Skipped",
210
+ "default": null,
211
+ "type": "array"
212
+ },
213
+ "transitioned": {
214
+ "description": "List of checks that were triggered",
215
+ "display_as": "Triggered",
216
+ "default": null,
217
+ "type": "array"
218
+ }
219
+ },
220
+ "display": "failed",
221
+ "description": "Force an immediate check of one or more checks"
222
+ }
223
+ ]
224
+ }
@@ -42,6 +42,7 @@ module MCollective
42
42
  def loadagent(agentname)
43
43
  agentfile = findagentfile(agentname)
44
44
  return false unless agentfile
45
+
45
46
  classname = class_for_agent(agentname)
46
47
 
47
48
  PluginManager.delete("#{agentname}_agent")
@@ -62,16 +63,16 @@ module MCollective
62
63
  Util.subscribe(Util.make_subscriptions(agentname, :broadcast)) unless @@agents.include?(agentname)
63
64
 
64
65
  @@agents[agentname] = {:file => agentfile}
65
- return true
66
+ true
66
67
  else
67
68
  Log.debug("Not activating agent #{agentname} due to agent policy in activate? method")
68
- return false
69
+ false
69
70
  end
70
71
  rescue Exception # rubocop:disable Lint/RescueException
71
72
  Log.error("Loading agent %s failed: %s" % [agentname, $!])
72
73
  PluginManager.delete("%s_agent" % agentname)
73
74
 
74
- return false
75
+ false
75
76
  end
76
77
  end
77
78
 
@@ -87,14 +88,14 @@ module MCollective
87
88
  klass = Kernel.const_get("MCollective").const_get("Agent").const_get(agent.capitalize)
88
89
 
89
90
  if klass.respond_to?("activate?")
90
- return klass.activate?
91
+ klass.activate?
91
92
  else
92
93
  Log.debug("#{klass} does not have an activate? method, activating as default")
93
- return true
94
+ true
94
95
  end
95
96
  rescue Exception # rubocop:disable Lint/RescueException
96
97
  Log.warn("Agent activation check for %s #{agent} failed: %s: %s" % [agent, $!.class, $!])
97
- return false
98
+ false
98
99
  end
99
100
 
100
101
  # searches the libdirs for agents
@@ -25,7 +25,7 @@ module MCollective
25
25
  format = (arguments.delete(:format) if arguments) || nil
26
26
  begin
27
27
  @functions << load_function(agg[:function]).new(output, arguments, format, @action)
28
- rescue Exception => e
28
+ rescue Exception => e # rubocop:disable Lint/RescueException
29
29
  Log.error("Cannot create aggregate function '%s': %s" % [output, e])
30
30
  @failed << {:name => output, :type => :startup}
31
31
  end
@@ -47,7 +47,7 @@ module MCollective
47
47
  Log.debug("Calling aggregate function %s for result" % function)
48
48
  begin
49
49
  function.process_result(reply[:data][function.output_name], reply)
50
- rescue Exception => e
50
+ rescue Exception => e # rubocop:disable Lint/RescueException
51
51
  Log.error("Could not process aggregate function for '%s': %s" % [function.output_name, e])
52
52
  @failed << {:name => function.output_name, :type => :process_result}
53
53
  @functions.delete(function)
@@ -60,7 +60,7 @@ module MCollective
60
60
  summary = @functions.map do |function|
61
61
  begin
62
62
  function.summarize
63
- rescue Exception => e
63
+ rescue Exception => e # rubocop:disable Lint/RescueException
64
64
  Log.error("Could not summarize aggregate result for '%s': %s" % [function.output_name, e])
65
65
  @failed << {:name => function.output_name, :type => :summarize}
66
66
  nil
@@ -78,7 +78,7 @@ module MCollective
78
78
 
79
79
  PluginManager.loadclass("MCollective::Aggregate::%s" % function_name) unless Aggregate.const_defined?(function_name)
80
80
  Aggregate.const_get(function_name)
81
- rescue Exception
81
+ rescue Exception # rubocop:disable Lint/RescueException
82
82
  raise("Aggregate function file '%s.rb' cannot be loaded" % function_name.downcase)
83
83
  end
84
84
  end
@@ -1,6 +1,6 @@
1
1
  module MCollective
2
2
  class Aggregate
3
- class Average<Base
3
+ class Average < Base
4
4
  # Before function is run processing
5
5
  def startup_hook
6
6
  @result[:value] = 0
@@ -9,7 +9,7 @@ module MCollective
9
9
  @count = 0
10
10
 
11
11
  # Set default aggregate_function if it is undefined
12
- @aggregate_format = "Average of #{@result[:output]}: %f" unless @aggregate_format
12
+ @aggregate_format ||= "Average of #{@result[:output]}: %f"
13
13
  end
14
14
 
15
15
  # Determines the average of a set of numerical values
@@ -17,9 +17,9 @@ module MCollective
17
17
  startup_hook
18
18
  end
19
19
 
20
- ['startup_hook', 'process_result'].each do |method|
20
+ ["startup_hook", "process_result"].each do |method|
21
21
  define_method method do
22
- raise RuntimeError, "'#{method}' method of function class #{@name} has not yet been implemented"
22
+ raise "'#{method}' method of function class #{@name} has not yet been implemented"
23
23
  end
24
24
  end
25
25
 
@@ -1,9 +1,9 @@
1
1
  module MCollective
2
2
  class Aggregate
3
3
  module Result
4
- require 'mcollective/aggregate/result/base'
5
- require 'mcollective/aggregate/result/numeric_result'
6
- require 'mcollective/aggregate/result/collection_result'
4
+ require "mcollective/aggregate/result/base"
5
+ require "mcollective/aggregate/result/numeric_result"
6
+ require "mcollective/aggregate/result/collection_result"
7
7
  end
8
8
  end
9
9
  end
@@ -1,13 +1,13 @@
1
1
  module MCollective
2
2
  class Aggregate
3
3
  module Result
4
- class CollectionResult<Base
4
+ class CollectionResult < Base
5
5
  def to_s
6
6
  return "" if @result[:value].keys.include?(nil)
7
7
 
8
8
  result = StringIO.new
9
9
 
10
- @result[:value].sort{|x,y| x[1] <=> y[1]}.reverse.each do |value|
10
+ @result[:value].sort {|x, y| x[1] <=> y[1]}.reverse.each do |value|
11
11
  result.puts @aggregate_format % [value[0], value[1]]
12
12
  end
13
13
 
@@ -1,11 +1,11 @@
1
1
  module MCollective
2
2
  class Aggregate
3
3
  module Result
4
- class NumericResult<Base
4
+ class NumericResult < Base
5
5
  def to_s
6
6
  return "" if @result[:value].nil?
7
7
 
8
- return @aggregate_format % @result[:value]
8
+ @aggregate_format % @result[:value]
9
9
  end
10
10
  end
11
11
  end
@@ -1,12 +1,12 @@
1
1
  module MCollective
2
2
  class Aggregate
3
- class Sum<Base
3
+ class Sum < Base
4
4
  def startup_hook
5
5
  @result[:value] = 0
6
6
  @result[:type] = :numeric
7
7
 
8
8
  # Set default aggregate_function if it is undefined
9
- @aggregate_format = "Sum of #{@result[:output]}: %f" unless @aggregate_format
9
+ @aggregate_format ||= "Sum of #{@result[:output]}: %f"
10
10
  end
11
11
 
12
12
  # Determines the average of a set of numerical values
@@ -1,13 +1,13 @@
1
1
  module MCollective
2
2
  class Aggregate
3
- class Summary<Base
3
+ class Summary < Base
4
4
  # Before function is run processing
5
5
  def startup_hook
6
6
  @result[:value] = {}
7
7
  @result[:type] = :collection
8
8
 
9
9
  # set default aggregate_format if it is undefined
10
- @aggregate_format = :calculate unless @aggregate_format
10
+ @aggregate_format ||= :calculate
11
11
  end
12
12
 
13
13
  # Increments the value field if value has been seen before
@@ -15,7 +15,7 @@ module MCollective
15
15
  def process_result(value, reply)
16
16
  unless value.nil?
17
17
  if value.is_a? Array
18
- value.map{|val| add_value(val)}
18
+ value.map {|val| add_value(val)}
19
19
  else
20
20
  add_value(value)
21
21
  end
@@ -33,7 +33,6 @@ module MCollective
33
33
  def summarize
34
34
  if @aggregate_format == :calculate
35
35
  max_key_length = @result[:value].keys.map do |k|
36
-
37
36
  # Response values retain their types. Here we check
38
37
  # if the response is a string and turn it into a string
39
38
  # if it isn't one.
@@ -31,6 +31,24 @@ module MCollective
31
31
  self[:description] = descr
32
32
  end
33
33
 
34
+ # Executes an external program instead of implement the logic in ruby
35
+ #
36
+ # @param [Hash] command the command to run
37
+ # @option command [String] :command the command to run
38
+ # @option command [Array] :args arguments to pass to the command
39
+ def external(command)
40
+ self[:external] = command
41
+ end
42
+
43
+ # Executes an external program to show help instead of supplying options
44
+ #
45
+ # @param [Hash] command the command to run
46
+ # @option command [String] :command the command to run
47
+ # @option command [Array] :args arguments to pass to the command
48
+ def external_help(command)
49
+ self[:external_help] = command
50
+ end
51
+
34
52
  # Supplies usage information, calling multiple times will
35
53
  # create multiple usage lines in --help output
36
54
  def usage(usage)
@@ -79,10 +97,12 @@ module MCollective
79
97
 
80
98
  # Creates an empty set of options
81
99
  def intialize_application_options
82
- @application_options = {:description => nil,
83
- :usage => [],
84
- :cli_arguments => [],
85
- :exclude_arg_sections => []}
100
+ @application_options = {:description => nil,
101
+ :usage => [],
102
+ :cli_arguments => [],
103
+ :exclude_arg_sections => [],
104
+ :external => nil,
105
+ :external_help => nil}
86
106
  end
87
107
  end
88
108
 
@@ -101,7 +121,7 @@ module MCollective
101
121
  validation_result = blk.call(value)
102
122
 
103
123
  unless validation_result == true
104
- STDERR.puts "Validation of #{name} failed: #{validation_result}"
124
+ warn "Validation of #{name} failed: #{validation_result}"
105
125
  exit 1
106
126
  end
107
127
  end
@@ -123,7 +143,7 @@ module MCollective
123
143
 
124
144
  post_option_parser(configuration) if respond_to?(:post_option_parser)
125
145
 
126
- return options
146
+ options
127
147
  rescue Exception # rubocop:disable Lint/RescueException
128
148
  application_failure($!)
129
149
  end
@@ -205,14 +225,15 @@ module MCollective
205
225
  application_cli_arguments.each do |carg|
206
226
  # Check for required arguments
207
227
  next unless carg[:required]
228
+
208
229
  unless configuration[carg[:name]]
209
230
  validation_passed = false
210
- STDERR.puts "The #{carg[:name]} option is mandatory"
231
+ warn "The #{carg[:name]} option is mandatory"
211
232
  end
212
233
  end
213
234
 
214
235
  unless validation_passed
215
- STDERR.puts "\nPlease run with --help for detailed help"
236
+ warn "\nPlease run with --help for detailed help"
216
237
  exit 1
217
238
  end
218
239
  end
@@ -242,23 +263,23 @@ module MCollective
242
263
 
243
264
  # Handles failure, if we're far enough in the initialization
244
265
  # phase it will log backtraces if its in verbose mode only
245
- def application_failure(e, err_dest=STDERR)
266
+ def application_failure(err, err_dest=$stderr)
246
267
  # peole can use exit() anywhere and not get nasty backtraces as a result
247
- if e.is_a?(SystemExit)
268
+ if err.is_a?(SystemExit)
248
269
  disconnect
249
- raise(e)
270
+ raise(err)
250
271
  end
251
272
 
252
273
  if options[:verbose]
253
- err_dest.puts "\nThe %s application failed to run: %s\n" % [Util.colorize(:bold, $0), Util.colorize(:red, e.to_s)]
274
+ err_dest.puts "\nThe %s application failed to run: %s\n" % [Util.colorize(:bold, $0), Util.colorize(:red, err.to_s)]
254
275
  else
255
- 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)]
276
+ 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, err.to_s)]
256
277
  end
257
278
 
258
279
  if options.nil? || options[:verbose]
259
- e.backtrace.first << Util.colorize(:red, " <----")
260
- err_dest.puts "\n%s %s" % [Util.colorize(:red, e.to_s), Util.colorize(:bold, "(#{e.class})")]
261
- e.backtrace.each {|l| err_dest.puts "\tfrom #{l}"}
280
+ err.backtrace.first << Util.colorize(:red, " <----")
281
+ err_dest.puts "\n%s %s" % [Util.colorize(:red, err.to_s), Util.colorize(:bold, "(#{err.class})")]
282
+ err.backtrace.each {|l| err_dest.puts "\tfrom #{l}"}
262
283
  end
263
284
 
264
285
  disconnect
@@ -266,7 +287,14 @@ module MCollective
266
287
  exit 1
267
288
  end
268
289
 
290
+ def external_help
291
+ ext = application_options[:external_help]
292
+ exec(ext[:command], ext[:args])
293
+ end
294
+
269
295
  def help
296
+ return external_help if application_options[:external_help]
297
+
270
298
  application_parse_options(true)
271
299
  end
272
300
 
@@ -274,6 +302,8 @@ module MCollective
274
302
  # the main as supplied by the user. Disconnects when done and pass any exception
275
303
  # onto the application_failure helper
276
304
  def run
305
+ return external_main if application_options[:external]
306
+
277
307
  application_parse_options
278
308
 
279
309
  validate_configuration(configuration) if respond_to?(:validate_configuration)
@@ -289,13 +319,21 @@ module MCollective
289
319
 
290
320
  def disconnect
291
321
  MCollective::PluginManager["connector_plugin"].disconnect
292
- rescue # rubocop:disable Lint/HandleExceptions
322
+ rescue # rubocop:disable Lint/SuppressedException
323
+ end
324
+
325
+ def external_main
326
+ ext = application_options[:external]
327
+ args = ext[:args] || []
328
+ args.concat(ARGV)
329
+
330
+ exec(ext[:command], *args)
293
331
  end
294
332
 
295
333
  # Fake abstract class that logs if the user tries to use an application without
296
334
  # supplying a main override method.
297
335
  def main
298
- STDERR.puts "Applications need to supply a 'main' method"
336
+ warn "Applications need to supply a 'main' method"
299
337
  exit 1
300
338
  end
301
339
 
@@ -305,9 +343,7 @@ module MCollective
305
343
  :okcount => 0,
306
344
  :failcount => 0}.merge(stats.to_hash)
307
345
 
308
- if request_stats[:discoverytime] == 0 && request_stats[:responses] == 0
309
- return 4
310
- end
346
+ return 4 if request_stats[:discoverytime] == 0 && request_stats[:responses] == 0
311
347
 
312
348
  if request_stats[:discovered] > 0
313
349
  if request_stats[:responses] == 0