Nested-Containers: trunk subports management

Add support to create/remove subports when vlan driver is used.

Partially Implements blueprint containers-in-instances

Change-Id: I26dfa04657c4904bcb46ecdc35ef7d76a1e81b16
This commit is contained in:
Luis Tomas Bolivar 2016-11-25 12:04:26 +00:00
parent d7373184a4
commit d6c47ded71
12 changed files with 592 additions and 47 deletions

View File

@ -248,6 +248,48 @@ The bash script creates the following file if it is missing:
Note the root privilege is required for creating and deleting the veth pairs Note the root privilege is required for creating and deleting the veth pairs
with `pyroute2 <http://docs.pyroute2.org/>`_ to run. with `pyroute2 <http://docs.pyroute2.org/>`_ to run.
How to try out nested-containers locally
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Installing OpenStack running devstack with the desired local.conf file but
including the next to make use of OVS-firewall and enabling Trunk Ports::
[[post-config|/$Q_PLUGIN_CONF_FILE]]
[DEFAULT]
service_plugins=trunk
[securitygroup]
firewall_driver=openvswitch
2. Launch a VM with `Neutron trunk port.
<https://wiki.openstack.org/wiki/Neutron/TrunkPort>`
3. Inside the VM install kuryr and kuryr-libnetwork following the normal
installation steps (see above steps at `Installing Kuryr's libnetwork
driver`).
4. Reconfigure kuryr inside the VM to point to the neutron server and to use the
vlan driver::
- Configure `/etc/kuryr/kuryr.conf`::
[binding]
driver = kuryr.lib.binding.drivers.vlan
link_iface = eth0 # VM vNIC
[neutron]
auth_url = http://KEYSTONE_SERVER_IP:35357/v3/
username = admin
user_domain_name = Default
password = ADMIN_PASSWORD
project_name = service
project_domain_name = Default
auth_type = password
- Restart kuryr service inside the VM
Testing Kuryr Testing Kuryr
------------- -------------

View File

