virt-manager/src/virtManager/addhardware.py

867 lines
39 KiB
Python
Raw Normal View History

#
# Copyright (C) 2006-2007 Red Hat, Inc.
# Copyright (C) 2006 Hugh O. Brock <hbrock@redhat.com>
#
# 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
import statvfs
from virtManager.asyncjob import vmmAsyncJob
from virtManager.error import vmmErrorDialog
from virtManager.createmeter import vmmCreateMeter
VM_STORAGE_PARTITION = 1
VM_STORAGE_FILE = 2
DEFAULT_STORAGE_FILE_SIZE = 500
PAGE_INTRO = 0
PAGE_DISK = 1
PAGE_NETWORK = 2
PAGE_INPUT = 3
PAGE_GRAPHICS = 4
PAGE_SUMMARY = 5
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_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_create_help_clicked": self.show_help,
})
hw_list = self.window.get_widget("hardware-type")
2007-07-14 22:43:52 +04:00
model = gtk.ListStore(str, str, int)
hw_list.set_model(model)
icon = gtk.CellRendererPixbuf()
hw_list.pack_start(icon, False)
2007-07-14 22:43:52 +04:00
hw_list.add_attribute(icon, 'stock-id', 1)
text = gtk.CellRendererText()
hw_list.pack_start(text, True)
hw_list.add_attribute(text, 'text', 0)
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")
2007-07-14 22:43:52 +04:00
device_model = gtk.ListStore(str, bool)
device_list.set_model(device_model)
text = gtk.CellRendererText()
device_list.pack_start(text, True)
device_list.add_attribute(text, 'text', 0)
2007-07-14 22:43:52 +04:00
device_list.add_attribute(text, 'sensitive', 1)
target_list = self.window.get_widget("target-device")
target_model = gtk.ListStore(str, int, str, str, str)
target_list.set_model(target_model)
icon = gtk.CellRendererPixbuf()
target_list.pack_start(icon, False)
target_list.add_attribute(icon, 'stock-id', 3)
text = gtk.CellRendererText()
target_list.pack_start(text, True)
target_list.add_attribute(text, 'text', 4)
input_list = self.window.get_widget("input-type")
input_model = gtk.ListStore(str, str, str, bool)
input_list.set_model(input_model)
text = gtk.CellRendererText()
input_list.pack_start(text, True)
input_list.add_attribute(text, 'text', 0)
input_list.add_attribute(text, 'sensitive', 3)
graphics_list = self.window.get_widget("graphics-type")
graphics_model = gtk.ListStore(str,str)
graphics_list.set_model(graphics_model)
text = gtk.CellRendererText()
graphics_list.pack_start(text, True)
graphics_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.window.get_widget("create-help").hide()
self.change_storage_type()
self.change_network_type()
self.change_macaddr_use()
self.change_port_auto()
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)
self.window.get_widget("hardware-type").set_active(0)
self.window.get_widget("net-type-network").set_active(True)
self.window.get_widget("net-type-device").set_active(False)
self.window.get_widget("mac-address").set_active(False)
self.window.get_widget("create-mac-address").set_text("")
net_box = self.window.get_widget("net-network")
self.populate_network_model(net_box.get_model())
net_box.set_active(0)
dev_box = self.window.get_widget("net-device")
2007-07-14 22:43:52 +04:00
if self.populate_device_model(dev_box.get_model()):
dev_box.set_active(0)
else:
dev_box.set_active(-1)
target_list = self.window.get_widget("target-device")
target_list.set_active(-1)
input_box = self.window.get_widget("input-type")
self.populate_input_model(input_box.get_model())
input_box.set_active(0)
graphics_box = self.window.get_widget("graphics-type")
self.populate_graphics_model(graphics_box.get_model())
graphics_box.set_active(0)
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("")
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:
model.append(["Network card", gtk.STOCK_NETWORK, PAGE_NETWORK])
# Can only customize HVM guests, no Xen PV
if self.vm.is_hvm():
model.append(["Input device", gtk.STOCK_INDEX, PAGE_INPUT])
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):
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_disk_target(self):
target = self.window.get_widget("target-device")
node = target.get_model().get_value(target.get_active_iter(), 0)
maxnode = target.get_model().get_value(target.get_active_iter(), 1)
device = target.get_model().get_value(target.get_active_iter(), 2)
return node, maxnode, device
def get_config_input(self):
target = self.window.get_widget("input-type")
label = target.get_model().get_value(target.get_active_iter(), 0)
type = target.get_model().get_value(target.get_active_iter(), 1)
bus = target.get_model().get_value(target.get_active_iter(), 2)
return label, type, bus
def get_config_graphics(self):
type = self.window.get_widget("graphics-type")
return type.get_model().get_value(type.get_active_iter(), 1)
def get_config_vnc_port(self):
port = self.window.get_widget("graphics-port")
portAuto = self.window.get_widget("graphics-port-auto")
if portAuto.get_active():
return -1
return int(port.get_value())
def get_config_vnc_address(self):
addr = self.window.get_widget("graphics-address")
if addr.get_active():
return "0.0.0.0"
return "127.0.0.1"
def get_config_vnc_password(self):
pw = self.window.get_widget("graphics-password")
return pw.get_text()
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 get_config_macaddr(self):
macaddr = None
if self.window.get_widget("mac-address").get_active():
macaddr = self.window.get_widget("create-mac-address").get_text()
return macaddr
def page_changed(self, notebook, page, page_number):
if page_number == PAGE_DISK:
target = self.window.get_widget("target-device")
if target.get_active() == -1:
self.populate_target_device_model(target.get_model())
elif page_number == PAGE_NETWORK:
pass
elif page_number == PAGE_SUMMARY:
hwpage = self.get_config_hardware_type()
self.window.get_widget("summary-disk").hide()
self.window.get_widget("summary-network").hide()
self.window.get_widget("summary-input").hide()
self.window.get_widget("summary-graphics").hide()
if hwpage == PAGE_DISK:
self.window.get_widget("summary-disk").show()
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-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]
macaddr = self.get_config_macaddr()
if macaddr != None:
self.window.get_widget("summary-mac-address").set_text(macaddr)
else:
self.window.get_widget("summary-mac-address").set_text("-")
elif hwpage == PAGE_INPUT:
self.window.get_widget("summary-input").show()
input = self.get_config_input()
self.window.get_widget("summary-input-type").set_text(input[0])
if input[1] == "tablet":
self.window.get_widget("summary-input-mode").set_text(_("Absolute movement"))
else:
self.window.get_widget("summary-input-mode").set_text(_("Relative movement"))
elif hwpage == PAGE_GRAPHICS:
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")
else:
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:
self.window.get_widget("summary-graphics-port").set_text(_("Automatically allocated"))
else:
self.window.get_widget("summary-graphics-port").set_text(str(self.get_config_vnc_port()))
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"))
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"))
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()
elif hw == PAGE_INPUT:
self.add_input()
elif hw == PAGE_GRAPHICS:
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.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()
mac = self.get_config_macaddr()
vnic = None
if net[0] == "bridge":
vnic = virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0], bridge=net[1])
elif net[0] == "network":
vnic = virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0], network=net[1])
else:
raise ValueError, "Unsupported networking type " + net[0]
vnic.setup(self.vm.get_connection().vmm)
self.add_device(vnic.get_xml_config())
def add_input(self):
input = self.get_config_input()
xml = "<input type='%s' bus='%s'/>\n" % (input[1], input[2])
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)
def add_storage(self):
node, maxnode, device = self.get_config_disk_target()
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,
device = device,
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():
# QEMU, only hdc can be a CDROM
if self.vm.get_connection().get_type().lower() == "qemu" and \
device == virtinst.VirtualDisk.DEVICE_CDROM:
nodes.append(node + "c")
else:
for n in range(maxnode):
nodes.append("%s%c" % (node, ord('a')+n))
else:
for n in range(maxnode):
nodes.append("%s%c" % (node, 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()
if self.install_error == None:
self.add_device(disk.get_xml_config(node))
def add_device(self, xml):
logging.debug("Adding device " + xml)
try:
self.vm.add_device(xml)
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 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)
folder = self.config.get_default_image_dir(self.vm.get_connection())
file = self._browse_file(_("Locate or Create New Storage File"), \
folder=folder, confirm_overwrite=True)
if file != None:
self.window.get_widget("storage-file-address").set_text(file)
def _browse_file(self, dialog_name, folder=None, type=None, confirm_overwrite=False):
# user wants to browse for an ISO
fcdialog = gtk.FileChooserDialog(dialog_name,
self.window.get_widget("vmm-add-hardware"),
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)
if confirm_overwrite:
fcdialog.set_do_overwrite_confirmation(True)
fcdialog.connect("confirm-overwrite", self.confirm_overwrite_callback)
response = fcdialog.run()
fcdialog.hide()
if(response == gtk.RESPONSE_ACCEPT):
filename = fcdialog.get_filename()
fcdialog.destroy()
return filename
else:
fcdialog.destroy()
return None
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 change_macaddr_use(self, ignore=None):
if self.window.get_widget("mac-address").get_active():
self.window.get_widget("create-mac-address").set_sensitive(True)
else:
self.window.get_widget("create-mac-address").set_sensitive(False)
def change_graphics_type(self,ignore=None):
graphics = self.get_config_graphics()
if graphics == "vnc":
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.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)
def change_port_auto(self,ignore=None):
if self.window.get_widget("graphics-port-auto").get_active():
self.window.get_widget("graphics-port").set_sensitive(False)
else:
self.window.get_widget("graphics-port").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
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
if not self.window.get_widget("storage-partition").get_active():
disk = self.get_config_disk_image()
size = self.get_config_disk_size()
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
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?"))
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
node, nodemax, device = self.get_config_disk_target()
if self.window.get_widget("storage-partition").get_active():
type = virtinst.VirtualDisk.TYPE_BLOCK
else:
type = virtinst.VirtualDisk.TYPE_FILE
d = virtinst.VirtualDisk(self.get_config_disk_image(),
self.get_config_disk_size(),
type = type,
sparse = self.is_sparse_file(),
device=device)
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
if self.window.get_widget("mac-address").get_active():
mac= self.window.get_widget("create-mac-address").get_text()
if len(mac) != 17:
self._validation_error_box(_("Invalid MAC address"), \
_("MAC adrress must be 17 characters"))
return False
if re.match("^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$",mac) == None:
self._validation_error_box(_("Invalid MAC address"), \
_("MAC address must be a form such as AA:BB:CC:DD:EE:FF, and MAC adrress may contain numeric and alphabet of A-F(a-f) and ':' characters only"))
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"))
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)
vnic = virtinst.VirtualNetworkInterface(macaddr=mac)
if (vnic.countMACaddr(vms) - vnic.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 vnic.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 ?"))
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():
net = self.vm.get_connection().get_net(uuid)
model.append([net.get_label(), net.get_name()])
def populate_device_model(self, model):
model.clear()
2007-07-14 22:43:52 +04:00
hasShared = False
for name in self.vm.get_connection().list_net_device_paths():
net = self.vm.get_connection().get_net_device(name)
if net.is_shared():
2007-07-14 22:43:52 +04:00
hasShared = True
model.append(["%s (%s %s)" % (net.get_name(), _("Bridge"), net.get_bridge()), True])
else:
model.append(["%s (%s)" % (net.get_name(), _("Not bridged")), False])
return hasShared
def populate_target_device_model(self, model):
model.clear()
if self.vm.is_hvm():
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(["xvd", 26, virtinst.VirtualDisk.DEVICE_DISK, gtk.STOCK_HARDDISK, "Virtual disk"])
#model.append(["usb", virtinst.VirtualDisk.DEVICE_DISK, gtk.STOCK_HARDDISK, "USB disk"])
else:
model.append(["xvd", 26, virtinst.VirtualDisk.DEVICE_DISK, gtk.STOCK_HARDDISK, "Virtual disk"])
def populate_input_model(self, model):
model.clear()
model.append([_("EvTouch USB Graphics Tablet"), "tablet", "usb", True])
# XXX libvirt needs to support 'model' for input devices to distinguish
# wacom from evtouch tablets
#model.append([_("Wacom Graphics Tablet"), "tablet", "usb", True])
model.append([_("Generic USB Mouse"), "mouse", "usb", True])
def populate_graphics_model(self, model):
model.clear()
model.append([_("VNC server"), "vnc"])
# XXX inclined to just not give this choice at all
model.append([_("Local SDL window"), "sdl"])
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)