# -*- coding: utf-8 -*- require 'isono' require 'ipaddress' module Dcmgr module NodeModules class HvaCollector < Isono::NodeModules::Base include Isono::NodeModules include Dcmgr::Logger initialize_hook do rpc = RpcChannel.new(node) app = Isono::Rack::ObjectMethod.new(myinstance) rpc.register_endpoint('hva-collector', Isono::Rack.build do use Isono::Rack::DataStore run proc { |req, res| Thread.current[Models::BaseNew::LOCK_TABLES_KEY] = {} app.call(req, res) } end) end terminate_hook do end def get_instance(instance_id) inst = Models::Instance[instance_id] raise "UnknownInstanceID" if inst.nil? ret = inst.to_hash ret end def update_instance(instance_id, data) inst = Models::Instance[instance_id] raise "UnknownInstanceID" if inst.nil? if data[:state] == :terminated inst.terminated_at = data[:terminated_at] # Instance#destroy do not really delete row. # just for chain react destroy hooks in the associated models. inst.destroy else inst.set(data).save end # do not respond model object. nil end def get_security_groups_of_instance(instance_id) inst = Models::Instance[instance_id] raise "UnknownInstanceID" if inst.nil? inst.security_groups.map { |g| g.to_hash } end #Returns an array containing the ip addresses of all instances in the same security group. # _set_ determines which ip addresses are returned. There are 3 possible values # :inside is the default value. This returns all inside ip addresses # :outside returns all the outside addresses for instances that are natted. # :all returns all ip addresses regardless of whether they're natted or not def get_group_instance_ipv4s(instance_id,set = :inside) inst = Models::Instance[instance_id] raise "UnknownInstanceID" if inst.nil? raise "Unknown ip set." unless [:inside,:all,:outside].member?(set) inst.security_groups.compact.map { |security_group| # do not include 'stopped' or 'scheduling' instances as they # are not allocated IP address. security_group.instances_dataset.runnings.all.compact.map { |instance| instance.ips.compact.map { |ip| case set when :all ip when :inside ip.map {|i| unless i.is_natted? then i.ipv4 else nil end}.compact when :outside ip.map {|i| if i.is_natted? then i.ipv4 else nil end}.compact end } } }.flatten.uniq.compact end def get_network(network_id) network = Models::Network[network_id] raise "UnknownNetworkID" if network.nil? network.to_hash end def get_nic(nic_uuid) nic = Models::Taggable.find(nic_uuid) raise "UnknownNIC" if nic.nil? nic.to_hash end def get_instance_of_nic(nic_uuid) nic = Models::Taggable.find(nic_uuid) raise "UnknownNIC" if nic.nil? instance = nic.instance raise "UnknownInstance" if instance.nil? instance.to_hash end #Returns the current iplease for nic with uuid _nic_uuid_ def get_iplease_for_nic(nic_uuid) nic = Models::Taggable.find(nic_uuid) raise "UnknownNIC" if nic.nil? Models::IpLease.find(:instance_nic_id => nic[:id])[:ipv4] end def get_nat_leases(nic_uuid) #TODO: get this to work with non canonical uuid nic = Models::Taggable.find(nic_uuid) leases = Models::IpLease.filter({:instance_nic_id => nic[:id]} & ~{:network_id => nic[:network_id]}) leases.map {|l| l[:ipv4]} end def is_natted_ip?(ip) lease = Models::IpLease.find(:ipv4 => ip) return false if lease.nil? #lease.instance_nic.network_id != lease.network_id lease.is_natted? end def get_networks networks = Models::Network.all networks.map { |network| network.to_hash } end def get_dhcp_conf(network_name) build_network_segment = proc { |network| nwaddr = network.ipv4_ipaddress h = { :uuid => network.canonical_uuid, :ipv4_first => nwaddr.first.to_s, :ipv4_last => nwaddr.last.to_s, :ipv4_gw=> network.ipv4_gw, :netmask => nwaddr.prefix.to_ip, :prefix => network.prefix, :dns_server=> network.dns_server, :domain_name => network.domain_name, :metadata_server => network.metadata_server, :mac2addr => [], :addr2host=> [], } network.ip_lease_dataset.filter(:alloc_type=>Models::IpLease::TYPE_AUTO).each { |ip| # ignore IPs unbound to vnic. next if ip.instance_nic.nil? || ip.instance_nic.instance.nil? h[:mac2addr] << { :mac_addr => ip.instance_nic.pretty_mac_addr, :ipaddr => ip.ipv4 } h[:addr2host] << { :hostname => ip.instance_nic.fqdn_hostname, :ipaddr => ip.instance_nic.nat_network_id.nil? ? ip.ipv4 : ip.nat_outside_lease.ipv4 } } h } network_set = nil Tags::NetworkPool Models::Network case network = Models::Taggable.find(network_name) when Models::Network network_set = [network] when Tags::NetworkPool network_set = network.mapped_uuids.map {|m| Models::Network[m.uuid] } else raise "Unknown network name: #{network_name}" end h = {} network_set.each {|n| h[n.canonical_uuid] = build_network_segment.call(n) } h end def get_instances_of_security_group(security_group_uuid) sg_map = Models::SecurityGroup[security_group_uuid] raise "Unknown security group ID: #{security_group_uuid}" if sg_map.nil? # do not include 'stopped' or 'scheduling' instances as they # are not allocated IP address. inst_maps = sg_map.instances_dataset.runnings.all.map { |inst| inst.to_hash }.flatten.uniq.compact inst_maps end def get_alive_instances(node_id) hp = Models::HostNode.find(:node_id => node_id) if hp.nil? logger.error("The node ID is not bound to HostNode yet: #{node_id}") return [] end hps = Models::HostNode.where(:account_id => hp.account_id).all inst_on_hp = hps.map { |hp| inst_on_hp = hp.instances_dataset.runnings.all.map { |inst| inst_map = inst.to_hash # Does the hva have instance? next unless inst_map[:host_node][:node_id] == node_id inst_map } }.flatten.uniq.compact inst_on_hp end # Method designed to get all data needed for the netfilter service in a single request def get_netfilter_data(node_id) inst_maps = get_alive_instances(node_id) #Determine which security groups are in use secg_uuids = inst_maps.map { |inst_map| inst_map[:security_groups] }.flatten.uniq secg_maps = Models::SecurityGroup.map { |secg| secg.to_hash if secg_uuids.member? secg.canonical_uuid }.compact # Trim out the data netfilter doesn't need and return a clean hash { :instances => inst_maps.map { |inst_map| { :uuid => inst_map[:uuid], :security_groups => inst_map[:security_groups], :vif => inst_map[:vif].map { |vif| vif.merge({:security_groups => inst_map[:security_groups]}) }# <-- Just putting the security groups in vif for the vnet isolator, gonna properly do this in the database asap } }, :security_groups => secg_maps } end end end end