UNIX Password, Roles & Node Management: Plugins
The two core applications in Password Management - password_generator.pl and password_xfer.pl - are based almost entirely on plugins. These plugins are little snippets of perl code that can be modified or augmented as needed. All plugins are registered with Covad::Pwman::register_plugins().
There are three classes of plugins: obtain, gen, and push. Each class of plugin has two phases: pre, and post. The gen class has a third phase: format. These classes and phases are detailed below:
alice
) needs to be converted to
a user entry (eg, alice:x:2000:2000:Alice User:/home/alice:/bin/sh
). It's the first class
of plugins executed by password_generator.pl.
You can have as many obtain_pre_* plugins that you need. You must have one obtain_post_* plugin, and only one.
passwd(4)
and shadow(4)
file formats. gen_post_* plugins can be
used to check and verify work files after they've been formatted.
If you were to look at the order of all classes and phases of plugins by application, it would look something like this:
Once the users are obtained, run the next type of plugins:
Each plugin is loaded at startup via a require
within an eval
. If the plugin
doesn't compile it is discarded.
When it comes time for a plugin to execute, all valid plugins for this type and phase
are essentially foreach
'd around with the same argument set. There is no particular
order to plugin execution; you can only be sure that you'll get all the phases for a
particular type at the same time (in other words, you can ensure that during a particular
phase - let's say the pre phase for type gen - you'll only be working on plugins
who are slated for gen_pre). If a plugin unexpectedly quits or times out, the
node will be considered in an undeterminiable state and will not continue being
processed.
It's fairly straightfoward to write new plugins; they're just little blocks of perl that get turned into coderefs, and executed one at a time. They have some rules, which are in this section.
Plugins need to be called what they are. The name of a plugin needs to meet the following syntax:
{type}_{phase}_{name}
...where:
gen
, push
, or obtain
pre
or post
. Note that if type is gen
, then phase can
also be format
.
a-z A-Z 0-9 . - _
Each plugin must assign a reference to a subroutine to a scalar called $plugin
.
The following should suffice:
$plugin = sub { ## do stuff here. }; 1;
You can specify any other file-scoped variables or subroutines that you like.
To avoid namespace collision, ensure that any additional subroutines
or variables are prefixed with _plugin_name
.
You can also, optionally, specify a single scalar called $info
, which
more clearly identifies what this plugin is supposed to accomplish.
Something like:
$info = "Sprekulates the antipasto."; $plugin = sub { unless ( sprekulate(@_) ) { return undef; } else { return 1; } };
...or similar.
Every plugin is passed a hashref of arguments. Accessing them is as simple as:
my(%arg) = @_;
For the most part, every plugin receives the following arguments:
hostname
props
users_file
hostname
.
tags
users
password_file
passwd
working file as a scalar. This file will
more than likely reside at pwman.work_dir/hostname
.passwd
.
Note that for gen_format plugins, this argument is a filehandle opened in write mode for the work file.
shadow_file
shadow
working file as a scalar. This file will
more than likely reside at pwman.work_dir/hostname
.shadow
.
Note that for gen_format plugins, this argument is a filehandle opened in write mode for the work file.
sudoers_file
sudoers
working file as a scalar. This file will
more than likely reside at pwman.work_dir/hostname
.sudoers
.
Note that for gen_format plugins, this argument is a filehandle opened in write mode for the work file.
digest_file
digest
working file as a scalar. This file will
more than likely reside at pwman.work_dir/hostname
.digest
.
Note that for gen_format plugins, this argument is a filehandle opened in write mode for the work file.
The exceptions to this list of arguments are in the obtain_pre and obtain_post
plugins. These two groups only receive the following arguments:
hostname
, users
, users_file
, tags
, and props
.
The format and content of these arguments is unchanged.
All options listed in etc/pwman.properties are made available to all plugins.
The property pwman.plugin_dir specifies where all plugins are located.
If a plugin needs to signal that it was not successful but that the node
is still intact (for example, to indicate that it did no work), it should
return undef
. A non-zero return status (eg, return 1;
) indicates success,
and that something was done. Plugins that reach a bad state may exit abnormally
with die
. If a plugin abnormally exits, the node is considered in an
undeterminable state and will be skipped.
Plugins are wrapped within an eval
, so an exit
or die
by a plugin gets
caught as you'd expect. If die
is used, then the contents of $@
are
dropped into the log and presented to the user. As a courtesy, please remember
to die
with a message containing the name of the plugin and a newline, something like:
die "gen_pre_sprocket: can't auto-frob the thrombosifier - please frob it manually.\n";
The distinct lack of returnable values means you have to edit the argments as they are passed in order to actually accomplish something. Ensure that plugins limit their modifications to only bits needed to accomplish it's goal.
If you need to disable a plugin (because it doesn't work in your environment, or
you don't need that particular feature check), you can just move it out of the way.
Or you can just delete it. (I prefer the method of renaming it to
DISABLED.plugin_filename
, but that's just me.)
the Covad::Pwman manpage, the Covad::Pwman::Parsers manpage, the Covad::Pwman::Roles manpage, the Covad::Pwman::Properties manpage
Jon Gilbert <jong@jong.org>
$Id: pwman_docs_plugins.pod,v 1.2 2005/10/20 08:46:34 jgilbertsjc Exp $