RouterPort OVO integration

This patch integrates the RouterPort OVO
in the rest of the neutron code base.

Partially-Implements: blueprint adopt-oslo-versioned-objects-for-db
Change-Id: I833fb9ed3524249f601b73dd282a0176d352da5a
This commit is contained in:
Lujin 2017-07-14 11:26:15 +09:00 committed by Ihar Hrachyshka
parent 71d9aab87e
commit 2ca6b5bce6
7 changed files with 98 additions and 74 deletions

View File

@ -51,6 +51,8 @@ from neutron.db import models_v2
from neutron.db import standardattrdescription_db as st_attr
from neutron.extensions import external_net
from neutron.extensions import l3
from neutron.objects import ports as port_obj
from neutron.objects import router as l3_obj
from neutron.plugins.common import utils as p_utils
from neutron import worker as neutron_worker
@ -369,13 +371,14 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
with context.session.begin(subtransactions=True):
router.gw_port = self._core_plugin._get_port(
context.elevated(), gw_port['id'])
router_port = l3_models.RouterPort(
router_port = l3_obj.RouterPort(
context,
router_id=router.id,
port_id=gw_port['id'],
port_type=DEVICE_OWNER_ROUTER_GW
)
context.session.add(router)
context.session.add(router_port)
router_port.create()
def _validate_gw_info(self, context, gw_port, info, ext_ips):
network_id = info['network_id'] if info else None
@ -853,13 +856,12 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
self._notify_attaching_interface(context, router_db=router,
port=port,
interface_info=interface_info)
with context.session.begin(subtransactions=True):
router_port = l3_models.RouterPort(
port_id=port['id'],
router_id=router.id,
port_type=device_owner
)
context.session.add(router_port)
l3_obj.RouterPort(
context,
port_id=port['id'],
router_id=router.id,
port_type=device_owner
).create()
# Update owner after actual process again in order to
# make sure the records in routerports table and ports
# table are consistent.
@ -915,15 +917,19 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
def _remove_interface_by_port(self, context, router_id,
port_id, subnet_id, owner):
qry = context.session.query(l3_models.RouterPort)
qry = qry.filter_by(
obj = l3_obj.RouterPort.get_object(
context,
port_id=port_id,
router_id=router_id,
port_type=owner
)
try:
port = self._core_plugin.get_port(context, qry.one().port_id)
except (n_exc.PortNotFound, exc.NoResultFound):
if obj:
try:
port = self._core_plugin.get_port(context, obj.port_id)
except n_exc.PortNotFound:
raise l3.RouterInterfaceNotFound(router_id=router_id,
port_id=port_id)
else:
raise l3.RouterInterfaceNotFound(router_id=router_id,
port_id=port_id)
port_subnet_ids = [fixed_ip['subnet_id']
@ -947,13 +953,8 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
subnet = self._core_plugin.get_subnet(context, subnet_id)
try:
rport_qry = context.session.query(models_v2.Port).join(
l3_models.RouterPort)
ports = rport_qry.filter(
l3_models.RouterPort.router_id == router_id,
l3_models.RouterPort.port_type == owner,
models_v2.Port.network_id == subnet['network_id']
)
ports = port_obj.Port.get_ports_by_router(
context, router_id, owner, subnet)
for p in ports:
try:
@ -1074,6 +1075,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
# Otherwise return the first router.
RouterPort = l3_models.RouterPort
gw_port = orm.aliased(models_v2.Port, name="gw_port")
# TODO(lujinluo): Need IPAllocation and Port object
routerport_qry = context.session.query(
RouterPort.router_id, models_v2.IPAllocation.ip_address).join(
models_v2.Port, models_v2.IPAllocation).filter(
@ -1599,14 +1601,12 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
DEVICE_OWNER_HA_REPLICATED_INT]
if not router_ids:
return []
qry = context.session.query(l3_models.RouterPort)
qry = qry.filter(
l3_models.RouterPort.router_id.in_(router_ids),
l3_models.RouterPort.port_type.in_(device_owners)
)
# TODO(lujinluo): Need Port as synthetic field
objs = l3_obj.RouterPort.get_objects(
context, router_id=router_ids, port_type=list(device_owners))
interfaces = [self._core_plugin._make_port_dict(rp.port)
for rp in qry]
interfaces = [self._core_plugin._make_port_dict(rp.db_obj.port)
for rp in objs]
return interfaces
@staticmethod
@ -1794,17 +1794,9 @@ class L3RpcNotifierMixin(object):
context = kwargs['context']
subnetpool_id = kwargs['subnetpool_id']
query = context.session.query(l3_models.RouterPort.router_id)
query = query.join(models_v2.Port)
query = query.join(
models_v2.Subnet,
models_v2.Subnet.network_id == models_v2.Port.network_id)
query = query.filter(
models_v2.Subnet.subnetpool_id == subnetpool_id,
l3_models.RouterPort.port_type.in_(n_const.ROUTER_PORT_OWNERS))
query = query.distinct()
router_ids = l3_obj.RouterPort.get_router_ids_by_subnetpool(
context, subnetpool_id)
router_ids = [r[0] for r in query]
l3plugin = directory.get_plugin(plugin_constants.L3)
if l3plugin:
l3plugin.notify_routers_updated(context, router_ids)

View File

@ -42,6 +42,7 @@ from neutron.extensions import l3
from neutron.ipam import utils as ipam_utils
from neutron.objects import agent as ag_obj
from neutron.objects import l3agent as rb_obj
from neutron.objects import router as l3_obj
from neutron.plugins.common import utils as p_utils
@ -168,14 +169,14 @@ class DVRResourceOperationHandler(object):
def _get_snat_interface_ports_for_router(self, context, router_id):
"""Return all existing snat_router_interface ports."""
qry = context.session.query(l3_models.RouterPort)
qry = qry.filter_by(
objs = l3_obj.RouterPort.get_objects(
context,
router_id=router_id,
port_type=const.DEVICE_OWNER_ROUTER_SNAT
)
port_type=const.DEVICE_OWNER_ROUTER_SNAT)
ports = [self.l3plugin._core_plugin._make_port_dict(rp.port)
for rp in qry]
# TODO(lujinluo): Need Port as synthetic field
ports = [self.l3plugin._core_plugin._make_port_dict(rp.db_obj.port)
for rp in objs]
return ports
def _add_csnat_router_interface_port(
@ -194,13 +195,12 @@ class DVRResourceOperationHandler(object):
msg = _("Unable to create the SNAT Interface Port")
raise n_exc.BadRequest(resource='router', msg=msg)
with context.session.begin(subtransactions=True):
router_port = l3_models.RouterPort(
port_id=snat_port['id'],
router_id=router.id,
port_type=const.DEVICE_OWNER_ROUTER_SNAT
)
context.session.add(router_port)
l3_obj.RouterPort(
context,
port_id=snat_port['id'],
router_id=router.id,
port_type=const.DEVICE_OWNER_ROUTER_SNAT
).create()
if do_pop:
return self.l3plugin._populate_mtu_and_subnets_for_ports(
@ -566,15 +566,16 @@ class _DVRAgentInterfaceMixin(object):
"""Query router interfaces that relate to list of router_ids."""
if not router_ids:
return []
qry = context.session.query(l3_models.RouterPort)
qry = qry.filter(
l3_models.RouterPort.router_id.in_(router_ids),
l3_models.RouterPort.port_type == const.DEVICE_OWNER_ROUTER_SNAT
)
objs = l3_obj.RouterPort.get_objects(
context,
router_id=router_ids,
port_type=const.DEVICE_OWNER_ROUTER_SNAT)
interfaces = collections.defaultdict(list)
for rp in qry:
for rp in objs:
# TODO(lujinluo): Need Port as synthetic field
interfaces[rp.router_id].append(
self._core_plugin._make_port_dict(rp.port))
self._core_plugin._make_port_dict(rp.db_obj.port))
LOG.debug("Return the SNAT ports: %s", interfaces)
return interfaces

View File

@ -44,11 +44,10 @@ from neutron.db.availability_zone import router as router_az_db
from neutron.db import l3_dvr_db
from neutron.db.l3_dvr_db import is_distributed_router
from neutron.db.models import agent as agent_model
from neutron.db.models import l3 as l3_models
from neutron.db.models import l3ha as l3ha_model
from neutron.extensions import l3
from neutron.extensions import l3_ext_ha_mode as l3_ha
from neutron.objects import router as l3_objs
from neutron.objects import router as l3_obj
from neutron.plugins.common import utils as p_utils
@ -268,10 +267,11 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin,
def _create_ha_port_binding(self, context, router_id, port_id):
try:
with context.session.begin():
routerportbinding = l3_models.RouterPort(
port_id=port_id, router_id=router_id,
port_type=constants.DEVICE_OWNER_ROUTER_HA_INTF)
context.session.add(routerportbinding)
l3_obj.RouterPort(
context,
port_id=port_id,
router_id=router_id,
port_type=constants.DEVICE_OWNER_ROUTER_HA_INTF).create()
portbinding = l3ha_model.L3HARouterAgentPortBinding(
port_id=port_id, router_id=router_id)
context.session.add(portbinding)
@ -722,7 +722,7 @@ def is_ha_router_port(context, device_owner, router_id):
if device_owner == constants.DEVICE_OWNER_HA_REPLICATED_INT:
return True
elif device_owner == constants.DEVICE_OWNER_ROUTER_SNAT:
return l3_objs.RouterExtraAttributes.objects_exist(
return l3_obj.RouterExtraAttributes.objects_exist(
context, router_id=router_id, ha=True)
else:
return False

View File

@ -21,6 +21,7 @@ from neutron.common import constants
from neutron.common import utils
from neutron.db import api as db_api
from neutron.db.models import dns as dns_models
from neutron.db.models import l3
from neutron.db.models import securitygroup as sg_models
from neutron.db import models_v2
from neutron.objects import base
@ -410,3 +411,14 @@ class Port(base.NeutronDbObject):
if _target_version < (1, 1):
primitive.pop('data_plane_status', None)
@classmethod
def get_ports_by_router(cls, context, router_id, owner, subnet):
rport_qry = context.session.query(models_v2.Port).join(
l3.RouterPort)
ports = rport_qry.filter(
l3.RouterPort.router_id == router_id,
l3.RouterPort.port_type == owner,
models_v2.Port.network_id == subnet['network_id']
)
return [cls._load_object(context, db_obj) for db_obj in ports.all()]

View File

@ -16,11 +16,13 @@ from oslo_versionedobjects import base as obj_base
from oslo_versionedobjects import fields as obj_fields
from sqlalchemy import func
from neutron.common import constants as n_const
from neutron.common import utils
from neutron.db.models import dvr as dvr_models
from neutron.db.models import l3
from neutron.db.models import l3_attrs
from neutron.db.models import l3agent as rb_model
from neutron.db import models_v2
from neutron.extensions import availability_zone as az_ext
from neutron.objects import base
from neutron.objects import common_types
@ -136,6 +138,19 @@ class RouterPort(base.NeutronDbObject):
'port_type': obj_fields.StringField(nullable=True),
}
@classmethod
def get_router_ids_by_subnetpool(cls, context, subnetpool_id):
query = context.session.query(l3.RouterPort.router_id)
query = query.join(models_v2.Port)
query = query.join(
models_v2.Subnet,
models_v2.Subnet.network_id == models_v2.Port.network_id)
query = query.filter(
models_v2.Subnet.subnetpool_id == subnetpool_id,
l3.RouterPort.port_type.in_(n_const.ROUTER_PORT_OWNERS))
query = query.distinct()
return [r[0] for r in query]
@obj_base.VersionedObjectRegistry.register
class DVRMacAddress(base.NeutronDbObject):

View File

@ -58,6 +58,7 @@ from neutron.db import rbac_db_models
from neutron.db import standard_attr
from neutron.ipam.drivers.neutrondb_ipam import driver as ipam_driver
from neutron.ipam import exceptions as ipam_exc
from neutron.objects import router as l3_obj
from neutron.tests import base
from neutron.tests import tools
from neutron.tests.unit.api import test_extensions
@ -4620,18 +4621,18 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
with db_api.context_manager.writer.using(ctx):
router = l3_models.Router()
ctx.session.add(router)
with db_api.context_manager.writer.using(ctx):
rp = l3_models.RouterPort(router_id=router.id,
port_id=port['port']['id'])
ctx.session.add(rp)
rp = l3_obj.RouterPort(ctx, router_id=router.id,
port_id=port['port']['id'])
rp.create()
data = {'subnet': {'gateway_ip': '10.0.0.99'}}
req = self.new_update_request('subnets', data,
s['id'])
res = req.get_response(self.api)
self.assertEqual(409, res.status_int)
# should work fine if it's not a router port
rp.delete()
with db_api.context_manager.writer.using(ctx):
ctx.session.delete(rp)
ctx.session.delete(router)
res = req.get_response(self.api)
self.assertEqual(res.status_int, 200)

View File

@ -39,13 +39,14 @@ from neutron._i18n import _
from neutron.common import utils
from neutron.db import agents_db
from neutron.db import api as db_api
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.db import provisioning_blocks
from neutron.db import segments_db
from neutron.extensions import availability_zone as az_ext
from neutron.extensions import external_net
from neutron.extensions import multiprovidernet as mpnet
from neutron.objects import base as base_obj
from neutron.objects import router as l3_obj
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2.common import exceptions as ml2_exc
from neutron.plugins.ml2 import config
@ -1496,9 +1497,11 @@ class TestMl2DvrPortsV2(TestMl2PortsV2):
# lie to turn the port into an SNAT interface
with db_api.context_manager.reader.using(self.context):
rp = self.context.session.query(l3_models.RouterPort).filter_by(
port_id=p['port_id']).first()
rp.port_type = constants.DEVICE_OWNER_ROUTER_SNAT
pager = base_obj.Pager(limit=1)
rp = l3_obj.RouterPort.get_objects(
self.context, _pager=pager, port_id=p['port_id'])
rp[0].port_type = constants.DEVICE_OWNER_ROUTER_SNAT
rp[0].update()
# take the port away before csnat gets a chance to delete it
# to simulate a concurrent delete