mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-03-12 20:58:28 +03:00
merge heads
This commit is contained in:
commit
d559c56a26
222
ChangeLog
222
ChangeLog
@ -1,5 +1,225 @@
|
||||
2008-03-10 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* NEWS, configure.ac, virt-manager.spec.in:
|
||||
Update for new release
|
||||
[81d87628fd7b] [tip]
|
||||
|
||||
* src/virtManager/create.py:
|
||||
Fix disk field visibility
|
||||
[2ccd1c5ccd1a]
|
||||
|
||||
2008-03-09 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* src/virtManager/connection.py, src/virtManager/create.py, src/vmm-
|
||||
create.glade, virt-manager.spec.in:
|
||||
Control create wizard state based on capabilities info
|
||||
[215779fe46c6]
|
||||
|
||||
2008-03-07 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* src/virtManager/console.py, src/vmm-console.glade:
|
||||
Enable VNC window scaling
|
||||
[9ef26db66b0b]
|
||||
|
||||
2008-03-06 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/virtManager/details.py:
|
||||
Have max memory consider current mem allocation when altered
|
||||
directly (Adam Stokes)
|
||||
[1f1ee216fcef]
|
||||
|
||||
* src/virtManager/details.py, src/virtManager/domain.py, src/vmm-
|
||||
details.glade:
|
||||
Add autostart and boot device selection support.
|
||||
[4770f435ab01]
|
||||
|
||||
2008-03-05 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* src/virtManager/connection.py:
|
||||
Merge heads
|
||||
[0b213f9406fd]
|
||||
|
||||
2008-03-04 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/virtManager/domain.py:
|
||||
Actually fix cdrom connect/disconnect error reporting
|
||||
[4d2416cd81ec]
|
||||
|
||||
* src/virtManager/host.py:
|
||||
Don't allow adding virtual networks is we are disconnected.
|
||||
[35372d4a6ffa]
|
||||
|
||||
2008-03-03 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/virtManager/connection.py:
|
||||
Fix typo in creds scanning.
|
||||
[7fcbb49d9add]
|
||||
|
||||
2008-02-28 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/virtManager/domain.py:
|
||||
Raise cdrom connect/disconnect failures.
|
||||
[191b7b0e2f21]
|
||||
|
||||
* src/virtManager/details.py:
|
||||
Raise previously ignored exceptions in widget update function.
|
||||
[49bba0b0389d]
|
||||
|
||||
2008-02-25 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/virt-manager.py.in:
|
||||
Add custom libvirt error handler.
|
||||
|
||||
The handler will ignore all libvirt _errors_, as these should be
|
||||
dealt with as exceptions. This will also prevent libvirt errors from
|
||||
being printed to the console when an exception is deliberately
|
||||
ignored. All other libvirt messages (warnings) will be logged.
|
||||
[bc4b197cdc1f]
|
||||
|
||||
* src/virtManager/manager.py:
|
||||
Fix delete button sensitivity if selected guest is shutdown.
|
||||
[dc9c723e13ff]
|
||||
|
||||
2008-02-22 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/virtManager/domain.py:
|
||||
Check vm maxmem directly before we set current mem value. (Thanks
|
||||
Adam Stokes)
|
||||
|
||||
Prevents a race when we set maxmem and current mem to new values at
|
||||
the same time. Maxmem isn't updated in time, so we check the vm info
|
||||
directly when setting the current mem to get the most up to date
|
||||
value.
|
||||
[8a68171fe280]
|
||||
|
||||
2008-02-21 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/virtManager/addhardware.py:
|
||||
Only offer SCSI disk option for xen hvm: qemu doesn't like sd*
|
||||
disks.
|
||||
[1eeb1546b21b]
|
||||
|
||||
2008-02-22 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/virtManager/connection.py:
|
||||
Reuse virtinst.util.get_max_vcpus
|
||||
[f46dcf034d35]
|
||||
|
||||
2008-03-05 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* src/virtManager/connection.py, src/virtManager/console.py,
|
||||
src/virtManager/create.py, src/virtManager/createnet.py,
|
||||
src/virtManager/opticalhelper.py:
|
||||
Fix use of DBus objects to always go via an explicit interface
|
||||
[43d82ba67ffa]
|
||||
|
||||
2008-02-23 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* src/virtManager/connection.py:
|
||||
Force connection to readonly if non-root and local HV uri and no
|
||||
policykit (Saori Fukuta)
|
||||
[d1c6390bbea9]
|
||||
|
||||
* Merge heads
|
||||
[01c1acc34b1c]
|
||||
|
||||
2008-02-21 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* src/virtManager/connection.py:
|
||||
Skip bonding if /sys/class/net/bonding_masters doesn't exist
|
||||
(Shigeki Sakamoto)
|
||||
[5c86a029ee3a]
|
||||
|
||||
2008-02-23 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* src/virtManager/create.py, src/vmm-create.glade:
|
||||
Allow choice between local CDROM & kernel/initrd network install for
|
||||
fullvirt guests
|
||||
[ea6903353938]
|
||||
|
||||
2008-02-18 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* Merge heads
|
||||
[07ff9bffe54d]
|
||||
|
||||
* src/virtManager/connection.py:
|
||||
Support bonding & VLAN devices for attaching guest NICs (S.Sakamoto)
|
||||
[6a155cfe437c]
|
||||
|
||||
2008-02-16 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* src/virtManager/engine.py, src/virtManager/host.py:
|
||||
Wire up hosts dialog about menu entry (Henry Zhang)
|
||||
[4a5c3994af32]
|
||||
|
||||
2008-02-14 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/virtManager/addhardware.py, src/virtManager/create.py:
|
||||
Auto add usermode nic during create and addhardware when
|
||||
appropriate: everything was in place but it was broken.
|
||||
[402283b6aa0a]
|
||||
|
||||
2008-02-03 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* src/virtManager/serialcon.py:
|
||||
Use pty.slave_open for Solaris portability (Henry Zhang)
|
||||
[a623336112b9]
|
||||
|
||||
2008-01-31 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* po/fr.po:
|
||||
Refresh French translation from Gauthier Ancelin
|
||||
[7bcfffba3a97]
|
||||
|
||||
* README, TODO, src/virt-manager.py.in, src/virtManager/connect.py,
|
||||
src/virtManager/connection.py, src/vmm-open-connection.glade, virt-
|
||||
manager.spec.in:
|
||||
Added support for libvirt authentication
|
||||
[1892867ca5c7]
|
||||
|
||||
2008-01-30 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/vmm-modify-file-storage.glade:
|
||||
Remove unused vmm-modify-file-storage
|
||||
[28067b47f82c]
|
||||
|
||||
* src/virtManager/addhardware.py:
|
||||
Fix adding virtual blktap disk to pv guest via addhardware wizard.
|
||||
rhbz 430926
|
||||
[90dd30034ebc]
|
||||
|
||||
2008-01-16 "Cole Robinson <crobinso@redhat.com>
|
||||
|
||||
* src/virtManager/addhardware.py, src/virtManager/create.py:
|
||||
Fix disk size sensitivity: opening and closing the file chooser
|
||||
would make the disk size field sensitive even if nothing was
|
||||
selected.
|
||||
[384724cb14e0]
|
||||
|
||||
* src/virtManager/addhardware.py:
|
||||
Adding a bridged network device was broken, adding the display name
|
||||
and not the interface name. Fix similar to cset 597. Fixes bug
|
||||
392881.
|
||||
[dbd25721f588]
|
||||
|
||||
2008-01-15 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* AUTHORS, src/virtManager/console.py, src/virtManager/create.py,
|
||||
src/virtManager/domain.py, src/virtManager/manager.py:
|
||||
Pass libvirt connection username through to VNC console instead of
|
||||
hardcoding root (Soren Hansen)
|
||||
[49c55daf788d]
|
||||
|
||||
2008-01-10 "Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* .hgtags:
|
||||
Added tag RELEASE-0.5.3-1 for changeset 49f8c16f0acc
|
||||
[d99010f79088]
|
||||
|
||||
* ChangeLog:
|
||||
Refresh changelog
|
||||
[49f8c16f0acc] [RELEASE-0.5.3-1]
|
||||
|
||||
* po/bg.po, po/bn_IN.po, po/bs.po, po/ca.po, po/cs.po, po/da.po,
|
||||
po/de.po, po/es.po, po/fi.po, po/fr.po, po/gu.po, po/hi.po,
|
||||
po/hr.po, po/hu.po, po/is.po, po/it.po, po/ja.po, po/kn.po,
|
||||
@ -8,7 +228,7 @@
|
||||
po/ru.po, po/sr.po, po/sr@Latn.po, po/sv.po, po/ta.po, po/te.po,
|
||||
po/tr.po, po/uk.po, po/virt-manager.pot, po/zh_CN.po, po/zh_TW.po:
|
||||
Refresh po files
|
||||
[c95c688762cf] [tip]
|
||||
[c95c688762cf]
|
||||
|
||||
* configure.ac, virt-manager.spec.in:
|
||||
Update in prep for new release
|
||||
|
26
NEWS
26
NEWS
@ -1,6 +1,32 @@
|
||||
Virtual Machine Manager News
|
||||
============================
|
||||
|
||||
Release 0.5.4
|
||||
-------------
|
||||
|
||||
This release focuses on minor feature enhancement and bug fixes. Using
|
||||
the new GTK-VNC accelerated scaling support, the guest console window
|
||||
can be smoothly resized to fill the screen. The SSH username is passed
|
||||
through to the VNC console when tunnelling. Adding bridged network
|
||||
devices is fixed. Support for all libvirt authentication methods is
|
||||
enabled including Kerberos and PolicyKit. Solaris portability fix for
|
||||
the text console. Support for detecting bonding and VLAN devices for
|
||||
attaching guest NICs. Allow fullvirt guests to install off kernel and
|
||||
initrd as well as existing CDROM methods. Fix invocation of DBus methods
|
||||
to use an interface. Allow setting of autostart flag, and changing boot
|
||||
device ordering. Control the new VM wizard based on declared hypervisor
|
||||
capabilities.
|
||||
|
||||
Release 0.5.3
|
||||
-------------
|
||||
|
||||
This is a bug fix release. The sizing of the VNC window is fixed for
|
||||
screens where the physical size is less than the guest screen size.
|
||||
The 'new vm' button is switched back to its old (more obvious style/
|
||||
placement). Restore of VMs is working again for local connections. A
|
||||
menu for sending special key sequences to the guest is added. Lots of
|
||||
other misc bug fixes
|
||||
|
||||
Release 0.5.2
|
||||
-------------
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
AC_INIT(virt-manager.spec.in)
|
||||
AM_INIT_AUTOMAKE(virt-manager, 0.5.3)
|
||||
AM_INIT_AUTOMAKE(virt-manager, 0.5.4)
|
||||
|
||||
ALL_LINGUAS="bg bn_IN bs ca cs da de es fi fr gu hi hr hu is it ja kn ko ml mr ms nb nl or pa pl pt_BR pt ro ru sr@Latn sr sv ta te tr uk zh_CN zh_TW"
|
||||
IT_PROG_INTLTOOL([0.35.0], [no-xml])
|
||||
|
@ -23,6 +23,8 @@ import os
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
import libvirt
|
||||
|
||||
import locale
|
||||
import gettext
|
||||
import logging
|
||||
@ -125,6 +127,13 @@ def setup_logging():
|
||||
rootLogger.addHandler(fileHandler)
|
||||
logging.info("Application startup")
|
||||
|
||||
# Register libvirt handler
|
||||
def libvirt_callback(ctx, err):
|
||||
if err[3] != libvirt.VIR_ERR_ERROR:
|
||||
# Don't log libvirt errors: global error handler will do that
|
||||
logging.warn("Non-error from libvirt: '%s'" % err[2])
|
||||
libvirt.registerErrorHandler(f=libvirt_callback, ctx=None)
|
||||
|
||||
# Log uncaught exceptions
|
||||
def exception_log(type, val, tb):
|
||||
import traceback
|
||||
|
@ -51,6 +51,8 @@ PAGE_INPUT = 3
|
||||
PAGE_GRAPHICS = 4
|
||||
PAGE_SUMMARY = 5
|
||||
|
||||
KEYBOARD_DIR = "/etc/sysconfig/keyboard"
|
||||
|
||||
class vmmAddHardware(gobject.GObject):
|
||||
__gsignals__ = {
|
||||
"action-show-help": (gobject.SIGNAL_RUN_FIRST,
|
||||
@ -60,10 +62,13 @@ class vmmAddHardware(gobject.GObject):
|
||||
self.__gobject_init__()
|
||||
self.config = config
|
||||
self.vm = vm
|
||||
self._net = None
|
||||
self._disk = None
|
||||
self._dev = None
|
||||
self.window = gtk.glade.XML(config.get_glade_dir() + "/vmm-add-hardware.glade", "vmm-add-hardware", domain="virt-manager")
|
||||
self.topwin = self.window.get_widget("vmm-add-hardware")
|
||||
self.err = vmmErrorDialog(self.topwin,
|
||||
0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
|
||||
_("Unexpected Error"),
|
||||
_("An unexpected error occurred"))
|
||||
self.topwin.hide()
|
||||
self.window.signal_autoconnect({
|
||||
"on_create_pages_switch_page" : self.page_changed,
|
||||
@ -80,6 +85,7 @@ class vmmAddHardware(gobject.GObject):
|
||||
"on_mac_address_clicked" : self.change_macaddr_use,
|
||||
"on_graphics_type_changed": self.change_graphics_type,
|
||||
"on_graphics_port_auto_toggled": self.change_port_auto,
|
||||
"on_graphics_keymap_toggled": self.change_keymap,
|
||||
"on_create_help_clicked": self.show_help,
|
||||
})
|
||||
|
||||
@ -206,14 +212,17 @@ class vmmAddHardware(gobject.GObject):
|
||||
self.window.get_widget("graphics-address").set_active(False)
|
||||
self.window.get_widget("graphics-port-auto").set_active(True)
|
||||
self.window.get_widget("graphics-password").set_text("")
|
||||
self.window.get_widget("graphics-keymap").set_text("")
|
||||
self.window.get_widget("graphics-keymap-chk").set_active(True)
|
||||
|
||||
model = self.window.get_widget("hardware-type").get_model()
|
||||
model.clear()
|
||||
model.append(["Storage device", gtk.STOCK_HARDDISK, PAGE_DISK])
|
||||
# User mode networking only allows a single card for now
|
||||
if (self.vm.get_connection().get_type().lower() == "qemu" and \
|
||||
os.getuid() == 0) or \
|
||||
self.vm.get_connection().get_type().lower() == "xen":
|
||||
# Can't use shared or virtual networking as regular user
|
||||
# Can only have one usermode network device
|
||||
if (os.getuid() == 0 or
|
||||
(self.vm.get_connection().get_type().lower() == "qemu" and
|
||||
len(self.vm.get_network_devices()) == 0)):
|
||||
model.append(["Network card", gtk.STOCK_NETWORK, PAGE_NETWORK])
|
||||
|
||||
# Can only customize HVM guests, no Xen PV
|
||||
@ -222,14 +231,20 @@ class vmmAddHardware(gobject.GObject):
|
||||
model.append(["Graphics device", gtk.STOCK_SELECT_COLOR, PAGE_GRAPHICS])
|
||||
|
||||
|
||||
|
||||
def forward(self, ignore=None):
|
||||
notebook = self.window.get_widget("create-pages")
|
||||
if(self.validate(notebook.get_current_page()) != True):
|
||||
try:
|
||||
if(self.validate(notebook.get_current_page()) != True):
|
||||
return
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Uncaught error validating hardware input: %s") % str(e),
|
||||
"".join(traceback.format_exc()))
|
||||
return
|
||||
|
||||
if notebook.get_current_page() == PAGE_INTRO:
|
||||
notebook.set_current_page(self.get_config_hardware_type())
|
||||
hwtype = self.get_config_hardware_type()
|
||||
if notebook.get_current_page() == PAGE_INTRO and \
|
||||
(hwtype != PAGE_NETWORK or os.getuid() == 0):
|
||||
notebook.set_current_page(hwtype)
|
||||
else:
|
||||
notebook.set_current_page(PAGE_SUMMARY)
|
||||
self.window.get_widget("create-finish").show()
|
||||
@ -240,7 +255,11 @@ class vmmAddHardware(gobject.GObject):
|
||||
notebook = self.window.get_widget("create-pages")
|
||||
|
||||
if notebook.get_current_page() == PAGE_SUMMARY:
|
||||
notebook.set_current_page(self.get_config_hardware_type())
|
||||
hwtype = self.get_config_hardware_type()
|
||||
if hwtype == PAGE_NETWORK and os.getuid() != 0:
|
||||
notebook.set_current_page(PAGE_INTRO)
|
||||
else:
|
||||
notebook.set_current_page(hwtype)
|
||||
self.window.get_widget("create-finish").hide()
|
||||
else:
|
||||
notebook.set_current_page(PAGE_INTRO)
|
||||
@ -302,6 +321,32 @@ class vmmAddHardware(gobject.GObject):
|
||||
pw = self.window.get_widget("graphics-password")
|
||||
return pw.get_text()
|
||||
|
||||
def get_config_keymap(self):
|
||||
if self.window.get_widget("graphics-keymap").get_property("sensitive") \
|
||||
and self.window.get_widget("graphics-keymap").get_text() != "":
|
||||
return self.window.get_widget("graphics-keymap").get_text()
|
||||
else:
|
||||
# Set keymap to same as hosts
|
||||
import keytable
|
||||
keymap = None
|
||||
try:
|
||||
f = open(KEYBOARD_DIR, "r")
|
||||
except IOError, e:
|
||||
logging.debug('addhardware: Could not open "/etc/sysconfig/keyboard" ' + str(e))
|
||||
else:
|
||||
while 1:
|
||||
s = f.readline()
|
||||
if s == "":
|
||||
break
|
||||
if re.search("KEYTABLE", s) != None:
|
||||
kt = s.split('"')[1]
|
||||
if keytable.keytable.has_key(kt):
|
||||
keymap = keytable.keytable[kt]
|
||||
else:
|
||||
logging.debug("addhardware: Didn't find keymap '%s' in keytable!" % kt)
|
||||
f.close
|
||||
return keymap
|
||||
|
||||
def get_config_network(self):
|
||||
if os.getuid() != 0:
|
||||
return ["user"]
|
||||
@ -374,9 +419,9 @@ class vmmAddHardware(gobject.GObject):
|
||||
self.window.get_widget("summary-graphics").show()
|
||||
graphics = self.get_config_graphics()
|
||||
if graphics == "vnc":
|
||||
self.window.get_widget("summary-graphics-type").set_text("VNC server")
|
||||
self.window.get_widget("summary-graphics-type").set_text(_("VNC server"))
|
||||
else:
|
||||
self.window.get_widget("summary-graphics-type").set_text("Local SDL window")
|
||||
self.window.get_widget("summary-graphics-type").set_text(_("Local SDL window"))
|
||||
if graphics == "vnc":
|
||||
self.window.get_widget("summary-graphics-address").set_text(self.get_config_vnc_address())
|
||||
if self.get_config_vnc_port() == -1:
|
||||
@ -386,11 +431,17 @@ class vmmAddHardware(gobject.GObject):
|
||||
if self.get_config_vnc_password() is not None and self.get_config_vnc_password() != "":
|
||||
self.window.get_widget("summary-graphics-password").set_text(_("Yes"))
|
||||
else:
|
||||
self.window.get_widget("summary-graphics-password").set_text(_("Yes"))
|
||||
self.window.get_widget("summary-graphics-password").set_text(_("No"))
|
||||
if self.get_config_keymap() != "":
|
||||
self.window.get_widget("summary-graphics-keymap").set_text(str(self.get_config_keymap()))
|
||||
else:
|
||||
self.window.get_widget("summary-graphics-keymap").set_text(_("Same as host"))
|
||||
|
||||
else:
|
||||
self.window.get_widget("summary-graphics-address").set_text(_("N/A"))
|
||||
self.window.get_widget("summary-graphics-port").set_text(_("N/A"))
|
||||
self.window.get_widget("summary-graphics-password").set_text(_("N/A"))
|
||||
self.window.get_widget("summary-graphics-keymap").set_text(_("N/A"))
|
||||
|
||||
def close(self, ignore1=None,ignore2=None):
|
||||
self.topwin.hide()
|
||||
@ -418,12 +469,7 @@ class vmmAddHardware(gobject.GObject):
|
||||
self.add_graphics()
|
||||
|
||||
if self.install_error is not None:
|
||||
dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
|
||||
self.install_error,
|
||||
self.install_details)
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
self.err.show_err(self.install_error, self.install_details)
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.TOP_LEFT_ARROW))
|
||||
# Don't close becase we allow user to go back in wizard & correct
|
||||
@ -436,8 +482,10 @@ class vmmAddHardware(gobject.GObject):
|
||||
self.close()
|
||||
|
||||
def add_network(self):
|
||||
self._net.setup(self.vm.get_connection().vmm)
|
||||
self.add_device(self._net.get_xml_config())
|
||||
if self._dev is None and os.getuid() != 0:
|
||||
self._dev = virtinst.VirtualNetworkInterface(type="user")
|
||||
self._dev.setup(self.vm.get_connection().vmm)
|
||||
self.add_device(self._dev.get_xml_config())
|
||||
|
||||
def add_input(self):
|
||||
input = self.get_config_input()
|
||||
@ -445,24 +493,7 @@ class vmmAddHardware(gobject.GObject):
|
||||
self.add_device(xml)
|
||||
|
||||
def add_graphics(self):
|
||||
graphics = self.get_config_graphics()
|
||||
if graphics == "vnc":
|
||||
port = self.get_config_vnc_port()
|
||||
pw = self.get_config_vnc_password()
|
||||
addr = self.get_config_vnc_address()
|
||||
if addr is None or addr == "":
|
||||
if pw is None or pw == "":
|
||||
xml = "<graphics type='vnc' port='%d'/>" % (port,)
|
||||
else:
|
||||
xml = "<graphics type='vnc' port='%d' passwd='%s'/>" % (port,pw)
|
||||
else:
|
||||
if pw is None or pw == "":
|
||||
xml = "<graphics type='vnc' listen='%s' port='%d'/>" % (addr,port)
|
||||
else:
|
||||
xml = "<graphics type='vnc' listen='%s' port='%d' passwd='%s'/>" % (addr,port,pw)
|
||||
else:
|
||||
xml = "<graphics type='sdl'/>"
|
||||
self.add_device(xml)
|
||||
self.add_device(self._dev.get_xml_config())
|
||||
|
||||
def add_storage(self):
|
||||
node, maxnode, device = self.get_config_disk_target()
|
||||
@ -498,14 +529,14 @@ class vmmAddHardware(gobject.GObject):
|
||||
self.install_details = details
|
||||
return
|
||||
|
||||
progWin = vmmAsyncJob(self.config, self.do_file_allocate, [self._disk],
|
||||
progWin = vmmAsyncJob(self.config, self.do_file_allocate, [self._dev],
|
||||
title=_("Creating Storage File"),
|
||||
text=_("Allocation of disk storage may take a few minutes " + \
|
||||
"to complete."))
|
||||
progWin.run()
|
||||
|
||||
if self.install_error == None:
|
||||
self.add_device(self._disk.get_xml_config(node))
|
||||
self.add_device(self._dev.get_xml_config(node))
|
||||
|
||||
def add_device(self, xml):
|
||||
logging.debug("Adding device " + xml)
|
||||
@ -623,12 +654,15 @@ class vmmAddHardware(gobject.GObject):
|
||||
self.window.get_widget("graphics-port-auto").set_sensitive(True)
|
||||
self.window.get_widget("graphics-address").set_sensitive(True)
|
||||
self.window.get_widget("graphics-password").set_sensitive(True)
|
||||
self.window.get_widget("graphics-keymap-chk").set_sensitive(True)
|
||||
self.change_port_auto()
|
||||
else:
|
||||
self.window.get_widget("graphics-port").set_sensitive(False)
|
||||
self.window.get_widget("graphics-port-auto").set_sensitive(False)
|
||||
self.window.get_widget("graphics-address").set_sensitive(False)
|
||||
self.window.get_widget("graphics-password").set_sensitive(False)
|
||||
self.window.get_widget("graphics-keymap-chk").set_sensitive(False)
|
||||
self.window.get_widget("graphics-keymap").set_sensitive(False)
|
||||
|
||||
def change_port_auto(self,ignore=None):
|
||||
if self.window.get_widget("graphics-port-auto").get_active():
|
||||
@ -636,23 +670,27 @@ class vmmAddHardware(gobject.GObject):
|
||||
else:
|
||||
self.window.get_widget("graphics-port").set_sensitive(True)
|
||||
|
||||
def change_keymap(self, ignore=None):
|
||||
if self.window.get_widget("graphics-keymap-chk").get_active():
|
||||
self.window.get_widget("graphics-keymap").set_sensitive(False)
|
||||
else:
|
||||
self.window.get_widget("graphics-keymap").set_sensitive(True)
|
||||
|
||||
def validate(self, page_num):
|
||||
if page_num == PAGE_INTRO:
|
||||
if self.get_config_hardware_type() == None:
|
||||
self._validation_error_box(_("Hardware Type Required"), \
|
||||
_("You must specify what type of hardware to add"))
|
||||
return False
|
||||
return self.err.val_err(_("Hardware Type Required"), \
|
||||
_("You must specify what type of hardware to add"))
|
||||
self._dev = None
|
||||
elif page_num == PAGE_DISK:
|
||||
path = self.get_config_disk_image()
|
||||
if path == None or len(path) == 0:
|
||||
self._validation_error_box(_("Storage Path Required"), \
|
||||
_("You must specify a partition or a file for disk storage."))
|
||||
return False
|
||||
return self.err.val_err(_("Storage Path Required"), \
|
||||
_("You must specify a partition or a file for disk storage."))
|
||||
|
||||
if self.window.get_widget("target-device").get_active() == -1:
|
||||
self._validation_error_box(_("Target Device Required"),
|
||||
_("You must select a target device for the disk"))
|
||||
return False
|
||||
return self.err.val_err(_("Target Device Required"),
|
||||
_("You must select a target device for the disk"))
|
||||
|
||||
node, nodemax, device = self.get_config_disk_target()
|
||||
if self.window.get_widget("storage-partition").get_active():
|
||||
@ -665,8 +703,8 @@ class vmmAddHardware(gobject.GObject):
|
||||
if not os.path.exists(path):
|
||||
dir = os.path.dirname(os.path.abspath(path))
|
||||
if not os.path.exists(dir):
|
||||
self._validation_error_box(_("Storage Path Does not exist"),
|
||||
_("The directory %s containing the disk image does not exist") % dir)
|
||||
self.err.val_err(_("Storage Path Does not exist"),
|
||||
_("The directory %s containing the disk image does not exist") % dir)
|
||||
return False
|
||||
else:
|
||||
vfs = os.statvfs(dir)
|
||||
@ -674,14 +712,12 @@ class vmmAddHardware(gobject.GObject):
|
||||
need = size * 1024 * 1024
|
||||
if need > avail:
|
||||
if self.is_sparse_file():
|
||||
res = self._yes_no_box(_("Not Enough Free Space"),
|
||||
_("The filesystem will not have enough free space to fully allocate the sparse file when the guest is running. Use this path anyway?"))
|
||||
if not res:
|
||||
if not self.err.yes_no(_("Not Enough Free Space"),
|
||||
_("The filesystem will not have enough free space to fully allocate the sparse file when the guest is running. Use this path anyway?")):
|
||||
return False
|
||||
else:
|
||||
self._validation_error_box(_("Not Enough Free Space"),
|
||||
_("There is not enough free space to create the disk"))
|
||||
return False
|
||||
return self.err.val_err(_("Not Enough Free Space"),
|
||||
_("There is not enough free space to create the disk"))
|
||||
|
||||
# Build disk object
|
||||
filesize = self.get_config_disk_size()
|
||||
@ -692,120 +728,86 @@ class vmmAddHardware(gobject.GObject):
|
||||
readonly=True
|
||||
|
||||
try:
|
||||
self._disk = virtinst.VirtualDisk(self.get_config_disk_image(),
|
||||
self._dev = virtinst.VirtualDisk(self.get_config_disk_image(),
|
||||
filesize,
|
||||
type = type,
|
||||
sparse = self.is_sparse_file(),
|
||||
readOnly=readonly,
|
||||
device=device)
|
||||
if self._disk.type == virtinst.VirtualDisk.TYPE_FILE and \
|
||||
if self._dev.type == virtinst.VirtualDisk.TYPE_FILE and \
|
||||
not self.vm.is_hvm() and virtinst.util.is_blktap_capable():
|
||||
self._disk.driver_name = virtinst.VirtualDisk.DRIVER_TAP
|
||||
self._dev.driver_name = virtinst.VirtualDisk.DRIVER_TAP
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid Storage Parameters"), \
|
||||
str(e))
|
||||
return False
|
||||
|
||||
if self._disk.is_conflict_disk(self.vm.get_connection().vmm) is True:
|
||||
res = self._yes_no_box(_('Disk "%s" is already in use by another guest!' % self._disk), \
|
||||
_("Do you really want to use the disk ?"))
|
||||
return self.err.val_err(_("Invalid Storage Parameters"), str(e))
|
||||
|
||||
if self._dev.is_conflict_disk(self.vm.get_connection().vmm) is True:
|
||||
res = self.err.yes_no(_('Disk "%s" is already in use by another guest!' % self._dev), \
|
||||
_("Do you really want to use the disk ?"))
|
||||
return res
|
||||
elif page_num == PAGE_NETWORK:
|
||||
net = self.get_config_network()
|
||||
if self.window.get_widget("net-type-network").get_active():
|
||||
if self.window.get_widget("net-network").get_active() == -1:
|
||||
self._validation_error_box(_("Virtual Network Required"),
|
||||
_("You must select one of the virtual networks"))
|
||||
return False
|
||||
return self.err.val_err(_("Virtual Network Required"),
|
||||
_("You must select one of the virtual networks"))
|
||||
else:
|
||||
if self.window.get_widget("net-device").get_active() == -1:
|
||||
self._validation_error_box(_("Physical Device Required"),
|
||||
_("You must select one of the physical devices"))
|
||||
return False
|
||||
return self.err.val_err(_("Physical Device Required"),
|
||||
_("You must select one of the physical devices"))
|
||||
|
||||
mac = self.get_config_macaddr()
|
||||
if self.window.get_widget("mac-address").get_active():
|
||||
|
||||
if mac is None or len(mac) == 0:
|
||||
self._validation_error_box(_("Invalid MAC address"), \
|
||||
_("No MAC address was entered. Please enter a valid MAC address."))
|
||||
return False
|
||||
|
||||
return self.err.val_err(_("Invalid MAC address"), \
|
||||
_("No MAC address was entered. Please enter a valid MAC address."))
|
||||
|
||||
try:
|
||||
self._net = virtinst.VirtualNetworkInterface(macaddr=mac)
|
||||
self._dev = virtinst.VirtualNetworkInterface(macaddr=mac)
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid MAC address"), \
|
||||
str(e))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid MAC address"), str(e))
|
||||
|
||||
|
||||
hostdevs = virtinst.util.get_host_network_devices()
|
||||
for hostdev in hostdevs:
|
||||
if mac.lower() == hostdev[4]:
|
||||
return self._validation_error_box(_('MAC address "%s" is already in use by the host') % mac, \
|
||||
_("Please enter a different MAC address or select no fixed MAC address"))
|
||||
vms = []
|
||||
for domains in self.vm.get_connection().vms.values():
|
||||
vms.append(domains.vm)
|
||||
|
||||
# get inactive Domains
|
||||
inactive_vm = []
|
||||
names = self.vm.get_connection().vmm.listDefinedDomains()
|
||||
for name in names:
|
||||
vm = self.vm.get_connection().vmm.lookupByName(name)
|
||||
inactive_vm.append(vm)
|
||||
|
||||
if (self._net.countMACaddr(vms) - self._net.countMACaddr(inactive_vm)) > 0:
|
||||
return self._validation_error_box(_('MAC address "%s" is already in use by an active guest') % mac, \
|
||||
_("Please enter a different MAC address or select no fixed MAC address"))
|
||||
elif self._net.countMACaddr(inactive_vm) > 0:
|
||||
return self._yes_no_box(_('MAC address "%s" is already in use by another inactive guest!') % mac, \
|
||||
_("Do you really want to use the MAC address ?"))
|
||||
|
||||
|
||||
try:
|
||||
if net[0] == "bridge":
|
||||
self._net = virtinst.VirtualNetworkInterface(macaddr=mac,
|
||||
self._dev = virtinst.VirtualNetworkInterface(macaddr=mac,
|
||||
type=net[0],
|
||||
bridge=net[1])
|
||||
elif net[0] == "network":
|
||||
self._net = virtinst.VirtualNetworkInterface(macaddr=mac,
|
||||
self._dev = virtinst.VirtualNetworkInterface(macaddr=mac,
|
||||
type=net[0],
|
||||
network=net[1])
|
||||
else:
|
||||
raise ValueError, _("Unsupported networking type") + net[0]
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid Network Parameter"), \
|
||||
str(e))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid Network Parameter"), \
|
||||
str(e))
|
||||
|
||||
conflict = self._dev.is_conflict_net(self.vm.get_connection().vmm)
|
||||
if conflict[0]:
|
||||
return self.err.val_err(_("Mac address collision"),\
|
||||
conflict[1])
|
||||
elif conflict[1] is not None:
|
||||
return self.err.yes_no(_("Mac address collision"),\
|
||||
conflict[1] + " " + _("Are you sure you want to use this address?"))
|
||||
|
||||
elif page_num == PAGE_GRAPHICS:
|
||||
graphics = self.get_config_graphics()
|
||||
if graphics == "vnc":
|
||||
type = virtinst.VirtualGraphics.TYPE_VNC
|
||||
else:
|
||||
type = virtinst.VirtualGraphics.TYPE_SDL
|
||||
self._dev = virtinst.VirtualGraphics(type=type)
|
||||
try:
|
||||
self._dev.port = self.get_config_vnc_port()
|
||||
self._dev.passwd = self.get_config_vnc_password()
|
||||
self._dev.listen = self.get_config_vnc_address()
|
||||
self._dev.keymap = self.get_config_keymap()
|
||||
except ValueError, e:
|
||||
self.err.val_err(_("Graphics device parameter error"), str(e))
|
||||
|
||||
return True
|
||||
|
||||
def _validation_error_box(self, text1, text2=None):
|
||||
message_box = gtk.MessageDialog(self.window.get_widget("vmm-add-hardware"), \
|
||||
0, \
|
||||
gtk.MESSAGE_ERROR, \
|
||||
gtk.BUTTONS_OK, \
|
||||
text1)
|
||||
if text2 != None:
|
||||
message_box.format_secondary_text(text2)
|
||||
message_box.run()
|
||||
message_box.destroy()
|
||||
|
||||
def _yes_no_box(self, text1, text2=None):
|
||||
message_box = gtk.MessageDialog(self.window.get_widget("vmm-add-hardware"), \
|
||||
0, \
|
||||
gtk.MESSAGE_WARNING, \
|
||||
gtk.BUTTONS_YES_NO, \
|
||||
text1)
|
||||
if text2 != None:
|
||||
message_box.format_secondary_text(text2)
|
||||
if message_box.run()== gtk.RESPONSE_YES:
|
||||
res = True
|
||||
else:
|
||||
res = False
|
||||
message_box.destroy()
|
||||
return res
|
||||
|
||||
def populate_network_model(self, model):
|
||||
model.clear()
|
||||
for uuid in self.vm.get_connection().list_net_uuids():
|
||||
@ -830,8 +832,8 @@ class vmmAddHardware(gobject.GObject):
|
||||
model.append(["hd", 4, virtinst.VirtualDisk.DEVICE_DISK, gtk.STOCK_HARDDISK, "IDE disk"])
|
||||
model.append(["hd", 4, virtinst.VirtualDisk.DEVICE_CDROM, gtk.STOCK_CDROM, "IDE cdrom"])
|
||||
model.append(["fd", 2, virtinst.VirtualDisk.DEVICE_FLOPPY, gtk.STOCK_FLOPPY, "Floppy disk"])
|
||||
model.append(["sd", 7, virtinst.VirtualDisk.DEVICE_DISK, gtk.STOCK_HARDDISK, "SCSI disk"])
|
||||
if self.vm.get_connection().get_type().lower() == "xen":
|
||||
model.append(["sd", 7, virtinst.VirtualDisk.DEVICE_DISK, gtk.STOCK_HARDDISK, "SCSI disk"])
|
||||
model.append(["xvd", 26, virtinst.VirtualDisk.DEVICE_DISK, gtk.STOCK_HARDDISK, "Virtual disk"])
|
||||
#model.append(["usb", virtinst.VirtualDisk.DEVICE_DISK, gtk.STOCK_HARDDISK, "USB disk"])
|
||||
else:
|
||||
|
@ -22,6 +22,7 @@ import gobject
|
||||
import logging
|
||||
import virtinst
|
||||
from virtManager.opticalhelper import vmmOpticalDriveHelper
|
||||
from virtManager.error import vmmErrorDialog
|
||||
|
||||
class vmmChooseCD(gobject.GObject):
|
||||
__gsignals__ = {"cdrom-chosen": (gobject.SIGNAL_RUN_FIRST,
|
||||
@ -31,6 +32,10 @@ class vmmChooseCD(gobject.GObject):
|
||||
def __init__(self, config, target):
|
||||
self.__gobject_init__()
|
||||
self.window = gtk.glade.XML(config.get_glade_dir() + "/vmm-choose-cd.glade", "vmm-choose-cd", domain="virt-manager")
|
||||
self.err = vmmErrorDialog(self.window.get_widget("vmm-choose-cd"),
|
||||
0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
|
||||
_("Unexpected Error"),
|
||||
_("An unexpected error occurred"))
|
||||
self.config = config
|
||||
self.window.get_widget("vmm-choose-cd").hide()
|
||||
self.target = target
|
||||
@ -87,16 +92,13 @@ class vmmChooseCD(gobject.GObject):
|
||||
path = model.get_value(cd.get_active_iter(), 0)
|
||||
|
||||
if path == "" or path == None:
|
||||
self._validation_error_box(_("Invalid Media Path"), \
|
||||
_("A media path must be specified."))
|
||||
return
|
||||
return self.err.val_err(_("Invalid Media Path"), \
|
||||
_("A media path must be specified."))
|
||||
|
||||
try:
|
||||
disk = virtinst.VirtualDisk(path=path, device=virtinst.VirtualDisk.DEVICE_CDROM, readOnly=True)
|
||||
except Exception, e:
|
||||
self._validation_error_box(_("Invalid Media Path"), str(e))
|
||||
return
|
||||
|
||||
return self.err.val_err(_("Invalid Media Path"), str(e))
|
||||
self.emit("cdrom-chosen", disk.type, disk.path, self.target)
|
||||
self.close()
|
||||
|
||||
@ -141,16 +143,5 @@ class vmmChooseCD(gobject.GObject):
|
||||
else:
|
||||
fcdialog.destroy()
|
||||
return None
|
||||
|
||||
def _validation_error_box(self, text1, text2=None):
|
||||
message_box = gtk.MessageDialog(self.window.get_widget("vmm-choosecd"), \
|
||||
0, \
|
||||
gtk.MESSAGE_ERROR, \
|
||||
gtk.BUTTONS_OK, \
|
||||
text1)
|
||||
if text2 != None:
|
||||
message_box.format_secondary_text(text2)
|
||||
message_box.run()
|
||||
message_box.destroy()
|
||||
|
||||
|
||||
gobject.type_register(vmmChooseCD)
|
||||
|
@ -311,7 +311,7 @@ class vmmConfig:
|
||||
# the url isn't already in the list, so add it
|
||||
uris.insert(len(uris) - 1,uri)
|
||||
self.conf.set_list(self.conf_dir + "/connections/uris", gconf.VALUE_STRING, uris)
|
||||
|
||||
|
||||
def remove_connection(self, uri):
|
||||
uris = self.conf.get_list(self.conf_dir + "/connections/uris", gconf.VALUE_STRING)
|
||||
if uris == None:
|
||||
@ -319,6 +319,31 @@ class vmmConfig:
|
||||
if uris.count(uri) != 0:
|
||||
uris.remove(uri)
|
||||
self.conf.set_list(self.conf_dir + "/connections/uris", gconf.VALUE_STRING, uris)
|
||||
if self.get_conn_autoconnect(uri):
|
||||
uris = self.conf.get_list(self.conf_dir + \
|
||||
"/connections/autoconnect",\
|
||||
gconf.VALUE_STRING)
|
||||
uris.remove(uri)
|
||||
self.conf.set_list(self.conf_dir + "/connections/autoconnect", \
|
||||
gconf.VALUE_STRING, uris)
|
||||
|
||||
|
||||
def get_conn_autoconnect(self, uri):
|
||||
uris = self.conf.get_list(self.conf_dir + "/connections/autoconnect",\
|
||||
gconf.VALUE_STRING)
|
||||
return ((uris is not None) and (uri in uris))
|
||||
|
||||
def toggle_conn_autoconnect(self, uri):
|
||||
uris = self.conf.get_list(self.conf_dir + "/connections/autoconnect",\
|
||||
gconf.VALUE_STRING)
|
||||
if uris is None:
|
||||
uris = []
|
||||
if uri in uris:
|
||||
uris.remove(uri)
|
||||
else:
|
||||
uris.append(uri)
|
||||
self.conf.set_list(self.conf_dir + "/connections/autoconnect", \
|
||||
gconf.VALUE_STRING, uris)
|
||||
|
||||
def get_media_urls(self):
|
||||
return self.conf.get_list(self.conf_dir + "/urls/media", gconf.VALUE_STRING)
|
||||
|
@ -22,6 +22,7 @@ import gobject
|
||||
import libvirt
|
||||
import logging
|
||||
import os, sys
|
||||
import glob
|
||||
import traceback
|
||||
from time import time
|
||||
import logging
|
||||
@ -29,11 +30,15 @@ from socket import gethostbyaddr, gethostname
|
||||
import dbus
|
||||
import threading
|
||||
import gtk
|
||||
import string
|
||||
import virtinst
|
||||
|
||||
from virtManager.domain import vmmDomain
|
||||
from virtManager.network import vmmNetwork
|
||||
from virtManager.netdev import vmmNetDevice
|
||||
|
||||
LIBVIRT_POLICY_FILE = "/usr/share/PolicyKit/policy/libvirtd.policy"
|
||||
|
||||
def get_local_hostname():
|
||||
try:
|
||||
(host, aliases, ipaddrs) = gethostbyaddr(gethostname())
|
||||
@ -111,7 +116,6 @@ class vmmConnection(gobject.GObject):
|
||||
def __init__(self, config, uri, readOnly = None):
|
||||
self.__gobject_init__()
|
||||
self.config = config
|
||||
self.readOnly = readOnly
|
||||
|
||||
self.connectThread = None
|
||||
self.connectError = None
|
||||
@ -119,6 +123,11 @@ class vmmConnection(gobject.GObject):
|
||||
if self.uri is None or self.uri.lower() == "xen":
|
||||
self.uri = "xen:///"
|
||||
|
||||
self.readOnly = readOnly
|
||||
if not self.is_remote() and os.getuid() != 0 and self.uri != "qemu:///session":
|
||||
if not os.path.exists(LIBVIRT_POLICY_FILE):
|
||||
self.readOnly = True
|
||||
|
||||
self.state = self.STATE_DISCONNECTED
|
||||
self.vmm = None
|
||||
|
||||
@ -133,10 +142,9 @@ class vmmConnection(gobject.GObject):
|
||||
# Resource utilization statistics
|
||||
self.record = []
|
||||
self.hostinfo = None
|
||||
self.autoconnect = self.config.get_conn_autoconnect(self.get_uri())
|
||||
|
||||
self.detect_network_devices()
|
||||
|
||||
def detect_network_devices(self):
|
||||
# Probe for network devices
|
||||
try:
|
||||
# Get a connection to the SYSTEM bus
|
||||
self.bus = dbus.SystemBus()
|
||||
@ -145,12 +153,24 @@ class vmmConnection(gobject.GObject):
|
||||
self.hal_iface = dbus.Interface(hal_object, 'org.freedesktop.Hal.Manager')
|
||||
|
||||
# Track device add/removes so we can detect newly inserted CD media
|
||||
self.hal_iface.connect_to_signal("DeviceAdded", self._device_added)
|
||||
self.hal_iface.connect_to_signal("DeviceRemoved", self._device_removed)
|
||||
self.hal_iface.connect_to_signal("DeviceAdded", self._net_phys_device_added)
|
||||
self.hal_iface.connect_to_signal("DeviceRemoved", self._net_phys_device_removed)
|
||||
|
||||
# Find info about all current present media
|
||||
# find all bonding master devices and register them
|
||||
# XXX bonding stuff is linux specific
|
||||
bondMasters = self._net_get_bonding_masters()
|
||||
if bondMasters is not None:
|
||||
for bond in bondMasters:
|
||||
sysfspath = "/sys/class/net/" + bond
|
||||
mac = self._net_get_mac_address(bond, sysfspath)
|
||||
self._net_device_added(bond, mac, sysfspath)
|
||||
# Add any associated VLANs
|
||||
self._net_tag_device_added(bond, sysfspath)
|
||||
|
||||
# Find info about all current present physical net devices
|
||||
# This is OS portable...
|
||||
for path in self.hal_iface.FindDeviceByCapability("net"):
|
||||
self._device_added(path)
|
||||
self._net_phys_device_added(path)
|
||||
except:
|
||||
(type, value, stacktrace) = sys.exc_info ()
|
||||
logging.error("Unable to connect to HAL to list network devices: '%s'" + \
|
||||
@ -159,56 +179,75 @@ class vmmConnection(gobject.GObject):
|
||||
self.bus = None
|
||||
self.hal_iface = None
|
||||
|
||||
def _device_added(self, path):
|
||||
def _net_phys_device_added(self, path):
|
||||
logging.debug("Got physical device %s" % path)
|
||||
obj = self.bus.get_object("org.freedesktop.Hal", path)
|
||||
if obj.QueryCapability("net"):
|
||||
name = obj.GetPropertyString("net.interface")
|
||||
mac = obj.GetPropertyString("net.address")
|
||||
objif = dbus.Interface(obj, "org.freedesktop.Hal.Device")
|
||||
if objif.QueryCapability("net"):
|
||||
name = objif.GetPropertyString("net.interface")
|
||||
# XXX ...but this is Linux specific again - patches welcomed
|
||||
#sysfspath = objif.GetPropertyString("linux.sysfs_path")
|
||||
# XXX hal gives back paths to /sys/devices/pci0000:00/0000:00:1e.0/0000:01:00.0/net/eth0
|
||||
# which doesnt' work so well - we want this:
|
||||
sysfspath = "/sys/class/net/" + name
|
||||
|
||||
# Now magic to determine if the device is part of a bridge
|
||||
shared = False
|
||||
bridge = None
|
||||
try:
|
||||
# XXX Linux specific - needs porting for other OS - patches
|
||||
# welcomed...
|
||||
sysfspath = obj.GetPropertyString("linux.sysfs_path")
|
||||
# If running a device in bridged mode, there's a reasonable
|
||||
# chance that the actual ethernet device has been renamed to
|
||||
# something else. ethN -> pethN
|
||||
psysfspath = sysfspath[0:len(sysfspath)-len(name)] + "p" + name
|
||||
if os.path.exists(psysfspath):
|
||||
logging.debug("Device %s named to p%s" % (name, name))
|
||||
name = "p" + name
|
||||
sysfspath = psysfspath
|
||||
|
||||
# If running a device in bridged mode, there's a reasonable
|
||||
# chance that the actual ethernet device has been renamed to
|
||||
# something else. ethN -> pethN
|
||||
psysfspath = sysfspath[0:len(sysfspath)-len(name)] + "p" + name
|
||||
if os.path.exists(psysfspath):
|
||||
name = "p" + name
|
||||
sysfspath = psysfspath
|
||||
# Ignore devices that are slaves of a bond
|
||||
if self._net_is_bonding_slave(name, sysfspath):
|
||||
logging.debug("Skipping device %s in bonding slave" % name)
|
||||
return
|
||||
|
||||
brportpath = os.path.join(sysfspath, "brport")
|
||||
mac = objif.GetPropertyString("net.address")
|
||||
|
||||
if os.path.exists(brportpath):
|
||||
shared = True
|
||||
brlinkpath = os.path.join(brportpath, "bridge")
|
||||
dest = os.readlink(brlinkpath)
|
||||
(head,tail) = os.path.split(dest)
|
||||
bridge = tail
|
||||
except:
|
||||
(type, value, stacktrace) = sys.exc_info ()
|
||||
logging.error("Unable to determine if device is shared:" +
|
||||
str(type) + " " + str(value) + "\n" + \
|
||||
traceback.format_exc (stacktrace))
|
||||
# Add the main NIC
|
||||
self._net_device_added(name, mac, sysfspath)
|
||||
|
||||
if self.netdevs.has_key(path):
|
||||
currDev = self.netdevs[path]
|
||||
if currDev.get_info() == (name, mac, shared, bridge):
|
||||
return
|
||||
del self.netdevs[path]
|
||||
dev = vmmNetDevice(self.config, self, name, mac, shared, bridge)
|
||||
self.netdevs[path] = dev
|
||||
self.emit("netdev-added", dev.get_name())
|
||||
# Add any associated VLANs
|
||||
self._net_tag_device_added(name, sysfspath)
|
||||
|
||||
def _device_removed(self, path):
|
||||
if self.netdevs.has_key(path):
|
||||
dev = self.netdevs[path]
|
||||
def _net_tag_device_added(self, name, sysfspath):
|
||||
logging.debug("Checking for VLANs on %s" % sysfspath)
|
||||
for vlanpath in glob.glob(sysfspath + ".*"):
|
||||
if os.path.exists(vlanpath):
|
||||
logging.debug("Process VLAN %s" % vlanpath)
|
||||
vlanmac = self._net_get_mac_address(name, vlanpath)
|
||||
(ignore,vlanname) = os.path.split(vlanpath)
|
||||
self._net_device_added(vlanname, vlanmac, vlanpath)
|
||||
|
||||
def _net_device_added(self, name, mac, sysfspath):
|
||||
# Race conditions mean we can occassionally see device twice
|
||||
if self.netdevs.has_key(name):
|
||||
return
|
||||
|
||||
bridge = self._net_get_bridge_owner(name, sysfspath)
|
||||
shared = False
|
||||
if bridge is not None:
|
||||
shared = True
|
||||
|
||||
logging.debug("Adding net device %s %s %s bridge %s" % (name, mac, sysfspath, str(bridge)))
|
||||
|
||||
dev = vmmNetDevice(self.config, self, name, mac, shared, bridge)
|
||||
self.netdevs[name] = dev
|
||||
self.emit("netdev-added", dev.get_name())
|
||||
|
||||
def _net_phys_device_removed(self, path):
|
||||
obj = self.bus.get_object("org.freedesktop.Hal", path)
|
||||
objif = dbus.Interface(obj, "org.freedesktop.Hal.Device")
|
||||
if objif.QueryCapability("net"):
|
||||
name = objif.GetPropertyString("net.interface")
|
||||
|
||||
if self.netdevs.has_key(name):
|
||||
dev = self.netdevs[name]
|
||||
self.emit("netdev-removed", dev.get_name())
|
||||
del self.netdevs[path]
|
||||
del self.netdevs[name]
|
||||
|
||||
def is_read_only(self):
|
||||
return self.readOnly
|
||||
@ -261,6 +300,9 @@ class vmmConnection(gobject.GObject):
|
||||
pass
|
||||
return "xen"
|
||||
|
||||
def get_capabilities(self):
|
||||
return virtinst.CapabilitiesParser.parse(self.vmm.getCapabilities())
|
||||
|
||||
def is_remote(self):
|
||||
try:
|
||||
(scheme, username, netloc, path, query, fragment) = uri_split(self.uri)
|
||||
@ -356,7 +398,7 @@ class vmmConnection(gobject.GObject):
|
||||
return self._do_creds_polkit(creds[0][1])
|
||||
|
||||
for cred in creds:
|
||||
if creds[0] == libvirt.VIR_CRED_EXTERNAL:
|
||||
if cred[0] == libvirt.VIR_CRED_EXTERNAL:
|
||||
return -1
|
||||
|
||||
return self._do_creds_dialog(creds)
|
||||
@ -460,12 +502,19 @@ class vmmConnection(gobject.GObject):
|
||||
def get_host_info(self):
|
||||
return self.hostinfo
|
||||
|
||||
def get_max_vcpus(self):
|
||||
try:
|
||||
return self.vmm.getMaxVcpus(self.get_type())
|
||||
except Exception, e:
|
||||
logging.debug('Unable to get max vcpu')
|
||||
return 32;
|
||||
def get_max_vcpus(self, type=None):
|
||||
return virtinst.util.get_max_vcpus(self.vmm, type)
|
||||
|
||||
def get_autoconnect(self):
|
||||
# Use a local variable to cache autoconnect so we don't repeatedly
|
||||
# have to poll gconf
|
||||
return self.autoconnect
|
||||
|
||||
def toggle_autoconnect(self):
|
||||
if self.is_remote():
|
||||
return
|
||||
self.config.toggle_conn_autoconnect(self.get_uri())
|
||||
self.autoconnect = (not self.autoconnect)
|
||||
|
||||
def connect(self, name, callback):
|
||||
handle_id = gobject.GObject.connect(self, name, callback)
|
||||
@ -546,38 +595,38 @@ class vmmConnection(gobject.GObject):
|
||||
except:
|
||||
logging.warn("Unable to list inactive networks")
|
||||
|
||||
# check of net devices
|
||||
newPaths = []
|
||||
if self.hal_iface:
|
||||
newPaths = self.hal_iface.FindDeviceByCapability("net")
|
||||
for newPath in newPaths:
|
||||
self._device_added(newPath)
|
||||
|
||||
for name in newActiveNetNames:
|
||||
net = self.vmm.networkLookupByName(name)
|
||||
uuid = self.uuidstr(net.UUID())
|
||||
if not oldNets.has_key(uuid):
|
||||
self.nets[uuid] = vmmNetwork(self.config, self, net, uuid, True)
|
||||
newNets[uuid] = self.nets[uuid]
|
||||
startNets[uuid] = newNets[uuid]
|
||||
else:
|
||||
self.nets[uuid] = oldNets[uuid]
|
||||
if not self.nets[uuid].is_active():
|
||||
self.nets[uuid].set_active(True)
|
||||
startNets[uuid] = self.nets[uuid]
|
||||
del oldNets[uuid]
|
||||
try:
|
||||
net = self.vmm.networkLookupByName(name)
|
||||
uuid = self.uuidstr(net.UUID())
|
||||
if not oldNets.has_key(uuid):
|
||||
self.nets[uuid] = vmmNetwork(self.config, self, net, uuid, True)
|
||||
newNets[uuid] = self.nets[uuid]
|
||||
startNets[uuid] = newNets[uuid]
|
||||
else:
|
||||
self.nets[uuid] = oldNets[uuid]
|
||||
if not self.nets[uuid].is_active():
|
||||
self.nets[uuid].set_active(True)
|
||||
startNets[uuid] = self.nets[uuid]
|
||||
del oldNets[uuid]
|
||||
except libvirt.libvirtError:
|
||||
logging.warn("Couldn't fetch active network name '" + name + "'")
|
||||
|
||||
for name in newInactiveNetNames:
|
||||
net = self.vmm.networkLookupByName(name)
|
||||
uuid = self.uuidstr(net.UUID())
|
||||
if not oldNets.has_key(uuid):
|
||||
self.nets[uuid] = vmmNetwork(self.config, self, net, uuid, False)
|
||||
newNets[uuid] = self.nets[uuid]
|
||||
else:
|
||||
self.nets[uuid] = oldNets[uuid]
|
||||
if self.nets[uuid].is_active():
|
||||
self.nets[uuid].set_active(False)
|
||||
stopNets[uuid] = self.nets[uuid]
|
||||
del oldNets[uuid]
|
||||
try:
|
||||
net = self.vmm.networkLookupByName(name)
|
||||
uuid = self.uuidstr(net.UUID())
|
||||
if not oldNets.has_key(uuid):
|
||||
self.nets[uuid] = vmmNetwork(self.config, self, net, uuid, False)
|
||||
newNets[uuid] = self.nets[uuid]
|
||||
else:
|
||||
self.nets[uuid] = oldNets[uuid]
|
||||
if self.nets[uuid].is_active():
|
||||
self.nets[uuid].set_active(False)
|
||||
stopNets[uuid] = self.nets[uuid]
|
||||
del oldNets[uuid]
|
||||
except libvirt.libvirtError:
|
||||
logging.warn("Couldn't fetch inactive network name '" + name + "'")
|
||||
|
||||
oldActiveIDs = {}
|
||||
oldInactiveNames = {}
|
||||
@ -596,7 +645,12 @@ class vmmConnection(gobject.GObject):
|
||||
# Now we can clear the list of actives from the last time through
|
||||
self.activeUUIDs = []
|
||||
|
||||
newActiveIDs = self.vmm.listDomainsID()
|
||||
newActiveIDs = []
|
||||
try:
|
||||
newActiveIDs = self.vmm.listDomainsID()
|
||||
except:
|
||||
logging.warn("Unable to list active domains")
|
||||
|
||||
newInactiveNames = []
|
||||
try:
|
||||
newInactiveNames = self.vmm.listDefinedDomains()
|
||||
@ -626,13 +680,16 @@ class vmmConnection(gobject.GObject):
|
||||
# May be a new VM, we have no choice but
|
||||
# to create the wrapper so we can see
|
||||
# if its a previously inactive domain.
|
||||
vm = self.vmm.lookupByID(id)
|
||||
uuid = self.uuidstr(vm.UUID())
|
||||
maybeNewUUIDs[uuid] = vm
|
||||
# also add the new or newly started VM to the "started" list
|
||||
startedUUIDs.append(uuid)
|
||||
#print "Maybe new active " + str(maybeNewUUIDs[uuid].get_name()) + " " + uuid
|
||||
self.activeUUIDs.append(uuid)
|
||||
try:
|
||||
vm = self.vmm.lookupByID(id)
|
||||
uuid = self.uuidstr(vm.UUID())
|
||||
maybeNewUUIDs[uuid] = vm
|
||||
# also add the new or newly started VM to the "started" list
|
||||
startedUUIDs.append(uuid)
|
||||
#print "Maybe new active " + str(maybeNewUUIDs[uuid].get_name()) + " " + uuid
|
||||
self.activeUUIDs.append(uuid)
|
||||
except libvirt.libvirtError:
|
||||
logging.debug("Couldn't fetch domain id " + str(id) + "; it probably went away")
|
||||
|
||||
# Filter out inactive domains which haven't changed
|
||||
if newInactiveNames != None:
|
||||
@ -711,7 +768,10 @@ class vmmConnection(gobject.GObject):
|
||||
|
||||
# Finally, we sample each domain
|
||||
now = time()
|
||||
self.hostinfo = self.vmm.getInfo()
|
||||
try:
|
||||
self.hostinfo = self.vmm.getInfo()
|
||||
except:
|
||||
logging.warn("Unable to get host information")
|
||||
|
||||
updateVMs = self.vms
|
||||
if noStatsUpdate:
|
||||
@ -847,5 +907,51 @@ class vmmConnection(gobject.GObject):
|
||||
else:
|
||||
return _("Unknown")
|
||||
|
||||
def _net_get_bridge_owner(self, name, sysfspath):
|
||||
# Now magic to determine if the device is part of a bridge
|
||||
brportpath = os.path.join(sysfspath, "brport")
|
||||
try:
|
||||
if os.path.exists(brportpath):
|
||||
brlinkpath = os.path.join(brportpath, "bridge")
|
||||
dest = os.readlink(brlinkpath)
|
||||
(ignore,bridge) = os.path.split(dest)
|
||||
return bridge
|
||||
except:
|
||||
(type, value, stacktrace) = sys.exc_info ()
|
||||
logging.error("Unable to determine if device is shared:" +
|
||||
str(type) + " " + str(value) + "\n" + \
|
||||
traceback.format_exc (stacktrace))
|
||||
|
||||
return None
|
||||
|
||||
def _net_get_mac_address(self, name, sysfspath):
|
||||
mac = None
|
||||
addrpath = sysfspath + "/address"
|
||||
if os.path.exists(addrpath):
|
||||
df = open(addrpath, 'r')
|
||||
mac = df.readline()
|
||||
df.close()
|
||||
return mac.strip(" \n\t")
|
||||
|
||||
def _net_get_bonding_masters(self):
|
||||
masters = []
|
||||
if os.path.exists("/sys/class/net/bonding_masters"):
|
||||
f = open("/sys/class/net/bonding_masters")
|
||||
while True:
|
||||
rline = f.readline()
|
||||
if not rline: break
|
||||
if rline == "\x00": continue
|
||||
rline = rline.strip("\n\t")
|
||||
masters = rline[:-1].split(' ')
|
||||
return masters
|
||||
else:
|
||||
return None
|
||||
|
||||
def _net_is_bonding_slave(self, name, sysfspath):
|
||||
masterpath = sysfspath + "/master"
|
||||
if os.path.exists(masterpath):
|
||||
return True
|
||||
return False
|
||||
|
||||
gobject.type_register(vmmConnection)
|
||||
|
||||
|
@ -30,8 +30,6 @@ import gtkvnc
|
||||
import os
|
||||
import socket
|
||||
|
||||
from virtManager.error import vmmErrorDialog
|
||||
|
||||
PAGE_UNAVAILABLE = 0
|
||||
PAGE_SCREENSHOT = 1
|
||||
PAGE_AUTHENTICATE = 2
|
||||
@ -75,16 +73,17 @@ class vmmConsole(gobject.GObject):
|
||||
self.gtk_settings_accel = None
|
||||
|
||||
self.vncViewer = gtkvnc.Display()
|
||||
self.window.get_widget("console-vnc-align").add(self.vncViewer)
|
||||
self.window.get_widget("console-vnc-viewport").add(self.vncViewer)
|
||||
self.vncViewer.realize()
|
||||
self.vncTunnel = None
|
||||
if self.config.get_console_keygrab() == 2:
|
||||
self.vncViewer.set_keyboard_grab(True)
|
||||
self.vncViewer.set_pointer_grab(True)
|
||||
else:
|
||||
self.vncViewer.set_keyboard_grab(False)
|
||||
self.vncViewer.set_pointer_grab(False)
|
||||
self.vncViewer.set_pointer_local(True)
|
||||
self.vncViewer.set_pointer_grab(True)
|
||||
if not topwin.is_composited():
|
||||
self.vncViewer.set_scaling(True)
|
||||
self.window.get_widget("menu-view-scale-display").set_active(True)
|
||||
|
||||
self.vncViewer.connect("vnc-pointer-grab", self.notify_grabbed)
|
||||
self.vncViewer.connect("vnc-pointer-ungrab", self.notify_ungrabbed)
|
||||
@ -147,6 +146,8 @@ class vmmConsole(gobject.GObject):
|
||||
"on_menu_send_caf7_activate": self.send_key,
|
||||
"on_menu_send_caf8_activate": self.send_key,
|
||||
"on_menu_send_printscreen_activate": self.send_key,
|
||||
|
||||
"on_menu_view_scale_display_activate": self.scale_display,
|
||||
})
|
||||
|
||||
self.vm.connect("status-changed", self.update_widget_states)
|
||||
@ -165,8 +166,10 @@ class vmmConsole(gobject.GObject):
|
||||
# widget it still seems to show scrollbars. So we do evil stuff here
|
||||
def _force_resize(self, src, size):
|
||||
w,h = src.get_size_request()
|
||||
if w == -1 or h == -1:
|
||||
return
|
||||
|
||||
self.window.get_widget("console-screenshot").set_size_request(w, h)
|
||||
self.window.get_widget("console-vnc-scroll").set_size_request(w, h)
|
||||
topw,toph = self.window.get_widget("vmm-console").size_request()
|
||||
|
||||
padx = topw-w
|
||||
@ -178,6 +181,7 @@ class vmmConsole(gobject.GObject):
|
||||
maxh = rooth - 100 - pady
|
||||
self.window.get_widget("console-vnc-viewport").set_size_request(w, h)
|
||||
self.window.get_widget("console-screenshot-viewport").set_size_request(w, h)
|
||||
self.window.get_widget("console-vnc-scroll").set_size_request(w, h)
|
||||
if w > maxw or h > maxh:
|
||||
self.window.get_widget("console-vnc-scroll").set_policy(gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS)
|
||||
self.window.get_widget("console-screenshot-scroll").set_policy(gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS)
|
||||
@ -185,26 +189,10 @@ class vmmConsole(gobject.GObject):
|
||||
self.window.get_widget("console-vnc-scroll").set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
|
||||
self.window.get_widget("console-screenshot-scroll").set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
|
||||
|
||||
# Auto-increase the window size to fit the console - within reason
|
||||
# though, cos we don't want a min window size greater than the screen
|
||||
# the user has scrollbars anyway if they want it smaller / it can't fit
|
||||
def autosize(self, src, size):
|
||||
rootWidth = gtk.gdk.screen_width()
|
||||
rootHeight = gtk.gdk.screen_height()
|
||||
|
||||
vncWidth, vncHeight = src.get_size_request()
|
||||
|
||||
if vncWidth > (rootWidth-200):
|
||||
vncWidth = rootWidth - 200
|
||||
if vncHeight > (rootHeight-200):
|
||||
vncHeight = rootHeight - 200
|
||||
|
||||
self.window.get_widget("console-vnc-vp").set_size_request(vncWidth+2, vncHeight+2)
|
||||
|
||||
def send_key(self, src):
|
||||
keys = None
|
||||
if src.get_name() == "menu-send-cad":
|
||||
keys = ["Control_L", "Alt_L", "Del"]
|
||||
keys = ["Control_L", "Alt_L", "Delete"]
|
||||
elif src.get_name() == "menu-send-cab":
|
||||
keys = ["Control_L", "Alt_L", "BackSpace"]
|
||||
elif src.get_name() == "menu-send-caf1":
|
||||
@ -287,10 +275,14 @@ class vmmConsole(gobject.GObject):
|
||||
def keygrab_changed(self, src, ignore1=None,ignore2=None,ignore3=None):
|
||||
if self.config.get_console_keygrab() == 2:
|
||||
self.vncViewer.set_keyboard_grab(True)
|
||||
self.vncViewer.set_pointer_grab(True)
|
||||
else:
|
||||
self.vncViewer.set_keyboard_grab(False)
|
||||
self.vncViewer.set_pointer_grab(False)
|
||||
|
||||
def scale_display(self, src):
|
||||
if src.get_active():
|
||||
self.vncViewer.set_scaling(True)
|
||||
else:
|
||||
self.vncViewer.set_scaling(False)
|
||||
|
||||
def toggle_fullscreen(self, src):
|
||||
if src.get_active():
|
||||
@ -669,6 +661,8 @@ class vmmConsole(gobject.GObject):
|
||||
cr.show_text(overlay)
|
||||
screenshot.set_from_pixmap(pixmap, None)
|
||||
self.activate_screenshot_page()
|
||||
elif self.window.get_widget("console-pages").get_current_page() == PAGE_SCREENSHOT:
|
||||
pass
|
||||
else:
|
||||
if self.window.get_widget("console-pages").get_current_page() != PAGE_UNAVAILABLE:
|
||||
self.vncViewer.close()
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2006 Red Hat, Inc.
|
||||
# Copyright (C) 2006, 2008 Red Hat, Inc.
|
||||
# Copyright (C) 2006 Hugh O. Brock <hbrock@redhat.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@ -49,17 +49,22 @@ VM_INSTALL_FROM_CD = 2
|
||||
VM_STORAGE_PARTITION = 1
|
||||
VM_STORAGE_FILE = 2
|
||||
|
||||
VM_INST_LOCAL = 1
|
||||
VM_INST_TREE = 2
|
||||
VM_INST_PXE = 3
|
||||
|
||||
DEFAULT_STORAGE_FILE_SIZE = 500
|
||||
|
||||
PAGE_INTRO = 0
|
||||
PAGE_NAME = 1
|
||||
PAGE_TYPE = 2
|
||||
PAGE_FVINST = 3
|
||||
PAGE_PVINST = 4
|
||||
PAGE_DISK = 5
|
||||
PAGE_NETWORK = 6
|
||||
PAGE_CPUMEM = 7
|
||||
PAGE_SUMMARY = 8
|
||||
PAGE_INST = 3
|
||||
PAGE_INST_LOCAL = 4
|
||||
PAGE_INST_TREE = 5
|
||||
PAGE_DISK = 6
|
||||
PAGE_NETWORK = 7
|
||||
PAGE_CPUMEM = 8
|
||||
PAGE_SUMMARY = 9
|
||||
|
||||
KEYBOARD_DIR = "/etc/sysconfig/keyboard"
|
||||
|
||||
@ -80,6 +85,10 @@ class vmmCreate(gobject.GObject):
|
||||
self.connection = connection
|
||||
self.window = gtk.glade.XML(config.get_glade_dir() + "/vmm-create.glade", "vmm-create", domain="virt-manager")
|
||||
self.topwin = self.window.get_widget("vmm-create")
|
||||
self.err = vmmErrorDialog(self.topwin,
|
||||
0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
|
||||
_("Unexpected Error"),
|
||||
_("An unexpected error occurred"))
|
||||
self.topwin.hide()
|
||||
self.window.signal_autoconnect({
|
||||
"on_create_pages_switch_page" : self.page_changed,
|
||||
@ -103,6 +112,7 @@ class vmmCreate(gobject.GObject):
|
||||
"on_create_help_clicked": self.show_help,
|
||||
})
|
||||
|
||||
self.caps = self.connection.get_capabilities()
|
||||
self.set_initial_state()
|
||||
|
||||
# Guest to fill in with values along the way
|
||||
@ -139,15 +149,13 @@ class vmmCreate(gobject.GObject):
|
||||
cd_list.add_attribute(text, 'sensitive', 2)
|
||||
try:
|
||||
self.optical_helper = vmmOpticalDriveHelper(self.window.get_widget("cd-path"))
|
||||
self.optical_helper.populate_opt_media()
|
||||
self.window.get_widget("media-physical").set_sensitive(True)
|
||||
except Exception, e:
|
||||
logging.error("Unable to create optical-helper widget: '%s'", e)
|
||||
self.window.get_widget("media-physical").set_sensitive(False)
|
||||
|
||||
if os.getuid() != 0:
|
||||
self.window.get_widget("media-physical").set_sensitive(False)
|
||||
self.window.get_widget("storage-partition").set_sensitive(False)
|
||||
self.window.get_widget("media-physical").set_sensitive(True)
|
||||
self.window.get_widget("storage-partition").set_sensitive(True)
|
||||
|
||||
# set up the lists for the url widgets
|
||||
media_url_list = self.window.get_widget("pv-media-url")
|
||||
@ -196,18 +204,13 @@ class vmmCreate(gobject.GObject):
|
||||
self.window.get_widget("create-host-memory").set_text(self.pretty_memory(memory))
|
||||
self.window.get_widget("create-memory-max").set_range(50, memory/1024)
|
||||
|
||||
if self.connection.get_type() == "QEMU":
|
||||
if os.uname()[4] == "x86_64":
|
||||
self.window.get_widget("cpu-architecture").set_active(1)
|
||||
else:
|
||||
self.window.get_widget("cpu-architecture").set_active(0)
|
||||
else:
|
||||
self.window.get_widget("cpu-architecture").set_active(-1)
|
||||
|
||||
self.window.get_widget("cpu-architecture").set_sensitive(False)
|
||||
self.window.get_widget("cpu-accelerate").set_sensitive(False)
|
||||
self.change_virt_method()
|
||||
archModel = gtk.ListStore(str)
|
||||
archList = self.window.get_widget("cpu-architecture")
|
||||
archList.set_model(archModel)
|
||||
|
||||
hyperModel = gtk.ListStore(str)
|
||||
hyperList = self.window.get_widget("hypervisor")
|
||||
hyperList.set_model(hyperModel)
|
||||
|
||||
def reset_state(self):
|
||||
notebook = self.window.get_widget("create-pages")
|
||||
@ -220,29 +223,34 @@ class vmmCreate(gobject.GObject):
|
||||
|
||||
# If we don't have full-virt support disable the choice, and
|
||||
# display a message telling the user why it is not working
|
||||
if self.connection.get_type().lower() == "qemu":
|
||||
self.window.get_widget("virt-method-pv").set_sensitive(False)
|
||||
self.window.get_widget("virt-method-fv").set_active(True)
|
||||
has_pv = False
|
||||
has_fv = False
|
||||
|
||||
for guest in self.caps.guests:
|
||||
if guest.os_type in ["xen", "linux"]:
|
||||
has_pv = True
|
||||
elif guest.os_type == "hvm":
|
||||
has_fv = True
|
||||
|
||||
self.window.get_widget("virt-method-pv").set_sensitive(has_pv)
|
||||
self.window.get_widget("virt-method-fv").set_sensitive(has_fv)
|
||||
|
||||
# prioritize pv if the option is available?
|
||||
self.window.get_widget("virt-method-fv").set_active(has_fv)
|
||||
self.window.get_widget("virt-method-pv").set_active(has_pv)
|
||||
self.change_virt_method() # repopulate arch and hypervisor lists
|
||||
|
||||
if has_fv:
|
||||
self.window.get_widget("virt-method-fv-unsupported").hide()
|
||||
self.window.get_widget("virt-method-fv-disabled").hide()
|
||||
else:
|
||||
self.window.get_widget("virt-method-pv").set_sensitive(True)
|
||||
self.window.get_widget("virt-method-pv").set_active(True)
|
||||
if virtinst.util.is_hvm_capable():
|
||||
self.window.get_widget("virt-method-fv").set_sensitive(True)
|
||||
self.window.get_widget("virt-method-fv-unsupported").hide()
|
||||
self.window.get_widget("virt-method-fv-disabled").hide()
|
||||
self.window.get_widget("virt-method-fv-unsupported").show()
|
||||
flags = self.caps.host.features.names()
|
||||
if "vmx" in flags or "svm" in flags:
|
||||
self.window.get_widget("virt-method-fv-disabled").show()
|
||||
else:
|
||||
self.window.get_widget("virt-method-fv").set_sensitive(False)
|
||||
flags = virtinst.util.get_cpu_flags()
|
||||
if "vmx" in flags or "svm" in flags:
|
||||
# Host has support, but disabled in bios
|
||||
self.window.get_widget("virt-method-fv-unsupported").hide()
|
||||
self.window.get_widget("virt-method-fv-disabled").show()
|
||||
else:
|
||||
# Host has no support
|
||||
self.window.get_widget("virt-method-fv-unsupported").show()
|
||||
self.window.get_widget("virt-method-fv-disabled").hide()
|
||||
self.window.get_widget("virt-method-fv-disabled").hide()
|
||||
|
||||
|
||||
self.change_media_type()
|
||||
self.change_storage_type()
|
||||
@ -251,10 +259,7 @@ class vmmCreate(gobject.GObject):
|
||||
self.window.get_widget("create-vm-name").set_text("")
|
||||
self.window.get_widget("media-iso-image").set_active(True)
|
||||
self.window.get_widget("fv-iso-location").set_text("")
|
||||
if os.getuid() == 0:
|
||||
self.window.get_widget("storage-partition").set_active(True)
|
||||
else:
|
||||
self.window.get_widget("storage-file-backed").set_active(True)
|
||||
self.window.get_widget("storage-file-backed").set_active(True)
|
||||
self.window.get_widget("storage-partition-address").set_text("")
|
||||
self.window.get_widget("storage-file-address").set_text("")
|
||||
self.window.get_widget("storage-file-size").set_value(2000)
|
||||
@ -292,14 +297,26 @@ class vmmCreate(gobject.GObject):
|
||||
|
||||
def forward(self, ignore=None):
|
||||
notebook = self.window.get_widget("create-pages")
|
||||
if(self.validate(notebook.get_current_page()) != True):
|
||||
try:
|
||||
if(self.validate(notebook.get_current_page()) != True):
|
||||
return
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Uncaught error validating input: %s") % str(e),
|
||||
"".join(traceback.format_exc()))
|
||||
return
|
||||
|
||||
if (notebook.get_current_page() == PAGE_TYPE and self.get_config_method() == VM_PARA_VIRT):
|
||||
notebook.set_current_page(PAGE_PVINST)
|
||||
elif (notebook.get_current_page() == PAGE_FVINST and self.get_config_method() == VM_FULLY_VIRT):
|
||||
if notebook.get_current_page() == PAGE_INST:
|
||||
if self.get_config_install_method() == VM_INST_LOCAL:
|
||||
notebook.set_current_page(PAGE_INST_LOCAL)
|
||||
elif self.get_config_install_method() == VM_INST_TREE:
|
||||
notebook.set_current_page(PAGE_INST_TREE)
|
||||
else:
|
||||
# No config for PXE needed (yet)
|
||||
notebook.set_current_page(PAGE_DISK)
|
||||
elif notebook.get_current_page() in [PAGE_INST_TREE, PAGE_INST_LOCAL]:
|
||||
notebook.set_current_page(PAGE_DISK)
|
||||
elif (notebook.get_current_page() == PAGE_DISK and os.getuid() != 0):
|
||||
elif notebook.get_current_page() == PAGE_DISK and self.connection.get_uri() == "qemu:///session":
|
||||
# Skip network for non-root
|
||||
notebook.set_current_page(PAGE_CPUMEM)
|
||||
else:
|
||||
notebook.next_page()
|
||||
@ -309,11 +326,18 @@ class vmmCreate(gobject.GObject):
|
||||
# do this always, since there's no "leaving a notebook page" event.
|
||||
self.window.get_widget("create-finish").hide()
|
||||
self.window.get_widget("create-forward").show()
|
||||
if notebook.get_current_page() == PAGE_PVINST and self.get_config_method() == VM_PARA_VIRT:
|
||||
notebook.set_current_page(PAGE_TYPE)
|
||||
elif notebook.get_current_page() == PAGE_DISK and self.get_config_method() == VM_FULLY_VIRT:
|
||||
notebook.set_current_page(PAGE_FVINST)
|
||||
elif notebook.get_current_page() == PAGE_CPUMEM and os.getuid() != 0:
|
||||
if notebook.get_current_page() in [PAGE_INST_TREE, PAGE_INST_LOCAL]:
|
||||
notebook.set_current_page(PAGE_INST)
|
||||
elif notebook.get_current_page() == PAGE_DISK:
|
||||
if self.get_config_install_method() == VM_INST_LOCAL:
|
||||
notebook.set_current_page(PAGE_INST_LOCAL)
|
||||
elif self.get_config_install_method() == VM_INST_TREE:
|
||||
notebook.set_current_page(PAGE_INST_TREE)
|
||||
else:
|
||||
# No config for PXE needed (yet)
|
||||
notebook.set_current_page(PAGE_INST)
|
||||
elif notebook.get_current_page() == PAGE_CPUMEM and self.connection.get_uri() == "qemu:///session":
|
||||
# Skip network for non-root
|
||||
notebook.set_current_page(PAGE_DISK)
|
||||
else:
|
||||
notebook.prev_page()
|
||||
@ -330,31 +354,29 @@ class vmmCreate(gobject.GObject):
|
||||
return VM_PARA_VIRT
|
||||
|
||||
def get_config_install_source(self):
|
||||
if self.get_config_method() == VM_PARA_VIRT:
|
||||
if self.get_config_install_method() == VM_INST_TREE:
|
||||
widget = self.window.get_widget("pv-media-url")
|
||||
url= widget.child.get_text()
|
||||
# Add the URL to the list, if it's different
|
||||
self.config.add_media_url(url)
|
||||
self.populate_url_model(widget.get_model(), self.config.get_media_urls())
|
||||
return url
|
||||
else:
|
||||
elif self.get_config_install_method() == VM_INST_LOCAL:
|
||||
if self.window.get_widget("media-iso-image").get_active():
|
||||
return self.window.get_widget("fv-iso-location").get_text()
|
||||
elif self.window.get_widget("media-physical").get_active():
|
||||
cd = self.window.get_widget("cd-path")
|
||||
model = cd.get_model()
|
||||
return model.get_value(cd.get_active_iter(), 0)
|
||||
else:
|
||||
return "PXE"
|
||||
|
||||
def get_config_installer(self, type):
|
||||
if self.get_config_method() == VM_FULLY_VIRT and self.window.get_widget("media-network").get_active():
|
||||
return virtinst.PXEInstaller(type = type)
|
||||
return self.window.get_widget("cd-path").get_active_text()
|
||||
else:
|
||||
return virtinst.DistroInstaller(type = type)
|
||||
return "PXE"
|
||||
|
||||
def get_config_installer(self, type, os_type):
|
||||
if self.get_config_install_method() == VM_INST_PXE:
|
||||
return virtinst.PXEInstaller(type = type, os_type = os_type)
|
||||
else:
|
||||
return virtinst.DistroInstaller(type = type, os_type = os_type)
|
||||
|
||||
def get_config_kickstart_source(self):
|
||||
if self.get_config_method() == VM_PARA_VIRT:
|
||||
if self.get_config_install_method() == VM_INST_TREE:
|
||||
widget = self.window.get_widget("pv-ks-url")
|
||||
url = widget.child.get_text()
|
||||
self.config.add_kickstart_url(url)
|
||||
@ -370,6 +392,8 @@ class vmmCreate(gobject.GObject):
|
||||
return self.window.get_widget("storage-file-address").get_text()
|
||||
|
||||
def get_config_disk_size(self):
|
||||
if not self.window.get_widget("storage-file-backed").get_active():
|
||||
return None
|
||||
if not self.window.get_widget("storage-file-size").get_editable():
|
||||
return None
|
||||
else:
|
||||
@ -379,7 +403,7 @@ class vmmCreate(gobject.GObject):
|
||||
return self.window.get_widget("kernel-params").get_text()
|
||||
|
||||
def get_config_network(self):
|
||||
if os.getuid() != 0:
|
||||
if self.connection.get_uri() == "qemu:///session":
|
||||
return ["user"]
|
||||
|
||||
if self.window.get_widget("net-type-network").get_active():
|
||||
@ -406,6 +430,14 @@ class vmmCreate(gobject.GObject):
|
||||
def get_config_virtual_cpus(self):
|
||||
return self.window.get_widget("create-vcpus").get_value()
|
||||
|
||||
def get_config_install_method(self):
|
||||
if self.window.get_widget("method-local").get_active():
|
||||
return VM_INST_LOCAL
|
||||
elif self.window.get_widget("method-tree").get_active():
|
||||
return VM_INST_TREE
|
||||
else:
|
||||
return VM_INST_PXE
|
||||
|
||||
def get_config_os_type(self):
|
||||
type = self.window.get_widget("os-type")
|
||||
if type.get_active_iter() != None:
|
||||
@ -438,9 +470,19 @@ class vmmCreate(gobject.GObject):
|
||||
name_widget.grab_focus()
|
||||
elif page_number == PAGE_TYPE:
|
||||
pass
|
||||
elif page_number == PAGE_FVINST:
|
||||
pass
|
||||
elif page_number == PAGE_PVINST:
|
||||
elif page_number == PAGE_INST:
|
||||
if self.get_config_method() == VM_PARA_VIRT:
|
||||
# Xen can't PXE or CDROM install :-(
|
||||
self.window.get_widget("method-local").set_sensitive(False)
|
||||
self.window.get_widget("method-pxe").set_sensitive(False)
|
||||
self.window.get_widget("method-tree").set_active(True)
|
||||
else:
|
||||
self.window.get_widget("method-local").set_sensitive(True)
|
||||
self.window.get_widget("method-pxe").set_sensitive(True)
|
||||
elif page_number == PAGE_INST_TREE:
|
||||
url_widget = self.window.get_widget("pv-media-url")
|
||||
url_widget.grab_focus()
|
||||
elif page_number == PAGE_INST_LOCAL:
|
||||
url_widget = self.window.get_widget("pv-media-url")
|
||||
url_widget.grab_focus()
|
||||
elif page_number == PAGE_DISK:
|
||||
@ -519,14 +561,25 @@ class vmmCreate(gobject.GObject):
|
||||
try:
|
||||
guest.uuid = virtinst.util.uuidToString(virtinst.util.randomUUID())
|
||||
except ValueError, E:
|
||||
self._validation_error_box(_("UUID Error"), str(e))
|
||||
return self.err.val_err(_("UUID Error"), str(e))
|
||||
|
||||
# HACK: If usermode, and no nic is setup, use usermode networking
|
||||
if self.connection.get_uri() == "qemu:///session":
|
||||
try:
|
||||
self._net = virtinst.VirtualNetworkInterface(type="user")
|
||||
except ValueError, e:
|
||||
return self.err.val_err(_("Failed to set up usermode networking"), str(e))
|
||||
|
||||
if self._disk is not None:
|
||||
guest.disks = [self._disk]
|
||||
else:
|
||||
logging.debug('No guest disks found in install phase.')
|
||||
if self._net is not None:
|
||||
guest.nics = [self._net]
|
||||
|
||||
# set up the graphics to use SDL
|
||||
else:
|
||||
logging.debug('No guest nics found in install phase.')
|
||||
|
||||
# Set vnc display to use same keymap as host
|
||||
import keytable
|
||||
keymap = None
|
||||
vncport = None
|
||||
@ -543,8 +596,17 @@ class vmmCreate(gobject.GObject):
|
||||
kt = s.split('"')[1]
|
||||
if keytable.keytable.has_key(kt):
|
||||
keymap = keytable.keytable[kt]
|
||||
else:
|
||||
logging.debug("Didn't find keymap '%s' in keytable!" % kt)
|
||||
f.close
|
||||
guest.graphics = (True, "vnc", vncport, keymap)
|
||||
try:
|
||||
guest._graphics_dev = virtinst.VirtualGraphics(type=virtinst.VirtualGraphics.TYPE_VNC,
|
||||
port=vncport,
|
||||
keymap=keymap)
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Error setting up graphics device:") + str(e),
|
||||
"".join(traceback.format_exc()))
|
||||
return False
|
||||
|
||||
logging.debug("Creating a VM " + guest.name + \
|
||||
"\n Type: " + guest.type + \
|
||||
@ -577,12 +639,7 @@ class vmmCreate(gobject.GObject):
|
||||
progWin.run()
|
||||
|
||||
if self.install_error != None:
|
||||
dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
|
||||
self.install_error,
|
||||
self.install_details)
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
self.err.show_err(self.install_error, self.install_details)
|
||||
self.topwin.set_sensitive(True)
|
||||
self.topwin.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.TOP_LEFT_ARROW))
|
||||
# Don't close becase we allow user to go back in wizard & correct
|
||||
@ -687,7 +744,10 @@ class vmmCreate(gobject.GObject):
|
||||
if file != None and len(file) > 0 and not(os.path.exists(file)):
|
||||
self.window.get_widget("storage-file-size").set_sensitive(True)
|
||||
self.window.get_widget("non-sparse").set_sensitive(True)
|
||||
self.window.get_widget("storage-file-size").set_value(4000)
|
||||
size = self.get_config_disk_size()
|
||||
if size == None:
|
||||
size = 4000
|
||||
self.window.get_widget("storage-file-size").set_value(size)
|
||||
else:
|
||||
self.window.get_widget("storage-file-size").set_sensitive(False)
|
||||
self.window.get_widget("non-sparse").set_sensitive(False)
|
||||
@ -767,8 +827,7 @@ class vmmCreate(gobject.GObject):
|
||||
try:
|
||||
self._guest.name = name
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid System Name"), str(e))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid System Name"), str(e))
|
||||
elif page_num == PAGE_TYPE:
|
||||
|
||||
# Set up appropriate guest object dependent on selected type
|
||||
@ -780,11 +839,36 @@ class vmmCreate(gobject.GObject):
|
||||
self._guest = virtinst.FullVirtGuest(type=self.get_domain_type(),
|
||||
arch=self.get_domain_arch(),
|
||||
hypervisorURI=self.connection.get_uri())
|
||||
|
||||
|
||||
self._guest.name = name # Transfer name over
|
||||
|
||||
elif page_num == PAGE_FVINST:
|
||||
self._guest.installer = self.get_config_installer(self.get_domain_type())
|
||||
elif page_num == PAGE_INST:
|
||||
if self.get_config_method() == VM_PARA_VIRT:
|
||||
os_type = "xen"
|
||||
else:
|
||||
os_type = "hvm"
|
||||
self._guest.installer = self.get_config_installer(self.get_domain_type(), os_type)
|
||||
|
||||
try:
|
||||
if self.get_config_os_type() is not None \
|
||||
and self.get_config_os_type() != "generic":
|
||||
logging.debug("OS Type: %s" % self.get_config_os_type())
|
||||
self._guest.os_type = self.get_config_os_type()
|
||||
except ValueError, e:
|
||||
return self.err.val_err(_("Invalid FV OS Type"), str(e))
|
||||
try:
|
||||
if self.get_config_os_variant() is not None \
|
||||
and self.get_config_os_type() != "generic":
|
||||
logging.debug("OS Variant: %s" % self.get_config_os_variant())
|
||||
self._guest.os_variant = self.get_config_os_variant()
|
||||
except ValueError, e:
|
||||
return self.err.val_err(_("Invalid FV OS Variant"), str(e))
|
||||
elif page_num == PAGE_INST_LOCAL:
|
||||
if self.get_config_method() == VM_PARA_VIRT:
|
||||
os_type = "xen"
|
||||
else:
|
||||
os_type = "hvm"
|
||||
self._guest.installer = self.get_config_installer(self.get_domain_type(), os_type)
|
||||
|
||||
if self.window.get_widget("media-iso-image").get_active():
|
||||
|
||||
@ -792,51 +876,28 @@ class vmmCreate(gobject.GObject):
|
||||
try:
|
||||
self._guest.cdrom = src
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("ISO Path Not Found"), str(e))
|
||||
return False
|
||||
elif self.window.get_widget("media-physical").get_active():
|
||||
return self.err.val_err(_("ISO Path Not Found"), str(e))
|
||||
else:
|
||||
cdlist = self.window.get_widget("cd-path")
|
||||
src = self.get_config_install_source()
|
||||
try:
|
||||
self._guest.cdrom = src
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("CD-ROM Path Error"), str(e))
|
||||
return False
|
||||
else:
|
||||
pass # No checks for PXE
|
||||
|
||||
try:
|
||||
if self.get_config_os_type() is not None \
|
||||
and self.get_config_os_type() != "generic":
|
||||
logging.debug("OS Type: %s" % self.get_config_os_type())
|
||||
self._guest.os_type = self.get_config_os_type()
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid FV OS Type"), str(e))
|
||||
return False
|
||||
try:
|
||||
if self.get_config_os_variant() is not None \
|
||||
and self.get_config_os_type() != "generic":
|
||||
logging.debug("OS Variant: %s" % self.get_config_os_variant())
|
||||
self._guest.os_variant = self.get_config_os_variant()
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid FV OS Variant"), str(e))
|
||||
return False
|
||||
elif page_num == PAGE_PVINST:
|
||||
return self.err.val_err(_("CD-ROM Path Error"), str(e))
|
||||
elif page_num == PAGE_INST_TREE:
|
||||
|
||||
src = self.get_config_install_source()
|
||||
try:
|
||||
self._guest.location = src
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid Install URL"), str(e))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid Install URL"), str(e))
|
||||
|
||||
ks = self.get_config_kickstart_source()
|
||||
if ks is not None and len(ks) != 0:
|
||||
if not (ks.startswith("http://") or ks.startswith("ftp://") \
|
||||
or ks.startswith("nfs:")):
|
||||
self._validation_error_box(_("Kickstart URL Error"), \
|
||||
_("Kickstart location must be an NFS, HTTP or FTP source"))
|
||||
return False
|
||||
return self.err.val_err(_("Kickstart URL Error"), \
|
||||
_("Kickstart location must be an NFS, HTTP or FTP source"))
|
||||
else:
|
||||
self._guest.extraargs = "ks=%s" % (ks,)
|
||||
|
||||
@ -852,9 +913,8 @@ class vmmCreate(gobject.GObject):
|
||||
|
||||
disk = self.get_config_disk_image()
|
||||
if disk == None or len(disk) == 0:
|
||||
self._validation_error_box(_("Storage Address Required"), \
|
||||
_("You must specify a partition or a file for storage for the guest install"))
|
||||
return False
|
||||
return self.err.val_err(_("Storage Address Required"), \
|
||||
_("You must specify a partition or a file for storage for the guest install"))
|
||||
|
||||
if not self.window.get_widget("storage-partition").get_active():
|
||||
disk = self.get_config_disk_image()
|
||||
@ -862,23 +922,21 @@ class vmmCreate(gobject.GObject):
|
||||
if not os.path.exists(disk):
|
||||
dir = os.path.dirname(os.path.abspath(disk))
|
||||
if not os.path.exists(dir):
|
||||
self._validation_error_box(_("Storage Path Does not exist"),
|
||||
_("The directory %s containing the disk image does not exist") % dir)
|
||||
return False
|
||||
return self.err.val_err(_("Storage Path Does not exist"),
|
||||
_("The directory %s containing the disk image does not exist") % dir)
|
||||
else:
|
||||
vfs = os.statvfs(dir)
|
||||
avail = vfs[statvfs.F_FRSIZE] * vfs[statvfs.F_BAVAIL]
|
||||
need = size * 1024 * 1024
|
||||
if need > avail:
|
||||
if self.is_sparse_file():
|
||||
res = self._yes_no_box(_("Not Enough Free Space"),
|
||||
_("The filesystem will not have enough free space to fully allocate the sparse file when the guest is running. Use this path anyway?"))
|
||||
res = self.err.yes_no(_("Not Enough Free Space"),
|
||||
_("The filesystem will not have enough free space to fully allocate the sparse file when the guest is running. Use this path anyway?"))
|
||||
if not res:
|
||||
return False
|
||||
else:
|
||||
self._validation_error_box(_("Not Enough Free Space"),
|
||||
_("There is not enough free space to create the disk"))
|
||||
return False
|
||||
return self.err.val_err(_("Not Enough Free Space"),
|
||||
_("There is not enough free space to create the disk"))
|
||||
|
||||
# Attempt to set disk
|
||||
filesize = None
|
||||
@ -907,41 +965,31 @@ class vmmCreate(gobject.GObject):
|
||||
else:
|
||||
self.non_sparse = False
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid Storage Address"), \
|
||||
str(e))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid Storage Address"), str(e))
|
||||
|
||||
if self._disk.is_conflict_disk(self.connection.vmm) is True:
|
||||
res = self._yes_no_box(_('Disk "%s" is already in use by another guest!' % disk), _("Do you really want to use the disk ?"))
|
||||
res = self.err.yes_no(_('Disk "%s" is already in use by another guest!' % disk), _("Do you really want to use the disk ?"))
|
||||
return res
|
||||
|
||||
elif page_num == PAGE_NETWORK:
|
||||
|
||||
if self.window.get_widget("net-type-network").get_active():
|
||||
if self.window.get_widget("net-network").get_active() == -1:
|
||||
self._validation_error_box(_("Virtual Network Required"),
|
||||
_("You must select one of the virtual networks"))
|
||||
return False
|
||||
return self.err.val_err(_("Virtual Network Required"),
|
||||
_("You must select one of the virtual networks"))
|
||||
else:
|
||||
if self.window.get_widget("net-device").get_active() == -1:
|
||||
self._validation_error_box(_("Physical Device Required"),
|
||||
_("You must select one of the physical devices"))
|
||||
return False
|
||||
return self.err.val_err(_("Physical Device Required"),
|
||||
_("You must select one of the physical devices"))
|
||||
|
||||
net = self.get_config_network()
|
||||
|
||||
if self.window.get_widget("mac-address").get_active():
|
||||
mac = self.window.get_widget("create-mac-address").get_text()
|
||||
if mac is None or len(mac) == 0:
|
||||
self._validation_error_box(_("Invalid MAC address"), \
|
||||
_("No MAC address was entered. Please enter a valid MAC address."))
|
||||
return False
|
||||
|
||||
hostdevs = virtinst.util.get_host_network_devices()
|
||||
for hostdev in hostdevs:
|
||||
if mac.lower() == hostdev[4]:
|
||||
return self._validation_error_box(_('MAC address "%s" is already in use by the host') % mac, \
|
||||
_("Please enter a different MAC address or select no fixed MAC address"))
|
||||
return self.err.val_err(_("Invalid MAC address"), \
|
||||
_("No MAC address was entered. Please enter a valid MAC address."))
|
||||
|
||||
else:
|
||||
mac = None
|
||||
try:
|
||||
@ -957,27 +1005,14 @@ class vmmCreate(gobject.GObject):
|
||||
self._net = virtinst.VirtualNetworkInterface(macaddr=mac, \
|
||||
type=net[0])
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Network Parameter Error"), \
|
||||
str(e))
|
||||
return False
|
||||
return self.err.val_err(_("Network Parameter Error"), str(e))
|
||||
|
||||
vms = []
|
||||
for domains in self.connection.vms.values():
|
||||
vms.append(domains.vm)
|
||||
|
||||
# get inactive Domains
|
||||
inactive_vm = []
|
||||
names = self.connection.vmm.listDefinedDomains()
|
||||
for name in names:
|
||||
vm = self.connection.vmm.lookupByName(name)
|
||||
inactive_vm.append(vm)
|
||||
|
||||
if (self._net.countMACaddr(vms) - self._net.countMACaddr(inactive_vm)) > 0:
|
||||
return self._validation_error_box(_('MAC address "%s" is already in use by a active guest') % mac, \
|
||||
_("Please enter a different MAC address or select no fixed MAC address"))
|
||||
elif self._net.countMACaddr(inactive_vm) > 0:
|
||||
return self._yes_no_box(_('MAC address "%s" is already in use by another inactive guest!') % mac, \
|
||||
_("Do you really want to use the MAC address ?"))
|
||||
conflict = self._net.is_conflict_net(self.connection.vmm)
|
||||
if conflict[0]:
|
||||
return self.err.val_err(_("Mac address collision"), conflict[1])
|
||||
elif conflict[1] is not None:
|
||||
return self.err.yes_no(_("Mac address collision"),\
|
||||
conflict[1] + " " + _("Are you sure you want to use this address?"))
|
||||
|
||||
elif page_num == PAGE_CPUMEM:
|
||||
|
||||
@ -985,54 +1020,22 @@ class vmmCreate(gobject.GObject):
|
||||
try:
|
||||
self._guest.vcpus = int(self.get_config_virtual_cpus())
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("VCPU Count Error"), \
|
||||
str(e))
|
||||
return False
|
||||
return self.err.val_err(_("VCPU Count Error"), str(e))
|
||||
# Set Memory
|
||||
try:
|
||||
self._guest.memory = int(self.get_config_initial_memory())
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Memory Amount Error"), \
|
||||
str(e))
|
||||
return False
|
||||
return self.err.val_err(_("Memory Amount Error"), str(e))
|
||||
# Set Max Memory
|
||||
try:
|
||||
self._guest.maxmemory = int(self.get_config_maximum_memory())
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Max Memory Amount Error"), \
|
||||
str(e))
|
||||
return False
|
||||
return self.err.val_err(_("Max Memory Amount Error"), str(e))
|
||||
|
||||
# do this always, since there's no "leaving a notebook page" event.
|
||||
self.window.get_widget("create-back").set_sensitive(True)
|
||||
return True
|
||||
|
||||
def _validation_error_box(self, text1, text2=None):
|
||||
message_box = gtk.MessageDialog(self.window.get_widget("vmm-create"), \
|
||||
0, \
|
||||
gtk.MESSAGE_ERROR, \
|
||||
gtk.BUTTONS_OK, \
|
||||
text1)
|
||||
if text2 != None:
|
||||
message_box.format_secondary_text(text2)
|
||||
message_box.run()
|
||||
message_box.destroy()
|
||||
|
||||
def _yes_no_box(self, text1, text2=None):
|
||||
#import pdb; pdb.set_trace()
|
||||
message_box = gtk.MessageDialog(self.window.get_widget("vmm-create"), \
|
||||
0, \
|
||||
gtk.MESSAGE_WARNING, \
|
||||
gtk.BUTTONS_YES_NO, \
|
||||
text1)
|
||||
if text2 != None:
|
||||
message_box.format_secondary_text(text2)
|
||||
if message_box.run()== gtk.RESPONSE_YES:
|
||||
res = True
|
||||
else:
|
||||
res = False
|
||||
message_box.destroy()
|
||||
return res
|
||||
|
||||
def populate_url_model(self, model, urls):
|
||||
model.clear()
|
||||
for url in urls:
|
||||
@ -1086,29 +1089,31 @@ class vmmCreate(gobject.GObject):
|
||||
|
||||
def change_virt_method(self, ignore=None):
|
||||
arch = self.window.get_widget("cpu-architecture")
|
||||
if self.connection.get_type() != "QEMU" or self.window.get_widget("virt-method-pv").get_active():
|
||||
arch.set_sensitive(False)
|
||||
|
||||
if self.get_config_method() == VM_PARA_VIRT:
|
||||
nativeArch = self.repopulate_cpu_arch(arch.get_model(), ["xen", "linux"])
|
||||
else:
|
||||
arch.set_sensitive(True)
|
||||
self.change_cpu_arch(arch)
|
||||
nativeArch = self.repopulate_cpu_arch(arch.get_model(), ["hvm"])
|
||||
arch.set_active(nativeArch)
|
||||
self.change_cpu_arch()
|
||||
|
||||
def change_cpu_arch(self, src):
|
||||
model = src.get_model()
|
||||
active = src.get_active()
|
||||
canAccel = False
|
||||
if active != -1 and src.get_property("sensitive") and \
|
||||
(virtinst.util.is_kvm_capable() or virtinst.util.is_kqemu_capable()):
|
||||
if os.uname()[4] == "i686" and model[active][0] == "i686":
|
||||
canAccel = True
|
||||
elif os.uname()[4] == "x86_64" and model[active][0] in ("i686", "x86_64"):
|
||||
canAccel = True
|
||||
def change_cpu_arch(self, ignore=None):
|
||||
hypervisor = self.window.get_widget("hypervisor")
|
||||
arch = self.get_domain_arch()
|
||||
|
||||
self.window.get_widget("cpu-accelerate").set_sensitive(canAccel)
|
||||
self.window.get_widget("cpu-accelerate").set_active(canAccel)
|
||||
if arch is None:
|
||||
hypervisor.set_active(-1)
|
||||
hypervisor.set_sensitive(False)
|
||||
return
|
||||
|
||||
hypervisor.set_sensitive(True)
|
||||
if self.get_config_method() == VM_PARA_VIRT:
|
||||
bestHyper = self.repopulate_hypervisor(hypervisor.get_model(), ["xen", "linux"], arch)
|
||||
else:
|
||||
bestHyper = self.repopulate_hypervisor(hypervisor.get_model(), ["hvm"], arch)
|
||||
hypervisor.set_active(bestHyper)
|
||||
|
||||
def get_domain_arch(self):
|
||||
if self.connection.get_type() != "QEMU":
|
||||
return None
|
||||
arch = self.window.get_widget("cpu-architecture")
|
||||
if arch.get_active() == -1:
|
||||
return None
|
||||
@ -1127,15 +1132,41 @@ class vmmCreate(gobject.GObject):
|
||||
return True
|
||||
|
||||
def get_domain_type(self):
|
||||
if self.connection.get_type() == "QEMU":
|
||||
if self.window.get_widget("cpu-accelerate").get_active():
|
||||
if virtinst.util.is_kvm_capable():
|
||||
return "kvm"
|
||||
elif virtinst.util.is_kqemu_capable():
|
||||
return "kqemu"
|
||||
return "qemu"
|
||||
else:
|
||||
return "xen"
|
||||
hypervisor = self.window.get_widget("hypervisor")
|
||||
|
||||
if hypervisor.get_active() == -1:
|
||||
return None
|
||||
|
||||
return hypervisor.get_model()[hypervisor.get_active()][0]
|
||||
|
||||
def repopulate_cpu_arch(self, model, ostype):
|
||||
model.clear()
|
||||
i = 0
|
||||
native = -1
|
||||
for guest in self.caps.guests:
|
||||
if guest.os_type not in ostype:
|
||||
continue
|
||||
|
||||
model.append([guest.arch])
|
||||
if guest.arch == self.caps.host.arch:
|
||||
native = i
|
||||
i = i + 1
|
||||
|
||||
return native
|
||||
|
||||
|
||||
def repopulate_hypervisor(self, model, ostype, arch):
|
||||
model.clear()
|
||||
i = -1
|
||||
for guest in self.caps.guests:
|
||||
if guest.os_type not in ostype or guest.arch != arch:
|
||||
continue
|
||||
|
||||
for domain in guest.domains:
|
||||
model.append([domain.hypervisor_type])
|
||||
i = i + 1
|
||||
|
||||
return i
|
||||
|
||||
def show_help(self, src):
|
||||
# help to show depends on the notebook page, yahoo
|
||||
@ -1146,10 +1177,12 @@ class vmmCreate(gobject.GObject):
|
||||
self.emit("action-show-help", "virt-manager-system-name")
|
||||
elif page == PAGE_TYPE:
|
||||
self.emit("action-show-help", "virt-manager-virt-method")
|
||||
elif page == PAGE_FVINST:
|
||||
self.emit("action-show-help", "virt-manager-installation-media-full-virt")
|
||||
elif page == PAGE_PVINST:
|
||||
self.emit("action-show-help", "virt-manager-installation-media-paravirt")
|
||||
elif page == PAGE_INST:
|
||||
self.emit("action-show-help", "virt-manager-installation-media")
|
||||
elif page == PAGE_INST_LOCAL:
|
||||
self.emit("action-show-help", "virt-manager-installation-media-local")
|
||||
elif page == PAGE_INST_TREE:
|
||||
self.emit("action-show-help", "virt-manager-installation-media-tree")
|
||||
elif page == PAGE_DISK:
|
||||
self.emit("action-show-help", "virt-manager-storage-space")
|
||||
elif page == PAGE_NETWORK:
|
||||
|
@ -28,8 +28,10 @@ import os, sys
|
||||
import logging
|
||||
import dbus
|
||||
import re
|
||||
import traceback
|
||||
|
||||
from virtManager.IPy import IP
|
||||
from virtManager.error import vmmErrorDialog
|
||||
|
||||
PAGE_INTRO = 0
|
||||
PAGE_NAME = 1
|
||||
@ -50,6 +52,10 @@ class vmmCreateNetwork(gobject.GObject):
|
||||
self.conn = conn
|
||||
self.window = gtk.glade.XML(config.get_glade_dir() + "/vmm-create-net.glade", "vmm-create-net", domain="virt-manager")
|
||||
self.topwin = self.window.get_widget("vmm-create-net")
|
||||
self.err = vmmErrorDialog(self.topwin,
|
||||
0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
|
||||
_("Unexpected Error"),
|
||||
_("An unexpected error occurred"))
|
||||
self.topwin.hide()
|
||||
self.window.signal_autoconnect({
|
||||
"on_create_pages_switch_page" : self.page_changed,
|
||||
@ -295,41 +301,40 @@ class vmmCreateNetwork(gobject.GObject):
|
||||
|
||||
logging.debug("About to create network " + xml)
|
||||
|
||||
self.conn.create_network(xml)
|
||||
try:
|
||||
self.conn.create_network(xml)
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Error creating virtual network: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
self.close()
|
||||
|
||||
def validate(self, page_num):
|
||||
if page_num == PAGE_NAME:
|
||||
name = self.window.get_widget("net-name").get_text()
|
||||
if len(name) > 50 or len(name) == 0:
|
||||
self._validation_error_box(_("Invalid Network Name"), \
|
||||
_("Network name must be non-blank and less than 50 characters"))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid Network Name"), \
|
||||
_("Network name must be non-blank and less than 50 characters"))
|
||||
if re.match("^[a-zA-Z0-9_]*$", name) == None:
|
||||
self._validation_error_box(_("Invalid Network Name"), \
|
||||
_("Network name may contain alphanumeric and '_' characters only"))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid Network Name"), \
|
||||
_("Network name may contain alphanumeric and '_' characters only"))
|
||||
|
||||
|
||||
elif page_num == PAGE_IPV4:
|
||||
ip = self.get_config_ip4()
|
||||
if ip is None:
|
||||
self._validation_error_box(_("Invalid Network Address"), \
|
||||
_("The network address could not be understood"))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid Network Address"), \
|
||||
_("The network address could not be understood"))
|
||||
|
||||
if ip.version() != 4:
|
||||
self._validation_error_box(_("Invalid Network Address"), \
|
||||
_("The network must be an IPv4 address"))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid Network Address"), \
|
||||
_("The network must be an IPv4 address"))
|
||||
|
||||
if ip.len() < 16:
|
||||
self._validation_error_box(_("Invalid Network Address"), \
|
||||
_("The network prefix must be at least /4 (16 addresses)"))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid Network Address"), \
|
||||
_("The network prefix must be at least /4 (16 addresses)"))
|
||||
|
||||
if ip.iptype() != "PRIVATE":
|
||||
res = self._yes_no_box(_("Check Network Address"), \
|
||||
res = self.err.yes_no(_("Check Network Address"), \
|
||||
_("The network should normally use a private IPv4 address. Use this non-private address anyway?"))
|
||||
if not res:
|
||||
return False
|
||||
@ -339,60 +344,29 @@ class vmmCreateNetwork(gobject.GObject):
|
||||
end = self.get_config_dhcp_end()
|
||||
|
||||
if start is None:
|
||||
self._validation_error_box(_("Invalid DHCP Address"), \
|
||||
_("The DHCP start address could not be understood"))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid DHCP Address"), \
|
||||
_("The DHCP start address could not be understood"))
|
||||
if end is None:
|
||||
self._validation_error_box(_("Invalid DHCP Address"), \
|
||||
_("The DHCP end address could not be understood"))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid DHCP Address"), \
|
||||
_("The DHCP end address could not be understood"))
|
||||
|
||||
if not ip.overlaps(start):
|
||||
self._validation_error_box(_("Invalid DHCP Address"), \
|
||||
_("The DHCP start address is not with the network %s") % (str(ip)))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid DHCP Address"), \
|
||||
_("The DHCP start address is not with the network %s") % (str(ip)))
|
||||
if not ip.overlaps(end):
|
||||
self._validation_error_box(_("Invalid DHCP Address"), \
|
||||
_("The DHCP end address is not with the network %s") % (str(ip)))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid DHCP Address"), \
|
||||
_("The DHCP end address is not with the network %s") % (str(ip)))
|
||||
elif page_num == PAGE_FORWARDING:
|
||||
if self.window.get_widget("net-forward-dev").get_active():
|
||||
dev = self.window.get_widget("net-forward")
|
||||
if dev.get_active() == -1:
|
||||
self._validation_error_box(_("Invalid forwarding mode"), \
|
||||
_("Please select where the traffic should be forwarded"))
|
||||
return False
|
||||
return self.err.val_err(_("Invalid forwarding mode"), \
|
||||
_("Please select where the traffic should be forwarded"))
|
||||
|
||||
# do this always, since there's no "leaving a notebook page" event.
|
||||
self.window.get_widget("create-back").set_sensitive(True)
|
||||
return True
|
||||
|
||||
def _validation_error_box(self, text1, text2=None):
|
||||
message_box = gtk.MessageDialog(self.window.get_widget("vmm-create-net"), \
|
||||
0, \
|
||||
gtk.MESSAGE_ERROR, \
|
||||
gtk.BUTTONS_OK, \
|
||||
text1)
|
||||
if text2 != None:
|
||||
message_box.format_secondary_text(text2)
|
||||
message_box.run()
|
||||
message_box.destroy()
|
||||
|
||||
def _yes_no_box(self, text1, text2=None):
|
||||
message_box = gtk.MessageDialog(self.window.get_widget("vmm-create-net"), \
|
||||
0, \
|
||||
gtk.MESSAGE_WARNING, \
|
||||
gtk.BUTTONS_YES_NO, \
|
||||
text1)
|
||||
if text2 != None:
|
||||
message_box.format_secondary_text(text2)
|
||||
if message_box.run()== gtk.RESPONSE_YES:
|
||||
res = True
|
||||
else:
|
||||
res = False
|
||||
message_box.destroy()
|
||||
return res
|
||||
|
||||
def populate_opt_media(self, model):
|
||||
# get a list of optical devices with data discs in, for FV installs
|
||||
vollabel = {}
|
||||
@ -404,10 +378,11 @@ class vmmCreateNetwork(gobject.GObject):
|
||||
# Find info about all current present media
|
||||
for d in self.hal_iface.FindDeviceByCapability("volume"):
|
||||
vol = self.bus.get_object("org.freedesktop.Hal", d)
|
||||
if vol.GetPropertyBoolean("volume.is_disc") and \
|
||||
vol.GetPropertyBoolean("volume.disc.has_data"):
|
||||
devnode = vol.GetProperty("block.device")
|
||||
label = vol.GetProperty("volume.label")
|
||||
volif = dbus.Interface(vol, "org.freedesktop.Hal.Device")
|
||||
if volif.GetPropertyBoolean("volume.is_disc") and \
|
||||
volif.GetPropertyBoolean("volume.disc.has_data"):
|
||||
devnode = volif.GetProperty("block.device")
|
||||
label = volif.GetProperty("volume.label")
|
||||
if label == None or len(label) == 0:
|
||||
label = devnode
|
||||
vollabel[devnode] = label
|
||||
@ -416,7 +391,8 @@ class vmmCreateNetwork(gobject.GObject):
|
||||
|
||||
for d in self.hal_iface.FindDeviceByCapability("storage.cdrom"):
|
||||
dev = self.bus.get_object("org.freedesktop.Hal", d)
|
||||
devnode = dev.GetProperty("block.device")
|
||||
devif = dbus.Interface(dev, "org.freedesktop.Hal.Device")
|
||||
devnode = devif.GetProperty("block.device")
|
||||
if vollabel.has_key(devnode):
|
||||
model.append([devnode, vollabel[devnode], True, volpath[devnode]])
|
||||
else:
|
||||
|
@ -49,6 +49,7 @@ HW_LIST_TYPE_DISK = 2
|
||||
HW_LIST_TYPE_NIC = 3
|
||||
HW_LIST_TYPE_INPUT = 4
|
||||
HW_LIST_TYPE_GRAPHICS = 5
|
||||
HW_LIST_TYPE_BOOT = 6
|
||||
|
||||
class vmmDetails(gobject.GObject):
|
||||
__gsignals__ = {
|
||||
@ -80,6 +81,10 @@ class vmmDetails(gobject.GObject):
|
||||
self.vm = vm
|
||||
|
||||
topwin = self.window.get_widget("vmm-details")
|
||||
self.err = vmmErrorDialog(topwin,
|
||||
0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
|
||||
_("Unexpected Error"),
|
||||
_("An unexpected error occurred"))
|
||||
topwin.hide()
|
||||
topwin.set_title(self.vm.get_name() + " " + topwin.get_title())
|
||||
|
||||
@ -134,6 +139,9 @@ class vmmDetails(gobject.GObject):
|
||||
"on_config_memory_changed": self.config_memory_changed,
|
||||
"on_config_maxmem_changed": self.config_maxmem_changed,
|
||||
"on_config_memory_apply_clicked": self.config_memory_apply,
|
||||
"on_config_boot_device_changed": self.config_boot_options_changed,
|
||||
"on_config_autostart_changed": self.config_boot_options_changed,
|
||||
"on_config_boot_apply_clicked": self.config_boot_options_apply,
|
||||
"on_details_help_activate": self.show_help,
|
||||
|
||||
"on_config_cdrom_connect_clicked": self.toggle_cdrom,
|
||||
@ -216,6 +224,9 @@ class vmmDetails(gobject.GObject):
|
||||
self.refresh_input_page()
|
||||
elif pagetype == HW_LIST_TYPE_GRAPHICS:
|
||||
self.refresh_graphics_page()
|
||||
elif pagetype == HW_LIST_TYPE_BOOT:
|
||||
self.refresh_boot_page()
|
||||
self.window.get_widget("config-boot-options-apply").set_sensitive(False)
|
||||
else:
|
||||
pagenum = -1
|
||||
|
||||
@ -275,7 +286,7 @@ class vmmDetails(gobject.GObject):
|
||||
self.window.get_widget("details-menu-run").set_sensitive(False)
|
||||
self.window.get_widget("config-vcpus").set_sensitive(self.vm.is_vcpu_hotplug_capable())
|
||||
self.window.get_widget("config-memory").set_sensitive(self.vm.is_memory_hotplug_capable())
|
||||
self.window.get_widget("config-maxmem").set_sensitive(False)
|
||||
self.window.get_widget("config-maxmem").set_sensitive(True)
|
||||
|
||||
if status in [ libvirt.VIR_DOMAIN_SHUTDOWN, libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_CRASHED ] or vm.is_read_only():
|
||||
self.window.get_widget("control-pause").set_sensitive(False)
|
||||
@ -298,6 +309,7 @@ class vmmDetails(gobject.GObject):
|
||||
self.window.get_widget("details-menu-pause").set_active(False)
|
||||
except:
|
||||
self.ignorePause = False
|
||||
raise
|
||||
self.ignorePause = False
|
||||
|
||||
self.window.get_widget("overview-status-text").set_text(self.vm.run_status())
|
||||
@ -362,7 +374,7 @@ class vmmDetails(gobject.GObject):
|
||||
self.window.get_widget("state-host-cpus").set_text("%d" % self.vm.get_connection().host_active_processor_count())
|
||||
status = self.vm.status()
|
||||
if status in [ libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_CRASHED ]:
|
||||
cpu_max = self.vm.get_connection().get_max_vcpus()
|
||||
cpu_max = self.vm.get_connection().get_max_vcpus(self.vm.get_type())
|
||||
self.window.get_widget("config-vcpus").get_adjustment().upper = cpu_max
|
||||
self.window.get_widget("state-vm-maxvcpus").set_text(str(cpu_max))
|
||||
else:
|
||||
@ -379,16 +391,25 @@ class vmmDetails(gobject.GObject):
|
||||
|
||||
def refresh_config_memory(self):
|
||||
self.window.get_widget("state-host-memory").set_text("%d MB" % (int(round(self.vm.get_connection().host_memory_size()/1024))))
|
||||
|
||||
curmem = self.window.get_widget("config-memory").get_adjustment()
|
||||
maxmem = self.window.get_widget("config-maxmem").get_adjustment()
|
||||
|
||||
|
||||
if self.window.get_widget("config-memory-apply").get_property("sensitive"):
|
||||
self.window.get_widget("config-memory").get_adjustment().upper = self.window.get_widget("config-maxmem").get_adjustment().value
|
||||
if curmem.value > maxmem.value:
|
||||
curmem.value = maxmem.value
|
||||
curmem.upper = maxmem.value
|
||||
else:
|
||||
self.window.get_widget("config-memory").get_adjustment().value = int(round(self.vm.get_memory()/1024.0))
|
||||
self.window.get_widget("config-maxmem").get_adjustment().value = int(round(self.vm.maximum_memory()/1024.0))
|
||||
curmem.value = int(round(self.vm.get_memory()/1024.0))
|
||||
maxmem.value = int(round(self.vm.maximum_memory()/1024.0))
|
||||
# XXX hack - changing the value above will have just re-triggered
|
||||
# the callback making apply button sensitive again. So we have to
|
||||
# turn it off again....
|
||||
self.window.get_widget("config-memory-apply").set_sensitive(False)
|
||||
|
||||
if not self.window.get_widget("config-memory").get_property("sensitive"):
|
||||
maxmem.lower = curmem.value
|
||||
self.window.get_widget("state-vm-memory").set_text("%d MB" % int(round(self.vm.get_memory()/1024.0)))
|
||||
|
||||
def refresh_disk_page(self):
|
||||
@ -483,11 +504,13 @@ class vmmDetails(gobject.GObject):
|
||||
self.window.get_widget("graphics-port").set_text(_("Automatically allocated"))
|
||||
else:
|
||||
self.window.get_widget("graphics-port").set_text(inputinfo[2])
|
||||
self.window.get_widget("graphics-password").set_text("")
|
||||
self.window.get_widget("graphics-password").set_text("-")
|
||||
self.window.get_widget("graphics-keymap").set_text(inputinfo[4] or _("Same as host"))
|
||||
else:
|
||||
self.window.get_widget("graphics-address").set_text(_("N/A"))
|
||||
self.window.get_widget("graphics-port").set_text(_("N/A"))
|
||||
self.window.get_widget("graphics-password").set_text("N/A")
|
||||
self.window.get_widget("graphics-keymap").set_text("N/A")
|
||||
|
||||
# Can't remove display from live guest
|
||||
if self.vm.is_active():
|
||||
@ -495,6 +518,40 @@ class vmmDetails(gobject.GObject):
|
||||
else:
|
||||
self.window.get_widget("config-input-remove").set_sensitive(True)
|
||||
|
||||
def refresh_boot_page(self):
|
||||
# Refresh autostart
|
||||
try:
|
||||
autoval = self.vm.get_autostart()
|
||||
self.window.get_widget("config-autostart").set_active(autoval)
|
||||
self.window.get_widget("config-autostart").set_sensitive(True)
|
||||
except libvirt.libvirtError, e:
|
||||
# Autostart isn't supported
|
||||
self.window.get_widget("config-autostart").set_active(False)
|
||||
self.window.get_widget("config-autostart").set_sensitive(False)
|
||||
|
||||
# Refresh Boot Device list and correct selection
|
||||
boot_combo = self.window.get_widget("config-boot-device")
|
||||
if not self.vm.is_hvm():
|
||||
# Boot dev selection not supported for PV guest
|
||||
boot_combo.set_sensitive(False)
|
||||
boot_combo.set_active(-1)
|
||||
return
|
||||
|
||||
self.repopulate_boot_list()
|
||||
bootdev = self.vm.get_boot_device()
|
||||
boot_combo = self.window.get_widget("config-boot-device")
|
||||
boot_model = boot_combo.get_model()
|
||||
for i in range(0, len(boot_model)):
|
||||
if bootdev == boot_model[i][2]:
|
||||
boot_combo.set_active(i)
|
||||
break
|
||||
|
||||
if boot_model[0][2] == None:
|
||||
# If no boot devices, select the 'No Device' entry
|
||||
boot_combo.set_active(0)
|
||||
|
||||
# TODO: if nothing selected, what to select? auto change device?
|
||||
|
||||
def config_vcpus_changed(self, src):
|
||||
self.window.get_widget("config-vcpus-apply").set_sensitive(True)
|
||||
|
||||
@ -517,16 +574,67 @@ class vmmDetails(gobject.GObject):
|
||||
|
||||
def config_memory_apply(self, src):
|
||||
status = self.vm.status()
|
||||
if status in [ libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_CRASHED ]:
|
||||
memory = self.window.get_widget("config-maxmem").get_adjustment().value
|
||||
logging.info("Setting max memory for " + self.vm.get_uuid() + " to " + str(memory))
|
||||
self.vm.set_max_memory(memory*1024)
|
||||
memory = self.window.get_widget("config-memory").get_adjustment().value
|
||||
logging.info("Setting memory for " + self.vm.get_uuid() + " to " + str(memory))
|
||||
self.vm.set_memory(memory*1024)
|
||||
self.refresh_config_memory()
|
||||
exc = None
|
||||
curmem = None
|
||||
maxmem = self.window.get_widget("config-maxmem").get_adjustment()
|
||||
if self.window.get_widget("config-memory").get_property("sensitive"):
|
||||
curmem = self.window.get_widget("config-memory").get_adjustment()
|
||||
|
||||
self.window.get_widget("config-memory-apply").set_sensitive(False)
|
||||
logging.info("Setting max-memory for " + self.vm.get_name() + \
|
||||
" to " + str(maxmem.value))
|
||||
|
||||
actual_cur = self.vm.get_memory()
|
||||
if curmem is not None:
|
||||
logging.info("Setting memory for " + self.vm.get_name() + \
|
||||
" to " + str(curmem.value))
|
||||
if (maxmem.value * 1024) < actual_cur:
|
||||
# Set current first to avoid error
|
||||
try:
|
||||
self.vm.set_memory(curmem.value * 1024)
|
||||
self.vm.set_max_memory(maxmem.value * 1024)
|
||||
except Exception, e:
|
||||
exc = e
|
||||
else:
|
||||
try:
|
||||
self.vm.set_max_memory(maxmem.value * 1024)
|
||||
self.vm.set_memory(curmem.value * 1024)
|
||||
except Exception, e:
|
||||
exc = e
|
||||
|
||||
else:
|
||||
try:
|
||||
self.vm.set_max_memory(maxmem.value * 1024)
|
||||
except Exception, e:
|
||||
exc = e
|
||||
|
||||
if exc:
|
||||
self.err.show_err(_("Error changing memory values: %s" % str(e)),\
|
||||
"".join(traceback.format_exc()))
|
||||
else:
|
||||
self.window.get_widget("config-memory-apply").set_sensitive(False)
|
||||
|
||||
def config_boot_options_changed(self, src):
|
||||
self.window.get_widget("config-boot-options-apply").set_sensitive(True)
|
||||
|
||||
def config_boot_options_apply(self, src):
|
||||
boot = self.window.get_widget("config-boot-device")
|
||||
auto = self.window.get_widget("config-autostart")
|
||||
if auto.get_property("sensitive"):
|
||||
try:
|
||||
self.vm.set_autostart(auto.get_active())
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Error changing autostart value: %s") % \
|
||||
str(e), "".join(traceback.format_exc()))
|
||||
|
||||
if boot.get_property("sensitive"):
|
||||
try:
|
||||
self.vm.set_boot_device(boot.get_model()[boot.get_active()][2])
|
||||
self.window.get_widget("config-boot-options-apply").set_sensitive(False)
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Error changing boot device: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
return
|
||||
|
||||
def remove_disk(self, src):
|
||||
vmlist = self.window.get_widget("hw-list")
|
||||
@ -553,9 +661,9 @@ class vmmDetails(gobject.GObject):
|
||||
else:
|
||||
vnic = virtinst.VirtualNetworkInterface(type=netinfo[0], macaddr=netinfo[3])
|
||||
except ValueError, e:
|
||||
self.err_dialog(_("Error Removing Network: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
return
|
||||
self.err.show_err(_("Error Removing Network: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
return False
|
||||
|
||||
xml = vnic.get_xml_config()
|
||||
self.remove_device(xml)
|
||||
@ -597,14 +705,30 @@ class vmmDetails(gobject.GObject):
|
||||
hwCol.add_attribute(hw_img, 'stock-size', HW_LIST_COL_STOCK_SIZE)
|
||||
hwCol.add_attribute(hw_img, 'pixbuf', HW_LIST_COL_PIXBUF)
|
||||
self.window.get_widget("hw-list").append_column(hwCol)
|
||||
self.prepare_boot_list()
|
||||
|
||||
self.populate_hw_list()
|
||||
self.repopulate_boot_list()
|
||||
|
||||
def prepare_boot_list(self):
|
||||
boot_list = self.window.get_widget("config-boot-device")
|
||||
# model = [ display name, icon name, boot type (hd, fd, etc) ]
|
||||
boot_list_model = gtk.ListStore(str, str, str)
|
||||
boot_list.set_model(boot_list_model)
|
||||
|
||||
icon = gtk.CellRendererPixbuf()
|
||||
boot_list.pack_start(icon, False)
|
||||
boot_list.add_attribute(icon, 'stock-id', 1)
|
||||
text = gtk.CellRendererText()
|
||||
boot_list.pack_start(text, True)
|
||||
boot_list.add_attribute(text, 'text', 0)
|
||||
|
||||
def populate_hw_list(self):
|
||||
hw_list_model = self.window.get_widget("hw-list").get_model()
|
||||
hw_list_model.clear()
|
||||
hw_list_model.append(["Processor", None, 0, self.pixbuf_processor, HW_LIST_TYPE_CPU, []])
|
||||
hw_list_model.append(["Memory", None, 0, self.pixbuf_memory, HW_LIST_TYPE_MEMORY, []])
|
||||
hw_list_model.append(["Boot Options", None, 0, self.pixbuf_memory, HW_LIST_TYPE_BOOT, []])
|
||||
self.repopulate_hw_list()
|
||||
|
||||
def repopulate_hw_list(self):
|
||||
@ -725,6 +849,36 @@ class vmmDetails(gobject.GObject):
|
||||
# Now actually remove it
|
||||
hw_list_model.remove(iter)
|
||||
|
||||
def repopulate_boot_list(self):
|
||||
hw_list_model = self.window.get_widget("hw-list").get_model()
|
||||
boot_combo = self.window.get_widget("config-boot-device")
|
||||
boot_model = boot_combo.get_model()
|
||||
boot_model.clear()
|
||||
found_dev = {}
|
||||
for row in hw_list_model:
|
||||
if row[4] == HW_LIST_TYPE_DISK:
|
||||
disk = row[5]
|
||||
if disk[2] == virtinst.VirtualDisk.DEVICE_DISK and not \
|
||||
found_dev.get(virtinst.VirtualDisk.DEVICE_DISK, False):
|
||||
boot_model.append(["Hard Disk", gtk.STOCK_HARDDISK, "hd"])
|
||||
found_dev[virtinst.VirtualDisk.DEVICE_DISK] = True
|
||||
elif disk[2] == virtinst.VirtualDisk.DEVICE_CDROM and not \
|
||||
found_dev.get(virtinst.VirtualDisk.DEVICE_CDROM, False):
|
||||
boot_model.append(["CDROM", gtk.STOCK_CDROM, "cdrom"])
|
||||
found_dev[virtinst.VirtualDisk.DEVICE_CDROM] = True
|
||||
elif disk[2] == virtinst.VirtualDisk.DEVICE_FLOPPY and not \
|
||||
found_dev.get(virtinst.VirtualDisk.DEVICE_FLOPPY, False):
|
||||
boot_model.append(["Floppy", gtk.STOCK_FLOPPY, "fd"])
|
||||
found_dev[virtinst.VirtualDisk.DEVICE_FLOPPY] = True
|
||||
elif row[4] == HW_LIST_TYPE_NIC and not \
|
||||
found_dev.get(HW_LIST_TYPE_NIC, False):
|
||||
boot_model.append(["Network (PXE)", gtk.STOCK_NETWORK, "network"])
|
||||
found_dev[HW_LIST_TYPE_NIC] = True
|
||||
|
||||
if len(boot_model) <= 0:
|
||||
boot_model.append([_("No Boot Device"), None, None])
|
||||
|
||||
boot_combo.set_model(boot_model)
|
||||
|
||||
def add_hardware(self, src):
|
||||
if self.addhw is None:
|
||||
@ -742,8 +896,8 @@ class vmmDetails(gobject.GObject):
|
||||
try:
|
||||
self.vm.disconnect_cdrom_device(self.window.get_widget("disk-target-device").get_text())
|
||||
except Exception, e:
|
||||
self._err_dialog(_("Error Removing CDROM: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
self.err.show_err(_("Error Removing CDROM: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
return
|
||||
|
||||
else:
|
||||
@ -759,21 +913,14 @@ class vmmDetails(gobject.GObject):
|
||||
try:
|
||||
self.vm.connect_cdrom_device(type, source, target)
|
||||
except Exception, e:
|
||||
self._err_dialog(_("Error Connecting CDROM: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
self.err.show_err(_("Error Connecting CDROM: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
|
||||
def remove_device(self, xml):
|
||||
try:
|
||||
self.vm.remove_device(xml)
|
||||
except Exception, e:
|
||||
self._err_dialog(_("Error Removing Device: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
self.err.show_err(_("Error Removing Device: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
|
||||
def _err_dialog(self, summary, details):
|
||||
dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE, summary, details)
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
|
||||
gobject.type_register(vmmDetails)
|
||||
|
@ -115,12 +115,17 @@ class vmmDomain(gobject.GObject):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_type(self):
|
||||
return self.get_xml_string("/domain/@type")
|
||||
|
||||
def is_vcpu_hotplug_capable(self):
|
||||
# Read only connections aren't allowed to change it
|
||||
if self.connection.is_read_only():
|
||||
return False
|
||||
# Running paravirt guests can change it, or any inactive guest
|
||||
if self.vm.OSType() == "linux" or self.get_id() < 0:
|
||||
if self.vm.OSType() == "linux" \
|
||||
or self.status() not in [libvirt.VIR_DOMAIN_RUNNING,\
|
||||
libvirt.VIR_DOMAIN_PAUSED]:
|
||||
return True
|
||||
# Everyone else is out of luck
|
||||
return False
|
||||
@ -130,7 +135,9 @@ class vmmDomain(gobject.GObject):
|
||||
if self.connection.is_read_only():
|
||||
return False
|
||||
# Running paravirt guests can change it, or any inactive guest
|
||||
if self.vm.OSType() == "linux" or self.get_id() < 0:
|
||||
if self.vm.OSType() == "linux" \
|
||||
or self.status() not in [libvirt.VIR_DOMAIN_RUNNING,\
|
||||
libvirt.VIR_DOMAIN_PAUSED]:
|
||||
return True
|
||||
# Everyone else is out of luck
|
||||
return False
|
||||
@ -390,8 +397,14 @@ class vmmDomain(gobject.GObject):
|
||||
self.vm.resume()
|
||||
self._update_status()
|
||||
|
||||
def save(self, file, ignore1=None):
|
||||
self.vm.save(file)
|
||||
def save(self, file, ignore1=None, background=True):
|
||||
if background:
|
||||
conn = libvirt.open(self.connection.uri)
|
||||
vm = conn.lookupByID(self.get_id())
|
||||
else:
|
||||
vm = self.vm
|
||||
|
||||
vm.save(file)
|
||||
self._update_status()
|
||||
|
||||
def destroy(self):
|
||||
@ -545,14 +558,18 @@ class vmmDomain(gobject.GObject):
|
||||
def _change_cdrom(self, newxml, origxml):
|
||||
# If vm is shutoff, remove device, and redefine with media
|
||||
if not self.is_active():
|
||||
logging.debug("_change_cdrom: removing original xml")
|
||||
self.remove_device(origxml)
|
||||
try:
|
||||
logging.debug("_change_cdrom: adding new xml")
|
||||
self.add_device(newxml)
|
||||
except Exception, e1:
|
||||
logging.debug("_change_cdrom: adding new xml failed. attempting to readd original device")
|
||||
try:
|
||||
self.add_device(origxml) # Try to re-add original
|
||||
except:
|
||||
raise e1
|
||||
except Exception, e2:
|
||||
raise RuntimeError(_("Failed to change cdrom and re-add original device. Exceptions were: \n%s\n%s") % (str(e1), str(e2)))
|
||||
raise e1
|
||||
else:
|
||||
self.vm.attachDevice(newxml)
|
||||
vmxml = self.vm.XMLDesc(0)
|
||||
@ -566,13 +583,18 @@ class vmmDomain(gobject.GObject):
|
||||
doc = libxml2.parseDoc(xml)
|
||||
ctx = doc.xpathNewContext()
|
||||
disk_fragment = ctx.xpathEval("/disk")
|
||||
driver_fragment = ctx.xpathEval("/disk/driver")
|
||||
origdisk = disk_fragment[0].serialize()
|
||||
disk_fragment[0].setProp("type", type)
|
||||
elem = disk_fragment[0].newChild(None, "source", None)
|
||||
if type == "file":
|
||||
elem.setProp("file", source)
|
||||
if driver_fragment:
|
||||
driver_fragment.setProp("name", type)
|
||||
else:
|
||||
elem.setProp("dev", source)
|
||||
if driver_fragment:
|
||||
driver_fragment.setProp("name", "phy")
|
||||
result = disk_fragment[0].serialize()
|
||||
logging.debug("connect_cdrom_device produced the following XML: %s" % result)
|
||||
finally:
|
||||
@ -694,7 +716,8 @@ class vmmDomain(gobject.GObject):
|
||||
if type == "vnc":
|
||||
listen = node.prop("listen")
|
||||
port = node.prop("port")
|
||||
graphics.append([type, listen, port, type])
|
||||
keymap = node.prop("keymap")
|
||||
graphics.append([type, listen, port, type, keymap])
|
||||
else:
|
||||
graphics.append([type, None, None, type])
|
||||
finally:
|
||||
@ -823,7 +846,10 @@ class vmmDomain(gobject.GObject):
|
||||
|
||||
def set_memory(self, memory):
|
||||
memory = int(memory)
|
||||
if (memory > self.maximum_memory()):
|
||||
# capture updated information due to failing to get proper maxmem setting
|
||||
# if both current & max allocation are set simultaneously
|
||||
maxmem = self.vm.info()
|
||||
if (memory > maxmem[1]):
|
||||
logging.warning("Requested memory " + str(memory) + " over maximum " + str(self.maximum_memory()))
|
||||
memory = self.maximum_memory()
|
||||
self.vm.setMemory(memory)
|
||||
@ -832,4 +858,64 @@ class vmmDomain(gobject.GObject):
|
||||
memory = int(memory)
|
||||
self.vm.setMaxMemory(memory)
|
||||
|
||||
def get_autostart(self):
|
||||
return self.vm.autostart()
|
||||
|
||||
def set_autostart(self, val):
|
||||
if self.get_autostart() != val:
|
||||
self.vm.setAutostart(val)
|
||||
|
||||
def get_boot_device(self):
|
||||
xml = self.get_xml()
|
||||
doc = None
|
||||
try:
|
||||
doc = libxml2.parseDoc(xml)
|
||||
except:
|
||||
return []
|
||||
ctx = doc.xpathNewContext()
|
||||
graphics = []
|
||||
dev = None
|
||||
try:
|
||||
ret = ctx.xpathEval("/domain/os/boot[1]")
|
||||
for node in ret:
|
||||
dev = node.prop("dev")
|
||||
finally:
|
||||
if ctx != None:
|
||||
ctx.xpathFreeContext()
|
||||
if doc != None:
|
||||
doc.freeDoc()
|
||||
return dev
|
||||
|
||||
def set_boot_device(self, boot_type):
|
||||
logging.debug("Setting boot device to type: %s" % boot_type)
|
||||
xml = self.get_xml()
|
||||
doc = None
|
||||
try:
|
||||
doc = libxml2.parseDoc(xml)
|
||||
except:
|
||||
return []
|
||||
ctx = doc.xpathNewContext()
|
||||
graphics = []
|
||||
dev = None
|
||||
try:
|
||||
ret = ctx.xpathEval("/domain/os/boot[1]")
|
||||
if len(ret) > 0:
|
||||
ret[0].unlinkNode()
|
||||
ret[0].freeNode()
|
||||
emptyxml=doc.serialize()
|
||||
index = emptyxml.find("</os>")
|
||||
newxml = emptyxml[0:index] + \
|
||||
"<boot dev=\"" + boot_type + "\"/>\n" + \
|
||||
emptyxml[index:]
|
||||
logging.debug("New boot device, redefining with: " + newxml)
|
||||
self.get_connection().define_domain(newxml)
|
||||
finally:
|
||||
if ctx != None:
|
||||
ctx.xpathFreeContext()
|
||||
if doc != None:
|
||||
doc.freeDoc()
|
||||
|
||||
# Invalidate cached xml
|
||||
self.xml = None
|
||||
|
||||
gobject.type_register(vmmDomain)
|
||||
|
@ -55,6 +55,10 @@ class vmmEngine(gobject.GObject):
|
||||
self.windowCreate = None
|
||||
self.windowManager = None
|
||||
self.connections = {}
|
||||
self.err = vmmErrorDialog(None,
|
||||
0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
|
||||
_("Unexpected Error"),
|
||||
_("An unexpected error occurred"))
|
||||
|
||||
self.timer = None
|
||||
self.last_timeout = 0
|
||||
@ -66,6 +70,7 @@ class vmmEngine(gobject.GObject):
|
||||
|
||||
self.schedule_timer()
|
||||
self.load_stored_uris()
|
||||
self.autostart_connections()
|
||||
self.tick()
|
||||
|
||||
def load_stored_uris(self):
|
||||
@ -75,6 +80,12 @@ class vmmEngine(gobject.GObject):
|
||||
for uri in uris:
|
||||
self.add_connection(uri)
|
||||
|
||||
def autostart_connections(self):
|
||||
for uri in self.connections:
|
||||
conn = self.connections[uri]["connection"]
|
||||
if conn.get_autoconnect():
|
||||
self.connect_to_uri(uri)
|
||||
|
||||
def connect_to_uri(self, uri, readOnly=None):
|
||||
return self._connect_to_uri(None, uri, readOnly)
|
||||
|
||||
@ -185,6 +196,10 @@ class vmmEngine(gobject.GObject):
|
||||
self.show_console(uri, uuid)
|
||||
def _do_show_terminal(self, src, uri, uuid):
|
||||
self.show_serial_console(uri, uuid)
|
||||
def _do_refresh_console(self, src, uri, uuid):
|
||||
self.refresh_console(uri, uuid)
|
||||
def _do_refresh_terminal(self, src, uri, uuid):
|
||||
self.refresh_serial_console(uri, uuid)
|
||||
def _do_save_domain(self, src, uri, uuid):
|
||||
self.save_domain(src, uri, uuid)
|
||||
def _do_destroy_domain(self, src, uri, uuid):
|
||||
@ -220,7 +235,7 @@ class vmmEngine(gobject.GObject):
|
||||
|
||||
if self.connections[uri]["windowHost"] == None:
|
||||
manager = vmmHost(self.get_config(), con)
|
||||
manager.connect("action-show-help", self._do_show_help)
|
||||
manager.connect("action-show-about", self._do_show_about)
|
||||
self.connections[uri]["windowHost"] = manager
|
||||
self.connections[uri]["windowHost"].show()
|
||||
|
||||
@ -258,6 +273,30 @@ class vmmEngine(gobject.GObject):
|
||||
self.connections[uri]["windowSerialConsole"][uuid] = console
|
||||
self.connections[uri]["windowSerialConsole"][uuid].show()
|
||||
|
||||
def refresh_console(self, uri, uuid):
|
||||
con = self.get_connection(uri)
|
||||
|
||||
if not(self.connections[uri]["windowConsole"].has_key(uuid)):
|
||||
return
|
||||
|
||||
console = self.connections[uri]["windowConsole"][uuid]
|
||||
if not(console.is_visible()):
|
||||
return
|
||||
|
||||
console.show()
|
||||
|
||||
def refresh_serial_console(self, uri, uuid):
|
||||
con = self.get_connection(uri)
|
||||
|
||||
if not(self.connections[uri]["windowSerialConsole"].has_key(uuid)):
|
||||
return
|
||||
|
||||
console = self.connections[uri]["windowSerialConsole"][uuid]
|
||||
if not(console.is_visible()):
|
||||
return
|
||||
|
||||
console.show()
|
||||
|
||||
def show_details_performance(self, uri, uuid):
|
||||
win = self.show_details(uri, uuid)
|
||||
win.activate_performance_page()
|
||||
@ -270,17 +309,21 @@ class vmmEngine(gobject.GObject):
|
||||
con = self.get_connection(uri)
|
||||
|
||||
if not(self.connections[uri]["windowDetails"].has_key(uuid)):
|
||||
details = vmmDetails(self.get_config(),
|
||||
con.get_vm(uuid))
|
||||
details.connect("action-show-console", self._do_show_console)
|
||||
details.connect("action-show-terminal", self._do_show_terminal)
|
||||
details.connect("action-save-domain", self._do_save_domain)
|
||||
details.connect("action-destroy-domain", self._do_destroy_domain)
|
||||
details.connect("action-show-help", self._do_show_help)
|
||||
details.connect("action-suspend-domain", self._do_suspend_domain)
|
||||
details.connect("action-resume-domain", self._do_resume_domain)
|
||||
details.connect("action-run-domain", self._do_run_domain)
|
||||
details.connect("action-shutdown-domain", self._do_shutdown_domain)
|
||||
try:
|
||||
details = vmmDetails(self.get_config(),
|
||||
con.get_vm(uuid))
|
||||
details.connect("action-show-console", self._do_show_console)
|
||||
details.connect("action-show-terminal", self._do_show_terminal)
|
||||
details.connect("action-save-domain", self._do_save_domain)
|
||||
details.connect("action-destroy-domain", self._do_destroy_domain)
|
||||
details.connect("action-show-help", self._do_show_help)
|
||||
details.connect("action-suspend-domain", self._do_suspend_domain)
|
||||
details.connect("action-resume-domain", self._do_resume_domain)
|
||||
details.connect("action-run-domain", self._do_run_domain)
|
||||
details.connect("action-shutdown-domain", self._do_shutdown_domain)
|
||||
except Exception, e:
|
||||
self.err.show_err(_("Error bringing up domain details: %s") % str(e),
|
||||
"".join(traceback.format_exc()))
|
||||
self.connections[uri]["windowDetails"][uuid] = details
|
||||
self.connections[uri]["windowDetails"][uuid].show()
|
||||
return self.connections[uri]["windowDetails"][uuid]
|
||||
@ -302,6 +345,8 @@ class vmmEngine(gobject.GObject):
|
||||
self.windowManager.connect("action-show-host", self._do_show_host)
|
||||
self.windowManager.connect("action-show-connect", self._do_show_connect)
|
||||
self.windowManager.connect("action-connect", self._do_connect)
|
||||
self.windowManager.connect("action-refresh-console", self._do_refresh_console)
|
||||
self.windowManager.connect("action-refresh-terminal", self._do_refresh_terminal)
|
||||
return self.windowManager
|
||||
|
||||
def show_manager(self):
|
||||
@ -359,13 +404,7 @@ class vmmEngine(gobject.GObject):
|
||||
def save_domain(self, src, uri, uuid):
|
||||
con = self.get_connection(uri, False)
|
||||
if con.is_remote():
|
||||
warn = gtk.MessageDialog(src.window.get_widget("vmm-details"),
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
gtk.MESSAGE_WARNING,
|
||||
gtk.BUTTONS_OK,
|
||||
_("Saving virtual machines over remote connections is not yet supported."))
|
||||
result = warn.run()
|
||||
warn.destroy()
|
||||
self.err.val_err(_("Saving virtual machines over remote connections is not yet supported."))
|
||||
return
|
||||
|
||||
vm = con.get_vm(uuid)
|
||||
@ -395,7 +434,7 @@ class vmmEngine(gobject.GObject):
|
||||
self.fcdialog.destroy()
|
||||
|
||||
if self._save_callback_info != []:
|
||||
self._err_dialog(_("Error saving domain: %s" % self._save_callback_info[0]), self._save_callback_info[1])
|
||||
self.err.show_err(_("Error saving domain: %s" % self._save_callback_info[0]), self._save_callback_info[1])
|
||||
self._save_callback_info = []
|
||||
|
||||
def _save_callback(self, vm, file_to_save, ignore1=None):
|
||||
@ -413,19 +452,12 @@ class vmmEngine(gobject.GObject):
|
||||
libvirt.VIR_DOMAIN_SHUTOFF ]:
|
||||
logging.warning("Destroy requested, but machine is shutdown / shutoff")
|
||||
else:
|
||||
message_box = gtk.MessageDialog(None, \
|
||||
gtk.DIALOG_MODAL, \
|
||||
gtk.MESSAGE_WARNING, \
|
||||
gtk.BUTTONS_OK_CANCEL, \
|
||||
_("About to destroy virtual machine %s" % vm.get_name()))
|
||||
message_box.format_secondary_text(_("This will immediately destroy the VM and may corrupt its disk image. Are you sure?"))
|
||||
response_id = message_box.run()
|
||||
message_box.destroy()
|
||||
if response_id == gtk.RESPONSE_OK:
|
||||
resp = self.err.yes_no(text1=_("About to destroy virtual machine %s" % vm.get_name()), text2=_("This will immediately destroy the VM and may corrupt its disk image. Are you sure?"))
|
||||
if resp:
|
||||
try:
|
||||
vm.destroy()
|
||||
except Exception, e:
|
||||
self._err_dialog(_("Error shutting down domain: %s" % str(e)), "".join(traceback.format_exc()))
|
||||
self.err.show_err(_("Error shutting down domain: %s" % str(e)), "".join(traceback.format_exc()))
|
||||
|
||||
def suspend_domain(self, src, uri, uuid):
|
||||
con = self.get_connection(uri, False)
|
||||
@ -441,8 +473,8 @@ class vmmEngine(gobject.GObject):
|
||||
try:
|
||||
vm.suspend()
|
||||
except Exception, e:
|
||||
self._err_dialog(_("Error pausing domain: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
self.err.show_err(_("Error pausing domain: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
|
||||
def resume_domain(self, src, uri, uuid):
|
||||
con = self.get_connection(uri, False)
|
||||
@ -456,8 +488,8 @@ class vmmEngine(gobject.GObject):
|
||||
try:
|
||||
vm.resume()
|
||||
except Exception, e:
|
||||
self._err_dialog(_("Error unpausing domain: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
self.err.show_err(_("Error unpausing domain: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
else:
|
||||
logging.warning("Resume requested, but machine is already running")
|
||||
|
||||
@ -471,8 +503,8 @@ class vmmEngine(gobject.GObject):
|
||||
try:
|
||||
vm.startup()
|
||||
except Exception, e:
|
||||
self._err_dialog(_("Error starting domain: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
self.err.show_err(_("Error starting domain: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
|
||||
def shutdown_domain(self, src, uri, uuid):
|
||||
con = self.get_connection(uri, False)
|
||||
@ -484,16 +516,9 @@ class vmmEngine(gobject.GObject):
|
||||
try:
|
||||
vm.shutdown()
|
||||
except Exception, e:
|
||||
self._err_dialog(_("Error shutting down domain: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
self.err.show_err(_("Error shutting down domain: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
else:
|
||||
logging.warning("Shutdown requested, but machine is already shutting down / shutoff")
|
||||
|
||||
def _err_dialog(self, summary, details):
|
||||
dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE, summary, details)
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
|
||||
gobject.type_register(vmmEngine)
|
||||
|
@ -24,21 +24,27 @@ import pango
|
||||
class vmmErrorDialog (gtk.MessageDialog):
|
||||
def __init__ (self, parent=None, flags=0, type=gtk.MESSAGE_INFO,
|
||||
buttons=gtk.BUTTONS_NONE, message_format=None,
|
||||
message_details=None):
|
||||
message_details=None, default_title=_("Error")):
|
||||
gtk.MessageDialog.__init__ (self,
|
||||
parent, flags, type, buttons,
|
||||
message_format)
|
||||
self.message_format = message_format
|
||||
self.message_details = message_details
|
||||
self.buffer = None
|
||||
self.default_title = default_title
|
||||
self.set_title(self.default_title)
|
||||
self.set_property("text", self.message_format)
|
||||
|
||||
if not message_details is None:
|
||||
# Expander section with details.
|
||||
expander = gtk.Expander (_("Details"))
|
||||
buffer = gtk.TextBuffer ()
|
||||
buffer.set_text (message_details)
|
||||
self.buffer = gtk.TextBuffer ()
|
||||
self.buffer.set_text (self.message_details)
|
||||
sw = gtk.ScrolledWindow ()
|
||||
sw.set_shadow_type (gtk.SHADOW_IN)
|
||||
sw.set_size_request (400, 240)
|
||||
sw.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
details = gtk.TextView (buffer)
|
||||
details = gtk.TextView (self.buffer)
|
||||
details.set_editable (False)
|
||||
details.set_overwrite (False)
|
||||
details.set_cursor_visible (False)
|
||||
@ -49,3 +55,41 @@ class vmmErrorDialog (gtk.MessageDialog):
|
||||
sw.show ()
|
||||
self.vbox.pack_start (expander)
|
||||
expander.show ()
|
||||
|
||||
def show_err(self, summary, details, title=None):
|
||||
if title is None:
|
||||
title = self.default_title
|
||||
self.set_title(title)
|
||||
self.set_property("text", summary)
|
||||
self.buffer.set_text(details)
|
||||
self.run()
|
||||
self.hide()
|
||||
|
||||
def val_err(self, text1, text2=None, title=None):
|
||||
message_box = gtk.MessageDialog(self.parent, \
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT, \
|
||||
gtk.MESSAGE_ERROR,\
|
||||
gtk.BUTTONS_OK, text1)
|
||||
if title is None:
|
||||
title = _("Input Error")
|
||||
message_box.set_title(title)
|
||||
if text2 is not None:
|
||||
message_box.format_secondary_text(text2)
|
||||
message_box.run()
|
||||
message_box.destroy()
|
||||
return False
|
||||
|
||||
def yes_no(self, text1, text2=None):
|
||||
message_box = gtk.MessageDialog(self.parent, \
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT, \
|
||||
gtk.MESSAGE_WARNING, \
|
||||
gtk.BUTTONS_YES_NO, text1)
|
||||
if text2 != None:
|
||||
message_box.format_secondary_text(text2)
|
||||
if message_box.run()== gtk.RESPONSE_YES:
|
||||
res = True
|
||||
else:
|
||||
res = False
|
||||
message_box.destroy()
|
||||
return res
|
||||
|
||||
|
@ -27,11 +27,12 @@ import logging
|
||||
import os
|
||||
|
||||
from virtManager.createnet import vmmCreateNetwork
|
||||
from virtManager.error import vmmErrorDialog
|
||||
|
||||
class vmmHost(gobject.GObject):
|
||||
__gsignals__ = {
|
||||
"action-show-help": (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, [str]),
|
||||
"action-show-about": (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, []),
|
||||
}
|
||||
def __init__(self, config, conn):
|
||||
self.__gobject_init__()
|
||||
@ -42,12 +43,18 @@ class vmmHost(gobject.GObject):
|
||||
topwin = self.window.get_widget("vmm-host")
|
||||
topwin.hide()
|
||||
|
||||
self.err = vmmErrorDialog(topwin,
|
||||
0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
|
||||
_("Unexpected Error"),
|
||||
_("An unexpected error occurred"))
|
||||
|
||||
self.window.get_widget("overview-uri").set_text(self.conn.get_uri())
|
||||
self.window.get_widget("overview-hostname").set_text(self.conn.get_hostname(True))
|
||||
self.window.get_widget("overview-hypervisor").set_text(self.conn.get_driver())
|
||||
self.window.get_widget("overview-memory").set_text(self.conn.pretty_host_memory_size())
|
||||
self.window.get_widget("overview-cpus").set_text(str(self.conn.host_active_processor_count()))
|
||||
self.window.get_widget("overview-arch").set_text(self.conn.host_architecture())
|
||||
self.window.get_widget("config-autoconnect").set_active(conn.get_autoconnect())
|
||||
|
||||
netListModel = gtk.ListStore(str, str, str)
|
||||
self.window.get_widget("net-list").set_model(netListModel)
|
||||
@ -81,18 +88,20 @@ class vmmHost(gobject.GObject):
|
||||
self.conn.connect("net-removed", self.repopulate_networks)
|
||||
|
||||
# XXX not technically correct once we enable remote management
|
||||
if os.getuid() != 0 and not self.conn.is_remote():
|
||||
if (os.getuid() != 0 and not self.conn.is_remote()) \
|
||||
or self.conn.get_state() is self.conn.STATE_DISCONNECTED:
|
||||
self.window.get_widget("net-add").set_sensitive(False)
|
||||
|
||||
|
||||
self.window.signal_autoconnect({
|
||||
"on_menu_file_close_activate": self.close,
|
||||
"on_vmm_host_delete_event": self.close,
|
||||
"on_menu_help_about_activate": self.show_help,
|
||||
"on_menu_help_about_activate": self.show_about,
|
||||
"on_net_add_clicked": self.add_network,
|
||||
"on_net_delete_clicked": self.delete_network,
|
||||
"on_net_stop_clicked": self.stop_network,
|
||||
"on_net_start_clicked": self.start_network,
|
||||
"on_config_autoconnect_toggled": self.toggle_autoconnect,
|
||||
})
|
||||
|
||||
self.conn.connect("resources-sampled", self.refresh_resources)
|
||||
@ -101,6 +110,8 @@ class vmmHost(gobject.GObject):
|
||||
self.refresh_resources()
|
||||
|
||||
def show(self):
|
||||
# Update autostart value
|
||||
self.window.get_widget("config-autoconnect").set_active(self.conn.get_autoconnect())
|
||||
dialog = self.window.get_widget("vmm-host")
|
||||
dialog.present()
|
||||
|
||||
@ -126,23 +137,25 @@ class vmmHost(gobject.GObject):
|
||||
|
||||
def add_network(self, src):
|
||||
if self.conn.is_remote():
|
||||
warn = gtk.MessageDialog(self.window.get_widget("vmm-manager"),
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
gtk.MESSAGE_WARNING,
|
||||
gtk.BUTTONS_OK,
|
||||
_("Creating new networks on remote connections is not yet supported"))
|
||||
result = warn.run()
|
||||
warn.destroy()
|
||||
self.err.val_err(_("Creating new networks on remote connections is not yet supported"))
|
||||
return
|
||||
|
||||
if self.add is None:
|
||||
self.add = vmmCreateNetwork(self.config, self.conn)
|
||||
self.add.show()
|
||||
|
||||
def toggle_autoconnect(self, ignore=None):
|
||||
if self.conn.get_autoconnect() != \
|
||||
self.window.get_widget("config-autoconnect").get_active():
|
||||
self.conn.toggle_autoconnect()
|
||||
|
||||
def show_help(self, src):
|
||||
# From the Details window, show the help document from the Details page
|
||||
self.emit("action-show-help", "virt-manager-host-window")
|
||||
|
||||
def show_about(self, src):
|
||||
self.emit("action-show-about")
|
||||
|
||||
def close(self,ignore1=None,ignore2=None):
|
||||
self.window.get_widget("vmm-host").hide()
|
||||
return 1
|
||||
|
@ -7,23 +7,24 @@ keytable = {
|
||||
"gb":"en-gb",
|
||||
"us":"en-us",
|
||||
"es":"es",
|
||||
"":"et",
|
||||
"et":"et",
|
||||
"se_FI":"fi",
|
||||
"":"fo",
|
||||
"":"fr",
|
||||
"fi":"fi",
|
||||
"fo":"fo",
|
||||
"fr":"fr",
|
||||
"be":"fr-be",
|
||||
"":"fr-ca",
|
||||
"fr-ca":"fr-ca",
|
||||
"fr_CH":"fr_ch",
|
||||
"hr":"hr",
|
||||
"":"hu",
|
||||
"":"is",
|
||||
"hu":"hu",
|
||||
"is":"is",
|
||||
"it":"it",
|
||||
"jp106":"ja",
|
||||
"lt":"lt",
|
||||
"lv":"lv",
|
||||
"mk":"mk",
|
||||
"": "nl",
|
||||
"":"nl-be",
|
||||
"nl": "nl",
|
||||
"nl-be":"nl-be",
|
||||
"no":"no",
|
||||
"pl":"pl",
|
||||
"pt":"pt",
|
||||
@ -31,7 +32,7 @@ keytable = {
|
||||
"br-abnt2":"pt-br",
|
||||
"ru":"ru",
|
||||
"sl":"sl",
|
||||
"":"sv",
|
||||
"sv":"sv",
|
||||
"th":"th",
|
||||
"tr":"tr",
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ ROW_VCPUS = 6
|
||||
ROW_MEM = 7
|
||||
ROW_MEM_USAGE = 8
|
||||
ROW_KEY = 9
|
||||
ROW_HINT = 10
|
||||
|
||||
# Columns in the tree view
|
||||
COL_NAME = 0
|
||||
@ -70,6 +71,10 @@ class vmmManager(gobject.GObject):
|
||||
gobject.TYPE_NONE, (str,str)),
|
||||
"action-show-terminal": (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, (str,str)),
|
||||
"action-refresh-console": (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, (str,str)),
|
||||
"action-refresh-terminal": (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, (str,str)),
|
||||
"action-show-details": (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, (str,str)),
|
||||
"action-show-about": (gobject.SIGNAL_RUN_FIRST,
|
||||
@ -96,6 +101,10 @@ class vmmManager(gobject.GObject):
|
||||
def __init__(self, config, engine):
|
||||
self.__gobject_init__()
|
||||
self.window = gtk.glade.XML(config.get_glade_dir() + "/vmm-manager.glade", "vmm-manager", domain="virt-manager")
|
||||
self.err = vmmErrorDialog(self.window.get_widget("vmm-manager"),
|
||||
0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
|
||||
_("Unexpected Error"),
|
||||
_("An unexpected error occurred"))
|
||||
self.config = config
|
||||
self.engine = engine
|
||||
self.connections = {}
|
||||
@ -283,13 +292,7 @@ class vmmManager(gobject.GObject):
|
||||
def restore_saved(self, src=None):
|
||||
conn = self.current_connection()
|
||||
if conn.is_remote():
|
||||
warn = gtk.MessageDialog(self.window.get_widget("vmm-manager"),
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
gtk.MESSAGE_WARNING,
|
||||
gtk.BUTTONS_OK,
|
||||
_("Restoring virtual machines over remote connections is not yet supported"))
|
||||
result = warn.run()
|
||||
warn.destroy()
|
||||
self.err.val_err(_("Restoring virtual machines over remote connections is not yet supported"))
|
||||
return
|
||||
|
||||
# get filename
|
||||
@ -312,30 +315,19 @@ class vmmManager(gobject.GObject):
|
||||
_("Restoring Virtual Machine"))
|
||||
progWin.run()
|
||||
else:
|
||||
err = gtk.MessageDialog(self.window.get_widget("vmm-manager"),
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_OK,
|
||||
_("The file '%s' does not appear to be a valid saved machine image") % file_to_load)
|
||||
err.run()
|
||||
err.destroy()
|
||||
self.err.val_err(_("The file '%s' does not appear to be a valid saved machine image") % file_to_load)
|
||||
return
|
||||
|
||||
self.fcdialog.destroy()
|
||||
if(self.domain_restore_error != ""):
|
||||
self.error_msg = gtk.MessageDialog(self.window.get_widget("vmm-manager"),
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_OK,
|
||||
self.domain_restore_error)
|
||||
self.error_msg.run()
|
||||
self.error_msg.destroy()
|
||||
self.err.val_err(self.domain_restore_error)
|
||||
self.domain_restore_error = ""
|
||||
|
||||
def is_valid_saved_image(self, file):
|
||||
try:
|
||||
f = open(file, "r")
|
||||
magic = f.read(16)
|
||||
if magic != "LinuxGuestRecord":
|
||||
if magic != "LinuxGuestRecord" and magic != "LibvirtQemudSave":
|
||||
return False
|
||||
return True
|
||||
except:
|
||||
@ -403,6 +395,9 @@ class vmmManager(gobject.GObject):
|
||||
self.emit("action-show-console", uri, vmuuid)
|
||||
elif not connect.is_remote():
|
||||
self.emit("action-show-terminal", uri, vmuuid)
|
||||
else:
|
||||
self.emit("action-refresh-console", uri, vmuuid)
|
||||
self.emit("action-refresh-terminal", uri, vmuuid)
|
||||
|
||||
def _append_vm(self, model, vm, conn):
|
||||
logging.debug("About to append vm: %s" % vm.get_name())
|
||||
@ -418,6 +413,8 @@ class vmmManager(gobject.GObject):
|
||||
row.insert(ROW_MEM, vm.get_memory_pretty())
|
||||
row.insert(ROW_MEM_USAGE, vm.current_memory_percentage())
|
||||
row.insert(ROW_KEY, vm.get_uuid())
|
||||
row.insert(ROW_HINT, None)
|
||||
|
||||
iter = model.append(parent, row)
|
||||
path = model.get_path(iter)
|
||||
self.rows[vm.get_uuid()] = model[path]
|
||||
@ -436,6 +433,8 @@ class vmmManager(gobject.GObject):
|
||||
row.insert(ROW_MEM, conn.pretty_current_memory())
|
||||
row.insert(ROW_MEM_USAGE, conn.current_memory_percentage())
|
||||
row.insert(ROW_KEY, conn.get_uri())
|
||||
row.insert(ROW_HINT, conn.get_uri())
|
||||
|
||||
iter = model.append(None, row)
|
||||
path = model.get_path(iter)
|
||||
self.rows[conn.get_uri()] = model[path]
|
||||
@ -501,6 +500,15 @@ class vmmManager(gobject.GObject):
|
||||
row[ROW_MEM_USAGE] = vm.current_memory_percentage()
|
||||
model.row_changed(row.path, row.iter)
|
||||
|
||||
if vm == self.current_vm():
|
||||
if vm.is_active():
|
||||
self.window.get_widget("vm-delete").set_sensitive(False)
|
||||
self.window.get_widget("menu_edit_delete").set_sensitive(False)
|
||||
else:
|
||||
self.window.get_widget("vm-delete").set_sensitive(True)
|
||||
self.window.get_widget("menu_edit_delete").set_sensitive(True)
|
||||
|
||||
|
||||
def conn_state_changed(self, conn):
|
||||
self.conn_refresh_resources(conn)
|
||||
|
||||
@ -711,13 +719,7 @@ class vmmManager(gobject.GObject):
|
||||
def new_vm(self, ignore=None):
|
||||
conn = self.current_connection()
|
||||
if conn.is_remote():
|
||||
warn = gtk.MessageDialog(self.window.get_widget("vmm-manager"),
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
gtk.MESSAGE_WARNING,
|
||||
gtk.BUTTONS_OK,
|
||||
_("Creating new guests on remote connections is not yet supported"))
|
||||
result = warn.run()
|
||||
warn.destroy()
|
||||
self.err.val_err(_("Creating new guests on remote connections is not yet supported"))
|
||||
else:
|
||||
self.emit("action-show-create", conn.get_uri())
|
||||
|
||||
@ -729,14 +731,8 @@ class vmmManager(gobject.GObject):
|
||||
if conn is None:
|
||||
return
|
||||
|
||||
warn = gtk.MessageDialog(self.window.get_widget("vmm-manager"),
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
gtk.MESSAGE_WARNING,
|
||||
gtk.BUTTONS_YES_NO,
|
||||
_("This will permanently delete the connection \"%s\", are you sure?") % self.rows[conn.get_uri()][ROW_NAME])
|
||||
result = warn.run()
|
||||
warn.destroy()
|
||||
if result == gtk.RESPONSE_NO:
|
||||
result = self.err.yes_no(_("This will permanently delete the connection \"%s\", are you sure?") % self.rows[conn.get_uri()][ROW_NAME])
|
||||
if not result:
|
||||
return
|
||||
self.engine.remove_connection(conn.get_uri())
|
||||
else:
|
||||
@ -746,21 +742,15 @@ class vmmManager(gobject.GObject):
|
||||
return
|
||||
|
||||
# are you sure you want to delete this VM?
|
||||
warn = gtk.MessageDialog(self.window.get_widget("vmm-manager"),
|
||||
gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
gtk.MESSAGE_WARNING,
|
||||
gtk.BUTTONS_YES_NO,
|
||||
_("This will permanently delete the vm \"%s,\" are you sure?") % vm.get_name())
|
||||
result = warn.run()
|
||||
warn.destroy()
|
||||
if result == gtk.RESPONSE_NO:
|
||||
result = self.err.yes_no(_("This will permanently delete the vm \"%s,\" are you sure?") % vm.get_name())
|
||||
if not result:
|
||||
return
|
||||
conn = vm.get_connection()
|
||||
try:
|
||||
vm.delete()
|
||||
except Exception, e:
|
||||
self._err_dialog(_("Error deleting domain: %s" % str(e)),\
|
||||
"".join(traceback.format_exc()))
|
||||
self.err.show_err(_("Error deleting domain: %s" % str(e)),\
|
||||
"".join(traceback.format_exc()))
|
||||
conn.tick(noStatsUpdate=True)
|
||||
|
||||
def show_about(self, src):
|
||||
@ -780,8 +770,14 @@ class vmmManager(gobject.GObject):
|
||||
vmlist = self.window.get_widget("vm-list")
|
||||
|
||||
# Handle, name, ID, status, status icon, cpu, [cpu graph], vcpus, mem, mem bar, uuid
|
||||
model = gtk.TreeStore(object, str, str, str, gtk.gdk.Pixbuf, str, int, str, int, str)
|
||||
model = gtk.TreeStore(object, str, str, str, gtk.gdk.Pixbuf, str, int, str, int, str, str)
|
||||
vmlist.set_model(model)
|
||||
try:
|
||||
vmlist.set_tooltip_column(ROW_HINT)
|
||||
except:
|
||||
# Catch & ignore errors - set_tooltip_column is in gtk >= 2.12
|
||||
# and we can easily work with lower versions
|
||||
pass
|
||||
|
||||
nameCol = gtk.TreeViewColumn(_("Name"))
|
||||
idCol = gtk.TreeViewColumn(_("ID"))
|
||||
@ -1020,30 +1016,17 @@ class vmmManager(gobject.GObject):
|
||||
|
||||
def _connect_error(self, conn, details):
|
||||
if conn.get_driver() == "xen" and not conn.is_remote():
|
||||
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE,
|
||||
_("Unable to open a connection to the Xen hypervisor/daemon.\n\n" +
|
||||
"Verify that:\n" +
|
||||
" - A Xen host kernel was booted\n" +
|
||||
" - The Xen service has been started\n"),
|
||||
details)
|
||||
self.err.show_err(_("Unable to open a connection to the Xen hypervisor/daemon.\n\n" +
|
||||
"Verify that:\n" +
|
||||
" - A Xen host kernel was booted\n" +
|
||||
" - The Xen service has been started\n"),
|
||||
details,
|
||||
title=_("Virtual Machine Manager Connection Failure"))
|
||||
else:
|
||||
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE,
|
||||
_("Unable to open a connection to the libvirt management daemon.\n\n" +
|
||||
"Verify that:\n" +
|
||||
" - The 'libvirtd' daemon has been started\n"),
|
||||
details)
|
||||
dg.set_title(_("Virtual Machine Manager Connection Failure"))
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
|
||||
def _err_dialog(self, summary, details):
|
||||
dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE, summary, details)
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
self.err.show_err(_("Unable to open a connection to the libvirt management daemon.\n\n" +
|
||||
"Verify that:\n" +
|
||||
" - The 'libvirtd' daemon has been started\n"),
|
||||
details,
|
||||
title=_("Virtual Machine Manager Connection Failure"))
|
||||
|
||||
gobject.type_register(vmmManager)
|
||||
|
@ -52,10 +52,11 @@ class vmmOpticalDriveHelper(gobject.GObject):
|
||||
# Find info about all current present media
|
||||
for d in self.hal_iface.FindDeviceByCapability("volume"):
|
||||
vol = self.bus.get_object("org.freedesktop.Hal", d)
|
||||
if vol.GetPropertyBoolean("volume.is_disc") and \
|
||||
vol.GetPropertyBoolean("volume.disc.has_data"):
|
||||
devnode = vol.GetProperty("block.device")
|
||||
label = vol.GetProperty("volume.label")
|
||||
volif = dbus.Interface(vol, "org.freedesktop.Hal.Device")
|
||||
if volif.GetPropertyBoolean("volume.is_disc") and \
|
||||
volif.GetPropertyBoolean("volume.disc.has_data"):
|
||||
devnode = volif.GetProperty("block.device")
|
||||
label = volif.GetProperty("volume.label")
|
||||
if label == None or len(label) == 0:
|
||||
label = devnode
|
||||
vollabel[devnode] = label
|
||||
@ -63,19 +64,21 @@ class vmmOpticalDriveHelper(gobject.GObject):
|
||||
|
||||
for d in self.hal_iface.FindDeviceByCapability("storage.cdrom"):
|
||||
dev = self.bus.get_object("org.freedesktop.Hal", d)
|
||||
devnode = dev.GetProperty("block.device")
|
||||
devif = dbus.Interface(dev, "org.freedesktop.Hal.Device")
|
||||
devnode = devif.GetProperty("block.device")
|
||||
if vollabel.has_key(devnode):
|
||||
self.model.append([devnode, vollabel[devnode], True, volpath[devnode]])
|
||||
self.model.append([devnode, "%s (%s)" % (vollabel[devnode], devnode), True, volpath[devnode]])
|
||||
else:
|
||||
self.model.append([devnode, _("No media present"), False, None])
|
||||
self.model.append([devnode, "%s (%s)" % (_("No media present"), devnode), False, None])
|
||||
|
||||
def _device_added(self, path):
|
||||
vol = self.bus.get_object("org.freedesktop.Hal", path)
|
||||
if vol.QueryCapability("volume"):
|
||||
if vol.GetPropertyBoolean("volume.is_disc") and \
|
||||
vol.GetPropertyBoolean("volume.disc.has_data"):
|
||||
devnode = vol.GetProperty("block.device")
|
||||
label = vol.GetProperty("volume.label")
|
||||
volif = dbus.Interface(vol, "org.freedesktop.Hal.Device")
|
||||
if volif.QueryCapability("volume"):
|
||||
if volif.GetPropertyBoolean("volume.is_disc") and \
|
||||
volif.GetPropertyBoolean("volume.disc.has_data"):
|
||||
devnode = volif.GetProperty("block.device")
|
||||
label = volif.GetProperty("volume.label")
|
||||
if label == None or len(label) == 0:
|
||||
label = devnode
|
||||
|
||||
@ -88,8 +91,6 @@ class vmmOpticalDriveHelper(gobject.GObject):
|
||||
row[3] = path
|
||||
|
||||
def _device_removed(self, path):
|
||||
vol = self.bus.get_object("org.freedesktop.Hal", path)
|
||||
|
||||
active = self.widget.get_active()
|
||||
idx = 0
|
||||
# Search for the row containing matching HAL volume path
|
||||
|
@ -25,7 +25,7 @@
|
||||
</property>
|
||||
<property name="wrap_license">False</property>
|
||||
<property name="website">http://virt-manager.et.redhat.com/</property>
|
||||
<property name="website_label" translatable="yes">http://virt-manager.et.redhat.com/</property>
|
||||
<property name="website_label">http://virt-manager.et.redhat.com/</property>
|
||||
<property name="authors">Daniel P. Berrange <berrange@redhat.com>
|
||||
Hugh O. Brock <hbrock@redhat.com>
|
||||
Máirín Duffy <duffy@redhat.com>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -151,6 +151,16 @@
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckMenuItem" id="menu-view-scale-display">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Scale display</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="active">False</property>
|
||||
<signal name="activate" handler="on_menu_view_scale_display_activate" last_modification_time="Fri, 07 Mar 2008 23:45:52 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="menu-view-serial">
|
||||
<property name="visible">True</property>
|
||||
@ -749,21 +759,7 @@
|
||||
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="console-vnc-align">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<property name="top_padding">0</property>
|
||||
<property name="bottom_padding">0</property>
|
||||
<property name="left_padding">0</property>
|
||||
<property name="right_padding">0</property>
|
||||
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
@ -1084,7 +1084,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="net-info-size">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">256</property>
|
||||
<property name="label">256</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -1112,7 +1112,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="net-info-gateway">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">192.168.1.1</property>
|
||||
<property name="label">192.168.1.1</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -1140,7 +1140,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="net-info-broadcast">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">192.168.1.255</property>
|
||||
<property name="label">192.168.1.255</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -1168,7 +1168,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="net-info-netmask">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">255.255.255.0</property>
|
||||
<property name="label">255.255.255.0</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -1938,7 +1938,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="summary-name">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">demo</property>
|
||||
<property name="label">demo</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -1965,7 +1965,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="summary-ip4-network">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">192.168.10.0/24</property>
|
||||
<property name="label">192.168.10.0/24</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -1992,7 +1992,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="summary-dhcp-end">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">5 GB</property>
|
||||
<property name="label">5 GB</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -2019,7 +2019,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="summary-ip4-gateway">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">192.168.10.254</property>
|
||||
<property name="label">192.168.10.254</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -2047,7 +2047,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="summary-ip4-netmask">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">255.255.255.0</property>
|
||||
<property name="label">255.255.255.0</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -2075,7 +2075,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="summary-dhcp-start">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">/xen/demo.img</property>
|
||||
<property name="label">/xen/demo.img</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -2355,7 +2355,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label379">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"> </property>
|
||||
<property name="label"> </property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -127,7 +127,7 @@
|
||||
<widget class="GtkTable" id="table1">
|
||||
<property name="border_width">3</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">6</property>
|
||||
<property name="n_rows">7</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">3</property>
|
||||
@ -276,7 +276,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="overview-hostname">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">example.com</property>
|
||||
<property name="label">example.com</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -330,7 +330,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="overview-memory">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">2000 MB</property>
|
||||
<property name="label">2000 MB</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -357,7 +357,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="overview-cpus">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">4</property>
|
||||
<property name="label">4</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -384,7 +384,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="overview-arch">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">x86_64</property>
|
||||
<property name="label">x86_64</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -439,7 +439,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="overview-uri">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">example.com</property>
|
||||
<property name="label">example.com</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -463,6 +463,57 @@
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label72">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Autoconnect:</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="bottom_attach">7</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="config-autoconnect">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes"></property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">False</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_config_autoconnect_toggled" last_modification_time="Mon, 24 Mar 2008 15:38:20 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="bottom_attach">7</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
@ -586,7 +637,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="performance-cpu">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">60%</property>
|
||||
<property name="label">60%</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
@ -614,7 +665,7 @@
|
||||
<child>
|
||||
<widget class="GtkLabel" id="performance-memory">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">1.59 GB of 2.2 GB</property>
|
||||
<property name="label">1.59 GB of 2.2 GB</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
|
@ -21,7 +21,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
Requires: pygtk2 >= 1.99.12-6
|
||||
Requires: gnome-python2-gconf >= 1.99.11-7
|
||||
# Absolutely require this version or newer
|
||||
Requires: libvirt-python >= 0.4.0-1
|
||||
Requires: libvirt-python >= 0.4.1
|
||||
# Definitely does not work with earlier due to python API changes
|
||||
Requires: dbus-python >= 0.61
|
||||
# Might work with earlier, but this is what we've tested
|
||||
@ -35,7 +35,7 @@ Requires: gnome-python2-gnomevfs >= 2.15.4
|
||||
# Minimum we've tested with
|
||||
Requires: libxml2-python >= 2.6.23
|
||||
# Required to install Xen & QEMU guests
|
||||
Requires: python-virtinst >= 0.300.2
|
||||
Requires: python-virtinst >= 0.300.3
|
||||
# Required for loading the glade UI
|
||||
Requires: pygtk2-libglade
|
||||
# Required for our graphics which are currently SVG format
|
||||
@ -45,7 +45,7 @@ Requires: vte >= 0.12.2
|
||||
# For online help
|
||||
Requires: scrollkeeper
|
||||
# For console widget
|
||||
Requires: gtk-vnc-python
|
||||
Requires: gtk-vnc-python >= 0.3.4
|
||||
# For local authentication against PolicyKit
|
||||
Requires: PolicyKit-gnome
|
||||
|
||||
@ -142,6 +142,10 @@ fi
|
||||
%{_datadir}/man/man1/%{name}.1*
|
||||
|
||||
%changelog
|
||||
* Mon Mar 10 2008 Daniel P Berrange <berrange@redhat.com> - 0.5.4-1
|
||||
- Use capabilities XML when creating guests
|
||||
- Allow scaling of VNC window
|
||||
|
||||
* Thu Jan 10 2008 Daniel P Berrange <berrange@redhat.com> - 0.5.3-1
|
||||
- Reintroduce 'new' button
|
||||
- Make restore work again
|
||||
|
Loading…
x
Reference in New Issue
Block a user