# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
-from image_creator.util import FatalError, check_guestfs_version
+from image_creator.util import FatalError
from image_creator.gpt import GPTPartitionTable
from image_creator.os_type import os_cls
self.size = 0
self.g = guestfs.GuestFS()
+ self.guestfs_enabled = False
+ self.guestfs_version = self.g.version()
+
+ def check_guestfs_version(self, major, minor, release):
+ """Checks if the version of the used libguestfs is smaller, equal or
+ greater than the one specified by the major, minor and release triplet
+
+ Returns:
+ < 0 if the installed version is smaller than the specified one
+ = 0 if they are equal
+ > 0 if the installed one is greater than the specified one
+ """
+
+ for (a, b) in (self.guestfs_version['major'], major), \
+ (self.guestfs_version['minor'], minor), \
+ (self.guestfs_version['release'], release):
+ if a != b:
+ return a - b
+
+ return 0
+
+ def enable(self):
+ """Enable a newly created Image instance"""
+
+ self.enable_guestfs()
+
+ self.out.output('Inspecting Operating System ...', False)
+ roots = self.g.inspect_os()
+
+ if len(roots) == 0 or len(roots) > 1:
+ self.root = None
+ self.ostype = "unsupported"
+ self.distro = "unsupported"
+ self.guestfs_device = '/dev/sda'
+ self.size = self.g.blockdev_getsize64(self.guestfs_device)
+
+ if len(roots) > 1:
+ reason = "Multiple operating systems found on the media."
+ else:
+ reason = "Unable to detect any operating system on the media."
+
+ self.set_unsupported(reason)
+ return
+
+ self.root = roots[0]
+ self.meta['PARTITION_TABLE'] = self.g.part_get_parttype('/dev/sda')
+ self.guestfs_device = '/dev/sda' # self.g.part_to_dev(self.root)
+ self.size = self.g.blockdev_getsize64(self.guestfs_device)
+
+ self.ostype = self.g.inspect_get_type(self.root)
+ self.distro = self.g.inspect_get_distro(self.root)
+ self.out.success(
+ 'found a(n) %s system' %
+ self.ostype if self.distro == "unknown" else self.distro)
+
+ # Inspect the OS
+ self.os.inspect()
+
+ def set_unsupported(self, reason):
+ """Flag this image us ansupported"""
+
+ self._unsupported = reason
+ self.meta['UNSUPPORTED'] = reason
+ self.out.warn('Media is not supported. Reason: %s' % reason)
+
+ def is_unsupported(self):
+ """Returns if this image is unsupported"""
+ return hasattr(self, '_unsupported')
+
+ def enable_guestfs(self):
+ """Enable the guestfs handler"""
+
+ if self.guestfs_enabled:
+ self.out.warn("Guestfs is already enabled")
+ return
+
+ # Before version 1.18.4 the behaviour of kill_subprocess was different
+ # and you need to reset the guestfs handler to relaunch a previously
+ # shut down qemu backend
+ if self.check_guestfs_version(1, 18, 4) < 0:
+ self.g = guestfs.GuestFS()
+
self.g.add_drive_opts(self.device, readonly=0, format="raw")
# Before version 1.17.14 the recovery process, which is a fork of the
# file descriptors. This can cause problems especially if the parent
# process has opened pipes. Since the recovery process is an optional
# feature of libguestfs, it's better to disable it.
- if check_guestfs_version(self.g, 1, 17, 14) >= 0:
+ if self.check_guestfs_version(1, 17, 14) >= 0:
self.out.output("Enabling recovery proc")
self.g.set_recovery_proc(1)
else:
#self.g.set_trace(1)
#self.g.set_verbose(1)
- self.guestfs_enabled = False
-
- def enable(self):
- """Enable a newly created Image instance"""
-
self.out.output('Launching helper VM (may take a while) ...', False)
# self.progressbar = self.out.Progress(100, "Launching helper VM",
# "percent")
# self.g.delete_event_callback(eh)
# self.progressbar.success('done')
# self.progressbar = None
+
+ if self.check_guestfs_version(1, 18, 4) < 0:
+ self.g.inspect_os() # some calls need this
+
self.out.success('done')
- self.out.output('Inspecting Operating System ...', False)
- roots = self.g.inspect_os()
- if len(roots) == 0:
- raise FatalError("No operating system found")
- if len(roots) > 1:
- raise FatalError("Multiple operating systems found."
- "We only support images with one OS.")
- self.root = roots[0]
- self.guestfs_device = self.g.part_to_dev(self.root)
- self.size = self.g.blockdev_getsize64(self.guestfs_device)
- self.meta['PARTITION_TABLE'] = \
- self.g.part_get_parttype(self.guestfs_device)
+ def disable_guestfs(self):
+ """Disable the guestfs handler"""
- self.ostype = self.g.inspect_get_type(self.root)
- self.distro = self.g.inspect_get_distro(self.root)
- self.out.success(
- 'found a(n) %s system' %
- self.ostype if self.distro == "unknown" else self.distro)
+ if not self.guestfs_enabled:
+ self.out.warn("Guestfs is already disabled")
+ return
+
+ self.out.output("Shutting down helper VM ...", False)
+ self.g.sync()
+ # guestfs_shutdown which is the prefered way to shutdown the backend
+ # process was introduced in version 1.19.16
+ if self.check_guestfs_version(1, 19, 16) >= 0:
+ self.g.shutdown()
+ else:
+ self.g.kill_subprocess()
+
+ self.guestfs_enabled = False
+ self.out.success('done')
def _get_os(self):
"""Return an OS class instance for this image"""
self.out.output("Shrinking image (this may take a while) ...", False)
+ if self.is_unsupported():
+ self.out.warn("Shrinking is disabled for unsupported images")
+ return self.size
+
sector_size = self.g.blockdev_getss(self.guestfs_device)
last_part = None
return self.size
part_dev = "%s%d" % (self.guestfs_device, last_part['part_num'])
- self.g.e2fsck_f(part_dev)
+
+ if self.check_guestfs_version(1, 15, 17) >= 0:
+ self.g.e2fsck(part_dev, forceall=1)
+ else:
+ self.g.e2fsck_f(part_dev)
+
self.g.resize2fs_M(part_dev)
out = self.g.tune2fs_l(part_dev)