VM Importing/Exporting

This patch adds support for exporting/importing a vm.

Change-Id: I9b27bd36753323364f8de05960af08729e37024d
This commit is contained in:
itoader 2016-07-12 04:44:37 -07:00 committed by Simona Iuliana Toader
parent 01caadebae
commit 2edc5fa3ff
11 changed files with 410 additions and 87 deletions

View File

@ -168,3 +168,7 @@ CLUSTER_GROUP_OFFLINE = 1
CLUSTER_GROUP_FAILED = 2
CLUSTER_GROUP_PARTIAL_ONLINE = 3
CLUSTER_GROUP_PENDING = 4
EXPORT_CONFIG_SNAPSHOTS_ALL = 0
EXPORT_CONFIG_NO_SNAPSHOTS = 1
EXPORT_CONFIG_ONE_SNAPSHOT = 2

View File

@ -24,6 +24,7 @@ from os_win import exceptions
from os_win.tests import test_base
from os_win.utils.compute import clusterutils
from os_win.utils.compute import livemigrationutils
from os_win.utils.compute import migrationutils
from os_win.utils.compute import rdpconsoleutils
from os_win.utils.compute import vmutils
from os_win.utils.dns import dnsutils
@ -146,3 +147,8 @@ class TestHyperVUtilsFactory(test_base.OsWinBaseTestCase):
self._check_get_class(
expected_class=dnsutils.DNSUtils,
class_type='dnsutils')
def test_get_migrationutils(self):
self._check_get_class(
expected_class=migrationutils.MigrationUtils,
class_type='migrationutils')

View File

