@@ -3,9 +3,49 @@
Simple script to setup unattended installs on KVM guests.
"""
# -*- coding: utf-8 -*-
-import os, sys, shutil, tempfile, re
+import os, sys, shutil, tempfile, re, ConfigParser, glob
import common
+KNOWN_PACKAGE_MANAGERS = ['rpm', 'dpkg']
+
+
+def command(cmd):
+ """
+ Find a given command on the user's PATH.
+
+ @param cmd: Command you wish to find (ie, 'ls').
+ @return: Full path to the command.
+ @raise ValueError: In case the command are not found on PATH.
+ """
+ for dir in os.environ['PATH'].split(':'):
+ file = os.path.join(dir, cmd)
+ if os.path.exists(file):
+ return file
+ raise ValueError('Missing command: %s' % cmd)
+
+
+def package_that_owns(file):
+ """
+ Inquiry the main package manager which package owns file.
+
+ @param file: Path to a given file
+ """
+ support_info = {}
+ for package_manager in KNOWN_PACKAGE_MANAGERS:
+ try:
+ command(package_manager)
+ support_info[package_manager] = True
+ except:
+ support_info[package_manager] = False
+
+ if support_info['rpm']:
+ return str(os.popen('rpm -qf %s' % file).read())
+ elif support_info['dpkg']:
+ return str(os.popen('dpkg -S %s' % file).read())
+ else:
+ return ('Did not find a known package manager to inquire about '
+ 'file %s' % file)
+
class SetupError(Exception):
"""
@@ -40,10 +80,44 @@ class UnattendedInstall(object):
self.tftp_root = tftp_root
self.kernel_args = os.environ.get('KVM_TEST_kernel_args', '')
- self.finish_program= os.environ.get('KVM_TEST_finish_program', '')
+ self.finish_program = os.environ.get('KVM_TEST_finish_program', '')
+
cdrom_iso = os.environ.get('KVM_TEST_cdrom')
self.unattended_file = os.environ.get('KVM_TEST_unattended_file')
+ install_virtio = os.environ.get('KVM_TEST_install_virtio', 'no')
+ if install_virtio == 'yes':
+ self.install_virtio = True
+ else:
+ self.install_virtio = False
+
+ virtio_floppy = os.environ.get('KVM_TEST_virtio_floppy', '')
+ self.virtio_floppy = None
+ self.virtio_floppy_mount = tempfile.mkdtemp(prefix='floppy_',
+ dir='/tmp')
+ if self.install_virtio:
+ if virtio_floppy and os.path.isfile(virtio_floppy):
+ print package_that_owns(virtio_floppy)
+ self.virtio_floppy = virtio_floppy
+ elif virtio_floppy and not os.path.isfile(virtio_floppy):
+ print ('Virtio floppy path %s was not found. Please verify' %
+ virtio_floppy)
+
+ vni = os.environ.get('KVM_TEST_virtio_network_installer', '')
+ self.virtio_network_installer = None
+ if self.install_virtio and vni:
+ self.virtio_network_installer = vni
+
+ voi = os.environ.get('KVM_TEST_virtio_oemsetup_id', '')
+ self.virtio_oemsetup_identifier = None
+ if self.install_virtio and voi:
+ self.virtio_oemsetup_identifier = voi
+
+ vsp = os.environ.get('KVM_TEST_virtio_storage_path', '')
+ self.virtio_storage_path = None
+ if self.install_virtio and vsp:
+ self.virtio_storage_path = vsp
+
self.qemu_img_bin = os.environ.get('KVM_TEST_qemu_img_binary')
if not os.path.isabs(self.qemu_img_bin):
self.qemu_img_bin = os.path.join(kvm_test_dir, self.qemu_img_bin)
@@ -72,6 +146,84 @@ class UnattendedInstall(object):
self.initrd_path = os.path.join(self.image_path, self.initrd)
+ def copy_virtio_drivers_floppy(self):
+ """
+ Copy the virtio drivers on the virtio floppy to the install floppy.
+
+ 1) Mount the floppy containing the viostor drivers
+ 2) Copy its contents to the root of the install floppy
+ """
+ m_cmd = 'mount -o loop %s %s' % (self.virtio_floppy,
+ self.virtio_floppy_mount)
+ pwd = os.getcwd()
+ try:
+ if os.system(m_cmd):
+ raise SetupError('Could not mount virtio floppy driver')
+ os.chdir(self.virtio_floppy_mount)
+ path_list = glob.glob('*')
+ for path in path_list:
+ src = os.path.join(self.virtio_floppy_mount, path)
+ dst = os.path.join(self.floppy_mount, path)
+ if os.path.isdir(path):
+ shutil.copytree(src, dst)
+ elif os.path.isfile(path):
+ shutil.copyfile(src, dst)
+ finally:
+ os.chdir(pwd)
+ u_cmd = 'umount %s' % self.virtio_floppy_mount
+ if os.system(u_cmd):
+ raise SetupError('Could not unmount virtio floppy at %s' %
+ self.virtio_floppy_mount)
+ self.cleanup(self.virtio_floppy_mount)
+
+
+ def setup_virtio_win2008(self):
+ """
+ Setup the install floppy with the virtio storage drivers, win2008 style.
+
+ Win2008, Vista and 7 require people to point out the path to the drivers
+ on the unattended file, so we just need to copy the drivers to the
+ driver floppy disk.
+ Process:
+
+ 1) Copy the virtio drivers on the virtio floppy to the install floppy
+ """
+ self.copy_virtio_drivers_floppy()
+
+
+ def setup_virtio_win2003(self):
+ """
+ Setup the install floppy with the virtio storage drivers, win2003 style.
+
+ Win2003 and WinXP depend on the file txtsetup.oem file to install
+ the virtio drivers from the floppy, which is a .ini file.
+ Process:
+
+ 1) Copy the virtio drivers on the virtio floppy to the install floppy
+ 2) Parse the ini file with config parser
+ 3) Modify the identifier of the default session that is going to be
+ executed on the config parser object
+ 4) Re-write the config file to the disk
+ """
+ self.copy_virtio_drivers_floppy()
+ txtsetup_oem = os.path.join(self.floppy_mount, 'txtsetup.oem')
+ if not os.path.isfile(txtsetup_oem):
+ raise SetupError('File txtsetup.oem not found on the install '
+ 'floppy. Please verify if your floppy virtio '
+ 'driver image has this file')
+ parser = ConfigParser.ConfigParser()
+ parser.read(txtsetup_oem)
+ if not parser.has_section('Defaults'):
+ raise SetupError('File txtsetup.oem does not have the session '
+ '"Defaults". Please check txtsetup.oem')
+ default_driver = parser.get('Defaults', 'SCSI')
+ if default_driver != self.virtio_oemsetup_identifier:
+ parser.set('Defaults', 'SCSI', self.virtio_oemsetup_identifier)
+ fp = open(txtsetup_oem, 'w')
+ parser.write(fp)
+ fp.close()
+
+
def create_boot_floppy(self):
"""
Prepares a boot floppy by creating a floppy image file, mounting it and
@@ -93,7 +245,8 @@ class UnattendedInstall(object):
raise SetupError('Error formatting floppy image.')
try:
- m_cmd = 'mount -o loop %s %s' % (self.floppy_img, self.floppy_mount)
+ m_cmd = 'mount -o loop,rw %s %s' % (self.floppy_img,
+ self.floppy_mount)
if os.system(m_cmd):
raise SetupError('Could not mount floppy image.')
@@ -103,6 +256,9 @@ class UnattendedInstall(object):
setup_file_path = os.path.join(self.unattended_dir, setup_file)
setup_file_dest = os.path.join(self.floppy_mount, setup_file)
shutil.copyfile(setup_file_path, setup_file_dest)
+ if self.install_virtio:
+ self.setup_virtio_win2003()
+
elif self.unattended_file.endswith('.ks'):
# Red Hat kickstart install
dest_fname = 'ks.cfg'
@@ -110,6 +266,8 @@ class UnattendedInstall(object):
if self.tftp_root is '':
# Windows unattended install
dest_fname = "autounattend.xml"
+ if self.install_virtio:
+ self.setup_virtio_win2008()
else:
# SUSE autoyast install
dest_fname = "autoinst.xml"
@@ -130,7 +288,7 @@ class UnattendedInstall(object):
print ("WARNING: 'cdkey' required but not specified for "
"this unattended installation")
- dummy_re = r'\bKVM_TEST_MEDIUM\b'
+ dummy_medium_re = r'\bKVM_TEST_MEDIUM\b'
if self.medium == "cdrom":
content = "cdrom"
elif self.medium == "url":
@@ -140,7 +298,46 @@ class UnattendedInstall(object):
else:
raise SetupError("Unexpected installation medium %s" % self.url)
- unattended_contents = re.sub(dummy_re, content, unattended_contents)
+ unattended_contents = re.sub(dummy_medium_re, content, unattended_contents)
+
+ dummy_path = "C:"
+
+ dummy_storage_re = r'\bKVM_TEST_STORAGE_DRIVER_PATH\b'
+ storage_driver = os.environ.get('KVM_TEST_virtio_storage_path', '')
+ if re.search(dummy_storage_re, unattended_contents):
+ if self.install_virtio:
+ unattended_contents = re.sub(dummy_storage_re,
+ storage_driver,
+ unattended_contents)
+ else:
+ unattended_contents = re.sub(dummy_storage_re,
+ dummy_path,
+ unattended_contents)
+
+ dummy_network_re = r'\bKVM_TEST_NETWORK_DRIVER_PATH\b'
+ network_driver = os.environ.get('KVM_TEST_virtio_network_path', '')
+ if re.search(dummy_network_re, unattended_contents):
+ if self.install_virtio:
+ unattended_contents = re.sub(dummy_network_re,
+ network_driver,
+ unattended_contents)
+ else:
+ unattended_contents = re.sub(dummy_network_re,
+ dummy_path,
+ unattended_contents)
+
+ dummy_nw_install_re = r'\bKVM_TEST_VIRTIO_NETWORK_INSTALLER\b'
+ nw_install = os.environ.get('KVM_TEST_virtio_network_installer',
+ 'help')
+ if re.search(dummy_nw_install_re, unattended_contents):
+ if self.install_virtio:
+ unattended_contents = re.sub(dummy_nw_install_re,
+ nw_install,
+ unattended_contents)
+ else:
+ unattended_contents = re.sub(dummy_nw_install_re,
+ 'help',
+ unattended_contents)
print
print "Unattended install %s contents:" % dest_fname