Merge "resync: Adds Hyper-V OVS ViF driver"

This commit is contained in:
Jenkins 2017-01-23 10:19:49 +00:00 committed by Gerrit Code Review
commit 59adc9faed
10 changed files with 224 additions and 231 deletions

View File

@ -29,7 +29,7 @@ from os_win import utilsfactory
from oslo_log import log as logging
import six
from hyperv.i18n import _, _LE
from hyperv.i18n import _LE
from hyperv.nova import eventhandler
from hyperv.nova import hostops
from hyperv.nova import imagecache
@ -173,7 +173,7 @@ class HyperVDriver(driver.ComputeDriver):
def cleanup(self, context, instance, network_info, block_device_info=None,
destroy_disks=True, migrate_data=None, destroy_vifs=True):
"""Cleanup after instance being destroyed by Hypervisor."""
pass
self.unplug_vifs(instance, network_info)
def get_info(self, instance):
return self._vmops.get_info(instance)
@ -294,13 +294,11 @@ class HyperVDriver(driver.ComputeDriver):
def plug_vifs(self, instance, network_info):
"""Plug VIFs into networks."""
msg = _("VIF plugging is not supported by the Hyper-V driver.")
raise NotImplementedError(msg)
self._vmops.plug_vifs(instance, network_info)
def unplug_vifs(self, instance, network_info):
"""Unplug VIFs from networks."""
msg = _("VIF unplugging is not supported by the Hyper-V driver.")
raise NotImplementedError(msg)
self._vmops.unplug_vifs(instance, network_info)
def ensure_filtering_rules_for_instance(self, instance, network_info):
LOG.debug("ensure_filtering_rules_for_instance called",

View File

@ -123,7 +123,7 @@ class LiveMigrationOps(object):
network_info, block_migration):
LOG.debug("post_live_migration_at_destination called",
instance=instance_ref)
self._vmops.post_start_vifs(instance_ref, network_info)
self._vmops.plug_vifs(instance_ref, network_info)
def check_can_live_migrate_destination(self, ctxt, instance_ref,
src_compute_info, dst_compute_info,

View File

@ -1,65 +0,0 @@
# Copyright 2014 Cloudbase Solutions Srl
# All Rights Reserved.
#
# 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.
"""
Implements necessary OVS helper functions. These functions are similar
to the linux_net ones but have linux specific options, such as run_as_root
and delete_net_dev, removed.
This also allows us the flexibility to adapt to any future platform
specific differences.
"""
import os
from nova import exception
from nova import utils
from oslo_config import cfg
from oslo_log import log as logging
from hyperv.i18n import _LE
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
CONF.import_opt('ovs_vsctl_timeout', 'nova.conf.network')
def _ovs_vsctl(args):
full_args = ['ovs-vsctl', '--timeout=%s' % CONF.ovs_vsctl_timeout] + args
try:
return utils.execute(*full_args)
except Exception as e:
LOG.error(_LE("Unable to execute %(cmd)s. Exception: %(exception)s"),
{'cmd': full_args, 'exception': e})
raise exception.AgentError(method=full_args)
def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id):
_ovs_vsctl(['--', '--if-exists', 'del-port', dev, '--',
'add-port', bridge, dev,
'--', 'set', 'Interface', dev,
'external-ids:iface-id=%s' % iface_id,
'external-ids:iface-status=active',
'external-ids:attached-mac=%s' % mac,
'external-ids:vm-uuid=%s' % instance_id])
def delete_ovs_vif_port(bridge, dev):
_ovs_vsctl(['--', '--if-exists', 'del-port', bridge, dev])
def check_bridge_has_dev(bridge, dev, run_as_root=True):
ports = _ovs_vsctl(['--', 'list-ports', bridge])[0]
return dev in ports.split(os.linesep)

View File

@ -17,30 +17,28 @@
import abc
import nova.conf
from nova.network import model as network_model
from nova import exception
from nova.i18n import _
from nova.network import model
from nova.network import os_vif_util
import os_vif
from os_win import utilsfactory
from hyperv.nova import ovsutils
CONF = nova.conf.CONF
class HyperVBaseVIFDriver(object):
class HyperVBaseVIFPlugin(object):
@abc.abstractmethod
def plug(self, instance, vif):
pass
@abc.abstractmethod
def post_start(self, instance, vif):
pass
@abc.abstractmethod
def unplug(self, instance, vif):
pass
class HyperVNeutronVIFDriver(HyperVBaseVIFDriver):
"""Neutron VIF driver."""
class HyperVNeutronVIFPlugin(HyperVBaseVIFPlugin):
"""Neutron VIF plugin."""
def plug(self, instance, vif):
# Neutron takes care of plugging the port
@ -51,8 +49,8 @@ class HyperVNeutronVIFDriver(HyperVBaseVIFDriver):
pass
class HyperVNovaNetworkVIFDriver(HyperVBaseVIFDriver):
"""Nova network VIF driver."""
class HyperVNovaNetworkVIFPlugin(HyperVBaseVIFPlugin):
"""Nova network VIF plugin."""
def __init__(self):
self._netutils = utilsfactory.get_networkutils()
@ -66,42 +64,40 @@ class HyperVNovaNetworkVIFDriver(HyperVBaseVIFDriver):
pass
class HyperVOVSVIFDriver(HyperVNovaNetworkVIFDriver):
class HyperVVIFDriver(object):
def __init__(self):
self._netutils = utilsfactory.get_networkutils()
if nova.network.is_neutron():
self._vif_plugin = HyperVNeutronVIFPlugin()
else:
self._vif_plugin = HyperVNovaNetworkVIFPlugin()
def _get_bridge_name(self, vif):
return vif['network']['bridge']
def plug(self, instance, vif):
vif_type = vif['type']
if vif_type == model.VIF_TYPE_HYPERV:
self._vif_plugin.plug(instance, vif)
elif vif_type == model.VIF_TYPE_OVS:
vif = os_vif_util.nova_to_osvif_vif(vif)
instance = os_vif_util.nova_to_osvif_instance(instance)
def _get_ovs_interfaceid(self, vif):
return vif.get('ovs_interfaceid') or vif['id']
def post_start(self, instance, vif):
nic_name = vif['id']
bridge = self._get_bridge_name(vif)
if ovsutils.check_bridge_has_dev(bridge, nic_name,
run_as_root=False):
return
ovsutils.create_ovs_vif_port(
self._get_bridge_name(vif),
nic_name,
self._get_ovs_interfaceid(vif),
vif['address'],
instance.uuid)
# NOTE(claudiub): the vNIC has to be connected to a vSwitch
# before the ovs port is created.
self._netutils.connect_vnic_to_vswitch(CONF.hyperv.vswitch_name,
vif.id)
os_vif.plug(vif, instance)
else:
reason = _("Failed to plug virtual interface: "
"unexpected vif_type=%s") % vif_type
raise exception.VirtualInterfacePlugException(reason)
def unplug(self, instance, vif):
ovsutils.delete_ovs_vif_port(
self._get_bridge_name(vif),
vif['id'])
def get_vif_driver(vif_type):
# results should be cached. Creating a global driver map
# with instantiated classes will cause tests to fail on
# non windows platforms
if vif_type == network_model.VIF_TYPE_OVS:
return HyperVOVSVIFDriver()
if nova.network.is_neutron():
return HyperVNeutronVIFDriver()
else:
return HyperVNovaNetworkVIFDriver()
vif_type = vif['type']
if vif_type == model.VIF_TYPE_HYPERV:
self._vif_plugin.unplug(instance, vif)
elif vif_type == model.VIF_TYPE_OVS:
vif = os_vif_util.nova_to_osvif_vif(vif)
instance = os_vif_util.nova_to_osvif_instance(instance)
os_vif.unplug(vif, instance)
else:
reason = _("unexpected vif_type=%s") % vif_type
raise exception.VirtualInterfaceUnplugException(reason=reason)

View File

