Merge "NSXv: Support update dvs list for VLAN provider networks"

This commit is contained in:
Jenkins
2017-02-09 07:26:00 +00:00
committed by Gerrit Code Review
3 changed files with 169 additions and 13 deletions

View File

@@ -523,6 +523,17 @@ def get_network_bindings_by_vlanid(session, vlan_id):
all())
def update_network_binding_phy_uuid(session, network_id, binding_type,
vlan_id, phy_uuid):
with session.begin(subtransactions=True):
bindings = (session.query(nsxv_models.NsxvTzNetworkBinding).filter_by(
vlan_id=vlan_id,
network_id=network_id,
binding_type=binding_type).all())
for binding in bindings:
binding['phy_uuid'] = phy_uuid
#
# Edge Firewall binding methods
#

View File

@@ -1307,11 +1307,75 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
[db_utils.resource_fields(network,
fields) for network in networks])
def _raise_if_updates_provider_attributes(self, original_network, attrs):
"""Raise exception if provider attributes are present.
For the NSX-V we want to allow changing the physical network of
vlan type networks.
"""
if (original_network.get(providernet.NETWORK_TYPE) ==
c_utils.NsxVNetworkTypes.VLAN
and validators.is_attr_set(
attrs.get(providernet.PHYSICAL_NETWORK))
and not validators.is_attr_set(
attrs.get(providernet.NETWORK_TYPE))
and not validators.is_attr_set(
attrs.get(providernet.SEGMENTATION_ID))):
self._validate_physical_network(
attrs[providernet.PHYSICAL_NETWORK])
return
providernet._raise_if_updates_provider_attributes(attrs)
def _update_vlan_network_dvs_ids(self, network, new_physical_network):
"""Update the dvs ids of a vlan provider network
The new values will be added to the current ones.
No support for removing dvs-ids.
Actions done in this function:
- Create a backend network for each new dvs
- Return the relevant information in order to later also update
the spoofguard policy, qos, network object and DB
Returns:
- dvs_list_changed True/False
- dvs_pg_mappings - mapping of the new elements dvs->moref
"""
net_morefs = []
dvs_pg_mappings = {}
current_dvs_ids = set(self._get_dvs_ids(
network[providernet.PHYSICAL_NETWORK]))
new_dvs_ids = set(self._get_dvs_ids(
new_physical_network))
additinal_dvs_ids = new_dvs_ids - current_dvs_ids
if not additinal_dvs_ids:
return False, dvs_pg_mappings
# create all the new ones
for dvs_id in additinal_dvs_ids:
try:
self._convert_to_transport_zones_dict(network)
net_moref = self._create_vlan_network_at_backend(
dvs_id=dvs_id,
net_data=network)
except nsx_exc.NsxPluginException:
with excutils.save_and_reraise_exception():
# Delete VLAN networks on other DVSes if it
# fails to be created on one DVS and reraise
# the original exception.
for net_moref in net_morefs:
self._delete_backend_network(net_moref)
dvs_pg_mappings[dvs_id] = net_moref
return True, dvs_pg_mappings
def update_network(self, context, id, network):
net_attrs = network['network']
original_network = self.get_network(context, id)
providernet._raise_if_updates_provider_attributes(net_attrs)
orig_net = self.get_network(context, id)
self._raise_if_updates_provider_attributes(
orig_net, net_attrs)
if net_attrs.get("admin_state_up") is False:
raise NotImplementedError(_("admin_state_up=False networks "
"are not supported."))
@@ -1322,7 +1386,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# PortSecurity validation checks
# TODO(roeyc): enacapsulate validation in a method
psec_update = (psec.PORTSECURITY in net_attrs and
original_network[psec.PORTSECURITY] !=
orig_net[psec.PORTSECURITY] !=
net_attrs[psec.PORTSECURITY])
if psec_update and not net_attrs[psec.PORTSECURITY]:
LOG.warning(_LW("Disabling port-security on network %s would "
@@ -1330,6 +1394,19 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
"installed in order for security-groups to "
"function properly."))
# Check if the physical network of a vlan provider network was updated
updated_morefs = False
if (net_attrs.get(providernet.PHYSICAL_NETWORK) and
orig_net.get(providernet.NETWORK_TYPE) ==
c_utils.NsxVNetworkTypes.VLAN):
(updated_morefs,
new_dvs_pg_mappings) = self._update_vlan_network_dvs_ids(
orig_net,
net_attrs[providernet.PHYSICAL_NETWORK])
if updated_morefs:
new_dvs = list(new_dvs_pg_mappings.values())
net_morefs.extend(new_dvs)
with context.session.begin(subtransactions=True):
net_res = super(NsxVPluginV2, self).update_network(context, id,
network)
@@ -1339,31 +1416,54 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
context, net_attrs, net_res)
self._process_l3_update(context, net_res, net_attrs)
self._extend_network_dict_provider(context, net_res)
if updated_morefs:
# Save netmoref to dvs id mappings for VLAN network
# type for future access.
all_dvs = net_res.get(providernet.PHYSICAL_NETWORK)
for dvs_id, netmoref in six.iteritems(new_dvs_pg_mappings):
nsx_db.add_neutron_nsx_network_mapping(
session=context.session,
neutron_id=id,
nsx_switch_id=netmoref,
dvs_id=dvs_id)
all_dvs = '%s, %s' % (all_dvs, dvs_id)
net_res[providernet.PHYSICAL_NETWORK] = all_dvs
vlan_id = net_res.get(providernet.SEGMENTATION_ID)
nsxv_db.update_network_binding_phy_uuid(
context.session, id,
net_res.get(providernet.NETWORK_TYPE),
vlan_id, all_dvs)
# Updating SpoofGuard policy if exists, on failure revert to network
# old state
if cfg.CONF.nsxv.spoofguard_enabled and psec_update:
if (cfg.CONF.nsxv.spoofguard_enabled and
(psec_update or updated_morefs)):
policy_id = nsxv_db.get_spoofguard_policy_id(context.session, id)
port_sec = (net_attrs[psec.PORTSECURITY]
if psec.PORTSECURITY in net_attrs
else orig_net.get(psec.PORTSECURITY))
try:
self.nsx_v.vcns.update_spoofguard_policy(
policy_id, net_morefs, id,
net_attrs[psec.PORTSECURITY])
policy_id, net_morefs, id, port_sec)
except Exception:
with excutils.save_and_reraise_exception():
revert_update = db_utils.resource_fields(
original_network, ['shared', psec.PORTSECURITY])
orig_net, ['shared', psec.PORTSECURITY])
self._process_network_port_security_update(
context, revert_update, net_res)
super(NsxVPluginV2, self).update_network(
context, id, {'network': revert_update})
# Handle QOS updates (Value can be None, meaning to delete the
# current policy)
if qos_consts.QOS_POLICY_ID in net_attrs:
# current policy), or moref updates with an existing qos policy
if ((qos_consts.QOS_POLICY_ID in net_attrs) or
(updated_morefs and orig_net.get(qos_consts.QOS_POLICY_ID))):
# update the qos data
qos_policy_id = (net_attrs[qos_consts.QOS_POLICY_ID]
if qos_consts.QOS_POLICY_ID in net_attrs
else orig_net.get(qos_consts.QOS_POLICY_ID))
qos_data = qos_utils.NsxVQosRule(
context=context,
qos_policy_id=net_attrs[qos_consts.QOS_POLICY_ID])
context=context, qos_policy_id=qos_policy_id)
# get the network moref/s from the db
for moref in net_morefs:
@@ -1373,7 +1473,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# attach the policy to the network in neutron DB
qos_com_utils.update_network_policy_binding(
context, id, net_attrs[qos_consts.QOS_POLICY_ID])
context, id, qos_policy_id)
net_res[qos_consts.QOS_POLICY_ID] = (
qos_com_utils.get_network_policy_id(context, id))

