この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
こんにちは植木和樹です。AWSでは様々なリソース(EC2とかRDS)にタグを設定することで、リソースを分類したりプログラムから参照しやすくする機能があります。機能アップデートによってタグが設定できるリソースも増えています。
- Amazon EC2 リソースにタグを付ける - Amazon Elastic Compute Cloud
- Amazon Web Services ブログ: 【AWS発表】すべてのAmazon RDS のリソースにタグ付け可能に
- 【新機能】ELBにタグ付けできるようになりました!
本日はAWS SDK for Rubyを用いて、EC2/EBS/ELB/RDSからタグを取得してみたいと思います。
環境説明
CmBillingGroupタグについて
下記スクリプトに登場するCmBillingGroupタグは、弊社メンバーズのお客様に提供しているメンバーズポータルサイトでAWS利用金額の分析をする際に用いているタグ名です。CmBillingGroupの値によって利用金額を分類することができます。同一AWSアカウント内で本番用・開発用でそれぞれ利用金額の割合をみたい場合などに設定します。
必要ライブラリ
スクリプトで利用しているaws/profile_parserは望月さん作のAWSプロファイル設定ライブラリです。
formatadorは、Rubyの配列をターミナルできれいにテーブル出力してくれるライブラリです。aws-sdkとあわせて、gemコマンドで事前にインストールしておいてください。
$ gem install aws-sdk
$ gem install aws-profile_parser
$ gem install formatador
バージョンなど
- ruby
- ruby 1.9.3p547 (2014-05-14 revision 45962) [x86_64-darwin13.3.0]
- AWS SDK for Ruby
- aws-sdk-1.52.0
EC2とEBS
EC2に設定されたNameとCmBillingGroupタグ、また各インスタンスにアタッチされたEBSのタグを取得して表示します。
EC2の場合はDescribeInstancesの結果にタグが含まれるので、tags.に続いてタグ名のメソッドをコールするだけで比較的容易にタグが取得できます。
cm-ec2-describe-billing-tag.rb
#!/usr/bin/env ruby
require 'aws-sdk'
require 'optparse'
require 'formatador'
begin
require 'aws/profile_parser'
rescue LoadError; end
ARGV.options do |opt|
begin
aws_opts = {}
opt.on('-h', '--help') { puts opt.help; exit 0 }
opt.on('-k', '--access-key ACCESS_KEY') { |v| aws_opts[:access_key_id] = v }
opt.on('-s', '--secret-key SECRET_KEY') { |v| aws_opts[:secret_access_key] = v }
opt.on('-r', '--region REGION') { |v| aws_opts[:region] = v }
opt.on('--profile PROFILE') { |v| parser = AWS::ProfileParser.new; aws_opts = parser.get(v) }
opt.parse!
if aws_opts.empty?
puts opt.help
exit 1
end
AWS.config(aws_opts)
rescue => e
$stderr.puts e
exit 1
end
end
instances = []
volumes = []
ec2 = AWS::EC2.new
ec2.instances.each do |i|
instances << {
:id => i.id,
:name => i.tags.Name,
:billing_group => i.tags.CmBillingGroup,
}
i.block_devices.each do |v|
volume_id = v[:ebs][:volume_id]
volumes << {
:id => volume_id,
:instance_id => i.id,
:name => ec2.volumes[volume_id].tags.Name,
:billing_group => ec2.volumes[volume_id].tags.CmBillingGroup,
}
end
end
Formatador.display_compact_table(instances, [:id, :name, :billing_group])
Formatador.display_compact_table(volumes, [:instance_id, :id, :name, :billing_group])
実行結果
$ ruby cm-ec2-describe-billing-tag.rb --profile default
+------------+-------------+---------------+
| id | name | billing_group |
+------------+-------------+---------------+
| i-ab2c61ad | Prod-Serv01 | Production |
| i-5b40605d | | |
+------------+-------------+---------------+
+-------------+--------------+------------------+---------------+
| instance_id | id | name | billing_group |
+-------------+--------------+------------------+---------------+
| i-ab2c61ad | vol-97df729d | Prod-Serv01_root | Production |
| i-5b40605d | vol-207ccf2a | | |
+-------------+--------------+------------------+---------------+
ELB
ELBはEC2と違い、ELBインスタンスにタグを取得するメソッドがありません。そのためAWS::ELB::Clientを用いて低レベルなAPIコールを行いタグを取得します。
cm-elb-describe-billing-tag.rb
#!/usr/bin/env ruby
require 'aws-sdk'
require 'optparse'
require 'formatador'
begin
require 'aws/profile_parser'
rescue LoadError; end
ARGV.options do |opt|
begin
aws_opts = {}
opt.on('-h', '--help') { puts opt.help; exit 0 }
opt.on('-k', '--access-key ACCESS_KEY') { |v| aws_opts[:access_key_id] = v }
opt.on('-s', '--secret-key SECRET_KEY') { |v| aws_opts[:secret_access_key] = v }
opt.on('-r', '--region REGION') { |v| aws_opts[:region] = v }
opt.on('--profile PROFILE') { |v| parser = AWS::ProfileParser.new; aws_opts = parser.get(v) }
opt.parse!
if aws_opts.empty?
puts opt.help
exit 1
end
AWS.config(aws_opts)
rescue => e
$stderr.puts e
exit 1
end
end
loadbalancers = []
elb = AWS::ELB.new
elb.load_balancers.each do |lb|
response = elb.client.describe_tags(:load_balancer_names => [lb.name])
name_tag = response[:tag_descriptions].first[:tags].find { |tag| tag[:key] == 'Name' }
bill_tag = response[:tag_descriptions].first[:tags].find { |tag| tag[:key] == 'CmBillingGroup' }
loadbalancers << {
:id => lb.name,
:name => name_tag.nil? ? "" : name_tag[:value],
:billing_group => bill_tag.nil? ? "" : bill_tag[:value],
}
end
Formatador.display_compact_table(loadbalancers, [:id, :name, :billing_group])
実行結果
$ ruby cm-elb-describe-billing-tag.rb --profile default
+---------------------------------+-----------+---------------+
| id | name | billing_group |
+---------------------------------+-----------+---------------+
| mylb-stac-ElasticL-G94ZD9MKWYN1 | Prod-MyLB | Production |
+---------------------------------+-----------+---------------+
RDS
RDSでタグを取得するのはEC2やELBよりも、さらに複雑になっています。list_tags_for_resourceに与えるインスタンス識別子はRDS名でなく、ARN(Amazon Resource Name)である必要があります。
ARN文字列には数字12桁のアカウント番号やリージョンを指定する必要があり、これらを別途取得しておく必要があります。
cm-rds-describe-billing-tag.rb
#!/usr/bin/env ruby
require 'aws-sdk'
require 'optparse'
require 'formatador'
begin
require 'aws/profile_parser'
rescue LoadError; end
ARGV.options do |opt|
begin
aws_opts = {}
opt.on('-h', '--help') { puts opt.help; exit 0 }
opt.on('-k', '--access-key ACCESS_KEY') { |v| aws_opts[:access_key_id] = v }
opt.on('-s', '--secret-key SECRET_KEY') { |v| aws_opts[:secret_access_key] = v }
opt.on('-r', '--region REGION') { |v| aws_opts[:region] = v }
opt.on('--profile PROFILE') { |v| parser = AWS::ProfileParser.new; aws_opts = parser.get(v) }
opt.parse!
if aws_opts.empty?
puts opt.help
exit 1
end
AWS.config(aws_opts)
rescue => e
$stderr.puts e
exit 1
end
end
def get_aws_region
AWS.config.region
end
def get_aws_account_id
begin
iam = AWS::IAM.new
iam = iam.client.get_user
r = iam[:user][:arn].match('^arn:aws:iam::([0-9]{12}):.*$')[1]
rescue AWS::IAM::Errors::AccessDenied
result = $!
r = result.to_s.match('^User: arn:aws:iam::([0-9]{12}):.*$')[1]
end
r
end
instances = []
rds = AWS::RDS.new
rds.instances.each do |i|
rds_arn = sprintf("arn:aws:rds:%s:%d:db:%s", get_aws_region, get_aws_account_id, i.db_instance_identifier)
response = rds.client.list_tags_for_resource(:resource_name => rds_arn)
name_tag = response[:tag_list].find { |tag| tag[:key] == 'Name' }
bill_tag = response[:tag_list].find { |tag| tag[:key] == 'CmBillingGroup' }
instances << {
:id => i.id,
:name => name_tag.nil? ? "" : name_tag[:value],
:billing_group => bill_tag.nil? ? "" : bill_tag[:value],
}
end
Formatador.display_compact_table(instances, [:id, :name, :billing_group])
実行結果
$ ruby cm-rds-describe-billing-tag.rb --profile default
+----------------------------------+-----------+---------------+
| id | name | billing_group |
+----------------------------------+-----------+---------------+
| od1ur9hcg5ij6ee | Prod-MyDB | Production |
| od1ur9hcg5ij6ee-till201408051140 | | |
+----------------------------------+-----------+---------------+
まとめ
EC2とEBSについてはとても簡単にインスタンスからタグを取得できます。しかしELBやRDSはインスタンスのメソッドから取得する術がなく、Clientを経由する必要があります。またRDSの場合はRDSインスタンス名でなくARNを指定しなければならず、少々複雑なコードになってしまいます。
AWS SDK for Rubyの将来的なバージョンでは、より簡単にタグが取得できるよう改善されるかもしれませんので期待しましょう。