mirror of
https://github.com/virt-manager/virt-manager.git
synced 2026-07-29 15:55:32 -05:00
uihelpers: Move a few more functions closer to their callers
This commit is contained in:
+19
-2
@@ -18,6 +18,7 @@
|
|||||||
# MA 02110-1301 USA.
|
# MA 02110-1301 USA.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
@@ -28,7 +29,6 @@ from gi.repository import Gtk
|
|||||||
# pylint: enable=E0611
|
# pylint: enable=E0611
|
||||||
|
|
||||||
from virtManager.baseclass import vmmGObjectUI
|
from virtManager.baseclass import vmmGObjectUI
|
||||||
from virtManager import uihelpers
|
|
||||||
|
|
||||||
HV_XEN = 0
|
HV_XEN = 0
|
||||||
HV_QEMU = 1
|
HV_QEMU = 1
|
||||||
@@ -99,6 +99,23 @@ class vmmConnect(vmmGObjectUI):
|
|||||||
|
|
||||||
self.reset_state()
|
self.reset_state()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default_uri(always_system=False):
|
||||||
|
if os.path.exists('/var/lib/xen'):
|
||||||
|
if (os.path.exists('/dev/xen/evtchn') or
|
||||||
|
os.path.exists("/proc/xen")):
|
||||||
|
return 'xen:///'
|
||||||
|
|
||||||
|
if (os.path.exists("/usr/bin/qemu") or
|
||||||
|
os.path.exists("/usr/bin/qemu-kvm") or
|
||||||
|
os.path.exists("/usr/bin/kvm") or
|
||||||
|
os.path.exists("/usr/libexec/qemu-kvm")):
|
||||||
|
if always_system or os.geteuid() == 0:
|
||||||
|
return "qemu:///system"
|
||||||
|
else:
|
||||||
|
return "qemu:///session"
|
||||||
|
return None
|
||||||
|
|
||||||
def cancel(self, ignore1=None, ignore2=None):
|
def cancel(self, ignore1=None, ignore2=None):
|
||||||
logging.debug("Cancelling open connection")
|
logging.debug("Cancelling open connection")
|
||||||
self.close()
|
self.close()
|
||||||
@@ -148,7 +165,7 @@ class vmmConnect(vmmGObjectUI):
|
|||||||
return self.widget("connect-remote").get_active()
|
return self.widget("connect-remote").get_active()
|
||||||
|
|
||||||
def set_default_hypervisor(self):
|
def set_default_hypervisor(self):
|
||||||
default = uihelpers.default_uri(always_system=True)
|
default = self.default_uri(always_system=True)
|
||||||
if not default or default.startswith("qemu"):
|
if not default or default.startswith("qemu"):
|
||||||
self.widget("hypervisor").set_active(1)
|
self.widget("hypervisor").set_active(1)
|
||||||
elif default.startswith("xen"):
|
elif default.startswith("xen"):
|
||||||
|
|||||||
@@ -129,6 +129,33 @@ class vmmConnection(vmmGObject):
|
|||||||
self._init_virtconn()
|
self._init_virtconn()
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def pretty_hv(gtype, domtype):
|
||||||
|
"""
|
||||||
|
Convert XML <domain type='foo'> and <os><type>bar</type>
|
||||||
|
into a more human relevant string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
gtype = gtype.lower()
|
||||||
|
domtype = domtype.lower()
|
||||||
|
|
||||||
|
label = domtype
|
||||||
|
if domtype == "kvm":
|
||||||
|
if gtype == "xen":
|
||||||
|
label = "xenner"
|
||||||
|
elif domtype == "xen":
|
||||||
|
if gtype == "xen":
|
||||||
|
label = "xen (paravirt)"
|
||||||
|
elif gtype == "hvm":
|
||||||
|
label = "xen (fullvirt)"
|
||||||
|
elif domtype == "test":
|
||||||
|
if gtype == "xen":
|
||||||
|
label = "test (xen)"
|
||||||
|
elif gtype == "hvm":
|
||||||
|
label = "test (hvm)"
|
||||||
|
|
||||||
|
return label
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# Init routines #
|
# Init routines #
|
||||||
#################
|
#################
|
||||||
@@ -713,6 +740,8 @@ class vmmConnection(vmmGObject):
|
|||||||
if p.get_name() == name:
|
if p.get_name() == name:
|
||||||
return p
|
return p
|
||||||
return None
|
return None
|
||||||
|
def get_default_pool(self):
|
||||||
|
return self.get_pool_by_name("default")
|
||||||
|
|
||||||
def get_vol_by_path(self, path):
|
def get_vol_by_path(self, path):
|
||||||
for pool in self.pools.values():
|
for pool in self.pools.values():
|
||||||
|
|||||||
@@ -679,7 +679,7 @@ class vmmCreate(vmmGObjectUI):
|
|||||||
continue
|
continue
|
||||||
dom = guest.domains[0]
|
dom = guest.domains[0]
|
||||||
domtype = dom.hypervisor_type
|
domtype = dom.hypervisor_type
|
||||||
label = uihelpers.pretty_hv(gtype, domtype)
|
label = self.conn.pretty_hv(gtype, domtype)
|
||||||
|
|
||||||
# Don't add multiple rows for each arch
|
# Don't add multiple rows for each arch
|
||||||
for m in model:
|
for m in model:
|
||||||
|
|||||||
@@ -165,6 +165,18 @@ class vmmCreateInterface(vmmGObjectUI):
|
|||||||
# Initialization routines #
|
# Initialization routines #
|
||||||
###########################
|
###########################
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def iface_in_use_by(conn, name):
|
||||||
|
use_str = ""
|
||||||
|
for i in conn.list_interface_names():
|
||||||
|
iface = conn.get_interface(i)
|
||||||
|
if name in iface.get_slave_names():
|
||||||
|
if use_str:
|
||||||
|
use_str += ", "
|
||||||
|
use_str += iface.get_name()
|
||||||
|
|
||||||
|
return use_str
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def build_interface_startmode_combo(combo):
|
def build_interface_startmode_combo(combo):
|
||||||
model = Gtk.ListStore(str)
|
model = Gtk.ListStore(str)
|
||||||
@@ -558,8 +570,8 @@ class vmmCreateInterface(vmmGObjectUI):
|
|||||||
|
|
||||||
for row in row_dict.values():
|
for row in row_dict.values():
|
||||||
name = row[INTERFACE_ROW_NAME]
|
name = row[INTERFACE_ROW_NAME]
|
||||||
row[INTERFACE_ROW_IN_USE_BY] = uihelpers.iface_in_use_by(self.conn,
|
row[INTERFACE_ROW_IN_USE_BY] = self.iface_in_use_by(self.conn,
|
||||||
name)
|
name)
|
||||||
|
|
||||||
for row in row_dict.values():
|
for row in row_dict.values():
|
||||||
model.append(row)
|
model.append(row)
|
||||||
|
|||||||
@@ -150,10 +150,10 @@ class vmmDeleteDialog(vmmGObjectUI):
|
|||||||
title = _("Are you sure you want to delete the storage?")
|
title = _("Are you sure you want to delete the storage?")
|
||||||
message = (_("The following paths will be deleted:\n\n%s") %
|
message = (_("The following paths will be deleted:\n\n%s") %
|
||||||
"\n".join(devs))
|
"\n".join(devs))
|
||||||
ret = uihelpers.chkbox_helper(self,
|
ret = self.err.chkbox_helper(
|
||||||
self.config.get_confirm_delstorage,
|
self.config.get_confirm_delstorage,
|
||||||
self.config.set_confirm_delstorage,
|
self.config.set_confirm_delstorage,
|
||||||
text1=title, text2=message)
|
text1=title, text2=message)
|
||||||
if not ret:
|
if not ret:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -1100,7 +1100,7 @@ class vmmDetails(vmmGObjectUI):
|
|||||||
if not self.widget("config-apply").get_sensitive():
|
if not self.widget("config-apply").get_sensitive():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not uihelpers.chkbox_helper(self,
|
if not self.err.chkbox_helper(
|
||||||
self.config.get_confirm_unapplied,
|
self.config.get_confirm_unapplied,
|
||||||
self.config.set_confirm_unapplied,
|
self.config.set_confirm_unapplied,
|
||||||
text1=(_("There are unapplied changes. Would you like to apply "
|
text1=(_("There are unapplied changes. Would you like to apply "
|
||||||
@@ -2243,7 +2243,7 @@ class vmmDetails(vmmGObjectUI):
|
|||||||
def remove_device(self, dev_type, dev_id_info):
|
def remove_device(self, dev_type, dev_id_info):
|
||||||
logging.debug("Removing device: %s %s", dev_type, dev_id_info)
|
logging.debug("Removing device: %s %s", dev_type, dev_id_info)
|
||||||
|
|
||||||
if not uihelpers.chkbox_helper(self, self.config.get_confirm_removedev,
|
if not self.err.chkbox_helper(self.config.get_confirm_removedev,
|
||||||
self.config.set_confirm_removedev,
|
self.config.set_confirm_removedev,
|
||||||
text1=(_("Are you sure you want to remove this device?"))):
|
text1=(_("Are you sure you want to remove this device?"))):
|
||||||
return
|
return
|
||||||
@@ -2360,7 +2360,7 @@ class vmmDetails(vmmGObjectUI):
|
|||||||
if self.is_visible():
|
if self.is_visible():
|
||||||
self.vm.refresh_xml()
|
self.vm.refresh_xml()
|
||||||
except libvirt.libvirtError, e:
|
except libvirt.libvirtError, e:
|
||||||
if uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
|
if util.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
|
||||||
self.close()
|
self.close()
|
||||||
return
|
return
|
||||||
raise
|
raise
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ from virtinst import Guest
|
|||||||
from virtinst import util
|
from virtinst import util
|
||||||
from virtinst import VirtualController
|
from virtinst import VirtualController
|
||||||
|
|
||||||
from virtManager import uihelpers
|
|
||||||
from virtManager.libvirtobject import vmmLibvirtObject
|
from virtManager.libvirtobject import vmmLibvirtObject
|
||||||
|
|
||||||
|
|
||||||
@@ -1011,7 +1010,7 @@ class vmmDomain(vmmLibvirtObject):
|
|||||||
def get_hv_type(self):
|
def get_hv_type(self):
|
||||||
return self.get_xmlobj().type
|
return self.get_xmlobj().type
|
||||||
def get_pretty_hv_type(self):
|
def get_pretty_hv_type(self):
|
||||||
return uihelpers.pretty_hv(self.get_abi_type(), self.get_hv_type())
|
return self.conn.pretty_hv(self.get_abi_type(), self.get_hv_type())
|
||||||
def get_arch(self):
|
def get_arch(self):
|
||||||
return self.get_xmlobj().os.arch
|
return self.get_xmlobj().os.arch
|
||||||
def get_init(self):
|
def get_init(self):
|
||||||
@@ -1274,7 +1273,7 @@ class vmmDomain(vmmLibvirtObject):
|
|||||||
try:
|
try:
|
||||||
return self._backend.hasManagedSaveImage(0)
|
return self._backend.hasManagedSaveImage(0)
|
||||||
except libvirt.libvirtError, e:
|
except libvirt.libvirtError, e:
|
||||||
if not uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
|
if not util.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
|
||||||
raise
|
raise
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -1573,7 +1572,7 @@ class vmmDomain(vmmLibvirtObject):
|
|||||||
info = self._backend.info()
|
info = self._backend.info()
|
||||||
self._update_status(info[0])
|
self._update_status(info[0])
|
||||||
except libvirt.libvirtError, e:
|
except libvirt.libvirtError, e:
|
||||||
if uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
|
if util.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
|
||||||
return
|
return
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ class vmmEngine(vmmGObject):
|
|||||||
if ret:
|
if ret:
|
||||||
tryuri = "qemu:///system"
|
tryuri = "qemu:///system"
|
||||||
else:
|
else:
|
||||||
tryuri = uihelpers.default_uri(always_system=True)
|
tryuri = vmmConnect.default_uri(always_system=True)
|
||||||
|
|
||||||
if tryuri is None:
|
if tryuri is None:
|
||||||
manager.set_startup_error(msg)
|
manager.set_startup_error(msg)
|
||||||
@@ -901,7 +901,7 @@ class vmmEngine(vmmGObject):
|
|||||||
"libvirt version or hypervisor."))
|
"libvirt version or hypervisor."))
|
||||||
return
|
return
|
||||||
|
|
||||||
if not uihelpers.chkbox_helper(src, self.config.get_confirm_poweroff,
|
if not src.err.chkbox_helper(self.config.get_confirm_poweroff,
|
||||||
self.config.set_confirm_poweroff,
|
self.config.set_confirm_poweroff,
|
||||||
text1=_("Are you sure you want to save '%s'?" % vm.get_name())):
|
text1=_("Are you sure you want to save '%s'?" % vm.get_name())):
|
||||||
return
|
return
|
||||||
@@ -971,7 +971,7 @@ class vmmEngine(vmmGObject):
|
|||||||
conn = self._lookup_conn(uri)
|
conn = self._lookup_conn(uri)
|
||||||
vm = conn.get_vm(uuid)
|
vm = conn.get_vm(uuid)
|
||||||
|
|
||||||
if not uihelpers.chkbox_helper(src,
|
if not src.err.chkbox_helper(
|
||||||
self.config.get_confirm_forcepoweroff,
|
self.config.get_confirm_forcepoweroff,
|
||||||
self.config.set_confirm_forcepoweroff,
|
self.config.set_confirm_forcepoweroff,
|
||||||
text1=_("Are you sure you want to force poweroff '%s'?" %
|
text1=_("Are you sure you want to force poweroff '%s'?" %
|
||||||
@@ -988,7 +988,7 @@ class vmmEngine(vmmGObject):
|
|||||||
conn = self._lookup_conn(uri)
|
conn = self._lookup_conn(uri)
|
||||||
vm = conn.get_vm(uuid)
|
vm = conn.get_vm(uuid)
|
||||||
|
|
||||||
if not uihelpers.chkbox_helper(src, self.config.get_confirm_pause,
|
if not src.err.chkbox_helper(self.config.get_confirm_pause,
|
||||||
self.config.set_confirm_pause,
|
self.config.set_confirm_pause,
|
||||||
text1=_("Are you sure you want to pause '%s'?" %
|
text1=_("Are you sure you want to pause '%s'?" %
|
||||||
vm.get_name())):
|
vm.get_name())):
|
||||||
@@ -1051,7 +1051,7 @@ class vmmEngine(vmmGObject):
|
|||||||
conn = self._lookup_conn(uri)
|
conn = self._lookup_conn(uri)
|
||||||
vm = conn.get_vm(uuid)
|
vm = conn.get_vm(uuid)
|
||||||
|
|
||||||
if not uihelpers.chkbox_helper(src, self.config.get_confirm_poweroff,
|
if not src.err.chkbox_helper(self.config.get_confirm_poweroff,
|
||||||
self.config.set_confirm_poweroff,
|
self.config.set_confirm_poweroff,
|
||||||
text1=_("Are you sure you want to poweroff '%s'?" %
|
text1=_("Are you sure you want to poweroff '%s'?" %
|
||||||
vm.get_name())):
|
vm.get_name())):
|
||||||
@@ -1065,7 +1065,7 @@ class vmmEngine(vmmGObject):
|
|||||||
conn = self._lookup_conn(uri)
|
conn = self._lookup_conn(uri)
|
||||||
vm = conn.get_vm(uuid)
|
vm = conn.get_vm(uuid)
|
||||||
|
|
||||||
if not uihelpers.chkbox_helper(src, self.config.get_confirm_poweroff,
|
if not src.err.chkbox_helper(self.config.get_confirm_poweroff,
|
||||||
self.config.set_confirm_poweroff,
|
self.config.set_confirm_poweroff,
|
||||||
text1=_("Are you sure you want to reboot '%s'?" %
|
text1=_("Are you sure you want to reboot '%s'?" %
|
||||||
vm.get_name())):
|
vm.get_name())):
|
||||||
@@ -1104,7 +1104,7 @@ class vmmEngine(vmmGObject):
|
|||||||
conn = self._lookup_conn(uri)
|
conn = self._lookup_conn(uri)
|
||||||
vm = conn.get_vm(uuid)
|
vm = conn.get_vm(uuid)
|
||||||
|
|
||||||
if not uihelpers.chkbox_helper(src,
|
if not src.err.chkbox_helper(
|
||||||
self.config.get_confirm_forcepoweroff,
|
self.config.get_confirm_forcepoweroff,
|
||||||
self.config.set_confirm_forcepoweroff,
|
self.config.set_confirm_forcepoweroff,
|
||||||
text1=_("Are you sure you want to force reset '%s'?" %
|
text1=_("Are you sure you want to force reset '%s'?" %
|
||||||
|
|||||||
@@ -179,6 +179,30 @@ class vmmErrorDialog(vmmGObject):
|
|||||||
secondary_text=text2,
|
secondary_text=text2,
|
||||||
chktext=chktext)
|
chktext=chktext)
|
||||||
|
|
||||||
|
def chkbox_helper(self, getcb, setcb, text1, text2=None,
|
||||||
|
alwaysrecord=False,
|
||||||
|
default=True,
|
||||||
|
chktext=_("Don't ask me again")):
|
||||||
|
"""
|
||||||
|
Helper to prompt user about proceeding with an operation
|
||||||
|
Returns True if the 'yes' or 'ok' button was selected, False otherwise
|
||||||
|
|
||||||
|
@alwaysrecord: Don't require user to select 'yes' to record chkbox value
|
||||||
|
@default: What value to return if getcb tells us not to prompt
|
||||||
|
"""
|
||||||
|
do_prompt = getcb()
|
||||||
|
if not do_prompt:
|
||||||
|
return default
|
||||||
|
|
||||||
|
res = self.warn_chkbox(text1=text1, text2=text2,
|
||||||
|
chktext=chktext,
|
||||||
|
buttons=Gtk.ButtonsType.YES_NO)
|
||||||
|
response, skip_prompt = res
|
||||||
|
if alwaysrecord or response:
|
||||||
|
setcb(not skip_prompt)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
class _errorDialog (Gtk.MessageDialog):
|
class _errorDialog (Gtk.MessageDialog):
|
||||||
"""
|
"""
|
||||||
|
|||||||
+3
-3
@@ -1003,7 +1003,7 @@ class vmmHost(vmmGObjectUI):
|
|||||||
if interface is None:
|
if interface is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not uihelpers.chkbox_helper(self, self.config.get_confirm_interface,
|
if not self.err.chkbox_helper(self.config.get_confirm_interface,
|
||||||
self.config.set_confirm_interface,
|
self.config.set_confirm_interface,
|
||||||
text1=_("Are you sure you want to stop the interface "
|
text1=_("Are you sure you want to stop the interface "
|
||||||
"'%s'?" % interface.get_name())):
|
"'%s'?" % interface.get_name())):
|
||||||
@@ -1018,7 +1018,7 @@ class vmmHost(vmmGObjectUI):
|
|||||||
if interface is None:
|
if interface is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not uihelpers.chkbox_helper(self, self.config.get_confirm_interface,
|
if not self.err.chkbox_helper(self.config.get_confirm_interface,
|
||||||
self.config.set_confirm_interface,
|
self.config.set_confirm_interface,
|
||||||
text1=_("Are you sure you want to start the interface "
|
text1=_("Are you sure you want to start the interface "
|
||||||
"'%s'?" % interface.get_name())):
|
"'%s'?" % interface.get_name())):
|
||||||
@@ -1160,7 +1160,7 @@ class vmmHost(vmmGObjectUI):
|
|||||||
# This can fail if other interfaces are busted, so ignore errors
|
# This can fail if other interfaces are busted, so ignore errors
|
||||||
used_by = None
|
used_by = None
|
||||||
try:
|
try:
|
||||||
used_by = uihelpers.iface_in_use_by(self.conn, name)
|
used_by = vmmCreateInterface.iface_in_use_by(self.conn, name)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
logging.debug("Error looking up iface usage: %s", e)
|
logging.debug("Error looking up iface usage: %s", e)
|
||||||
self.widget("interface-inuseby").set_text(used_by or "-")
|
self.widget("interface-inuseby").set_text(used_by or "-")
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ from gi.repository import GObject
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from virtManager import uihelpers
|
|
||||||
from virtManager.baseclass import vmmGObject
|
from virtManager.baseclass import vmmGObject
|
||||||
|
|
||||||
|
|
||||||
@@ -54,6 +53,21 @@ class vmmLibvirtObject(vmmGObject):
|
|||||||
|
|
||||||
self.connect("config-changed", self._reparse_xml)
|
self.connect("config-changed", self._reparse_xml)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def log_redefine_xml_diff(obj, origxml, newxml):
|
||||||
|
objname = "<%s name=%s>" % (obj.__class__.__name__, obj.get_name())
|
||||||
|
if origxml == newxml:
|
||||||
|
logging.debug("Redefine requested for %s, but XML didn't change!",
|
||||||
|
objname)
|
||||||
|
return
|
||||||
|
|
||||||
|
import difflib
|
||||||
|
diff = "".join(difflib.unified_diff(origxml.splitlines(1),
|
||||||
|
newxml.splitlines(1),
|
||||||
|
fromfile="Original XML",
|
||||||
|
tofile="New XML"))
|
||||||
|
logging.debug("Redefining %s with XML diff:\n%s", objname, diff)
|
||||||
|
|
||||||
def _cleanup(self):
|
def _cleanup(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -205,7 +219,7 @@ class vmmLibvirtObject(vmmGObject):
|
|||||||
return self._xmlobj_to_define
|
return self._xmlobj_to_define
|
||||||
|
|
||||||
def _redefine_helper(self, origxml, newxml):
|
def _redefine_helper(self, origxml, newxml):
|
||||||
uihelpers.log_redefine_xml_diff(self, origxml, newxml)
|
self.log_redefine_xml_diff(self, origxml, newxml)
|
||||||
|
|
||||||
if origxml != newxml:
|
if origxml != newxml:
|
||||||
self._define(newxml)
|
self._define(newxml)
|
||||||
|
|||||||
@@ -790,7 +790,7 @@ class vmmManager(vmmGObjectUI):
|
|||||||
desc = desc or ""
|
desc = desc or ""
|
||||||
row[ROW_HINT] = util.xml_escape(desc)
|
row[ROW_HINT] = util.xml_escape(desc)
|
||||||
except libvirt.libvirtError, e:
|
except libvirt.libvirtError, e:
|
||||||
if uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
|
if util.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
|
||||||
return
|
return
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ class vmmSnapshotPage(vmmGObjectUI):
|
|||||||
xmlobj.description = desc
|
xmlobj.description = desc
|
||||||
newxml = xmlobj.get_xml_config()
|
newxml = xmlobj.get_xml_config()
|
||||||
|
|
||||||
uihelpers.log_redefine_xml_diff(snap, origxml, newxml)
|
self.vm.log_redefine_xml_diff(snap, origxml, newxml)
|
||||||
if newxml == origxml:
|
if newxml == origxml:
|
||||||
return
|
return
|
||||||
self.vm.create_snapshot(newxml, redefine=True)
|
self.vm.create_snapshot(newxml, redefine=True)
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ class vmmStorageBrowser(vmmGObjectUI):
|
|||||||
|
|
||||||
if not self._first_run:
|
if not self._first_run:
|
||||||
self._first_run = True
|
self._first_run = True
|
||||||
pool = uihelpers.get_default_pool(self.conn)
|
pool = self.conn.get_default_pool()
|
||||||
uihelpers.set_row_selection(
|
uihelpers.set_row_selection(
|
||||||
self.widget("pool-list"), pool and pool.get_uuid() or None)
|
self.widget("pool-list"), pool and pool.get_uuid() or None)
|
||||||
# Manually trigger vol_selected, so buttons are in the correct state
|
# Manually trigger vol_selected, so buttons are in the correct state
|
||||||
|
|||||||
+127
-244
@@ -28,8 +28,6 @@ from gi.repository import GObject
|
|||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
# pylint: enable=E0611
|
# pylint: enable=E0611
|
||||||
|
|
||||||
import libvirt
|
|
||||||
|
|
||||||
import virtinst
|
import virtinst
|
||||||
from virtManager import config
|
from virtManager import config
|
||||||
|
|
||||||
@@ -63,9 +61,16 @@ def set_sparse_tooltip(widget):
|
|||||||
widget.set_tooltip_text(sparse_str)
|
widget.set_tooltip_text(sparse_str)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_default_dir(conn):
|
||||||
|
pool = conn.get_default_pool()
|
||||||
|
if pool:
|
||||||
|
return pool.get_target_path()
|
||||||
|
return config.running_config.get_default_image_dir(conn)
|
||||||
|
|
||||||
|
|
||||||
def host_disk_space(conn):
|
def host_disk_space(conn):
|
||||||
pool = get_default_pool(conn)
|
pool = conn.get_default_pool()
|
||||||
path = get_default_dir(conn)
|
path = _get_default_dir(conn)
|
||||||
|
|
||||||
avail = 0
|
avail = 0
|
||||||
if pool and pool.is_active():
|
if pool and pool.is_active():
|
||||||
@@ -98,7 +103,7 @@ def update_host_space(conn, widget):
|
|||||||
|
|
||||||
|
|
||||||
def check_default_pool_active(err, conn):
|
def check_default_pool_active(err, conn):
|
||||||
default_pool = get_default_pool(conn)
|
default_pool = conn.get_default_pool()
|
||||||
if default_pool and not default_pool.is_active():
|
if default_pool and not default_pool.is_active():
|
||||||
res = err.yes_no(_("Default pool is not active."),
|
res = err.yes_no(_("Default pool is not active."),
|
||||||
_("Storage pool '%s' is not active. "
|
_("Storage pool '%s' is not active. "
|
||||||
@@ -118,6 +123,121 @@ def check_default_pool_active(err, conn):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _get_ideal_path_info(conn, name):
|
||||||
|
path = _get_default_dir(conn)
|
||||||
|
suffix = ".img"
|
||||||
|
return (path, name, suffix)
|
||||||
|
|
||||||
|
|
||||||
|
def get_ideal_path(conn, name):
|
||||||
|
target, name, suffix = _get_ideal_path_info(conn, name)
|
||||||
|
return os.path.join(target, name) + suffix
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_path(conn, name, collidelist=None):
|
||||||
|
collidelist = collidelist or []
|
||||||
|
pool = conn.get_default_pool()
|
||||||
|
|
||||||
|
default_dir = _get_default_dir(conn)
|
||||||
|
|
||||||
|
def path_exists(p):
|
||||||
|
return os.path.exists(p) or p in collidelist
|
||||||
|
|
||||||
|
if not pool:
|
||||||
|
# Use old generating method
|
||||||
|
origf = os.path.join(default_dir, name + ".img")
|
||||||
|
f = origf
|
||||||
|
|
||||||
|
n = 1
|
||||||
|
while path_exists(f) and n < 100:
|
||||||
|
f = os.path.join(default_dir, name +
|
||||||
|
"-" + str(n) + ".img")
|
||||||
|
n += 1
|
||||||
|
|
||||||
|
if path_exists(f):
|
||||||
|
f = origf
|
||||||
|
|
||||||
|
path = f
|
||||||
|
else:
|
||||||
|
target, ignore, suffix = _get_ideal_path_info(conn, name)
|
||||||
|
|
||||||
|
# Sanitize collidelist to work with the collision checker
|
||||||
|
newcollidelist = []
|
||||||
|
for c in collidelist:
|
||||||
|
if c and os.path.dirname(c) == pool.get_target_path():
|
||||||
|
newcollidelist.append(os.path.basename(c))
|
||||||
|
|
||||||
|
path = virtinst.StorageVolume.find_free_name(
|
||||||
|
pool.get_backend(), name,
|
||||||
|
suffix=suffix, collidelist=newcollidelist)
|
||||||
|
|
||||||
|
path = os.path.join(target, path)
|
||||||
|
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def check_path_search_for_qemu(err, conn, path):
|
||||||
|
if conn.is_remote() or not conn.is_qemu_system():
|
||||||
|
return
|
||||||
|
|
||||||
|
user = config.running_config.default_qemu_user
|
||||||
|
|
||||||
|
for i in conn.caps.host.secmodels:
|
||||||
|
if i.model == "dac":
|
||||||
|
label = i.baselabels.get("kvm") or i.baselabels.get("qemu")
|
||||||
|
if not label:
|
||||||
|
continue
|
||||||
|
pwuid = pwd.getpwuid(int(label.split(":")[0].replace("+", "")))
|
||||||
|
if pwuid:
|
||||||
|
user = pwuid[0]
|
||||||
|
|
||||||
|
skip_paths = config.running_config.get_perms_fix_ignore()
|
||||||
|
broken_paths = virtinst.VirtualDisk.check_path_search_for_user(
|
||||||
|
conn.get_backend(),
|
||||||
|
path, user)
|
||||||
|
for p in broken_paths:
|
||||||
|
if p in skip_paths:
|
||||||
|
broken_paths.remove(p)
|
||||||
|
|
||||||
|
if not broken_paths:
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.debug("No search access for dirs: %s", broken_paths)
|
||||||
|
resp, chkres = err.warn_chkbox(
|
||||||
|
_("The emulator may not have search permissions "
|
||||||
|
"for the path '%s'.") % path,
|
||||||
|
_("Do you want to correct this now?"),
|
||||||
|
_("Don't ask about these directories again."),
|
||||||
|
buttons=Gtk.ButtonsType.YES_NO)
|
||||||
|
|
||||||
|
if chkres:
|
||||||
|
config.running_config.add_perms_fix_ignore(broken_paths)
|
||||||
|
if not resp:
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.debug("Attempting to correct permission issues.")
|
||||||
|
errors = virtinst.VirtualDisk.fix_path_search_for_user(conn.get_backend(),
|
||||||
|
path, user)
|
||||||
|
if not errors:
|
||||||
|
return
|
||||||
|
|
||||||
|
errmsg = _("Errors were encountered changing permissions for the "
|
||||||
|
"following directories:")
|
||||||
|
details = ""
|
||||||
|
for path, error in errors.items():
|
||||||
|
if path not in broken_paths:
|
||||||
|
continue
|
||||||
|
details += "%s : %s\n" % (path, error)
|
||||||
|
|
||||||
|
logging.debug("Permission errors:\n%s", details)
|
||||||
|
|
||||||
|
ignore, chkres = err.err_chkbox(errmsg, details,
|
||||||
|
_("Don't ask about these directories again."))
|
||||||
|
|
||||||
|
if chkres:
|
||||||
|
config.running_config.add_perms_fix_ignore(errors.keys())
|
||||||
|
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
# VM <interface> device listing helpers #
|
# VM <interface> device listing helpers #
|
||||||
#########################################
|
#########################################
|
||||||
@@ -678,70 +798,6 @@ class VMActionMenu(_VMMenu):
|
|||||||
child.get_child().set_label(text)
|
child.get_child().set_label(text)
|
||||||
|
|
||||||
|
|
||||||
#####################################
|
|
||||||
# Path permissions checker for qemu #
|
|
||||||
#####################################
|
|
||||||
|
|
||||||
def check_path_search_for_qemu(err, conn, path):
|
|
||||||
if conn.is_remote() or not conn.is_qemu_system():
|
|
||||||
return
|
|
||||||
|
|
||||||
user = config.running_config.default_qemu_user
|
|
||||||
|
|
||||||
for i in conn.caps.host.secmodels:
|
|
||||||
if i.model == "dac":
|
|
||||||
label = i.baselabels.get("kvm") or i.baselabels.get("qemu")
|
|
||||||
if not label:
|
|
||||||
continue
|
|
||||||
pwuid = pwd.getpwuid(int(label.split(":")[0].replace("+", "")))
|
|
||||||
if pwuid:
|
|
||||||
user = pwuid[0]
|
|
||||||
|
|
||||||
skip_paths = config.running_config.get_perms_fix_ignore()
|
|
||||||
broken_paths = virtinst.VirtualDisk.check_path_search_for_user(
|
|
||||||
conn.get_backend(),
|
|
||||||
path, user)
|
|
||||||
for p in broken_paths:
|
|
||||||
if p in skip_paths:
|
|
||||||
broken_paths.remove(p)
|
|
||||||
|
|
||||||
if not broken_paths:
|
|
||||||
return
|
|
||||||
|
|
||||||
logging.debug("No search access for dirs: %s", broken_paths)
|
|
||||||
resp, chkres = err.warn_chkbox(
|
|
||||||
_("The emulator may not have search permissions "
|
|
||||||
"for the path '%s'.") % path,
|
|
||||||
_("Do you want to correct this now?"),
|
|
||||||
_("Don't ask about these directories again."),
|
|
||||||
buttons=Gtk.ButtonsType.YES_NO)
|
|
||||||
|
|
||||||
if chkres:
|
|
||||||
config.running_config.add_perms_fix_ignore(broken_paths)
|
|
||||||
if not resp:
|
|
||||||
return
|
|
||||||
|
|
||||||
logging.debug("Attempting to correct permission issues.")
|
|
||||||
errors = virtinst.VirtualDisk.fix_path_search_for_user(conn.get_backend(),
|
|
||||||
path, user)
|
|
||||||
if not errors:
|
|
||||||
return
|
|
||||||
|
|
||||||
errmsg = _("Errors were encountered changing permissions for the "
|
|
||||||
"following directories:")
|
|
||||||
details = ""
|
|
||||||
for path, error in errors.items():
|
|
||||||
if path not in broken_paths:
|
|
||||||
continue
|
|
||||||
details += "%s : %s\n" % (path, error)
|
|
||||||
|
|
||||||
logging.debug("Permission errors:\n%s", details)
|
|
||||||
|
|
||||||
ignore, chkres = err.err_chkbox(errmsg, details,
|
|
||||||
_("Don't ask about these directories again."))
|
|
||||||
|
|
||||||
if chkres:
|
|
||||||
config.running_config.add_perms_fix_ignore(errors.keys())
|
|
||||||
|
|
||||||
|
|
||||||
################
|
################
|
||||||
@@ -762,83 +818,11 @@ def spin_get_helper(widget):
|
|||||||
txt = widget.get_text()
|
txt = widget.get_text()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ret = int(txt)
|
return int(txt)
|
||||||
except:
|
except:
|
||||||
ret = adj.get_value()
|
return adj.get_value()
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def get_ideal_path_info(conn, name):
|
|
||||||
path = get_default_dir(conn)
|
|
||||||
suffix = ".img"
|
|
||||||
return (path, name, suffix)
|
|
||||||
|
|
||||||
|
|
||||||
def get_ideal_path(conn, name):
|
|
||||||
target, name, suffix = get_ideal_path_info(conn, name)
|
|
||||||
return os.path.join(target, name) + suffix
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_pool(conn):
|
|
||||||
pool = None
|
|
||||||
for uuid in conn.list_pool_uuids():
|
|
||||||
p = conn.get_pool(uuid)
|
|
||||||
if p.get_name() == "default":
|
|
||||||
pool = p
|
|
||||||
|
|
||||||
return pool
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_dir(conn):
|
|
||||||
pool = get_default_pool(conn)
|
|
||||||
|
|
||||||
if pool:
|
|
||||||
return pool.get_target_path()
|
|
||||||
else:
|
|
||||||
return config.running_config.get_default_image_dir(conn)
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_path(conn, name, collidelist=None):
|
|
||||||
collidelist = collidelist or []
|
|
||||||
pool = get_default_pool(conn)
|
|
||||||
|
|
||||||
default_dir = get_default_dir(conn)
|
|
||||||
|
|
||||||
def path_exists(p):
|
|
||||||
return os.path.exists(p) or p in collidelist
|
|
||||||
|
|
||||||
if not pool:
|
|
||||||
# Use old generating method
|
|
||||||
origf = os.path.join(default_dir, name + ".img")
|
|
||||||
f = origf
|
|
||||||
|
|
||||||
n = 1
|
|
||||||
while path_exists(f) and n < 100:
|
|
||||||
f = os.path.join(default_dir, name +
|
|
||||||
"-" + str(n) + ".img")
|
|
||||||
n += 1
|
|
||||||
|
|
||||||
if path_exists(f):
|
|
||||||
f = origf
|
|
||||||
|
|
||||||
path = f
|
|
||||||
else:
|
|
||||||
target, ignore, suffix = get_ideal_path_info(conn, name)
|
|
||||||
|
|
||||||
# Sanitize collidelist to work with the collision checker
|
|
||||||
newcollidelist = []
|
|
||||||
for c in collidelist:
|
|
||||||
if c and os.path.dirname(c) == pool.get_target_path():
|
|
||||||
newcollidelist.append(os.path.basename(c))
|
|
||||||
|
|
||||||
path = virtinst.StorageVolume.find_free_name(
|
|
||||||
pool.get_backend(), name,
|
|
||||||
suffix=suffix, collidelist=newcollidelist)
|
|
||||||
|
|
||||||
path = os.path.join(target, path)
|
|
||||||
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def browse_local(parent, dialog_name, conn, start_folder=None,
|
def browse_local(parent, dialog_name, conn, start_folder=None,
|
||||||
_type=None, dialog_type=None,
|
_type=None, dialog_type=None,
|
||||||
@@ -926,70 +910,6 @@ def browse_local(parent, dialog_name, conn, start_folder=None,
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def pretty_hv(gtype, domtype):
|
|
||||||
"""
|
|
||||||
Convert XML <domain type='foo'> and <os><type>bar</type>
|
|
||||||
into a more human relevant string.
|
|
||||||
"""
|
|
||||||
|
|
||||||
gtype = gtype.lower()
|
|
||||||
domtype = domtype.lower()
|
|
||||||
|
|
||||||
label = domtype
|
|
||||||
if domtype == "kvm":
|
|
||||||
if gtype == "xen":
|
|
||||||
label = "xenner"
|
|
||||||
elif domtype == "xen":
|
|
||||||
if gtype == "xen":
|
|
||||||
label = "xen (paravirt)"
|
|
||||||
elif gtype == "hvm":
|
|
||||||
label = "xen (fullvirt)"
|
|
||||||
elif domtype == "test":
|
|
||||||
if gtype == "xen":
|
|
||||||
label = "test (xen)"
|
|
||||||
elif gtype == "hvm":
|
|
||||||
label = "test (hvm)"
|
|
||||||
|
|
||||||
return label
|
|
||||||
|
|
||||||
|
|
||||||
def iface_in_use_by(conn, name):
|
|
||||||
use_str = ""
|
|
||||||
for i in conn.list_interface_names():
|
|
||||||
iface = conn.get_interface(i)
|
|
||||||
if name in iface.get_slave_names():
|
|
||||||
if use_str:
|
|
||||||
use_str += ", "
|
|
||||||
use_str += iface.get_name()
|
|
||||||
|
|
||||||
return use_str
|
|
||||||
|
|
||||||
|
|
||||||
def chkbox_helper(src, getcb, setcb, text1, text2=None,
|
|
||||||
alwaysrecord=False,
|
|
||||||
default=True,
|
|
||||||
chktext=_("Don't ask me again")):
|
|
||||||
"""
|
|
||||||
Helper to prompt user about proceeding with an operation
|
|
||||||
Returns True if the 'yes' or 'ok' button was selected, False otherwise
|
|
||||||
|
|
||||||
@alwaysrecord: Don't require user to select 'yes' to record chkbox value
|
|
||||||
@default: What value to return if getcb tells us not to prompt
|
|
||||||
"""
|
|
||||||
do_prompt = getcb()
|
|
||||||
if not do_prompt:
|
|
||||||
return default
|
|
||||||
|
|
||||||
res = src.err.warn_chkbox(text1=text1, text2=text2,
|
|
||||||
chktext=chktext,
|
|
||||||
buttons=Gtk.ButtonsType.YES_NO)
|
|
||||||
response, skip_prompt = res
|
|
||||||
if alwaysrecord or response:
|
|
||||||
setcb(not skip_prompt)
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def get_list_selection(widget):
|
def get_list_selection(widget):
|
||||||
selection = widget.get_selection()
|
selection = widget.get_selection()
|
||||||
active = selection.get_selected()
|
active = selection.get_selected()
|
||||||
@@ -1055,40 +975,3 @@ def set_grid_row_visible(child, visible):
|
|||||||
for child in parent.get_children():
|
for child in parent.get_children():
|
||||||
if child_get_property(parent, child, "top-attach") == row:
|
if child_get_property(parent, child, "top-attach") == row:
|
||||||
child.set_visible(visible)
|
child.set_visible(visible)
|
||||||
|
|
||||||
|
|
||||||
def default_uri(always_system=False):
|
|
||||||
if os.path.exists('/var/lib/xen'):
|
|
||||||
if (os.path.exists('/dev/xen/evtchn') or
|
|
||||||
os.path.exists("/proc/xen")):
|
|
||||||
return 'xen:///'
|
|
||||||
|
|
||||||
if (os.path.exists("/usr/bin/qemu") or
|
|
||||||
os.path.exists("/usr/bin/qemu-kvm") or
|
|
||||||
os.path.exists("/usr/bin/kvm") or
|
|
||||||
os.path.exists("/usr/libexec/qemu-kvm")):
|
|
||||||
if always_system or os.geteuid() == 0:
|
|
||||||
return "qemu:///system"
|
|
||||||
else:
|
|
||||||
return "qemu:///session"
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def exception_is_libvirt_error(e, error):
|
|
||||||
return (hasattr(libvirt, error) and
|
|
||||||
e.get_error_code() == getattr(libvirt, error))
|
|
||||||
|
|
||||||
|
|
||||||
def log_redefine_xml_diff(obj, origxml, newxml):
|
|
||||||
objname = "<%s name=%s>" % (obj.__class__.__name__, obj.get_name())
|
|
||||||
if origxml == newxml:
|
|
||||||
logging.debug("Redefine requested for %s, but XML didn't change!",
|
|
||||||
objname)
|
|
||||||
return
|
|
||||||
|
|
||||||
import difflib
|
|
||||||
diff = "".join(difflib.unified_diff(origxml.splitlines(1),
|
|
||||||
newxml.splitlines(1),
|
|
||||||
fromfile="Original XML",
|
|
||||||
tofile="New XML"))
|
|
||||||
logging.debug("Redefining %s with XML diff:\n%s", objname, diff)
|
|
||||||
|
|||||||
@@ -442,6 +442,11 @@ def is_error_nosupport(err):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def exception_is_libvirt_error(e, error):
|
||||||
|
return (hasattr(libvirt, error) and
|
||||||
|
e.get_error_code() == getattr(libvirt, error))
|
||||||
|
|
||||||
|
|
||||||
def local_libvirt_version():
|
def local_libvirt_version():
|
||||||
"""
|
"""
|
||||||
Lookup the local libvirt library version, but cache the value since
|
Lookup the local libvirt library version, but cache the value since
|
||||||
|
|||||||
Reference in New Issue
Block a user