View File

@@ -458,6 +458,51 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxVPluginV2TestCase):
# physical network attribute.
self.assertEqual(2, vlan_net_call.call_count)
def test_update_vlan_network_with_multiple_dvs(self):
name = 'multi-dvs-vlan-net'
providernet_args = {pnet.NETWORK_TYPE: 'vlan',
pnet.SEGMENTATION_ID: 100,
pnet.PHYSICAL_NETWORK: 'dvs-1, dvs-2'}
p = directory.get_plugin()
with mock.patch.object(
p, '_create_vlan_network_at_backend',
# Return three netmorefs as side effect
side_effect=[_uuid(), _uuid(), _uuid()]) as vlan_net_call:
with self.network(name=name,
providernet_args=providernet_args,
arg_list=(pnet.NETWORK_TYPE,
pnet.SEGMENTATION_ID,
pnet.PHYSICAL_NETWORK)) as net:
# _create_vlan_network_at_backend is expected to be called
# 2 times since we have 2 DVS IDs in the physical
# network attribute.
self.assertEqual(2, vlan_net_call.call_count)
self.assertEqual('dvs-1, dvs-2',
net['network'][pnet.PHYSICAL_NETWORK])
# Add another dvs
data = {'network': {pnet.PHYSICAL_NETWORK: 'dvs-3'}}
req = self.new_update_request('networks', data,
net['network']['id'])
res = self.deserialize('json', req.get_response(self.api))
self.assertEqual(3, vlan_net_call.call_count)
self.assertEqual('dvs-1, dvs-2, dvs-3',
res['network'][pnet.PHYSICAL_NETWORK])
# make sure it is updates also in the DB
req = self.new_show_request('networks', net['network']['id'])
res = self.deserialize('json', req.get_response(self.api))
self.assertEqual('dvs-1, dvs-2, dvs-3',
res['network'][pnet.PHYSICAL_NETWORK])
# update again - with no real change
data = {'network': {pnet.PHYSICAL_NETWORK: 'dvs-3'}}
req = self.new_update_request('networks', data,
net['network']['id'])
res = self.deserialize('json', req.get_response(self.api))
self.assertEqual(3, vlan_net_call.call_count)
self.assertEqual('dvs-1, dvs-2, dvs-3',
res['network'][pnet.PHYSICAL_NETWORK])
def test_get_dvs_ids_for_multiple_dvs_vlan_network(self):
p = directory.get_plugin()
# If no DVS-ID is provided as part of physical network, return