source: trunk/packages/sipb-xen-guest-installer/files/usr/sbin/sipb-xen-duplicate @ 336

Last change on this file since 336 was 336, checked in by price, 16 years ago

copying installer works now (maybe?)

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.

  • Property svn:executable set to *
File size: 5.6 KB
Line 
1#!/usr/bin/env python2.5
2
3import sys
4import os
5import shutil
6import tempfile
7import time
8from subprocess import call, check_call, Popen, PIPE
9
10# TODO:
11# . pick a loop device sanely
12# x adapt size of partition to fit volume
13# . fix hostname, root password
14# - (once debugging diminishes) umount, losetup -d, maybe rm -r
15# - avoid race conditions with other loop-device users, too (somehow)
16# - get numbers from actual source partition table rather than
17#   as magic numbers based on what sipb-xen-make-iso does with etch.
18
19def losetup(source, offset=0):
20  # XXX we avoid colliding with other instances of ourself,
21  #     but when it comes to other loop-device users we just
22  #     pick a range things don't seem to use and hope...
23  lockfilename = '/tmp/losetup.lock'
24  os.close(os.open(lockfilename, os.O_CREAT+os.O_EXCL)) #lock
25  try:
26    loopdevice = None
27    for i in xrange(32,60): # totally arbitrary, just looks to be unused on black-mesa
28      filename = '/dev/loop%d'%i
29      if 0 == len(file(filename).read(1)):
30        loopdevice = filename # it's empty
31        break
32    if loopdevice is not None:
33      call(['losetup', '-o', str(offset), loopdevice, source])
34    else:
35      raise RuntimeError('out of loop devices for copying VM image: too many at once?')
36  finally:
37    os.unlink(lockfilename) #unlock
38  return loopdevice
39  # XX this means we can duplicate 9 at once.  since it takes around 30 seconds,
40  # this seems like an adequate capacity.
41
42def duplicate_lv(source, dest):
43  '''OBSOLETE: duplicate boot record, filesystem from LV source to LV dest
44 
45  source, dest should be device filenames.
46
47  Now we just dd.  Doesn't support resizing, but it's easier,
48  especially if we allow the partition table to vary between images.
49  '''
50  # XXX this is very specific to what the etch sipb-xen-make-iso installer does.
51  # XXXX also, it's specific to four gigs.
52  # step 1: copy the MBR
53  call(['dd', 'if='+source, 'bs=512', 'count=63', 'of='+dest])
54  # step 2: fix up partition table
55  # XX actually do this; this is our opportunity to resize the filesystem
56  # step 3: make the filesystem, and copy its contents in
57  sourcefs = losetup(source, 32256)
58  destfs = losetup(dest, 32256)
59  call(['mkfs.ext3', '-b', '4096', destfs, '987989'])
60  tmptree = tempfile.mkdtemp('', 'auto-install.dup.', '/tmp')#yes, args backward
61  os.mkdir(tmptree+"/source")
62  call(['mount', '-t', 'ext3', '-o', 'ro', sourcefs, tmptree+"/source"])
63  os.mkdir(tmptree+"/dest")
64  call(['mount', '-t', 'ext3', destfs, tmptree+"/dest"])
65  call(['cp', '-aT', tmptree+"/source", tmptree+"/dest"])
66  # step 4: twiddle what we want to twiddle
67  # XX do this
68  # step 5: make the swap area
69  swapfs = losetup(dest, 4046870016)
70  call(['mkswap', swapfs, str(240943)])
71  # call(['losetup', '-d', swapfs])
72  print 'losetup -d '+swapfs
73  # step 6: clean up.
74  # XX actually unmount etc (leaving it is for debugging)
75  print 'umount '+tmptree+'/source'
76  call(['umount', tmptree+"/dest"]) # needed to flush writes
77  print 'losetup -d '+sourcefs
78  print 'losetup -d '+destfs
79
80def frob_copy(target, *args):
81  # 1. prepare arguments volume
82  args_volume = prefix+target+'_args'
83  args_device = '/dev/xenvg/' + args_volume
84  check_call(['/sbin/lvcreate', 'xenvg', '--name', args_volume, '--size', '4K'])
85  file(args_device, 'w').write('\n'.join(args) + '\n')
86
87  # 2. invoke frobber vm
88  copier_device = '/dev/xenvg/d_wert_hda'
89  check_call(['/usr/sbin/xm', 'create', 'sipb-database',
90              'machine_name='+target,
91              'disks=' + ' '.join(['phy:'+copier_device+',hda,w',
92                                   'phy:'+target_device+',hdc,w',
93                                   'phy:'+args_device+',hdd,w'])])
94
95  # XXX should check_call(['/sbin/lvremove', '-f', 'xenvg/'+args_volume])
96
97def frob_copy_simple(target, hostname, rootpw, *args):
98  """target should be an LV device filename
99
100  This is highly specific to the etch install produced by sipb-xen-make-iso.
101  Generalizing and customizing to other distros is left to the future...
102  """
103  # 1: mount filesystem
104  fs = losetup(target, 32256)
105  mntdir = tempfile.mkdtemp('', 'auto-install.frob.', '/tmp')
106  call(['mount', '-t', 'ext3', fs, mntdir])
107  # 2: do frobbing
108  # 2a:  (printf "%s\n" "$ROOTPW"; sleep .3; printf "%s\n" "$ROOTPW")
109  #      | /usr/sbin/chroot "$TARGET" /usr/bin/passwd root
110  p = Popen(['/usr/sbin/chroot', mntdir, '/usr/bin/passwd', 'root'], stdin=PIPE)
111  p.stdin.write(rootpw+'\n')
112  time.sleep(1)
113  p.stdin.write(rootpw+'\n')
114  p.stdin.close()
115  p.wait()
116  os.chdir(mntdir)
117  # 2b: clear generated file that has eth0's old MAC address
118  #      rm $TARGET/etc/udev/rules.d/z25_persistent-net.rules
119  os.unlink('etc/udev/rules.d/z25_persistent-net.rules')
120  # 2c: hostname.
121  # XX Use nullmailer in image, not exim4.  (Fewer copies of hostname.)
122  # 2c1: rm /var/lib/dhcp3/dhclient.eth0.leases
123  os.unlink('var/lib/dhcp3/dhclient.eth0.leases')
124  # 2c2: /etc/hosts, /etc/hostname; /etc/motd? /etc/mailname?
125  call(['perl', '-i', '-pe', 's/ice3.servers.csail.mit.edu/'+hostname+'/g',
126        'etc/hosts', 'etc/hostname', 'etc/motd', 'etc/mailname'])
127  # 3: clean up
128  os.chdir('/')
129  call(['umount', mntdir])
130  call(['losetup', '-d', fs])
131
132def duplicate_by_vm(source, target, *args):
133  # source, target should be machine names
134  prefix = 'd_'
135  # 1. copy (by dd) source to target
136  source_device = '/dev/xenvg/' + prefix + source + '_hda'
137  target_device = '/dev/xenvg/' + prefix + target + '_hda'
138  check_call(['/bin/dd', 'bs=1M', 'conv=nocreat',
139              'if='+source_device, 'of='+target_device])
140  # 2. frob target
141  frob_copy_simple(target_device, *args)
142
143if __name__ == '__main__':
144  duplicate_by_vm(*sys.argv[1:])
Note: See TracBrowser for help on using the repository browser.