Merge "Quantum Floating IP support"

This commit is contained in:
Jenkins 2013-02-07 14:21:45 +00:00 committed by Gerrit Code Review
commit a366264d62
19 changed files with 941 additions and 227 deletions

View File

@ -36,6 +36,7 @@ from openstack_dashboard.api import base
from openstack_dashboard.api import cinder
from openstack_dashboard.api import glance
from openstack_dashboard.api import keystone
from openstack_dashboard.api import network
from openstack_dashboard.api import nova
from openstack_dashboard.api import quantum
from openstack_dashboard.api import swift

View File

@ -0,0 +1,171 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 NEC Corporation
#
# Licensed 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.
"""Abstraction layer of networking functionalities.
Now Nova and Quantum have duplicated features.
Thie API layer is introduced to hide the differences between them
from dashboard implementations.
"""
import abc
class NetworkClient(object):
def __init__(self, request):
from openstack_dashboard import api
if api.base.is_service_enabled(request, 'network'):
self.floating_ips = api.quantum.FloatingIpManager(request)
else:
self.floating_ips = api.nova.FloatingIpManager(request)
class FloatingIpManager(object):
"""Abstract class to implement Floating IP methods
FloatingIP object returned from methods in this class
must contains the following attributes:
- id : ID of Floating IP
- ip : Floating IP address
- pool : ID of Floating IP pool from which the address is allocated
- fixed_ip : Fixed IP address of a VIF associated with the address
- port_id : ID of a VIF associated with the address
(instance_id when Nova floating IP is used)
- instance_id : Instance ID of an associated with the Floating IP
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def list_pools(self):
"""Fetches a list of all floating IP pools.
A list of FloatingIpPool object is returned.
FloatingIpPool object is an APIResourceWrapper/APIDictWrapper
where 'id' and 'name' attributes are defined.
"""
pass
@abc.abstractmethod
def list(self):
"""Fetches a list all floating IPs.
A returned value is a list of FloatingIp object.
"""
pass
@abc.abstractmethod
def get(self, floating_ip_id):
"""Fetches the floating IP.
It returns a FloatingIp object corresponding to floating_ip_id.
"""
pass
@abc.abstractmethod
def allocate(self, pool=None):
"""Allocates a floating IP to the tenant.
You must provide a pool name or id for which you would like to
allocate an floating IP.
"""
pass
@abc.abstractmethod
def release(self, floating_ip_id):
"""Releases a floating IP specified."""
pass
@abc.abstractmethod
def associate(self, floating_ip_id, port_id):
"""Associates the floating IP to the port.
port_id is a fixed IP of a instance (Nova) or
a port_id attached to a VNIC of a instance.
"""
pass
@abc.abstractmethod
def disassociate(self, floating_ip_id, port_id):
"""Disassociates the floating IP from the port.
port_id is a fixed IP of a instance (Nova) or
a port_id attached to a VNIC of a instance.
"""
pass
@abc.abstractmethod
def list_targets(self):
"""Returns a list of association targets of instance VIFs.
Each association target is represented as FloatingIpTarget object.
FloatingIpTarget is a APIResourceWrapper/APIDictWrapper and
'id' and 'name' attributes must be defined in each object.
FloatingIpTarget.id can be passed as port_id in associate().
FloatingIpTarget.name is displayed in Floating Ip Association Form.
"""
pass
@abc.abstractmethod
def get_target_id_by_instance(self, instance_id):
"""Returns a target ID of floating IP association based on
a backend implementation.
"""
pass
@abc.abstractmethod
def is_simple_associate_supported(self):
"""Returns True if the default floating IP pool is enabled."""
pass
def floating_ip_pools_list(request):
return NetworkClient(request).floating_ips.list_pools()
def tenant_floating_ip_list(request):
return NetworkClient(request).floating_ips.list()
def tenant_floating_ip_get(request, floating_ip_id):
return NetworkClient(request).floating_ips.get(floating_ip_id)
def tenant_floating_ip_allocate(request, pool=None):
return NetworkClient(request).floating_ips.allocate(pool)
def tenant_floating_ip_release(request, floating_ip_id):
return NetworkClient(request).floating_ips.release(floating_ip_id)
def floating_ip_associate(request, floating_ip_id, port_id):
return NetworkClient(request).floating_ips.associate(floating_ip_id,
port_id)
def floating_ip_disassociate(request, floating_ip_id, port_id):
return NetworkClient(request).floating_ips.disassociate(floating_ip_id,
port_id)
def floating_ip_target_list(request):
return NetworkClient(request).floating_ips.list_targets()
def floating_ip_target_get_by_instance(request, instance_id):
return NetworkClient(request).floating_ips.get_target_id_by_instance(
instance_id)

View File

@ -32,10 +32,12 @@ from novaclient.v1_1 import security_group_rules as nova_rules
from novaclient.v1_1.security_groups import SecurityGroup as NovaSecurityGroup
from novaclient.v1_1.servers import REBOOT_HARD
from horizon.conf import HORIZON_CONFIG
from horizon.utils.memoized import memoized
from openstack_dashboard.api.base import (APIResourceWrapper, QuotaSet,
APIDictWrapper, url_for)
from openstack_dashboard.api import network
LOG = logging.getLogger(__name__)
@ -182,6 +184,71 @@ class FlavorExtraSpec(object):
self.value = val
class FloatingIp(APIResourceWrapper):
_attrs = ['id', 'ip', 'fixed_ip', 'port_id', 'instance_id', 'pool']
def __init__(self, fip):
fip.__setattr__('port_id', fip.instance_id)
super(FloatingIp, self).__init__(fip)
class FloatingIpPool(APIDictWrapper):
def __init__(self, pool):
pool_dict = {'id': pool.name,
'name': pool.name}
super(FloatingIpPool, self).__init__(pool_dict)
class FloatingIpTarget(APIDictWrapper):
def __init__(self, server):
server_dict = {'name': '%s (%s)' % (server.name, server.id),
'id': server.id}
super(FloatingIpTarget, self).__init__(server_dict)
class FloatingIpManager(network.FloatingIpManager):
def __init__(self, request):
self.request = request
self.client = novaclient(request)
def list_pools(self):
return [FloatingIpPool(pool)
for pool in self.client.floating_ip_pools.list()]
def list(self):
return [FloatingIp(fip)
for fip in self.client.floating_ips.list()]
def get(self, floating_ip_id):
return FloatingIp(self.client.floating_ips.get(floating_ip_id))
def allocate(self, pool):
return FloatingIp(self.client.floating_ips.create(pool=pool))
def release(self, floating_ip_id):
self.client.floating_ips.delete(floating_ip_id)
def associate(self, floating_ip_id, port_id):
# In Nova implied port_id is instance_id
server = self.client.servers.get(port_id)
fip = self.client.floating_ips.get(floating_ip_id)
self.client.servers.add_floating_ip(server.id, fip.ip)
def disassociate(self, floating_ip_id, port_id):
fip = self.client.floating_ips.get(floating_ip_id)
server = self.client.servers.get(fip.instance_id)
self.client.servers.remove_floating_ip(server.id, fip.ip)
def list_targets(self):
return [FloatingIpTarget(s) for s in self.client.servers.list()]
def get_target_id_by_instance(self, instance_id):
return instance_id
def is_simple_associate_supported(self):
return HORIZON_CONFIG["simple_ip_management"]
def novaclient(request):
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
LOG.debug('novaclient connection created using token "%s" and url "%s"' %
@ -255,33 +322,6 @@ def flavor_extra_set(request, flavor_id, metadata):
return flavor.set_keys(metadata)
def tenant_floating_ip_list(request):
"""Fetches a list of all floating ips."""
return novaclient(request).floating_ips.list()
def floating_ip_pools_list(request):
"""Fetches a list of all floating ip pools."""
return novaclient(request).floating_ip_pools.list()
def tenant_floating_ip_get(request, floating_ip_id):
"""Fetches a floating ip."""
return novaclient(request).floating_ips.get(floating_ip_id)
def tenant_floating_ip_allocate(request, pool=None):
"""Allocates a floating ip to tenant. Optionally you may provide a pool
for which you would like the IP.
"""
return novaclient(request).floating_ips.create(pool=pool)
def tenant_floating_ip_release(request, floating_ip_id):
"""Releases floating ip from the pool of a tenant."""
return novaclient(request).floating_ips.delete(floating_ip_id)
def snapshot_create(request, instance_id, name):
return novaclient(request).servers.create_image(instance_id, name)
@ -402,22 +442,6 @@ def server_revert_resize(request, instance_id):
novaclient(request).servers.revert_resize(instance_id)
def server_add_floating_ip(request, server, floating_ip):
"""Associates floating IP to server's fixed IP.
"""
server = novaclient(request).servers.get(server)
fip = novaclient(request).floating_ips.get(floating_ip)
return novaclient(request).servers.add_floating_ip(server.id, fip.ip)
def server_remove_floating_ip(request, server, floating_ip):
"""Removes relationship between floating and server's fixed ip.
"""
fip = novaclient(request).floating_ips.get(floating_ip)
server = novaclient(request).servers.get(fip.instance_id)
return novaclient(request).servers.remove_floating_ip(server.id, fip.ip)
def tenant_quota_get(request, tenant_id):
return QuotaSet(novaclient(request).quotas.get(tenant_id))

View File

@ -26,11 +26,17 @@ import logging
from quantumclient.v2_0 import client as quantum_client
from django.utils.datastructures import SortedDict
from horizon.conf import HORIZON_CONFIG
from openstack_dashboard.api.base import APIDictWrapper, url_for
from openstack_dashboard.api import network
from openstack_dashboard.api import nova
LOG = logging.getLogger(__name__)
IP_VERSION_DICT = {4: 'IPv4', 6: 'IPv6'}
class QuantumAPIDictWrapper(APIDictWrapper):
@ -87,7 +93,116 @@ class Router(QuantumAPIDictWrapper):
super(Router, self).__init__(apiresource)
IP_VERSION_DICT = {4: 'IPv4', 6: 'IPv6'}
class FloatingIp(APIDictWrapper):
_attrs = ['id', 'ip', 'fixed_ip', 'port_id', 'instance_id', 'pool']
def __init__(self, fip):
fip['ip'] = fip['floating_ip_address']
fip['fixed_ip'] = fip['fixed_ip_address']
fip['pool'] = fip['floating_network_id']
super(FloatingIp, self).__init__(fip)
class FloatingIpPool(APIDictWrapper):
pass
class FloatingIpTarget(APIDictWrapper):
pass
class FloatingIpManager(network.FloatingIpManager):
def __init__(self, request):
self.request = request
self.client = quantumclient(request)
def list_pools(self):
search_opts = {'router:external': True}
return [FloatingIpPool(pool) for pool
in self.client.list_networks(**search_opts).get('networks')]
def list(self):
fips = self.client.list_floatingips().get('floatingips')
# Get port list to add instance_id to floating IP list
# instance_id is stored in device_id attribute
ports = port_list(self.request)
device_id_dict = SortedDict([(p['id'], p['device_id']) for p in ports])
for fip in fips:
if fip['port_id']:
fip['instance_id'] = device_id_dict[fip['port_id']]
else:
fip['instance_id'] = None
return [FloatingIp(fip) for fip in fips]
def get(self, floating_ip_id):
fip = self.client.show_floatingip(floating_ip_id).get('floatingip')
if fip['port_id']:
fip['instance_id'] = port_get(self.request,
fip['port_id']).device_id
else:
fip['instance_id'] = None
return FloatingIp(fip)
def allocate(self, pool):
body = {'floatingip': {'floating_network_id': pool}}
fip = self.client.create_floatingip(body).get('floatingip')
fip['instance_id'] = None
return FloatingIp(fip)
def release(self, floating_ip_id):
self.client.delete_floatingip(floating_ip_id)
def associate(self, floating_ip_id, port_id):
# NOTE: In Quantum Horizon floating IP support, port_id is
# "<port_id>_<ip_address>" format to identify multiple ports.
pid, ip_address = port_id.split('_', 1)
update_dict = {'port_id': pid,
'fixed_ip_address': ip_address}
self.client.update_floatingip(floating_ip_id,
{'floatingip': update_dict})
def disassociate(self, floating_ip_id, port_id):
update_dict = {'port_id': None}
self.client.update_floatingip(floating_ip_id,
{'floatingip': update_dict})
def list_targets(self):
ports = port_list(self.request)
servers = nova.server_list(self.request)
server_dict = SortedDict([(s.id, s.name) for s in servers])
targets = []
for p in ports:
# Remove network ports from Floating IP targets
if p.device_owner.startswith('network:'):
continue
port_id = p.id
server_name = server_dict.get(p.device_id)
for ip in p.fixed_ips:
target = {'name': '%s: %s' % (server_name, ip['ip_address']),
'id': '%s_%s' % (port_id, ip['ip_address'])}
targets.append(FloatingIpTarget(target))
return targets
def get_target_id_by_instance(self, instance_id):
# In Quantum one port can have multiple ip addresses, so this method
# picks up the first one and generate target id.
if not instance_id:
return None
search_opts = {'device_id': instance_id}
ports = port_list(self.request, **search_opts)
if not ports:
return None
return '%s_%s' % (ports[0].id, ports[0].fixed_ips[0]['ip_address'])
def is_simple_associate_supported(self):
# NOTE: There are two reason that simple association support
# needs more considerations. (1) Quantum does not support the
# default floating IP pool at the moment. It can be avoided
# in case where only one floating IP pool exists.
# (2) Quantum floating IP is associated with each VIF and
# we need to check whether such VIF is only one for an instance
# to enable simple association support.
return False
def get_ipver_str(ip_version):

View File

@ -38,7 +38,7 @@ class FloatingIpAllocate(forms.SelfHandlingForm):
def handle(self, request, data):
try:
fip = api.nova.tenant_floating_ip_allocate(request,
fip = api.network.tenant_floating_ip_allocate(request,
pool=data['pool'])
messages.success(request,
_('Allocated Floating IP %(ip)s.')

View File

@ -53,7 +53,7 @@ class ReleaseIPs(tables.BatchAction):
classes = ('btn-danger', 'btn-release')
def action(self, request, obj_id):
api.nova.tenant_floating_ip_release(request, obj_id)
api.network.tenant_floating_ip_release(request, obj_id)
class AssociateIP(tables.LinkAction):
@ -63,7 +63,7 @@ class AssociateIP(tables.LinkAction):
classes = ("ajax-modal", "btn-associate")
def allowed(self, request, fip):
if fip.instance_id:
if fip.port_id:
return False
return True
@ -79,15 +79,15 @@ class DisassociateIP(tables.Action):
classes = ("btn-disassociate", "btn-danger")
def allowed(self, request, fip):
if fip.instance_id:
if fip.port_id:
return True
return False
def single(self, table, request, obj_id):
try:
fip = table.get_object_by_id(get_int_or_uuid(obj_id))
api.nova.server_remove_floating_ip(request, fip.instance_id,
fip.id)
api.network.floating_ip_disassociate(request, fip.id,
fip.port_id)
LOG.info('Disassociating Floating IP "%s".' % obj_id)
messages.success(request,
_('Successfully disassociated Floating IP: %s')
@ -116,7 +116,7 @@ class FloatingIPsTable(tables.DataTable):
link=get_instance_link,
verbose_name=_("Instance"),
empty_value="-")
pool = tables.Column("pool",
pool = tables.Column("pool_name",
verbose_name=_("Floating IP Pool"),
empty_value="-")

View File

@ -38,11 +38,11 @@ NAMESPACE = "horizon:project:access_and_security:floating_ips"
class FloatingIpViewTests(test.TestCase):
def test_associate(self):
self.mox.StubOutWithMock(api.nova, 'server_list')
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
api.nova.server_list(IsA(http.HttpRequest)) \
self.mox.StubOutWithMock(api.network, 'floating_ip_target_list')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list')
api.network.floating_ip_target_list(IsA(http.HttpRequest)) \
.AndReturn(self.servers.list())
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
self.mox.ReplayAll()
@ -58,17 +58,17 @@ class FloatingIpViewTests(test.TestCase):
def test_associate_post(self):
floating_ip = self.floating_ips.list()[1]
server = self.servers.first()
self.mox.StubOutWithMock(api.nova, 'server_add_floating_ip')
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.nova, 'server_list')
self.mox.StubOutWithMock(api.network, 'floating_ip_associate')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.network, 'floating_ip_target_list')
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.server_list(IsA(http.HttpRequest)) \
api.network.floating_ip_target_list(IsA(http.HttpRequest)) \
.AndReturn(self.servers.list())
api.nova.server_add_floating_ip(IsA(http.HttpRequest),
server.id,
floating_ip.id)
api.network.floating_ip_associate(IsA(http.HttpRequest),
floating_ip.id,
server.id)
self.mox.ReplayAll()
form_data = {'instance_id': server.id,
@ -80,17 +80,17 @@ class FloatingIpViewTests(test.TestCase):
def test_associate_post_with_redirect(self):
floating_ip = self.floating_ips.list()[1]
server = self.servers.first()
self.mox.StubOutWithMock(api.nova, 'server_add_floating_ip')
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.nova, 'server_list')
self.mox.StubOutWithMock(api.network, 'floating_ip_associate')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.network, 'floating_ip_target_list')
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.server_list(IsA(http.HttpRequest)) \
api.network.floating_ip_target_list(IsA(http.HttpRequest)) \
.AndReturn(self.servers.list())
api.nova.server_add_floating_ip(IsA(http.HttpRequest),
server.id,
floating_ip.id)
api.network.floating_ip_associate(IsA(http.HttpRequest),
floating_ip.id,
server.id)
self.mox.ReplayAll()
form_data = {'instance_id': server.id,
@ -103,17 +103,17 @@ class FloatingIpViewTests(test.TestCase):
def test_associate_post_with_exception(self):
floating_ip = self.floating_ips.list()[1]
server = self.servers.first()
self.mox.StubOutWithMock(api.nova, 'server_add_floating_ip')
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.nova, 'server_list')
self.mox.StubOutWithMock(api.network, 'floating_ip_associate')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.network, 'floating_ip_target_list')
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.server_list(IsA(http.HttpRequest)) \
api.network.floating_ip_target_list(IsA(http.HttpRequest)) \
.AndReturn(self.servers.list())
api.nova.server_add_floating_ip(IsA(http.HttpRequest),
server.id,
floating_ip.id) \
api.network.floating_ip_associate(IsA(http.HttpRequest),
floating_ip.id,
server.id) \
.AndRaise(self.exceptions.nova)
self.mox.ReplayAll()
@ -128,9 +128,9 @@ class FloatingIpViewTests(test.TestCase):
server = self.servers.first()
self.mox.StubOutWithMock(api.nova, 'keypair_list')
self.mox.StubOutWithMock(api.nova, 'security_group_list')
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_get')
self.mox.StubOutWithMock(api.nova, 'server_remove_floating_ip')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_get')
self.mox.StubOutWithMock(api.network, 'floating_ip_disassociate')
self.mox.StubOutWithMock(api.nova, 'server_list')
api.nova.server_list(IsA(http.HttpRequest),
@ -139,11 +139,11 @@ class FloatingIpViewTests(test.TestCase):
.AndReturn(self.keypairs.list())
api.nova.security_group_list(IsA(http.HttpRequest)) \
.AndReturn(self.security_groups.list())
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.server_remove_floating_ip(IsA(http.HttpRequest),
server.id,
floating_ip.id)
api.network.floating_ip_disassociate(IsA(http.HttpRequest),
floating_ip.id,
server.id)
self.mox.ReplayAll()
action = "floating_ips__disassociate__%s" % floating_ip.id
@ -156,9 +156,9 @@ class FloatingIpViewTests(test.TestCase):
server = self.servers.first()
self.mox.StubOutWithMock(api.nova, 'keypair_list')
self.mox.StubOutWithMock(api.nova, 'security_group_list')
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_get')
self.mox.StubOutWithMock(api.nova, 'server_remove_floating_ip')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_get')
self.mox.StubOutWithMock(api.network, 'floating_ip_disassociate')
self.mox.StubOutWithMock(api.nova, 'server_list')
api.nova.server_list(IsA(http.HttpRequest),
@ -167,13 +167,13 @@ class FloatingIpViewTests(test.TestCase):
.AndReturn(self.keypairs.list())
api.nova.security_group_list(IsA(http.HttpRequest)) \
.AndReturn(self.security_groups.list())
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.server_remove_floating_ip(IsA(http.HttpRequest),
server.id,
floating_ip.id) \
.AndRaise(self.exceptions.nova)
api.network.floating_ip_disassociate(IsA(http.HttpRequest),
floating_ip.id,
server.id) \
.AndRaise(self.exceptions.nova)
self.mox.ReplayAll()
action = "floating_ips__disassociate__%s" % floating_ip.id
@ -184,8 +184,13 @@ class FloatingIpViewTests(test.TestCase):
class FloatingIpQuantumViewTests(FloatingIpViewTests):
def setUp(self):
super(FloatingIpViewTests, self).setUp()
self._floating_ips_orig = self.floating_ips
self.floating_ips = self.floating_ips_uuid
def tearDown(self):
self.floating_ips = self._floating_ips_orig
super(FloatingIpViewTests, self).tearDown()
class FloatingIpUtilsTests(test.TestCase):
def test_accept_valid_integer(self):

View File

@ -59,12 +59,12 @@ class AllocateView(forms.ModalFormView):
def get_initial(self):
try:
pools = api.nova.floating_ip_pools_list(self.request)
pools = api.network.floating_ip_pools_list(self.request)
except:
pools = []
exceptions.handle(self.request,
_("Unable to retrieve floating IP pools."))
pool_list = [(pool.name, pool.name) for pool in pools]
pool_list = [(pool.id, pool.name) for pool in pools]
if not pool_list:
pool_list = [(None, _("No floating IP pools available."))]
return {'pool_list': pool_list}

View File

@ -42,15 +42,34 @@ class AssociateIPAction(workflows.Action):
help_text = _("Select the IP address you wish to associate with "
"the selected instance.")
def __init__(self, *args, **kwargs):
super(AssociateIPAction, self).__init__(*args, **kwargs)
if api.base.is_service_enabled(self.request, 'network'):
label = _("Port to be associated")
else:
label = _("Instance to be associated")
self.fields['instance_id'].label = label
# If AssociateIP is invoked from instance menu, instance_id parameter
# is passed in URL. In Quantum based Floating IP implementation
# an association target is not an instance but a port, so we need
# to get an association target based on a received instance_id
# and set the initial value of instance_id ChoiceField.
q_instance_id = self.request.GET.get('instance_id')
if q_instance_id:
target_id = api.network.floating_ip_target_get_by_instance(
self.request, q_instance_id)
self.initial['instance_id'] = target_id
def populate_ip_id_choices(self, request, context):
try:
ips = api.nova.tenant_floating_ip_list(self.request)
ips = api.network.tenant_floating_ip_list(self.request)
except:
redirect = reverse('horizon:project:access_and_security:index')
exceptions.handle(self.request,
_('Unable to retrieve floating IP addresses.'),
redirect=redirect)
options = sorted([(ip.id, ip.ip) for ip in ips if not ip.instance_id])
options = sorted([(ip.id, ip.ip) for ip in ips if not ip.port_id])
if options:
options.insert(0, ("", _("Select an IP address")))
else:
@ -60,24 +79,32 @@ class AssociateIPAction(workflows.Action):
def populate_instance_id_choices(self, request, context):
try:
servers = api.nova.server_list(self.request)
targets = api.network.floating_ip_target_list(self.request)
except:
redirect = reverse('horizon:project:access_and_security:index')
exceptions.handle(self.request,
_('Unable to retrieve instance list.'),
redirect=redirect)
instances = []
for server in servers:
server_name = "%s (%s)" % (server.name, server.id)
instances.append((server.id, server_name))
for target in targets:
instances.append((target.id, target.name))
# Sort instances for easy browsing
instances = sorted(instances, key=lambda x: x[1])
quantum_enabled = api.base.is_service_enabled(request, 'network')
if instances:
instances.insert(0, ("", _("Select an instance")))
if quantum_enabled:
label = _("Select a port")
else:
label = _("Select an instance")
instances.insert(0, ("", label))
else:
instances = (("", _("No instances available")),)
if quantum_enabled:
label = _("No ports available")
else:
label = _("No instances available")
instances = (("", label),)
return instances
@ -108,9 +135,9 @@ class IPAssociationWorkflow(workflows.Workflow):
def handle(self, request, data):
try:
api.nova.server_add_floating_ip(request,
data['instance_id'],
data['ip_id'])
api.network.floating_ip_associate(request,
data['ip_id'],
data['instance_id'])
except:
exceptions.handle(request)
return False

View File

@ -37,15 +37,15 @@ class KeyPairViewTests(test.TestCase):
self.mox.StubOutWithMock(api.nova, 'keypair_list')
self.mox.StubOutWithMock(api.nova, 'keypair_delete')
self.mox.StubOutWithMock(api.nova, 'security_group_list')
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.nova, 'server_list')
api.nova.server_list(IsA(http.HttpRequest),
all_tenants=True).AndReturn(self.servers.list())
api.nova.security_group_list(IsA(http.HttpRequest)) \
.AndReturn(self.security_groups.list())
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
.AndReturn(self.security_groups.list())
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.keypair_list(IsA(http.HttpRequest)) \
.AndReturn(self.keypairs.list())
api.nova.keypair_delete(IsA(http.HttpRequest), keypair.name)
@ -60,15 +60,15 @@ class KeyPairViewTests(test.TestCase):
self.mox.StubOutWithMock(api.nova, 'keypair_list')
self.mox.StubOutWithMock(api.nova, 'keypair_delete')
self.mox.StubOutWithMock(api.nova, 'security_group_list')
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.nova, 'server_list')
api.nova.server_list(IsA(http.HttpRequest),
all_tenants=True).AndReturn(self.servers.list())
api.nova.security_group_list(IsA(http.HttpRequest)) \
.AndReturn(self.security_groups.list())
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
.AndReturn(self.security_groups.list())
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.keypair_list(IsA(http.HttpRequest)) \
.AndReturn(self.keypairs.list())
api.nova.keypair_delete(IsA(http.HttpRequest), keypair.name) \

View File

@ -30,11 +30,14 @@ from openstack_dashboard.test import helpers as test
class AccessAndSecurityTests(test.TestCase):
def setUp(self):
super(AccessAndSecurityTests, self).setUp()
def test_index(self):
keypairs = self.keypairs.list()
sec_groups = self.security_groups.list()
floating_ips = self.floating_ips.list()
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.nova, 'security_group_list')
self.mox.StubOutWithMock(api.nova, 'keypair_list')
self.mox.StubOutWithMock(api.nova, 'server_list')
@ -42,7 +45,7 @@ class AccessAndSecurityTests(test.TestCase):
api.nova.server_list(IsA(http.HttpRequest),
all_tenants=True).AndReturn(self.servers.list())
api.nova.keypair_list(IsA(http.HttpRequest)).AndReturn(keypairs)
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(floating_ips)
api.nova.security_group_list(IsA(http.HttpRequest)) \
.AndReturn(sec_groups)
@ -60,21 +63,24 @@ class AccessAndSecurityTests(test.TestCase):
floating_ips)
def test_association(self):
servers = self.servers.list()
# Add duplicate instance name to test instance name with [IP]
# change id and private IP
servers = [api.nova.Server(s, self.request)
for s in self.servers.list()]
# Add duplicate instance name to test instance name with [ID]
# Change id and private IP
server3 = api.nova.Server(self.servers.first(), self.request)
server3.id = 101
server3.addresses = deepcopy(server3.addresses)
server3.addresses['private'][0]['addr'] = "10.0.0.5"
self.servers.add(server3)
servers.append(server3)
self.mox.StubOutWithMock(api.nova, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.nova, 'server_list')
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
targets = [api.nova.FloatingIpTarget(s) for s in servers]
self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list')
self.mox.StubOutWithMock(api.network, 'floating_ip_target_list')
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.server_list(IsA(http.HttpRequest)).AndReturn(servers)
api.network.floating_ip_target_list(IsA(http.HttpRequest)) \
.AndReturn(targets)
self.mox.ReplayAll()
res = self.client.get(reverse("horizon:project:access_and_security:"
@ -89,7 +95,7 @@ class AccessAndSecurityTests(test.TestCase):
self.assertContains(res, '<option value="2">server_2 (2)</option>')
class AccessAndSecurityQuantumTests(AccessAndSecurityTests):
class AccessAndSecurityQuantumProxyTests(AccessAndSecurityTests):
def setUp(self):
super(AccessAndSecurityTests, self).setUp()
super(AccessAndSecurityQuantumProxyTests, self).setUp()
self.floating_ips = self.floating_ips_uuid

View File

@ -27,9 +27,11 @@ import logging
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import messages
from horizon import tables
from openstack_dashboard import api
from openstack_dashboard.api import network
from openstack_dashboard.api import nova
from .keypairs.tables import KeypairsTable
from .floating_ips.tables import FloatingIPsTable
from .security_groups.tables import SecurityGroupsTable
@ -44,7 +46,7 @@ class IndexView(tables.MultiTableView):
def get_keypairs_data(self):
try:
keypairs = api.nova.keypair_list(self.request)
keypairs = nova.keypair_list(self.request)
except:
keypairs = []
exceptions.handle(self.request,
@ -53,7 +55,7 @@ class IndexView(tables.MultiTableView):
def get_security_groups_data(self):
try:
security_groups = api.nova.security_group_list(self.request)
security_groups = nova.security_group_list(self.request)
except:
security_groups = []
exceptions.handle(self.request,
@ -62,15 +64,23 @@ class IndexView(tables.MultiTableView):
def get_floating_ips_data(self):
try:
floating_ips = api.nova.tenant_floating_ip_list(self.request)
floating_ips = network.tenant_floating_ip_list(self.request)
except:
floating_ips = []
exceptions.handle(self.request,
_('Unable to retrieve floating IP addresses.'))
try:
floating_ip_pools = network.floating_ip_pools_list(self.request)
except:
floating_ip_pools = []
messages.warning(self.request,
_('Unable to retrieve floating IP pools.'))
pool_dict = dict([(obj.id, obj.name) for obj in floating_ip_pools])
instances = []
try:
instances = api.nova.server_list(self.request, all_tenants=True)
instances = nova.server_list(self.request, all_tenants=True)
except:
exceptions.handle(self.request,
_('Unable to retrieve instance list.'))
@ -80,5 +90,6 @@ class IndexView(tables.MultiTableView):
for ip in floating_ips:
ip.instance_name = instances_dict[ip.instance_id].name \
if ip.instance_id in instances_dict else None
ip.pool_name = pool_dict.get(ip.pool, ip.pool)
return floating_ips

View File

@ -276,7 +276,8 @@ class AssociateIP(tables.LinkAction):
classes = ("ajax-modal", "btn-associate")
def allowed(self, request, instance):
if HORIZON_CONFIG["simple_ip_management"]:
fip = api.network.NetworkClient(request).floating_ips
if fip.is_simple_associate_supported():
return False
return not is_deleting(instance)
@ -290,19 +291,20 @@ class AssociateIP(tables.LinkAction):
class SimpleAssociateIP(tables.Action):
name = "associate"
name = "associate-simple"
verbose_name = _("Associate Floating IP")
classes = ("btn-associate",)
classes = ("btn-associate-simple",)
def allowed(self, request, instance):
if not HORIZON_CONFIG["simple_ip_management"]:
fip = api.network.NetworkClient(request).floating_ips
if not fip.is_simple_associate_supported():
return False
return not is_deleting(instance)
def single(self, table, request, instance):
try:
fip = api.nova.tenant_floating_ip_allocate(request)
api.nova.server_add_floating_ip(request, instance, fip.id)
fip = api.network.tenant_floating_ip_allocate(request)
api.network.floating_ip_associate(request, fip.id, instance)
messages.success(request,
_("Successfully associated floating IP: %s")
% fip.ip)
@ -312,12 +314,6 @@ class SimpleAssociateIP(tables.Action):
return shortcuts.redirect("horizon:project:instances:index")
if HORIZON_CONFIG["simple_ip_management"]:
CurrentAssociateIP = SimpleAssociateIP
else:
CurrentAssociateIP = AssociateIP
class SimpleDisassociateIP(tables.Action):
name = "disassociate"
verbose_name = _("Disassociate Floating IP")
@ -330,16 +326,15 @@ class SimpleDisassociateIP(tables.Action):
def single(self, table, request, instance_id):
try:
fips = [fip for fip in api.nova.tenant_floating_ip_list(request)
if fip.instance_id == instance_id]
fips = [fip for fip in api.network.tenant_floating_ip_list(request)
if fip.port_id == instance_id]
# Removing multiple floating IPs at once doesn't work, so this pops
# off the first one.
if fips:
fip = fips.pop()
api.nova.server_remove_floating_ip(request,
instance_id,
fip.id)
api.nova.tenant_floating_ip_release(request, fip.id)
api.network.floating_ip_disassociate(request,
fip.id, instance_id)
api.network.tenant_floating_ip_release(request, fip.id)
messages.success(request,
_("Successfully disassociated "
"floating IP: %s") % fip.ip)
@ -452,6 +447,7 @@ class InstancesTable(tables.DataTable):
row_class = UpdateRow
table_actions = (LaunchLink, TerminateInstance)
row_actions = (ConfirmResize, RevertResize, CreateSnapshot,
CurrentAssociateIP, SimpleDisassociateIP, EditInstance,
SimpleAssociateIP, AssociateIP,
SimpleDisassociateIP, EditInstance,
ConsoleLink, LogLink, TogglePause, ToggleSuspend,
RebootInstance, TerminateInstance)

View File

@ -0,0 +1,291 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 NEC Corporation
#
# Licensed 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.
from django import http
from mox import IsA
from novaclient.v1_1.floating_ip_pools import FloatingIPPool
from openstack_dashboard import api
from openstack_dashboard.test import helpers as test
class NetworkApiNovaFloatingIpTests(test.APITestCase):
def setUp(self):
super(NetworkApiNovaFloatingIpTests, self).setUp()
self.mox.StubOutWithMock(api.base, 'is_service_enabled')
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
.AndReturn(False)
def test_floating_ip_pools_list(self):
pool_names = ['pool1', 'pool2']
pools = [FloatingIPPool(None, {'name': pool}) for pool in pool_names]
novaclient = self.stub_novaclient()
novaclient.floating_ip_pools = self.mox.CreateMockAnything()
novaclient.floating_ip_pools.list().AndReturn(pools)
self.mox.ReplayAll()
ret = api.network.floating_ip_pools_list(self.request)
self.assertEqual([p.name for p in ret], pool_names)
def test_floating_ip_list(self):
fips = self.api_floating_ips.list()
novaclient = self.stub_novaclient()
novaclient.floating_ips = self.mox.CreateMockAnything()
novaclient.floating_ips.list().AndReturn(fips)
self.mox.ReplayAll()
ret = api.network.tenant_floating_ip_list(self.request)
for r, e in zip(ret, fips):
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'instance_id']:
self.assertEqual(r.__getattr__(attr), e.__getattr__(attr))
self.assertEqual(r.port_id, e.instance_id)
def test_floating_ip_get(self):
fip = self.api_floating_ips.first()
novaclient = self.stub_novaclient()
novaclient.floating_ips = self.mox.CreateMockAnything()
novaclient.floating_ips.get(fip.id).AndReturn(fip)
self.mox.ReplayAll()
ret = api.network.tenant_floating_ip_get(self.request, fip.id)
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'instance_id']:
self.assertEqual(ret.__getattr__(attr), fip.__getattr__(attr))
self.assertEqual(ret.port_id, fip.instance_id)
def test_floating_ip_allocate(self):
pool_name = 'fip_pool'
fip = self.api_floating_ips.first()
novaclient = self.stub_novaclient()
novaclient.floating_ips = self.mox.CreateMockAnything()
novaclient.floating_ips.create(pool=pool_name).AndReturn(fip)
self.mox.ReplayAll()
ret = api.network.tenant_floating_ip_allocate(self.request, pool_name)
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'instance_id']:
self.assertEqual(ret.__getattr__(attr), fip.__getattr__(attr))
self.assertEqual(ret.port_id, fip.instance_id)
def test_floating_ip_release(self):
fip = self.api_floating_ips.first()
novaclient = self.stub_novaclient()
novaclient.floating_ips = self.mox.CreateMockAnything()
novaclient.floating_ips.delete(fip.id)
self.mox.ReplayAll()
api.network.tenant_floating_ip_release(self.request, fip.id)
def test_floating_ip_associate(self):
server = api.nova.Server(self.servers.first(), self.request)
floating_ip = self.floating_ips.first()
novaclient = self.stub_novaclient()
novaclient.floating_ips = self.mox.CreateMockAnything()
novaclient.servers = self.mox.CreateMockAnything()
novaclient.servers.get(server.id).AndReturn(server)
novaclient.floating_ips.get(floating_ip.id).AndReturn(floating_ip)
novaclient.servers.add_floating_ip(server.id, floating_ip.ip) \
.AndReturn(server)
self.mox.ReplayAll()
api.network.floating_ip_associate(self.request,
floating_ip.id,
server.id)
def test_floating_ip_disassociate(self):
server = api.nova.Server(self.servers.first(), self.request)
floating_ip = self.api_floating_ips.first()
novaclient = self.stub_novaclient()
novaclient.servers = self.mox.CreateMockAnything()
novaclient.floating_ips = self.mox.CreateMockAnything()
novaclient.servers.get(server.id).AndReturn(server)
novaclient.floating_ips.get(floating_ip.id).AndReturn(floating_ip)
novaclient.servers.remove_floating_ip(server.id, floating_ip.ip) \
.AndReturn(server)
self.mox.ReplayAll()
api.network.floating_ip_disassociate(self.request,
floating_ip.id,
server.id)
def test_floating_ip_target_list(self):
servers = self.servers.list()
novaclient = self.stub_novaclient()
novaclient.servers = self.mox.CreateMockAnything()
novaclient.servers.list().AndReturn(servers)
self.mox.ReplayAll()
targets = api.network.floating_ip_target_list(self.request)
for target, server in zip(targets, servers):
self.assertEqual(target.id, server.id)
self.assertEqual(target.name, '%s (%s)' % (server.name, server.id))
def test_floating_ip_target_get_by_instance(self):
self.mox.ReplayAll()
instance_id = self.servers.first().id
ret = api.network.floating_ip_target_get_by_instance(self.request,
instance_id)
self.assertEqual(instance_id, ret)
class NetworkApiQuantumFloatingIpTests(test.APITestCase):
def setUp(self):
super(NetworkApiQuantumFloatingIpTests, self).setUp()
self.mox.StubOutWithMock(api.base, 'is_service_enabled')
api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \
.AndReturn(True)
self.qclient = self.stub_quantumclient()
def test_floating_ip_pools_list(self):
search_opts = {'router:external': True}
ext_nets = [n for n in self.api_networks.list()
if n['router:external']]
self.qclient.list_networks(**search_opts) \
.AndReturn({'networks': ext_nets})
self.mox.ReplayAll()
rets = api.network.floating_ip_pools_list(self.request)
for attr in ['id', 'name']:
self.assertEqual([p.__getattr__(attr) for p in rets],
[p[attr] for p in ext_nets])
def test_floating_ip_list(self):
fips = self.api_q_floating_ips.list()
self.qclient.list_floatingips().AndReturn({'floatingips': fips})
self.qclient.list_ports().AndReturn({'ports': self.api_ports.list()})
self.mox.ReplayAll()
rets = api.network.tenant_floating_ip_list(self.request)
assoc_port = self.api_ports.list()[1]
self.assertEqual(len(fips), len(rets))
for ret, exp in zip(rets, fips):
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'port_id']:
self.assertEqual(ret.__getattr__(attr), exp[attr])
if exp['port_id']:
dev_id = assoc_port['device_id'] if exp['port_id'] else None
self.assertEqual(ret.instance_id, dev_id)
def test_floating_ip_get_associated(self):
fip = self.api_q_floating_ips.list()[1]
assoc_port = self.api_ports.list()[1]
self.qclient.show_floatingip(fip['id']).AndReturn({'floatingip': fip})
self.qclient.show_port(assoc_port['id']) \
.AndReturn({'port': assoc_port})
self.mox.ReplayAll()
ret = api.network.tenant_floating_ip_get(self.request, fip['id'])
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'port_id']:
self.assertEqual(ret.__getattr__(attr), fip[attr])
self.assertEqual(ret.instance_id, assoc_port['device_id'])
def test_floating_ip_get_unassociated(self):
fip = self.api_q_floating_ips.list()[0]
self.qclient.show_floatingip(fip['id']).AndReturn({'floatingip': fip})
self.mox.ReplayAll()
ret = api.network.tenant_floating_ip_get(self.request, fip['id'])
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'port_id']:
self.assertEqual(ret.__getattr__(attr), fip[attr])
self.assertEqual(ret.instance_id, None)
def test_floating_ip_allocate(self):
ext_nets = [n for n in self.api_networks.list()
if n['router:external']]
ext_net = ext_nets[0]
fip = self.api_q_floating_ips.first()
self.qclient.create_floatingip(
{'floatingip': {'floating_network_id': ext_net['id']}}) \
.AndReturn({'floatingip': fip})
self.mox.ReplayAll()
ret = api.network.tenant_floating_ip_allocate(self.request,
ext_net['id'])
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'port_id']:
self.assertEqual(ret.__getattr__(attr), fip[attr])
self.assertEqual(ret.instance_id, None)
def test_floating_ip_release(self):
fip = self.api_q_floating_ips.first()
self.qclient.delete_floatingip(fip['id'])
self.mox.ReplayAll()
api.network.tenant_floating_ip_release(self.request, fip['id'])
def test_floating_ip_associate(self):
fip = self.api_q_floating_ips.list()[1]
assoc_port = self.api_ports.list()[1]
ip_address = assoc_port['fixed_ips'][0]['ip_address']
target_id = '%s_%s' % (assoc_port['id'], ip_address)
params = {'port_id': assoc_port['id'],
'fixed_ip_address': ip_address}
self.qclient.update_floatingip(fip['id'],
{'floatingip': params})
self.mox.ReplayAll()
api.network.floating_ip_associate(self.request, fip['id'], target_id)
def test_floating_ip_disassociate(self):
fip = self.api_q_floating_ips.list()[1]
assoc_port = self.api_ports.list()[1]
ip_address = assoc_port['fixed_ips'][0]['ip_address']
target_id = '%s_%s' % (assoc_port['id'], ip_address)
self.qclient.update_floatingip(fip['id'],
{'floatingip': {'port_id': None}})
self.mox.ReplayAll()
api.network.floating_ip_disassociate(self.request, fip['id'],
target_id)
def _get_target_id(self, port):
param = {'id': port['id'],
'addr': port['fixed_ips'][0]['ip_address']}
return '%(id)s_%(addr)s' % param
def _get_target_name(self, port):
param = {'svrid': port['device_id'],
'addr': port['fixed_ips'][0]['ip_address']}
return 'server_%(svrid)s: %(addr)s' % param
def test_floating_ip_target_list(self):
ports = self.api_ports.list()
target_ports = [(self._get_target_id(p),
self._get_target_name(p)) for p in ports
if not p['device_owner'].startswith('network:')]
self.qclient.list_ports().AndReturn({'ports': ports})
servers = self.servers.list()
novaclient = self.stub_novaclient()
novaclient.servers = self.mox.CreateMockAnything()
search_opts = {'project_id': self.request.user.tenant_id}
novaclient.servers.list(True, search_opts).AndReturn(servers)
self.mox.ReplayAll()
rets = api.network.floating_ip_target_list(self.request)
self.assertEqual(len(rets), len(target_ports))
for ret, exp in zip(rets, target_ports):
self.assertEqual(ret.id, exp[0])
self.assertEqual(ret.name, exp[1])
def test_floating_ip_target_get_by_instance(self):
ports = self.api_ports.list()
candidates = [p for p in ports if p['device_id'] == '1']
search_opts = {'device_id': '1'}
self.qclient.list_ports(**search_opts).AndReturn({'ports': candidates})
self.mox.ReplayAll()
ret = api.network.floating_ip_target_get_by_instance(self.request, '1')
self.assertEqual(ret, self._get_target_id(candidates[0]))

View File

@ -138,42 +138,6 @@ class ComputeApiTests(test.APITestCase):
ret_val = api.nova.server_get(self.request, server.id)
self.assertIsInstance(ret_val, api.nova.Server)
def test_server_remove_floating_ip(self):
server = api.nova.Server(self.servers.first(), self.request)
floating_ip = self.floating_ips.first()
novaclient = self.stub_novaclient()
novaclient.servers = self.mox.CreateMockAnything()
novaclient.floating_ips = self.mox.CreateMockAnything()
novaclient.servers.get(server.id).AndReturn(server)
novaclient.floating_ips.get(floating_ip.id).AndReturn(floating_ip)
novaclient.servers.remove_floating_ip(server.id, floating_ip.ip) \
.AndReturn(server)
self.mox.ReplayAll()
server = api.nova.server_remove_floating_ip(self.request,
server.id,
floating_ip.id)
self.assertIsInstance(server, api.nova.Server)
def test_server_add_floating_ip(self):
server = api.nova.Server(self.servers.first(), self.request)
floating_ip = self.floating_ips.first()
novaclient = self.stub_novaclient()
novaclient.floating_ips = self.mox.CreateMockAnything()
novaclient.servers = self.mox.CreateMockAnything()
novaclient.servers.get(server.id).AndReturn(server)
novaclient.floating_ips.get(floating_ip.id).AndReturn(floating_ip)
novaclient.servers.add_floating_ip(server.id, floating_ip.ip) \
.AndReturn(server)
self.mox.ReplayAll()
server = api.nova.server_add_floating_ip(self.request,
server.id,
floating_ip.id)
self.assertIsInstance(server, api.nova.Server)
def test_absolute_limits_handle_unlimited(self):
values = {"maxTotalCores": -1, "maxTotalInstances": 10}
limits = self.mox.CreateMockAnything()

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import json
import uuid
@ -23,6 +24,7 @@ from novaclient.v1_1 import (flavors, keypairs, servers, volumes,
security_groups as sec_groups)
from openstack_dashboard.api.base import Quota, QuotaSet as QuotaSetWrapper
from openstack_dashboard.api.nova import FloatingIp as NetFloatingIp
from openstack_dashboard.usage.quotas import QuotaUsage
from .utils import TestDataContainer
@ -150,6 +152,11 @@ def data(TEST):
TEST.volume_snapshots = TestDataContainer()
TEST.volume_types = TestDataContainer()
# Data return by novaclient.
# It is used if API layer does data conversion.
TEST.api_floating_ips = TestDataContainer()
TEST.api_floating_ips_uuid = TestDataContainer()
# Volumes
volume = volumes.Volume(volumes.VolumeManager(None),
dict(id="41023e92-8008-4c8b-8059-7f2293ff3775",
@ -356,26 +363,36 @@ def data(TEST):
{'id': 1,
'fixed_ip': '10.0.0.4',
'instance_id': server_1.id,
'ip': '58.58.58.58'})
'ip': '58.58.58.58',
'pool': 'pool1'})
fip_2 = floating_ips.FloatingIP(floating_ips.FloatingIPManager(None),
{'id': 2,
'fixed_ip': None,
'instance_id': None,
'ip': '58.58.58.58'})
TEST.floating_ips.add(fip_1, fip_2)
'ip': '58.58.58.58',
'pool': 'pool2'})
TEST.api_floating_ips.add(fip_1, fip_2)
# Floating IP with UUID id (for Floating IP with Quantum)
TEST.floating_ips.add(NetFloatingIp(copy.deepcopy(fip_1)),
NetFloatingIp(copy.deepcopy(fip_2)))
# Floating IP with UUID id (for Floating IP with Quantum Proxy)
fip_3 = floating_ips.FloatingIP(floating_ips.FloatingIPManager(None),
{'id': str(uuid.uuid4()),
'fixed_ip': '10.0.0.4',
'instance_id': server_1.id,
'ip': '58.58.58.58'})
'ip': '58.58.58.58',
'pool': 'pool1'})
fip_4 = floating_ips.FloatingIP(floating_ips.FloatingIPManager(None),
{'id': str(uuid.uuid4()),
'fixed_ip': None,
'instance_id': None,
'ip': '58.58.58.58'})
TEST.floating_ips_uuid.add(fip_3, fip_4)
'ip': '58.58.58.58',
'pool': 'pool2'})
TEST.api_floating_ips_uuid.add(fip_3, fip_4)
TEST.floating_ips_uuid.add(NetFloatingIp(copy.deepcopy(fip_3)),
NetFloatingIp(copy.deepcopy(fip_4)))
# Usage
usage_vals = {"tenant_id": TEST.tenant.id,

View File

@ -14,7 +14,8 @@
import copy
from openstack_dashboard.api.quantum import Network, Subnet, Port, Router
from openstack_dashboard.api.quantum import (Network, Subnet, Port,
Router, FloatingIp)
from .utils import TestDataContainer
@ -25,13 +26,16 @@ def data(TEST):
TEST.subnets = TestDataContainer()
TEST.ports = TestDataContainer()
TEST.routers = TestDataContainer()
TEST.q_floating_ips = TestDataContainer()
# data return by quantumclient
TEST.api_networks = TestDataContainer()
TEST.api_subnets = TestDataContainer()
TEST.api_ports = TestDataContainer()
TEST.api_routers = TestDataContainer()
TEST.api_q_floating_ips = TestDataContainer()
#------------------------------------------------------------
# 1st network
network_dict = {'admin_state_up': True,
'id': '82288d84-e0a5-42ac-95be-e6af08727e42',
@ -53,6 +57,17 @@ def data(TEST):
'name': 'mysubnet1',
'network_id': network_dict['id'],
'tenant_id': network_dict['tenant_id']}
TEST.api_networks.add(network_dict)
TEST.api_subnets.add(subnet_dict)
network = copy.deepcopy(network_dict)
subnet = Subnet(subnet_dict)
network['subnets'] = [subnet]
TEST.networks.add(Network(network))
TEST.subnets.add(subnet)
# ports on 1st network
port_dict = {'admin_state_up': True,
'device_id': 'af75c8e5-a1cc-4567-8d04-44fcd6922890',
'device_owner': 'network:dhcp',
@ -64,17 +79,25 @@ def data(TEST):
'network_id': network_dict['id'],
'status': 'ACTIVE',
'tenant_id': network_dict['tenant_id']}
TEST.api_networks.add(network_dict)
TEST.api_subnets.add(subnet_dict)
TEST.api_ports.add(port_dict)
network = copy.deepcopy(network_dict)
subnet = Subnet(subnet_dict)
network['subnets'] = [subnet]
TEST.networks.add(Network(network))
TEST.subnets.add(subnet)
TEST.ports.add(Port(port_dict))
port_dict = {'admin_state_up': True,
'device_id': '1',
'device_owner': 'compute:nova',
'fixed_ips': [{'ip_address': '10.0.0.4',
'subnet_id': subnet_dict['id']}],
'id': '7e6ce62c-7ea2-44f8-b6b4-769af90a8406',
'mac_address': 'fa:16:3e:9d:e6:2f',
'name': '',
'network_id': network_dict['id'],
'status': 'ACTIVE',
'tenant_id': network_dict['tenant_id']}
TEST.api_ports.add(port_dict)
TEST.ports.add(Port(port_dict))
assoc_port = port_dict
#------------------------------------------------------------
# 2nd network
network_dict = {'admin_state_up': True,
'id': '72c3ab6c-c80f-4341-9dc5-210fa31ac6c2',
@ -82,7 +105,7 @@ def data(TEST):
'status': 'ACTIVE',
'subnets': ['3f7c5d79-ee55-47b0-9213-8e669fb03009'],
'tenant_id': '2',
'router:external': True,
'router:external': False,
'shared': True}
subnet_dict = {'allocation_pools': [{'end': '172.16.88.254',
'start': '172.16.88.2'}],
@ -99,28 +122,66 @@ def data(TEST):
'name': 'aaaa',
'network_id': network_dict['id'],
'tenant_id': network_dict['tenant_id']}
port_dict = {'admin_state_up': True,
'device_id': '40e536b1-b9fd-4eb7-82d6-84db5d65a2ac',
'device_owner': 'compute:nova',
'fixed_ips': [{'ip_address': '172.16.88.3',
'subnet_id': subnet_dict['id']}],
'id': '7e6ce62c-7ea2-44f8-b6b4-769af90a8406',
'mac_address': 'fa:16:3e:56:e6:2f',
'name': '',
'network_id': network_dict['id'],
'status': 'ACTIVE',
'tenant_id': network_dict['tenant_id']}
TEST.api_networks.add(network_dict)
TEST.api_subnets.add(subnet_dict)
TEST.api_ports.add(port_dict)
network = copy.deepcopy(network_dict)
subnet = Subnet(subnet_dict)
network['subnets'] = [subnet]
TEST.networks.add(Network(network))
TEST.subnets.add(subnet)
port_dict = {'admin_state_up': True,
'device_id': '2',
'device_owner': 'compute:nova',
'fixed_ips': [{'ip_address': '172.16.88.3',
'subnet_id': subnet_dict['id']}],
'id': '1db2cc37-3553-43fa-b7e2-3fc4eb4f9905',
'mac_address': 'fa:16:3e:56:e6:2f',
'name': '',
'network_id': network_dict['id'],
'status': 'ACTIVE',
'tenant_id': network_dict['tenant_id']}
TEST.api_ports.add(port_dict)
TEST.ports.add(Port(port_dict))
#------------------------------------------------------------
# external network
network_dict = {'admin_state_up': True,
'id': '9b466b94-213a-4cda-badf-72c102a874da',
'name': 'ext_net',
'status': 'ACTIVE',
'subnets': ['d6bdc71c-7566-4d32-b3ff-36441ce746e8'],
'tenant_id': '3',
'router:external': True,
'shared': False}
subnet_dict = {'allocation_pools': [{'start': '172.24.4.226.',
'end': '172.24.4.238'}],
'dns_nameservers': [],
'host_routes': [],
'cidr': '172.24.4.0/28',
'enable_dhcp': False,
'gateway_ip': '172.24.4.225',
'id': 'd6bdc71c-7566-4d32-b3ff-36441ce746e8',
'ip_version': 4,
'name': 'ext_subnet',
'network_id': network_dict['id'],
'tenant_id': network_dict['tenant_id']}
ext_net = network_dict
ext_subnet = subnet_dict
TEST.api_networks.add(network_dict)
TEST.api_subnets.add(subnet_dict)
network = copy.deepcopy(network_dict)
subnet = Subnet(subnet_dict)
network['subnets'] = [subnet]
TEST.networks.add(Network(network))
TEST.subnets.add(subnet)
#------------------------------------------------------------
# Set up router data
port_dict = {'admin_state_up': True,
'device_id': '7180cede-bcd8-4334-b19f-f7ef2f331f53',
@ -146,3 +207,27 @@ def data(TEST):
'tenant_id': '1'}
TEST.api_routers.add(router_dict)
TEST.routers.add(Router(router_dict))
#------------------------------------------------------------
# floating IP
# unassociated
fip_dict = {'tenant_id': '1',
'floating_ip_address': '172.16.88.227',
'floating_network_id': ext_net['id'],
'id': '9012cd70-cfae-4e46-b71e-6a409e9e0063',
'fixed_ip_address': None,
'port_id': None,
'router_id': None}
TEST.api_q_floating_ips.add(fip_dict)
TEST.q_floating_ips.add(FloatingIp(fip_dict))
# associated (with compute port on 1st network)
fip_dict = {'tenant_id': '1',
'floating_ip_address': '172.16.88.228',
'floating_network_id': ext_net['id'],
'id': 'a97af8f2-3149-4b97-abbd-e49ad19510f7',
'fixed_ip_address': assoc_port['fixed_ips'][0]['ip_address'],
'port_id': assoc_port['id'],
'router_id': router_dict['id']}
TEST.api_q_floating_ips.add(fip_dict)
TEST.q_floating_ips.add(FloatingIp(fip_dict))

View File

@ -33,8 +33,8 @@ from openstack_dashboard.usage import quotas
class QuotaTests(test.APITestCase):
@test.create_stubs({api.nova: ('server_list',
'flavor_list',
'tenant_floating_ip_list',
'tenant_quota_get',),
api.network: ('tenant_floating_ip_list',),
quotas: ('is_service_enabled',),
cinder: ('volume_list', 'tenant_quota_get',)})
def test_tenant_quota_usages(self):
@ -44,7 +44,7 @@ class QuotaTests(test.APITestCase):
.AndReturn(self.flavors.list())
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
.AndReturn(self.quotas.first())
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.server_list(IsA(http.HttpRequest)) \
.AndReturn(self.servers.list())
@ -73,8 +73,8 @@ class QuotaTests(test.APITestCase):
@test.create_stubs({api.nova: ('server_list',
'flavor_list',
'tenant_floating_ip_list',
'tenant_quota_get',),
api.network: ('tenant_floating_ip_list',),
quotas: ('is_service_enabled',)})
def test_tenant_quota_usages_without_volume(self):
quotas.is_service_enabled(IsA(http.HttpRequest),
@ -83,7 +83,7 @@ class QuotaTests(test.APITestCase):
.AndReturn(self.flavors.list())
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
.AndReturn(self.quotas.first())
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.server_list(IsA(http.HttpRequest)) \
.AndReturn(self.servers.list())
@ -106,8 +106,8 @@ class QuotaTests(test.APITestCase):
@test.create_stubs({api.nova: ('server_list',
'flavor_list',
'tenant_floating_ip_list',
'tenant_quota_get',),
api.network: ('tenant_floating_ip_list',),
quotas: ('is_service_enabled',)})
def test_tenant_quota_usages_no_instances_running(self):
quotas.is_service_enabled(IsA(http.HttpRequest),
@ -116,7 +116,8 @@ class QuotaTests(test.APITestCase):
.AndReturn(self.flavors.list())
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
.AndReturn(self.quotas.first())
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)).AndReturn([])
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn([])
api.nova.server_list(IsA(http.HttpRequest)).AndReturn([])
self.mox.ReplayAll()
@ -137,8 +138,8 @@ class QuotaTests(test.APITestCase):
@test.create_stubs({api.nova: ('server_list',
'flavor_list',
'tenant_floating_ip_list',
'tenant_quota_get',),
api.network: ('tenant_floating_ip_list',),
quotas: ('is_service_enabled',),
cinder: ('volume_list', 'tenant_quota_get',)})
def test_tenant_quota_usages_unlimited_quota(self):
@ -151,7 +152,7 @@ class QuotaTests(test.APITestCase):
.AndReturn(self.flavors.list())
api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \
.AndReturn(inf_quota)
api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \
api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \
.AndReturn(self.floating_ips.list())
api.nova.server_list(IsA(http.HttpRequest)) \
.AndReturn(self.servers.list())

View File

@ -4,7 +4,7 @@ import itertools
from horizon import exceptions
from horizon.utils.memoized import memoized
from openstack_dashboard.api import nova, cinder
from openstack_dashboard.api import nova, cinder, network
from openstack_dashboard.api.base import is_service_enabled, QuotaSet
@ -85,7 +85,7 @@ def tenant_quota_usages(request):
usages.add_quota(quota)
# Get our usages.
floating_ips = nova.tenant_floating_ip_list(request)
floating_ips = network.tenant_floating_ip_list(request)
flavors = dict([(f.id, f) for f in nova.flavor_list(request)])
instances = nova.server_list(request)
# Fetch deleted flavors if necessary.