lib/dcmgr/endpoints/metadata.rb in wakame-vdc-agents-11.06.0 vs lib/dcmgr/endpoints/metadata.rb in wakame-vdc-agents-11.12.0

- old
+ new

@@ -3,34 +3,39 @@ require 'extlib' require 'sinatra/base' require 'sinatra/sequel_transaction' require 'yaml' require 'json' +require 'ipaddress' require 'dcmgr' # Metadata service endpoint for running VMs. # The running VM can not identify itself that who or where i am. The service supplies these information from somewhere -# out of the VM. It publishes some very crucial information to each VM so that the access control to this service is +# out of the VM. It publishes some very crucial information to each VM so that the access control to this service is # mandated at both levels, the network and the application itself. -# -# The concept of the service is similar with Amazon EC2's Metadata service given via http://169.254.169.254/. The +# +# The concept of the service is similar with Amazon EC2's Metadata service given via http://169.254.169.254/. The # difference is the URI structure. This gives the single point URI as per below: # http://metadata.server/[version]/meatadata.[format] -# It will return a document which results in a syntax specified in the last extension field. The document contains +# It will return a document which results in a syntax specified in the last extension field. The document contains # over all information that the VM needs for self recoginition. +# +# see also +# http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html?instancedata-data-categories.html + module Dcmgr module Endpoints class Metadata < Sinatra::Base include Dcmgr::Logger register Sinatra::SequelTransaction disable :sessions disable :show_exceptions LATEST_PROVIDER_VER_ID='2011-05-19' - + get '/' do '' end get '/:version/meta-data/:data' do @@ -39,11 +44,11 @@ get '/:version/metadata.*' do #get %r!\A/(\d{4}-\d{2}-\d{2})/metadata.(\w+)\Z! do v = parse_version params[:version] ext = params[:splat][0] - + hash_doc = begin self.class.find_const("Provider_#{v}").new.document(request.ip) rescue NameError => e raise e if e.is_a? NoMethodError logger.error("ERROR: Unsupported metadata version: #{v}") @@ -66,13 +71,13 @@ end private def get_data(params) v = parse_version params[:version] - + get_method = params[:data].gsub(/-/,'_') - + provider = begin self.class.find_const("Provider_#{v}").new rescue NameError => e raise e if e.is_a? NoMethodError logger.error("ERROR: Unsupported metadata version: #{v}") @@ -91,23 +96,23 @@ error(404, "Unknown metadata: #{get_method}") end result end - + def parse_version(v) ret = case v when 'latest' LATEST_PROVIDER_VER_ID when /\A\d{4}-\d{2}-\d{2}\Z/ v else - raise "Invalid syntax in the version" + raise "Invalid syntax in the version" end ret.gsub(/-/, '') end - + def shell_dump(hash) # TODO: values to be shell escaped hash.map {|k,v| "#{k.to_s.upcase}='#{v}'" }.join("\n") @@ -153,11 +158,11 @@ } ret[:volume] = inst.volume.map { |v| } ret end - + def get_instance_from_ip(src_ip) ip = Models::IpLease.find(:ipv4=>src_ip) if ip.nil? || ip.instance_nic.nil? raise UnknownSourceIpError, src_ip end @@ -206,33 +211,33 @@ # http://169.254.169.254/latest/meta-data/reservation-id def wmi_id(src_ip) get_instance_from_ip(src_ip).image.cuuid end alias ami_id wmi_id - + def mac(src_ip) get_instance_from_ip(src_ip).nic.map { |nic| nic.pretty_mac_addr }.join("\n") end - + def network(src_ip) get_instance_from_ip(src_ip).nic.map { |nic| nic.ip.map { |ip| ip.network.cuuid } }.join("\n") end - + def instance_id(src_ip) get_instance_from_ip(src_ip).cuuid end - + def local_hostname(src_ip) get_instance_from_ip(src_ip).hostname end - + def local_ipv4(src_ip) get_instance_from_ip(src_ip).nic.map { |nic| nic.ip.map { |ip| unless ip.is_natted? ip.ipv4 @@ -240,11 +245,11 @@ nil end }.compact }.join("\n") end - + def public_ipv4(src_ip) get_instance_from_ip(src_ip).nic.map { |nic| nic.ip.map { |ip| if ip.is_natted? ip.ipv4 @@ -252,25 +257,357 @@ nil end }.compact }.join("\n") end - + def public_keys(src_ip) i = get_instance_from_ip(src_ip) # ssh_key_data is possible to be nil. i.ssh_key_data.nil? ? '' : i.ssh_key_data[:public_key] end - + def security_groups(src_ip) - get_instance_from_ip(src_ip).netfilter_groups.map { |grp| - grp.name + get_instance_from_ip(src_ip).security_groups.map { |grp| + grp.canonical_uuid }.join("\n") end - + def user_data(src_ip) get_instance_from_ip(src_ip).user_data end end end + + class Ec2Metadata < Sinatra::Base + include Dcmgr::Logger + register Sinatra::SequelTransaction + + disable :sessions + disable :show_exceptions + + API_VERSIONS = ['latest', '2011-01-01'] + TOP_LEVEL_ITEMS = ['meta-data', 'user-data' ] + TOP_LEVEL_METADATA_ITEMS = [ + 'ami-id', + 'ami-launch-index', + 'ami-manifest-path', + 'ancestor-ami-ids', + 'block-device-mapping/', + 'hostname', + 'instance-action', + 'instance-id', + 'instance-type', + 'kernel-id', + 'local-hostname', + 'local-ipv4', + 'mac', + 'network/', + 'placement/', + 'product-codes', + 'public-hostname', + 'public-ipv4', + 'public-keys/', + 'ramdisk-id', + 'reservation-id', + 'security-groups', + ] + + get '/' do + API_VERSIONS.join("\n") + end + + get '/:version' do + '' + end + + get '/:version/' do + TOP_LEVEL_ITEMS.join("\n") + end + + get '/:version/user-data' do + instance[:user_data] + end + + get '/:version/meta-data/' do + TOP_LEVEL_METADATA_ITEMS.join("\n") + end + + get '/:version/meta-data/ami-id' do + instance[:image][:uuid] + end + + get '/:version/meta-data/ami-launch-index' do + # TODO + '0' + end + + get '/:version/meta-data/ami-manifest-path' do + # TODO + '' + end + + get '/:version/meta-data/ancestor-ami-ids' do + # TODO + '' + end + + get '/:version/meta-data/block-device-mapping/' do + # TODO + 'root' + end + + get '/:version/meta-data/block-device-mapping/root' do + # TODO + '/dev/sda' + end + + get '/:version/meta-data/hostname' do + instance[:hostname] + end + + get '/:version/meta-data/instance-action' do + instance[:state] + end + + get '/:version/meta-data/instance-id' do + instance[:uuid] + end + + get '/:version/meta-data/instance-type' do + instance[:instance_spec][:uuid] + end + + get '/:version/meta-data/kernel-id' do + # TODO + '' + end + + get '/:version/meta-data/local-hostname' do + instance[:hostname] + end + + get '/:version/meta-data/local-ipv4' do + instance[:ips].first + end + + get '/:version/meta-data/mac' do + vnic = instance[:instance_nics].first || {} + vnic[:mac_addr].unpack('A2'*6).join(':') + end + + get '/:version/meta-data/network/' do + 'interfaces/' + end + + get '/:version/meta-data/network/interfaces/' do + 'macs/' + end + + get '/:version/meta-data/network/interfaces/macs/' do + instance[:vif].map { |vnic| + "#{vnic[:mac_addr].unpack('A2'*6).join(':')}/" + }.join("\n") + end + + get '/:version/meta-data/network/interfaces/macs/:mac/' do + if vnic_mac?(params[:mac]) + [ + 'local-hostname', + 'local-ipv4s', + 'mac', + 'public-hostname', + 'public-ipv4s', + 'security-groups', + # wakame-vdc extention items. + 'x-gateway', + 'x-netmask', + 'x-network', + 'x-broadcast', + 'x-metric', + ].join("\n") + else + # TODO + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/local-hostname' do + if vnic_mac?(params[:mac]) + instance[:hostname] + else + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/local-ipv4s' do + if vnic_mac?(params[:mac]) + vnic = vnic(params[:mac]) + vnic[:ipv4][:address] + else + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/mac' do + if vnic_mac?(params[:mac]) + params[:mac] + else + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/public-hostname' do + if vnic_mac?(params[:mac]) + instance[:hostname] + else + # TODO + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/public-ipv4s' do + if vnic_mac?(params[:mac]) + vnic = vnic(params[:mac]) + vnic[:ipv4][:nat_address] + else + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/security-groups' do + if vnic_mac?(params[:mac]) + instance[:security_groups].join("\n") + else + # TODO + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/x-gateway' do + if vnic_mac?(params[:mac]) + vnic(params[:mac])[:ipv4][:network][:ipv4_gw] + else + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/x-netmask' do + if vnic_mac?(params[:mac]) + vnic = vnic(params[:mac]) + netaddr = IPAddress::IPv4.new("#{vnic[:ipv4][:network][:ipv4_network]}/#{vnic[:ipv4][:network][:prefix]}") + netaddr.prefix.to_ip + else + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/x-network' do + if vnic_mac?(params[:mac]) + vnic = vnic(params[:mac]) + vnic[:ipv4][:network][:ipv4_network] + else + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/x-broadcast' do + if vnic_mac?(params[:mac]) + vnic = vnic(params[:mac]) + netaddr = IPAddress::IPv4.new("#{vnic[:ipv4][:network][:ipv4_network]}/#{vnic[:ipv4][:network][:prefix]}") + netaddr.broadcast.to_s + else + '' + end + end + + get '/:version/meta-data/network/interfaces/macs/:mac/x-metric' do + if vnic_mac?(params[:mac]) + vnic = vnic(params[:mac]) + vnic[:ipv4][:network][:metric].to_s + else + '' + end + end + + get '/:version/meta-data/placement/' do + 'availability-zone' + end + + get '/:version/meta-data/placement/availability-zone' do + # TODO + '' + end + + get '/:version/meta-data/product-codes' do + # TODO + '' + end + + get '/:version/meta-data/public-hostname' do + # TODO + instance[:hostname] + end + + get '/:version/meta-data/public-ipv4' do + instance[:nat_ips] + end + + get '/:version/meta-data/public-keys/' do + ssh_key_data = instance[:ssh_key_data] + ssh_key_data.nil? ? '' : [0, ssh_key_data[:uuid]].join("=") + end + + get '/:version/meta-data/public-keys/0/' do + ssh_key_data = instance[:ssh_key_data] + ssh_key_data.nil? ? '' : 'openssh-key' + end + + get '/:version/meta-data/public-keys/0/openssh-key' do + ssh_key_data = instance[:ssh_key_data] + # ssh_key_data is possible to be nil. + ssh_key_data.nil? ? '' : ssh_key_data[:public_key] + end + + get '/:version/meta-data/ramdisk-id' do + # TODO + '' + end + + get '/:version/meta-data/reservation-id' do + # TODO + '' + end + + get '/:version/meta-data/security-groups' do + instance[:security_groups].join("\n") + end + + private + def instance + ip = Models::IpLease.find(:ipv4 => request.ip) + if ip.nil? || ip.instance_nic.nil? + raise UnknownSourceIpError, request.ip + end + ip.instance_nic.instance.to_hash + end + + def vnic_mac?(mac) + if vnic(mac).size > 0 + true + else + false + end + end + + def vnic(mac) + instance[:vif].map { |vnic| + vnic if mac == vnic[:mac_addr].unpack('A2'*6).join(':') + }.compact.first + end + + class UnknownSourceIpError < StandardError; end + + end + end end