import os
import shutil
import tempfile
-from subprocess import call, check_call, Popen
+import time
+from subprocess import call, check_call, Popen, PIPE
# TODO:
# . pick a loop device sanely
-# - adapt size of partition to fit volume
-# - fix hostname, root password
+# x adapt size of partition to fit volume
+# . fix hostname, root password
# - (once debugging diminishes) umount, losetup -d, maybe rm -r
# - avoid race conditions with other loop-device users, too (somehow)
# - get numbers from actual source partition table rather than
break
if loopdevice is not None:
call(['losetup', '-o', str(offset), loopdevice, source])
+ else:
+ raise RuntimeError('out of loop devices for copying VM image: too many at once?')
finally:
os.unlink(lockfilename) #unlock
return loopdevice
# this seems like an adequate capacity.
def duplicate_lv(source, dest):
- '''duplicate boot record, filesystem from LV source to LV dest
+ '''OBSOLETE: duplicate boot record, filesystem from LV source to LV dest
source, dest should be device filenames.
+
+ Now we just dd. Doesn't support resizing, but it's easier,
+ especially if we allow the partition table to vary between images.
'''
# XXX this is very specific to what the etch sipb-xen-make-iso installer does.
# XXXX also, it's specific to four gigs.
sourcefs = losetup(source, 32256)
destfs = losetup(dest, 32256)
call(['mkfs.ext3', '-b', '4096', destfs, '987989'])
- tmptree = tempfile.mkdtemp('', 'auto-install.dup.', '/tmp')
+ tmptree = tempfile.mkdtemp('', 'auto-install.dup.', '/tmp')#yes, args backward
os.mkdir(tmptree+"/source")
call(['mount', '-t', 'ext3', '-o', 'ro', sourcefs, tmptree+"/source"])
os.mkdir(tmptree+"/dest")
print 'losetup -d '+sourcefs
print 'losetup -d '+destfs
-def duplicate_by_vm(source, target, *args):
- # source, target should be machine names
- prefix = 'd_'
- # 1. copy (by dd) source to target
- source_device = '/dev/xenvg/' + prefix + source + '_hda'
- target_device = '/dev/xenvg/' + prefix + target + '_hda'
- #check_call(['/bin/dd', 'bs=1M', 'conv=nocreat',
- # 'if='+source_device, 'of='+target_device])
- # 2. prepare arguments volume
+def frob_copy(target, *args):
+ # 1. prepare arguments volume
args_volume = prefix+target+'_args'
args_device = '/dev/xenvg/' + args_volume
check_call(['/sbin/lvcreate', 'xenvg', '--name', args_volume, '--size', '4K'])
file(args_device, 'w').write('\n'.join(args) + '\n')
+ # 2. invoke frobber vm
copier_device = '/dev/xenvg/d_wert_hda'
check_call(['/usr/sbin/xm', 'create', 'sipb-database',
'machine_name='+target,
'disks=' + ' '.join(['phy:'+copier_device+',hda,w',
'phy:'+target_device+',hdc,w',
'phy:'+args_device+',hdd,w'])])
- boot = 'c'
- # XXX make this happen! check_call(['/sbin/lvremove', '-f', 'xenvg/'+args_volume])
-
+ # XXX should check_call(['/sbin/lvremove', '-f', 'xenvg/'+args_volume])
+
+def frob_copy_simple(target, hostname, rootpw, *args):
+ """target should be an LV device filename
+
+ This is highly specific to the etch install produced by sipb-xen-make-iso.
+ Generalizing and customizing to other distros is left to the future...
+ """
+ # 1: mount filesystem
+ fs = losetup(target, 32256)
+ mntdir = tempfile.mkdtemp('', 'auto-install.frob.', '/tmp')
+ call(['mount', '-t', 'ext3', fs, mntdir])
+ # 2: do frobbing
+ # 2a: (printf "%s\n" "$ROOTPW"; sleep .3; printf "%s\n" "$ROOTPW")
+ # | /usr/sbin/chroot "$TARGET" /usr/bin/passwd root
+ p = Popen(['/usr/sbin/chroot', mntdir, '/usr/bin/passwd', 'root'], stdin=PIPE)
+ p.stdin.write(rootpw+'\n')
+ time.sleep(1)
+ p.stdin.write(rootpw+'\n')
+ p.stdin.close()
+ p.wait()
+ os.chdir(mntdir)
+ # 2b: clear generated file that has eth0's old MAC address
+ # rm $TARGET/etc/udev/rules.d/z25_persistent-net.rules
+ os.unlink('etc/udev/rules.d/z25_persistent-net.rules')
+ # 2c: hostname.
+ # XX Use nullmailer in image, not exim4. (Fewer copies of hostname.)
+ # 2c1: rm /var/lib/dhcp3/dhclient.eth0.leases
+ os.unlink('var/lib/dhcp3/dhclient.eth0.leases')
+ # 2c2: /etc/hosts, /etc/hostname; /etc/motd? /etc/mailname?
+ call(['perl', '-i', '-pe', 's/ice3.servers.csail.mit.edu/'+hostname+'/g',
+ 'etc/hosts', 'etc/hostname', 'etc/motd', 'etc/mailname'])
+ # 3: clean up
+ os.chdir('/')
+ call(['umount', mntdir])
+ call(['losetup', '-d', fs])
+
+def duplicate_by_vm(source, target, *args):
+ # source, target should be machine names
+ prefix = 'd_'
+ # 1. copy (by dd) source to target
+ source_device = '/dev/xenvg/' + prefix + source + '_hda'
+ target_device = '/dev/xenvg/' + prefix + target + '_hda'
+ check_call(['/bin/dd', 'bs=1M', 'conv=nocreat',
+ 'if='+source_device, 'of='+target_device])
+ # 2. frob target
+ frob_copy_simple(target_device, *args)
if __name__ == '__main__':
duplicate_by_vm(*sys.argv[1:])