source: trunk/packages/sipb-xen-guest-installer/files/usr/sbin/sipb-xen-lvcopy @ 343

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

todo has moved to trac

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