GBrowse
view release on metacpan or search on metacpan
lib/Bio/Graphics/Browser2/Render/Slave/AWS_Balancer.pm view on Meta::CPAN
# This module is used to manage GBrowse slaves in an on-demand Amazon EC2
# environment.
use strict;
use Parse::Apache::ServerStatus;
use VM::EC2 1.22;
use VM::EC2::Instance::Metadata;
use VM::EC2::Staging::Manager;
use LWP::Simple 'get','head';
use LWP::UserAgent;
use Parse::Apache::ServerStatus;
use IO::File;
use POSIX 'strftime','setsid','setuid';
use Carp 'croak';
use FindBin '$Bin';
use constant CONFIGURE_SLAVES => "$Bin/gbrowse_configure_slaves.pl";
# arguments:
# ( -conf => $config_path,
# -access_key => $aws_access_key,
# -secret_key => $aws_secret_key,
# -logfile => $path_to_logfile,
# -pidfile => $path_to_pidfile,
# -user => $user_name_to_run_under,# (root only)
# -daemon => $daemon_mode,
# -ssh_key => $ssh_login_key (optional)
# )
sub new {
my $class = shift;
my %args = @_;
$args{-conf} or croak "-conf argument required";
-e $args{-conf} or croak "$args{-conf} not found";
#setup EC2 environment
$args{-access_key} ||= $ENV{EC2_ACCESS_KEY};
$args{-secret_key} ||= $ENV{EC2_SECRET_KEY};
my $self = bless {
access_key => $args{-access_key},
secret_key => $args{-secret_key},
logfile => $args{-logfile},
pidfile => $args{-pidfile},
user => $args{-user},
conf_file => $args{-conf},
daemon => $args{-daemon},
ssh_key => $args{-ssh_key},
verbosity => 2,
},ref $class || $class;
$self->initialize();
return $self;
}
sub logfile {shift->{logfile}}
sub pidfile {shift->{pidfile}}
sub pid {shift->{pid}}
sub user {shift->{user}}
sub daemon {shift->{daemon}}
sub ssh_key {shift->{ssh_key}}
sub ec2_credentials {
my $self = shift;
if ($self->running_as_instance) {
my $credentials = $self->{instance_metadata}->iam_credentials;
return (-security_token => $credentials) if $credentials;
$self->log_debug('No instance security credentials. Does this instance have an IAM role?');
}
$self->{access_key} ||= $self->_prompt('Enter your EC2 access key:');
$self->{secret_key} ||= $self->_prompt('Enter your EC2 secret key:');
return (-access_key => $self->{access_key},
-secret_key => $self->{secret_key})
}
sub logfh {
my $self = shift;
my $d = $self->{logfh};
$self->{logfh} = shift if @_;
$d;
}
sub verbosity {
my $self = shift;
my $d = $self->{verbosity};
$self->{verbosity} = shift if @_;
$d;
}
sub initialize {
my $self = shift;
$self->_parse_conf_file;
$self->_parse_instance_metadata;
}
sub DESTROY {
my $self = shift;
$self->cleanup;
}
sub run {
my $self = shift;
$self->become_daemon && return
if $self->daemon;
my $killed;
local $SIG{INT} = local $SIG{TERM} = sub {$self->log_info('Termination signal received');
$killed++; };
$self->{pid} = $$;
my $poll = $self->master_poll;
eval {$self->ec2} or croak $@;
$self->log_info("Monitoring load at intervals of $poll sec\n");
while (sleep $poll) {
last if $killed;
my $load = $self->get_load();
$self->log_debug("Current load: $load req/s\n");
$self->adjust_instances($load);
$self->update_requests();
}
$self->log_info('Normal termination');
}
sub stop_daemon {
my $self = shift;
my $pid = $self->pid;
if (!$pid && (my $pidfile = $self->pidfile)) {
my $fh = IO::File->new($pidfile) or croak "No PID file; is daemon runnning?";
lib/Bio/Graphics/Browser2/Render/Slave/AWS_Balancer.pm view on Meta::CPAN
my $image = $self->ec2->describe_images($self->slave_image_id)
or die "Could not find image ",$self->slave_image_id;
my $root = $image->rootDeviceName;
my @root = grep {$_->deviceName eq $root} $image->blockDeviceMapping;
my @snaps = $self->slave_data_snapshots;
my @bdm;
DEVICE:
for my $major ('g'..'z') {
for my $minor (1..15) {
my $snap = shift @snaps or last DEVICE;
push @bdm,"/dev/sd${major}${minor}=${snap}::true";
}
}
return [@root,@bdm];
}
sub slave_subnet {
my $self = shift;
if ($self->running_as_instance) {
return eval {(values %{$self->{instance_metadata}->interfaces})[0]{subnetId}};
} else {
$self->option('SLAVE','subnet');
}
}
sub slave_ssh_key {
my $self = shift;
my $key = $self->ssh_key;
$key ||= $self->option('SLAVE','ssh_key');
return $key;
}
sub slave_security_group {
my $self = shift;
my $sg = $self->{slave_security_group};
return $sg if $sg;
my $ec2 = $self->ec2;
$sg = eval {$ec2->describe_security_groups(-name => "GBROWSE_SLAVE_$$")};
$sg ||= $ec2->create_security_group(-name => "GBROWSE_SLAVE_$$",
-description => 'Temporary security group for slave communications');
my $ip = $self->running_as_instance ? $self->internal_ip : $self->master_ip;
$self->log_debug(
$sg->authorize_incoming(-protocol => 'tcp',
-port => $_,
-source_ip => "$ip/32")
) foreach $self->slave_ports;
$self->log_debug(
$sg->authorize_incoming(-protocol => 'tcp',
-port => 22,
-source_ip=> "$ip/32"))
if $self->slave_ssh_key;
$sg->update or croak $ec2->error_str;
return $self->{slave_security_group} = $sg;
}
sub ec2 {
my $self = shift;
# create a new ec2 each time because security credentials may expire
my @credentials = $self->ec2_credentials;
return $self->{ec2} = VM::EC2->new(-endpoint => $self->slave_endpoint,
-raise_error => 1,
@credentials);
}
sub internal_ip {
my $self = shift;
return unless $self->running_as_instance;
return $self->{instance_metadata}->privateIpAddress;
}
sub master_security_group {
my $self = shift;
return unless $self->running_as_instance;
my $sg = ($self->{instance_metadata}->securityGroups)[0];
$sg =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
return $sg;
}
sub master_ip {
my $self = shift;
my $ip = $self->option('MASTER','external_ip');
$ip ||= $self->_get_external_ip;
return $ip;
}
# poll interval in seconds
sub master_poll {
my $self = shift;
my $pi = $self->option('MASTER','poll_interval');
return $pi * 60;
}
sub master_server_status_url {
my $self = shift;
return $self->option('MASTER','server_status_url')
|| 'http://localhost/server-status';
}
sub running_as_instance {
my $self = shift;
return -e '/var/lib/cloud/data/previous-instance-id'
&& head('http://169.254.169.254');
}
# update conf file with new snapshot images
sub update_data_snapshots {
my $self = shift;
my @snapshot_ids = @_;
my $timestamp = 'synchronized with local filesystem on '.localtime;
my $conf_file = $self->conf_file;
my ($user,$group) = (stat($conf_file))[4,5];
open my $in,'<',$conf_file or die "Couldn't open $conf_file: $!";
open my $out,'>',"$conf_file.new" or die "Couldn't open $conf_file: $!";
while (<$in>) {
chomp;
s/^(data_snapshots\s*=).*/$1 @snapshot_ids # $timestamp/;
print $out "$_\n";
}
close $in;
close $out;
rename "$conf_file","$conf_file.bak" or die "Can't rename $conf_file: $!";
( run in 1.540 second using v1.01-cache-2.11-cpan-5735350b133 )