'Add Physical Host Device' wizard for existing guests.

This commit is contained in:
Cole Robinson 2009-03-09 16:20:23 -04:00
parent b1f69cffd8
commit a590888ef6
3 changed files with 1048 additions and 693 deletions

View File

@ -44,7 +44,8 @@ PAGE_NETWORK = 2
PAGE_INPUT = 3
PAGE_GRAPHICS = 4
PAGE_SOUND = 5
PAGE_SUMMARY = 6
PAGE_HOSTDEV = 6
PAGE_SUMMARY = 7
class vmmAddHardware(gobject.GObject):
__gsignals__ = {
@ -85,6 +86,7 @@ class vmmAddHardware(gobject.GObject):
"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_host_device_type_changed": self.change_host_device_type,
"on_create_help_clicked": self.show_help,
})
@ -170,6 +172,24 @@ class vmmAddHardware(gobject.GObject):
sound_list.pack_start(text, True)
sound_list.add_attribute(text, 'text', 0)
host_devtype = self.window.get_widget("host-device-type")
# Description, nodedev type, specific type capability, sub type,
# sub cap
host_devtype_model = gtk.ListStore(str, str, str, str, str)
host_devtype.set_model(host_devtype_model)
text = gtk.CellRendererText()
host_devtype.pack_start(text, True)
host_devtype.add_attribute(text, 'text', 0)
host_dev = self.window.get_widget("host-device")
# Description, nodedev name
host_dev_model = gtk.ListStore(str, str)
host_dev.set_model(host_dev_model)
text = gtk.CellRendererText()
host_dev.pack_start(text, True)
host_dev.add_attribute(text, 'text', 0)
host_dev_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
def reset_state(self):
notebook = self.window.get_widget("create-pages")
notebook.set_current_page(0)
@ -232,6 +252,13 @@ class vmmAddHardware(gobject.GObject):
self.populate_sound_model_model(sound_box.get_model())
sound_box.set_active(0)
host_devtype = self.window.get_widget("host-device-type")
self.populate_host_device_type_model(host_devtype.get_model())
host_devtype.set_active(0)
# FIXME: All of these needs to have better transparency.
# All options should be listed, but disabled with a tooltip if
# it can't be used.
model = self.window.get_widget("hardware-type").get_model()
model.clear()
model.append(["Storage", gtk.STOCK_HARDDISK, PAGE_DISK])
@ -250,6 +277,10 @@ class vmmAddHardware(gobject.GObject):
if self.vm.is_hvm():
model.append(["Sound", gtk.STOCK_MEDIA_PLAY, PAGE_SOUND])
if (self.vm.get_connection().get_driver().lower() != "xen" or
not self.vm.get_connection().is_nodedev_capable()):
# Libvirt doesn't support this for xen yet
model.append(["Physical Host Device", None, PAGE_HOSTDEV])
def forward(self, ignore=None):
notebook = self.window.get_widget("create-pages")
@ -396,6 +427,14 @@ class vmmAddHardware(gobject.GObject):
modelstr = model.get_model().get_value(model.get_active_iter(), 0)
return modelstr
def get_config_host_device_type_info(self):
devbox = self.window.get_widget("host-device-type")
return devbox.get_model()[devbox.get_active()]
def get_config_host_device_info(self):
devbox = self.window.get_widget("host-device")
return devbox.get_model()[devbox.get_active()]
def page_changed(self, notebook, page, page_number):
remote = self.vm.get_connection().is_remote()
if page_number == PAGE_DISK:
@ -427,6 +466,7 @@ class vmmAddHardware(gobject.GObject):
self.window.get_widget("summary-input").hide()
self.window.get_widget("summary-graphics").hide()
self.window.get_widget("summary-sound").hide()
self.window.get_widget("summary-hostdev").hide()
if hwpage == PAGE_DISK:
self.window.get_widget("summary-disk").show()
@ -495,6 +535,10 @@ class vmmAddHardware(gobject.GObject):
elif hwpage == PAGE_SOUND:
self.window.get_widget("summary-sound").show()
self.window.get_widget("summary-sound-model").set_text(self._dev.model)
elif hwpage == PAGE_HOSTDEV:
self.window.get_widget("summary-hostdev").show()
self.window.get_widget("summary-host-device-type").set_text(self.get_config_host_device_type_info()[0])
self.window.get_widget("summary-host-device").set_text(self.get_config_host_device_info()[0])
def close(self, ignore1=None,ignore2=None):
self.topwin.hide()
@ -512,16 +556,22 @@ class vmmAddHardware(gobject.GObject):
self.topwin.set_sensitive(False)
self.topwin.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
if hw == PAGE_NETWORK:
self.add_network()
elif hw == PAGE_DISK:
self.add_storage()
elif hw == PAGE_INPUT:
self.add_input()
elif hw == PAGE_GRAPHICS:
self.add_graphics()
elif hw == PAGE_SOUND:
self.add_sound()
try:
if hw == PAGE_NETWORK:
self.add_network()
elif hw == PAGE_DISK:
self.add_storage()
elif hw == PAGE_INPUT:
self.add_input()
elif hw == PAGE_GRAPHICS:
self.add_graphics()
elif hw == PAGE_SOUND:
self.add_sound()
elif hw == PAGE_HOSTDEV:
self.add_hostdev()
except Exception, e:
self.err.show_err(_("Uncaught error adding device: %s") % str(e),
"".join(traceback.format_exc()))
if self.install_error is not None:
self.err.show_err(self.install_error, self.install_details)
@ -553,6 +603,10 @@ class vmmAddHardware(gobject.GObject):
def add_sound(self):
self.add_device(self._dev.get_xml_config())
def add_hostdev(self):
self._dev.setup()
self.add_device(self._dev.get_xml_config())
def add_storage(self):
used = []
for d in self.vm.get_disk_devices():
@ -753,6 +807,18 @@ class vmmAddHardware(gobject.GObject):
else:
self.window.get_widget("graphics-keymap").set_sensitive(True)
def change_host_device_type(self, src):
devbox = self.window.get_widget("host-device")
if src.get_active() < 0:
devbox.get_model().clear()
return
(ignore, devtype, devcap,
subtype, subcap) = src.get_model()[src.get_active()]
self.populate_host_device_model(devbox.get_model(), devtype, devcap,
subtype, subcap)
devbox.set_active(0)
def validate(self, page_num):
if page_num == PAGE_INTRO:
if self.get_config_hardware_type() == None:
@ -881,7 +947,23 @@ class vmmAddHardware(gobject.GObject):
try:
self._dev = virtinst.VirtualAudio(model=smodel)
except Exception, e:
self.err.val_err(_("Sound device parameter error"), str(e))
return self.err.val_err(_("Sound device parameter error"),
str(e))
elif page_num == PAGE_HOSTDEV:
ignore, nodedev_name = self.get_config_host_device_info()
if nodedev_name == None:
return self.err.val_err(_("Physical Device Requried"),
_("A device must be selected."))
try:
self._dev = virtinst.VirtualHostDevice.device_from_node(
conn = self.vm.get_connection().vmm,
name = nodedev_name)
except Exception, e:
return self.err.val_err(_("Host device parameter error",
str(e)))
return True
@ -963,6 +1045,33 @@ class vmmAddHardware(gobject.GObject):
for m in lst:
model.append([m])
def populate_host_device_type_model(self, model):
model.clear()
for m in [ ["PCI Device", "pci", None, "net", "80203"],
["USB Device", "usb_device", None, None, None]]:
model.append(m)
def populate_host_device_model(self, model, devtype, devcap, subtype,
subcap):
model.clear()
subdevs = []
if subtype:
subdevs = self.vm.get_connection().get_devices(subtype, subcap)
devs = self.vm.get_connection().get_devices(devtype, devcap)
for dev in devs:
prettyname = dev.pretty_name()
for subdev in subdevs:
if dev.name == subdev.parent:
prettyname = dev.pretty_name(subdev)
model.append([prettyname, dev.name])
if len(model) == 0:
model.append([_("No Devices Available"), None])
def is_sparse_file(self):
if self.window.get_widget("non-sparse").get_active():
return False

View File

@ -295,6 +295,9 @@ class vmmConnection(gobject.GObject):
def is_storage_capable(self):
return virtinst.util.is_storage_capable(self.vmm)
def is_nodedev_capable(self):
return virtinst.NodeDeviceParser.is_nodedev_capable(self.vmm)
def is_qemu_session(self):
(scheme, ignore, ignore,
path, ignore, ignore) = virtinst.util.uri_split(self.uri)
@ -343,6 +346,24 @@ class vmmConnection(gobject.GObject):
def get_pool(self, uuid):
return self.pools[uuid]
def get_devices(self, devtype=None, devcap=None):
if not self.is_nodedev_capable():
return []
devs = self.vmm.listDevices(devtype, 0)
retdevs = []
for name in devs:
dev = self.vmm.nodeDeviceLookupByName(name)
vdev = virtinst.NodeDeviceParser.parse(dev.XMLDesc(0))
if devcap and vdev.capability_type != devcap:
continue
retdevs.append(vdev)
return retdevs
def is_valid_saved_image(self, path):
# FIXME: Not really sure why we are even doing this check? If libvirt
# isn't exporting this information, seems like we shouldn't be duping

File diff suppressed because it is too large Load Diff