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 : |