Skip to content

Instantly share code, notes, and snippets.

@dap
Created January 19, 2011 21:39
Show Gist options
  • Save dap/786922 to your computer and use it in GitHub Desktop.
Save dap/786922 to your computer and use it in GitHub Desktop.
#!/usr/local/bin/perl
use strict;
use warnings;
use Getopt::Long; # option parsing
use Capture::Tiny qw/capture/; # output capture
use Date::Format; # date formatting
use Method::Signatures; # "func" syntax
use Sysadm::Install qw/:all/; # utilities for system administration
# pgdump is expected at the following path
our $pg_dump_path = '/usr/local/var/postgres/8.4/bin/pg_dump';
# psql is expected at the following path
our $psql_path = '/usr/bin/psql';
# sudo is expected at the following path
our $sudo_path = '/opt/sfw/bin/sudo';
# rsync is expected at the following path
our $rsync_path = '/opt/sfw/bin/rsync';
# ssh is expected at the following path
our $ssh_path = '/usr/bin/ssh';
# perl is expected at the following path
our $perl_path = '/usr/local/bin/perl';
our @addl_perl_lib_paths = ('/usr/local/var/www/cspa/par/perl5/lib',
'/usr/local/var/www/cspa/par/perl5/lib/sun4-solaris');
# openssl is expected at the following path
our $openssl_path = '/usr/sfw/bin/openssl';
# This script will verify the following:
our @verify_actions = qw/
verify_certs
verify_cosign
verify_postgres
verify_wmc
/;
#sync_postgres
# And sync the following:
our @sync_actions = qw/
sync_certs
sync_cosign
sync_wmc
/;
# These Postgres databases will be synched
our @pg_databases = qw/
wmc
/;
# Flags used by GetOpts
our ($quiet, $verbose) = (0, 0);
func main {
GetOptions(
'quiet' => \$quiet,
'verbose' => \$verbose
);
exit_with_error('No destination host specified.')
unless defined $ARGV[0];
my $other_host_name = $ARGV[0];
print "Verifying local data integrity...\n";
foreach my $verify_action (@verify_actions) {
no strict 'refs';
print "\t$verify_action\t";
my $return = $verify_action->();
# This is intended to be a string comparison
print $return eq 1 ? 'OK' : ($return || 'FAILED'), "\n";
}
print "done.\n\nSynching to $other_host_name...\n";
foreach my $sync_action (@sync_actions) {
no strict 'refs';
print "\t$sync_action\t";
my $return = $sync_action->($other_host_name);
# This is intended to be a string comparison
print $return eq 1 ? 'OK' : ($return || 'FAILED'), "\n";
}
print "done.\n\nVerifying remote data integrity...\n";
foreach my $verify_action (@verify_actions) {
no strict 'refs';
print "\t$verify_action\t";
my $return = $verify_action->($other_host_name);
# This is intended to be a string comparison
print $return eq 1 ? 'OK' : ($return || 'FAILED'), "\n";
}
print "done.\n";
}
func verify_certs () {
my $status;
my $user = 'cspa';
my @certs = glob '/usr/local/cosign/certs/SIGNING/*.crt';
foreach my $cert (@certs) {
# Based on http://helpdesk.wisc.edu/middleware/page.php?id=4064
my $openssl_command = "(openssl x509 -noout -modulus -in $base_name.crt | openssl md5 ; openssl rsa -noout -modulus -in $base_name.key | openssl md5) | uniq";
say $cert;
}
my @sudo_command = _sudo_su_invocation($user);
my ($stdout, $stderr) = capture {
if ($other_host_name) {
$status = ssh(
$other_host_name,
join(' ', @sudo_command) . ' "' . join(' ', @cosignd_command) . '"'
);
}
else {
$status = run_as($user, join(' ', @cosignd_command) );
}
};
print $stdout if ($verbose && !$quiet);
return 1 if (0 == $status);
print $stderr if ($verbose && !$quiet);
return 0;
}
func verify_cosign ($other_host_name?) {
my $status;
my $user = 'cosign';
my @sudo_command = _sudo_su_invocation($user);
my @cosignd_command = (
'/usr/local/cosign/sbin/cosignd',
'-n',
'-c',
'/usr/local/cosign/conf/cosign.conf'
);
my ($stdout, $stderr) = capture {
if ($other_host_name) {
$status = ssh(
$other_host_name,
join(' ', @sudo_command) . ' "' . join(' ', @cosignd_command) . '"'
);
}
else {
$status = run_as($user, join(' ', @cosignd_command) );
}
};
print $stdout if ($verbose && !$quiet);
return 1 if (0 == $status);
print $stderr if ($verbose && !$quiet);
return 0;
}
func verify_postgres () {
return 'Not yet implemented.';
}
func verify_wmc ($other_host_name?) {
my $status;
my $user = 'cspa';
my @sudo_command = _sudo_su_invocation($user);
my @perl_command = ($perl_path);
foreach my $path (@addl_perl_lib_paths) {
push @perl_command, "-I$path";
}
push @perl_command, ('-c', 'conf/config.pl');
my ($stdout, $stderr) = capture {
if ($other_host_name) {
$status = ssh(
$other_host_name,
join(' ', @sudo_command) . ' "' . join(' ', @perl_command) . '"'
);
}
else {
$status = run_as($user, join(' ', @perl_command) );
}
};
print $stdout if ($verbose && !$quiet);
return 1 if (0 == $status);
print $stderr if ($verbose && !$quiet);
return 0;
}
func sync_certs ($other_host_name) {
my $status;
my ($stdout, $stderr) = capture {
$status = rsync_as(
'cspa',
'/usr/local/cosign/certs/SIGNING/',
"$other_host_name:/usr/local/cosign/certs/SIGNING/"
);
};
print $stdout if ($verbose && !$quiet);
return 1 if (0 == $status);
print $stderr if ($verbose && !$quiet);
return 0;
}
func sync_cosign ($other_host_name) {
my $status;
my ($stdout, $stderr) = capture {
$status = rsync_as(
'cosign',
'/usr/local/cosign/conf/',
"$other_host_name:/usr/local/cosign/conf/"
);
};
print $stdout if ($verbose && !$quiet);
return 1 if (0 == $status);
print $stderr if ($verbose && !$quiet);
return 0;
}
func sync_postgres ($other_host_name) {
my $status;
my ($stdout, $stderr) = capture {
foreach my $database (@pg_databases) {
my $time = Date::Format::time2str( '%Y-%m-%d_%H%M%S', time() );
my $filename = '/tmp/'. $database . '_' . $time . '.sql';
$status = system($pg_dump_path, '-U', 'postgres', '-f', $filename, $database);
last unless $status == 0;
$status = rsync($filename, "$other_host_name:$filename");
last unless $status == 0;
$status = ssh($other_host_name, "psql -U postgres -f $filename wmc");
last unless $status == 0;
}
};
print $stdout if ($verbose && !$quiet);
return 1 if (0 == $status);
print $stderr if ($verbose && !$quiet);
return 0;
}
func sync_wmc ($other_host_name) {
return 'WMC config must be synced manually.'
unless $quiet;
}
func rsync ($source, $destination) {
return system(
$rsync_path,
"--rsync-path=$rsync_path",
'-av',
$source,
$destination,
);
}
func rsync_as ($user, $source, $destination) {
my @sudo_command = (
$rsync_path,
"--rsync-path=$rsync_path",
'-nav',
$source,
$destination,
);
return run_as( $user, join(' ', @sudo_command) );
}
func run_as ($user, $command) {
my @sudo_su_invocation = _sudo_su_invocation($user);
return system(@sudo_su_invocation, $command );
}
func ssh ($destination, $command) {
return system(
$ssh_path,
# -t gives us a tty; without it, we don't get STDERR - ghamlin
'-t',
$destination,
$command
);
}
func _sudo_su_invocation ($user) {
return ($sudo_path, 'su', '-', $user, '-c');
}
func exit_with_error ($message) {
print "Error: $message\n";
exit 1;
}
main();
__END__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment