Statistics
| Branch: | Tag: | Revision:

root / image_creator / disk.py @ 333ff548

History | View | Annotate | Download (3.4 kB)

1 d57775d4 Nikos Skalkotos
#!/usr/bin/env python
2 d57775d4 Nikos Skalkotos
3 d57775d4 Nikos Skalkotos
import losetup
4 d57775d4 Nikos Skalkotos
import stat
5 d57775d4 Nikos Skalkotos
import os
6 d57775d4 Nikos Skalkotos
import tempfile
7 d57775d4 Nikos Skalkotos
import uuid
8 d57775d4 Nikos Skalkotos
import re
9 d57775d4 Nikos Skalkotos
from pbs import dmsetup
10 d57775d4 Nikos Skalkotos
from pbs import blockdev
11 d57775d4 Nikos Skalkotos
from pbs import dd
12 d57775d4 Nikos Skalkotos
from pbs import kpartx
13 d57775d4 Nikos Skalkotos
from pbs import mount
14 d57775d4 Nikos Skalkotos
from pbs import umount
15 d57775d4 Nikos Skalkotos
16 d57775d4 Nikos Skalkotos
class Disk(object):
17 d57775d4 Nikos Skalkotos
18 d57775d4 Nikos Skalkotos
    def __init__(self, source):
19 d57775d4 Nikos Skalkotos
        self._cleanup_jobs = []
20 d57775d4 Nikos Skalkotos
        self._devices = []
21 d57775d4 Nikos Skalkotos
        self.source = source
22 d57775d4 Nikos Skalkotos
23 d57775d4 Nikos Skalkotos
    def _add_cleanup(self, job, *args):
24 d57775d4 Nikos Skalkotos
        self._cleanup_jobs.append((job, args))
25 d57775d4 Nikos Skalkotos
26 d57775d4 Nikos Skalkotos
    def _losetup(self, fname):
27 d57775d4 Nikos Skalkotos
        loop = losetup.find_unused_loop_device()
28 d57775d4 Nikos Skalkotos
        loop.mount(fname)
29 d57775d4 Nikos Skalkotos
        self._add_cleanup(loop.unmount)
30 d57775d4 Nikos Skalkotos
        return loop.device
31 d57775d4 Nikos Skalkotos
32 d57775d4 Nikos Skalkotos
    def _dir_to_disk(self):
33 d57775d4 Nikos Skalkotos
        raise NotImplementedError
34 d57775d4 Nikos Skalkotos
35 d57775d4 Nikos Skalkotos
    def cleanup(self):
36 d57775d4 Nikos Skalkotos
        while len(self._cleanup_jobs):
37 d57775d4 Nikos Skalkotos
            job, args = self._cleanup_jobs.pop()
38 d57775d4 Nikos Skalkotos
            job(*args)
39 d57775d4 Nikos Skalkotos
40 d57775d4 Nikos Skalkotos
    def get_device(self):
41 d57775d4 Nikos Skalkotos
        sourcedev = self.source
42 d57775d4 Nikos Skalkotos
        mode = os.stat(self.source).st_mode
43 d57775d4 Nikos Skalkotos
        if stat.S_ISDIR(mode):
44 d57775d4 Nikos Skalkotos
            return self._losetup(self._dir_to_disk())
45 d57775d4 Nikos Skalkotos
        elif stat.S_ISREG(mode):
46 d57775d4 Nikos Skalkotos
            sourcedev = self._losetup(self.source)
47 d57775d4 Nikos Skalkotos
        elif not stat.S_ISBLK(mode):
48 d57775d4 Nikos Skalkotos
            raise ValueError("Value for self.source is invalid")
49 d57775d4 Nikos Skalkotos
50 d57775d4 Nikos Skalkotos
        # Take a snapshot and return it to the user
51 d57775d4 Nikos Skalkotos
        size = blockdev('--getsize', sourcedev)
52 d57775d4 Nikos Skalkotos
        cowfd, cow = tempfile.mkstemp()
53 d57775d4 Nikos Skalkotos
        self._add_cleanup(os.unlink, cow)
54 333ff548 Nikos Skalkotos
        # Create 1G cow file
55 333ff548 Nikos Skalkotos
        dd('if=/dev/null', 'of=%s' % cow, 'bs=1k' ,'seek=%d' % (1024*1024))
56 d57775d4 Nikos Skalkotos
        cowdev = self._losetup(cow)
57 d57775d4 Nikos Skalkotos
58 d57775d4 Nikos Skalkotos
        snapshot = uuid.uuid4().hex
59 d57775d4 Nikos Skalkotos
        tablefd, table = tempfile.mkstemp()
60 d57775d4 Nikos Skalkotos
        try:
61 d57775d4 Nikos Skalkotos
            os.write(tablefd, "0 %d snapshot %s %s n 8" % \
62 d57775d4 Nikos Skalkotos
                                        (int(size), sourcedev, cowdev))
63 d57775d4 Nikos Skalkotos
            dmsetup('create', snapshot, table)
64 d57775d4 Nikos Skalkotos
            self._add_cleanup(dmsetup, 'remove', snapshot)
65 d57775d4 Nikos Skalkotos
        finally:
66 d57775d4 Nikos Skalkotos
            os.unlink(table)
67 d57775d4 Nikos Skalkotos
68 d57775d4 Nikos Skalkotos
        new_device = DiskDevice(self, "/dev/mapper/%s" % snapshot)
69 d57775d4 Nikos Skalkotos
        self._devices.append(new_device)
70 d57775d4 Nikos Skalkotos
        return new_device
71 d57775d4 Nikos Skalkotos
72 d57775d4 Nikos Skalkotos
class DiskDevice(object):
73 d57775d4 Nikos Skalkotos
74 333ff548 Nikos Skalkotos
    def __init__(self, disk, device, bootable = True):
75 d57775d4 Nikos Skalkotos
        self.disk = disk
76 333ff548 Nikos Skalkotos
        self.device = device
77 333ff548 Nikos Skalkotos
        self.is_bootable = bootable
78 d57775d4 Nikos Skalkotos
        self.partitions_mapped = False
79 d57775d4 Nikos Skalkotos
        self.magic_number = uuid.uuid4().hex
80 d57775d4 Nikos Skalkotos
81 d57775d4 Nikos Skalkotos
    def list_partitions(self):
82 333ff548 Nikos Skalkotos
        if not self.partitions_mapped:
83 333ff548 Nikos Skalkotos
            kpartx("-a", "-p", self.magic_number, self.dev)
84 333ff548 Nikos Skalkotos
            self.disk._cleanup_jobs.append(kpartx, "-d", "-p",
85 333ff548 Nikos Skalkotos
                        self.magic_number, self.dev)
86 333ff548 Nikos Skalkotos
            self.partitions_mapped = True
87 333ff548 Nikos Skalkotos
88 d57775d4 Nikos Skalkotos
        output = kpartx("-l", "-p", self.magic_number, self.dev)
89 d57775d4 Nikos Skalkotos
        return [ "/dev/mapper/%s" % x for x in
90 d57775d4 Nikos Skalkotos
                re.findall('^\S+', str(output), flags=re.MULTILINE)]
91 d57775d4 Nikos Skalkotos
92 d57775d4 Nikos Skalkotos
    def mount(self, partition):
93 d57775d4 Nikos Skalkotos
        if not self.partitions_mapped:
94 333ff548 Nikos Skalkotos
            self.list_partitions()
95 d57775d4 Nikos Skalkotos
            kpartx("-a", "-p", self.magic_number, self.dev)
96 d57775d4 Nikos Skalkotos
            self.disk._cleanup_jobs.append(kpartx, "-d", "-p",
97 d57775d4 Nikos Skalkotos
                        self.magic_number, self.dev)
98 d57775d4 Nikos Skalkotos
            self.partitions_mapped = True
99 d57775d4 Nikos Skalkotos
100 d57775d4 Nikos Skalkotos
        targetfd, target = tempfile.mkdtemp()
101 d57775d4 Nikos Skalkotos
        try:
102 d57775d4 Nikos Skalkotos
            mount(dev, partition)
103 d57775d4 Nikos Skalkotos
        except:
104 d57775d4 Nikos Skalkotos
            os.rmdir(table)
105 d57775d4 Nikos Skalkotos
            raise
106 d57775d4 Nikos Skalkotos
        return target
107 d57775d4 Nikos Skalkotos
108 d57775d4 Nikos Skalkotos
    def unmount(self, partition):
109 d57775d4 Nikos Skalkotos
        umount(target)
110 d57775d4 Nikos Skalkotos
111 d57775d4 Nikos Skalkotos
        mode = os.stat(self.source).st_mode
112 d57775d4 Nikos Skalkotos
        if stat.S_ISDIR(mode):
113 d57775d4 Nikos Skalkotos
            os.rmdir(target)
114 d57775d4 Nikos Skalkotos
115 d57775d4 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :