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
This commit is contained in:
parent
3eded6ba37
commit
e8d102b500
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
0
os_vif/internal/command/ip/linux/__init__.py
Normal file
0
os_vif/internal/command/ip/linux/__init__.py
Normal file
@ -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
|
0
os_vif/internal/command/ip/windows/__init__.py
Normal file
0
os_vif/internal/command/ip/windows/__init__.py
Normal file
45
os_vif/internal/command/ip/windows/impl_netifaces.py
Normal file
45
os_vif/internal/command/ip/windows/impl_netifaces.py
Normal file
@ -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')
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
@ -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')
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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'])
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user