VM-EC2
view release on metacpan or search on metacpan
bin/sync_to_snapshot.pl view on Meta::CPAN
# Provision the volume
print STDERR "Provisioning a $gb GB volume...\n";
my($volume,$needs_mkfs,$needs_resize) = provision_volume($gb,$Snapshot_name);
$Volume = $volume;
# Create a temporary key for ssh'ing
print STDERR "Creating a temporary ssh key...\n";
my $keypairname = "${Program_name}_$$";
$KeyFile = File::Spec->catfile(File::Spec->tmpdir,"$keypairname.pem");
$KeyPair = $ec2->create_key_pair($keypairname);
my $private_key = $KeyPair->privateKey;
open my $k,'>',$KeyFile or die "Couldn't create $KeyFile: $!";
chmod 0600,$KeyFile or die "Couldn't chmod $KeyFile: $!";
print $k $private_key;
close $k;
# Create a temporary security group for ssh'ing
print STDERR "Creating a temporary security group with ssh enabled...\n";
$Group = $ec2->create_security_group(-name => "${Program_name}_$$",
-description => "Temporary security group created by $Program_name"
) or die $ec2->error_str;
$Group->authorize_incoming(-protocol => 'tcp',
-port => 'ssh');
$Group->update or die $ec2->error_str;
# Provision an instance in the same availability zone
print STDERR "Provisioning staging instance...\n";
my $zone = $Volume->availabilityZone;
$Instance = $ec2->run_instances(-image_id => $Image,
-zone => $zone,
-key_name => $KeyPair,
-instance_type => $Type,
-security_group_id => $Group) or die $ec2->error_str;
$Instance->add_tag(Name => "Staging instance for snapshot $Snapshot_name created by $Program_name");
# wait until the instance is running and the ssh daemon is responding...
print STDERR "Waiting for instance to come up. This may take a while...\n";
$ec2->wait_for_instances($Instance);
$Instance->current_status eq 'running' or die "Instance $Instance, status = ",$Instance->current_status;
wait_for_ssh_daemon(); # we may die on this step
my $device = eval{unused_device()} or die "Couldn't find suitable device to attach";
# attach and initialize volume
print STDERR "Attaching staging volume...\n";
my $s = $Instance->attach_volume($Volume=>$device) or die "Couldn't attach $Volume to $Instance via $device";
$ec2->wait_for_attachments($s) or die "Couldn't attach $Volume to $Instance via $device";
$s->current_status eq 'attached' or die "Couldn't attach $Volume to $Instance via $device";
if ($needs_resize) {
die "Sorry, but can only resize ext volumes " unless $Filesystem =~ /^ext/;
print STDERR "Resizing previously-snapshotted volume to $gb GB...\n";
ssh("sudo /sbin/resize2fs $device");
} elsif ($needs_mkfs) {
print STDERR "Making $Filesystem filesystem on staging volume...\n";
ssh("sudo /sbin/mkfs.$Filesystem $device");
}
# do the rsync
print STDERR "Mounting staging volume...\n";
ssh("sudo mkdir -p /mnt/transfer; sudo mount $device /mnt/transfer; sudo chown $Username /mnt/transfer");
print STDERR "Beginning rsync...\n";
my $Host = $Instance->dnsName;
system "rsync -Ravz -e'ssh -o \"StrictHostKeyChecking no\" -i $KeyFile -l $Username' @locations $Host:/mnt/transfer";
ssh('sudo umount /mnt/transfer');
$Instance->detach_volume($Volume);
# snapshot stuff
my $version = 1;
if (my $snap = $Volume->from_snapshot) {
$version = $snap->tags->{Version} || 0;
$version++;
}
print STDERR "Creating snapshot $Snapshot_name version $version...\n";
my $snap = $Volume->create_snapshot($Snapshot_name);
$snap->add_tags(Version => $version);
$snap->add_tags(Name => $Snapshot_name);
print "Created snap $snap\n";
};
warn $@ if $@;
cleanup();
exit 0;
sub ssh {
my @cmd = @_;
$Instance or die "Remote instance not set up correctly";
my $host = $Instance->dnsName;
my $pid = open my $kid,"-|"; #this does a fork
die "Couldn't fork: $!" unless defined $pid;
if ($pid) {
my @results;
while (<$kid>) {
push @results,$_;
}
close $kid;
die "ssh failed with status ",$?>>8 unless $?==0;
if (wantarray) {
chomp(@results);
return @results;
} else {
return join '',@results;
}
}
# in child
exec '/usr/bin/ssh','-o','CheckHostIP no','-o','StrictHostKeyChecking no','-i',$KeyFile,'-l',$Username,$host,@cmd;
}
sub unused_device {
my %devices = map {$_=>1} ssh('ls /dev/*d[a-z][0-9]*');
my $base = $devices{'/dev/sda1'} ? '/dev/sd'
:$devices{'/dev/xvda1'} ? '/dev/xvd'
:die "can't figure out whether to use /dev/sd or /dev/xvd";
for my $major ('f'..'p') {
for my $minor (1..15) {
( run in 0.955 second using v1.01-cache-2.11-cpan-5511b514fd6 )