Fix errors on master branch

- Adapt plugin code to changes in _update_router_gw_info
- Add portbindings DB class implementation as it has been
  removed from the neutron repository
- Skip new unit tests pertaining unsupported IPv6 use cases

Change-Id: I863e3302feb45b54cda07a39b68d0a3b63634837
This commit is contained in:
Salvatore Orlando 2022-01-28 13:40:33 -08:00 committed by Kobi Samoray
parent 0253265f75
commit ddeea92ab9
15 changed files with 192 additions and 26 deletions

View File

@ -106,6 +106,7 @@ disable=
consider-using-with,
unused-private-member,
arguments-renamed,
redefined-outer-name,
[BASIC]
# Variable names can be 1 to 31 characters long, with lowercase and underscores
@ -136,7 +137,7 @@ additional-builtins=_
[CLASSES]
# List of interface methods to ignore, separated by a comma.
ignore-iface-methods=
#ignore-iface-methods=
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma

View File

@ -54,7 +54,6 @@ requests==2.14.2
sphinx==3.3.0
SQLAlchemy==1.2.0
stestr==1.0.0
stevedore==2.0.1
tenacity==6.0.0
testscenarios==0.4
testtools==2.2.0

View File

@ -27,12 +27,12 @@ from neutron_lib import exceptions
from neutron_lib.plugins import directory
from neutron_lib.plugins import utils as p_utils
from neutron.db import portbindings_db as pbin_db
from neutron.plugins.ml2 import models as pbin_model
from vmware_nsx._i18n import _
from vmware_nsx.common import nsx_constants
from vmware_nsx.common import utils as c_utils
from vmware_nsx.db import nsxv_db
from vmware_nsx.db import portbindings_db as pbin_db
from vmware_nsx.extensions import projectpluginmap

View File

@ -0,0 +1,36 @@
# Copyright 2013 IBM Corp.
# All Rights Reserved.
#
# 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.
# This model class is not used by any vmware NSX plugin but is needed for
# correct operations of the Port Bindings DB Mixin class
from neutron_lib.db import model_base
import sqlalchemy as sa
from sqlalchemy import orm
from neutron.db import models_v2
class PortBindingPort(model_base.BASEV2):
port_id = sa.Column(sa.String(36),
sa.ForeignKey('ports.id', ondelete="CASCADE"),
primary_key=True)
host = sa.Column(sa.String(255), nullable=False)
port = orm.relationship(
models_v2.Port, load_on_pending=True,
backref=orm.backref("portbinding",
lazy='joined', uselist=False,
cascade='delete'))
revises_on_change = ('port', )

View File

