Adding methods to network driver to get more info

The network driver needs the ability to retrieve specific information about
subnets and ports and pass that information to other components.  Having info
about the subnet gives us cidr and gateway data that is valuable when setting
up the amphora's routes for the separation of tenant data and management data.
Because of this need, methods to retrieve network, subnet, and port details
has been added.

This also adds a another data model AmphoraNetworkConfig that contains subnet
and port information for the vip, vrrp, and ha networks on an amphora.  A
network task has been added that builds this data structure by calling the new
methods added to the network driver.

Change-Id: Ica912337c7d52659a9733096878664f734f27b00
This commit is contained in:
Brandon Logan 2015-07-22 21:16:29 -05:00
parent ec206a3cca
commit f074222842
11 changed files with 445 additions and 112 deletions

View File

@ -252,7 +252,9 @@ class UpdateAmphoraVIPData(BaseDatabaseTask):
for amp_data in amps_data:
self.repos.amphora.update(db_apis.get_session(), amp_data.id,
vrrp_ip=amp_data.vrrp_ip,
ha_ip=amp_data.ha_ip)
ha_ip=amp_data.ha_ip,
vrrp_port_id=amp_data.vrrp_port_id,
ha_port_id=amp_data.ha_port_id)
class MapLoadbalancerToAmphora(BaseDatabaseTask):

View File

@ -16,6 +16,7 @@
import logging
from oslo_config import cfg
import six
from stevedore import driver as stevedore_driver
from taskflow import task
from taskflow.types import failure
@ -63,7 +64,7 @@ class CalculateDelta(BaseNetworkTask):
:returns the delta
"""
deltas = []
deltas = {}
for amphora in loadbalancer.amphorae:
LOG.debug("Calculating network delta for amphora id: %s"
@ -71,11 +72,12 @@ class CalculateDelta(BaseNetworkTask):
# Figure out what networks we want
# seed with lb network(s)
subnet = self.network_driver.get_subnet(loadbalancer.vip.subnet_id)
desired_network_ids = {CONF.controller_worker.amp_network,
loadbalancer.vip.network_id}
subnet.network_id}
if not loadbalancer.listeners:
return []
return {}
for listener in loadbalancer.listeners:
if (not listener.default_pool) or (
@ -101,10 +103,9 @@ class CalculateDelta(BaseNetworkTask):
add_ids = desired_network_ids - set(actual_network_nics)
add_nics = list(data_models.Interface(
network_id=net_id) for net_id in add_ids)
deltas.append(data_models.Delta(amphora_id=amphora.id,
compute_id=amphora.compute_id,
add_nics=add_nics,
delete_nics=delete_nics))
deltas[amphora.id] = data_models.Delta(
amphora_id=amphora.id, compute_id=amphora.compute_id,
add_nics=add_nics, delete_nics=delete_nics)
return deltas
@ -200,28 +201,26 @@ class HandleNetworkDeltas(BaseNetworkTask):
def execute(self, deltas):
"""Handle network plugging based off deltas."""
for delta in deltas:
for amp_id, delta in six.iteritems(deltas):
for nic in delta.add_nics:
self.network_driver.plug_network(delta.compute_id,
nic.network_id)
for nic in delta.delete_nics:
try:
self.network_driver.unplug_network(delta.compute_id,
nic.network_id)
except base.NetworkNotFound as e:
except base.NetworkNotFound:
LOG.debug("Network %d not found ", nic.network_id)
pass
except Exception as e:
LOG.error(
_LE("Unable to unplug network - exception: %s"),
str(e))
pass
_LE("Unable to unplug network - exception: %s"), e)
def revert(self, deltas):
def revert(self, result, deltas):
"""Handle a network plug or unplug failures."""
for delta in deltas:
if isinstance(result, failure.Failure):
return
for amp_id, delta in six.iteritems(deltas):
LOG.warn(_LW("Unable to plug networks for amp id %s"),
delta.amphora_id)
if not delta:
@ -316,3 +315,32 @@ class UpdateVIP(BaseNetworkTask):
LOG.debug("Updating VIP of load_balancer %s." % loadbalancer.id)
self.network_driver.update_vip(loadbalancer)
class GetAmphoraeNetworkConfigs(BaseNetworkTask):
"""Task to retrieve amphorae network details."""
def execute(self, loadbalancer):
LOG.debug("Retrieving vip network details.")
vip_subnet = self.network_driver.get_subnet(loadbalancer.vip.subnet_id)
vip_port = self.network_driver.get_port(loadbalancer.vip.port_id)
amp_net_configs = {}
for amp in loadbalancer.amphorae:
LOG.debug("Retrieving network details for "
"amphora {0}".format(amp.id))
vrrp_port = self.network_driver.get_port(amp.vrrp_port_id)
vrrp_subnet = self.network_driver.get_subnet(
vrrp_port.get_subnet_id(amp.vrrp_ip))
ha_port = self.network_driver.get_port(amp.ha_port_id)
ha_subnet = self.network_driver.get_subnet(
ha_port.get_subnet_id(amp.ha_ip))
amp_net_configs[amp.id] = data_models.AmphoraNetworkConfig(
amphora=amp,
vip_subnet=vip_subnet,
vip_port=vip_port,
vrrp_subnet=vrrp_subnet,
vrrp_port=vrrp_port,
ha_subnet=ha_subnet,
ha_port=ha_port
)
return amp_net_configs

View File

@ -59,6 +59,10 @@ class NetworkNotFound(NetworkException):
pass
class SubnetNotFound(NetworkException):
pass
class VIPConfigurationNotFound(NetworkException):
pass
@ -182,11 +186,31 @@ class AbstractNetworkDriver(object):
pass
@abc.abstractmethod
def get_network(self, network_id=None, subnet_id=None):
"""Retrieves network from network id or subnet id .
def get_network(self, network_id):
"""Retrieves network from network id.
:param network_id: id of an network to retrieve
:param subnet_id: id of an subnet to retrieve network
:return: octavia.network.data_models.Network
:raises: NetworkException, NetworkNotFound
"""
pass
@abc.abstractmethod
def get_subnet(self, subnet_id):
"""Retrieves subnet from subnet id.
:param subnet_id: id of a subnet to retrieve
:return: octavia.network.data_models.Subnet
:raises: NetworkException, SubnetNotFound
"""
pass
@abc.abstractmethod
def get_port(self, port_id):
"""Retrieves port from port id.
:param port_id: id of a port to retrieve
:return: octavia.network.data_models.Port
:raises: NetworkException, PortNotFound
"""
pass

