diff --git a/src/virtManager/addhardware.py b/src/virtManager/addhardware.py new file mode 100644 index 000000000..cdbc89f70 --- /dev/null +++ b/src/virtManager/addhardware.py @@ -0,0 +1,570 @@ +# +# Copyright (C) 2006-2007 Red Hat, Inc. +# Copyright (C) 2006 Hugh O. Brock +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +import gobject +import gtk +import gtk.gdk +import gtk.glade +import pango +import libvirt +import virtinst +import os, sys +import re +import subprocess +import urlgrabber.progress as progress +import tempfile +import logging +import dbus +import traceback + +from virtManager.asyncjob import vmmAsyncJob +from virtManager.error import vmmErrorDialog + +VM_STORAGE_PARTITION = 1 +VM_STORAGE_FILE = 2 + +DEFAULT_STORAGE_FILE_SIZE = 500 + +PAGE_INTRO = 0 +PAGE_DISK = 1 +PAGE_NETWORK = 2 +PAGE_SUMMARY = 3 + +class vmmCreateMeter(progress.BaseMeter): + def __init__(self, asyncjob): + # progress meter has to run asynchronously, so pass in the + # async job to call back to with progress info + progress.BaseMeter.__init__(self) + self.asyncjob = asyncjob + + def _do_start(self, now): + if self.text is not None: + text = self.text + else: + text = self.basename + if self.size is None: + out = " %5sB" % (0) + self.asyncjob.pulse_pbar(out, text) + else: + out = "%3i%% %5sB" % (0, 0) + self.asyncjob.set_pbar_fraction(0, out, text) + + def _do_update(self, amount_read, now=None): + if self.text is not None: + text = self.text + else: + text = self.basename + fread = progress.format_number(amount_read) + if self.size is None: + out = " %5sB" % (fread) + self.asyncjob.pulse_pbar(out, text) + else: + frac = self.re.fraction_read() + out = "%3i%% %5sB" % (frac*100, fread) + self.asyncjob.set_pbar_fraction(frac, out, text) + + def _do_end(self, amount_read, now=None): + if self.text is not None: + text = self.text + else: + text = self.basename + fread = progress.format_number(amount_read) + if self.size is None: + out = " %5sB" % (fread) + self.asyncjob.pulse_pbar(out, text) + else: + out = "%3i%% %5sB" % (100, fread) + self.asyncjob.set_pbar_done(out, text) + +class vmmAddHardware(gobject.GObject): + __gsignals__ = { + "action-show-help": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, [str]), + } + def __init__(self, config, vm): + self.__gobject_init__() + self.config = config + self.vm = vm + 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.topwin.hide() + self.window.signal_autoconnect({ + "on_create_pages_switch_page" : self.page_changed, + "on_create_cancel_clicked" : self.close, + "on_vmm_create_delete_event" : self.close, + "on_create_back_clicked" : self.back, + "on_create_forward_clicked" : self.forward, + "on_create_finish_clicked" : self.finish, + "on_storage_partition_address_browse_clicked" : self.browse_storage_partition_address, + "on_storage_file_address_browse_clicked" : self.browse_storage_file_address, + "on_storage_file_address_changed": self.toggle_storage_size, + "on_storage_toggled" : self.change_storage_type, + "on_network_toggled" : self.change_network_type, + "on_create_help_clicked": self.show_help, + }) + + hw_list = self.window.get_widget("hardware-type") + model = gtk.ListStore(str, gtk.gdk.Pixbuf, int) + hw_list.set_model(model) + icon = gtk.CellRendererPixbuf() + hw_list.pack_start(icon, False) + hw_list.add_attribute(icon, 'pixbuf', 1) + text = gtk.CellRendererText() + hw_list.pack_start(text, True) + hw_list.add_attribute(text, 'text', 0) + + pixbuf_disk = gtk.gdk.pixbuf_new_from_file(config.get_icon_dir() + "/icon_hdd.png") + pixbuf_nic = gtk.gdk.pixbuf_new_from_file(config.get_icon_dir() + "/icon_ethernet.png") + + model.append(["Storage device", pixbuf_disk, PAGE_DISK]) + model.append(["Network card", pixbuf_nic, PAGE_NETWORK]) + + self.set_initial_state() + + def show(self): + self.reset_state() + self.topwin.show() + self.topwin.present() + + def set_initial_state(self): + notebook = self.window.get_widget("create-pages") + notebook.set_show_tabs(False) + + #XXX I don't think I should have to go through and set a bunch of background colors + # in code, but apparently I do... + black = gtk.gdk.color_parse("#000") + for num in range(PAGE_SUMMARY+1): + name = "page" + str(num) + "-title" + self.window.get_widget(name).modify_bg(gtk.STATE_NORMAL,black) + + if os.getuid() != 0: + self.window.get_widget("storage-partition").set_sensitive(False) + + # set up the lists for the networks + network_list = self.window.get_widget("net-network") + network_model = gtk.ListStore(str, str) + network_list.set_model(network_model) + text = gtk.CellRendererText() + network_list.pack_start(text, True) + network_list.add_attribute(text, 'text', 1) + + device_list = self.window.get_widget("net-device") + device_model = gtk.ListStore(str) + device_list.set_model(device_model) + text = gtk.CellRendererText() + device_list.pack_start(text, True) + device_list.add_attribute(text, 'text', 0) + + def reset_state(self): + notebook = self.window.get_widget("create-pages") + notebook.set_current_page(0) + # Hide the "finish" button until the appropriate time + self.window.get_widget("create-finish").hide() + self.window.get_widget("create-forward").show() + self.window.get_widget("create-back").set_sensitive(False) + self.window.get_widget("storage-file-size").set_sensitive(False) + + self.change_storage_type() + self.change_network_type() + 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-partition-address").set_text("") + self.window.get_widget("storage-file-address").set_text("") + self.window.get_widget("storage-file-size").set_value(2000) + self.window.get_widget("non-sparse").set_active(True) + + model = self.window.get_widget("net-network").get_model() + self.populate_network_model(model) + device = self.window.get_widget("net-device").get_model() + self.populate_device_model(device) + + + def forward(self, ignore=None): + notebook = self.window.get_widget("create-pages") + if(self.validate(notebook.get_current_page()) != True): + return + + if notebook.get_current_page() == PAGE_INTRO: + notebook.set_current_page(self.get_config_hardware_type()) + else: + notebook.set_current_page(PAGE_SUMMARY) + self.window.get_widget("create-finish").show() + self.window.get_widget("create-forward").hide() + self.window.get_widget("create-back").set_sensitive(True) + + def back(self, ignore=None): + notebook = self.window.get_widget("create-pages") + + if notebook.get_current_page() == PAGE_SUMMARY: + notebook.set_current_page(self.get_config_hardware_type()) + self.window.get_widget("create-finish").hide() + else: + notebook.set_current_page(PAGE_INTRO) + self.window.get_widget("create-back").set_sensitive(False) + self.window.get_widget("create-forward").show() + + def get_config_hardware_type(self): + type = self.window.get_widget("hardware-type") + if type.get_active_iter() == None: + return None + return type.get_model().get_value(type.get_active_iter(), 2) + + def get_config_disk_image(self): + if self.window.get_widget("storage-partition").get_active(): + return self.window.get_widget("storage-partition-address").get_text() + else: + return self.window.get_widget("storage-file-address").get_text() + + def get_config_disk_size(self): + if self.window.get_widget("storage-partition").get_active(): + return None + else: + return self.window.get_widget("storage-file-size").get_value() + + def get_config_network(self): + if os.getuid() != 0: + return ["user"] + + if self.window.get_widget("net-type-network").get_active(): + net = self.window.get_widget("net-network") + model = net.get_model() + return ["network", model.get_value(net.get_active_iter(), 0)] + else: + dev = self.window.get_widget("net-device") + model = dev.get_model() + return ["bridge", model.get_value(dev.get_active_iter(), 0)] + + def page_changed(self, notebook, page, page_number): + if page_number == PAGE_DISK: + pass + elif page_number == PAGE_NETWORK: + pass + elif page_number == PAGE_SUMMARY: + hwpage = self.get_config_hardware_type() + + if hwpage == PAGE_DISK: + self.window.get_widget("summary-disk").show() + self.window.get_widget("summary-network").hide() + self.window.get_widget("summary-disk-image").set_text(self.get_config_disk_image()) + disksize = self.get_config_disk_size() + if disksize != None: + self.window.get_widget("summary-disk-size").set_text(str(int(disksize)) + " MB") + else: + self.window.get_widget("summary-disk-size").set_text("-") + elif hwpage == PAGE_NETWORK: + self.window.get_widget("summary-disk").hide() + self.window.get_widget("summary-network").show() + net = self.get_config_network() + if net[0] == "bridge": + self.window.get_widget("summary-net-type").set_text(_("Shared physical device")) + self.window.get_widget("summary-net-target").set_text(net[1]) + elif net[0] == "network": + self.window.get_widget("summary-net-type").set_text(_("Virtual network")) + self.window.get_widget("summary-net-target").set_text(net[1]) + elif net[0] == "user": + self.window.get_widget("summary-net-type").set_text(_("Usermode networking")) + self.window.get_widget("summary-net-target").set_text("-") + else: + raise ValueError, "Unknown networking type " + net[0] + + def close(self, ignore1=None,ignore2=None): + self.topwin.hide() + return 1 + + def is_visible(self): + if self.topwin.flags() & gtk.VISIBLE: + return 1 + return 0 + + def finish(self, ignore=None): + hw = self.get_config_hardware_type() + + self.install_error = None + 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() + + 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.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 + # their mistakes + #self.close() + return + + self.topwin.set_sensitive(True) + self.topwin.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.TOP_LEFT_ARROW)) + self.close() + + def add_network(self): + net = self.get_config_network() + vnic = None + if net[0] == "bridge": + vnic = virtinst.VirtualNetworkInterface(type=net[0], bridge=net[1]) + elif net[0] == "network": + vnic = virtinst.VirtualNetworkInterface(type=net[0], network=net[1]) + else: + raise ValueError, "Unsupported networking type " + net[0] + + vnic.setup(self.vm.get_connection().vmm) + xml = vnic.get_xml_config() + logging.debug("Adding network " + xml) + self.vm.add_device(xml) + + def add_storage(self): + filesize = None + disk = None + if self.get_config_disk_size() != None: + filesize = self.get_config_disk_size() / 1024.0 + try: + disk = virtinst.VirtualDisk(self.get_config_disk_image(), filesize, sparse = self.is_sparse_file()) + if disk.type == virtinst.VirtualDisk.TYPE_FILE and \ + not self.vm.is_hvm() \ + and virtinst.util.is_blktap_capable(): + disk.driver_name = virtinst.VirtualDisk.DRIVER_TAP + except ValueError, e: + self._validation_error_box(_("Invalid storage address"), e.args[0]) + return + + used = {} + for d in self.vm.get_disk_devices(): + dev = d[3] + used[dev] = 1 + + nodes = [] + if self.vm.is_hvm(): + for n in range(4): + nodes.append("hd%c" % (ord('a')+n)) + else: + for n in range(26): + nodes.append("xvd%c" % (ord('a')+n)) + + node = None + for n in nodes: + if not used.has_key(n): + node = n + break + + if node is None: + self._validation_error_box(_("Too many virtual disks"), + _("There are no more available virtual disk device nodes")) + return + + progWin = vmmAsyncJob(self.config, self.do_file_allocate, [disk], + title=_("Creating Storage File"), + text=_("Allocation of disk storage may take a few minutes " + \ + "to complete.")) + progWin.run() + + xml = disk.get_xml_config(node) + logging.debug("Adding disk " + xml) + self.vm.add_device(xml) + + def do_file_allocate(self, disk, asyncjob): + meter = vmmCreateMeter(asyncjob) + try: + logging.debug("Starting background file allocate process") + disk.setup(meter) + logging.debug("Allocation completed") + except: + (type, value, stacktrace) = sys.exc_info () + + # Detailed error message, in English so it can be Googled. + details = \ + "Unable to complete install '%s'" % \ + (str(type) + " " + str(value) + "\n" + \ + traceback.format_exc (stacktrace)) + + self.install_error = _("Unable to complete install: '%s'") % str(value) + self.install_details = details + logging.error(details) + + def browse_storage_partition_address(self, src, ignore=None): + part = self._browse_file(_("Locate Storage Partition"), "/dev") + if part != None: + self.window.get_widget("storage-partition-address").set_text(part) + + def browse_storage_file_address(self, src, ignore=None): + self.window.get_widget("storage-file-size").set_sensitive(True) + fcdialog = gtk.FileChooserDialog(_("Locate or Create New Storage File"), + self.window.get_widget("vmm-create"), + gtk.FILE_CHOOSER_ACTION_SAVE, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT), + None) + + fcdialog.set_current_folder(self.config.get_default_image_dir(self.vm.get_connection())) + fcdialog.set_do_overwrite_confirmation(True) + fcdialog.connect("confirm-overwrite", self.confirm_overwrite_callback) + response = fcdialog.run() + fcdialog.hide() + file = None + if(response == gtk.RESPONSE_ACCEPT): + file = fcdialog.get_filename() + if file != None: + self.window.get_widget("storage-file-address").set_text(file) + + def toggle_storage_size(self, ignore1=None, ignore2=None): + file = self.get_config_disk_image() + 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) + else: + self.window.get_widget("storage-file-size").set_sensitive(False) + self.window.get_widget("non-sparse").set_sensitive(False) + if os.path.isfile(file): + size = os.path.getsize(file)/(1024*1024) + self.window.get_widget("storage-file-size").set_value(size) + else: + self.window.get_widget("storage-file-size").set_value(0) + + def confirm_overwrite_callback(self, chooser): + # Only called when the user has chosen an existing file + self.window.get_widget("storage-file-size").set_sensitive(False) + return gtk.FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME + + def change_storage_type(self, ignore=None): + if self.window.get_widget("storage-partition").get_active(): + self.window.get_widget("storage-partition-box").set_sensitive(True) + self.window.get_widget("storage-file-box").set_sensitive(False) + self.window.get_widget("storage-file-size").set_sensitive(False) + self.window.get_widget("non-sparse").set_sensitive(False) + else: + self.window.get_widget("storage-partition-box").set_sensitive(False) + self.window.get_widget("storage-file-box").set_sensitive(True) + self.toggle_storage_size() + + def change_network_type(self, ignore=None): + if self.window.get_widget("net-type-network").get_active(): + self.window.get_widget("net-network").set_sensitive(True) + self.window.get_widget("net-device").set_sensitive(False) + else: + self.window.get_widget("net-network").set_sensitive(False) + self.window.get_widget("net-device").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 + + elif page_num == PAGE_DISK: + 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 + + if not self.window.get_widget("storage-partition").get_active(): + if os.path.isdir(disk): + self._validation_error_box(_("Storage Address Is Directory"), \ + _("You chose 'Simple File' storage for your storage method, but chose a directory instead of a file. Please enter a new filename or choose an existing file.")) + return False + + d = virtinst.VirtualDisk(self.get_config_disk_image(), self.get_config_disk_size(), sparse = self.is_sparse_file()) + if d.is_conflict_disk(self.vm.get_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 ?")) + 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 + 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 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_network_model(self, model): + model.clear() + for uuid in self.vm.get_connection().list_net_uuids(): + net = self.vm.get_connection().get_net(uuid) + model.append([net.get_label(), net.get_name()]) + + def populate_device_model(self, model): + model.clear() + for name in self.vm.get_connection().list_net_device_paths(): + net = self.vm.get_connection().get_net_device(name) + if net.is_shared(): + model.append([net.get_bridge()]) + + def is_sparse_file(self): + if self.window.get_widget("non-sparse").get_active(): + return False + else: + return True + + def show_help(self, src): + # help to show depends on the notebook page, yahoo + page = self.window.get_widget("create-pages").get_current_page() + if page == PAGE_INTRO: + self.emit("action-show-help", "virt-manager-create-wizard") + elif page == PAGE_DISK: + self.emit("action-show-help", "virt-manager-storage-space") + elif page == PAGE_NETWORK: + self.emit("action-show-help", "virt-manager-network") + +gobject.type_register(vmmAddHardware) diff --git a/src/virtManager/details.py b/src/virtManager/details.py index 774567903..482a701cb 100644 --- a/src/virtManager/details.py +++ b/src/virtManager/details.py @@ -26,6 +26,7 @@ import logging import traceback from virtManager.error import vmmErrorDialog +from virtManager.addhardware import vmmAddHardware import virtinst import urlgrabber.progress as progress @@ -35,7 +36,6 @@ VMM_HW_CPU = 0 VMM_HW_MEMORY = 1 VMM_HW_DISK = 2 VMM_HW_NIC = 3 -VMM_HW_DEVICES = [_("Virtual Disk"), _("Virtual NIC")] class vmmDetails(gobject.GObject): __gsignals__ = { @@ -68,6 +68,7 @@ class vmmDetails(gobject.GObject): self.window.get_widget("hw-panel").set_show_tabs(False) + self.addhw = None self.cpu_usage_graph = sparkline.Sparkline() self.window.get_widget("graph-table").attach(self.cpu_usage_graph, 1, 2, 0, 1) @@ -75,7 +76,6 @@ class vmmDetails(gobject.GObject): self.memory_usage_graph = sparkline.Sparkline() self.window.get_widget("graph-table").attach(self.memory_usage_graph, 1, 2, 1, 2) - self.network_traffic_graph = sparkline.Sparkline() self.window.get_widget("graph-table").attach(self.network_traffic_graph, 1, 2, 3, 4) @@ -111,45 +111,21 @@ class vmmDetails(gobject.GObject): "on_storage_file_address_changed": self.toggle_storage_size, "on_storage_toggled" : self.change_storage_type, "on_add_hardware_button_clicked": self.add_hardware, - "on_vnic_apply_clicked": self.add_vnic, - "on_vnic_cancel_clicked": self.clean_up_add_hardware, - "on_vbd_add_apply_clicked": self.add_vbd, - "on_vbd_add_cancel_clicked": self.clean_up_add_hardware, - }) self.vm.connect("status-changed", self.update_widget_states) self.vm.connect("resources-sampled", self.refresh_resources) self.window.get_widget("hw-list").get_selection().connect("changed", self.hw_selected) - # set up the list for new hardware devices - hw_type_list = self.window.get_widget("add-hardware-device") - hw_type_model = hw_type_list.get_model() - for device_name in VMM_HW_DEVICES: - hw_type_model.append([device_name]) - hw_type_list.set_active(0) - - # list for network pulldown - network_list = self.window.get_widget("network-name-pulldown") - network_model = gtk.ListStore(str, str, str) - network_list.set_model(network_model) - text = gtk.CellRendererText() - network_list.pack_start(text, True) - network_list.add_attribute(text, 'text', 0) - - #using this as the flag for whether the network page is in edit mode. Ugh. - self.adding_hardware = False - self.update_widget_states(vm, vm.status()) self.refresh_resources(vm) self.pixbuf_processor = gtk.gdk.pixbuf_new_from_file(config.get_icon_dir() + "/icon_cpu.png") self.pixbuf_memory = gtk.gdk.pixbuf_new_from_file(config.get_icon_dir() + "/icon_cpu.png") self.pixbuf_disk = gtk.gdk.pixbuf_new_from_file(config.get_icon_dir() + "/icon_hdd.png") - self.pixbuf_network = gtk.gdk.pixbuf_new_from_file(config.get_icon_dir() + "/icon_ethernet.png") + self.pixbuf_nic = gtk.gdk.pixbuf_new_from_file(config.get_icon_dir() + "/icon_ethernet.png") self.prepare_hw_list() self.hw_selected() - def toggle_toolbar(self, src): if src.get_active(): @@ -170,8 +146,7 @@ class vmmDetails(gobject.GObject): def show_help(self, src): # From the Details window, show the help document from the Details page - self.emit("action-show-help", "virt-manager-details-window") - + self.emit("action-show-help", "virt-manager-details-window") def activate_performance_page(self): self.window.get_widget("details-pages").set_current_page(0) @@ -189,14 +164,14 @@ class vmmDetails(gobject.GObject): return 0 def hw_selected(self, src=None): - self.adding_hardware = False vmlist = self.window.get_widget("hw-list") selection = vmlist.get_selection() active = selection.get_selected() if active[1] != None: - pagetype = active[0].get_value(active[1], 3) + pagetype = active[0].get_value(active[1], 2) self.window.get_widget("hw-panel").set_sensitive(True) + pagenum = -1 if pagetype == VMM_HW_CPU: self.window.get_widget("config-vcpus-apply").set_sensitive(False) self.refresh_config_cpu() @@ -209,18 +184,13 @@ class vmmDetails(gobject.GObject): self.refresh_disk_page() pagenum = 2 elif pagetype == VMM_HW_NIC: - self.window.get_widget("network-name-pulldown").hide() - self.window.get_widget("network-buttons").hide() - self.window.get_widget("network-name").set_editable(False) - self.window.get_widget("network-mac-address").set_editable(False) - self.window.get_widget("net-devlabel-label").show() - self.window.get_widget("network-device-name").show() self.refresh_network_page() pagenum = 3 + self.window.get_widget("hw-panel").set_current_page(pagenum) else: logging.debug("In hw_selected with null tree iter") - self.window.get_widget("hw-panel").set_sensitive(True) + self.window.get_widget("hw-panel").set_sensitive(False) selection.select_path(0) self.window.get_widget("hw-panel").set_current_page(0) @@ -342,66 +312,34 @@ class vmmDetails(gobject.GObject): self.window.get_widget("details-menu-serial").set_sensitive(False) def refresh_resources(self, ignore): - self.refresh_summary() - if self.window.get_widget("details-pages").get_current_page() == 1: + details = self.window.get_widget("details-pages") + if details.get_current_page() == 0: + self.refresh_summary() + else: #XXX for this week this only works for active domains, and it's temporary. if self.vm.is_active(): self.window.get_widget("add-hardware-button").set_sensitive(True) else: self.window.get_widget("add-hardware-button").set_sensitive(False) - - if self.adding_hardware: - return + # reload the hw model, go to the correct page, and refresh that page hw_list = self.window.get_widget("hw-list") hw_panel = self.window.get_widget("hw-panel") selection = hw_list.get_selection() active = selection.get_selected() if active[1] != None: - pagetype = active[0].get_value(active[1], 3) - device_info = active[0].get_value(active[1], 4) - self.populate_hw_list() + pagetype = active[0].get_value(active[1], 2) + device_info = active[0].get_value(active[1], 3) + self.repopulate_hw_list() hw_model = hw_list.get_model() if pagetype == VMM_HW_CPU: self.refresh_config_cpu() - pagenum = 0 - selection.select_path(0) elif pagetype == VMM_HW_MEMORY: self.refresh_config_memory() - pagenum = 1 - selection.select_path(1) elif pagetype == VMM_HW_DISK: self.refresh_disk_page() - # try to match the old source dev to one of the new source devs - selection.select_path(0) - pagenum = 0 - i=0 - for hw in hw_model: - if hw[3] == VMM_HW_DISK: - if device_info[1] == hw[4][1]: - selection.select_path(i) - pagenum = 2 - break - i = i + 1 elif pagetype == VMM_HW_NIC: self.refresh_network_page() - selection.select_path(0) - pagenum = 0 - i=0 - for hw in hw_model: - if hw[3] == VMM_HW_NIC: - if device_info[3] == hw[4][3]: - selection.select_path(i) - pagenum = 3 - break - i = i + 1 - hw_panel.set_current_page(pagenum) - - else: - logging.debug("In hw_selected with null tree iter") - hw_panel.set_sensitive(True) - selection.select_path(0) - hw_panel.set_current_page(0) def refresh_summary(self): self.window.get_widget("overview-cpu-usage-text").set_text("%d %%" % self.vm.cpu_time_percentage()) @@ -460,32 +398,24 @@ class vmmDetails(gobject.GObject): selection = vmlist.get_selection() active = selection.get_selected() if active[1] != None: - diskinfo = active[0].get_value(active[1], 4) - # fill the fields on the screen - self.window.get_widget("disk-type").set_text(diskinfo[0]) - self.window.get_widget("storage-source").set_text(diskinfo[1]) - self.window.get_widget("storage-device").set_text(diskinfo[2]) - self.window.get_widget("device-label").set_text(diskinfo[3]) + diskinfo = active[0].get_value(active[1], 3) + self.window.get_widget("disk-source-type").set_text(diskinfo[0]) + self.window.get_widget("disk-source-path").set_text(diskinfo[1]) + self.window.get_widget("disk-target-type").set_text(diskinfo[2]) + self.window.get_widget("disk-target-device").set_text(diskinfo[3]) def refresh_network_page(self): - # get the line what was clicked - if not self.adding_hardware: - # viewing net page, not adding a device. If adding, don't try to refresh - vmlist = self.window.get_widget("hw-list") - selection = vmlist.get_selection() - active = selection.get_selected() - if active[1] != None: - netinfo = active[0].get_value(active[1], 4) - if netinfo[1] == "-": - netname = "No network name" - else: - netname = netinfo[1] - name_widget = self.window.get_widget("network-name") - name_widget.set_text(netname) - name_widget.show() - self.window.get_widget("network-mac-address").set_text(netinfo[3]) - self.window.get_widget("network-device-name").set_text(netinfo[2]) - + # viewing net page, not adding a device. If adding, don't try to refresh + vmlist = self.window.get_widget("hw-list") + selection = vmlist.get_selection() + active = selection.get_selected() + if active[1] != None: + netinfo = active[0].get_value(active[1], 3) + self.window.get_widget("network-source-type").set_text(netinfo[0]) + self.window.get_widget("network-source-device").set_text(netinfo[1]) + self.window.get_widget("network-target-device").set_text(netinfo[2]) + self.window.get_widget("network-mac-address").set_text(netinfo[3]) + def config_vcpus_changed(self, src): self.window.get_widget("config-vcpus-apply").set_sensitive(True) @@ -576,171 +506,71 @@ class vmmDetails(gobject.GObject): self.toggle_storage_size() def prepare_hw_list(self): - hw_list_model = gtk.ListStore(int, str, gtk.gdk.Pixbuf, int, gobject.TYPE_PYOBJECT) + hw_list_model = gtk.ListStore(str, gtk.gdk.Pixbuf, int, gobject.TYPE_PYOBJECT) self.window.get_widget("hw-list").set_model(hw_list_model) - self.populate_hw_list() hwCol = gtk.TreeViewColumn("Hardware") hw_txt = gtk.CellRendererText() hw_img = gtk.CellRendererPixbuf() hwCol.pack_start(hw_txt, True) hwCol.pack_start(hw_img, False) - hwCol.add_attribute(hw_txt, 'text', 1) - hwCol.add_attribute(hw_img, 'pixbuf', 2) + hwCol.add_attribute(hw_txt, 'text', 0) + hwCol.add_attribute(hw_img, 'pixbuf', 1) self.window.get_widget("hw-list").append_column(hwCol) + self.populate_hw_list() + def populate_hw_list(self): hw_list_model = self.window.get_widget("hw-list").get_model() hw_list_model.clear() - hw_list_model.append([0, "Processor", self.pixbuf_processor, VMM_HW_CPU, []]) - hw_list_model.append([1, "Memory", self.pixbuf_memory, VMM_HW_MEMORY, []]) + hw_list_model.append(["Processor", self.pixbuf_processor, VMM_HW_CPU, []]) + hw_list_model.append(["Memory", self.pixbuf_memory, VMM_HW_MEMORY, []]) + self.repopulate_hw_list() + + def repopulate_hw_list(self): + hw_list_model = self.window.get_widget("hw-list").get_model() + + # Populate list of disks + for disk in self.vm.get_disk_devices(): + missing = True + insertAt = 0 + for row in hw_list_model: + if row[2] == VMM_HW_DISK and row[3][3] == disk[3]: + # Update metadata + row[3] = disk + missing = False + # The insert position must be *before* any NICs + if row[2] != VMM_HW_NIC: + insertAt = insertAt + 1 + + # Add in row + if missing: + hw_list_model.insert(insertAt, ["Disk %s" % disk[3], self.pixbuf_disk, VMM_HW_DISK, disk]) + + # Populate list of NICs + for nic in self.vm.get_network_devices(): + missing = True + insertAt = 0 + for row in hw_list_model: + if row[2] == VMM_HW_NIC and row[3][3] == nic[3]: + # Update metadata + row[3] = nic + missing = False + + # Insert poisition is at end.... + # XXX until we add support for Mice, etc + insertAt = insertAt + 1 + + # Add in row + if missing: + hw_list_model.insert(insertAt, ["NIC %s" % nic[2], self.pixbuf_nic, VMM_HW_NIC, nic]) - #all disks - disk_list = self.vm.get_disk_devices() - for i in range(len(disk_list)): - hw_list_model.append([i + 2, "Disk %d" % (i + 1), self.pixbuf_disk, VMM_HW_DISK, disk_list[i]]) - #all nics - nic_list = self.vm.get_network_devices() - offset = len(disk_list) + 2 - for i in range(len(nic_list)): - hw_list_model.append([offset + i, "Network %d" % (i + 1), self.pixbuf_network, VMM_HW_NIC, nic_list[i]]) - def add_hardware(self, src): - self.adding_hardware = True - widget = self.window.get_widget("add-hardware-device") - iter = widget.get_active_iter() - device = widget.get_model().get_value(iter, 0) - if VMM_HW_DEVICES.index(device) == 0: - # a new virtual disk - self.window.get_widget("hw-panel").set_current_page(4) - elif VMM_HW_DEVICES.index(device) == 1: - # a new vnic - network_menu = self.window.get_widget("network-name-pulldown") - self.populate_network_model(network_menu.get_model()) - network_menu.set_active(0) - network_menu.show() - self.window.get_widget("network-buttons").show() - self.window.get_widget("network-name").hide() - mac_addr = self.window.get_widget("network-mac-address") - mac_addr.set_editable(True) - mac_addr.set_text("") - self.window.get_widget("net-devlabel-label").hide() - self.window.get_widget("network-device-name").hide() - self.window.get_widget("hw-panel").set_current_page(3) - else: - pass - - def populate_network_model(self, model): - model.clear() - for uuid in self.vm.get_connection().list_net_uuids(): - net = self.vm.get_connection().get_net(uuid) - model.append([net.get_label(), net.get_name(), "network"]) - br = virtinst.util.default_bridge() - model.append([_("default bridge"), br, "bridge"]) + if self.addhw is None: + self.addhw = vmmAddHardware(self.config, self.vm) - def add_vnic(self, src): - network = None - bridge = None - net_name_widget = self.window.get_widget("network-name-pulldown") - net_name = net_name_widget.get_model().get_value(net_name_widget.get_active_iter(), 1) - net_type = net_name_widget.get_model().get_value(net_name_widget.get_active_iter(), 2) - mac_addr = self.window.get_widget("network-mac-address").get_text() - if mac_addr == "": - mac_addr = None - if net_type == "network": - network = net_name - else: - bridge = net_name - self.vm.add_network_device(mac_addr, net_type, bridge, network) - self.clean_up_add_hardware() + self.addhw.show() - def add_vbd(self, src): - # disks -# filesize = None -# if self.vm.is_hvm(): -# disknode = "hd" -# else: -# disknode = "xvd" -# if self.get_config_disk_size() != None: -# filesize = self.get_config_disk_size() / 1024.0 -# try: -# d = virtinst.VirtualDisk(self.get_config_disk_image(), filesize, sparse = self.is_sparse_file()) -# if d.type == virtinst.VirtualDisk.TYPE_FILE and \ -# self.vm.is_hvm() == False \ -# and virtinst.util.is_blktap_capable(): -# d.driver_name = virtinst.VirtualDisk.DRIVER_TAP -# if d.type == virtinst.VirtualDisk.TYPE_FILE and not \ -# self.is_sparse_file(): -# self.non_sparse = True -# else: -# self.non_sparse = False -# except ValueError, e: -# self._validation_error_box(_("Invalid storage address"), e.args[0]) -# return - -# #XXX add the progress bar in here... -# d.setup(progress.BaseMeter) -# xml = d.get_xml_config(disknode) -# logging.debug("Disk XML: %s" % d) -# self.vm.add_disk_device(xml) - self.clean_up_add_hardware() - - def get_config_disk_image(self): - if self.window.get_widget("storage-partition").get_active(): - return self.window.get_widget("storage-partition-address").get_text() - else: - return self.window.get_widget("storage-file-address").get_text() - - def get_config_disk_size(self): - if self.window.get_widget("storage-partition").get_active(): - return None - else: - return self.window.get_widget("storage-file-size").get_value() - - def is_sparse_file(self): - if self.window.get_widget("non-sparse").get_active(): - return False - else: - return True - - def clean_up_add_hardware(self, src=None): - self.adding_hardware = False - self.hw_selected() - - def _validation_error_box(self, text1, text2=None): - message_box = gtk.MessageDialog(self.window.get_widget("vmm-details"), \ - 0, \ - gtk.MESSAGE_ERROR, \ - gtk.BUTTONS_OK, \ - text1) - if text2 != None: - message_box.format_secondary_text(text2) - message_box.run() - message_box.destroy() - - def _browse_file(self, dialog_name, folder=None, type=None): - # user wants to browse for an ISO - fcdialog = gtk.FileChooserDialog(dialog_name, - self.window.get_widget("vmm-details"), - gtk.FILE_CHOOSER_ACTION_OPEN, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT), - None) - if type != None: - f = gtk.FileFilter() - f.add_pattern("*." + type) - fcdialog.set_filter(f) - if folder != None: - fcdialog.set_current_folder(folder) - response = fcdialog.run() - fcdialog.hide() - if(response == gtk.RESPONSE_ACCEPT): - filename = fcdialog.get_filename() - fcdialog.destroy() - return filename - else: - fcdialog.destroy() - return None gobject.type_register(vmmDetails) diff --git a/src/virtManager/domain.py b/src/virtManager/domain.py index b4cd6c563..f5a264c9a 100644 --- a/src/virtManager/domain.py +++ b/src/virtManager/domain.py @@ -23,7 +23,7 @@ import libxml2 import os import sys import logging -import virtinst + class vmmDomain(gobject.GObject): __gsignals__ = { @@ -44,6 +44,12 @@ class vmmDomain(gobject.GObject): self.lastStatus = None self.record = [] self._update_status() + self.xml = None + + def get_xml(self): + if self.xml is None: + self.xml = self.vm.XMLDesc(0) + return self.xml def set_handle(self, vm): self.vm = vm @@ -65,7 +71,7 @@ class vmmDomain(gobject.GObject): if id < 0: return "-" return str(id) - + def get_name(self): return self.vm.name() @@ -129,6 +135,8 @@ class vmmDomain(gobject.GObject): self.emit("status-changed", status) def tick(self, now): + # Clear cached XML + self.xml = None hostInfo = self.connection.get_host_info() info = self.vm.info() expected = self.config.get_stats_history_length() @@ -390,7 +398,7 @@ class vmmDomain(gobject.GObject): return self.config.get_vm_status_icon(self.status()) def get_xml_string(self, path): - xml = self.vm.XMLDesc(0) + xml = self.get_xml() doc = None try: doc = libxml2.parseDoc(xml) @@ -432,7 +440,7 @@ class vmmDomain(gobject.GObject): return [type, None, None] def get_disk_devices(self): - xml = self.vm.XMLDesc(0) + xml = self.get_xml() doc = None try: doc = libxml2.parseDoc(xml) @@ -476,7 +484,7 @@ class vmmDomain(gobject.GObject): self.vm.attachDevice(xml) def get_network_devices(self): - xml = self.vm.XMLDesc(0) + xml = self.get_xml() doc = None try: doc = libxml2.parseDoc(xml) @@ -487,31 +495,29 @@ class vmmDomain(gobject.GObject): try: ret = ctx.xpathEval("/domain/devices/interface") + n = 0 for node in ret: type = node.prop("type") devmac = None source = None - target = "Unspecified" + target = "eth%d" % n + n = n + 1 for child in node.children: if child.name == "source": if type == "bridge": - if child.prop("bridge") != None: - source = child.prop("bridge") - else: - source = child.prop("dev") + source = child.prop("bridge") + elif type == "ethernet": + source = child.prop("dev") elif type == "network": source = child.prop("network") elif type == "user": - source = "SLIRP network" + source = None + else: + source = None elif child.name == "mac": devmac = child.prop("address") - elif child.name == "target": - target = child.prop("dev") - if source == None: - source = "-" nics.append([type, source, target, devmac]) - finally: if ctx != None: ctx.xpathFreeContext() @@ -519,12 +525,12 @@ class vmmDomain(gobject.GObject): doc.freeDoc() return nics - def add_network_device(self, macaddr, type="bridge", bridge=None, network=None): - vnic = virtinst.VirtualNetworkInterface(macaddr, type, bridge, network) - vnic.setup(self.connection.vmm) - xml = vnic.get_xml_config() + def add_device(self, xml): self.vm.attachDevice(xml) + def remove_device(self, xml): + self.vm.detachDevice(xml) + def set_vcpu_count(self, vcpus): vcpus = int(vcpus) self.vm.setVcpus(vcpus) diff --git a/src/vmm-add-hardware.glade b/src/vmm-add-hardware.glade new file mode 100644 index 000000000..d52b9acf0 --- /dev/null +++ b/src/vmm-add-hardware.glade @@ -0,0 +1,2002 @@ + + + + + + + True + Add new virtual hardware + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + True + False + 0 + + + + 2 + True + True + True + True + GTK_POS_TOP + False + False + + + + + True + False + 0 + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 0 + 0 + + + + True + True + False + + + + True + <span weight="heavy" size="xx-large" foreground="#FFF">Adding new virtual hardware </span> + False + True + GTK_JUSTIFY_FILL + False + False + 0 + 0 + 5 + 6 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + 0 + False + True + + + + + + True + False + 0 + + + + True + This assistant will guide you through adding a new piece of virtual hardware. First select what type of hardware you wish to add: + False + True + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 20 + 10 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 25 + 0 + + + + 6 + True + 1 + 2 + False + 3 + 3 + + + + True + Hardware type: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + False + True + + + 1 + 2 + 0 + 1 + fill + + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + False + True + + + + + + True + Intro + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 1 + True + False + 0 + + + + True + True + False + + + + True + <span weight="heavy" size="xx-large" foreground="#FFF">Assigning storage space</span> + False + True + GTK_JUSTIFY_FILL + False + False + 0 + 0 + 5 + 6 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + 0 + False + True + + + + + + True + False + 0 + + + + True + Please indicate how you'd like to assign space on this physical host system for your new virtual storage device. + False + True + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 20 + 10 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 25 + 15 + + + + True + 9 + 5 + False + 2 + 0 + + + + True + 0.5 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + + + + + 0 + 1 + 1 + 2 + fill + fill + + + + + + True + P_artition: + True + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 4 + 0 + storage-partition-address + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 1 + 2 + fill + + + + + + + True + False + 0 + + + + True + 4 + gtk-info + 0.5 + 0.5 + 0 + 0 + + + 0 + False + True + + + + + + True + <small><b>Example:</b> /dev/hdc2</small> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 7 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 3 + 4 + 2 + 3 + fill + + + + + + True + File _Location: + True + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 4 + 0 + storage-file-address + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 5 + 6 + fill + + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 3 + 4 + 3 + 4 + fill + + + + + + + True + 0.5 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + + True + True + Normal Disk _Partition: + True + GTK_RELIEF_NORMAL + True + True + False + True + + + + + + 0 + 5 + 0 + 1 + fill + fill + + + + + + True + 0.5 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + + + + True + True + Simple F_ile: + True + GTK_RELIEF_NORMAL + True + False + False + True + storage-partition + + + + + + 0 + 5 + 4 + 5 + fill + fill + + + + + + True + False + 0 + + + + True + True + True + True + 0 + + True + + False + + + 0 + True + True + + + + + + True + True + Browse... + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + 3 + 5 + 1 + 2 + fill + fill + + + + + + True + False + 0 + + + + True + True + True + True + 0 + + True + + False + + + + 0 + True + True + + + + + + True + True + Browse... + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + 3 + 5 + 5 + 6 + fill + fill + + + + + + True + File _Size: + True + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 4 + 0 + storage-file-size + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 6 + 7 + fill + + + + + + + True + False + 0 + + + + True + 0 + 0.5 + 0 + 1 + 0 + 0 + 0 + 0 + + + + True + False + True + 1 + 0 + True + GTK_UPDATE_ALWAYS + True + False + 500 0 4000000 100 500 500 + + + + + + 0 + False + True + + + + + + True + MB + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 3 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + True + + + + + + + + + 3 + 4 + 6 + 7 + fill + fill + + + + + + True + False + 0 + + + + True + 4 + gtk-dialog-warning + 0.5 + 0 + 0 + 0 + + + 0 + False + True + + + + + + True + <small><b>Warning:</b> If you do not allocate the entire disk at VM creation, space will be allocated as needed while the guest is running. If sufficient free space is not available on the host, this may result in data corruption on the guest.</small> + False + True + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 7 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 2 + 5 + 8 + 9 + fill + + + + + + True + True + Allocate entire virtual disk now? + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 3 + 4 + 7 + 8 + fill + + + + + + + + 0 + False + True + + + + + 0 + True + True + + + + + False + True + + + + + + True + Disk + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 1 + True + False + 0 + + + + True + True + False + + + + True + <span weight="heavy" size="xx-large" foreground="#FFF">Connect to host network</span> + False + True + GTK_JUSTIFY_FILL + False + False + 0 + 0 + 5 + 6 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + 0 + False + True + + + + + + True + False + 0 + + + + True + Please indicate how you'd like to connect your new virtual network device to the host network. + False + True + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 20 + 10 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 25 + 15 + + + + True + 6 + 2 + False + 6 + 0 + + + + True + False + True + + + 1 + 2 + 4 + 5 + fill + fill + + + + + + True + True + _Virtual network + True + GTK_RELIEF_NORMAL + True + True + False + True + + + + 0 + 2 + 0 + 1 + fill + fill + + + + + + True + True + _Shared physical device + True + GTK_RELIEF_NORMAL + True + False + False + True + net-type-network + + + + 0 + 2 + 3 + 4 + fill + fill + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 40 + 0 + + + + True + False + 0 + + + + True + 4 + gtk-dialog-info + 0.5 + 0 + 0 + 0 + + + 0 + False + True + + + + + + True + <small><b>Tip:</b> Choose this option if your host is disconnected, connected via wireless, or dynamically configured with NetworkManager.</small> + False + True + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 7 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + 0 + 2 + 2 + 3 + fill + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 40 + 0 + + + + True + False + 0 + + + + True + 4 + gtk-dialog-info + 0.5 + 0 + 0 + 0 + + + 0 + False + True + + + + + + True + <small><b>Tip:</b> Choose this option if your host is statically connected to wired ethernet, to gain the ability to migrate the virtual system.</small> + False + True + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 7 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + 0 + 2 + 5 + 6 + fill + + + + + + True + False + True + + + 1 + 2 + 1 + 2 + fill + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 40 + 0 + + + + True + True + False + + + + True + _Network: + True + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 4 + 0 + storage-partition-address + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 40 + 0 + + + + True + True + False + + + + True + _Device: + True + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 4 + 0 + storage-file-address + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + 0 + 1 + 4 + 5 + fill + + + + + + + + 0 + False + True + + + + + 0 + True + True + + + + + False + True + + + + + + True + Network + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 1 + True + False + 0 + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 0 + 0 + + + + True + True + False + + + + True + <span weight="heavy" size="xx-large" foreground="#FFF">Ready to add hardware</span> + False + True + GTK_JUSTIFY_FILL + False + False + 0 + 0 + 5 + 6 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + + + 0 + False + True + + + + + + True + 0.10000000149 + 0.10000000149 + 1 + 0 + 6 + 6 + 24 + 6 + + + + True + False + 0 + + + + 6 + True + 3 + 3 + False + 3 + 3 + + + + True + 5 GB + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 2 + 3 + + + + + + + True + /xen/demo.img + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_MIDDLE + -1 + False + 0 + + + 2 + 3 + 1 + 2 + fill + + + + + + + True + Disk image: + False + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + Disk size: + False + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 2 + 3 + fill + + + + + + + True + <b>Storage</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 5 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 3 + 0 + 1 + fill + + + + + + 0 + True + True + + + + + + 6 + True + 3 + 3 + False + 3 + 3 + + + + True + <b>Network</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 5 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 3 + 0 + 1 + fill + + + + + + + True + Shared Physical Device + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 1 + 2 + fill + + + + + + + True + eth0 + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 2 + 3 + fill + + + + + + + True + Connection type: + False + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + Target: + False + True + GTK_JUSTIFY_LEFT + False + False + 1 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 2 + 3 + fill + + + + + + 0 + True + True + + + + + + + 0 + True + True + + + + + False + True + + + + + + True + Complete + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + 0 + 0.5 + 1 + 1 + 0 + 0 + 0 + 0 + + + + True + True + gtk-help + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + False + True + + + + + + True + 1 + 0.5 + 1 + 1 + 0 + 0 + 0 + 0 + + + + True + False + 10 + + + + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + True + True + gtk-go-back + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + True + True + gtk-go-forward + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-quit + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + _Finish + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + 0 + False + False + + + + + + + 0 + False + False + GTK_PACK_END + + + + + 0 + False + False + + + + + + + diff --git a/src/vmm-add-virtual-nic.glade b/src/vmm-add-virtual-nic.glade deleted file mode 100644 index f95e8fec6..000000000 --- a/src/vmm-add-virtual-nic.glade +++ /dev/null @@ -1,397 +0,0 @@ - - - - - - - True - Add Virtual NIC - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - True - - - - True - False - 0 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - True - True - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - -5 - - - - - 0 - False - True - GTK_PACK_END - - - - - - True - False - 0 - - - - True - Add virtual NIC with: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 5 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - Randomly generated MAC address - True - GTK_RELIEF_NORMAL - True - True - False - True - - mac-addr-random - - - - 0 - False - False - - - - - - True - False - True - Specified MAC address: - True - GTK_RELIEF_NORMAL - True - False - False - True - mac-addr-random - - - 0 - False - False - - - - - - True - 0.5 - 0.5 - 1 - 1 - 0 - 0 - 11 - 0 - - - - True - False - 0 - - - - True - 00:16:3e: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 2 - - True - - False - 2 - - - 0 - False - False - - - - - - True - : - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 2 - - True - - True - 2 - - - 0 - False - False - - - - - - True - : - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - True - True - True - 2 - - True - - False - 2 - - - 0 - False - False - - - - - - - 0 - False - True - - - - - - True - False - 0 - - - - True - 0.5 - 0.5 - 1 - 1 - 0 - 0 - 13 - 0 - - - - True - gtk-info - 4 - 0.5 - 0.5 - 0 - 0 - - - - - 0 - False - False - - - - - - True - 0.5 - 0.5 - 1 - 1 - 0 - 0 - 3 - 0 - - - - True - <b>Tip:</b> Acceptable values for hex digits are the numbers 0-9 and the letters A-F - False - True - GTK_JUSTIFY_LEFT - True - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - - - 0 - False - False - - - - - 0 - True - False - - - - - 0 - True - True - - - - - - - diff --git a/src/vmm-details.glade b/src/vmm-details.glade index 507c168a1..b1137b612 100644 --- a/src/vmm-details.glade +++ b/src/vmm-details.glade @@ -877,13 +877,13 @@ + 5 True False - 0 + 6 - 10 True True GTK_POLICY_AUTOMATIC @@ -913,87 +913,14 @@ - + True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 0 - 0 - 12 - 0 - - - - True - False - 0 - - - - True - - False - True - - - 0 - True - True - - - - - - True - True - gtk-add - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - - - - - True - Add hardware: - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - + True + gtk-add + True + GTK_RELIEF_NORMAL + True + 0 @@ -1952,7 +1879,7 @@ GTK_SHADOW_NONE - + True 0.5 0.5 @@ -1965,17 +1892,18 @@ + 3 True 4 - 3 + 2 False - 0 - 0 + 3 + 3 True - Storage Type: + Source type: True False GTK_JUSTIFY_LEFT @@ -1985,7 +1913,6 @@ 0.5 0 0 - network-name PANGO_ELLIPSIZE_NONE -1 False @@ -2004,7 +1931,7 @@ True - _Source: + Source path: True False GTK_JUSTIFY_LEFT @@ -2014,7 +1941,6 @@ 0.5 0 0 - storage-source PANGO_ELLIPSIZE_NONE -1 False @@ -2023,8 +1949,8 @@ 0 1 - 2 - 3 + 1 + 2 fill @@ -2033,7 +1959,7 @@ True - _Device Label: + Target device: True False GTK_JUSTIFY_LEFT @@ -2043,7 +1969,6 @@ 0.5 0 0 - device-label PANGO_ELLIPSIZE_NONE -1 False @@ -2060,49 +1985,7 @@ - - True - True - False - True - 0 - - True - - False - - - 1 - 3 - 3 - 4 - - - - - - - True - True - False - True - 0 - - True - - False - - - 1 - 3 - 2 - 3 - - - - - - + True Block False @@ -2130,7 +2013,7 @@ - + True disk False @@ -2150,8 +2033,8 @@ 1 2 - 1 - 2 + 2 + 3 fill @@ -2160,7 +2043,7 @@ True - Storage Device: + Target type: True False GTK_JUSTIFY_LEFT @@ -2178,6 +2061,62 @@ 0 1 + 2 + 3 + fill + + + + + + + True + label393 + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 3 + 4 + fill + + + + + + + True + label402 + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 1 2 fill @@ -2271,7 +2210,7 @@ True - <b>Tip:</b> "Source" is the path to the virtual disk's backing store on the host. "Device Label" is the label your virtual machine will use when referring to this virtual disk. + <b>Tip:</b> 'source' refers to information seen from the host OS, while 'target' refers to information seen from the guest OS False True GTK_JUSTIFY_LEFT @@ -2372,17 +2311,18 @@ + 3 True - 7 - 3 + 4 + 2 False - 0 - 0 + 3 + 3 True - _Network: + Source type: True False GTK_JUSTIFY_LEFT @@ -2392,7 +2332,6 @@ 0.5 0 0 - network-name PANGO_ELLIPSIZE_NONE -1 False @@ -2400,6 +2339,34 @@ 0 + 1 + 0 + 1 + fill + + + + + + + True + label395 + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 2 0 1 @@ -2408,39 +2375,10 @@ - - - True - _Device Label: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - network-device-name - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - 2 - 5 - 6 - fill - - - - True - _MAC Address: + MAC address: True False GTK_JUSTIFY_LEFT @@ -2458,6 +2396,34 @@ 0 + 1 + 3 + 4 + fill + + + + + + + True + label396 + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 2 3 4 @@ -2467,79 +2433,113 @@ - + True - False - True + Source device: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 - 1 - 3 + 0 + 1 1 2 fill - - - - - - True - True - True - True - 0 - - True - - False - - - 1 - 3 - 4 - 5 - + True - True - False - True - 0 - - True - - False + Target device: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 - 1 - 3 - 6 - 7 - - - - - - - True - True - False - True - 0 - - True - - False - - - 1 - 3 + 0 + 1 2 3 + fill + + + + + + + True + label399 + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 2 + 3 + fill + + + + + + + True + label401 + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 1 + 2 + fill @@ -2602,7 +2602,7 @@ gtk-info 4 0.5 - 0.5 + 0 0 0 @@ -2628,9 +2628,9 @@ 0 - + True - <b>Tip:</b> "No network name" typically means this virtual network interface is bridged directly to the physical NIC. + <b>Tip:</b> 'source' refers to information seen from the host OS, while 'target' refers to information seen from the guest OS False True GTK_JUSTIFY_LEFT @@ -2660,46 +2660,6 @@ False - - - - True - GTK_BUTTONBOX_END - 5 - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - - True - True - True - gtk-apply - True - GTK_RELIEF_NORMAL - True - - - - - - 0 - False - False - GTK_PACK_END - - False @@ -2729,717 +2689,6 @@ tab - - - - True - False - 0 - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - False - 0 - - - - True - Please choose a partition or a file to use as physical storage for your virtual disk: - False - True - GTK_JUSTIFY_LEFT - True - False - 0 - 0.5 - 20 - 10 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - 0.5 - 0.5 - 1 - 1 - 0 - 0 - 25 - 15 - - - - True - 9 - 5 - False - 2 - 0 - - - - True - 0.5 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - - - - - - - 0 - 1 - 1 - 2 - fill - fill - - - - - - True - P_artition: - True - True - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 4 - 0 - storage-partition-address - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 2 - 3 - 1 - 2 - fill - - - - - - - True - False - 0 - - - - True - 4 - gtk-info - 0.5 - 0.5 - 0 - 0 - - - 0 - False - True - - - - - - True - <small><b>Example:</b> /dev/hdc2</small> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 7 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - 3 - 4 - 2 - 3 - fill - - - - - - True - File _Location: - True - True - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 4 - 0 - storage-file-address - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 2 - 3 - 5 - 6 - fill - - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 3 - 4 - 3 - 4 - fill - - - - - - - True - 0.5 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - - - - True - True - Normal Disk _Partition: - True - GTK_RELIEF_NORMAL - True - True - False - True - - - - - - 0 - 5 - 0 - 1 - fill - fill - - - - - - True - 0.5 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - - - - True - True - Simple F_ile: - True - GTK_RELIEF_NORMAL - True - False - False - True - storage-partition - - - - - - 0 - 5 - 4 - 5 - fill - fill - - - - - - True - False - 0 - - - - True - True - True - True - 0 - - True - - False - - - 0 - True - True - - - - - - True - True - Browse... - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - 3 - 5 - 1 - 2 - fill - fill - - - - - - True - False - 0 - - - - True - True - True - True - 0 - - True - - False - - - - 0 - True - True - - - - - - True - True - Browse... - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - 3 - 5 - 5 - 6 - fill - fill - - - - - - True - File _Size: - True - True - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 4 - 0 - storage-file-size - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 2 - 3 - 6 - 7 - fill - - - - - - - True - False - 0 - - - - True - 0 - 0.5 - 0 - 1 - 0 - 0 - 0 - 0 - - - - True - False - True - 1 - 0 - True - GTK_UPDATE_ALWAYS - True - False - 500 0 4000000 100 500 500 - - - - - - 0 - False - True - - - - - - True - MB - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 3 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - True - - - - - - - - - 3 - 4 - 6 - 7 - fill - fill - - - - - - True - False - 0 - - - - True - 4 - gtk-dialog-warning - 0.5 - 0 - 0 - 0 - - - 0 - False - True - - - - - - True - <small><b>Warning:</b> If you do not allocate the entire virtual disk when you create it, space will be allocated as needed while the guest is running. If sufficient free space is not available on the host, this may result in data corruption on the guest.</small> - False - True - GTK_JUSTIFY_LEFT - True - False - 0.5 - 0.5 - 7 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - 2 - 5 - 8 - 9 - fill - - - - - - True - True - Allocate entire virtual disk now? - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 3 - 4 - 7 - 8 - fill - - - - - - - - 0 - False - True - - - - - - - - True - <b>Virtual Disk</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - label_item - - - - - 15 - True - True - - - - - - True - GTK_BUTTONBOX_END - 5 - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - - - True - True - True - gtk-apply - True - GTK_RELIEF_NORMAL - True - - - - - - 0 - False - False - - - - - False - True - - - - - - True - Add Disk - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - tab - - True