# -*- coding: utf-8 -*-
require 'json'
require 'gviz'
DISPLAY_INSTANCE_TAG = ['Name', 'status', 'role']
DISPLAY_INSTANCE_ATTR = ['PrivateIpAddress']
def get_tag_value(tags, key)
return nil if tags.nil? or tags == []
tags.each do |k, v|
next unless k
return k['Value'] if k['Key'].downcase == key.downcase
end
nil
end
def get_vpc_info
ret = {}
JSON.parse(`aws ec2 describe-vpcs`)['Vpcs'].each do |vpc|
ret[vpc['VpcId']] = { 'name' => get_tag_value(vpc['Tags'], "name"), 'vpc_id' => vpc['VpcId'], 'subnets' => [], 'elbs' => [] }
end
ret
end
def get_subnet_info
ret = {}
JSON.parse(`aws ec2 describe-subnets`)['Subnets'].each do |subnet|
name = get_tag_value(subnet['Tags'], "name")
ret[subnet['SubnetId']] = { 'name' => get_tag_value(subnet['Tags'], "name"), 'subnet_id' => subnet['SubnetId'], 'vpc_id' => subnet['VpcId'], 'instances' => [] }
end
ret
end
def get_instance_info
ret = {}
JSON.parse(`aws ec2 describe-instances`)['Reservations'].each do |i|
i['Instances'].each do |inst|
attr = {'instance_id' => inst['InstanceId'], 'subnet_id' => inst['SubnetId']}
# 表示させたいタグを取得&設定
DISPLAY_INSTANCE_TAG.each do |tag|
attr.merge!(tag => get_tag_value(inst['Tags'], tag))
end
# 表示させたい属性を取得&設定
DISPLAY_INSTANCE_ATTR.each do |attr_key|
attr.merge!(attr_key => inst[attr_key])
end
ret[inst['InstanceId']] = attr
end
end
ret
end
def get_elb_info
ret = {}
JSON.parse(`aws elb describe-load-balancers`)['LoadBalancerDescriptions'].each do |e|
instance_ids = []
e['Instances'].select {|inst| instance_ids << inst['InstanceId'] if inst['InstanceId'] }
ret[e['LoadBalancerName']] = { 'name' => e['LoadBalancerName'], 'vpc_id' => e['VPCId'], 'instances' => instance_ids, 'health' => {} }
end
ret
end
def get_elb_health(elb_name)
ret = {}
JSON.parse(`aws elb describe-instance-health --load-balancer-name #{elb_name}`)['InstanceStates'].each do |e|
ret[e['InstanceId']] = e['State']
end
ret
end
# VPC情報を取得
vpc = get_vpc_info
# Subnet情報の取得
subnet = get_subnet_info
# VPC情報にSubnetを追加
subnet.each do |subnet_id, v|
next unless vpc[v['vpc_id']]
vpc[v['vpc_id']]['subnets'] << subnet_id
end
# EC2情報を取得
instance = get_instance_info
# Subnet情報にEC2を追加
instance.each do |inst_id, v|
next unless subnet[v['subnet_id']]
subnet[v['subnet_id']]['instances'] << inst_id
end
# ELB情報を取得
elb = get_elb_info
# VPC情報にELBを追加
elb.each do |elb_name, v|
next unless vpc[v['vpc_id']]
vpc[v['vpc_id']]['elbs'] << elb_name
v['health'] = get_elb_health(elb_name)
end
vpc.each do |vpc_id, v|
Graph do
subgraph do
global label:"#{vpc[vpc_id]['name']}"
v['subnets'].each_with_index do |subnet_id, i|
subgraph("cluster#{i+1}") do
global label:"#{subnet[subnet_id]['name']}"
subnet[subnet_id]['instances'].each do |inst_id|
label = "{ "
DISPLAY_INSTANCE_TAG.each_with_index do |tag, i|
label += " | " if i > 0
label += instance[inst_id][tag] ? instance[inst_id][tag] : ""
end
DISPLAY_INSTANCE_ATTR.each_with_index do |at, i|
label += " | "
label += instance[inst_id][at] ? instance[inst_id][at] : ""
end
label += " }"
node:"#{instance[inst_id]['Name'].gsub("-","")}",
:shape => :Mrecord,
:style => :filled,
:fillcolor => :yellow,
:label => label
end
end
end
v['elbs'].each do |elb_name|
node:"#{elb_name.gsub("-","")}"
instance_names = []
elb[elb_name]['instances'].each do |inst_id|
instance_names << instance[inst_id]['Name'].gsub("-","")
color = elb[elb_name]['health'][inst_id] == 'InService' ? "blue" : "red"
edge :"#{elb_name.gsub("-","")}_#{instance[inst_id]['Name'].gsub("-","")}", color:"#{color}"
end
route :"#{elb_name.gsub("-","")}" => instance_names
end
end
save(:"#{v['name']}", :png)
end
`dot -Tpng #{v['name']}.dot -o #{v['name']}.png`
end