Comprobando la Portabilidad del Código

Para comprobar la portabilidad del código establezca un sistema de autentificación automática via ssh usando pares de claves privada-pública entre la máquina en la que desarrolla y cada una de las máquinas en las que desea probar su aplicación.

Autentificación Automática

SSH es un protocolo de red y un conjunto de estándares que permiten una conexión encriptada entre dos computadoras. Usa criptografía de clave pública para autentificar al computador y al usuario. Por defecto suele usar el puerto TCP 22.

SSH soporta autentificación basada en RSA. RSA fué el primer algoritmo publicado que permite el encriptado y la firma digital. Se cree que es seguro si las claves son lo suficientemente largas. Se usa aún en comercio electrónico. Una opción alternativa es DSA que corresponde a Digital Signature Algorithm. DSA es propiedad del gobierno de los Estados Unidos de America.

Hay criptosistemas -a los que RSA pertenece - en los cuales el encriptado y desencriptado se hace utilizando claves separadas y no es posible derivar la clave de desencriptado del conocimiento de la clave de encriptado. El cliente utiliza un par de claves pública/privada para la autentificación. El servidor sólo conoce la clave pública. Funciona como una pareja llave/cerradura en la que el conocimiento de la cerradura no permite deducir la forma de la llave.

Generación de una Pareja de Claves Pública-Privada

Para la generación de una pareja de claves pública-privada se realiza ejecutando en el cliente ssh-keygen:

$ ssh-keygen  -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
The key fingerprint is:
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx user@machine

Las claves se almacenan por defecto en ~/.ssh/, quedando el directorio así:

$ ls -l
total 12
-rw-------  1 user user  883 2005-08-13 14:16 id_rsa
-rw-r--r--  1 user user  223 2005-08-13 14:16 id_rsa.pub
-rw-r--r--  1 user user 1344 2005-08-04 02:14 known_hosts

Los ficheros id_rsa e id_rsa.pub contienen respectivamente las claves privada y pública. El fichero known_hosts contiene la lista de las claves públicas de las máquinas reconocidas.

Transferencia de la Clave Pública al Servidor

Ahora se debe copiar la clave pública al servidor, al fichero ~/.ssh/authorized_keys. Para ello se utiliza el comando ssh-copy-id:

$ssh-copy-id -i ~/.ssh/id_rsa.pub user@machine1
$ssh-copy-id -i ~/.ssh/id_rsa.pub user@machine2

ssh-copy-id es un script que se conecta a la máquina y copia el archivo (indicado por la opción -i) en ~/.ssh/authorized_keys, y ajusta los permisos a los valores adecuados.

Si no se dispone del programa ssh-copy-id se puede realizar una copia manual a la máquina remota del fichero conteniendo la clave pública (por ejemplo usando scp o sftp) y añadir su contenido al fichero ~/.ssh/authorized_keys.

Ahora la conexión debería funcionar sin necesidad de introducir la clave. Si no es así es posible que sea un problema de permisos en los ficheros. Los permisos correctos deben ser similares a estos:

    $ chmod go-w $HOME $HOME/.ssh
    $ chmod 600 $HOME/.ssh/authorized_keys

Controlando el Login de Usuario

Es posible indicarle a ssh nuestra identidad en máquinas remotas usando el fichero de configuración ~/.ssh/config:

hp@nereida:~/Lperl/src/perl_networking/ch2$ cat -n ~/.ssh/config
     1  # man  ssh_config
     2  Host machine1.domain
     3  user casiano
     4
     5  Host machine2.domain
     6  user pp2

Para saber más sobre ssh lea la sección Conexiones con ssh en los apuntes de Programación en Paralelo II.

Ejecutando las Pruebas en un Conjunto de Máquinas

El siguiente programa muestra un guión sencillo que permite ejecutar las pruebas en un conjunto de máquinas remotas con las que se ha establecido un sistema de autentificación automática. Al ejecutar el programa se transfiere la distribución, se desempaqueta y se pasan las pruebas sobre cada máquina:

lhp@nereida:~/Lperl/src/perl_testing_adn_examples/chapter_03/Algorithm-Knap01DP-0.25$ make remotetest
remotetest.pl Algorithm-Knap01DP-0.25.tar.gz orion beowulf
************orion************
Checking if your kit is complete...
Looks good
Writing Makefile for Algorithm::Knap01DP
cp lib/Algorithm/Knap01DP.pm blib/lib/Algorithm/Knap01DP.pm
Manifying blib/man3/Algorithm::Knap01DP.3pm
PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" \
       "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/01alltests....ok
t/02bench.......ok
        1/2 skipped: Algorithm::Knapsack not installed
All tests successful, 1 subtest skipped.
Files=2, Tests=16,  0 wallclock secs ( 0.10 cusr +  0.01 csys =  0.11 CPU)
************beowulf************
Checking if your kit is complete...
Looks good
Writing Makefile for Algorithm::Knap01DP
cp lib/Algorithm/Knap01DP.pm blib/lib/Algorithm/Knap01DP.pm
Manifying blib/man3/Algorithm::Knap01DP.3pm
PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" \
       "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/01alltests....ok
