Merge "Refactor the AAP driver to not depend on nova"

This commit is contained in:
Zuul 2018-10-16 06:23:20 +00:00 committed by Gerrit Code Review
commit e9bd56f094
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,