import eventlet
import netaddr
+import os
from oslo_config import cfg
from oslo_log import log as logging
LOOPBACK_DEVNAME = 'lo'
-# NOTE(ethuleau): depend of the version of iproute2, the vlan
-# interface details vary.
-VLAN_INTERFACE_DETAIL = ['vlan protocol 802.1q',
- 'vlan protocol 802.1Q',
- 'vlan id']
+
+SYS_NET_PATH = '/sys/class/net'
class SubProcessBase(object):
def get_devices(self, exclude_loopback=False):
retval = []
- output = self._run(['o', 'd'], 'link', ('list',))
- for line in output.split('\n'):
- if '<' not in line:
- continue
- tokens = line.split(' ', 2)
- if len(tokens) == 3:
- if any(v in tokens[2] for v in VLAN_INTERFACE_DETAIL):
- delimiter = '@'
- else:
- delimiter = ':'
- name = tokens[1].rpartition(delimiter)[0].strip()
+ if self.namespace:
+ # we call out manually because in order to avoid screen scraping
+ # iproute2 we use find to see what is in the sysfs directory, as
+ # suggested by Stephen Hemminger (iproute2 dev).
+ output = utils.execute(['ip', 'netns', 'exec', self.namespace,
+ 'find', SYS_NET_PATH, '-maxdepth', '1',
+ '-type', 'l', '-printf', '%f '],
+ run_as_root=True,
+ log_fail_as_error=self.log_fail_as_error
+ ).split()
+ else:
+ output = (
+ i for i in os.listdir(SYS_NET_PATH)
+ if os.path.islink(os.path.join(SYS_NET_PATH, i))
+ )
- if exclude_loopback and name == LOOPBACK_DEVNAME:
- continue
+ for name in output:
+ if exclude_loopback and name == LOOPBACK_DEVNAME:
+ continue
+ retval.append(IPDevice(name, namespace=self.namespace))
- retval.append(IPDevice(name, namespace=self.namespace))
return retval
def add_tuntap(self, name, mode='tap'):
import netaddr
from neutron.agent.linux import ip_lib
+from neutron.agent.linux import utils # noqa
from neutron.common import exceptions
from neutron.tests import base
self.execute_p = mock.patch.object(ip_lib.IPWrapper, '_execute')
self.execute = self.execute_p.start()
- def test_get_devices(self):
- self.execute.return_value = '\n'.join(LINK_SAMPLE)
+ @mock.patch('os.path.islink')
+ @mock.patch('os.listdir', return_value=['lo'])
+ def test_get_devices(self, mocked_listdir, mocked_islink):
retval = ip_lib.IPWrapper().get_devices()
- self.assertEqual(retval,
- [ip_lib.IPDevice('lo'),
- ip_lib.IPDevice('eth0'),
- ip_lib.IPDevice('br-int'),
- ip_lib.IPDevice('gw-ddc717df-49'),
- ip_lib.IPDevice('foo:foo'),
- ip_lib.IPDevice('foo@foo'),
- ip_lib.IPDevice('foo:foo@foo'),
- ip_lib.IPDevice('foo@foo:foo'),
- ip_lib.IPDevice('bar.9'),
- ip_lib.IPDevice('bar'),
- ip_lib.IPDevice('bar:bar'),
- ip_lib.IPDevice('bar@bar'),
- ip_lib.IPDevice('bar:bar@bar'),
- ip_lib.IPDevice('bar@bar:bar')])
-
- self.execute.assert_called_once_with(['o', 'd'], 'link', ('list',),
- log_fail_as_error=True)
-
- def test_get_devices_malformed_line(self):
- self.execute.return_value = '\n'.join(LINK_SAMPLE + ['gibberish'])
- retval = ip_lib.IPWrapper().get_devices()
- self.assertEqual(retval,
- [ip_lib.IPDevice('lo'),
- ip_lib.IPDevice('eth0'),
- ip_lib.IPDevice('br-int'),
- ip_lib.IPDevice('gw-ddc717df-49'),
- ip_lib.IPDevice('foo:foo'),
- ip_lib.IPDevice('foo@foo'),
- ip_lib.IPDevice('foo:foo@foo'),
- ip_lib.IPDevice('foo@foo:foo'),
- ip_lib.IPDevice('bar.9'),
- ip_lib.IPDevice('bar'),
- ip_lib.IPDevice('bar:bar'),
- ip_lib.IPDevice('bar@bar'),
- ip_lib.IPDevice('bar:bar@bar'),
- ip_lib.IPDevice('bar@bar:bar')])
-
- self.execute.assert_called_once_with(['o', 'd'], 'link', ('list',),
- log_fail_as_error=True)
+ mocked_islink.assert_called_once_with('/sys/class/net/lo')
+ self.assertEqual(retval, [ip_lib.IPDevice('lo')])
+
+ @mock.patch('neutron.agent.linux.utils.execute')
+ def test_get_devices_namespaces(self, mocked_execute):
+ fake_str = mock.Mock()
+ fake_str.split.return_value = ['lo']
+ mocked_execute.return_value = fake_str
+ retval = ip_lib.IPWrapper(namespace='foo').get_devices()
+ mocked_execute.assert_called_once_with(
+ ['ip', 'netns', 'exec', 'foo', 'find', '/sys/class/net',
+ '-maxdepth', '1', '-type', 'l', '-printf', '%f '],
+ run_as_root=True, log_fail_as_error=True)
+ self.assertTrue(fake_str.split.called)
+ self.assertEqual(retval, [ip_lib.IPDevice('lo', namespace='foo')])
def test_get_namespaces(self):
self.execute.return_value = '\n'.join(NETNS_SAMPLE)