t/02bench.......ok
        1/2 skipped: various reasons
All tests successful, 1 subtest skipped.
Files=2, Tests=16,  0 wallclock secs ( 0.11 cusr +  0.01 csys =  0.12 CPU)
lhp@nereida:~/Lperl/src/perl_testing_adn_examples/chapter_03/Algorithm-Knap01DP-0.25$

Añadiendo Objetivos al Makefile Construido

Es posible entonces establecer la ejecución del guión anterior extendiendo Makefile.PL con una función MY::postamble. La cadena retornada por esta función es añadida al Makefile construido:

lhp@nereida:$ cat -n Makefile.PL
 1  use ExtUtils::MakeMaker;
 2  # See lib/ExtUtils/MakeMaker.pm for details of how to influence
 3  # the contents of the Makefile that is written.
 4  WriteMakefile(
 5      NAME              => 'Algorithm::Knap01DP',
 6      VERSION_FROM      => 'lib/Algorithm/Knap01DP.pm', # finds $VERSION
 7      PREREQ_PM         => {}, # e.g., Module::Name => 1.1
 8      ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
 9        (ABSTRACT_FROM  => 'lib/Algorithm/Knap01DP.pm', # retrieve abstract from module
10         AUTHOR         => 'Lenguajes y Herramientas de Programacion <lhp@>') : ()),
11  );
12
13  sub MY::postamble {
14    my @machines = qw( orion beowulf);
15
16  return <<"EOT";
17  remotetest:
18          remotetest.pl \${DISTVNAME}.tar.gz @machines
19  EOT
20  }

Elaborando una Ejecución Remota

El siguiente programa remotetest.pl copia para cada máquina la distribucion y ejecuta las pruebas en la máquina remota. Forma parte de la distribución GRID::Machine disponible en CPAN.

$ cat -n /usr/local/bin/remotetest.pl
  1  #!/usr/bin/perl -w
  2
  3  eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}'
  4      if 0; # not running under some shell
  5  use strict;
  6  use GRID::Machine;
  7
  .  ....................................................................
 28
 29  my $dist = shift or die "Usage:\n$0 distribution.tar.gz machine1 machine2 ... \n";
 30
 31  die "No distribution $dist found\n" unless -r $dist;
 32
 33    die "Distribution does not follow standard name convention\n"
 34  unless $dist =~ m{([\w.-]+)\.tar\.gz$};
 35  my $dir = $1;
 36
 37  die "Usage:\n$0 distribution.tar.gz machine1 machine2 ... \n" unless @ARGV;
 38  for my $host (@ARGV) {
 39
 40    my $m = eval {
 41      GRID::Machine->new(host => $host)
 42    };
 43
 44    warn "Cant' create GRID::Machine connection with $host\n", next unless UNIVERSAL::isa($m, 'GRID::Machine');
 45
 46    my $r = $m->eval(q{
 47        our $tmpdir = File::Temp::tempdir;
 48        chdir($tmpdir) or die "Can't change to dir <$tmpdir>\n";
 49      }
 50    );
 51
 52    warn($r),next unless $r->ok;
 53
 54    my $preamble = $host.".preamble.pl";
 55    if (-r $preamble) {
 56      local $/ = undef;
 57
 58      my $code = slurp_file($preamble);
 59      $r = $m->eval($code);
 60      warn("Error in $host preamble: $r"),next unless $r->ok;
 61    }
 62
 63    $m->put([$dist]) or die "Can't copy distribution in $host\n";
 64
 65    $r = $m->eval(q{
 66        my $dist = shift;
 67
 68        eval('use Archive::Tar');
 69        if (Archive::Tar->can('new')) {
 70          # Archive::Tar is installed, use it
 71          my $tar = Archive::Tar->new;
 72          $tar->read($dist,1) or die "Archive::Tar error: Can't read distribution $dist\n";
 73          $tar->extract() or die "Archive::Tar error: Can't extract distribution $dist\n";
 74        }
 75        else {
 76          system('gunzip', $dist) or die "Can't gunzip $dist\n";
 77          my $tar = $dist =~ s/\.gz$//;
 78          system('tar', '-xf', $tar) or die "Can't untar $tar\n";
 79        }
 80      },
 81      $dist # arg for eval
 82    );
 83
 84    warn($r), next unless $r->ok;
 85
 86    $m->chdir($dir)->ok or do {
 87      warn "$host: Can't change to directory $dir\n";
 88      next;
 89    };
 90
 91    print "************$host************\n";
 92    next unless $m->run('perl Makefile.PL');
 93    next unless $m->run('make');
 94    next unless $m->run('make test');
 95
 96    # Clean files
 97    $m->eval( q{
 98      our $tmpdir;
 99      chdir "$tmpdir/..";
100      system ('rm -fR $dir');
101    });
102  }



Subsecciones
Casiano Rodríguez León
2009-10-04