Validate portgroup physical network consistency

When creating or updating a port that is a member of a portgroup, we
need to validate the consistency of the physical networks of the ports
in the portgroup.

There are 3 cases we are interested in:

- Creating a port which is a member of a portgroup.
- Updating the physical network of a port which is a member of a
  portgroup.
- Updating the portgroup of a port.

All ports in a portgroup should have the same value (which may be None)
for their physical_network field.

During creation or update of a port in a portgroup we apply the
following validation criteria:

- If the portgroup has existing ports with different physical networks,
  we raise PortgroupPhysnetInconsistent. This shouldn't ever happen.
- If the port has a physical network that is inconsistent with other
  ports in the portgroup, we raise exception.Conflict.

If a port's physical network is None, this indicates that ironic's VIF
attachment mapping algorithm should operate in a legacy (physical
network unaware) mode for this port or portgroup. This allows existing
ironic nodes to continue to function after an upgrade to a release
including physical network support.

Change-Id: I6a6d248155f98109dd36dba5837494f6974846e6
Partial-Bug: #1666009
This commit is contained in:
Mark Goddard 2017-06-01 15:24:44 +01:00 committed by John L. Villalovos
parent 6084277a51
commit 039225610d
7 changed files with 590 additions and 11 deletions

View File

@ -750,3 +750,9 @@ class RedfishError(IronicException):
class RedfishConnectionError(RedfishError):
_msg_fmt = _("Redfish connection failed for node %(node)s: %(error)s")
class PortgroupPhysnetInconsistent(IronicException):
_msg_fmt = _("Port group %(portgroup)s has member ports with inconsistent "
"physical networks (%(physical_networks)s). All ports in a "
"port group must have the same physical network.")

View File

@ -42,3 +42,25 @@ def get_node_vif_ids(task):
port_vifs[port.uuid] = vif
vifs['ports'] = port_vifs
return vifs
def get_portgroup_by_id(task, portgroup_id):
"""Lookup a portgroup by ID on a task object.
:param task: a TaskManager instance
:param portgroup_id: ID of the portgroup.
:returns: A Portgroup object or None.
"""
for portgroup in task.portgroups:
if portgroup.id == portgroup_id:
return portgroup
def get_ports_by_portgroup_id(task, portgroup_id):
"""Lookup ports by their portgroup ID on a task object.
:param task: a TaskManager instance
:param portgroup_id: ID of the portgroup.
:returns: A list of Port objects.
"""
return [port for port in task.ports if port.portgroup_id == portgroup_id]

View File

@ -1838,7 +1838,9 @@ class ConductorManager(base_manager.BaseConductorManager):
@METRICS.timer('ConductorManager.create_port')
@messaging.expected_exceptions(exception.NodeLocked,
exception.MACAlreadyExists)
exception.Conflict,
exception.MACAlreadyExists,
exception.PortgroupPhysnetInconsistent)
def create_port(self, context, port_obj):
"""Create a port.
@ -1847,12 +1849,17 @@ class ConductorManager(base_manager.BaseConductorManager):
:raises: NodeLocked if node is locked by another conductor
:raises: MACAlreadyExists if the port has a MAC which is registered on
another port already.
:raises: Conflict if the port is a member of a portgroup which is on a
different physical network.
:raises: PortgroupPhysnetInconsistent if the port's portgroup has
ports which are not all assigned the same physical network.
"""
port_uuid = port_obj.uuid
LOG.debug("RPC create_port called for port %s.", port_uuid)
with task_manager.acquire(context, port_obj.node_id,
purpose='port create'):
purpose='port create') as task:
utils.validate_port_physnet(task, port_obj)
port_obj.create()
return port_obj
@ -1864,7 +1871,8 @@ class ConductorManager(base_manager.BaseConductorManager):
exception.FailedToUpdateDHCPOptOnPort,
exception.Conflict,
exception.InvalidParameterValue,
exception.NetworkError)
exception.NetworkError,
exception.PortgroupPhysnetInconsistent)
def update_port(self, context, port_obj):
"""Update a port.
@ -1881,6 +1889,10 @@ class ConductorManager(base_manager.BaseConductorManager):
:raises: Conflict if trying to set extra/vif_port_id or
pxe_enabled=True on port which is a member of portgroup with
standalone_ports_supported=False.
:raises: Conflict if the port is a member of a portgroup which is on a
different physical network.
:raises: PortgroupPhysnetInconsistent if the port's portgroup has
ports which are not all assigned the same physical network.
"""
port_uuid = port_obj.uuid
LOG.debug("RPC update_port called for port %s.", port_uuid)
@ -1900,13 +1912,14 @@ class ConductorManager(base_manager.BaseConductorManager):
'port': port_uuid})
# If port update is modifying the portgroup membership of the port
# or modifying the local_link_connection or pxe_enabled flags then
# node should be in MANAGEABLE/INSPECTING/ENROLL provisioning state
# or in maintenance mode.
# Otherwise InvalidState exception is raised.
# or modifying the local_link_connection, pxe_enabled or physical
# network flags then node should be in MANAGEABLE/INSPECTING/ENROLL
# provisioning state or in maintenance mode. Otherwise
# InvalidState exception is raised.
connectivity_attr = {'portgroup_id',
'pxe_enabled',
'local_link_connection'}
'local_link_connection',
'physical_network'}
allowed_update_states = [states.ENROLL,
states.INSPECTING,
states.MANAGEABLE]
@ -1924,6 +1937,7 @@ class ConductorManager(base_manager.BaseConductorManager):
'connect': ', '.join(connectivity_attr),
'allowed': ', '.join(allowed_update_states)})
utils.validate_port_physnet(task, port_obj)
task.driver.network.validate(task)
# Handle mac_address update and VIF attach/detach stuff.
task.driver.network.port_changed(task, port_obj)

View File

@ -19,6 +19,7 @@ from oslo_utils import reflection
from ironic.common import exception
from ironic.common.i18n import _
from ironic.common import network
from ironic.common import states
from ironic.conductor import notification_utils as notify_utils
from ironic.conductor import task_manager
@ -505,3 +506,73 @@ def _validate_user_clean_steps(task, user_steps):
if errors:
raise exception.InvalidParameterValue('; '.join(errors))
return result
@task_manager.require_exclusive_lock
def validate_port_physnet(task, port_obj):
"""Validate the consistency of physical networks of ports in a portgroup.
Validate the consistency of a port's physical network with other ports in
the same portgroup. All ports in a portgroup should have the same value
(which may be None) for their physical_network field.
During creation or update of a port in a portgroup we apply the
following validation criteria:
- If the portgroup has existing ports with different physical networks, we
raise PortgroupPhysnetInconsistent. This shouldn't ever happen.
- If the port has a physical network that is inconsistent with other
ports in the portgroup, we raise exception.Conflict.
If a port's physical network is None, this indicates that ironic's VIF
attachment mapping algorithm should operate in a legacy (physical
network unaware) mode for this port or portgroup. This allows existing
ironic nodes to continue to function after an upgrade to a release
including physical network support.
:param task: a TaskManager instance
:param port_obj: a port object to be validated.
:raises: Conflict if the port is a member of a portgroup which is on a
different physical network.
:raises: PortgroupPhysnetInconsistent if the port's portgroup has
ports which are not all assigned the same physical network.
"""
if 'portgroup_id' not in port_obj or not port_obj.portgroup_id:
return
delta = port_obj.obj_what_changed()
# We can skip this step if the port's portgroup membership or physical
# network assignment is not being changed (during creation these will
# appear changed).
if not (delta & {'portgroup_id', 'physical_network'}):
return
# Determine the current physical network of the portgroup.
pg_ports = network.get_ports_by_portgroup_id(task, port_obj.portgroup_id)
port_obj_id = port_obj.id if 'id' in port_obj else None
pg_physnets = {port.physical_network
for port in pg_ports if port.id != port_obj_id}
if not pg_physnets:
return
# Sanity check that all existing ports in the group have the same
# physical network (should never happen).
if len(pg_physnets) > 1:
portgroup = network.get_portgroup_by_id(task, port_obj.portgroup_id)
raise exception.PortgroupPhysnetInconsistent(
portgroup=portgroup.uuid, physical_networks=", ".join(pg_physnets))
# Check that the port has the same physical network as any existing
# member ports.
pg_physnet = pg_physnets.pop()
port_physnet = (port_obj.physical_network
if 'physical_network' in port_obj else None)
if port_physnet != pg_physnet:
portgroup = network.get_portgroup_by_id(task, port_obj.portgroup_id)
msg = _("Port with physical network %(physnet)s cannot become a "
"member of port group %(portgroup)s which has ports in "
"physical network %(pg_physnet)s.")
raise exception.Conflict(
msg % {'portgroup': portgroup.uuid, 'physnet': port_physnet,
'pg_physnet': pg_physnet})