@ -208,22 +208,6 @@ def _create_port(endpoint_id, neutron_network_id, interface_mac, fixed_ips):
return rcvd_port['port'] return rcvd_port['port']
def _update_port(port, endpoint_id):
port['name'] = utils.get_neutron_port_name(endpoint_id)
try:
response_port = app.neutron.update_port(
port['id'],
{'port': {
'name': port['name'],
'device_owner': lib_const.DEVICE_OWNER,
'device_id': endpoint_id}})
except n_exceptions.NeutronClientException as ex:
app.logger.error(_LE("Error happened during updating a "
"Neutron port: %s"), ex)
raise
return response_port['port']
def _get_fixed_ips_by_interface_cidr(subnets, interface_cidrv4, def _get_fixed_ips_by_interface_cidr(subnets, interface_cidrv4,
interface_cidrv6, fixed_ips): interface_cidrv6, fixed_ips):
for subnet in subnets: for subnet in subnets:
@ -273,7 +257,7 @@ def _create_or_update_port(neutron_network_id, endpoint_id,
interface_mac, fixed_ips) interface_mac, fixed_ips)
elif num_port == 1: elif num_port == 1:
port = filtered_ports['ports'][0] port = filtered_ports['ports'][0]
response_port = _update_port(port, endpoint_id) response_port = app.driver.update_port(port, endpoint_id)
else: else:
raise n_exceptions.DuplicatedResourceException( raise n_exceptions.DuplicatedResourceException(
"Multiple ports exist for the cidrs {0} and {1}" "Multiple ports exist for the cidrs {0} and {1}"

View File

@ -49,3 +49,12 @@ class BaseNestedDriver(driver.Driver):
raise exceptions.KuryrException("Cannot find a Neutron port " raise exceptions.KuryrException("Cannot find a Neutron port "
"associated to interface name {0}".format(ifname)) "associated to interface name {0}".format(ifname))
def get_container_iface_name(self, neutron_port_id):
"""Returns interface name of a container in the default namespace.
:param neutron_port_id: The ID of a neutron port as string
:returns: interface name as string.
"""
_, container_iface_name = utils.get_veth_pair_names(neutron_port_id)
return container_iface_name

View File

@ -15,8 +15,14 @@ import six
from oslo_utils import importutils from oslo_utils import importutils
from neutronclient.common import exceptions as n_exceptions
from kuryr.lib._i18n import _LE
from kuryr.lib import constants as lib_const
from kuryr.lib import exceptions from kuryr.lib import exceptions
from kuryr_libnetwork import app
from kuryr_libnetwork import config from kuryr_libnetwork import config
from kuryr_libnetwork import utils as libnet_utils
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
@ -106,6 +112,32 @@ class Driver(object):
""" """
raise NotImplementedError() raise NotImplementedError()
def update_port(self, port, endpoint_id):
"""Updates port information and performs extra driver-specific actions.
It returns the updated port dictionary after the required actions
performed depending on the binding driver.
:param port: a neutron port dictionary returned from
python-neutronclient
:param endpoint_id: the ID of the endpoint as string
:returns: the updated Neutron port id dictionary as returned by
python-neutronclient
"""
port['name'] = libnet_utils.get_neutron_port_name(endpoint_id)
try:
response_port = app.neutron.update_port(port['id'],
{'port': {
'name': port['name'],
'device_owner': lib_const.DEVICE_OWNER,
'device_id': endpoint_id
}})
except n_exceptions.NeutronClientException as ex:
app.logger.error(_LE("Error happened during updating a "
"Neutron port: %s"), ex)
raise
return response_port['port']
def __str__(self): def __str__(self):
return self.__class__.__name__ return self.__class__.__name__

View File

@ -15,7 +15,6 @@ from oslo_log import log
from kuryr.lib._i18n import _LE from kuryr.lib._i18n import _LE
from kuryr.lib import binding from kuryr.lib import binding
from kuryr.lib.binding.drivers import utils
from kuryr.lib import exceptions from kuryr.lib import exceptions
from kuryr_libnetwork import app from kuryr_libnetwork import app
@ -121,15 +120,6 @@ class NestedDriver(base.BaseNestedDriver):
self._remove_from_allowed_address_pairs(vm_port, container_ips) self._remove_from_allowed_address_pairs(vm_port, container_ips)
return binding.port_unbind(endpoint_id, neutron_port) return binding.port_unbind(endpoint_id, neutron_port)
def get_container_iface_name(self, neutron_port_id):
"""Returns interface name of a container in the default namespace.
:param neutron_port_id: The ID of a neutron port as string
:returns: interface name as string
"""
_, container_iface_name = utils.get_veth_pair_names(neutron_port_id)
return container_iface_name
def _add_to_allowed_address_pairs(self, port, ip_addresses, def _add_to_allowed_address_pairs(self, port, ip_addresses,
mac_address=None): mac_address=None):
address_pairs = port['allowed_address_pairs'] address_pairs = port['allowed_address_pairs']

View File

@ -12,6 +12,7 @@
from kuryr.lib import binding from kuryr.lib import binding
from kuryr.lib.binding.drivers import utils from kuryr.lib.binding.drivers import utils
from kuryr_libnetwork.port_driver import driver from kuryr_libnetwork.port_driver import driver

View File

@ -0,0 +1,172 @@
# 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 neutronclient.common import exceptions as n_exceptions
from oslo_log import log
from kuryr.lib._i18n import _LE
from kuryr.lib import binding
from kuryr.lib import exceptions
from kuryr.lib import segmentation_type_drivers as seg_driver
from kuryr_libnetwork import app
from kuryr_libnetwork.port_driver import base
LOG = log.getLogger(__name__)
class VlanDriver(base.BaseNestedDriver):
"""Driver for container-in-VM deployments with Trunk Ports."""
BINDING_DRIVERS = ('vlan',)
def __init__(self):
super(VlanDriver, self).__init__()
self.port_vlan_dic = {}
self.trunk_port = self._get_port_from_host_iface(self.link_iface)
self._check_for_vlan_ids()
def _check_for_vlan_ids(self):
"""Gathers information about vlans already in use."""
for subport in self.trunk_port['trunk_details']['sub_ports']:
self.port_vlan_dic[subport['port_id']] = subport['segmentation_id']
def get_supported_bindings(self):
"""Returns a tuple of supported binding driver names for the driver.
:returns: a tuple of strings
"""
return self.BINDING_DRIVERS
def get_default_network_id(self):
"""Returns a Neutron network ID as per driver logic, if any.
:returns: the Neutron network UUID as a string
:raises: exceptions.KuryrException
"""
return None
def update_port(self, port, endpoint_id):
segmentation_id = self._get_segmentation_id(port['id'])
self._attach_subport(self.trunk_port['trunk_details']['trunk_id'],
port['id'],
segmentation_id)
return super(VlanDriver, self).update_port(port, endpoint_id)
def create_host_iface(self, endpoint_id, neutron_port, subnets,
network=None):
"""Instantiates a host interface and binds it to the host.
A host linked interface will be created for the specific Neutron port
by delegating to the pre-selected kuryr-lib driver.
This driver will attach the port to the trunk port as a subport by
using a segmentation id available.
:param endpoint_id: the ID of the endpoint as string
:param neutron_port: the container Neutron port dictionary as returned
by python-neutronclient
:param subnets: an iterable of all the Neutron subnets which the
endpoint is trying to join
:param network: the Neutron network which the endpoint is trying
to join
:returns: the tuple of stdout and stderr returned by
processutils.execute invoked
with the executable script for binding
:raises: exceptions.VethCreationFailure,
exceptions.KuryrException,
n_exceptions.NeutronClientException,
processutils.ProcessExecutionError
"""
container_ips = neutron_port['fixed_ips']
if not container_ips:
raise exceptions.KuryrException(
"Neutron port {0} does not have fixed_ips."
.format(neutron_port['id']))
vm_port = self._get_port_from_host_iface(self.link_iface)
segmentation_id = self._get_segmentation_id(neutron_port['id'])
_, _, (stdout, stderr) = binding.port_bind(
endpoint_id, neutron_port, subnets, network, vm_port,
segmentation_id)
return (stdout, stderr)
def delete_host_iface(self, endpoint_id, neutron_port):
"""Deletes a host interface after unbinding it from the host.
The host Slave interface associated to the Neutron port will be deleted
by delegating to the selected kuryr-lib driver.
This driver will also remove the subport attached to the trunk port
and will release its segmentation id
:param endpoint_id: the ID of the Docker container as string
:param neutron_port: a port dictionary returned from
python-neutronclient
:returns: the tuple of stdout and stderr returned
by processutils.execute invoked with the executable script
for unbinding
:raises: exceptions.VethDeletionFailure,
exceptions.KuryrException,
n_exceptions.NeutronClientException,
processutils.ProcessExecutionError,
"""
vm_port = self._get_port_from_host_iface(self.link_iface)
stdout, stderr = binding.port_unbind(endpoint_id, neutron_port)
subports = [{'port_id': neutron_port['id']}]
try:
app.neutron.trunk_remove_subports(
vm_port['trunk_details']['trunk_id'],
{'sub_ports': subports})
except n_exceptions.NeutronClientException as ex:
app.logger.error(_LE("Error happened during subport deletion "
"%(port_id)s: %(ex)s"),
{'port_id': neutron_port['id'], 'ex': ex})
raise
self._release_segmentation_id(neutron_port['id'])
return stdout, stderr
def _attach_subport(self, trunk_id, port_id, segmentation_id):
subport = [
{
'segmentation_id': segmentation_id,
'port_id': port_id,
'segmentation_type': 'vlan'
}
]
try:
app.neutron.trunk_add_subports(trunk_id, {'sub_ports': subport})
except n_exceptions.NeutronClientException as ex:
app.logger.error(_LE("Error happened adding subport %(port_id)s "
"to trunk port %(trunk_id)s: %(ex)s"),
port_id, trunk_id, ex)
raise
def _get_segmentation_id(self, id):
if id in self.port_vlan_dic.keys():
return self.port_vlan_dic[id]
seg_id = seg_driver.allocate_segmentation_id(
self.port_vlan_dic.values())
self.port_vlan_dic[id] = seg_id
return seg_id
def _release_segmentation_id(self, id):
seg_driver.release_segmentation_id(id)
del self.port_vlan_dic[id]
def _get_port_vlan(self, port_id):
return self.port_vlan_dic[port_id]

View File

@ -158,7 +158,8 @@ class TestKuryrBase(TestCase):
neutron_subnet_v6_id=None, neutron_subnet_v6_id=None,
neutron_subnet_v4_address="192.168.1.2", neutron_subnet_v4_address="192.168.1.2",
neutron_subnet_v6_address="fe80::f816:3eff:fe20:57c4", neutron_subnet_v6_address="fe80::f816:3eff:fe20:57c4",
device_owner=None): device_owner=None,
neutron_trunk_id=None):
# The following fake response is retrieved from the Neutron doc: # The following fake response is retrieved from the Neutron doc:
# http://developer.openstack.org/api-ref-networking-v2.html#createPort # noqa # http://developer.openstack.org/api-ref-networking-v2.html#createPort # noqa
fake_port = { fake_port = {
@ -188,6 +189,9 @@ class TestKuryrBase(TestCase):
"subnet_id": neutron_subnet_v6_id, "subnet_id": neutron_subnet_v6_id,
"ip_address": neutron_subnet_v6_address "ip_address": neutron_subnet_v6_address
}) })
if neutron_trunk_id:
fake_port['port']['trunk_details'] = {'trunk_id': neutron_trunk_id}
return fake_port return fake_port
@classmethod @classmethod