@ -104,35 +104,24 @@ class LiveMigrationUtilsTestCase(test_base.OsWinBaseTestCase):
mock.sentinel.ret_val,
mock.sentinel.job_path)
def test_get_planned_vms(self):
mock_conn_v2 = mock.MagicMock()
mock_conn_v2.Msvm_PlannedComputerSystem.return_value = (
mock.sentinel.planned_vms)
planned_vms = self.liveutils._get_planned_vms(mock_conn_v2,
mock.sentinel.vm_name)
mock_conn_v2.Msvm_PlannedComputerSystem.assert_called_once_with(
ElementName=mock.sentinel.vm_name)
self.assertEqual(mock.sentinel.planned_vms, planned_vms)
@ddt.data({'planned_vm': None}, {'planned_vm': mock.sentinel.planned_vm})
@ddt.unpack
@mock.patch.object(livemigrationutils.LiveMigrationUtils,
'_destroy_planned_vm')
@mock.patch.object(livemigrationutils.LiveMigrationUtils,
'_get_planned_vms')
def test_destroy_existing_planned_vms(self, mock_get_planned_vms,
mock_destroy_planned_vm):
mock_planned_vms = [mock.sentinel.planned_vm,
mock.sentinel.another_planned_vm]
mock_get_planned_vms.return_value = mock_planned_vms
'_get_planned_vm')
def test_destroy_existing_planned_vm(self, mock_get_planned_vm,
mock_destroy_planned_vm, planned_vm):
mock_get_planned_vm.return_value = planned_vm
self.liveutils.destroy_existing_planned_vms(mock.sentinel.vm_name)
self.liveutils.destroy_existing_planned_vm(mock.sentinel.vm_name)
mock_get_planned_vms.assert_called_once_with(self._conn,
mock.sentinel.vm_name)
mock_destroy_planned_vm.assert_has_calls(
[mock.call(mock.sentinel.planned_vm),
mock.call(mock.sentinel.another_planned_vm)])
mock_get_planned_vm.assert_called_once_with(
mock.sentinel.vm_name, self._conn)
if planned_vm:
mock_destroy_planned_vm.assert_called_once_with(planned_vm)
else:
self.assertFalse(mock_destroy_planned_vm.called)
def test_create_planned_vm_helper(self):
mock_vm = mock.MagicMock()
@ -303,19 +292,12 @@ class LiveMigrationUtilsTestCase(test_base.OsWinBaseTestCase):
MigrationSettingData=mock_vsmsd.GetText_.return_value,
NewResourceSettingData=mock.sentinel.FAKE_RASD_PATH)
def test_live_migrate_multiple_planned_vms(self):
mock_vm = self._get_vm()
self._conn.Msvm_PlannedComputerSystem.return_value = [
mock_vm, mock_vm]
self.assertRaises(exceptions.OSWinException,
self.liveutils.live_migrate_vm,
mock.sentinel.vm_name,
mock.sentinel.host)
@ddt.data(True, False)
@mock.patch.object(livemigrationutils.LiveMigrationUtils,
'_get_planned_vm')
@mock.patch.object(livemigrationutils, 'vmutils')
def test_live_migrate_no_planned_vm(self, migrate_disks, mock_vm_utils):
def test_live_migrate_no_planned_vm(self, migrate_disks, mock_vm_utils,
mock_get_planned_vm):
mock_vm_utils_remote = mock_vm_utils.VMUtils.return_value
mock_vm = self._get_vm()
@ -333,7 +315,7 @@ class LiveMigrationUtilsTestCase(test_base.OsWinBaseTestCase):
_get_vhd_setting_data=mock.DEFAULT,
_live_migrate_vm=mock.DEFAULT):
self._conn.Msvm_PlannedComputerSystem.return_value = []
mock_get_planned_vm.return_value = None
disk_paths = {
mock.sentinel.FAKE_IDE_PATH: mock.sentinel.FAKE_SASD_RESOURCE}
self.liveutils._get_physical_disk_paths.return_value = disk_paths
@ -345,7 +327,8 @@ class LiveMigrationUtilsTestCase(test_base.OsWinBaseTestCase):
self.liveutils.live_migrate_vm(mock.sentinel.vm_name,
mock.sentinel.FAKE_HOST,
migrate_disks=migrate_disks)
mock_get_planned_vm.assert_called_once_with(
mock.sentinel.vm_name, self._conn)
self.liveutils._get_remote_disk_data.assert_called_once_with(
mock_vm_utils_remote, disk_paths, mock.sentinel.FAKE_HOST)
self.liveutils._create_planned_vm.assert_called_once_with(
@ -372,7 +355,9 @@ class LiveMigrationUtilsTestCase(test_base.OsWinBaseTestCase):
mock.sentinel.FAKE_HOST,
expected_migr_type)
def test_live_migrate_single_planned_vm(self):
@mock.patch.object(
livemigrationutils.LiveMigrationUtils, '_get_planned_vm')
def test_live_migrate_single_planned_vm(self, mock_get_planned_vm):
mock_vm = self._get_vm()
mock_migr_svc = self._conn.Msvm_VirtualSystemMigrationService()[0]
@ -385,7 +370,7 @@ class LiveMigrationUtilsTestCase(test_base.OsWinBaseTestCase):
_get_vhd_setting_data=mock.DEFAULT,
_live_migrate_vm=mock.DEFAULT):
self._conn.Msvm_PlannedComputerSystem.return_value = [mock_vm]
mock_get_planned_vm.return_value = mock_vm
self.liveutils.live_migrate_vm(mock.sentinel.vm_name,
mock.sentinel.FAKE_HOST)
self.liveutils._live_migrate_vm.assert_called_once_with(
@ -394,6 +379,8 @@ class LiveMigrationUtilsTestCase(test_base.OsWinBaseTestCase):
self.liveutils._get_vhd_setting_data.return_value,
mock.sentinel.FAKE_HOST,
self.liveutils._MIGRATION_TYPE_VIRTUAL_SYSTEM_AND_STORAGE)
mock_get_planned_vm.assert_called_once_with(
mock.sentinel.vm_name, self._conn)
@mock.patch.object(vmutils, 'VMUtils')
@mock.patch.object(livemigrationutils.LiveMigrationUtils, '_get_vm')
@ -404,7 +391,7 @@ class LiveMigrationUtilsTestCase(test_base.OsWinBaseTestCase):
@mock.patch.object(livemigrationutils.LiveMigrationUtils,
'_create_planned_vm')
@mock.patch.object(livemigrationutils.LiveMigrationUtils,
'destroy_existing_planned_vms')
'destroy_existing_planned_vm')
@mock.patch.object(livemigrationutils.LiveMigrationUtils,
'_get_disk_data')
def test_create_planned_vm(self, mock_get_disk_data,

View File

@ -0,0 +1,142 @@
# Copyright 2016 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.
import ddt
import mock
from os_win import constants
from os_win import exceptions
from os_win.tests import test_base
from os_win.utils.compute import migrationutils
@ddt.ddt
class MigrationUtilsTestCase(test_base.OsWinBaseTestCase):
"""Unit tests for the Hyper-V MigrationUtils class."""
_FAKE_VM_NAME = 'fake_vm'
def setUp(self):
super(MigrationUtilsTestCase, self).setUp()
self._migrationutils = migrationutils.MigrationUtils()
self._migrationutils._vmutils = mock.MagicMock()
self._migrationutils._conn_attr = mock.MagicMock()
self._migrationutils._jobutils = mock.MagicMock()
def test_get_export_setting_data(self):
mock_vm = self._migrationutils._vmutils._lookup_vm.return_value
mock_conn = self._migrationutils._conn
mock_exp = mock_conn.Msvm_VirtualSystemExportSettingData
mock_exp.return_value = [mock.sentinel.export_setting_data]
expected_result = mock.sentinel.export_setting_data
actual_result = self._migrationutils._get_export_setting_data(
self._FAKE_VM_NAME)
self.assertEqual(expected_result, actual_result)
mock_exp.assert_called_once_with(InstanceID=mock_vm.InstanceID)
@mock.patch.object(
migrationutils.MigrationUtils, '_get_export_setting_data')
def test_export_vm(self, mock_get_export_setting_data):
mock_vm = self._migrationutils._vmutils._lookup_vm.return_value
export_setting_data = mock_get_export_setting_data.return_value
mock_svc = self._migrationutils._vs_man_svc
mock_svc.ExportSystemDefinition.return_value = (
mock.sentinel.job_path, mock.sentinel.ret_val)
self._migrationutils.export_vm(
vm_name=self._FAKE_VM_NAME,
export_path=mock.sentinel.fake_export_path)
self.assertEqual(constants.EXPORT_CONFIG_SNAPSHOTS_ALL,
export_setting_data.CopySnapshotConfiguration)
self.assertFalse(export_setting_data.CopyVmStorage)
self.assertFalse(export_setting_data.CreateVmExportSubdirectory)
mock_get_export_setting_data.assert_called_once_with(
self._FAKE_VM_NAME)
mock_svc.ExportSystemDefinition.assert_called_once_with(
ComputerSystem=mock_vm.path_(),
ExportDirectory=mock.sentinel.fake_export_path,
ExportSettingData=export_setting_data.GetText_(1))
self._migrationutils._jobutils.check_ret_val.assert_called_once_with(
mock.sentinel.ret_val, mock.sentinel.job_path)
def test_import_vm_definition(self):
mock_svc = self._migrationutils._vs_man_svc
mock_svc.ImportSystemDefinition.return_value = (
mock.sentinel.ref,
mock.sentinel.job_path,
mock.sentinel.ret_val)
self._migrationutils.import_vm_definition(
export_config_file_path=mock.sentinel.export_config_file_path,
snapshot_folder_path=mock.sentinel.snapshot_folder_path)
mock_svc.ImportSystemDefinition.assert_called_once_with(
False, mock.sentinel.snapshot_folder_path,
mock.sentinel.export_config_file_path)
self._migrationutils._jobutils.check_ret_val.assert_called_once_with(
mock.sentinel.ret_val, mock.sentinel.job_path)
@mock.patch.object(migrationutils.MigrationUtils, '_get_planned_vm')
def test_realize_vm(self, mock_get_planned_vm):
mock_get_planned_vm.return_value = mock.MagicMock()
self._migrationutils._vs_man_svc.ValidatePlannedSystem.return_value = (
mock.sentinel.job_path_ValidatePlannedSystem,
mock.sentinel.ret_val_ValidatePlannedSystem)
self._migrationutils._vs_man_svc.RealizePlannedSystem.return_value = (
mock.sentinel.job_path_RealizePlannedSystem,
mock.sentinel.ref_RealizePlannedSystem,
mock.sentinel.ret_val_RealizePlannedSystem)
self._migrationutils.realize_vm(self._FAKE_VM_NAME)
mock_get_planned_vm.assert_called_once_with(
self._FAKE_VM_NAME, fail_if_not_found=True)
expected_call = [
mock.call(mock.sentinel.ret_val_ValidatePlannedSystem,
mock.sentinel.job_path_ValidatePlannedSystem),
mock.call(mock.sentinel.ret_val_RealizePlannedSystem,
mock.sentinel.job_path_RealizePlannedSystem)]
self._migrationutils._jobutils.check_ret_val.has_calls(expected_call)
@ddt.data([mock.sentinel.planned_vm], [])
def test_get_planned_vm(self, planned_vm):
planned_computer_system = (
self._migrationutils._conn.Msvm_PlannedComputerSystem)
planned_computer_system.return_value = planned_vm
actual_result = self._migrationutils._get_planned_vm(
self._FAKE_VM_NAME, fail_if_not_found=False)
if planned_vm:
self.assertEqual(planned_vm[0], actual_result)
else:
self.assertIsNone(actual_result)
planned_computer_system.assert_called_once_with(
ElementName=self._FAKE_VM_NAME)
def test_get_planned_vm_exception(self):
planned_computer_system = (
self._migrationutils._conn.Msvm_PlannedComputerSystem)
planned_computer_system.return_value = None
self.assertRaises(exceptions.HyperVException,
self._migrationutils._get_planned_vm,
self._FAKE_VM_NAME, fail_if_not_found=True)
planned_computer_system.assert_called_once_with(
ElementName=self._FAKE_VM_NAME)

View File

@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
import mock
from six.moves import range # noqa
@ -23,6 +25,7 @@ from os_win.utils import _wqlutils
from os_win.utils.compute import vmutils
@ddt.ddt
class VMUtilsTestCase(test_base.OsWinBaseTestCase):
"""Unit tests for the Hyper-V VMUtils class."""
@ -214,26 +217,41 @@ class VMUtilsTestCase(test_base.OsWinBaseTestCase):
self.assertEqual(mock_vm.ConfigurationDataRoot, config_root_dir)
@mock.patch.object(vmutils.VMUtils, '_get_vm_disks')
def test_get_vm_storage_paths(self, mock_get_vm_disks):
self._lookup_vm()
@mock.patch.object(vmutils.VMUtils, '_lookup_vm_check')
@mock.patch.object(vmutils.VMUtils, '_get_virtual_system_type')
def test_get_vm_storage_paths(self, mock_get_virtual_system_type,
mock_lookup_vm_check, mock_get_vm_disks):
virtual_system_type = mock_get_virtual_system_type.return_value
mock_rasds = self._create_mock_disks()
mock_get_vm_disks.return_value = ([mock_rasds[0]], [mock_rasds[1]])
storage = self._vmutils.get_vm_storage_paths(self._FAKE_VM_NAME)
storage = self._vmutils.get_vm_storage_paths(
self._FAKE_VM_NAME,
is_planned_vm=False)
(disk_files, volume_drives) = storage
self.assertEqual([self._FAKE_VHD_PATH], disk_files)
self.assertEqual([self._FAKE_VOLUME_DRIVE_PATH], volume_drives)
mock_get_virtual_system_type.assert_called_once_with(False)
mock_lookup_vm_check.assert_called_once_with(
self._FAKE_VM_NAME, virtual_system_type=virtual_system_type)
@mock.patch.object(vmutils.VMUtils, '_get_vm_disks')
def test_get_vm_disks_by_instance_name(self, mock_get_vm_disks):
@mock.patch.object(vmutils.VMUtils, '_get_virtual_system_type')
def test_get_vm_disks_by_instance_name(self,
mock_get_virtual_system_type,
mock_get_vm_disks):
virtual_system_type = mock_get_virtual_system_type.return_value
self._lookup_vm()
mock_get_vm_disks.return_value = mock.sentinel.vm_disks
vm_disks = self._vmutils.get_vm_disks(self._FAKE_VM_NAME)
vm_disks = self._vmutils.get_vm_disks(
self._FAKE_VM_NAME, is_planned_vm=False)
mock_get_virtual_system_type.assert_called_once_with(False)
self._vmutils._lookup_vm_check.assert_called_once_with(
self._FAKE_VM_NAME)
self._FAKE_VM_NAME,
virtual_system_type=virtual_system_type)
self.assertEqual(mock.sentinel.vm_disks, vm_disks)
@mock.patch.object(_wqlutils, 'get_element_associated_class')
@ -280,23 +298,42 @@ class VMUtilsTestCase(test_base.OsWinBaseTestCase):
self.assertRaises(exceptions.HyperVAuthorizationException,
self._vmutils.check_admin_permissions)
@ddt.data(
{'configuration_root_dir': mock.sentinel.configuration_root_dir},
{'snapshot_dir': mock.sentinel.snapshot_dir, 'is_planned_vm': True},
{'is_planned_vm': True}, {})
@ddt.unpack
@mock.patch.object(vmutils.VMUtils, '_modify_virtual_system')
@mock.patch.object(vmutils.VMUtils, '_set_vm_vcpus')
@mock.patch.object(vmutils.VMUtils, '_set_vm_memory')
def test_update_vm(self, mock_set_mem, mock_set_vcpus):
mock_vmsettings = self._lookup_vm()
@mock.patch.object(vmutils.VMUtils, '_lookup_vm_check')
@mock.patch.object(vmutils.VMUtils, '_get_virtual_system_type')
def test_update_vm(self, mock_get_virtual_system_type,
mock_lookup_vm_check, mock_set_mem, mock_set_vcpus,
mock_modify_virtual_system,
configuration_root_dir=None,
snapshot_dir=None, is_planned_vm=False):
mock_vmsettings = mock_lookup_vm_check.return_value
virtual_system_type = mock_get_virtual_system_type.return_value
self._vmutils.update_vm(
mock.sentinel.vm_name, mock.sentinel.memory_mb,
mock.sentinel.memory_per_numa, mock.sentinel.vcpus_num,
mock.sentinel.vcpus_per_numa, mock.sentinel.limit_cpu_features,
mock.sentinel.dynamic_mem_ratio)
mock.sentinel.dynamic_mem_ratio, configuration_root_dir,
snapshot_dir, is_planned_vm=is_planned_vm)
mock_get_virtual_system_type.assert_called_once_with(is_planned_vm)
mock_lookup_vm_check.assert_called_once_with(
mock.sentinel.vm_name, virtual_system_type=virtual_system_type)
mock_set_mem.assert_called_once_with(
mock_vmsettings, mock.sentinel.memory_mb,
mock.sentinel.memory_per_numa, mock.sentinel.dynamic_mem_ratio)
mock_set_vcpus.assert_called_once_with(
mock_vmsettings, mock.sentinel.vcpus_num,
mock.sentinel.vcpus_per_numa, mock.sentinel.limit_cpu_features)
if configuration_root_dir or snapshot_dir:
mock_modify_virtual_system.assert_called_once_with(
mock_vmsettings)
@mock.patch.object(vmutils.VMUtils, '_set_vm_memory')
@mock.patch.object(vmutils.VMUtils, '_create_vm_obj')
@ -524,9 +561,8 @@ class VMUtilsTestCase(test_base.OsWinBaseTestCase):
getattr(mock_svc, self._DESTROY_SYSTEM).assert_called_with(
self._FAKE_VM_PATH)
@mock.patch.object(vmutils.VMUtils, '_get_vm_disks')
@mock.patch.object(vmutils.VMUtils, 'get_vm_disks')
def test_get_vm_physical_disk_mapping(self, mock_get_vm_disks):
self._lookup_vm()
mock_phys_disk = self._create_mock_disks()[1]
expected_serial = mock_phys_disk.ElementName
@ -539,8 +575,11 @@ class VMUtilsTestCase(test_base.OsWinBaseTestCase):
mock_get_vm_disks.return_value = ([], [mock_phys_disk])
result = self._vmutils.get_vm_physical_disk_mapping(self._FAKE_VM_NAME)
result = self._vmutils.get_vm_physical_disk_mapping(
self._FAKE_VM_NAME, is_planned_vm=False)
self.assertEqual(expected_mapping, result)
mock_get_vm_disks.assert_called_once_with(
self._FAKE_VM_NAME, is_planned_vm=False)
@mock.patch.object(vmutils.VMUtils, '_get_wmi_obj')
def test_set_disk_host_res(self, mock_get_wmi_obj):
@ -1232,3 +1271,25 @@ class VMUtilsTestCase(test_base.OsWinBaseTestCase):
def test_vm_has_s3_controller(self, mock_get_vm_generation):
self.assertTrue(self._vmutils._vm_has_s3_controller(
mock.sentinel.fake_vm_name))
@mock.patch.object(vmutils.VMUtils, '_get_mounted_disk_resource_from_path')
def test_update_vm_disk_path(self, mock_get_disk_resource_from_path):
disk_resource = mock_get_disk_resource_from_path.return_value
self._vmutils.update_vm_disk_path(mock.sentinel.disk_path,
mock.sentinel.new_path,
is_physical=True)
mock_get_disk_resource_from_path.assert_called_once_with(
disk_path=mock.sentinel.disk_path, is_physical=True)
self._vmutils._jobutils.modify_virt_resource.assert_called_once_with(
disk_resource)
self.assertEqual(disk_resource.HostResource, [mock.sentinel.new_path])
@ddt.data(True, False)
def test_get_virtual_system_type(self, is_planned_vm):
exp_result = (
self._vmutils._VIRTUAL_SYSTEM_TYPE_PLANNED if is_planned_vm
else self._vmutils._VIRTUAL_SYSTEM_TYPE_REALIZED)
actual_result = self._vmutils._get_virtual_system_type(
is_planned_vm=is_planned_vm)
self.assertEqual(exp_result, actual_result)

