From 63285645c72d3a5dcb232b5a129cf99602f2a607 Mon Sep 17 00:00:00 2001 From: Devananda van der Veen Date: Sun, 10 Feb 2013 12:49:53 -0800 Subject: Baremetal driver returns accurate list of instance Add 'instance_name' to bm_nodes table so that baremetal driver is able to return the names of all instances it believes are still running. Previously, baremetal.driver.list_instances was fetching all allocated instances from baremetal database, then calling VirtAPI to get the instance name. This would raise an InstanceNotFound exception for deleted instances. This prevented ComputeManager from ever detecting a running-but-deleted baremetal instance, and could leave baremetal instances in an undeletable state. Fixes bug 1096723. Change-Id: Ifae532e8e70e97e48c589608cb3c7000bb6a7609 --- nova/tests/baremetal/test_driver.py | 47 ++++++++++++++++++++++ .../versions/004_add_instance_name_to_bm_nodes.py | 37 +++++++++++++++++ nova/virt/baremetal/db/sqlalchemy/models.py | 1 + nova/virt/baremetal/driver.py | 16 ++------ 4 files changed, 88 insertions(+), 13 deletions(-) create mode 100644 nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/004_add_instance_name_to_bm_nodes.py (limited to 'nova') diff --git a/nova/tests/baremetal/test_driver.py b/nova/tests/baremetal/test_driver.py index 160ca35df..8e23908f4 100644 --- a/nova/tests/baremetal/test_driver.py +++ b/nova/tests/baremetal/test_driver.py @@ -150,6 +150,7 @@ class BareMetalDriverWithDBTestCase(bm_db_base.BMDBTestCase): row = db.bm_node_get(self.context, node['node']['id']) self.assertEqual(row['task_state'], baremetal_states.ACTIVE) self.assertEqual(row['instance_uuid'], node['instance']['uuid']) + self.assertEqual(row['instance_name'], node['instance']['hostname']) def test_macs_for_instance(self): node = self._create_node() @@ -165,6 +166,12 @@ class BareMetalDriverWithDBTestCase(bm_db_base.BMDBTestCase): self.assertEqual( expected, self.driver.macs_for_instance(node['instance'])) + def test_macs_for_instance(self): + node = self._create_node() + expected = set(['01:23:45:67:89:01', '01:23:45:67:89:02']) + self.assertEqual( + expected, self.driver.macs_for_instance(node['instance'])) + def test_macs_for_instance_no_interfaces(self): # Nodes cannot boot with no MACs, so we raise an error if that happens. node = self._create_node(nic_info=[]) @@ -236,6 +243,7 @@ class BareMetalDriverWithDBTestCase(bm_db_base.BMDBTestCase): row = db.bm_node_get(self.context, node['node']['id']) self.assertEqual(row['task_state'], baremetal_states.DELETED) self.assertEqual(row['instance_uuid'], None) + self.assertEqual(row['instance_name'], None) def test_destroy_fails(self): node = self._create_node() @@ -308,3 +316,42 @@ class BareMetalDriverWithDBTestCase(bm_db_base.BMDBTestCase): self.assertEqual(2, len(self.driver.get_available_nodes())) self.assertEqual([node1['node']['uuid'], node2['node']['uuid']], self.driver.get_available_nodes()) + + def test_list_instances(self): + self.assertEqual([], self.driver.list_instances()) + + node1 = self._create_node() + self.assertEqual([], self.driver.list_instances()) + + node_info = bm_db_utils.new_bm_node( + id=456, + service_host='test_host', + cpus=2, + memory_mb=2048, + ) + nic_info = [ + {'address': 'cc:cc:cc', 'datapath_id': '0x1', + 'port_no': 1}, + {'address': 'dd:dd:dd', 'datapath_id': '0x2', + 'port_no': 2}, + ] + node2 = self._create_node(node_info=node_info, nic_info=nic_info) + self.assertEqual([], self.driver.list_instances()) + + node1['instance']['hostname'] = 'test-host-1' + node2['instance']['hostname'] = 'test-host-2' + + self.driver.spawn(**node1['spawn_params']) + self.assertEqual(['test-host-1'], + self.driver.list_instances()) + + self.driver.spawn(**node2['spawn_params']) + self.assertEqual(['test-host-1', 'test-host-2'], + self.driver.list_instances()) + + self.driver.destroy(**node1['destroy_params']) + self.assertEqual(['test-host-2'], + self.driver.list_instances()) + + self.driver.destroy(**node2['destroy_params']) + self.assertEqual([], self.driver.list_instances()) diff --git a/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/004_add_instance_name_to_bm_nodes.py b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/004_add_instance_name_to_bm_nodes.py new file mode 100644 index 000000000..68fbe0960 --- /dev/null +++ b/nova/virt/baremetal/db/sqlalchemy/migrate_repo/versions/004_add_instance_name_to_bm_nodes.py @@ -0,0 +1,37 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from sqlalchemy import Column, MetaData, String, Table + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + t = Table('bm_nodes', meta, autoload=True) + name_col = Column('instance_name', String(255)) + t.create_column(name_col) + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + t = Table('bm_nodes', meta, autoload=True) + name_col = Column('instance_name', String(length=255)) + + t.drop_column(name_col) diff --git a/nova/virt/baremetal/db/sqlalchemy/models.py b/nova/virt/baremetal/db/sqlalchemy/models.py index e1a8ebb3a..756376cb7 100644 --- a/nova/virt/baremetal/db/sqlalchemy/models.py +++ b/nova/virt/baremetal/db/sqlalchemy/models.py @@ -37,6 +37,7 @@ class BareMetalNode(BASE, models.NovaBase): uuid = Column(String(36)) service_host = Column(String(255)) instance_uuid = Column(String(36), nullable=True) + instance_name = Column(String(255), nullable=True) cpus = Column(Integer) memory_mb = Column(Integer) local_gb = Column(Integer) diff --git a/nova/virt/baremetal/driver.py b/nova/virt/baremetal/driver.py index b95a3ad61..8dff0a785 100755 --- a/nova/virt/baremetal/driver.py +++ b/nova/virt/baremetal/driver.py @@ -102,6 +102,7 @@ def _update_state(context, node, instance, state): values = {'task_state': state} if not instance: values['instance_uuid'] = None + values['instance_name'] = None db.bm_node_update(context, node['id'], values) @@ -170,19 +171,7 @@ class BareMetalDriver(driver.ComputeDriver): l = [] context = nova_context.get_admin_context() for node in db.bm_node_get_associated(context, service_host=CONF.host): - if not node['instance_uuid']: - # Not currently assigned to an instance. - continue - try: - inst = self.virtapi.instance_get_by_uuid( - context, node['instance_uuid']) - except exception.InstanceNotFound: - # Assigned to an instance that no longer exists. - LOG.warning(_("Node %(id)r assigned to instance %(uuid)r " - "which cannot be found."), - dict(id=node['id'], uuid=node['instance_uuid'])) - continue - l.append(inst['name']) + l.append(node['instance_name']) return l def _require_node(self, instance): @@ -244,6 +233,7 @@ class BareMetalDriver(driver.ComputeDriver): # allocates this node before we begin provisioning it. node = db.bm_node_associate_and_update(context, node_uuid, {'instance_uuid': instance['uuid'], + 'instance_name': instance['hostname'], 'task_state': baremetal_states.BUILDING}) try: -- cgit