Merge "RouterPort OVO integration"

This commit is contained in:
Jenkins 2017-07-31 09:39:02 +00:00 committed by Gerrit Code Review
commit 58e5a6c64e
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.db import standardattrdescription_db as st_attr
from neutron.extensions import external_net from neutron.extensions import external_net
from neutron.extensions import l3 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.plugins.common import utils as p_utils
from neutron import worker as neutron_worker from neutron import worker as neutron_worker
@ -369,13 +371,14 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
router.gw_port = self._core_plugin._get_port( router.gw_port = self._core_plugin._get_port(
context.elevated(), gw_port['id']) context.elevated(), gw_port['id'])
router_port = l3_models.RouterPort( router_port = l3_obj.RouterPort(
context,
router_id=router.id, router_id=router.id,
port_id=gw_port['id'], port_id=gw_port['id'],
port_type=DEVICE_OWNER_ROUTER_GW port_type=DEVICE_OWNER_ROUTER_GW
) )
context.session.add(router) context.session.add(router)
context.session.add(router_port) router_port.create()
def _validate_gw_info(self, context, gw_port, info, ext_ips): def _validate_gw_info(self, context, gw_port, info, ext_ips):
network_id = info['network_id'] if info else None 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, self._notify_attaching_interface(context, router_db=router,
port=port, port=port,
interface_info=interface_info) interface_info=interface_info)
with context.session.begin(subtransactions=True): l3_obj.RouterPort(
router_port = l3_models.RouterPort( context,
port_id=port['id'], port_id=port['id'],
router_id=router.id, router_id=router.id,
port_type=device_owner port_type=device_owner
) ).create()
context.session.add(router_port)
# Update owner after actual process again in order to # Update owner after actual process again in order to
# make sure the records in routerports table and ports # make sure the records in routerports table and ports
# table are consistent. # table are consistent.
@ -915,15 +917,19 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
def _remove_interface_by_port(self, context, router_id, def _remove_interface_by_port(self, context, router_id,
port_id, subnet_id, owner): port_id, subnet_id, owner):
qry = context.session.query(l3_models.RouterPort) obj = l3_obj.RouterPort.get_object(
qry = qry.filter_by( context,
port_id=port_id, port_id=port_id,
router_id=router_id, router_id=router_id,
port_type=owner port_type=owner
) )
if obj:
try: try:
port = self._core_plugin.get_port(context, qry.one().port_id) port = self._core_plugin.get_port(context, obj.port_id)
except (n_exc.PortNotFound, exc.NoResultFound): except n_exc.PortNotFound:
raise l3.RouterInterfaceNotFound(router_id=router_id,
port_id=port_id)
else:
raise l3.RouterInterfaceNotFound(router_id=router_id, raise l3.RouterInterfaceNotFound(router_id=router_id,
port_id=port_id) port_id=port_id)
port_subnet_ids = [fixed_ip['subnet_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) subnet = self._core_plugin.get_subnet(context, subnet_id)
try: try:
rport_qry = context.session.query(models_v2.Port).join( ports = port_obj.Port.get_ports_by_router(
l3_models.RouterPort) context, router_id, owner, subnet)
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']
)
for p in ports: for p in ports:
try: try:
@ -1074,6 +1075,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
# Otherwise return the first router. # Otherwise return the first router.
RouterPort = l3_models.RouterPort RouterPort = l3_models.RouterPort
gw_port = orm.aliased(models_v2.Port, name="gw_port") gw_port = orm.aliased(models_v2.Port, name="gw_port")
# TODO(lujinluo): Need IPAllocation and Port object
routerport_qry = context.session.query( routerport_qry = context.session.query(
RouterPort.router_id, models_v2.IPAllocation.ip_address).join( RouterPort.router_id, models_v2.IPAllocation.ip_address).join(
models_v2.Port, models_v2.IPAllocation).filter( models_v2.Port, models_v2.IPAllocation).filter(
@ -1599,14 +1601,12 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
DEVICE_OWNER_HA_REPLICATED_INT] DEVICE_OWNER_HA_REPLICATED_INT]
if not router_ids: if not router_ids:
return [] return []
qry = context.session.query(l3_models.RouterPort) # TODO(lujinluo): Need Port as synthetic field
qry = qry.filter( objs = l3_obj.RouterPort.get_objects(
l3_models.RouterPort.router_id.in_(router_ids), context, router_id=router_ids, port_type=list(device_owners))
l3_models.RouterPort.port_type.in_(device_owners)
)
interfaces = [self._core_plugin._make_port_dict(rp.port) interfaces = [self._core_plugin._make_port_dict(rp.db_obj.port)
for rp in qry] for rp in objs]
return interfaces return interfaces
@staticmethod @staticmethod
@ -1794,17 +1794,9 @@ class L3RpcNotifierMixin(object):
context = kwargs['context'] context = kwargs['context']
subnetpool_id = kwargs['subnetpool_id'] subnetpool_id = kwargs['subnetpool_id']
query = context.session.query(l3_models.RouterPort.router_id) router_ids = l3_obj.RouterPort.get_router_ids_by_subnetpool(
query = query.join(models_v2.Port) context, subnetpool_id)
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 = [r[0] for r in query]
l3plugin = directory.get_plugin(plugin_constants.L3) l3plugin = directory.get_plugin(plugin_constants.L3)
if l3plugin: if l3plugin:
l3plugin.notify_routers_updated(context, router_ids) 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.ipam import utils as ipam_utils
from neutron.objects import agent as ag_obj from neutron.objects import agent as ag_obj
from neutron.objects import l3agent as rb_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 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): def _get_snat_interface_ports_for_router(self, context, router_id):
"""Return all existing snat_router_interface ports.""" """Return all existing snat_router_interface ports."""
qry = context.session.query(l3_models.RouterPort) objs = l3_obj.RouterPort.get_objects(
qry = qry.filter_by( context,
router_id=router_id, 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) # TODO(lujinluo): Need Port as synthetic field
for rp in qry] ports = [self.l3plugin._core_plugin._make_port_dict(rp.db_obj.port)
for rp in objs]
return ports return ports
def _add_csnat_router_interface_port( def _add_csnat_router_interface_port(
@ -194,13 +195,12 @@ class DVRResourceOperationHandler(object):
msg = _("Unable to create the SNAT Interface Port") msg = _("Unable to create the SNAT Interface Port")
raise n_exc.BadRequest(resource='router', msg=msg) raise n_exc.BadRequest(resource='router', msg=msg)
with context.session.begin(subtransactions=True): l3_obj.RouterPort(
router_port = l3_models.RouterPort( context,
port_id=snat_port['id'], port_id=snat_port['id'],
router_id=router.id, router_id=router.id,
port_type=const.DEVICE_OWNER_ROUTER_SNAT port_type=const.DEVICE_OWNER_ROUTER_SNAT
) ).create()
context.session.add(router_port)
if do_pop: if do_pop:
return self.l3plugin._populate_mtu_and_subnets_for_ports( 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.""" """Query router interfaces that relate to list of router_ids."""
if not router_ids: if not router_ids:
return [] return []
qry = context.session.query(l3_models.RouterPort) objs = l3_obj.RouterPort.get_objects(
qry = qry.filter( context,
l3_models.RouterPort.router_id.in_(router_ids), router_id=router_ids,
l3_models.RouterPort.port_type == const.DEVICE_OWNER_ROUTER_SNAT port_type=const.DEVICE_OWNER_ROUTER_SNAT)
)
interfaces = collections.defaultdict(list) interfaces = collections.defaultdict(list)
for rp in qry: for rp in objs:
# TODO(lujinluo): Need Port as synthetic field
interfaces[rp.router_id].append( 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) LOG.debug("Return the SNAT ports: %s", interfaces)
return 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 import l3_dvr_db
from neutron.db.l3_dvr_db import is_distributed_router from neutron.db.l3_dvr_db import is_distributed_router
from neutron.db.models import agent as agent_model 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.db.models import l3ha as l3ha_model
from neutron.extensions import l3 from neutron.extensions import l3
from neutron.extensions import l3_ext_ha_mode as l3_ha 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 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): def _create_ha_port_binding(self, context, router_id, port_id):
try: try:
with context.session.begin(): with context.session.begin():
routerportbinding = l3_models.RouterPort( l3_obj.RouterPort(
port_id=port_id, router_id=router_id, context,
port_type=constants.DEVICE_OWNER_ROUTER_HA_INTF) port_id=port_id,
context.session.add(routerportbinding) router_id=router_id,
port_type=constants.DEVICE_OWNER_ROUTER_HA_INTF).create()
portbinding = l3ha_model.L3HARouterAgentPortBinding( portbinding = l3ha_model.L3HARouterAgentPortBinding(
port_id=port_id, router_id=router_id) port_id=port_id, router_id=router_id)
context.session.add(portbinding) 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: if device_owner == constants.DEVICE_OWNER_HA_REPLICATED_INT:
return True return True
elif device_owner == constants.DEVICE_OWNER_ROUTER_SNAT: 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) context, router_id=router_id, ha=True)
else: else:
return False return False

View File

@ -21,6 +21,7 @@ from neutron.common import constants
from neutron.common import utils from neutron.common import utils
from neutron.db import api as db_api from neutron.db import api as db_api
from neutron.db.models import dns as dns_models 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.models import securitygroup as sg_models
from neutron.db import models_v2 from neutron.db import models_v2
from neutron.objects import base from neutron.objects import base
@ -417,3 +418,14 @@ class Port(base.NeutronDbObject):
if _target_version < (1, 1): if _target_version < (1, 1):
primitive.pop('data_plane_status', None) 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 oslo_versionedobjects import fields as obj_fields
from sqlalchemy import func from sqlalchemy import func
from neutron.common import constants as n_const
from neutron.common import utils from neutron.common import utils
from neutron.db.models import dvr as dvr_models from neutron.db.models import dvr as dvr_models
from neutron.db.models import l3 from neutron.db.models import l3
from neutron.db.models import l3_attrs from neutron.db.models import l3_attrs
from neutron.db.models import l3agent as rb_model 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.extensions import availability_zone as az_ext
from neutron.objects import base from neutron.objects import base
from neutron.objects import common_types from neutron.objects import common_types
@ -136,6 +138,19 @@ class RouterPort(base.NeutronDbObject):
'port_type': obj_fields.StringField(nullable=True), '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 @obj_base.VersionedObjectRegistry.register
class DVRMacAddress(base.NeutronDbObject): 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.db import standard_attr
from neutron.ipam.drivers.neutrondb_ipam import driver as ipam_driver from neutron.ipam.drivers.neutrondb_ipam import driver as ipam_driver
from neutron.ipam import exceptions as ipam_exc 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 base
from neutron.tests import tools from neutron.tests import tools
from neutron.tests.unit.api import test_extensions from neutron.tests.unit.api import test_extensions
@ -4620,18 +4621,18 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
with db_api.context_manager.writer.using(ctx): with db_api.context_manager.writer.using(ctx):
router = l3_models.Router() router = l3_models.Router()
ctx.session.add(router) ctx.session.add(router)
with db_api.context_manager.writer.using(ctx): rp = l3_obj.RouterPort(ctx, router_id=router.id,
rp = l3_models.RouterPort(router_id=router.id,
port_id=port['port']['id']) port_id=port['port']['id'])
ctx.session.add(rp) rp.create()
data = {'subnet': {'gateway_ip': '10.0.0.99'}} data = {'subnet': {'gateway_ip': '10.0.0.99'}}
req = self.new_update_request('subnets', data, req = self.new_update_request('subnets', data,
s['id']) s['id'])
res = req.get_response(self.api) res = req.get_response(self.api)
self.assertEqual(409, res.status_int) self.assertEqual(409, res.status_int)
# should work fine if it's not a router port # should work fine if it's not a router port
rp.delete()
with db_api.context_manager.writer.using(ctx): with db_api.context_manager.writer.using(ctx):
ctx.session.delete(rp)
ctx.session.delete(router) ctx.session.delete(router)
res = req.get_response(self.api) res = req.get_response(self.api)
self.assertEqual(res.status_int, 200) self.assertEqual(res.status_int, 200)

View File

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