View File

@ -13,6 +13,7 @@
# under the License.
import os
import shutil
import mock
@ -199,3 +200,14 @@ class PathUtilsTestCase(test_base.OsWinBaseTestCase):
self.assertEqual(mock.sentinel.temporary_file, tmp_file)
self.assertFalse(mock_delete.called)
mock_delete.assert_called_once_with(mock.sentinel.temporary_file)
@mock.patch.object(shutil, 'copytree')
@mock.patch('os.path.abspath')
def test_copy_dir(self, mock_abspath, mock_copytree):
mock_abspath.side_effect = [mock.sentinel.src, mock.sentinel.dest]
self._pathutils.copy_dir(mock.sentinel.src, mock.sentinel.dest)
mock_abspath.has_calls(
[mock.call(mock.sentinel.src), mock.call(mock.sentinel.dest)])
mock_copytree.assert_called_once_with(mock.sentinel.src,
mock.sentinel.dest)

View File

@ -20,15 +20,14 @@ from oslo_log import log as logging
from os_win._i18n import _, _LE
from os_win import exceptions
from os_win.utils import _wqlutils
from os_win.utils import baseutils
from os_win.utils.compute import migrationutils
from os_win.utils.compute import vmutils
from os_win.utils import jobutils
from os_win.utils.storage.initiator import iscsi_wmi_utils
LOG = logging.getLogger(__name__)
class LiveMigrationUtils(baseutils.BaseUtilsVirt):
class LiveMigrationUtils(migrationutils.MigrationUtils):
_STORAGE_ALLOC_SETTING_DATA_CLASS = 'Msvm_StorageAllocationSettingData'
_CIM_RES_ALLOC_SETTING_DATA_CLASS = 'CIM_ResourceAllocationSettingData'
@ -38,8 +37,6 @@ class LiveMigrationUtils(baseutils.BaseUtilsVirt):
def __init__(self):
super(LiveMigrationUtils, self).__init__()
self._vmutils = vmutils.VMUtils()
self._jobutils = jobutils.JobUtils()
self._iscsi_initiator = iscsi_wmi_utils.ISCSIInitiatorWMIUtils()
def _get_conn_v2(self, host='localhost'):
@ -87,12 +84,9 @@ class LiveMigrationUtils(baseutils.BaseUtilsVirt):
ret_val) = self._vs_man_svc.DestroySystem(planned_vm.path_())
self._jobutils.check_ret_val(ret_val, job_path)
def _get_planned_vms(self, conn_v2, vm_name):
return conn_v2.Msvm_PlannedComputerSystem(ElementName=vm_name)
def destroy_existing_planned_vms(self, vm_name):
planned_vms = self._get_planned_vms(self._compat_conn, vm_name)
for planned_vm in planned_vms:
def destroy_existing_planned_vm(self, vm_name):
planned_vm = self._get_planned_vm(vm_name, self._compat_conn)
if planned_vm:
self._destroy_planned_vm(planned_vm)
def _create_planned_vm(self, conn_v2_local, conn_v2_remote,
@ -238,14 +232,8 @@ class LiveMigrationUtils(baseutils.BaseUtilsVirt):
rmt_ip_addr_list = self._get_ip_address_list(conn_v2_remote,
dest_host)
planned_vms = self._get_planned_vms(conn_v2_remote, vm_name)
if len(planned_vms) > 1:
err_msg = _("Multiple planned VMs were found for VM %(vm_name)s "
"on host %(dest_host)s")
raise exceptions.OSWinException(
err_msg % dict(vm_name=vm_name,
dest_host=dest_host))
elif not planned_vms:
planned_vm = self._get_planned_vm(vm_name, conn_v2_remote)
if not planned_vm:
# TODO(claudiub): Remove this branch after the livemigrationutils
# usage has been updated to create planned VM on the destination
# host beforehand.
@ -262,8 +250,6 @@ class LiveMigrationUtils(baseutils.BaseUtilsVirt):
dest_host)
self._update_planned_vm_disk_resources(
conn_v2_remote, planned_vm, vm_name, disk_paths_remote)
else:
planned_vm = planned_vms[0]
if migrate_disks:
new_resource_setting_data = self._get_vhd_setting_data(vm)
@ -285,7 +271,7 @@ class LiveMigrationUtils(baseutils.BaseUtilsVirt):
vm = self._get_vm(conn_v2_remote, vm_name)
# Make sure there are no planned VMs already.
self.destroy_existing_planned_vms(vm_name)
self.destroy_existing_planned_vm(vm_name)
ip_addr_list = self._get_ip_address_list(self._compat_conn,
dest_host)

View File

@ -0,0 +1,80 @@
# Copyright 2016 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.
from os_win._i18n import _
from os_win import constants
from os_win import exceptions
from os_win.utils import baseutils
from os_win.utils.compute import vmutils
from os_win.utils import jobutils
class MigrationUtils(baseutils.BaseUtilsVirt):
def __init__(self):
super(MigrationUtils, self).__init__()
self._vmutils = vmutils.VMUtils()
self._jobutils = jobutils.JobUtils()
def _get_export_setting_data(self, vm_name):
vm = self._vmutils._lookup_vm(vm_name)
export_setting_data = self._conn.Msvm_VirtualSystemExportSettingData(
InstanceID=vm.InstanceID)
return export_setting_data[0]
def export_vm(self, vm_name, export_path,
copy_snapshots_config=constants.EXPORT_CONFIG_SNAPSHOTS_ALL,
copy_vm_storage=False, create_export_subdir=False):
vm = self._vmutils._lookup_vm(vm_name)
export_setting_data = self._get_export_setting_data(vm_name)
export_setting_data.CopySnapshotConfiguration = copy_snapshots_config
export_setting_data.CopyVmStorage = copy_vm_storage
export_setting_data.CreateVmExportSubdirectory = create_export_subdir
(job_path, ret_val) = self._vs_man_svc.ExportSystemDefinition(
ComputerSystem=vm.path_(),
ExportDirectory=export_path,
ExportSettingData=export_setting_data.GetText_(1))
self._jobutils.check_ret_val(ret_val, job_path)
def import_vm_definition(self, export_config_file_path,
snapshot_folder_path,
new_uuid=False):
(ref, job_path, ret_val) = self._vs_man_svc.ImportSystemDefinition(
new_uuid, snapshot_folder_path, export_config_file_path)
self._jobutils.check_ret_val(ret_val, job_path)
def realize_vm(self, vm_name):
planned_vm = self._get_planned_vm(vm_name, fail_if_not_found=True)
if planned_vm:
(job_path, ret_val) = (
self._vs_man_svc.ValidatePlannedSystem(planned_vm.path_()))
self._jobutils.check_ret_val(ret_val, job_path)
(job_path, ref, ret_val) = (
self._vs_man_svc.RealizePlannedSystem(planned_vm.path_()))
self._jobutils.check_ret_val(ret_val, job_path)
def _get_planned_vm(self, vm_name, conn_v2=None, fail_if_not_found=False):
if not conn_v2:
conn_v2 = self._conn
planned_vm = conn_v2.Msvm_PlannedComputerSystem(ElementName=vm_name)
if planned_vm:
return planned_vm[0]
elif fail_if_not_found:
raise exceptions.HyperVException(
_('Cannot find planned VM with name: %s') % vm_name)
return None

