mcollective-client 2.0.0 → 2.2.0
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.
- data/lib/mcollective.rb +32 -23
- data/lib/mcollective/agent.rb +5 -0
- data/lib/mcollective/agents.rb +5 -16
- data/lib/mcollective/aggregate.rb +61 -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/application.rb +7 -4
- data/lib/mcollective/applications.rb +3 -14
- data/lib/mcollective/cache.rb +145 -0
- data/lib/mcollective/client.rb +10 -87
- data/lib/mcollective/config.rb +22 -8
- data/lib/mcollective/data.rb +87 -0
- data/lib/mcollective/data/base.rb +67 -0
- data/lib/mcollective/data/result.rb +40 -0
- data/lib/mcollective/ddl.rb +113 -0
- data/lib/mcollective/ddl/agentddl.rb +185 -0
- data/lib/mcollective/ddl/base.rb +220 -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/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/logger/console_logger.rb +15 -15
- data/lib/mcollective/matcher.rb +167 -0
- data/lib/mcollective/matcher/parser.rb +60 -25
- data/lib/mcollective/matcher/scanner.rb +156 -78
- data/lib/mcollective/message.rb +47 -6
- data/lib/mcollective/monkey_patches.rb +17 -0
- data/lib/mcollective/optionparser.rb +18 -1
- data/lib/mcollective/pluginmanager.rb +3 -3
- data/lib/mcollective/pluginpackager.rb +10 -3
- data/lib/mcollective/pluginpackager/agent_definition.rb +28 -20
- data/lib/mcollective/pluginpackager/standard_definition.rb +11 -9
- data/lib/mcollective/registration/base.rb +3 -1
- data/lib/mcollective/rpc.rb +18 -24
- data/lib/mcollective/rpc/agent.rb +37 -113
- data/lib/mcollective/rpc/client.rb +186 -64
- data/lib/mcollective/rpc/helpers.rb +42 -80
- data/lib/mcollective/rpc/progress.rb +3 -3
- data/lib/mcollective/rpc/reply.rb +37 -13
- data/lib/mcollective/rpc/request.rb +17 -6
- data/lib/mcollective/rpc/result.rb +9 -5
- data/lib/mcollective/rpc/stats.rb +71 -24
- data/lib/mcollective/security/base.rb +41 -34
- data/lib/mcollective/shell.rb +1 -1
- data/lib/mcollective/ssl.rb +34 -0
- data/lib/mcollective/util.rb +194 -23
- data/lib/mcollective/validator.rb +80 -0
- data/spec/fixtures/util/1.in +10 -0
- data/spec/fixtures/util/1.out +10 -0
- data/spec/fixtures/util/2.in +1 -0
- data/spec/fixtures/util/2.out +1 -0
- data/spec/fixtures/util/3.in +1 -0
- data/spec/fixtures/util/3.out +2 -0
- data/spec/fixtures/util/4.in +5 -0
- data/spec/fixtures/util/4.out +9 -0
- data/spec/spec.opts +1 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/agents_spec.rb +34 -19
- data/spec/unit/aggregate/base_spec.rb +57 -0
- data/spec/unit/aggregate/result/base_spec.rb +28 -0
- data/spec/unit/aggregate/result/collection_result_spec.rb +18 -0
- data/spec/unit/aggregate/result/numeric_result_spec.rb +22 -0
- data/spec/unit/aggregate_spec.rb +110 -0
- data/spec/unit/application_spec.rb +8 -3
- data/spec/unit/applications_spec.rb +2 -2
- data/spec/unit/cache_spec.rb +115 -0
- data/spec/unit/client_spec.rb +78 -0
- data/spec/unit/config_spec.rb +32 -34
- data/spec/unit/data/base_spec.rb +90 -0
- data/spec/unit/data/result_spec.rb +64 -0
- data/spec/unit/data_spec.rb +158 -0
- data/spec/unit/ddl/agentddl_spec.rb +217 -0
- data/spec/unit/{rpc/ddl_spec.rb → ddl/base_spec.rb} +238 -224
- data/spec/unit/ddl/dataddl_spec.rb +65 -0
- data/spec/unit/ddl/discoveryddl_spec.rb +58 -0
- data/spec/unit/ddl_spec.rb +84 -0
- data/spec/unit/discovery_spec.rb +196 -0
- data/spec/unit/facts/base_spec.rb +1 -1
- data/spec/unit/generators/agent_generator_spec.rb +72 -0
- data/spec/unit/generators/base_spec.rb +83 -0
- data/spec/unit/generators/data_generator_spec.rb +37 -0
- data/spec/unit/generators/snippets/agent_ddl +19 -0
- data/spec/unit/generators/snippets/data_ddl +20 -0
- data/spec/unit/logger/console_logger_spec.rb +76 -0
- data/spec/unit/logger/syslog_logger_spec.rb +2 -2
- data/spec/unit/matcher/parser_spec.rb +27 -10
- data/spec/unit/matcher/scanner_spec.rb +108 -5
- data/spec/unit/matcher_spec.rb +260 -0
- data/spec/unit/message_spec.rb +35 -13
- data/spec/unit/optionparser_spec.rb +2 -2
- data/spec/unit/pluginpackager/agent_definition_spec.rb +59 -42
- data/spec/unit/pluginpackager/standard_definition_spec.rb +10 -8
- data/spec/unit/pluginpackager_spec.rb +131 -0
- data/spec/unit/plugins/mcollective/aggregate/average_spec.rb +45 -0
- data/spec/unit/plugins/mcollective/aggregate/sum_spec.rb +31 -0
- data/spec/unit/plugins/mcollective/aggregate/summary_spec.rb +45 -0
- data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +1 -1
- data/spec/unit/plugins/mcollective/connector/rabbitmq_spec.rb +478 -0
- data/spec/unit/plugins/mcollective/connector/stomp_spec.rb +2 -0
- data/spec/unit/plugins/mcollective/data/agent_data_spec.rb +43 -0
- data/spec/unit/plugins/mcollective/data/fstat_data_spec.rb +135 -0
- data/spec/unit/plugins/mcollective/discovery/flatfile_spec.rb +48 -0
- data/spec/unit/plugins/mcollective/discovery/mc_spec.rb +40 -0
- data/spec/unit/plugins/mcollective/packagers/debpackage_packager_spec.rb +41 -15
- data/spec/unit/plugins/mcollective/packagers/ospackage_spec.rb +1 -1
- data/spec/unit/plugins/mcollective/packagers/rpmpackage_packager_spec.rb +22 -38
- data/spec/unit/plugins/mcollective/validator/array_validator_spec.rb +19 -0
- data/spec/unit/plugins/mcollective/validator/ipv4address_validator_spec.rb +19 -0
- data/spec/unit/plugins/mcollective/validator/ipv6address_validator_spec.rb +19 -0
- data/spec/unit/plugins/mcollective/validator/length_validator_spec.rb +19 -0
- data/spec/unit/plugins/mcollective/validator/regex_validator_spec.rb +19 -0
- data/spec/unit/plugins/mcollective/validator/shellsafe_validator_spec.rb +21 -0
- data/spec/unit/plugins/mcollective/validator/typecheck_validator_spec.rb +23 -0
- data/spec/unit/registration/base_spec.rb +1 -1
- data/spec/unit/rpc/actionrunner_spec.rb +2 -2
- data/spec/unit/rpc/agent_spec.rb +41 -65
- data/spec/unit/rpc/client_spec.rb +430 -134
- data/spec/unit/rpc/reply_spec.rb +31 -1
- data/spec/unit/rpc/request_spec.rb +33 -12
- data/spec/unit/rpc/result_spec.rb +7 -0
- data/spec/unit/rpc/stats_spec.rb +14 -14
- data/spec/unit/rpc_spec.rb +16 -0
- data/spec/unit/security/base_spec.rb +8 -8
- data/spec/unit/ssl_spec.rb +20 -2
- data/spec/unit/string_spec.rb +15 -0
- data/spec/unit/util_spec.rb +141 -21
- data/spec/unit/validator_spec.rb +67 -0
- metadata +145 -7
- data/lib/mcollective/rpc/ddl.rb +0 -258
data/lib/mcollective.rb
CHANGED
|
@@ -11,6 +11,7 @@ require 'rbconfig'
|
|
|
11
11
|
require 'tempfile'
|
|
12
12
|
require 'tmpdir'
|
|
13
13
|
require 'mcollective/monkey_patches'
|
|
14
|
+
require 'mcollective/cache'
|
|
14
15
|
|
|
15
16
|
# == The Marionette Collective
|
|
16
17
|
#
|
|
@@ -23,42 +24,50 @@ require 'mcollective/monkey_patches'
|
|
|
23
24
|
# http://www.devco.net/archives/2009/10/18/middleware_for_systems_administration.php
|
|
24
25
|
module MCollective
|
|
25
26
|
# Exceptions for the RPC system
|
|
27
|
+
class DDLValidationError<RuntimeError;end
|
|
28
|
+
class ValidatorError<RuntimeError; end
|
|
29
|
+
class MsgDoesNotMatchRequestID < RuntimeError; end
|
|
30
|
+
class MsgTTLExpired<RuntimeError;end
|
|
31
|
+
class NotTargettedAtUs<RuntimeError;end
|
|
26
32
|
class RPCError<StandardError;end
|
|
33
|
+
class SecurityValidationFailed<RuntimeError;end
|
|
34
|
+
|
|
35
|
+
class InvalidRPCData<RPCError;end
|
|
36
|
+
class MissingRPCData<RPCError;end
|
|
27
37
|
class RPCAborted<RPCError;end
|
|
28
38
|
class UnknownRPCAction<RPCError;end
|
|
29
|
-
class MissingRPCData<RPCError;end
|
|
30
|
-
class InvalidRPCData<RPCError;end
|
|
31
39
|
class UnknownRPCError<RPCError;end
|
|
32
|
-
class NotTargettedAtUs<RuntimeError;end
|
|
33
|
-
class SecurityValidationFailed<RuntimeError;end
|
|
34
|
-
class DDLValidationError<RuntimeError;end
|
|
35
|
-
class MsgTTLExpired<RuntimeError;end
|
|
36
|
-
class MsgDoesNotMatchRequestID < RuntimeError; end
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
autoload :Config, "mcollective/config"
|
|
40
|
-
autoload :Log, "mcollective/log"
|
|
41
|
-
autoload :Logger, "mcollective/logger"
|
|
42
|
-
autoload :Runner, "mcollective/runner"
|
|
43
|
-
autoload :RunnerStats, "mcollective/runnerstats"
|
|
41
|
+
autoload :Agent, "mcollective/agent"
|
|
44
42
|
autoload :Agents, "mcollective/agents"
|
|
43
|
+
autoload :Aggregate, "mcollective/aggregate"
|
|
44
|
+
autoload :Application, "mcollective/application"
|
|
45
|
+
autoload :Applications, "mcollective/applications"
|
|
45
46
|
autoload :Client, "mcollective/client"
|
|
46
|
-
autoload :
|
|
47
|
-
autoload :Optionparser, "mcollective/optionparser"
|
|
47
|
+
autoload :Config, "mcollective/config"
|
|
48
48
|
autoload :Connector, "mcollective/connector"
|
|
49
|
-
autoload :
|
|
49
|
+
autoload :Data, "mcollective/data"
|
|
50
|
+
autoload :DDL, "mcollective/ddl"
|
|
51
|
+
autoload :Discovery, "mcollective/discovery"
|
|
50
52
|
autoload :Facts, "mcollective/facts"
|
|
51
|
-
autoload :
|
|
52
|
-
autoload :
|
|
53
|
-
autoload :RPC, "mcollective/rpc"
|
|
53
|
+
autoload :Logger, "mcollective/logger"
|
|
54
|
+
autoload :Log, "mcollective/log"
|
|
54
55
|
autoload :Matcher, "mcollective/matcher"
|
|
55
56
|
autoload :Message, "mcollective/message"
|
|
57
|
+
autoload :Optionparser, "mcollective/optionparser"
|
|
58
|
+
autoload :Generators, "mcollective/generators"
|
|
59
|
+
autoload :PluginManager, "mcollective/pluginmanager"
|
|
60
|
+
autoload :PluginPackager, "mcollective/pluginpackager"
|
|
61
|
+
autoload :Registration, "mcollective/registration"
|
|
62
|
+
autoload :RPC, "mcollective/rpc"
|
|
63
|
+
autoload :Runner, "mcollective/runner"
|
|
64
|
+
autoload :RunnerStats, "mcollective/runnerstats"
|
|
65
|
+
autoload :Security, "mcollective/security"
|
|
66
|
+
autoload :Shell, "mcollective/shell"
|
|
56
67
|
autoload :SSL, "mcollective/ssl"
|
|
57
|
-
autoload :
|
|
58
|
-
autoload :
|
|
68
|
+
autoload :Util, "mcollective/util"
|
|
69
|
+
autoload :Validator, "mcollective/validator"
|
|
59
70
|
autoload :Vendor, "mcollective/vendor"
|
|
60
|
-
autoload :Shell, "mcollective/shell"
|
|
61
|
-
autoload :PluginPackager, "mcollective/pluginpackager"
|
|
62
71
|
|
|
63
72
|
MCollective::Vendor.load_vendored
|
|
64
73
|
|
data/lib/mcollective/agents.rb
CHANGED
|
@@ -54,6 +54,11 @@ module MCollective
|
|
|
54
54
|
if activate_agent?(agentname)
|
|
55
55
|
PluginManager << {:type => "#{agentname}_agent", :class => classname, :single_instance => single_instance}
|
|
56
56
|
|
|
57
|
+
# Attempt to instantiate the agent once so any validation and hooks get run
|
|
58
|
+
# this does a basic sanity check on the agent as a whole, if this fails it
|
|
59
|
+
# will be removed from the plugin list
|
|
60
|
+
PluginManager["#{agentname}_agent"]
|
|
61
|
+
|
|
57
62
|
Util.subscribe(Util.make_subscriptions(agentname, :broadcast)) unless @@agents.include?(agentname)
|
|
58
63
|
|
|
59
64
|
@@agents[agentname] = {:file => agentfile}
|
|
@@ -108,22 +113,6 @@ module MCollective
|
|
|
108
113
|
PluginManager.include?("#{agentname}_agent")
|
|
109
114
|
end
|
|
110
115
|
|
|
111
|
-
# Returns the help for an agent after first trying to get
|
|
112
|
-
# rid of some indentation infront
|
|
113
|
-
def help(agentname)
|
|
114
|
-
raise("No such agent") unless include?(agentname)
|
|
115
|
-
|
|
116
|
-
body = PluginManager["#{agentname}_agent"].help.split("\n")
|
|
117
|
-
|
|
118
|
-
if body.first =~ /^(\s+)\S/
|
|
119
|
-
indent = $1
|
|
120
|
-
|
|
121
|
-
body = body.map {|b| b.gsub(/^#{indent}/, "")}
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
body.join("\n")
|
|
125
|
-
end
|
|
126
|
-
|
|
127
116
|
# Dispatches a message to an agent, accepts a block that will get run if there are
|
|
128
117
|
# any replies to process from the agent
|
|
129
118
|
def dispatch(request, connection)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
class Aggregate
|
|
3
|
+
autoload :Result, 'mcollective/aggregate/result'
|
|
4
|
+
autoload :Base, 'mcollective/aggregate/base'
|
|
5
|
+
|
|
6
|
+
attr_accessor :ddl, :functions, :action
|
|
7
|
+
|
|
8
|
+
def initialize(ddl)
|
|
9
|
+
@functions = []
|
|
10
|
+
@ddl = ddl
|
|
11
|
+
@action = ddl[:action]
|
|
12
|
+
|
|
13
|
+
create_functions
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Creates instances of the Aggregate functions and stores them in the function array.
|
|
17
|
+
# All aggregate call and summarize method calls operate on these function as a batch.
|
|
18
|
+
def create_functions
|
|
19
|
+
@ddl[:aggregate].each_with_index do |agg, i|
|
|
20
|
+
contains_output?(agg[:args][0])
|
|
21
|
+
|
|
22
|
+
output = agg[:args][0]
|
|
23
|
+
arguments = agg[:args][1..(agg[:args].size)]
|
|
24
|
+
|
|
25
|
+
@functions << load_function(agg[:function]).new(output, arguments, agg[:format], @action)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Check if the function param is defined as an output for the action in the ddl
|
|
30
|
+
def contains_output?(output)
|
|
31
|
+
raise "'#{@ddl[:action]}' action does not contain output '#{output}'" unless @ddl[:output].keys.include?(output)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Call all the appropriate functions with the reply data received from RPC::Client
|
|
35
|
+
def call_functions(reply)
|
|
36
|
+
@functions.each do |function|
|
|
37
|
+
Log.debug("Calling aggregate function #{function} for result")
|
|
38
|
+
function.process_result(reply[:data][function.output_name], reply)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Finalizes the function returning a result object
|
|
43
|
+
def summarize
|
|
44
|
+
summary = @functions.map do |function|
|
|
45
|
+
function.summarize
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
summary.sort{|x,y| x.result[:output] <=> y.result[:output]}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Loads function from disk for use
|
|
52
|
+
def load_function(function_name)
|
|
53
|
+
function_name = function_name.to_s.capitalize
|
|
54
|
+
|
|
55
|
+
PluginManager.loadclass("MCollective::Aggregate::#{function_name}") unless Aggregate.const_defined?(function_name)
|
|
56
|
+
Aggregate.const_get(function_name)
|
|
57
|
+
rescue Exception
|
|
58
|
+
raise "Aggregate function file '#{function_name.downcase}.rb' cannot be loaded"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -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
|
+
autoload :Base, 'mcollective/aggregate/result/base'
|
|
5
|
+
autoload :NumericResult, 'mcollective/aggregate/result/numeric_result'
|
|
6
|
+
autoload :CollectionResult, '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
|
|
@@ -171,12 +171,12 @@ module MCollective
|
|
|
171
171
|
end
|
|
172
172
|
|
|
173
173
|
# type was given and its not one of our special types, just pass it onto optparse
|
|
174
|
-
opts_array << carg[:type] if carg[:type]
|
|
174
|
+
opts_array << carg[:type] if carg[:type] && ![:boolean, :bool, :array].include?(carg[:type])
|
|
175
175
|
|
|
176
176
|
opts_array << carg[:description]
|
|
177
177
|
|
|
178
178
|
# Handle our special types else just rely on the optparser to handle the types
|
|
179
|
-
if carg[:type]
|
|
179
|
+
if [:bool, :boolean].include?(carg[:type])
|
|
180
180
|
parser.send(*opts_array) do |v|
|
|
181
181
|
validate_option(carg[:validate], carg[:name], v)
|
|
182
182
|
|
|
@@ -255,9 +255,11 @@ module MCollective
|
|
|
255
255
|
raise(e)
|
|
256
256
|
end
|
|
257
257
|
|
|
258
|
-
err_dest.puts "
|
|
258
|
+
err_dest.puts "\nThe %s application failed to run, use -v for full error details: %s\n" % [ Util.colorize(:bold, $0), Util.colorize(:red, e.to_s)]
|
|
259
259
|
|
|
260
260
|
if options.nil? || options[:verbose]
|
|
261
|
+
e.backtrace.first << Util.colorize(:red, " <----")
|
|
262
|
+
err_dest.puts "\n%s %s" % [ Util.colorize(:red, e.to_s), Util.colorize(:bold, "(#{e.class.to_s})")]
|
|
261
263
|
e.backtrace.each{|l| err_dest.puts "\tfrom #{l}"}
|
|
262
264
|
end
|
|
263
265
|
|
|
@@ -307,7 +309,7 @@ module MCollective
|
|
|
307
309
|
# Exit with 0 if no discovery were done and > 0 responses were received
|
|
308
310
|
# Exit with 1 if no nodes were discovered
|
|
309
311
|
# Exit with 2 if nodes were discovered but some RPC requests failed
|
|
310
|
-
# Exit with 3 if nodes were discovered, but not responses
|
|
312
|
+
# Exit with 3 if nodes were discovered, but not responses received
|
|
311
313
|
# Exit with 4 if no discovery were done and no responses were received
|
|
312
314
|
def halt(stats)
|
|
313
315
|
request_stats = {:discoverytime => 0,
|
|
@@ -347,6 +349,7 @@ module MCollective
|
|
|
347
349
|
# cli options wouldnt take effect which could have a disasterous outcome
|
|
348
350
|
def rpcclient(agent, flags = {})
|
|
349
351
|
flags[:options] = options unless flags.include?(:options)
|
|
352
|
+
flags[:exit_on_failure] = false
|
|
350
353
|
|
|
351
354
|
super
|
|
352
355
|
end
|
|
@@ -11,10 +11,10 @@ module MCollective
|
|
|
11
11
|
begin
|
|
12
12
|
load_application(appname)
|
|
13
13
|
rescue Exception => e
|
|
14
|
-
e.backtrace.first <<
|
|
14
|
+
e.backtrace.first << Util.colorize(:red, " <----")
|
|
15
15
|
STDERR.puts "Application '#{appname}' failed to load:"
|
|
16
16
|
STDERR.puts
|
|
17
|
-
STDERR.puts
|
|
17
|
+
STDERR.puts Util.colorize(:red, " #{e} (#{e.class})")
|
|
18
18
|
STDERR.puts
|
|
19
19
|
STDERR.puts " %s" % [e.backtrace.join("\n ")]
|
|
20
20
|
exit 1
|
|
@@ -36,18 +36,7 @@ module MCollective
|
|
|
36
36
|
def self.list
|
|
37
37
|
load_config
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
Config.instance.libdir.each do |libdir|
|
|
42
|
-
applicationdir = "#{libdir}/mcollective/application"
|
|
43
|
-
next unless File.directory?(applicationdir)
|
|
44
|
-
|
|
45
|
-
Dir.entries(applicationdir).grep(/\.rb$/).each do |application|
|
|
46
|
-
applist << File.basename(application, ".rb")
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
applist
|
|
39
|
+
PluginManager.find("application")
|
|
51
40
|
rescue SystemExit
|
|
52
41
|
exit 1
|
|
53
42
|
rescue Exception => e
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
module MCollective
|
|
2
|
+
# A class to manage a number of named caches. Each cache can have a unique
|
|
3
|
+
# timeout for keys in it and each cache has an independent Mutex protecting
|
|
4
|
+
# access to it.
|
|
5
|
+
#
|
|
6
|
+
# This cache is setup early in the process of loading the mcollective
|
|
7
|
+
# libraries, before any threads are created etc making it suitable as a
|
|
8
|
+
# cross thread cache or just a store for Mutexes you need to use across
|
|
9
|
+
# threads like in an Agent or something.
|
|
10
|
+
#
|
|
11
|
+
# # sets up a new cache, noop if it already exist
|
|
12
|
+
# Cache.setup(:ddl, 600)
|
|
13
|
+
# => true
|
|
14
|
+
#
|
|
15
|
+
# # writes an item to the :ddl cache, this item will
|
|
16
|
+
# # be valid on the cache for 600 seconds
|
|
17
|
+
# Cache.write(:ddl, :something, "value")
|
|
18
|
+
# => "value"
|
|
19
|
+
#
|
|
20
|
+
# # reads from the cache, read failures due to non existing
|
|
21
|
+
# # data or expired data will raise an exception
|
|
22
|
+
# Cache.read(:ddl, :something)
|
|
23
|
+
# => "value"
|
|
24
|
+
#
|
|
25
|
+
# # time left till expiry, raises if nothing is found
|
|
26
|
+
# Cache.ttl(:ddl, :something)
|
|
27
|
+
# => 500
|
|
28
|
+
#
|
|
29
|
+
# # forcibly evict something from the cache
|
|
30
|
+
# Cache.invalidate!(:ddl, :something)
|
|
31
|
+
# => "value"
|
|
32
|
+
#
|
|
33
|
+
# # deletes an entire named cache and its mutexes
|
|
34
|
+
# Cache.delete!(:ddl)
|
|
35
|
+
# => true
|
|
36
|
+
#
|
|
37
|
+
# # you can also just use this cache as a global mutex store
|
|
38
|
+
# Cache.setup(:mylock)
|
|
39
|
+
#
|
|
40
|
+
# Cache.synchronize(:mylock) do
|
|
41
|
+
# do_something()
|
|
42
|
+
# end
|
|
43
|
+
#
|
|
44
|
+
module Cache
|
|
45
|
+
# protects access to @cache_locks and top level @cache
|
|
46
|
+
@locks_mutex = Mutex.new
|
|
47
|
+
|
|
48
|
+
# stores a mutex per named cache
|
|
49
|
+
@cache_locks = {}
|
|
50
|
+
|
|
51
|
+
# the named caches protected by items in @cache_locks
|
|
52
|
+
@cache = {}
|
|
53
|
+
|
|
54
|
+
def self.setup(cache_name, ttl=300)
|
|
55
|
+
@locks_mutex.synchronize do
|
|
56
|
+
break if @cache_locks.include?(cache_name)
|
|
57
|
+
|
|
58
|
+
@cache_locks[cache_name] = Mutex.new
|
|
59
|
+
|
|
60
|
+
@cache_locks[cache_name].synchronize do
|
|
61
|
+
@cache[cache_name] = {:max_age => Float(ttl)}
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
true
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.has_cache?(cache_name)
|
|
69
|
+
@locks_mutex.synchronize do
|
|
70
|
+
@cache.include?(cache_name)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.delete!(cache_name)
|
|
75
|
+
@locks_mutex.synchronize do
|
|
76
|
+
raise("No cache called '%s'" % cache_name) unless @cache_locks.include?(cache_name)
|
|
77
|
+
|
|
78
|
+
@cache_locks.delete(cache_name)
|
|
79
|
+
@cache.delete(cache_name)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.write(cache_name, key, value)
|
|
86
|
+
raise("No cache called '%s'" % cache_name) unless @cache.include?(cache_name)
|
|
87
|
+
|
|
88
|
+
@cache_locks[cache_name].synchronize do
|
|
89
|
+
@cache[cache_name][key] ||= {}
|
|
90
|
+
@cache[cache_name][key][:cache_create_time] = Time.now
|
|
91
|
+
@cache[cache_name][key][:value] = value
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
value
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def self.read(cache_name, key)
|
|
98
|
+
raise("No cache called '%s'" % cache_name) unless @cache.include?(cache_name)
|
|
99
|
+
|
|
100
|
+
unless ttl(cache_name, key) > 0
|
|
101
|
+
Log.debug("Cache expired on '%s' key '%s'" % [cache_name, key])
|
|
102
|
+
raise("Cache for item '%s' on cache '%s' has expired" % [key, cache_name])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
Log.debug("Cache hit on '%s' key '%s'" % [cache_name, key])
|
|
106
|
+
|
|
107
|
+
@cache_locks[cache_name].synchronize do
|
|
108
|
+
@cache[cache_name][key][:value]
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def self.ttl(cache_name, key)
|
|
113
|
+
raise("No cache called '%s'" % cache_name) unless @cache.include?(cache_name)
|
|
114
|
+
|
|
115
|
+
@cache_locks[cache_name].synchronize do
|
|
116
|
+
unless @cache[cache_name].include?(key)
|
|
117
|
+
Log.debug("Cache miss on '%s' key '%s'" % [cache_name, key])
|
|
118
|
+
raise("No item called '%s' for cache '%s'" % [key, cache_name])
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
@cache[cache_name][:max_age] - (Time.now - @cache[cache_name][key][:cache_create_time])
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def self.synchronize(cache_name)
|
|
126
|
+
raise("No cache called '%s'" % cache_name) unless @cache.include?(cache_name)
|
|
127
|
+
|
|
128
|
+
raise ("No block supplied to synchronize") unless block_given?
|
|
129
|
+
|
|
130
|
+
@cache_locks[cache_name].synchronize do
|
|
131
|
+
yield
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def self.invalidate!(cache_name, key)
|
|
136
|
+
raise("No cache called '%s'" % cache_name) unless @cache.include?(cache_name)
|
|
137
|
+
|
|
138
|
+
@cache_locks[cache_name].synchronize do
|
|
139
|
+
return false unless @cache[cache_name].include?(key)
|
|
140
|
+
|
|
141
|
+
@cache[cache_name].delete(key)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|