1
from VMBuilder.util import run_cmd
9
def __init__(self, size='5G', preallocated=False, filename=None, dir=None):
10
self.size = self.parse_size(size)
11
self.preallocated = preallocated
13
self.filename = filename
15
self.filename = 'disk%d.img' % Disk.index
16
# This will only work for up to 26 disks. If you *actually*
17
# need more than that, just shout, but right now, I can't
18
# be bothered to fix it. - Soren
19
self.devname = '/dev/sd%s' % string.ascii_lowercase[Disk.index]
21
self.filename = '%s/%s' % (dir, self.filename)
25
def parse_size(self, size_str):
26
"""Takes a size like qemu-img would accept it and returns the size in MB"""
33
num = int(size_str[:-1])
35
raise ValueError("Invalid size: %s" % size_str)
37
if size_str[-1:] == 'g' or size_str[-1:] == 'G':
39
if size_str[-1:] == 'm' or size_str[-1:] == 'M':
41
if size_str[-1:] == 'k' or size_str[-1:] == 'K':
45
if not self.preallocated:
46
logging.info('Creating disk image: %s' % self.filename)
47
run_cmd('qemu-img', 'create', '-f', 'raw', self.filename, '%dM' % self.size)
49
logging.info('Adding partition table to disk image: %s' % self.filename)
50
run_cmd('parted', '--script', self.filename, 'mklabel', 'msdos')
52
for part in self.partitions:
55
logging.info('Creating loop devices corresponding to the created partitions')
56
kpartx_output = run_cmd('kpartx', '-av', self.filename)
57
VMBuilder.add_clean_cb(lambda : self.unmap(ignore_fail=True))
58
parts = kpartx_output.split('\n')[2:-1]
61
mapdevs.append(line.split(' ')[2])
62
for (part, mapdev) in zip(self.partitions, mapdevs):
63
part.mapdev = '/dev/mapper/%s' % mapdev
65
logging.info("Creating file systems")
66
for part in self.partitions:
69
def unmap(self, ignore_fail=False):
70
run_cmd('kpartx', '-d', self.filename, ignore_fail=ignore_fail)
72
def add_part(self, begin, length, type, mntpnt):
74
for part in self.partitions:
75
if (begin >= part.begin and begin <= part.end) or \
76
(end >= part.begin and end <= part.end):
77
raise Exception('Partitions are overlapping')
79
raise Exception('Partition\'s last block is before its first')
80
if begin < 0 or end > self.size:
81
raise Exception('Partition is out of bounds. start=%d, end=%d, disksize=%d' % (begin,end,self.size))
82
part = self.Partition(begin=begin, end=end, type=self.Partition.str_to_type(type), mntpnt=mntpnt)
83
self.partitions.append(part)
84
self.partitions.sort(cmp=lambda x,y: x.begin - y.begin)
86
def convert(self, destination, format):
87
logging.info('Converting %s to %s, format %s' % (self.filename, format, destination))
88
run_cmd('qemu-img', 'convert', '-O', format, self.filename, destination)
90
class Partition(object):
96
def __init__(self, begin, end, type, mntpnt):
103
def parted_fstype(self):
104
return { self.TYPE_EXT2: 'ext2', self.TYPE_EXT3: 'ext2', self.TYPE_XFS: 'ext2', self.TYPE_SWAP: 'linux-swap' }[self.type]
106
def mkfs_fstype(self):
107
return { self.TYPE_EXT2: 'mkfs.ext2', self.TYPE_EXT3: 'mkfs.ext3', self.TYPE_XFS: 'mkfs.xfs', self.TYPE_SWAP: 'mkswap' }[self.type]
109
def fstab_fstype(self):
110
return { self.TYPE_EXT2: 'ext2', self.TYPE_EXT3: 'ext3', self.TYPE_XFS: 'xfs', self.TYPE_SWAP: 'swap' }[self.type]
112
def fstab_options(self):
115
def create(self, disk):
116
logging.info('Adding type %d partition to disk image: %s' % (self.type, disk.filename))
117
run_cmd('parted', '--script', '--', disk.filename, 'mkpart', 'primary', self.parted_fstype(), self.begin, self.end)
121
raise Exception('We can\'t mkfs before we have a mapper device')
122
run_cmd(self.mkfs_fstype(), self.mapdev)
123
self.uuid = run_cmd('vol_id', '--uuid', self.mapdev).rstrip()
126
def str_to_type(cls, type):
128
return { 'ext2': cls.TYPE_EXT2,
129
'ext3': cls.TYPE_EXT3,
131
'swap': cls.TYPE_SWAP,
132
'linux-swap': cls.TYPE_SWAP }[type]
134
raise Exception('Unknown partition type')