mcollective-client 1.3.3
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.
- data/bin/mc-call-agent +54 -0
- data/bin/mco +27 -0
- data/lib/mcollective.rb +70 -0
- data/lib/mcollective/agents.rb +160 -0
- data/lib/mcollective/application.rb +354 -0
- data/lib/mcollective/applications.rb +145 -0
- data/lib/mcollective/client.rb +292 -0
- data/lib/mcollective/config.rb +202 -0
- data/lib/mcollective/connector.rb +18 -0
- data/lib/mcollective/connector/base.rb +24 -0
- data/lib/mcollective/facts.rb +39 -0
- data/lib/mcollective/facts/base.rb +86 -0
- data/lib/mcollective/log.rb +103 -0
- data/lib/mcollective/logger.rb +5 -0
- data/lib/mcollective/logger/base.rb +73 -0
- data/lib/mcollective/logger/console_logger.rb +61 -0
- data/lib/mcollective/logger/file_logger.rb +46 -0
- data/lib/mcollective/logger/syslog_logger.rb +53 -0
- data/lib/mcollective/matcher.rb +16 -0
- data/lib/mcollective/matcher/parser.rb +93 -0
- data/lib/mcollective/matcher/scanner.rb +123 -0
- data/lib/mcollective/message.rb +201 -0
- data/lib/mcollective/monkey_patches.rb +104 -0
- data/lib/mcollective/optionparser.rb +164 -0
- data/lib/mcollective/pluginmanager.rb +180 -0
- data/lib/mcollective/pluginpackager.rb +26 -0
- data/lib/mcollective/pluginpackager/agent_definition.rb +79 -0
- data/lib/mcollective/pluginpackager/standard_definition.rb +59 -0
- data/lib/mcollective/registration.rb +16 -0
- data/lib/mcollective/registration/base.rb +75 -0
- data/lib/mcollective/rpc.rb +188 -0
- data/lib/mcollective/rpc/actionrunner.rb +142 -0
- data/lib/mcollective/rpc/agent.rb +441 -0
- data/lib/mcollective/rpc/audit.rb +38 -0
- data/lib/mcollective/rpc/client.rb +793 -0
- data/lib/mcollective/rpc/ddl.rb +258 -0
- data/lib/mcollective/rpc/helpers.rb +339 -0
- data/lib/mcollective/rpc/progress.rb +63 -0
- data/lib/mcollective/rpc/reply.rb +61 -0
- data/lib/mcollective/rpc/request.rb +51 -0
- data/lib/mcollective/rpc/result.rb +41 -0
- data/lib/mcollective/rpc/stats.rb +185 -0
- data/lib/mcollective/runnerstats.rb +90 -0
- data/lib/mcollective/security.rb +26 -0
- data/lib/mcollective/security/base.rb +237 -0
- data/lib/mcollective/shell.rb +87 -0
- data/lib/mcollective/ssl.rb +246 -0
- data/lib/mcollective/unix_daemon.rb +37 -0
- data/lib/mcollective/util.rb +274 -0
- data/lib/mcollective/vendor.rb +41 -0
- data/lib/mcollective/vendor/require_vendored.rb +2 -0
- data/lib/mcollective/windows_daemon.rb +25 -0
- data/spec/Rakefile +16 -0
- data/spec/fixtures/application/test.rb +7 -0
- data/spec/fixtures/test-cert.pem +15 -0
- data/spec/fixtures/test-private.pem +15 -0
- data/spec/fixtures/test-public.pem +6 -0
- data/spec/monkey_patches/instance_variable_defined.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/unit/agents_spec.rb +280 -0
- data/spec/unit/application_spec.rb +636 -0
- data/spec/unit/applications_spec.rb +155 -0
- data/spec/unit/array.rb +30 -0
- data/spec/unit/config_spec.rb +148 -0
- data/spec/unit/facts/base_spec.rb +118 -0
- data/spec/unit/facts_spec.rb +39 -0
- data/spec/unit/log_spec.rb +71 -0
- data/spec/unit/logger/base_spec.rb +110 -0
- data/spec/unit/logger/syslog_logger_spec.rb +86 -0
- data/spec/unit/matcher/parser_spec.rb +106 -0
- data/spec/unit/matcher/scanner_spec.rb +71 -0
- data/spec/unit/message_spec.rb +401 -0
- data/spec/unit/optionparser_spec.rb +113 -0
- data/spec/unit/pluginmanager_spec.rb +173 -0
- data/spec/unit/pluginpackager/agent_definition_spec.rb +130 -0
- data/spec/unit/pluginpackager/standard_definition_spec.rb +75 -0
- data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +533 -0
- data/spec/unit/plugins/mcollective/connector/stomp/eventlogger_spec.rb +34 -0
- data/spec/unit/plugins/mcollective/connector/stomp_spec.rb +417 -0
- data/spec/unit/plugins/mcollective/packagers/ospackage_spec.rb +229 -0
- data/spec/unit/plugins/mcollective/security/psk_spec.rb +156 -0
- data/spec/unit/registration/base_spec.rb +77 -0
- data/spec/unit/rpc/actionrunner_spec.rb +213 -0
- data/spec/unit/rpc/agent_spec.rb +155 -0
- data/spec/unit/rpc/client_spec.rb +523 -0
- data/spec/unit/rpc/ddl_spec.rb +388 -0
- data/spec/unit/rpc/helpers_spec.rb +55 -0
- data/spec/unit/rpc/reply_spec.rb +143 -0
- data/spec/unit/rpc/request_spec.rb +115 -0
- data/spec/unit/rpc/result_spec.rb +66 -0
- data/spec/unit/rpc/stats_spec.rb +288 -0
- data/spec/unit/runnerstats_spec.rb +40 -0
- data/spec/unit/security/base_spec.rb +279 -0
- data/spec/unit/shell_spec.rb +144 -0
- data/spec/unit/ssl_spec.rb +244 -0
- data/spec/unit/symbol.rb +11 -0
- data/spec/unit/unix_daemon.rb +41 -0
- data/spec/unit/util_spec.rb +342 -0
- data/spec/unit/vendor_spec.rb +34 -0
- data/spec/unit/windows_daemon.rb +43 -0
- data/spec/windows_spec.opts +1 -0
- metadata +242 -0
@@ -0,0 +1,104 @@
|
|
1
|
+
# Make arrays of Symbols sortable
|
2
|
+
class Symbol
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
def <=>(other)
|
6
|
+
self.to_s <=> other.to_s
|
7
|
+
end unless method_defined?("<=>")
|
8
|
+
end
|
9
|
+
|
10
|
+
# This provides an alias for RbConfig to Config for versions of Ruby older then
|
11
|
+
# # version 1.8.5. This allows us to use RbConfig in place of the older Config in
|
12
|
+
# # our code and still be compatible with at least Ruby 1.8.1.
|
13
|
+
# require 'rbconfig'
|
14
|
+
unless defined? ::RbConfig
|
15
|
+
::RbConfig = ::Config
|
16
|
+
end
|
17
|
+
|
18
|
+
# a method # that walks an array in groups, pass a block to
|
19
|
+
# call the block on each sub array
|
20
|
+
class Array
|
21
|
+
def in_groups_of(chunk_size, padded_with=nil, &block)
|
22
|
+
arr = self.clone
|
23
|
+
|
24
|
+
# how many to add
|
25
|
+
padding = chunk_size - (arr.size % chunk_size)
|
26
|
+
|
27
|
+
# pad at the end
|
28
|
+
arr.concat([padded_with] * padding) unless padding == chunk_size
|
29
|
+
|
30
|
+
# how many chunks we'll make
|
31
|
+
count = arr.size / chunk_size
|
32
|
+
|
33
|
+
# make that many arrays
|
34
|
+
result = []
|
35
|
+
count.times {|s| result << arr[s * chunk_size, chunk_size]}
|
36
|
+
|
37
|
+
if block_given?
|
38
|
+
result.each_with_index do |a, i|
|
39
|
+
case block.arity
|
40
|
+
when 1
|
41
|
+
yield(a)
|
42
|
+
when 2
|
43
|
+
yield(a, (i == result.size - 1))
|
44
|
+
else
|
45
|
+
raise "Expected 1 or 2 arguments, got #{block.arity}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
else
|
49
|
+
result
|
50
|
+
end
|
51
|
+
end unless method_defined?(:in_groups_of)
|
52
|
+
end
|
53
|
+
|
54
|
+
class Dir
|
55
|
+
def self.mktmpdir(prefix_suffix=nil, tmpdir=nil)
|
56
|
+
case prefix_suffix
|
57
|
+
when nil
|
58
|
+
prefix = "d"
|
59
|
+
suffix = ""
|
60
|
+
when String
|
61
|
+
prefix = prefix_suffix
|
62
|
+
suffix = ""
|
63
|
+
when Array
|
64
|
+
prefix = prefix_suffix[0]
|
65
|
+
suffix = prefix_suffix[1]
|
66
|
+
else
|
67
|
+
raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
|
68
|
+
end
|
69
|
+
tmpdir ||= Dir.tmpdir
|
70
|
+
t = Time.now.strftime("%Y%m%d")
|
71
|
+
n = nil
|
72
|
+
begin
|
73
|
+
path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
|
74
|
+
path << "-#{n}" if n
|
75
|
+
path << suffix
|
76
|
+
Dir.mkdir(path, 0700)
|
77
|
+
rescue Errno::EEXIST
|
78
|
+
n ||= 0
|
79
|
+
n += 1
|
80
|
+
retry
|
81
|
+
end
|
82
|
+
|
83
|
+
if block_given?
|
84
|
+
begin
|
85
|
+
yield path
|
86
|
+
ensure
|
87
|
+
FileUtils.remove_entry_secure path
|
88
|
+
end
|
89
|
+
else
|
90
|
+
path
|
91
|
+
end
|
92
|
+
end unless method_defined?(:mktmpdir)
|
93
|
+
|
94
|
+
def self.tmpdir
|
95
|
+
tmp = '.'
|
96
|
+
for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], '/tmp']
|
97
|
+
if dir and stat = File.stat(dir) and stat.directory? and stat.writable?
|
98
|
+
tmp = dir
|
99
|
+
break
|
100
|
+
end rescue nil
|
101
|
+
end
|
102
|
+
File.expand_path(tmp)
|
103
|
+
end unless method_defined?(:tmpdir)
|
104
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module MCollective
|
2
|
+
# A simple helper to build cli tools that supports a uniform command line
|
3
|
+
# layout.
|
4
|
+
class Optionparser
|
5
|
+
attr_reader :parser
|
6
|
+
|
7
|
+
# Creates a new instance of the parser, you can supply defaults and include named groups of options.
|
8
|
+
#
|
9
|
+
# Starts a parser that defaults to verbose and that includs the filter options:
|
10
|
+
#
|
11
|
+
# oparser = MCollective::Optionparser.new({:verbose => true}, "filter")
|
12
|
+
#
|
13
|
+
# Stats a parser in non verbose mode that does support discovery
|
14
|
+
#
|
15
|
+
# oparser = MCollective::Optionparser.new()
|
16
|
+
#
|
17
|
+
# Starts a parser in verbose mode that does not show the common options:
|
18
|
+
#
|
19
|
+
# oparser = MCollective::Optionparser.new({:verbose => true}, "filter", "common")
|
20
|
+
def initialize(defaults = {}, include_sections = nil, exclude_sections = nil)
|
21
|
+
@parser = ::OptionParser.new
|
22
|
+
|
23
|
+
@include = [include_sections].flatten
|
24
|
+
@exclude = [exclude_sections].flatten
|
25
|
+
|
26
|
+
@options = Util.default_options
|
27
|
+
|
28
|
+
@options.merge!(defaults)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Parse the options returning the options, you can pass a block that adds additional options
|
32
|
+
# to the Optionparser.
|
33
|
+
#
|
34
|
+
# The sample below starts a parser that also prompts for --arguments in addition to the defaults.
|
35
|
+
# It also sets the description and shows a usage message specific to this app.
|
36
|
+
#
|
37
|
+
# options = oparser.parse{|parser, options|
|
38
|
+
# parser.define_head "Control the mcollective controller daemon"
|
39
|
+
# parser.banner = "Usage: sh-mcollective [options] command"
|
40
|
+
#
|
41
|
+
# parser.on('--arg', '--argument ARGUMENT', 'Argument to pass to agent') do |v|
|
42
|
+
# options[:argument] = v
|
43
|
+
# end
|
44
|
+
# }
|
45
|
+
#
|
46
|
+
# Users can set default options that get parsed in using the MCOLLECTIVE_EXTRA_OPTS environemnt
|
47
|
+
# variable
|
48
|
+
def parse(&block)
|
49
|
+
yield(@parser, @options) if block_given?
|
50
|
+
|
51
|
+
add_required_options
|
52
|
+
|
53
|
+
add_common_options unless @exclude.include?("common")
|
54
|
+
|
55
|
+
@include.each do |i|
|
56
|
+
next if @exclude.include?(i)
|
57
|
+
|
58
|
+
options_name = "add_#{i}_options"
|
59
|
+
send(options_name) if respond_to?(options_name)
|
60
|
+
end
|
61
|
+
|
62
|
+
@parser.environment("MCOLLECTIVE_EXTRA_OPTS")
|
63
|
+
|
64
|
+
@parser.parse!
|
65
|
+
|
66
|
+
@options[:collective] = Config.instance.main_collective unless @options[:collective]
|
67
|
+
|
68
|
+
@options
|
69
|
+
end
|
70
|
+
|
71
|
+
# These options will be added if you pass 'filter' into the include list of the
|
72
|
+
# constructor.
|
73
|
+
def add_filter_options
|
74
|
+
@parser.separator ""
|
75
|
+
@parser.separator "Host Filters"
|
76
|
+
|
77
|
+
@parser.on('-W', '--with FILTER', 'Combined classes and facts filter') do |f|
|
78
|
+
f.split(" ").each do |filter|
|
79
|
+
begin
|
80
|
+
fact_parsed = parse_fact(filter)
|
81
|
+
@options[:filter]["fact"] << fact_parsed
|
82
|
+
rescue
|
83
|
+
@options[:filter]["cf_class"] << filter
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
@parser.on('-S', '--select FILTER', 'Compound filter combining facts and classes') do |f|
|
89
|
+
@options[:filter]["compound"] << MCollective::Matcher::Parser.new(f).execution_stack
|
90
|
+
end
|
91
|
+
|
92
|
+
@parser.on('-F', '--wf', '--with-fact fact=val', 'Match hosts with a certain fact') do |f|
|
93
|
+
fact_parsed = parse_fact(f)
|
94
|
+
|
95
|
+
@options[:filter]["fact"] << fact_parsed if fact_parsed
|
96
|
+
end
|
97
|
+
|
98
|
+
@parser.on('-C', '--wc', '--with-class CLASS', 'Match hosts with a certain config management class') do |f|
|
99
|
+
@options[:filter]["cf_class"] << f
|
100
|
+
end
|
101
|
+
|
102
|
+
@parser.on('-A', '--wa', '--with-agent AGENT', 'Match hosts with a certain agent') do |a|
|
103
|
+
@options[:filter]["agent"] << a
|
104
|
+
end
|
105
|
+
|
106
|
+
@parser.on('-I', '--wi', '--with-identity IDENT', 'Match hosts with a certain configured identity') do |a|
|
107
|
+
@options[:filter]["identity"] << a
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# These options should always be present
|
112
|
+
def add_required_options
|
113
|
+
@parser.on('-c', '--config FILE', 'Load configuratuion from file rather than default') do |f|
|
114
|
+
@options[:config] = f
|
115
|
+
end
|
116
|
+
|
117
|
+
@parser.on('-v', '--verbose', 'Be verbose') do |v|
|
118
|
+
@options[:verbose] = v
|
119
|
+
end
|
120
|
+
|
121
|
+
@parser.on('-h', '--help', 'Display this screen') do
|
122
|
+
puts @parser
|
123
|
+
exit! 1
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# These options will be added to most cli tools
|
128
|
+
def add_common_options
|
129
|
+
@parser.separator ""
|
130
|
+
@parser.separator "Common Options"
|
131
|
+
|
132
|
+
@parser.on('-T', '--target COLLECTIVE', 'Target messages to a specific sub collective') do |f|
|
133
|
+
@options[:collective] = f
|
134
|
+
end
|
135
|
+
|
136
|
+
@parser.on('--dt', '--discovery-timeout SECONDS', Integer, 'Timeout for doing discovery') do |t|
|
137
|
+
@options[:disctimeout] = t
|
138
|
+
end
|
139
|
+
|
140
|
+
@parser.on('-t', '--timeout SECONDS', Integer, 'Timeout for calling remote agents') do |t|
|
141
|
+
@options[:timeout] = t
|
142
|
+
end
|
143
|
+
|
144
|
+
@parser.on('-q', '--quiet', 'Do not be verbose') do |v|
|
145
|
+
@options[:verbose] = false
|
146
|
+
end
|
147
|
+
|
148
|
+
@parser.on('--ttl TTL', 'Set the message validity period') do |v|
|
149
|
+
@options[:ttl] = v.to_i
|
150
|
+
end
|
151
|
+
|
152
|
+
@parser.on('--reply-to TARGET', 'Set a custom target for replies') do |v|
|
153
|
+
@options[:reply_to] = v
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
# Parse a fact filter string like foo=bar into the tuple hash thats needed
|
159
|
+
def parse_fact(fact)
|
160
|
+
Util.parse_fact_string(fact)
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module MCollective
|
2
|
+
# A simple plugin manager, it stores one plugin each of a specific type
|
3
|
+
# the idea is that we can only have one security provider, one connector etc.
|
4
|
+
module PluginManager
|
5
|
+
@plugins = {}
|
6
|
+
|
7
|
+
# Adds a plugin to the list of plugins, we expect a hash like:
|
8
|
+
#
|
9
|
+
# {:type => "base",
|
10
|
+
# :class => foo.new}
|
11
|
+
#
|
12
|
+
# or like:
|
13
|
+
# {:type => "base",
|
14
|
+
# :class => "Foo::Bar"}
|
15
|
+
#
|
16
|
+
# In the event that we already have a class with the given type
|
17
|
+
# an exception will be raised.
|
18
|
+
#
|
19
|
+
# If the :class passed is a String then we will delay instantiation
|
20
|
+
# till the first time someone asks for the plugin, this is because most likely
|
21
|
+
# the registration gets done by inherited() hooks, at which point the plugin class is not final.
|
22
|
+
#
|
23
|
+
# If we were to do a .new here the Class initialize method would get called and not
|
24
|
+
# the plugins, we there for only initialize the classes when they get requested via []
|
25
|
+
#
|
26
|
+
# By default all plugin instances are cached and returned later so there's
|
27
|
+
# always a single instance. You can pass :single_instance => false when
|
28
|
+
# calling this to instruct it to always return a new instance when a copy
|
29
|
+
# is requested. This only works with sending a String for :class.
|
30
|
+
def self.<<(plugin)
|
31
|
+
plugin[:single_instance] = true unless plugin.include?(:single_instance)
|
32
|
+
|
33
|
+
type = plugin[:type]
|
34
|
+
klass = plugin[:class]
|
35
|
+
single = plugin[:single_instance]
|
36
|
+
|
37
|
+
raise("Plugin #{type} already loaded") if @plugins.include?(type)
|
38
|
+
|
39
|
+
|
40
|
+
# If we get a string then store 'nil' as the instance, signalling that we'll
|
41
|
+
# create the class later on demand.
|
42
|
+
if klass.is_a?(String)
|
43
|
+
@plugins[type] = {:loadtime => Time.now, :class => klass, :instance => nil, :single => single}
|
44
|
+
Log.debug("Registering plugin #{type} with class #{klass} single_instance: #{single}")
|
45
|
+
else
|
46
|
+
@plugins[type] = {:loadtime => Time.now, :class => klass.class, :instance => klass, :single => true}
|
47
|
+
Log.debug("Registering plugin #{type} with class #{klass.class} single_instance: true")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Removes a plugim the list
|
52
|
+
def self.delete(plugin)
|
53
|
+
@plugins.delete(plugin) if @plugins.include?(plugin)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Finds out if we have a plugin with the given name
|
57
|
+
def self.include?(plugin)
|
58
|
+
@plugins.include?(plugin)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Provides a list of plugins we know about
|
62
|
+
def self.pluginlist
|
63
|
+
@plugins.keys
|
64
|
+
end
|
65
|
+
|
66
|
+
# deletes all registered plugins
|
67
|
+
def self.clear
|
68
|
+
@plugins.clear
|
69
|
+
end
|
70
|
+
|
71
|
+
# Gets a plugin by type
|
72
|
+
def self.[](plugin)
|
73
|
+
raise("No plugin #{plugin} defined") unless @plugins.include?(plugin)
|
74
|
+
|
75
|
+
klass = @plugins[plugin][:class]
|
76
|
+
|
77
|
+
if @plugins[plugin][:single]
|
78
|
+
# Create an instance of the class if one hasn't been done before
|
79
|
+
if @plugins[plugin][:instance] == nil
|
80
|
+
Log.debug("Returning new plugin #{plugin} with class #{klass}")
|
81
|
+
@plugins[plugin][:instance] = create_instance(klass)
|
82
|
+
else
|
83
|
+
Log.debug("Returning cached plugin #{plugin} with class #{klass}")
|
84
|
+
end
|
85
|
+
|
86
|
+
@plugins[plugin][:instance]
|
87
|
+
else
|
88
|
+
Log.debug("Returning new plugin #{plugin} with class #{klass}")
|
89
|
+
create_instance(klass)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# use eval to create an instance of a class
|
94
|
+
def self.create_instance(klass)
|
95
|
+
begin
|
96
|
+
eval("#{klass}.new")
|
97
|
+
rescue Exception => e
|
98
|
+
raise("Could not create instance of plugin #{klass}: #{e}")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Finds plugins in all configured libdirs
|
103
|
+
#
|
104
|
+
# find("agent")
|
105
|
+
#
|
106
|
+
# will return an array of just agent names, for example:
|
107
|
+
#
|
108
|
+
# ["puppetd", "package"]
|
109
|
+
#
|
110
|
+
# Can also be used to find files of other extensions:
|
111
|
+
#
|
112
|
+
# find("agent", "ddl")
|
113
|
+
#
|
114
|
+
# Will return the same list but only of files with extension .ddl
|
115
|
+
# in the agent subdirectory
|
116
|
+
def self.find(type, extension="rb")
|
117
|
+
extension = ".#{extension}" unless extension.match(/^\./)
|
118
|
+
|
119
|
+
plugins = []
|
120
|
+
|
121
|
+
Config.instance.libdir.each do |libdir|
|
122
|
+
plugdir = File.join([libdir, "mcollective", type])
|
123
|
+
next unless File.directory?(plugdir)
|
124
|
+
|
125
|
+
Dir.new(plugdir).grep(/#{extension}$/).map do |plugin|
|
126
|
+
plugins << File.basename(plugin, extension)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
plugins.sort.uniq
|
131
|
+
end
|
132
|
+
|
133
|
+
# Finds and loads from disk all plugins from all libdirs that match
|
134
|
+
# certain criteria.
|
135
|
+
#
|
136
|
+
# find_and_load("pluginpackager")
|
137
|
+
#
|
138
|
+
# Will find all .rb files in the libdir/mcollective/pluginpackager/
|
139
|
+
# directory in all libdirs and load them from disk.
|
140
|
+
#
|
141
|
+
# You can influence what plugins get loaded using a block notation:
|
142
|
+
#
|
143
|
+
# find_and_load("pluginpackager") do |plugin|
|
144
|
+
# plugin.match(/puppet/)
|
145
|
+
# end
|
146
|
+
#
|
147
|
+
# This will load only plugins matching /puppet/
|
148
|
+
def self.find_and_load(type, extension="rb")
|
149
|
+
extension = ".#{extension}" unless extension.match(/^\./)
|
150
|
+
|
151
|
+
klasses = find(type, extension).map do |plugin|
|
152
|
+
if block_given?
|
153
|
+
next unless yield(plugin)
|
154
|
+
end
|
155
|
+
|
156
|
+
"%s::%s::%s" % [ "MCollective", type.capitalize, plugin.capitalize ]
|
157
|
+
end.compact
|
158
|
+
|
159
|
+
klasses.sort.uniq.each {|klass| loadclass(klass, true)}
|
160
|
+
end
|
161
|
+
|
162
|
+
# Loads a class from file by doing some simple search/replace
|
163
|
+
# on class names and then doing a require.
|
164
|
+
def self.loadclass(klass, squash_failures=false)
|
165
|
+
fname = klass.gsub("::", "/").downcase + ".rb"
|
166
|
+
|
167
|
+
Log.debug("Loading #{klass} from #{fname}")
|
168
|
+
|
169
|
+
load fname
|
170
|
+
rescue Exception => e
|
171
|
+
Log.error("Failed to load #{klass}: #{e}")
|
172
|
+
raise unless squash_failures
|
173
|
+
end
|
174
|
+
|
175
|
+
# Grep's over the plugin list and returns the list found
|
176
|
+
def self.grep(regex)
|
177
|
+
@plugins.keys.grep regex
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|