Merge "Switch create/delete interfaces to pyroute2"
This commit is contained in:
commit
3ff872b913
@ -167,10 +167,14 @@ class IPWrapper(SubProcessBase):
|
|||||||
return IPDevice(devices[0]['name'], namespace=self.namespace)
|
return IPDevice(devices[0]['name'], namespace=self.namespace)
|
||||||
|
|
||||||
def add_tuntap(self, name, mode='tap'):
|
def add_tuntap(self, name, mode='tap'):
|
||||||
self._as_root([], 'tuntap', ('add', name, 'mode', mode))
|
privileged.create_interface(
|
||||||
|
name, self.namespace, "tuntap", mode=mode)
|
||||||
return IPDevice(name, namespace=self.namespace)
|
return IPDevice(name, namespace=self.namespace)
|
||||||
|
|
||||||
def add_veth(self, name1, name2, namespace2=None):
|
def add_veth(self, name1, name2, namespace2=None):
|
||||||
|
# TODO(slaweq): switch to pyroute2 when issue
|
||||||
|
# https://github.com/svinota/pyroute2/issues/463
|
||||||
|
# will be closed
|
||||||
args = ['add', name1, 'type', 'veth', 'peer', 'name', name2]
|
args = ['add', name1, 'type', 'veth', 'peer', 'name', name2]
|
||||||
|
|
||||||
if namespace2 is None:
|
if namespace2 is None:
|
||||||
@ -185,18 +189,20 @@ class IPWrapper(SubProcessBase):
|
|||||||
IPDevice(name2, namespace=namespace2))
|
IPDevice(name2, namespace=namespace2))
|
||||||
|
|
||||||
def add_macvtap(self, name, src_dev, mode='bridge'):
|
def add_macvtap(self, name, src_dev, mode='bridge'):
|
||||||
args = ['add', 'link', src_dev, 'name', name, 'type', 'macvtap',
|
privileged.create_interface(name,
|
||||||
'mode', mode]
|
self.namespace,
|
||||||
self._as_root([], 'link', tuple(args))
|
"macvtap",
|
||||||
|
physical_interface=src_dev,
|
||||||
|
mode=mode)
|
||||||
return IPDevice(name, namespace=self.namespace)
|
return IPDevice(name, namespace=self.namespace)
|
||||||
|
|
||||||
def del_veth(self, name):
|
def del_veth(self, name):
|
||||||
"""Delete a virtual interface between two namespaces."""
|
"""Delete a virtual interface between two namespaces."""
|
||||||
self._as_root([], 'link', ('del', name))
|
privileged.delete_interface(name, self.namespace)
|
||||||
|
|
||||||
def add_dummy(self, name):
|
def add_dummy(self, name):
|
||||||
"""Create a Linux dummy interface with the given name."""
|
"""Create a Linux dummy interface with the given name."""
|
||||||
self._as_root([], 'link', ('add', name, 'type', 'dummy'))
|
privileged.create_interface(name, self.namespace, "dummy")
|
||||||
return IPDevice(name, namespace=self.namespace)
|
return IPDevice(name, namespace=self.namespace)
|
||||||
|
|
||||||
def ensure_namespace(self, name):
|
def ensure_namespace(self, name):
|
||||||
@ -224,35 +230,37 @@ class IPWrapper(SubProcessBase):
|
|||||||
device.link.set_netns(self.namespace)
|
device.link.set_netns(self.namespace)
|
||||||
|
|
||||||
def add_vlan(self, name, physical_interface, vlan_id):
|
def add_vlan(self, name, physical_interface, vlan_id):
|
||||||
cmd = ['add', 'link', physical_interface, 'name', name,
|
privileged.create_interface(name,
|
||||||
'type', 'vlan', 'id', vlan_id]
|
self.namespace,
|
||||||
self._as_root([], 'link', cmd)
|
"vlan",
|
||||||
|
physical_interface=physical_interface,
|
||||||
|
vlan_id=vlan_id)
|
||||||
return IPDevice(name, namespace=self.namespace)
|
return IPDevice(name, namespace=self.namespace)
|
||||||
|
|
||||||
def add_vxlan(self, name, vni, group=None, dev=None, ttl=None, tos=None,
|
def add_vxlan(self, name, vni, group=None, dev=None, ttl=None, tos=None,
|
||||||
local=None, srcport=None, dstport=None, proxy=False):
|
local=None, srcport=None, dstport=None, proxy=False):
|
||||||
cmd = ['add', name, 'type', 'vxlan', 'id', vni]
|
kwargs = {'vxlan_id': vni}
|
||||||
if group:
|
if group:
|
||||||
cmd.extend(['group', group])
|
kwargs['vxlan_group'] = group
|
||||||
if dev:
|
if dev:
|
||||||
cmd.extend(['dev', dev])
|
kwargs['physical_interface'] = dev
|
||||||
if ttl:
|
if ttl:
|
||||||
cmd.extend(['ttl', ttl])
|
kwargs['vxlan_ttl'] = ttl
|
||||||
if tos:
|
if tos:
|
||||||
cmd.extend(['tos', tos])
|
kwargs['vxlan_tos'] = tos
|
||||||
if local:
|
if local:
|
||||||
cmd.extend(['local', local])
|
kwargs['vxlan_local'] = local
|
||||||
if proxy:
|
if proxy:
|
||||||
cmd.append('proxy')
|
kwargs['vxlan_proxy'] = proxy
|
||||||
# tuple: min,max
|
# tuple: min,max
|
||||||
if srcport:
|
if srcport:
|
||||||
if len(srcport) == 2 and srcport[0] <= srcport[1]:
|
if len(srcport) == 2 and srcport[0] <= srcport[1]:
|
||||||
cmd.extend(['srcport', str(srcport[0]), str(srcport[1])])
|
kwargs['vxlan_port_range'] = (str(srcport[0]), str(srcport[1]))
|
||||||
else:
|
else:
|
||||||
raise n_exc.NetworkVxlanPortRangeError(vxlan_range=srcport)
|
raise n_exc.NetworkVxlanPortRangeError(vxlan_range=srcport)
|
||||||
if dstport:
|
if dstport:
|
||||||
cmd.extend(['dstport', str(dstport)])
|
kwargs['vxlan_port'] = str(dstport)
|
||||||
self._as_root([], 'link', cmd)
|
privileged.create_interface(name, self.namespace, "vxlan", **kwargs)
|
||||||
return (IPDevice(name, namespace=self.namespace))
|
return (IPDevice(name, namespace=self.namespace))
|
||||||
|
|
||||||
@removals.remove(version='Queens', removal_version='Rocky',
|
@removals.remove(version='Queens', removal_version='Rocky',
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
import errno
|
import errno
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
from neutron_lib import constants
|
||||||
import pyroute2
|
import pyroute2
|
||||||
from pyroute2.netlink import rtnl
|
from pyroute2.netlink import rtnl
|
||||||
from pyroute2.netlink.rtnl import ndmsg
|
from pyroute2.netlink.rtnl import ndmsg
|
||||||
@ -90,16 +91,33 @@ def _get_iproute(namespace):
|
|||||||
return pyroute2.IPRoute()
|
return pyroute2.IPRoute()
|
||||||
|
|
||||||
|
|
||||||
def _run_iproute_neigh(command, device, namespace, **kwargs):
|
def _get_link_id(device, namespace):
|
||||||
try:
|
try:
|
||||||
with _get_iproute(namespace) as ip:
|
with _get_iproute(namespace) as ip:
|
||||||
idx = ip.link_lookup(ifname=device)[0]
|
return ip.link_lookup(ifname=device)[0]
|
||||||
return ip.neigh(command, ifindex=idx, **kwargs)
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
msg = _("Network interface %(device)s not found in namespace "
|
msg = _("Network interface %(device)s not found in namespace "
|
||||||
"%(namespace)s.") % {'device': device,
|
"%(namespace)s.") % {'device': device,
|
||||||
'namespace': namespace}
|
'namespace': namespace}
|
||||||
raise NetworkInterfaceNotFound(msg)
|
raise NetworkInterfaceNotFound(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _run_iproute_link(command, device, namespace, **kwargs):
|
||||||
|
try:
|
||||||
|
with _get_iproute(namespace) as ip:
|
||||||
|
idx = _get_link_id(device, namespace)
|
||||||
|
return ip.link(command, index=idx, **kwargs)
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == errno.ENOENT:
|
||||||
|
raise NetworkNamespaceNotFound(netns_name=namespace)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def _run_iproute_neigh(command, device, namespace, **kwargs):
|
||||||
|
try:
|
||||||
|
with _get_iproute(namespace) as ip:
|
||||||
|
idx = _get_link_id(device, namespace)
|
||||||
|
return ip.neigh(command, ifindex=idx, **kwargs)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno == errno.ENOENT:
|
if e.errno == errno.ENOENT:
|
||||||
raise NetworkNamespaceNotFound(netns_name=namespace)
|
raise NetworkNamespaceNotFound(netns_name=namespace)
|
||||||
@ -109,13 +127,8 @@ def _run_iproute_neigh(command, device, namespace, **kwargs):
|
|||||||
def _run_iproute_addr(command, device, namespace, **kwargs):
|
def _run_iproute_addr(command, device, namespace, **kwargs):
|
||||||
try:
|
try:
|
||||||
with _get_iproute(namespace) as ip:
|
with _get_iproute(namespace) as ip:
|
||||||
idx = ip.link_lookup(ifname=device)[0]
|
idx = _get_link_id(device, namespace)
|
||||||
return ip.addr(command, index=idx, **kwargs)
|
return ip.addr(command, index=idx, **kwargs)
|
||||||
except IndexError:
|
|
||||||
msg = _("Network interface %(device)s not found in namespace "
|
|
||||||
"%(namespace)s.") % {'device': device,
|
|
||||||
'namespace': namespace}
|
|
||||||
raise NetworkInterfaceNotFound(msg)
|
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno == errno.ENOENT:
|
if e.errno == errno.ENOENT:
|
||||||
raise NetworkNamespaceNotFound(netns_name=namespace)
|
raise NetworkNamespaceNotFound(netns_name=namespace)
|
||||||
@ -152,19 +165,35 @@ def flush_ip_addresses(ip_version, device, namespace):
|
|||||||
family = _IP_VERSION_FAMILY_MAP[ip_version]
|
family = _IP_VERSION_FAMILY_MAP[ip_version]
|
||||||
try:
|
try:
|
||||||
with _get_iproute(namespace) as ip:
|
with _get_iproute(namespace) as ip:
|
||||||
idx = ip.link_lookup(ifname=device)[0]
|
idx = _get_link_id(device, namespace)
|
||||||
ip.flush_addr(index=idx, family=family)
|
ip.flush_addr(index=idx, family=family)
|
||||||
except IndexError:
|
|
||||||
msg = _("Network interface %(device)s not found in namespace "
|
|
||||||
"%(namespace)s.") % {'device': device,
|
|
||||||
'namespace': namespace}
|
|
||||||
raise NetworkInterfaceNotFound(msg)
|
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno == errno.ENOENT:
|
if e.errno == errno.ENOENT:
|
||||||
raise NetworkNamespaceNotFound(netns_name=namespace)
|
raise NetworkNamespaceNotFound(netns_name=namespace)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@privileged.default.entrypoint
|
||||||
|
def create_interface(ifname, namespace, kind, **kwargs):
|
||||||
|
ifname = ifname[:constants.DEVICE_NAME_MAX_LEN]
|
||||||
|
try:
|
||||||
|
with _get_iproute(namespace) as ip:
|
||||||
|
physical_interface = kwargs.pop("physical_interface", None)
|
||||||
|
if physical_interface:
|
||||||
|
link_key = "vxlan_link" if kind == "vxlan" else "link"
|
||||||
|
kwargs[link_key] = _get_link_id(physical_interface, namespace)
|
||||||
|
return ip.link("add", ifname=ifname, kind=kind, **kwargs)
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == errno.ENOENT:
|
||||||
|
raise NetworkNamespaceNotFound(netns_name=namespace)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@privileged.default.entrypoint
|
||||||
|
def delete_interface(ifname, namespace, **kwargs):
|
||||||
|
_run_iproute_link("del", ifname, namespace, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@privileged.default.entrypoint
|
@privileged.default.entrypoint
|
||||||
def add_neigh_entry(ip_version, ip_address, mac_address, device, namespace,
|
def add_neigh_entry(ip_version, ip_address, mac_address, device, namespace,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
@ -341,11 +341,10 @@ class TestIpWrapper(base.BaseTestCase):
|
|||||||
self.assertEqual(1, priv_listnetns.call_count)
|
self.assertEqual(1, priv_listnetns.call_count)
|
||||||
self.assertFalse(listnetns.called)
|
self.assertFalse(listnetns.called)
|
||||||
|
|
||||||
def test_add_tuntap(self):
|
@mock.patch.object(priv_lib, 'create_interface')
|
||||||
|
def test_add_tuntap(self, create):
|
||||||
ip_lib.IPWrapper().add_tuntap('tap0')
|
ip_lib.IPWrapper().add_tuntap('tap0')
|
||||||
self.execute.assert_called_once_with([], 'tuntap',
|
create.assert_called_once_with('tap0', None, 'tuntap', mode='tap')
|
||||||
('add', 'tap0', 'mode', 'tap'),
|
|
||||||
run_as_root=True, namespace=None)
|
|
||||||
|
|
||||||
def test_add_veth(self):
|
def test_add_veth(self):
|
||||||
ip_lib.IPWrapper().add_veth('tap0', 'tap1')
|
ip_lib.IPWrapper().add_veth('tap0', 'tap1')
|
||||||
@ -354,19 +353,17 @@ class TestIpWrapper(base.BaseTestCase):
|
|||||||
'peer', 'name', 'tap1'),
|
'peer', 'name', 'tap1'),
|
||||||
run_as_root=True, namespace=None)
|
run_as_root=True, namespace=None)
|
||||||
|
|
||||||
def test_add_macvtap(self):
|
@mock.patch.object(priv_lib, 'create_interface')
|
||||||
|
def test_add_macvtap(self, create):
|
||||||
ip_lib.IPWrapper().add_macvtap('macvtap0', 'eth0', 'bridge')
|
ip_lib.IPWrapper().add_macvtap('macvtap0', 'eth0', 'bridge')
|
||||||
self.execute.assert_called_once_with([], 'link',
|
create.assert_called_once_with(
|
||||||
('add', 'link', 'eth0', 'name',
|
'macvtap0', None, 'macvtap', physical_interface='eth0',
|
||||||
'macvtap0', 'type', 'macvtap',
|
mode='bridge')
|
||||||
'mode', 'bridge'),
|
|
||||||
run_as_root=True, namespace=None)
|
|
||||||
|
|
||||||
def test_del_veth(self):
|
@mock.patch.object(priv_lib, 'delete_interface')
|
||||||
|
def test_del_veth(self, delete):
|
||||||
ip_lib.IPWrapper().del_veth('fpr-1234')
|
ip_lib.IPWrapper().del_veth('fpr-1234')
|
||||||
self.execute.assert_called_once_with([], 'link',
|
delete.assert_called_once_with('fpr-1234', None)
|
||||||
('del', 'fpr-1234'),
|
|
||||||
run_as_root=True, namespace=None)
|
|
||||||
|
|
||||||
def test_add_veth_with_namespaces(self):
|
def test_add_veth_with_namespaces(self):
|
||||||
ns2 = 'ns2'
|
ns2 = 'ns2'
|
||||||
@ -379,12 +376,10 @@ class TestIpWrapper(base.BaseTestCase):
|
|||||||
'netns', ns2),
|
'netns', ns2),
|
||||||
run_as_root=True, namespace=None)
|
run_as_root=True, namespace=None)
|
||||||
|
|
||||||
def test_add_dummy(self):
|
@mock.patch.object(priv_lib, 'create_interface')
|
||||||
|
def test_add_dummy(self, create):
|
||||||
ip_lib.IPWrapper().add_dummy('dummy0')
|
ip_lib.IPWrapper().add_dummy('dummy0')
|
||||||
self.execute.assert_called_once_with([], 'link',
|
create.assert_called_once_with('dummy0', None, 'dummy')
|
||||||
('add', 'dummy0',
|
|
||||||
'type', 'dummy'),
|
|
||||||
run_as_root=True, namespace=None)
|
|
||||||
|
|
||||||
def test_get_device(self):
|
def test_get_device(self):
|
||||||
dev = ip_lib.IPWrapper(namespace='ns').device('eth0')
|
dev = ip_lib.IPWrapper(namespace='ns').device('eth0')
|
||||||
@ -477,17 +472,42 @@ class TestIpWrapper(base.BaseTestCase):
|
|||||||
self.assertNotIn(mock.call().delete('ns'),
|
self.assertNotIn(mock.call().delete('ns'),
|
||||||
ip_ns_cmd_cls.mock_calls)
|
ip_ns_cmd_cls.mock_calls)
|
||||||
|
|
||||||
def test_add_vlan(self):
|
@mock.patch.object(priv_lib, 'create_interface')
|
||||||
|
def test_add_vlan(self, create):
|
||||||
retval = ip_lib.IPWrapper().add_vlan('eth0.1', 'eth0', '1')
|
retval = ip_lib.IPWrapper().add_vlan('eth0.1', 'eth0', '1')
|
||||||
self.assertIsInstance(retval, ip_lib.IPDevice)
|
self.assertIsInstance(retval, ip_lib.IPDevice)
|
||||||
self.assertEqual(retval.name, 'eth0.1')
|
self.assertEqual(retval.name, 'eth0.1')
|
||||||
self.execute.assert_called_once_with([], 'link',
|
create.assert_called_once_with('eth0.1',
|
||||||
['add', 'link', 'eth0',
|
None,
|
||||||
'name', 'eth0.1',
|
'vlan',
|
||||||
'type', 'vlan', 'id', '1'],
|
physical_interface='eth0',
|
||||||
run_as_root=True, namespace=None)
|
vlan_id='1')
|
||||||
|
|
||||||
|
@mock.patch.object(priv_lib, 'create_interface')
|
||||||
|
def test_add_vxlan_valid_srcport_length(self, create):
|
||||||
|
self.call_params = {}
|
||||||
|
|
||||||
|
def fake_create_interface(ifname, namespace, kind, **kwargs):
|
||||||
|
self.call_params = dict(
|
||||||
|
ifname=ifname,
|
||||||
|
namespace=namespace,
|
||||||
|
kind=kind,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
create.side_effect = fake_create_interface
|
||||||
|
expected_call_params = {
|
||||||
|
'ifname': 'vxlan0',
|
||||||
|
'namespace': None,
|
||||||
|
'kind': 'vxlan',
|
||||||
|
'vxlan_id': 'vni0',
|
||||||
|
'vxlan_group': 'group0',
|
||||||
|
'physical_interface': 'dev0',
|
||||||
|
'vxlan_ttl': 'ttl0',
|
||||||
|
'vxlan_tos': 'tos0',
|
||||||
|
'vxlan_local': 'local0',
|
||||||
|
'vxlan_proxy': True,
|
||||||
|
'vxlan_port_range': ('1', '2')}
|
||||||
|
|
||||||
def test_add_vxlan_valid_srcport_length(self):
|
|
||||||
retval = ip_lib.IPWrapper().add_vxlan('vxlan0', 'vni0',
|
retval = ip_lib.IPWrapper().add_vxlan('vxlan0', 'vni0',
|
||||||
group='group0',
|
group='group0',
|
||||||
dev='dev0', ttl='ttl0',
|
dev='dev0', ttl='ttl0',
|
||||||
@ -496,14 +516,7 @@ class TestIpWrapper(base.BaseTestCase):
|
|||||||
srcport=(1, 2))
|
srcport=(1, 2))
|
||||||
self.assertIsInstance(retval, ip_lib.IPDevice)
|
self.assertIsInstance(retval, ip_lib.IPDevice)
|
||||||
self.assertEqual(retval.name, 'vxlan0')
|
self.assertEqual(retval.name, 'vxlan0')
|
||||||
self.execute.assert_called_once_with([], 'link',
|
self.assertDictEqual(expected_call_params, self.call_params)
|
||||||
['add', 'vxlan0', 'type',
|
|
||||||
'vxlan', 'id', 'vni0', 'group',
|
|
||||||
'group0', 'dev', 'dev0',
|
|
||||||
'ttl', 'ttl0', 'tos', 'tos0',
|
|
||||||
'local', 'local0', 'proxy',
|
|
||||||
'srcport', '1', '2'],
|
|
||||||
run_as_root=True, namespace=None)
|
|
||||||
|
|
||||||
def test_add_vxlan_invalid_srcport_length(self):
|
def test_add_vxlan_invalid_srcport_length(self):
|
||||||
wrapper = ip_lib.IPWrapper()
|
wrapper = ip_lib.IPWrapper()
|
||||||
@ -521,7 +534,32 @@ class TestIpWrapper(base.BaseTestCase):
|
|||||||
local='local0', proxy=True,
|
local='local0', proxy=True,
|
||||||
srcport=(2000, 1000))
|
srcport=(2000, 1000))
|
||||||
|
|
||||||
def test_add_vxlan_dstport(self):
|
@mock.patch.object(priv_lib, 'create_interface')
|
||||||
|
def test_add_vxlan_dstport(self, create):
|
||||||
|
self.call_params = {}
|
||||||
|
|
||||||
|
def fake_create_interface(ifname, namespace, kind, **kwargs):
|
||||||
|
self.call_params = dict(
|
||||||
|
ifname=ifname,
|
||||||
|
namespace=namespace,
|
||||||
|
kind=kind,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
create.side_effect = fake_create_interface
|
||||||
|
expected_call_params = {
|
||||||
|
'ifname': 'vxlan0',
|
||||||
|
'namespace': None,
|
||||||
|
'kind': 'vxlan',
|
||||||
|
'vxlan_id': 'vni0',
|
||||||
|
'vxlan_group': 'group0',
|
||||||
|
'physical_interface': 'dev0',
|
||||||
|
'vxlan_ttl': 'ttl0',
|
||||||
|
'vxlan_tos': 'tos0',
|
||||||
|
'vxlan_local': 'local0',
|
||||||
|
'vxlan_proxy': True,
|
||||||
|
'vxlan_port_range': ('1', '2'),
|
||||||
|
'vxlan_port': '4789'}
|
||||||
|
|
||||||
retval = ip_lib.IPWrapper().add_vxlan('vxlan0', 'vni0',
|
retval = ip_lib.IPWrapper().add_vxlan('vxlan0', 'vni0',
|
||||||
group='group0',
|
group='group0',
|
||||||
dev='dev0', ttl='ttl0',
|
dev='dev0', ttl='ttl0',
|
||||||
@ -532,15 +570,7 @@ class TestIpWrapper(base.BaseTestCase):
|
|||||||
|
|
||||||
self.assertIsInstance(retval, ip_lib.IPDevice)
|
self.assertIsInstance(retval, ip_lib.IPDevice)
|
||||||
self.assertEqual(retval.name, 'vxlan0')
|
self.assertEqual(retval.name, 'vxlan0')
|
||||||
self.execute.assert_called_once_with([], 'link',
|
self.assertDictEqual(expected_call_params, self.call_params)
|
||||||
['add', 'vxlan0', 'type',
|
|
||||||
'vxlan', 'id', 'vni0', 'group',
|
|
||||||
'group0', 'dev', 'dev0',
|
|
||||||
'ttl', 'ttl0', 'tos', 'tos0',
|
|
||||||
'local', 'local0', 'proxy',
|
|
||||||
'srcport', '1', '2',
|
|
||||||
'dstport', '4789'],
|
|
||||||
run_as_root=True, namespace=None)
|
|
||||||
|
|
||||||
def test_add_device_to_namespace(self):
|
def test_add_device_to_namespace(self):
|
||||||
dev = mock.Mock()
|
dev = mock.Mock()
|
||||||
|
@ -23,6 +23,54 @@ from neutron.tests import base
|
|||||||
|
|
||||||
class IpLibTestCase(base.BaseTestCase):
|
class IpLibTestCase(base.BaseTestCase):
|
||||||
|
|
||||||
|
def _test_run_iproute_link(self, namespace=None):
|
||||||
|
ip_obj = "NetNS" if namespace else "IPRoute"
|
||||||
|
with mock.patch.object(pyroute2, ip_obj) as ip_mock_cls:
|
||||||
|
ip_mock = ip_mock_cls()
|
||||||
|
ip_mock.__enter__().link_lookup.return_value = [2]
|
||||||
|
priv_lib._run_iproute_link("test_cmd", "eth0", namespace,
|
||||||
|
test_param="test_value")
|
||||||
|
ip_mock.assert_has_calls([
|
||||||
|
mock.call.__enter__().link_lookup(ifname="eth0"),
|
||||||
|
mock.call.__exit__(None, None, None),
|
||||||
|
mock.call.__enter__().link("test_cmd", index=2,
|
||||||
|
test_param="test_value")])
|
||||||
|
|
||||||
|
def test_run_iproute_link_no_namespace(self):
|
||||||
|
self._test_run_iproute_link()
|
||||||
|
|
||||||
|
def test_run_iproute_link_in_namespace(self):
|
||||||
|
self._test_run_iproute_link(namespace="testns")
|
||||||
|
|
||||||
|
def test_run_iproute_link_interface_not_exists(self):
|
||||||
|
with mock.patch.object(pyroute2, "IPRoute") as iproute_mock:
|
||||||
|
ip_mock = iproute_mock()
|
||||||
|
ip_mock.__enter__().link_lookup.return_value = []
|
||||||
|
self.assertRaises(
|
||||||
|
priv_lib.NetworkInterfaceNotFound,
|
||||||
|
priv_lib._run_iproute_link,
|
||||||
|
"test_cmd", "eth0", None, test_param="test_value")
|
||||||
|
|
||||||
|
def test_run_iproute_link_namespace_not_exists(self):
|
||||||
|
with mock.patch.object(pyroute2, "IPRoute") as iproute_mock:
|
||||||
|
iproute_mock.side_effect = OSError(
|
||||||
|
errno.ENOENT, "Test no netns exception")
|
||||||
|
self.assertRaises(
|
||||||
|
priv_lib.NetworkNamespaceNotFound,
|
||||||
|
priv_lib._run_iproute_link,
|
||||||
|
"test_cmd", "eth0", None, test_param="test_value")
|
||||||
|
|
||||||
|
def test_run_iproute_link_error(self):
|
||||||
|
with mock.patch.object(pyroute2, "IPRoute") as iproute_mock:
|
||||||
|
iproute_mock.side_effect = OSError(
|
||||||
|
errno.EINVAL, "Test invalid argument exception")
|
||||||
|
try:
|
||||||
|
priv_lib._run_iproute_link(
|
||||||
|
"test_cmd", "eth0", None, test_param="test_value")
|
||||||
|
self.fail("OSError exception not raised")
|
||||||
|
except OSError as e:
|
||||||
|
self.assertEqual(errno.EINVAL, e.errno)
|
||||||
|
|
||||||
def _test_run_iproute_neigh(self, namespace=None):
|
def _test_run_iproute_neigh(self, namespace=None):
|
||||||
ip_obj = "NetNS" if namespace else "IPRoute"
|
ip_obj = "NetNS" if namespace else "IPRoute"
|
||||||
with mock.patch.object(pyroute2, ip_obj) as ip_mock_cls:
|
with mock.patch.object(pyroute2, ip_obj) as ip_mock_cls:
|
||||||
@ -32,6 +80,7 @@ class IpLibTestCase(base.BaseTestCase):
|
|||||||
test_param="test_value")
|
test_param="test_value")
|
||||||
ip_mock.assert_has_calls([
|
ip_mock.assert_has_calls([
|
||||||
mock.call.__enter__().link_lookup(ifname="eth0"),
|
mock.call.__enter__().link_lookup(ifname="eth0"),
|
||||||
|
mock.call.__exit__(None, None, None),
|
||||||
mock.call.__enter__().neigh("test_cmd", ifindex=2,
|
mock.call.__enter__().neigh("test_cmd", ifindex=2,
|
||||||
test_param="test_value")])
|
test_param="test_value")])
|
||||||
|
|
||||||
@ -79,6 +128,7 @@ class IpLibTestCase(base.BaseTestCase):
|
|||||||
test_param="test_value")
|
test_param="test_value")
|
||||||
ip_mock.assert_has_calls([
|
ip_mock.assert_has_calls([
|
||||||
mock.call.__enter__().link_lookup(ifname="eth0"),
|
mock.call.__enter__().link_lookup(ifname="eth0"),
|
||||||
|
mock.call.__exit__(None, None, None),
|
||||||
mock.call.__enter__().addr("test_cmd", index=2,
|
mock.call.__enter__().addr("test_cmd", index=2,
|
||||||
test_param="test_value")])
|
test_param="test_value")])
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user