View File

@ -53,3 +53,60 @@ class Network(data_models.BaseDataModel):
self.provider_physical_network = provider_physical_network
self.provider_segmentation_id = provider_segmentation_id
self.router_external = router_external
self.mtu = mtu
class Subnet(data_models.BaseDataModel):
def __init__(self, id=None, name=None, network_id=None, tenant_id=None,
gateway_ip=None, cidr=None, ip_version=None):
self.id = id
self.name = name
self.network_id = network_id
self.tenant_id = tenant_id
self.gateway_ip = gateway_ip
self.cidr = cidr
self.ip_version = ip_version
class Port(data_models.BaseDataModel):
def __init__(self, id=None, name=None, device_id=None, device_owner=None,
mac_address=None, network_id=None, status=None,
tenant_id=None, admin_state_up=None, fixed_ips=None):
self.id = id
self.name = name
self.device_id = device_id
self.device_owner = device_owner
self.mac_address = mac_address
self.network_id = network_id
self.status = status
self.tenant_id = tenant_id
self.admin_state_up = admin_state_up
self.fixed_ips = fixed_ips or []
def get_subnet_id(self, fixed_ip_address):
for fixed_ip in self.fixed_ips:
if fixed_ip.ip_address == fixed_ip_address:
return fixed_ip.subnet_id
class FixedIP(data_models.BaseDataModel):
def __init__(self, subnet_id=None, ip_address=None):
self.subnet_id = subnet_id
self.ip_address = ip_address
class AmphoraNetworkConfig(data_models.BaseDataModel):
def __init__(self, amphora=None, vip_subnet=None, vip_port=None,
vrrp_subnet=None, vrrp_port=None, ha_subnet=None,
ha_port=None):
self.amphora = amphora
self.vip_subnet = vip_subnet
self.vip_port = vip_port
self.vrrp_subnet = vrrp_subnet
self.vrrp_port = vrrp_port
self.ha_subnet = ha_subnet
self.ha_port = ha_port

View File

