copying installer works now (maybe?)
authorGreg Price <price@mit.edu>
Sun, 30 Mar 2008 06:49:43 +0000 (02:49 -0400)
committerGreg Price <price@mit.edu>
Sun, 30 Mar 2008 06:49:43 +0000 (02:49 -0400)
At least for the image 'ice3', which IIRC was created with
/usr/sbin/sipb-xen-make-iso.  It's an etch amd64 image.
It also had to have package nullmailer installed, replacing exim4.

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

files/usr/sbin/sipb-xen-duplicate

index a78d3a1..a01bf80 100755 (executable)
@@ -4,12 +4,13 @@ import sys
 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
@@ -30,6 +31,8 @@ def losetup(source, offset=0):
         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
@@ -37,9 +40,12 @@ def losetup(source, offset=0):
   # 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.
@@ -51,7 +57,7 @@ def duplicate_lv(source, dest):
   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")
@@ -71,30 +77,68 @@ def duplicate_lv(source, 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:])