package WebGUI::Operation::Spectre; #------------------------------------------------------------------- # 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 #------------------------------------------------------------------- use strict; use JSON; use POE::Component::IKC::ClientLite; use WebGUI::Utility; use WebGUI::Workflow::Cron; use WebGUI::Workflow::Instance; =head1 NAME Package WebGUI::Operation::Spectre =head1 DESCRIPTION Operations for Spectre. =cut #---------------------------------------------------------------------------- =head2 canView ( session [, user] ) Returns true if the user can administrate this operation. user defaults to the current user. =cut sub canView { my $session = shift; my $user = shift || $session->user; return $user->isInGroup( $session->setting->get("groupIdAdminSpectre") ); } #------------------------------------------------------------------- =head2 www_spectreGetSiteData ( ) Checks to ensure the requestor is who we think it is, and then returns a JSON string with worklfow and cron data. We do it in one payload for efficiency. =cut sub www_spectreGetSiteData { my $session = shift; $session->http->setMimeType("application/json"); $session->http->setCacheControl("none"); my %siteData = (); my $subnets = $session->config->get("spectreSubnets"); if (!defined $subnets) { $subnets = []; } if (!isInSubnet($session->env->getIp, $subnets)) { $session->errorHandler->security("Tried to make a Spectre workflow data load request, but we're only allowed to accept requests from " .join(",",@{$subnets})."."); } else { my $sitename = $session->config->get("sitename")->[0]; my $gateway = $session->config->get("gateway"); my $cookieName = $session->config->getCookieName; my @instances = (); foreach my $instance (@{WebGUI::Workflow::Instance->getAllInstances($session)}) { next unless $instance->getWorkflow && $instance->getWorkflow->get("enabled"); push(@instances, { instanceId => $instance->getId, priority => $instance->get("priority"), cookieName => $cookieName, gateway => $gateway, sitename => $sitename, }); } $siteData{workflow} = \@instances; my @schedules = (); foreach my $task (@{WebGUI::Workflow::Cron->getAllTasks($session)}) { next unless $task->get("enabled"); push(@schedules, { taskId => $task->getId, cookieName => $cookieName, gateway => $gateway, sitename => $sitename, minuteOfHour => $task->get('minuteOfHour'), hourOfDay => $task->get('hourOfDay'), dayOfMonth => $task->get('dayOfMonth'), monthOfYear => $task->get('monthOfYear'), dayOfWeek => $task->get('dayOfWeek'), runOnce => $task->get('runOnce'), }); } $siteData{cron} = \@schedules; } return JSON::to_json(\%siteData); } #------------------------------------------------------------------- =head2 www_spectreStatus ( ) Show information about Spectre's current workload. =cut sub www_spectreStatus { my $session = shift; return $session->privilege->adminOnly unless canView($session); # start to prepare the display my $ac = WebGUI::AdminConsole->new($session, 'spectre'); my $i18n = WebGUI::International->new($session, 'Spectre'); $session->http->setCacheControl("none"); my $remote = POE::Component::IKC::ClientLite->spawn( port=>$session->config->get("spectrePort"), ip=>$session->config->get("spectreIp"), name=>rand(100000), timeout=>10 ); if (!$remote) { return $ac->render($i18n->get('not running'), $i18n->get('spectre')); } my $sitename = $session->config()->get('sitename')->[0]; my $workflowResult = $remote->post_respond('workflow/getJsonStatus',$sitename); if (!$workflowResult) { $remote->disconnect(); return $ac->render($i18n->get('workflow status error'), $i18n->get('spectre')); } my $cronResult = $remote->post_respond('cron/getJsonStatus',$sitename); if (! defined $cronResult) { $remote->disconnect(); return $ac->render($i18n->get('cron status error'), $i18n->get('spectre')); } my %data = ( workflow => decode_json($workflowResult), cron => decode_json($cronResult), ); my $workflowCount = @{ $data{workflow}{Suspended} } + @{ $data{workflow}{Waiting} } + @{ $data{workflow}{Running} }; my $workflowUrl = $session->url->page('op=showRunningWorkflows'); my $cronCount = keys %{ $data{cron} }; my $cronUrl = $session->url->page('op=manageCron'); my $output = $i18n->get('running').'
'; $output .= sprintf $i18n->get('workflow header'), $workflowUrl, $workflowCount; $output .= sprintf $i18n->get('cron header'), $cronUrl, $cronCount; return $ac->render($output, $i18n->get('spectre')); } #------------------------------------------------------------------- =head2 www_spectreTest ( ) Spectre executes this function to see if WebGUI connectivity is working. Note, the subnet checking is done in here because it is only, ever intended that Spectre use this method. If a user were to call this method, it would lie, since it would be checking if the user's IP address was a valid spectreSubnet, instead of checking the IP address of the spectre process. =cut sub www_spectreTest { my $session = shift; $session->http->setMimeType("text/plain"); $session->http->setCacheControl("none"); my $subnets = $session->config->get("spectreSubnets"); if (!defined $subnets) { $subnets = []; } my $sessionIp = $session->env->getIp; unless (isInSubnet($sessionIp, $subnets)) { $session->errorHandler->security( sprintf "Tried to make a Spectre workflow runner request from %s, but we're only allowed to accept requests from %s", $sessionIp, join(",",@{$subnets}) ); return "subnet"; } return WebGUI::Operation::Spectre::spectreTest($session); } #------------------------------------------------------------------- =head2 spectreTest ( ) Spectre executes this function to see if WebGUI connectivity is working. It does not do subnet checking, yet. =cut sub spectreTest{ my $session = shift; my $remote = POE::Component::IKC::ClientLite->spawn( port=>$session->config->get("spectrePort"), ip=>$session->config->get("spectreIp"), name=>rand(100000), timeout=>10 ); # Can't perform this test until I get smarter. =) return "spectre" unless defined $remote; my $result = $remote->post_respond('admin/ping'); $remote->disconnect; return "spectre" unless defined $result; ##A real spectre subnet test would go here, and would consist of the following ##events: ## 1) WebGUI talks to spectre. ## 2) Spectre makes a request of WebGUI ## 3) WebGUI returns a token or an error ## 4) spectre returns the result of the request to WebGUI ## 5) WebGUI lets the user know how it all ended up. return "success"; } 1;