a78d3a1a08917861c79f24b928b05708fb3a80cf
[invirt/packages/invirt-autoinstaller.git] / files / usr / sbin / sipb-xen-duplicate
1 #!/usr/bin/env python2.5
2
3 import sys
4 import os
5 import shutil
6 import tempfile
7 from subprocess import call, check_call, Popen
8
9 # TODO:
10 # . pick a loop device sanely
11 # - adapt size of partition to fit volume
12 # - fix hostname, root password
13 # - (once debugging diminishes) umount, losetup -d, maybe rm -r
14 # - avoid race conditions with other loop-device users, too (somehow)
15 # - get numbers from actual source partition table rather than
16 #   as magic numbers based on what sipb-xen-make-iso does with etch.
17
18 def losetup(source, offset=0):
19   # XXX we avoid colliding with other instances of ourself,
20   #     but when it comes to other loop-device users we just
21   #     pick a range things don't seem to use and hope...
22   lockfilename = '/tmp/losetup.lock'
23   os.close(os.open(lockfilename, os.O_CREAT+os.O_EXCL)) #lock
24   try:
25     loopdevice = None
26     for i in xrange(32,60): # totally arbitrary, just looks to be unused on black-mesa
27       filename = '/dev/loop%d'%i
28       if 0 == len(file(filename).read(1)):
29         loopdevice = filename # it's empty
30         break
31     if loopdevice is not None:
32       call(['losetup', '-o', str(offset), loopdevice, source])
33   finally:
34     os.unlink(lockfilename) #unlock
35   return loopdevice
36   # XX this means we can duplicate 9 at once.  since it takes around 30 seconds,
37   # this seems like an adequate capacity.
38
39 def duplicate_lv(source, dest):
40   '''duplicate boot record, filesystem from LV source to LV dest
41   
42   source, dest should be device filenames.
43   '''
44   # XXX this is very specific to what the etch sipb-xen-make-iso installer does.
45   # XXXX also, it's specific to four gigs.
46   # step 1: copy the MBR
47   call(['dd', 'if='+source, 'bs=512', 'count=63', 'of='+dest])
48   # step 2: fix up partition table
49   # XX actually do this; this is our opportunity to resize the filesystem
50   # step 3: make the filesystem, and copy its contents in
51   sourcefs = losetup(source, 32256)
52   destfs = losetup(dest, 32256)
53   call(['mkfs.ext3', '-b', '4096', destfs, '987989'])
54   tmptree = tempfile.mkdtemp('', 'auto-install.dup.', '/tmp')
55   os.mkdir(tmptree+"/source")
56   call(['mount', '-t', 'ext3', '-o', 'ro', sourcefs, tmptree+"/source"])
57   os.mkdir(tmptree+"/dest")
58   call(['mount', '-t', 'ext3', destfs, tmptree+"/dest"])
59   call(['cp', '-aT', tmptree+"/source", tmptree+"/dest"])
60   # step 4: twiddle what we want to twiddle
61   # XX do this
62   # step 5: make the swap area
63   swapfs = losetup(dest, 4046870016)
64   call(['mkswap', swapfs, str(240943)])
65   # call(['losetup', '-d', swapfs])
66   print 'losetup -d '+swapfs
67   # step 6: clean up.
68   # XX actually unmount etc (leaving it is for debugging)
69   print 'umount '+tmptree+'/source'
70   call(['umount', tmptree+"/dest"]) # needed to flush writes
71   print 'losetup -d '+sourcefs
72   print 'losetup -d '+destfs
73
74 def duplicate_by_vm(source, target, *args):
75   # source, target should be machine names
76   prefix = 'd_'
77   # 1. copy (by dd) source to target
78   source_device = '/dev/xenvg/' + prefix + source + '_hda'
79   target_device = '/dev/xenvg/' + prefix + target + '_hda'
80   #check_call(['/bin/dd', 'bs=1M', 'conv=nocreat',
81   #            'if='+source_device, 'of='+target_device])
82   # 2. 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   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   boot = 'c'
95
96   # XXX make this happen! check_call(['/sbin/lvremove', '-f', 'xenvg/'+args_volume])
97   
98
99 if __name__ == '__main__':
100   duplicate_by_vm(*sys.argv[1:])