def _default_vol_name(self): hint = self._name_hint or "vol" suffix = self._default_suffix() ret = "" try: ret = StorageVolume.find_free_name(self.conn.get_backend(), self._parent_pool.get_backend(), hint, suffix=suffix) if ret and suffix: ret = ret.rsplit(".", 1)[0] except Exception: log.exception("Error finding a default vol name") return ret
def _get_inspection_icon_pixbuf(vm, w, h): # libguestfs gives us the PNG data as a string. png_data = vm.inspection.icon if png_data is None: return None try: pb = GdkPixbuf.PixbufLoader() pb.set_size(w, h) pb.write(png_data) pb.close() return pb.get_pixbuf() except Exception: # pragma: no cover log.exception("Error loading inspection icon data") vm.inspection.icon = None return None
def cleanup(self): if self.__cleaned_up: return try: self.close() vmmGObject.cleanup(self) self.builder = None if not self._external_topwin: self.topwin.destroy() self.topwin = None self._err = None except Exception: log.exception("Error cleaning up %s", self) self.__cleaned_up = True
def val_err(self, text1, text2=None, title=_("Input Error"), modal=True): logtext = _("Validation Error: %s") % text1 if text2: logtext += " %s" % text2 if isinstance(text1, Exception) or isinstance(text2, Exception): log.exception(logtext) else: self._logtrace(logtext) dtype = Gtk.MessageType.ERROR buttons = Gtk.ButtonsType.OK self._simple_dialog(dtype, buttons, str(text1), text2 and str(text2) or "", str(title), None, modal) return False
def _add_secret(self, secret): try: props = { "org.freedesktop.Secret.Item.Label": GLib.Variant("s", secret.get_name()), "org.freedesktop.Secret.Item.Attributes": GLib.Variant("a{ss}", secret.attributes), } params = (self._session, [], [ord(v) for v in secret.get_secret()], "text/plain; charset=utf8") replace = True dummy, prompt = self._collection.CreateItem( "(a{sv}(oayays)b)", props, params, replace) self._do_prompt_if_needed(prompt) except Exception: # pragma: no cover log.exception("Failed to add keyring secret")
def _snapshot_selected(self, selection): ignore = selection snap = self._get_selected_snapshots() if not snap: self._set_error_page(_("No snapshot selected.")) return if len(snap) > 1: self._set_error_page(_("Multiple snapshots selected.")) self.widget("snapshot-start").set_sensitive(False) self.widget("snapshot-apply").set_sensitive(False) self.widget("snapshot-delete").set_sensitive(True) return try: self._set_snapshot_state(snap[0]) except Exception as e: # pragma: no cover log.exception(e) self._set_error_page(_("Error selecting snapshot: %s") % str(e))
def do_we_have_session(): pid = os.getpid() ret = False try: # pragma: no cover bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) manager = Gio.DBusProxy.new_sync(bus, 0, None, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", None) # This raises an error exception out = manager.GetSessionByPID("(u)", pid) log.debug("Found login1 session=%s", out) ret = True except Exception: # pragma: no cover log.exception("Failure talking to logind") return ret
def _add_secret(self, secret): ret = None try: props = { "org.freedesktop.Secret.Item.Label": GLib.Variant("s", secret.get_name()), "org.freedesktop.Secret.Item.Attributes": GLib.Variant("a{ss}", secret.attributes), } params = (self._session, [], [ord(v) for v in secret.get_secret()], "text/plain; charset=utf8") replace = True _id = self._collection.CreateItem("(a{sv}(oayays)b)", props, params, replace)[0] ret = int(_id.rsplit("/")[-1]) except Exception: # pragma: no cover log.exception("Failed to add keyring secret") return ret
def __init__(self): self._collection = None try: self._dbus = Gio.bus_get_sync(Gio.BusType.SESSION, None) self._service = Gio.DBusProxy.new_sync( self._dbus, 0, None, "org.freedesktop.secrets", "/org/freedesktop/secrets", "org.freedesktop.Secret.Service", None) self._session = self._service.OpenSession("(sv)", "plain", GLib.Variant("s", ""))[1] self._collection = Gio.DBusProxy.new_sync( self._dbus, 0, None, "org.freedesktop.secrets", "/org/freedesktop/secrets/aliases/default", "org.freedesktop.Secret.Collection", None) log.debug("Using keyring session %s", self._session) except Exception: log.exception("Error determining keyring")
def _do_we_default(conn, vm_name, vol, diskdata): """ Returns (do we delete by default?, info string if not)""" info = "" def append_str(str1, str2, delim="\n"): if not str2: return str1 if str1: str1 += delim str1 += str2 return str1 if diskdata.ro: info = append_str(info, _("Storage is read-only.")) elif not vol and not os.access(diskdata.path, os.W_OK): info = append_str(info, _("No write access to path.")) if diskdata.shared: info = append_str(info, _("Storage is marked as shareable.")) if not info and diskdata.is_media: info = append_str(info, _("Storage is a media device.")) try: names = virtinst.DeviceDisk.path_in_use_by(conn.get_backend(), diskdata.path) if len(names) > 1: namestr = "" names.remove(vm_name) for name in names: namestr = append_str(namestr, name, delim="\n- ") info = append_str( info, _("Storage is in use by the following " "virtual machines:\n- %s " % namestr)) except Exception as e: log.exception("Failed checking disk conflict: %s", str(e)) return (not info, info)
def do_we_have_session(): pid = os.getpid() try: bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) except Exception: log.exception("Error getting system bus handle") return # Check systemd try: manager = Gio.DBusProxy.new_sync(bus, 0, None, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", None) ret = manager.GetSessionByPID("(u)", pid) log.debug("Found login1 session=%s", ret) return True except Exception: log.exception("Couldn't connect to logind") return False
def _do_create_snapshot(self, asyncjob, xml, name, mime, sndata): ignore = asyncjob self.vm.create_snapshot(xml) try: cachedir = self.vm.get_cache_dir() basesn = os.path.join(cachedir, "snap-screenshot-%s" % name) # Remove any pre-existing screenshots so we don't show stale data for ext in list(mimemap.values()): p = basesn + "." + ext if os.path.exists(basesn + "." + ext): os.unlink(p) if not mime or not sndata: return filename = basesn + "." + _mime_to_ext(mime) log.debug("Writing screenshot to %s", filename) open(filename, "wb").write(sndata) except Exception: # pragma: no cover log.exception("Error saving screenshot")
def _process_vm(self, conn, vm): # Try processing a single VM, keeping into account whether it was # visited already, and whether there are cached data for it. def _set_vm_inspection_data(_data): vm.inspection = _data vm.inspection_data_updated() self._cached_data[vm.get_uuid()] = _data prettyvm = conn.get_uri() + ":" + vm.get_name() vmuuid = vm.get_uuid() if vmuuid in self._cached_data: data = self._cached_data.get(vmuuid) if vm.inspection != data: log.debug("Found cached data for %s", prettyvm) _set_vm_inspection_data(data) return try: data = self._inspect_vm(conn, vm) except Exception as e: data = _inspection_error(_("Error inspection VM: %s") % str(e)) log.exception("%s: exception while processing", prettyvm) _set_vm_inspection_data(data)
def parse_vmdk(filename): """ Parse a VMDK descriptor file Reference: http://sanbarrow.com/vmdk-basics.html """ # Detect if passed file is a descriptor file # Assume descriptor isn't larger than 10K if not os.path.exists(filename): log.debug("VMDK file '%s' doesn't exist", filename) return if os.path.getsize(filename) > (10 * 1024): log.debug("VMDK file '%s' too big to be a descriptor", filename) return f = open(filename, "r") content = f.readlines() f.close() try: vmdkfile = _VMXFile(content) except Exception: log.exception("%s looked like a vmdk file, but parsing failed", filename) return disklines = [l for l in vmdkfile.lines if l.is_disk] if len(disklines) == 0: raise RuntimeError( _("Didn't detect a storage line in the VMDK " "descriptor file")) if len(disklines) > 1: raise RuntimeError( _("Don't know how to handle multistorage VMDK " "descriptors")) return disklines[0].parse_disk_path()
def __del__(self): try: if config.vmmConfig.is_initialized() and self._leak_check: self.config.remove_object(self.object_key) except Exception: log.exception("Error removing %s", self.object_key)
def _add_default_conn(self): """ If there's no cached connections, or any requested on the command line, try to determine a default URI and open it, first checking if libvirt is running """ manager = self._get_manager() log.debug("Trying to start libvirtd through systemd") unitname = "libvirtd.service" libvirtd_installed = False libvirtd_active = False unitpath = None # Fetch all units from systemd try: bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) systemd = Gio.DBusProxy.new_sync(bus, 0, None, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", None) units = systemd.ListUnits() log.debug("Successfully listed units via systemd") except Exception: units = [] log.exception("Couldn't connect to systemd") libvirtd_installed = os.path.exists("/var/run/libvirt") libvirtd_active = os.path.exists("/var/run/libvirt/libvirt-sock") # Check if libvirtd is installed and running for unitinfo in units: if unitinfo[0] != unitname: continue libvirtd_installed = True libvirtd_active = unitinfo[3] == "active" unitpath = unitinfo[6] break log.debug("libvirtd_installed=%s libvirtd_active=%s unitpath=%s", libvirtd_installed, libvirtd_active, unitpath) # If it's not running, try to start it try: if unitpath and libvirtd_installed and not libvirtd_active: unit = Gio.DBusProxy.new_sync( bus, 0, None, "org.freedesktop.systemd1", unitpath, "org.freedesktop.systemd1.Unit", None) if not self.config.CLITestOptions.first_run: unit.Start("(s)", "fail") time.sleep(2) libvirtd_active = True except Exception: log.exception("Error starting libvirtd") if self.config.CLITestOptions.first_run: log.debug("--test-first-run, using uri=None to trigger error") tryuri = None else: tryuri = vmmCreateConn.default_uri() log.debug("Probed default URI=%s", tryuri) # Manager fail message msg = "" if not libvirtd_installed: msg += _("The libvirtd service does not appear to be installed. " "Install and run the libvirtd service to manage " "virtualization on this host.") elif not libvirtd_active: msg += _("libvirtd is installed but not running. Start the " "libvirtd service to manage virtualization on this host.") if not tryuri or "qemu" not in tryuri: if msg: msg += "\n\n" msg += _("Could not detect a default hypervisor. Make " "sure the appropriate QEMU/KVM virtualization " "packages are installed to manage virtualization " "on this host.") if msg: msg += "\n\n" msg += _("A virtualization connection can be manually " "added via File->Add Connection") if (tryuri is None or not libvirtd_installed or not libvirtd_active): manager.set_startup_error(msg) return # Launch idle callback to connect to default URI def idle_connect(): def _open_completed(c, ConnectError): if ConnectError: self._handle_conn_error(c, ConnectError) conn = vmmConnectionManager.get_instance().add_conn(tryuri) conn.set_autoconnect(True) conn.connect_once("open-completed", _open_completed) conn.open() self.idle_add(idle_connect)
def _tick(self, stats_update=False, pollvm=False, pollnet=False, pollpool=False, pollnodedev=False, force=False, initial_poll=False): """ main update function: polls for new objects, updates stats, ... :param force: Perform the requested polling even if async events are in use. """ if self._closing: return # pragma: no cover if self.is_disconnected(): return # pragma: no cover if self.is_connecting() and not force: return # pragma: no cover # We need to set this before the event check, since stats polling # is independent of events if not pollvm: stats_update = False if self.using_domain_events and not force: pollvm = False if self.using_network_events and not force: pollnet = False if self.using_storage_pool_events and not force: pollpool = False if self.using_node_device_events and not force: pollnodedev = False self._hostinfo = self._backend.getInfo() if stats_update: self.statsmanager.cache_all_stats(self) gone_objects, preexisting_objects = self._poll( initial_poll, pollvm, pollnet, pollpool, pollnodedev) self.idle_add(self._gone_object_signals, gone_objects) # Only tick() pre-existing objects, since new objects will be # initialized asynchronously and tick() would be redundant for obj in preexisting_objects: try: if obj.reports_stats() and stats_update: pass elif obj.is_domain() and not pollvm: continue elif obj.is_network() and not pollnet: continue elif obj.is_pool() and not pollpool: continue elif obj.is_nodedev() and not pollnodedev: continue if self.config.CLITestOptions.conn_crash: self._backend.close() e = libvirt.libvirtError("fake error") e.err = [libvirt.VIR_ERR_SYSTEM_ERROR] raise e obj.tick(stats_update=stats_update) except Exception as e: log.exception("Tick for %s failed", obj) if (isinstance(e, libvirt.libvirtError) and (getattr(e, "get_error_code")() == libvirt.VIR_ERR_SYSTEM_ERROR)): # Try a simple getInfo call to see if conn was dropped self._backend.getInfo() log.debug( # pragma: no cover "vm tick raised system error but " "connection doesn't seem to have dropped. " "Ignoring.") if stats_update: self._recalculate_stats( [o for o in preexisting_objects if o.reports_stats()]) self.idle_emit("resources-sampled")
def _perform_inspection(conn, vm): # pragma: no cover """ Perform the actual guestfs interaction and return results in a vmmInspectionData object """ import guestfs # pylint: disable=import-error g = guestfs.GuestFS(close_on_exit=False, python_return_dict=True) prettyvm = conn.get_uri() + ":" + vm.get_name() try: g.add_libvirt_dom(vm.get_backend(), readonly=1) g.launch() except Exception as e: log.debug("%s: Error launching libguestfs appliance: %s", prettyvm, str(e)) return _inspection_error( _("Error launching libguestfs appliance: %s") % str(e)) log.debug("%s: inspection appliance connected", prettyvm) # Inspect the operating system. roots = g.inspect_os() if len(roots) == 0: log.debug("%s: no operating systems found", prettyvm) return _inspection_error(_("Inspection found no operating systems.")) # Arbitrarily pick the first root device. root = roots[0] # Inspection results. os_type = 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 package_format = g.inspect_get_package_format(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 # 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) mps = sorted(mps.items(), key=lambda k: len(k[0])) for mp, dev in mps: try: g.mount_ro(dev, mp) filesystems_mounted = True except Exception: log.exception("%s: exception mounting %s on %s " "(ignored)", prettyvm, dev, mp) icon = None apps = None if filesystems_mounted: # string containing PNG data icon = g.inspect_get_icon(root, favicon=0, highquality=1) if icon is None or len(icon) == 0: # no high quality icon, try a low quality one icon = g.inspect_get_icon(root, favicon=0, highquality=0) if icon is None or len(icon) == 0: icon = None # Inspection applications. try: gapps = g.inspect_list_applications2(root) # applications listing worked, so make apps a real list # (instead of None) apps = [] for gapp in gapps: app = vmmInspectionApplication() if gapp["app2_name"]: app.name = gapp["app2_name"] if gapp["app2_display_name"]: app.display_name = gapp["app2_display_name"] app.epoch = gapp["app2_epoch"] if gapp["app2_version"]: app.version = gapp["app2_version"] if gapp["app2_release"]: app.release = gapp["app2_release"] if gapp["app2_summary"]: app.summary = gapp["app2_summary"] if gapp["app2_description"]: app.description = gapp["app2_description"] apps.append(app) except Exception: log.exception("%s: exception while listing apps (ignored)", prettyvm) # Force the libguestfs handle to close right now. del g # Log what we found. log.debug("%s: detected operating system: %s %s %d.%d (%s) (%s)", prettyvm, os_type, distro, major_version, minor_version, product_name, package_format) log.debug("hostname: %s", hostname) if icon: log.debug("icon: %d bytes", len(icon)) if apps: log.debug("# apps: %d", len(apps)) data = vmmInspectionData() data.os_type = str(os_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 or []) data.package_format = str(package_format) return data
def check_all_storage(self): """ Determine which storage is cloneable, and which isn't """ diskinfos = self.vm.xmlobj.devices.disk cd = self.clone_design storage_list = {} # We need to determine which disks fail (and why). all_targets = [d.target for d in diskinfos] for disk in diskinfos: force_target = disk.target path = disk.path ro = disk.read_only shared = disk.shareable devtype = disk.device size = None clone_path = None failinfo = "" definfo = "" storage_row = [] storage_row.insert(STORAGE_INFO_ORIG_PATH, path or "-") storage_row.insert(STORAGE_INFO_NEW_PATH, clone_path) storage_row.insert(STORAGE_INFO_TARGET, force_target) storage_row.insert(STORAGE_INFO_SIZE, size) storage_row.insert(STORAGE_INFO_DEVTYPE, devtype) storage_row.insert(STORAGE_INFO_DO_CLONE, False) storage_row.insert(STORAGE_INFO_CAN_CLONE, False) storage_row.insert(STORAGE_INFO_CAN_SHARE, False) storage_row.insert(STORAGE_INFO_DO_DEFAULT, False) storage_row.insert(STORAGE_INFO_DEFINFO, definfo) storage_row.insert(STORAGE_INFO_FAILINFO, failinfo) storage_row.insert(STORAGE_INFO_COMBO, None) storage_row.insert(STORAGE_INFO_MANUAL_PATH, False) skip_targets = all_targets[:] skip_targets.remove(force_target) vol = self.conn.get_vol_by_path(path) default, definfo, can_default = do_we_default( self.conn, vol, path, ro, shared, devtype) def storage_add(failinfo=None): # pylint: disable=cell-var-from-loop storage_row[STORAGE_INFO_DEFINFO] = definfo storage_row[STORAGE_INFO_DO_DEFAULT] = default storage_row[STORAGE_INFO_CAN_SHARE] = bool(definfo) if failinfo: storage_row[STORAGE_INFO_FAILINFO] = failinfo storage_row[STORAGE_INFO_DO_CLONE] = False storage_list[force_target] = storage_row # If origdisk is empty, deliberately make it fail if not path: storage_add(_("Nothing to clone.")) continue try: cd.skip_target = skip_targets cd.setup_original() except Exception as e: log.exception("Disk target '%s' caused clone error", force_target) storage_add(str(e)) continue can_clone, cloneinfo = can_we_clone(self.conn, vol, path) if not can_clone: storage_add(cloneinfo) continue storage_row[STORAGE_INFO_CAN_CLONE] = True # If we cannot create default clone_path don't even try to do that if not can_default: storage_add() continue try: # Generate disk path, make sure that works clone_path = self.generate_clone_path_name(path) log.debug("Original path: %s\nGenerated clone path: %s", path, clone_path) cd.clone_paths = clone_path size = cd.original_disks[0].get_size() except Exception as e: log.exception("Error setting generated path '%s'", clone_path) storage_add(str(e)) storage_row[STORAGE_INFO_NEW_PATH] = clone_path storage_row[STORAGE_INFO_SIZE] = self.pretty_storage(size) storage_add() return storage_list, all_targets