Relocate L3 DB Models

As we have started oslo versioned objects implementations. There
would be issue of cyclic import while implementation for objects
which have db models definitions and mixins in same file. This patch
will move routers models as discussed in [1].

For example DNS models and some queries are in same file [2]. for object
implementation I have separate models definitions and mixins where
queries were being done [3].

[1]. https://www.mail-archive.com/openstack-dev@lists.openstack.org/msg88910.html
[2]. https://review.openstack.org/#/c/334695/15/neutron/db/dns_db.py
[3]. https://review.openstack.org/#/c/334695/15/neutron/db/models/dns_models.py

Change-Id: I9b9a44da5d28252be58cea1a920a64e18d8bbf32
Partial-Bug: #1597913
This commit is contained in:
Manjeet Singh Bhatia 2016-07-28 21:05:51 +00:00
parent bf39b0b35d
commit 2b66c6a2ed
21 changed files with 224 additions and 187 deletions

View File

@ -24,7 +24,7 @@ from sqlalchemy import orm
from neutron._i18n import _, _LE
from neutron.common import utils
from neutron.db import db_base_plugin_v2
from neutron.db import l3_db
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.extensions import dns
from neutron.extensions import l3
@ -70,7 +70,7 @@ class FloatingIPDNS(model_base.BASEV2):
# Add a relationship to the FloatingIP model in order to instruct
# SQLAlchemy to eagerly load this association
floatingip = orm.relationship(l3_db.FloatingIP,
floatingip = orm.relationship(l3_models.FloatingIP,
backref=orm.backref("dns",
lazy='joined',
uselist=False,

View File

@ -30,7 +30,7 @@ from neutron.callbacks import exceptions as c_exc
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.db import db_base_plugin_v2
from neutron.db import l3_db
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
@ -231,12 +231,12 @@ class External_net_db_mixin(object):
ports = context.session.query(models_v2.Port.id).filter_by(
device_owner=DEVICE_OWNER_ROUTER_GW,
network_id=policy['object_id'])
router = context.session.query(l3_db.Router).filter(
l3_db.Router.gw_port_id.in_(ports))
router = context.session.query(l3_models.Router).filter(
l3_models.Router.gw_port_id.in_(ports))
rbac = rbac_db.NetworkRBAC
if policy['target_tenant'] != '*':
router = router.filter(
l3_db.Router.tenant_id == policy['target_tenant'])
l3_models.Router.tenant_id == policy['target_tenant'])
# if there is a wildcard entry we can safely proceed without the
# router lookup because they will have access either way
if context.session.query(rbac_db.NetworkRBAC).filter(
@ -261,11 +261,12 @@ class External_net_db_mixin(object):
rbac.action == 'access_as_external',
rbac.target_tenant != '*'))
router = router.filter(
~l3_db.Router.tenant_id.in_(tenants_with_entries))
~l3_models.Router.tenant_id.in_(tenants_with_entries))
if new_tenant:
# if this is an update we also need to ignore any router
# interfaces that belong to the new target.
router = router.filter(l3_db.Router.tenant_id != new_tenant)
router = router.filter(
l3_models.Router.tenant_id != new_tenant)
if router.count():
msg = _("There are routers attached to this network that "
"depend on this policy for access.")

View File