@ -100,6 +100,7 @@ class VMOps(object):
self._serial_console_ops = serialconsoleops.SerialConsoleOps()
self._block_dev_man = (
block_device_manager.BlockDeviceInfoManager())
self._vif_driver = vif_utils.HyperVVIFDriver()
self._pdk = pdk.PDK()
def list_instance_uuids(self):
@ -210,14 +211,6 @@ class VMOps(object):
return root_vhd_path
def _get_vif_driver(self, vif_type):
vif_driver = self._vif_driver_cache.get(vif_type)
if vif_driver:
return vif_driver
vif_driver = vif_utils.get_vif_driver(vif_type)
self._vif_driver_cache[vif_type] = vif_driver
return vif_driver
def _is_resize_needed(self, vhd_path, old_size, new_size, instance):
if new_size < old_size:
raise exception.FlavorDiskSmallerThanImage(
@ -414,8 +407,6 @@ class VMOps(object):
self._vmutils.create_nic(instance_name,
vif['id'],
vif['address'])
vif_driver = self._get_vif_driver(vif.get('type'))
vif_driver.plug(instance, vif)
if CONF.hyperv.enable_instance_metrics_collection:
self._metricsutils.enable_vm_metrics_collection(instance_name)
@ -715,6 +706,7 @@ class VMOps(object):
# Stop the VM first.
self._vmutils.stop_vm_jobs(instance_name)
self.power_off(instance)
self.unplug_vifs(instance, network_info)
self._vmutils.destroy_vm(instance_name)
self._volumeops.disconnect_volumes(block_device_info)
@ -723,7 +715,6 @@ class VMOps(object):
if destroy_disks:
self._delete_disk_files(instance_name)
self.unplug_vifs(instance, network_info)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE('Failed to destroy instance: %s'),
@ -837,7 +828,7 @@ class VMOps(object):
block_device_info)
self._set_vm_state(instance, os_win_const.HYPERV_VM_STATE_ENABLED)
self.post_start_vifs(instance, network_info)
self.plug_vifs(instance, network_info)
def _set_vm_state(self, instance, req_state):
instance_name = instance.name
@ -906,6 +897,16 @@ class VMOps(object):
for path in dvd_disk_paths:
self._pathutils.copyfile(path, dest_path)
def plug_vifs(self, instance, network_info):
if network_info:
for vif in network_info:
self._vif_driver.plug(instance, vif)
def unplug_vifs(self, instance, network_info):
if network_info:
for vif in network_info:
self._vif_driver.unplug(instance, vif)
def _get_image_serial_port_settings(self, image_meta):
image_props = image_meta['properties']
serial_ports = {}
@ -961,9 +962,7 @@ class VMOps(object):
LOG.debug('Attaching vif: %s', vif['id'], instance=instance)
self._vmutils.create_nic(instance.name, vif['id'], vif['address'])
vif_driver = self._get_vif_driver(vif.get('type'))
vif_driver.plug(instance, vif)
vif_driver.post_start(instance, vif)
self._vif_driver.plug(instance, vif)
def detach_interface(self, instance, vif):
try:
@ -972,8 +971,7 @@ class VMOps(object):
instance_uuid=instance.uuid)
LOG.debug('Detaching vif: %s', vif['id'], instance=instance)
vif_driver = self._get_vif_driver(vif.get('type'))
vif_driver.unplug(instance, vif)
self._vif_driver.unplug(instance, vif)
self._vmutils.destroy_nic(instance.name, vif['id'])
except os_win_exc.HyperVVMNotFoundException:
# TODO(claudiub): add set log level to error after string freeze.
@ -1115,18 +1113,6 @@ class VMOps(object):
filtered_specs[key] = value
return filtered_specs
def unplug_vifs(self, instance, network_info):
if network_info:
for vif in network_info:
vif_driver = self._get_vif_driver(vif.get('type'))
vif_driver.unplug(instance, vif)
def post_start_vifs(self, instance, network_info):
if network_info:
for vif in network_info:
vif_driver = self._get_vif_driver(vif.get('type'))
vif_driver.post_start(instance, vif)
def _configure_secure_vm(self, context, instance, image_meta,
secure_boot_enabled):
"""Adds and enables a vTPM, encrypting the disks.

View File

@ -183,6 +183,16 @@ class HyperVDriverTestCase(test_base.HyperVBaseTestCase):
mock.sentinel.instance, mock.sentinel.network_info,
mock.sentinel.block_device_info, mock.sentinel.destroy_disks)
def test_cleanup(self):
self.driver.cleanup(
mock.sentinel.context, mock.sentinel.instance,
mock.sentinel.network_info, mock.sentinel.block_device_info,
mock.sentinel.destroy_disks, mock.sentinel.migrate_data,
mock.sentinel.destroy_vifs)
self.driver._vmops.unplug_vifs.assert_called_once_with(
mock.sentinel.instance, mock.sentinel.network_info)
def test_get_info(self):
self.driver.get_info(mock.sentinel.instance)
self.driver._vmops.get_info.assert_called_once_with(
@ -384,12 +394,18 @@ class HyperVDriverTestCase(test_base.HyperVBaseTestCase):
mock.sentinel.dest_check_data)
def test_plug_vifs(self):
self.assertRaises(NotImplementedError, self.driver.plug_vifs,
mock.sentinel.instance, mock.sentinel.network_info)
self.driver.plug_vifs(
mock.sentinel.instance, mock.sentinel.network_info)
self.driver._vmops.plug_vifs.assert_called_once_with(
mock.sentinel.instance, mock.sentinel.network_info)
def test_unplug_vifs(self):
self.assertRaises(NotImplementedError, self.driver.unplug_vifs,
mock.sentinel.instance, mock.sentinel.network_info)
self.driver.unplug_vifs(
mock.sentinel.instance, mock.sentinel.network_info)
self.driver._vmops.unplug_vifs.assert_called_once_with(
mock.sentinel.instance, mock.sentinel.network_info)
def test_refresh_instance_security_rules(self):
self.assertRaises(NotImplementedError,

View File

@ -222,3 +222,12 @@ class LiveMigrationOpsTestCase(test_base.HyperVBaseTestCase):
self.assertEqual(mock_migr_data_cls.return_value, migr_data)
self.assertEqual(mock_check_shared_inst_dir.return_value,
migr_data.is_shared_instance_path)
@mock.patch.object(livemigrationops.vmops.VMOps, 'plug_vifs')
def test_post_live_migration_at_destination(self, mock_plug_vifs):
self._livemigrops.post_live_migration_at_destination(
self.context, mock.sentinel.instance,
network_info=mock.sentinel.NET_INFO,
block_migration=mock.sentinel.BLOCK_INFO)
mock_plug_vifs.assert_called_once_with(mock.sentinel.instance,
mock.sentinel.NET_INFO)

View File

@ -279,7 +279,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
self._migrationops._vmops.set_boot_order.assert_called_once_with(
mock_instance.name, get_image_vm_gen.return_value,
mock.sentinel.block_device_info)
self._vmops.power_on.assert_called_once_with(
self._migrationops._vmops.power_on.assert_called_once_with(
mock_instance, network_info=mock.sentinel.network_info)
def test_merge_base_vhd(self):

View File

@ -15,15 +15,21 @@
# under the License.
import mock
import nova.conf
from nova import exception
from nova.network import model
from hyperv.nova import vif
from hyperv.tests.unit import test_base
class HyperVNovaNetworkVIFDriverTestCase(test_base.HyperVBaseTestCase):
CONF = nova.conf.CONF
class HyperVNovaNetworkVIFPluginTestCase(test_base.HyperVBaseTestCase):
def setUp(self):
super(HyperVNovaNetworkVIFDriverTestCase, self).setUp()
self.vif_driver = vif.HyperVNovaNetworkVIFDriver()
super(HyperVNovaNetworkVIFPluginTestCase, self).setUp()
self.vif_driver = vif.HyperVNovaNetworkVIFPlugin()
def test_plug(self):
self.flags(vswitch_name='fake_vswitch_name', group='hyperv')
@ -33,3 +39,85 @@ class HyperVNovaNetworkVIFDriverTestCase(test_base.HyperVBaseTestCase):
netutils = self.vif_driver._netutils
netutils.connect_vnic_to_vswitch.assert_called_once_with(
'fake_vswitch_name', mock.sentinel.fake_id)
class HyperVVIFDriverTestCase(test_base.HyperVBaseTestCase):
def setUp(self):
super(HyperVVIFDriverTestCase, self).setUp()
self.vif_driver = vif.HyperVVIFDriver()
self.vif_driver._netutils = mock.MagicMock()
self.vif_driver._vif_plugin = mock.MagicMock()
@mock.patch.object(vif.nova.network, 'is_neutron')
def test_init_neutron(self, mock_is_neutron):
mock_is_neutron.return_value = True
driver = vif.HyperVVIFDriver()
self.assertIsInstance(driver._vif_plugin, vif.HyperVNeutronVIFPlugin)
@mock.patch.object(vif.nova.network, 'is_neutron')
def test_init_nova(self, mock_is_neutron):
mock_is_neutron.return_value = False
driver = vif.HyperVVIFDriver()
self.assertIsInstance(driver._vif_plugin,
vif.HyperVNovaNetworkVIFPlugin)
def test_plug(self):
vif = {'type': model.VIF_TYPE_HYPERV}
self.vif_driver.plug(mock.sentinel.instance, vif)
self.vif_driver._vif_plugin.plug.assert_called_once_with(
mock.sentinel.instance, vif)
@mock.patch.object(vif, 'os_vif')
@mock.patch.object(vif.os_vif_util, 'nova_to_osvif_instance')
@mock.patch.object(vif.os_vif_util, 'nova_to_osvif_vif')
def test_plug_ovs(self, mock_nova_to_osvif_vif,
mock_nova_to_osvif_instance, mock_os_vif):
vif = {'type': model.VIF_TYPE_OVS}
self.vif_driver.plug(mock.sentinel.instance, vif)
mock_nova_to_osvif_vif.assert_called_once_with(vif)
mock_nova_to_osvif_instance.assert_called_once_with(
mock.sentinel.instance)
connect_vnic = self.vif_driver._netutils.connect_vnic_to_vswitch
connect_vnic.assert_called_once_with(
CONF.hyperv.vswitch_name, mock_nova_to_osvif_vif.return_value.id)
mock_os_vif.plug.assert_called_once_with(
mock_nova_to_osvif_vif.return_value,
mock_nova_to_osvif_instance.return_value)
def test_plug_type_unknown(self):
vif = {'type': mock.sentinel.vif_type}
self.assertRaises(exception.VirtualInterfacePlugException,
self.vif_driver.plug,
mock.sentinel.instance, vif)
def test_unplug(self):
vif = {'type': model.VIF_TYPE_HYPERV}
self.vif_driver.unplug(mock.sentinel.instance, vif)
self.vif_driver._vif_plugin.unplug.assert_called_once_with(
mock.sentinel.instance, vif)
@mock.patch.object(vif, 'os_vif')
@mock.patch.object(vif.os_vif_util, 'nova_to_osvif_instance')
@mock.patch.object(vif.os_vif_util, 'nova_to_osvif_vif')
def test_unplug_ovs(self, mock_nova_to_osvif_vif,
mock_nova_to_osvif_instance, mock_os_vif):
vif = {'type': model.VIF_TYPE_OVS}
self.vif_driver.unplug(mock.sentinel.instance, vif)
mock_nova_to_osvif_vif.assert_called_once_with(vif)
mock_nova_to_osvif_instance.assert_called_once_with(
mock.sentinel.instance)
mock_os_vif.unplug.assert_called_once_with(
mock_nova_to_osvif_vif.return_value,
mock_nova_to_osvif_instance.return_value)
def test_unplug_type_unknown(self):
vif = {'type': mock.sentinel.vif_type}
self.assertRaises(exception.VirtualInterfaceUnplugException,
self.vif_driver.unplug,
mock.sentinel.instance, vif)

View File

@ -74,23 +74,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
self._vmops._pdk = mock.MagicMock()
self._vmops._serial_console_ops = mock.MagicMock()
self._vmops._block_dev_man = mock.MagicMock()
def test_get_vif_driver_cached(self):
self._vmops._vif_driver_cache = mock.MagicMock()
self._vmops._vif_driver_cache.get.return_value = mock.sentinel.VIF_DRV
self._vmops._get_vif_driver(mock.sentinel.VIF_TYPE)
self._vmops._vif_driver_cache.get.assert_called_with(
mock.sentinel.VIF_TYPE)
@mock.patch('hyperv.nova.vif.get_vif_driver')
def test_get_vif_driver_not_cached(self, mock_get_vif_driver):
mock_get_vif_driver.return_value = mock.sentinel.VIF_DRV
self._vmops._get_vif_driver(mock.sentinel.VIF_TYPE)
mock_get_vif_driver.assert_called_once_with(mock.sentinel.VIF_TYPE)
self.assertEqual(mock.sentinel.VIF_DRV,
self._vmops._vif_driver_cache[mock.sentinel.VIF_TYPE])
self._vmops._vif_driver = mock.MagicMock()
def test_list_instances(self):
mock_instance = mock.MagicMock()
@ -438,11 +422,9 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
@mock.patch('hyperv.nova.vmops.VMOps._delete_disk_files')
@mock.patch('hyperv.nova.vmops.VMOps._get_neutron_events',
return_value=[])
@mock.patch('hyperv.nova.vif.get_vif_driver')
@mock.patch.object(block_device_manager.BlockDeviceInfoManager,
'validate_and_update_bdi')
def _test_spawn(self, mock_validate_and_update_bdi,
mock_get_vif_driver,
mock_get_neutron_events,
mock_delete_disk_files,
mock_create_root_device,
@ -575,7 +557,6 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
events)
@mock.patch.object(vmops.VMOps, '_configure_secure_vm')
@mock.patch('hyperv.nova.vif.get_vif_driver')
@mock.patch.object(vmops.VMOps, '_requires_secure_boot')
@mock.patch.object(vmops.VMOps, '_requires_certificate')
@mock.patch.object(vmops.VMOps, '_get_instance_vnuma_config')
@ -596,13 +577,11 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock_get_vnuma_config,
mock_requires_certificate,
mock_requires_secure_boot,
mock_get_vif_driver,
mock_configure_secure_vm,
enable_instance_metrics,
vm_gen=constants.VM_GEN_1,
vnuma_enabled=False,
requires_sec_boot=True):
mock_vif_driver = mock_get_vif_driver()
self.flags(dynamic_memory_ratio=2.0, group='hyperv')
self.flags(enable_instance_metrics_collection=enable_instance_metrics,
group='hyperv')
@ -664,8 +643,6 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
self._vmops._vmutils.create_nic.assert_called_once_with(
mock_instance.name, mock.sentinel.ID, mock.sentinel.ADDRESS)
mock_vif_driver.plug.assert_called_once_with(mock_instance,
fake_network_info)
mock_enable = self._vmops._metricsutils.enable_vm_metrics_collection
if enable_instance_metrics:
mock_enable.assert_called_once_with(mock_instance.name)
@ -1120,20 +1097,20 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
self._vmops._vmutils.vm_exists.return_value = True
self._vmops.destroy(instance=mock_instance,
network_info=mock.sentinel.fake_network_info,
block_device_info=mock.sentinel.FAKE_BD_INFO)
block_device_info=mock.sentinel.FAKE_BD_INFO,
network_info=mock.sentinel.fake_network_info)
self._vmops._vmutils.vm_exists.assert_called_with(
mock_instance.name)
mock_power_off.assert_called_once_with(mock_instance)
mock_unplug_vifs.assert_called_once_with(
mock_instance, mock.sentinel.fake_network_info)
self._vmops._vmutils.destroy_vm.assert_called_once_with(
mock_instance.name)
mock_disconnect_volumes.assert_called_once_with(
mock.sentinel.FAKE_BD_INFO)
mock_delete_disk_files.assert_called_once_with(
mock_instance.name)
mock_unplug_vifs.assert_called_once_with(
mock_instance, mock.sentinel.fake_network_info)
def test_destroy_inexistent_instance(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
@ -1337,13 +1314,13 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock_set_vm_state.assert_called_once_with(
mock_instance, os_win_const.HYPERV_VM_STATE_ENABLED)
@mock.patch.object(vmops.VMOps, 'post_start_vifs')
def test_power_on_with_network_info(self, mock_post_start_vifs):
@mock.patch.object(vmops.VMOps, 'plug_vifs')
def test_power_on_with_network_info(self, mock_plug_vifs):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops.power_on(mock_instance,
network_info=mock.sentinel.fake_network_info)
mock_post_start_vifs.assert_called_once_with(
mock_plug_vifs.assert_called_once_with(
mock_instance, mock.sentinel.fake_network_info)
def _test_set_vm_state(self, state):
@ -1447,6 +1424,34 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock.call(mock.sentinel.FAKE_DVD_PATH2,
mock.sentinel.FAKE_DEST_PATH))
def test_plug_vifs(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_vif1 = {'id': mock.sentinel.ID1,
'type': mock.sentinel.vif_type1}
fake_vif2 = {'id': mock.sentinel.ID2,
'type': mock.sentinel.vif_type2}
mock_network_info = [fake_vif1, fake_vif2]
calls = [mock.call(mock_instance, fake_vif1),
mock.call(mock_instance, fake_vif2)]
self._vmops.plug_vifs(mock_instance,
network_info=mock_network_info)
self._vmops._vif_driver.plug.assert_has_calls(calls)
def test_unplug_vifs(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_vif1 = {'id': mock.sentinel.ID1,
'type': mock.sentinel.vif_type1}
fake_vif2 = {'id': mock.sentinel.ID2,
'type': mock.sentinel.vif_type2}
mock_network_info = [fake_vif1, fake_vif2]
calls = [mock.call(mock_instance, fake_vif1),
mock.call(mock_instance, fake_vif2)]
self._vmops.unplug_vifs(mock_instance,
network_info=mock_network_info)
self._vmops._vif_driver.unplug.assert_has_calls(calls)
def _setup_remotefx_mocks(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_instance.flavor.extra_specs = {
@ -1547,10 +1552,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
self._test_check_hotplug_available(
expected_result=False, windows_version=self._WIN_VERSION_6_3)
@mock.patch.object(vmops.VMOps, '_get_vif_driver')
@mock.patch.object(vmops.VMOps, '_check_hotplug_available')
def test_attach_interface(self, mock_check_hotplug_available,
mock_get_vif_driver):
def test_attach_interface(self, mock_check_hotplug_available):
mock_check_hotplug_available.return_value = True
fake_vm = fake_instance.fake_instance_obj(self.context)
fake_vif = test_virtual_interface.fake_vif
@ -1558,9 +1561,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
self._vmops.attach_interface(fake_vm, fake_vif)
mock_check_hotplug_available.assert_called_once_with(fake_vm)
mock_get_vif_driver.return_value.plug.assert_called_once_with(
fake_vm, fake_vif)
mock_get_vif_driver.return_value.post_start.assert_called_once_with(
self._vmops._vif_driver.plug.assert_called_once_with(
fake_vm, fake_vif)
self._vmops._vmutils.create_nic.assert_called_once_with(
fake_vm.name, fake_vif['id'], fake_vif['address'])
@ -1572,10 +1573,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
self._vmops.attach_interface,
mock.MagicMock(), mock.sentinel.fake_vif)
@mock.patch.object(vmops.VMOps, '_get_vif_driver')
@mock.patch.object(vmops.VMOps, '_check_hotplug_available')
def test_detach_interface(self, mock_check_hotplug_available,
mock_get_vif_driver):
def test_detach_interface(self, mock_check_hotplug_available):
mock_check_hotplug_available.return_value = True
fake_vm = fake_instance.fake_instance_obj(self.context)
fake_vif = test_virtual_interface.fake_vif
@ -1583,7 +1582,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
self._vmops.detach_interface(fake_vm, fake_vif)
mock_check_hotplug_available.assert_called_once_with(fake_vm)
mock_get_vif_driver.return_value.unplug.assert_called_once_with(
self._vmops._vif_driver.unplug.assert_called_once_with(
fake_vm, fake_vif)
self._vmops._vmutils.destroy_nic.assert_called_once_with(
fake_vm.name, fake_vif['id'])
@ -1822,40 +1821,6 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
}
self.assertEqual(expected_specs, ret_val)
@mock.patch.object(vmops.VMOps, '_get_vif_driver')
def test_unplug_vifs(self, mock_get_vif_driver):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_vif1 = {'id': mock.sentinel.ID1,
'type': mock.sentinel.vif_type1}
fake_vif2 = {'id': mock.sentinel.ID2,
'type': mock.sentinel.vif_type2}
mock_network_info = [fake_vif1, fake_vif2]
fake_vif_driver = mock.MagicMock()
mock_get_vif_driver.return_value = fake_vif_driver
calls = [mock.call(mock_instance, fake_vif1),
mock.call(mock_instance, fake_vif2)]
self._vmops.unplug_vifs(mock_instance,
network_info=mock_network_info)
fake_vif_driver.unplug.assert_has_calls(calls)
@mock.patch.object(vmops.VMOps, '_get_vif_driver')
def test_post_start_vifs(self, mock_get_vif_driver):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_vif1 = {'id': mock.sentinel.ID1,
'type': mock.sentinel.vif_type1}
fake_vif2 = {'id': mock.sentinel.ID2,
'type': mock.sentinel.vif_type2}
mock_network_info = [fake_vif1, fake_vif2]
fake_vif_driver = mock.MagicMock()
mock_get_vif_driver.return_value = fake_vif_driver
calls = [mock.call(mock_instance, fake_vif1),
mock.call(mock_instance, fake_vif2)]
self._vmops.post_start_vifs(mock_instance,
network_info=mock_network_info)
fake_vif_driver.post_start.assert_has_calls(calls)
def _mock_get_port_settings(self, logging_port, interactive_port):
mock_image_port_settings = {
constants.IMAGE_PROP_LOGGING_SERIAL_PORT: logging_port,