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
RevLine 
[245]1#!/usr/bin/env python2.5
[231]2
3import sys
4import os
5import shutil
6import tempfile
[336]7import time
8from subprocess import call, check_call, Popen, PIPE
[231]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])
[336]25    else:
26      raise RuntimeError('out of loop devices for copying VM image: too many at once?')
[231]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):
[336]34  '''OBSOLETE: duplicate boot record, filesystem from LV source to LV dest
[231]35 
36  source, dest should be device filenames.
[336]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.
[231]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'])
[336]51  tmptree = tempfile.mkdtemp('', 'auto-install.dup.', '/tmp')#yes, args backward
[231]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
[336]71def frob_copy(target, *args):
[338]72  '''UNUSED: maybe we'll use this someday; it does isolate the frobber.'''
[336]73  # 1. prepare arguments volume
[245]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
[336]79  # 2. invoke frobber vm
[245]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
[336]87  # XXX should check_call(['/sbin/lvremove', '-f', 'xenvg/'+args_volume])
[245]88
[338]89def frob_copy_simple(target, hostname, rootpw):
[336]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])
[338]122  os.rmdir(mntdir)
[336]123  call(['losetup', '-d', fs])
124
[338]125def duplicate_by_vm(source, target, rootpw, nodd=False):
[336]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'
[338]131  if not nodd:
132    check_call(['/bin/dd', 'bs=1M', 'conv=nocreat',
133                'if='+source_device, 'of='+target_device])
[336]134  # 2. frob target
[338]135  frob_copy_simple(target_device, target, rootpw)
[336]136
[338]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
[231]152if __name__ == '__main__':
[338]153  sys.exit(main(*sys.argv))
Note: See TracBrowser for help on using the repository browser.