12 from pbs import dmsetup
13 from pbs import blockdev
16 class DiskError(Exception): pass
20 def __init__(self, source):
21 self._cleanup_jobs = []
25 def _add_cleanup(self, job, *args):
26 self._cleanup_jobs.append((job, args))
28 def _losetup(self, fname):
29 loop = losetup.find_unused_loop_device()
31 self._add_cleanup(loop.unmount)
34 def _dir_to_disk(self):
35 raise NotImplementedError
38 while len(self._devices):
39 device = self._devices.pop()
42 while len(self._cleanup_jobs):
43 job, args = self._cleanup_jobs.pop()
47 sourcedev = self.source
48 mode = os.stat(self.source).st_mode
49 if stat.S_ISDIR(mode):
50 return self._losetup(self._dir_to_disk())
51 elif stat.S_ISREG(mode):
52 sourcedev = self._losetup(self.source)
53 elif not stat.S_ISBLK(mode):
54 raise ValueError("Value for self.source is invalid")
56 # Take a snapshot and return it to the user
57 size = blockdev('--getsize', sourcedev)
58 cowfd, cow = tempfile.mkstemp()
59 self._add_cleanup(os.unlink, cow)
61 dd('if=/dev/null', 'of=%s' % cow, 'bs=1k' ,'seek=%d' % (1024*1024))
62 cowdev = self._losetup(cow)
64 snapshot = uuid.uuid4().hex
65 tablefd, table = tempfile.mkstemp()
67 os.write(tablefd, "0 %d snapshot %s %s n 8" % \
68 (int(size), sourcedev, cowdev))
69 dmsetup('create', snapshot, table)
70 self._add_cleanup(dmsetup, 'remove', snapshot)
74 new_device = DiskDevice("/dev/mapper/%s" % snapshot)
75 self._devices.append(new_device)
78 def destroy_device(self, device):
79 self._devices.remove(device)
82 class DiskDevice(object):
84 def __init__(self, device, bootable = True):
86 self.bootable = bootable
88 self.g = guestfs.GuestFS()
92 self.g.add_drive_opts(device, readonly = 0)
94 roots = self.g.inspect_os()
96 raise DiskError("No operating system found")
98 raise DiskError("Multiple operating systems found")
101 self.ostype = self.g.inspect_get_type(self.root)
102 self.distro = self.g.inspect_get_distro(self.root)
107 # Close the guestfs handler
112 mps = self.g.inspect_get_mountpoints(self.root)
113 # Sort the keys to mount the fs in a correct order.
114 # / should be mounted befor /boot, etc
116 if len(a[0]) > len(b[0]): return 1
117 elif len(a[0]) == len(b[0]): return 0
122 self.g.mount(dev, mp)
123 except RuntimeError as msg:
124 print "%s (ignored)" % msg
126 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :