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