diff --git a/ironic/conductor/manager.py b/ironic/conductor/manager.py index db2d85b6cb..187b25a17d 100644 --- a/ironic/conductor/manager.py +++ b/ironic/conductor/manager.py @@ -1202,14 +1202,12 @@ class ConductorManager(periodic_task.PeriodicTasks): node_iter = self.iter_nodes( fields=['id', 'reservation'], filters={'provision_state': states.DEPLOYING, - 'maintenance': False}) + 'maintenance': False, + 'reserved_by_any_of': offline_conductors}) if not node_iter: return for node_uuid, driver, node_id, conductor_hostname in node_iter: - if conductor_hostname not in offline_conductors: - continue - # NOTE(lucasagomes): Although very rare, this may lead to a # race condition. By the time we release the lock the conductor # that was previously managing the node could be back online. diff --git a/ironic/db/api.py b/ironic/db/api.py index a9f39c22f9..e80b5ad33f 100644 --- a/ironic/db/api.py +++ b/ironic/db/api.py @@ -56,6 +56,7 @@ class Connection(object): :associated: True | False :reserved: True | False + :reserved_by_any_of: [conductor1, conductor2] :maintenance: True | False :chassis_uuid: uuid of chassis :driver: driver's name diff --git a/ironic/db/sqlalchemy/api.py b/ironic/db/sqlalchemy/api.py index 12fb55edf8..6f0ecf9279 100644 --- a/ironic/db/sqlalchemy/api.py +++ b/ironic/db/sqlalchemy/api.py @@ -168,6 +168,9 @@ class Connection(api.Connection): query = query.filter(models.Node.reservation != sql.null()) else: query = query.filter(models.Node.reservation == sql.null()) + if 'reserved_by_any_of' in filters: + query = query.filter(models.Node.reservation.in_( + filters['reserved_by_any_of'])) if 'maintenance' in filters: query = query.filter_by(maintenance=filters['maintenance']) if 'driver' in filters: diff --git a/ironic/tests/db/test_nodes.py b/ironic/tests/db/test_nodes.py index 021934c35a..2249060052 100644 --- a/ironic/tests/db/test_nodes.py +++ b/ironic/tests/db/test_nodes.py @@ -113,9 +113,14 @@ class DbNodeTestCase(base.DbTestCase): driver='driver-two', uuid=uuidutils.generate_uuid(), maintenance=True) + node3 = utils.create_test_node( + driver='driver-one', + uuid=uuidutils.generate_uuid(), + reservation='another-fake-host') res = self.dbapi.get_nodeinfo_list(filters={'driver': 'driver-one'}) - self.assertEqual([node1.id], [r[0] for r in res]) + self.assertEqual(sorted([node1.id, node3.id]), + sorted([r[0] for r in res])) res = self.dbapi.get_nodeinfo_list(filters={'driver': 'bad-driver'}) self.assertEqual([], [r[0] for r in res]) @@ -124,10 +129,12 @@ class DbNodeTestCase(base.DbTestCase): self.assertEqual([node1.id], [r[0] for r in res]) res = self.dbapi.get_nodeinfo_list(filters={'associated': False}) - self.assertEqual([node2.id], [r[0] for r in res]) + self.assertEqual(sorted([node2.id, node3.id]), + sorted([r[0] for r in res])) res = self.dbapi.get_nodeinfo_list(filters={'reserved': True}) - self.assertEqual([node1.id], [r[0] for r in res]) + self.assertEqual(sorted([node1.id, node3.id]), + sorted([r[0] for r in res])) res = self.dbapi.get_nodeinfo_list(filters={'reserved': False}) self.assertEqual([node2.id], [r[0] for r in res]) @@ -136,7 +143,14 @@ class DbNodeTestCase(base.DbTestCase): self.assertEqual([node2.id], [r.id for r in res]) res = self.dbapi.get_node_list(filters={'maintenance': False}) - self.assertEqual([node1.id], [r.id for r in res]) + self.assertEqual(sorted([node1.id, node3.id]), + sorted([r.id for r in res])) + + res = self.dbapi.get_node_list( + filters={'reserved_by_any_of': ['fake-host', + 'another-fake-host']}) + self.assertEqual(sorted([node1.id, node3.id]), + sorted([r.id for r in res])) @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_get_nodeinfo_list_provision(self, mock_utcnow):