You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by ma...@redhat.com on 2013/03/20 18:02:49 UTC
Network-API-rev-2-RFC
patches are at http://tracker.deltacloud.org/set/395
write-up at http://mariosandreou.com/deltacloud/cloud_API/2013/03/20/deltacloud-networks-api-rfc.html
I'll be working on RHEV-M next - any comments are very much appreciated!
thanks, marios
[PATCH 1/4] Network API rev 2 (RFC) - Models
Posted by ma...@redhat.com.
From: marios <ma...@redhat.com>
Signed-off-by: marios <ma...@redhat.com>
---
server/lib/deltacloud/models.rb | 2 ++
server/lib/deltacloud/models/instance.rb | 1 +
server/lib/deltacloud/models/network.rb | 25 +++++++++++++++++++++++++
server/lib/deltacloud/models/subnet.rb | 27 +++++++++++++++++++++++++++
4 files changed, 55 insertions(+)
create mode 100644 server/lib/deltacloud/models/network.rb
create mode 100644 server/lib/deltacloud/models/subnet.rb
diff --git a/server/lib/deltacloud/models.rb b/server/lib/deltacloud/models.rb
index e6020e6..7dbf3dc 100644
--- a/server/lib/deltacloud/models.rb
+++ b/server/lib/deltacloud/models.rb
@@ -32,3 +32,5 @@ require_relative 'models/realm'
require_relative 'models/state_machine'
require_relative 'models/storage_snapshot'
require_relative 'models/storage_volume'
+require_relative 'models/network'
+require_relative 'models/subnet'
diff --git a/server/lib/deltacloud/models/instance.rb b/server/lib/deltacloud/models/instance.rb
index 6c6b018..e88e5f0 100644
--- a/server/lib/deltacloud/models/instance.rb
+++ b/server/lib/deltacloud/models/instance.rb
@@ -34,6 +34,7 @@ module Deltacloud
attr_accessor :create_image
attr_accessor :firewalls
attr_accessor :storage_volumes
+ attr_accessor :network_bindings
def to_hash(context)
r = {
diff --git a/server/lib/deltacloud/models/network.rb b/server/lib/deltacloud/models/network.rb
new file mode 100644
index 0000000..e8a9082
--- /dev/null
+++ b/server/lib/deltacloud/models/network.rb
@@ -0,0 +1,25 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+module Deltacloud
+class Network < BaseModel
+
+ attr_accessor :name
+ attr_accessor :subnets
+ attr_accessor :address_blocks
+ attr_accessor :state
+
+end
+end
diff --git a/server/lib/deltacloud/models/subnet.rb b/server/lib/deltacloud/models/subnet.rb
new file mode 100644
index 0000000..d91a7a9
--- /dev/null
+++ b/server/lib/deltacloud/models/subnet.rb
@@ -0,0 +1,27 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+class Subnet < BaseModel
+
+ attr_accessor :name
+ attr_accessor :network
+ attr_accessor :address_block
+ attr_accessor :state
+ attr_accessor :type
+
+end
+end
--
1.8.1.4
[PATCH 3/4] Network API rev 2 (RFC) - Views
Posted by ma...@redhat.com.
From: marios <ma...@redhat.com>
Signed-off-by: marios <ma...@redhat.com>
---
server/views/instances/new.html.haml | 9 +++++++++
server/views/instances/show.html.haml | 9 +++++++++
server/views/networks/index.html.haml | 10 ++++++++++
server/views/networks/index.xml.haml | 4 ++++
server/views/networks/new.html.haml | 10 ++++++++++
server/views/networks/show.html.haml | 24 ++++++++++++++++++++++++
server/views/networks/show.xml.haml | 15 +++++++++++++++
server/views/subnets/index.html.haml | 10 ++++++++++
server/views/subnets/index.xml.haml | 4 ++++
server/views/subnets/new.html.haml | 14 ++++++++++++++
server/views/subnets/show.html.haml | 24 ++++++++++++++++++++++++
server/views/subnets/show.xml.haml | 13 +++++++++++++
12 files changed, 146 insertions(+)
create mode 100644 server/views/networks/index.html.haml
create mode 100644 server/views/networks/index.xml.haml
create mode 100644 server/views/networks/new.html.haml
create mode 100644 server/views/networks/show.html.haml
create mode 100644 server/views/networks/show.xml.haml
create mode 100644 server/views/subnets/index.html.haml
create mode 100644 server/views/subnets/index.xml.haml
create mode 100644 server/views/subnets/new.html.haml
create mode 100644 server/views/subnets/show.html.haml
create mode 100644 server/views/subnets/show.xml.haml
diff --git a/server/views/instances/new.html.haml b/server/views/instances/new.html.haml
index f6f674e..e22a110 100644
--- a/server/views/instances/new.html.haml
+++ b/server/views/instances/new.html.haml
@@ -84,6 +84,15 @@
%input{ :type => :text, :id => "path#{i}", :name => "path#{i}", :value => ""} Path #{i}
%input{ :type => "file", :name => "content#{i}", :size => 50 }
+ - if driver.has_capability? :networks
+ %div{ 'data-role' => :fieldcontain }
+ %label{ :for => :network, :class => 'ui-input-text'} Network to Launch Instance into:
+ %select{:name => 'network_id', :'data-native-menu' => "true" }
+ %option{ :value => ''} None
+ - @networks.each do |net|
+ - net.subnets.each do |sn|
+ %option{ :value => "#{net.id}+#{sn}" } #{net.id}+#{sn}
+
- if !@hardware_profiles.empty?
%div{ 'data-role' => :fieldcontain }
%h3 Instance profile
diff --git a/server/views/instances/show.html.haml b/server/views/instances/show.html.haml
index ae193aa..37446bf 100644
--- a/server/views/instances/show.html.haml
+++ b/server/views/instances/show.html.haml
@@ -56,6 +56,15 @@
-@instance.storage_volumes.each do |vol|
%li
%a{ :href => storage_volume_url("#{vol.keys.first}"), :'data-ajax' => 'false'}=["#{vol.keys.first}", "#{vol.values.first}"].compact.reject{ |e| e.empty? }.join(' <---> ')
+ - if @instance.network_bindings
+ %li{ :'data-role' => 'list-divider'} Network Bindings
+ -@instance.network_bindings.each do |net_bind|
+ %li
+ %a{ :href => network_url("#{net_bind[:network]}"), :'data-ajax' => 'false'}="Network #{net_bind[:network]}"
+ %li
+ %a{ :href => subnet_url("#{net_bind[:subnet]}"), :'data-ajax' => 'false'}="Subnet #{net_bind[:subnet]}"
+ %li="Address #{net_bind[:ip_address]}"
+ %li
%li{ :'data-role' => 'list-divider'} Actions
%li
%div{ :'data-role' => 'controlgroup', :'data-type' => "horizontal" }
diff --git a/server/views/networks/index.html.haml b/server/views/networks/index.html.haml
new file mode 100644
index 0000000..aa0050b
--- /dev/null
+++ b/server/views/networks/index.html.haml
@@ -0,0 +1,10 @@
+=header "Networks" do
+ %a{ :href => url_for('networks/new'), :'data-icon' => :plus, :'data-role' => :button, :class => 'ui-btn-right'} Create new network
+
+%div{ :'data-role' => :content, :'data-theme' => 'c'}
+ %ul{ :'data-role' => :listview , :'data-inset' => :true, :'data-divider-theme' => 'a'}
+ - @elements.each do |net|
+ %li
+ %a{ :href => network_url(net.id), :'data-ajax' => 'false'}
+ %img{ :class => 'ui-link-thumb', :src => '/images/cloud.png'}
+ %h3=net.id
diff --git a/server/views/networks/index.xml.haml b/server/views/networks/index.xml.haml
new file mode 100644
index 0000000..f2eaac6
--- /dev/null
+++ b/server/views/networks/index.xml.haml
@@ -0,0 +1,4 @@
+!!!XML
+%networks
+ - @elements.each do |c|
+ = haml :'networks/show', :locals => { :@network => c, :partial => true }
diff --git a/server/views/networks/new.html.haml b/server/views/networks/new.html.haml
new file mode 100644
index 0000000..0087259
--- /dev/null
+++ b/server/views/networks/new.html.haml
@@ -0,0 +1,10 @@
+=header "Create new network"
+
+%div{ :'data-role' => :content, :'data-theme' => 'c', :class => 'middle-dialog'}
+ %form{ :action => networks_url, :method => :post}
+ %div{ 'data-role' => :fieldcontain }
+ %p
+ %label{ :for => :address_block} CIDR Address block (optional):
+ %p
+ %input{ :type => :text, :id => :address_block, :name => :address_block, :value => '' }
+ %button{ :type => :submit} Create network
diff --git a/server/views/networks/show.html.haml b/server/views/networks/show.html.haml
new file mode 100644
index 0000000..18fef78
--- /dev/null
+++ b/server/views/networks/show.html.haml
@@ -0,0 +1,24 @@
+=header "Network"
+=subheader @network.id
+
+%div{ :'data-role' => :content, :'data-theme' => 'c'}
+ %ul{ :'data-role' => :listview , :'data-inset' => :true, :'data-divider-theme' => 'd'}
+ %li{ :'data-role' => 'list-divider'} Identifier
+ %li
+ %p{ :'data-role' => 'fieldcontain'}=@network.id
+ %li{ :'data-role' => 'list-divider'} Name
+ %li
+ %p{ :'data-role' => 'fieldcontain'}=@network.name
+ %li{ :'data-role' => 'list-divider'} State
+ %li
+ %p{ :'data-role' => 'fieldcontain'}=@network.state
+ %li{ :'data-role' => 'list-divider'} Address Blocks
+ %li
+ %p{ :'data-role' => 'fieldcontain'}=(@network.address_blocks ? @network.address_blocks.join(",") : nil)
+ %li{ :'data-role' => 'list-divider'} Subnets
+ %li
+ %p{ :'data-role' => 'fieldcontain'}= (@network.subnets ? @network.subnets.join(",") : nil)
+ %li{ :'data-role' => 'list-divider'} Actions
+ %li
+ %div{ :'data-role' => 'controlgroup', :'data-type' => "horizontal" }
+ =link_to_action "Destroy", destroy_network_url(@network.id), :delete
diff --git a/server/views/networks/show.xml.haml b/server/views/networks/show.xml.haml
new file mode 100644
index 0000000..0ebb170
--- /dev/null
+++ b/server/views/networks/show.xml.haml
@@ -0,0 +1,15 @@
+- unless defined?(partial)
+ !!! XML
+%network{ :href => network_url(@network.id), :id => @network.id }
+ %name=@network.name
+ %state<
+ =@network.state
+ %address_blocks
+ - @network.address_blocks.each do |addr_block|
+ %address_block=addr_block
+ %subnets
+ - (@network.subnets || []).each do |subnet|
+ %subnet{:href => subnet_url(subnet), :id=>subnet}
+ %actions
+ - if driver.respond_to?(:destroy_network)
+ %link{ :rel => "destroy", :method => "delete", :href => destroy_network_url(@network.id)}
diff --git a/server/views/subnets/index.html.haml b/server/views/subnets/index.html.haml
new file mode 100644
index 0000000..5442c17
--- /dev/null
+++ b/server/views/subnets/index.html.haml
@@ -0,0 +1,10 @@
+=header "Subnets" do
+ %a{ :href => url_for('subnets/new'), :'data-icon' => :plus, :'data-role' => :button, :class => 'ui-btn-right'} Create new subnet
+
+%div{ :'data-role' => :content, :'data-theme' => 'c'}
+ %ul{ :'data-role' => :listview , :'data-inset' => :true, :'data-divider-theme' => 'a'}
+ - @elements.each do |subnet|
+ %li
+ %a{ :href => subnet_url(subnet.id), :'data-ajax' => 'false'}
+ %img{ :class => 'ui-link-thumb', :src => '/images/cloud.png'}
+ %h3=subnet.id
diff --git a/server/views/subnets/index.xml.haml b/server/views/subnets/index.xml.haml
new file mode 100644
index 0000000..17f66b4
--- /dev/null
+++ b/server/views/subnets/index.xml.haml
@@ -0,0 +1,4 @@
+!!!XML
+%subnets
+ - @elements.each do |c|
+ = haml :'subnets/show', :locals => { :@subnet => c, :partial => true }
diff --git a/server/views/subnets/new.html.haml b/server/views/subnets/new.html.haml
new file mode 100644
index 0000000..c542d8e
--- /dev/null
+++ b/server/views/subnets/new.html.haml
@@ -0,0 +1,14 @@
+=header "Create new subnet"
+
+%div{ :'data-role' => :content, :'data-theme' => 'c', :class => 'middle-dialog'}
+ %form{ :action => subnets_url, :method => :post}
+ %div{ 'data-role' => :fieldcontain }
+ %p
+ %label{ :for => :network_id} Network ID:
+ %p
+ %input{ :type => :text, :id => :network_id, :name => :network_id, :value => '' }
+ %p
+ %label{ :for => :address_block} CIDR Address block:
+ %p
+ %input{ :type => :text, :id => :address_block, :name => :address_block, :value => '' }
+ %button{ :type => :submit} Create subnet
diff --git a/server/views/subnets/show.html.haml b/server/views/subnets/show.html.haml
new file mode 100644
index 0000000..e9cfadb
--- /dev/null
+++ b/server/views/subnets/show.html.haml
@@ -0,0 +1,24 @@
+=header "Subnet"
+=subheader @subnet.id
+
+%div{ :'data-role' => :content, :'data-theme' => 'c'}
+ %ul{ :'data-role' => :listview , :'data-inset' => :true, :'data-divider-theme' => 'd'}
+ %li{ :'data-role' => 'list-divider'} Identifier
+ %li
+ %p{ :'data-role' => 'fieldcontain'}=@subnet.id
+ %li{ :'data-role' => 'list-divider'} Name
+ %li
+ %p{ :'data-role' => 'fieldcontain'}=@subnet.name
+ %li{ :'data-role' => 'list-divider'} Network
+ %li
+ %a{ :href => network_url(@subnet.network), :'data-ajax'=>'false' }=@subnet.network
+ %li{ :'data-role' => 'list-divider'} State
+ %li
+ %p{ :'data-role' => 'fieldcontain'}=@subnet.state
+ %li{ :'data-role' => 'list-divider'} Address Block
+ %li
+ %p{ :'data-role' => 'fieldcontain'}=(@subnet.address_block ? @subnet.address_block : nil)
+ %li{ :'data-role' => 'list-divider'} Actions
+ %li
+ %div{ :'data-role' => 'controlgroup', :'data-type' => "horizontal" }
+ =link_to_action "Destroy", destroy_subnet_url(@subnet.id), :delete
diff --git a/server/views/subnets/show.xml.haml b/server/views/subnets/show.xml.haml
new file mode 100644
index 0000000..3c47e59
--- /dev/null
+++ b/server/views/subnets/show.xml.haml
@@ -0,0 +1,13 @@
+- unless defined?(partial)
+ !!! XML
+%subnet{ :href => subnet_url(@subnet.id), :id => @subnet.id }
+ %name=@subnet.name
+ %state<
+ =@subnet.state
+ %address_block
+ =@subnet.address_block
+ %network
+ =@subnet.network
+ %actions
+ - if driver.respond_to?(:destroy_subnet)
+ %link{ :rel => "destroy", :method => "delete", :href => destroy_subnet_url(@subnet.id)}
--
1.8.1.4
Re: Network-API-rev-2-RFC
Posted by "marios@redhat.com" <ma...@redhat.com>.
On 20/03/13 19:02, marios@redhat.com wrote:
> patches are at http://tracker.deltacloud.org/set/395
>
updated patches are at http://tracker.deltacloud.org/set/396 - the
difference is that this new set includes mock driver functionality - the
new set is also independent/stand-alone (doesn't need to be applied on
top of the previous one)
thanks, marios
> write-up at http://mariosandreou.com/deltacloud/cloud_API/2013/03/20/deltacloud-networks-api-rfc.html
>
> I'll be working on RHEV-M next - any comments are very much appreciated!
>
> thanks, marios
>
[PATCH 4/4] Network API rev 2 (RFC) - Drivers - Openstack and EC2
Posted by ma...@redhat.com.
From: marios <ma...@redhat.com>
Signed-off-by: marios <ma...@redhat.com>
---
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
[PATCH 2/4] Network API rev 2 (RFC) - Collections (Routes)
Posted by ma...@redhat.com.
From: marios <ma...@redhat.com>
Signed-off-by: marios <ma...@redhat.com>
---
server/lib/deltacloud/collections/instances.rb | 5 ++
server/lib/deltacloud/collections/networks.rb | 63 +++++++++++++++++++++++++
server/lib/deltacloud/collections/subnets.rb | 65 ++++++++++++++++++++++++++
3 files changed, 133 insertions(+)
create mode 100644 server/lib/deltacloud/collections/networks.rb
create mode 100644 server/lib/deltacloud/collections/subnets.rb
diff --git a/server/lib/deltacloud/collections/instances.rb b/server/lib/deltacloud/collections/instances.rb
index ee48f30..ecd6d00 100644
--- a/server/lib/deltacloud/collections/instances.rb
+++ b/server/lib/deltacloud/collections/instances.rb
@@ -29,6 +29,7 @@ module Deltacloud::Collections
@realms ||= driver.realms(credentials)
@firewalls = driver.firewalls(credentials) if driver.class.has_feature? :instances, :firewalls
@keys = driver.keys(credentials) if driver.class.has_feature? :instances, :authentication_key
+ @networks = driver.networks(credentials) if driver.has_capability? :networks
end
get '/instances/:id/run' do
@@ -48,7 +49,11 @@ module Deltacloud::Collections
param :realm_id, :string, :optional
param :hwp_id, :string, :optional
param :keyname, :string, :optional
+ param :network_id, :string, :optional
+ param :subnet_id, :string, :optional
control do
+ params.merge!({:network_id => params["network_id"].split("+").first}) unless params["network_id"].empty?
+ params.merge!({:subnet_id => params["network_id"].split("+").last}) unless params["network_id"].empty?
@instance = driver.create_instance(credentials, params[:image_id], params)
if @instance.kind_of? Array
@elements = @instance
diff --git a/server/lib/deltacloud/collections/networks.rb b/server/lib/deltacloud/collections/networks.rb
new file mode 100644
index 0000000..34c7fad
--- /dev/null
+++ b/server/lib/deltacloud/collections/networks.rb
@@ -0,0 +1,63 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+ class Networks < Base
+
+ include Deltacloud::Features
+
+ set :capability, lambda { |m| driver.respond_to? m }
+ check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
+
+ get '/networks/new' do
+ respond_to do |format|
+ format.html { haml :"networks/new" }
+ end
+ end
+
+ collection :networks do
+
+ standard_show_operation
+ standard_index_operation
+
+ operation :create, :with_capability => :create_network do
+ param :address_block, :string, :optional
+ param :name, :string, :optional
+ control do
+ @network = driver.create_network(credentials, { :address_block => params[:address_block]})
+ respond_to do |format|
+ format.xml { haml :"networks/show" }
+ format.html { haml :"networks/show" }
+ format.json { xml_to_json("networks/show")}
+ end
+ end
+ end
+
+ operation :destroy, :with_capability => :destroy_network do
+ control do
+ driver.destroy_network(credentials, params[:id])
+ status 204
+ respond_to do |format|
+ format.xml
+ format.json
+ format.html { redirect(networks_url) }
+ end
+ end
+ end
+
+ end
+
+ end
+end
diff --git a/server/lib/deltacloud/collections/subnets.rb b/server/lib/deltacloud/collections/subnets.rb
new file mode 100644
index 0000000..9d5fd74
--- /dev/null
+++ b/server/lib/deltacloud/collections/subnets.rb
@@ -0,0 +1,65 @@
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+ class Subnets < Base
+
+ include Deltacloud::Features
+
+ set :capability, lambda { |m| driver.respond_to? m }
+ check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
+
+ get '/subnets/new' do
+ respond_to do |format|
+ format.html { haml :"subnets/new" }
+ end
+ end
+
+
+ collection :subnets do
+
+ standard_show_operation
+ standard_index_operation
+
+ operation :create, :with_capability => :create_subnet do
+ param :network_id, :string, :required
+ param :address_block, :string, :required
+ control do
+ @subnet = driver.create_subnet(credentials, { :network_id => params[:network_id], :address_block => params[:address_block]})
+ respond_to do |format|
+ format.xml { haml :"subnets/show"}
+ format.html { haml :"subnets/show" }
+ format.json { xml_to_json("subnets/show")}
+ end
+ end
+ end
+
+ operation :destroy, :with_capability => :destroy_subnet do
+ control do
+ driver.destroy_subnet(credentials, params[:id])
+ status 204
+ respond_to do |format|
+ format.xml
+ format.json
+ format.html { redirect(subnets_url) }
+ end
+ end
+ end
+
+ end
+
+ end
+end
--
1.8.1.4