OVO External Networks

This patch introduces and implements Olso-Versioned Objects for
network extension External Networks.

There were joined performed to order the fetching of external
networks by standard attribute which seems useless because,
in networks/services/auto_allocated/db.py while fetching
external networks it logs error when multiple networks are
returned. Expected default external network there is one, so
ordering does not make much sense.

Co-Authored-By: Manjeet Singh Bhatia <manjeet.s.bhatia@intel.com>
Co-Authored-By: Victor Morales <victor.morales@intel.com>

Change-Id: Iad609f72945b84df7881b43d1fdf9a188e5816bc
Partially-Implements: blueprint adopt-oslo-versioned-objects-for-db
This commit is contained in:
Ankur Gupta 2016-08-09 14:50:07 -05:00 committed by Ihar Hrachyshka
parent 4118ea2e7b
commit 55090400ad
9 changed files with 80 additions and 55 deletions

View File

@ -17,7 +17,6 @@ from neutron_lib.api import validators
from neutron_lib import constants
from neutron_lib import exceptions as n_exc
from neutron_lib.plugins import directory
from sqlalchemy.orm import exc
from sqlalchemy.sql import expression as expr
from neutron._i18n import _
@ -28,12 +27,12 @@ from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.db import _utils as db_utils
from neutron.db import db_base_plugin_v2
from neutron.db.models import external_net as ext_net_models
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.db import rbac_db_models as rbac_db
from neutron.extensions import external_net
from neutron.extensions import rbac as rbac_ext
from neutron.objects import network as net_obj
DEVICE_OWNER_ROUTER_GW = constants.DEVICE_OWNER_ROUTER_GW
@ -79,13 +78,8 @@ class External_net_db_mixin(object):
'_network_result_filter_hook')
def _network_is_external(self, context, net_id):
try:
context.session.query(
ext_net_models.ExternalNetwork).filter_by(
network_id=net_id).one()
return True
except exc.NoResultFound:
return False
return net_obj.ExternalNetwork.objects_exist(
context, network_id=net_id)
def _extend_network_dict_l3(self, network_res, network_db):
# Comparing with None for converting uuid into bool
@ -104,8 +98,8 @@ class External_net_db_mixin(object):
return
if external:
context.session.add(
ext_net_models.ExternalNetwork(network_id=net_data['id']))
net_obj.ExternalNetwork(
context, network_id=net_data['id']).create()
context.session.add(rbac_db.NetworkRBAC(
object_id=net_data['id'], action='access_as_external',
target_tenant='*', tenant_id=net_data['tenant_id']))
@ -138,8 +132,8 @@ class External_net_db_mixin(object):
return
if new_value:
context.session.add(
ext_net_models.ExternalNetwork(network_id=net_id))
net_obj.ExternalNetwork(
context, network_id=net_id).create()
net_data[external_net.EXTERNAL] = True
if allow_all:
context.session.add(rbac_db.NetworkRBAC(
@ -155,9 +149,8 @@ class External_net_db_mixin(object):
if port:
raise external_net.ExternalNetworkInUse(net_id=net_id)
for edb in (context.session.query(ext_net_models.ExternalNetwork).
filter_by(network_id=net_id)):
context.session.delete(edb)
net_obj.ExternalNetwork.delete_objects(
context, network_id=net_id)
for rbdb in (context.session.query(rbac_db.NetworkRBAC).filter_by(
object_id=net_id, action='access_as_external')):
context.session.delete(rbdb)
@ -226,10 +219,8 @@ class External_net_db_mixin(object):
# deleting the wildcard is okay as long as the tenants with
# attached routers have their own entries and the network is
# not the default external network.
is_default = context.session.query(
ext_net_models.ExternalNetwork).filter_by(
network_id=policy['object_id'], is_default=True).count()
if is_default:
if net_obj.ExternalNetwork.objects_exist(
context, network_id=policy['object_id'], is_default=True):
msg = _("Default external networks must be shared to "
"everyone.")
raise rbac_ext.RbacPolicyInUse(object_id=policy['object_id'],

View File

@ -17,6 +17,7 @@ from oslo_versionedobjects import fields as obj_fields
from neutron.db import api as db_api
from neutron.db.models import dns as dns_models
from neutron.db.models import external_net as ext_net_model
from neutron.db.models import segment as segment_model
from neutron.db import models_v2
from neutron.db.port_security import models as ps_models
@ -76,6 +77,23 @@ class NetworkPortSecurity(base_ps._PortSecurity):
fields_need_translation = {'id': 'network_id'}
@obj_base.VersionedObjectRegistry.register
class ExternalNetwork(base.NeutronDbObject):
# Version 1.0: Initial version
VERSION = '1.0'
db_model = ext_net_model.ExternalNetwork
foreign_keys = {'Network': {'network_id': 'id'}}
primary_keys = ['network_id']
fields = {
'network_id': common_types.UUIDField(),
'is_default': obj_fields.BooleanField(default=False),
}
@obj_base.VersionedObjectRegistry.register
class Network(rbac_db.NeutronRbacObject):
# Version 1.0: Initial version

View File

@ -18,7 +18,6 @@ from neutron_lib import constants
from neutron_lib import exceptions as n_exc
from neutron_lib.plugins import directory
from oslo_log import log as logging
from sqlalchemy import sql
from neutron._i18n import _, _LE
from neutron.api.v2 import attributes
@ -30,12 +29,11 @@ from neutron.db import _utils as db_utils
from neutron.db import api as db_api
from neutron.db import common_db_mixin
from neutron.db import db_base_plugin_v2
from neutron.db.models import external_net as ext_net_models
from neutron.db import models_v2
from neutron.db import standard_attr
from neutron.extensions import l3
from neutron.objects import auto_allocate as auto_allocate_obj
from neutron.objects import base as base_obj
from neutron.objects import exceptions as obj_exc
from neutron.objects import network as net_obj
from neutron.plugins.common import utils as p_utils
from neutron.services.auto_allocate import exceptions
@ -58,16 +56,20 @@ def _ensure_external_network_default_value_callback(
is_default = request.get(IS_DEFAULT, False)
if event in (events.BEFORE_CREATE, events.BEFORE_UPDATE) and is_default:
# ensure there is only one default external network at any given time
obj = (context.session.query(ext_net_models.ExternalNetwork).
filter_by(is_default=True)).first()
if obj and network['id'] != obj.network_id:
raise exceptions.DefaultExternalNetworkExists(
net_id=obj.network_id)
pager = base_obj.Pager(limit=1)
objs = net_obj.ExternalNetwork.get_objects(context,
_pager=pager, is_default=True)
if objs:
if objs[0] and network['id'] != objs[0].network_id:
raise exceptions.DefaultExternalNetworkExists(
net_id=objs[0].network_id)
# Reflect the status of the is_default on the create/update request
obj = (context.session.query(ext_net_models.ExternalNetwork).
filter_by(network_id=network['id']))
obj.update({IS_DEFAULT: is_default})
obj = net_obj.ExternalNetwork.get_object(context,
network_id=network['id'])
if obj:
obj.is_default = is_default
obj.update()
class AutoAllocatedTopologyMixin(common_db_mixin.CommonDbMixin):
@ -216,13 +218,9 @@ class AutoAllocatedTopologyMixin(common_db_mixin.CommonDbMixin):
def _get_default_external_network(self, context):
"""Get the default external network for the deployment."""
with context.session.begin(subtransactions=True):
default_external_networks = (context.session.query(
ext_net_models.ExternalNetwork).
filter_by(is_default=sql.true()).
join(models_v2.Network).
join(standard_attr.StandardAttribute).
order_by(standard_attr.StandardAttribute.id).all())
default_external_networks = net_obj.ExternalNetwork.get_objects(
context, is_default=True)
if not default_external_networks:
LOG.error(_LE("Unable to find default external network "

View File

@ -21,7 +21,7 @@ from neutron_lib import context
from oslo_utils import uuidutils
import testscenarios
from neutron.db.models import external_net as ext_net_models
from neutron.objects import network as net_obj
from neutron.scheduler import l3_agent_scheduler
from neutron.services.l3_router import l3_router_plugin
from neutron.tests.common import helpers
@ -570,9 +570,9 @@ class L3DVRSchedulerBaseTest(L3SchedulerBaseTest):
network = self.plugin.create_network(self.adminContext,
{'network': network_dict})
if external:
with self.adminContext.session.begin():
network = ext_net_models.ExternalNetwork(network_id=net_id)
self.adminContext.session.add(network)
network = net_obj.ExternalNetwork(
self.adminContext, network_id=net_id)
network.create()
return network

View File

@ -30,7 +30,6 @@ from neutron.common import utils
from neutron.db import api as db_api
from neutron.db import l3_db
from neutron.db import l3_gwmode_db
from neutron.db.models import external_net as ext_net_models
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.extensions import l3
@ -138,10 +137,10 @@ class TestL3GwModeMixin(testlib_api.SqlTestCase):
project_id=self.tenant_id,
admin_state_up=True,
status=constants.NET_STATUS_ACTIVE)
self.net_ext = ext_net_models.ExternalNetwork(
network_id=self.ext_net_id)
self.net_ext = net_obj.ExternalNetwork(
self.context, network_id=self.ext_net_id)
self.network.create()
self.context.session.add(self.net_ext)
self.net_ext.create()
self.router = l3_models.Router(
id=_uuid(),
name=None,

View File

@ -32,7 +32,6 @@ import testtools
from neutron.common import constants
from neutron.common import utils
from neutron.db import db_base_plugin_v2
from neutron.db.models import external_net as ext_net_model
from neutron.db.models import l3 as l3_model
from neutron.db import standard_attr
from neutron import objects
@ -1278,12 +1277,10 @@ class BaseDbObjectTestCase(_BaseObjectTestCase,
def _create_external_network(self):
test_network = self._create_network()
# TODO(manjeets) replace this with ext_net ovo
# once it is implemented
return obj_db_api.create_object(
self.context,
ext_net_model.ExternalNetwork,
{'network_id': test_network['id']})
ext_net = net_obj.ExternalNetwork(self.context,
network_id=test_network['id'])
ext_net.create()
return ext_net
def _create_test_fip(self):
fake_fip = '172.23.3.0'

View File

@ -181,3 +181,20 @@ class NetworkDNSDomainDbObjectTestcase(obj_test_base.BaseDbObjectTestCase,
super(NetworkDNSDomainDbObjectTestcase, self).setUp()
self.update_obj_fields(
{'network_id': lambda: self._create_network().id})
class ExternalNetworkIfaceObjectTestCase(
obj_test_base.BaseObjectIfaceTestCase):
_test_class = network.ExternalNetwork
class ExternalNetworkDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
testlib_api.SqlTestCase):
_test_class = network.ExternalNetwork
def setUp(self):
super(ExternalNetworkDbObjectTestCase, self).setUp()
self.update_obj_fields(
{'network_id': lambda: self._create_network().id})

View File

@ -34,6 +34,7 @@ object_data = {
'AutoAllocatedTopology': '1.0-74642e58c53bf3610dc224c59f81b242',
'DistributedPortBinding': '1.0-39c0d17b281991dcb66716fee5a8bef2',
'DNSNameServer': '1.0-bf87a85327e2d812d1666ede99d9918b',
'ExternalNetwork': '1.0-53d885e033cb931f9bb3bdd6bbe3f0ce',
'ExtraDhcpOpt': '1.0-632f689cbeb36328995a7aed1d0a78d3',
'FlatAllocation': '1.0-bf666f24f4642b047eeca62311fbcb41',
'Flavor': '1.0-82194de5c9aafce08e8527bb7977f5c6',

View File

@ -25,10 +25,14 @@ from neutron.services.auto_allocate import exceptions
from neutron.tests.unit import testlib_api
class AutoAllocateTestCase(testlib_api.SqlTestCaseLight):
DB_PLUGIN_KLASS = 'neutron.db.db_base_plugin_v2.NeutronDbPluginV2'
class AutoAllocateTestCase(testlib_api.SqlTestCase):
def setUp(self):
super(AutoAllocateTestCase, self).setUp()
self.setup_coreplugin(core_plugin=DB_PLUGIN_KLASS)
self.ctx = context.get_admin_context()
self.mixin = db.AutoAllocatedTopologyMixin()
self.mixin._l3_plugin = mock.Mock()