Multi-DVS Support When Hypervisor is vCenter

This patch supports creation and deletion of portgroups
on multiple distributed switches on vCenter. If user
doesn't provide --provider-physical-network argument, then
portgroup is created on configured DVS in nsx.ini else if
the --provider-physical-network argument is provided with
dvs name in vcenter then portgroup is created on that
distributed virtual switch(DVS).

Change-Id: I0636745835a6f4b0e5fae6e01b6ee754e1d9176d
Closes-Bug: #1714428
This commit is contained in:
PriyankaJ 2018-09-07 01:24:07 -07:00 committed by Adit Sarfaty
parent 1c3873c6fd
commit d07d4f0d12
3 changed files with 76 additions and 37 deletions

View File

@ -38,40 +38,28 @@ class SingleDvsManager(object):
the operations supported by the manager.
"""
def __init__(self):
self._dvs = DvsManager()
self.dvs = DvsManager()
self._dvs_moref = self._get_dvs_moref_by_name(
self._dvs.get_vc_session(),
self.dvs.get_vc_session(),
dvs_utils.dvs_name_get())
def _get_dvs_moref_by_name(self, session, dvs_name):
"""Get the moref of the configured DVS."""
results = session.invoke_api(vim_util,
'get_objects',
session.vim,
'DistributedVirtualSwitch',
100)
while results:
for dvs in results.objects:
for prop in dvs.propSet:
if dvs_name == prop.val:
vim_util.cancel_retrieval(session.vim, results)
return dvs.obj
results = vim_util.continue_retrieval(session.vim, results)
raise nsx_exc.DvsNotFound(dvs=dvs_name)
return self.dvs.get_dvs_moref_by_name(dvs_name, session)
def add_port_group(self, net_id, vlan_tag=None, trunk_mode=False):
return self._dvs.add_port_group(self._dvs_moref, net_id,
vlan_tag=vlan_tag,
trunk_mode=trunk_mode)
return self.dvs.add_port_group(self._dvs_moref, net_id,
vlan_tag=vlan_tag,
trunk_mode=trunk_mode)
def delete_port_group(self, net_id):
return self._dvs.delete_port_group(self._dvs_moref, net_id)
return self.dvs.delete_port_group(self._dvs_moref, net_id)
def get_port_group_info(self, net_id):
return self._dvs.get_port_group_info(self._dvs_moref, net_id)
return self.dvs.get_port_group_info(self._dvs_moref, net_id)
def net_id_to_moref(self, net_id):
return self._dvs._net_id_to_moref(self._dvs_moref, net_id)
return self.dvs._net_id_to_moref(self._dvs_moref, net_id)
class VCManagerBase(object):
@ -95,6 +83,24 @@ class DvsManager(VCManagerBase):
The dvs-id is not a class member, since multiple dvs-es can be supported.
"""
def get_dvs_moref_by_name(self, dvs_name, session=None):
"""Get the moref of DVS."""
if not session:
session = self.get_vc_session()
results = session.invoke_api(vim_util,
'get_objects',
session.vim,
'DistributedVirtualSwitch',
100)
while results:
for dvs in results.objects:
for prop in dvs.propSet:
if dvs_name == prop.val:
vim_util.cancel_retrieval(session.vim, results)
return dvs.obj
results = vim_util.continue_retrieval(session.vim, results)
raise nsx_exc.DvsNotFound(dvs=dvs_name)
def _get_dvs_moref_by_id(self, dvs_id):
return vim_util.get_moref(dvs_id, 'VmwareDistributedVirtualSwitch')

View File

