NAME
OpenInteract2::Manage - Provide common functions and factory for management tasks
SYNOPSIS
# Common programmatic use of management task:
use strict;
use OpenInteract2::Manage;
my $task = OpenInteract2::Manage->new(
'install_package',
{ filename => '/home/httpd/site/uploads/file.tar.gz',
website_dir => '/home/httpd/site' } );
my @status = eval { $task->execute };
if ( $@ ) {
if ( $@->isa( 'OpenInteract2::Exception::Parameter' ) ) {
my $failures = $@->parameter_fail;
while ( my ( $field, $reasons ) = each %{ $failures } ) {
print "Field $field: ", join( ", ", @{ $reasons } ), "\n";
}
}
exit;
}
foreach my $s ( @status ) {
print "Status: ", ( $s->{is_ok} eq 'yes' ) ? 'OK' : 'NOT OK';
print "\n$s->{message}\n";
}
# Every task needs to implement the following:
sub run_task {}
sub get_parameters {} # if it has parameters
# The task can implement this to initialize the object
sub init {}
# The task can also implement these for setting up/clearing out the
# environment
sub setup_task {}
sub tear_down_task {}
# The task can also implement this for checking/validating parameters
sub validate_param {}
# This task is strongly advised to implement this to let the outside
# world know about its purpose
sub get_brief_description {}
DESCRIPTION
First, most people don't really care about this class. You'll use the oi2_manage
front-end to this set of tasks, so you probably want to look there if you're itching to do something quickly.
OpenInteract2::Manage is the organizer, interface and factory for tasks managing OpenInteract2. Its goal is to make these tasks runnable from anywhere, not just the command-line, and to provide output that can be parsed in a sufficiently generic format to be useful anywhere.
Since it is an organizing module it does not actually perform the tasks. You will want to see OpenInteract2::Manage::Package or OpenInteract2::Manage::Website to get closer to that metal. You can also subclass this class directly, but look first into the other subclasses as they may provide functionality to make your task easier to implement.
If you're interested in subclassing you should really read OpenInteract2::Manual::Management. It was written just for you!
METHODS
Class Methods
new( $task_name, [ \%params, ], [ @extra_params ] )
Creates a new management task of type $task_name
. If type $task_name
is not yet registered, the method throws an exception.
You can also pass any number of \%params
with which the management task gets initialized (using init()
, below). These are blindly set and not checked until you run execute()
.
All of the extra_params
are passed to init()
, which subclasses may implement to do any additional initialization.
Returns: New management task object
is_valid_task( $task_name )
Returns: true if $task_name
is a valid task, false if not.
valid_tasks()
Query the class about what tasks are currently registered.
Returns: list of registered tasks
valid_tasks_description()
Query the class about what tasks are currently registered, plus get a brief description of each.
Returns: hashref of registered tasks (keys) and their descriptions (values).
task_parameters( [ $task_name ] )
Ask the task for $task_name
what its parameters are. Note that you can use this as an object method as well, skipping the $task_name
parameter.
Returns: hashref with keys as parameter names and values as hashrefs with the following data:
- name
-
Parameter name
- description
-
Description of this parameter for this task
- is_required
-
Set to 'yes' if the parameter is required for operation
- is_boolean
-
Set to 'yes' if it's a toggled parameter
- is_multivalued
-
Set to 'yes' if the parameter can handle multiple values
- default
-
Set to the default value for this parameter
all_parameters()
Find all parameters used by all registered tasks and get the same data
used in task_parameters
for each. The only change is that the 'description' key is not available since there's no task context. (That is, 'website_dir' may have one meaning in one task but another slightly different one in another.)
Returns: hashref with parameter names as keys and values the hashrefs described in task_parameters
except with no 'description' key.
all_parameters_long_options()
Shortcut for CLI programs (like oi2_manage
...) that use Getopt::Long. Returns an array of option specifiers that you can send directly to the GetOptions( \%, @ )
signature. For instance, say that from all_parameters()
we get that 'website_dir' is a normal (non-boolean, non-multivalue) parameter. Its entry would look like this:
website_dir=s
A parameter 'analyze' with 'is_boolean' set to 'yes' would simply be:
analyze
And a parameter 'package' with 'is_multivialued' set to 'yes' would be:
package=s@
Returns: list of option specifiers compatible with Getopt::Long.
find_management_tasks( @directories )
Find all management tasks under directories in @directories
and require
them. Note that when this class is included it runs this for every directory in @INC
, so you should only need to run it if you add directories to @INC
(using use lib
or manually).
Returns: nothing
Object Methods
execute()
Runs through the methods check_parameters()
, setup_task()
, run_task()
, tear_down_task()
.
Any of these methods can throw an exception, so it is up to you to wrap the call to execute()
in an eval
block and examine $@
.
Returns: an arrayref of status hash references. These should include the keys 'is_ok' (set to 'yes' if the item succeeded, 'no' if not) and 'message' describing the results. Tasks may set additional items as well, all of which should be documented in the task.
You can also retrieve the status messages by calling get_status()
.
param( $key, $value )
If $key
is unspecified, returns all parameters as a hashref.
If $value
is unspecified, returns the current value set for parameter $key
.
If both $key
and $value
are specified, sets the parameter $key
to $value
and returns it.
Example:
$task->param( 'website_dir', '/home/httpd/test' );
$task->param( package => [ 'pkg1', 'pkg2' ] );
my $all_params = $task->param;
Another way of setting parameters is by passing them into the constructor. The second argument (hashref) passed into the new()
call can be set to the parameters you want to use for the task. This makes it simple to do initialization and execution in one step:
my @status = OpenInteract2::Manage->new( 'create_website',
{ website_dir => '/home/httpd/test' } )
->execute();
param_copy_from( $other_task )
Copy all parameters from $other_task
into this object.
Returns: results of param()
on this object.
get_status()
Returns a list of all status messages. This won't be populated until after you run execute()
.
VALIDATING PARAMETERS
Every management task should be initialized with parameters that tell the task how or where to perform its work. This parent class provides the means to ensure required parameters are defined and that they are valid. This parameter checking is very flexible so it is simple to define your own validation checks and tell them to this parent class.
Checking Parameters: Flow
The management class has a fairly simple but flexible way for you to ensure that your task gets valid parameters.
First, you can ensure that all the parameters required are defined by the task caller. Just tag Simply create a method list_param_required()
which returns an arrayref of parameters that require a value to be defined:
TODO: Get rid of me
sub list_param_required { return [ 'website_dir', 'package_dir' ] }
You can also override the method check_required_parameters()
, but this requires you to throw the exceptions yourself.
Next, you need to ensure that all the parameters are valid. There are a couple of ways to do this
Checking Parameters: Methods
check_parameters()
This method is a wrapper for a number of separate jobs: parameter initialization, required parameter checking and parameter validation.
It is called from execute()
before run_task()
is called, so any initialization done there (like creating a OpenInteract2::Context) hasn't been done yet. This may force some tasks to put off validating some parameters until run_task()
. That's an acceptable behavior for now.
It uses the 'is_required' and 'do_validate' keys of the parameter metadata passed back from get_parameters()
.
The first action it performs is to call param_initialize()
so your task can do any necessary parameter manipulation.
Next it checks the required parameters, which cycling through the parameters flagged with 'is_required' and ensuring that a value for each parameter exists.
Finally it validates parameters, ensuring that parameters requiring validation (those with 'is_required' or 'do_validate' toggled on) are valid.
Any errors thrown by these methods are percolated up back to the caller. Barring strange runtime errors they're going to be OpenInteract2::Exception::Parameter objects, which means the caller can do a filter as needed, displaying more pertient information:
eval { $task->execute }
my $error = $@;;
if ( $error ) {
if ( $error->isa( 'OpenInteract2::Exception::Parameter' ) ) {
print "Caught an exception with one or more paramters:\n";
my $failed = $error->parameter_fail;
while ( my ( $field, $fail ) = each %{ $failed } ) {
my @failures = ( ref $fail eq 'ARRAY' ) ? @{ $fail } : ( $fail );
foreach my $failure ( @failures ) {
print sprintf( "%-20s-> %s\n", $field, $failure );
}
}
}
else {
print "Caught an error: $@";
}
}
param_initialize()
This class implements this method to massage the 'package' parameter into a consistent format.
You may want to implement it to modify your parameters before any checking or validation. For instance, tasks dealing with packages typically allow you to pass in a list or a comma-separated string, or even use a keyword to represent multiple packages. The param_initialize()
method can change each of these into a consistent format, allowing the task to assume it will always be dealing with an arrayref. This is done at initialization. (You don't have to do this, it's just an example.)
validate_param( $param_name, $param_value )
If $param_name
with $param_value
is valid return nothing, otherwise return one or more error messages in a list. If you're a subclass you should forward the request onto your parents via SUPER
. See examples of this in OpenInteract2::Manual::Management.
OBSERVERS
Every management task is observable. (See Class::Observable for what this means.) As a creator and user of a task you can add your own observers to it and receive status and progress messages from the task as it performs its work.
There are two types of standard observations posted from management tasks. This type is passed as the first argument to your observer.
status: This is a normal status message. (See "STATUS MESSAGES" for what this means.) The second argument passed to your observer will be the hashref representing the status message.
progress: Indicates a new stage of the process has been reached or completed. The second argument to your observer is a text message, the optional third argument is a hashref of additional information. Currently this has only one option: long may be set to 'yes', and if so the task is telling you it's about to begin a long-running process.
For an example of an observer, see oi2_manage
.
STATUS MESSAGES
Status messages are simple hashrefs with at least three entries:
is_ok: Set to 'yes' if this a successful status, 'no' if not.
action: Name of the action.
message: Message describing the action or the error encountered.
Each message may have any number of additional entries. A common one is filename, which is used to indicate the file acted upon. Every management task should list what keys its status messages support, not including the three listed above.
Some tasks can generate a lot of status messages, so the method merge_status_by_action
will merge all status messages with the same action
into a single message with the keys action
(the action) and status
(an arrayref of the collected status messages under that action).
SEE ALSO
OpenInteract2::Manual::Management
OpenInteract2::Manage::Package
OpenInteract2::Manage::Website
COPYRIGHT
Copyright (c) 2002-2004 Chris Winters. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
AUTHORS
Chris Winters <chris@cwinters.com>