Revision 1377b8a7 image_creator/disk.py

b/image_creator/disk.py
6 6
import tempfile
7 7
import uuid
8 8
import re
9
import sys
10
import guestfs
11

  
9 12
from pbs import dmsetup
10 13
from pbs import blockdev
11 14
from pbs import dd
12
from pbs import kpartx
13
from pbs import mount
14
from pbs import umount
15

  
16
class DiskError(Exception): pass
15 17

  
16 18
class Disk(object):
17 19

  
......
33 35
        raise NotImplementedError
34 36

  
35 37
    def cleanup(self):
38
        while len(self._devices):
39
            device = self._devices.pop()
40
            device.destroy()
41
            
36 42
        while len(self._cleanup_jobs):
37 43
            job, args = self._cleanup_jobs.pop()
38 44
            job(*args)
......
65 71
        finally:
66 72
            os.unlink(table)
67 73

  
68
        new_device = DiskDevice(self, "/dev/mapper/%s" % snapshot)
74
        new_device = DiskDevice("/dev/mapper/%s" % snapshot)
69 75
        self._devices.append(new_device)
70 76
        return new_device
71 77

  
78
    def destroy_device(self, device):
79
        self._devices.remove(device)
80
        device.destroy()
81

  
72 82
class DiskDevice(object):
73 83

  
74
    def __init__(self, disk, device, bootable = True):
75
        self.disk = disk
84
    def __init__(self, device, bootable = True):
76 85
        self.device = device
77
        self.is_bootable = bootable
78
        self.partitions_mapped = False
79
        self.magic_number = uuid.uuid4().hex
80

  
81
    def list_partitions(self):
82
        if not self.partitions_mapped:
83
            kpartx("-a", "-p", self.magic_number, self.dev)
84
            self.disk._cleanup_jobs.append(kpartx, "-d", "-p",
85
                        self.magic_number, self.dev)
86
            self.partitions_mapped = True
87

  
88
        output = kpartx("-l", "-p", self.magic_number, self.dev)
89
        return [ "/dev/mapper/%s" % x for x in
90
                re.findall('^\S+', str(output), flags=re.MULTILINE)]
91

  
92
    def mount(self, partition):
93
        if not self.partitions_mapped:
94
            self.list_partitions()
95
            kpartx("-a", "-p", self.magic_number, self.dev)
96
            self.disk._cleanup_jobs.append(kpartx, "-d", "-p",
97
                        self.magic_number, self.dev)
98
            self.partitions_mapped = True
99

  
100
        targetfd, target = tempfile.mkdtemp()
101
        try:
102
            mount(dev, partition)
103
        except:
104
            os.rmdir(table)
105
            raise
106
        return target
107

  
108
    def unmount(self, partition):
109
        umount(target)
110

  
111
        mode = os.stat(self.source).st_mode
112
        if stat.S_ISDIR(mode):
113
            os.rmdir(target)
86
        self.bootable = bootable
87

  
88
        self.g = guestfs.GuestFS()
89
        self.g.add_drive_opts(device, readonly = 0)
90
        self.g.launch()
91
        roots = self.g.inspect_os()
92
        if len(roots) == 0:
93
            raise DiskError("No operating system found")
94
        if len(roots) > 1:
95
            raise DiskError("Multiple operating systems found")
96

  
97
        self.root = roots[0]
98
    
99
    def destroy(self):
100
        self.g.umount_all()
101
        self.g.sync()
102
        # Close the guestfs handler
103
        del self.g
104
    
105
    def get_image_metadata(self):
106
        meta = {}
107
        meta["OSFAMILY"] = self.g.inspect_get_type(self.root)
108
        meta["OS"] = self.g.inspect_get_distro(self.root)
109
        meta["description"] = self.g.inspect_get_product_name(self.root)
110
        return meta
111

  
112
    def mount(self):
113
        mps = g.inspect_get_mountpoints(self.root)
114
        # Sort the keys to mount the fs in a correct order.
115
        # / should be mounted befor /boot, etc
116
        def compare (a, b):
117
            if len(a[0]) > len(b[0]): return 1
118
            elif len(a[0]) == len(b[0]): return 0
119
            else: return -1
120
        mps.sort(compare)
121
        for mp, dev in mps:
122
            try:
123
                self.g.mount(dev, mp)
124
            except RuntimeError as msg:
125
                print "%s (ignored)" % msg
114 126

  
115 127
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :

Also available in: Unified diff