package Spectre::Admin; =head1 LEGAL ------------------------------------------------------------------- WebGUI is Copyright 2001-2009 Plain Black Corporation. ------------------------------------------------------------------- Please read the legal notices (docs/legal.txt) and the license (docs/license.txt) that came with this distribution before using this software. ------------------------------------------------------------------- http://www.plainblack.com info@plainblack.com ------------------------------------------------------------------- =cut use strict; use HTTP::Request; use JSON; use Log::Log4perl; use LWP::UserAgent; use POE; use POE::Component::IKC::Server; use POE::Component::IKC::Specifier; use Spectre::Cron; use Spectre::Workflow; #------------------------------------------------------------------- =head2 _safe_shutdown ( ) Stops the kernel when TERM signal is received =cut sub _safe_shutdown { my ($obj) = $_[ OBJECT ]; $obj->error('Spectre shut down'); POE::Kernel->stop; } #------------------------------------------------------------------- =head2 _start ( ) Initializes the admin interface. =cut sub _start { my ( $kernel, $self, $publicEvents) = @_[ KERNEL, OBJECT, ARG0 ]; $self->debug("Starting Spectre administrative manager."); my $serviceName = "admin"; $kernel->alias_set($serviceName); $kernel->call( IKC => publish => $serviceName, $publicEvents ); $kernel->delay_set("loadSiteData",3); $kernel->sig( TERM => '_safe_shutdown' ); } #------------------------------------------------------------------- =head2 config ( ) Returns a reference to the config object. =cut sub config { my $self = shift; return $self->{_config}; } #------------------------------------------------------------------- =head2 debug ( output ) Prints out debug information if debug is enabled. =head3 output The debug message to be printed if debug is enabled. =cut sub debug { my $self = shift; my $output = shift; if ($self->{_debug}) { print "ADMIN: ".$output."\n"; } $self->getLogger->debug("ADMIN: ".$output); } #------------------------------------------------------------------- =head2 error ( output ) Prints out error information. =head3 output The error message to be printed if debug is enabled. =cut sub error { my $self = shift; my $output = shift; print "ADMIN: [Error] ".$output."\n"; $self->getLogger->error("ADMIN: ".$output); } #------------------------------------------------------------------- =head2 getLogger ( ) Returns a reference to the logger. =cut sub getLogger { my $self = shift; return $self->{_logger}; } #------------------------------------------------------------------- =head2 loadSiteData ( ) Fetches the site from each defined site, and loads it into the Workflow and Cron governors. =cut sub loadSiteData { my ( $kernel, $self) = @_[ KERNEL, OBJECT ]; my $configs = WebGUI::Config->readAllConfigs($self->{_config}->getWebguiRoot); $self->debug("Reading site configs."); foreach my $key (keys %{$configs}) { next if $key =~ m/^demo/; $self->debug("Fetching site data for $key"); my $userAgent = new LWP::UserAgent; if (!$self->config->get('ignoreEnvProxy')) { $userAgent->env_proxy; } $userAgent->agent("Spectre"); $userAgent->timeout(30); my $url = "http://".$configs->{$key}->get("sitename")->[0].":".$self->{_config}->get("webguiPort").$configs->{$key}->get("gateway")."?op=spectreGetSiteData"; my $request = new HTTP::Request (GET => $url); my $response = $userAgent->request($request); if ($response->is_error) { $self->error( "Couldn't connect to WebGUI site $key at $url. Response: " . $response->status_line ); } else { my $siteData = {}; eval { $siteData = JSON::decode_json($response->content); }; if ($@) { $self->error("Couldn't fetch Spectre configuration data for $key : $@"); } else { $self->debug("Loading workflow data for $key"); foreach my $instance (@{$siteData->{workflow}}) { $kernel->post("workflow" ,"addInstance", $instance); } $self->debug("Loading scheduler data for $key"); foreach my $task (@{$siteData->{cron}}) { $task->{config} = $key; $kernel->post("cron", "addJob", $task); } } } } } #------------------------------------------------------------------- =head2 new ( config [ , debug ] ) Constructor. =head3 config A WebGUI::Config object that represents the spectre.conf file. =head3 debug A boolean indicating Spectre should spew forth debug as it runs. =cut sub new { my $class = shift; my $config = shift; my $debug = shift; Log::Log4perl->init( $config->getWebguiRoot."/etc/log.conf" ); $Log::Log4perl::caller_depth = $Log::Log4perl::caller_depth+3; my $logger = Log::Log4perl->get_logger($config->getFilename); my $self = {_debug=>$debug, _config=>$config, _logger=>$logger}; bless $self, $class; $self->debug("Trying to bind to ".$config->get("ip").":".$config->get("port")); create_ikc_server( ip => $config->get("ip"), port => $config->get("port"), name => 'Spectre' ); POE::Session->create( object_states => [ $self => {_start=>"_start", "ping"=>"ping", "loadSiteData"=>"loadSiteData", "_safe_shutdown" => "_safe_shutdown"} ], args=>[["ping"]] ); Spectre::Workflow->new($config, $logger, $debug); Spectre::Cron->new($config, $logger, $debug); POE::Kernel->run(); } #------------------------------------------------------------------- =head2 ping ( ) Check to see if Spectre is alive. Returns "pong". =cut sub ping { my ($kernel, $request) = @_[KERNEL,ARG0]; my ($data, $rsvp) = @$request; $kernel->call(IKC=>post=>$rsvp,"pong"); } #------------------------------------------------------------------- =head2 runTests ( ) Executes a test to see if Spectre can establish a connection to WebGUI and get back a valid response. This is a class method. =head3 config A WebGUI::Config object that represents the spectre.conf file. =cut sub runTests { my $class = shift; my $config = shift; print "Running connectivity tests.\n"; my $configs = WebGUI::Config->readAllConfigs($config->getWebguiRoot); foreach my $key (keys %{$configs}) { next if $key =~ m/^demo/; print "Testing $key\n"; my $userAgent = new LWP::UserAgent; if (!$config->get('ignoreEnvProxy')) { $userAgent->env_proxy; } $userAgent->agent("Spectre"); $userAgent->timeout(30); my $url = "http://".$configs->{$key}->get("sitename")->[0].":".$config->get("webguiPort").$configs->{$key}->get("gateway")."?op=spectreTest"; my $request = new HTTP::Request (GET => $url); my $response = $userAgent->request($request); if ($response->is_error) { print "ERROR: Couldn't connect to WebGUI site $key\n"; } else { my $response = $response->content; if ($response eq "subnet") { print "ERROR: Spectre cannot communicate with WebGUI. Perhaps you need to adjust the spectreSubnets setting in this config file: $key.\n"; } elsif ($response eq "spectre") { print "ERROR: WebGUI cannot communicate with Spectre. Perhaps you need to adjust the spectreIp or spectrePort setting the this config file: $key."; } elsif ($response ne "success") { print "ERROR: Spectre received an invalid response ($response) from WebGUI while testing $key\n"; } } } print "Tests completed.\n"; } 1;