Alessandro Pilotti 10 лет назад
Родитель
Сommit
9979bdb49d

+ 0 - 1
coriolis/osmorphing/manager.py

@@ -2,7 +2,6 @@ from oslo_log import log as logging
 
 from coriolis.osmorphing import factory as osmorphing_factory
 from coriolis.osmorphing.osmount import factory as osmount_factory
-from coriolis import utils
 
 LOG = logging.getLogger(__name__)
 

+ 10 - 0
coriolis/osmorphing/osmount/windows.py

@@ -21,6 +21,8 @@ class WindowsMountTools(base.BaseOSMountTools):
         cert_key_pem = connection_info.get("cert_key_pem")
         url = "https://%s:%s/wsman" % (host, port)
 
+        LOG.info("Connection info: %s", str(connection_info))
+
         LOG.info("Waiting for connectivity on host: %(host)s:%(port)s",
                  {"host": host, "port": port})
         utils.wait_for_port_connectivity(host, port)
@@ -51,10 +53,17 @@ class WindowsMountTools(base.BaseOSMountTools):
             "Update-HostStorageCache", ignore_stdout=True)
 
     def _bring_all_disks_online(self):
+        LOG.info("Bringing offline disks online")
         self._conn.exec_ps_command(
             "Get-Disk |? IsOffline | Set-Disk -IsOffline $False",
             ignore_stdout=True)
 
+    def _set_all_disks_rw_mode(self):
+        LOG.info("Setting RW mode on RO disks")
+        self._conn.exec_ps_command(
+            "Get-Disk |? IsReadOnly | Set-Disk -IsReadOnly $False",
+            ignore_stdout=True)
+
     def _bring_disk_offline(self, drive_letter):
         self._conn.exec_ps_command(
             "Get-Volume |? DriveLetter -eq \"%s\" | Get-Partition | "
@@ -71,6 +80,7 @@ class WindowsMountTools(base.BaseOSMountTools):
     def mount_os(self, volume_devs):
         self._refresh_storage()
         self._bring_all_disks_online()
+        self._set_all_disks_rw_mode()
         fs_roots = self._get_fs_roots()
         system_drive = self._get_system_drive()
 

+ 93 - 35
coriolis/osmorphing/windows.py

@@ -1,5 +1,6 @@
 import os
 import re
+import uuid
 
 from distutils import version
 from oslo_config import cfg
@@ -12,7 +13,7 @@ from coriolis.osmorphing import base
 opts = [
     cfg.StrOpt('virtio_iso_url',
                default='https://fedorapeople.org/groups/virt/virtio-win/'
-               'direct-downloads/latest-virtio/virtio-win.iso',
+               'direct-downloads/stable-virtio/virtio-win.iso',
                help="Location of the virtio-win ISO"),
 ]
 
@@ -25,8 +26,11 @@ LOG = logging.getLogger(__name__)
 class WindowsMorphingTools(base.BaseOSMorphingTools):
     def _check_os(self):
         try:
-            version = self._get_image_version()
-            return ('Windows', version)
+            (self._version_number,
+             self._edition_id,
+             self._installation_type,
+             self._product_name) = self._get_image_version_info()
+            return ('Windows', self._product_name)
         except exception.CoriolisException:
             pass
 
@@ -42,25 +46,70 @@ class WindowsMorphingTools(base.BaseOSMorphingTools):
         # TODO: implement
         pass
 
-    def _get_dism_features(self):
-        LOG.info("Getting image features")
-        return self._conn.exec_command(
-            "dism.exe", ["/get-features",  "/image:%s" % self._os_root_dir])
+    def _get_dism_path(self):
+        return "c:\\Windows\\System32\\dism.exe"
+
+    def _load_registry_hive(self, subkey, path):
+        self._conn.exec_command("reg.exe", ["load", subkey, path])
+
+    def _unload_registry_hive(self, subkey):
+        self._conn.exec_command("reg.exe", ["unload", subkey])
+
+    def _get_ps_fl_value(self, data, name):
+        m = re.search(r'^%s\s*: (.*)$' % name, data, re.MULTILINE)
+        if m:
+            return m.groups()[0]
+
+    def _get_image_version_info(self):
+        key_name = str(uuid.uuid4())
+
+        self._load_registry_hive(
+            "HKLM\%s" % key_name,
+            "%sWindows\\System32\\config\\SOFTWARE" % self._os_root_dir)
+        try:
+            version_info_str = self._conn.exec_ps_command(
+                "Get-ItemProperty "
+                "'HKLM:\%s\Microsoft\Windows NT\CurrentVersion' "
+                "| select CurrentVersion, CurrentMajorVersionNumber, "
+                "CurrentMinorVersionNumber,  CurrentBuildNumber, "
+                "InstallationType, ProductName, EditionID | FL" %
+                key_name).replace(self._conn.EOL, os.linesep)
+        finally:
+            self._unload_registry_hive("HKLM\%s" % key_name)
+
+        version_info = {}
+        for n in ["CurrentVersion", "CurrentMajorVersionNumber",
+                  "CurrentMinorVersionNumber", "CurrentBuildNumber",
+                  "InstallationType", "ProductName", "EditionID"]:
+            version_info[n] = self._get_ps_fl_value(version_info_str, n)
+
+        if (not version_info["CurrentMajorVersionNumber"] and
+                not version_info["CurrentVersion"]):
+            raise exception.CoriolisException(
+                "Cannot find Windows version info")
+
+        if version_info["CurrentMajorVersionNumber"]:
+            version_str = "%s.%s.%s" % (
+                version_info["CurrentMajorVersionNumber"],
+                version_info["CurrentMinorVersionNumber"],
+                version_info["CurrentBuildNumber"])
+        else:
+            version_str = "%s.%s" % (
+                version_info["CurrentVersion"],
+                version_info["CurrentBuildNumber"])
+
+        return (version.LooseVersion(version_str),
+                version_info["EditionID"],
+                version_info["InstallationType"],
+                version_info["ProductName"])
 
     def _add_dism_driver(self, driver_path):
         LOG.info("Adding driver: %s" % driver_path)
+        dism_path = self._get_dism_path()
         return self._conn.exec_command(
-            "dism.exe /add-driver /image:%s /driver:%s /recurse /forceunsigned"
-            % (self._os_root_dir, driver_path))
-
-    def _get_image_version(self):
-        features = self._get_dism_features()
-        m = re.search(r'^Image Version: (.*)$',
-                      features.replace(self._conn.EOL, os.linesep),
-                      re.MULTILINE)
-        if not m:
-            raise exception.CoriolisException("Could not find OS version")
-        return m.groups()[0]
+            dism_path,
+            ["/add-driver", "/image:%s" % self._os_root_dir,
+             "/driver:%s" % driver_path, "/recurse", "/forceunsigned"])
 
     def _mount_disk_image(self, path):
         LOG.info("Mounting disk image: %s" % path)
@@ -77,22 +126,30 @@ class WindowsMorphingTools(base.BaseOSMorphingTools):
         # TODO: add support for x86
         arch = "amd64"
 
+        CLIENT = 1
+        SERVER = 2
+
         # Ordered by version number
-        # TODO(alexpilotti): distinguish client and server
         virtio_dirs = [
-            ("xp", version.LooseVersion("5.1")),
-            ("2k3", version.LooseVersion("5.2")),
-            ("2k8", version.LooseVersion("6.0")),
-            ("w7", version.LooseVersion("6.1")),
-            ("2k8R2", version.LooseVersion("6.1")),
-            ("w8", version.LooseVersion("6.2")),
-            ("2k12", version.LooseVersion("6.2")),
-            ("w8.1", version.LooseVersion("6.3")),
-            ("2k12R2", version.LooseVersion("6.3")),
-            ("w10", version.LooseVersion("10.0")),
+            ("xp", version.LooseVersion("5.1"), CLIENT),
+            ("2k3", version.LooseVersion("5.2"), SERVER),
+            ("2k8", version.LooseVersion("6.0"), SERVER | CLIENT),
+            ("w7", version.LooseVersion("6.1"), CLIENT),
+            ("2k8R2", version.LooseVersion("6.1"), SERVER),
+            ("w8", version.LooseVersion("6.2"), CLIENT),
+            ("2k12", version.LooseVersion("6.2"), SERVER),
+            ("w8.1", version.LooseVersion("6.3"), CLIENT),
+            ("2k12R2", version.LooseVersion("6.3"), SERVER),
+            ("w10", version.LooseVersion("10.0"), SERVER | CLIENT),
             ]
 
-        drivers = ["Balloon", "NetKVM", "qxldod", "pvpanic", "viorng",
+        # The list of all possible editions is huge, this is a semplification
+        if "Server" in self._edition_id:
+            edition_type = SERVER
+        else:
+            edition_type = CLIENT
+
+        drivers = ["Balloon", "NetKVM", "qxl", "qxldod", "pvpanic", "viorng",
                    "vioscsi", "vioserial", "viostor"]
 
         self._event_manager.progress_update("Downloading virtio-win drivers")
@@ -105,10 +162,10 @@ class WindowsMorphingTools(base.BaseOSMorphingTools):
 
         virtio_drive = self._mount_disk_image(virtio_iso_path)
         try:
-            image_version = version.LooseVersion(self._version)
-
-            for virtio_dir, dir_version in reversed(virtio_dirs):
-                if image_version >= dir_version:
+            for virtio_dir, dir_version, dir_edition_type in reversed(
+                    virtio_dirs):
+                if self._version_number >= dir_version and (
+                        edition_type & dir_edition_type):
                     path = "%s:\\Balloon\\%s\\%s" % (
                         virtio_drive, virtio_dir, arch)
                     if self._conn.test_path(path):
@@ -118,7 +175,8 @@ class WindowsMorphingTools(base.BaseOSMorphingTools):
                             virtio_drive, d, virtio_dir, arch)
                             for d in drivers]
             for driver_path in driver_paths:
-                self._add_dism_driver(driver_path)
+                if self._conn.test_path(driver_path):
+                    self._add_dism_driver(driver_path)
         finally:
             self._dismount_disk_image(virtio_iso_path)
 

+ 2 - 1
coriolis/providers/openstack/__init__.py

@@ -359,7 +359,8 @@ class ImportProvider(base.BaseImportProvider):
 
         migr_image_name = target_environment.get(
             "migr_image_name",
-            target_environment.get("migr_image_name_map", {}).get(os_type,
+            target_environment.get("migr_image_name_map", {}).get(
+                os_type,
                 CONF.openstack_migration_provider.migr_image_name_map.get(
                     os_type)))
         migr_flavor_name = target_environment.get(

+ 1 - 1
coriolis/wsman.py

@@ -80,7 +80,7 @@ class WSManConnection(object):
         else:
             cmd_fmt = "\"%s\""
 
-        std_out = self.exec_command("powershell.exe", [cmd_fmt % cmd])
+        self.exec_command("powershell.exe", [cmd_fmt % cmd])
 
         if not ignore_stdout:
             return self.exec_command("cmd.exe", ["/c", "type", "out.txt"])[:-2]