2010
06.03

What a pain is to have to associate elastic IPs when launching Amazon AWS ec2 instances. Think about 15-20 machines which need static (elastic) ip. I solved this problem with a bit of Perl code:

First thing You need to do is to have ec2-api-tools installed in /usr/local/ec2/ec2-api-tools and your cert-…pem and pk-….pem file in /root/.ec2/. Then You need to install ec2-metadata API tool to be able to get the user data passed on launch of the instance:

user@computer:$
cd /usr/local/bin
wget http://s3.amazonaws.com/ec2metadata/ec2-metadata
chmod +x ec2-metadata

Ok. Now You should be ready to write a script that will associate elastic IP:

You to make sure perl script can run API tools by adding ENV vars.:

$ENV{EC2_HOME} = '/usr/local/ec2/ec2-api-tools';
$ENV{PATH} = '$EC2_HOME/bin:'.$ENV{PATH};
$ENV{JAVA_HOME} = "/usr";
$ENV{EC2_PRIVATE_KEY} = '/root/.ec2/pk-XXX.pem';
$ENV{EC2_CERT} = '/root/.ec2/cert-XXX.pem';
$ENV{EC2_REGION} = 'eu-west-1';
$ENV{EC2_URL} = 'https://eu-west-1.ec2.amazonaws.com';

this bit will get the elastic_ip from user data:

my @params = qx(/usr/local/bin/ec2-metadata -d | cut -d ':' -f 2 | awk '{sub\(/^[ \t]+/, ""\); print}' | tr '|' '\n');
chomp @params;
my %options;
my $params_check = scalar @params;
if ($params_check == 0)
{
        print "No user-data defined !\n";
        exit;  
}

User data is supplied in following format: key=value|key2=value|key3=value|… but can be also supplied as single variable: key=value

associate Elastic IP:

if ($options{'elastic_ip'})
{
        my $elastic_ip = $options{'elastic_ip'};
        print "Associating Elastic IP: $elastic_ip\n";
        my $instance_id = qx(/usr/local/bin/ec2-metadata -i | cut -d ':' -f 2 | awk '{sub\(/^[ \t]+/, ""\); print}');
        chomp $instance_id;
        system("/usr/local/ec2/ec2-api-tools/bin/ec2-associate-address $elastic_ip -i $instance_id");
}

and wait for Elastic IP to be associated:

while (my $external_ip = qx(/usr/local/bin/ec2-metadata -v | cut -d ':' -f 2 | awk '{sub\(/^[ \t]+/, ""\); print}'))
{
        chomp $external_ip;
        if ($external_ip eq $options{'elastic_ip'})
        {
                print "Elastic IP attached\n";
                last;
        }
        else
        {
                print "Waiting for Elastic IP\n";
                sleep 5;
        }
}

yes, this is endless loop but it will make sure that script will not exit until elastic IP is associated. This is useful when some services depend on it.

The complete script can look something like this:

#!/usr/bin/perl -w

use strict;

# Set variables for ec2
$ENV{EC2_HOME} = '/usr/local/ec2/ec2-api-tools';
$ENV{PATH} = '$EC2_HOME/bin:'.$ENV{PATH};
$ENV{JAVA_HOME} = "/usr";
$ENV{EC2_PRIVATE_KEY} = '/root/.ec2/pk-XXX.pem';
$ENV{EC2_CERT} = '/root/.ec2/cert-XXX.pem';
$ENV{EC2_REGION} = 'eu-west-1';
$ENV{EC2_URL} = 'https://eu-west-1.ec2.amazonaws.com';

# Get user data parameters provided on instance launch
# User data needs to be supplied in following format: key=value|key2=value|key3=value|...
print "Getting parameters\n";
my @params = qx(/usr/local/bin/ec2-metadata -d | cut -d ':' -f 2 | awk '{sub\(/^[ \t]+/, ""\); print}' | tr '|' '\n');
chomp @params;
my %options;

my $params_check = scalar @params;

if ($params_check == 0)
{
        print "No user-data defined !\n";
        exit;
}

# Print out all user data to screen (helps when getting system log from instance)
print "User data:\n";
foreach (@params)
{
        my ($key, $value) = split(/\=/, $_);
        print "\t$key: $value\n";
        $options{$key} = $value;
}

# Exit if disable_boot_script option is set
if ($options{'disable_boot_script'})
{
        print "Booting script disabled, exiting\nBye!\n";
        exit;
}

# Associate Elastic IP
if ($options{'elastic_ip'})
{
        my $elastic_ip = $options{'elastic_ip'};
        print "Associating Elastic IP: $elastic_ip\n";
        my $instance_id = qx(/usr/local/bin/ec2-metadata -i | cut -d ':' -f 2 | awk '{sub\(/^[ \t]+/, ""\); print}');
        chomp $instance_id;
        system("/usr/local/ec2/ec2-api-tools/bin/ec2-associate-address $elastic_ip -i $instance_id");
}

# Wait for Elastic IP to be associated (Yes, this is endless loop !)
while (my $external_ip = qx(/usr/local/bin/ec2-metadata -v | cut -d ':' -f 2 | awk '{sub\(/^[ \t]+/, ""\); print}'))
{
        chomp $external_ip;
        if ($external_ip eq $options{'elastic_ip'})
        {
                print "Elastic IP attached\n";
                last;
        }
        else
        {
                print "Waiting for Elastic IP\n";
                sleep 5;
        }
}

# Set hostname
my $hostname = $options{'hostname'};
print "Setting up hostname to $hostname\n";
system("hostname $hostname");

print "All done here\n";

now add this script to /etc/rc.local, problem solved :)

Of course this makes only sense on private AMIs. Please let me know what You think !

Bookmark and Share

No Comment.

Add Your Comment