2017-10-20 04:19:32 +00:00
package Anvil::Tools ;
2017-04-13 21:04:03 +00:00
#
# This is the "root" package that manages the sub modules and controls access to their methods.
#
BEGIN
{
2017-05-27 05:23:34 +00:00
our $ VERSION = "3.0.0" ;
2017-04-13 21:04:03 +00:00
# This suppresses the 'could not find ParserDetails.ini in /PerlApp/XML/SAX' warning message in
# XML::Simple calls.
2017-05-27 05:23:34 +00:00
#$ENV{HARNESS_ACTIVE} = 1;
2017-04-13 21:04:03 +00:00
}
use strict ;
use warnings ;
2017-08-17 21:16:45 +00:00
use Scalar::Util qw( weaken isweak ) ;
2017-10-04 06:11:03 +00:00
use Time::HiRes ;
2017-05-02 04:41:12 +00:00
use Data::Dumper ;
2017-12-08 22:04:36 +00:00
use CGI ;
2017-04-13 21:04:03 +00:00
my $ THIS_FILE = "Tools.pm" ;
2017-05-27 05:23:34 +00:00
### Methods;
# data
# environment
2017-08-02 01:04:35 +00:00
# nice_exit
2017-05-27 05:23:34 +00:00
# _add_hash_reference
2017-07-07 05:54:49 +00:00
# _hostname
2017-05-27 05:23:34 +00:00
# _make_hash_reference
# _set_defaults
# _set_paths
2017-07-07 05:54:49 +00:00
# _short_hostname
2017-05-27 05:23:34 +00:00
2017-04-13 21:04:03 +00:00
use utf8 ;
2017-05-27 05:23:34 +00:00
binmode ( STDERR , ':encoding(utf-8)' ) ;
binmode ( STDOUT , ':encoding(utf-8)' ) ;
2017-04-13 21:04:03 +00:00
2017-05-02 04:41:12 +00:00
# I intentionally don't use EXPORT, @ISA and the like because I want my "subclass"es to be accessed in a
# somewhat more OO style. I know some may wish to strike me down for this, but I like the idea of accessing
2017-10-20 04:19:32 +00:00
# methods via their containing module's name. (A La: C<< $anvil->Module->method >> rather than C<< $anvil->method >>).
use Anvil::Tools::Alert ;
use Anvil::Tools::Database ;
use Anvil::Tools::Convert ;
use Anvil::Tools::Get ;
use Anvil::Tools::Log ;
use Anvil::Tools::Storage ;
use Anvil::Tools::System ;
use Anvil::Tools::Template ;
use Anvil::Tools::Words ;
use Anvil::Tools::Validate ;
2017-05-02 04:41:12 +00:00
2017-04-13 21:04:03 +00:00
= pod
= encoding utf8
= head1 NAME
2017-10-20 04:19:32 +00:00
Anvil:: Tools
2017-04-13 21:04:03 +00:00
2017-10-20 04:19:32 +00:00
Provides a common oject handle to all Anvil::Tools:: * module methods and handles invocation configuration .
2017-04-13 21:04:03 +00:00
= head1 SYNOPSIS
2017-10-20 04:19:32 +00:00
use Anvil::Tools ;
2017-04-13 21:04:03 +00:00
2017-10-20 04:19:32 +00:00
# Get a common object handle on all Anvil::Tools::* modules.
my $ anvil = Anvil::Tools - > new ( ) ;
2017-05-27 05:23:34 +00:00
2017-10-20 04:19:32 +00:00
# Again, but this time sets some initial values in the '$anvil->data' hash.
my $ anvil = Anvil::Tools - > new (
2017-04-13 21:04:03 +00:00
{
data = > {
foo = > "" ,
bar = > [] ,
baz = > { } ,
} ,
} ) ;
# This example gets the handle and also sets the default user and log
# languages as Japanese, sets a custom log file and sets the log level to
# '2'.
2017-10-20 04:19:32 +00:00
my $ anvil = Anvil::Tools - > new (
2017-04-13 21:04:03 +00:00
{
'Log' = > {
2017-05-27 05:23:34 +00:00
user_language = > "jp" ,
2017-04-13 21:04:03 +00:00
log_language = > "jp"
level = > 2 ,
2017-05-27 05:23:34 +00:00
} ,
2017-04-13 21:04:03 +00:00
} ) ;
= head1 DESCRIPTION
2017-10-20 04:19:32 +00:00
The Anvil:: Tools module and all sub - modules are designed for use by Alteeve - based applications . It can be used as a general framework by anyone interested .
2017-04-13 21:04:03 +00:00
Core features are ;
* Supports per user , per logging language selection where translations from from XML - formatted "String" files that support UTF8 and variable substitutions .
* Support for command - line and HTML output . Skinning support for HTML - based user interfaces .
* Redundant database access , resynchronization and archiving .
* Highly - native with minimal use of external perl modules and compiled code .
2017-05-02 04:41:12 +00:00
= head1 METHODS
2017-04-13 21:04:03 +00:00
Methods in the core module ;
= cut
# The constructor through which all other module's methods will be accessed.
sub new
{
my $ class = shift ;
my $ parameter = shift ;
my $ self = {
HANDLE = > {
2017-10-20 04:19:32 +00:00
ALERT = > Anvil::Tools::Alert - > new ( ) ,
DATABASE = > Anvil::Tools::Database - > new ( ) ,
CONVERT = > Anvil::Tools::Convert - > new ( ) ,
GET = > Anvil::Tools::Get - > new ( ) ,
LOG = > Anvil::Tools::Log - > new ( ) ,
STORAGE = > Anvil::Tools::Storage - > new ( ) ,
SYSTEM = > Anvil::Tools::System - > new ( ) ,
TEMPLATE = > Anvil::Tools::Template - > new ( ) ,
WORDS = > Anvil::Tools::Words - > new ( ) ,
VALIDATE = > Anvil::Tools::Validate - > new ( ) ,
2017-04-13 21:04:03 +00:00
} ,
DATA = > { } ,
ENV_VALUES = > {
ENVIRONMENT = > 'cli' ,
} ,
2017-06-07 16:15:03 +00:00
HOST = > {
# This is the host's UUID. It should never be manually set.
UUID = > "" ,
} ,
2017-04-13 21:04:03 +00:00
} ;
2017-08-17 21:16:45 +00:00
2017-04-13 21:04:03 +00:00
# Bless you!
bless $ self , $ class ;
2017-08-17 21:16:45 +00:00
2017-04-13 21:04:03 +00:00
# This isn't needed, but it makes the code below more consistent with and portable to other modules.
2017-10-20 04:19:32 +00:00
my $ anvil = $ self ;
weaken ( $ anvil ) ; # Helps avoid memory leaks. See Scalar::Utils
2017-05-02 04:41:12 +00:00
2017-10-04 06:11:03 +00:00
# Record the start time.
2017-10-20 04:19:32 +00:00
$ anvil - > data - > { ENV_VALUES } { START_TIME } = Time::HiRes:: time ;
2017-10-04 06:11:03 +00:00
2017-05-02 04:41:12 +00:00
# Get a handle on the various submodules
2017-10-20 04:19:32 +00:00
$ anvil - > Alert - > parent ( $ anvil ) ;
$ anvil - > Database - > parent ( $ anvil ) ;
$ anvil - > Convert - > parent ( $ anvil ) ;
$ anvil - > Get - > parent ( $ anvil ) ;
$ anvil - > Log - > parent ( $ anvil ) ;
$ anvil - > Storage - > parent ( $ anvil ) ;
$ anvil - > System - > parent ( $ anvil ) ;
$ anvil - > Template - > parent ( $ anvil ) ;
$ anvil - > Words - > parent ( $ anvil ) ;
$ anvil - > Validate - > parent ( $ anvil ) ;
2017-08-17 21:16:45 +00:00
2017-04-13 21:04:03 +00:00
# Set some system paths and system default variables
2017-10-20 04:19:32 +00:00
$ anvil - > _set_paths ;
$ anvil - > _set_defaults ;
2017-08-17 21:16:45 +00:00
# This will help clean up if we catch a signal.
2017-10-20 04:19:32 +00:00
$ SIG { INT } = sub { $ anvil - > catch_sig ( { signal = > "INT" } ) ; } ;
$ SIG { TERM } = sub { $ anvil - > catch_sig ( { signal = > "TERM" } ) ; } ;
2017-08-17 21:16:45 +00:00
2017-06-11 07:00:35 +00:00
# This sets the environment this program is running in.
if ( $ ENV { SERVER_NAME } )
{
2017-10-20 04:19:32 +00:00
$ anvil - > environment ( "html" ) ;
2017-06-11 07:00:35 +00:00
# There is no PWD environment variable, so we'll use 'DOCUMENT_ROOT' as 'PWD'
$ ENV { PWD } = $ ENV { DOCUMENT_ROOT } ;
}
else
{
2017-10-20 04:19:32 +00:00
$ anvil - > environment ( "cli" ) ;
2017-06-11 07:00:35 +00:00
}
2017-08-17 21:16:45 +00:00
2017-10-20 04:19:32 +00:00
# Setup my '$anvil->data' hash right away so that I have a place to store the strings hash.
$ anvil - > data ( $ parameter - > { data } ) if $ parameter - > { data } ;
2017-05-27 05:23:34 +00:00
2017-06-05 12:02:14 +00:00
# Initialize the list of directories to seach.
2017-10-20 04:19:32 +00:00
$ anvil - > Storage - > search_directories ( { initialize = > 1 } ) ;
2017-08-17 21:16:45 +00:00
2017-04-13 21:04:03 +00:00
# I need to read the initial words early.
2017-10-20 04:19:32 +00:00
$ anvil - > Words - > read ( { file = > $ anvil - > data - > { path } { words } { 'words.xml' } } ) ;
2017-06-07 15:36:06 +00:00
# If the local './tools.conf' file exists, read it in.
2017-10-20 04:19:32 +00:00
if ( - r $ anvil - > data - > { path } { configs } { 'anvil.conf' } )
2017-06-07 15:36:06 +00:00
{
2017-10-20 04:19:32 +00:00
$ anvil - > Storage - > read_config ( { file = > $ anvil - > data - > { path } { configs } { 'anvil.conf' } } ) ;
2017-06-07 15:36:06 +00:00
}
2017-06-07 16:15:03 +00:00
# Read in any command line switches.
2017-10-20 04:19:32 +00:00
$ anvil - > Get - > switches ;
2017-06-07 16:15:03 +00:00
2017-04-13 21:04:03 +00:00
# Set passed parameters if needed.
if ( ref ( $ parameter ) eq "HASH" )
{
2017-05-27 05:23:34 +00:00
### TODO: Calls to allow the user to override defaults...
# Local parameters...
2017-04-13 21:04:03 +00:00
}
2017-05-02 04:41:12 +00:00
elsif ( $ parameter )
2017-04-13 21:04:03 +00:00
{
2017-05-02 04:41:12 +00:00
# Um...
2017-10-20 04:19:32 +00:00
print $ THIS_FILE . " " . __LINE__ . "; Anvil::Tools->new() invoked with an invalid parameter. Expected a hash reference, but got: [$parameter]\n" ;
2017-05-02 04:41:12 +00:00
exit ( 1 ) ;
2017-04-13 21:04:03 +00:00
}
2017-08-17 21:16:45 +00:00
2017-04-13 21:04:03 +00:00
return ( $ self ) ;
}
2017-05-02 04:41:12 +00:00
#############################################################################################################
# Public methods #
#############################################################################################################
2017-04-13 21:04:03 +00:00
= head2 data
This is the method used to access the main hash reference that all user - accessible values are stored in . This includes words , configuration file variables and so forth .
2017-10-20 04:19:32 +00:00
When called without an argument , it returns the existing '$anvil->data' hash reference .
2017-04-13 21:04:03 +00:00
2017-10-20 04:19:32 +00:00
my $ anvil = $ anvil - > data ( ) ;
2017-04-13 21:04:03 +00:00
2017-10-20 04:19:32 +00:00
When called with a hash reference as the argument , it sets '$anvil->data' to the new hash .
2017-04-13 21:04:03 +00:00
my $ some_hash = { } ;
2017-10-20 04:19:32 +00:00
my $ anvil = $ anvil - > data ( $ some_hash ) ;
2017-04-13 21:04:03 +00:00
2017-10-20 04:19:32 +00:00
Data can be entered into or access by treating '$anvil->data' as a normal hash reference .
2017-04-13 21:04:03 +00:00
2017-10-20 04:19:32 +00:00
my $ anvil = Anvil::Tools - > new (
2017-04-13 21:04:03 +00:00
{
data = > {
foo = > "" ,
bar = > [ 6 , 4 , 12 ] ,
baz = > {
animal = > "Cat" ,
thing = > "Boat" ,
} ,
} ,
} ) ;
# Copy the 'Cat' value into the $animal variable.
2017-10-20 04:19:32 +00:00
my $ animal = $ anvil - > data - > { baz } { animal } ;
2017-04-13 21:04:03 +00:00
# Set 'A thing' in 'foo'.
2017-10-20 04:19:32 +00:00
$ anvil - > data - > { foo } = "A thing" ;
2017-04-13 21:04:03 +00:00
2017-10-20 04:19:32 +00:00
The C <$an> variable is set inside all modules and acts as shared storage for variables , values and references in all modules . It acts as the core storage for most applications using Anvil:: Tools .
2017-04-13 21:04:03 +00:00
= cut
sub data
{
2017-10-20 04:19:32 +00:00
my ( $ anvil ) = shift ;
2017-04-13 21:04:03 +00:00
# Pick up the passed in hash, if any.
2017-10-20 04:19:32 +00:00
$ anvil - > { DATA } = shift if $ _ [ 0 ] ;
2017-04-13 21:04:03 +00:00
2017-10-20 04:19:32 +00:00
return ( $ anvil - > { DATA } ) ;
2017-04-13 21:04:03 +00:00
}
= head2 environment
This is the method used to check or set whether the program is outputting to command line or a browser .
When called without an argument , it returns the current environment .
2017-10-20 04:19:32 +00:00
if ( $ anvil - > environment ( ) eq "cli" )
2017-04-13 21:04:03 +00:00
{
# format for STDOUT
}
2017-10-20 04:19:32 +00:00
elsif ( $ anvil - > environment ( ) eq "html" )
2017-04-13 21:04:03 +00:00
{
# Use the template system to output HTML
}
When called with a string as the argument , that string will be set as the environment string .
2017-10-20 04:19:32 +00:00
$ anvil - > environment ( "cli" ) ;
2017-04-13 21:04:03 +00:00
Technically , any string can be used , however only 'cli' or 'html' are used by convention .
= cut
sub environment
{
2017-10-20 04:19:32 +00:00
my ( $ anvil ) = shift ;
weaken ( $ anvil ) ;
2017-08-17 21:16:45 +00:00
2017-04-13 21:04:03 +00:00
# Pick up the passed in delimiter, if any.
2017-09-04 15:10:02 +00:00
if ( $ _ [ 0 ] )
{
2017-10-20 04:19:32 +00:00
$ anvil - > { ENV_VALUES } { ENVIRONMENT } = shift ;
2017-12-08 22:04:36 +00:00
# Load the CGI stuff if we're in a browser
2017-10-20 04:19:32 +00:00
if ( $ anvil - > { ENV_VALUES } { ENVIRONMENT } eq "html" )
2017-09-04 15:10:02 +00:00
{
2017-12-08 22:04:36 +00:00
CGI::Carp - > import ( qw( fatalsToBrowser ) ) ;
2017-09-04 15:10:02 +00:00
}
}
2017-05-02 04:41:12 +00:00
2017-10-20 04:19:32 +00:00
return ( $ anvil - > { ENV_VALUES } { ENVIRONMENT } ) ;
2017-05-02 04:41:12 +00:00
}
2017-08-02 01:04:35 +00:00
= head2 nice_exit
This is a simple method to exit cleanly , closing database connections and exiting with the set exit code .
Parameters ;
= head3 exit_code ( optional )
If set , this will be the exit code . The default is to exit with code C << 0 >> .
= cut
sub nice_exit
{
my $ self = shift ;
my $ parameter = shift ;
2017-10-20 04:19:32 +00:00
my $ anvil = $ self ;
2017-08-02 01:04:35 +00:00
my $ exit_code = defined $ parameter - > { exit_code } ? $ parameter - > { exit_code } : 0 ;
# Close database connections (if any).
2017-10-20 04:19:32 +00:00
$ anvil - > Database - > disconnect ( ) ;
2017-08-02 01:04:35 +00:00
2017-10-04 06:11:03 +00:00
# Report the runtime.
my $ end_time = Time::HiRes:: time ;
2017-10-20 04:19:32 +00:00
my $ run_time = $ end_time - $ anvil - > data - > { ENV_VALUES } { START_TIME } ;
2017-12-08 22:04:36 +00:00
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 3 , list = > {
2017-10-20 04:19:32 +00:00
's1:ENV_VALUES::START_TIME' = > $ anvil - > data - > { ENV_VALUES } { START_TIME } ,
2017-10-04 06:11:03 +00:00
's2:end_time' = > $ end_time ,
's3:run_time' = > $ run_time ,
} } ) ;
2017-10-20 04:19:32 +00:00
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 1 , key = > "log_0135" , variables = > { runtime = > $ run_time } } ) ;
2017-10-04 06:11:03 +00:00
2017-08-02 01:04:35 +00:00
exit ( $ exit_code ) ;
}
2017-05-02 04:41:12 +00:00
#############################################################################################################
# Public methods used to access sub modules. #
#############################################################################################################
= head1 Submodule Access Methods
2017-10-20 04:19:32 +00:00
The methods below are used to access methods of submodules using 'C<< $anvil->Module->method() >>' .
2017-05-02 04:41:12 +00:00
= cut
= head2 Alert
2017-10-20 04:19:32 +00:00
Access the C <Alert.pm> methods via 'C<< $anvil->Alert->method >>' .
2017-05-02 04:41:12 +00:00
= cut
sub Alert
{
my $ self = shift ;
return ( $ self - > { HANDLE } { ALERT } ) ;
}
2017-06-13 21:08:38 +00:00
= head2 Database
2017-10-20 04:19:32 +00:00
Access the C <Database.pm> methods via 'C<< $anvil->Database->method >>' .
2017-06-13 21:08:38 +00:00
= cut
sub Database
{
my $ self = shift ;
return ( $ self - > { HANDLE } { DATABASE } ) ;
}
= head2 Convert
2017-10-20 04:19:32 +00:00
Access the C <Convert.pm> methods via 'C<< $anvil->Convert->method >>' .
2017-06-13 21:08:38 +00:00
= cut
sub Convert
{
my $ self = shift ;
return ( $ self - > { HANDLE } { CONVERT } ) ;
}
2017-06-05 12:02:14 +00:00
= head2 Get
2017-10-20 04:19:32 +00:00
Access the C <Get.pm> methods via 'C<< $anvil->Get->method >>' .
2017-06-05 12:02:14 +00:00
= cut
sub Get
{
my $ self = shift ;
return ( $ self - > { HANDLE } { GET } ) ;
}
= head2 Log
2017-10-20 04:19:32 +00:00
Access the C <Log.pm> methods via 'C<< $anvil->Log->method >>' .
2017-06-05 12:02:14 +00:00
= cut
sub Log
{
my $ self = shift ;
return ( $ self - > { HANDLE } { LOG } ) ;
}
2017-05-02 04:41:12 +00:00
= head2 Storage
2017-10-20 04:19:32 +00:00
Access the C <Storage.pm> methods via 'C<< $anvil->Storage->method >>' .
2017-05-02 04:41:12 +00:00
= cut
sub Storage
{
my $ self = shift ;
2017-04-13 21:04:03 +00:00
2017-05-02 04:41:12 +00:00
return ( $ self - > { HANDLE } { STORAGE } ) ;
2017-04-13 21:04:03 +00:00
}
2017-05-02 04:41:12 +00:00
2017-06-10 06:38:04 +00:00
= head2 System
2017-10-20 04:19:32 +00:00
Access the C <System.pm> methods via 'C<< $anvil->System->method >>' .
2017-06-10 06:38:04 +00:00
= cut
sub System
{
my $ self = shift ;
return ( $ self - > { HANDLE } { SYSTEM } ) ;
}
2017-06-09 08:29:25 +00:00
= head2 Template
2017-10-20 04:19:32 +00:00
Access the C <Template.pm> methods via 'C<< $anvil->Template->method >>' .
2017-06-09 08:29:25 +00:00
= cut
sub Template
{
my $ self = shift ;
return ( $ self - > { HANDLE } { TEMPLATE } ) ;
}
2017-05-10 19:01:36 +00:00
= head2 Words
2017-10-20 04:19:32 +00:00
Access the C <Words.pm> methods via 'C<< $anvil->Words->method >>' .
2017-05-10 19:01:36 +00:00
= cut
sub Words
{
my $ self = shift ;
return ( $ self - > { HANDLE } { WORDS } ) ;
}
2017-06-07 16:30:28 +00:00
= head2 Validate
2017-10-20 04:19:32 +00:00
Access the C <Validate.pm> methods via 'C<< $anvil->Validate->method >>' .
2017-06-07 16:30:28 +00:00
= cut
sub Validate
{
my $ self = shift ;
return ( $ self - > { HANDLE } { VALIDATE } ) ;
}
2017-05-02 04:41:12 +00:00
= head1 Private Functions ;
2017-10-20 04:19:32 +00:00
These methods generally should never be called from a program using Anvil:: Tools . However , we are not your boss .
2017-05-02 04:41:12 +00:00
= cut
#############################################################################################################
# Private methods #
#############################################################################################################
2017-05-27 05:23:34 +00:00
= head2 _add_hash_reference
2017-10-20 04:19:32 +00:00
This is a helper to the '$anvil->_make_hash_reference' method . It is called each time a new string is to be created as a new hash key in the passed hash reference .
2017-05-02 04:41:12 +00:00
2017-05-27 05:23:34 +00:00
NOTE: Contributed by Shaun Fryer and Viktor Pavlenko by way of Toronto Perl Mongers .
2017-05-02 04:41:12 +00:00
= cut
2017-05-27 05:23:34 +00:00
sub _add_hash_reference
2017-05-02 04:41:12 +00:00
{
2017-05-27 05:23:34 +00:00
my $ self = shift ;
my $ href1 = shift ;
my $ href2 = shift ;
2017-05-02 04:41:12 +00:00
2017-05-27 05:23:34 +00:00
for my $ key ( keys %$ href2 )
2017-05-02 04:41:12 +00:00
{
2017-05-27 05:23:34 +00:00
if ( ref $ href1 - > { $ key } eq 'HASH' )
2017-05-02 04:41:12 +00:00
{
2017-05-27 05:23:34 +00:00
$ self - > _add_hash_reference ( $ href1 - > { $ key } , $ href2 - > { $ key } ) ;
2017-05-02 04:41:12 +00:00
}
2017-05-27 05:23:34 +00:00
else
2017-05-02 04:41:12 +00:00
{
2017-05-27 05:23:34 +00:00
$ href1 - > { $ key } = $ href2 - > { $ key } ;
2017-05-02 04:41:12 +00:00
}
}
2017-05-27 05:23:34 +00:00
}
2017-07-07 05:54:49 +00:00
= head2 _hostname
This returns the ( full ) hostname for the machine this is running on .
= cut
sub _hostname
{
my $ self = shift ;
2017-10-20 04:19:32 +00:00
my $ anvil = $ self ;
2017-07-07 05:54:49 +00:00
my $ hostname = "" ;
if ( $ ENV { HOSTNAME } )
{
# We have an environment variable, so use it.
$ hostname = $ ENV { HOSTNAME } ;
}
else
{
# The environment variable isn't set. Call 'hostname' on the command line.
2017-10-20 04:19:32 +00:00
$ hostname = $ anvil - > System - > call ( { shell_call = > $ anvil - > data - > { path } { exe } { hostname } } ) ;
2017-07-07 05:54:49 +00:00
}
return ( $ hostname ) ;
}
2017-06-04 04:40:17 +00:00
= head2 _get_hash_reference
2017-10-20 04:19:32 +00:00
This is called when we need to parse a double - colon separated string into two or more elements which represent keys in the 'C<< $anvil->data >>' hash . Once suitably split up , the value is read and returned .
2017-06-04 04:40:17 +00:00
For example ;
2017-10-20 04:19:32 +00:00
$ anvil - > data - > { foo } { bar } = "baz" ;
my $ value = $ anvil - > _get_hash_reference ( { key = > "foo::bar" } ) ;
2017-06-04 04:40:17 +00:00
The 'C<< $value >>' now contains "C<< baz >>" .
NOTE: If the key is not found , 'C<< undef >>' is returned .
Parameters ;
= head3 key ( required )
This is the key to return the value for . If it is not passed , or if it does not have 'C<< :: >>' in it , 'C<< undef >>' will be returned .
= cut
sub _get_hash_reference
{
# 'href' is the hash reference I am working on.
my $ self = shift ;
my $ parameter = shift ;
2017-10-20 04:19:32 +00:00
my $ anvil = $ self ;
2017-06-04 04:40:17 +00:00
#print "$THIS_FILE ".__LINE__."; hash: [".$an."], key: [$parameter->{key}]\n";
die "$THIS_FILE " . __LINE__ . "; The hash key string: [$parameter->{key}] doesn't seem to be valid. It should be a string in the format 'foo::bar::baz'.\n" if $ parameter - > { key } !~ /::/ ;
# Split up the keys.
my $ key = $ parameter - > { key } ? $ parameter - > { key } : "" ;
my $ value = undef ; # We return 'undef' so that the caller can tell the difference between an empty string versus nothing found.
if ( $ key =~ /::/ )
{
my @ keys = split /::/ , $ key ;
my $ last_key = pop @ keys ;
# Re-order the array.
2017-10-20 04:19:32 +00:00
my $ current_hash_ref = $ anvil - > data ;
2017-06-04 04:40:17 +00:00
foreach my $ key ( @ keys )
{
$ current_hash_ref = $ current_hash_ref - > { $ key } ;
}
$ value = $ current_hash_ref - > { $ last_key } ;
}
return ( $ value ) ;
}
2017-05-27 05:23:34 +00:00
= head2 _make_hash_reference
This takes a string with double - colon seperators and divides on those double - colons to create a hash reference where each element is a hash key .
NOTE: Contributed by Shaun Fryer and Viktor Pavlenko by way of Toronto Perl Mongers .
= cut
sub _make_hash_reference
{
my $ self = shift ;
my $ href = shift ;
my $ key_string = shift ;
my $ value = shift ;
my @ keys = split /::/ , $ key_string ;
my $ last_key = pop @ keys ;
my $ _href = { } ;
$ _href - > { $ last_key } = $ value ;
while ( my $ key = pop @ keys )
{
my $ elem = { } ;
$ elem - > { $ key } = $ _href ;
$ _href = $ elem ;
}
$ self - > _add_hash_reference ( $ href , $ _href ) ;
}
= head2 _set_defaults
This sets default variable values for the program .
= cut
sub _set_defaults
{
2017-10-20 04:19:32 +00:00
my ( $ anvil ) = shift ;
2017-05-27 05:23:34 +00:00
2017-10-20 04:19:32 +00:00
$ anvil - > data - > { sys } = {
2017-08-17 17:40:15 +00:00
daemons = > {
restart_firewalld = > 1 ,
} ,
2017-08-02 01:36:57 +00:00
database = > {
2017-08-23 06:45:10 +00:00
archive = > {
compress = > 1 ,
count = > 50000 ,
2017-10-20 04:19:32 +00:00
directory = > "/usr/local/anvil/archives/" ,
2017-08-23 06:45:10 +00:00
division = > 6000 ,
trigger = > 100000 ,
} ,
2017-10-20 04:19:32 +00:00
# grep 'CREATE TABLE' tools/anvil.sql | grep -v history. | awk '{print $3}' | sort
2017-08-18 06:09:35 +00:00
core_tables = > [
"alerts" ,
"alert_sent" ,
2017-10-20 04:19:32 +00:00
"bonds" ,
"bridges" ,
"hosts" ,
"host_variable" ,
"network_interfaces" ,
2017-08-18 06:09:35 +00:00
"states" ,
2017-08-19 06:40:14 +00:00
"updated" ,
2017-10-20 04:19:32 +00:00
"variables" ,
2017-08-18 06:09:35 +00:00
] ,
2017-08-02 01:36:57 +00:00
local_lock_active = > 0 ,
locking_reap_age = > 300 ,
log_transactions = > 0 ,
maximum_batch_size = > 25000 ,
} ,
host_type = > "" ,
use_base2 = > 1 ,
} ;
2017-10-20 04:19:32 +00:00
$ anvil - > data - > { defaults } = {
2017-07-24 06:28:11 +00:00
database = > {
locking = > {
reap_age = > 300 ,
}
} ,
2017-06-11 07:00:35 +00:00
language = > {
2017-06-04 04:40:17 +00:00
# Default language for all output shown to a user.
2017-05-27 05:23:34 +00:00
output = > 'en_CA' ,
} ,
2017-06-04 04:40:17 +00:00
limits = > {
# This is the maximum number of times we're allow to loop when injecting variables
2017-10-20 04:19:32 +00:00
# into a string being processed in Anvil::Tools::Words->string();
2017-06-04 04:40:17 +00:00
string_loops = > 1000 ,
2017-06-05 12:02:14 +00:00
} ,
'log' = > {
db_transactions = > 0 ,
2017-06-07 15:36:06 +00:00
facility = > "local0" ,
2017-06-05 12:02:14 +00:00
language = > "en_CA" ,
level = > 1 ,
secure = > 0 ,
2017-06-07 15:36:06 +00:00
server = > "" ,
2017-10-20 04:19:32 +00:00
tag = > "anvil" ,
2017-06-05 12:02:14 +00:00
} ,
2017-07-20 06:00:40 +00:00
sql = > {
test_table = > "hosts" ,
} ,
2017-06-09 08:29:25 +00:00
template = > {
html = > "alteeve" ,
} ,
2017-05-27 05:23:34 +00:00
} ;
2017-05-02 04:41:12 +00:00
return ( 0 ) ;
}
= head2 _set_paths
This sets default paths to many system commands , checking to make sure the binary exists at the path and , if not , try to find it .
= cut
sub _set_paths
{
2017-10-20 04:19:32 +00:00
my ( $ anvil ) = shift ;
2017-05-02 04:41:12 +00:00
# Executables
2017-10-20 04:19:32 +00:00
$ anvil - > data - > { path } = {
2017-08-02 01:04:35 +00:00
configs = > {
2017-08-09 05:04:25 +00:00
'firewalld.conf' = > "/etc/firewalld/firewalld.conf" ,
2017-10-04 06:11:03 +00:00
'journald_an' = > "/etc/systemd/journald.conf.d/an.conf" ,
2017-06-20 02:32:35 +00:00
'pg_hba.conf' = > "/var/lib/pgsql/data/pg_hba.conf" ,
'postgresql.conf' = > "/var/lib/pgsql/data/postgresql.conf" ,
2017-07-07 05:54:49 +00:00
ssh_config = > "/etc/ssh/ssh_config" ,
2017-10-20 04:19:32 +00:00
'anvil.conf' = > "/etc/anvil/anvil.conf" ,
2017-07-07 05:54:49 +00:00
} ,
2017-08-02 01:04:35 +00:00
data = > {
2017-09-27 07:24:27 +00:00
group = > "/etc/group" ,
host_uuid = > "/etc/an/host.uuid" ,
2017-07-07 05:54:49 +00:00
passwd = > "/etc/passwd" ,
2017-06-20 02:32:35 +00:00
} ,
2017-08-02 01:04:35 +00:00
directories = > {
2017-10-20 04:19:32 +00:00
backups = > "/usr/sbin/anvil/backups" ,
2017-06-11 07:00:35 +00:00
'cgi-bin' = > "/var/www/cgi-bin" ,
2017-08-09 05:04:25 +00:00
firewalld_services = > "/usr/lib/firewalld/services" ,
2017-08-16 06:49:48 +00:00
firewalld_zones = > "/etc/firewalld/zones" ,
2017-06-11 07:00:35 +00:00
html = > "/var/www/html" ,
2017-06-10 06:38:04 +00:00
skins = > "/var/www/html/skins" ,
2017-10-20 04:19:32 +00:00
tools = > "/usr/sbin/anvil" ,
2017-06-10 06:38:04 +00:00
units = > "/usr/lib/systemd/system" ,
} ,
2017-08-02 01:04:35 +00:00
exe = > {
2017-10-20 15:13:00 +00:00
'anvil-prep-database' = > "/usr/sbin/anvil/anvil-prep-database" ,
'anvil-update-states' = > "/usr/sbin/anvil/anvil-update-states" ,
2017-10-20 04:19:32 +00:00
'anvil-report-memory' = > "/usr/sbin/anvil-report-memory" ,
2017-06-11 07:00:35 +00:00
'chmod' = > "/usr/bin/chmod" ,
'chown' = > "/usr/bin/chown" ,
2017-06-20 02:32:35 +00:00
cp = > "/usr/bin/cp" ,
createdb = > "/usr/bin/createdb" ,
createuser = > "/usr/bin/createuser" ,
2017-06-07 16:15:03 +00:00
dmidecode = > "/usr/sbin/dmidecode" ,
2017-06-20 02:32:35 +00:00
echo = > "/usr/bin/echo" ,
2017-09-22 04:56:35 +00:00
ethtool = > "/usr/sbin/ethtool" ,
2017-08-07 16:47:32 +00:00
'firewall-cmd' = > "/usr/bin/firewall-cmd" ,
2017-05-10 19:01:36 +00:00
gethostip = > "/usr/bin/gethostip" ,
2017-06-20 02:32:35 +00:00
hostname = > "/usr/bin/hostname" ,
2017-06-13 21:08:38 +00:00
ip = > "/usr/sbin/ip" ,
2017-08-17 07:07:45 +00:00
'iptables-save' = > "/usr/sbin/iptables-save" ,
2017-06-22 00:09:22 +00:00
journalctl = > "/usr/bin/journalctl" ,
2017-06-07 15:36:06 +00:00
logger = > "/usr/bin/logger" ,
2017-12-07 23:42:48 +00:00
md5sum = > "/usr/bin/md5sum" ,
2017-06-11 07:00:35 +00:00
'mkdir' = > "/usr/bin/mkdir" ,
2017-07-07 05:54:49 +00:00
ping = > "/usr/bin/ping" ,
2017-08-02 01:04:35 +00:00
pgrep = > "/usr/bin/pgrep" ,
2017-06-20 02:32:35 +00:00
psql = > "/usr/bin/psql" ,
'postgresql-setup' = > "/usr/bin/postgresql-setup" ,
2017-12-08 22:04:36 +00:00
pwd = > "/usr/bin/pwd" ,
2017-06-20 02:32:35 +00:00
su = > "/usr/bin/su" ,
systemctl = > "/usr/bin/systemctl" ,
2017-08-02 07:00:08 +00:00
touch = > "/usr/bin/touch" ,
timeout = > "/usr/bin/timeout" ,
2017-06-23 02:57:51 +00:00
uuidgen = > "/usr/bin/uuidgen" ,
2017-06-20 02:32:35 +00:00
} ,
2017-08-02 01:04:35 +00:00
'lock' = > {
2017-10-20 04:19:32 +00:00
database = > "/tmp/anvil-tools.database.lock" ,
2017-08-02 01:04:35 +00:00
} ,
2017-06-20 02:32:35 +00:00
secure = > {
postgres_pgpass = > "/var/lib/pgsql/.pgpass" ,
2017-05-10 19:01:36 +00:00
} ,
2017-06-10 06:38:04 +00:00
sysfs = > {
network_interfaces = > "/sys/class/net" ,
} ,
2017-07-20 06:00:40 +00:00
sql = > {
2017-10-20 04:19:32 +00:00
'anvil.sql' = > "/usr/sbin/anvil/anvil.sql" ,
2017-07-20 06:00:40 +00:00
} ,
2017-06-12 18:39:20 +00:00
urls = > {
skins = > "/skins" ,
} ,
2017-05-10 19:01:36 +00:00
words = > {
2017-10-20 04:19:32 +00:00
'words.xml' = > "/usr/sbin/anvil/words.xml" ,
2017-05-10 19:01:36 +00:00
} ,
2017-05-02 04:41:12 +00:00
} ;
2017-05-10 19:01:36 +00:00
# Make sure we actually have the requested files.
2017-10-20 04:19:32 +00:00
foreach my $ type ( sort { $ a cmp $ b } keys % { $ anvil - > data - > { path } } )
2017-05-02 04:41:12 +00:00
{
2017-06-12 18:39:20 +00:00
# We don't look for urls because they're relative to the domain.
next if $ type eq "urls" ;
2017-10-20 04:19:32 +00:00
foreach my $ file ( sort { $ a cmp $ b } keys % { $ anvil - > data - > { path } { $ type } } )
2017-05-02 04:41:12 +00:00
{
2017-10-20 04:19:32 +00:00
if ( not - e $ anvil - > data - > { path } { $ type } { $ file } )
2017-05-02 04:41:12 +00:00
{
2017-10-20 04:19:32 +00:00
my $ full_path = $ anvil - > Storage - > find ( { file = > $ file } ) ;
2017-06-20 02:32:35 +00:00
if ( ( $ full_path ) && ( $ full_path ne "#!not_found!#" ) )
2017-05-10 19:01:36 +00:00
{
2017-10-20 04:19:32 +00:00
$ anvil - > data - > { path } { $ type } { $ file } = $ full_path ;
2017-05-10 19:01:36 +00:00
}
2017-05-02 04:41:12 +00:00
}
}
2017-06-09 08:29:25 +00:00
} ;
2017-05-02 04:41:12 +00:00
return ( 0 ) ;
}
2017-07-07 05:54:49 +00:00
= head3 _short_hostname
This returns the short hostname for the machine this is running on . That is to say , the hostname up to the first '.' .
= cut
sub _short_hostname
{
2017-10-20 04:19:32 +00:00
my $ self = shift ;
my $ anvil = $ self ;
2017-07-07 05:54:49 +00:00
2017-10-20 04:19:32 +00:00
my $ short_host_name = $ anvil - > _hostname ;
2017-07-07 05:54:49 +00:00
$ short_host_name =~ s/\..*$// ;
return ( $ short_host_name ) ;
}
2017-05-02 04:41:12 +00:00
= head1 Exit Codes
= head2 C <1>
2017-10-20 04:19:32 +00:00
Anvil::Tools - > new ( ) passed something other than a hash reference .
2017-05-02 04:41:12 +00:00
= head2 C <2>
2017-10-20 04:19:32 +00:00
Failed to find the requested file in C << Anvil::Tools::Storage - > find >> and 'fatal' was set .
2017-05-02 04:41:12 +00:00
= head1 Requirements
The following packages are required on EL7 .
* C <expect>
* C <httpd>
* C <mailx>
* C <perl-Test-Simple>
* C <policycoreutils-python>
* C <postgresql>
* C <syslinux>
2017-05-27 05:23:34 +00:00
* C <perl-XML-Simple>
2017-05-02 04:41:12 +00:00
= head1 Recommended Packages
The following packages provide non - critical functionality .
* C <subscription-manager>
= cut
2017-08-17 21:16:45 +00:00
# This catches SIGINT and SIGTERM and fires out an email before shutting down.
sub catch_sig
{
my $ self = shift ;
my $ parameter = shift ;
2017-10-20 04:19:32 +00:00
my $ anvil = $ self ;
2017-08-17 21:16:45 +00:00
my $ signal = $ parameter - > { signal } ? $ parameter - > { signal } : "" ;
if ( $ signal )
{
print "Process with PID: [$$] exiting on SIG" . $ signal . ".\n" ;
}
2017-10-20 04:19:32 +00:00
$ anvil - > nice_exit ( { code = > 255 } ) ;
2017-08-17 21:16:45 +00:00
}
2017-05-02 04:41:12 +00:00
1 ;