@ -0,0 +1,109 @@
# Copyright 2013 IBM Corp.
# All Rights Reserved.
#
# 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.api.definitions import port as port_def
from neutron_lib.api.definitions import portbindings
from neutron_lib.api import validators
from neutron_lib.db import api as db_api
from neutron_lib.db import model_query
from neutron_lib.db import resource_extend
from neutron_lib.plugins import directory
from neutron.db import models_v2
from vmware_nsx.db import portbinding as pmodels
def _port_model_hook(context, original_model, query):
query = query.outerjoin(
pmodels.PortBindingPort,
(original_model.id == pmodels.PortBindingPort.port_id))
return query
def _port_result_filter_hook(query, filters):
values = filters and filters.get(portbindings.HOST_ID, [])
if not values:
return query
query = query.filter(pmodels.PortBindingPort.host.in_(values))
return query
@resource_extend.has_resource_extenders
class PortBindingMixin(object):
def __new__(cls, *args, **kwargs):
model_query.register_hook(
models_v2.Port,
"portbindings_port",
query_hook=_port_model_hook,
filter_hook=None,
result_filters=_port_result_filter_hook)
return super(PortBindingMixin, cls).__new__(cls, *args, **kwargs)
def _process_portbindings_create_and_update(self, context, port_data,
port):
binding_profile = port.get(portbindings.PROFILE)
binding_profile_set = validators.is_attr_set(binding_profile)
if not binding_profile_set and binding_profile is not None:
del port[portbindings.PROFILE]
binding_vnic = port.get(portbindings.VNIC_TYPE)
binding_vnic_set = validators.is_attr_set(binding_vnic)
if not binding_vnic_set and binding_vnic is not None:
del port[portbindings.VNIC_TYPE]
# REVISIT(irenab) Add support for vnic_type for plugins that
# can handle more than one type.
# Currently implemented for ML2 plugin that does not use
# PortBindingMixin.
host = port_data.get(portbindings.HOST_ID)
host_set = validators.is_attr_set(host)
with db_api.CONTEXT_WRITER.using(context):
bind_port = context.session.query(
pmodels.PortBindingPort).filter_by(port_id=port['id']).first()
if host_set:
if not bind_port:
context.session.add(
pmodels.PortBindingPort(port_id=port['id'], host=host))
else:
bind_port.host = host
else:
host = bind_port.host if bind_port else None
self._extend_port_dict_binding_host(port, host)
def get_port_host(self, context, port_id):
with db_api.CONTEXT_READER.using(context):
bind_port = (
context.session.query(pmodels.PortBindingPort.host).
filter_by(port_id=port_id).
first()
)
return bind_port.host if bind_port else None
def _extend_port_dict_binding_host(self, port_res, host):
port_res[portbindings.HOST_ID] = host
def extend_port_dict_binding(self, port_res, port_db):
host = port_db.portbinding.host if port_db.portbinding else None
self._extend_port_dict_binding_host(port_res, host)
@staticmethod
@resource_extend.extends([port_def.COLLECTION_NAME])
def _extend_port_dict_binding(port_res, port_db):
plugin = directory.get_plugin()
if not isinstance(plugin, PortBindingMixin):
return
plugin.extend_port_dict_binding(port_res, port_db)

View File

@ -39,7 +39,6 @@ from neutron.db import l3_db
from neutron.db import l3_gwmode_db
from neutron.db.models import securitygroup as securitygroup_model
from neutron.db import models_v2
from neutron.db import portbindings_db
from neutron.db import portsecurity_db
from neutron.db.quota import driver_nolock # noqa
from neutron.db import securitygroups_db
@ -83,6 +82,7 @@ from vmware_nsx.db import extended_security_group as extended_sec
from vmware_nsx.db import extended_security_group_rule as extend_sg_rule
from vmware_nsx.db import maclearning as mac_db
from vmware_nsx.db import nsx_portbindings_db as pbin_db
from vmware_nsx.db import portbindings_db
from vmware_nsx.extensions import advancedserviceproviders as as_providers
from vmware_nsx.extensions import maclearning as mac_ext
from vmware_nsx.extensions import providersecuritygroup as provider_sg

View File

@ -43,7 +43,6 @@ from neutron.db import external_net_db
from neutron.db import l3_db
from neutron.db.models import securitygroup as securitygroup_model
from neutron.db import models_v2
from neutron.db import portbindings_db
from neutron.db import portsecurity_db
from neutron.db import securitygroups_db
from neutron.db import vlantransparent_db as vlan_ext_db
@ -59,6 +58,7 @@ from vmware_nsx.common import nsx_constants
from vmware_nsx.common import utils as c_utils
from vmware_nsx.db import db as nsx_db
from vmware_nsx.db import nsxv_db
from vmware_nsx.db import portbindings_db
from vmware_nsx.dhcp_meta import modes as dhcpmeta_modes
from vmware_nsx.dvs import dvs
from vmware_nsx.dvs import dvs_utils

View File