@ -24,6 +24,7 @@ from octavia.common import keystone
from octavia.i18n import _LE, _LI
from octavia.network import base
from octavia.network import data_models as network_models
from octavia.network.drivers.neutron import utils
LOG = logging.getLogger(__name__)
@ -58,15 +59,18 @@ class AllowedAddressPairsDriver(base.AbstractNetworkDriver):
'will not manage any security groups.'))
self.sec_grp_enabled = False
def _port_to_vip(self, port, load_balancer_id=None):
def _port_to_vip(self, port, load_balancer):
port = port['port']
ip_address = port['fixed_ips'][0]['ip_address']
subnet_id = port['fixed_ips'][0]['subnet_id']
fixed_ip = {}
for port_fixed_ip in port['fixed_ips']:
if port_fixed_ip['subnet_id'] == load_balancer.vip.subnet_id:
fixed_ip = port_fixed_ip
break
port_id = port['id']
return data_models.Vip(ip_address=ip_address,
subnet_id=subnet_id,
return data_models.Vip(ip_address=fixed_ip.get('ip_address'),
subnet_id=fixed_ip.get('subnet_id'),
port_id=port_id,
load_balancer_id=load_balancer_id)
load_balancer_id=load_balancer.id)
def _nova_interface_to_octavia_interface(self, amphora_id, nova_interface):
ip_address = nova_interface.fixed_ips[0]['ip_address']
@ -181,17 +185,6 @@ class AllowedAddressPairsDriver(base.AbstractNetworkDriver):
self.nova_client.servers.add_security_group(
amphora.compute_id, sec_grp.get('id'))
def _map_network_to_data_model(self, network):
nw = network.get('network')
return network_models.Network(
id=nw.get('id'), name=nw.get('name'), subnets=nw.get('subnets'),
tenant_id=nw.get('tenant_id'),
admin_state_up=nw.get('admin_state_up'), mtu=nw.get('mtu'),
provider_network_type=nw.get('provider:network_type'),
provider_physical_network=nw.get('provider:physical_network'),
provider_segmentation_id=nw.get('provider:segmentation_id'),
router_external=nw.get('router:external'))
def deallocate_vip(self, vip):
port = self.neutron_client.show_port(vip.port_id)
admin_tenant_id = keystone.get_session().get_project_id()
@ -235,7 +228,9 @@ class AllowedAddressPairsDriver(base.AbstractNetworkDriver):
id=amphora.id,
compute_id=amphora.compute_id,
vrrp_ip=interface.ip_address,
ha_ip=vip.ip_address))
ha_ip=vip.ip_address,
vrrp_port_id=interface.port_id,
ha_port_id=vip.port_id))
return plugged_amphorae
def allocate_vip(self, load_balancer):
@ -256,7 +251,7 @@ class AllowedAddressPairsDriver(base.AbstractNetworkDriver):
port_id=load_balancer.vip.port_id)
LOG.exception(message)
raise base.AllocateVIPException(message)
return self._port_to_vip(port)
return self._port_to_vip(port, load_balancer)
# Must retrieve the network_id from the subnet
try:
@ -285,7 +280,7 @@ class AllowedAddressPairsDriver(base.AbstractNetworkDriver):
network_id=subnet['network_id'])
LOG.exception(message)
raise base.AllocateVIPException(message)
return self._port_to_vip(new_port)
return self._port_to_vip(new_port, load_balancer)
def unplug_vip(self, load_balancer, vip):
try:
@ -397,30 +392,53 @@ class AllowedAddressPairsDriver(base.AbstractNetworkDriver):
sec_grp = self._get_lb_security_group(load_balancer.id)
self._update_security_group_rules(load_balancer, sec_grp.get('id'))
def get_network(self, network_id=None, subnet_id=None):
network = None
def get_network(self, network_id):
try:
if network_id:
network = self.neutron_client.show_network(network_id)
elif subnet_id:
subnet = (self.neutron_client.show_subnet(subnet_id)
.get('subnet').get('network_id'))
network = self.neutron_client.show_network(subnet)
except base.NetworkNotFound:
network = self.neutron_client.show_network(network_id)
return utils.convert_network_dict_to_model(network)
except neutron_client_exceptions.NotFound:
message = _LE('Network not found '
'(network id: {network_id} '
'and subnet id: {subnet_id}.').format(
network_id=network_id,
subnet_id=subnet_id)
'(network id: {network_id}.').format(
network_id=network_id)
LOG.exception(message)
raise base.NetworkNotFound(message)
except Exception:
message = _LE('Error retrieving network '
'(network id: {network_id} '
'and subnet id: {subnet_id}.').format(
network_id=network_id,
'(network id: {network_id}.').format(
network_id=network_id)
LOG.exception(message)
raise base.NetworkException(message)
def get_subnet(self, subnet_id):
try:
subnet = self.neutron_client.show_subnet(subnet_id)
return utils.convert_subnet_dict_to_model(subnet)
except neutron_client_exceptions.NotFound:
message = _LE('Subnet not found '
'(subnet id: {subnet_id}.').format(
subnet_id=subnet_id)
LOG.exception(message)
raise base.SubnetNotFound(message)
except Exception:
message = _LE('Error retrieving subnet '
'(subnet id: {subnet_id}.').format(
subnet_id=subnet_id)
LOG.exception(message)
raise base.NetworkException(message)
return self._map_network_to_data_model(network)
def get_port(self, port_id):
try:
port = self.neutron_client.show_port(port_id)
return utils.convert_port_dict_to_model(port)
except neutron_client_exceptions.NotFound:
message = _LE('Port not found '
'(port id: {port_id}.').format(
port_id=port_id)
LOG.exception(message)
raise base.PortNotFound(message)
except Exception:
message = _LE('Error retrieving port '
'(port id: {port_id}.').format(
port_id=port_id)
LOG.exception(message)
raise base.NetworkException(message)

