Commit 86c42bba authored by Nikos Skalkotos's avatar Nikos Skalkotos

Merge branch 'release-0.7' into debian-release-0.7

parents bef488b5 a413acff
2014-09-12, v0.7rc2
* Support all QEMU supported disk image formats as input media
* Detect if a Windows input media is sysprepped
* Support VirtIO driver installation in Windows
* Do a major code cleanup
* Fix bugs
2014-06-10, v0.6.2
* Add support for Ubuntu 14.04
* Fix a bug in Windows image creation
......
......@@ -704,11 +704,12 @@ def virtio(session):
(code, choice) = d.menu(
"In this menu you can see details about the installed VirtIO "
"drivers on the input media. Press <OK> to see more information "
"drivers on the input media. Press <Info> to see more information "
"about a specific installed driver or <Update> to install one or "
"more new drivers.", height=16, width=WIDTH, choices=choices,
menu_height=len(choices), cancel="Back", title="VirtIO Drivers",
extra_button=1, extra_label="Update", default_item=default_item)
ok_label="Info", menu_height=len(choices), cancel="Back",
title="VirtIO Drivers", extra_button=1, extra_label="Update",
default_item=default_item)
if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
return True
......@@ -832,13 +833,12 @@ def sysprep(session):
sysprep_help = "%s\n%s\n\n" % (help_title, '=' * len(help_title))
for task in syspreps:
name, descr = image.os.sysprep_info(task)
display_name = name.replace('-', ' ').capitalize()
sysprep_help += "%s\n" % display_name
sysprep_help += "%s\n" % ('-' * len(display_name))
name, descr, display = image.os.sysprep_info(task)
sysprep_help += "%s\n" % display
sysprep_help += "%s\n" % ('-' * len(display))
sysprep_help += "%s\n\n" % wrapper.fill(" ".join(descr.split()))
enabled = 1 if image.os.sysprep_enabled(task) else 0
choices.append((str(index + 1), display_name, enabled))
choices.append((str(index + 1), display, enabled))
index += 1
(code, tags) = d.checklist(
......
......@@ -156,10 +156,13 @@ class Disk(object):
self.out.warn("Snapshotting ignored for host bundling mode.")
return self.file
# Examine media file
mode = os.stat(self.file).st_mode
self.out.output("Snapshotting media source ...", False)
# Create a qcow2 snapshot for image files
if not stat.S_ISBLK(os.stat(self.file).st_mode):
if not stat.S_ISBLK(mode):
snapshot = create_snapshot(self.file, self.tmp)
self._add_cleanup(os.unlink, snapshot)
self.out.success('done')
......
......@@ -292,12 +292,14 @@ class OSBase(object):
"""Returns information about a sysprep object"""
assert hasattr(obj, '_sysprep'), "Object is not a sysprep"
SysprepInfo = namedtuple("SysprepInfo", "name description")
SysprepInfo = namedtuple("SysprepInfo", "name description display")
name = obj.__name__.replace('_', '-')[1:]
description = textwrap.dedent(obj.__doc__)
display = getattr(obj, '_sysprep_display',
name.replace('-', ' ').capitalize())
return SysprepInfo(name, description)
return SysprepInfo(name, description, display)
def get_sysprep_by_name(self, name):
"""Returns the sysprep object with the given name"""
......
......@@ -240,7 +240,7 @@ class Windows(OSBase):
@add_sysprep_param('virtio', 'dir', "", DESCR['virtio'],
check=virtio_dir_check, hidden=True)
@add_sysprep_param(
'virtio_timeout', 'posint', 300, DESCR['virtio_timeout'])
'virtio_timeout', 'posint', 900, DESCR['virtio_timeout'])
def __init__(self, image, **kargs):
super(Windows, self).__init__(image, **kargs)
......@@ -313,20 +313,21 @@ class Windows(OSBase):
self.image.device, self.sysprep_params,
namedtuple('User', 'rid name')(admin, self.usernames[admin]))
@sysprep('Disabling IPv6 privacy extensions')
@sysprep('Disabling IPv6 privacy extensions',
display="Disable IPv6 privacy extensions")
def _disable_ipv6_privacy_extensions(self):
"""Disable IPv6 privacy extensions"""
self.vm.rexec('netsh interface ipv6 set global '
'randomizeidentifiers=disabled store=persistent')
@sysprep('Disabling Teredo interface')
@sysprep('Disabling Teredo interface', display="Disable Teredo")
def _disable_teredo(self):
"""Disable Teredo interface"""
self.vm.rexec('netsh interface teredo set state disabled')
@sysprep('Disabling ISATAP Adapters')
@sysprep('Disabling ISATAP Adapters', display="Disable ISATAP")
def _disable_isatap(self):
"""Disable ISATAP Adapters"""
......@@ -338,7 +339,7 @@ class Windows(OSBase):
self.vm.rexec('netsh firewall set icmpsetting 8')
@sysprep('Setting the system clock to UTC')
@sysprep('Setting the system clock to UTC', display="UTC")
def _utc(self):
"""Set the hardware clock to UTC"""
......@@ -354,7 +355,8 @@ class Windows(OSBase):
"cmd /q /c for /f \"tokens=*\" %l in ('wevtutil el') do "
"wevtutil cl \"%l\"")
@sysprep('Executing Sysprep on the image (may take more that 10 min)')
@sysprep('Executing Sysprep on the image (may take more that 10 min)',
display="Microsoft Sysprep")
def _microsoft_sysprep(self):
"""Run the Microsoft System Preparation Tool. This will remove
system-specific data and will make the image ready to be deployed.
......@@ -365,7 +367,8 @@ class Windows(OSBase):
r'/quiet /generalize /oobe /shutdown', uninstall=True)
self.sysprepped = True
@sysprep('Converting the image into a KMS client', enabled=False)
@sysprep('Converting the image into a KMS client', enabled=False,
display="KMS client setup")
def _kms_client_setup(self):
"""Install the appropriate KMS client setup key to the image to convert
it to a KMS client. Computers that are running volume licensing
......@@ -701,7 +704,7 @@ class Windows(OSBase):
"""Check if winexe works on the Windows VM"""
retries = self.sysprep_params['connection_retries'].value
timeout = [2]
timeout = [5]
for i in xrange(1, retries - 1):
timeout.insert(0, timeout[0] * 2)
......@@ -724,8 +727,9 @@ class Windows(OSBase):
log.close()
self.out.output("failed! See: `%s' for the full output" % log.name)
if i < retries - 1:
self.out.output("retrying ...", False)
time.sleep(timeout.pop())
wait = timeout.pop()
self.out.output("retrying in %d seconds ..." % wait, False)
time.sleep(wait)
raise FatalError("Connection to the Windows VM failed after %d retries"
% retries)
......
......@@ -23,6 +23,7 @@ import signal
import tempfile
import os
import time
import errno
from string import lowercase, uppercase, digits
from image_creator.util import FatalError, get_kvm_binary
......@@ -168,8 +169,9 @@ class VM(object):
if self.serial is not None:
try:
os.unlink(self.serial)
except FileNotFoundError:
pass
except OSError as e:
if errno.errorcode[e.errno] != 'ENOENT': # File not found
raise
def wait_on_serial(self, timeout):
"""Wait until the random token appears on the VM's serial port"""
......
......@@ -25,9 +25,6 @@ import os
import re
import json
import tempfile
from sh import qemu_img
from sh import qemu_nbd
from sh import modprobe
class FatalError(Exception):
......@@ -35,8 +32,25 @@ class FatalError(Exception):
pass
def get_command(command):
"""Return a file system binary command"""
def find_sbin_command(command, exception):
search_paths = ['/usr/local/sbin', '/usr/sbin', '/sbin']
for fullpath in map(lambda x: "%s/%s" % (x, command), search_paths):
if os.path.exists(fullpath) and os.access(fullpath, os.X_OK):
return sh.Command(fullpath)
raise exception
try:
return sh.__getattr__(command)
except sh.CommandNotFound as e:
return find_sbin_command(command, e)
def image_info(image):
"""Returns information about an image file"""
qemu_img = get_command('qemu-img')
info = qemu_img('info', '--output', 'json', image)
return json.loads(str(info))
......@@ -44,6 +58,7 @@ def image_info(image):
def create_snapshot(source, target_dir):
"""Returns a qcow2 snapshot of an image file"""
qemu_img = get_command('qemu-img')
snapfd, snap = tempfile.mkstemp(prefix='snapshot-', dir=target_dir)
os.close(snapfd)
qemu_img('create', '-f', 'qcow2', '-o',
......@@ -51,21 +66,6 @@ def create_snapshot(source, target_dir):
return snap
def get_command(command):
"""Return a file system binary command"""
def find_sbin_command(command, exception):
search_paths = ['/usr/local/sbin', '/usr/sbin', '/sbin']
for fullpath in map(lambda x: "%s/%s" % (x, command), search_paths):
if os.path.exists(fullpath) and os.access(fullpath, os.X_OK):
return sh.Command(fullpath)
raise exception
try:
return sh.__getattr__(command)
except sh.CommandNotFound as e:
return find_sbin_command(command, e)
def get_kvm_binary():
"""Returns the path to the kvm binary and some extra arguments if needed"""
......@@ -131,6 +131,8 @@ class QemuNBD(object):
self.image = image
self.device = None
self.pattern = re.compile('^nbd\d+$')
self.modprobe = get_command('modprobe')
self.qemu_nbd = get_command('qemu-nbd')
def _list_devices(self):
"""Returns all the NBD block devices"""
......@@ -141,7 +143,7 @@ class QemuNBD(object):
devs = self._list_devices()
if len(devs) == 0: # Is nbd module loaded?
modprobe('nbd', 'max_part=16')
self.modprobe('nbd', 'max_part=16')
# Wait a second for /dev to be populated
time.sleep(1)
devs = self._list_devices()
......@@ -166,7 +168,7 @@ class QemuNBD(object):
args.append('-r')
args.append(self.image)
qemu_nbd(*args)
self.qemu_nbd(*args)
self.device = device
return device
......@@ -174,7 +176,7 @@ class QemuNBD(object):
"""Disconnect the image from the connected device"""
assert self.device is not None, "No device connected"
qemu_nbd('-d', self.device)
self.qemu_nbd('-d', self.device)
self.device = None
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
__version__ = "0.7rc1"
__version__ = "0.7rc2"
__version_vcs_info__ = {
'branch': 'release-0.7',
'revid': '96d50cb',
'revno': 555}
'revid': '9813162',
'revno': 564}
__version_user_email__ = "skalkoto@grnet.gr"
__version_user_name__ = "Nikos Skalkotos"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment