Move floating ip db access to calling side.
Most of the allocation for floating ips can be done on the calling side, including finding the proper host to send the message to. This saves us from making an rpc call for allocate/deallocate and makes sure that we only need 1 call for associate/disassociate by finding the proper host to send the message to immediately. Getting exceptions to work properly required pulling in the helper that was used by the conductor to regenerate exceptions that are wrapped for rpc. Since this is now a shared class, it was moved to utils. Also a few config options were moved to avoid circular imports. Part of blueprint optimize-nova-network Change-Id: I6ec65b1f3e8d00cab778b10eec620760886567e0
This commit is contained in:
parent
4c8fc34d73
commit
12fa59dbb2
@ -14,14 +14,13 @@
|
||||
|
||||
"""Handles all requests to the conductor service."""
|
||||
|
||||
import functools
|
||||
|
||||
from nova.conductor import manager
|
||||
from nova.conductor import rpcapi
|
||||
from nova import exception as exc
|
||||
from nova.openstack.common import cfg
|
||||
from nova.openstack.common import log as logging
|
||||
from nova.openstack.common.rpc import common as rpc_common
|
||||
from nova import utils
|
||||
|
||||
conductor_opts = [
|
||||
cfg.BoolOpt('use_local',
|
||||
@ -43,25 +42,6 @@ CONF.register_opts(conductor_opts, conductor_group)
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ExceptionHelper(object):
|
||||
"""Class to wrap another and translate the ClientExceptions raised by its
|
||||
function calls to the actual ones"""
|
||||
|
||||
def __init__(self, target):
|
||||
self._target = target
|
||||
|
||||
def __getattr__(self, name):
|
||||
func = getattr(self._target, name)
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except rpc_common.ClientException, e:
|
||||
raise (e._exc_info[1], None, e._exc_info[2])
|
||||
return wrapper
|
||||
|
||||
|
||||
class LocalAPI(object):
|
||||
"""A local version of the conductor API that does database updates
|
||||
locally instead of via RPC"""
|
||||
@ -69,7 +49,7 @@ class LocalAPI(object):
|
||||
def __init__(self):
|
||||
# TODO(danms): This needs to be something more generic for
|
||||
# other/future users of this sort of functionality.
|
||||
self._manager = ExceptionHelper(manager.ConductorManager())
|
||||
self._manager = utils.ExceptionHelper(manager.ConductorManager())
|
||||
|
||||
def wait_until_ready(self, context, *args, **kwargs):
|
||||
# nothing to wait for in the local case.
|
||||
|
@ -22,10 +22,12 @@ import inspect
|
||||
|
||||
from nova.db import base
|
||||
from nova import exception
|
||||
from nova.network import floating_ips
|
||||
from nova.network import model as network_model
|
||||
from nova.network import rpcapi as network_rpcapi
|
||||
from nova.openstack.common import log as logging
|
||||
from nova import policy
|
||||
from nova import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -103,11 +105,14 @@ class API(base.Base):
|
||||
This is a pluggable module - other implementations do networking via
|
||||
other services (such as Quantum).
|
||||
"""
|
||||
|
||||
_sentinel = object()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.network_rpcapi = network_rpcapi.NetworkAPI()
|
||||
helper = utils.ExceptionHelper
|
||||
# NOTE(vish): this local version of floating_manager has to convert
|
||||
# ClientExceptions back since they aren't going over rpc.
|
||||
self.floating_manager = helper(floating_ips.LocalManager())
|
||||
super(API, self).__init__(**kwargs)
|
||||
|
||||
@wrap_check_policy
|
||||
@ -190,19 +195,15 @@ class API(base.Base):
|
||||
@wrap_check_policy
|
||||
def allocate_floating_ip(self, context, pool=None):
|
||||
"""Adds (allocates) a floating ip to a project from a pool."""
|
||||
# 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
|
||||
# at some point.
|
||||
return self.network_rpcapi.allocate_floating_ip(context,
|
||||
context.project_id, pool, False)
|
||||
return self.floating_manager.allocate_floating_ip(context,
|
||||
context.project_id, False, pool)
|
||||
|
||||
@wrap_check_policy
|
||||
def release_floating_ip(self, context, address,
|
||||
affect_auto_assigned=False):
|
||||
"""Removes (deallocates) a floating ip with address from a project."""
|
||||
return self.network_rpcapi.deallocate_floating_ip(context, address,
|
||||
affect_auto_assigned)
|
||||
return self.floating_manager.deallocate_floating_ip(context, address,
|
||||
affect_auto_assigned)
|
||||
|
||||
@wrap_check_policy
|
||||
@refresh_cache
|
||||
@ -211,10 +212,13 @@ class API(base.Base):
|
||||
affect_auto_assigned=False):
|
||||
"""Associates a floating ip with a fixed ip.
|
||||
|
||||
ensures floating ip is allocated to the project in context
|
||||
Ensures floating ip is allocated to the project in context.
|
||||
Does not verify ownership of the fixed ip. Caller is assumed to have
|
||||
checked that the instance is properly owned.
|
||||
|
||||
"""
|
||||
orig_instance_uuid = self.network_rpcapi.associate_floating_ip(context,
|
||||
floating_address, fixed_address, affect_auto_assigned)
|
||||
orig_instance_uuid = self.floating_manager.associate_floating_ip(
|
||||
context, floating_address, fixed_address, affect_auto_assigned)
|
||||
|
||||
if orig_instance_uuid:
|
||||
msg_dict = dict(address=floating_address,
|
||||
@ -232,7 +236,7 @@ class API(base.Base):
|
||||
def disassociate_floating_ip(self, context, instance, address,
|
||||
affect_auto_assigned=False):
|
||||
"""Disassociates a floating ip from fixed ip it is associated with."""
|
||||
self.network_rpcapi.disassociate_floating_ip(context, address,
|
||||
return self.floating_manager.disassociate_floating_ip(context, address,
|
||||
affect_auto_assigned)
|
||||
|
||||
@wrap_check_policy
|
||||
@ -249,6 +253,10 @@ class API(base.Base):
|
||||
with requested_networks which is user supplied).
|
||||
:returns: network info as from get_instance_nw_info() below
|
||||
"""
|
||||
# NOTE(vish): We can't do the floating ip allocation here because
|
||||
# this is called from compute.manager which shouldn't
|
||||
# have db access so we do it on the other side of the
|
||||
# rpc.
|
||||
args = {}
|
||||
args['vpn'] = vpn
|
||||
args['requested_networks'] = requested_networks
|
||||
@ -265,7 +273,10 @@ class API(base.Base):
|
||||
@wrap_check_policy
|
||||
def deallocate_for_instance(self, context, instance):
|
||||
"""Deallocates all network structures related to instance."""
|
||||
|
||||
# NOTE(vish): We can't do the floating ip deallocation here because
|
||||
# this is called from compute.manager which shouldn't
|
||||
# have db access so we do it on the other side of the
|
||||
# rpc.
|
||||
args = {}
|
||||
args['instance_id'] = instance['id']
|
||||
args['project_id'] = instance['project_id']
|
||||
|
@ -18,14 +18,18 @@
|
||||
# under the License.
|
||||
|
||||
from nova import context
|
||||
from nova.db import base
|
||||
from nova import exception
|
||||
from nova.network import rpcapi as network_rpcapi
|
||||
from nova.openstack.common import cfg
|
||||
from nova.openstack.common import excutils
|
||||
from nova.openstack.common import importutils
|
||||
from nova.openstack.common import lockutils
|
||||
from nova.openstack.common import log as logging
|
||||
from nova.openstack.common.notifier import api as notifier
|
||||
from nova.openstack.common.rpc import common as rpc_common
|
||||
from nova import quota
|
||||
from nova import servicegroup
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -38,6 +42,15 @@ floating_opts = [
|
||||
cfg.BoolOpt('auto_assign_floating_ip',
|
||||
default=False,
|
||||
help='Autoassigning floating ip to VM'),
|
||||
cfg.StrOpt('floating_ip_dns_manager',
|
||||
default='nova.network.noop_dns_driver.NoopDNSDriver',
|
||||
help='full class name for the DNS Manager for floating IPs'),
|
||||
cfg.StrOpt('instance_dns_manager',
|
||||
default='nova.network.noop_dns_driver.NoopDNSDriver',
|
||||
help='full class name for the DNS Manager for instance IPs'),
|
||||
cfg.StrOpt('instance_dns_domain',
|
||||
default='',
|
||||
help='full class name for the DNS Zone for instance IPs'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -662,3 +675,17 @@ class FloatingIP(object):
|
||||
|
||||
def _get_project_for_domain(self, context, domain):
|
||||
return self.db.dnsdomain_project(context, domain)
|
||||
|
||||
|
||||
class LocalManager(base.Base, FloatingIP):
|
||||
def __init__(self):
|
||||
super(LocalManager, self).__init__()
|
||||
# NOTE(vish): setting the host to none ensures that the actual
|
||||
# l3driver commands for l3 are done via rpc.
|
||||
self.host = None
|
||||
self.servicegroup_api = servicegroup.API()
|
||||
self.network_rpcapi = network_rpcapi.NetworkAPI()
|
||||
self.floating_dns_manager = importutils.import_object(
|
||||
CONF.floating_ip_dns_manager)
|
||||
self.instance_dns_manager = importutils.import_object(
|
||||
CONF.instance_dns_manager)
|
||||
|
@ -164,15 +164,6 @@ network_opts = [
|
||||
cfg.StrOpt('l3_lib',
|
||||
default='nova.network.l3.LinuxNetL3',
|
||||
help="Indicates underlying L3 management library"),
|
||||
cfg.StrOpt('instance_dns_manager',
|
||||
default='nova.network.noop_dns_driver.NoopDNSDriver',
|
||||
help='full class name for the DNS Manager for instance IPs'),
|
||||
cfg.StrOpt('instance_dns_domain',
|
||||
default='',
|
||||
help='full class name for the DNS Zone for instance IPs'),
|
||||
cfg.StrOpt('floating_ip_dns_manager',
|
||||
default='nova.network.noop_dns_driver.NoopDNSDriver',
|
||||
help='full class name for the DNS Manager for floating IPs'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -27,7 +27,6 @@ from nova import db
|
||||
from nova import exception
|
||||
from nova import network
|
||||
from nova.openstack.common import jsonutils
|
||||
from nova.openstack.common import rpc
|
||||
from nova import test
|
||||
from nova.tests.api.openstack import fakes
|
||||
from nova.tests import fake_network
|
||||
@ -275,12 +274,11 @@ class FloatingIpTest(test.TestCase):
|
||||
self.assertIn(self.floating_ip, ip_list)
|
||||
self.assertNotIn(self.floating_ip_2, ip_list)
|
||||
|
||||
# test floating ip allocate/release(deallocate)
|
||||
def test_floating_ip_allocate_no_free_ips(self):
|
||||
def fake_call(*args, **kwargs):
|
||||
def fake_allocate(*args, **kwargs):
|
||||
raise exception.NoMoreFloatingIps()
|
||||
|
||||
self.stubs.Set(rpc, "call", fake_call)
|
||||
self.stubs.Set(network.api.API, "allocate_floating_ip", fake_allocate)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-floating-ips')
|
||||
self.assertRaises(exception.NoMoreFloatingIps,
|
||||
@ -316,9 +314,12 @@ class FloatingIpTest(test.TestCase):
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/os-floating-ips/1')
|
||||
self.controller.delete(req, 1)
|
||||
|
||||
# test floating ip add/remove -> associate/disassociate
|
||||
|
||||
def test_floating_ip_associate(self):
|
||||
def fake_associate_floating_ip(*args, **kwargs):
|
||||
pass
|
||||
|
||||
self.stubs.Set(network.api.API, "associate_floating_ip",
|
||||
fake_associate_floating_ip)
|
||||
body = dict(addFloatingIp=dict(address=self.floating_ip))
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
|
||||
|
@ -30,8 +30,8 @@ CONF.import_opt('scheduler_driver', 'nova.scheduler.manager')
|
||||
CONF.import_opt('fake_network', 'nova.network.manager')
|
||||
CONF.import_opt('network_size', 'nova.network.manager')
|
||||
CONF.import_opt('num_networks', 'nova.network.manager')
|
||||
CONF.import_opt('floating_ip_dns_manager', 'nova.network.manager')
|
||||
CONF.import_opt('instance_dns_manager', 'nova.network.manager')
|
||||
CONF.import_opt('floating_ip_dns_manager', 'nova.network.floating_ips')
|
||||
CONF.import_opt('instance_dns_manager', 'nova.network.floating_ips')
|
||||
CONF.import_opt('policy_file', 'nova.policy')
|
||||
CONF.import_opt('compute_driver', 'nova.virt.driver')
|
||||
CONF.import_opt('api_paste_config', 'nova.wsgi')
|
||||
|
@ -26,8 +26,8 @@ from nova import context
|
||||
from nova import exception
|
||||
from nova import network
|
||||
from nova.network import api
|
||||
from nova.network import floating_ips
|
||||
from nova.network import rpcapi as network_rpcapi
|
||||
from nova.openstack.common import rpc
|
||||
from nova import policy
|
||||
from nova import test
|
||||
|
||||
@ -90,10 +90,11 @@ class ApiTestCase(test.TestCase):
|
||||
|
||||
new_instance = {'uuid': 'new-uuid'}
|
||||
|
||||
def fake_rpc_call(context, topic, msg, timeout=None):
|
||||
def fake_associate(*args, **kwargs):
|
||||
return orig_instance_uuid
|
||||
|
||||
self.stubs.Set(rpc, 'call', fake_rpc_call)
|
||||
self.stubs.Set(floating_ips.FloatingIP, 'associate_floating_ip',
|
||||
fake_associate)
|
||||
|
||||
def fake_instance_get_by_uuid(context, instance_uuid):
|
||||
return {'uuid': instance_uuid}
|
||||
|
@ -48,6 +48,7 @@ from nova.openstack.common import cfg
|
||||
from nova.openstack.common import excutils
|
||||
from nova.openstack.common import importutils
|
||||
from nova.openstack.common import log as logging
|
||||
from nova.openstack.common.rpc import common as rpc_common
|
||||
from nova.openstack.common import timeutils
|
||||
|
||||
notify_decorator = 'nova.openstack.common.notifier.api.notify_decorator'
|
||||
@ -1321,3 +1322,22 @@ def getcallargs(function, *args, **kwargs):
|
||||
keyed_args[argname] = value
|
||||
|
||||
return keyed_args
|
||||
|
||||
|
||||
class ExceptionHelper(object):
|
||||
"""Class to wrap another and translate the ClientExceptions raised by its
|
||||
function calls to the actual ones"""
|
||||
|
||||
def __init__(self, target):
|
||||
self._target = target
|
||||
|
||||
def __getattr__(self, name):
|
||||
func = getattr(self._target, name)
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except rpc_common.ClientException, e:
|
||||
raise (e._exc_info[1], None, e._exc_info[2])
|
||||
return wrapper
|
||||
|
Loading…
Reference in New Issue
Block a user