Module MCollective::PluginManager
In: lib/mcollective/pluginmanager.rb

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.

Methods

<<   []   clear   create_instance   delete   find   find_and_load   grep   include?   loadclass   pluginlist  

Public Class methods

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.

[Source]

    # File lib/mcollective/pluginmanager.rb, line 30
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

Gets a plugin by type

[Source]

    # File lib/mcollective/pluginmanager.rb, line 72
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

deletes all registered plugins

[Source]

    # File lib/mcollective/pluginmanager.rb, line 67
67:     def self.clear
68:       @plugins.clear
69:     end

use eval to create an instance of a class

[Source]

     # File lib/mcollective/pluginmanager.rb, line 94
 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

Removes a plugim the list

[Source]

    # File lib/mcollective/pluginmanager.rb, line 52
52:     def self.delete(plugin)
53:       @plugins.delete(plugin) if @plugins.include?(plugin)
54:     end

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

[Source]

     # File lib/mcollective/pluginmanager.rb, line 116
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.to_s])
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

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/

[Source]

     # File lib/mcollective/pluginmanager.rb, line 148
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

Grep‘s over the plugin list and returns the list found

[Source]

     # File lib/mcollective/pluginmanager.rb, line 176
176:     def self.grep(regex)
177:       @plugins.keys.grep(regex)
178:     end

Finds out if we have a plugin with the given name

[Source]

    # File lib/mcollective/pluginmanager.rb, line 57
57:     def self.include?(plugin)
58:       @plugins.include?(plugin)
59:     end

Loads a class from file by doing some simple search/replace on class names and then doing a require.

[Source]

     # File lib/mcollective/pluginmanager.rb, line 164
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

Provides a list of plugins we know about

[Source]

    # File lib/mcollective/pluginmanager.rb, line 62
62:     def self.pluginlist
63:       @plugins.keys.sort
64:     end

[Validate]