def guestfs_working(): try: import guestfs except ImportError: return False g = guestfs.GuestFS(python_return_dict=True) g.add_drive_opts("/dev/null", format="raw", readonly=1) try: g.launch() except RuntimeError: return False return True
def setup(self): LOG.debug( _("Setting up appliance for %(imgfile)s %(imgfmt)s") % { 'imgfile': self.imgfile, 'imgfmt': self.imgfmt }) try: self.handle = tpool.Proxy(guestfs.GuestFS(close_on_exit=False)) except TypeError as e: if 'close_on_exit' in str(e): # NOTE(russellb) In case we're not using a version of # libguestfs new enough to support the close_on_exit paramater, # which was added in libguestfs 1.20. self.handle = tpool.Proxy(guestfs.GuestFS()) else: raise try: self.handle.add_drive_opts(self.imgfile, format=self.imgfmt) self.handle.launch() self.setup_os() self.handle.aug_init("/", 0) except RuntimeError as e: # explicitly teardown instead of implicit close() # to prevent orphaned VMs in cases when an implicit # close() is not enough self.teardown() raise exception.NovaException( _("Error mounting %(imgfile)s with libguestfs (%(e)s)") % { 'imgfile': self.imgfile, 'e': e }) except Exception: # explicitly teardown instead of implicit close() # to prevent orphaned VMs in cases when an implicit # close() is not enough self.teardown() raise
def ClamAVFunc(self, vm, av_args): print 'Running in ClamAV thread scanning %s\n' % (vm.vmid) img_path = self.Get_ImagePath(vm.vmid) dirname = self.Get_TmpDir() domethod = av_args['doMethod'] scandir = av_args['scanDir'] scanstyle = '--recursive' g = guestfs.GuestFS() g.add_drive_opts(img_path, format="raw") g.launch() partitions = g.list_partitions() if len(partitions) == 0: print 'No partition found in the image!\n' #raise NoPartitionImageError return False for p in partitions: #TODO:Check the opts #mount_options(self, options, device, mountpoint) #print 'partition %s\n' %p g.mount_options("user_xattr", p, "/") #must be done and return successfully before the mount_local_run if g.mount_local(dirname) == -1: print 'Fail to mount local %s!\n' % p continue child_pid = os.fork() if child_pid == 0: #child process to do the antivirus thing print 'Scanning partition %s .......\n' % p #time.sleep(8) av_bin = 'clamscan' log_path = '/tmp/oav-%s.log' % vm.vmid execommand = ' '.join( [av_bin, domethod, scanstyle, dirname, '-l', log_path]) os.system(execommand) print 'Execute %s \n' % execommand print 'Finish scanning partition %s .......\n' % p g.umount_local() os._exit(0) else: #parent process handle the infinitely looping mount_local_run until the filesystem is unmounted if g.mount_local_run() == -1: print 'Fail to mount local!\n' #raise MountLocalError continue #wait for the child process to finish and umount the filesystem and then the next partition is to be worked upon os.waitpid(child_pid, os.WNOHANG) g.umount("/") #guestfs handle should be closed after all the work related to it done g.close() print 'Finished in ClamAV thread scanning %s!\n' % vm.vmid
def create_ext2_image(self, image_file, image_size=(1024*1024*1024*30)): # Why ext2? Why not? There's no need for the overhead of journaling. This disk will be mounted once and thrown away. self.log.debug("Creating disk image of size (%d) in file (%s) with single partition containint ext2 filesystem" % (image_size, image_file)) raw_fs_image=open(image_file,"w") raw_fs_image.truncate(image_size) raw_fs_image.close() g = guestfs.GuestFS() g.add_drive(image_file) g.launch() g.part_disk("/dev/sda","msdos") g.part_set_mbr_id("/dev/sda",1,0x83) g.mkfs("ext2", "/dev/sda1") g.sync()
def __init__(self, conf, guest_image, partition): self.g = guestfs.GuestFS(python_return_dict=True) self.partition = partition self.conf = conf # required to resolve error "Assertion `ret == cpu->kvm_msr_buf->nmsrs` failed"; caused by running within vmware self.g.set_backend_setting("force_tcg", "1") self.g.add_drive_opts(guest_image, readonly=True) logger.debug("Launching guestfs...") self.g.launch() logger.debug("Mounting guest filesystem...") self.g.mount(self.partition, "/")
def prepare(self): """ Initialise guestfs """ self.message("Preparing %s" % self.settings['image']) self.guest_os = guestfs.GuestFS(python_return_dict=True) self.guest_os.add_drive_opts(self.settings['image'], format="raw", readonly=1) # ensure launch is only called once per run self.guest_os.launch() drives = self.guest_os.inspect_os() self.mps = self.guest_os.inspect_get_mountpoints(drives[0])
def f(self, *args, **kwargs): if self.gfs is None: self.gfs = guestfs.GuestFS() readonly = 0 if self.readonly: readonly = 1 self.gfs.add_drive_opts(self.image_path, readonly=readonly) self.logger.debug('Launching guestfs') self.gfs.launch() result = func(self, *args, **kwargs) return result
def bootstrap(self): results = {} ansible_module_params = self.module.params self.image = ansible_module_params.get('image') self.automount = ansible_module_params.get('automount') self.network = ansible_module_params.get('network') if os.path.exists(self.image) is False: results['msg'] = 'Could not find image' self.module.fail_json(**results) g = guestfs.GuestFS(python_return_dict=True) g.add_drive_opts(self.image, readonly=0) if self.network: g.set_network(True) try: g.launch() except Exception as e: results[ 'msg'] = 'Could not mount guest disk image, python exception:\n {}'.format( str(e)) self.module.fail_json(**results) if self.automount: roots = g.inspect_os() if len(roots) == 0: results[ 'msg'] = 'Automount failed, no devices were found in guest disk image' self.module.fail_json(**results) for root in roots: mps = g.inspect_get_mountpoints(root) for mountpoint, device in mps.items(): try: g.mount(device, mountpoint) except RuntimeError as e: results[ 'msg'] = "Couldn't mount device inside guest disk image, python exception:\n {}".format( str(e)) self.module.fail_json(**results) self.mount = True # TODO (vkhitrin): Implement an option to supply manual mounts when not using automount else: results[ 'msg'] = "automount is false, can't proceed with this module" self.module.fail_json(**results) self.handle = g return g
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 behavior 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) # Before version 1.17.14 the recovery process, which is a fork of the # original process that called libguestfs, did not close its inherited # 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 self.check_guestfs_version(1, 17, 14) >= 0: self.out.info("Enabling recovery process ...", False) self.g.set_recovery_proc(1) self.out.success('done') else: self.g.set_recovery_proc(0) # self.g.set_trace(1) # self.g.set_verbose(1) self.out.info('Launching helper VM (may take a while) ...', False) # self.progressbar = self.out.Progress(100, "Launching helper VM", # "percent") # eh = self.g.set_event_callback(self.progress_callback, # guestfs.EVENT_PROGRESS) try: self.g.launch() except RuntimeError as e: raise FatalError( "Launching libguestfs's helper VM failed!\nReason: %s.\n\n" "Please run `libguestfs-test-tool' for more info." % str(e)) self.guestfs_enabled = True # 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')
def __init__(self, **kwargs): self.uuid = kwargs.get('uuid', None) self.name = kwargs.get('name', None) self.password = kwargs.get('password', None) # 模板镜像路径 self.template_path = kwargs.get('template_path', None) # 不提供链接克隆(完整克隆,后期可以在模板目录,直接删除模板文件。从理论上讲,基于完整克隆的 Guest 读写速度、快照都应该快于链接克隆。) # self.clone = True # Guest 系统盘及数据磁盘 self.disk = kwargs.get('disk', None) self.xml = kwargs.get('xml', None) # Guest 系统镜像路径,不包含 dfs 卷标 self.system_image_path = None self.g = guestfs.GuestFS(python_return_dict=True)
def bootstrap(disk_path, modifications): g = guestfs.GuestFS(python_return_dict=True) g.add_drive_opts(disk_path, format='qcow2', readonly=0) g.set_backend('direct') g.launch() try: rootfs = filter(lambda x: 'root' in x, g.list_filesystems())[0] g.mount(rootfs, '/') for mod in modifications: mod(g) finally: g.shutdown() g.close()
def create_local_repository(self): """ Create raw disk image with dummy root file system and index file which contains the metadata used by virt-builder. """ g = guestfs.GuestFS(python_return_dict=True) g.disk_create(self.image['path'], format=self.image['format'], size=self.image['size']) g.add_drive(self.image['path'], readonly=False, format=self.image['format']) g.launch() g.mkfs('ext2', '/dev/sda') g.mount('/dev/sda', '/') for user in self.rootfs_tree: usr_uid = self.rootfs_tree[user]['uid'] usr_gid = self.rootfs_tree[user]['gid'] for member in self.rootfs_tree[user]['dirs']: dir_name = '/' + member g.mkdir_p(dir_name) g.chown(usr_uid, usr_gid, dir_name) for member in self.rootfs_tree[user]['files']: if isinstance(member, tuple): m_name, m_permissions, m_data = member file_name = '/' + m_name g.write(file_name, m_data) g.chmod(m_permissions & 0o777, file_name) else: file_name = '/' + member g.touch(file_name) g.chmod(DEFAULT_FILE_MODE & 0o777, file_name) g.chown(usr_uid, usr_gid, file_name) # Create index file with open(self.repo_index, 'w') as index_file: index_file.write( '[{template}]\n' 'name=Test\n' 'arch={arch}\n' 'file={filename}\n' # Relative (not real) path must be used. 'format={format}\n' 'expand=/dev/sda\n' 'size={size}\n'.format(**self.image) # The new line at the end of the index file is required. # Otherwise, virt-builder will return "syntax error". )
def prepare_install_base(output, size): """ Create an empty image of the specified size (in bytes), ready for an installer to partition, create filesystem(s) and install files. """ guest = guestfs.GuestFS(python_return_dict=True) guest.disk_create(output, "raw", size) guest.add_drive_opts(output, format="raw", readonly=False) guest.launch() devices = guest.list_devices() if len(devices) != 1: raise InfrastructureError("Unable to prepare guestfs") guest.shutdown()
def get_manifest(tmpdir, full_manifest): disk = get_disk(tmpdir) guestfish = guestfs.GuestFS(python_return_dict=True) guestfish.add_drive_opts(disk, readonly=1) guestfish.launch() rootdev = guestfish.inspect_os()[0] guestfish.mount(rootdev, "/") var_lv = [l for l in guestfish.lvs() if l.endswith("/var")] if var_lv: guestfish.mount(var_lv[0], "/var") pkgs, all_pkgs = query(guestfish, full_manifest) guestfish.umount_all() return pkgs, all_pkgs
def __init__(self, input_disk, input_disk_type): self.log = logging.getLogger(__name__) self.g_handle = guestfs.GuestFS(python_return_dict=True) self.log.debug("Adding disk image %s", input_disk) # NOTE: we use "add_drive_opts" here so we can specify the type # of the diskimage. Otherwise it might be possible for an attacker # to fool libguestfs with a specially-crafted diskimage that looks # like a qcow2 disk (thanks to rjones for the tip) self.g_handle.add_drive_opts(input_disk, format=input_disk_type) self.log.debug("Launching guestfs") self.g_handle.launch()
def test_qcow2_build_image(self): """ Ensures that the root file system is copied correctly to single partition qcow2 image and layers are converted correctly to qcow2 images. """ layers_rootfs = self.call_bootstrap() ################### # Check base layer ################### base_layer_path = self.get_image_path() img_format = self.get_image_info(base_layer_path)[1] self.assertEqual(img_format, 'file format: qcow2') images = [base_layer_path] ########################### # Check backing chains ########################### for i in range(1, len(layers_rootfs)): img_path = self.get_image_path(i) # img_info contains the output of "qemu-img info" img_info = self.get_image_info(img_path) self.assertEqual( img_info[1], 'file format: qcow2', 'Invalid qcow2 disk image: %s' % img_path ) backing_file = self.get_image_path(i - 1) self.assertEqual( img_info[5], 'backing file: %s' % backing_file, "Incorrect backing file for: %s\n" "Expected: %s\n" "Found: %s" % (img_info, backing_file, img_info[5]) ) images.append(img_path) ############################### # Check extracted files/folders ############################### g = guestfs.GuestFS(python_return_dict=True) for path in images: g.add_drive_opts(path, readonly=True) g.launch() devices = g.list_filesystems() for dev, rootfs in zip(sorted(devices), layers_rootfs): self.rootfs_tree = rootfs g.mount(dev, '/') self.check_image(g) g.umount('/') g.shutdown()
def launch(self, readonly=False): try: self.handle = guestfs.GuestFS(python_return_dict=True, close_on_exit=True) except TypeError as e: if 'close_on_exit' in six.text_type( e) or 'python_return_dict' in six.text_type(e): self.handle = guestfs.GuestFS() else: raise if self.domain is not None: if readonly: self.handle.add_domain(self.domain, readonly=readonly, readonlydisk='read') else: self.handle.add_domain(self.domain, readonly=readonly, readonlydisk='write') else: self.handle.add_drive(self.imgfile, readonly) self.handle.launch()
def main(): format_options_and_help = { 'json': 'JSON without newlines. Suitable for consumption by ' 'another program.', 'human': 'Readable format that includes newlines and indents.', 'daisy': 'Key-value format supported by Daisy\'s serial log collector.', } parser = argparse.ArgumentParser( description='Find boot-related properties of a disk.') parser.add_argument('--format', choices=format_options_and_help.keys(), default='human', help=' '.join([ '`%s`: %s' % (key, value) for key, value in format_options_and_help.items() ])) parser.add_argument('device', help='a block device or disk file.') args = parser.parse_args() results = inspect_pb2.InspectionResults() try: g = guestfs.GuestFS(python_return_dict=True) g.add_drive_opts(args.device, readonly=1) g.launch() except BaseException as e: print('Failed to mount guest: ', e) results.ErrorWhen = inspect_pb2.InspectionResults.ErrorWhen.MOUNTING_GUEST globals()['_output_' + args.format](results) return try: print('Inspecting OS') results = inspection.inspect_device(g) except BaseException as e: print('Failed to inspect OS: ', e) results.ErrorWhen = inspect_pb2.InspectionResults.ErrorWhen.INSPECTING_OS try: boot_results = inspection.inspect_boot_loader(g, args.device) results.bios_bootable = boot_results.bios_bootable results.uefi_bootable = boot_results.uefi_bootable results.root_fs = boot_results.root_fs except BaseException as e: print('Failed to inspect boot loader: ', e) results.ErrorWhen = \ inspect_pb2.InspectionResults.ErrorWhen.INSPECTING_BOOTLOADER globals()['_output_' + args.format](results)
def unpack_base(self, modify_func=None): assert not self._process if not os.path.exists(self.run_dir): os.makedirs(self.run_dir, 0750) image = "%s-%s" % (self.os, self.arch) tarball = os.path.join(self.test_data, "%s.tar.gz" % (image, )) if not os.path.exists(tarball): raise Failure("Unsupported configuration %s: %s not found." % (image, tarball)) import guestfs gf = guestfs.GuestFS(python_return_dict=True) if self.verbose: gf.set_trace(1) try: # Create a qcow2-format disk image self.message("Building disk:", self._image_root) subprocess.check_call([ "qemu-img", "create", "-q", "-f", "qcow2", self._image_root, "4G" ]) # Attach the disk image to libguestfs. gf.add_drive_opts(self._image_root, format="qcow2", readonly=0) gf.launch() devices = gf.list_devices() assert len(devices) == 1 gf.mkfs("ext2", devices[0]) gf.mount(devices[0], "/") self.message("Unpacking %s into %s" % (tarball, self._image_root)) gf.tgz_in(tarball, "/") kernels = gf.glob_expand("/boot/vmlinuz-*") initrds = gf.glob_expand("/boot/initramfs-*") self.message("Extracting:", kernels[0], initrds[0]) gf.download(kernels[0], self._image_kernel) gf.download(initrds[0], self._image_initrd) if modify_func: modify_func(gf) finally: gf.close()
def test_qcow2_setting_root_password(self): """ Ensures that the root password is set in the last qcow2 image. """ self.root_password = "******" layers_rootfs = self.call_bootstrap() g = guestfs.GuestFS(python_return_dict=True) g.add_drive_opts(self.get_image_path(len(layers_rootfs)), readonly=True) g.launch() g.mount('/dev/sda', '/') self.validate_shadow_file_in_image(g) g.umount('/') g.shutdown()
def _start_guestfs(): try: path = self.get_tmp_volume_path() guest = guestfs.GuestFS() guest.add_drive(path) guest.launch() guest.mount("/dev/sda1", "/") if guest.exists('/etc/sysconfig/selinux'): guest.get_selinux = lambda: 1 except RuntimeError as e: raise error.ExecError("guestfs error: {}".format(e)) return guest
def __init__(self, layers, dest, progress): """ @param tar_files: Tarballs to be converted to qcow2 images @param dest: Directory where the qcow2 images will be created @param progress: Instance of the progress module Note: uid_map and gid_map have the format: [[<start>, <target>, <count>], [<start>, <target>, <count>] ...] """ self.g = guestfs.GuestFS(python_return_dict=True) self.layers = layers self.nlayers = len(layers) self.dest = dest self.progress = progress self.qcow2_files = []
def test_explicit_close(self): g = guestfs.GuestFS(python_return_dict=True) g.close() # explicit close del g # implicit close - should be no error/warning # Expect an exception if we call a method on a closed handle. g = guestfs.GuestFS(python_return_dict=True) g.close() self.assertRaises(guestfs.ClosedHandle, g.set_memsize, 512) del g # Verify that the handle is really being closed by g.close, by # setting up a close event and testing that it happened. g = guestfs.GuestFS(python_return_dict=True) g.set_event_callback(close_callback, guestfs.EVENT_CLOSE) self.assertEqual(close_invoked, 0) g.close() self.assertEqual(close_invoked, 1) del g self.assertEqual(close_invoked, 1)
def getHandle(pathToVMI, rootRequired=False): """ Returns the guestfs handle for the vmi located at pathToVMI. If rootRequired is specified, a tuple (handle,root) is returned :param pathToVMI: :param rootRequired: :return: """ def compare(a, b): return len(a) - len(b) guest = guestfs.GuestFS(python_return_dict=True) guest.add_drive_opts(pathToVMI, readonly=False) guest.launch() #guest.set_verbose(1) # Obtain root filesystem that contains the OS roots = guest.inspect_os() if len(roots) == 0: raise (Exception("inspect_vm: no operating systems found")) if len(roots) > 1: raise (Exception("inspect_vm: more than one operating system found")) root = roots[0] # Obtain and try to mount all required filesystems associated with OS mps = guest.inspect_get_mountpoints(root) for device in sorted(mps.keys(), compare): try: guest.mount(mps[device], device) except RuntimeError as msg: print "%s (ignored)" % msg #guest.sh("mount -t proc proc proc/") #guest.sh("mount --rbind /sys sys/") #guest.sh("mount --rbind /dev dev/") #guest.sh("mkdir -p -m 755 /sysroot/dev/pts") #guest.sh("mount -t devpts /dev/pts /sysroot/dev/pts -o nosuid,noexec,gid=5,mode=620,ptmxmode=666") # print guest.sh("cat /etc/fstab") #print guest.dmesg() #print guest.sh("mount") if rootRequired: return (guest, root) else: return guest
def open_archive(self): if not guestfs: return None self.g = guestfs.GuestFS (python_return_dict=True) self.g.add_drive_opts (self.source.path, format="raw", readonly=1) try: self.g.launch() except RuntimeError: logger.exception("guestfs can't be launched") logger.error("If memory is too tight for 512 MiB, try running with LIBGUESTFS_MEMSIZE=256 or lower.") return None devices = self.g.list_devices() self.g.mount(devices[0], "/") self.fs = self.g.list_filesystems()[devices[0]] return self
def sync(self, localfile, remotefile): g = guestfs.GuestFS(python_return_dict=True) g.add_drive_opts(self.imagename, format=self.diskformat, readonly=False) g.launch() g.inspect_os() ROOT = g.inspect_get_roots() #['/dev/sda3'] g.inspect_get_mountpoints( ROOT[0]) #{'/boot': '/dev/sda1', '/': '/dev/sda3'} g.inspect_get_filesystems( ROOT[0]) #['/dev/sda3', '/dev/sda1', '/dev/sda2'] g.mount(ROOT[0], '/') g.upload(localfile, remotefile) g.shutdown() g.close()
def __init__(self, vm_name, uri): # connect to QEMU logging.info('Connecting to {}'.format(uri)) self.con = libvirt.open(uri) if self.con == None: logging.info('Failed to connect to Hypervisor !') sys.exit(1) # search vm logging.info('Searching VM') vm = self.con.lookupByName(vm_name) # find qcow path logging.info('Finding hard disk') root = ET.fromstring(vm.XMLDesc()) disk = root.find("./devices/disk[@type='file'][@device='disk']") if disk is None: logging.info('Cannot find VM main disk !') sys.exit(1) qcow_path = disk.find('source').get('file') logging.info(qcow_path) # init libguestfs self.g = guestfs.GuestFS(python_return_dict=True) # attach drive self.g.add_drive_opts(qcow_path, readonly=1) # run libguestfs backend logging.info('Running libguestfs') self.g.launch() # inspect operating system roots = self.g.inspect_os() if len(roots) == 0: logging.info('No operating system found !') sys.exit(1) # we should have one main filesystem root = roots[0] mps = self.g.inspect_get_mountpoints(root) # mount filesystem logging.info('Mounting main filesystem') for mount_point, device in mps.items(): self.g.mount_ro(device, mount_point) self.graph = Graph(password=DB_PASSWORD) # debug, erase every node self.graph.delete_all() # init variables self.counter = 0 self.total_entries = 0
def modify_oz_filesystem(self): self.log.debug( "Doing further Factory specific modification of Oz image") self.log.debug("init guestfs") g = guestfs.GuestFS() self.log.debug("add input image") g.add_drive(self.image) self.log.debug("launch guestfs") g.launch() g.mount_options("", "/dev/VolGroup00/LogVol00", "/") # F16 and upwards end up with boot on sda2 due to GRUB changes if (self.tdlobj.distro == 'Fedora') and (int(self.tdlobj.update) >= 16): g.mount_options("", "/dev/sda2", "/boot") else: g.mount_options("", "/dev/sda1", "/boot") self.log.info("Creating cloud-info file indicating target (%s)" % (self.target)) tmpl = 'CLOUD_TYPE="%s"\n' % (self.target) g.write("/etc/sysconfig/cloud-info", tmpl) # In the cloud context we currently never need or want persistent net device names # This is known to break networking in RHEL/VMWare and could potentially do so elsewhere # Just delete the file to be safe if g.is_file("/etc/udev/rules.d/70-persistent-net.rules"): g.rm("/etc/udev/rules.d/70-persistent-net.rules") # Also clear out the MAC address this image was bound to. g.aug_init("/", 1) if g.aug_rm("/files/etc/sysconfig/network-scripts/ifcfg-eth0/HWADDR"): self.log.debug( "Removed HWADDR from image's /etc/sysconfig/network-scripts/ifcfg-eth0" ) g.aug_save() else: self.log.debug( "Failed to remove HWADDR from image's /etc/sysconfig/network-scripts/ifcfg-eth0" ) g.aug_close() g.sync() g.umount_all()
def __init__(self, win_disk_image, virtio_iso_image, win_iso=None): """ Adds the images as block devices, launches the machine and fetches some version information about the guest. """ self.g = guestfs.GuestFS() self.g.add_drive(win_disk_image) if win_iso: self.g.add_drive_ro(win_iso) self.g.add_drive_ro(virtio_iso_image) self.g.launch() self.win_root = "/win" self.win_blkroot = self._mount_block_devices() self.win_ver = "{}.{}".format( self.g.inspect_get_major_version(self.win_blkroot), self.g.inspect_get_minor_version(self.win_blkroot)) self.is_x64 = self.g.inspect_get_arch(self.win_blkroot) == "x86_64"
def probe_image(image_path): if not os.path.isfile(image_path): raise InvalidParameter("KCHIMG0004E", {'filename': image_path}) if not os.access(image_path, os.R_OK): raise ImageFormatError("KCHIMG0003E", {'filename': image_path}) try: import guestfs g = guestfs.GuestFS(python_return_dict=True) g.add_drive_opts(image_path, readonly=1) g.launch() roots = g.inspect_os() except ImportError: return ("unknown", "unknown") except Exception, e: raise ImageFormatError("KCHIMG0001E", {'err': str(e)})