Add guantanamo: a way to execute command in an unknown environnement
This commit is contained in:
parent
b951c4dc04
commit
8ef18c4a3f
3 changed files with 307 additions and 1 deletions
|
@ -320,6 +320,30 @@ sub getFirstChild ($)
|
||||||
return $self->{children}[0];
|
return $self->{children}[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub recreateNode
|
||||||
|
{
|
||||||
|
my $self = shift;
|
||||||
|
my $doc = shift;
|
||||||
|
my $parent = shift;
|
||||||
|
|
||||||
|
my $node = $doc->createElement($self->{nodeName});
|
||||||
|
for my $attkey (keys %{ $self->{attributes} })
|
||||||
|
{
|
||||||
|
$node->addChild( $doc->createAttribute($attkey, $self->{attributes}{ $attkey }) );
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $child (@{ $self->{children} })
|
||||||
|
{
|
||||||
|
$child->recreateNode($doc, $node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($self->{nodeValue}) {
|
||||||
|
$node->appendText( $self->{nodeValue} );
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent->appendChild($node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
package ProcessHandler;
|
package ProcessHandler;
|
||||||
|
|
||||||
|
@ -399,7 +423,6 @@ sub end_element
|
||||||
{
|
{
|
||||||
my $item = pop @{ $self->{subtreeStack} };
|
my $item = pop @{ $self->{subtreeStack} };
|
||||||
$item->{nodeValue} .= $self->{values};
|
$item->{nodeValue} .= $self->{values};
|
||||||
$item->{nodeValue} =~ s/\n+/ /g;
|
|
||||||
$item->{nodeValue} =~ s/ +/ /g;
|
$item->{nodeValue} =~ s/ +/ /g;
|
||||||
if (@{ $self->{subtreeStack} } > 0) {
|
if (@{ $self->{subtreeStack} } > 0) {
|
||||||
push @{ $self->{subtreeStack}[-1]->{children} }, $item;
|
push @{ $self->{subtreeStack}[-1]->{children} }, $item;
|
||||||
|
|
175
process/exec/guantanamo.pl
Normal file
175
process/exec/guantanamo.pl
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use v5.10.1;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Gearman::Worker;
|
||||||
|
use MIME::Base64;
|
||||||
|
use XML::LibXML;
|
||||||
|
|
||||||
|
use ACU::LDAP;
|
||||||
|
use ACU::Log;
|
||||||
|
use ACU::Process;
|
||||||
|
|
||||||
|
my %master_actions =
|
||||||
|
(
|
||||||
|
"launch" => \&master_launch,
|
||||||
|
"register" => \&master_register,
|
||||||
|
);
|
||||||
|
|
||||||
|
my @nodes;
|
||||||
|
|
||||||
|
sub master_register
|
||||||
|
{
|
||||||
|
my $args = shift;
|
||||||
|
|
||||||
|
if ($args->{param}{nodename}) {
|
||||||
|
my $nodename = $args->{param}{nodename};
|
||||||
|
|
||||||
|
log INFO, "New node: $nodename";
|
||||||
|
push @nodes, "$nodename";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log WARN, "nodename empty, cannot register new node";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub build_task_xml
|
||||||
|
{
|
||||||
|
my $files = shift;
|
||||||
|
my $subtree = shift;
|
||||||
|
|
||||||
|
my $doc = XML::LibXML::Document->new('1.0');
|
||||||
|
my $root = $doc->createElement("guantanamo");
|
||||||
|
$doc->setDocumentElement( $root );
|
||||||
|
|
||||||
|
log TRACE, $subtree;
|
||||||
|
|
||||||
|
if ($files)
|
||||||
|
{
|
||||||
|
log TRACE, $files;
|
||||||
|
|
||||||
|
for my $key (keys %{ $files })
|
||||||
|
{
|
||||||
|
my $file = $doc->createElement("file");
|
||||||
|
$file->addChild( $doc->createAttribute("name", $key) );
|
||||||
|
$file->addChild( $doc->createAttribute("encoding", "base64") );
|
||||||
|
$file->appendText(encode_base64($files->{$key}));
|
||||||
|
$root->appendChild($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($subtree) {
|
||||||
|
$subtree->recreateNode($doc, $root);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $ret = $doc->toString();
|
||||||
|
log TRACE, $ret;
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub master_launch
|
||||||
|
{
|
||||||
|
my $args = shift;
|
||||||
|
|
||||||
|
my @lnodes;
|
||||||
|
my @warn;
|
||||||
|
|
||||||
|
if ($args->{unamed})
|
||||||
|
{
|
||||||
|
for (my $i = $args->{unamed}; $i > 0; $i--)
|
||||||
|
{
|
||||||
|
if (grep { $args->{param}{$i} eq $_ } @nodes) {
|
||||||
|
push @lnodes, $args->{param}{$i};
|
||||||
|
} else {
|
||||||
|
push @warn, $args->{param}{$i}." not a currently launched architecture.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@lnodes = @nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
log DEBUG, "Launching nodes...";
|
||||||
|
|
||||||
|
my %ret;
|
||||||
|
|
||||||
|
my $client = Gearman::Client->new;
|
||||||
|
$client->job_servers('gearmand:4730');
|
||||||
|
my $taskset = $client->new_task_set;
|
||||||
|
for my $node (@lnodes)
|
||||||
|
{
|
||||||
|
log DEBUG, "Launching $node...";
|
||||||
|
|
||||||
|
$taskset->add_task(
|
||||||
|
"guantanamo_".$node => build_task_xml($args->{files}, $args->{subtree}),
|
||||||
|
{
|
||||||
|
on_complete => sub {
|
||||||
|
my $dom = XML::LibXML->load_xml(string => ${ $_[0] });
|
||||||
|
$ret{ $node } = $dom;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$taskset->wait;
|
||||||
|
|
||||||
|
if ($args->{subtree}->hasAttribute("output") && $args->{subtree}->getAttribute("output") eq "text")
|
||||||
|
{
|
||||||
|
my $output = "";
|
||||||
|
|
||||||
|
for my $w (@warn) {
|
||||||
|
$output .= $w."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $node (@lnodes) {
|
||||||
|
my $o = $ret{$node}->documentElement->getElementsByTagName("out");
|
||||||
|
if ($o) {
|
||||||
|
$output .= $o[0]->firstChild->nodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$e = $ret{$node}->documentElement->getElementsByTagName("err");
|
||||||
|
if ($e) {
|
||||||
|
$output .= $e[0]->firstChild->nodeValue;
|
||||||
|
}
|
||||||
|
$output .= $e[0]->firstChild->nodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
my $doc = XML::LibXML::Document->new('1.0');
|
||||||
|
my $root = $doc->createElement("process");
|
||||||
|
$doc->setDocumentElement( $root );
|
||||||
|
|
||||||
|
for my $w (@warn)
|
||||||
|
{
|
||||||
|
my $warning = $doc->createElement("warning");
|
||||||
|
$warning->appendText($w);
|
||||||
|
$root->appendChild($warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $k (keys %ret)
|
||||||
|
{
|
||||||
|
$root->appendChild($ret{ $k }->documentElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $doc->toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub process_master
|
||||||
|
{
|
||||||
|
my ($given_args, $args) = @_;
|
||||||
|
|
||||||
|
my $action = $args->{param}{action} // "launch";
|
||||||
|
|
||||||
|
if (! exists $master_actions{$action}) {
|
||||||
|
log WARN, "Unknown action '$action' for guantanamo master process.";
|
||||||
|
}
|
||||||
|
return $master_actions{$action}($args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
log INFO, "Starting guantanamo.pl as master process";
|
||||||
|
|
||||||
|
Process::register("guantanamo", \&process_master);
|
108
process/exec/guantanamo_node.pl
Normal file
108
process/exec/guantanamo_node.pl
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use v5.10.1;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Carp;
|
||||||
|
use File::Path qw(make_path remove_tree);
|
||||||
|
use File::Temp qw/tempfile tempdir/;
|
||||||
|
use IPC::Open3;
|
||||||
|
use XML::LibXML;
|
||||||
|
|
||||||
|
use ACU::LDAP;
|
||||||
|
use ACU::Log;
|
||||||
|
use ACU::Process;
|
||||||
|
|
||||||
|
my %node_actions =
|
||||||
|
(
|
||||||
|
"launch" => \&node_launch,
|
||||||
|
);
|
||||||
|
|
||||||
|
sub node_launch
|
||||||
|
{
|
||||||
|
my $args = shift;
|
||||||
|
|
||||||
|
# First, create a temporary directory
|
||||||
|
my $dir = tempdir();
|
||||||
|
chdir( $dir );
|
||||||
|
|
||||||
|
# Extract all files to current directory
|
||||||
|
for my $filename (keys %{ $args->{files} })
|
||||||
|
{
|
||||||
|
open my $fh, ">", $filename or croak("$filename: $!");
|
||||||
|
print $fh $args->{files}{$filename};
|
||||||
|
close $fh;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $doc = XML::LibXML::Document->new('1.0');
|
||||||
|
my $root = $doc->createElement("target");
|
||||||
|
$root->addChild( $doc->createAttribute("name", $ARGV[0]) );
|
||||||
|
$doc->setDocumentElement( $root );
|
||||||
|
|
||||||
|
for my $c ($args->{subtree}->getElementsByTagName("command"))
|
||||||
|
{
|
||||||
|
if (! exists $c->{attributes}{target} ||
|
||||||
|
index($c->{attributes}{target}, $ARGV[0]) != -1) {
|
||||||
|
|
||||||
|
my $cmd = $doc->createElement("cmd");
|
||||||
|
if (! exists $c->{attributes}{hide}) {
|
||||||
|
$root->appendChild($cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $command = $doc->createElement("command");
|
||||||
|
$command->appendText($c->{nodeValue});
|
||||||
|
$cmd->appendChild($command);
|
||||||
|
|
||||||
|
my($wtr, $rdr, $stderr);
|
||||||
|
my $pid = open3($wtr, $rdr, $stderr, $c->{nodeValue});
|
||||||
|
waitpid( $pid, 0 );
|
||||||
|
my $rv = $? >> 8;
|
||||||
|
|
||||||
|
my $out = $doc->createElement("out");
|
||||||
|
my $str = "";
|
||||||
|
if ($rdr) {
|
||||||
|
$str .= $_ while (<$rdr>);
|
||||||
|
}
|
||||||
|
$out->appendText($str);
|
||||||
|
$cmd->appendChild($out);
|
||||||
|
|
||||||
|
my $err = $doc->createElement("err");
|
||||||
|
$str = "";
|
||||||
|
if ($stderr) {
|
||||||
|
$str .= $_ while (<$stderr>);
|
||||||
|
}
|
||||||
|
$err->appendText($str);
|
||||||
|
$cmd->appendChild($err);
|
||||||
|
|
||||||
|
my $ret = $doc->createElement("return");
|
||||||
|
$ret->appendText($rv);
|
||||||
|
$cmd->appendChild($ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chdir();
|
||||||
|
remove_tree( $dir );
|
||||||
|
|
||||||
|
return $doc->toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub process_node
|
||||||
|
{
|
||||||
|
my ($given_args, $args) = @_;
|
||||||
|
|
||||||
|
my $action = $args->{param}{action} // "launch";
|
||||||
|
|
||||||
|
if (! exists $node_actions{$action}) {
|
||||||
|
log WARN, "Unknown action '$action' for guantanamo node process.";
|
||||||
|
}
|
||||||
|
return $node_actions{$action}($args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($#ARGV == 0)
|
||||||
|
{
|
||||||
|
log INFO, "Starting guantanamo.pl as node process";
|
||||||
|
|
||||||
|
Process::Client::launch("guantanamo", {"action" => "register", "nodename" => $ARGV[0]});
|
||||||
|
|
||||||
|
Process::register("guantanamo_".$ARGV[0], \&process_node);
|
||||||
|
}
|
Reference in a new issue