Revision 82e8c357
b/image_creator/dialog_menu.py | ||
---|---|---|
70 | 70 |
|
71 | 71 |
SYSPREP_PARAM_MAXLEN = 20 |
72 | 72 |
|
73 |
|
|
73 | 74 |
class MetadataMonitor(object): |
74 | 75 |
"""Monitors image metadata chages""" |
75 | 76 |
def __init__(self, session, meta): |
... | ... | |
632 | 633 |
if len(needed) == 0: |
633 | 634 |
return True |
634 | 635 |
|
635 |
fields = [] |
|
636 |
for name in names: |
|
637 |
param = needed[name] |
|
638 |
default = available[name] if name in available else "" |
|
639 |
fields.append(("%s: " % param.description, default, |
|
640 |
SYSPREP_PARAM_MAXLEN)) |
|
636 |
while 1: |
|
637 |
fields = [] |
|
638 |
for name in names: |
|
639 |
param = needed[name] |
|
640 |
default = str(available[name]) if name in available else "" |
|
641 |
fields.append(("%s: " % param.description, default, |
|
642 |
SYSPREP_PARAM_MAXLEN)) |
|
641 | 643 |
|
642 |
txt = "Please provide the following system preparation parameters:" |
|
643 |
code, output = d.form(txt, height=13, width=WIDTH, form_height=len(fields),
|
|
644 |
fields=fields) |
|
644 |
txt = "Please provide the following system preparation parameters:"
|
|
645 |
code, output = d.form(txt, height=13, width=WIDTH,
|
|
646 |
form_height=len(fields), fields=fields)
|
|
645 | 647 |
|
646 |
if code in (d.DIALOG_CANCEL, d.DIALOG_ESC): |
|
647 |
return False |
|
648 |
if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
|
|
649 |
return False
|
|
648 | 650 |
|
649 |
for i in range(len(fields)): |
|
650 |
param = needed[names[i]] |
|
651 |
try: |
|
652 |
value = param.type(output[i]) |
|
653 |
if param.validate(value): |
|
654 |
image.os.sysprep_params[names[i]] = value |
|
655 |
continue |
|
656 |
except ValueError: |
|
657 |
pass |
|
651 |
def check_params(): |
|
652 |
for i in range(len(fields)): |
|
653 |
param = needed[names[i]] |
|
654 |
try: |
|
655 |
value = param.type(output[i]) |
|
656 |
if param.validate(value): |
|
657 |
image.os.sysprep_params[names[i]] = value |
|
658 |
continue |
|
659 |
except ValueError: |
|
660 |
pass |
|
661 |
|
|
662 |
d.msgbox("Invalid value for parameter: `%s'" % names[i], |
|
663 |
width=SMALL_WIDTH) |
|
664 |
return False |
|
665 |
return True |
|
658 | 666 |
|
659 |
d.msgbox("The value you provided for parameter: `%s' is not valid" % |
|
660 |
names[i], width=SMALL_WIDTH) |
|
661 |
return False |
|
667 |
if check_params(): |
|
668 |
break |
|
662 | 669 |
|
663 | 670 |
return True |
664 | 671 |
|
b/image_creator/dialog_wizard.py | ||
---|---|---|
336 | 336 |
|
337 | 337 |
# Create Sysprep Params Wizard Page |
338 | 338 |
needed = image.os.needed_sysprep_params |
339 |
param_names = needed.keys() |
|
339 |
# Only show the parameters that don't have default values |
|
340 |
param_names = [param for param in needed if needed[param].default is None] |
|
340 | 341 |
|
341 | 342 |
def sysprep_params_fields(): |
342 | 343 |
fields = [] |
343 | 344 |
available = image.os.sysprep_params |
344 | 345 |
for name in param_names: |
345 | 346 |
text = needed[name].description |
346 |
default = available[name] if name in available else ""
|
|
347 |
default = str(available[name]) if name in available else ""
|
|
347 | 348 |
fields.append(("%s: " % text, default, SYSPREP_PARAM_MAXLEN)) |
348 | 349 |
return fields |
349 | 350 |
|
... | ... | |
359 | 360 |
pass |
360 | 361 |
|
361 | 362 |
session['dialog'].msgbox("Invalid value for parameter `%s'" % |
362 |
param_names[i])
|
|
363 |
param_names[i]) |
|
363 | 364 |
raise WizardReloadPage |
364 | 365 |
return params |
365 | 366 |
|
b/image_creator/os_type/__init__.py | ||
---|---|---|
62 | 62 |
|
63 | 63 |
|
64 | 64 |
def add_prefix(target): |
65 |
"""Decorator that adds a prefix to the result of a function""" |
|
65 | 66 |
def wrapper(self, *args): |
66 | 67 |
prefix = args[0] |
67 | 68 |
return [prefix + path for path in target(self, *args)] |
... | ... | |
98 | 99 |
init(self, *args, **kwargs) |
99 | 100 |
self.needed_sysprep_params[name] = \ |
100 | 101 |
self.SysprepParam(type, default, descr, validate) |
102 |
if default is not None: |
|
103 |
self.sysprep_params[name] = default |
|
101 | 104 |
return inner |
102 | 105 |
return wrapper |
103 | 106 |
|
b/image_creator/os_type/windows.py | ||
---|---|---|
50 | 50 |
import subprocess |
51 | 51 |
import struct |
52 | 52 |
|
53 |
BOOT_TIMEOUT = 300 |
|
54 |
SHUTDOWN_TIMEOUT = 120 |
|
55 |
CONNECTION_RETRIES = 5 |
|
56 |
|
|
57 | 53 |
# For more info see: http://technet.microsoft.com/en-us/library/jj612867.aspx |
58 | 54 |
KMS_CLIENT_SETUP_KEYS = { |
59 | 55 |
"Windows 8 Professional": "NG4HW-VH26C-733KW-K6F98-J8CK4", |
... | ... | |
104 | 100 |
"Windows Server 2008 for Itanium-Based Systems": |
105 | 101 |
"4DWFP-JF3DJ-B7DTH-78FJB-PDRHK"} |
106 | 102 |
|
103 |
_POSINT = lambda x: type(x) == int and x >= 0 |
|
104 |
|
|
107 | 105 |
|
108 | 106 |
class Windows(OSBase): |
109 | 107 |
"""OS class for Windows""" |
110 |
|
|
108 |
@add_sysprep_param( |
|
109 |
'shutdown_timeout', int, 120, "Shutdown Timeout (seconds)", _POSINT) |
|
110 |
@add_sysprep_param( |
|
111 |
'boot_timeout', int, 300, "Boot Timeout (seconds)", _POSINT) |
|
112 |
@add_sysprep_param( |
|
113 |
'connection_retries', int, 5, "Connection Retries", _POSINT) |
|
111 | 114 |
@add_sysprep_param('password', str, None, 'Image Administrator Password') |
112 | 115 |
def __init__(self, image, **kargs): |
113 | 116 |
super(Windows, self).__init__(image, **kargs) |
... | ... | |
311 | 314 |
self.out.output("Starting windows VM ...", False) |
312 | 315 |
monitorfd, monitor = tempfile.mkstemp() |
313 | 316 |
os.close(monitorfd) |
314 |
vm = _VM(self.image.device, monitor) |
|
317 |
vm = _VM(self.image.device, monitor, self.sysprep_params)
|
|
315 | 318 |
self.out.success("started (console on vnc display: %d)." % |
316 | 319 |
vm.display) |
317 | 320 |
|
... | ... | |
362 | 365 |
self.out.success("done") |
363 | 366 |
|
364 | 367 |
self.out.output("Waiting for windows to shut down ...", False) |
365 |
vm.wait(SHUTDOWN_TIMEOUT)
|
|
368 |
vm.wait(self.sysprep_params['shutdown_timeout'])
|
|
366 | 369 |
self.out.success("done") |
367 | 370 |
finally: |
368 | 371 |
if monitor is not None: |
... | ... | |
395 | 398 |
def _wait_vm_boot(self, vm, fname, msg): |
396 | 399 |
"""Wait until a message appears on a file or the vm process dies""" |
397 | 400 |
|
398 |
for _ in range(BOOT_TIMEOUT):
|
|
401 |
for _ in range(self.sysprep_params['boot_timeout']):
|
|
399 | 402 |
time.sleep(1) |
400 | 403 |
with open(fname) as f: |
401 | 404 |
for line in f: |
... | ... | |
685 | 688 |
def _check_connectivity(self): |
686 | 689 |
"""Check if winexe works on the Windows VM""" |
687 | 690 |
|
691 |
retries = self.sysprep_params['connection_retries'] |
|
692 |
# If the connection_retries parameter is set to 0 disable the |
|
693 |
# connectivity check |
|
694 |
if retries == 0: |
|
695 |
return True |
|
696 |
|
|
688 | 697 |
passwd = self.sysprep_params['password'] |
689 | 698 |
winexe = WinEXE('Administrator', passwd, 'localhost') |
690 | 699 |
winexe.uninstall().debug(9) |
691 | 700 |
|
692 |
for i in range(CONNECTION_RETRIES):
|
|
701 |
for i in range(retries):
|
|
693 | 702 |
(stdout, stderr, rc) = winexe.run('cmd /C') |
694 | 703 |
if rc == 0: |
695 | 704 |
return True |
... | ... | |
699 | 708 |
finally: |
700 | 709 |
log.close() |
701 | 710 |
self.out.output("failed! See: `%s' for the full output" % log.name) |
702 |
if i < CONNECTION_RETRIES - 1: |
|
703 |
self.out.output("Retrying ...", False) |
|
704 |
raise FatalError("Connection to the VM failed after %d retries" % |
|
705 |
CONNECTION_RETRIES) |
|
711 |
if i < retries - 1: |
|
712 |
self.out.output("retrying ...", False) |
|
713 |
|
|
714 |
raise FatalError("Connection to the Windows VM failed after %d retries" |
|
715 |
% retries) |
|
706 | 716 |
|
707 | 717 |
def _guest_exec(self, command, fatal=True): |
708 | 718 |
"""Execute a command on a windows VM""" |
... | ... | |
729 | 739 |
|
730 | 740 |
class _VM(object): |
731 | 741 |
"""Windows Virtual Machine""" |
732 |
def __init__(self, disk, serial): |
|
742 |
def __init__(self, disk, serial, params):
|
|
733 | 743 |
"""Create _VM instance |
734 | 744 |
|
735 | 745 |
disk: VM's hard disk |
... | ... | |
738 | 748 |
|
739 | 749 |
self.disk = disk |
740 | 750 |
self.serial = serial |
751 |
self.params = params |
|
741 | 752 |
|
742 | 753 |
def random_mac(): |
743 | 754 |
"""creates a random mac address""" |
... | ... | |
782 | 793 |
|
783 | 794 |
signal.signal(signal.SIGALRM, handler) |
784 | 795 |
|
785 |
signal.alarm(SHUTDOWN_TIMEOUT)
|
|
796 |
signal.alarm(self.params['shutdown_timeout'])
|
|
786 | 797 |
self.process.communicate(input="system_powerdown\n") |
787 | 798 |
signal.alarm(0) |
788 | 799 |
|
Also available in: Unified diff