Port-to-VIF os-vif translator for hybrid OVS case
This patch introduces Port-to-VIF translation to 'os_vif_util' and implements a translator that supports hybrid OpenVSwitch plugging case. Change-Id: I9f5c36fa32b51da8cccf377455b096270f23a782 Partially-Implements: blueprint kuryr-k8s-integration
This commit is contained in:
parent
d20a512600
commit
634290839a
|
@ -51,6 +51,9 @@ neutron_defaults = [
|
|||
help=_("Default Neutron subnet ID for Kubernetes pods")),
|
||||
cfg.ListOpt('pod_security_groups',
|
||||
help=_("Default Neutron security groups' IDs for Kubernetes pods")),
|
||||
cfg.StrOpt('ovs_bridge',
|
||||
help=_("Default OpenVSwitch integration bridge"),
|
||||
sample_default="br-int")
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
|
|
@ -18,5 +18,9 @@ class K8sClientException(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class IntegrityError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def format_msg(exception):
|
||||
return "%s: %s" % (exception.__class__.__name__, exception)
|
||||
|
|
|
@ -13,15 +13,38 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from kuryr.lib._i18n import _LE
|
||||
from kuryr.lib.binding.drivers import utils as kl_utils
|
||||
from kuryr.lib import constants as kl_const
|
||||
from os_vif.objects import fixed_ip as osv_fixed_ip
|
||||
from os_vif.objects import network as osv_network
|
||||
from os_vif.objects import route as osv_route
|
||||
from os_vif.objects import subnet as osv_subnet
|
||||
from os_vif.objects import vif as osv_vif
|
||||
from oslo_config import cfg as oslo_cfg
|
||||
from oslo_log import log as logging
|
||||
from stevedore import driver as stv_driver
|
||||
|
||||
from kuryr_kubernetes import config
|
||||
from kuryr_kubernetes import exceptions as k_exc
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# REVISIT(ivc): consider making this module part of kuryr-lib
|
||||
_VIF_TRANSLATOR_NAMESPACE = "kuryr_kubernetes.vif_translators"
|
||||
_VIF_MANAGERS = {}
|
||||
|
||||
|
||||
def neutron_to_osvif_network(neutron_network):
|
||||
"""Converts Neutron network to os-vif Subnet.
|
||||
|
||||
:param neutron_network: dict containing network information as returned by
|
||||
neutron client's 'show_network'
|
||||
:return: an os-vif Network object
|
||||
"""
|
||||
|
||||
obj = osv_network.Network(id=neutron_network['id'])
|
||||
|
||||
if neutron_network.get('name') is not None:
|
||||
|
@ -34,6 +57,13 @@ def neutron_to_osvif_network(neutron_network):
|
|||
|
||||
|
||||
def neutron_to_osvif_subnet(neutron_subnet):
|
||||
"""Converts Neutron subnet to os-vif Subnet.
|
||||
|
||||
:param neutron_subnet: dict containing subnet information as returned by
|
||||
neutron client's 'show_subnet'
|
||||
:return: an os-vif Subnet object
|
||||
"""
|
||||
|
||||
obj = osv_subnet.Subnet(
|
||||
cidr=neutron_subnet['cidr'],
|
||||
dns=neutron_subnet['dns_nameservers'],
|
||||
|
@ -46,8 +76,188 @@ def neutron_to_osvif_subnet(neutron_subnet):
|
|||
|
||||
|
||||
def _neutron_to_osvif_routes(neutron_routes):
|
||||
"""Converts Neutron host_routes to os-vif RouteList.
|
||||
|
||||
:param neutron_routes: list of routes as returned by neutron client's
|
||||
'show_subnet' in 'host_routes' attribute
|
||||
:return: an os-vif RouteList object
|
||||
"""
|
||||
|
||||
obj_list = [osv_route.Route(cidr=route['destination'],
|
||||
gateway=route['nexthop'])
|
||||
for route in neutron_routes]
|
||||
|
||||
return osv_route.RouteList(objects=obj_list)
|
||||
|
||||
|
||||
def _make_vif_subnet(subnets, subnet_id):
|
||||
"""Makes a copy of an os-vif Subnet from subnets mapping.
|
||||
|
||||
:param subnets: subnet mapping as returned by PodSubnetsDriver.get_subnets
|
||||
:param subnet_id: ID of the subnet to extract from 'subnets' mapping
|
||||
:return: a copy of an os-vif Subnet object matching 'subnet_id'
|
||||
"""
|
||||
|
||||
network = subnets[subnet_id]
|
||||
|
||||
if len(network.subnets.objects) != 1:
|
||||
raise k_exc.IntegrityError(_LE(
|
||||
"Network object for subnet %(subnet_id)s is invalid, "
|
||||
"must contain a single subnet, but %(num_subnets)s found") % {
|
||||
'subnet_id': subnet_id,
|
||||
'num_subnets': len(network.subnets.objects)})
|
||||
|
||||
subnet = network.subnets.objects[0].obj_clone()
|
||||
subnet.ips = osv_fixed_ip.FixedIPList(objects=[])
|
||||
return subnet
|
||||
|
||||
|
||||
def _make_vif_subnets(neutron_port, subnets):
|
||||
"""Gets a list of os-vif Subnet objects for port.
|
||||
|
||||
:param neutron_port: dict containing port information as returned by
|
||||
neutron client's 'show_port'
|
||||
:param subnets: subnet mapping as returned by PodSubnetsDriver.get_subnets
|
||||
:return: list of os-vif Subnet object
|
||||
"""
|
||||
|
||||
vif_subnets = {}
|
||||
|
||||
for neutron_fixed_ip in neutron_port.get('fixed_ips', []):
|
||||
subnet_id = neutron_fixed_ip['subnet_id']
|
||||
ip_address = neutron_fixed_ip['ip_address']
|
||||
|
||||
if subnet_id not in subnets:
|
||||
continue
|
||||
|
||||
try:
|
||||
subnet = vif_subnets[subnet_id]
|
||||
except KeyError:
|
||||
subnet = _make_vif_subnet(subnets, subnet_id)
|
||||
vif_subnets[subnet_id] = subnet
|
||||
|
||||
subnet.ips.objects.append(osv_fixed_ip.FixedIP(address=ip_address))
|
||||
|
||||
if not vif_subnets:
|
||||
raise k_exc.IntegrityError(_LE(
|
||||
"No valid subnets found for port %(port_id)s") % {
|
||||
'port_id': neutron_port.get('id')})
|
||||
|
||||
return list(vif_subnets.values())
|
||||
|
||||
|
||||
def _make_vif_network(neutron_port, subnets):
|
||||
"""Gets a os-vif Network object for port.
|
||||
|
||||
:param neutron_port: dict containing port information as returned by
|
||||
neutron client's 'show_port'
|
||||
:param subnets: subnet mapping as returned by PodSubnetsDriver.get_subnets
|
||||
:return: os-vif Network object
|
||||
"""
|
||||
|
||||
try:
|
||||
network = next(net.obj_clone() for net in subnets.values()
|
||||
if net.id == neutron_port.get('network_id'))
|
||||
except StopIteration:
|
||||
raise k_exc.IntegrityError(_LE(
|
||||
"Port %(port_id)s belongs to network %(network_id)s, "
|
||||
"but requested networks are: %(requested_networks)s") % {
|
||||
'port_id': neutron_port.get('id'),
|
||||
'network_id': neutron_port.get('network_id'),
|
||||
'requested_networks': [net.id for net in subnets.values()]})
|
||||
|
||||
network.subnets = osv_subnet.SubnetList(
|
||||
objects=_make_vif_subnets(neutron_port, subnets))
|
||||
|
||||
return network
|
||||
|
||||
|
||||
def _get_vif_name(neutron_port):
|
||||
"""Gets a VIF device name for port.
|
||||
|
||||
:param neutron_port: dict containing port information as returned by
|
||||
neutron client's 'show_port'
|
||||
"""
|
||||
|
||||
vif_name, _ = kl_utils.get_veth_pair_names(neutron_port['id'])
|
||||
return vif_name
|
||||
|
||||
|
||||
def _get_ovs_hybrid_bridge_name(neutron_port):
|
||||
"""Gets a name of the Linux bridge name for hybrid OpenVSwitch port.
|
||||
|
||||
:param neutron_port: dict containing port information as returned by
|
||||
neutron client's 'show_port'
|
||||
"""
|
||||
return ('qbr' + neutron_port['id'])[:kl_const.NIC_NAME_LEN]
|
||||
|
||||
|
||||
def _is_port_active(neutron_port):
|
||||
"""Checks if port is active.
|
||||
|
||||
:param neutron_port: dict containing port information as returned by
|
||||
neutron client's 'show_port'
|
||||
"""
|
||||
|
||||
return (neutron_port['status'] == kl_const.PORT_STATUS_ACTIVE)
|
||||
|
||||
|
||||
def neutron_to_osvif_vif_ovs(vif_plugin, neutron_port, subnets):
|
||||
"""Converts Neutron port to VIF object for os-vif 'ovs' plugin.
|
||||
|
||||
:param vif_plugin: name of the os-vif plugin to use (i.e. 'ovs')
|
||||
:param neutron_port: dict containing port information as returned by
|
||||
neutron client's 'show_port'
|
||||
:param subnets: subnet mapping as returned by PodSubnetsDriver.get_subnets
|
||||
:return: os-vif VIF object
|
||||
"""
|
||||
|
||||
profile = osv_vif.VIFPortProfileOpenVSwitch(
|
||||
interface_id=neutron_port['id'])
|
||||
|
||||
details = neutron_port.get('binding:vif_details', {})
|
||||
ovs_bridge = details.get('bridge_name',
|
||||
config.CONF.neutron_defaults.ovs_bridge)
|
||||
if not ovs_bridge:
|
||||
raise oslo_cfg.RequiredOptError('ovs_bridge', 'neutron_defaults')
|
||||
|
||||
network = _make_vif_network(neutron_port, subnets)
|
||||
network.bridge = ovs_bridge
|
||||
|
||||
if details.get('ovs_hybrid_plug'):
|
||||
vif = osv_vif.VIFBridge(
|
||||
id=neutron_port['id'],
|
||||
address=neutron_port['mac_address'],
|
||||
network=network,
|
||||
has_traffic_filtering=details.get('port_filter', False),
|
||||
preserve_on_delete=False,
|
||||
active=_is_port_active(neutron_port),
|
||||
port_profile=profile,
|
||||
plugin=vif_plugin,
|
||||
vif_name=_get_vif_name(neutron_port),
|
||||
bridge_name=_get_ovs_hybrid_bridge_name(neutron_port))
|
||||
else:
|
||||
raise NotImplementedError(_LE(
|
||||
"Non-hybrid OVS VIF is not supported yet"))
|
||||
|
||||
return vif
|
||||
|
||||
|
||||
def neutron_to_osvif_vif(vif_plugin, neutron_port, subnets):
|
||||
"""Converts Neutron port to os-vif VIF object.
|
||||
|
||||
:param vif_plugin: name of the os-vif plugin to use
|
||||
:param neutron_port: dict containing port information as returned by
|
||||
neutron client
|
||||
:param subnets: subnet mapping as returned by PodSubnetsDriver.get_subnets
|
||||
:return: os-vif VIF object
|
||||
"""
|
||||
|
||||
try:
|
||||
mgr = _VIF_MANAGERS[vif_plugin]
|
||||
except KeyError:
|
||||
mgr = stv_driver.DriverManager(namespace=_VIF_TRANSLATOR_NAMESPACE,
|
||||
name=vif_plugin, invoke_on_load=False)
|
||||
_VIF_MANAGERS[vif_plugin] = mgr
|
||||
|
||||
return mgr.driver(vif_plugin, neutron_port, subnets)
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
import mock
|
||||
|
||||
from os_vif.objects import route as osv_route
|
||||
from oslo_config import cfg as o_cfg
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from kuryr_kubernetes import exceptions as k_exc
|
||||
from kuryr_kubernetes import os_vif_util as ovu
|
||||
from kuryr_kubernetes.tests import base as test_base
|
||||
|
||||
|
@ -115,3 +117,238 @@ class TestOSVIFUtils(test_base.TestCase):
|
|||
self.assertEqual(len(routes), len(route_list.objects))
|
||||
for route in route_list.objects:
|
||||
self.assertEqual(routes_map[str(route.cidr)], str(route.gateway))
|
||||
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._VIF_MANAGERS')
|
||||
def test_neutron_to_osvif_vif(self, m_mgrs):
|
||||
vif_plugin = mock.sentinel.vif_plugin
|
||||
port = mock.sentinel.port
|
||||
subnets = mock.sentinel.subnets
|
||||
m_mgr = mock.Mock()
|
||||
m_mgrs.__getitem__.return_value = m_mgr
|
||||
|
||||
ovu.neutron_to_osvif_vif(vif_plugin, port, subnets)
|
||||
|
||||
m_mgrs.__getitem__.assert_called_with(vif_plugin)
|
||||
m_mgr.driver.assert_called_with(vif_plugin, port, subnets)
|
||||
|
||||
@mock.patch('stevedore.driver.DriverManager')
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._VIF_MANAGERS')
|
||||
def test_neutron_to_osvif_vif_load(self, m_mgrs, m_stv_drm):
|
||||
vif_plugin = mock.sentinel.vif_plugin
|
||||
port = mock.sentinel.port
|
||||
subnets = mock.sentinel.subnets
|
||||
m_mgr = mock.Mock()
|
||||
m_mgrs.__getitem__.side_effect = KeyError
|
||||
m_stv_drm.return_value = m_mgr
|
||||
|
||||
ovu.neutron_to_osvif_vif(vif_plugin, port, subnets)
|
||||
|
||||
m_stv_drm.assert_called_once_with(
|
||||
namespace=ovu._VIF_TRANSLATOR_NAMESPACE,
|
||||
name=vif_plugin,
|
||||
invoke_on_load=False)
|
||||
m_mgrs.__setitem__.assert_called_once_with(vif_plugin, m_mgr)
|
||||
m_mgr.driver.assert_called_once_with(vif_plugin, port, subnets)
|
||||
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._get_ovs_hybrid_bridge_name')
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._get_vif_name')
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._is_port_active')
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._make_vif_network')
|
||||
@mock.patch('os_vif.objects.vif.VIFBridge')
|
||||
@mock.patch('os_vif.objects.vif.VIFPortProfileOpenVSwitch')
|
||||
def test_neutron_to_osvif_vif_ovs_hybrid(self,
|
||||
m_mk_profile,
|
||||
m_mk_vif,
|
||||
m_make_vif_network,
|
||||
m_is_port_active,
|
||||
m_get_vif_name,
|
||||
m_get_ovs_hybrid_bridge_name):
|
||||
vif_plugin = 'ovs'
|
||||
port_id = mock.sentinel.port_id
|
||||
mac_address = mock.sentinel.mac_address
|
||||
ovs_bridge = mock.sentinel.ovs_bridge
|
||||
port_filter = mock.sentinel.port_filter
|
||||
subnets = mock.sentinel.subnets
|
||||
port_profile = mock.sentinel.port_profile
|
||||
network = mock.sentinel.network
|
||||
port_active = mock.sentinel.port_active
|
||||
vif_name = mock.sentinel.vif_name
|
||||
hybrid_bridge = mock.sentinel.hybrid_bridge
|
||||
vif = mock.sentinel.vif
|
||||
|
||||
m_mk_profile.return_value = port_profile
|
||||
m_make_vif_network.return_value = network
|
||||
m_is_port_active.return_value = port_active
|
||||
m_get_vif_name.return_value = vif_name
|
||||
m_get_ovs_hybrid_bridge_name.return_value = hybrid_bridge
|
||||
m_mk_vif.return_value = vif
|
||||
|
||||
port = {'id': port_id,
|
||||
'mac_address': mac_address,
|
||||
'binding:vif_details': {
|
||||
'ovs_hybrid_plug': True,
|
||||
'bridge_name': ovs_bridge,
|
||||
'port_filter': port_filter},
|
||||
}
|
||||
|
||||
self.assertEqual(vif, ovu.neutron_to_osvif_vif_ovs(vif_plugin, port,
|
||||
subnets))
|
||||
|
||||
m_mk_profile.assert_called_once_with(interface_id=port_id)
|
||||
m_make_vif_network.assert_called_once_with(port, subnets)
|
||||
m_is_port_active.assert_called_once_with(port)
|
||||
m_get_ovs_hybrid_bridge_name.assert_called_once_with(port)
|
||||
m_get_vif_name.assert_called_once_with(port)
|
||||
self.assertEqual(ovs_bridge, network.bridge)
|
||||
m_mk_vif.assert_called_once_with(
|
||||
id=port_id,
|
||||
address=mac_address,
|
||||
network=network,
|
||||
has_traffic_filtering=port_filter,
|
||||
preserve_on_delete=False,
|
||||
active=port_active,
|
||||
port_profile=port_profile,
|
||||
plugin=vif_plugin,
|
||||
vif_name=vif_name,
|
||||
bridge_name=hybrid_bridge)
|
||||
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._make_vif_network')
|
||||
@mock.patch('os_vif.objects.vif.VIFPortProfileOpenVSwitch')
|
||||
def test_neutron_to_osvif_vif_ovs_native(self,
|
||||
m_mk_profile,
|
||||
m_make_vif_network):
|
||||
vif_plugin = 'ovs'
|
||||
port_id = mock.sentinel.port_id
|
||||
mac_address = mock.sentinel.mac_address
|
||||
ovs_bridge = mock.sentinel.ovs_bridge
|
||||
subnets = mock.sentinel.subnets
|
||||
port = {'id': port_id,
|
||||
'mac_address': mac_address,
|
||||
'binding:vif_details': {
|
||||
'ovs_hybrid_plug': False,
|
||||
'bridge_name': ovs_bridge},
|
||||
}
|
||||
|
||||
# TODO(ivc): implement proper tests once ovs-native VIFs are supported
|
||||
self.assertRaises(NotImplementedError, ovu.neutron_to_osvif_vif_ovs,
|
||||
vif_plugin, port, subnets)
|
||||
|
||||
def test_neutron_to_osvif_vif_ovs_no_bridge(self):
|
||||
vif_plugin = 'ovs'
|
||||
port = {'id': uuidutils.generate_uuid()}
|
||||
subnets = {}
|
||||
|
||||
self.assertRaises(o_cfg.RequiredOptError,
|
||||
ovu.neutron_to_osvif_vif_ovs,
|
||||
vif_plugin, port, subnets)
|
||||
|
||||
def test_get_ovs_hybrid_bridge_name(self):
|
||||
port_id = uuidutils.generate_uuid()
|
||||
port = {'id': port_id}
|
||||
|
||||
self.assertEqual("qbr" + port_id[:11],
|
||||
ovu._get_ovs_hybrid_bridge_name(port))
|
||||
|
||||
def test_is_port_active(self):
|
||||
port = {'status': 'ACTIVE'}
|
||||
|
||||
self.assertTrue(ovu._is_port_active(port))
|
||||
|
||||
def test_is_port_inactive(self):
|
||||
port = {'status': 'DOWN'}
|
||||
|
||||
self.assertFalse(ovu._is_port_active(port))
|
||||
|
||||
@mock.patch('kuryr.lib.binding.drivers.utils.get_veth_pair_names')
|
||||
def test_get_vif_name(self, m_get_veth_pair_names):
|
||||
port_id = mock.sentinel.port_id
|
||||
vif_name = mock.sentinel.vif_name
|
||||
port = {'id': port_id}
|
||||
m_get_veth_pair_names.return_value = (vif_name, mock.sentinel.any)
|
||||
|
||||
self.assertEqual(vif_name, ovu._get_vif_name(port))
|
||||
m_get_veth_pair_names.assert_called_once_with(port_id)
|
||||
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._make_vif_subnets')
|
||||
@mock.patch('os_vif.objects.subnet.SubnetList')
|
||||
def test_make_vif_network(self, m_mk_subnet_list, m_make_vif_subnets):
|
||||
network_id = mock.sentinel.network_id
|
||||
network = mock.Mock()
|
||||
orig_network = mock.Mock()
|
||||
orig_network.id = network_id
|
||||
orig_network.obj_clone.return_value = network
|
||||
subnet_id = mock.sentinel.subnet_id
|
||||
subnets = {subnet_id: orig_network}
|
||||
vif_subnets = mock.sentinel.vif_subnets
|
||||
subnet_list = mock.sentinel.subnet_list
|
||||
m_make_vif_subnets.return_value = vif_subnets
|
||||
m_mk_subnet_list.return_value = subnet_list
|
||||
port = {'network_id': network_id}
|
||||
|
||||
self.assertEqual(network, ovu._make_vif_network(port, subnets))
|
||||
self.assertEqual(subnet_list, network.subnets)
|
||||
m_make_vif_subnets.assert_called_once_with(port, subnets)
|
||||
m_mk_subnet_list.assert_called_once_with(objects=vif_subnets)
|
||||
|
||||
def test_make_vif_network_not_found(self):
|
||||
network_id = mock.sentinel.network_id
|
||||
port = {'network_id': network_id}
|
||||
subnets = {}
|
||||
|
||||
self.assertRaises(k_exc.IntegrityError, ovu._make_vif_network,
|
||||
port, subnets)
|
||||
|
||||
@mock.patch('kuryr_kubernetes.os_vif_util._make_vif_subnet')
|
||||
@mock.patch('os_vif.objects.fixed_ip.FixedIP')
|
||||
def test_make_vif_subnets(self, m_mk_fixed_ip, m_make_vif_subnet):
|
||||
subnet_id = mock.sentinel.subnet_id
|
||||
ip_address = mock.sentinel.ip_address
|
||||
fixed_ip = mock.sentinel.fixed_ip
|
||||
subnet = mock.Mock()
|
||||
subnets = mock.MagicMock()
|
||||
subnets.__contains__.return_value = True
|
||||
m_mk_fixed_ip.return_value = fixed_ip
|
||||
m_make_vif_subnet.return_value = subnet
|
||||
port = {'fixed_ips': [
|
||||
{'subnet_id': subnet_id, 'ip_address': ip_address}]}
|
||||
|
||||
self.assertEqual([subnet], ovu._make_vif_subnets(port, subnets))
|
||||
m_make_vif_subnet.assert_called_once_with(subnets, subnet_id)
|
||||
m_mk_fixed_ip.assert_called_once_with(address=ip_address)
|
||||
subnet.ips.objects.append.assert_called_once_with(fixed_ip)
|
||||
|
||||
def test_make_vif_subnets_not_found(self):
|
||||
subnet_id = mock.sentinel.subnet_id
|
||||
ip_address = mock.sentinel.ip_address
|
||||
subnets = mock.MagicMock()
|
||||
subnets.__contains__.return_value = False
|
||||
port = {'fixed_ips': [
|
||||
{'subnet_id': subnet_id, 'ip_address': ip_address}]}
|
||||
|
||||
self.assertRaises(k_exc.IntegrityError, ovu._make_vif_subnets,
|
||||
port, subnets)
|
||||
|
||||
@mock.patch('os_vif.objects.fixed_ip.FixedIPList')
|
||||
def test_make_vif_subnet(self, m_mk_fixed_ip_list):
|
||||
subnet_id = mock.sentinel.subnet_id
|
||||
fixed_ip_list = mock.sentinel.fixed_ip_list
|
||||
subnet = mock.Mock()
|
||||
orig_subnet = mock.Mock()
|
||||
orig_subnet.obj_clone.return_value = subnet
|
||||
orig_network = mock.Mock()
|
||||
orig_network.subnets.objects = [orig_subnet]
|
||||
m_mk_fixed_ip_list.return_value = fixed_ip_list
|
||||
subnets = {subnet_id: orig_network}
|
||||
|
||||
self.assertEqual(subnet, ovu._make_vif_subnet(subnets, subnet_id))
|
||||
self.assertEqual(fixed_ip_list, subnet.ips)
|
||||
m_mk_fixed_ip_list.assert_called_once_with(objects=[])
|
||||
|
||||
def test_make_vif_subnet_invalid(self):
|
||||
subnet_id = mock.sentinel.subnet_id
|
||||
orig_network = mock.Mock()
|
||||
orig_network.subnets.objects = []
|
||||
subnets = {subnet_id: orig_network}
|
||||
|
||||
self.assertRaises(k_exc.IntegrityError, ovu._make_vif_subnet,
|
||||
subnets, subnet_id)
|
||||
|
|
|
@ -26,6 +26,9 @@ oslo.config.opts =
|
|||
console_scripts =
|
||||
kuryr-k8s-controller = kuryr_kubernetes.cmd.eventlet.controller:start
|
||||
|
||||
kuryr_kubernetes.vif_translators =
|
||||
ovs = kuryr_kubernetes.os_vif_util:neutron_to_osvif_vif_ovs
|
||||
|
||||
kuryr_kubernetes.controller.drivers.pod_project =
|
||||
default = kuryr_kubernetes.controller.drivers.default_project:DefaultPodProjectDriver
|
||||
|
||||
|
|
Loading…
Reference in New Issue