Merge "resync: Adds Hyper-V OVS ViF driver"
This commit is contained in:
commit
59adc9faed
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue