Add portgroups to support LAG interfaces - RPC

Ironic should be able to provide the requisite connectivity
information to the Neutron ML2 plugin to allow drivers to
provision the top-of-rack switch for the bare metal server.
The addition of portgroups in Ironic allows the concept of
link aggregation to be handled in Ironic in order to provide
support for cases where multiple interfaces on the bare metal
server connect to switch ports of a single LAG.

This commit includes changes to:
- the RPC API (to include portgroup methods)
- the RPC tests

Partial-bug: #1526403
DocImpact
Co-Authored-By: Jenny Moorehead (jenny.moorehead@sap.com)
Co-Authored-By: Will Stevenson (will.stevenson@sap.com)

Change-Id: Iac6355e615e57e6ed002facd6795c9ff06188998
This commit is contained in:
Laura Moore 2015-07-27 17:14:40 -04:00 committed by vsaienko
parent 134ad4cbf6
commit a603e3c12c
6 changed files with 403 additions and 60 deletions

View File

@ -184,7 +184,7 @@ class ConductorManager(base_manager.BaseConductorManager):
"""Ironic Conductor manager main class."""
# NOTE(rloo): This must be in sync with rpcapi.ConductorAPI's.
RPC_API_VERSION = '1.32'
RPC_API_VERSION = '1.33'
target = messaging.Target(version=RPC_API_VERSION)
@ -1511,6 +1511,30 @@ class ConductorManager(base_manager.BaseConductorManager):
'%(node)s'),
{'port': port.uuid, 'node': task.node.uuid})
@messaging.expected_exceptions(exception.NodeLocked,
exception.NodeNotFound,
exception.PortgroupNotEmpty)
def destroy_portgroup(self, context, portgroup):
"""Delete a portgroup.
:param context: request context.
:param portgroup: portgroup object
:raises: NodeLocked if node is locked by another conductor.
:raises: NodeNotFound if the node associated with the portgroup does
not exist.
:raises: PortgroupNotEmpty if portgroup is not empty
"""
LOG.debug('RPC destroy_portgroup called for portgroup %(portgroup)s',
{'portgroup': portgroup.uuid})
with task_manager.acquire(context, portgroup.node_id,
purpose='portgroup deletion') as task:
portgroup.destroy()
LOG.info(_LI('Successfully deleted portgroup %(portgroup)s. '
'The node associated with the portgroup was '
'%(node)s'),
{'portgroup': portgroup.uuid, 'node': task.node.uuid})
@messaging.expected_exceptions(exception.NodeLocked,
exception.UnsupportedDriverExtension,
exception.NodeConsoleNotEnabled,
@ -1616,7 +1640,8 @@ class ConductorManager(base_manager.BaseConductorManager):
@messaging.expected_exceptions(exception.NodeLocked,
exception.FailedToUpdateMacOnPort,
exception.MACAlreadyExists)
exception.MACAlreadyExists,
exception.InvalidState)
def update_port(self, context, port_obj):
"""Update a port.
@ -1627,6 +1652,9 @@ class ConductorManager(base_manager.BaseConductorManager):
failed.
:raises: MACAlreadyExists if the update is setting a MAC which is
registered on another port already.
:raises: InvalidState if port connectivity attributes
are updated while node not in a MANAGEABLE or ENROLL or
INSPECTING state or not in MAINTENANCE mode.
"""
port_uuid = port_obj.uuid
LOG.debug("RPC update_port called for port %s.", port_uuid)
@ -1634,6 +1662,32 @@ class ConductorManager(base_manager.BaseConductorManager):
with task_manager.acquire(context, port_obj.node_id,
purpose='port update') as task:
node = task.node
# 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.
connectivity_attr = {'portgroup_uuid',
'pxe_enabled',
'local_link_connection'}
allowed_update_states = [states.ENROLL,
states.INSPECTING,
states.MANAGEABLE]
if (set(port_obj.obj_what_changed()) & connectivity_attr
and not (task.node.provision_state in allowed_update_states
or task.node.maintenance)):
action = _("Port %(port)s can not have any connectivity "
"attributes (%(connect)s) updated unless "
"node %(node)s is in a %(allowed)s state "
"or in maintenance mode.")
raise exception.InvalidState(
action % {'port': port_uuid,
'node': task.node.uuid,
'connect': ', '.join(connectivity_attr),
'allowed': ', '.join(allowed_update_states)})
if 'address' in port_obj.obj_what_changed():
vif = port_obj.extra.get('vif_port_id')
if vif:
@ -1653,6 +1707,51 @@ class ConductorManager(base_manager.BaseConductorManager):
return port_obj
@messaging.expected_exceptions(exception.NodeLocked,
exception.FailedToUpdateMacOnPort,
exception.PortgroupMACAlreadyExists)
def update_portgroup(self, context, portgroup_obj):
"""Update a portgroup.
:param context: request context.
:param portgroup_obj: a changed (but not saved) portgroup object.
:raises: DHCPLoadError if the dhcp_provider cannot be loaded.
:raises: FailedToUpdateMacOnPort if MAC address changed and update
failed.
:raises: PortgroupMACAlreadyExists if the update is setting a MAC which
is registered on another portgroup already.
"""
portgroup_uuid = portgroup_obj.uuid
LOG.debug("RPC update_portgroup called for portgroup %s.",
portgroup_uuid)
lock_purpose = 'update portgroup'
with task_manager.acquire(context,
portgroup_obj.node_id,
purpose=lock_purpose) as task:
node = task.node
if 'address' in portgroup_obj.obj_what_changed():
vif = portgroup_obj.extra.get('vif_portgroup_id')
if vif:
api = dhcp_factory.DHCPFactory()
api.provider.update_port_address(
vif,
portgroup_obj.address,
token=context.auth_token)
# Log warning if there is no vif_portgroup_id and an instance
# is associated with the node.
elif node.instance_uuid:
LOG.warning(_LW(
"No VIF was found for instance %(instance)s "
"on node %(node)s, when attempting to update "
"portgroup %(portgroup)s MAC address."),
{'portgroup': portgroup_uuid,
'instance': node.instance_uuid,
'node': node.uuid})
portgroup_obj.save()
return portgroup_obj
@messaging.expected_exceptions(exception.DriverNotFound)
def get_driver_properties(self, context, driver_name):
"""Get the properties of the driver.

View File

@ -79,11 +79,12 @@ class ConductorAPI(object):
| object_class_action_versions, object_action and
| object_backport_versions
| 1.32 - Add do_node_clean
| 1.33 - Added update and destroy portgroup.
"""
# NOTE(rloo): This must be in sync with manager.ConductorManager's.
RPC_API_VERSION = '1.32'
RPC_API_VERSION = '1.33'
def __init__(self, topic=None):
super(ConductorAPI, self).__init__()
@ -435,6 +436,38 @@ class ConductorAPI(object):
cctxt = self.client.prepare(topic=topic or self.topic, version='1.13')
return cctxt.call(context, 'update_port', port_obj=port_obj)
def update_portgroup(self, context, portgroup_obj, topic=None):
"""Synchronously, have a conductor update the portgroup's information.
Update the portgroup's information in the database and return a
portgroup object.
The conductor will lock related node and trigger specific driver
actions if they are needed.
:param context: request context.
:param portgroup_obj: a changed (but not saved) portgroup object.
:param topic: RPC topic. Defaults to self.topic.
:returns: updated portgroup object, including all fields.
"""
cctxt = self.client.prepare(topic=topic or self.topic, version='1.33')
return cctxt.call(context, 'update_portgroup',
portgroup_obj=portgroup_obj)
def destroy_portgroup(self, context, portgroup, topic=None):
"""Delete a portgroup.
:param context: request context.
:param portgroup: portgroup object
:param topic: RPC topic. Defaults to self.topic.
:raises: NodeLocked if node is locked by another conductor.
:raises: NodeNotFound if the node associated with the portgroup does
not exist.
:raises: PortgroupNotEmpty if portgroup is not empty
"""
cctxt = self.client.prepare(topic=topic or self.topic, version='1.33')
return cctxt.call(context, 'destroy_portgroup', portgroup=portgroup)
def get_driver_properties(self, context, driver_name, topic=None):
"""Get the properties of the driver.

View File

@ -204,7 +204,10 @@ class TaskManager(object):
else:
self._debug_timer.restart()
self.node = objects.Node.get(context, node_id)
self.ports = objects.Port.list_by_node_id(context, self.node.id)
self.portgroups = objects.Portgroup.list_by_node_id(context,
self.node.id)
self.driver = driver_factory.get_driver(driver_name or
self.node.driver)
@ -313,6 +316,7 @@ class TaskManager(object):
self.node = None
self.driver = None
self.ports = None
self.portgroups = None
self.fsm = None
def _thread_release_resources(self, t):

View File

@ -2580,6 +2580,44 @@ class UpdatePortTestCase(mgr_utils.ServiceSetUpMixin,
self.assertEqual(new_address, res.address)
self.assertFalse(mac_update_mock.called)
def test_update_port_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_pxe = port.pxe_enabled
port.pxe_enabled = True
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_pxe, port.pxe_enabled)
def test_update_port_node_manageable_state(self):
node = obj_utils.create_test_node(self.context, driver='fake',
provision_state=states.MANAGEABLE)
port = obj_utils.create_test_port(self.context,
node_id=node.id,
extra={'foo': 'bar'})
port.pxe_enabled = True
self.service.update_port(self.context, port)
port.refresh()
self.assertEqual(True, port.pxe_enabled)
def test_update_port_node_active_state_and_maintenance(self):
node = obj_utils.create_test_node(self.context, driver='fake',
provision_state=states.ACTIVE,
maintenance=True)
port = obj_utils.create_test_port(self.context,
node_id=node.id,
extra={'foo': 'bar'})
port.pxe_enabled = True
self.service.update_port(self.context, port)
port.refresh()
self.assertEqual(True, port.pxe_enabled)
def test__filter_out_unsupported_types_all(self):
self._start_service()
CONF.set_override('send_sensor_data_types', ['All'], group='conductor')
@ -2780,6 +2818,80 @@ class UpdatePortTestCase(mgr_utils.ServiceSetUpMixin,
exc.exc_info[0])
@mgr_utils.mock_record_keepalive
class UpdatePortgroupTestCase(mgr_utils.ServiceSetUpMixin,
tests_db_base.DbTestCase):
def test_update_portgroup(self):
node = obj_utils.create_test_node(self.context, driver='fake')
portgroup = obj_utils.create_test_portgroup(self.context,
node_id=node.id,
extra={'foo': 'bar'})
new_extra = {'foo': 'baz'}
portgroup.extra = new_extra
self.service.update_portgroup(self.context, portgroup)
portgroup.refresh()
self.assertEqual(new_extra, portgroup.extra)
def test_update_portgroup_node_locked(self):
node = obj_utils.create_test_node(self.context, driver='fake',
reservation='fake-reserv')
portgroup = obj_utils.create_test_portgroup(self.context,
node_id=node.id)
old_extra = portgroup.extra
portgroup.extra = {'foo': 'baz'}
exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.update_portgroup,
self.context, portgroup)
# Compare true exception hidden by @messaging.expected_exceptions
self.assertEqual(exception.NodeLocked, exc.exc_info[0])
portgroup.refresh()
self.assertEqual(old_extra, portgroup.extra)
@mock.patch('ironic.dhcp.neutron.NeutronDHCPApi.update_port_address')
def test_update_portgroup_address(self, mac_update_mock):
node = obj_utils.create_test_node(self.context, driver='fake')
pg = obj_utils.create_test_portgroup(
self.context, node_id=node.id,
extra={'vif_portgroup_id': 'fake-id'})
new_address = '11:22:33:44:55:bb'
pg.address = new_address
self.service.update_portgroup(self.context, pg)
pg.refresh()
self.assertEqual(new_address, pg.address)
mac_update_mock.assert_called_once_with('fake-id', new_address,
token=self.context.auth_token)
@mock.patch('ironic.dhcp.neutron.NeutronDHCPApi.update_port_address')
def test_update_portgroup_address_fail(self, mac_update_mock):
node = obj_utils.create_test_node(self.context, driver='fake')
pg = obj_utils.create_test_portgroup(
self.context, node_id=node.id,
extra={'vif_portgroup_id': 'fake-id'})
old_address = pg.address
pg.address = '11:22:33:44:55:bb'
mac_update_mock.side_effect = (
exception.FailedToUpdateMacOnPort(port_id=pg.uuid))
exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.update_portgroup,
self.context, pg)
# Compare true exception hidden by @messaging.expected_exceptions
self.assertEqual(exception.FailedToUpdateMacOnPort, exc.exc_info[0])
pg.refresh()
self.assertEqual(old_address, pg.address)
@mock.patch('ironic.dhcp.neutron.NeutronDHCPApi.update_port_address')
def test_update_portgroup_address_no_vif_id(self, mac_update_mock):
node = obj_utils.create_test_node(self.context, driver='fake')
pg = obj_utils.create_test_port(self.context, node_id=node.id)
new_address = '11:22:33:44:55:bb'
pg.address = new_address
self.service.update_portgroup(self.context, pg)
pg.refresh()
self.assertEqual(new_address, pg.address)
self.assertFalse(mac_update_mock.called)
@mgr_utils.mock_record_keepalive
class RaidTestCases(mgr_utils.ServiceSetUpMixin, tests_db_base.DbTestCase):
@ -4284,6 +4396,28 @@ class DestroyPortTestCase(mgr_utils.ServiceSetUpMixin,
self.assertEqual(exception.NodeLocked, exc.exc_info[0])
@mgr_utils.mock_record_keepalive
class DestroyPortgroupTestCase(mgr_utils.ServiceSetUpMixin,
tests_db_base.DbTestCase):
def test_destroy_portgroup(self):
node = obj_utils.create_test_node(self.context, driver='fake')
portgroup = obj_utils.create_test_portgroup(self.context,
node_id=node.id)
self.service.destroy_portgroup(self.context, portgroup)
self.assertRaises(exception.PortgroupNotFound, portgroup.refresh)
def test_destroy_portgroup_node_locked(self):
node = obj_utils.create_test_node(self.context, driver='fake',
reservation='fake-reserv')
portgroup = obj_utils.create_test_portgroup(self.context,
node_id=node.id)
exc = self.assertRaises(messaging.rpc.ExpectedException,
self.service.destroy_portgroup,
self.context, portgroup)
# Compare true exception hidden by @messaging.expected_exceptions
self.assertEqual(exception.NodeLocked, exc.exc_info[0])
@mgr_utils.mock_record_keepalive
@mock.patch.object(manager.ConductorManager, '_fail_if_in_state')
@mock.patch.object(manager.ConductorManager, '_mapped_to_this_conductor')

View File

@ -53,6 +53,7 @@ class RPCAPITestCase(base.DbTestCase):
self.fake_node = dbutils.get_test_node(driver='fake-driver')
self.fake_node_obj = objects.Node._from_db_object(
objects.Node(self.context), self.fake_node)
self.fake_portgroup = dbutils.get_test_portgroup()
def test_serialized_instance_has_uuid(self):
self.assertTrue('uuid' in self.fake_node)
@ -380,3 +381,15 @@ class RPCAPITestCase(base.DbTestCase):
rpcapi.object_backport_versions, self.context,
objinst='fake-object',
object_versions={'fake-object': '1.0'})
def test_update_portgroup(self):
self._test_rpcapi('update_portgroup',
'call',
version='1.33',
portgroup_obj=self.fake_portgroup)
def test_destroy_portgroup(self):
self._test_rpcapi('destroy_portgroup',
'call',
version='1.33',
portgroup=self.fake_portgroup)

View File

@ -38,6 +38,7 @@ from ironic.tests.unit.objects import utils as obj_utils
@mock.patch.object(objects.Node, 'reserve')
@mock.patch.object(driver_factory, 'get_driver')
@mock.patch.object(objects.Port, 'list_by_node_id')
@mock.patch.object(objects.Portgroup, 'list_by_node_id')
class TaskManagerTestCase(tests_db_base.DbTestCase):
def setUp(self):
super(TaskManagerTestCase, self).setUp()
@ -47,68 +48,77 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
self.config(node_locked_retry_interval=0, group='conductor')
self.node = obj_utils.create_test_node(self.context)
def test_excl_lock(self, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
def test_excl_lock(self, get_portgroups_mock, get_ports_mock,
get_driver_mock, reserve_mock, release_mock,
node_get_mock):
reserve_mock.return_value = self.node
with task_manager.TaskManager(self.context, 'fake-node-id') as task:
self.assertEqual(self.context, task.context)
self.assertEqual(self.node, task.node)
self.assertEqual(get_ports_mock.return_value, task.ports)
self.assertEqual(get_portgroups_mock.return_value, task.portgroups)
self.assertEqual(get_driver_mock.return_value, task.driver)
self.assertFalse(task.shared)
reserve_mock.assert_called_once_with(self.context, self.host,
'fake-node-id')
get_ports_mock.assert_called_once_with(self.context, self.node.id)
get_portgroups_mock.assert_called_once_with(self.context, self.node.id)
get_driver_mock.assert_called_once_with(self.node.driver)
release_mock.assert_called_once_with(self.context, self.host,
self.node.id)
self.assertFalse(node_get_mock.called)
def test_excl_lock_with_driver(self, get_ports_mock, get_driver_mock,
reserve_mock, release_mock,
node_get_mock):
def test_excl_lock_with_driver(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
reserve_mock.return_value = self.node
with task_manager.TaskManager(self.context, 'fake-node-id',
driver_name='fake-driver') as task:
self.assertEqual(self.context, task.context)
self.assertEqual(self.node, task.node)
self.assertEqual(get_ports_mock.return_value, task.ports)
self.assertEqual(get_portgroups_mock.return_value, task.portgroups)
self.assertEqual(get_driver_mock.return_value, task.driver)
self.assertFalse(task.shared)
reserve_mock.assert_called_once_with(self.context, self.host,
'fake-node-id')
get_ports_mock.assert_called_once_with(self.context, self.node.id)
get_portgroups_mock.assert_called_once_with(self.context, self.node.id)
get_driver_mock.assert_called_once_with('fake-driver')
release_mock.assert_called_once_with(self.context, self.host,
self.node.id)
self.assertFalse(node_get_mock.called)
def test_excl_nested_acquire(self, get_ports_mock, get_driver_mock,
reserve_mock, release_mock,
node_get_mock):
def test_excl_nested_acquire(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
node2 = obj_utils.create_test_node(self.context,
uuid=uuidutils.generate_uuid(),
driver='fake')
reserve_mock.return_value = self.node
get_ports_mock.return_value = mock.sentinel.ports1
get_portgroups_mock.return_value = mock.sentinel.portgroups1
get_driver_mock.return_value = mock.sentinel.driver1
with task_manager.TaskManager(self.context, 'node-id1') as task:
reserve_mock.return_value = node2
get_ports_mock.return_value = mock.sentinel.ports2
get_portgroups_mock.return_value = mock.sentinel.portgroups2
get_driver_mock.return_value = mock.sentinel.driver2
with task_manager.TaskManager(self.context, 'node-id2') as task2:
self.assertEqual(self.context, task.context)
self.assertEqual(self.node, task.node)
self.assertEqual(mock.sentinel.ports1, task.ports)
self.assertEqual(mock.sentinel.portgroups1, task.portgroups)
self.assertEqual(mock.sentinel.driver1, task.driver)
self.assertFalse(task.shared)
self.assertEqual(self.context, task2.context)
self.assertEqual(node2, task2.node)
self.assertEqual(mock.sentinel.ports2, task2.ports)
self.assertEqual(mock.sentinel.portgroups2, task2.portgroups)
self.assertEqual(mock.sentinel.driver2, task2.driver)
self.assertFalse(task2.shared)
@ -127,9 +137,9 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
release_mock.call_args_list)
self.assertFalse(node_get_mock.called)
def test_excl_lock_exception_then_lock(self, get_ports_mock,
get_driver_mock, reserve_mock,
release_mock, node_get_mock):
def test_excl_lock_exception_then_lock(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
retry_attempts = 3
self.config(node_locked_retry_attempts=retry_attempts,
group='conductor')
@ -147,9 +157,9 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
reserve_mock.assert_has_calls(expected_calls)
self.assertEqual(2, reserve_mock.call_count)
def test_excl_lock_reserve_exception(self, get_ports_mock,
get_driver_mock, reserve_mock,
release_mock, node_get_mock):
def test_excl_lock_reserve_exception(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
retry_attempts = 3
self.config(node_locked_retry_attempts=retry_attempts,
group='conductor')
@ -165,13 +175,14 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
'fake-node-id')
self.assertEqual(retry_attempts, reserve_mock.call_count)
self.assertFalse(get_ports_mock.called)
self.assertFalse(get_portgroups_mock.called)
self.assertFalse(get_driver_mock.called)
self.assertFalse(release_mock.called)
self.assertFalse(node_get_mock.called)
def test_excl_lock_get_ports_exception(self, get_ports_mock,
get_driver_mock, reserve_mock,
release_mock, node_get_mock):
def test_excl_lock_get_ports_exception(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
reserve_mock.return_value = self.node
get_ports_mock.side_effect = exception.IronicException('foo')
@ -188,9 +199,28 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
self.node.id)
self.assertFalse(node_get_mock.called)
def test_excl_lock_get_driver_exception(self, get_ports_mock,
get_driver_mock, reserve_mock,
release_mock, node_get_mock):
def test_excl_lock_get_portgroups_exception(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
reserve_mock.return_value = self.node
get_portgroups_mock.side_effect = exception.IronicException('foo')
self.assertRaises(exception.IronicException,
task_manager.TaskManager,
self.context,
'fake-node-id')
reserve_mock.assert_called_once_with(self.context, self.host,
'fake-node-id')
get_portgroups_mock.assert_called_once_with(self.context, self.node.id)
self.assertFalse(get_driver_mock.called)
release_mock.assert_called_once_with(self.context, self.host,
self.node.id)
self.assertFalse(node_get_mock.called)
def test_excl_lock_get_driver_exception(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
reserve_mock.return_value = self.node
get_driver_mock.side_effect = (
exception.DriverNotFound(driver_name='foo'))
@ -203,19 +233,22 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
reserve_mock.assert_called_once_with(self.context, self.host,
'fake-node-id')
get_ports_mock.assert_called_once_with(self.context, self.node.id)
get_portgroups_mock.assert_called_once_with(self.context, self.node.id)
get_driver_mock.assert_called_once_with(self.node.driver)
release_mock.assert_called_once_with(self.context, self.host,
self.node.id)
self.assertFalse(node_get_mock.called)
def test_shared_lock(self, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
def test_shared_lock(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
node_get_mock.return_value = self.node
with task_manager.TaskManager(self.context, 'fake-node-id',
shared=True) as task:
self.assertEqual(self.context, task.context)
self.assertEqual(self.node, task.node)
self.assertEqual(get_ports_mock.return_value, task.ports)
self.assertEqual(get_portgroups_mock.return_value, task.portgroups)
self.assertEqual(get_driver_mock.return_value, task.driver)
self.assertTrue(task.shared)
@ -223,11 +256,12 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
self.assertFalse(release_mock.called)
node_get_mock.assert_called_once_with(self.context, 'fake-node-id')
get_ports_mock.assert_called_once_with(self.context, self.node.id)
get_portgroups_mock.assert_called_once_with(self.context, self.node.id)
get_driver_mock.assert_called_once_with(self.node.driver)
def test_shared_lock_with_driver(self, get_ports_mock, get_driver_mock,
reserve_mock, release_mock,
node_get_mock):
def test_shared_lock_with_driver(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
node_get_mock.return_value = self.node
with task_manager.TaskManager(self.context,
'fake-node-id',
@ -236,6 +270,7 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
self.assertEqual(self.context, task.context)
self.assertEqual(self.node, task.node)
self.assertEqual(get_ports_mock.return_value, task.ports)
self.assertEqual(get_portgroups_mock.return_value, task.portgroups)
self.assertEqual(get_driver_mock.return_value, task.driver)
self.assertTrue(task.shared)
@ -243,11 +278,12 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
self.assertFalse(release_mock.called)
node_get_mock.assert_called_once_with(self.context, 'fake-node-id')
get_ports_mock.assert_called_once_with(self.context, self.node.id)
get_portgroups_mock.assert_called_once_with(self.context, self.node.id)
get_driver_mock.assert_called_once_with('fake-driver')
def test_shared_lock_node_get_exception(self, get_ports_mock,
get_driver_mock, reserve_mock,
release_mock, node_get_mock):
def test_shared_lock_node_get_exception(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
node_get_mock.side_effect = exception.NodeNotFound(node='foo')
self.assertRaises(exception.NodeNotFound,
@ -260,11 +296,12 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
self.assertFalse(release_mock.called)
node_get_mock.assert_called_once_with(self.context, 'fake-node-id')
self.assertFalse(get_ports_mock.called)
self.assertFalse(get_portgroups_mock.called)
self.assertFalse(get_driver_mock.called)
def test_shared_lock_get_ports_exception(self, get_ports_mock,
get_driver_mock, reserve_mock,
release_mock, node_get_mock):
def test_shared_lock_get_ports_exception(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
node_get_mock.return_value = self.node
get_ports_mock.side_effect = exception.IronicException('foo')
@ -280,9 +317,27 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
get_ports_mock.assert_called_once_with(self.context, self.node.id)
self.assertFalse(get_driver_mock.called)
def test_shared_lock_get_driver_exception(self, get_ports_mock,
get_driver_mock, reserve_mock,
release_mock, node_get_mock):
def test_shared_lock_get_portgroups_exception(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
node_get_mock.return_value = self.node
get_portgroups_mock.side_effect = exception.IronicException('foo')
self.assertRaises(exception.IronicException,
task_manager.TaskManager,
self.context,
'fake-node-id',
shared=True)
self.assertFalse(reserve_mock.called)
self.assertFalse(release_mock.called)
node_get_mock.assert_called_once_with(self.context, 'fake-node-id')
get_portgroups_mock.assert_called_once_with(self.context, self.node.id)
self.assertFalse(get_driver_mock.called)
def test_shared_lock_get_driver_exception(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
node_get_mock.return_value = self.node
get_driver_mock.side_effect = (
exception.DriverNotFound(driver_name='foo'))
@ -297,10 +352,12 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
self.assertFalse(release_mock.called)
node_get_mock.assert_called_once_with(self.context, 'fake-node-id')
get_ports_mock.assert_called_once_with(self.context, self.node.id)
get_portgroups_mock.assert_called_once_with(self.context, self.node.id)
get_driver_mock.assert_called_once_with(self.node.driver)
def test_upgrade_lock(self, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
def test_upgrade_lock(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
node_get_mock.return_value = self.node
reserve_mock.return_value = self.node
with task_manager.TaskManager(self.context, 'fake-node-id',
@ -308,6 +365,7 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
self.assertEqual(self.context, task.context)
self.assertEqual(self.node, task.node)
self.assertEqual(get_ports_mock.return_value, task.ports)
self.assertEqual(get_portgroups_mock.return_value, task.portgroups)
self.assertEqual(get_driver_mock.return_value, task.driver)
self.assertTrue(task.shared)
self.assertFalse(reserve_mock.called)
@ -325,10 +383,12 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
self.node.id)
node_get_mock.assert_called_once_with(self.context, 'fake-node-id')
get_ports_mock.assert_called_once_with(self.context, self.node.id)
get_portgroups_mock.assert_called_once_with(self.context, self.node.id)
get_driver_mock.assert_called_once_with(self.node.driver)
def test_spawn_after(self, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
def test_spawn_after(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
thread_mock = mock.Mock(spec_set=['link', 'cancel'])
spawn_mock = mock.Mock(return_value=thread_mock)
task_release_mock = mock.Mock()
@ -347,11 +407,9 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
# thread
self.assertFalse(task_release_mock.called)
def test_spawn_after_exception_while_yielded(self, get_ports_mock,
get_driver_mock,
reserve_mock,
release_mock,
node_get_mock):
def test_spawn_after_exception_while_yielded(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
spawn_mock = mock.Mock()
task_release_mock = mock.Mock()
reserve_mock.return_value = self.node
@ -366,9 +424,9 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
self.assertFalse(spawn_mock.called)
task_release_mock.assert_called_once_with()
def test_spawn_after_spawn_fails(self, get_ports_mock, get_driver_mock,
reserve_mock, release_mock,
node_get_mock):
def test_spawn_after_spawn_fails(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
spawn_mock = mock.Mock(side_effect=exception.IronicException('foo'))
task_release_mock = mock.Mock()
reserve_mock.return_value = self.node
@ -383,9 +441,9 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
spawn_mock.assert_called_once_with(1, 2, foo='bar', cat='meow')
task_release_mock.assert_called_once_with()
def test_spawn_after_link_fails(self, get_ports_mock, get_driver_mock,
reserve_mock, release_mock,
node_get_mock):
def test_spawn_after_link_fails(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
thread_mock = mock.Mock(spec_set=['link', 'cancel'])
thread_mock.link.side_effect = exception.IronicException('foo')
spawn_mock = mock.Mock(return_value=thread_mock)
@ -405,9 +463,9 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
thread_mock.cancel.assert_called_once_with()
task_release_mock.assert_called_once_with()
def test_spawn_after_on_error_hook(self, get_ports_mock, get_driver_mock,
reserve_mock, release_mock,
node_get_mock):
def test_spawn_after_on_error_hook(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
expected_exception = exception.IronicException('foo')
spawn_mock = mock.Mock(side_effect=expected_exception)
task_release_mock = mock.Mock()
@ -427,9 +485,9 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
on_error_handler.assert_called_once_with(expected_exception,
'fake-argument')
def test_spawn_after_on_error_hook_exception(self, get_ports_mock,
get_driver_mock, reserve_mock,
release_mock, node_get_mock):
def test_spawn_after_on_error_hook_exception(
self, get_portgroups_mock, get_ports_mock, get_driver_mock,
reserve_mock, release_mock, node_get_mock):
expected_exception = exception.IronicException('foo')
spawn_mock = mock.Mock(side_effect=expected_exception)
task_release_mock = mock.Mock()
@ -454,8 +512,8 @@ class TaskManagerTestCase(tests_db_base.DbTestCase):
@mock.patch.object(states.machine, 'copy')
def test_init_prepares_fsm(
self, copy_mock, get_ports_mock, get_driver_mock, reserve_mock,
release_mock, node_get_mock):
self, copy_mock, get_portgroups_mock, get_ports_mock,
get_driver_mock, reserve_mock, release_mock, node_get_mock):
m = mock.Mock(spec=fsm.FSM)
reserve_mock.return_value = self.node
copy_mock.return_value = m
@ -481,6 +539,7 @@ class TaskManagerStateModelTestCases(tests_base.TestCase):
t.release_resources = task_manager.TaskManager.release_resources
t.driver = mock.Mock()
t.ports = mock.Mock()
t.portgroups = mock.Mock()
t.shared = True
t._purpose = 'purpose'
t._debug_timer = mock.Mock()
@ -489,6 +548,7 @@ class TaskManagerStateModelTestCases(tests_base.TestCase):
self.assertIsNone(t.node)
self.assertIsNone(t.driver)
self.assertIsNone(t.ports)
self.assertIsNone(t.portgroups)
self.assertIsNone(t.fsm)
def test_process_event_fsm_raises(self):