@ -2759,7 +2759,7 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
method()
def _update_router_gw_info(self, context, router_id, info,
called_from=None):
request_body, called_from=None):
# Get the original data of the router GW
router = self._get_router(context, router_id)
orig_info = self._get_router_gw_info(context, router_id)
@ -2779,8 +2779,9 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
[sub['network_id'] for sub in router_subnets])
# First update the neutron DB
# We do not need to pass a request body
super(NsxPolicyPlugin, self)._update_router_gw_info(
context, router_id, info, router=router)
context, router_id, info, None, router=router)
router = self._get_router(context, router_id)
# Get the new tier0 of the updated router (or None if GW was removed)
@ -2868,7 +2869,7 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
LOG.error("Rolling back router %s GW info update because "
"of NSX failure %s", router_id, e)
super(NsxPolicyPlugin, self)._update_router_gw_info(
context, router_id, orig_info, router=router)
context, router_id, orig_info, None, router)
def _update_router_advertisement_rules(self, router_id, subnets,
advertise_ipv6):
@ -2934,7 +2935,7 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
if gw_info and gw_info != const.ATTR_NOT_SPECIFIED:
try:
self._update_router_gw_info(context, router['id'], gw_info,
called_from="create")
None, called_from="create")
except (db_exc.DBError, nsx_lib_exc.NsxLibException):
with excutils.save_and_reraise_exception():
LOG.error("Failed to set gateway info for router "
@ -2953,7 +2954,7 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
if gw_info:
try:
self._update_router_gw_info(context, router_id, {},
called_from="delete")
None, called_from="delete")
except nsx_lib_exc.NsxLibException as e:
LOG.error("Failed to remove router %s gw info before "
"deletion, but going on with the deletion anyway: "
@ -3030,8 +3031,8 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
context, router_id, router)
# Update the policy backend
added_routes = removed_routes = False
try:
added_routes = removed_routes = False
# Updating name & description
if 'name' in router_data or 'description' in router_data:
router_name = utils.get_name_and_uuid(

View File

@ -169,8 +169,9 @@ class RouterDistributedDriver(router_driver.RouterBaseDriver):
# verify the edge was deployed before calling super code.
tlr_edge_id = self._get_edge_id_or_raise(context, router_id)
# Pass None request body to function
super(nsx_v.NsxVPluginV2, self.plugin)._update_router_gw_info(
context, router_id, info, router=router)
context, router_id, info, None, router=router)
router = self.plugin._get_router(context, router_id)
new_ext_net_id = router.gw_port_id and router.gw_port.network_id

View File

@ -136,7 +136,7 @@ class RouterExclusiveDriver(router_driver.RouterBaseDriver):
gw_info = {'network_id': external_net_id,
'enable_snat': router_db.enable_snat}
self.plugin._update_router_gw_info(
context, router_id, gw_info, force_update=True)
context, router_id, gw_info, None, force_update=True)
def delete_router(self, context, router_id):
edge_id, az_name = self.plugin._get_edge_id_and_az_by_rtr_id(
@ -179,9 +179,9 @@ class RouterExclusiveDriver(router_driver.RouterBaseDriver):
orgaddr, orgmask, orgnexthop = (
self.plugin._get_external_attachment_info(
context, router))
# We do not need to pass request_body to this function
super(nsx_v.NsxVPluginV2, self.plugin)._update_router_gw_info(
context, router_id, info, router=router)
context, router_id, info, None, router=router)
router = self.plugin._get_router(context, router_id)
new_ext_net_id = router.gw_port_id and router.gw_port.network_id

View File

@ -84,7 +84,8 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
context, router_id, router)
if gw_info != constants.ATTR_NOT_SPECIFIED:
self.plugin._update_router_gw_info(context, router_id, gw_info)
self.plugin._update_router_gw_info(context, router_id,
gw_info, None)
if 'admin_state_up' in r:
# If router was deployed on a different edge then
# admin-state-up is already updated on the new edge.
@ -700,8 +701,9 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
router = self.plugin._get_router(context, router_id)
edge_id = edge_utils.get_router_edge_id(context, router_id)
if not edge_id:
# Pass a None request_body since we do not need it
super(nsx_v.NsxVPluginV2, self.plugin)._update_router_gw_info(
context, router_id, info, router=router)
context, router_id, info, None, router=router)
# UPDATE gw info only if the router has been attached to an edge
else:
is_migrated = False
@ -714,7 +716,7 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
self.plugin._get_external_attachment_info(
context, router))
super(nsx_v.NsxVPluginV2, self.plugin)._update_router_gw_info(
context, router_id, info, router=router)
context, router_id, info, None, router=router)
router = self.plugin._get_router(context, router_id)
new_ext_net_id = (router.gw_port_id and
router.gw_port.network_id)

View File

