1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
# Copyright 2017 Lars Wirzenius
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# =*= License: GPL-3+ =*=
import os
import stat
import time
import vmdb
class MkpartPlugin(vmdb.Plugin):
def enable(self):
self.app.step_runners.add(MkpartStepRunner())
class MkpartStepRunner(vmdb.StepRunnerInterface):
def get_key_spec(self):
return {
"mkpart": str,
"device": str,
"start": str,
"end": str,
"tag": "",
"part-tag": "",
"fs-type": "ext2",
}
def run(self, values, settings, state):
part_type = values["mkpart"]
device = values["device"]
start = values["start"]
end = values["end"]
tag = values["tag"] or values["part-tag"] or None
fs_type = values["fs-type"]
device = os.path.realpath(device)
orig = self.list_partitions(device)
vmdb.runcmd(["parted", "-s", device, "--", "mkpart", part_type, fs_type, start, end])
new = self.list_partitions(device)
diff = self.diff_partitions(orig, new)
if len(diff) == 0:
raise ExpectedNewPartition()
if len(diff) > 1:
raise UnexpectedNewPartitions(diff)
state.tags.append(tag)
# If device is a real block device (e.g, /dev/sdb), the
# parition we have in diff are also real devices (e.g.,
# /dev/sdb1), and we should remember those in tags.
#
# If, however, device is a disk image file (e.g, foo.img), the
# partition in diff is not a device file but something like
# foo.img1. We don't need to remember that in tags. The user
# will use the kpartx step later to add those partitions into
# tags.
if self.is_block_dev(device):
self.wait_for_file_to_exist(diff[0])
vmdb.progress("remembering partition {} as {}".format(diff[0], tag))
state.tags.set_dev(tag, diff[0])
def is_block_dev(self, filename):
st = os.lstat(filename)
return stat.S_ISBLK(st.st_mode)
def list_partitions(self, device):
output = vmdb.runcmd(["parted", "-m", device, "print"])
output = output.decode("UTF-8")
partitions = [line.split(":")[0] for line in output.splitlines() if ":" in line]
return [
word if word.startswith("/") else "{}{}".format(device, word)
for word in partitions
]
def diff_partitions(self, old, new):
return [line for line in new if line not in old]
def wait_for_file_to_exist(self, filename):
while not os.path.exists(filename):
time.sleep(1)
class MkpartError(Exception):
pass
class ExpectedNewPartition(MkpartError):
def __init__(self):
super().__init__("Expected a new partition to exist after mkpart")
class UnexpectedNewPartitions(MkpartError):
def __init__(self, diff):
super().__init__(
"Expected only one new partition to exist after mkpart, "
"but found {}".format(" ".join(diff))
)
|