moved floating ip db access and sanity checking from network api into network manager

added floating ip get by fixed address
added fixed_ip_get
moved floating ip testing from osapi into the network tests where they
belong

Change-Id: I3ee53971206e37405a2adc2491412f7896e1af87
This commit is contained in:
Trey Morris
2011-09-16 14:07:41 -05:00
parent 070e60d217
commit 15b2a3b85b
11 changed files with 455 additions and 309 deletions

View File

@@ -80,8 +80,8 @@ class FloatingIPController(object):
context = req.environ['nova.context']
try:
# FIXME(ja) - why does self.network_api.list_floating_ips raise?
floating_ips = self.network_api.list_floating_ips(context)
get_floating_ips = self.network_api.get_floating_ips_by_project
floating_ips = get_floating_ips(context)
except exception.FloatingIpNotFoundForProject:
floating_ips = []
@@ -92,7 +92,7 @@ class FloatingIPController(object):
try:
address = self.network_api.allocate_floating_ip(context)
ip = self.network_api.get_floating_ip_by_ip(context, address)
ip = self.network_api.get_floating_ip_by_address(context, address)
except rpc.RemoteError as ex:
# NOTE(tr3buchet) - why does this block exist?
if ex.exc_type == 'NoMoreFloatingIps':
@@ -162,7 +162,8 @@ class Floating_ips(extensions.ExtensionDescriptor):
msg = _("Address not specified")
raise webob.exc.HTTPBadRequest(explanation=msg)
floating_ip = self.network_api.get_floating_ip_by_ip(context, address)
floating_ip = self.network_api.get_floating_ip_by_address(context,
address)
if floating_ip.get('fixed_ip'):
try:
self.network_api.disassociate_floating_ip(context, address)

View File

@@ -1521,8 +1521,8 @@ class API(base.Base):
LOG.warning(_("multiple fixed_ips exist, using the first: %s"),
fixed_ip_addrs[0])
self.network_api.associate_floating_ip(context,
floating_ip=address,
fixed_ip=fixed_ip_addrs[0])
floating_address=address,
fixed_address=fixed_ip_addrs[0])
def get_instance_metadata(self, context, instance_id):
"""Get all metadata associated with an instance."""

View File

@@ -372,6 +372,11 @@ def fixed_ip_disassociate_all_by_timeout(context, host, time):
return IMPL.fixed_ip_disassociate_all_by_timeout(context, host, time)
def fixed_ip_get(context, id):
"""Get fixed ip by id or raise if it does not exist."""
return IMPL.fixed_ip_get(context, id)
def fixed_ip_get_all(context):
"""Get all defined fixed ips."""
return IMPL.fixed_ip_get_all(context)

View File

@@ -796,6 +796,25 @@ def fixed_ip_disassociate_all_by_timeout(_context, host, time):
return result
@require_context
def fixed_ip_get(context, id, session=None):
if not session:
session = get_session()
result = session.query(models.FixedIp).\
filter_by(id=id).\
filter_by(deleted=can_read_deleted(context)).\
options(joinedload('floating_ips')).\
options(joinedload('network')).\
first()
if not result:
raise exception.FixedIpNotFound(id=id)
if is_user_context(context):
authorize_project_context(context, result.instance.project_id)
return result
@require_admin_context
def fixed_ip_get_all(context, session=None):
if not session:

View File

@@ -539,8 +539,12 @@ class NoMoreFloatingIps(FloatingIpNotFound):
message = _("Zero floating ips available.")
class FloatingIpAlreadyInUse(NovaException):
message = _("Floating ip %(address)s already in use by %(fixed_ip)s.")
class FloatingIpAssociated(NovaException):
message = _("Floating ip %(address)s is associated.")
class FloatingIpNotAssociated(NovaException):
message = _("Floating ip %(address)s is not associated.")
class NoFloatingIpsDefined(NotFound):

View File