@ -1349,6 +1349,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# the original exception.
for dvsm, netm in dvs_pg_mappings.items():
self._delete_backend_network(netm, dvsm)
predefined = None
try:
net_data[psec.PORTSECURITY] = net_data.get(psec.PORTSECURITY, True)
if not cfg.CONF.nsxv.spoofguard_enabled:
@ -3506,7 +3507,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
self.metadata_proxy_handler))
if gw_info != constants.ATTR_NOT_SPECIFIED and gw_info:
self._update_router_gw_info(
context, lrouter['id'], gw_info)
context, lrouter['id'], gw_info, None)
except Exception:
LOG.exception("Failed to create router %s", router)
with excutils.save_and_reraise_exception():
@ -3769,7 +3770,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
edge_utils.update_routes(self.nsx_v, context, router_id,
routes, nexthop)
def _update_current_gw_port(self, context, router_id, router, ext_ips):
def _update_current_gw_port(self, context, router_id, router, ext_ips,
_request_body):
"""Override this function in order not to call plugins' update_port
since the actual backend work was already done by the router driver,
and it may cause a deadlock.
@ -3790,7 +3792,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
'updated_port': updated_port
}))
def _update_router_gw_info(self, context, router_id, info,
def _update_router_gw_info(self, context, router_id, info, request_body,
is_routes_update=False,
force_update=False):
with db_api.CONTEXT_WRITER.using(context):

View File

@ -903,8 +903,8 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
vlt))
is_backend_network = True
rollback_network = False
try:
rollback_network = False
with db_api.CONTEXT_WRITER.using(context):
# Create network in Neutron
created_net = super(NsxV3Plugin, self).create_network(context,
@ -2007,7 +2007,7 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
LOG.info("Deleted service router for %s (NSX logical router %s)",
router_id, nsx_router_id)
def _update_router_gw_info(self, context, router_id, info):
def _update_router_gw_info(self, context, router_id, info, _request_body):
router = self._get_router(context, router_id)
org_tier0_uuid = self._get_tier0_uuid_by_router(context, router)
org_enable_snat = router.enable_snat
@ -2028,8 +2028,9 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
# TODO(berlin): For nonat use case, we actually don't need a gw port
# which consumes one external ip. But after looking at the DB logic
# and we need to make a big change so don't touch it at present.
# NOTE: We do not need to pass request_body to the function below
super(NsxV3Plugin, self)._update_router_gw_info(
context, router_id, info, router=router)
context, router_id, info, None, router=router)
router = self._get_router(context, router_id)
new_tier0_uuid = self._get_tier0_uuid_by_router(context, router)
@ -2184,7 +2185,8 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
if gw_info and gw_info != const.ATTR_NOT_SPECIFIED:
try:
self._update_router_gw_info(context, router['id'], gw_info)
self._update_router_gw_info(context, router['id'],
gw_info, None)
except (db_exc.DBError, nsx_lib_exc.ManagerError):
with excutils.save_and_reraise_exception():
LOG.error("Failed to set gateway info for router "
@ -2203,7 +2205,7 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
interface=None)
gw_info = self._get_router_gw_info(context, router_id)
if gw_info:
self._update_router_gw_info(context, router_id, {})
self._update_router_gw_info(context, router_id, {}, None)
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
router_id)
super(NsxV3Plugin, self).delete_router(context, router_id)

View File

@ -43,6 +43,16 @@ class DummyAgentApi(object):
class NsxFwaasCallbacksV2(firewall_l3_agent_v2.L3WithFWaaS):
"""Common NSX RPC callbacks for Firewall As A Service - V2."""
# Mock implementation of the l3 agent extension interface.
# This is needed as the base class extends l3 agent extension
def update_network(self, context, data):
pass
def ha_state_change(self, context, data):
pass
def __init__(self, with_rpc):
# The super code needs a configuration object with the neutron host
# and an agent_mode, which our driver doesn't use.

View File

@ -995,6 +995,9 @@ class TestSubnetsV2(common_v3.NsxV3TestSubnets, NsxV3PluginTestCaseMixin):
def test_create_subnet_ipv6_slaac_with_db_reference_error(self):
self.skipTest('No DHCP v6 Support yet')
def test_update_subnet_the_same_gw_as_in_use_by_router_ipv6(self):
self.skipTest('No SLAAC/DHCPv6 Support yet')
class TestPortsV2(common_v3.NsxV3SubnetMixin,
common_v3.NsxV3TestPorts, NsxV3PluginTestCaseMixin,