View File

@ -0,0 +1,319 @@
# 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.
import mock
from oslo_utils import uuidutils
from kuryr.lib import binding
from kuryr.lib.binding.drivers import utils
from kuryr.lib import constants as lib_const
from kuryr.lib import exceptions
from kuryr.lib import segmentation_type_drivers as seg_driver
from kuryr.lib import utils as lib_utils
from kuryr_libnetwork.port_driver.drivers import vlan
from kuryr_libnetwork.tests.unit import base
from kuryr_libnetwork import utils as libnet_utils
mock_interface = mock.MagicMock()
class TestVlanDriver(base.TestKuryrBase):
"""Unit tests for the VlanDriver port driver"""
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._check_for_vlan_ids')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._get_port_from_host_iface')
def test_get_supported_bindings(self, mock_trunk_port, mock_vlan_check):
mock_trunk_port.return_value = None
mock_vlan_check.return_value = None
vlan_driver = vlan.VlanDriver()
bindings = vlan_driver.get_supported_bindings()
self.assertEqual(bindings, vlan.VlanDriver.BINDING_DRIVERS)
@mock.patch('kuryr_libnetwork.config.CONF')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._check_for_vlan_ids')
@mock.patch.object(binding, 'port_bind')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._get_segmentation_id')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._get_port_from_host_iface')
def test_create_host_iface(self, mock_get_port_from_host,
mock_segmentation_id,
mock_port_bind, mock_vlan_check, mock_conf):
mock_vlan_check.return_value = None
fake_endpoint_id = lib_utils.get_hash()
fake_neutron_port_id = uuidutils.generate_uuid()
fake_neutron_net_id = uuidutils.generate_uuid()
fake_neutron_v4_subnet_id = uuidutils.generate_uuid()
fake_neutron_v6_subnet_id = uuidutils.generate_uuid()
fake_vm_port_id = uuidutils.generate_uuid()
fake_neutron_port = self._get_fake_port(
fake_endpoint_id, fake_neutron_net_id,
fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE,
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
'192.168.1.3', 'fe80::f816:3eff:fe1c:36a9')['port']
fake_neutron_port['mac_address'] = 'fa:16:3e:20:57:c3'
fake_vm_port = self._get_fake_port(
fake_endpoint_id, fake_neutron_net_id,
fake_vm_port_id, lib_const.PORT_STATUS_ACTIVE,
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
'192.168.1.2', 'fe80::f816:3eff:fe20:57c4')['port']
fake_vm_port['allowed_address_pairs'] = [
{'ip_address': '192.168.1.2',
'mac_address': fake_vm_port['mac_address']},
{'ip_address': 'fe80::f816:3eff:fe20:57c4',
'mac_address': fake_vm_port['mac_address']}]
fake_subnets = self._get_fake_subnets(
fake_endpoint_id, fake_neutron_net_id,
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)['subnets']
fake_network = mock.sentinel.binding_network
mock_conf.binding.link_iface = 'eth0'
fake_exec_response = ('fake_stdout', '')
fake_segmentation_id = 1
mock_port_bind.return_value = ('fake_host_ifname',
'fake_container_ifname', fake_exec_response)
mock_segmentation_id.return_value = fake_segmentation_id
mock_get_port_from_host.return_value = fake_vm_port
vlan_driver = vlan.VlanDriver()
response = vlan_driver.create_host_iface(fake_endpoint_id,
fake_neutron_port, fake_subnets, fake_network)
mock_get_port_from_host.assert_called_with(
mock_conf.binding.link_iface)
mock_port_bind.assert_called_with(fake_endpoint_id,
fake_neutron_port, fake_subnets, fake_network, fake_vm_port,
fake_segmentation_id)
mock_segmentation_id.assert_called_with(fake_neutron_port['id'])
self.assertEqual(response, fake_exec_response)
@mock.patch('kuryr_libnetwork.config.CONF')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._check_for_vlan_ids')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._release_segmentation_id')
@mock.patch.object(binding, 'port_unbind')
@mock.patch('kuryr_libnetwork.app.neutron.trunk_remove_subports')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._get_port_from_host_iface')
def test_delete_host_iface(self, mock_get_port_from_host,
mock_trunk_remove_subports, mock_port_unbind,
mock_release_seg_id, mock_vlan_check,
mock_conf):
mock_vlan_check.return_value = None
fake_endpoint_id = lib_utils.get_hash()
fake_neutron_port_id = uuidutils.generate_uuid()
fake_neutron_net_id = uuidutils.generate_uuid()
fake_neutron_trunk_id = uuidutils.generate_uuid()
fake_neutron_v4_subnet_id = uuidutils.generate_uuid()
fake_neutron_v6_subnet_id = uuidutils.generate_uuid()
fake_vm_port_id = uuidutils.generate_uuid()
fake_neutron_port = self._get_fake_port(
fake_endpoint_id, fake_neutron_net_id, fake_neutron_port_id,
lib_const.PORT_STATUS_ACTIVE,
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
'192.168.1.3', 'fe80::f816:3eff:fe1c:36a9')['port']
fake_neutron_port['mac_address'] = 'fa:16:3e:20:57:c3'
fake_vm_port = self._get_fake_port(
fake_endpoint_id, fake_neutron_net_id,
fake_vm_port_id, lib_const.PORT_STATUS_ACTIVE,
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
'192.168.1.2', 'fe80::f816:3eff:fe20:57c4',
None, fake_neutron_trunk_id)['port']
fake_vm_port['allowed_address_pairs'] = [
{'ip_address': '192.168.1.3',
'mac_address': fake_neutron_port['mac_address']},
{'ip_address': 'fe80::f816:3eff:fe1c:36a9',
'mac_address': fake_neutron_port['mac_address']}]
mock_conf.binding.link_iface = 'eth0'
fake_unbind_response = ('fake_stdout', '')
mock_get_port_from_host.return_value = fake_vm_port
mock_port_unbind.return_value = fake_unbind_response
vlan_driver = vlan.VlanDriver()
response = vlan_driver.delete_host_iface(fake_endpoint_id,
fake_neutron_port)
mock_get_port_from_host.assert_called_with(
mock_conf.binding.link_iface)
mock_port_unbind.assert_called_with(fake_endpoint_id,
fake_neutron_port)
mock_trunk_remove_subports.assert_called_with(fake_neutron_trunk_id,
{'sub_ports': [{
'port_id': fake_neutron_port_id
}]})
mock_release_seg_id.assert_called_with(fake_neutron_port_id)
self.assertEqual(response, fake_unbind_response)
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._check_for_vlan_ids')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._get_port_from_host_iface')
@mock.patch.object(utils, 'get_veth_pair_names',
return_value=("fake_host_ifname", "fake_container_name"))
def test_get_container_iface_name(self, mock_get_pair_names,
mock_trunk_port, mock_vlan_check):
mock_trunk_port.return_value = None
mock_vlan_check.return_value = None
vlan_driver = vlan.VlanDriver()
fake_neutron_port_id = uuidutils.generate_uuid()
response = vlan_driver.get_container_iface_name(fake_neutron_port_id)
mock_get_pair_names.assert_called_with(fake_neutron_port_id)
self.assertEqual(response, "fake_container_name")
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._check_for_vlan_ids')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._get_port_from_host_iface')
@mock.patch('kuryr_libnetwork.app.neutron.trunk_add_subports')
def test_attach_subport(self, mock_trunk_add_subports, mock_trunk_port,
mock_vlan_check):
mock_trunk_port.return_value = None
mock_vlan_check.return_value = None
fake_neutron_trunk_id = uuidutils.generate_uuid()
fake_neutron_port_id = uuidutils.generate_uuid()
fake_segmentation_id = 1
fake_subport = [
{
'segmentation_id': fake_segmentation_id,
'port_id': fake_neutron_port_id,
'segmentation_type': 'vlan'
}
]
vlan_driver = vlan.VlanDriver()
vlan_driver._attach_subport(fake_neutron_trunk_id,
fake_neutron_port_id,
fake_segmentation_id)
mock_trunk_add_subports.assert_called_with(fake_neutron_trunk_id,
{'sub_ports': fake_subport})
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._check_for_vlan_ids')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._get_port_from_host_iface')
@mock.patch.object(seg_driver, 'allocate_segmentation_id')
def test_get_segmentation_id(self, mock_alloc_seg_id, mock_trunk_port,
mock_vlan_check):
mock_trunk_port.return_value = None
mock_vlan_check.return_value = None
fake_neutron_port1_id = uuidutils.generate_uuid()
fake_neutron_port2_id = uuidutils.generate_uuid()
mock_alloc_seg_id.side_effect = [1, 2]
vlan_driver = vlan.VlanDriver()
response = vlan_driver._get_segmentation_id(fake_neutron_port1_id)
mock_alloc_seg_id.assert_called_once()
self.assertEqual(response, 1)
mock_alloc_seg_id.reset_mock()
response = vlan_driver._get_segmentation_id(fake_neutron_port1_id)
mock_alloc_seg_id.assert_not_called()
self.assertEqual(response, 1)
response = vlan_driver._get_segmentation_id(fake_neutron_port2_id)
mock_alloc_seg_id.assert_called_once()
self.assertEqual(response, 2)
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._check_for_vlan_ids')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._get_port_from_host_iface')
@mock.patch('kuryr_libnetwork.app.neutron.update_port')
@mock.patch.object(libnet_utils, 'get_neutron_port_name')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._attach_subport')
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._get_segmentation_id')
def test_update_port(self, mock_get_seg_id, mock_attach_subport,
mock_get_port_name, mock_update_port,
mock_get_port_from_host, mock_vlan_check):
fake_endpoint_id = lib_utils.get_hash()
fake_neutron_port_id = uuidutils.generate_uuid()
fake_neutron_net_id = uuidutils.generate_uuid()
fake_neutron_trunk_id = uuidutils.generate_uuid()
fake_neutron_v4_subnet_id = uuidutils.generate_uuid()
fake_neutron_v6_subnet_id = uuidutils.generate_uuid()
fake_vm_port_id = uuidutils.generate_uuid()
fake_neutron_port = self._get_fake_port(
fake_endpoint_id, fake_neutron_net_id,
fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE,
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
'192.168.1.3', 'fe80::f816:3eff:fe1c:36a9')['port']
fake_neutron_port['mac_address'] = 'fa:16:3e:20:57:c3'
fake_vm_port = self._get_fake_port(
fake_endpoint_id, fake_neutron_net_id,
fake_vm_port_id, lib_const.PORT_STATUS_ACTIVE,
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id,
'192.168.1.2', 'fe80::f816:3eff:fe20:57c4',
None, fake_neutron_trunk_id)['port']
fake_segmentation_id = 1
fake_port_name = 'port1'
mock_get_seg_id.return_value = fake_segmentation_id
mock_get_port_name.return_value = fake_port_name
mock_get_port_from_host.return_value = fake_vm_port
mock_vlan_check.return_value = None
vlan_driver = vlan.VlanDriver()
vlan_driver.update_port(fake_neutron_port, fake_endpoint_id)
mock_get_seg_id.assert_called_with(fake_neutron_port_id)
mock_get_port_name.assert_called_with(fake_endpoint_id)
mock_attach_subport.assert_called_with(fake_neutron_trunk_id,
fake_neutron_port_id,
fake_segmentation_id)
mock_update_port.assert_called_with(fake_neutron_port_id,
{'port': {
'name': fake_port_name,
'device_owner': lib_const.DEVICE_OWNER,
'device_id': fake_endpoint_id
}})
class TestVlanDriverFailures(base.TestKuryrFailures):
"""Unit tests for the VlanDriver port driver failures"""
@mock.patch('kuryr_libnetwork.port_driver.drivers.vlan'
'.VlanDriver._get_port_from_host_iface')
def test_create_host_iface(self, mock_get_port_from_host):
fake_endpoint_id = lib_utils.get_hash()
fake_neutron_port_id = uuidutils.generate_uuid()
fake_neutron_net_id = uuidutils.generate_uuid()
fake_neutron_port = self._get_fake_port(
fake_endpoint_id, fake_neutron_net_id,
fake_neutron_port_id, lib_const.PORT_STATUS_ACTIVE)['port']
vlan_driver = vlan.VlanDriver()
self.assertRaises(exceptions.KuryrException,
vlan_driver.create_host_iface, fake_endpoint_id,
fake_neutron_port, None)

