prototype fast installer.
authorGreg Price <price@mit.edu>
Sun, 4 Nov 2007 05:41:11 +0000 (01:41 -0400)
committerGreg Price <price@mit.edu>
Sun, 4 Nov 2007 05:41:11 +0000 (01:41 -0400)
To install a distribution on a new volume, we take an existing
installed volume produced with sipb-xen-make-iso, and
 1. copy GRUB's data with dd
 2. frob the partition table with sfdisk, if the disk size is different
 3. make the filesystem
 4. twiddle the hostname and root password and whatever else
 5. make the swap area
 6. boot!

In this prototype, steps 2 and 4 aren't implemented yet;
steps 1, 3, and 5 all use numbers that come from what the
sipb-xen-make-iso etch installer does rather than from
actually reading the partition table; and the whole thing
is just a program in /usr/sbin, not integrated into what
remctl / the web app invoke.

It all takes about thirty seconds (28.0s most recently),
excluding the boot.

svn path=/trunk/packages/sipb-xen-guest-installer/sipb-xen-guest-installer/; revision=231

files/srv/guest-installer/etch/preseed.cfg
files/usr/sbin/sipb-xen-duplicate [new file with mode: 0755]

index 2e309de..72d59ab 100644 (file)
@@ -44,14 +44,14 @@ d-i mirror/http/proxy string
 d-i partman-auto/disk string /dev/discs/disc0/disc
 # In addition, you'll need to specify the method to use.
 # The presently available methods are: "regular", "lvm" and "crypto"
-d-i partman-auto/method string lvm
+d-i partman-auto/method string regular
 
 # If one of the disks that are going to be automatically partitioned
 # contains an old LVM configuration, the user will normally receive a
 # warning. This can be preseeded away...
 d-i partman-auto/purge_lvm_from_device boolean true
 # And the same goes for the confirmation to write the lvm partitions.
-d-i partman-lvm/confirm boolean true
+#d-i partman-lvm/confirm boolean true
 
 # You can choose from any of the predefined partitioning recipes.
 # Note: this must be preseeded with a localized (translated) value.
diff --git a/files/usr/sbin/sipb-xen-duplicate b/files/usr/sbin/sipb-xen-duplicate
new file mode 100755 (executable)
index 0000000..fa24e23
--- /dev/null
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+import sys
+import os
+import shutil
+import tempfile
+from subprocess import call, Popen
+
+# TODO:
+# . pick a loop device sanely
+# - 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
+#   as magic numbers based on what sipb-xen-make-iso does with etch.
+
+def losetup(source, offset=0):
+  # XXX we avoid colliding with other instances of ourself,
+  #     but when it comes to other loop-device users we just
+  #     pick a range things don't seem to use and hope...
+  lockfilename = '/tmp/losetup.lock'
+  os.close(os.open(lockfilename, os.O_CREAT+os.O_EXCL)) #lock
+  try:
+    loopdevice = None
+    for i in xrange(32,60): # totally arbitrary, just looks to be unused on black-mesa
+      filename = '/dev/loop%d'%i
+      if 0 == len(file(filename).read(1)):
+        loopdevice = filename # it's empty
+        break
+    if loopdevice is not None:
+      call(['losetup', '-o', str(offset), loopdevice, source])
+  finally:
+    os.unlink(lockfilename) #unlock
+  return loopdevice
+  # XX this means we can duplicate 9 at once.  since it takes around 30 seconds,
+  # this seems like an adequate capacity.
+
+def duplicate_lv(source, dest):
+  '''duplicate boot record, filesystem from LV source to LV dest
+  
+  source, dest should be device filenames.
+  '''
+  # XXX this is very specific to what the etch sipb-xen-make-iso installer does.
+  # XXXX also, it's specific to four gigs.
+  # step 1: copy the MBR
+  call(['dd', 'if='+source, 'bs=512', 'count=63', 'of='+dest])
+  # step 2: fix up partition table
+  # XX actually do this; this is our opportunity to resize the filesystem
+  # step 3: make the filesystem, and copy its contents in
+  sourcefs = losetup(source, 32256)
+  destfs = losetup(dest, 32256)
+  call(['mkfs.ext3', '-b', '4096', destfs, '987989'])
+  tmptree = tempfile.mkdtemp('', 'auto-install.dup.', '/tmp')
+  os.mkdir(tmptree+"/source")
+  call(['mount', '-t', 'ext3', '-o', 'ro', sourcefs, tmptree+"/source"])
+  os.mkdir(tmptree+"/dest")
+  call(['mount', '-t', 'ext3', destfs, tmptree+"/dest"])
+  call(['cp', '-aT', tmptree+"/source", tmptree+"/dest"])
+  # step 4: twiddle what we want to twiddle
+  # XX do this
+  # step 5: make the swap area
+  swapfs = losetup(dest, 4046870016)
+  call(['mkswap', swapfs, str(240943)])
+  # call(['losetup', '-d', swapfs])
+  print 'losetup -d '+swapfs
+  # step 6: clean up.
+  # XX actually unmount etc (leaving it is for debugging)
+  print 'umount '+tmptree+'/source'
+  call(['umount', tmptree+"/dest"]) # needed to flush writes
+  print 'losetup -d '+sourcefs
+  print 'losetup -d '+destfs
+
+if __name__ == '__main__':
+  duplicate_lv(*sys.argv[1:])