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:
parent
d7373184a4
commit
d6c47ded71
42
README.rst
42
README.rst
@ -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
|
||||
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
|
||||
-------------
|
||||
|
||||
|
@ -208,22 +208,6 @@ def _create_port(endpoint_id, neutron_network_id, interface_mac, fixed_ips):
|
||||
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,
|
||||
interface_cidrv6, fixed_ips):
|
||||
for subnet in subnets:
|
||||
@ -273,7 +257,7 @@ def _create_or_update_port(neutron_network_id, endpoint_id,
|
||||
interface_mac, fixed_ips)
|
||||
elif num_port == 1:
|
||||
port = filtered_ports['ports'][0]
|
||||
response_port = _update_port(port, endpoint_id)
|
||||
response_port = app.driver.update_port(port, endpoint_id)
|
||||
else:
|
||||
raise n_exceptions.DuplicatedResourceException(
|
||||
"Multiple ports exist for the cidrs {0} and {1}"
|
||||
|
@ -49,3 +49,12 @@ class BaseNestedDriver(driver.Driver):
|
||||
|
||||
raise exceptions.KuryrException("Cannot find a Neutron port "
|
||||
"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
|
||||
|
@ -15,8 +15,14 @@ import six
|
||||
|
||||
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_libnetwork import app
|
||||
from kuryr_libnetwork import config
|
||||
from kuryr_libnetwork import utils as libnet_utils
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
@ -106,6 +112,32 @@ class Driver(object):
|
||||
"""
|
||||
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):
|
||||
return self.__class__.__name__
|
||||
|
||||
|
@ -15,7 +15,6 @@ from oslo_log import log
|
||||
|
||||
from kuryr.lib._i18n import _LE
|
||||
from kuryr.lib import binding
|
||||
from kuryr.lib.binding.drivers import utils
|
||||
from kuryr.lib import exceptions
|
||||
|
||||
from kuryr_libnetwork import app
|
||||
@ -121,15 +120,6 @@ class NestedDriver(base.BaseNestedDriver):
|
||||
self._remove_from_allowed_address_pairs(vm_port, container_ips)
|
||||
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,
|
||||
mac_address=None):
|
||||
address_pairs = port['allowed_address_pairs']
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
from kuryr.lib import binding
|
||||
from kuryr.lib.binding.drivers import utils
|
||||
|
||||
from kuryr_libnetwork.port_driver import driver
|
||||
|
||||
|
||||
|
172
kuryr_libnetwork/port_driver/drivers/vlan.py
Normal file
172
kuryr_libnetwork/port_driver/drivers/vlan.py
Normal 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]
|
@ -158,7 +158,8 @@ class TestKuryrBase(TestCase):
|
||||
neutron_subnet_v6_id=None,
|
||||
neutron_subnet_v4_address="192.168.1.2",
|
||||
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:
|
||||
# http://developer.openstack.org/api-ref-networking-v2.html#createPort # noqa
|
||||
fake_port = {
|
||||
@ -188,6 +189,9 @@ class TestKuryrBase(TestCase):
|
||||
"subnet_id": neutron_subnet_v6_id,
|
||||
"ip_address": neutron_subnet_v6_address
|
||||
})
|
||||
if neutron_trunk_id:
|
||||
fake_port['port']['trunk_details'] = {'trunk_id': neutron_trunk_id}
|
||||
|
||||
return fake_port
|
||||
|
||||
@classmethod
|
||||
|
319
kuryr_libnetwork/tests/unit/port_driver/drivers/test_vlan.py
Normal file
319
kuryr_libnetwork/tests/unit/port_driver/drivers/test_vlan.py
Normal 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)
|
@ -35,6 +35,9 @@ class TestBaseDriver(d_base.BaseNestedDriver):
|
||||
def get_supported_bindings(self):
|
||||
pass
|
||||
|
||||
def update_port(self, neutron_port_id, endpoint_id):
|
||||
pass
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestBaseNestedDriver(base.TestKuryrBase):
|
||||
|
@ -849,7 +849,7 @@ class TestKuryr(base.TestKuryrBase):
|
||||
@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.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_subnets')
|
||||
@mock.patch('kuryr_libnetwork.controllers.app')
|
||||
@ -922,7 +922,7 @@ class TestKuryr(base.TestKuryrBase):
|
||||
fake_updated_port = fake_port_response['port']
|
||||
fake_updated_port['name'] = utils.get_neutron_port_name(
|
||||
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_v6_subnet['subnet']]
|
||||
@ -931,7 +931,6 @@ class TestKuryr(base.TestKuryrBase):
|
||||
mock_create_host_iface.return_value = fake_create_iface_response
|
||||
|
||||
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_docker_endpoint_id, fake_neutron_net_id,
|
||||
fake_port_id, lib_const.PORT_STATUS_ACTIVE,
|
||||
@ -958,13 +957,8 @@ class TestKuryr(base.TestKuryrBase):
|
||||
mock_list_subnets.assert_any_call(
|
||||
network_id=fake_neutron_net_id, cidr='fe80::/64')
|
||||
mock_list_ports.assert_called_with(fixed_ips=fake_fixed_ips)
|
||||
mock_update_port.assert_called_with(
|
||||
fake_updated_port['id'],
|
||||
{'port': {
|
||||
'name': fake_updated_port['name'],
|
||||
'device_owner': lib_const.DEVICE_OWNER,
|
||||
'device_id': fake_docker_endpoint_id
|
||||
}})
|
||||
mock_update_port.assert_called_with(fake_port_response['port'],
|
||||
fake_docker_endpoint_id)
|
||||
mock_list_networks.assert_any_call(tags=t)
|
||||
mock_create_host_iface.assert_called_with(fake_docker_endpoint_id,
|
||||
fake_updated_port, fake_neutron_subnets,
|
||||
|
@ -105,7 +105,7 @@ class TestKuryrEndpointCreateFailures(base.TestKuryrFailures):
|
||||
self.assertEqual({'Err': GivenException.message}, decoded_json)
|
||||
|
||||
@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_ports')
|
||||
@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['name'] = utils.get_neutron_port_name(
|
||||
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_v6_subnet['subnet']]
|
||||
@ -195,13 +195,8 @@ class TestKuryrEndpointCreateFailures(base.TestKuryrFailures):
|
||||
mock.call(cidr='fe80::/64', network_id=fake_neutron_network_id)]
|
||||
mock_list_subnets.assert_has_calls(expect_calls, any_order=True)
|
||||
mock_list_ports.assert_called_with(fixed_ips=fake_fixed_ips)
|
||||
mock_update_port.assert_called_with(
|
||||
fake_updated_port['id'],
|
||||
{'port': {
|
||||
'name': fake_updated_port['name'],
|
||||
'device_owner': lib_const.DEVICE_OWNER,
|
||||
'device_id': fake_docker_endpoint_id
|
||||
}})
|
||||
mock_update_port.assert_called_with(fake_port_response['port'],
|
||||
fake_docker_endpoint_id)
|
||||
mock_create_host_iface.assert_called_with(
|
||||
fake_docker_endpoint_id, fake_updated_port, fake_neutron_subnets,
|
||||
fake_neutron_network['networks'][0])
|
||||
|
Loading…
Reference in New Issue
Block a user