View File

@ -35,6 +35,9 @@ class TestBaseDriver(d_base.BaseNestedDriver):
def get_supported_bindings(self): def get_supported_bindings(self):
pass pass
def update_port(self, neutron_port_id, endpoint_id):
pass
@ddt.ddt @ddt.ddt
class TestBaseNestedDriver(base.TestKuryrBase): class TestBaseNestedDriver(base.TestKuryrBase):

View File

@ -849,7 +849,7 @@ class TestKuryr(base.TestKuryrBase):
@mock.patch('kuryr_libnetwork.controllers.app.driver.create_host_iface') @mock.patch('kuryr_libnetwork.controllers.app.driver.create_host_iface')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_networks') @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_networks')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.show_port') @mock.patch('kuryr_libnetwork.controllers.app.neutron.show_port')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.update_port') @mock.patch('kuryr_libnetwork.controllers.app.driver.update_port')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_ports') @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_ports')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets') @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets')
@mock.patch('kuryr_libnetwork.controllers.app') @mock.patch('kuryr_libnetwork.controllers.app')
@ -922,7 +922,7 @@ class TestKuryr(base.TestKuryrBase):
fake_updated_port = fake_port_response['port'] fake_updated_port = fake_port_response['port']
fake_updated_port['name'] = utils.get_neutron_port_name( fake_updated_port['name'] = utils.get_neutron_port_name(
fake_docker_endpoint_id) fake_docker_endpoint_id)
mock_update_port.return_value = fake_port_response mock_update_port.return_value = fake_port_response['port']
fake_neutron_subnets = [fake_v4_subnet['subnet'], fake_neutron_subnets = [fake_v4_subnet['subnet'],
fake_v6_subnet['subnet']] fake_v6_subnet['subnet']]
@ -931,7 +931,6 @@ class TestKuryr(base.TestKuryrBase):
mock_create_host_iface.return_value = fake_create_iface_response mock_create_host_iface.return_value = fake_create_iface_response
if vif_plug_is_fatal: if vif_plug_is_fatal:
mock_vif.vif_plug_is_fatal = vif_plug_is_fatal
fake_neutron_ports_response_2 = self._get_fake_port( fake_neutron_ports_response_2 = self._get_fake_port(
fake_docker_endpoint_id, fake_neutron_net_id, fake_docker_endpoint_id, fake_neutron_net_id,
fake_port_id, lib_const.PORT_STATUS_ACTIVE, fake_port_id, lib_const.PORT_STATUS_ACTIVE,
@ -958,13 +957,8 @@ class TestKuryr(base.TestKuryrBase):
mock_list_subnets.assert_any_call( mock_list_subnets.assert_any_call(
network_id=fake_neutron_net_id, cidr='fe80::/64') network_id=fake_neutron_net_id, cidr='fe80::/64')
mock_list_ports.assert_called_with(fixed_ips=fake_fixed_ips) mock_list_ports.assert_called_with(fixed_ips=fake_fixed_ips)
mock_update_port.assert_called_with( mock_update_port.assert_called_with(fake_port_response['port'],
fake_updated_port['id'], fake_docker_endpoint_id)
{'port': {
'name': fake_updated_port['name'],
'device_owner': lib_const.DEVICE_OWNER,
'device_id': fake_docker_endpoint_id
}})
mock_list_networks.assert_any_call(tags=t) mock_list_networks.assert_any_call(tags=t)
mock_create_host_iface.assert_called_with(fake_docker_endpoint_id, mock_create_host_iface.assert_called_with(fake_docker_endpoint_id,
fake_updated_port, fake_neutron_subnets, fake_updated_port, fake_neutron_subnets,

View File

@ -105,7 +105,7 @@ class TestKuryrEndpointCreateFailures(base.TestKuryrFailures):
self.assertEqual({'Err': GivenException.message}, decoded_json) self.assertEqual({'Err': GivenException.message}, decoded_json)
@mock.patch('kuryr_libnetwork.controllers.app.driver.create_host_iface') @mock.patch('kuryr_libnetwork.controllers.app.driver.create_host_iface')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.update_port') @mock.patch('kuryr_libnetwork.controllers.app.driver.update_port')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets') @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_ports') @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_ports')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_networks') @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_networks')
@ -172,7 +172,7 @@ class TestKuryrEndpointCreateFailures(base.TestKuryrFailures):
fake_updated_port = fake_port_response['port'] fake_updated_port = fake_port_response['port']
fake_updated_port['name'] = utils.get_neutron_port_name( fake_updated_port['name'] = utils.get_neutron_port_name(
fake_docker_endpoint_id) fake_docker_endpoint_id)
mock_update_port.return_value = fake_port_response mock_update_port.return_value = fake_port_response['port']
fake_neutron_subnets = [fake_v4_subnet['subnet'], fake_neutron_subnets = [fake_v4_subnet['subnet'],
fake_v6_subnet['subnet']] fake_v6_subnet['subnet']]
@ -195,13 +195,8 @@ class TestKuryrEndpointCreateFailures(base.TestKuryrFailures):
mock.call(cidr='fe80::/64', network_id=fake_neutron_network_id)] mock.call(cidr='fe80::/64', network_id=fake_neutron_network_id)]
mock_list_subnets.assert_has_calls(expect_calls, any_order=True) mock_list_subnets.assert_has_calls(expect_calls, any_order=True)
mock_list_ports.assert_called_with(fixed_ips=fake_fixed_ips) mock_list_ports.assert_called_with(fixed_ips=fake_fixed_ips)
mock_update_port.assert_called_with( mock_update_port.assert_called_with(fake_port_response['port'],
fake_updated_port['id'], fake_docker_endpoint_id)
{'port': {
'name': fake_updated_port['name'],
'device_owner': lib_const.DEVICE_OWNER,
'device_id': fake_docker_endpoint_id
}})
mock_create_host_iface.assert_called_with( mock_create_host_iface.assert_called_with(
fake_docker_endpoint_id, fake_updated_port, fake_neutron_subnets, fake_docker_endpoint_id, fake_updated_port, fake_neutron_subnets,
fake_neutron_network['networks'][0]) fake_neutron_network['networks'][0])