From: marios <[email protected]>
Signed-off-by: marios <[email protected]> --- server/lib/deltacloud/drivers/base_driver.rb | 7 + server/lib/deltacloud/drivers/ec2/ec2_driver.rb | 105 ++++++++-- .../drivers/openstack/openstack_driver.rb | 216 ++++++++++++++++++++- 3 files changed, 309 insertions(+), 19 deletions(-) diff --git a/server/lib/deltacloud/drivers/base_driver.rb b/server/lib/deltacloud/drivers/base_driver.rb index 85a2148..3d14611 100644 --- a/server/lib/deltacloud/drivers/base_driver.rb +++ b/server/lib/deltacloud/drivers/base_driver.rb @@ -259,6 +259,13 @@ module Deltacloud addresses(credentials, opts).first if has_capability?(:addresses) end + def network(credentials, opts={}) + networks(credentials, opts).first if has_capability?(:networks) + end + + def subnet(credentials, opts={}) + subnets(credentials, opts).first if has_capability?(:subnets) + end MEMBER_SHOW_METHODS = [ :realm, :image, :instance, :storage_volume, :bucket, :blob, :key, :firewall ] unless defined?(MEMBER_SHOW_METHODS) diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb index 62c72cc..88016eb 100644 --- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb +++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb @@ -268,14 +268,8 @@ module Deltacloud if opts[:metrics] and !opts[:metrics].empty? instance_options[:monitoring_enabled] = true end - if opts[:realm_id] - az, sn = opts[:realm_id].split(":") - if sn - instance_options[:subnet_id] = sn - else - instance_options[:availability_zone] = az - end - end + instance_options[:availability_zone] = opts[:realm_id] if opts[:realm_id] + instance_options[:subnet_id] = opts[:subnet_id] if opts[:subnet_id] #FIXME should we fail if no :network_id ? don't need it but need consistency in API... instance_options[:key_name] = opts[:keyname] if opts[:keyname] instance_options[:instance_type] = opts[:hwp_id] if opts[:hwp_id] && opts[:hwp_id].length > 0 firewalls = opts.inject([]){|res, (k,v)| res << v if k =~ /firewalls\d+$/; res} @@ -835,6 +829,73 @@ module Deltacloud end end + #Deltacloud Networks == Amazon VPC + def networks(credentials, opts={}) + ec2 = new_client(credentials) + networks = [] + safely do + subnets = subnets(credentials) #get all subnets once + ec2.describe_vpcs.each do |vpc| + vpc_subnets = subnets.inject([]){|res,cur| res<<cur if cur.network==vpc[:vpc_id] ;res} #collect subnets for this.network + networks << convert_vpc(vpc, vpc_subnets) + end + end + networks = filter_on(networks, :id, opts) + end + + def create_network(credentials, opts={}) + ec2 = new_client(credentials) + safely do + network = ec2.create_vpc(opts[:address_block]).first + convert_vpc(network) + end + end + + def destroy_network(credentials, network_id) + ec2 = new_client(credentials) + safely do + ec2.delete_vpc(network_id) + end + end + + def subnets(credentials, opts={}) + ec2 = new_client(credentials) + subnets = [] + safely do + ec2.describe_subnets.each do |sn| + subnets << convert_subnet(sn) + end + end + subnets = filter_on(subnets, :id, opts) + end + + def create_subnet(credentials, opts={}) + ec2 = new_client(credentials) + safely do + subnet = ec2.create_subnet(opts[:network_id], opts[:address_block]) + convert_subnet(subnet) + end + end + + def destroy_subnet(credentials, opts={}) + # this method need to be called + # with the subnet_id as parameter + # in order to work + + # ec2 = new_client(credentials) + # safely do + # ec2.delete_subnet(opts[:vpc_id]) + # end + # Subnet.delete(:name=>opts[:vpc_id]) + # + end + + def ports(credentials, opts={}) + # + # Need more investigations + # + end + def providers(credentials, opts={}) ec2 = new_client(credentials) @providers ||= ec2.describe_regions.map{|r| Provider.new( {:id=>r, :name=>r, @@ -966,7 +1027,7 @@ module Deltacloud unless instance[:subnet_id].empty? realm_id = "#{realm_id}:#{instance[:subnet_id]}" end - Instance.new( + inst_params = { :id => instance[:aws_instance_id], :name => instance[:aws_image_id], :state => convert_state(instance[:aws_state]), @@ -981,8 +1042,11 @@ module Deltacloud :private_addresses => [InstanceAddress.new(instance[:private_dns_name], :type => :hostname)], :firewalls => instance[:aws_groups], :storage_volumes => instance[:block_device_mappings].map{|vol| {vol.values.first=>vol.keys.first } }, - :create_image => can_create_image - ) + :create_image => can_create_image } + if instance[:vpc_id] + inst_params.merge!(:network_bindings => [{:network=>instance[:vpc_id], :subnet=>instance[:subnet_id], :ip_address=> instance[:aws_private_ip_address]}]) + end + Instance.new(inst_params) end def convert_key(key) @@ -1159,6 +1223,25 @@ module Deltacloud end end + def convert_vpc(vpc, subnets=[]) + addr_blocks = subnets.inject([]){|res,cur| res << cur.address_block ; res} + Network.new({ :id => vpc[:vpc_id], + :name => vpc[:vpc_id], + :state=> vpc[:state], + :subnets => subnets.inject([]){|res,cur| res << cur.id ;res}, + :address_blocks=> (addr_blocks.empty? ? [vpc[:cidr_block]] : addr_blocks) }) + end + + def convert_subnet(subnet) + Subnet.new({ :id => subnet[:subnet_id], + :name => subnet[:subnet_id], + :network =>subnet[:vpc_id], + :address_block => subnet[:cidr_block], + :state => subnet[:state] }) + end + + + exceptions do on /root device is not supported for the instance/ do diff --git a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb index 343934d..bfcca85 100644 --- a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb +++ b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb @@ -162,19 +162,24 @@ module Deltacloud def instances(credentials, opts={}) os = new_client(credentials) - insts = attachments = [] + insts = attachments = ports = [] safely do + if quantum = have_quantum?(credentials) + ports = quantum.ports + end if opts[:id] begin server = os.get_server(opts[:id]) - insts << convert_from_server(server, os.connection.authuser, get_attachments(opts[:id], os)) + net_bind = get_net_bindings_for(server.id, ports) + insts << convert_from_server(server, os.connection.authuser, get_attachments(opts[:id], os), net_bind) rescue => e raise e unless e.message =~ /The resource could not be found/ insts = [] end else insts = os.list_servers_detail.collect do |s| - convert_from_server(s, os.connection.authuser,get_attachments(s[:id], os)) + net_bind = get_net_bindings_for(s[:id], ports) + convert_from_server(s, os.connection.authuser,get_attachments(s[:id], os), net_bind) end end end @@ -182,6 +187,30 @@ module Deltacloud insts end + #le port: + #=> #<OpenStack::Network::Port:0x95a833c @id="d601db9e-c936-4811-904a-bb5a27d105f3", @network_id="c4dfe90e-a7ce-41f7-b9b2-2f9773f42a6b", @name="", @admin_state_up=true, @status="ACTIVE", @mac_address="fa:16:3e:f4:e8:bc", @fixed_ips=[{"subnet_id"=>"f78bfc05-ead0-40a6-8325-a35eb2b535c3", "ip_address"=>"10.0.0.4"}], @device_id="fe4022fa-a77c-4adf-be45-6e069fb3a314", @device_owner="", @tenant_id="7be215d541ea4db4a23b3a84b0882408"> + def get_net_bindings_for(server_id, ports) + return [] if ports.empty? + net_bind = [] + ports.each do |port| + if port.device_id == server_id + port.fixed_ips.each do |fix_ip| + net_bind << {:network=> port.network_id, :subnet=>fix_ip["subnet_id"] , :ip_address=>fix_ip["ip_address"]} + end + end + end + net_bind + end + + def have_quantum?(credentials) + begin + quantum = new_client(credentials, "network") + rescue => e + return nil + end + quantum + end + def create_instance(credentials, image_id, opts) os = new_client( credentials, "compute") result = nil @@ -203,7 +232,13 @@ module Deltacloud end safely do server = os.create_server(params) - result = convert_from_server(server, os.connection.authuser, get_attachments(server.id, os)) + net_bind = [] + if opts[:network_id] && opts[:subnet_id] && (quantum=have_quantum?(credentials)) #place instance into a network + port = quantum.create_port(opts[:network_id], {"fixed_ips"=>[{"subnet_id"=>opts[:subnet_id]}], "device_id"=>server.id}) + net_bind = [{:network=>opts[:network], :subnet=>opts[:subnet_id], :ip_address=>port.fixed_ips.first["ip_address"]}] + server.refresh + end + result = convert_from_server(server, os.connection.authuser, get_attachments(server.id, os), net_bind) end result end @@ -224,6 +259,13 @@ module Deltacloud safely do server = os.get_server(instance_id) server.delete! + if quantum = have_quantum?(credentials) #destroy ports if any + quantum.ports.each do |port| + if port.device_id == server.id + quantum.delete_port(port.id) + end + end + end end begin server.populate @@ -473,6 +515,160 @@ module Deltacloud end end + def networks(credentials, opts={}) + os = new_client(credentials, "network") + networks = [] + safely do + subnets = os.subnets + os.networks.each do |net| + addr_blocks = get_address_blocks_for(net.id, subnets) + networks << convert_network(net, addr_blocks) + end + end + networks = filter_on(networks, :id, opts) + end + + def get_address_blocks_for(network_id, subnets) + return [] if subnets.empty? + addr_blocks = [] + subnets.each do |sn| + if sn.network_id == network_id + addr_blocks << sn.cidr + end + end + addr_blocks + end + + + def convert_network(net, addr_blocks) + Network.new({ :id => net.id, + :name => net.name, + :subnets => net.subnets, + :state => (net.admin_state_up ? "UP" : "DOWN"), + :address_blocks => addr_blocks + #NOT USED :address_block, :ports + }) + end + + #require params for openstack: {:name} + def create_network(credentials, opts={}) + os = new_client(credentials, "network") + safely do + net = os.create_network(opts[:name] || "net_#{Time.now.to_i}") + convert_network(net) + end + end + + def destroy_network(credentials, id) + os = new_client(credentials, "network") + safely do + os.delete_network(id) + end + end + + #can update name or admin_state_up (true/false) + def update_network(credentials, opts={}) + os = new_client(credentials, "network") + safely do + os.update_network(opts) + end + end + + #you can list all subnets - don't need to supply network_id + #each subnet returned 'knows' its parent network_id + #no opts - could use opts for filtering = e.g. ?name=foo + def subnets(credentials, opts={}) + os = new_client(credentials, "network") + subnets = [] + safely do + os.subnets.each do |subnet| + subnets << convert_subnet(subnet) + end + end + subnets = filter_on(subnets, :id, opts) + end + + def convert_subnet(subnet) + Subnet.new({ :id => subnet.id, + :name => subnet.name, + :network => subnet.network_id, + :address_block => subnet.cidr, #or allocation_pools? start..end + # :state :type + # in quantum, ports have a 'network_id' + }) + end + + #required params: :network_id, cidr_block + #optional params: :ip_version, :gateway_ip, :allocation_pools + def create_subnet(credentials, opts={}) + os = new_client(credentials, "network") + safely do + convert_subnet(os.create_subnet(opts[:network_id], opts[:address_block])) + end + end + + #can update gateway_ip, name + def update_subnet(credentials, opts={}) + os = new_client(credentials, "network") + safely do + os.update_subnet() + end + end + + def destroy_subnet(credentials, subnet_id) + os = new_client(credentials, "network") + safely do + os.delete_subnet(subnet_id) + end + end + +# def ports(credentials, opts={}) +# os = new_client(credentials, "network") +# ports = [] +# safely do +# os.ports.each do |port| +# ports << convert_port(port) +# end +# end +# ports +# end +# +# def convert_port(port) +# Port.new({ :id => port.id, +# :attachment => port.device_id, +# :network => port.network_id, #network, not subnet +# :mac_address => port.mac_address, +# :state => (port.admin_state_up ? "UP" : "DOWN" ), # true/false +# :ip_address => port.fixed_ips # this is a structure; like [{"subnet_id": "f45087fa-a673-4c98-ba9e-e21642448997", "ip_address": "10.0.0.5"}] - COULD BE >1 address here... +# # UNUSED/no mapping for :type, :attachment (can be inferred from IP address(es)?) +# }) +# end +# +# #required params: network_id +# #optional params: name, mac_address, state, fixedIP (subnet_id AND/OR IP) +# def create_port(credentials, opts={}) +# os = new_client(credentials, "network") +# safely do +# convert_port(os.create_port(opts)) +# end +# end +# +# +# #can update name, device_id, state (what else? not clear from API docs) +# def update_port(credentials, opts={}) +# os = new_client(credentials, "network") +# safely do +# os.update_port(opts[:id], opts) +# end +# end +# +# def destroy_port(credentials, port_id) +# os = new_client(credentials, "network") +# safely do +# os.delete_port(port_id) +# end +# end +# private #for v2 authentication credentials.name == "username+tenant_name" def new_client(credentials, type="compute", ignore_provider=false) @@ -495,7 +691,7 @@ private connection_params.merge!({:region => region}) if region && !ignore_provider # hack needed for 'def providers' safely do raise ValidationFailure.new(Exception.new("Error: tried to initialise Openstack connection using" + - " an unknown service_type: #{type}")) unless ["volume", "compute", "object-store"].include? type + " an unknown service_type: #{type}")) unless ["volume", "compute", "object-store", "network"].include? type OpenStack::Connection.create(connection_params) end end @@ -529,7 +725,7 @@ private }) end - def convert_from_server(server, owner, attachments=[]) + def convert_from_server(server, owner, attachments=[], net_bind=[]) op = (server.class == Hash)? :fetch : :send image = server.send(op, :image) flavor = server.send(op, :flavor) @@ -538,7 +734,7 @@ private rescue IndexError password = "" end - inst = Instance.new( + inst_params = { :id => server.send(op, :id).to_s, :realm_id => "default", :owner_id => owner, @@ -555,7 +751,11 @@ private :keyname => server.send(op, :key_name), :launch_time => server.send(op, :created), :storage_volumes => attachments.inject([]){|res, cur| res << {cur[:volumeId] => cur[:device]} ;res} - ) + } + unless net_bind.empty? + inst_params.merge!(:network_bindings=>net_bind) + end + inst = Instance.new(inst_params) inst.actions = instance_actions_for(inst.state) inst.create_image = 'RUNNING'.eql?(inst.state) inst -- 1.8.1.4
