Select the right lb_network_ip interface using AZ

If the AZ system is being used and there is also a default boot network
set in the main config, the nova driver would not pick the right
interface when translating the amphora info for amps in custom AZs.

This affects the step that fetches the lb_network_ip (the management
address) from nova, immediately before the step that updates the
database with the correct IP. That IP is then used in the rest of the
amphora creation flow, which pulls in that address and uses it to
connect to the amp.

Change-Id: Ie4869035a557ebcddea2fce693067c82fbd2d2a9
This commit is contained in:
Adam Harwell 2020-01-29 22:49:52 -08:00
parent e0ae8a3cac
commit 2c76209003
11 changed files with 99 additions and 48 deletions

View File

@ -69,10 +69,11 @@ class ComputeBase(object):
"""
@abc.abstractmethod
def get_amphora(self, compute_id):
def get_amphora(self, compute_id, management_network_id=None):
"""Retrieve an amphora object
:param compute_id: the id of the desired amphora
:param compute_id: the compute id of the desired amphora
:param management_network_id: ID of the management network
:returns: the amphora object
:returns: fault message or None
"""

View File

@ -63,10 +63,11 @@ class NoopManager(object):
self.computeconfig[compute_id] = (compute_id, 'status')
return constants.UP
def get_amphora(self, compute_id):
LOG.debug("Compute %s no-op, compute_id %s",
self.__class__.__name__, compute_id)
self.computeconfig[compute_id] = (compute_id, 'get_amphora')
def get_amphora(self, compute_id, management_network_id=None):
LOG.debug("Compute %s no-op, compute_id %s, management_network_id %s",
self.__class__.__name__, compute_id, management_network_id)
self.computeconfig[(compute_id, management_network_id)] = (
compute_id, management_network_id, 'get_amphora')
return data_models.Amphora(
compute_id=compute_id,
status=constants.ACTIVE,
@ -143,8 +144,8 @@ class NoopComputeDriver(driver_base.ComputeBase):
def status(self, compute_id):
return self.driver.status(compute_id)
def get_amphora(self, compute_id):
return self.driver.get_amphora(compute_id)
def get_amphora(self, compute_id, management_network_id=None):
return self.driver.get_amphora(compute_id, management_network_id)
def create_server_group(self, name, policy):
return self.driver.create_server_group(name, policy)

View File

@ -218,10 +218,11 @@ class VirtualMachineManager(compute_base.ComputeBase):
raise exceptions.ComputeStatusException()
return constants.DOWN
def get_amphora(self, compute_id):
def get_amphora(self, compute_id, management_network_id=None):
'''Retrieve the information in nova of a virtual machine.
:param amphora_id: virtual machine UUID
:param compute_id: virtual machine UUID
:param management_network_id: ID of the management network
:returns: an amphora object
:returns: fault message or None
'''
@ -231,12 +232,13 @@ class VirtualMachineManager(compute_base.ComputeBase):
except Exception:
LOG.exception("Error retrieving nova virtual machine.")
raise exceptions.ComputeGetException()
return self._translate_amphora(amphora)
return self._translate_amphora(amphora, management_network_id)
def _translate_amphora(self, nova_response):
def _translate_amphora(self, nova_response, management_network_id=None):
'''Convert a nova virtual machine into an amphora object.
:param nova_response: JSON response from nova
:param management_network_id: ID of the management network
:returns: an amphora object
:returns: fault message or None
'''
@ -246,19 +248,19 @@ class VirtualMachineManager(compute_base.ComputeBase):
lb_network_ip = None
availability_zone = None
image_id = None
fault = None
if management_network_id:
boot_networks = [management_network_id]
else:
boot_networks = CONF.controller_worker.amp_boot_network_list
try:
inf_list = nova_response.interface_list()
no_boot_networks = (
not CONF.controller_worker.amp_boot_network_list)
for interface in inf_list:
net_id = interface.net_id
is_boot_network = (
net_id in CONF.controller_worker.amp_boot_network_list)
# Pick the first fixed_ip if this is a boot network or if
# there are no boot networks configured (use default network)
if is_boot_network or no_boot_networks:
if net_id in boot_networks or not boot_networks:
lb_network_ip = interface.fixed_ips[0]['ip_address']
break
try:

View File

@ -193,7 +193,8 @@ class AmphoraFlows(object):
requires=(constants.AMPHORA_ID, constants.COMPUTE_ID)))
create_amp_for_lb_subflow.add(compute_tasks.ComputeActiveWait(
name=sf_name + '-' + constants.COMPUTE_WAIT,
requires=(constants.COMPUTE_ID, constants.AMPHORA_ID),
requires=(constants.COMPUTE_ID, constants.AMPHORA_ID,
constants.AVAILABILITY_ZONE),
provides=constants.COMPUTE_OBJ))
create_amp_for_lb_subflow.add(database_tasks.UpdateAmphoraInfo(
name=sf_name + '-' + constants.UPDATE_AMPHORA_INFO,

View File

@ -204,14 +204,18 @@ class ComputeDelete(BaseComputeTask):
class ComputeActiveWait(BaseComputeTask):
"""Wait for the compute driver to mark the amphora active."""
def execute(self, compute_id, amphora_id):
def execute(self, compute_id, amphora_id, availability_zone):
"""Wait for the compute driver to mark the amphora active
:raises: Generic exception if the amphora is not active
:returns: An amphora object
"""
if availability_zone:
amp_network = availability_zone.get(constants.MANAGEMENT_NETWORK)
else:
amp_network = None
for i in range(CONF.controller_worker.amp_active_retries):
amp, fault = self.compute.get_amphora(compute_id)
amp, fault = self.compute.get_amphora(compute_id, amp_network)
if amp.status == constants.ACTIVE:
if CONF.haproxy_amphora.build_rate_limit != -1:
self.rate_limit.remove_from_build_req_queue(amphora_id)

View File

@ -200,7 +200,8 @@ class AmphoraFlows(object):
requires=(constants.AMPHORA_ID, constants.COMPUTE_ID)))
create_amp_for_lb_subflow.add(compute_tasks.ComputeActiveWait(
name=sf_name + '-' + constants.COMPUTE_WAIT,
requires=(constants.COMPUTE_ID, constants.AMPHORA_ID),
requires=(constants.COMPUTE_ID, constants.AMPHORA_ID,
constants.AVAILABILITY_ZONE),
provides=constants.COMPUTE_OBJ))
create_amp_for_lb_subflow.add(database_tasks.UpdateAmphoraInfo(
name=sf_name + '-' + constants.UPDATE_AMPHORA_INFO,

View File

@ -59,6 +59,8 @@ class ComputeCreate(BaseComputeTask):
availability_zone=None):
"""Create an amphora
:param availability_zone: availability zone metadata dictionary
:returns: an amphora
"""
ports = ports or []
@ -156,6 +158,8 @@ class CertComputeCreate(ComputeCreate):
availability_zone=None):
"""Create an amphora
:param availability_zone: availability zone metadata dictionary
:returns: an amphora
"""
@ -211,14 +215,22 @@ class ComputeDelete(BaseComputeTask):
class ComputeActiveWait(BaseComputeTask):
"""Wait for the compute driver to mark the amphora active."""
def execute(self, compute_id, amphora_id):
def execute(self, compute_id, amphora_id, availability_zone):
"""Wait for the compute driver to mark the amphora active
:param compute_id: virtual machine UUID
:param amphora_id: id of the amphora object
:param availability_zone: availability zone metadata dictionary
:raises: Generic exception if the amphora is not active
:returns: An amphora object
"""
if availability_zone:
amp_network = availability_zone.get(constants.MANAGEMENT_NETWORK)
else:
amp_network = None
for i in range(CONF.controller_worker.amp_active_retries):
amp, fault = self.compute.get_amphora(compute_id)
amp, fault = self.compute.get_amphora(compute_id, amp_network)
if amp.status == constants.ACTIVE:
if CONF.haproxy_amphora.build_rate_limit != -1:
self.rate_limit.remove_from_build_req_queue(amphora_id)

View File

@ -88,10 +88,12 @@ class TestNoopComputeDriver(base.TestCase):
self.amphora_id])
def test_get_amphora(self):
self.driver.get_amphora(self.amphora_id)
self.assertEqual((self.amphora_id, 'get_amphora'),
self.driver.driver.computeconfig[
self.amphora_id])
management_network_id = uuidutils.generate_uuid()
self.driver.get_amphora(self.amphora_id, management_network_id)
self.assertEqual(
(self.amphora_id, management_network_id, 'get_amphora'),
self.driver.driver.computeconfig[
self.amphora_id, management_network_id])
def test_create_server_group(self):
self.driver.create_server_group(self.server_group_name,

View File

@ -434,15 +434,23 @@ class TestComputeTasks(base.TestCase):
mock_driver.get_amphora.return_value = _amphora_mock, None
computewait = compute_tasks.ComputeActiveWait()
computewait.execute(COMPUTE_ID, AMPHORA_ID)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID)
# Test with no AZ
computewait.execute(COMPUTE_ID, AMPHORA_ID, None)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID, None)
# Test with AZ
mock_driver.reset_mock()
az = {constants.MANAGEMENT_NETWORK: uuidutils.generate_uuid()}
computewait.execute(COMPUTE_ID, AMPHORA_ID, az)
mock_driver.get_amphora.assert_called_once_with(
COMPUTE_ID, az[constants.MANAGEMENT_NETWORK])
# Test with deleted amp
_amphora_mock.status = constants.DELETED
self.assertRaises(exceptions.ComputeWaitTimeoutException,
computewait.execute,
_amphora_mock, AMPHORA_ID)
_amphora_mock, AMPHORA_ID, None)
@mock.patch('octavia.controller.worker.amphora_rate_limit'
'.AmphoraBuildRateLimit.remove_from_build_req_queue')
@ -461,15 +469,15 @@ class TestComputeTasks(base.TestCase):
mock_driver.get_amphora.return_value = _amphora_mock, None
computewait = compute_tasks.ComputeActiveWait()
computewait.execute(COMPUTE_ID, AMPHORA_ID)
computewait.execute(COMPUTE_ID, AMPHORA_ID, None)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID, None)
_amphora_mock.status = constants.ERROR
self.assertRaises(exceptions.ComputeBuildException,
computewait.execute,
_amphora_mock, AMPHORA_ID)
_amphora_mock, AMPHORA_ID, None)
@mock.patch('octavia.controller.worker.amphora_rate_limit'
'.AmphoraBuildRateLimit.remove_from_build_req_queue')
@ -486,9 +494,9 @@ class TestComputeTasks(base.TestCase):
mock_driver.get_amphora.return_value = _amphora_mock, None
computewait = compute_tasks.ComputeActiveWait()
computewait.execute(COMPUTE_ID, AMPHORA_ID)
computewait.execute(COMPUTE_ID, AMPHORA_ID, None)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID, None)
mock_remove_from_build_queue.assert_not_called()
@mock.patch('stevedore.driver.DriverManager.driver')

View File

@ -54,10 +54,15 @@ class TestAmphoraFlows(base.TestCase):
self.assertIn(constants.AMPHORA, amp_flow.provides)
self.assertIn(constants.AMPHORA_ID, amp_flow.provides)
self.assertIn(constants.COMPUTE_ID, amp_flow.provides)
self.assertIn(constants.COMPUTE_OBJ, amp_flow.provides)
self.assertIn(constants.SERVER_PEM, amp_flow.provides)
self.assertIn(constants.BUILD_TYPE_PRIORITY, amp_flow.requires)
self.assertIn(constants.FLAVOR, amp_flow.requires)
self.assertIn(constants.AVAILABILITY_ZONE, amp_flow.requires)
self.assertEqual(5, len(amp_flow.provides))
self.assertEqual(2, len(amp_flow.requires))
self.assertEqual(3, len(amp_flow.requires))
def test_get_create_amphora_flow_cert(self, mock_get_net_driver):
self.AmpFlow = amphora_flows.AmphoraFlows()
@ -69,9 +74,15 @@ class TestAmphoraFlows(base.TestCase):
self.assertIn(constants.AMPHORA, amp_flow.provides)
self.assertIn(constants.AMPHORA_ID, amp_flow.provides)
self.assertIn(constants.COMPUTE_ID, amp_flow.provides)
self.assertIn(constants.COMPUTE_OBJ, amp_flow.provides)
self.assertIn(constants.SERVER_PEM, amp_flow.provides)
self.assertIn(constants.BUILD_TYPE_PRIORITY, amp_flow.requires)
self.assertIn(constants.FLAVOR, amp_flow.requires)
self.assertIn(constants.AVAILABILITY_ZONE, amp_flow.requires)
self.assertEqual(5, len(amp_flow.provides))
self.assertEqual(2, len(amp_flow.requires))
self.assertEqual(3, len(amp_flow.requires))
def test_get_create_amphora_for_lb_flow(self, mock_get_net_driver):

View File

@ -447,15 +447,23 @@ class TestComputeTasks(base.TestCase):
mock_driver.get_amphora.return_value = _db_amphora_mock, None
computewait = compute_tasks.ComputeActiveWait()
computewait.execute(COMPUTE_ID, AMPHORA_ID)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID)
# Test with no AZ
computewait.execute(COMPUTE_ID, AMPHORA_ID, None)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID, None)
# Test with AZ
mock_driver.reset_mock()
az = {constants.MANAGEMENT_NETWORK: uuidutils.generate_uuid()}
computewait.execute(COMPUTE_ID, AMPHORA_ID, az)
mock_driver.get_amphora.assert_called_once_with(
COMPUTE_ID, az[constants.MANAGEMENT_NETWORK])
# Test with deleted amp
_db_amphora_mock.status = constants.DELETED
self.assertRaises(exceptions.ComputeWaitTimeoutException,
computewait.execute,
_db_amphora_mock, AMPHORA_ID)
_amphora_mock, AMPHORA_ID, None)
@mock.patch('octavia.controller.worker.amphora_rate_limit'
'.AmphoraBuildRateLimit.remove_from_build_req_queue')
@ -474,15 +482,15 @@ class TestComputeTasks(base.TestCase):
mock_driver.get_amphora.return_value = _db_amphora_mock, None
computewait = compute_tasks.ComputeActiveWait()
computewait.execute(COMPUTE_ID, AMPHORA_ID)
computewait.execute(COMPUTE_ID, AMPHORA_ID, None)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID, None)
_db_amphora_mock.status = constants.ERROR
self.assertRaises(exceptions.ComputeBuildException,
computewait.execute,
_db_amphora_mock, AMPHORA_ID)
_db_amphora_mock, AMPHORA_ID, None)
@mock.patch('octavia.controller.worker.amphora_rate_limit'
'.AmphoraBuildRateLimit.remove_from_build_req_queue')
@ -499,9 +507,9 @@ class TestComputeTasks(base.TestCase):
mock_driver.get_amphora.return_value = _db_amphora_mock, None
computewait = compute_tasks.ComputeActiveWait()
computewait.execute(COMPUTE_ID, AMPHORA_ID)
computewait.execute(COMPUTE_ID, AMPHORA_ID, None)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID)
mock_driver.get_amphora.assert_called_once_with(COMPUTE_ID, None)
mock_remove_from_build_queue.assert_not_called()
@mock.patch('stevedore.driver.DriverManager.driver')