mcollective-client 2.0.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mcollective-client might be problematic. Click here for more details.

Files changed (140) hide show
  1. data/lib/mcollective.rb +32 -23
  2. data/lib/mcollective/agent.rb +5 -0
  3. data/lib/mcollective/agents.rb +5 -16
  4. data/lib/mcollective/aggregate.rb +61 -0
  5. data/lib/mcollective/aggregate/base.rb +40 -0
  6. data/lib/mcollective/aggregate/result.rb +9 -0
  7. data/lib/mcollective/aggregate/result/base.rb +25 -0
  8. data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
  9. data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
  10. data/lib/mcollective/application.rb +7 -4
  11. data/lib/mcollective/applications.rb +3 -14
  12. data/lib/mcollective/cache.rb +145 -0
  13. data/lib/mcollective/client.rb +10 -87
  14. data/lib/mcollective/config.rb +22 -8
  15. data/lib/mcollective/data.rb +87 -0
  16. data/lib/mcollective/data/base.rb +67 -0
  17. data/lib/mcollective/data/result.rb +40 -0
  18. data/lib/mcollective/ddl.rb +113 -0
  19. data/lib/mcollective/ddl/agentddl.rb +185 -0
  20. data/lib/mcollective/ddl/base.rb +220 -0
  21. data/lib/mcollective/ddl/dataddl.rb +56 -0
  22. data/lib/mcollective/ddl/discoveryddl.rb +52 -0
  23. data/lib/mcollective/ddl/validatorddl.rb +6 -0
  24. data/lib/mcollective/discovery.rb +143 -0
  25. data/lib/mcollective/generators.rb +7 -0
  26. data/lib/mcollective/generators/agent_generator.rb +51 -0
  27. data/lib/mcollective/generators/base.rb +46 -0
  28. data/lib/mcollective/generators/data_generator.rb +51 -0
  29. data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
  30. data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
  31. data/lib/mcollective/generators/templates/ddl.erb +8 -0
  32. data/lib/mcollective/generators/templates/plugin.erb +7 -0
  33. data/lib/mcollective/logger/console_logger.rb +15 -15
  34. data/lib/mcollective/matcher.rb +167 -0
  35. data/lib/mcollective/matcher/parser.rb +60 -25
  36. data/lib/mcollective/matcher/scanner.rb +156 -78
  37. data/lib/mcollective/message.rb +47 -6
  38. data/lib/mcollective/monkey_patches.rb +17 -0
  39. data/lib/mcollective/optionparser.rb +18 -1
  40. data/lib/mcollective/pluginmanager.rb +3 -3
  41. data/lib/mcollective/pluginpackager.rb +10 -3
  42. data/lib/mcollective/pluginpackager/agent_definition.rb +28 -20
  43. data/lib/mcollective/pluginpackager/standard_definition.rb +11 -9
  44. data/lib/mcollective/registration/base.rb +3 -1
  45. data/lib/mcollective/rpc.rb +18 -24
  46. data/lib/mcollective/rpc/agent.rb +37 -113
  47. data/lib/mcollective/rpc/client.rb +186 -64
  48. data/lib/mcollective/rpc/helpers.rb +42 -80
  49. data/lib/mcollective/rpc/progress.rb +3 -3
  50. data/lib/mcollective/rpc/reply.rb +37 -13
  51. data/lib/mcollective/rpc/request.rb +17 -6
  52. data/lib/mcollective/rpc/result.rb +9 -5
  53. data/lib/mcollective/rpc/stats.rb +71 -24
  54. data/lib/mcollective/security/base.rb +41 -34
  55. data/lib/mcollective/shell.rb +1 -1
  56. data/lib/mcollective/ssl.rb +34 -0
  57. data/lib/mcollective/util.rb +194 -23
  58. data/lib/mcollective/validator.rb +80 -0
  59. data/spec/fixtures/util/1.in +10 -0
  60. data/spec/fixtures/util/1.out +10 -0
  61. data/spec/fixtures/util/2.in +1 -0
  62. data/spec/fixtures/util/2.out +1 -0
  63. data/spec/fixtures/util/3.in +1 -0
  64. data/spec/fixtures/util/3.out +2 -0
  65. data/spec/fixtures/util/4.in +5 -0
  66. data/spec/fixtures/util/4.out +9 -0
  67. data/spec/spec.opts +1 -1
  68. data/spec/spec_helper.rb +2 -0
  69. data/spec/unit/agents_spec.rb +34 -19
  70. data/spec/unit/aggregate/base_spec.rb +57 -0
  71. data/spec/unit/aggregate/result/base_spec.rb +28 -0
  72. data/spec/unit/aggregate/result/collection_result_spec.rb +18 -0
  73. data/spec/unit/aggregate/result/numeric_result_spec.rb +22 -0
  74. data/spec/unit/aggregate_spec.rb +110 -0
  75. data/spec/unit/application_spec.rb +8 -3
  76. data/spec/unit/applications_spec.rb +2 -2
  77. data/spec/unit/cache_spec.rb +115 -0
  78. data/spec/unit/client_spec.rb +78 -0
  79. data/spec/unit/config_spec.rb +32 -34
  80. data/spec/unit/data/base_spec.rb +90 -0
  81. data/spec/unit/data/result_spec.rb +64 -0
  82. data/spec/unit/data_spec.rb +158 -0
  83. data/spec/unit/ddl/agentddl_spec.rb +217 -0
  84. data/spec/unit/{rpc/ddl_spec.rb → ddl/base_spec.rb} +238 -224
  85. data/spec/unit/ddl/dataddl_spec.rb +65 -0
  86. data/spec/unit/ddl/discoveryddl_spec.rb +58 -0
  87. data/spec/unit/ddl_spec.rb +84 -0
  88. data/spec/unit/discovery_spec.rb +196 -0
  89. data/spec/unit/facts/base_spec.rb +1 -1
  90. data/spec/unit/generators/agent_generator_spec.rb +72 -0
  91. data/spec/unit/generators/base_spec.rb +83 -0
  92. data/spec/unit/generators/data_generator_spec.rb +37 -0
  93. data/spec/unit/generators/snippets/agent_ddl +19 -0
  94. data/spec/unit/generators/snippets/data_ddl +20 -0
  95. data/spec/unit/logger/console_logger_spec.rb +76 -0
  96. data/spec/unit/logger/syslog_logger_spec.rb +2 -2
  97. data/spec/unit/matcher/parser_spec.rb +27 -10
  98. data/spec/unit/matcher/scanner_spec.rb +108 -5
  99. data/spec/unit/matcher_spec.rb +260 -0
  100. data/spec/unit/message_spec.rb +35 -13
  101. data/spec/unit/optionparser_spec.rb +2 -2
  102. data/spec/unit/pluginpackager/agent_definition_spec.rb +59 -42
  103. data/spec/unit/pluginpackager/standard_definition_spec.rb +10 -8
  104. data/spec/unit/pluginpackager_spec.rb +131 -0
  105. data/spec/unit/plugins/mcollective/aggregate/average_spec.rb +45 -0
  106. data/spec/unit/plugins/mcollective/aggregate/sum_spec.rb +31 -0
  107. data/spec/unit/plugins/mcollective/aggregate/summary_spec.rb +45 -0
  108. data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +1 -1
  109. data/spec/unit/plugins/mcollective/connector/rabbitmq_spec.rb +478 -0
  110. data/spec/unit/plugins/mcollective/connector/stomp_spec.rb +2 -0
  111. data/spec/unit/plugins/mcollective/data/agent_data_spec.rb +43 -0
  112. data/spec/unit/plugins/mcollective/data/fstat_data_spec.rb +135 -0
  113. data/spec/unit/plugins/mcollective/discovery/flatfile_spec.rb +48 -0
  114. data/spec/unit/plugins/mcollective/discovery/mc_spec.rb +40 -0
  115. data/spec/unit/plugins/mcollective/packagers/debpackage_packager_spec.rb +41 -15
  116. data/spec/unit/plugins/mcollective/packagers/ospackage_spec.rb +1 -1
  117. data/spec/unit/plugins/mcollective/packagers/rpmpackage_packager_spec.rb +22 -38
  118. data/spec/unit/plugins/mcollective/validator/array_validator_spec.rb +19 -0
  119. data/spec/unit/plugins/mcollective/validator/ipv4address_validator_spec.rb +19 -0
  120. data/spec/unit/plugins/mcollective/validator/ipv6address_validator_spec.rb +19 -0
  121. data/spec/unit/plugins/mcollective/validator/length_validator_spec.rb +19 -0
  122. data/spec/unit/plugins/mcollective/validator/regex_validator_spec.rb +19 -0
  123. data/spec/unit/plugins/mcollective/validator/shellsafe_validator_spec.rb +21 -0
  124. data/spec/unit/plugins/mcollective/validator/typecheck_validator_spec.rb +23 -0
  125. data/spec/unit/registration/base_spec.rb +1 -1
  126. data/spec/unit/rpc/actionrunner_spec.rb +2 -2
  127. data/spec/unit/rpc/agent_spec.rb +41 -65
  128. data/spec/unit/rpc/client_spec.rb +430 -134
  129. data/spec/unit/rpc/reply_spec.rb +31 -1
  130. data/spec/unit/rpc/request_spec.rb +33 -12
  131. data/spec/unit/rpc/result_spec.rb +7 -0
  132. data/spec/unit/rpc/stats_spec.rb +14 -14
  133. data/spec/unit/rpc_spec.rb +16 -0
  134. data/spec/unit/security/base_spec.rb +8 -8
  135. data/spec/unit/ssl_spec.rb +20 -2
  136. data/spec/unit/string_spec.rb +15 -0
  137. data/spec/unit/util_spec.rb +141 -21
  138. data/spec/unit/validator_spec.rb +67 -0
  139. metadata +145 -7
  140. 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 :Util, "mcollective/util"
47
- autoload :Optionparser, "mcollective/optionparser"
47
+ autoload :Config, "mcollective/config"
48
48
  autoload :Connector, "mcollective/connector"
49
- autoload :Security, "mcollective/security"
49
+ autoload :Data, "mcollective/data"
50
+ autoload :DDL, "mcollective/ddl"
51
+ autoload :Discovery, "mcollective/discovery"
50
52
  autoload :Facts, "mcollective/facts"
51
- autoload :Registration, "mcollective/registration"
52
- autoload :PluginManager, "mcollective/pluginmanager"
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 :Application, "mcollective/application"
58
- autoload :Applications, "mcollective/applications"
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
 
@@ -0,0 +1,5 @@
1
+ module MCollective
2
+ module Agent
3
+
4
+ end
5
+ end
@@ -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
@@ -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
@@ -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] and ! [:bool, :array].include?(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] == :bool
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 "#{$0} failed to run: #{e} (#{e.class})"
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 receivedif
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 << RPC::Helpers.colorize(:red, " <----")
14
+ e.backtrace.first << Util.colorize(:red, " <----")
15
15
  STDERR.puts "Application '#{appname}' failed to load:"
16
16
  STDERR.puts
17
- STDERR.puts RPC::Helpers.colorize(:red, " #{e} (#{e.class})")
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
- applist = []
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