View File

@ -151,3 +151,51 @@ class TestNetwork(db_base.DbTestCase):
def test_get_node_vif_ids_during_provisioning(self):
self._test_get_node_vif_ids_multitenancy('provisioning_vif_port_id')
class GetPortgroupByIdTestCase(db_base.DbTestCase):
def test_portgroup_by_id(self):
node = object_utils.create_test_node(self.context, driver='fake')
portgroup = object_utils.create_test_portgroup(self.context,
node_id=node.id)
object_utils.create_test_portgroup(self.context,
node_id=node.id,
uuid=uuidutils.generate_uuid(),
address='00:11:22:33:44:55',
name='pg2')
with task_manager.acquire(self.context, node.uuid) as task:
res = network.get_portgroup_by_id(task, portgroup.id)
self.assertEqual(portgroup.id, res.id)
def test_portgroup_by_id_no_such_portgroup(self):
node = object_utils.create_test_node(self.context, driver='fake')
object_utils.create_test_portgroup(self.context, node_id=node.id)
with task_manager.acquire(self.context, node.uuid) as task:
portgroup_id = 'invalid-portgroup-id'
res = network.get_portgroup_by_id(task, portgroup_id)
self.assertIsNone(res)
class GetPortsByPortgroupIdTestCase(db_base.DbTestCase):
def test_ports_by_portgroup_id(self):
node = object_utils.create_test_node(self.context, driver='fake')
portgroup = object_utils.create_test_portgroup(self.context,
node_id=node.id)
port = object_utils.create_test_port(self.context, node_id=node.id,
portgroup_id=portgroup.id)
object_utils.create_test_port(self.context, node_id=node.id,
uuid=uuidutils.generate_uuid(),
address='00:11:22:33:44:55')
with task_manager.acquire(self.context, node.uuid) as task:
res = network.get_ports_by_portgroup_id(task, portgroup.id)
self.assertEqual([port.id], [p.id for p in res])
def test_ports_by_portgroup_id_empty(self):
node = object_utils.create_test_node(self.context, driver='fake')
portgroup = object_utils.create_test_portgroup(self.context,
node_id=node.id)
with task_manager.acquire(self.context, node.uuid) as task:
res = network.get_ports_by_portgroup_id(task, portgroup.id)
self.assertEqual([], res)

View File

