X-Git-Url: https://code.grnet.gr/git/snf-image-creator/blobdiff_plain/6228d45e380c388a44d484d4c35185f5286c80c3..fb2d189cae88acfcb5fffe62a7490248d578769e:/image_creator/disk.py diff --git a/image_creator/disk.py b/image_creator/disk.py index f8794ba..4209462 100644 --- a/image_creator/disk.py +++ b/image_creator/disk.py @@ -34,6 +34,7 @@ from image_creator.util import get_command from image_creator.util import FatalError from image_creator.util import try_fail_repeat +from image_creator.util import free_space from image_creator.gpt import GPTPartitionTable from image_creator.bundle_volume import BundleVolume @@ -53,6 +54,9 @@ losetup = get_command('losetup') blockdev = get_command('blockdev') +TMP_CANDIDATES = ['/var/tmp', os.path.expanduser('~'), '/mnt'] + + class Disk(object): """This class represents a hard disk hosting an Operating System @@ -61,7 +65,7 @@ class Disk(object): the Linux kernel. """ - def __init__(self, source, output): + def __init__(self, source, output, tmp=None): """Create a new Disk instance out of a source media. The source media can be an image file, a block device or a directory. """ @@ -70,6 +74,26 @@ class Disk(object): self.source = source self.out = output self.meta = {} + self.tmp = tempfile.mkdtemp(prefix='.snf_image_creator.', + dir=self._get_tmp_dir(tmp)) + + self._add_cleanup(os.removedirs, self.tmp) + + def _get_tmp_dir(self, default=None): + if default is not None: + return default + + space = map(free_space, TMP_CANDIDATES) + + max_idx = 0 + max_val = space[0] + for i, val in zip(range(len(space)), space): + if val > max_val: + max_val = val + max_idx = i + + # Return the candidate path with more available space + return TMP_CANDIDATES[max_idx] def _add_cleanup(self, job, *args): self._cleanup_jobs.append((job, args)) @@ -83,7 +107,7 @@ class Disk(object): def _dir_to_disk(self): if self.source == '/': bundle = BundleVolume(self.out, self.meta) - image = '/var/tmp/%s.diskdump' % uuid.uuid4().hex + image = '%s/%s.diskdump' % (self.tmp, uuid.uuid4().hex) def check_unlink(path): if os.path.exists(path): @@ -114,7 +138,7 @@ class Disk(object): instance. """ - self.out.output("Examining source media `%s'..." % self.source, False) + self.out.output("Examining source media `%s' ..." % self.source, False) sourcedev = self.source mode = os.stat(self.source).st_mode if stat.S_ISDIR(mode): @@ -132,7 +156,7 @@ class Disk(object): # Take a snapshot and return it to the user self.out.output("Snapshotting media source...", False) size = blockdev('--getsz', sourcedev) - cowfd, cow = tempfile.mkstemp() + cowfd, cow = tempfile.mkstemp(dir=self.tmp) os.close(cowfd) self._add_cleanup(os.unlink, cow) # Create cow sparse file @@ -261,7 +285,7 @@ class DiskDevice(object): mount = self.g.mount_ro if readonly else self.g.mount msg = " read-only" if readonly else "" - self.out.output("Mounting the media%s..." % msg, False) + self.out.output("Mounting the media%s ..." % msg, False) mps = self.g.inspect_get_mountpoints(self.root) # Sort the keys to mount the fs in a correct order. @@ -292,16 +316,17 @@ class DiskDevice(object): raise FatalError(msg) is_extended = lambda p: \ - self.g.part_get_mbr_id(self.guestfs_device, p['part_num']) == 5 + self.g.part_get_mbr_id(self.guestfs_device, p['part_num']) \ + in (0x5, 0xf) is_logical = lambda p: \ - self.meta['PARTITION_TABLE'] != 'msdos' and p['part_num'] > 4 + self.meta['PARTITION_TABLE'] == 'msdos' and p['part_num'] > 4 partitions = self.g.part_list(self.guestfs_device) last_partition = partitions[-1] if is_logical(last_partition): # The disk contains extended and logical partitions.... - extended = [p for p in partitions if is_extended(p)][0] + extended = filter(is_extended, partitions)[0] last_primary = [p for p in partitions if p['part_num'] <= 4][-1] # check if extended is the last primary partition @@ -325,7 +350,8 @@ class DiskDevice(object): self.meta['PARTITION_TABLE'] == 'msdos' and p['part_num'] > 4 is_extended = lambda p: \ self.meta['PARTITION_TABLE'] == 'msdos' and \ - self.g.part_get_mbr_id(self.guestfs_device, p['part_num']) == 5 + self.g.part_get_mbr_id(self.guestfs_device, p['part_num']) \ + in (0x5, 0xf) part_add = lambda ptype, start, stop: \ self.g.part_add(self.guestfs_device, ptype, start, stop) @@ -340,7 +366,7 @@ class DiskDevice(object): MB = 2 ** 20 - self.out.output("Shrinking image (this may take a while)...", False) + self.out.output("Shrinking image (this may take a while) ...", False) sector_size = self.g.blockdev_getss(self.guestfs_device) @@ -375,10 +401,8 @@ class DiskDevice(object): self.g.resize2fs_M(part_dev) out = self.g.tune2fs_l(part_dev) - block_size = int( - filter(lambda x: x[0] == 'Block size', out)[0][1]) - block_cnt = int( - filter(lambda x: x[0] == 'Block count', out)[0][1]) + block_size = int(filter(lambda x: x[0] == 'Block size', out)[0][1]) + block_cnt = int(filter(lambda x: x[0] == 'Block count', out)[0][1]) start = last_part['part_start'] / sector_size end = start + (block_size * block_cnt) / sector_size - 1 @@ -394,16 +418,16 @@ class DiskDevice(object): 'num': partition['part_num'], 'start': partition['part_start'] / sector_size, 'end': partition['part_end'] / sector_size, - 'id': part_get_(partition['part_num']), + 'id': part_get_id(partition['part_num']), 'bootable': part_get_bootable(partition['part_num']) }) logical[-1]['end'] = end # new end after resize # Recreate the extended partition - extended = [p for p in partitions if self._is_extended(p)][0] + extended = filter(is_extended, partitions)[0] part_del(extended['part_num']) - part_add('e', extended['part_start'], end) + part_add('e', extended['part_start'] / sector_size, end) # Create all the logical partitions back for l in logical: