Clustericious-Admin

 view release on metacpan or  search on metacpan

lib/Clustericious/Admin/Server.pm  view on Meta::CPAN

  #     print out extra diagnostics
  #
  #   version: required number or 'dev'
  #     the client version
  #
  #   require: optional, number or 'dev'
  #     specifies the minimum required server
  #     server should die if requirement isn't met
  #     ignored if set to 'dev'
  #
  #   files: optional list of hashref   [ 1.01 ]
  #     each hashref has:
  #       name: the file basename (no directory)
  #       content: the content of the file
  #       mode: (optional) octal unix permission mode as a string (ie "0755" or "0644")
  #       env: (optional) environment variable to use instead of FILEx
  #
  #   dir: optional hash of hash        [ 1.02 ]
  #     each key is a path
  #       each value is a hash
  #         is_dir
  #         content
  #         mode
  #
  #   stdin: optional scalar            [ 1.04 ]

  if(ref $payload->{command} ne 'ARRAY' || @{ $payload->{command} } == 0)
  {
    print STDERR "Clad Server: Unable to find command\n";
    return 2;
  }
  
  if(defined $payload->{env} && ref $payload->{env} ne 'HASH')
  {
    print STDERR "Clad Server: env is not hash\n";
    return 2;
  }
  
  unless($payload->{version})
  {
    print STDERR "Clad Server: no client version\n";
    return 2;
  }
  
  if($payload->{require} && defined $Clustericious::Admin::Server::VERSION)
  {
    if($payload->{require} ne 'dev' && $payload->{require} > $Clustericious::Admin::Server::VERSION)
    {
      print STDERR "Clad Server: client requested version @{[ $payload->{require} ]} but this is only $Clustericious::Admin::Server::VERSION\n";
      return 2;
    }
  }

  if($payload->{files})
  {
    my $count = 1;
    foreach my $file (@{ $payload->{files} })
    {
      my $path = File::Spec->catfile( tempdir( CLEANUP => 1 ), $file->{name} );
      open my $fh, '>', $path;
      chmod oct($file->{mode}), $path if defined $file->{mode};
      binmode $fh;
      print $fh $file->{content};
      close $fh;
      my $env = $file->{env};
      $env = "FILE@{[ $count++ ]}" unless defined $env;
      $ENV{$env} = $path;
    }
  }
  
  if($payload->{dir})
  {
    my $root = $ENV{DIR} = tempdir( CLEANUP => 1 );
    
    foreach my $name (sort keys %{ $payload->{dir} })
    {
      my $dir = $payload->{dir}->{$name};
      next unless $dir->{is_dir};
      my $path = File::Spec->catdir($root, $name);
      mkdir $path;
      chmod oct($dir->{mode}), $path if defined $dir->{mode};
    }
    
    foreach my $name (sort keys %{ $payload->{dir} })
    {
      my $file = $payload->{dir}->{$name};
      next if $file->{is_dir};
      my $path = File::Spec->catfile($root, $name);
      open my $fh, '>', $path;
      chmod oct($file->{mode}), $fh if defined $file->{mode};
      binmode $fh;
      print $fh $file->{content};
      close $fh;
    }
  }

  $ENV{$_} = $payload->{env}->{$_} for keys %{ $payload->{env} };
  
  if(defined $payload->{stdin})
  {
    my $filename = File::Spec->catfile(tempdir(CLEANUP => 1), 'stdin.txt');
    open OUT, ">$filename"; 
    print OUT $payload->{stdin};
    close OUT;
    open STDIN, "<$filename";
  }
  
  system @{ $payload->{command} };
  
  if($? == -1)
  {
    print STDERR "Clad Server: failed to execute on @{[ hostname ]}\n";
    return 2;
  }
  elsif($? & 127)
  {
    print STDERR "Clad Server: died with signal @{[ $? & 127 ]} on @{[ hostname ]}\n";
    return 2;
  }
  
  return $? >> 8;
}

exit __PACKAGE__->_server(*DATA) unless caller;

1;

=pod

=encoding UTF-8

=head1 NAME

Clustericious::Admin::Server - Parallel SSH client server side code

=head1 VERSION

version 1.11

=head1 SYNOPSIS

 % perldoc clad

=head1 DESCRIPTION

This module provides part of the implementation for the
L<clad> command.  See the L<clad> command for the public
interface.

=head1 SEE ALSO



( run in 0.445 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )