Statistics
| Branch: | Tag: | Revision:

root / image_creator / disk.py @ d57775d4

History | View | Annotate | Download (3 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 d57775d4 Nikos Skalkotos
        dd('if=/dev/zero', 'of=%s' % cow, 'count=%d' % (1024*1024))#(int(size)/4))
55 d57775d4 Nikos Skalkotos
        cowdev = self._losetup(cow)
56 d57775d4 Nikos Skalkotos
57 d57775d4 Nikos Skalkotos
        snapshot = uuid.uuid4().hex
58 d57775d4 Nikos Skalkotos
        tablefd, table = tempfile.mkstemp()
59 d57775d4 Nikos Skalkotos
        try:
60 d57775d4 Nikos Skalkotos
            os.write(tablefd, "0 %d snapshot %s %s n 8" % \
61 d57775d4 Nikos Skalkotos
                                        (int(size), sourcedev, cowdev))
62 d57775d4 Nikos Skalkotos
            dmsetup('create', snapshot, table)
63 d57775d4 Nikos Skalkotos
            self._add_cleanup(dmsetup, 'remove', snapshot)
64 d57775d4 Nikos Skalkotos
        finally:
65 d57775d4 Nikos Skalkotos
            os.unlink(table)
66 d57775d4 Nikos Skalkotos
67 d57775d4 Nikos Skalkotos
        new_device = DiskDevice(self, "/dev/mapper/%s" % snapshot)
68 d57775d4 Nikos Skalkotos
        self._devices.append(new_device)
69 d57775d4 Nikos Skalkotos
        return new_device
70 d57775d4 Nikos Skalkotos
71 d57775d4 Nikos Skalkotos
class DiskDevice(object):
72 d57775d4 Nikos Skalkotos
73 d57775d4 Nikos Skalkotos
    def __init__(self, disk, device):
74 d57775d4 Nikos Skalkotos
        self.disk = disk
75 d57775d4 Nikos Skalkotos
        self.dev = device
76 d57775d4 Nikos Skalkotos
        self.partitions_mapped = False
77 d57775d4 Nikos Skalkotos
        self.magic_number = uuid.uuid4().hex
78 d57775d4 Nikos Skalkotos
79 d57775d4 Nikos Skalkotos
    def list_partitions(self):
80 d57775d4 Nikos Skalkotos
        output = kpartx("-l", "-p", self.magic_number, self.dev)
81 d57775d4 Nikos Skalkotos
        return [ "/dev/mapper/%s" % x for x in
82 d57775d4 Nikos Skalkotos
                re.findall('^\S+', str(output), flags=re.MULTILINE)]
83 d57775d4 Nikos Skalkotos
84 d57775d4 Nikos Skalkotos
    def mount(self, partition):
85 d57775d4 Nikos Skalkotos
        if not self.partitions_mapped:
86 d57775d4 Nikos Skalkotos
            kpartx("-a", "-p", self.magic_number, self.dev)
87 d57775d4 Nikos Skalkotos
            self.disk._cleanup_jobs.append(kpartx, "-d", "-p",
88 d57775d4 Nikos Skalkotos
                        self.magic_number, self.dev)
89 d57775d4 Nikos Skalkotos
            self.partitions_mapped = True
90 d57775d4 Nikos Skalkotos
91 d57775d4 Nikos Skalkotos
        targetfd, target = tempfile.mkdtemp()
92 d57775d4 Nikos Skalkotos
        try:
93 d57775d4 Nikos Skalkotos
            mount(dev, partition)
94 d57775d4 Nikos Skalkotos
        except:
95 d57775d4 Nikos Skalkotos
            os.rmdir(table)
96 d57775d4 Nikos Skalkotos
            raise
97 d57775d4 Nikos Skalkotos
        return target
98 d57775d4 Nikos Skalkotos
99 d57775d4 Nikos Skalkotos
    def unmount(self, partition):
100 d57775d4 Nikos Skalkotos
        umount(target)
101 d57775d4 Nikos Skalkotos
102 d57775d4 Nikos Skalkotos
        mode = os.stat(self.source).st_mode
103 d57775d4 Nikos Skalkotos
        if stat.S_ISDIR(mode):
104 d57775d4 Nikos Skalkotos
            os.rmdir(target)
105 d57775d4 Nikos Skalkotos
106 d57775d4 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :