In windows.py turn some constants to syspep params
authorNikos Skalkotos <skalkoto@grnet.gr>
Mon, 29 Jul 2013 14:23:02 +0000 (17:23 +0300)
committerNikos Skalkotos <skalkoto@grnet.gr>
Tue, 30 Jul 2013 13:43:59 +0000 (16:43 +0300)
Remove constants BOOT_TIMEOUT, SHUTDOWN_TIMEOUT and CONNECTION_RETRIES
and add then as sysprep_parameters

image_creator/dialog_menu.py
image_creator/dialog_wizard.py
image_creator/os_type/__init__.py
image_creator/os_type/windows.py

index d14925f..4d913cb 100644 (file)
@@ -70,6 +70,7 @@ CONFIGURATION_TASKS = [
 
 SYSPREP_PARAM_MAXLEN = 20
 
 
 SYSPREP_PARAM_MAXLEN = 20
 
+
 class MetadataMonitor(object):
     """Monitors image metadata chages"""
     def __init__(self, session, meta):
 class MetadataMonitor(object):
     """Monitors image metadata chages"""
     def __init__(self, session, meta):
@@ -632,33 +633,39 @@ def sysprep_params(session):
     if len(needed) == 0:
         return True
 
     if len(needed) == 0:
         return True
 
-    fields = []
-    for name in names:
-        param = needed[name]
-        default = available[name] if name in available else ""
-        fields.append(("%s: " % param.description, default,
-                       SYSPREP_PARAM_MAXLEN))
+    while 1:
+        fields = []
+        for name in names:
+            param = needed[name]
+            default = str(available[name]) if name in available else ""
+            fields.append(("%s: " % param.description, default,
+                           SYSPREP_PARAM_MAXLEN))
 
 
-    txt = "Please provide the following system preparation parameters:"
-    code, output = d.form(txt, height=13, width=WIDTH, form_height=len(fields),
-                          fields=fields)
+        txt = "Please provide the following system preparation parameters:"
+        code, output = d.form(txt, height=13, width=WIDTH,
+                              form_height=len(fields), fields=fields)
 
 
-    if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
-        return False
+        if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
+            return False
 
 
-    for i in range(len(fields)):
-        param = needed[names[i]]
-        try:
-            value = param.type(output[i])
-            if param.validate(value):
-                image.os.sysprep_params[names[i]] = value
-                continue
-        except ValueError:
-            pass
+        def check_params():
+            for i in range(len(fields)):
+                param = needed[names[i]]
+                try:
+                    value = param.type(output[i])
+                    if param.validate(value):
+                        image.os.sysprep_params[names[i]] = value
+                        continue
+                except ValueError:
+                    pass
+
+                d.msgbox("Invalid value for parameter: `%s'" % names[i],
+                         width=SMALL_WIDTH)
+                return False
+            return True
 
 
-        d.msgbox("The value you provided for parameter: `%s' is not valid" %
-                 names[i], width=SMALL_WIDTH)
-        return False
+        if check_params():
+            break
 
     return True
 
 
     return True
 
index c737e51..0856d8a 100644 (file)
@@ -336,14 +336,15 @@ def start_wizard(session):
 
     # Create Sysprep Params Wizard Page
     needed = image.os.needed_sysprep_params
 
     # Create Sysprep Params Wizard Page
     needed = image.os.needed_sysprep_params
-    param_names = needed.keys()
+    # Only show the parameters that don't have default values
+    param_names = [param for param in needed if needed[param].default is None]
 
     def sysprep_params_fields():
         fields = []
         available = image.os.sysprep_params
         for name in param_names:
             text = needed[name].description
 
     def sysprep_params_fields():
         fields = []
         available = image.os.sysprep_params
         for name in param_names:
             text = needed[name].description
-            default = available[name] if name in available else ""
+            default = str(available[name]) if name in available else ""
             fields.append(("%s: " % text, default, SYSPREP_PARAM_MAXLEN))
         return fields
 
             fields.append(("%s: " % text, default, SYSPREP_PARAM_MAXLEN))
         return fields
 
@@ -359,7 +360,7 @@ def start_wizard(session):
                 pass
 
             session['dialog'].msgbox("Invalid value for parameter `%s'" %
                 pass
 
             session['dialog'].msgbox("Invalid value for parameter `%s'" %
-                                         param_names[i])
+                                     param_names[i])
             raise WizardReloadPage
         return params
 
             raise WizardReloadPage
         return params
 
index 6cecbb9..69e45d9 100644 (file)
@@ -62,6 +62,7 @@ def os_cls(distro, osfamily):
 
 
 def add_prefix(target):
 
 
 def add_prefix(target):
+    """Decorator that adds a prefix to the result of a function"""
     def wrapper(self, *args):
         prefix = args[0]
         return [prefix + path for path in target(self, *args)]
     def wrapper(self, *args):
         prefix = args[0]
         return [prefix + path for path in target(self, *args)]
@@ -98,6 +99,8 @@ def add_sysprep_param(name, type, default, descr, validate=lambda x: True):
             init(self, *args, **kwargs)
             self.needed_sysprep_params[name] = \
                 self.SysprepParam(type, default, descr, validate)
             init(self, *args, **kwargs)
             self.needed_sysprep_params[name] = \
                 self.SysprepParam(type, default, descr, validate)
+            if default is not None:
+                self.sysprep_params[name] = default
         return inner
     return wrapper
 
         return inner
     return wrapper
 
index 58d98c8..20029a3 100644 (file)
@@ -50,10 +50,6 @@ import string
 import subprocess
 import struct
 
 import subprocess
 import struct
 
-BOOT_TIMEOUT = 300
-SHUTDOWN_TIMEOUT = 120
-CONNECTION_RETRIES = 5
-
 # For more info see: http://technet.microsoft.com/en-us/library/jj612867.aspx
 KMS_CLIENT_SETUP_KEYS = {
     "Windows 8 Professional": "NG4HW-VH26C-733KW-K6F98-J8CK4",
 # For more info see: http://technet.microsoft.com/en-us/library/jj612867.aspx
 KMS_CLIENT_SETUP_KEYS = {
     "Windows 8 Professional": "NG4HW-VH26C-733KW-K6F98-J8CK4",
@@ -104,10 +100,17 @@ KMS_CLIENT_SETUP_KEYS = {
     "Windows Server 2008 for Itanium-Based Systems":
     "4DWFP-JF3DJ-B7DTH-78FJB-PDRHK"}
 
     "Windows Server 2008 for Itanium-Based Systems":
     "4DWFP-JF3DJ-B7DTH-78FJB-PDRHK"}
 
+_POSINT = lambda x: type(x) == int and x >= 0
+
 
 class Windows(OSBase):
     """OS class for Windows"""
 
 class Windows(OSBase):
     """OS class for Windows"""
-
+    @add_sysprep_param(
+        'shutdown_timeout', int, 120, "Shutdown Timeout (seconds)", _POSINT)
+    @add_sysprep_param(
+        'boot_timeout', int, 300, "Boot Timeout (seconds)", _POSINT)
+    @add_sysprep_param(
+        'connection_retries', int, 5, "Connection Retries", _POSINT)
     @add_sysprep_param('password', str, None, 'Image Administrator Password')
     def __init__(self, image, **kargs):
         super(Windows, self).__init__(image, **kargs)
     @add_sysprep_param('password', str, None, 'Image Administrator Password')
     def __init__(self, image, **kargs):
         super(Windows, self).__init__(image, **kargs)
@@ -311,7 +314,7 @@ class Windows(OSBase):
             self.out.output("Starting windows VM ...", False)
             monitorfd, monitor = tempfile.mkstemp()
             os.close(monitorfd)
             self.out.output("Starting windows VM ...", False)
             monitorfd, monitor = tempfile.mkstemp()
             os.close(monitorfd)
-            vm = _VM(self.image.device, monitor)
+            vm = _VM(self.image.device, monitor, self.sysprep_params)
             self.out.success("started (console on vnc display: %d)." %
                              vm.display)
 
             self.out.success("started (console on vnc display: %d)." %
                              vm.display)
 
@@ -362,7 +365,7 @@ class Windows(OSBase):
             self.out.success("done")
 
             self.out.output("Waiting for windows to shut down ...", False)
             self.out.success("done")
 
             self.out.output("Waiting for windows to shut down ...", False)
-            vm.wait(SHUTDOWN_TIMEOUT)
+            vm.wait(self.sysprep_params['shutdown_timeout'])
             self.out.success("done")
         finally:
             if monitor is not None:
             self.out.success("done")
         finally:
             if monitor is not None:
@@ -395,7 +398,7 @@ class Windows(OSBase):
     def _wait_vm_boot(self, vm, fname, msg):
         """Wait until a message appears on a file or the vm process dies"""
 
     def _wait_vm_boot(self, vm, fname, msg):
         """Wait until a message appears on a file or the vm process dies"""
 
-        for _ in range(BOOT_TIMEOUT):
+        for _ in range(self.sysprep_params['boot_timeout']):
             time.sleep(1)
             with open(fname) as f:
                 for line in f:
             time.sleep(1)
             with open(fname) as f:
                 for line in f:
@@ -685,11 +688,17 @@ class Windows(OSBase):
     def _check_connectivity(self):
         """Check if winexe works on the Windows VM"""
 
     def _check_connectivity(self):
         """Check if winexe works on the Windows VM"""
 
+        retries = self.sysprep_params['connection_retries']
+        # If the connection_retries parameter is set to 0 disable the
+        # connectivity check
+        if retries == 0:
+            return True
+
         passwd = self.sysprep_params['password']
         winexe = WinEXE('Administrator', passwd, 'localhost')
         winexe.uninstall().debug(9)
 
         passwd = self.sysprep_params['password']
         winexe = WinEXE('Administrator', passwd, 'localhost')
         winexe.uninstall().debug(9)
 
-        for i in range(CONNECTION_RETRIES):
+        for i in range(retries):
             (stdout, stderr, rc) = winexe.run('cmd /C')
             if rc == 0:
                 return True
             (stdout, stderr, rc) = winexe.run('cmd /C')
             if rc == 0:
                 return True
@@ -699,10 +708,11 @@ class Windows(OSBase):
             finally:
                 log.close()
             self.out.output("failed! See: `%s' for the full output" % log.name)
             finally:
                 log.close()
             self.out.output("failed! See: `%s' for the full output" % log.name)
-            if i < CONNECTION_RETRIES - 1:
-                self.out.output("Retrying ...", False)
-        raise FatalError("Connection to the VM failed after %d retries" %
-                         CONNECTION_RETRIES)
+            if i < retries - 1:
+                self.out.output("retrying ...", False)
+
+        raise FatalError("Connection to the Windows VM failed after %d retries"
+                         % retries)
 
     def _guest_exec(self, command, fatal=True):
         """Execute a command on a windows VM"""
 
     def _guest_exec(self, command, fatal=True):
         """Execute a command on a windows VM"""
@@ -729,7 +739,7 @@ class Windows(OSBase):
 
 class _VM(object):
     """Windows Virtual Machine"""
 
 class _VM(object):
     """Windows Virtual Machine"""
-    def __init__(self, disk, serial):
+    def __init__(self, disk, serial, params):
         """Create _VM instance
 
             disk: VM's hard disk
         """Create _VM instance
 
             disk: VM's hard disk
@@ -738,6 +748,7 @@ class _VM(object):
 
         self.disk = disk
         self.serial = serial
 
         self.disk = disk
         self.serial = serial
+        self.params = params
 
         def random_mac():
             """creates a random mac address"""
 
         def random_mac():
             """creates a random mac address"""
@@ -782,7 +793,7 @@ class _VM(object):
 
         signal.signal(signal.SIGALRM, handler)
 
 
         signal.signal(signal.SIGALRM, handler)
 
-        signal.alarm(SHUTDOWN_TIMEOUT)
+        signal.alarm(self.params['shutdown_timeout'])
         self.process.communicate(input="system_powerdown\n")
         signal.alarm(0)
 
         self.process.communicate(input="system_powerdown\n")
         signal.alarm(0)