NSX|V prevent deleting md proxy neutron objects

It is not allowed to delete metadata network / subnet / port or router.

Change-Id: I7d99c9c1f51ffa076bda63ec3e59aea2a977f2d6
This commit is contained in:
Adit Sarfaty 2017-12-10 11:00:23 +02:00
parent a48f364cff
commit 75bf6bdef0
4 changed files with 62 additions and 2 deletions

View File

@ -412,6 +412,12 @@ def get_nsxv_internal_networks(session, network_purpose):
filter_by(network_purpose=network_purpose).all())
def get_nsxv_internal_network_by_id(session, network_id):
with session.begin(subtransactions=True):
return (session.query(nsxv_models.NsxvInternalNetworks).
filter_by(network_id=network_id).first())
def delete_nsxv_internal_network(session, network_purpose, network_id):
with session.begin(subtransactions=True):
return (session.query(nsxv_models.NsxvInternalNetworks).
@ -453,6 +459,12 @@ def get_nsxv_internal_edges_by_purpose(session, purpose):
filter_by(purpose=purpose).all())
def get_nsxv_internal_edge_by_router(session, router_id):
with session.begin(subtransactions=True):
return (session.query(nsxv_models.NsxvInternalEdges).
filter_by(router_id=router_id).first())
def delete_nsxv_internal_edge(session, ext_ip_address):
with session.begin(subtransactions=True):
return (session.query(nsxv_models.NsxvInternalEdges).

View File

@ -524,7 +524,8 @@ class NsxVMetadataProxyHandler(object):
for port in ports:
self.nsxv_plugin.delete_port(context, port['id'],
l3_port_check=True,
nw_gw_port_check=True)
nw_gw_port_check=True,
allow_delete_internal=True)
nsxv_db.delete_nsxv_internal_edge(
context.session,

View File

@ -1394,6 +1394,13 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
return True
return False
def _validate_internal_network(self, context, network_id):
if nsxv_db.get_nsxv_internal_network_by_id(
context.elevated().session, network_id):
msg = (_("Cannot delete internal network %s or its subnets and "
"ports") % network_id)
raise n_exc.InvalidInput(error_message=msg)
def delete_network(self, context, id):
mappings = nsx_db.get_nsx_network_mappings(context.session, id)
bindings = nsxv_db.get_network_bindings(context.session, id)
@ -1401,6 +1408,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
sg_policy_id = nsxv_db.get_spoofguard_policy_id(
context.session, id)
self._validate_internal_network(context, id)
# Update the DHCP edge for metadata and clean the vnic in DHCP edge
# if there is only no other existing port besides DHCP port
filters = {'network_id': [id]}
@ -2336,10 +2345,15 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
return db_utils.resource_fields(port, fields)
def delete_port(self, context, id, l3_port_check=True,
nw_gw_port_check=True, force_delete_dhcp=False):
nw_gw_port_check=True, force_delete_dhcp=False,
allow_delete_internal=False):
neutron_db_port = self.get_port(context, id)
device_id = neutron_db_port['device_id']
is_compute_port = self._is_compute_port(neutron_db_port)
if not allow_delete_internal:
self._validate_internal_network(
context, neutron_db_port['network_id'])
if is_compute_port and device_id:
# Lock on the device ID to make sure we do not change/delete
# ports of the same device at the same time
@ -2374,6 +2388,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
neutron_db_port['device_owner'] in [constants.DEVICE_OWNER_DHCP]):
msg = (_('Can not delete DHCP port %s') % neutron_db_port['id'])
raise n_exc.BadRequest(resource='port', msg=msg)
# If this port is attached to a device, remove the corresponding vnic
# from all NSXv Security-Groups and the spoofguard policy
port_index = neutron_db_port.get(ext_vnic_idx.VNIC_INDEX)
@ -2431,6 +2446,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# deleting subnet's corresponding dhcp interface rest call and lead to
# overlap response from backend.
network_id = subnet['network_id']
self._validate_internal_network(context, network_id)
with locking.LockManager.get_lock(network_id):
with db_api.context_manager.writer.using(context):
self.base_delete_subnet(context, id)
@ -3204,6 +3221,11 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
if ports:
raise l3_exc.RouterInUse(router_id=router_id)
if nsxv_db.get_nsxv_internal_edge_by_router(
context.elevated().session, router_id):
msg = _("Cannot delete internal router %s") % router_id
raise n_exc.InvalidInput(error_message=msg)
def delete_router(self, context, id):
self._check_router_in_use(context, id)
router_driver = self._find_router_driver(context, id)

View File

@ -17,8 +17,12 @@ import mock
from oslo_config import cfg
from neutron_lib import context
from vmware_nsx.db import nsxv_db
from vmware_nsx.db import nsxv_models
from vmware_nsx.plugins.nsx_v.vshield.common import (
constants as vcns_const)
from vmware_nsx.plugins.nsx_v.vshield import edge_utils
from vmware_nsx.tests.unit.nsx_v import test_plugin
@ -53,6 +57,12 @@ class NsxVPluginWithMdV2TestCase(test_plugin.NsxVPluginV2TestCase):
plugin=plugin, ext_mgr=ext_mgr,
service_plugins=service_plugins)
self.context = context.get_admin_context()
self.internal_net_id = nsxv_db.get_nsxv_internal_network_for_az(
self.context.session,
vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE,
'default')['network_id']
class TestNetworksWithMdV2(test_plugin.TestNetworksV2,
NsxVPluginWithMdV2TestCase):
@ -107,6 +117,11 @@ class TestNetworksWithMdV2(test_plugin.TestNetworksV2,
def test_create_networks_bulk_emulated_plugin_failure(self):
self.skipTest("The test is not suitable for the metadata test case")
def test_cannot_delete_md_net(self):
req = self.new_delete_request('networks', self.internal_net_id)
net_del_res = req.get_response(self.api)
self.assertEqual(net_del_res.status_int, 400)
class TestSubnetsWithMdV2(test_plugin.TestSubnetsV2,
NsxVPluginWithMdV2TestCase):
@ -145,6 +160,16 @@ class TestSubnetsWithMdV2(test_plugin.TestSubnetsV2,
def test_create_subnets_bulk_emulated_plugin_failure(self):
self.skipTest("The test is not suitable for the metadata test case")
def test_cannot_delete_md_subnet(self):
query_params = "network_id=%s" % self.internal_net_id
res = self._list('subnets',
neutron_context=self.context,
query_params=query_params)
internal_sub = res['subnets'][0]['id']
req = self.new_delete_request('subnets', internal_sub)
net_del_res = req.get_response(self.api)
self.assertEqual(net_del_res.status_int, 400)
class TestExclusiveRouterWithMdTestCase(
test_plugin.TestExclusiveRouterTestCase,