Amazon EC2を簡単操作するWebインターフェース

AmazonのEC2で遊び中なのだが、コマンドやIDをぽちぽち打つのがどうにも面倒くさいのでブラウザ上でクリック操作できるCGIを書いてみた。
なかなか便利だったので公開。

使い方

インストールしたURLにアクセスすると現在実行中のインスタンスと実行可能なイメージが表示される。イメージの横にある"spawn"ボタンで実行開始、"shutdown"で実行停止。sshアクセス時に必要な秘密鍵を生成したりする"setup"も作ったのだが、ポートを開放する部分がまだうまく動いていないです(1/21修正。これで動くか?)、、、。

インストール

あらかじめアマゾンのサイトでAWSのアカウントを作ってEC2の利用契約を済ませておく。
スクリプトを"ec2web.cgi"という名前でどこかにセーブ、最初の部分に書かれた設定を自分の環境用に変更。
インストールしたURLにアクセスしたときにパッケージがないぞといわれたら、CPANからNet::Amazon::EC2(thanks to Jeff Kim)をインストール。

perl -MCPAN -e "install Net::Amazon::EC2"

個々のインスタンスのアップタイムをモニタしたい場合は、以下の内容をインスタンスの/var/www/cgi-bin/uptime.cgiとしてセーブ+パーミッションを755にしておく。

#!/bin/bash
echo "Content-Type: text/plain"
echo ""
uptime

使用上の注意

このスクリプトを使うことによって発生するいかなる被害について作者(id:yosukema)は責任を負うものではありません。

EC2は課金サービスであるため以下の2点については特に気をつけてください。

  • スクリプトを人から見えるところに置いておくと、いたずらされて金銭的な被害が発生する危険があります。
  • インスタンスが実行され続ける限り課金は止まりません。最終的な実行状態の確認はスクリプトに頼らず自分の手で行ってください。
#!/usr/bin/perl
# ec2web - a simple cgi to control amazon ec2
#  see http://d.hatena.ne.jp/yosukema/20070119 for details

use MIME::Base64;
use Net::Amazon::EC2;

my $script_name = "ec2web.cgi";
my $key_name = "key1";
my $aws_id = 'YOUR_AWS_ID';
my $aws_secret_key = 'YOUR_AWS_SECRET_KEY';
my $enable_uptime = 1;

my $ec2 = Net::Amazon::EC2->new(AWSAccessKeyId => $aws_id, SecretAccessKey => $aws_secret_key);

my $access=$ENV{'QUERY_STRING'};
my ($cmd, $id) = split(/=/, $access, 2);

print "Content-type: text/html\n";
print "\n";

if ($cmd eq "spawn") {
    my $instance = $ec2->run_instances(ImageId => $id, MinCount => 1, MaxCount => 1, KeyName => $key_name);
    print "sent spawn to $id<br>\n";
    print "<a href=\"$script_name\">go back</a>\n";
} elsif ($cmd eq "shutdown") {
    my $result = $ec2->terminate_instances(InstanceId => $id);
    print "sent shutdown to $id<br>\n";
    print "<a href=\"$script_name\">go back</a>\n";
} elsif ($cmd eq "register") {
    $id =~ s/%([a-fA-F0-9]{2})/pack("C",hex($1))/eg;
    my $result = $ec2->register_image(ImageLocation => $id);
    print "register $id<br>\n";
    print "<a href=\"$script_name\">go back</a>\n";
} elsif ($cmd eq "deregister") {
    my $result = $ec2->deregister_image(ImageId => $id);
    print "sent deregister to $id<br>\n";
    print "<a href=\"$script_name\">go back</a>\n";
} elsif ($cmd eq "console") {
    $ec2->{version} = '2007-01-03';
    my $result = $ec2->_sign(Action => 'GetConsoleOutput', InstanceId => $id);
    if ( grep { defined && length } $result->{Errors} ) {
	print $result->{Errors}{Error}{Message};
    } else {
	print "<h3>".$result->{timestamp}."</h3>\n";
	print "<pre>";
	print decode_base64($result->{output});
	print "</pre>";
    }
} elsif ($cmd eq "setup") {
    $ec2->delete_key_pair(KeyName => $key_name);
    my $key = $ec2->create_key_pair(KeyName => $key_name);
    print "Your private key:<br>\n";
    print "<pre>$key->{keyMaterial}</pre><br>\n";
    $ec2->authorize_security_group_ingress(GroupName => 'default', IpProtocol => 'tcp', FromPort => '22', ToPort => '22', CidrIp => '0.0.0.0/0');
    $ec2->authorize_security_group_ingress(GroupName => 'default', IpProtocol => 'tcp', FromPort => '80', ToPort => '80', CidrIp => '0.0.0.0/0');
    print "<a href=\"$script_name\">go back</a>\n";
} else {
    print "<h2>Your Running Instance</h2>\n";
    my $running_instances = $ec2->describe_instances();
    foreach my $inst (@{$running_instances}) {
	my $id = $inst->{instance}[0]{instanceId};
	my $dns = $inst->{instance}[0]{dnsName};
	my $state = $inst->{instance}[0]{instanceState}{name};
	print "$id : <a href=\"http://$dns/\" target=\"_blank\">$dns</a>";
	print " <a href=\"$script_name?console=$id\" target=\"_blank\">[console]</a> ";
	print " ($state) <a href=\"$script_name?shutdown=$id\">shutdown</a><br>\n";
        if ($enable_uptime > 0) {
	    print "<pre>    </pre>";
            system("wget -O - -q http://$dns/cgi-bin/uptime.cgi");
	}
    }
    print "<h2>Available Images</h2>\n";
    my $avail_images = $ec2->describe_images();
    foreach my $img (@{$avail_images}) {
	my $id = $img->{imageId};
	if ($img->{imageState} ne "deregistered") {
	    print "$id : $img->{imageLocation} ($img->{imageOwnerId}) <a href=\"$script_name?spawn=$id\">spawn</a>";
	    if ($img->{isPublic} eq "false") {
		print " <a href=\"$script_name?deregister=$id\">deregister</a>";
	    }
	    print "<br>\n";
	}
    }
    print "<h2>Register Image</h2>\n";
    print '<FORM METHOD="GET" ACTION="'.$script_name.'">';
    print 'S3 location:<INPUT NAME="register" SIZE=40>';
    print '<INPUT TYPE="submit" VALUE="ADD">';
    print '</FORM>';
    print "<h2>Utility</h2>\n";
    print "<a href=\"$script_name?setup>Setup</a><br>\n";
}

関連リンク

ソースコードは自由に改変して使ってください。改変物を公開する場合は、このページにトラックバックいただけると以下にリンクを張って紹介します。

履歴

2007-01-21 ポート開放の部分を修正。アップタイムモニタ機能を追加。
2007-02-10 コンソール表示機能を追加。
2007-02-18 イメージ登録関係の機能を追加。