View File

@ -79,6 +79,7 @@ class VMUtils(baseutils.BaseUtilsVirt):
_VIRTUAL_SYSTEM_SUBTYPE = 'VirtualSystemSubType'
_VIRTUAL_SYSTEM_TYPE_REALIZED = 'Microsoft:Hyper-V:System:Realized'
_VIRTUAL_SYSTEM_TYPE_PLANNED = 'Microsoft:Hyper-V:System:Planned'
_VIRTUAL_SYSTEM_SUBTYPE_GEN2 = 'Microsoft:Hyper-V:SubType:2'
_SNAPSHOT_FULL = 2
@ -190,18 +191,21 @@ class VMUtils(baseutils.BaseUtilsVirt):
settings = self.get_vm_summary_info(vm_name)
return settings['EnabledState']
def _lookup_vm_check(self, vm_name, as_vssd=True, for_update=False):
vm = self._lookup_vm(vm_name, as_vssd, for_update)
def _lookup_vm_check(self, vm_name, as_vssd=True, for_update=False,
virtual_system_type=_VIRTUAL_SYSTEM_TYPE_REALIZED):
vm = self._lookup_vm(vm_name, as_vssd, for_update,
virtual_system_type)
if not vm:
raise exceptions.HyperVVMNotFoundException(vm_name=vm_name)
return vm
def _lookup_vm(self, vm_name, as_vssd=True, for_update=False):
def _lookup_vm(self, vm_name, as_vssd=True, for_update=False,
virtual_system_type=_VIRTUAL_SYSTEM_TYPE_REALIZED):
if as_vssd:
conn = self._compat_conn if for_update else self._conn
vms = conn.Msvm_VirtualSystemSettingData(
ElementName=vm_name,
VirtualSystemType=self._VIRTUAL_SYSTEM_TYPE_REALIZED)
VirtualSystemType=virtual_system_type)
else:
vms = self._conn.Msvm_ComputerSystem(ElementName=vm_name)
n = len(vms)
@ -267,12 +271,24 @@ class VMUtils(baseutils.BaseUtilsVirt):
self._jobutils.modify_virt_resource(procsetting)
def update_vm(self, vm_name, memory_mb, memory_per_numa_node, vcpus_num,
vcpus_per_numa_node, limit_cpu_features, dynamic_mem_ratio):
vmsetting = self._lookup_vm_check(vm_name)
vcpus_per_numa_node, limit_cpu_features, dynamic_mem_ratio,
configuration_root_dir=None, snapshot_dir=None,
is_planned_vm=False):
virtual_system_type = self._get_virtual_system_type(is_planned_vm)
vmsetting = self._lookup_vm_check(
vm_name, virtual_system_type=virtual_system_type)
if configuration_root_dir:
vmsetting.ConfigurationDataRoot = configuration_root_dir
if snapshot_dir:
vmsetting.SnapshotDataRoot = snapshot_dir
self._set_vm_memory(vmsetting, memory_mb, memory_per_numa_node,
dynamic_mem_ratio)
self._set_vm_vcpus(vmsetting, vcpus_num, vcpus_per_numa_node,
limit_cpu_features)
if configuration_root_dir or snapshot_dir:
self._modify_virtual_system(vmsetting)
def check_admin_permissions(self):
if not self._compat_conn.Msvm_VirtualSystemManagementService():
@ -488,9 +504,10 @@ class VMUtils(baseutils.BaseUtilsVirt):
diskdrive.ElementName = serial
self._jobutils.modify_virt_resource(diskdrive)
def get_vm_physical_disk_mapping(self, vm_name):
def get_vm_physical_disk_mapping(self, vm_name, is_planned_vm=False):
mapping = {}
physical_disks = self.get_vm_disks(vm_name)[1]
physical_disks = (
self.get_vm_disks(vm_name, is_planned_vm=is_planned_vm)[1])
for diskdrive in physical_disks:
mapping[diskdrive.ElementName] = dict(
resource_path=diskdrive.path_(),
@ -599,8 +616,11 @@ class VMUtils(baseutils.BaseUtilsVirt):
vmsettings = self._lookup_vm_check(vm_name)
return vmsettings.ConfigurationDataRoot
def get_vm_storage_paths(self, vm_name):
vmsettings = self._lookup_vm_check(vm_name)
def get_vm_storage_paths(self, vm_name, is_planned_vm=False):
virtual_system_type = self._get_virtual_system_type(is_planned_vm)
vmsettings = self._lookup_vm_check(
vm_name,
virtual_system_type=virtual_system_type)
(disk_resources, volume_resources) = self._get_vm_disks(vmsettings)
volume_drives = []
@ -615,8 +635,10 @@ class VMUtils(baseutils.BaseUtilsVirt):
return (disk_files, volume_drives)
def get_vm_disks(self, vm_name):
vmsettings = self._lookup_vm_check(vm_name)
def get_vm_disks(self, vm_name, is_planned_vm=False):
virtual_system_type = self._get_virtual_system_type(is_planned_vm)
vmsettings = self._lookup_vm_check(
vm_name, virtual_system_type=virtual_system_type)
return self._get_vm_disks(vmsettings)
def _get_vm_disks(self, vmsettings):
@ -1078,3 +1100,14 @@ class VMUtils(baseutils.BaseUtilsVirt):
def is_secure_vm(self, instance_name):
return False
def update_vm_disk_path(self, disk_path, new_disk_path, is_physical=True):
disk_resource = self._get_mounted_disk_resource_from_path(
disk_path=disk_path, is_physical=is_physical)
disk_resource.HostResource = [new_disk_path]
self._jobutils.modify_virt_resource(disk_resource)
def _get_virtual_system_type(self, is_planned_vm):
return (
self._VIRTUAL_SYSTEM_TYPE_PLANNED if is_planned_vm
else self._VIRTUAL_SYSTEM_TYPE_REALIZED)

View File

@ -60,6 +60,9 @@ class PathUtils(object):
def rename(self, src, dest):
os.rename(src, dest)
def copy_dir(self, src, dest):
shutil.copytree(src, dest)
def copyfile(self, src, dest):
self.copy(src, dest)

View File

@ -83,6 +83,11 @@ utils_map = {
'min_version': 6.2,
'max_version': None,
'path': 'os_win.utils.metrics.metricsutils.MetricsUtils'}},
'migrationutils': {
'MigrationUtils': {
'min_version': 6.2,
'max_version': None,
'path': 'os_win.utils.compute.migrationutils.MigrationUtils'}},
'networkutils': {
'NetworkUtils': {
'min_version': 6.2,
@ -232,3 +237,7 @@ def get_clusterutils():
def get_dnsutils():
return _get_class(class_type='dnsutils')
def get_migrationutils():
return _get_class(class_type='migrationutils')