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

Class::Factory

OpenInteract2::Manage::Package

OpenInteract2::Manage::Website

OpenInteract2::Setup

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>