Catch exception if servers are in error state with no bm_node attached

There have been reports (rhbz#1851507) where generating the fencing
parameters fails because of one or more servers in error state, like
when a scale out operation doesn't go as planned.

This commit wraps get_by_instance_uuid in a try/except block to prevent
this from happening, skipping the node in error state and allowing
users to still get a valid fencing config for the remaining servers.

Change-Id: I397f8d641504ac2ceed36fa975cf97fac5bbb81a
This commit is contained in:
Luca Miccini 2020-07-01 11:14:27 +02:00
parent d7dfc59b09
commit 7d2c25319b
2 changed files with 71 additions and 4 deletions

View File

@ -16,10 +16,12 @@ from unittest import mock
import yaml
from swiftclient import exceptions as swiftexceptions
from ironicclient import exceptions as ironicexceptions
from tripleo_common import constants
from tripleo_common.tests import base
from tripleo_common.utils import stack_parameters
from tripleo_common.utils import nodes
class StackParametersTest(base.TestCase):
@ -475,6 +477,64 @@ class StackParametersTest(base.TestCase):
result = stack_parameters.get_flattened_parameters(swift, mock_heat)
self.assertEqual(result, expected_value)
def test_generate_hostmap(self):
# two instances in 'nova list'.
# vm1 with id=123 and vm2 with id=234
server1 = mock.MagicMock()
server1.id = 123
server1.name = 'vm1'
server2 = mock.MagicMock()
server2.id = 234
server2.name = 'vm2'
servers = mock.MagicMock()
servers = [server1, server2]
compute_client = mock.MagicMock()
compute_client.servers.list.side_effect = (servers, )
# we assume instance id=123 has been provisioned using bm node 'bm1'
# while instance id=234 is in error state, so no bm node has been used
def side_effect(args):
if args == 123:
return bm1
elif args == 234:
raise ironicexceptions.NotFound
baremetal_client = mock.MagicMock()
baremetal_client.node.get_by_instance_uuid = mock.MagicMock(
side_effect=side_effect)
# bm server with name='bm1' and uuid='9876'
bm1 = mock.MagicMock()
bm1.uuid = 9876
bm1.name = 'bm1'
# 'bm1' has a single port with mac='aa:bb:cc:dd:ee:ff'
port1 = mock.MagicMock()
port1.address = 'aa:bb:cc:dd:ee:ff'
def side_effect2(node, *args):
if node == 9876:
return [port1, ]
else:
raise ironicexceptions.NotFound
baremetal_client.port.list = mock.MagicMock(side_effect=side_effect2)
expected_hostmap = {
'aa:bb:cc:dd:ee:ff': {
'compute_name': 'vm1',
'baremetal_name': 'bm1'
}
}
result = nodes.generate_hostmap(baremetal_client, compute_client)
self.assertEqual(result, expected_hostmap)
@mock.patch('tripleo_common.utils.nodes.generate_hostmap')
def test_generate_fencing_parameters(self, mock_generate_hostmap):
test_hostmap = {

View File

@ -19,6 +19,7 @@ import re
from oslo_utils import netutils
import six
from ironicclient import exceptions as ironicexceptions
from oslo_concurrency import processutils
from tripleo_common import exception
from tripleo_common.utils import glance
@ -708,10 +709,16 @@ def generate_hostmap(baremetal_client, compute_client):
"""Create a map between Compute nodes and Baremetal nodes"""
hostmap = {}
for node in compute_client.servers.list():
bm_node = baremetal_client.node.get_by_instance_uuid(node.id)
for port in baremetal_client.port.list(node=bm_node.uuid):
hostmap[port.address] = {"compute_name": node.name,
"baremetal_name": bm_node.name}
try:
bm_node = baremetal_client.node.get_by_instance_uuid(node.id)
for port in baremetal_client.port.list(node=bm_node.uuid):
hostmap[port.address] = {"compute_name": node.name,
"baremetal_name": bm_node.name}
except ironicexceptions.NotFound:
LOG.warning('Baremetal node for server %s not found - skipping it',
node.id)
pass
if hostmap == {}:
return None
else: