From e8d102b500c7fbd5a0dfb8bd8dee82ff081a8678 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Fri, 22 Dec 2017 12:24:34 +0000 Subject: [PATCH] Add support for Windows network commands Added a network library dependant on the operating system. Windows and Linux OS are supported. The library is choosen automatically depending on Python ``os.name``. Linux library is based on ``ip`` commands and still relying on ``processutils`` library. Linux implementation can't use ``netifaces`` because this library doesn't provide the needed functionality. [1] will migrate all ``ip`` commands to ``pyroute2`` library. Windows library relies on Python's ``netifaces`` library because is enough for the reduced set of commands used. The only functionality implemented, to cover the bug resolution, is the device existence check. New functionalities could be added following, for example, the Neutron implementation. [1] https://review.openstack.org/#/c/484386/ Closes-Bug: #1672812 Change-Id: I84e3582135ed02137366c8f55f1dd1e4c115f0b5 --- os_vif/exception.py | 4 ++ os_vif/internal/command/ip/__init__.py | 5 +++ os_vif/internal/command/ip/api.py | 19 +++++--- os_vif/internal/command/ip/linux/__init__.py | 0 .../command/ip/{ => linux}/impl_pyroute2.py | 6 +++ .../internal/command/ip/windows/__init__.py | 0 .../command/ip/windows/impl_netifaces.py | 45 +++++++++++++++++++ .../internal/command/ip/test_impl_pyroute2.py | 2 +- .../internal/command/ip/linux/__init__.py | 0 .../ip/{ => linux}/test_impl_pyroute2.py | 2 +- .../internal/command/ip/windows/__init__.py | 0 .../command/ip/windows/test_impl_netifaces.py | 44 ++++++++++++++++++ vif_plug_linux_bridge/linux_net.py | 11 ++--- .../tests/unit/test_linux_net.py | 18 ++++---- vif_plug_ovs/linux_net.py | 11 ++--- vif_plug_ovs/ovs.py | 5 ++- vif_plug_ovs/tests/unit/test_linux_net.py | 16 +++---- vif_plug_ovs/tests/unit/test_plugin.py | 12 ++--- 18 files changed, 151 insertions(+), 49 deletions(-) create mode 100644 os_vif/internal/command/ip/linux/__init__.py rename os_vif/internal/command/ip/{ => linux}/impl_pyroute2.py (94%) create mode 100644 os_vif/internal/command/ip/windows/__init__.py create mode 100644 os_vif/internal/command/ip/windows/impl_netifaces.py create mode 100644 os_vif/tests/unit/internal/command/ip/linux/__init__.py rename os_vif/tests/unit/internal/command/ip/{ => linux}/test_impl_pyroute2.py (99%) create mode 100644 os_vif/tests/unit/internal/command/ip/windows/__init__.py create mode 100644 os_vif/tests/unit/internal/command/ip/windows/test_impl_netifaces.py diff --git a/os_vif/exception.py b/os_vif/exception.py index 1a21cf57..cc956f5e 100644 --- a/os_vif/exception.py +++ b/os_vif/exception.py @@ -94,3 +94,7 @@ class ExternalImport(ExceptionBase): msg_fmt = _("Use of this module outside of os_vif is not allowed. It must " "not be imported in os-vif plugins that are out of tree as it " "is not a public interface of os-vif.") + + +class NotImplementedForOS(ExceptionBase): + msg_fmt = _("Function %(function)s for %(os)s operating system") diff --git a/os_vif/internal/command/ip/__init__.py b/os_vif/internal/command/ip/__init__.py index d533d222..ad0339d9 100644 --- a/os_vif/internal/command/ip/__init__.py +++ b/os_vif/internal/command/ip/__init__.py @@ -32,3 +32,8 @@ def add(device, dev_type, check_exit_code=None, peer=None, link=None, def delete(device, check_exit_code=None): """Method to delete an interface.""" return api._get_impl().delete(device, check_exit_code=check_exit_code) + + +def exists(device): + """Method to check if an interface exists.""" + return api._get_impl().exists(device) diff --git a/os_vif/internal/command/ip/api.py b/os_vif/internal/command/ip/api.py index aa75387d..a7f2792f 100644 --- a/os_vif/internal/command/ip/api.py +++ b/os_vif/internal/command/ip/api.py @@ -11,11 +11,14 @@ # under the License. import abc +import os import six from oslo_log import log as logging from oslo_utils import importutils +from os_vif.internal.command.ip.windows import impl_netifaces as win_ip_lib + LOG = logging.getLogger(__name__) @@ -27,12 +30,16 @@ impl_map = { def _get_impl(): - # NOTE(sean-k-mooney): currently pyroute2 has a file handle leak. An - # iptools driver has been added as a workaround but No config options are - # exposed to the user. The iptools driver is considered deprecated and - # will be removed when a new release of pyroute2 is available. - driver = 'IPTools' - return importutils.import_object(impl_map[driver]) + if os.name == 'nt': + return win_ip_lib + else: + # NOTE(sean-k-mooney): currently pyroute2 has a file handle leak. An + # iptools driver has been added as a workaround but No config options + # are # exposed to the user. The iptools driver is considered + # deprecated and # will be removed when a new release of pyroute2 is + # available. + driver = 'IPTools' + return importutils.import_object(impl_map[driver]) @six.add_metaclass(abc.ABCMeta) diff --git a/os_vif/internal/command/ip/linux/__init__.py b/os_vif/internal/command/ip/linux/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/os_vif/internal/command/ip/impl_pyroute2.py b/os_vif/internal/command/ip/linux/impl_pyroute2.py similarity index 94% rename from os_vif/internal/command/ip/impl_pyroute2.py rename to os_vif/internal/command/ip/linux/impl_pyroute2.py index a229b917..d1e446a5 100644 --- a/os_vif/internal/command/ip/impl_pyroute2.py +++ b/os_vif/internal/command/ip/linux/impl_pyroute2.py @@ -92,3 +92,9 @@ class PyRoute2(api.IpCommand): idx = idx[0] return self._ip_link(ip, 'del', check_exit_code, **{'index': idx}) + + def exists(self, device): + """Return True if the device exists.""" + ip = iproute.IPRoute() + idx = ip.link_lookup(ifname=device) + return True if idx else False diff --git a/os_vif/internal/command/ip/windows/__init__.py b/os_vif/internal/command/ip/windows/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/os_vif/internal/command/ip/windows/impl_netifaces.py b/os_vif/internal/command/ip/windows/impl_netifaces.py new file mode 100644 index 00000000..eda20962 --- /dev/null +++ b/os_vif/internal/command/ip/windows/impl_netifaces.py @@ -0,0 +1,45 @@ +# Derived from: neutron/agent/windows/ip_lib.py +# +# 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 netifaces + +from oslo_log import log as logging + +from os_vif import exception + + +LOG = logging.getLogger(__name__) + + +def exists(device): + """Return True if the device exists in the namespace.""" + try: + return bool(netifaces.ifaddresses(device)) + except ValueError: + LOG.warning("The device does not exist on the system: %s", device) + except OSError: + LOG.error("Failed to get interface addresses: %s", device) + return False + + +def set(*args): + exception.NotImplementedForOS(function='ip.set', os='Windows') + + +def add(*args): + exception.NotImplementedForOS(function='ip.add', os='Windows') + + +def delete(*args): + exception.NotImplementedForOS(function='ip.delete', os='Windows') diff --git a/os_vif/tests/functional/internal/command/ip/test_impl_pyroute2.py b/os_vif/tests/functional/internal/command/ip/test_impl_pyroute2.py index 16353c7c..f891cb7c 100644 --- a/os_vif/tests/functional/internal/command/ip/test_impl_pyroute2.py +++ b/os_vif/tests/functional/internal/command/ip/test_impl_pyroute2.py @@ -15,7 +15,7 @@ import re from oslo_concurrency import processutils from oslo_utils import excutils -from os_vif.internal.command.ip import impl_pyroute2 +from os_vif.internal.command.ip.linux import impl_pyroute2 from os_vif.tests.functional import base from os_vif.tests.functional import privsep diff --git a/os_vif/tests/unit/internal/command/ip/linux/__init__.py b/os_vif/tests/unit/internal/command/ip/linux/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/os_vif/tests/unit/internal/command/ip/test_impl_pyroute2.py b/os_vif/tests/unit/internal/command/ip/linux/test_impl_pyroute2.py similarity index 99% rename from os_vif/tests/unit/internal/command/ip/test_impl_pyroute2.py rename to os_vif/tests/unit/internal/command/ip/linux/test_impl_pyroute2.py index 43adeb04..b28b0594 100644 --- a/os_vif/tests/unit/internal/command/ip/test_impl_pyroute2.py +++ b/os_vif/tests/unit/internal/command/ip/linux/test_impl_pyroute2.py @@ -16,7 +16,7 @@ from pyroute2.netlink import exceptions as ipexc from pyroute2.netlink.rtnl import ifinfmsg from os_vif import exception -from os_vif.internal.command.ip import impl_pyroute2 +from os_vif.internal.command.ip.linux import impl_pyroute2 from os_vif.tests.unit import base diff --git a/os_vif/tests/unit/internal/command/ip/windows/__init__.py b/os_vif/tests/unit/internal/command/ip/windows/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/os_vif/tests/unit/internal/command/ip/windows/test_impl_netifaces.py b/os_vif/tests/unit/internal/command/ip/windows/test_impl_netifaces.py new file mode 100644 index 00000000..71ddbec7 --- /dev/null +++ b/os_vif/tests/unit/internal/command/ip/windows/test_impl_netifaces.py @@ -0,0 +1,44 @@ +# 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 +import netifaces + +from os_vif.internal.command.ip.windows import impl_netifaces as ip_lib +from os_vif.tests.unit import base + + +class TestIPDevice(base.TestCase): + + def setUp(self): + super(TestIPDevice, self).setUp() + self.device_name = 'test_device' + self.mock_log = mock.patch.object(ip_lib, "LOG").start() + + @mock.patch.object(netifaces, 'ifaddresses', return_value=True) + def test_exists(self, mock_ifaddresses): + self.assertTrue(ip_lib.exists(self.device_name)) + mock_ifaddresses.assert_called_once_with(self.device_name) + + @mock.patch.object(netifaces, 'ifaddresses', side_effect=ValueError()) + def test_exists_not_found(self, mock_ifaddresses): + self.assertFalse(ip_lib.exists(self.device_name)) + mock_ifaddresses.assert_called_once_with(self.device_name) + self.mock_log.warning.assert_called_once_with( + "The device does not exist on the system: %s", self.device_name) + + @mock.patch.object(netifaces, 'ifaddresses', side_effect=OSError()) + def test_exists_os_error_exception(self, mock_ifaddresses): + self.assertFalse(ip_lib.exists(self.device_name)) + mock_ifaddresses.assert_called_once_with(self.device_name) + self.mock_log.error.assert_called_once_with( + "Failed to get interface addresses: %s", self.device_name) diff --git a/vif_plug_linux_bridge/linux_net.py b/vif_plug_linux_bridge/linux_net.py index 596b571d..5b3a3d32 100644 --- a/vif_plug_linux_bridge/linux_net.py +++ b/vif_plug_linux_bridge/linux_net.py @@ -34,11 +34,6 @@ LOG = logging.getLogger(__name__) _IPTABLES_MANAGER = None -def device_exists(device): - """Check if ethernet device exists.""" - return os.path.exists('/sys/class/net/%s' % device) - - def _set_device_mtu(dev, mtu): """Set the device MTU.""" if mtu: @@ -76,7 +71,7 @@ def _ensure_vlan_privileged(vlan_num, bridge_interface, mac_address, mtu): with elevated privileges. """ interface = 'vlan%s' % vlan_num - if not device_exists(interface): + if not ip_lib.exists(interface): LOG.debug('Starting VLAN interface %s', interface) ip_lib.add(interface, 'vlan', link=bridge_interface, vlan_id=vlan_num, check_exit_code=[0, 2, 254]) @@ -121,13 +116,13 @@ def _ensure_bridge_privileged(bridge, interface, net_attrs, gateway, interface onto the bridge and reset the default gateway if necessary. """ - if not device_exists(bridge): + if not ip_lib.exists(bridge): LOG.debug('Starting Bridge %s', bridge) try: processutils.execute('brctl', 'addbr', bridge) except Exception: with excutils.save_and_reraise_exception() as ectx: - ectx.reraise = not device_exists(bridge) + ectx.reraise = not ip_lib.exists(bridge) processutils.execute('brctl', 'setfd', bridge, 0) # processutils.execute('brctl setageing %s 10' % bridge) processutils.execute('brctl', 'stp', bridge, 'off') diff --git a/vif_plug_linux_bridge/tests/unit/test_linux_net.py b/vif_plug_linux_bridge/tests/unit/test_linux_net.py index dabb2354..214153b8 100644 --- a/vif_plug_linux_bridge/tests/unit/test_linux_net.py +++ b/vif_plug_linux_bridge/tests/unit/test_linux_net.py @@ -54,7 +54,7 @@ class LinuxNetTest(testtools.TestCase): @mock.patch.object(ip_lib, "add") @mock.patch.object(ip_lib, "set") - @mock.patch.object(linux_net, "device_exists", return_value=False) + @mock.patch.object(ip_lib, "exists", return_value=False) @mock.patch.object(linux_net, "_set_device_mtu") def test_ensure_vlan(self, mock_set_mtu, mock_dev_exists, mock_ip_set, mock_ip_add): @@ -73,23 +73,23 @@ class LinuxNetTest(testtools.TestCase): mock_set_mtu.assert_called_once_with('vlan123', 1500) @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", return_value=True) + @mock.patch.object(ip_lib, "exists", return_value=True) def test_ensure_bridge_exists(self, mock_dev_exists, mock_exec): linux_net.ensure_bridge("br0", None, filtering=False) mock_exec.assert_not_called() mock_dev_exists.assert_called_once_with("br0") + @mock.patch.object(ip_lib, "exists", return_value=False) @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", return_value=False) - def test_ensure_bridge_addbr_exception(self, mock_dev_exists, mock_exec): + def test_ensure_bridge_addbr_exception(self, mock_exec, mock_dev_exists): mock_exec.side_effect = ValueError() with testtools.ExpectedException(ValueError): linux_net.ensure_bridge("br0", None, filtering=False) @mock.patch.object(ip_lib, "set") @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", side_effect=[False, True]) + @mock.patch.object(ip_lib, "exists", side_effect=[False, True]) def test_ensure_bridge_concurrent_add(self, mock_dev_exists, mock_exec, mock_ip_set): mock_exec.side_effect = [ValueError(), 0, 0, 0] @@ -106,7 +106,7 @@ class LinuxNetTest(testtools.TestCase): @mock.patch.object(linux_net, "_set_device_mtu") @mock.patch.object(os.path, "exists", return_value=False) @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", return_value=False) + @mock.patch.object(ip_lib, "exists", return_value=False) def test_ensure_bridge_mtu_not_called(self, mock_dev_exists, mock_exec, mock_path_exists, mock_set_mtu, mock_ip_set): """This test validates that mtus are updated only if an interface @@ -121,7 +121,7 @@ class LinuxNetTest(testtools.TestCase): @mock.patch.object(linux_net, "_set_device_mtu") @mock.patch.object(os.path, "exists", return_value=False) @mock.patch.object(processutils, "execute", return_value=("", "")) - @mock.patch.object(linux_net, "device_exists", return_value=False) + @mock.patch.object(ip_lib, "exists", return_value=False) def test_ensure_bridge_mtu_order(self, mock_dev_exists, mock_exec, mock_path_exists, mock_set_mtu, mock_ip_set): """This test validates that when adding an interface @@ -141,7 +141,7 @@ class LinuxNetTest(testtools.TestCase): @mock.patch.object(ip_lib, "set") @mock.patch.object(os.path, "exists", return_value=False) @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", return_value=False) + @mock.patch.object(ip_lib, "exists", return_value=False) def test_ensure_bridge_new_ipv4(self, mock_dev_exists, mock_exec, mock_path_exists, mock_ip_set): linux_net.ensure_bridge("br0", None, filtering=False) @@ -156,7 +156,7 @@ class LinuxNetTest(testtools.TestCase): @mock.patch.object(ip_lib, "set") @mock.patch.object(os.path, "exists", return_value=True) @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", return_value=False) + @mock.patch.object(ip_lib, "exists", return_value=False) def test_ensure_bridge_new_ipv6(self, mock_dev_exists, mock_exec, mock_path_exists, mock_ip_set): linux_net.ensure_bridge("br0", None, filtering=False) diff --git a/vif_plug_ovs/linux_net.py b/vif_plug_ovs/linux_net.py index 6a0dbc58..9bef005f 100644 --- a/vif_plug_ovs/linux_net.py +++ b/vif_plug_ovs/linux_net.py @@ -113,11 +113,6 @@ def delete_ovs_vif_port(bridge, dev, timeout=None, _delete_net_dev(dev) -def device_exists(device): - """Check if ethernet device exists.""" - return os.path.exists('/sys/class/net/%s' % device) - - def interface_in_bridge(bridge, device): """Check if an ethernet device belongs to a Linux Bridge.""" return os.path.exists('/sys/class/net/%(bridge)s/brif/%(device)s' % @@ -126,7 +121,7 @@ def interface_in_bridge(bridge, device): def _delete_net_dev(dev): """Delete a network device only if it exists.""" - if device_exists(dev): + if ip_lib.exists(dev): try: ip_lib.delete(dev, check_exit_code=[0, 2, 254]) LOG.debug("Net device removed: '%s'", dev) @@ -166,7 +161,7 @@ def ensure_ovs_bridge(bridge, datapath_type, timeout=None, @privsep.vif_plug.entrypoint def ensure_bridge(bridge): - if not device_exists(bridge): + if not ip_lib.exists(bridge): processutils.execute('brctl', 'addbr', bridge) processutils.execute('brctl', 'setfd', bridge, 0) processutils.execute('brctl', 'stp', bridge, 'off') @@ -188,7 +183,7 @@ def ensure_bridge(bridge): @privsep.vif_plug.entrypoint def delete_bridge(bridge, dev): - if device_exists(bridge): + if ip_lib.exists(bridge): if interface_in_bridge(bridge, dev): processutils.execute('brctl', 'delif', bridge, dev) diff --git a/vif_plug_ovs/ovs.py b/vif_plug_ovs/ovs.py index 53c9618e..0cfe8b87 100644 --- a/vif_plug_ovs/ovs.py +++ b/vif_plug_ovs/ovs.py @@ -19,6 +19,7 @@ import sys +from os_vif.internal.command import ip as ip_lib from os_vif import objects from os_vif import plugin from oslo_config import cfg @@ -172,7 +173,7 @@ class OvsPlugin(plugin.PluginBase): linux_net.ensure_bridge(vif.bridge_name) mtu = self._get_mtu(vif) - if not linux_net.device_exists(v2_name): + if not ip_lib.exists(v2_name): linux_net.create_veth_pair(v1_name, v2_name, mtu) linux_net.add_bridge_port(vif.bridge_name, v1_name) linux_net.ensure_ovs_bridge(vif.network.bridge, @@ -187,7 +188,7 @@ class OvsPlugin(plugin.PluginBase): def _plug_vif_windows(self, vif, instance_info): """Create a per-VIF OVS port.""" - if not linux_net.device_exists(vif.id): + if not ip_lib.exists(vif.id): linux_net.ensure_ovs_bridge(vif.network.bridge, self._get_vif_datapath_type(vif)) self._create_vif_port(vif, vif.id, instance_info) diff --git a/vif_plug_ovs/tests/unit/test_linux_net.py b/vif_plug_ovs/tests/unit/test_linux_net.py index b0f71ee0..47ed9c08 100644 --- a/vif_plug_ovs/tests/unit/test_linux_net.py +++ b/vif_plug_ovs/tests/unit/test_linux_net.py @@ -32,7 +32,7 @@ class LinuxNetTest(testtools.TestCase): privsep.vif_plug.set_client_mode(False) @mock.patch.object(ip_lib, "set") - @mock.patch.object(linux_net, "device_exists", return_value=True) + @mock.patch.object(ip_lib, "exists", return_value=True) def test_ensure_bridge_exists(self, mock_dev_exists, mock_ip_set): linux_net.ensure_bridge("br0") @@ -43,7 +43,7 @@ class LinuxNetTest(testtools.TestCase): @mock.patch.object(ip_lib, "set") @mock.patch.object(os.path, "exists", return_value=False) @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", return_value=False) + @mock.patch.object(ip_lib, "exists", return_value=False) def test_ensure_bridge_new_ipv4(self, mock_dev_exists, mock_execute, mock_path_exists, mock_ip_set): linux_net.ensure_bridge("br0") @@ -62,11 +62,11 @@ class LinuxNetTest(testtools.TestCase): check_exit_code=[0, 2, 254]) @mock.patch.object(ip_lib, "set") + @mock.patch.object(ip_lib, "exists", return_value=False) @mock.patch.object(os.path, "exists", return_value=True) @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", return_value=False) - def test_ensure_bridge_new_ipv6(self, mock_dev_exists, mock_execute, - mock_path_exists, mock_ip_set): + def test_ensure_bridge_new_ipv6(self, mock_execute, mock_path_exists, + mock_dev_exists, mock_ip_set): linux_net.ensure_bridge("br0") calls = [ @@ -85,7 +85,7 @@ class LinuxNetTest(testtools.TestCase): check_exit_code=[0, 2, 254]) @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", return_value=False) + @mock.patch.object(ip_lib, "exists", return_value=False) @mock.patch.object(linux_net, "interface_in_bridge", return_value=False) def test_delete_bridge_none(self, mock_interface_br, mock_dev_exists, mock_execute,): @@ -97,7 +97,7 @@ class LinuxNetTest(testtools.TestCase): @mock.patch.object(ip_lib, "set") @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", return_value=True) + @mock.patch.object(ip_lib, "exists", return_value=True) @mock.patch.object(linux_net, "interface_in_bridge", return_value=True) def test_delete_bridge_exists(self, mock_interface_br, mock_dev_exists, mock_execute, mock_ip_set): @@ -113,7 +113,7 @@ class LinuxNetTest(testtools.TestCase): @mock.patch.object(ip_lib, "set") @mock.patch.object(processutils, "execute") - @mock.patch.object(linux_net, "device_exists", return_value=True) + @mock.patch.object(ip_lib, "exists", return_value=True) @mock.patch.object(linux_net, "interface_in_bridge", return_value=False) def test_delete_interface_not_present(self, mock_interface_br, mock_dev_exists, mock_execute, mock_ip_set): diff --git a/vif_plug_ovs/tests/unit/test_plugin.py b/vif_plug_ovs/tests/unit/test_plugin.py index c1754b2d..dc6cff04 100644 --- a/vif_plug_ovs/tests/unit/test_plugin.py +++ b/vif_plug_ovs/tests/unit/test_plugin.py @@ -13,6 +13,7 @@ import mock import testtools +from os_vif.internal.command import ip as ip_lib from os_vif import objects from os_vif.objects import fields @@ -167,7 +168,7 @@ class PluginTest(testtools.TestCase): @mock.patch.object(linux_net, 'add_bridge_port') @mock.patch.object(linux_net, 'update_veth_pair') @mock.patch.object(linux_net, 'create_veth_pair') - @mock.patch.object(linux_net, 'device_exists') + @mock.patch.object(ip_lib, 'exists') @mock.patch.object(linux_net, 'ensure_bridge') @mock.patch.object(ovs, 'sys') def test_plug_ovs_bridge(self, mock_sys, ensure_bridge, device_exists, @@ -222,7 +223,6 @@ class PluginTest(testtools.TestCase): # plugging existing devices should result in devices being updated device_exists.return_value = True - self.assertTrue(linux_net.device_exists('test')) plugin.plug(self.vif_ovs_hybrid, self.instance) create_veth_pair.assert_not_called() _create_vif_port.assert_not_called() @@ -231,13 +231,13 @@ class PluginTest(testtools.TestCase): @mock.patch.object(linux_net, 'ensure_ovs_bridge') @mock.patch.object(ovs.OvsPlugin, '_create_vif_port') - @mock.patch.object(linux_net, 'device_exists', return_value=False) + @mock.patch.object(ip_lib, 'exists', return_value=False) @mock.patch.object(ovs, 'sys') - def _check_plug_ovs_windows(self, vif, mock_sys, device_exists, + def _check_plug_ovs_windows(self, vif, mock_sys, mock_exists, _create_vif_port, ensure_ovs_bridge): dp_type = ovs.OvsPlugin._get_vif_datapath_type(vif) calls = { - 'device_exists': [mock.call(vif.id)], + 'exists': [mock.call(vif.id)], '_create_vif_port': [mock.call(vif, vif.id, self.instance)], 'ensure_ovs_bridge': [mock.call('br0', dp_type)] } @@ -245,7 +245,7 @@ class PluginTest(testtools.TestCase): mock_sys.platform = constants.PLATFORM_WIN32 plugin = ovs.OvsPlugin.load(constants.PLUGIN_NAME) plugin.plug(vif, self.instance) - device_exists.assert_has_calls(calls['device_exists']) + mock_exists.assert_has_calls(calls['exists']) _create_vif_port.assert_has_calls(calls['_create_vif_port']) ensure_ovs_bridge.assert_has_calls(calls['ensure_ovs_bridge'])