diff --git a/metalsmith/_provisioner.py b/metalsmith/_provisioner.py index f37cc71..2b26d38 100644 --- a/metalsmith/_provisioner.py +++ b/metalsmith/_provisioner.py @@ -50,6 +50,8 @@ class Provisioner(object): OpenStack API during provisioning. """ + allocations_cache = dict() + def __init__(self, session=None, cloud_region=None, dry_run=False): if cloud_region is None: if session is None: @@ -630,6 +632,8 @@ class Provisioner(object): :return: list of :py:class:`metalsmith.Instance` objects. """ nodes = self.connection.baremetal.nodes(associated=True, details=True) + Provisioner.allocations_cache = { + a.id: a for a in self.connection.baremetal.allocations()} instances = [i for i in map(self._get_instance, nodes) if i.state != _instance.InstanceState.UNKNOWN] return instances @@ -678,13 +682,24 @@ class Provisioner(object): 'with a node' % node) def _get_instance(self, ident): - node, allocation = self._find_node_and_allocation(ident) - if allocation is None and node.allocation_id: + if hasattr(ident, 'allocation_id'): + node = ident try: - allocation = self.connection.baremetal.get_allocation( - node.allocation_id) + try: + allocation = Provisioner.allocations_cache[ + node.instance_id] + except KeyError: + allocation = self.connection.baremetal.get_allocation( + node.allocation_id) except os_exc.ResourceNotFound as exc: raise exceptions.InstanceNotFound(str(exc)) - + else: + node, allocation = self._find_node_and_allocation(ident) + if allocation is None and node.allocation_id: + try: + allocation = self.connection.baremetal.get_allocation( + node.allocation_id) + except os_exc.ResourceNotFound as exc: + raise exceptions.InstanceNotFound(str(exc)) return _instance.Instance(self.connection, node, allocation=allocation) diff --git a/metalsmith/test/test_provisioner.py b/metalsmith/test/test_provisioner.py index 53a3e4a..49dcb45 100644 --- a/metalsmith/test/test_provisioner.py +++ b/metalsmith/test/test_provisioner.py @@ -32,6 +32,7 @@ NODE_FIELDS = ['name', 'id', 'instance_info', 'instance_id', 'is_maintenance', 'maintenance_reason', 'properties', 'provision_state', 'extra', 'last_error', 'traits', 'resource_class', 'conductor_group', 'allocation_id'] +ALLOCATION_FIELDS = ['id', 'name', 'node_id'] class TestInit(unittest.TestCase): @@ -2073,14 +2074,16 @@ class TestListInstances(Base): self.nodes[0].allocation_id = 'id2' self.nodes[6].instance_id = None self.api.baremetal.nodes.return_value = self.nodes + self.allocations = [mock.Mock(id='id2')] + self.api.baremetal.allocations.return_value = self.allocations def test_list(self): instances = self.pr.list_instances() self.assertTrue(all(isinstance(i, _instance.Instance) for i in instances)) self.assertEqual(self.nodes[:6], [i.node for i in instances]) - self.assertEqual([self.api.baremetal.get_allocation.return_value] - + [None] * 5, + self.assertEqual([self.api.baremetal.get_allocation.return_value] * 6, [i.allocation for i in instances]) self.api.baremetal.nodes.assert_called_once_with(associated=True, details=True) + self.api.baremetal.allocations.assert_called_once()