def _process(self, conn, vm, vmuuid): if re.search(r"^guestfs-", vm.get_name()): logging.debug("ignore libvirt/guestfs temporary VM %s", vm.get_name()) return g = GuestFS() prettyvm = conn.get_uri() + ":" + vm.get_name() ignore = vmuuid disks = [] for disk in vm.get_disk_devices(): if (disk.path and (disk.type == "block" or disk.type == "file") and not disk.device == "cdrom"): disks.append(disk) if not disks: logging.debug("%s: nothing to inspect", prettyvm) return # Add the disks. Note they *must* be added with readonly flag set. for disk in disks: path = disk.path driver_type = disk.driver_type if not (os.path.exists(path) and os.access(path, os.R_OK)): logging.debug("%s: cannot access '%s', skipping inspection", prettyvm, path) return g.add_drive_opts(path, readonly=1, format=driver_type) g.launch() # Inspect the operating system. roots = g.inspect_os() if len(roots) == 0: logging.debug("%s: no operating systems found", prettyvm) return # Arbitrarily pick the first root device. root = roots[0] # Inspection results. typ = g.inspect_get_type(root) # eg. "linux" distro = g.inspect_get_distro(root) # eg. "fedora" major_version = g.inspect_get_major_version(root) # eg. 14 minor_version = g.inspect_get_minor_version(root) # eg. 0 hostname = g.inspect_get_hostname(root) # string product_name = g.inspect_get_product_name(root) # string product_variant = g.inspect_get_product_variant(root) # string # For inspect_list_applications and inspect_get_icon we # require that the guest filesystems are mounted. However # don't fail if this is not possible (I'm looking at you, # FreeBSD). filesystems_mounted = False try: # Mount up the disks, like guestfish --ro -i. # Sort keys by length, shortest first, so that we end up # mounting the filesystems in the correct order. mps = list(g.inspect_get_mountpoints(root)) def compare(a, b): if len(a[0]) > len(b[0]): return 1 elif len(a[0]) == len(b[0]): return 0 else: return -1 mps.sort(compare) for mp_dev in mps: try: g.mount_ro(mp_dev[1], mp_dev[0]) except: logging.exception( "%s: exception mounting %s on %s " "(ignored)", prettyvm, mp_dev[1], mp_dev[0]) filesystems_mounted = True except: logging.exception("%s: exception while mounting disks (ignored)", prettyvm) icon = None apps = None if filesystems_mounted: # string containing PNG data icon = g.inspect_get_icon(root, favicon=0, highquality=1) if icon == "": icon = None # Inspection applications. apps = g.inspect_list_applications(root) # Force the libguestfs handle to close right now. del g # Log what we found. logging.debug("%s: detected operating system: %s %s %d.%d (%s)", prettyvm, typ, distro, major_version, minor_version, product_name) logging.debug("hostname: %s", hostname) if icon: logging.debug("icon: %d bytes", len(icon)) if apps: logging.debug("# apps: %d", len(apps)) data = vmmInspectionData() data.type = str(type) data.distro = str(distro) data.major_version = int(major_version) data.minor_version = int(minor_version) data.hostname = str(hostname) data.product_name = str(product_name) data.product_variant = str(product_variant) data.icon = icon data.applications = list(apps) self._set_vm_inspection_data(vm, data)
class FileSystem: """Convenience wrapper over GuestFS instance. Simplifies some common routines. Automatically translates paths according to the contained File System. """ def __init__(self, disk_path): self._root = None self._handler = GuestFS() self._disk_path = disk_path def __enter__(self): self.mount() return self def __exit__(self, *_): self.umount() def __getattr__(self, attr): return getattr(self._handler, attr) @property def osname(self): """Returns the Operating System name.""" return self._handler.inspect_get_type(self._root) @property def fsroot(self): """Returns the file system root.""" if self.osname == "windows": return "{}:\\".format(self._handler.inspect_get_drive_mappings(self._root)[0][0]) else: return self._handler.inspect_get_mountpoints(self._root)[0][0] def mount(self, readonly=True): """Mounts the given disk. It must be called before any other method. """ self._handler.add_drive_opts(self._disk_path, readonly=True) self._handler.launch() for mountpoint, device in self._inspect_disk(): if readonly: self._handler.mount_ro(device, mountpoint) else: self._handler.mount(device, mountpoint) if self._handler.inspect_get_type(self._root) == "windows": self.path = self._windows_path else: self.path = posix_path def _inspect_disk(self): """Inspects the disk and returns the mountpoints mapping as a list which order is the supposed one for correct mounting. """ roots = self._handler.inspect_os() if roots: self._root = roots[0] return sorted(self._handler.inspect_get_mountpoints(self._root), key=lambda m: len(m[0])) else: raise RuntimeError("No OS found on the given disk image.") def umount(self): """Unmounts the disk. After this method is called no further action is allowed. """ self._handler.close() def download(self, source, destination): """Downloads the file on the disk at source into destination.""" self._handler.download(posix_path(source), destination) def ls(self, path): """Lists the content at the given path.""" return self._handler.ls(posix_path(path)) def nodes(self, path): """Iterates over the files and directories contained within the disk starting from the given path. Yields the path of the nodes. """ path = posix_path(path) yield from (self.path(path, e) for e in self._handler.find(path)) def checksum(self, path, hashtype="sha1"): """Returns the checksum of the given path.""" return self._handler.checksum(hashtype, posix_path(path)) def checksums(self, path, hashtype="sha1"): """Iterates over the files hashes contained within the disk starting from the given path. The hashtype keyword allows to choose the file hashing algorithm. Yields the following values: "C:\\Windows\\System32\\NTUSER.DAT", "hash" for windows "/home/user/text.txt", "hash" for other FS """ with NamedTemporaryFile(buffering=0) as tempfile: self._handler.checksums_out(hashtype, posix_path(path), tempfile.name) yield from ( (self.path(f[1].lstrip(".")), f[0]) for f in (l.decode("utf8").strip().split(None, 1) for l in tempfile) ) def stat(self, path): """Retrieves the status of the node at the given path. Returns a dictionary. """ return self._handler.stat(posix_path(path)) def file(self, path): """Analogous to Unix file command. Returns the type of node at the given path. """ return self._handler.file(posix_path(path)) def exists(self, path): """Returns whether the path exists.""" return self._handler.exists(posix_path(path)) def path(self, *segments): """Normalizes the path returned by guestfs in the File System format.""" raise NotImplementedError("FileSystem needs to be mounted first") def _windows_path(self, *segments): drive = self._handler.inspect_get_drive_mappings(self._root)[0][0] return "%s:%s" % (drive, os.path.join(*segments).replace("/", "\\"))
def _process(self, conn, vm): if re.search(r"^guestfs-", vm.get_name()): logging.debug("ignore libvirt/guestfs temporary VM %s", vm.get_name()) return None g = GuestFS(close_on_exit=False) prettyvm = conn.get_uri() + ":" + vm.get_name() g.add_libvirt_dom(vm.get_backend(), readonly=1) g.launch() # Inspect the operating system. roots = g.inspect_os() if len(roots) == 0: logging.debug("%s: no operating systems found", prettyvm) return None # Arbitrarily pick the first root device. root = roots[0] # Inspection results. typ = g.inspect_get_type(root) # eg. "linux" distro = g.inspect_get_distro(root) # eg. "fedora" major_version = g.inspect_get_major_version(root) # eg. 14 minor_version = g.inspect_get_minor_version(root) # eg. 0 hostname = g.inspect_get_hostname(root) # string product_name = g.inspect_get_product_name(root) # string product_variant = g.inspect_get_product_variant(root) # string # For inspect_list_applications and inspect_get_icon we # require that the guest filesystems are mounted. However # don't fail if this is not possible (I'm looking at you, # FreeBSD). filesystems_mounted = False try: # Mount up the disks, like guestfish --ro -i. # Sort keys by length, shortest first, so that we end up # mounting the filesystems in the correct order. mps = list(g.inspect_get_mountpoints(root)) def compare(a, b): if len(a[0]) > len(b[0]): return 1 elif len(a[0]) == len(b[0]): return 0 else: return -1 mps.sort(compare) for mp_dev in mps: try: g.mount_ro(mp_dev[1], mp_dev[0]) except: logging.exception("%s: exception mounting %s on %s " "(ignored)", prettyvm, mp_dev[1], mp_dev[0]) filesystems_mounted = True except: logging.exception("%s: exception while mounting disks (ignored)", prettyvm) icon = None apps = None if filesystems_mounted: # string containing PNG data icon = g.inspect_get_icon(root, favicon=0, highquality=1) if icon == "": icon = None # Inspection applications. apps = g.inspect_list_applications(root) # Force the libguestfs handle to close right now. del g # Log what we found. logging.debug("%s: detected operating system: %s %s %d.%d (%s)", prettyvm, typ, distro, major_version, minor_version, product_name) logging.debug("hostname: %s", hostname) if icon: logging.debug("icon: %d bytes", len(icon)) if apps: logging.debug("# apps: %d", len(apps)) data = vmmInspectionData() data.type = str(type) data.distro = str(distro) data.major_version = int(major_version) data.minor_version = int(minor_version) data.hostname = str(hostname) data.product_name = str(product_name) data.product_variant = str(product_variant) data.icon = icon data.applications = list(apps) data.error = False return data
def _process(self, conn, vm, vmuuid): g = GuestFS() prettyvm = conn.get_uri() + ":" + vm.get_name() ignore = vmuuid disks = [] for disk in vm.get_disk_devices(): if (disk.path and (disk.type == "block" or disk.type == "file") and not disk.device == "cdrom"): disks.append(disk) if not disks: logging.debug("%s: nothing to inspect", prettyvm) return # Add the disks. Note they *must* be added with readonly flag set. for disk in disks: path = disk.path driver_type = disk.driver_type if not (os.path.exists(path) and os.access(path, os.R_OK)): logging.debug("%s: cannot access '%s', skipping inspection", prettyvm, path) return g.add_drive_opts(path, readonly=1, format=driver_type) g.launch() # Inspect the operating system. roots = g.inspect_os() if len(roots) == 0: logging.debug("%s: no operating systems found", prettyvm) return # Arbitrarily pick the first root device. root = roots[0] # Inspection results. typ = g.inspect_get_type(root) # eg. "linux" distro = g.inspect_get_distro(root) # eg. "fedora" major_version = g.inspect_get_major_version(root) # eg. 14 minor_version = g.inspect_get_minor_version(root) # eg. 0 hostname = g.inspect_get_hostname(root) # string product_name = g.inspect_get_product_name(root) # string # Added in libguestfs 1.9.13: product_variant = None if hasattr(g, "inspect_get_product_variant"): product_variant = g.inspect_get_product_variant(root) # string # For inspect_list_applications and inspect_get_icon we # require that the guest filesystems are mounted. However # don't fail if this is not possible (I'm looking at you, # FreeBSD). filesystems_mounted = False try: # Mount up the disks, like guestfish --ro -i. # Sort keys by length, shortest first, so that we end up # mounting the filesystems in the correct order. mps = g.inspect_get_mountpoints(root) def compare(a, b): if len(a[0]) > len(b[0]): return 1 elif len(a[0]) == len(b[0]): return 0 else: return -1 mps.sort(compare) for mp_dev in mps: try: g.mount_ro(mp_dev[1], mp_dev[0]) except: logging.exception("%s: exception mounting %s on %s " "(ignored)", prettyvm, mp_dev[1], mp_dev[0]) filesystems_mounted = True except: logging.exception("%s: exception while mounting disks (ignored)", prettyvm) icon = None apps = None if filesystems_mounted: # Added in libguestfs 1.11.12: if hasattr(g, "inspect_get_icon"): # string containing PNG data icon = g.inspect_get_icon(root, favicon=0, highquality=1) if icon == "": icon = None # Inspection applications. apps = g.inspect_list_applications(root) # Force the libguestfs handle to close right now. del g # Log what we found. logging.debug("%s: detected operating system: %s %s %d.%d (%s)", prettyvm, typ, distro, major_version, minor_version, product_name) logging.debug("hostname: %s", hostname) if icon: logging.debug("icon: %d bytes", len(icon)) if apps: logging.debug("# apps: %d", len(apps)) data = vmmInspectionData() data.type = str(type) data.distro = str(distro) data.major_version = int(major_version) data.minor_version = int(minor_version) data.hostname = str(hostname) data.product_name = str(product_name) data.product_variant = str(product_variant) data.icon = str(icon) data.applications = list(apps) self._set_vm_inspection_data(vm, data)
class FileSystem: """Convenience wrapper over GuestFS instance. Simplifies some common routines. Automatically translates paths according to the contained File System. """ def __init__(self, disk_path): self._root = None self._handler = GuestFS() self.disk_path = disk_path def __enter__(self): self.mount() return self def __exit__(self, *_): self.umount() def __getattr__(self, attr): return getattr(self._handler, attr) @property def osname(self): """Returns the Operating System name.""" return self._handler.inspect_get_type(self._root) @property def fsroot(self): """Returns the file system root.""" if self.osname == 'windows': return '{}:\\'.format( self._handler.inspect_get_drive_mappings(self._root)[0][0]) else: return self._handler.inspect_get_mountpoints(self._root)[0][0] def mount(self, readonly=True): """Mounts the given disk. It must be called before any other method. """ self._handler.add_drive_opts(self.disk_path, readonly=True) self._handler.launch() for mountpoint, device in self._inspect_disk(): if readonly: self._handler.mount_ro(device, mountpoint) else: self._handler.mount(device, mountpoint) if self._handler.inspect_get_type(self._root) == 'windows': self.path = self._windows_path else: self.path = posix_path def _inspect_disk(self): """Inspects the disk and returns the mountpoints mapping as a list which order is the supposed one for correct mounting. """ roots = self._handler.inspect_os() if roots: self._root = roots[0] return sorted(self._handler.inspect_get_mountpoints(self._root), key=lambda m: len(m[0])) else: raise RuntimeError("No OS found on the given disk image.") def umount(self): """Unmounts the disk. After this method is called no further action is allowed. """ self._handler.close() def download(self, source, destination): """Downloads the file on the disk at source into destination.""" self._handler.download(posix_path(source), destination) def ls(self, path): """Lists the content at the given path.""" return self._handler.ls(posix_path(path)) def nodes(self, path): """Iterates over the files and directories contained within the disk starting from the given path. Yields the path of the nodes. """ path = posix_path(path) yield from (self.path(path, e) for e in self._handler.find(path)) def checksum(self, path, hashtype='sha1'): """Returns the checksum of the given path.""" return self._handler.checksum(hashtype, posix_path(path)) def checksums(self, path, hashtype='sha1'): """Iterates over the files hashes contained within the disk starting from the given path. The hashtype keyword allows to choose the file hashing algorithm. Yields the following values: "C:\\Windows\\System32\\NTUSER.DAT", "hash" for windows "/home/user/text.txt", "hash" for other FS """ with NamedTemporaryFile(buffering=0) as tempfile: self._handler.checksums_out(hashtype, posix_path(path), tempfile.name) yield from ((self.path(f[1].lstrip('.')), f[0]) for f in (l.decode('utf8').strip().split(None, 1) for l in tempfile)) def stat(self, path): """Retrieves the status of the node at the given path. Returns a dictionary. """ return self._handler.stat(posix_path(path)) def file(self, path): """Analogous to Unix file command. Returns the type of node at the given path. """ return self._handler.file(posix_path(path)) def exists(self, path): """Returns whether the path exists.""" return self._handler.exists(posix_path(path)) def path(self, *segments): """Normalizes the path returned by guestfs in the File System format.""" raise NotImplementedError("FileSystem needs to be mounted first") def _windows_path(self, *segments): drive = self._handler.inspect_get_drive_mappings(self._root)[0][0] return "%s:%s" % (drive, os.path.join(*segments).replace('/', '\\'))