@ -176,6 +176,18 @@ class NsxDvsV2(addr_pair_db.AllowedAddressPairsMixin,
# maximum prefix for name is 43
return '%s-%s' % (net_data['name'][:43], net_data['id'])
def _add_port_group(self, dvs_id, net_data, vlan_tag, trunk_mode):
if validators.is_attr_set(net_data.get(pnet.PHYSICAL_NETWORK)):
dvs_name = net_data.get(pnet.PHYSICAL_NETWORK)
dvs_moref = self._dvs.dvs.get_dvs_moref_by_name(dvs_name)
self._dvs.dvs.add_port_group(dvs_moref, dvs_id, vlan_tag,
trunk_mode=trunk_mode)
else:
dvs_name = dvs_utils.dvs_name_get()
self._dvs.add_port_group(dvs_id, vlan_tag,
trunk_mode=trunk_mode)
return dvs_name
def _dvs_create_network(self, context, network):
net_data = network['network']
if net_data['admin_state_up'] is False:
@ -192,7 +204,7 @@ class NsxDvsV2(addr_pair_db.AllowedAddressPairsMixin,
if net_data.get(vlan_apidef.VLANTRANSPARENT) is True:
trunk_mode = True
net_id = None
net_id = dvs_name = None
if net_data.get(pnet.NETWORK_TYPE) == c_utils.NetworkTypes.PORTGROUP:
net_id = net_data.get(pnet.PHYSICAL_NETWORK)
pg_info = self._dvs.get_port_group_info(net_id)
@ -206,8 +218,8 @@ class NsxDvsV2(addr_pair_db.AllowedAddressPairsMixin,
else:
dvs_id = self._dvs_get_id(net_data)
try:
self._dvs.add_port_group(dvs_id, vlan_tag,
trunk_mode=trunk_mode)
dvs_name = self._add_port_group(dvs_id, net_data, vlan_tag,
trunk_mode=trunk_mode)
except dvs_utils.DvsOperationBulkFault:
LOG.warning('One or more hosts may not be configured')
@ -230,17 +242,17 @@ class NsxDvsV2(addr_pair_db.AllowedAddressPairsMixin,
nsx_db.add_network_binding(
context.session, new_net['id'],
net_data.get(pnet.NETWORK_TYPE),
net_id or 'dvs',
net_id or dvs_name,
vlan_tag)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception('Failed to create network')
if (net_data.get(pnet.NETWORK_TYPE) !=
c_utils.NetworkTypes.PORTGROUP):
self._dvs.delete_port_group(dvs_id)
self._delete_port_group(dvs_id, dvs_name)
new_net[pnet.NETWORK_TYPE] = net_data.get(pnet.NETWORK_TYPE)
new_net[pnet.PHYSICAL_NETWORK] = net_id or 'dvs'
new_net[pnet.PHYSICAL_NETWORK] = net_id or dvs_name
new_net[pnet.SEGMENTATION_ID] = vlan_tag
# this extra lookup is necessary to get the
@ -294,6 +306,13 @@ class NsxDvsV2(addr_pair_db.AllowedAddressPairsMixin,
self._validate_network(context, network['network'])
return self._dvs_create_network(context, network)
def _delete_port_group(self, dvs_id, dvs_name):
if dvs_name == dvs_utils.dvs_name_get():
self._dvs.delete_port_group(dvs_id)
else:
dvs_moref = self._dvs.dvs.get_dvs_moref_by_name(dvs_name)
self._dvs.dvs.delete_port_group(dvs_moref, dvs_id)
def _dvs_delete_network(self, context, id):
network = self._get_network(context, id)
dvs_id = self._dvs_get_id(network)
@ -304,7 +323,8 @@ class NsxDvsV2(addr_pair_db.AllowedAddressPairsMixin,
try:
if (not bindings or
bindings[0].binding_type != c_utils.NetworkTypes.PORTGROUP):
self._dvs.delete_port_group(dvs_id)
dvs_name = bindings[0].phy_uuid
self._delete_port_group(dvs_id, dvs_name)
except Exception:
LOG.exception('Unable to delete DVS port group %s', id)
self.handle_network_dhcp_access(context, id, action='delete_network')

View File

@ -75,7 +75,7 @@ class DvsTestCase(base.BaseTestCase):
return_value='fake-spec')
def test_add_port_group_with_exception(self, fake_get_spec):
with (
mock.patch.object(self._dvs._dvs._session, 'wait_for_task',
mock.patch.object(self._dvs.dvs._session, 'wait_for_task',
side_effect=exp.NeutronException())
):
self.assertRaises(exp.NeutronException,
@ -95,7 +95,7 @@ class DvsTestCase(base.BaseTestCase):
return_value='fake-moref')
def test_delete_port_group_with_exception(self, fake_get_moref):
with (
mock.patch.object(self._dvs._dvs._session, 'wait_for_task',
mock.patch.object(self._dvs.dvs._session, 'wait_for_task',
side_effect=exp.NeutronException())
):
self.assertRaises(exp.NeutronException,
@ -166,9 +166,17 @@ class NeutronSimpleDvsTest(NeutronSimpleDvsTestCase):
with mock.patch.object(self._plugin._dvs,
'add_port_group') as mock_add,\
mock.patch.object(self._plugin._dvs,
'delete_port_group') as mock_delete,\
'delete_port_group') as mock_delete,\
mock.patch.object(dvs.DvsManager,
'_get_trunk_vlan_spec') as mock_trunk_vlan:
'add_port_group') as mock_dvs_add,\
mock.patch.object(dvs.DvsManager,
'delete_port_group'),\
mock.patch.object(dvs.DvsManager,
'get_dvs_moref_by_name',
return_value=mock.MagicMock()
) as mock_dvs_moref,\
mock.patch.object(dvs.DvsManager,
'_get_trunk_vlan_spec') as mock_trunk_vlan:
with self.network(**params) as network:
ctx = context.get_admin_context()
id = network['network']['id']
@ -178,11 +186,11 @@ class NeutronSimpleDvsTest(NeutronSimpleDvsTestCase):
if network_type == 'flat':
self.assertEqual('flat', binding[0].binding_type)
self.assertEqual(0, binding[0].vlan_id)
self.assertEqual('dvs', binding[0].phy_uuid)
self.assertEqual('fake-moid', binding[0].phy_uuid)
elif network_type == 'vlan':
self.assertEqual('vlan', binding[0].binding_type)
self.assertEqual(vlan_tag, binding[0].vlan_id)
self.assertEqual('dvs', binding[0].phy_uuid)
self.assertEqual('fake-moid', binding[0].phy_uuid)
elif network_type == 'portgroup':
self.assertEqual('portgroup', binding[0].binding_type)
self.assertEqual(0, binding[0].vlan_id)
@ -190,8 +198,10 @@ class NeutronSimpleDvsTest(NeutronSimpleDvsTestCase):
else:
self.fail()
if network_type != 'portgroup':
mock_add.assert_called_once_with(dvs_id, vlan_tag,
trunk_mode=trunk_mode)
mock_dvs_add.assert_called_once_with(
mock_dvs_moref.return_value,
dvs_id, vlan_tag,
trunk_mode=trunk_mode)
else:
mock_add.call_count = 0
mock_delete.call_count = 0
@ -235,7 +245,10 @@ class NeutronSimpleDvsTest(NeutronSimpleDvsTestCase):
'provider:segmentation_id': 7}
params['arg_list'] = tuple(params.keys())
with mock.patch.object(self._plugin._dvs, 'add_port_group'),\
mock.patch.object(self._plugin._dvs, 'delete_port_group'):
mock.patch.object(self._plugin._dvs, 'delete_port_group'),\
mock.patch.object(dvs.DvsManager, 'get_dvs_moref_by_name'),\
mock.patch.object(dvs.DvsManager, 'add_port_group'),\
mock.patch.object(dvs.DvsManager, 'delete_port_group'):
with self.network(**params) as network,\
self.subnet(network) as subnet,\
self.port(subnet) as port: