blob: 6ceeef1cc7673da5c2385d314f6d72eae1e4e6da [file] [log] [blame]
lmr5d73e2f2009-10-09 20:46:36 +00001#!/usr/bin/python
2"""
3Simple script to setup unattended installs on KVM guests.
4"""
5# -*- coding: utf-8 -*-
6import os, sys, shutil, tempfile, re
7import common
8
9
10class SetupError(Exception):
11 """
12 Simple wrapper for the builtin Exception class.
13 """
14 pass
15
16
17class UnattendedInstall(object):
18 """
19 Creates a floppy disk image that will contain a config file for unattended
20 OS install. Optionally, sets up a PXE install server using qemu built in
21 TFTP and DHCP servers to install a particular operating system. The
22 parameters to the script are retrieved from environment variables.
23 """
24 def __init__(self):
25 """
26 Gets params from environment variables and sets class attributes.
27 """
28 script_dir = os.path.dirname(sys.modules[__name__].__file__)
29 kvm_test_dir = os.path.abspath(os.path.join(script_dir, ".."))
30 images_dir = os.path.join(kvm_test_dir, 'images')
31 self.deps_dir = os.path.join(kvm_test_dir, 'deps')
32 self.unattended_dir = os.path.join(kvm_test_dir, 'unattended')
33
34 try:
35 tftp_root = os.environ['KVM_TEST_tftp']
36 self.tftp_root = os.path.join(images_dir, tftp_root)
37 if not os.path.isdir(self.tftp_root):
38 os.makedirs(self.tftp_root)
39 except KeyError:
40 self.tftp_root = ''
41
42 try:
43 self.kernel_args = os.environ['KVM_TEST_kernel_args']
44 except KeyError:
45 self.kernel_args = ''
46
47 try:
48 self.finish_program= os.environ['KVM_TEST_finish_program']
49 except:
50 self.finish_program = None
51
52
53 cdrom_iso = os.environ['KVM_TEST_cdrom']
54 self.unattended_file = os.environ['KVM_TEST_unattended_file']
55
56 self.qemu_img_bin = os.path.join(kvm_test_dir, 'qemu-img')
57 self.cdrom_iso = os.path.join(kvm_test_dir, cdrom_iso)
58 self.floppy_mount = tempfile.mkdtemp(prefix='floppy_', dir='/tmp')
59 self.cdrom_mount = tempfile.mkdtemp(prefix='cdrom_', dir='/tmp')
60 self.floppy_img = os.path.join(images_dir, 'floppy.img')
61
62
63 def create_boot_floppy(self):
64 """
65 Prepares a boot floppy by creating a floppy image file, mounting it and
66 copying an answer file (kickstarts for RH based distros, answer files
67 for windows) to it. After that the image is umounted.
68 """
69 print "Creating boot floppy"
70
71 if os.path.exists(self.floppy_img):
72 os.remove(self.floppy_img)
73
74 c_cmd = '%s create -f raw %s 1440k' % (self.qemu_img_bin, self.floppy_img)
75 if os.system(c_cmd):
76 raise SetupError('Could not create floppy image.')
77
78 f_cmd = 'mkfs.msdos -s 1 %s' % self.floppy_img
79 if os.system(f_cmd):
80 raise SetupError('Error formatting floppy image.')
81
82 m_cmd = 'mount -o loop %s %s' % (self.floppy_img, self.floppy_mount)
83 if os.system(m_cmd):
84 raise SetupError('Could not mount floppy image.')
85
86 if self.unattended_file.endswith('.sif'):
87 dest_fname = 'winnt.sif'
88 setup_file = 'winnt.bat'
89 setup_file_path = os.path.join(self.unattended_dir, setup_file)
90 setup_file_dest = os.path.join(self.floppy_mount, setup_file)
91 shutil.copyfile(setup_file_path, setup_file_dest)
92 elif self.unattended_file.endswith('.ks'):
93 dest_fname = 'ks.cfg'
94
95 dest = os.path.join(self.floppy_mount, dest_fname)
96 shutil.copyfile(self.unattended_file, dest)
97
98 if self.finish_program:
99 dest_fname = os.path.basename(self.finish_program)
100 dest = os.path.join(self.floppy_mount, dest_fname)
101 shutil.copyfile(self.finish_program, dest)
102
103 u_cmd = 'umount %s' % self.floppy_mount
104 if os.system(u_cmd):
105 raise SetupError('Could not unmount floppy at %s.' %
106 self.floppy_mount)
107
108 os.chmod(self.floppy_img, 0755)
109
110 print "Boot floppy created successfuly"
111
112
113 def setup_pxe_boot(self):
114 """
115 Sets up a PXE boot environment using the built in qemu TFTP server.
116 Copies the PXE Linux bootloader pxelinux.0 from the host (needs the
117 pxelinux package or equivalent for your distro), and vmlinuz and
118 initrd.img files from the CD to a directory that qemu will serve trough
119 TFTP to the VM.
120 """
121 print "Setting up PXE boot using TFTP root %s" % self.tftp_root
122
123 pxe_file = None
124 pxe_paths = ['/usr/lib/syslinux/pxelinux.0',
125 '/usr/share/syslinux/pxelinux.0']
126 for path in pxe_paths:
127 if os.path.isfile(path):
128 pxe_file = path
129 break
130
131 if not pxe_file:
132 raise SetupError('Cannot find PXE boot loader pxelinux.0. Make '
133 'sure pxelinux or equivalent package for your '
134 'distro is installed.')
135
136 pxe_dest = os.path.join(self.tftp_root, 'pxelinux.0')
137 shutil.copyfile(pxe_file, pxe_dest)
138
139 m_cmd = 'mount -t iso9660 -v -o loop %s %s' % (self.cdrom_iso,
140 self.cdrom_mount)
141 if os.system(m_cmd):
142 raise SetupError('Could not mount CD image %s.' % self.cdrom_iso)
143
144 p = os.path.join('images', 'pxeboot')
145 pxe_dir = os.path.join(self.cdrom_mount, p)
146 pxe_image = os.path.join(pxe_dir, 'vmlinuz')
147 pxe_initrd = os.path.join(pxe_dir, 'initrd.img')
148
149 if not os.path.isdir(pxe_dir):
150 raise SetupError('The ISO image does not have a %s dir. The script '
151 'assumes that the cd has a %s dir where to search '
152 'for the vmlinuz image.' % (p, p))
153
154 if not os.path.isfile(pxe_image) or not os.path.isfile(pxe_initrd):
155 raise SetupError('The location %s is lacking either a vmlinuz or a '
156 'initrd.img file. Cannot find a PXE image to '
157 'proceed.' % pxe_dir)
158
159 tftp_image = os.path.join(self.tftp_root, 'vmlinuz')
160 tftp_initrd = os.path.join(self.tftp_root, 'initrd.img')
161 shutil.copyfile(pxe_image, tftp_image)
162 shutil.copyfile(pxe_initrd, tftp_initrd)
163
164 u_cmd = 'umount %s' % self.cdrom_mount
165 if os.system(u_cmd):
166 raise SetupError('Could not unmount CD at %s.' % self.cdrom_mount)
167
168 pxe_config_dir = os.path.join(self.tftp_root, 'pxelinux.cfg')
169 if not os.path.isdir(pxe_config_dir):
170 os.makedirs(pxe_config_dir)
171 pxe_config_path = os.path.join(pxe_config_dir, 'default')
172
173 pxe_config = open(pxe_config_path, 'w')
174 pxe_config.write('DEFAULT pxeboot\n')
175 pxe_config.write('TIMEOUT 20\n')
176 pxe_config.write('PROMPT 0\n')
177 pxe_config.write('LABEL pxeboot\n')
178 pxe_config.write(' KERNEL vmlinuz\n')
179 pxe_config.write(' KERNEL vmlinuz\n')
180 pxe_config.write(' APPEND initrd=initrd.img %s\n' %
181 self.kernel_args)
182 pxe_config.close()
183
184 print "PXE boot successfuly set"
185
186 def cleanup(self):
187 """
188 Clean up previously used mount points.
189 """
190 print "Cleaning up unused mount points"
191 for mount in [self.floppy_mount, self.cdrom_mount]:
192 if os.path.isdir(mount):
193 if os.path.ismount(mount):
194 print "Path %s is still mounted, please verify" % mount
195 else:
196 print "Removing mount point %s" % mount
197 os.rmdir(mount)
198
199
200 def setup(self):
201 print "Starting unattended install setup"
202
203 print "Variables set:"
204 print " qemu_img_bin: " + str(self.qemu_img_bin)
205 print " cdrom iso: " + str(self.cdrom_iso)
206 print " unattended_file: " + str(self.unattended_file)
207 print " kernel_args: " + str(self.kernel_args)
208 print " tftp_root: " + str(self.tftp_root)
209 print " floppy_mount: " + str(self.floppy_mount)
210 print " floppy_img: " + str(self.floppy_img)
211 print " finish_program: " + str(self.finish_program)
212
213 self.create_boot_floppy()
214 if self.tftp_root:
215 self.setup_pxe_boot()
216 self.cleanup()
217 print "Unattended install setup finished successfuly"
218
219
220if __name__ == "__main__":
221 os_install = UnattendedInstall()
222 os_install.setup()