@ -24,6 +24,7 @@ from neutron._i18n import _
from neutron.common import utils
from neutron.db import db_base_plugin_v2
from neutron.db import l3_db
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.extensions import extraroute
from neutron.extensions import l3
@ -46,7 +47,7 @@ class RouterRoute(model_base.BASEV2, models_v2.Route):
ondelete="CASCADE"),
primary_key=True)
router = orm.relationship(l3_db.Router,
router = orm.relationship(l3_models.Router,
backref=orm.backref("route_list",
lazy='joined',
cascade='delete'))

View File

@ -19,32 +19,29 @@ from debtcollector import removals
import netaddr
from neutron_lib.api import validators
from neutron_lib import constants as lib_constants
from neutron_lib.db import model_base
from neutron_lib import exceptions as n_exc
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_utils import uuidutils
import six
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.orm import exc
from neutron._i18n import _, _LI
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
from neutron.api.v2 import attributes
from neutron.callbacks import events
from neutron.callbacks import exceptions
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.common import _deprecate
from neutron.common import constants as n_const
from neutron.common import ipv6_utils
from neutron.common import rpc as n_rpc
from neutron.common import utils
from neutron.db import api as db_api
from neutron.db import common_db_mixin
from neutron.db import l3_agentschedulers_db as l3_agt
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.db import standard_attr
from neutron.db import standardattrdescription_db as st_attr
from neutron.extensions import external_net
from neutron.extensions import l3
@ -55,6 +52,11 @@ from neutron.plugins.common import utils as p_utils
LOG = logging.getLogger(__name__)
_deprecate._moved_global('RouterPort', new_module=l3_models)
_deprecate._moved_global('Router', new_module=l3_models)
_deprecate._moved_global('FloatingIP', new_module=l3_models)
DEVICE_OWNER_HA_REPLICATED_INT = lib_constants.DEVICE_OWNER_HA_REPLICATED_INT
DEVICE_OWNER_ROUTER_INTF = lib_constants.DEVICE_OWNER_ROUTER_INTF
DEVICE_OWNER_ROUTER_GW = lib_constants.DEVICE_OWNER_ROUTER_GW
@ -68,90 +70,6 @@ API_TO_DB_COLUMN_MAP = {'port_id': 'fixed_port_id'}
CORE_ROUTER_ATTRS = ('id', 'name', 'tenant_id', 'admin_state_up', 'status')
class RouterPort(model_base.BASEV2):
router_id = sa.Column(
sa.String(36),
sa.ForeignKey('routers.id', ondelete="CASCADE"),
primary_key=True)
port_id = sa.Column(
sa.String(36),
sa.ForeignKey('ports.id', ondelete="CASCADE"),
primary_key=True,
unique=True)
revises_on_change = ('router', )
# The port_type attribute is redundant as the port table already specifies
# it in DEVICE_OWNER.However, this redundancy enables more efficient
# queries on router ports, and also prevents potential error-prone
# conditions which might originate from users altering the DEVICE_OWNER
# property of router ports.
port_type = sa.Column(sa.String(attributes.DEVICE_OWNER_MAX_LEN))
port = orm.relationship(
models_v2.Port,
backref=orm.backref('routerport', uselist=False, cascade="all,delete"),
lazy='joined')
class Router(standard_attr.HasStandardAttributes, model_base.BASEV2,
model_base.HasId, model_base.HasProject):
"""Represents a v2 neutron router."""
name = sa.Column(sa.String(attributes.NAME_MAX_LEN))
status = sa.Column(sa.String(16))
admin_state_up = sa.Column(sa.Boolean)
gw_port_id = sa.Column(sa.String(36), sa.ForeignKey('ports.id'))
gw_port = orm.relationship(models_v2.Port, lazy='joined')
flavor_id = sa.Column(sa.String(36),
sa.ForeignKey("flavors.id"), nullable=True)
attached_ports = orm.relationship(
RouterPort,
backref='router',
lazy='dynamic')
l3_agents = orm.relationship(
'Agent', lazy='joined', viewonly=True,
secondary=l3_agt.RouterL3AgentBinding.__table__)
api_collections = [l3.ROUTERS]
class FloatingIP(standard_attr.HasStandardAttributes, model_base.BASEV2,
model_base.HasId, model_base.HasProject):
"""Represents a floating IP address.
This IP address may or may not be allocated to a tenant, and may or
may not be associated with an internal port/ip address/router.
"""
floating_ip_address = sa.Column(sa.String(64), nullable=False)
floating_network_id = sa.Column(sa.String(36), nullable=False)
floating_port_id = sa.Column(sa.String(36),
sa.ForeignKey('ports.id', ondelete="CASCADE"),
nullable=False)
# The ORM-level "delete" cascade relationship between port and floating_ip
# is required for causing the in-Python event "after_delete" that needs for
# proper quota management in case when cascade removal of the floating_ip
# happens after removal of the floating_port
port = orm.relationship(models_v2.Port,
backref=orm.backref('floating_ips',
cascade='all,delete-orphan'),
foreign_keys='FloatingIP.floating_port_id')
fixed_port_id = sa.Column(sa.String(36), sa.ForeignKey('ports.id'))
fixed_ip_address = sa.Column(sa.String(64))
router_id = sa.Column(sa.String(36), sa.ForeignKey('routers.id'))
# Additional attribute for keeping track of the router where the floating
# ip was associated in order to be able to ensure consistency even if an
# asynchronous backend is unavailable when the floating IP is disassociated
last_known_router_id = sa.Column(sa.String(36))
status = sa.Column(sa.String(16))
router = orm.relationship(Router, backref='floating_ips')
__table_args__ = (
sa.UniqueConstraint(
floating_network_id, fixed_port_id, fixed_ip_address,
name=('uniq_floatingips0floatingnetworkid'
'0fixedportid0fixedipaddress')),
model_base.BASEV2.__table_args__,)
api_collections = [l3.FLOATINGIPS]
class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
st_attr.StandardAttrDescriptionMixin):
"""Mixin class to add L3/NAT router methods to db_base_plugin_v2."""
@ -193,7 +111,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
def _get_router(self, context, router_id):
try:
router = self._get_by_id(context, Router, router_id)
router = self._get_by_id(context, l3_models.Router, router_id)
except exc.NoResultFound:
raise l3.RouterNotFound(router_id=router_id)
return router
@ -230,6 +148,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
only part of a router's information was populated in sync_routers
due to it being deleted during the sync.
"""
Router = l3_models.Router
router_ids = set(r['id'] for r in routers)
query = (context.session.query(Router.id).
filter(
@ -250,12 +169,13 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
status = router.get('status', n_const.ROUTER_STATUS_ACTIVE)
router.setdefault('id', uuidutils.generate_uuid())
router['tenant_id'] = tenant_id
router_db = Router(id=router['id'],
tenant_id=router['tenant_id'],
name=router['name'],
admin_state_up=router['admin_state_up'],
status=status,
description=router.get('description'))
router_db = l3_models.Router(
id=router['id'],
tenant_id=router['tenant_id'],
name=router['name'],
admin_state_up=router['admin_state_up'],
status=status,
description=router.get('description'))
context.session.add(router_db)
registry.notify(resources.ROUTER, events.PRECOMMIT_CREATE,
self, context=context, router=router,
@ -407,7 +327,7 @@ 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 = RouterPort(
router_port = l3_models.RouterPort(
router_id=router.id,
port_id=gw_port['id'],
port_type=DEVICE_OWNER_ROUTER_GW
@ -593,7 +513,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
sorts=None, limit=None, marker=None,
page_reverse=False):
marker_obj = self._get_marker_obj(context, 'router', limit, marker)
return self._get_collection(context, Router,
return self._get_collection(context, l3_models.Router,
self._make_router_dict,
filters=filters, fields=fields,
sorts=sorts,
@ -603,7 +523,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
@db_api.retry_if_session_inactive()
def get_routers_count(self, context, filters=None):
return self._get_collection_count(context, Router,
return self._get_collection_count(context, l3_models.Router,
filters=filters)
def _check_for_dup_router_subnets(self, context, router,
@ -824,7 +744,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
if new_port:
with mgr:
with context.session.begin(subtransactions=True):
router_port = RouterPort(
router_port = l3_models.RouterPort(
port_id=port['id'],
router_id=router.id,
port_type=device_owner
@ -864,7 +784,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
subnet_id):
subnet = self._core_plugin.get_subnet(context, subnet_id)
subnet_cidr = netaddr.IPNetwork(subnet['cidr'])
fip_qry = context.session.query(FloatingIP)
fip_qry = context.session.query(l3_models.FloatingIP)
try:
kwargs = {'context': context, 'router_id': router_id,
'subnet_id': subnet_id}
@ -884,7 +804,7 @@ 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(RouterPort)
qry = context.session.query(l3_models.RouterPort)
qry = qry.filter_by(
port_id=port_id,
router_id=router_id,
@ -916,10 +836,11 @@ 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(RouterPort)
rport_qry = context.session.query(models_v2.Port).join(
l3_models.RouterPort)
ports = rport_qry.filter(
RouterPort.router_id == router_id,
RouterPort.port_type == owner,
l3_models.RouterPort.router_id == router_id,
l3_models.RouterPort.port_type == owner,
models_v2.Port.network_id == subnet['network_id']
)
@ -985,7 +906,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
def _get_floatingip(self, context, id):
try:
floatingip = self._get_by_id(context, FloatingIP, id)
floatingip = self._get_by_id(context, l3_models.FloatingIP, id)
except exc.NoResultFound:
raise l3.FloatingIPNotFound(floatingip_id=id)
return floatingip
@ -1038,6 +959,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
# Among them, if the router's interface address matches
# with subnet's gateway-ip, return that router.
# Otherwise return the first router.
RouterPort = l3_models.RouterPort
gw_port = orm.aliased(models_v2.Port, name="gw_port")
routerport_qry = context.session.query(
RouterPort.router_id, models_v2.IPAllocation.ip_address).join(
@ -1146,7 +1068,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
# Floating IP association is not changed.
return port_id, internal_ip_address, router_id
fip_qry = context.session.query(FloatingIP)
fip_qry = context.session.query(l3_models.FloatingIP)
try:
fip_qry.filter_by(
fixed_port_id=fip['port_id'],
@ -1261,7 +1183,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
floating_fixed_ip = external_ipv4_ips[0]
floating_ip_address = floating_fixed_ip['ip_address']
floatingip_db = FloatingIP(
floatingip_db = l3_models.FloatingIP(
id=fip_id,
tenant_id=fip['tenant_id'],
status=initial_status,
@ -1326,8 +1248,8 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
@db_api.retry_if_session_inactive()
def update_floatingip_status(self, context, floatingip_id, status):
"""Update operational status for floating IP in neutron DB."""
fip_query = self._model_query(context, FloatingIP).filter(
FloatingIP.id == floatingip_id)
fip_query = self._model_query(context, l3_models.FloatingIP).filter(
l3_models.FloatingIP.id == floatingip_id)
fip_query.update({'status': status}, synchronize_session=False)
def _delete_floatingip(self, context, id):
@ -1364,7 +1286,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
if key in filters:
filters[val] = filters.pop(key)
return self._get_collection(context, FloatingIP,
return self._get_collection(context, l3_models.FloatingIP,
self._make_floatingip_dict,
filters=filters, fields=fields,
sorts=sorts,
@ -1374,7 +1296,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
@db_api.retry_if_session_inactive()
def delete_disassociated_floatingips(self, context, network_id):
query = self._model_query(context, FloatingIP)
query = self._model_query(context, l3_models.FloatingIP)
query = query.filter_by(floating_network_id=network_id,
fixed_port_id=None,
router_id=None)
@ -1383,7 +1305,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
@db_api.retry_if_session_inactive()
def get_floatingips_count(self, context, filters=None):
return self._get_collection_count(context, FloatingIP,
return self._get_collection_count(context, l3_models.FloatingIP,
filters=filters)
def _router_exists(self, context, router_id):
@ -1459,7 +1381,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
router_ids = set()
with context.session.begin(subtransactions=True):
fip_qry = context.session.query(FloatingIP)
fip_qry = context.session.query(l3_models.FloatingIP)
floating_ips = fip_qry.filter_by(fixed_port_id=port_id)
for floating_ip in floating_ips:
router_ids.add(floating_ip['router_id'])
@ -1496,7 +1418,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
if active is not None:
filters['admin_state_up'] = [active]
router_dicts = self._get_collection(
context, Router, self._make_router_dict_with_gw_port,
context, l3_models.Router, self._make_router_dict_with_gw_port,
filters=filters)
if not router_dicts:
return []
@ -1509,7 +1431,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
def _unique_floatingip_iterator(query):
"""Iterates over only one row per floating ip. Ignores others."""
# Group rows by fip id. They must be sorted by same.
q = query.order_by(FloatingIP.id)
q = query.order_by(l3_models.FloatingIP.id)
keyfunc = lambda row: row[0]['id']
group_iterator = itertools.groupby(q, keyfunc)
@ -1535,10 +1457,10 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
if not router_ids:
return []
query = context.session.query(FloatingIP,
query = context.session.query(l3_models.FloatingIP,
models_v2.SubnetPool.address_scope_id)
query = query.join(models_v2.Port,
FloatingIP.fixed_port_id == models_v2.Port.id)
l3_models.FloatingIP.fixed_port_id == models_v2.Port.id)
# Outer join of Subnet can cause each ip to have more than one row.
query = query.outerjoin(models_v2.Subnet,
models_v2.Subnet.network_id == models_v2.Port.network_id)
@ -1547,7 +1469,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id)
# Filter out on router_ids
query = query.filter(FloatingIP.router_id.in_(router_ids))
query = query.filter(l3_models.FloatingIP.router_id.in_(router_ids))
return [self._make_floatingip_dict_with_scope(*row)
for row in self._unique_floatingip_iterator(query)]
@ -1558,10 +1480,10 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
DEVICE_OWNER_HA_REPLICATED_INT]
if not router_ids:
return []
qry = context.session.query(RouterPort)
qry = context.session.query(l3_models.RouterPort)
qry = qry.filter(
RouterPort.router_id.in_(router_ids),
RouterPort.port_type.in_(device_owners)
l3_models.RouterPort.router_id.in_(router_ids),
l3_models.RouterPort.port_type.in_(device_owners)
)
interfaces = [self._core_plugin._make_port_dict(rp.port, None)
@ -1893,14 +1815,14 @@ def _notify_subnetpool_address_scope_update(resource, event,
context = kwargs['context']
subnetpool_id = kwargs['subnetpool_id']
query = context.session.query(RouterPort.router_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,
RouterPort.port_type.in_(n_const.ROUTER_PORT_OWNERS))
l3_models.RouterPort.port_type.in_(n_const.ROUTER_PORT_OWNERS))
query = query.distinct()
router_ids = [r[0] for r in query]
@ -1915,3 +1837,6 @@ def _notify_subnetpool_address_scope_update(resource, event,
)
def subscribe():
pass
_deprecate._MovedGlobals()

View File

@ -34,6 +34,7 @@ from neutron.db import l3_agentschedulers_db as l3_sched_db
from neutron.db import l3_attrs_db
from neutron.db import l3_db
from neutron.db.models import allowed_address_pair as aap_models
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.extensions import l3
from neutron.extensions import portbindings
@ -303,7 +304,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
def _get_floatingip_on_port(self, context, port_id=None):
"""Helper function to retrieve the fip associated with port."""
fip_qry = context.session.query(l3_db.FloatingIP)
fip_qry = context.session.query(l3_models.FloatingIP)
floating_ip = fip_qry.filter_by(fixed_port_id=port_id)
return floating_ip.first()
@ -351,7 +352,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
port['fixed_ips'][-1]['subnet_id'])
with context.session.begin(subtransactions=True):
router_port = l3_db.RouterPort(
router_port = l3_models.RouterPort(
port_id=port['id'],
router_id=router.id,
port_type=device_owner
@ -538,10 +539,10 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
"""Query router interfaces that relate to list of router_ids."""
if not router_ids:
return []
qry = context.session.query(l3_db.RouterPort)
qry = context.session.query(l3_models.RouterPort)
qry = qry.filter(
l3_db.RouterPort.router_id.in_(router_ids),
l3_db.RouterPort.port_type == const.DEVICE_OWNER_ROUTER_SNAT
l3_models.RouterPort.router_id.in_(router_ids),
l3_models.RouterPort.port_type == const.DEVICE_OWNER_ROUTER_SNAT
)
interfaces = collections.defaultdict(list)
for rp in qry:
@ -775,7 +776,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
def _get_snat_interface_ports_for_router(self, context, router_id):
"""Return all existing snat_router_interface ports."""
qry = context.session.query(l3_db.RouterPort)
qry = context.session.query(l3_models.RouterPort)
qry = qry.filter_by(
router_id=router_id,
port_type=const.DEVICE_OWNER_ROUTER_SNAT
@ -802,7 +803,7 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
raise n_exc.BadRequest(resource='router', msg=msg)
with context.session.begin(subtransactions=True):
router_port = l3_db.RouterPort(
router_port = l3_models.RouterPort(
port_id=snat_port['id'],
router_id=router.id,
port_type=const.DEVICE_OWNER_ROUTER_SNAT
@ -1029,8 +1030,8 @@ class L3_NAT_with_dvr_db_mixin(l3_db.L3_NAT_db_mixin,
(port_dict['status'] == const.PORT_STATUS_ACTIVE))
if not port_valid_state:
return
query = context.session.query(l3_db.FloatingIP).filter(
l3_db.FloatingIP.fixed_ip_address == port_addr_pair_ip)
query = context.session.query(l3_models.FloatingIP).filter(
l3_models.FloatingIP.fixed_ip_address == port_addr_pair_ip)
fip = query.first()
return self._core_plugin.get_port(
context, fip.fixed_port_id) if fip else None

View File

@ -20,6 +20,7 @@ from sqlalchemy import sql
from neutron._i18n import _
from neutron.db import db_base_plugin_v2
from neutron.db import l3_db
from neutron.db.models import l3 as l3_models
from neutron.extensions import l3
@ -32,7 +33,7 @@ cfg.CONF.register_opts(OPTS)
EXTERNAL_GW_INFO = l3.EXTERNAL_GW_INFO
# Modify the Router Data Model adding the enable_snat attribute
setattr(l3_db.Router, 'enable_snat',
setattr(l3_models.Router, 'enable_snat',
sa.Column(sa.Boolean, default=True, server_default=sql.true(),
nullable=False))

View File

@ -39,9 +39,9 @@ from neutron.db import api as db_api
from neutron.db.availability_zone import router as router_az_db
from neutron.db import common_db_mixin
from neutron.db import l3_attrs_db
from neutron.db import l3_db
from neutron.db import l3_dvr_db
from neutron.db.l3_dvr_db import is_distributed_router
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.extensions import l3
from neutron.extensions import l3_ext_ha_mode as l3_ha
@ -345,7 +345,7 @@ 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_db.RouterPort(
routerportbinding = l3_models.RouterPort(
port_id=port_id, router_id=router_id,
port_type=constants.DEVICE_OWNER_ROUTER_HA_INTF)
context.session.add(routerportbinding)

View File

@ -22,7 +22,7 @@ from neutron.callbacks import resources
from neutron.db import agents_db
from neutron.db import l3_agentschedulers_db as l3_sch_db
from neutron.db import l3_attrs_db
from neutron.db import l3_db
from neutron.db.models import l3 as l3_models
from neutron.extensions import portbindings
from neutron import manager
from neutron.plugins.common import constants as service_constants
@ -46,11 +46,11 @@ class L3_HA_scheduler_db_mixin(l3_sch_db.AZL3AgentSchedulerDbMixin):
join(l3_attrs_db.RouterExtraAttributes,
binding_model.router_id ==
l3_attrs_db.RouterExtraAttributes.router_id).
join(l3_db.Router).
join(l3_models.Router).
filter(l3_attrs_db.RouterExtraAttributes.ha == sql.true()).
group_by(binding_model.router_id).subquery())
query = (context.session.query(l3_db.Router, sub_query.c.count).
query = (context.session.query(l3_models.Router, sub_query.c.count).
join(sub_query))
return [(self._make_router_dict(router), agent_count)

View File

@ -23,7 +23,7 @@ from neutron.api.rpc.agentnotifiers import metering_rpc_agent_api
from neutron.api.v2 import attributes as attr
from neutron.common import constants
from neutron.db import common_db_mixin as base_db
from neutron.db import l3_db
from neutron.db.models import l3 as l3_models
from neutron.extensions import metering
@ -46,7 +46,7 @@ class MeteringLabel(model_base.BASEV2,
rules = orm.relationship(MeteringLabelRule, backref="label",
cascade="delete", lazy="joined")
routers = orm.relationship(
l3_db.Router,
l3_models.Router,
primaryjoin="MeteringLabel.tenant_id==Router.tenant_id",
foreign_keys='MeteringLabel.tenant_id',
uselist=True)
@ -214,7 +214,7 @@ class MeteringDbMixin(metering.MeteringPluginBase,
if label.shared:
if not all_routers:
all_routers = self._get_collection_query(context,
l3_db.Router)
l3_models.Router)
routers = all_routers
else:
routers = label.routers
@ -238,7 +238,7 @@ class MeteringDbMixin(metering.MeteringPluginBase,
rule['metering_label_id'])
if label.shared:
routers = self._get_collection_query(context, l3_db.Router)
routers = self._get_collection_query(context, l3_models.Router)
else:
routers = label.routers
@ -259,6 +259,6 @@ class MeteringDbMixin(metering.MeteringPluginBase,
labels = labels.filter(MeteringLabel.id == label_id)
elif router_ids:
labels = (labels.join(MeteringLabel.routers).
filter(l3_db.Router.id.in_(router_ids)))
filter(l3_models.Router.id.in_(router_ids)))
return self._process_sync_metering_data(context, labels)

View File

@ -36,7 +36,6 @@ from neutron.db import extraroute_db # noqa
from neutron.db import flavors_db # noqa
from neutron.db import l3_agentschedulers_db # noqa
from neutron.db import l3_attrs_db # noqa
from neutron.db import l3_db # noqa
from neutron.db import l3_dvrscheduler_db # noqa
from neutron.db import l3_gwmode_db # noqa
from neutron.db import l3_hamode_db # noqa

105
neutron/db/models/l3.py Normal file
View File

@ -0,0 +1,105 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron_lib.db import model_base
import sqlalchemy as sa
from sqlalchemy import orm
from neutron.api.v2 import attributes
from neutron.db import l3_agentschedulers_db as l3_agt
from neutron.db import models_v2
from neutron.db import standard_attr
from neutron.extensions import l3
class RouterPort(model_base.BASEV2):
router_id = sa.Column(
sa.String(36),
sa.ForeignKey('routers.id', ondelete="CASCADE"),
primary_key=True)
port_id = sa.Column(
sa.String(36),
sa.ForeignKey('ports.id', ondelete="CASCADE"),
primary_key=True,
unique=True)
revises_on_change = ('router', )
# The port_type attribute is redundant as the port table already specifies
# it in DEVICE_OWNER.However, this redundancy enables more efficient
# queries on router ports, and also prevents potential error-prone
# conditions which might originate from users altering the DEVICE_OWNER
# property of router ports.
port_type = sa.Column(sa.String(attributes.DEVICE_OWNER_MAX_LEN))
port = orm.relationship(
models_v2.Port,
backref=orm.backref('routerport', uselist=False, cascade="all,delete"),
lazy='joined')
class Router(standard_attr.HasStandardAttributes, model_base.BASEV2,
model_base.HasId, model_base.HasProject):
"""Represents a v2 neutron router."""
name = sa.Column(sa.String(attributes.NAME_MAX_LEN))
status = sa.Column(sa.String(16))
admin_state_up = sa.Column(sa.Boolean)
gw_port_id = sa.Column(sa.String(36), sa.ForeignKey('ports.id'))
gw_port = orm.relationship(models_v2.Port, lazy='joined')
flavor_id = sa.Column(sa.String(36),
sa.ForeignKey("flavors.id"), nullable=True)
attached_ports = orm.relationship(
RouterPort,
backref='router',
lazy='dynamic')
l3_agents = orm.relationship(
'Agent', lazy='joined', viewonly=True,
secondary=l3_agt.RouterL3AgentBinding.__table__)
api_collections = [l3.ROUTERS]
class FloatingIP(standard_attr.HasStandardAttributes, model_base.BASEV2,
model_base.HasId, model_base.HasProject):
"""Represents a floating IP address.
This IP address may or may not be allocated to a tenant, and may or
may not be associated with an internal port/ip address/router.
"""
floating_ip_address = sa.Column(sa.String(64), nullable=False)
floating_network_id = sa.Column(sa.String(36), nullable=False)
floating_port_id = sa.Column(sa.String(36),
sa.ForeignKey('ports.id', ondelete="CASCADE"),
nullable=False)
# The ORM-level "delete" cascade relationship between port and floating_ip
# is required for causing the in-Python event "after_delete" that needs for
# proper quota management in case when cascade removal of the floating_ip
# happens after removal of the floating_port
port = orm.relationship(models_v2.Port,
backref=orm.backref('floating_ips',
cascade='all,delete-orphan'),
foreign_keys='FloatingIP.floating_port_id')
fixed_port_id = sa.Column(sa.String(36), sa.ForeignKey('ports.id'))
fixed_ip_address = sa.Column(sa.String(64))
router_id = sa.Column(sa.String(36), sa.ForeignKey('routers.id'))
# Additional attribute for keeping track of the router where the floating
# ip was associated in order to be able to ensure consistency even if an
# asynchronous backend is unavailable when the floating IP is disassociated
last_known_router_id = sa.Column(sa.String(36))
status = sa.Column(sa.String(16))
router = orm.relationship(Router, backref='floating_ips')
__table_args__ = (
sa.UniqueConstraint(
floating_network_id, fixed_port_id, fixed_ip_address,
name=('uniq_floatingips0floatingnetworkid'
'0fixedportid0fixedipaddress')),
model_base.BASEV2.__table_args__,)
api_collections = [l3.FLOATINGIPS]

View File

@ -31,8 +31,8 @@ from neutron.common import constants
from neutron.common import utils
from neutron.db import api as db_api
from neutron.db import l3_agentschedulers_db
from neutron.db import l3_db
from neutron.db import l3_hamode_db
from neutron.db.models import l3 as l3_models
from neutron.extensions import availability_zone as az_ext
from neutron.extensions import l3
@ -85,10 +85,11 @@ class L3Scheduler(object):
"""Get routers with no agent binding."""
# TODO(gongysh) consider the disabled agent's router
no_agent_binding = ~sql.exists().where(
l3_db.Router.id ==
l3_models.Router.id ==
l3_agentschedulers_db.RouterL3AgentBinding.router_id)
query = context.session.query(l3_db.Router.id).filter(no_agent_binding)
query = query.filter(l3_db.Router.status ==
query = context.session.query(
l3_models.Router.id).filter(no_agent_binding)
query = query.filter(l3_models.Router.status ==
constants.ROUTER_STATUS_ACTIVE)
unscheduled_router_ids = [router_id_[0] for router_id_ in query]
if unscheduled_router_ids:

View File

@ -25,12 +25,12 @@ from neutron.common import topics
from neutron.db import common_db_mixin
from neutron.db import dns_db
from neutron.db import extraroute_db
from neutron.db import l3_db
from neutron.db import l3_dvr_ha_scheduler_db
from neutron.db import l3_dvrscheduler_db
from neutron.db import l3_gwmode_db
from neutron.db import l3_hamode_db
from neutron.db import l3_hascheduler_db
from neutron.db.models import l3 as l3_models
from neutron.extensions import l3
from neutron.plugins.common import constants
from neutron.quota import resource_registry
@ -64,8 +64,8 @@ class L3RouterPlugin(service_base.ServicePluginBase,
__native_pagination_support = True
__native_sorting_support = True
@resource_registry.tracked_resources(router=l3_db.Router,
floatingip=l3_db.FloatingIP)
@resource_registry.tracked_resources(router=l3_models.Router,
floatingip=l3_models.FloatingIP)
def __init__(self):
self.router_scheduler = importutils.import_object(
cfg.CONF.router_scheduler_driver)

View File

@ -50,7 +50,7 @@ from neutron import context
from neutron.db import api as db_api
from neutron.db import db_base_plugin_common
from neutron.db import ipam_backend_mixin
from neutron.db import l3_db
from neutron.db.models import l3 as l3_models
from neutron.db.models import securitygroup as sg_models
from neutron.db import models_v2
from neutron.db import standard_attr
@ -4457,11 +4457,11 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
# to make this port belong to a router
ctx = context.get_admin_context()
with ctx.session.begin():
router = l3_db.Router()
router = l3_models.Router()
ctx.session.add(router)
with ctx.session.begin():
rp = l3_db.RouterPort(router_id=router.id,
port_id=port['port']['id'])
rp = l3_models.RouterPort(router_id=router.id,
port_id=port['port']['id'])
ctx.session.add(rp)
data = {'subnet': {'gateway_ip': '10.0.0.99'}}
req = self.new_update_request('subnets', data,
@ -6046,15 +6046,15 @@ class DbModelMixin(object):
def _make_floating_ip(self, ctx, port_id):
with ctx.session.begin():
flip = l3_db.FloatingIP(floating_ip_address='1.2.3.4',
floating_network_id='somenet',
floating_port_id=port_id)
flip = l3_models.FloatingIP(floating_ip_address='1.2.3.4',
floating_network_id='somenet',
floating_port_id=port_id)
ctx.session.add(flip)
return flip
def _make_router(self, ctx):
with ctx.session.begin():
router = l3_db.Router()
router = l3_models.Router()
ctx.session.add(router)
return router
@ -6104,7 +6104,7 @@ class DbModelMixin(object):
ctx = context.get_admin_context()
router = self._make_router(ctx)
self._test_staledata_error_on_concurrent_object_update(
l3_db.Router, router['id'])
l3_models.Router, router['id'])
def test_staledata_error_on_concurrent_object_update_floatingip(self):
ctx = context.get_admin_context()
@ -6112,7 +6112,7 @@ class DbModelMixin(object):
port = self._make_port(ctx, network.id)
flip = self._make_floating_ip(ctx, port.id)
self._test_staledata_error_on_concurrent_object_update(
l3_db.FloatingIP, flip['id'])
l3_models.FloatingIP, flip['id'])
def test_staledata_error_on_concurrent_object_update_sg(self):
ctx = context.get_admin_context()

View File

@ -22,6 +22,7 @@ from neutron.callbacks import events
from neutron.callbacks import registry
from neutron.callbacks import resources
from neutron.db import l3_db
from neutron.db.models import l3 as l3_models
from neutron.extensions import l3
from neutron import manager
from neutron.tests import base
@ -141,7 +142,7 @@ class TestL3_NAT_dbonly_mixin(base.BaseTestCase):
query.reset_mock()
result = list(
l3_db.L3_NAT_dbonly_mixin._unique_floatingip_iterator(query))
query.order_by.assert_called_once_with(l3_db.FloatingIP.id)
query.order_by.assert_called_once_with(l3_models.FloatingIP.id)
self.assertEqual([({'id': 'id1'}, 'scope1'),
({'id': 'id2'}, 'scope2'),
({'id': 'id3'}, 'scope3')], result)
@ -212,7 +213,7 @@ class TestL3_NAT_dbonly_mixin(base.BaseTestCase):
def test__check_and_get_fip_assoc_with_extra_association_no_change(self):
fip = {'extra_key': 'value'}
context = mock.MagicMock()
floatingip_db = l3_db.FloatingIP(
floatingip_db = l3_models.FloatingIP(
id='fake_fip_id',
floating_network_id='fake_floating_network_id',
floating_ip_address='8.8.8.8',
@ -234,7 +235,7 @@ class L3_NAT_db_mixin(base.BaseTestCase):
self.db = l3_db.L3_NAT_db_mixin()
def _test_create_router(self, external_gateway_info=None):
router_db = l3_db.Router(id='123')
router_db = l3_models.Router(id='123')
router_dict = {'id': '123', 'tenant_id': '456',
'external_gateway_info': external_gateway_info}
# Need to use a copy here as the create_router method pops the gateway

View File

@ -25,7 +25,7 @@ from neutron.api.v2 import attributes as attr
from neutron import context
from neutron.db import api as dbapi
from neutron.db import flavors_db
from neutron.db import l3_db
from neutron.db.models import l3 as l3_models
from neutron.db import servicetype_db
from neutron.extensions import flavors
from neutron.plugins.common import constants
@ -669,7 +669,7 @@ class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase,
# make use of router since it has a flavor id
fl, data = self._create_flavor()
with self.ctx.session.begin():
self.ctx.session.add(l3_db.Router(flavor_id=fl['id']))
self.ctx.session.add(l3_models.Router(flavor_id=fl['id']))
self.assertRaises(
flavors.FlavorInUse,
self.plugin.delete_flavor,

View File

@ -44,6 +44,7 @@ from neutron.db import l3_attrs_db
from neutron.db import l3_db
from neutron.db import l3_dvr_db
from neutron.db import l3_dvrscheduler_db
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.extensions import external_net
from neutron.extensions import l3
@ -2807,18 +2808,18 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
internal_subnet, external_network_id):
gw_port = orm.aliased(models_v2.Port, name="gw_port")
routerport_qry = context.session.query(
l3_db.RouterPort.router_id,
l3_models.RouterPort.router_id,
models_v2.IPAllocation.ip_address
).join(
models_v2.Port, models_v2.IPAllocation
).filter(
models_v2.Port.network_id == internal_port['network_id'],
l3_db.RouterPort.port_type.in_(
l3_models.RouterPort.port_type.in_(
lib_constants.ROUTER_INTERFACE_OWNERS
),
models_v2.IPAllocation.subnet_id == internal_subnet['id']
).join(
gw_port, gw_port.device_id == l3_db.RouterPort.router_id
gw_port, gw_port.device_id == l3_models.RouterPort.router_id
).filter(
gw_port.network_id == external_network_id,
).distinct()

View File

@ -28,6 +28,7 @@ from neutron.db import api as db_api
from neutron.db import external_net_db
from neutron.db import l3_db
from neutron.db import l3_gwmode_db
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.extensions import l3
from neutron.extensions import l3_ext_gw_mode
@ -138,7 +139,7 @@ class TestL3GwModeMixin(testlib_api.SqlTestCase):
# foreign key violations
self.context.session.flush()
self.context.session.add(self.net_ext)
self.router = l3_db.Router(
self.router = l3_models.Router(
id=_uuid(),
name=None,
tenant_id=self.tenant_id,
@ -217,7 +218,7 @@ class TestL3GwModeMixin(testlib_api.SqlTestCase):
network_id=self.int_net.id,
subnet_id=self.int_sub_id,
ip_address='3.3.3.3')
self.fip = l3_db.FloatingIP(
self.fip = l3_models.FloatingIP(
id=_uuid(),
floating_ip_address='1.1.1.2',
floating_network_id=self.ext_net_id,

View File

@ -19,8 +19,8 @@ from neutron.common import constants as n_const
from neutron.common import utils
from neutron import context
from neutron.db import l3_attrs_db
from neutron.db import l3_db
from neutron.db import l3_hamode_db
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.extensions import portbindings
from neutron.plugins.ml2.drivers.l2pop import db as l2pop_db
@ -51,7 +51,7 @@ class TestL2PopulationDBTestCase(testlib_api.SqlTestCase):
def _create_router(self, distributed=True, ha=False):
with self.ctx.session.begin(subtransactions=True):
self.ctx.session.add(l3_db.Router(id=TEST_ROUTER_ID))
self.ctx.session.add(l3_models.Router(id=TEST_ROUTER_ID))
self.ctx.session.add(l3_attrs_db.RouterExtraAttributes(
router_id=TEST_ROUTER_ID, distributed=distributed, ha=ha))

View File

@ -22,7 +22,7 @@ from sqlalchemy.orm import query
from neutron import context
from neutron.db import db_base_plugin_v2
from neutron.db import l3_db
from neutron.db.models import l3 as l3_models
from neutron.db import models_v2
from neutron.db import segments_db
from neutron.extensions import portbindings
@ -293,7 +293,7 @@ class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
def _setup_neutron_router(self):
with self.ctx.session.begin(subtransactions=True):
router = l3_db.Router()
router = l3_models.Router()
self.ctx.session.add(router)
return router

View File

@ -38,7 +38,7 @@ from neutron import context
from neutron.db import agents_db
from neutron.db import api as db_api
from neutron.db import db_base_plugin_v2 as base_plugin
from neutron.db import l3_db
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
@ -1404,7 +1404,7 @@ class TestMl2DvrPortsV2(TestMl2PortsV2):
# lie to turn the port into an SNAT interface
with self.context.session.begin():
rp = self.context.session.query(l3_db.RouterPort).filter_by(
rp = self.context.session.query(l3_models.RouterPort).filter_by(
port_id=p['port_id']).first()
rp.port_type = constants.DEVICE_OWNER_ROUTER_SNAT