Convert get_hypervisor_ip to use hostnames

Instead of using ID to lookup hypervisor IPs, use hostnames. IDs are
different in undercloud and overcloud (a compute node's Ironic node
UUID in the undercloud isn't the same as its hypervisor UUID in the
overcloud). In addition, Nova uses both integer IDs (before 2.53) and
UUIDs (2.53 and later) for hypervisors. Hostnames are common to both
undercloud and overcloud, and don't change depending on the
microversion.

Change-Id: I34445e0f566dd48271740c357f74f632152776ed
This commit is contained in:
Artom Lifshitz 2018-07-16 13:15:03 -04:00
parent b668dcea44
commit a2d308991e
4 changed files with 32 additions and 74 deletions

View File

@ -50,10 +50,8 @@ class PointerDeviceTypeFromImages(base.BaseTest):
def _verify_pointer_device_type_from_images(self, server_id):
# Retrieve the server's hypervizor hostname
server = self.servers_client.show_server(server_id)['server']
hostname = server['OS-EXT-SRV-ATTR:host']
compute_node_address = whitebox_utils.get_hypervisor_ip(
self.hypervisor_client, hostname)
self.servers_client, server_id)
self.assertIsNotNone(compute_node_address)
# Retrieve input device from virsh dumpxml

View File

@ -21,39 +21,11 @@ CONF = config.CONF
LOG = logging.getLogger(__name__)
def _get_hv_ip_from_conf(id):
conf_hvs = CONF.whitebox.hypervisors
if conf_hvs:
return conf_hvs.get(id)
def get_hypervisor_ip(client, hostname):
"""Get the IP for a comute node's hypervisor.
Finds the IP address of a compute node based on its hostname. This is
necessary in case a compute node isn't accessible by its IP address as it
appears in the nova API. Such a situation arises in infrared deployments of
OSP12, for example.
:param client: The hypervisors client to use.
:param hostname: The compute node's hostname, from the instance's
``OS-EXT-SRV-ATTR:host`` attribute.
:return: The IP address of the compute node - either as configuired in the
hypervisors section of our config file, or as returned by the nova API
as fallback.
"""
hvs = client.list_hypervisors(detail=True)['hypervisors']
compute_node_address = None
for hv in hvs:
if hv['service']['host'] == hostname:
hv_ip = _get_hv_ip_from_conf(str(hv['id']))
if hv_ip:
compute_node_address = hv_ip
LOG.info('Using %s for hypervisor %s from config file',
hv_ip, hv['id'])
else:
compute_node_address = hv['host_ip']
LOG.info('Using %s as fallback since hypervisor %s not in '
'config file', compute_node_address, hv['id'])
return compute_node_address
def get_hypervisor_ip(admin_servers_client, server_id):
server = admin_servers_client.show_server(server_id)
host = server['server']['OS-EXT-SRV-ATTR:host']
try:
return CONF.whitebox.hypervisors[host]
except KeyError:
LOG.error('Unable to find IP in conf. Server: %s, host: %s.',
(server_id, host))

View File

@ -39,9 +39,11 @@ opts = [
help='Deployment is containerized.'),
cfg.DictOpt(
'hypervisors',
help="Dictionary of hypervisor IP addresses, in the "
"id => IP format. Should be used when the IP returned "
"by 'nova hypervisor-show' isn't reachable from the "
"node running tempest. Starting with microversion "
"2.53, the id is a UUID."),
help="Dictionary of hypervisor IP addresses. The keys are the "
"hostnames as they appear in the OS-EXT-SRV-ATTR:host field of "
"Nova's show server details API. The values are the ctlplane IP "
"addresses. For example:"
""
" hypervisors = compute-0.localdomain:172.16.42.11,"
" controller-0.localdomain:172.16.42.10"),
]

View File

@ -18,40 +18,26 @@ from whitebox_tempest_plugin.common import utils
from whitebox_tempest_plugin.tests import base
def fake_show_server(server_id):
if server_id == 'fake-id':
return {'server': {'OS-EXT-SRV-ATTR:host': 'fake-host'}}
else:
return {'server': {'OS-EXT-SRV-ATTR:host': 'missing-host'}}
class UtilsTestCase(base.WhiteboxPluginTestCase):
def setUp(self):
super(UtilsTestCase, self).setUp()
self.client = mock.Mock()
fake_hvs = {
'hypervisors': [
{'service': {'host': 'host1'},
'host_ip': '192.168.0.1',
'id': 1},
{'service': {'host': 'host2'},
'host_ip': '192.168.0.2',
'id': 2},
{'service': {'host': 'host3'},
'host_ip': '192.168.0.3',
'id': 3}
]
}
self.client.list_hypervisors = mock.Mock(return_value=fake_hvs)
self.client.show_server = fake_show_server
self.flags(hypervisors={'fake-host': 'fake-ip'}, group='whitebox')
@mock.patch.object(utils.LOG, 'info')
def test_get_hypervisor_ip_hv_in_config(self, mock_log):
self.flags(hypervisors={'1': '10.0.0.1'}, group='whitebox')
self.assertEqual('10.0.0.1',
utils.get_hypervisor_ip(self.client, 'host1'))
self.assertIn('from config file', mock_log.call_args_list[0][0][0])
def test_get_hypervisor_ip(self):
self.assertEqual('fake-ip',
utils.get_hypervisor_ip(self.client, 'fake-id'))
@mock.patch.object(utils.LOG, 'info')
def test_get_hypervisor_ip_hv_not_in_config(self, mock_log):
self.flags(hypervisors={'1': '10.0.0.1'}, group='whitebox')
self.assertEqual('192.168.0.2',
utils.get_hypervisor_ip(self.client, 'host2'))
self.assertIn('not in config file', mock_log.call_args_list[0][0][0])
def test_get_hypervisor_ip_no_hvs_in_config(self):
self.assertEqual('192.168.0.3',
utils.get_hypervisor_ip(self.client, 'host3'))
@mock.patch.object(utils.LOG, 'error')
def test_get_hypervisor_ip_keyerror(self, mock_log):
self.assertIsNone(utils.get_hypervisor_ip(self.client, 'missing-id'))
self.assertIn('Unable', mock_log.call_args_list[0][0][0])