View File

@ -0,0 +1,66 @@
# Copyright 2015 Rackspace
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log as logging
from octavia.network import data_models as network_models
LOG = logging.getLogger(__name__)
def convert_subnet_dict_to_model(subnet_dict):
subnet = subnet_dict.get('subnet') or subnet_dict
return network_models.Subnet(id=subnet.get('id'), name=subnet.get('name'),
network_id=subnet.get('network_id'),
tenant_id=subnet.get('tenant_id'),
gateway_ip=subnet.get('gateway_ip'),
cidr=subnet.get('cidr'),
ip_version=subnet.get('ip_version')
)
def convert_port_dict_to_model(port_dict):
port = port_dict.get('port') or port_dict
fixed_ips = [network_models.FixedIP(subnet_id=fixed_ip.get('subnet_id'),
ip_address=fixed_ip.get('ip_address'))
for fixed_ip in port.get('fixed_ips', [])]
return network_models.Port(
id=port.get('id'),
name=port.get('name'),
device_id=port.get('device_id'),
device_owner=port.get('device_owner'),
mac_address=port.get('mac_address'),
network_id=port.get('network_id'),
status=port.get('status'),
tenant_id=port.get('tenant_id'),
admin_state_up=port.get('admin_state_up'),
fixed_ips=fixed_ips
)
def convert_network_dict_to_model(network_dict):
nw = network_dict.get('network') or network_dict
return network_models.Network(
id=nw.get('id'),
name=nw.get('name'),
subnets=nw.get('subnets'),
tenant_id=nw.get('tenant_id'),
admin_state_up=nw.get('admin_state_up'),
mtu=nw.get('mtu'),
provider_network_type=nw.get('provider:network_type'),
provider_physical_network=nw.get('provider:physical_network'),
provider_segmentation_id=nw.get('provider:segmentation_id'),
router_external=nw.get('router:external')
)

View File

@ -59,12 +59,12 @@ class NoopManager(object):
self.networkconfigconfig[(amphora_id, network_id, ip_address)] = (
amphora_id, network_id, ip_address, 'plug_network')
def unplug_network(self, amphora_id, network_id):
def unplug_network(self, amphora_id, network_id, ip_address=None):
LOG.debug("Network %s no-op, unplug_network amphora_id %s, "
"network_id %s",
self.__class__.__name__, amphora_id, network_id)
self.networkconfigconfig[(amphora_id, network_id)] = (
amphora_id, network_id, 'unplug_network')
self.networkconfigconfig[(amphora_id, network_id, ip_address)] = (
amphora_id, network_id, ip_address, 'unplug_network')
def get_plugged_networks(self, amphora_id):
LOG.debug("Network %s no-op, get_plugged_networks amphora_id %s",
@ -77,11 +77,20 @@ class NoopManager(object):
self.__class__.__name__, load_balancer)
self.networkconfigconfig[load_balancer] = (load_balancer, 'update_vip')
def get_network(self, network_id=None, subnet_id=None):
def get_network(self, network_id):
LOG.debug("Network %s no-op, get_network network_id %s",
self.__class__.__name__, network_id)
self.networkconfigconfig[network_id, subnet_id] = (
network_id, subnet_id, 'get_network')
self.networkconfigconfig[network_id] = (network_id, 'get_network')
def get_subnet(self, subnet_id):
LOG.debug("Subnet %s no-op, get_subnet subnet_id %s",
self.__class__.__name__, subnet_id)
self.networkconfigconfig[subnet_id] = (subnet_id, 'get_subnet')
def get_port(self, port_id):
LOG.debug("Port %s no-op, get_port port_id %s",
self.__class__.__name__, port_id)
self.networkconfigconfig[port_id] = (port_id, 'get_port')
class NoopNetworkDriver(driver_base.AbstractNetworkDriver):
@ -104,8 +113,9 @@ class NoopNetworkDriver(driver_base.AbstractNetworkDriver):
def plug_network(self, amphora_id, network_id, ip_address=None):
self.driver.plug_network(amphora_id, network_id, ip_address)
def unplug_network(self, amphora_id, network_id):
self.driver.unplug_network(amphora_id, network_id)
def unplug_network(self, amphora_id, network_id, ip_address=None):
self.driver.unplug_network(amphora_id, network_id,
ip_address=ip_address)
def get_plugged_networks(self, amphora_id):
self.driver.get_plugged_networks(amphora_id)
@ -113,5 +123,11 @@ class NoopNetworkDriver(driver_base.AbstractNetworkDriver):
def update_vip(self, load_balancer):
self.driver.update_vip(load_balancer)
def get_network(self, network_id=None, subnet_id=None):
self.driver.get_network(network_id, subnet_id)
def get_network(self, network_id):
self.driver.get_network(network_id)
def get_subnet(self, subnet_id):
self.driver.get_subnet(subnet_id)
def get_port(self, port_id):
self.driver.get_port(port_id)

