From 2727b04df37e4903fa14c4b8368e87b55dc9ba69 Mon Sep 17 00:00:00 2001 From: Jason Stephenson Date: Thu, 1 Dec 2011 12:38:55 -0500 Subject: [PATCH] Make some improvements to Cronscript.pm. Allow the session method to function when called more than once with different service names. Add some useful new methods: logout: Calls open-ils.auth.session.delete if we're logged in. die_event: Causes a script to croak if the object passed in is an event, or optionally a certain named event. warn_event: Causes a script to output an error message if the object passed in is an event, or optionally a certain named event. Use OpenILS::Application::AppUtils. Default to staff login in Cronscript->authenticate method. Improve the Croncript.pm.in POD to include a better synopsis of its features. Clean up some other sections of the POD, remove the TODO section, and add some SEE ALSO entries. Signed-off-by: Jason Stephenson Signed-off-by: Bill Erickson --- .../perlmods/lib/OpenILS/Utils/Cronscript.pm.in | 201 +++++++++++++++++---- 1 file changed, 170 insertions(+), 31 deletions(-) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Utils/Cronscript.pm.in b/Open-ILS/src/perlmods/lib/OpenILS/Utils/Cronscript.pm.in index 472c445532..e96866df83 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Utils/Cronscript.pm.in +++ b/Open-ILS/src/perlmods/lib/OpenILS/Utils/Cronscript.pm.in @@ -3,6 +3,8 @@ package OpenILS::Utils::Cronscript; # --------------------------------------------------------------- # Copyright (C) 2010 Equinox Software, Inc # Author: Joe Atzberger +# Portions Copyright (C) 2011 Merrimack Valley Library Consortium +# Author: Jason Stephenson # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -32,6 +34,7 @@ use OpenSRF::EX qw(:try); use OpenILS::Utils::Fieldmapper; use OpenILS::Utils::Lockfile; use OpenILS::Utils::CStoreEditor q/:funcs/; +use OpenILS::Application::AppUtils; use File::Basename qw/fileparse/; @@ -47,6 +50,8 @@ our @extra_opts = ( # additional keys are stored here our $debug = 0; +my $apputils = 'OpenILS::Application::AppUtils'; + sub _default_self { return { # opts => {}, @@ -251,7 +256,7 @@ sub session { my $self = shift or return; $self->{bootstrapped} or $self->bootstrap(); @_ or croak "session() called without required argument (app_name, e.g. 'open-ils.acq')"; - return ($self->{session} ||= OpenSRF::AppSession->create(@_)); + return OpenSRF::AppSession->create(@_); } sub bootstrap { @@ -285,6 +290,34 @@ sub editor { return new_editor(@_); } +# Die on an event. Takes an optional third parameter for the textcode +# of an event to die on. If the event textcode does not match the +# third parameter, will warn on the event instead of dying. +sub die_event { + my $self = shift; + my $e = shift; + my $name = shift; + if ($apputils->event_code($e)) { + if (!defined($name) || $apputils->event_equals($e,$name)) { + croak(Dumper $e); + } else { + carp(Dumper $e); + } + } +} + +# Prints warning on an even. Takes an optional third parameter for the +# textcode of an event to warn on. +sub warn_event { + my $self = shift; + my $e = shift; + my $name = shift; + if ($apputils->event_code($e) + && (!defined($name) || $apputils->event_equals($e, $name))) { + carp(Dumper $e); + } +} + # Authenticate with the open-ils.auth module. # Takes a hash ref of arguments: # { @@ -300,9 +333,10 @@ sub authenticate { my $self = shift or return; my $args = shift or return; if ($args && ref($args) eq 'HASH') { - $self->{bootstrapped} or $self->bootstrap(); + # Default to staff in case the back end ever stops doing so. + $args->{type} = 'staff' unless (defined($args->{type})); - my $session = OpenSRF::AppSession->create('open-ils.auth'); + my $session = $self->session('open-ils.auth'); my $seed = $session->request( 'open-ils.auth.authenticate.init', $args->{'username'} )->gather(1); @@ -319,6 +353,7 @@ sub authenticate { } else { $self->{authtoken} = undef; $self->{authtime} = undef; + carp("Authentication failed"); } $session->disconnect(); return $self->authtoken; @@ -327,6 +362,27 @@ sub authenticate { } } +# Deletes the session for our authtoken if we have logged in with the +# authenticate method. +sub logout { + my $self = shift or return; + my $token = shift || $self->{authtoken}; + if ($token) { + my $session = $self->session('open-ils.auth'); + if ($session->request('open-ils.auth.session.delete', $token)->gather(1)) { + if ($token eq $self->{authtoken}) { + $self->{authtoken} = undef; + $self->{authtime} = undef; + } + } else { + carp("Not authenticated"); + } + $session->disconnect(); + } else { + carp("No authtoken"); + } +} + sub authtoken { my $self = shift; return $self->{authtoken}; @@ -344,7 +400,8 @@ __END__ =head1 NAME -OpenILS::Utils::Cronscript - Consolidated options handling for any script (not just cron, really) +OpenILS::Utils::Cronscript - Consolidated options handling and utility +methods for any script (not just cron, really) =head1 SYNOPSIS @@ -356,47 +413,131 @@ OpenILS::Utils::Cronscript - Consolidated options handling for any script (not j 'user=s' => 'admin', 'password=s' => '', 'nolockfile' => 1, - }; + ); my $core = OpenILS::Utils::Cronscript->new(\%defaults); my $opts = $core->MyGetOptions(); # options now in, e.g.: $opts->{max} $core->bootstrap; -Or if you don't need any additional options and just want to get a session going: - +You can skip alot of the above if you're happy with the defaults: + + my $script = OpenILS::Utils::Cronscript->new(); + +If you just don't want a lock file: + + my $core = OpenILS::Utils::Cronscript->new({nolockfile=>1}); + +Or if you don't need any additional options and just want to get a +session going: + use OpenILS::Utils::Cronscript; my $session = OpenILS::Utils::Cronscript->new()->session('open-ils.acq'); +Cronscript gives you access to many useful methods: + +You can login if necessary: + + my $account = { + username => 'admin', + password => 'password', + workstation => 'workstation_name', # optional + type => 'staff' # optional, but staff is the default + }; + my $authtoken = $core->authenticate($account); + +You can logout a session given its authtoken: + + $core->logout($authtoken); + +Or, if you've authenticated with the authenticate method, you can +logout the most recently authenticated session: + + $core->logout(); + +If you have logged in with the authenticate method, you can retrieve +your current authtoken or authtime values: + + my $token = $core->authtoken; + my $authtime = $core->authtime; + +You can create a CStoreEdtor object: + + my $editor = $core->editor(); # With defaults. + my $editor = $core->editor(authtoken=>$authtoken); # with a given + # session + my $editor = $core->editor(xact=>1); # With transactions or any + # other CStoreEditor options. + +You can create OpenSRF AppSesions to run commands: + + my $pcrud = $core->session('open-ils.pcrud'); + #...Do some pcrud stuff here. + +You can print warnings or die on events: + + my $evt ...; + $core->warn_event($evt); + $core->die_event($evt); + +Or only on certain events: + + $core->warn_event($evt, 'PERM_FAILURE'); + $core->die_event($evt, 'PERM_FAILURE'); + +Includes a shared debug flag so you can turn debug mode on and off: + + $OpenILS::Utils::Cronscript::debug = 1; # Debugging on + $OpenILS::Utils::Cronscript::debug = 0; # Debugging off + +Includes OpenILS::Application::Apputils so using AppUtils methods is +as simple as: + + my $apputils = 'OpenILS::Application::AppUtils'; + $apputils->event_code($evt); + +Uses and imports the OpenILS::Utils::Fieldmapper so you don't have to. + +Includes Data::Dumper, so you don't have to. + =head1 DESCRIPTION -There are a few main problems when writing a new script for Evergreen. +There are a few main problems when writing a new script for Evergreen. =head2 Initialization -The runtime -environment for the application requires a lot of initialization, but during normal operation it -has already occured (when Evergreen was started). So most of the EG code never has to deal with -this problem, but standalone scripts do. The timing and sequence of requisite events is important and not obvious. +The runtime environment for the application requires a lot of +initialization, but during normal operation it has already occured +(when Evergreen was started). So most of the EG code never has to +deal with this problem, but standalone scripts do. The timing and +sequence of requisite events is important and not obvious. =head2 Common Options, Consistent Options -We need several common options for each script that accesses the database or -uses EG data objects and methods. Logically, these options often deal with initialization. They -should take the B same form(s) for each script and should not be -dependent on the local author to copy and paste them from some reference source. We really don't want to encourage (let alone force) -admins to use C<--config>, C<--osrf-confg>, C<-c>, and C<@ARGV[2]> for the same purpose in different scripts, with different -default handling, help descriptions and error messages (or lack thereof). +We need several common options for each script that accesses the +database or uses EG data objects and methods. Logically, these +options often deal with initialization. They should take the B +same form(s) for each script and should not be dependent on the local +author to copy and paste them from some reference source. We really +don't want to encourage (let alone force) admins to use C<--config>, +C<--osrf-confg>, C<-c>, and C<@ARGV[2]> for the same purpose in +different scripts, with different default handling, help descriptions +and error messages (or lack thereof). -This suggests broader problem of UI consistency and uniformity, also partially addressed by this module. +This suggests broader problem of UI consistency and uniformity, also +partially addressed by this module. =head2 Lockfiles -A lockfile is necessary for a script that wants to prevent possible simultaneous execution. For example, consider a script -that is scheduled to run frequently, but that experiences occasional high load: you wouldn't want crontab to start running -it again if the first instance had not yet finished. +A lockfile is necessary for a script that wants to prevent possible +simultaneous execution. For example, consider a script that is +scheduled to run frequently, but that experiences occasional high +load: you wouldn't want crontab to start running it again if the first +instance had not yet finished. -But the code for creating, writing to, checking for, reading and cleaning up a lockfile for the script bloats what might otherwise be a terse -method call. Conscript handles lockfile generation and removal automatically. +But the code for creating, writing to, checking for, reading and +cleaning up a lockfile for the script bloats what might otherwise be a +terse method call. Conscript handles lockfile generation and removal +automatically. =head1 OPTIONS @@ -408,19 +549,17 @@ The common options (and default values) are: 'verbose+' => 0, 'help' => 0, -=head1 TODO - -More docs here. - =head1 SEE ALSO Getopt::Long + OpenILS::Application::AppUtils + OpenILS::Utils::Fieldmapper OpenILS::Utils::Lockfile - oils_header.pl -=head1 AUTHOR +=head1 AUTHORS -Joe Atzberger + Joe Atzberger + Jason Stephenson =cut -- 2.11.0