Refactor the AAP driver to not depend on nova

Replace calls to the nova client with calls to the compute driver.
This will help non vm efforts (e.g. zune) and also make the code
easier to break up later.

Change-Id: I7ee175c5ecb98af0ca5e299c2ac10e43eb40ed30
This commit is contained in:
German Eichberger 2018-09-20 14:32:41 -07:00 committed by German Eichberger
parent 7fa83ef8e6
commit 79cd851548
7 changed files with 197 additions and 68 deletions

View File

@ -96,3 +96,28 @@ class ComputeBase(object):
:param server_group_id: the uuid of a server group
"""
pass
@abc.abstractmethod
def attach_network_or_port(self, compute_id, network_id=None,
ip_address=None, port_id=None):
"""Connects an existing amphora to an existing network.
:param compute_id: id of an amphora in the compute service
:param network_id: id of a network
:param ip_address: ip address to attempt to be assigned to interface
:param port_id: id of the neutron port
:return: nova interface
:raises: Exception
"""
pass
@abc.abstractmethod
def detach_port(self, compute_id, port_id):
"""Disconnects an existing amphora from an existing port.
:param compute_id: id of an amphora in the compute service
:param port_id: id of the port
:return: None
:raises: Exception
"""
pass

View File

@ -18,6 +18,7 @@ from oslo_utils import uuidutils
from octavia.common import constants
from octavia.common import data_models
from octavia.compute import compute_base as driver_base
from octavia.network import data_models as network_models
LOG = logging.getLogger(__name__)
@ -81,6 +82,30 @@ class NoopManager(object):
self.__class__.__name__, server_group_id)
self.computeconfig[server_group_id] = (server_group_id, 'delete')
def attach_network_or_port(self, compute_id, network_id, ip_address=None,
port_id=None):
LOG.debug("Compute %s no-op, attach_network_or_port compute_id %s,"
"network_id %s, ip_address %s, port_id %s",
self.__class__.__name__, compute_id,
network_id, ip_address, port_id)
self.computeconfig[(compute_id, network_id, ip_address, port_id)] = (
compute_id, network_id, ip_address, port_id,
'attach_network_or_port')
return network_models.Interface(
id=uuidutils.generate_uuid(),
compute_id=compute_id,
network_id=network_id,
fixed_ips=[],
port_id=uuidutils.generate_uuid()
)
def detach_port(self, compute_id, port_id):
LOG.debug("Compute %s no-op, detach_network compute_id %s, "
"port_id %s",
self.__class__.__name__, compute_id, port_id)
self.computeconfig[(compute_id, port_id)] = (
compute_id, port_id, 'detach_port')
class NoopComputeDriver(driver_base.ComputeBase):
def __init__(self):
@ -114,3 +139,11 @@ class NoopComputeDriver(driver_base.ComputeBase):
def delete_server_group(self, server_group_id):
self.driver.delete_server_group(server_group_id)
def attach_network_or_port(self, compute_id, network_id, ip_address=None,
port_id=None):
self.driver.attach_network_or_port(compute_id, network_id, ip_address,
port_id)
def detach_port(self, compute_id, port_id):
self.driver.detach_port(compute_id, port_id)

View File

@ -24,6 +24,7 @@ from octavia.common import constants
from octavia.common import data_models as models
from octavia.common import exceptions
from octavia.compute import compute_base
from octavia.i18n import _
LOG = logging.getLogger(__name__)
@ -282,3 +283,46 @@ class VirtualMachineManager(compute_base.ComputeBase):
except Exception:
LOG.exception("Error delete server group instance.")
raise exceptions.ServerGroupObjectDeleteException()
def attach_network_or_port(self, compute_id, network_id, ip_address=None,
port_id=None):
"""Attaching a port or a network to an existing amphora
:param compute_id: id of an amphora in the compute service
:param network_id: id of a network
:param ip_address: ip address to attempt to be assigned to interface
:param port_id: id of the neutron port
:return: nova interface instance
:raises: Exception
"""
try:
interface = self.manager.interface_attach(
server=compute_id, net_id=network_id, fixed_ip=ip_address,
port_id=port_id)
except Exception:
message = _('Error attaching network {network_id} with ip '
'{ip_address} and port {port} to amphora '
'(compute_id: {compute_id}) ').format(
compute_id=compute_id,
network_id=network_id,
ip_address=ip_address,
port=port_id)
LOG.error(message)
raise
return interface
def detach_port(self, compute_id, port_id):
"""Detaches a port from an existing amphora.
:param compute_id: id of an amphora in the compute service
:param port_id: id of the port
:return: None
"""
try:
self.manager.interface_detach(server=compute_id,
port_id=port_id)
except Exception:
LOG.error('Error detaching port {port_id} from amphora '
'with compute ID {compute_id}. '
'Skipping.'.format(port_id=port_id,
compute_id=compute_id))

View File

@ -20,8 +20,8 @@ from novaclient import exceptions as nova_client_exceptions
from oslo_config import cfg
from oslo_log import log as logging
import six
from stevedore import driver as stevedore_driver
from octavia.common import clients
from octavia.common import constants
from octavia.common import data_models
from octavia.common import exceptions
@ -45,14 +45,11 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
def __init__(self):
super(AllowedAddressPairsDriver, self).__init__()
self._check_aap_loaded()
self.nova_client = clients.NovaAuth.get_nova_client(
endpoint=CONF.nova.endpoint,
region=CONF.nova.region_name,
endpoint_type=CONF.nova.endpoint_type,
service_name=CONF.nova.service_name,
insecure=CONF.nova.insecure,
cacert=CONF.nova.ca_certificates_file
)
self.compute = stevedore_driver.DriverManager(
namespace='octavia.compute.drivers',
name=CONF.controller_worker.compute_driver,
invoke_on_load=True
).driver
def _check_aap_loaded(self):
if not self._check_extension_enabled(AAP_EXT_ALIAS):
@ -481,9 +478,9 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
def plug_network(self, compute_id, network_id, ip_address=None):
try:
interface = self.nova_client.servers.interface_attach(
server=compute_id, net_id=network_id, fixed_ip=ip_address,
port_id=None)
interface = self.compute.attach_network_or_port(
compute_id=compute_id, network_id=network_id,
ip_address=ip_address)
except nova_client_exceptions.NotFound as e:
if 'Instance' in str(e):
raise base.AmphoraNotFound(str(e))
@ -511,14 +508,8 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
unpluggers = self._get_interfaces_to_unplug(interfaces, network_id,
ip_address=ip_address)
for index, unplugger in enumerate(unpluggers):
try:
self.nova_client.servers.interface_detach(
server=compute_id, port_id=unplugger.port_id)
except Exception:
LOG.warning('Error unplugging port {port_id} from amphora '
'with compute ID {compute_id}. '
'Skipping.'.format(port_id=unplugger.port_id,
compute_id=compute_id))
self.compute.detach_port(
compute_id=compute_id, port_id=unplugger.port_id)
def update_vip(self, load_balancer, for_delete=False):
sec_grp = self._get_lb_security_group(load_balancer.id)
@ -561,9 +552,9 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
def plug_port(self, amphora, port):
try:
interface = self.nova_client.servers.interface_attach(
server=amphora.compute_id, net_id=None,
fixed_ip=None, port_id=port.id)
interface = self.compute.attach_network_or_port(
compute_id=amphora.compute_id, network_id=None,
ip_address=None, port_id=port.id)
plugged_interface = self._nova_interface_to_octavia_interface(
amphora.compute_id, interface)
except nova_client_exceptions.NotFound as e:

View File

@ -46,6 +46,9 @@ class TestNoopComputeDriver(base.TestCase):
self.server_group_name = 'my_server_group'
self.server_group_id = self.FAKE_UUID_6
self.port_ids = ['port-id-1']
self.port_id = 88
self.network_id = uuidutils.generate_uuid()
self.ip_address = "192.0.2.2"
def test_build(self):
self.driver.build(self.name, self.amphora_flavor,
@ -101,3 +104,19 @@ class TestNoopComputeDriver(base.TestCase):
self.assertEqual((self.server_group_id, 'delete'),
self.driver.driver.computeconfig[
self.server_group_id])
def test_attach_network_or_port(self):
self.driver.attach_network_or_port(self.amphora_id, self.network_id,
self.ip_address, self.port_id)
self.assertEqual((self.amphora_id, self.network_id, self.ip_address,
self.port_id, 'attach_network_or_port'),
self.driver.driver.computeconfig[(
self.amphora_id, self.network_id,
self.ip_address, self.port_id)])
def test_detach_port(self):
self.driver.detach_port(self.amphora_id, self.port_id)
self.assertEqual((self.amphora_id, self.port_id,
'detach_port'),
self.driver.driver.computeconfig[(
self.amphora_id, self.port_id)])

View File

@ -144,6 +144,10 @@ class TestNovaClient(base.TestCase):
self.server_group_mock.policy = self.server_group_policy
self.server_group_mock.id = self.server_group_id
self.port_id = uuidutils.generate_uuid()
self.compute_id = uuidutils.generate_uuid()
self.network_id = uuidutils.generate_uuid()
super(TestNovaClient, self).setUp()
def test_build(self):
@ -342,3 +346,28 @@ class TestNovaClient(base.TestCase):
self.manager.delete_server_group,
self.server_group_id)
self.manager.server_groups.delete.called_with(self.server_group_id)
def test_attach_network_or_port(self):
self.manager.attach_network_or_port(self.compute_id,
self.network_id)
self.manager.manager.interface_attach.assert_called_with(
server=self.compute_id, net_id=self.network_id, fixed_ip=None,
port_id=None)
def test_attach_network_or_port_exception(self):
self.manager.manager.interface_attach.side_effect = [
nova_exceptions.NotFound('test_exception')]
self.assertRaises(nova_exceptions.NotFound,
self.manager.attach_network_or_port,
self.compute_id, self.network_id)
def test_detach_network(self):
self.manager.detach_port(self.compute_id,
self.port_id)
self.manager.manager.interface_detach.assert_called_with(
server=self.compute_id, port_id=self.port_id)
def test_detach_network_with_exception(self):
self.manager.manager.interface_detach.side_effect = [Exception]
self.manager.detach_port(self.compute_id,
self.port_id)

View File

@ -61,7 +61,7 @@ class TestAllowedAddressPairsDriver(base.TestCase):
super(TestAllowedAddressPairsDriver, self).setUp()
with mock.patch('octavia.common.clients.neutron_client.Client',
autospec=True) as neutron_client:
with mock.patch('octavia.common.clients.nova_client.Client',
with mock.patch('stevedore.driver.DriverManager.driver',
autospec=True):
client = neutron_client(clients.NEUTRON_VERSION)
client.list_extensions.return_value = {
@ -317,8 +317,8 @@ class TestAllowedAddressPairsDriver(base.TestCase):
]
list_security_groups.side_effect = lsc_side_effect
interface_attach = self.driver.nova_client.servers.interface_attach
interface_attach.side_effect = nova_exceptions.NotFound(404, "Network")
network_attach = self.driver.compute.attach_network_or_port
network_attach.side_effect = nova_exceptions.NotFound(404, "Network")
self.assertRaises(network_base.PlugVIPException,
self.driver.plug_vip, lb, lb.vip)
@ -339,8 +339,8 @@ class TestAllowedAddressPairsDriver(base.TestCase):
}
]
list_security_groups.side_effect = lsc_side_effect
interface_attach = self.driver.nova_client.servers.interface_attach
interface_attach.return_value = t_constants.MOCK_NOVA_INTERFACE
network_attach = self.driver.compute.attach_network_or_port
network_attach.return_value = t_constants.MOCK_NOVA_INTERFACE
update_port = self.driver.neutron_client.update_port
update_port.side_effect = neutron_exceptions.PortNotFoundClient
@ -360,9 +360,9 @@ class TestAllowedAddressPairsDriver(base.TestCase):
port1 = t_constants.MOCK_MANAGEMENT_PORT1['port']
port2 = t_constants.MOCK_MANAGEMENT_PORT2['port']
list_ports.side_effect = [{'ports': [port1]}, {'ports': [port2]}]
interface_attach = self.driver.nova_client.servers.interface_attach
interface_attach.side_effect = [t_constants.MOCK_VRRP_INTERFACE1,
t_constants.MOCK_VRRP_INTERFACE2]
network_attach = self.driver.compute.attach_network_or_port
network_attach.side_effect = [t_constants.MOCK_VRRP_INTERFACE1,
t_constants.MOCK_VRRP_INTERFACE2]
list_security_groups = self.driver.neutron_client.list_security_groups
list_security_groups.return_value = {
'security_groups': [
@ -408,7 +408,7 @@ class TestAllowedAddressPairsDriver(base.TestCase):
self._set_safely(t_constants.MOCK_MANAGEMENT_FIXED_IPS2[0],
'ip_address', lb.amphorae[1].lb_network_ip)
list_ports.side_effect = [{'ports': [port1]}, {'ports': [port2]}]
interface_attach = self.driver.nova_client.servers.interface_attach
network_attach = self.driver.compute.attach_network_or_port
self._set_safely(t_constants.MOCK_VRRP_INTERFACE1,
'net_id', t_constants.MOCK_MANAGEMENT_NET_ID)
self._set_safely(t_constants.MOCK_VRRP_FIXED_IPS1[0],
@ -417,8 +417,8 @@ class TestAllowedAddressPairsDriver(base.TestCase):
'net_id', t_constants.MOCK_MANAGEMENT_NET_ID)
self._set_safely(t_constants.MOCK_VRRP_FIXED_IPS2[0],
'subnet_id', t_constants.MOCK_MANAGEMENT_SUBNET_ID)
interface_attach.side_effect = [t_constants.MOCK_VRRP_INTERFACE1,
t_constants.MOCK_VRRP_INTERFACE2]
network_attach.side_effect = [t_constants.MOCK_VRRP_INTERFACE1,
t_constants.MOCK_VRRP_INTERFACE2]
list_security_groups = self.driver.neutron_client.list_security_groups
list_security_groups.return_value = {
'security_groups': [
@ -595,8 +595,8 @@ class TestAllowedAddressPairsDriver(base.TestCase):
def test_plug_network_when_compute_instance_cant_be_found(self):
net_id = t_constants.MOCK_NOVA_INTERFACE.net_id
interface_attach = self.driver.nova_client.servers.interface_attach
interface_attach.side_effect = nova_exceptions.NotFound(
network_attach = self.driver.compute.attach_network_or_port
network_attach.side_effect = nova_exceptions.NotFound(
404, message='Instance not found')
self.assertRaises(network_base.AmphoraNotFound,
self.driver.plug_network,
@ -604,8 +604,8 @@ class TestAllowedAddressPairsDriver(base.TestCase):
def test_plug_network_when_network_cant_be_found(self):
net_id = t_constants.MOCK_NOVA_INTERFACE.net_id
interface_attach = self.driver.nova_client.servers.interface_attach
interface_attach.side_effect = nova_exceptions.NotFound(
network_attach = self.driver.compute.attach_network_or_port
network_attach.side_effect = nova_exceptions.NotFound(
404, message='Network not found')
self.assertRaises(network_base.NetworkException,
self.driver.plug_network,
@ -613,16 +613,16 @@ class TestAllowedAddressPairsDriver(base.TestCase):
def test_plug_network_when_interface_attach_fails(self):
net_id = t_constants.MOCK_NOVA_INTERFACE.net_id
interface_attach = self.driver.nova_client.servers.interface_attach
interface_attach.side_effect = TypeError
network_attach = self.driver.compute.attach_network_or_port
network_attach.side_effect = TypeError
self.assertRaises(network_base.PlugNetworkException,
self.driver.plug_network,
t_constants.MOCK_COMPUTE_ID, net_id)
def test_plug_network(self):
net_id = t_constants.MOCK_NOVA_INTERFACE.net_id
interface_attach = self.driver.nova_client.servers.interface_attach
interface_attach.return_value = t_constants.MOCK_NOVA_INTERFACE
network_attach = self.driver.compute.attach_network_or_port
network_attach.return_value = t_constants.MOCK_NOVA_INTERFACE
oct_interface = self.driver.plug_network(
t_constants.MOCK_COMPUTE_ID, net_id)
exp_ips = [fixed_ip.get('ip_address')
@ -650,19 +650,6 @@ class TestAllowedAddressPairsDriver(base.TestCase):
self.driver.unplug_network,
t_constants.MOCK_COMPUTE_ID, net_id)
def test_unplug_network_when_interface_detach_fails(self):
list_ports = self.driver.neutron_client.list_ports
port1 = t_constants.MOCK_NEUTRON_PORT['port']
port2 = {
'id': '4', 'network_id': '3', 'fixed_ips':
[{'ip_address': '10.0.0.2'}]
}
list_ports.return_value = {'ports': [port1, port2]}
interface_detach = self.driver.nova_client.servers.interface_detach
interface_detach.side_effect = Exception
self.driver.unplug_network(t_constants.MOCK_COMPUTE_ID,
port2.get('network_id'))
def test_unplug_network(self):
list_ports = self.driver.neutron_client.list_ports
port1 = t_constants.MOCK_NEUTRON_PORT['port']
@ -671,11 +658,11 @@ class TestAllowedAddressPairsDriver(base.TestCase):
[{'ip_address': '10.0.0.2'}]
}
list_ports.return_value = {'ports': [port1, port2]}
interface_detach = self.driver.nova_client.servers.interface_detach
port_detach = self.driver.compute.detach_port
self.driver.unplug_network(t_constants.MOCK_COMPUTE_ID,
port2.get('network_id'))
interface_detach.assert_called_once_with(
server=t_constants.MOCK_COMPUTE_ID, port_id=port2.get('id'))
port_detach.assert_called_once_with(
compute_id=t_constants.MOCK_COMPUTE_ID, port_id=port2.get('id'))
def test_update_vip(self):
listeners = [data_models.Listener(protocol_port=80, peer_port=1024,
@ -907,7 +894,8 @@ class TestAllowedAddressPairsDriver(base.TestCase):
def test_plug_port(self):
port = mock.MagicMock()
port.id = self.PORT_ID
interface_attach = self.driver.nova_client.servers.interface_attach
network_attach = self.driver.compute.attach_network_or_port
network_attach.return_value = t_constants.MOCK_NOVA_INTERFACE
amphora = data_models.Amphora(
id=self.AMPHORA_ID, load_balancer_id=self.LB_ID,
compute_id=self.COMPUTE_ID, status=self.ACTIVE,
@ -915,25 +903,25 @@ class TestAllowedAddressPairsDriver(base.TestCase):
ha_ip=self.HA_IP)
self.driver.plug_port(amphora, port)
interface_attach.assert_called_once_with(server=amphora.compute_id,
net_id=None,
fixed_ip=None,
port_id=self.PORT_ID)
network_attach.assert_called_once_with(compute_id=amphora.compute_id,
network_id=None,
ip_address=None,
port_id=self.PORT_ID)
# NotFound cases
interface_attach.side_effect = nova_exceptions.NotFound(
network_attach.side_effect = nova_exceptions.NotFound(
1, message='Instance')
self.assertRaises(network_base.AmphoraNotFound,
self.driver.plug_port,
amphora,
port)
interface_attach.side_effect = nova_exceptions.NotFound(
network_attach.side_effect = nova_exceptions.NotFound(
1, message='Network')
self.assertRaises(network_base.NetworkNotFound,
self.driver.plug_port,
amphora,
port)
interface_attach.side_effect = nova_exceptions.NotFound(
network_attach.side_effect = nova_exceptions.NotFound(
1, message='bogus')
self.assertRaises(network_base.PlugNetworkException,
self.driver.plug_port,
@ -941,11 +929,11 @@ class TestAllowedAddressPairsDriver(base.TestCase):
port)
# Already plugged case should not raise an exception
interface_attach.side_effect = nova_exceptions.Conflict(1)
network_attach.side_effect = nova_exceptions.Conflict(1)
self.driver.plug_port(amphora, port)
# Unknown error case
interface_attach.side_effect = TypeError
network_attach.side_effect = TypeError
self.assertRaises(network_base.PlugNetworkException,
self.driver.plug_port,
amphora,