View File

@ -65,12 +65,12 @@ class TestNetworkTasks(base.TestCase):
def test_calculate_delta(self,
mock_driver):
EMPTY = []
empty_deltas = [data_models.Delta(
EMPTY = {}
empty_deltas = {self.amphora_mock.id: data_models.Delta(
amphora_id=self.amphora_mock.id,
compute_id=self.amphora_mock.compute_id,
add_nics=[],
delete_nics=[])]
delete_nics=[])}
def _interface(network_id):
return [data_models.Interface(network_id=network_id)]
@ -105,7 +105,8 @@ class TestNetworkTasks(base.TestCase):
compute_id=self.amphora_mock.compute_id,
add_nics=_interface(2),
delete_nics=[])
self.assertEqual([ndm], net.execute(self.load_balancer_mock))
self.assertEqual({self.amphora_mock.id: ndm},
net.execute(self.load_balancer_mock))
mock_driver.get_network.assert_called_once_with(subnet_id=1)
@ -117,7 +118,8 @@ class TestNetworkTasks(base.TestCase):
compute_id=self.amphora_mock.compute_id,
add_nics=_interface(2),
delete_nics=_interface(3))
self.assertEqual([ndm], net.execute(self.load_balancer_mock))
self.assertEqual({self.amphora_mock.id: ndm},
net.execute(self.load_balancer_mock))
pool_mock.members = []
mock_driver.get_plugged_networks.return_value = _interface(2)
@ -125,7 +127,8 @@ class TestNetworkTasks(base.TestCase):
compute_id=self.amphora_mock.compute_id,
add_nics=[],
delete_nics=_interface(2))
self.assertEqual([ndm], net.execute(self.load_balancer_mock))
self.assertEqual({self.amphora_mock.id: ndm},
net.execute(self.load_balancer_mock))
def test_get_plumbed_networks(self,
mock_driver):
@ -232,32 +235,32 @@ class TestNetworkTasks(base.TestCase):
net = network_tasks.HandleNetworkDeltas()
net.execute([])
net.execute({})
self.assertFalse(mock_driver.plug_network.called)
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
compute_id=self.amphora_mock.compute_id,
add_nics=[],
delete_nics=[])
net.execute([delta])
net.execute({self.amphora_mock.id: delta})
self.assertFalse(mock_driver.plug_network.called)
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
compute_id=self.amphora_mock.compute_id,
add_nics=_interface(1),
delete_nics=[])
net.execute([delta])
net.execute({self.amphora_mock.id: delta})
mock_driver.plug_network.assert_called_once_with(COMPUTE_ID, 1)
# revert
net.execute([delta])
net.execute({self.amphora_mock.id: delta})
self.assertFalse(mock_driver.unplug_network.called)
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
compute_id=self.amphora_mock.compute_id,
add_nics=[],
delete_nics=[])
net.execute([delta])
net.execute({self.amphora_mock.id: delta})
self.assertFalse(mock_driver.unplug_network.called)
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
@ -270,36 +273,37 @@ class TestNetworkTasks(base.TestCase):
mock_driver.reset_mock()
mock_driver.unplug_network.side_effect = TestException('test')
self.assertRaises(TestException, net.revert, [delta])
self.assertRaises(TestException, net.revert, mock.ANY,
{self.amphora_mock.id: delta})
mock_driver.unplug_network.assert_called_once_with(COMPUTE_ID, 1)
mock_driver.reset_mock()
net.execute([])
net.execute({})
self.assertFalse(mock_driver.unplug_network.called)
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
compute_id=self.amphora_mock.compute_id,
add_nics=[],
delete_nics=[])
net.execute([delta])
net.execute({self.amphora_mock.id: delta})
self.assertFalse(mock_driver.unplug_network.called)
delta = data_models.Delta(amphora_id=self.amphora_mock.id,
compute_id=self.amphora_mock.compute_id,
add_nics=[],
delete_nics=_interface(1))
net.execute([delta])
net.execute({self.amphora_mock.id: delta})
mock_driver.unplug_network.assert_called_once_with(COMPUTE_ID, 1)
mock_driver.reset_mock()
mock_driver.unplug_network.side_effect = net_base.NetworkNotFound
net.execute([delta])
net.execute({self.amphora_mock.id: delta})
mock_driver.unplug_network.assert_called_once_with(COMPUTE_ID, 1)
# Do a test with a general exception in case behavior changes
mock_driver.reset_mock()
mock_driver.unplug_network.side_effect = Exception()
net.execute([delta])
net.execute({self.amphora_mock.id: delta})
mock_driver.unplug_network.assert_called_once_with(COMPUTE_ID, 1)
def test_plug_vip(self,

View File

@ -19,6 +19,7 @@ from novaclient.client import exceptions as nova_exceptions
from octavia.common import constants
from octavia.common import data_models
from octavia.network import base as network_base
from octavia.network import data_models as network_models
from octavia.network.drivers.neutron import allowed_address_pairs
from octavia.tests.common import data_model_helpers as dmh
from octavia.tests.unit import base
@ -29,17 +30,23 @@ class MockNovaInterface(object):
port_id = None
fixed_ips = []
MOCK_NETWORK_ID = '1'
MOCK_SUBNET_ID = '2'
MOCK_PORT_ID = '3'
MOCK_COMPUTE_ID = '4'
MOCK_IP_ADDRESS = '10.0.0.1'
MOCK_CIDR = '10.0.0.0/24'
MOCK_MAC_ADDR = 'fe:16:3e:00:95:5c'
MOCK_NOVA_INTERFACE = MockNovaInterface()
MOCK_NOVA_INTERFACE.net_id = '1'
MOCK_NOVA_INTERFACE.port_id = '2'
MOCK_NOVA_INTERFACE.fixed_ips = [{'ip_address': '10.0.0.1', 'subnet_id': '10'}]
MOCK_SUBNET = {'subnet': {'id': '10', 'network_id': '1'}}
MOCK_SUBNET = {'subnet': {'id': MOCK_SUBNET_ID, 'network_id': MOCK_NETWORK_ID}}
MOCK_NOVA_INTERFACE.net_id = MOCK_NETWORK_ID
MOCK_NOVA_INTERFACE.port_id = MOCK_PORT_ID
MOCK_NOVA_INTERFACE.fixed_ips = [{'ip_address': MOCK_IP_ADDRESS}]
MOCK_NEUTRON_PORT = {'port': {'network_id': '1',
'id': '2',
'fixed_ips': [{'ip_address': '10.0.0.1',
'subnet_id': '10'}]}}
MOCK_NEUTRON_PORT = {'port': {'network_id': MOCK_NETWORK_ID,
'id': MOCK_PORT_ID,
'fixed_ips': [{'ip_address': MOCK_IP_ADDRESS,
'subnet_id': MOCK_SUBNET_ID}]}}
class TestAllowedAddressPairsDriver(base.TestCase):
@ -70,8 +77,9 @@ class TestAllowedAddressPairsDriver(base.TestCase):
self.driver._check_extensions_loaded)
def test_port_to_vip(self):
fake_lb_id = '4'
vip = self.driver._port_to_vip(MOCK_NEUTRON_PORT, fake_lb_id)
lb = dmh.generate_load_balancer_tree()
lb.vip.subnet_id = MOCK_SUBNET_ID
vip = self.driver._port_to_vip(MOCK_NEUTRON_PORT, lb)
self.assertIsInstance(vip, data_models.Vip)
self.assertEqual(
MOCK_NEUTRON_PORT['port']['fixed_ips'][0]['ip_address'],
@ -80,7 +88,7 @@ class TestAllowedAddressPairsDriver(base.TestCase):
MOCK_NEUTRON_PORT['port']['fixed_ips'][0]['subnet_id'],
vip.subnet_id)
self.assertEqual(MOCK_NEUTRON_PORT['port']['id'], vip.port_id)
self.assertEqual(fake_lb_id, vip.load_balancer_id)
self.assertEqual(lb.id, vip.load_balancer_id)
def test_nova_interface_to_octavia_interface(self):
nova_interface = MockNovaInterface()
@ -192,7 +200,8 @@ class TestAllowedAddressPairsDriver(base.TestCase):
self.driver.allocate_vip, fake_lb)
show_port = self.driver.neutron_client.show_port
show_port.return_value = MOCK_NEUTRON_PORT
fake_lb_vip = data_models.Vip(port_id=MOCK_NEUTRON_PORT['port']['id'])
fake_lb_vip = data_models.Vip(port_id=MOCK_NEUTRON_PORT['port']['id'],
subnet_id=MOCK_SUBNET_ID)
fake_lb = data_models.LoadBalancer(id='1', vip=fake_lb_vip)
vip = self.driver.allocate_vip(fake_lb)
self.assertIsInstance(vip, data_models.Vip)
@ -203,7 +212,7 @@ class TestAllowedAddressPairsDriver(base.TestCase):
MOCK_NEUTRON_PORT['port']['fixed_ips'][0]['subnet_id'],
vip.subnet_id)
self.assertEqual(MOCK_NEUTRON_PORT['port']['id'], vip.port_id)
self.assertIsNone(vip.load_balancer_id)
self.assertEqual(fake_lb.id, vip.load_balancer_id)
create_port = self.driver.neutron_client.create_port
create_port.return_value = MOCK_NEUTRON_PORT
@ -219,7 +228,7 @@ class TestAllowedAddressPairsDriver(base.TestCase):
MOCK_NEUTRON_PORT['port']['fixed_ips'][0]['subnet_id'],
vip.subnet_id)
self.assertEqual(MOCK_NEUTRON_PORT['port']['id'], vip.port_id)
self.assertIsNone(vip.load_balancer_id)
self.assertEqual(fake_lb.id, vip.load_balancer_id)
def test_unplug_vip(self):
lb = dmh.generate_load_balancer_tree()
@ -372,3 +381,43 @@ class TestAllowedAddressPairsDriver(base.TestCase):
self.driver.update_vip(lb)
delete_rule.assert_called_once_with('rule-22')
self.assertFalse(create_rule.called)
def test_get_network(self):
show_network = self.driver.neutron_client.show_network
show_network.return_value = {'network': {'id': MOCK_NETWORK_ID,
'subnets': [MOCK_SUBNET_ID]}}
network = self.driver.get_network(MOCK_NETWORK_ID)
self.assertIsInstance(network, network_models.Network)
self.assertEqual(MOCK_NETWORK_ID, network.id)
self.assertEqual(1, len(network.subnets))
self.assertEqual(MOCK_SUBNET_ID, network.subnets[0])
def test_get_subnet(self):
show_subnet = self.driver.neutron_client.show_subnet
show_subnet.return_value = {'subnet': {'id': MOCK_SUBNET_ID,
'gateway_ip': MOCK_IP_ADDRESS,
'cidr': MOCK_CIDR}}
subnet = self.driver.get_subnet(MOCK_SUBNET_ID)
self.assertIsInstance(subnet, network_models.Subnet)
self.assertEqual(MOCK_SUBNET_ID, subnet.id)
self.assertEqual(MOCK_IP_ADDRESS, subnet.gateway_ip)
self.assertEqual(MOCK_CIDR, subnet.cidr)
def test_get_port(self):
show_port = self.driver.neutron_client.show_port
show_port.return_value = {'port': {'id': MOCK_PORT_ID,
'mac_address': MOCK_MAC_ADDR,
'network_id': MOCK_NETWORK_ID,
'fixed_ips': [{
'subnet_id': MOCK_SUBNET_ID,
'ip_address': MOCK_IP_ADDRESS
}]}}
port = self.driver.get_port(MOCK_PORT_ID)
self.assertIsInstance(port, network_models.Port)
self.assertEqual(MOCK_PORT_ID, port.id)
self.assertEqual(MOCK_MAC_ADDR, port.mac_address)
self.assertEqual(MOCK_NETWORK_ID, port.network_id)
self.assertEqual(1, len(port.fixed_ips))
self.assertIsInstance(port.fixed_ips[0], network_models.FixedIP)
self.assertEqual(MOCK_SUBNET_ID, port.fixed_ips[0].subnet_id)
self.assertEqual(MOCK_IP_ADDRESS, port.fixed_ips[0].ip_address)

