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

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

some cleanups in copying autoinstaller

  • Property svn:executable set to *
File size: 6.0 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  '''UNUSED: maybe we'll use this someday; it does isolate the frobber.'''
82  # 1. prepare arguments volume
83  args_volume = prefix+target+'_args'
84  args_device = '/dev/xenvg/' + args_volume
85  check_call(['/sbin/lvcreate', 'xenvg', '--name', args_volume, '--size', '4K'])
86  file(args_device, 'w').write('\n'.join(args) + '\n')
87
88  # 2. invoke frobber vm
89  copier_device = '/dev/xenvg/d_wert_hda'
90  check_call(['/usr/sbin/xm', 'create', 'sipb-database',
91              'machine_name='+target,
92              'disks=' + ' '.join(['phy:'+copier_device+',hda,w',
93                                   'phy:'+target_device+',hdc,w',
94                                   'phy:'+args_device+',hdd,w'])])
95
96  # XXX should check_call(['/sbin/lvremove', '-f', 'xenvg/'+args_volume])
97
98def frob_copy_simple(target, hostname, rootpw):
99  """target should be an LV device filename
100
101  This is highly specific to the etch install produced by sipb-xen-make-iso.
102  Generalizing and customizing to other distros is left to the future...
103  """
104  # 1: mount filesystem
105  fs = losetup(target, 32256)
106  mntdir = tempfile.mkdtemp('', 'auto-install.frob.', '/tmp')
107  call(['mount', '-t', 'ext3', fs, mntdir])
108  # 2: do frobbing
109  # 2a:  (printf "%s\n" "$ROOTPW"; sleep .3; printf "%s\n" "$ROOTPW")
110  #      | /usr/sbin/chroot "$TARGET" /usr/bin/passwd root
111  p = Popen(['/usr/sbin/chroot', mntdir, '/usr/bin/passwd', 'root'], stdin=PIPE)
112  p.stdin.write(rootpw+'\n')
113  time.sleep(1)
114  p.stdin.write(rootpw+'\n')
115  p.stdin.close()
116  p.wait()
117  os.chdir(mntdir)
118  # 2b: clear generated file that has eth0's old MAC address
119  #      rm $TARGET/etc/udev/rules.d/z25_persistent-net.rules
120  os.unlink('etc/udev/rules.d/z25_persistent-net.rules')
121  # 2c: hostname.
122  # XX Use nullmailer in image, not exim4.  (Fewer copies of hostname.)
123  # 2c1: rm /var/lib/dhcp3/dhclient.eth0.leases
124  os.unlink('var/lib/dhcp3/dhclient.eth0.leases')
125  # 2c2: /etc/hosts, /etc/hostname; /etc/motd? /etc/mailname?
126  call(['perl', '-i', '-pe', 's/ice3.servers.csail.mit.edu/'+hostname+'/g',
127        'etc/hosts', 'etc/hostname', 'etc/motd', 'etc/mailname'])
128  # 3: clean up
129  os.chdir('/')
130  call(['umount', mntdir])
131  os.rmdir(mntdir)
132  call(['losetup', '-d', fs])
133
134def duplicate_by_vm(source, target, rootpw, nodd=False):
135  # source, target should be machine names
136  prefix = 'd_'
137  # 1. copy (by dd) source to target
138  source_device = '/dev/xenvg/' + prefix + source + '_hda'
139  target_device = '/dev/xenvg/' + prefix + target + '_hda'
140  if not nodd:
141    check_call(['/bin/dd', 'bs=1M', 'conv=nocreat',
142                'if='+source_device, 'of='+target_device])
143  # 2. frob target
144  frob_copy_simple(target_device, target, rootpw)
145
146def main(*argv):
147  subcommand = argv[1]
148  args = argv[2:]
149  os.environ['PATH'] = '/usr/sbin:/usr/bin:/sbin:/bin'
150  if subcommand == 'lvcopy':
151    kwargs = {}
152    if args[0] == '--nodd':
153      args = args[1:]
154      kwargs['nodd'] = True
155    duplicate_by_vm(*args, **kwargs)
156  else:
157    print >>sys.stderr, argv[0]+": unknown subcommand: "+subcommand
158    return 2
159  return 0
160
161if __name__ == '__main__':
162  sys.exit(main(*sys.argv))
Note: See TracBrowser for help on using the repository browser.