Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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")
Ejemplo n.º 6
0
    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))
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
    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")
Ejemplo n.º 10
0
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)
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
    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")
Ejemplo n.º 13
0
    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)
Ejemplo n.º 14
0
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()
Ejemplo n.º 15
0
 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)
Ejemplo n.º 16
0
    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)
Ejemplo n.º 17
0
    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")
Ejemplo n.º 18
0
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
Ejemplo n.º 19
0
    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