The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl

use strict;
use warnings;
use YAML::XS;
use Digest::MD5;

use Hermes;
use MIO::TCP;
use Poros::Query;
use Vulcan::Sudo;
use Vulcan::OptConf;

our $PORT = 12345;

$| ++;

=head1 SYNOPSIS

 $0 -r range users

=cut
Vulcan::Sudo->sudo();

my $option = Vulcan::OptConf->load();
my %o = Vulcan::OptConf->load()->get( qw( range=s ) )->dump();
my ( @file, @conf ) = qw( id_rsa id_rsa.pub id_dsa id_dsa.pub authorized_keys );

for my $user ( @ARGV )
{
    next unless my $dir = ( getpwnam $user )[7];
    next unless -d ( $dir = "$dir/.ssh" );

    for my $file ( @file )
    {
        next unless -f ( $file = "$dir/$file" );
        my $cont = `cat $file`;
        push @conf,
        {
            path => $file, chown => $user, file => $cont,
            md5 => Digest::MD5->new()->add( $cont )->hexdigest(),
            chmod => sprintf "%lo", ( stat $file )[2] & 07777,
        } 
    }
}

die "invalid user or user has no key\n" unless @conf;

my %query = ( code => 'dump', argv => \@conf );
my $range = Hermes->new( $option->dump( 'range' ) );

my ( %result, %mesg ) = MIO::TCP
    ->new( map { join ':', $_, $PORT } $range->load( delete $o{range} )->list )
    ->run( %o, input => Poros::Query->dump( \%query ) );

while ( my ( $type, $mesg ) = each %result )
{
    while ( my ( $mesg, $node ) = each %$mesg )
    {
        map { $_ =~ s/:$PORT$// } @$node;
        $mesg =~ s/--- \d+\n$//;
        $node = $range->load( $node )->dump();
        $mesg{$type}{$node} = YAML::XS::Load( $mesg ) if $mesg;
    }
}

YAML::XS::DumpFile \*STDOUT, \%mesg if %mesg;
exit 0;