Windows OSs."""
from image_creator.os_type import OSBase, sysprep, add_sysprep_param
-from image_creator.util import FatalError, check_guestfs_version, \
- get_kvm_binary
+from image_creator.util import FatalError, get_kvm_binary
from image_creator.winexe import WinEXE, WinexeTimeout
import hivex
import string
import subprocess
import struct
+import re
# For more info see: http://technet.microsoft.com/en-us/library/jj612867.aspx
KMS_CLIENT_SETUP_KEYS = {
+ "Windows 8.1 Professional": "GCRJD-8NW9H-F2CDX-CCM8D-9D6T9",
+ "Windows 8.1 Professional N": "HMCNV-VVBFX-7HMBH-CTY9B-B4FXY",
+ "Windows 8.1 Enterprise": "MHF9N-XY6XB-WVXMC-BTDCT-MKKG7",
+ "Windows 8.1 Enterprise N": "TT4HM-HN7YT-62K67-RGRQJ-JFFXW",
+ "Windows Server 2012 R2 Server Standard": "D2N9P-3P6X9-2R39C-7RTCD-MDVJX",
+ "Windows Server 2012 R2 Datacenter": "W3GGN-FT8W3-Y4M27-J84CP-Q3VJ9",
+ "Windows Server 2012 R2 Essentials": "KNC87-3J2TX-XB4WP-VCPJV-M4FWM",
"Windows 8 Professional": "NG4HW-VH26C-733KW-K6F98-J8CK4",
"Windows 8 Professional N": "XCVCF-2NXM9-723PB-MHCB7-2RYQQ",
"Windows 8 Enterprise": "32JNW-9KQ84-P47T8-D8GGY-CWCK7",
'boot_timeout', int, 300, "Boot Timeout (seconds)", _POSINT)
@add_sysprep_param(
'connection_retries', int, 5, "Connection Retries", _POSINT)
+ @add_sysprep_param(
+ 'smp', int, 1, "Number of CPUs for the helper VM", _POSINT)
+ @add_sysprep_param(
+ 'mem', int, 1024, "Virtual RAM size for the helper VM (MiB)", _POSINT)
@add_sysprep_param('password', str, None, 'Image Administrator Password')
def __init__(self, image, **kargs):
super(Windows, self).__init__(image, **kargs)
+ # The commit with the following message was added in
+ # libguestfs 1.17.18 and was backported in version 1.16.11:
+ #
+ # When a Windows guest doesn't have a HKLM\SYSTEM\MountedDevices node,
+ # inspection fails. However inspection should not completely fail just
+ # because we cannot get the drive letter mapping from a guest.
+ #
+ # Since Microsoft Sysprep removes the aforementioned key, image
+ # creation for windows can only be supported if the installed guestfs
+ # version is 1.17.18 or higher
+ if self.image.check_guestfs_version(1, 17, 18) < 0 and \
+ (self.image.check_guestfs_version(1, 17, 0) >= 0 or
+ self.image.check_guestfs_version(1, 16, 11) < 0):
+ raise FatalError(
+ 'For windows support libguestfs 1.16.11 or above is required')
+
+ # Check if winexe is installed
+ if not WinEXE.is_installed():
+ raise FatalError(
+ "For windows support `Winexe' needs to be installed")
+
device = self.image.g.part_to_dev(self.root)
self.last_part_num = self.image.g.part_list(device)[-1]['part_num']
"""Install the appropriate KMS client setup key to the image to convert
it to a KMS client. Computers that are running volume licensing
editions of Windows 8, Windows Server 2012, Windows 7, Windows Server
- 2008 R2, Windows Vista, and Windows Server 2008 are, by default, KMS
+ 2008 R2, Windows Vista, and Windows Server 2008 are by default KMS
clients with no additional configuration needed.
"""
try:
# The maximum number of reclaimable bytes is: xxxx MB
#
if line.find('reclaimable') >= 0:
- querymax = line.split(':')[1].split()[0].strip()
- assert querymax.isdigit(), \
- "Number of reclaimable bytes not a number"
+ answer = line.split(':')[1].strip()
+ m = re.search('(\d+) MB', answer)
+ if m:
+ querymax = m.group(1)
+ else:
+ FatalError(
+ "Unexpected output for `shrink querymax' command: %s" %
+ line)
if querymax is None:
FatalError("Error in shrinking! "
querymax -= 100
if querymax < 0:
- self.out.warn("Not enought available space to shrink the image!")
+ self.out.warn("Not enough available space to shrink the image!")
return
self.out.output("\tReclaiming %dMB ..." % querymax)
r'IF NOT !ERRORLEVEL! EQU 0 EXIT /B 1 & ' +
r'DEL /Q %SCRIPT%"')
- stdout, stderr, rc = self._guest_exec(cmd)
+ stdout, stderr, rc = self._guest_exec(cmd, False)
+ if rc != 0:
+ FatalError("Shrinking failed. Please make sure the media is "
+ "defraged with a command like this: "
+ "`Defrag.exe /U /X /W'")
for line in stdout.splitlines():
if line.find('shrunk') >= 0:
self.out.output(line)
# Use ganeti's VNC port range for a random vnc port
self.display = random.randint(11000, 14999) - 5900
- kvm = get_kvm_binary()
+ kvm, needed_args = get_kvm_binary()
if kvm is None:
FatalError("Can't find the kvm binary")
- args = [
- kvm, '-smp', '1', '-m', '1024', '-drive',
- 'file=%s,format=raw,cache=unsafe,if=virtio' % self.disk,
+ args = [kvm]
+ args.extend(needed_args)
+
+ args.extend([
+ '-smp', str(self.params['smp']), '-m', str(self.params['mem']),
+ '-drive', 'file=%s,format=raw,cache=unsafe,if=virtio' % self.disk,
'-netdev', 'type=user,hostfwd=tcp::445-:445,id=netdev0',
'-device', 'virtio-net-pci,mac=%s,netdev=netdev0' % random_mac(),
'-vnc', ':%d' % self.display, '-serial', 'file:%s' % self.serial,
- '-monitor', 'stdio']
+ '-monitor', 'stdio'])
self.process = subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE)