choria-mcorpc-support 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/mco +64 -0
- data/lib/mcollective.rb +63 -0
- data/lib/mcollective/agent.rb +5 -0
- data/lib/mcollective/agents.rb +149 -0
- data/lib/mcollective/aggregate.rb +85 -0
- data/lib/mcollective/aggregate/average.ddl +33 -0
- data/lib/mcollective/aggregate/average.rb +29 -0
- data/lib/mcollective/aggregate/base.rb +40 -0
- data/lib/mcollective/aggregate/result.rb +9 -0
- data/lib/mcollective/aggregate/result/base.rb +25 -0
- data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
- data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
- data/lib/mcollective/aggregate/sum.ddl +33 -0
- data/lib/mcollective/aggregate/sum.rb +18 -0
- data/lib/mcollective/aggregate/summary.ddl +33 -0
- data/lib/mcollective/aggregate/summary.rb +53 -0
- data/lib/mcollective/application.rb +365 -0
- data/lib/mcollective/application/completion.rb +104 -0
- data/lib/mcollective/application/describe_filter.rb +87 -0
- data/lib/mcollective/application/facts.rb +62 -0
- data/lib/mcollective/application/find.rb +23 -0
- data/lib/mcollective/application/help.rb +28 -0
- data/lib/mcollective/application/inventory.rb +344 -0
- data/lib/mcollective/application/ping.rb +82 -0
- data/lib/mcollective/application/plugin.rb +369 -0
- data/lib/mcollective/application/rpc.rb +111 -0
- data/lib/mcollective/applications.rb +134 -0
- data/lib/mcollective/cache.rb +145 -0
- data/lib/mcollective/client.rb +353 -0
- data/lib/mcollective/config.rb +245 -0
- data/lib/mcollective/connector.rb +18 -0
- data/lib/mcollective/connector/base.rb +26 -0
- data/lib/mcollective/data.rb +91 -0
- data/lib/mcollective/data/agent_data.ddl +22 -0
- data/lib/mcollective/data/agent_data.rb +17 -0
- data/lib/mcollective/data/base.rb +67 -0
- data/lib/mcollective/data/collective_data.ddl +20 -0
- data/lib/mcollective/data/collective_data.rb +9 -0
- data/lib/mcollective/data/fact_data.ddl +28 -0
- data/lib/mcollective/data/fact_data.rb +55 -0
- data/lib/mcollective/data/fstat_data.ddl +89 -0
- data/lib/mcollective/data/fstat_data.rb +56 -0
- data/lib/mcollective/data/result.rb +45 -0
- data/lib/mcollective/ddl.rb +113 -0
- data/lib/mcollective/ddl/agentddl.rb +253 -0
- data/lib/mcollective/ddl/base.rb +217 -0
- data/lib/mcollective/ddl/dataddl.rb +56 -0
- data/lib/mcollective/ddl/discoveryddl.rb +52 -0
- data/lib/mcollective/ddl/validatorddl.rb +6 -0
- data/lib/mcollective/discovery.rb +143 -0
- data/lib/mcollective/discovery/flatfile.ddl +11 -0
- data/lib/mcollective/discovery/flatfile.rb +48 -0
- data/lib/mcollective/discovery/mc.ddl +11 -0
- data/lib/mcollective/discovery/mc.rb +30 -0
- data/lib/mcollective/discovery/stdin.ddl +11 -0
- data/lib/mcollective/discovery/stdin.rb +68 -0
- data/lib/mcollective/exceptions.rb +28 -0
- data/lib/mcollective/facts.rb +39 -0
- data/lib/mcollective/facts/base.rb +100 -0
- data/lib/mcollective/facts/yaml_facts.rb +65 -0
- data/lib/mcollective/generators.rb +7 -0
- data/lib/mcollective/generators/agent_generator.rb +51 -0
- data/lib/mcollective/generators/base.rb +46 -0
- data/lib/mcollective/generators/data_generator.rb +51 -0
- data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
- data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
- data/lib/mcollective/generators/templates/ddl.erb +8 -0
- data/lib/mcollective/generators/templates/plugin.erb +7 -0
- data/lib/mcollective/log.rb +118 -0
- data/lib/mcollective/logger.rb +5 -0
- data/lib/mcollective/logger/base.rb +77 -0
- data/lib/mcollective/logger/console_logger.rb +61 -0
- data/lib/mcollective/logger/file_logger.rb +53 -0
- data/lib/mcollective/logger/syslog_logger.rb +53 -0
- data/lib/mcollective/matcher.rb +224 -0
- data/lib/mcollective/matcher/parser.rb +128 -0
- data/lib/mcollective/matcher/scanner.rb +241 -0
- data/lib/mcollective/message.rb +248 -0
- data/lib/mcollective/monkey_patches.rb +152 -0
- data/lib/mcollective/optionparser.rb +197 -0
- data/lib/mcollective/pluginmanager.rb +180 -0
- data/lib/mcollective/pluginpackager.rb +98 -0
- data/lib/mcollective/pluginpackager/agent_definition.rb +94 -0
- data/lib/mcollective/pluginpackager/debpackage_packager.rb +237 -0
- data/lib/mcollective/pluginpackager/modulepackage_packager.rb +127 -0
- data/lib/mcollective/pluginpackager/ospackage_packager.rb +59 -0
- data/lib/mcollective/pluginpackager/rpmpackage_packager.rb +180 -0
- data/lib/mcollective/pluginpackager/standard_definition.rb +69 -0
- data/lib/mcollective/pluginpackager/templates/debian/Makefile.erb +7 -0
- data/lib/mcollective/pluginpackager/templates/debian/changelog.erb +5 -0
- data/lib/mcollective/pluginpackager/templates/debian/compat.erb +1 -0
- data/lib/mcollective/pluginpackager/templates/debian/control.erb +15 -0
- data/lib/mcollective/pluginpackager/templates/debian/copyright.erb +8 -0
- data/lib/mcollective/pluginpackager/templates/debian/rules.erb +6 -0
- data/lib/mcollective/pluginpackager/templates/module/Modulefile.erb +5 -0
- data/lib/mcollective/pluginpackager/templates/module/README.md.erb +37 -0
- data/lib/mcollective/pluginpackager/templates/module/_manifest.pp.erb +9 -0
- data/lib/mcollective/pluginpackager/templates/redhat/rpm_spec.erb +63 -0
- data/lib/mcollective/registration/base.rb +91 -0
- data/lib/mcollective/rpc.rb +182 -0
- data/lib/mcollective/rpc/actionrunner.rb +158 -0
- data/lib/mcollective/rpc/agent.rb +374 -0
- data/lib/mcollective/rpc/audit.rb +38 -0
- data/lib/mcollective/rpc/client.rb +1066 -0
- data/lib/mcollective/rpc/helpers.rb +321 -0
- data/lib/mcollective/rpc/progress.rb +63 -0
- data/lib/mcollective/rpc/reply.rb +87 -0
- data/lib/mcollective/rpc/request.rb +86 -0
- data/lib/mcollective/rpc/result.rb +90 -0
- data/lib/mcollective/rpc/stats.rb +294 -0
- data/lib/mcollective/runnerstats.rb +90 -0
- data/lib/mcollective/security.rb +26 -0
- data/lib/mcollective/security/base.rb +244 -0
- data/lib/mcollective/shell.rb +126 -0
- data/lib/mcollective/ssl.rb +285 -0
- data/lib/mcollective/util.rb +579 -0
- data/lib/mcollective/validator.rb +85 -0
- data/lib/mcollective/validator/array_validator.ddl +7 -0
- data/lib/mcollective/validator/array_validator.rb +9 -0
- data/lib/mcollective/validator/ipv4address_validator.ddl +7 -0
- data/lib/mcollective/validator/ipv4address_validator.rb +16 -0
- data/lib/mcollective/validator/ipv6address_validator.ddl +7 -0
- data/lib/mcollective/validator/ipv6address_validator.rb +16 -0
- data/lib/mcollective/validator/length_validator.ddl +7 -0
- data/lib/mcollective/validator/length_validator.rb +11 -0
- data/lib/mcollective/validator/regex_validator.ddl +7 -0
- data/lib/mcollective/validator/regex_validator.rb +9 -0
- data/lib/mcollective/validator/shellsafe_validator.ddl +7 -0
- data/lib/mcollective/validator/shellsafe_validator.rb +13 -0
- data/lib/mcollective/validator/typecheck_validator.ddl +7 -0
- data/lib/mcollective/validator/typecheck_validator.rb +28 -0
- metadata +215 -0
|
@@ -0,0 +1,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,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,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
|