AWS EC2インスタンス上でメールサーバを構築する実験をしている最中、どうしても「今まで使用したことが無いEIPが欲しい」という状況に遭遇しました。
…とは言っても、EIP確保コマンド(ec2-allocate-address)に、そんなオプション指定は存在しないので……何度もEIP確保を繰り返して、気に入らなければ解放する…という作業になります。

ハッキリ言ってメンドクサイので、自動化しました。AmazonLinux + ruby 1.8.7 (2012-10-12 patchlevel 371) [i386-linux] で動作確認しています。

・allocate_flesh_address.rb
#!/usr/bin/ruby
# encoding: utf8

# 2013-04-09 Original Coding by ExploreAWS (http://exploreaws.doorblog.jp/)

require "time"
require "open3"
require "ipaddr"
require "optparse"

DEFAULT_WAIT_TIMER = 10 # as secconds
INCREMENT_WAIT_TIMER = 60 # increment at retry
MAX_WAIT_TIMER = (60*5) # as secconds
MAX_RETRY_COUNT = 99 #

ALLOCATOR_COMMAND = 'ec2-allocate-address' ## AWS ec2 command
ALLOCATOR_VPC_COMMAND = 'ec2-allocate-address --domain vpc' ## AWS ec2 command
DEALLOCATOR_COMMAND = 'ec2-release-address' ## AWS ec2 command
DEALLOCATOR_VPC_COMMAND = 'ec2-release-address --allocation-id' ## AWS ec2 command
UNFAVORITE_IP_DIR = 'unfavorite_ipv4/'


################################################################################
## PRINT LOG
def printLog( msg )
print Time.now.strftime( "%Y-%m-%d %H:%M:%S %Z" ) + " : " + msg
end


################################################################################
## GET A LIST OF UNFAVOTITE IPv4 ADDRESSES
def getUnfavoriteIpList() ## RET: Array of string (as IPv4s)
tFile = Dir::entries( UNFAVORITE_IP_DIR )
tIp = Array.new()
tFile.each do |v|
v.strip!
v.sub!( %r!^.*/!, '' ) ## remove the path string before its filename.
next if v.length < 8
begin
if (IPAddr.new( v ).ipv4?) # trash unless it's a valid IPv4.
tIp.push( v )
end
rescue => err
## Nothing to do... just ignore error ##
end
end
return tIp
end

################################################################################
## DEALLOCATE A IPv4, AND GIVE IT BACK TO AWS
def deallocateIp( ip, allocation_id = nil ) ## RET: ture / false
command = if (allocation_id.nil?)
DEALLOCATOR_COMMAND + ' ' + ip
else
DEALLOCATOR_VPC_COMMAND + ' ' + allocation_id
end
return system( command + ' > /dev/null')
end


################################################################################
## ALLOCATE A IPv4from AWS
def allocateIp( fVPC = false ) ## RET: string ip, string allocation_id
strError = nil
strResult = nil

command = (fVPC ? ALLOCATOR_VPC_COMMAND : ALLOCATOR_COMMAND )
Open3.popen3( command ) do |stdin, stdout, stderr|
stdin.close() # no need...
strError = stderr.read()
strResult = stdout.readlines()
end

if (strError.length > 0)
raise "#{command} returns an error. \n" + strError
end

if (strResult.length != 1 || !strResult[0].match( /^ADDRESS/ ))
raise "#{command} returns unknown result... \n" + strResult
end

t = strResult[0].split( "\t" )
address = t[1].strip
allocation_id = (t[4].strip rescue nil)

ip = nil
begin
ip = IPAddr.new( address )
if (! ip.ipv4?) then raise "#{address} is not a valid IPv4 address." end
rescue => err
raise err
end

allocation_id = nil if (allocation_id.length <= 0) ## regulate...

return address, allocation_id
end



################################################################################
## main

# initialize
fVPC = false
tUnfavoriteIp = getUnfavoriteIpList()

# options
opt = OptionParser.new()
opt.on( '-vpc' ) { fVPC = true }
opt.on( '--vpc' ) { fVPC = true }
opt.parse!( ARGV )


# main loop
#begin
nWaitTimer = DEFAULT_WAIT_TIMER
nRetryCount = 0
while( true ) do
ip, allocation_id = allocateIp( fVPC )
printLog "IP - " + ip
if (!tUnfavoriteIp.include?( ip ))
print " ... appreciated! \n"
break
end

print " ... but I hate it. \n"
deallocateIp( ip, allocation_id )

nRetryCount += 1
if (nRetryCount > MAX_RETRY_COUNT)
raise "Give up!"
end

sleep( nWaitTimer )
nWaitTimer += INCREMENT_WAIT_TIMER
nWaitTimer += MAX_WAIT_TIMER if (MAX_WAIT_TIMER < nWaitTimer)
end
#rescue => err
# print "\n"
# puts err
# exit( -1 )
#end


# End of Main
exit( 0 )

# END of FILE #


使い方は、以下の通り。
  1. 気に入らないEIPのIPアドレスをファイル名として ./unfavorite_ipv4/ ディレクトリ内に touch しておく。
  2. ruby スクリプトを実行する。VPC用 EIPが必要な場合は --vpc オプションを指定しておく。


実際のコマンドだと、こんな感じになります。

$ ls allocate_flesh_address.rb
allocate_flesh_address.rb


$ mkdir  unfavorite_ipv4/
$ touch unfavorite_ipv4/54.248.98.67

$ touch unfavorite_ipv4/54.248.98.92


$ ruby allocate_flesh_address.rb
2013-04-09 11:54:53 UTC : IP - 54.248.98.67 ... but I hate it.

2013-04-09 11:55:05 UTC : IP - 54.248.98.92 ... but I hate it.
2013-04-09 11:56:17 UTC : IP - 54.248.98.67 ... but I hate it.
2013-04-09 11:58:29 UTC : IP - 54.248.98.67 ... but I hate it.
2013-04-09 12:01:42 UTC : IP - 54.248.98.67 ... but I hate it.
2013-04-09 12:05:54 UTC : IP - 54.248.246.65 ... appreciated!


$ ec2-describe-addresses
ADDRESS 54.248.246.65           standard


そんなに高度なものではありませんが、人力で作業するより全然マシになりました(^^;


AWSの中の人に見られたら「そんなEIP確保の仕方はダメだ!」と怒られるかもしれませんが…(x_x;




参考まで…。