Module: MCollective::PluginManager
- Defined in:
- lib/mcollective/pluginmanager.rb
Overview
A simple plugin manager, it stores one plugin each of a specific type the idea is that we can only have one security provider, one connector etc.
Class Method Summary collapse
-
.<<(plugin) ⇒ Object
Adds a plugin to the list of plugins, we expect a hash like:.
-
.[](plugin) ⇒ Object
Gets a plugin by type.
-
.clear ⇒ Object
deletes all registered plugins.
-
.create_instance(klass) ⇒ Object
use eval to create an instance of a class.
-
.delete(plugin) ⇒ Object
Removes a plugim the list.
-
.find(type, extension = "rb") ⇒ Object
Finds plugins in all configured libdirs.
-
.find_and_load(type, extension = "rb") ⇒ Object
Finds and loads from disk all plugins from all libdirs that match certain criteria.
-
.grep(regex) ⇒ Object
Grep’s over the plugin list and returns the list found.
-
.include?(plugin) ⇒ Boolean
Finds out if we have a plugin with the given name.
-
.loadclass(klass, squash_failures = false) ⇒ Object
Loads a class from file by doing some simple search/replace on class names and then doing a require.
-
.pluginlist ⇒ Object
Provides a list of plugins we know about.
Class Method Details
.<<(plugin) ⇒ Object
Adds a plugin to the list of plugins, we expect a hash like:
{:type => "base",
:class => foo.new}
or like:
{:type => "base",
:class => "Foo::Bar"}
In the event that we already have a class with the given type an exception will be raised.
If the :class passed is a String then we will delay instantiation till the first time someone asks for the plugin, this is because most likely the registration gets done by inherited() hooks, at which point the plugin class is not final.
If we were to do a .new here the Class initialize method would get called and not the plugins, we there for only initialize the classes when they get requested via []
By default all plugin instances are cached and returned later so there’s always a single instance. You can pass :single_instance => false when calling this to instruct it to always return a new instance when a copy is requested. This only works with sending a String for :class.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/mcollective/pluginmanager.rb', line 30 def self.<<(plugin) plugin[:single_instance] = true unless plugin.include?(:single_instance) type = plugin[:type] klass = plugin[:class] single = plugin[:single_instance] raise("Plugin #{type} already loaded") if @plugins.include?(type) # If we get a string then store 'nil' as the instance, signalling that we'll # create the class later on demand. if klass.is_a?(String) @plugins[type] = {:loadtime => Time.now, :class => klass, :instance => nil, :single => single} Log.debug("Registering plugin #{type} with class #{klass} single_instance: #{single}") else @plugins[type] = {:loadtime => Time.now, :class => klass.class, :instance => klass, :single => true} Log.debug("Registering plugin #{type} with class #{klass.class} single_instance: true") end end |
.[](plugin) ⇒ Object
Gets a plugin by type
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/mcollective/pluginmanager.rb', line 71 def self.[](plugin) raise("No plugin #{plugin} defined") unless @plugins.include?(plugin) klass = @plugins[plugin][:class] if @plugins[plugin][:single] # Create an instance of the class if one hasn't been done before if @plugins[plugin][:instance].nil? Log.debug("Returning new plugin #{plugin} with class #{klass}") @plugins[plugin][:instance] = create_instance(klass) else Log.debug("Returning cached plugin #{plugin} with class #{klass}") end @plugins[plugin][:instance] else Log.debug("Returning new plugin #{plugin} with class #{klass}") create_instance(klass) end end |
.clear ⇒ Object
deletes all registered plugins
66 67 68 |
# File 'lib/mcollective/pluginmanager.rb', line 66 def self.clear @plugins.clear end |
.create_instance(klass) ⇒ Object
use eval to create an instance of a class
93 94 95 96 97 |
# File 'lib/mcollective/pluginmanager.rb', line 93 def self.create_instance(klass) eval("#{klass}.new") # rubocop:disable Security/Eval, Style/EvalWithLocation rescue Exception => e # rubocop:disable Lint/RescueException raise("Could not create instance of plugin #{klass}: #{e}") end |
.delete(plugin) ⇒ Object
Removes a plugim the list
51 52 53 |
# File 'lib/mcollective/pluginmanager.rb', line 51 def self.delete(plugin) @plugins.delete(plugin) if @plugins.include?(plugin) end |
.find(type, extension = "rb") ⇒ Object
Finds plugins in all configured libdirs
find("agent")
will return an array of just agent names, for example:
["puppetd", "package"]
Can also be used to find files of other extensions:
find("agent", "ddl")
Will return the same list but only of files with extension .ddl in the agent subdirectory
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/mcollective/pluginmanager.rb', line 113 def self.find(type, extension="rb") extension = ".#{extension}" unless extension =~ /^\./ plugins = [] Config.instance.libdir.each do |libdir| plugdir = File.join([libdir, "mcollective", type.to_s]) next unless File.directory?(plugdir) Dir.new(plugdir).grep(/#{extension}$/).map do |plugin| plugins << File.basename(plugin, extension) end end plugins.sort.uniq end |
.find_and_load(type, extension = "rb") ⇒ Object
Finds and loads from disk all plugins from all libdirs that match certain criteria.
find_and_load("pluginpackager")
Will find all .rb files in the libdir/mcollective/pluginpackager/ directory in all libdirs and load them from disk.
You can influence what plugins get loaded using a block notation:
find_and_load("pluginpackager") do |plugin|
plugin.match(/puppet/)
end
This will load only plugins matching /puppet/
145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/mcollective/pluginmanager.rb', line 145 def self.find_and_load(type, extension="rb") extension = ".#{extension}" unless extension =~ /^\./ klasses = find(type, extension).map do |plugin| next if block_given? && !yield(plugin) "%s::%s::%s" % ["MCollective", type.capitalize, plugin.capitalize] end.compact klasses.sort.uniq.each {|klass| loadclass(klass, true)} end |
.grep(regex) ⇒ Object
Grep’s over the plugin list and returns the list found
171 172 173 |
# File 'lib/mcollective/pluginmanager.rb', line 171 def self.grep(regex) @plugins.keys.grep(regex) end |
.include?(plugin) ⇒ Boolean
Finds out if we have a plugin with the given name
56 57 58 |
# File 'lib/mcollective/pluginmanager.rb', line 56 def self.include?(plugin) @plugins.include?(plugin) end |
.loadclass(klass, squash_failures = false) ⇒ Object
Loads a class from file by doing some simple search/replace on class names and then doing a require.
159 160 161 162 163 164 165 166 167 168 |
# File 'lib/mcollective/pluginmanager.rb', line 159 def self.loadclass(klass, squash_failures=false) fname = "#{klass.gsub('::', '/').downcase}.rb" Log.debug("Loading #{klass} from #{fname}") load fname rescue Exception => e # rubocop:disable Lint/RescueException Log.error("Failed to load #{klass}: #{e}") raise unless squash_failures end |
.pluginlist ⇒ Object
Provides a list of plugins we know about
61 62 63 |
# File 'lib/mcollective/pluginmanager.rb', line 61 def self.pluginlist @plugins.keys.sort end |