@ -3160,7 +3160,8 @@ class DestroyNodeTestCase(mgr_utils.ServiceSetUpMixin,
class CreatePortTestCase(mgr_utils.ServiceSetUpMixin,
tests_db_base.DbTestCase):
def test_create_port(self):
@mock.patch.object(conductor_utils, 'validate_port_physnet')
def test_create_port(self, mock_validate):
node = obj_utils.create_test_node(self.context, driver='fake')
port = obj_utils.get_test_port(self.context, node_id=node.id,
extra={'foo': 'bar'})
@ -3168,6 +3169,7 @@ class CreatePortTestCase(mgr_utils.ServiceSetUpMixin,
self.assertEqual({'foo': 'bar'}, res.extra)
res = objects.Port.get_by_uuid(self.context, port['uuid'])
self.assertEqual({'foo': 'bar'}, res.extra)
mock_validate.assert_called_once_with(mock.ANY, port)
def test_create_port_node_locked(self):
node = obj_utils.create_test_node(self.context, driver='fake',
@ -3181,7 +3183,8 @@ class CreatePortTestCase(mgr_utils.ServiceSetUpMixin,
self.assertRaises(exception.PortNotFound, port.get_by_uuid,
self.context, port.uuid)
def test_create_port_mac_exists(self):
@mock.patch.object(conductor_utils, 'validate_port_physnet')
def test_create_port_mac_exists(self, mock_validate):
node = obj_utils.create_test_node(self.context, driver='fake')
port = obj_utils.create_test_port(self.context, node_id=node.id)
port = obj_utils.get_test_port(self.context, node_id=node.id,
@ -3194,14 +3197,45 @@ class CreatePortTestCase(mgr_utils.ServiceSetUpMixin,
self.assertRaises(exception.PortNotFound, port.get_by_uuid,
self.context, port.uuid)
@mock.patch.object(conductor_utils, 'validate_port_physnet')
def test_create_port_physnet_validation_failure_conflict(self,
mock_validate):
mock_validate.side_effect = exception.Conflict
node = obj_utils.create_test_node(self.context, driver='fake')
port = obj_utils.get_test_port(self.context, node_id=node.id)
exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.create_port,
self.context, port)
# Compare true exception hidden by @messaging.expected_exceptions
self.assertEqual(exception.Conflict, exc.exc_info[0])
self.assertRaises(exception.PortNotFound, port.get_by_uuid,
self.context, port.uuid)
@mock.patch.object(conductor_utils, 'validate_port_physnet')
def test_create_port_physnet_validation_failure_inconsistent(
self, mock_validate):
mock_validate.side_effect = exception.PortgroupPhysnetInconsistent(
portgroup='pg1', physical_networks='physnet1, physnet2')
node = obj_utils.create_test_node(self.context, driver='fake')
port = obj_utils.get_test_port(self.context, node_id=node.id)
exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.create_port,
self.context, port)
# Compare true exception hidden by @messaging.expected_exceptions
self.assertEqual(exception.PortgroupPhysnetInconsistent,
exc.exc_info[0])
self.assertRaises(exception.PortNotFound, port.get_by_uuid,
self.context, port.uuid)
@mgr_utils.mock_record_keepalive
class UpdatePortTestCase(mgr_utils.ServiceSetUpMixin,
tests_db_base.DbTestCase):
@mock.patch.object(conductor_utils, 'validate_port_physnet')
@mock.patch.object(n_flat.FlatNetwork, 'port_changed', autospec=True)
@mock.patch.object(n_flat.FlatNetwork, 'validate', autospec=True)
def test_update_port(self, mock_val, mock_pc):
def test_update_port(self, mock_val, mock_pc, mock_vpp):
node = obj_utils.create_test_node(self.context, driver='fake')
port = obj_utils.create_test_port(self.context,
@ -3213,6 +3247,7 @@ class UpdatePortTestCase(mgr_utils.ServiceSetUpMixin,
self.assertEqual(new_extra, res.extra)
mock_val.assert_called_once_with(mock.ANY, mock.ANY)
mock_pc.assert_called_once_with(mock.ANY, mock.ANY, port)
mock_vpp.assert_called_once_with(mock.ANY, port)
def test_update_port_node_locked(self):
node = obj_utils.create_test_node(self.context, driver='fake',
@ -3375,6 +3410,69 @@ class UpdatePortTestCase(mgr_utils.ServiceSetUpMixin,
mock_val.assert_called_once_with(mock.ANY, mock.ANY)
mock_pc.assert_called_once_with(mock.ANY, mock.ANY, port)
@mock.patch.object(n_flat.FlatNetwork, 'port_changed', autospec=True)
@mock.patch.object(n_flat.FlatNetwork, 'validate', autospec=True)
def test_update_port_physnet_maintenance(self, mock_val, mock_pc):
node = obj_utils.create_test_node(
self.context, driver='fake', maintenance=True,
instance_uuid=uuidutils.generate_uuid(), provision_state='active')
port = obj_utils.create_test_port(self.context,
node_id=node.id,
extra={'vif_port_id': 'fake-id'})
new_physnet = 'physnet1'
port.physical_network = new_physnet
res = self.service.update_port(self.context, port)
self.assertEqual(new_physnet, res.physical_network)
mock_val.assert_called_once_with(mock.ANY, mock.ANY)
mock_pc.assert_called_once_with(mock.ANY, mock.ANY, port)
def test_update_port_physnet_node_deleting_state(self):
node = obj_utils.create_test_node(self.context, driver='fake',
provision_state=states.DELETING)
port = obj_utils.create_test_port(self.context,
node_id=node.id,
extra={'foo': 'bar'})
old_physnet = port.physical_network
port.physical_network = 'physnet1'
exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.update_port,
self.context, port)
self.assertEqual(exception.InvalidState, exc.exc_info[0])
port.refresh()
self.assertEqual(old_physnet, port.physical_network)
@mock.patch.object(conductor_utils, 'validate_port_physnet')
def test_update_port_physnet_validation_failure_conflict(self,
mock_validate):
mock_validate.side_effect = exception.Conflict
node = obj_utils.create_test_node(self.context, driver='fake')
port = obj_utils.create_test_port(self.context, node_id=node.id,
uuid=uuidutils.generate_uuid())
port.extra = {'foo': 'bar'}
exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.update_port,
self.context, port)
# Compare true exception hidden by @messaging.expected_exceptions
self.assertEqual(exception.Conflict, exc.exc_info[0])
mock_validate.assert_called_once_with(mock.ANY, port)
@mock.patch.object(conductor_utils, 'validate_port_physnet')
def test_update_port_physnet_validation_failure_inconsistent(
self, mock_validate):
mock_validate.side_effect = exception.PortgroupPhysnetInconsistent(
portgroup='pg1', physical_networks='physnet1, physnet2')
node = obj_utils.create_test_node(self.context, driver='fake')
port = obj_utils.create_test_port(self.context, node_id=node.id,
uuid=uuidutils.generate_uuid())
port.extra = {'foo': 'bar'}
exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.update_port,
self.context, port)
# Compare true exception hidden by @messaging.expected_exceptions
self.assertEqual(exception.PortgroupPhysnetInconsistent,
exc.exc_info[0])
mock_validate.assert_called_once_with(mock.ANY, port)
def test__filter_out_unsupported_types_all(self):
self._start_service()
CONF.set_override('send_sensor_data_types', ['All'], group='conductor')

View File

@ -16,6 +16,7 @@ from oslo_utils import uuidutils
from ironic.common import driver_factory
from ironic.common import exception
from ironic.common import network
from ironic.common import states
from ironic.conductor import task_manager
from ironic.conductor import utils as conductor_utils
@ -990,3 +991,322 @@ class ErrorHandlersTestCase(tests_base.TestCase):
conductor_utils.power_state_error_handler(exc, self.node, 'foo')
self.assertFalse(self.node.save.called)
self.assertFalse(log_mock.warning.called)
class ValidatePortPhysnetTestCase(base.DbTestCase):
def setUp(self):
super(ValidatePortPhysnetTestCase, self).setUp()
self.node = obj_utils.create_test_node(self.context, driver='fake')
@mock.patch.object(objects.Port, 'obj_what_changed')
def test_validate_port_physnet_no_portgroup_create(self, mock_owc):
port = obj_utils.get_test_port(self.context, node_id=self.node.id)
# NOTE(mgoddard): The port object passed to the conductor will not have
# a portgroup_id attribute in this case.
del port.portgroup_id
with task_manager.acquire(self.context, self.node.uuid) as task:
conductor_utils.validate_port_physnet(task, port)
# Verify the early return in the non-portgroup case.
self.assertFalse(mock_owc.called)
@mock.patch.object(network, 'get_ports_by_portgroup_id')
def test_validate_port_physnet_no_portgroup_update(self, mock_gpbpi):
port = obj_utils.create_test_port(self.context, node_id=self.node.id)
port.extra = {'foo': 'bar'}
with task_manager.acquire(self.context, self.node.uuid) as task:
conductor_utils.validate_port_physnet(task, port)
# Verify the early return in the no portgroup update case.
self.assertFalse(mock_gpbpi.called)
def test_validate_port_physnet_inconsistent_physnets(self):
# NOTE(mgoddard): This *shouldn't* happen, but let's make sure we can
# handle it.
portgroup = obj_utils.create_test_portgroup(self.context,
node_id=self.node.id)
obj_utils.create_test_port(self.context, node_id=self.node.id,
portgroup_id=portgroup.id,
address='00:11:22:33:44:55',
physical_network='physnet1',
uuid=uuidutils.generate_uuid())
obj_utils.create_test_port(self.context, node_id=self.node.id,
portgroup_id=portgroup.id,
address='00:11:22:33:44:56',
physical_network='physnet2',
uuid=uuidutils.generate_uuid())
port = obj_utils.get_test_port(self.context, node_id=self.node.id,
portgroup_id=portgroup.id,
address='00:11:22:33:44:57',
physical_network='physnet2',
uuid=uuidutils.generate_uuid())
with task_manager.acquire(self.context, self.node.uuid) as task:
self.assertRaises(exception.PortgroupPhysnetInconsistent,
conductor_utils.validate_port_physnet,
task, port)
def test_validate_port_physnet_inconsistent_physnets_fix(self):
# NOTE(mgoddard): This *shouldn't* happen, but let's make sure that if
# we do get into this state that it is possible to resolve by setting
# the physical_network correctly.
portgroup = obj_utils.create_test_portgroup(self.context,
node_id=self.node.id)
obj_utils.create_test_port(self.context, node_id=self.node.id,
portgroup_id=portgroup.id,
address='00:11:22:33:44:55',
physical_network='physnet1',
uuid=uuidutils.generate_uuid())
port = obj_utils.create_test_port(self.context, node_id=self.node.id,
portgroup_id=portgroup.id,
address='00:11:22:33:44:56',
physical_network='physnet2',
uuid=uuidutils.generate_uuid())
port.physical_network = 'physnet1'
with task_manager.acquire(self.context, self.node.uuid) as task:
conductor_utils.validate_port_physnet(task, port)
def _test_validate_port_physnet(self,
num_current_ports,
current_physnet,
new_physnet,
operation,
valid=True):
"""Helper method for testing validate_port_physnet.
:param num_current_ports: Number of existing ports in the portgroup.
:param current_physnet: Physical network of existing ports in the
portgroup.
:param new_physnet: Physical network to set on the port that is being
created or updated.
portgroup.
:param operation: The operation to perform. One of 'create', 'update',
or 'update_add'. 'create' creates a new port and adds
it to the portgroup. 'update' updates one of the
existing ports. 'update_add' updates a port and adds
it to the portgroup.
:param valid: Whether the operation is expected to succeed.
"""
# Prepare existing resources - a node, and a portgroup with optional
# existing ports.
port = None
portgroup = obj_utils.create_test_portgroup(self.context,
node_id=self.node.id)
macs = ("00:11:22:33:44:%02x" % index
for index in range(num_current_ports + 1))
for _ in range(num_current_ports):
# NOTE: When operation == 'update' we update the last port in the
# portgroup.
port = obj_utils.create_test_port(
self.context, node_id=self.node.id, portgroup_id=portgroup.id,
address=next(macs), physical_network=current_physnet,
uuid=uuidutils.generate_uuid())
# Prepare the port on which we are performing the operation.
if operation == 'create':
# NOTE(mgoddard): We use utils here rather than obj_utils as it
# allows us to create a Port without a physical_network field, more
# closely matching what happens during creation of a port when a
# physical_network is not specified.
port = utils.get_test_port(
node_id=self.node.id, portgroup_id=portgroup.id,
address=next(macs), uuid=uuidutils.generate_uuid(),
physical_network=new_physnet)
if new_physnet is None:
del port["physical_network"]
port = objects.Port(self.context, **port)
elif operation == 'update_add':
port = obj_utils.create_test_port(
self.context, node_id=self.node.id, portgroup_id=None,
address=next(macs), physical_network=current_physnet,
uuid=uuidutils.generate_uuid())
port.portgroup_id = portgroup.id
if operation != 'create' and new_physnet != current_physnet:
port.physical_network = new_physnet
# Perform the validation.
with task_manager.acquire(self.context, self.node.uuid) as task:
if valid:
conductor_utils.validate_port_physnet(task, port)
else:
self.assertRaises(exception.Conflict,
conductor_utils.validate_port_physnet,
task, port)
def _test_validate_port_physnet_create(self, **kwargs):
self._test_validate_port_physnet(operation='create', **kwargs)
def _test_validate_port_physnet_update(self, **kwargs):
self._test_validate_port_physnet(operation='update', **kwargs)
def _test_validate_port_physnet_update_add(self, **kwargs):
self._test_validate_port_physnet(operation='update_add', **kwargs)
# Empty portgroup
def test_validate_port_physnet_empty_portgroup_create_1(self):
self._test_validate_port_physnet_create(
num_current_ports=0,
current_physnet=None,
new_physnet=None)
def test_validate_port_physnet_empty_portgroup_create_2(self):
self._test_validate_port_physnet_create(
num_current_ports=0,
current_physnet=None,
new_physnet='physnet1')
def test_validate_port_physnet_empty_portgroup_update_1(self):
self._test_validate_port_physnet_update_add(
num_current_ports=0,
current_physnet=None,
new_physnet=None)
def test_validate_port_physnet_empty_portgroup_update_2(self):
self._test_validate_port_physnet_update_add(
num_current_ports=0,
current_physnet=None,
new_physnet='physnet1')
# 1-port portgroup, no physnet.
def test_validate_port_physnet_1_port_portgroup_no_physnet_create_1(self):
self._test_validate_port_physnet_create(
num_current_ports=1,
current_physnet=None,
new_physnet=None)
def test_validate_port_physnet_1_port_portgroup_no_physnet_create_2(self):
self._test_validate_port_physnet_create(
num_current_ports=1,
current_physnet=None,
new_physnet='physnet1',
valid=False)
def test_validate_port_physnet_1_port_portgroup_no_physnet_update_1(self):
self._test_validate_port_physnet_update(
num_current_ports=1,
current_physnet=None,
new_physnet=None)
def test_validate_port_physnet_1_port_portgroup_no_physnet_update_2(self):
self._test_validate_port_physnet_update(
num_current_ports=1,
current_physnet=None,
new_physnet='physnet1')
def test_validate_port_physnet_1_port_portgroup_no_physnet_update_add_1(
self):
self._test_validate_port_physnet_update_add(
num_current_ports=1,
current_physnet=None,
new_physnet=None)
def test_validate_port_physnet_1_port_portgroup_no_physnet_update_add_2(
self):
self._test_validate_port_physnet_update_add(
num_current_ports=1,
current_physnet=None,
new_physnet='physnet1',
valid=False)
# 1-port portgroup, with physnet 'physnet1'.
def test_validate_port_physnet_1_port_portgroup_w_physnet_create_1(self):
self._test_validate_port_physnet_create(
num_current_ports=1,
current_physnet='physnet1',
new_physnet='physnet1')
def test_validate_port_physnet_1_port_portgroup_w_physnet_create_2(self):
self._test_validate_port_physnet_create(
num_current_ports=1,
current_physnet='physnet1',
new_physnet='physnet2',
valid=False)
def test_validate_port_physnet_1_port_portgroup_w_physnet_create_3(self):
self._test_validate_port_physnet_create(
num_current_ports=1,
current_physnet='physnet1',
new_physnet=None,
valid=False)
def test_validate_port_physnet_1_port_portgroup_w_physnet_update_1(self):
self._test_validate_port_physnet_update(
num_current_ports=1,
current_physnet='physnet1',
new_physnet='physnet1')
def test_validate_port_physnet_1_port_portgroup_w_physnet_update_2(self):
self._test_validate_port_physnet_update(
num_current_ports=1,
current_physnet='physnet1',
new_physnet='physnet2')
def test_validate_port_physnet_1_port_portgroup_w_physnet_update_3(self):
self._test_validate_port_physnet_update(
num_current_ports=1,
current_physnet='physnet1',
new_physnet=None)
def test_validate_port_physnet_1_port_portgroup_w_physnet_update_add_1(
self):
self._test_validate_port_physnet_update_add(
num_current_ports=1,
current_physnet='physnet1',
new_physnet='physnet1')
def test_validate_port_physnet_1_port_portgroup_w_physnet_update_add_2(
self):
self._test_validate_port_physnet_update_add(
num_current_ports=1,
current_physnet='physnet1',
new_physnet='physnet2',
valid=False)
def test_validate_port_physnet_1_port_portgroup_w_physnet_update_add_3(
self):
self._test_validate_port_physnet_update_add(
num_current_ports=1,
current_physnet='physnet1',
new_physnet=None,
valid=False)
# 2-port portgroup, no physnet
def test_validate_port_physnet_2_port_portgroup_no_physnet_update_1(self):
self._test_validate_port_physnet_update(
num_current_ports=2,
current_physnet=None,
new_physnet=None)
def test_validate_port_physnet_2_port_portgroup_no_physnet_update_2(self):
self._test_validate_port_physnet_update(
num_current_ports=2,
current_physnet=None,
new_physnet='physnet1',
valid=False)
# 2-port portgroup, with physnet 'physnet1'
def test_validate_port_physnet_2_port_portgroup_w_physnet_update_1(self):
self._test_validate_port_physnet_update(
num_current_ports=2,
current_physnet='physnet1',
new_physnet='physnet1')
def test_validate_port_physnet_2_port_portgroup_w_physnet_update_2(self):
self._test_validate_port_physnet_update(
num_current_ports=2,
current_physnet='physnet1',
new_physnet='physnet2',
valid=False)
def test_validate_port_physnet_2_port_portgroup_w_physnet_update_3(self):
self._test_validate_port_physnet_update(
num_current_ports=2,
current_physnet='physnet1',
new_physnet=None,
valid=False)