Futher development for bundle_volume
authorNikos Skalkotos <skalkoto@grnet.gr>
Mon, 10 Dec 2012 18:24:16 +0000 (20:24 +0200)
committerNikos Skalkotos <skalkoto@grnet.gr>
Tue, 11 Dec 2012 14:43:40 +0000 (16:43 +0200)
Create a sparse file under /mnt in the size of the root hard disk
and copy the mbr into this file. Not yet workable.

image_creator/bundle_volume.py
image_creator/disk.py

index 2051738..311dd24 100644 (file)
 # interpreted as representing official policies, either expressed
 # or implied, of GRNET S.A.
 
 # interpreted as representing official policies, either expressed
 # or implied, of GRNET S.A.
 
+import os
+import re
+import parted
+import uuid
+
+from image_creator.util import get_command
 from image_creator.util import FatalError
 
 from image_creator.util import FatalError
 
-def bundle_volume():
-    raise FatalError("Creating an image out of a running system is not yet "
-        "supported.")
+findfs = get_command('findfs')
+truncate = get_command('truncate')
+dd = get_command('dd')
+
+def get_root_partition():
+    if not os.path.isfile('/etc/fstab'):
+        raise FatalError("Unable to open `/etc/fstab'. File is missing.")
+
+    with open('/etc/fstab') as fstab:
+        for line in iter(fstab):
+            entry = line.split('#')[0].strip().split()
+            if len(entry) != 6:
+                continue
+
+            if entry[1] == "/":
+                return entry[0]
+
+        raise FatalError("Unable to find root device in /etc/fstab")
+
+def mnt_mounted():
+    if not os.path.isfile('/etc/mtab'):
+        raise FatalError("Unable to open `/etc/fstab'. File is missing.")
+
+    with open('/etc/mtab') as mtab:
+        for line in iter(mtab):
+            entry = line.split('#')[0].strip().split()
+            if len(entry) != 6:
+                continue
+
+            if entry[1] == '/mnt':
+                return True
+
+    return False
+
+
+def part_to_dev(part):
+    return re.split('[0-9]', part)[0]
+
+def part_to_num(part):
+    return re.split('[^0-9]+', part)[-1]
+
+def bundle_volume(out):
+
+    if mnt_mounted():
+        raise FatalError('The directory /mnt where the image will be hosted'
+            'is mounted. Please unmount it and start over again.')
+
+    out.output('Searching for root device...', False)
+    root_part = get_root_partition()
+
+    if root_part.startswith("UUID=") or root_part.startswith("LABEL="):
+        root_part = findfs(root_part)
+    elif not root_part.startswith("/"):
+        raise FatalError("Unable to find a block device for: %s" % root_dev)
+
+    if not re.match('/dev/[hsv]d[a-z][1-9]*$', root_part):
+        raise FatalError("Don't know how to handle root device: %s" % root_dev)
+
+    device = parted.Device(part_to_dev(root_part))
+
+    image = '/mnt/%s.diskdump' % uuid.uuid4().hex
+
+    # Create sparse file to host the image
+    truncate("-s", "%d" % (device.getLength() * device.sectorSize), image)
+
+    disk = parted.Disk(device)
+    if disk.type != 'msdos':
+        raise FatalError('For now we can only handle msdos partition tables')
+
+    # Copy the MBR and the space between the MBR and the first partition.
+    # In Grub version 1 Stage 1.5 is located there.
+    first_sector = disk.getPrimaryPartitions()[0].geometry.start
+
+    dd('if=%s' % device.path, 'of=%s' % image, 'bs=%d' % device.sectorSize,
+        'count=%d' % first_sector, 'conv=notrunc')
+
+    return image
 
 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
 
 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
index f3df5e8..deafb95 100644 (file)
@@ -79,7 +79,7 @@ class Disk(object):
 
     def _dir_to_disk(self):
         if self.source == '/':
 
     def _dir_to_disk(self):
         if self.source == '/':
-            return bundle_volume()
+            return bundle_volume(self.out)
         raise FatalError("Using a directory as media source is supported")
 
     def cleanup(self):
         raise FatalError("Using a directory as media source is supported")
 
     def cleanup(self):