View File

@ -40,6 +40,8 @@ class TestNoopNetworkDriver(base.TestCase):
self.vip = models.Vip()
self.vip.ip_address = "10.0.0.1"
self.amphora_id = self.FAKE_UUID_1
self.compute_id = self.FAKE_UUID_2
self.subnet_id = self.FAKE_UUID_3
def test_allocate_vip(self):
self.driver.allocate_vip(self.load_balancer)
@ -78,11 +80,13 @@ class TestNoopNetworkDriver(base.TestCase):
self.ip_address)])
def test_unplug_network(self):
self.driver.unplug_network(self.amphora_id, self.network_id)
self.assertEqual((self.amphora_id, self.network_id,
self.driver.unplug_network(self.amphora_id, self.network_id,
ip_address=self.ip_address)
self.assertEqual((self.amphora_id, self.network_id, self.ip_address,
'unplug_network'),
self.driver.driver.networkconfigconfig[(
self.amphora_id, self.network_id)])
self.amphora_id, self.network_id,
self.ip_address)])
def test_get_plugged_networks(self):
self.driver.get_plugged_networks(self.amphora_id)
@ -95,4 +99,25 @@ class TestNoopNetworkDriver(base.TestCase):
self.assertEqual((self.load_balancer, 'update_vip'),
self.driver.driver.networkconfigconfig[(
self.load_balancer
)])
)])
def test_get_network(self):
self.driver.get_network(self.network_id)
self.assertEqual(
(self.network_id, 'get_network'),
self.driver.driver.networkconfigconfig[self.network_id]
)
def test_get_subnet(self):
self.driver.get_subnet(self.subnet_id)
self.assertEqual(
(self.subnet_id, 'get_subnet'),
self.driver.driver.networkconfigconfig[self.subnet_id]
)
def test_get_port(self):
self.driver.get_port(self.port_id)
self.assertEqual(
(self.port_id, 'get_port'),
self.driver.driver.networkconfigconfig[self.port_id]
)

View File

@ -84,6 +84,41 @@ New data models:
* provider_physical_network
* provider_segmentation_id
* router_external
* mtu
* class Subnet
* id
* name
* network_id
* tenant_id
* gateway_ip
* cidr
* ip_version
* class Port
* id
* name
* device_id
* device_owner
* mac_address
* network_id
* status
* tenant_id
* admin_state_up
* fixed_ips - list of FixedIP objects
* FixedIP
* subnet_id
* ip_address
* AmphoraNetworkConfig
* amphora - Amphora object
* vip_subnet - Subnet object
* vip_port - Port object
* vrrp_subnet - Subnet object
* vrrp_port - Port object
* ha_subnet - Subnet object
* ha_port - Port object
New Exceptions defined in the octavia.network package:
@ -97,6 +132,7 @@ New Exceptions defined in the octavia.network package:
* UnplugNetworkException
* VIPInUse
* PortNotFound
* SubnetNotFound
* NetworkNotFound
* VIPConfigurationNotFound
* AmphoraNotFound
@ -179,14 +215,27 @@ class AbstractNetworkDriver
of the passed in loadbalancer
* loadbalancer: instance of a data_models.LoadBalancer
* get_network(network_id=None, subnet_id=None):
* get_network(network_id):
* Retrieves the network from network_id or subnet_id
* Retrieves the network from network_id
* network_id = id of an network to retrieve
* subnet_id = id of an subnet to retrieve network
* returns = Network data model
* raises NetworkException, NetworkNotFound
* get_subnet(subnet_id):
* Retrieves the subnet from subnet_id
* subnet_id = id of a subnet to retrieve
* returns = Subnet data model
* raises NetworkException, SubnetNotFound
* get_port(port_id):
* Retrieves the port from port_id
* port_id = id of a port to retrieve
* returns = Port data model
* raises NetworkException, PortNotFound
Alternatives
------------
@ -199,16 +248,11 @@ Data model impact
* The Interface data model defined above will just be a class. We may later
decide that it needs to be stored in the database, but we can optimize on
that in a later review if needed.
* Remove floating_ip_id from VIP model and migration
* Remove floating_ip_network_id from VIP model and migration
* Rename net_port_id to just port_id in VIP model and migration
* Rename subnet_id to network_id in VIP model and migration
REST API impact
---------------
* Remove floating_ip_id from WSME VIP type
* Remove floating_ip_network_id from WSME VIP type
None
Security impact
---------------