@@ -34,17 +34,27 @@ class API(base.Base):
"""API for interacting with the network manager."""
def get_floating_ip(self, context, id):
rv = self.db.floating_ip_get(context, id)
return dict(rv.iteritems())
return rpc.call(context,
FLAGS.network_topic,
{'method': 'get_floating_ip',
'args': {'id': id}})
def get_floating_ip_by_ip(self, context, address):
res = self.db.floating_ip_get_by_address(context, address)
return dict(res.iteritems())
def get_floating_ip_by_address(self, context, address):
return rpc.call(context,
FLAGS.network_topic,
{'method': 'get_floating_ip_by_address',
'args': {'address': address}})
def list_floating_ips(self, context):
ips = self.db.floating_ip_get_all_by_project(context,
context.project_id)
return ips
def get_floating_ips_by_project(self, context):
return rpc.call(context,
FLAGS.network_topic,
{'method': 'get_floating_ips_by_project'})
def get_floating_ips_by_fixed_address(self, context, fixed_address):
return rpc.call(context,
FLAGS.network_topic,
{'method': 'get_floating_ips_by_fixed_address',
'args': {'address': address}})
def get_floating_ips_by_fixed_address(self, context, fixed_address):
return rpc.call(context,
@@ -53,12 +63,13 @@ class API(base.Base):
'args': {'fixed_address': fixed_address}})
def get_vifs_by_instance(self, context, instance_id):
return rpc.call(context, FLAGS.network_topic,
return rpc.call(context,
FLAGS.network_topic,
{'method': 'get_vifs_by_instance',
'args': {'instance_id': instance_id}})
def allocate_floating_ip(self, context):
"""Adds a floating ip to a project."""
"""Adds a floating ip to a project. (allocates)"""
# NOTE(vish): We don't know which network host should get the ip
# when we allocate, so just send it to any one. This
# will probably need to move into a network supervisor
@@ -70,89 +81,33 @@ class API(base.Base):
def release_floating_ip(self, context, address,
affect_auto_assigned=False):
"""Removes floating ip with address from a project."""
floating_ip = self.db.floating_ip_get_by_address(context, address)
if floating_ip['fixed_ip']:
raise exception.ApiError(_('Floating ip is in use. '
'Disassociate it before releasing.'))
if not affect_auto_assigned and floating_ip.get('auto_assigned'):
return
# NOTE(vish): We don't know which network host should get the ip
# when we deallocate, so just send it to any one. This
# will probably need to move into a network supervisor
# at some point.
"""Removes floating ip with address from a project. (deallocates)"""
rpc.cast(context,
FLAGS.network_topic,
{'method': 'deallocate_floating_ip',
'args': {'floating_address': floating_ip['address']}})
'args': {'floating_address': address,
'affect_auto_assigned': affect_auto_assigned}})
def associate_floating_ip(self, context, floating_ip, fixed_ip,
def associate_floating_ip(self, context, floating_address, fixed_address,
affect_auto_assigned=False):
"""Associates a floating ip with a fixed ip.
ensures floating ip is allocated to the project in context
:param fixed_ip: is either fixed_ip object or a string fixed ip address
:param floating_ip: is a string floating ip address
"""
# NOTE(tr3buchet): i don't like the "either or" argument type
# funcationility but i've left it alone for now
# TODO(tr3buchet): this function needs to be rewritten to move
# the network related db lookups into the network host code
if isinstance(fixed_ip, basestring):
fixed_ip = self.db.fixed_ip_get_by_address(context, fixed_ip)
floating_ip = self.db.floating_ip_get_by_address(context, floating_ip)
if not affect_auto_assigned and floating_ip.get('auto_assigned'):
return
# Check if the floating ip address is allocated
if floating_ip['project_id'] is None:
raise exception.ApiError(_('Address (%s) is not allocated') %
floating_ip['address'])
# Check if the floating ip address is allocated to the same project
if floating_ip['project_id'] != context.project_id:
LOG.warn(_('Address (%(address)s) is not allocated to your '
'project (%(project)s)'),
{'address': floating_ip['address'],
'project': context.project_id})
raise exception.ApiError(_('Address (%(address)s) is not '
'allocated to your project'
'(%(project)s)') %
{'address': floating_ip['address'],
'project': context.project_id})
# If this address has been previously associated to a
# different instance, disassociate the floating_ip
if floating_ip['fixed_ip'] and floating_ip['fixed_ip'] is not fixed_ip:
self.disassociate_floating_ip(context, floating_ip['address'])
# NOTE(vish): if we are multi_host, send to the instances host
if fixed_ip['network']['multi_host']:
host = fixed_ip['instance']['host']
else:
host = fixed_ip['network']['host']
rpc.cast(context,
self.db.queue_get_for(context, FLAGS.network_topic, host),
FLAGS.network_topic,
{'method': 'associate_floating_ip',
'args': {'floating_address': floating_ip['address'],
'fixed_address': fixed_ip['address']}})
'args': {'floating_address': floating_address,
'fixed_address': fixed_address,
'affect_auto_assigned': affect_auto_assigned}})
def disassociate_floating_ip(self, context, address,
affect_auto_assigned=False):
"""Disassociates a floating ip from fixed ip it is associated with."""
floating_ip = self.db.floating_ip_get_by_address(context, address)
if not affect_auto_assigned and floating_ip.get('auto_assigned'):
return
if not floating_ip.get('fixed_ip'):
raise exception.ApiError('Address is not associated.')
# NOTE(vish): if we are multi_host, send to the instances host
if floating_ip['fixed_ip']['network']['multi_host']:
host = floating_ip['fixed_ip']['instance']['host']
else:
host = floating_ip['fixed_ip']['network']['host']
rpc.call(context,
self.db.queue_get_for(context, FLAGS.network_topic, host),
rpc.cast(context,
FLAGS.network_topic,
{'method': 'disassociate_floating_ip',
'args': {'floating_address': floating_ip['address']}})
'args': {'address': address}})
def allocate_for_instance(self, context, instance, **kwargs):
"""Allocates all network structures for an instance.

View File

@@ -219,26 +219,26 @@ class FloatingIP(object):
# call the next inherited class's allocate_for_instance()
# which is currently the NetworkManager version
# do this first so fixed ip is already allocated
ips = super(FloatingIP, self).allocate_for_instance(context, **kwargs)
nw_info = \
super(FloatingIP, self).allocate_for_instance(context, **kwargs)
if FLAGS.auto_assign_floating_ip:
# allocate a floating ip (public_ip is just the address string)
public_ip = self.allocate_floating_ip(context, project_id)
# allocate a floating ip
floating_address = self.allocate_floating_ip(context, project_id)
# set auto_assigned column to true for the floating ip
self.db.floating_ip_set_auto_assigned(context, public_ip)
# get the floating ip object from public_ip string
floating_ip = self.db.floating_ip_get_by_address(context,
public_ip)
self.db.floating_ip_set_auto_assigned(context, floating_address)
# get the first fixed_ip belonging to the instance
fixed_ips = self.db.fixed_ip_get_by_instance(context, instance_id)
fixed_ip = fixed_ips[0] if fixed_ips else None
# get the first fixed address belonging to the instance
for nw, info in nw_info:
if info.get('ips'):
fixed_address = info['ips'][0]['ip']
break
# call to correct network host to associate the floating ip
self.network_api.associate_floating_ip(context,
floating_ip,
fixed_ip,
# associate the floating ip to fixed_ip
self.associate_floating_ip(context,
floating_address,
fixed_address,
affect_auto_assigned=True)
return ips
return nw_info
def deallocate_for_instance(self, context, **kwargs):
"""Handles deallocating floating IP resources for an instance.
@@ -258,21 +258,33 @@ class FloatingIP(object):
# disassociate floating ips related to fixed_ip
for floating_ip in fixed_ip.floating_ips:
address = floating_ip['address']
self.network_api.disassociate_floating_ip(context, address)
self.disassociate_floating_ip(context, address, True)
# deallocate if auto_assigned
if floating_ip['auto_assigned']:
self.network_api.release_floating_ip(context,
address,
True)
self.release_floating_ip(context, address, True)
# call the next inherited class's deallocate_for_instance()
# which is currently the NetworkManager version
# call this after so floating IPs are handled first
super(FloatingIP, self).deallocate_for_instance(context, **kwargs)
def _floating_ip_owned_by_project(self, context, floating_ip):
"""Raises if floating ip does not belong to project"""
if floating_ip['project_id'] != context.project_id:
if floating_ip['project_id'] is None:
LOG.warn(_('Address |%(address)s| is not allocated'),
{'address': floating_ip['address']})
raise exception.NotAuthorized()
else:
LOG.warn(_('Address |%(address)s| is not allocated to your '
'project |%(project)s|'),
{'address': floating_ip['address'],
'project': context.project_id})
raise exception.NotAuthorized()
def allocate_floating_ip(self, context, project_id):
"""Gets an floating ip from the pool."""
# NOTE(tr3buchet): all networks hosts in zone now use the same pool
# NOTE(tr3buchet): all network hosts in zone now use the same pool
LOG.debug("QUOTA: %s" % quota.allowed_floating_ips(context, 1))
if quota.allowed_floating_ips(context, 1) < 1:
LOG.warn(_('Quota exceeded for %s, tried to allocate '
@@ -284,32 +296,146 @@ class FloatingIP(object):
return self.db.floating_ip_allocate_address(context,
project_id)
def associate_floating_ip(self, context, floating_address, fixed_address):
"""Associates an floating ip to a fixed ip."""
def deallocate_floating_ip(self, context, address,
affect_auto_assigned=False):
"""Returns an floating ip to the pool."""
floating_ip = self.db.floating_ip_get_by_address(context, address)
# handle auto_assigned
if not affect_auto_assigned and floating_ip.get('auto_assigned'):
return
# make sure project ownz this floating ip (allocated)
self._floating_ip_owned_by_project(context, floating_ip)
# make sure floating ip is not associated
if floating_ip['fixed_ip_id']:
floating_address = floating_ip['address']
raise exception.FloatingIpAssociated(address=floating_address)
self.db.floating_ip_deallocate(context, address)
def associate_floating_ip(self, context, floating_address, fixed_address,
affect_auto_assigned=False):
"""Associates a floating ip with a fixed ip.
Makes sure everything makes sense then calls _associate_floating_ip,
rpc'ing to correct host if i'm not it.
"""
floating_ip = self.db.floating_ip_get_by_address(context,
floating_address)
if floating_ip['fixed_ip']:
raise exception.FloatingIpAlreadyInUse(
address=floating_ip['address'],
fixed_ip=floating_ip['fixed_ip']['address'])
# handle auto_assigned
if not affect_auto_assigned and floating_ip.get('auto_assigned'):
return
# make sure project ownz this floating ip (allocated)
self._floating_ip_owned_by_project(context, floating_ip)
# make sure floating ip isn't already associated
if floating_ip['fixed_ip_id']:
floating_address = floating_ip['address']
raise exception.FloatingIpAssociated(address=floating_address)
fixed_ip = self.db.fixed_ip_get_by_address(context, fixed_address)
# send to correct host, unless i'm the correct host
if fixed_ip['network']['multi_host']:
instance = self.db.instance_get(context, fixed_ip['instance_id'])
host = instance['host']
else:
host = fixed_ip['network']['host']
LOG.info("%s", self.host)
if host == self.host:
# i'm the correct host
self._associate_floating_ip(context, floating_address,
fixed_address)
else:
# send to correct host
rpc.cast(context,
self.db.queue_get_for(context, FLAGS.network_topic, host),
{'method': '_associate_floating_ip',
'args': {'floating_address': floating_ip['address'],
'fixed_address': fixed_ip['address']}})
def _associate_floating_ip(self, context, floating_address, fixed_address):
"""Performs db and driver calls to associate floating ip & fixed ip"""
# associate floating ip
self.db.floating_ip_fixed_ip_associate(context,
floating_address,
fixed_address,
self.host)
# gogo driver time
self.driver.bind_floating_ip(floating_address)
self.driver.ensure_floating_forward(floating_address, fixed_address)
def disassociate_floating_ip(self, context, floating_address):
"""Disassociates a floating ip."""
fixed_address = self.db.floating_ip_disassociate(context,
floating_address)
self.driver.unbind_floating_ip(floating_address)
self.driver.remove_floating_forward(floating_address, fixed_address)
def disassociate_floating_ip(self, context, address,
affect_auto_assigned=False):
"""Disassociates a floating ip from its fixed ip.
def deallocate_floating_ip(self, context, floating_address):
"""Returns an floating ip to the pool."""
self.db.floating_ip_deallocate(context, floating_address)
Makes sure everything makes sense then calls _disassociate_floating_ip,
rpc'ing to correct host if i'm not it.
"""
floating_ip = self.db.floating_ip_get_by_address(context, address)
# handle auto assigned
if not affect_auto_assigned and floating_ip.get('auto_assigned'):
return
# make sure project ownz this floating ip (allocated)
self._floating_ip_owned_by_project(context, floating_ip)
# make sure floating ip is associated
if not floating_ip.get('fixed_ip_id'):
floating_address = floating_ip['address']
raise exception.FloatingIpNotAssociated(address=floating_address)
fixed_ip = self.db.fixed_ip_get(context, floating_ip['fixed_ip_id'])
# send to correct host, unless i'm the correct host
if fixed_ip['network']['multi_host']:
instance = self.db.instance_get(context, fixed_ip['instance_id'])
host = instance['host']
else:
host = fixed_ip['network']['host']
if host == self.host:
# i'm the correct host
self._disassociate_floating_ip(context, address)
else:
# send to correct host
rpc.cast(context,
self.db.queue_get_for(context, FLAGS.network_topic, host),
{'method': '_disassociate_floating_ip',
'args': {'address': address}})
def _disassociate_floating_ip(self, context, address):
"""Performs db and driver calls to disassociate floating ip"""
# disassociate floating ip
fixed_address = self.db.floating_ip_disassociate(context, address)
# go go driver time
self.driver.unbind_floating_ip(address)
self.driver.remove_floating_forward(address, fixed_address)
def get_floating_ip(self, context, id):
"""Returns a floating IP as a dict"""
return dict(self.db.floating_ip_get(context, id).iteritems())
def get_floating_ip_by_address(self, context, address):
"""Returns a floating IP as a dict"""
return dict(self.db.floating_ip_get_by_address(context,
address).iteritems())
def get_floating_ips_by_project(self, context):
"""Returns the floating IPs allocated to a project"""
ips = self.db.floating_ip_get_all_by_project(context,
context.project_id)
return [dict(ip.iteritems()) for ip in ips]
def get_floating_ips_by_fixed_address(self, context, fixed_address):
"""Returns the floating IPs associated with a fixed_address"""
floating_ips = self.db.floating_ip_get_by_fixed_address(context,
fixed_address)
return [floating_ip['address'] for floating_ip in floating_ips]
def get_floating_ips_by_fixed_address(self, context, fixed_address):
"""Returns the floating IPs associated with a fixed_address"""
@@ -414,11 +540,6 @@ class NetworkManager(manager.SchedulerDependentManager):
# floating ips MUST override this or use the Mixin
return []
def get_vifs_by_instance(self, context, instance_id):
vifs = self.db.virtual_interface_get_by_instance(context,
instance_id)
return vifs
def get_instance_uuids_by_ip_filter(self, context, filters):
fixed_ip_filter = filters.get('fixed_ip')
ip_filter = re.compile(str(filters.get('ip')))
@@ -946,6 +1067,11 @@ class NetworkManager(manager.SchedulerDependentManager):
def _get_networks_by_uuids(self, context, network_uuids):
return self.db.network_get_all_by_uuids(context, network_uuids)
def get_vifs_by_instance(self, context, instance_id):
"""Returns the vifs associated with an instance"""
vifs = self.db.virtual_interface_get_by_instance(context, instance_id)
return [dict(vif.iteritems()) for vif in vifs]
class FlatManager(NetworkManager):
"""Basic network where no vlans are used.
@@ -1004,7 +1130,7 @@ class FlatManager(NetworkManager):
self.db.network_update(context, network_ref['id'], net)
class FlatDHCPManager(FloatingIP, RPCAllocateFixedIP, NetworkManager):
class FlatDHCPManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
"""Flat networking with dhcp.
FlatDHCPManager will start up one dhcp server to give out addresses.

View File

@@ -56,6 +56,7 @@ LOG = log.getLogger('nova.tests')
class skip_test(object):
"""Decorator that skips a test."""
# TODO(tr3buchet): remember forever what comstud did here
def __init__(self, msg):
self.message = msg

View File

@@ -130,24 +130,6 @@ class CloudTestCase(test.TestCase):
result = self.cloud.release_address(self.context, address)
self.assertEqual(result['releaseResponse'], ['Address released.'])
def test_release_address_still_associated(self):
address = "10.10.10.10"
fixed_ip = {'instance': {'id': 1}}
floating_ip = {'id': 0,
'address': address,
'fixed_ip_id': 0,
'fixed_ip': fixed_ip,
'project_id': None,
'auto_assigned': False}
network_api = network.api.API()
self.mox.StubOutWithMock(network_api.db, 'floating_ip_get_by_address')
network_api.db.floating_ip_get_by_address(mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(floating_ip)
self.mox.ReplayAll()
release = self.cloud.release_address
# ApiError: Floating ip is in use. Disassociate it before releasing.
self.assertRaises(exception.ApiError, release, self.context, address)
def test_associate_disassociate_address(self):
"""Verifies associate runs cleanly without raising an exception"""
address = "10.10.10.10"

View File

@@ -36,12 +36,12 @@ def network_api_get_floating_ip(self, context, id):
'fixed_ip': None}
def network_api_get_floating_ip_by_ip(self, context, address):
def network_api_get_floating_ip_by_address(self, context, address):
return {'id': 1, 'address': '10.10.10.10',
'fixed_ip': {'address': '10.0.0.1', 'instance_id': 1}},
'fixed_ip': {'address': '10.0.0.1', 'instance_id': 1}}
def network_api_list_floating_ips(self, context):
def network_api_get_floating_ips_by_project(self, context):
return [{'id': 1,
'address': '10.10.10.10',
'fixed_ip': {'address': '10.0.0.1', 'instance_id': 1}},
@@ -57,11 +57,11 @@ def network_api_release(self, context, address):
pass
def compute_api_associate(self, context, instance_id, floating_ip):
def compute_api_associate(self, context, instance_id, address):
pass
def network_api_associate(self, context, floating_ip, fixed_ip):
def network_api_associate(self, context, floating_address, fixed_address):
pass
@@ -110,10 +110,10 @@ class FloatingIpTest(test.TestCase):
super(FloatingIpTest, self).setUp()
self.stubs.Set(network.api.API, "get_floating_ip",
network_api_get_floating_ip)
self.stubs.Set(network.api.API, "get_floating_ip_by_ip",
network_api_get_floating_ip)
self.stubs.Set(network.api.API, "list_floating_ips",
network_api_list_floating_ips)
self.stubs.Set(network.api.API, "get_floating_ip_by_address",
network_api_get_floating_ip_by_address)
self.stubs.Set(network.api.API, "get_floating_ips_by_project",
network_api_get_floating_ips_by_project)
self.stubs.Set(network.api.API, "release_floating_ip",
network_api_release)
self.stubs.Set(network.api.API, "disassociate_floating_ip",
@@ -184,6 +184,7 @@ class FloatingIpTest(test.TestCase):
self.assertEqual(res_dict['floating_ip']['ip'], '10.10.10.10')
self.assertEqual(res_dict['floating_ip']['instance_id'], 1)
# test floating ip allocate/release(deallocate)
def test_floating_ip_allocate_no_free_ips(self):
def fake_call(*args, **kwargs):
raise(rpc.RemoteError('NoMoreFloatingIps', '', ''))
@@ -196,8 +197,16 @@ class FloatingIpTest(test.TestCase):
self.assertEqual(res.status_int, 400)
def test_floating_ip_allocate(self):
def fake1(*args, **kwargs):
pass
def fake2(*args, **kwargs):
return {'id': 1, 'address': '10.10.10.10'}
self.stubs.Set(network.api.API, "allocate_floating_ip",
network_api_allocate)
fake1)
self.stubs.Set(network.api.API, "get_floating_ip_by_address",
fake2)
req = webob.Request.blank('/v1.1/123/os-floating-ips')
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
@@ -212,50 +221,16 @@ class FloatingIpTest(test.TestCase):
"fixed_ip": None}
self.assertEqual(ip, expected)
def test_floating_ip_release_associated(self):
self.disassociated = False
def get_floating_ip(ignore, context, id):
return {'id': 1, 'address': '10.10.10.10',
'fixed_ip': {'id': 1}}
def disassociate(ignore, context, floating_address):
self.disassociated = True
self.stubs.Set(network.api.API, "get_floating_ip",
get_floating_ip)
self.stubs.Set(network.api.API, "disassociate_floating_ip",
disassociate)
def test_floating_ip_release(self):
req = webob.Request.blank('/v1.1/123/os-floating-ips/1')
req.method = 'DELETE'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
self.assertTrue(self.disassociated)
def test_floating_ip_release_disassociated(self):
self.disassociated = False
# test floating ip add/remove -> associate/disassociate
def fake_get_floating_ip(ignore, context, id):
return {'id': 1, 'address': '10.10.10.10',
'fixed_ip': None}
def fake_disassociate(ignore, context, floating_address):
self.disassociated = True
self.stubs.Set(network.api.API, "get_floating_ip",
fake_get_floating_ip)
self.stubs.Set(network.api.API, "disassociate_floating_ip",
fake_disassociate)
req = webob.Request.blank('/v1.1/123/os-floating-ips/1')
req.method = 'DELETE'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
self.assertFalse(self.disassociated)
def test_add_floating_ip_to_instance(self):
self.stubs.Set(network.api.API, "associate_floating_ip",
network_api_associate)
body = dict(addFloatingIp=dict(address='11.0.0.1'))
def test_floating_ip_associate(self):
body = dict(addFloatingIp=dict(address=self.address))
req = webob.Request.blank('/v1.1/123/servers/test_inst/action')
req.method = "POST"
req.body = json.dumps(body)
@@ -264,79 +239,7 @@ class FloatingIpTest(test.TestCase):
resp = req.get_response(fakes.wsgi_app())
self.assertEqual(resp.status_int, 202)
def test_associate_floating_ip_to_instance_wrong_project_id(self):
def fake_fixed_ip_get_by_address(ctx, address, session=None):
return {'address': address, 'network': {'multi_host': None,
'host': 'fake'}}
self.stubs.Set(db.api, "fixed_ip_get_by_address",
fake_fixed_ip_get_by_address)
db.floating_ip_update(self.context, self.address, {'project_id': 'bad',
'fixed_ip_id': 1})
body = dict(addFloatingIp=dict(address=self.address))
req = webob.Request.blank('/v1.1/123/servers/test_inst/action')
req.method = "POST"
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
resp = req.get_response(fakes.wsgi_app())
self.assertEqual(resp.status_int, 401)
def test_associate_floating_ip_to_instance_no_project_id(self):
def fake_fixed_ip_get_by_address(ctx, address, session=None):
return {'address': address, 'network': {'multi_host': None,
'host': 'fake'}}
self.stubs.Set(db.api, "fixed_ip_get_by_address",
fake_fixed_ip_get_by_address)
db.floating_ip_update(self.context, self.address, {'project_id': None,
'fixed_ip_id': 1})
body = dict(addFloatingIp=dict(address=self.address))
req = webob.Request.blank('/v1.1/123/servers/test_inst/action')
req.method = "POST"
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
resp = req.get_response(fakes.wsgi_app())
self.assertEqual(resp.status_int, 400)
def test_add_associated_floating_ip_to_instance(self):
def fake_fixed_ip_get_by_address(ctx, address, session=None):
return {'address': address, 'network': {'multi_host': None,
'host': 'fake'}}
self.disassociated = False
def fake_network_api_disassociate(local_self, ctx, floating_address):
self.disassociated = True
db.floating_ip_update(self.context, self.address, {'project_id': '123',
'fixed_ip_id': 1})
self.stubs.Set(network.api.API, "disassociate_floating_ip",
fake_network_api_disassociate)
self.stubs.Set(db.api, "fixed_ip_get_by_address",
fake_fixed_ip_get_by_address)
body = dict(addFloatingIp=dict(address=self.address))
req = webob.Request.blank('/v1.1/123/servers/test_inst/action')
req.method = "POST"
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
resp = req.get_response(fakes.wsgi_app())
self.assertEqual(resp.status_int, 202)
self.assertTrue(self.disassociated)
def test_remove_associated_floating_ip_from_instance(self):
self.disassociated = False
def fake_get_floating_ip_by_ip(ignore, context, ip):
return {'id': 1, 'address': '10.10.10.10',
'fixed_ip': {'id': 1}}
def fake_disassociate(ignore, context, floating_address):
self.disassociated = True
self.stubs.Set(network.api.API, "get_floating_ip_by_ip",
fake_get_floating_ip_by_ip)
self.stubs.Set(network.api.API, "disassociate_floating_ip",
fake_disassociate)
def test_floating_ip_disassociate(self):
body = dict(removeFloatingIp=dict(address='10.10.10.10'))
req = webob.Request.blank('/v1.1/123/servers/test_inst/action')
req.method = "POST"
@@ -345,31 +248,8 @@ class FloatingIpTest(test.TestCase):
resp = req.get_response(fakes.wsgi_app())
self.assertEqual(resp.status_int, 202)
self.assertTrue(self.disassociated)
def test_remove_disassociated_floating_ip_from_instance(self):
self.disassociated = False
def fake_get_floating_ip_by_ip(ignore, context, ip):
return {'id': 1, 'address': '10.10.10.10',
'fixed_ip': None}
def fake_disassociate(ignore, context, floating_address):
self.disassociated = True
self.stubs.Set(network.api.API, "get_floating_ip_by_ip",
fake_get_floating_ip_by_ip)
self.stubs.Set(network.api.API, "disassociate_floating_ip",
fake_disassociate)
body = dict(removeFloatingIp=dict(address='10.10.10.10'))
req = webob.Request.blank('/v1.1/123/servers/test_inst/action')
req.method = "POST"
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
resp = req.get_response(fakes.wsgi_app())
self.assertEqual(resp.status_int, 202)
self.assertFalse(self.disassociated)
# these are a few bad param tests
def test_bad_address_param_in_remove_floating_ip(self):
body = dict(removeFloatingIp=dict(badparam='11.0.0.1'))
@@ -391,16 +271,6 @@ class FloatingIpTest(test.TestCase):
resp = req.get_response(fakes.wsgi_app())
self.assertEqual(resp.status_int, 400)
def test_bad_address_param_in_add_floating_ip(self):
body = dict(addFloatingIp=dict(badparam='11.0.0.1'))
req = webob.Request.blank('/v1.1/123/servers/test_inst/action')
req.method = "POST"
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
resp = req.get_response(fakes.wsgi_app())
self.assertEqual(resp.status_int, 400)
def test_missing_dict_param_in_add_floating_ip(self):
body = dict(addFloatingIp='11.0.0.1')
req = webob.Request.blank('/v1.1/123/servers/test_inst/action')

View File

@@ -20,6 +20,8 @@ from nova import context
from nova import db
from nova import exception
from nova import log as logging
from nova import quota
from nova import rpc
from nova import test
from nova.network import manager as network_manager
from nova.tests import fake_network
@@ -394,22 +396,203 @@ class VlanNetworkTestCase(test.TestCase):
self.mox.ReplayAll()
self.network.validate_networks(self.context, requested_networks)
def test_cant_associate_associated_floating_ip(self):
def test_floating_ip_owned_by_project(self):
ctxt = context.RequestContext('testuser', 'testproject',
is_admin=False)
def fake_floating_ip_get_by_address(context, address):
return {'address': '10.10.10.10',
'fixed_ip': {'address': '10.0.0.1'}}
self.stubs.Set(self.network.db, 'floating_ip_get_by_address',
fake_floating_ip_get_by_address)
# raises because floating_ip project_id is None
floating_ip = {'address': '10.0.0.1',
'project_id': None}
self.assertRaises(exception.NotAuthorized,
self.network._floating_ip_owned_by_project,
ctxt,
floating_ip)
self.assertRaises(exception.FloatingIpAlreadyInUse,
# raises because floating_ip project_id is not equal to ctxt project_id
floating_ip = {'address': '10.0.0.1',
'project_id': ctxt.project_id + '1'}
self.assertRaises(exception.NotAuthorized,
self.network._floating_ip_owned_by_project,
ctxt,
floating_ip)
# does not raise (floating ip is owned by ctxt project)
floating_ip = {'address': '10.0.0.1',
'project_id': ctxt.project_id}
self.network._floating_ip_owned_by_project(ctxt, floating_ip)
def test_allocate_floating_ip(self):
ctxt = context.RequestContext('testuser', 'testproject',
is_admin=False)
def fake1(*args, **kwargs):
return {'address': '10.0.0.1'}
def fake2(*args, **kwargs):
return 25
def fake3(*args, **kwargs):
return 0
self.stubs.Set(self.network.db, 'floating_ip_allocate_address', fake1)
# this time should raise
self.stubs.Set(self.network.db, 'floating_ip_count_by_project', fake2)
self.assertRaises(quota.QuotaError,
self.network.allocate_floating_ip,
ctxt,
ctxt.project_id)
# this time should not
self.stubs.Set(self.network.db, 'floating_ip_count_by_project', fake3)
self.network.allocate_floating_ip(ctxt, ctxt.project_id)
def test_deallocate_floating_ip(self):
ctxt = context.RequestContext('testuser', 'testproject',
is_admin=False)
def fake1(*args, **kwargs):
pass
def fake2(*args, **kwargs):
return {'address': '10.0.0.1', 'fixed_ip_id': 1}
def fake3(*args, **kwargs):
return {'address': '10.0.0.1', 'fixed_ip_id': None}
self.stubs.Set(self.network.db, 'floating_ip_deallocate', fake1)
self.stubs.Set(self.network, '_floating_ip_owned_by_project', fake1)
# this time should raise because floating ip is associated to fixed_ip
self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake2)
self.assertRaises(exception.FloatingIpAssociated,
self.network.deallocate_floating_ip,
ctxt,
mox.IgnoreArg())
# this time should not raise
self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake3)
self.network.deallocate_floating_ip(ctxt, ctxt.project_id)
def test_associate_floating_ip(self):
ctxt = context.RequestContext('testuser', 'testproject',
is_admin=False)
def fake1(*args, **kwargs):
pass
# floating ip that's already associated
def fake2(*args, **kwargs):
return {'address': '10.0.0.1',
'fixed_ip_id': 1}
# floating ip that isn't associated
def fake3(*args, **kwargs):
return {'address': '10.0.0.1',
'fixed_ip_id': None}
# fixed ip with remote host
def fake4(*args, **kwargs):
return {'address': '10.0.0.1',
'network': {'multi_host': False, 'host': 'jibberjabber'}}
# fixed ip with local host
def fake5(*args, **kwargs):
return {'address': '10.0.0.1',
'network': {'multi_host': False, 'host': 'testhost'}}
def fake6(*args, **kwargs):
self.local = False
def fake7(*args, **kwargs):
self.local = True
self.stubs.Set(self.network, '_floating_ip_owned_by_project', fake1)
# raises because floating_ip is already associated to a fixed_ip
self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake2)
self.assertRaises(exception.FloatingIpAssociated,
self.network.associate_floating_ip,
ctxt,
mox.IgnoreArg(),
mox.IgnoreArg())
self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake3)
# does not raise and makes call remotely
self.local = True
self.stubs.Set(self.network.db, 'fixed_ip_get_by_address', fake4)
self.stubs.Set(rpc, 'cast', fake6)
self.network.associate_floating_ip(ctxt, mox.IgnoreArg(),
mox.IgnoreArg())
self.assertFalse(self.local)
# does not raise and makes call locally
self.local = False
self.stubs.Set(self.network.db, 'fixed_ip_get_by_address', fake5)
self.stubs.Set(self.network, '_associate_floating_ip', fake7)
self.network.associate_floating_ip(ctxt, mox.IgnoreArg(),
mox.IgnoreArg())
self.assertTrue(self.local)
def test_disassociate_floating_ip(self):
ctxt = context.RequestContext('testuser', 'testproject',
is_admin=False)
def fake1(*args, **kwargs):
pass
# floating ip that isn't associated
def fake2(*args, **kwargs):
return {'address': '10.0.0.1',
'fixed_ip_id': None}
# floating ip that is associated
def fake3(*args, **kwargs):
return {'address': '10.0.0.1',
'fixed_ip_id': 1}
# fixed ip with remote host
def fake4(*args, **kwargs):
return {'address': '10.0.0.1',
'network': {'multi_host': False, 'host': 'jibberjabber'}}
# fixed ip with local host
def fake5(*args, **kwargs):
return {'address': '10.0.0.1',
'network': {'multi_host': False, 'host': 'testhost'}}
def fake6(*args, **kwargs):
self.local = False
def fake7(*args, **kwargs):
self.local = True
self.stubs.Set(self.network, '_floating_ip_owned_by_project', fake1)
# raises because floating_ip is not associated to a fixed_ip
self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake2)
self.assertRaises(exception.FloatingIpNotAssociated,
self.network.disassociate_floating_ip,
ctxt,
mox.IgnoreArg())
self.stubs.Set(self.network.db, 'floating_ip_get_by_address', fake3)
# does not raise and makes call remotely
self.local = True
self.stubs.Set(self.network.db, 'fixed_ip_get', fake4)
self.stubs.Set(rpc, 'cast', fake6)
self.network.disassociate_floating_ip(ctxt, mox.IgnoreArg())
self.assertFalse(self.local)
# does not raise and makes call locally
self.local = False
self.stubs.Set(self.network.db, 'fixed_ip_get', fake5)
self.stubs.Set(self.network, '_disassociate_floating_ip', fake7)
self.network.disassociate_floating_ip(ctxt, mox.IgnoreArg())
self.assertTrue(self.local)
def test_add_fixed_ip_instance_without_vpn_requested_networks(self):
self.mox.StubOutWithMock(db, 'network_get')
self.mox.StubOutWithMock(db, 'fixed_ip_associate_pool')