2
# Copyright (C) 2006-2007 Red Hat, Inc.
3
# Copyright (C) 2006 Hugh O. Brock <hbrock@redhat.com>
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
30
from virtinst import (VirtualCharDevice, VirtualDevice, VirtualVideoDevice,
33
import virtManager.util as util
34
import virtManager.uihelpers as uihelpers
35
from virtManager.asyncjob import vmmAsyncJob
36
from virtManager.error import vmmErrorDialog
37
from virtManager.createmeter import vmmCreateMeter
38
from virtManager.storagebrowse import vmmStorageBrowser
40
VM_STORAGE_PARTITION = 1
43
DEFAULT_STORAGE_FILE_SIZE = 500
57
char_widget_mappings = {
58
"source_path" : "char-path",
59
"source_mode" : "char-mode",
60
"source_host" : "char-host",
61
"source_port" : "char-port",
62
"bind_port": "char-bind-port",
63
"bind_host": "char-bind-host",
64
"protocol" : "char-use-telnet",
67
class vmmAddHardware(gobject.GObject):
69
"action-show-help": (gobject.SIGNAL_RUN_FIRST,
70
gobject.TYPE_NONE, [str]),
72
def __init__(self, config, vm):
73
self.__gobject_init__()
76
self.conn = vm.get_connection()
77
self.window = gtk.glade.XML(config.get_glade_dir() + "/vmm-add-hardware.glade", "vmm-add-hardware", domain="virt-manager")
78
self.topwin = self.window.get_widget("vmm-add-hardware")
79
self.err = vmmErrorDialog(self.topwin,
80
0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
81
_("Unexpected Error"),
82
_("An unexpected error occurred"))
84
self.storage_browser = None
87
self.host_storage_timer = None
92
self.window.signal_autoconnect({
93
"on_create_pages_switch_page" : self.page_changed,
94
"on_create_cancel_clicked" : self.close,
95
"on_vmm_create_delete_event" : self.close,
96
"on_create_back_clicked" : self.back,
97
"on_create_forward_clicked" : self.forward,
98
"on_create_finish_clicked" : self.finish,
99
"on_create_help_clicked": self.show_help,
101
"on_hardware_type_changed" : self.hardware_type_changed,
103
"on_config_storage_browse_clicked": self.browse_storage,
104
"on_config_storage_select_toggled": self.toggle_storage_select,
106
"on_mac_address_clicked" : self.change_macaddr_use,
108
"on_graphics_type_changed": self.change_graphics_type,
109
"on_graphics_port_auto_toggled": self.change_port_auto,
110
"on_graphics_keymap_toggled": self.change_keymap,
112
"on_host_device_type_changed": self.change_host_device_type,
114
"on_char_device_type_changed": self.change_char_device_type,
116
# Char dev info signals
117
"char_device_type_focus": (self.update_doc, "char_type"),
118
"char_path_focus_in": (self.update_doc, "source_path"),
119
"char_mode_changed": (self.update_doc_changed, "source_mode"),
120
"char_mode_focus" : (self.update_doc, "source_mode"),
121
"char_host_focus_in": (self.update_doc, "source_host"),
122
"char_bind_host_focus_in": (self.update_doc, "bind_host"),
123
"char_telnet_focus_in": (self.update_doc, "protocol"),
125
util.bind_escape_key_close(self)
127
# XXX: Help docs useless/out of date
128
self.window.get_widget("create-help").hide()
130
finish_img = gtk.image_new_from_stock(gtk.STOCK_QUIT,
131
gtk.ICON_SIZE_BUTTON)
132
self.window.get_widget("create-finish").set_image(finish_img)
134
self.set_initial_state()
136
def update_doc(self, ignore1, ignore2, param):
137
doc = self._build_doc_str(param)
138
self.window.get_widget("char-info").set_markup(doc)
140
def update_doc_changed(self, ignore1, param):
141
# Wrapper for update_doc and 'changed' signal
142
self.update_doc(None, None, param)
144
def _build_doc_str(self, param, docstr=None):
146
doctmpl = "<i>%s</i>"
149
doc = doctmpl % (docstr)
151
devclass = self._dev.__class__
152
if hasattr(devclass, param):
153
doc = doctmpl % (getattr(devclass, param).__doc__)
159
self.topwin.present()
161
def close(self, ignore1=None,ignore2=None):
166
def remove_timers(self):
168
if self.host_storage_timer:
169
gobject.source_remove(self.host_storage_timer)
170
self.host_storage_timer = None
174
def is_visible(self):
175
if self.topwin.flags() & gtk.VISIBLE:
180
##########################
181
# Initialization methods #
182
##########################
184
def set_initial_state(self):
185
notebook = self.window.get_widget("create-pages")
186
notebook.set_show_tabs(False)
188
black = gtk.gdk.color_parse("#000")
189
for num in range(PAGE_SUMMARY+1):
190
name = "page" + str(num) + "-title"
191
self.window.get_widget(name).modify_bg(gtk.STATE_NORMAL,black)
194
hw_list = self.window.get_widget("hardware-type")
195
# Name, icon name, page number, is sensitive, tooltip, icon size
196
model = gtk.ListStore(str, str, int, bool, str)
197
hw_list.set_model(model)
198
icon = gtk.CellRendererPixbuf()
199
icon.set_property("stock-size", gtk.ICON_SIZE_BUTTON)
200
hw_list.pack_start(icon, False)
201
hw_list.add_attribute(icon, 'icon-name', 1)
202
text = gtk.CellRendererText()
203
text.set_property("xpad", 6)
204
hw_list.pack_start(text, True)
205
hw_list.add_attribute(text, 'text', 0)
206
hw_list.add_attribute(text, 'sensitive', 3)
208
# Virtual network list
209
net_list = self.window.get_widget("net-list")
210
bridge_box = self.window.get_widget("net-bridge-box")
211
uihelpers.init_network_list(net_list, bridge_box)
214
netmodel_list = self.window.get_widget("net-model")
215
uihelpers.build_netmodel_combo(self.vm, netmodel_list)
217
# Disk device type / bus
218
target_list = self.window.get_widget("config-storage-devtype")
219
target_model = gtk.ListStore(str, str, str, str, int)
220
target_list.set_model(target_model)
221
icon = gtk.CellRendererPixbuf()
222
icon.set_property("stock-size", gtk.ICON_SIZE_BUTTON)
223
target_list.pack_start(icon, False)
224
target_list.add_attribute(icon, 'icon-name', 2)
225
text = gtk.CellRendererText()
226
text.set_property("xpad", 6)
227
target_list.pack_start(text, True)
228
target_list.add_attribute(text, 'text', 3)
231
sparse_info = self.window.get_widget("config-storage-nosparse-info")
232
uihelpers.set_sparse_tooltip(sparse_info)
235
input_list = self.window.get_widget("input-type")
236
input_model = gtk.ListStore(str, str, str, bool)
237
input_list.set_model(input_model)
238
text = gtk.CellRendererText()
239
input_list.pack_start(text, True)
240
input_list.add_attribute(text, 'text', 0)
241
input_list.add_attribute(text, 'sensitive', 3)
244
graphics_list = self.window.get_widget("graphics-type")
245
graphics_model = gtk.ListStore(str,str)
246
graphics_list.set_model(graphics_model)
247
text = gtk.CellRendererText()
248
graphics_list.pack_start(text, True)
249
graphics_list.add_attribute(text, 'text', 0)
252
sound_list = self.window.get_widget("sound-model")
253
uihelpers.build_sound_combo(self.vm, sound_list)
255
host_devtype = self.window.get_widget("host-device-type")
256
# Description, nodedev type, specific type capability, sub type,
258
host_devtype_model = gtk.ListStore(str, str, str, str, str)
259
host_devtype.set_model(host_devtype_model)
260
text = gtk.CellRendererText()
261
host_devtype.pack_start(text, True)
262
host_devtype.add_attribute(text, 'text', 0)
264
host_dev = self.window.get_widget("host-device")
265
# Description, nodedev name
266
host_dev_model = gtk.ListStore(str, str)
267
host_dev.set_model(host_dev_model)
268
text = gtk.CellRendererText()
269
host_dev.pack_start(text, True)
270
host_dev.add_attribute(text, 'text', 0)
271
host_dev_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
274
video_dev = self.window.get_widget("video-model")
275
uihelpers.build_video_combo(self.vm, video_dev)
277
char_devtype = self.window.get_widget("char-device-type")
279
char_devtype_model = gtk.ListStore(str, str)
280
char_devtype.set_model(char_devtype_model)
281
text = gtk.CellRendererText()
282
char_devtype.pack_start(text, True)
283
char_devtype.add_attribute(text, 'text', 1)
284
char_devtype_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
285
for t in VirtualCharDevice.char_types:
286
desc = VirtualCharDevice.get_char_type_desc(t)
287
char_devtype_model.append([t, desc + " (%s)" % t])
289
char_mode = self.window.get_widget("char-mode")
291
char_mode_model = gtk.ListStore(str, str)
292
char_mode.set_model(char_mode_model)
293
text = gtk.CellRendererText()
294
char_mode.pack_start(text, True)
295
char_mode.add_attribute(text, 'text', 1)
296
char_mode_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
297
for t in VirtualCharDevice.char_modes:
298
desc = VirtualCharDevice.get_char_mode_desc(t)
299
char_mode_model.append([t, desc + " (%s)" % t])
301
self.window.get_widget("char-info-box").modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("grey"))
304
combo = self.window.get_widget("watchdog-model")
305
uihelpers.build_watchdogmodel_combo(self.vm, combo)
307
combo = self.window.get_widget("watchdog-action")
308
uihelpers.build_watchdogaction_combo(self.vm, combo)
311
def reset_state(self):
312
is_local = not self.conn.is_remote()
313
is_storage_capable = self.conn.is_storage_capable()
315
notebook = self.window.get_widget("create-pages")
316
notebook.set_current_page(0)
318
# Hide the "finish" button until the appropriate time
319
self.window.get_widget("create-finish").hide()
320
self.window.get_widget("create-forward").show()
321
self.window.get_widget("create-forward").grab_focus()
322
self.window.get_widget("create-back").set_sensitive(False)
323
self.window.get_widget("create-help").hide()
326
label_widget = self.window.get_widget("phys-hd-label")
327
if not self.host_storage_timer:
328
self.host_storage_timer = util.safe_timeout_add(3 * 1000,
329
uihelpers.host_space_tick,
330
self.conn, self.config,
332
self.window.get_widget("config-storage-create").set_active(True)
333
self.window.get_widget("config-storage-size").set_value(8)
334
self.window.get_widget("config-storage-entry").set_text("")
335
self.window.get_widget("config-storage-nosparse").set_active(True)
336
target_list = self.window.get_widget("config-storage-devtype")
337
self.populate_target_device_model(target_list.get_model())
338
if len(target_list.get_model()) > 0:
339
target_list.set_active(0)
341
have_storage = (is_local or is_storage_capable)
342
storage_tooltip = None
344
storage_tooltip = _("Connection does not support storage"
348
newmac = uihelpers.generate_macaddr(self.vm.get_connection())
349
self.window.get_widget("mac-address").set_active(bool(newmac))
350
self.window.get_widget("create-mac-address").set_text(newmac)
351
self.change_macaddr_use()
353
net_list = self.window.get_widget("net-list")
354
net_warn = self.window.get_widget("net-list-warn")
355
uihelpers.populate_network_list(net_list, self.vm.get_connection())
357
error = self.vm.get_connection().netdev_error
360
util.tooltip_wrapper(net_warn, error)
364
netmodel = self.window.get_widget("net-model")
365
uihelpers.populate_netmodel_combo(self.vm, netmodel)
366
netmodel.set_active(0)
369
input_box = self.window.get_widget("input-type")
370
self.populate_input_model(input_box.get_model())
371
input_box.set_active(0)
374
self.change_port_auto()
375
graphics_box = self.window.get_widget("graphics-type")
376
self.populate_graphics_model(graphics_box.get_model())
377
graphics_box.set_active(0)
378
self.window.get_widget("graphics-address").set_active(False)
379
self.window.get_widget("graphics-port-auto").set_active(True)
380
self.window.get_widget("graphics-password").set_text("")
381
self.window.get_widget("graphics-keymap").set_text("")
382
self.window.get_widget("graphics-keymap-chk").set_active(True)
385
sound_box = self.window.get_widget("sound-model")
386
sound_box.set_active(0)
389
host_devtype = self.window.get_widget("host-device-type")
390
self.populate_host_device_type_model(host_devtype.get_model())
391
host_devtype.set_active(0)
393
# Set available HW options
396
self.window.get_widget("char-device-type").set_active(0)
397
self.window.get_widget("char-path").set_text("")
398
self.window.get_widget("char-host").set_text("127.0.0.1")
399
self.window.get_widget("char-port").get_adjustment().value = 4555
400
self.window.get_widget("char-bind-host").set_text("127.0.0.1")
401
self.window.get_widget("char-bind-port").get_adjustment().value = 4556
402
self.window.get_widget("char-use-telnet").set_active(False)
404
# Available HW options
405
model = self.window.get_widget("hardware-type").get_model()
408
def add_hw_option(name, icon, page, sensitive, tooltip):
409
model.append([name, icon, page, sensitive, tooltip])
411
add_hw_option("Storage", "drive-harddisk", PAGE_DISK, have_storage,
412
have_storage and storage_tooltip or None)
413
add_hw_option("Network", "network-idle", PAGE_NETWORK, True, None)
414
add_hw_option("Input", "input-mouse", PAGE_INPUT, self.vm.is_hvm(),
415
_("Not supported for this guest type."))
416
add_hw_option("Graphics", "video-display", PAGE_GRAPHICS,
418
add_hw_option("Sound", "audio-card", PAGE_SOUND,
420
_("Not supported for this guest type."))
421
add_hw_option("Serial", gtk.STOCK_CONNECT, PAGE_CHAR,
423
_("Not supported for this guest type."))
424
add_hw_option("Parallel", gtk.STOCK_CONNECT, PAGE_CHAR,
426
_("Not supported for this guest type."))
427
add_hw_option("Physical Host Device", "system-run", PAGE_HOSTDEV,
428
self.vm.get_connection().is_nodedev_capable(),
429
_("Connection does not support host device "
431
add_hw_option("Video", "video-display", PAGE_VIDEO,
432
virtinst.support.check_conn_support(
433
self.vm.get_connection().vmm,
434
virtinst.support.SUPPORT_CONN_DOMAIN_VIDEO),
435
_("Libvirt version does not support video devices."))
436
add_hw_option("Watchdog", "device_pci", PAGE_WATCHDOG,
438
_("Not supported for this guest type."))
440
self.window.get_widget("hardware-type").set_active(0)
442
#########################
443
# UI population methods #
444
#########################
446
def populate_target_device_model(self, model):
448
#[bus, device, icon, desc, iconsize]
449
def add_dev(bus, device, desc):
450
if device == virtinst.VirtualDisk.DEVICE_FLOPPY:
451
icon = "media-floppy"
452
elif device == virtinst.VirtualDisk.DEVICE_CDROM:
453
icon = "media-optical"
455
icon = "drive-harddisk"
456
model.append([bus, device, icon, desc, gtk.ICON_SIZE_BUTTON])
459
add_dev("ide", virtinst.VirtualDisk.DEVICE_DISK, "IDE disk")
460
add_dev("ide", virtinst.VirtualDisk.DEVICE_CDROM, "IDE cdrom")
461
add_dev("fdc", virtinst.VirtualDisk.DEVICE_FLOPPY, "Floppy disk")
462
add_dev("scsi",virtinst.VirtualDisk.DEVICE_DISK, "SCSI disk")
463
add_dev("usb", virtinst.VirtualDisk.DEVICE_DISK, "USB disk")
464
if self.vm.get_hv_type() == "kvm":
465
add_dev("virtio", virtinst.VirtualDisk.DEVICE_DISK, "Virtio Disk")
466
if self.vm.get_connection().is_xen():
467
add_dev("xen", virtinst.VirtualDisk.DEVICE_DISK, "Virtual disk")
469
def populate_input_model(self, model):
471
model.append([_("EvTouch USB Graphics Tablet"), "tablet", "usb", True])
472
# XXX libvirt needs to support 'model' for input devices to distinguish
473
# wacom from evtouch tablets
474
#model.append([_("Wacom Graphics Tablet"), "tablet", "usb", True])
475
model.append([_("Generic USB Mouse"), "mouse", "usb", True])
477
def populate_graphics_model(self, model):
479
model.append([_("VNC server"), "vnc"])
480
model.append([_("Local SDL window"), "sdl"])
482
def populate_host_device_type_model(self, model):
484
for m in [ ["PCI Device", "pci", None, "net", "80203"],
485
["USB Device", "usb_device", None, None, None]]:
488
def populate_host_device_model(self, model, devtype, devcap, subtype,
494
subdevs = self.vm.get_connection().get_devices(subtype, subcap)
496
devs = self.vm.get_connection().get_devices(devtype, devcap)
498
prettyname = dev.pretty_name()
500
for subdev in subdevs:
501
if dev.name == subdev.parent:
502
prettyname = dev.pretty_name(subdev)
504
model.append([prettyname, dev.name])
507
model.append([_("No Devices Available"), None])
510
########################
511
# get_config_* methods #
512
########################
514
def get_config_hardware_type(self):
515
_type = self.window.get_widget("hardware-type")
516
if _type.get_active_iter() == None:
518
return _type.get_model().get_value(_type.get_active_iter(), 2)
521
def is_default_storage(self):
522
return self.window.get_widget("config-storage-create").get_active()
524
def get_storage_info(self):
526
size = self.window.get_widget("config-storage-size").get_value()
527
sparse = not self.window.get_widget("config-storage-nosparse").get_active()
529
if self.is_default_storage():
530
path = util.get_default_path(self.conn, self.config,
532
logging.debug("Default storage path is: %s" % path)
534
path = self.window.get_widget("config-storage-entry").get_text()
536
return (path, size, sparse)
538
def get_config_disk_target(self):
539
target = self.window.get_widget("config-storage-devtype")
540
model = target.get_model()
541
idx = target.get_active()
546
device = model[idx][1]
550
def get_config_input(self):
551
target = self.window.get_widget("input-type")
552
label = target.get_model().get_value(target.get_active_iter(), 0)
553
_type = target.get_model().get_value(target.get_active_iter(), 1)
554
bus = target.get_model().get_value(target.get_active_iter(), 2)
555
return label, _type, bus
558
def get_config_graphics(self):
559
_type = self.window.get_widget("graphics-type")
560
if _type.get_active_iter() is None:
562
return _type.get_model().get_value(_type.get_active_iter(), 1)
564
def get_config_vnc_port(self):
565
port = self.window.get_widget("graphics-port")
566
portAuto = self.window.get_widget("graphics-port-auto")
567
if portAuto.get_active():
569
return int(port.get_value())
571
def get_config_vnc_address(self):
572
addr = self.window.get_widget("graphics-address")
573
if addr.get_active():
577
def get_config_vnc_password(self):
578
pw = self.window.get_widget("graphics-password")
581
def get_config_keymap(self):
582
g = self.window.get_widget("graphics-keymap")
583
if g.get_property("sensitive") and g.get_text() != "":
589
def get_config_network(self):
590
net_list = self.window.get_widget("net-list")
591
bridge_ent = self.window.get_widget("net-bridge")
593
net_type, net_src = uihelpers.get_network_selection(net_list,
596
return net_type, net_src
598
def get_config_net_model(self):
599
model = self.window.get_widget("net-model")
600
if model.get_active_iter():
601
modelxml = model.get_model().get_value(model.get_active_iter(), 0)
602
modelstr = model.get_model().get_value(model.get_active_iter(), 1)
604
modelxml = modelstr = None
605
return modelxml, modelstr
607
def get_config_macaddr(self):
609
if self.window.get_widget("mac-address").get_active():
610
macaddr = self.window.get_widget("create-mac-address").get_text()
614
def get_config_sound_model(self):
615
model = self.window.get_widget("sound-model")
616
modelstr = model.get_model().get_value(model.get_active_iter(), 0)
619
# Host device getters
620
def get_config_host_device_type_info(self):
621
devbox = self.window.get_widget("host-device-type")
622
return devbox.get_model()[devbox.get_active()]
624
def get_config_host_device_info(self):
625
devbox = self.window.get_widget("host-device")
626
return devbox.get_model()[devbox.get_active()]
629
def get_config_video_model(self):
630
modbox = self.window.get_widget("video-model")
631
return modbox.get_model()[modbox.get_active()][0]
634
def get_config_watchdog_model(self):
635
modbox = self.window.get_widget("watchdog-model")
636
return modbox.get_model()[modbox.get_active()][0]
637
def get_config_watchdog_action(self):
638
modbox = self.window.get_widget("watchdog-action")
639
return modbox.get_model()[modbox.get_active()][0]
645
def hardware_type_changed(self, src):
646
if src.get_active() < 0:
649
row = src.get_model()[src.get_active()]
654
self.window.get_widget("create-forward").set_sensitive(sens)
655
self.window.get_widget("hardware-info-box").set_property("visible",
657
self.window.get_widget("hardware-info").set_text(msg)
659
def forward(self, ignore=None):
660
notebook = self.window.get_widget("create-pages")
662
if self.validate(notebook.get_current_page()) == False:
665
self.err.show_err(_("Uncaught error validating hardware "
666
"input: %s") % str(e),
667
"".join(traceback.format_exc()))
670
hwtype = self.get_config_hardware_type()
671
if notebook.get_current_page() == PAGE_INTRO:
672
notebook.set_current_page(hwtype)
674
notebook.set_current_page(PAGE_SUMMARY)
675
self.window.get_widget("create-finish").show()
676
self.window.get_widget("create-finish").grab_focus()
677
self.window.get_widget("create-forward").hide()
678
self.window.get_widget("create-back").set_sensitive(True)
680
def back(self, ignore=None):
681
notebook = self.window.get_widget("create-pages")
683
if notebook.get_current_page() == PAGE_SUMMARY:
684
hwtype = self.get_config_hardware_type()
685
notebook.set_current_page(hwtype)
686
self.window.get_widget("create-finish").hide()
688
notebook.set_current_page(PAGE_INTRO)
689
self.window.get_widget("create-back").set_sensitive(False)
691
self.window.get_widget("create-forward").show()
693
def page_changed(self, notebook, page, page_number):
694
devbox = self.window.get_widget("host-device")
697
if page_number == PAGE_CHAR:
698
devtype = self.window.get_widget("char-device-type")
699
self.change_char_device_type(devtype)
700
self.set_page_char_type()
702
elif page_number == PAGE_SUMMARY:
703
self.populate_summary()
705
elif page_number == PAGE_HOSTDEV:
710
def populate_summary(self):
711
hwpage = self.get_config_hardware_type()
713
summary_table = self.window.get_widget("summary-table")
714
for c in summary_table.get_children():
715
summary_table.remove(c)
717
def set_table(title, info_list):
718
self.window.get_widget("summary-title").set_markup("<b>%s</b>" %
721
for label, value in info_list:
722
label = gtk.Label(label)
723
label.set_alignment(1, .5)
724
value = gtk.Label(value)
725
value.set_alignment(0, .5)
727
summary_table.attach(label, 0, 1, row, row+1, gtk.FILL, 0)
728
summary_table.attach(value, 1, 2, row, row+1, gtk.FILL, 0)
734
summary_table.show_all()
736
if hwpage == PAGE_DISK:
737
size_str = (self._dev.size and ("%2.2f GB" % self._dev.size)
741
(_("Disk image:"), self._dev.path),
742
(_("Disk size:"), size_str),
743
(_("Device type:"), self._dev.device),
744
(_("Bus type:"), self._dev.bus),
748
elif hwpage == PAGE_NETWORK:
749
net_type, net_target = self.get_config_network()
750
macaddr = self.get_config_macaddr()
751
model = self.get_config_net_model()[1]
752
net_label = virtinst.VirtualNetworkInterface.get_network_type_desc(net_type)
753
net_target = net_target or "-"
756
(_("Network type:"), net_label),
757
(_("Target:"), net_target),
758
(_("MAC address:"), macaddr or "-"),
759
(_("Model:"), model or "-"),
763
elif hwpage == PAGE_INPUT:
764
ignore, typ, model = self.get_config_input()
765
if typ == virtinst.VirtualInputDevice.INPUT_TYPE_TABLET:
766
mode_label = _("Absolute movement")
768
mode_label = _("Relative movement")
772
(_("Mode:"), mode_label),
776
elif hwpage == PAGE_GRAPHICS:
777
graphics = self.get_config_graphics()
778
is_vnc = (graphics == virtinst.VirtualGraphics.TYPE_VNC)
780
type_label = is_vnc and _("VNC server") or _("Local SDL window")
781
addr = is_vnc and self.get_config_vnc_address() or _("N/A")
782
port_label = _("N/A")
783
passwd_label = _("N/A")
784
keymap_label = _("N/A")
787
port = self.get_config_vnc_port()
788
passwd = self.get_config_vnc_password()
789
keymap = self.get_config_keymap()
791
port_label = ((port == -1) and ("Automatically allocated")
793
passwd_label = passwd and _("Yes") or _("No")
794
keymap_label = keymap and keymap or _("Same as host")
797
(_("Type:"), type_label),
798
(_("Address:"), addr),
799
(_("Port:"), port_label),
800
(_("Password:"), passwd_label),
801
(_("Keymap:"), keymap_label),
803
title = _("Graphics")
805
elif hwpage == PAGE_SOUND:
807
(_("Model:"), self._dev.model),
811
elif hwpage == PAGE_CHAR:
815
(_("Type:"), VirtualCharDevice.get_char_type_desc(self._dev.char_type)),
818
if hasattr(self._dev, "source_mode"):
819
mode = self._dev.source_mode.capitalize()
820
if hasattr(self._dev, "source_path"):
821
path = self._dev.source_path
822
label = "%sPath:" % (mode and mode + " " or "")
823
info_list.append((label, path))
825
if hasattr(self._dev, "source_host"):
826
host = "%s:%s" % (self._dev.source_host, self._dev.source_port)
827
label = "%sHost:" % (mode and mode + " " or "")
828
info_list.append((label, host))
830
if hasattr(self._dev, "bind_host"):
831
bind_host = "%s:%s" % (self._dev.bind_host,
833
info_list.append(("Bind Host:", bind_host))
834
if hasattr(self._dev, "protocol"):
835
proto = self._dev.protocol
836
info_list.append((_("Protocol:"), proto))
838
title = self.get_char_type().capitalize()
840
elif hwpage == PAGE_HOSTDEV:
842
(_("Type:"), self.get_config_host_device_type_info()[0]),
843
(_("Device:"), self.get_config_host_device_info()[0]),
845
title = _("Physical Host Device")
847
elif hwpage == PAGE_VIDEO:
849
(_("Model:"), self._dev.model_type),
853
elif hwpage == PAGE_WATCHDOG:
854
title = _("Watchdog")
856
(_("Model:"), self._dev.model),
857
(_("Action:"), self._dev.get_action_desc(self._dev.action))
860
set_table(title, info_list)
863
def finish(self, ignore=None):
864
self.topwin.set_sensitive(False)
865
self.topwin.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
868
failure, errinfo = self.add_device()
869
error, details = errinfo or (None, None)
872
error = _("Unable to add device: %s") % str(e)
873
details = "".join(traceback.format_exc())
875
if error is not None:
876
self.err.show_err(error, details)
878
self.topwin.set_sensitive(True)
879
self.topwin.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.TOP_LEFT_ARROW))
885
def browse_storage(self, ignore1):
886
self._browse_file(self.window.get_widget("config-storage-entry"))
888
def toggle_storage_select(self, src):
889
act = src.get_active()
890
self.window.get_widget("config-storage-browse-box").set_sensitive(act)
892
def set_disk_storage_path(self, ignore, path):
893
self.window.get_widget("config-storage-entry").set_text(path)
896
def change_macaddr_use(self, ignore=None):
897
if self.window.get_widget("mac-address").get_active():
898
self.window.get_widget("create-mac-address").set_sensitive(True)
900
self.window.get_widget("create-mac-address").set_sensitive(False)
903
def change_graphics_type(self,ignore=None):
904
graphics = self.get_config_graphics()
905
if graphics == "vnc":
906
self.window.get_widget("graphics-port-auto").set_sensitive(True)
907
self.window.get_widget("graphics-address").set_sensitive(True)
908
self.window.get_widget("graphics-password").set_sensitive(True)
909
self.window.get_widget("graphics-keymap-chk").set_sensitive(True)
910
self.change_port_auto()
912
self.window.get_widget("graphics-port").set_sensitive(False)
913
self.window.get_widget("graphics-port-auto").set_sensitive(False)
914
self.window.get_widget("graphics-address").set_sensitive(False)
915
self.window.get_widget("graphics-password").set_sensitive(False)
916
self.window.get_widget("graphics-keymap-chk").set_sensitive(False)
917
self.window.get_widget("graphics-keymap").set_sensitive(False)
919
def change_port_auto(self,ignore=None):
920
if self.window.get_widget("graphics-port-auto").get_active():
921
self.window.get_widget("graphics-port").set_sensitive(False)
923
self.window.get_widget("graphics-port").set_sensitive(True)
925
def change_keymap(self, ignore=None):
926
if self.window.get_widget("graphics-keymap-chk").get_active():
927
self.window.get_widget("graphics-keymap").set_sensitive(False)
929
self.window.get_widget("graphics-keymap").set_sensitive(True)
931
# Hostdevice listeners
932
def change_host_device_type(self, src):
933
devbox = self.window.get_widget("host-device")
934
if src.get_active() < 0:
935
devbox.get_model().clear()
938
(ignore, devtype, devcap,
939
subtype, subcap) = src.get_model()[src.get_active()]
940
self.populate_host_device_model(devbox.get_model(), devtype, devcap,
944
# Char device listeners
945
def get_char_type(self):
946
hw_list = self.window.get_widget("hardware-type")
947
if hw_list.get_active() < 0:
950
label = hw_list.get_model()[hw_list.get_active()][0]
952
if label.lower() == "parallel":
953
return VirtualDevice.VIRTUAL_DEV_PARALLEL
954
return VirtualDevice.VIRTUAL_DEV_SERIAL
956
def set_page_char_type(self):
957
char_type = self.get_char_type().capitalize()
958
self.window.get_widget("char-title-label").set_markup(
959
"""<span weight="heavy" size="xx-large" foreground="#FFF">%s Device</span>""" % char_type)
961
def change_char_device_type(self, src):
962
self.update_doc(None, None, "char_type")
964
chartype = self.get_char_type()
965
devtype = src.get_model()[src.get_active()][0]
966
conn = self.vm.get_connection().vmm
968
self._dev = VirtualCharDevice.get_dev_instance(conn,
972
for param_name, widget_name in char_widget_mappings.items():
973
make_visible = hasattr(self._dev, param_name)
974
self.window.get_widget(widget_name).set_sensitive(make_visible)
976
has_mode = hasattr(self._dev, "source_mode")
978
if has_mode and self.window.get_widget("char-mode").get_active() == -1:
979
self.window.get_widget("char-mode").set_active(0)
982
######################
983
# Add device methods #
984
######################
986
def setup_device(self):
987
if (self._dev.virtual_device_type ==
988
virtinst.VirtualDevice.VIRTUAL_DEV_DISK):
989
progWin = vmmAsyncJob(self.config, self.do_file_allocate,
991
title=_("Creating Storage File"),
992
text=_("Allocation of disk storage may take "
993
"a few minutes to complete."))
996
error, details = progWin.get_error()
998
return (error, details)
1001
self._dev.setup_dev(self.conn.vmm)
1003
def add_device(self):
1004
ret = self.setup_device()
1006
# Encountered an error
1009
self._dev.get_xml_config()
1010
logging.debug("Adding device:\n" + self._dev.get_xml_config())
1015
self.vm.attach_device(self._dev)
1016
except Exception, e:
1017
logging.debug("Device could not be hotplugged: %s" % str(e))
1021
if not self.err.yes_no(_("Are you sure you want to add this "
1023
_("This device could not be attached to "
1024
"the running machine. Would you like to "
1025
"make the device available after the "
1026
"next VM shutdown?")):
1027
return (False, None)
1029
# Alter persistent config
1031
self.vm.add_device(self._dev)
1032
except Exception, e:
1033
self.err.show_err(_("Error adding device: %s" % str(e)),
1034
"".join(traceback.format_exc()))
1037
return (False, None)
1039
def do_file_allocate(self, disk, asyncjob):
1040
meter = vmmCreateMeter(asyncjob)
1043
# If creating disk via storage API, we need to thread
1044
# off a new connection
1045
if disk.vol_install:
1046
newconn = util.dup_lib_conn(self.config, disk.conn)
1048
logging.debug("Starting background file allocate process")
1049
disk.setup_dev(self.conn.vmm, meter=meter)
1050
logging.debug("Allocation completed")
1051
except Exception, e:
1052
details = (_("Unable to complete install: '%s'") %
1053
"".join(traceback.format_exc()))
1054
error = _("Unable to complete install: '%s'") % str(e)
1055
asyncjob.set_error(error, details)
1058
###########################
1059
# Page validation methods #
1060
###########################
1062
def validate(self, page_num):
1063
if page_num == PAGE_INTRO:
1064
return self.validate_page_intro()
1065
elif page_num == PAGE_DISK:
1066
return self.validate_page_storage()
1067
elif page_num == PAGE_NETWORK:
1068
return self.validate_page_network()
1069
elif page_num == PAGE_INPUT:
1070
return self.validate_page_input()
1071
elif page_num == PAGE_GRAPHICS:
1072
return self.validate_page_graphics()
1073
elif page_num == PAGE_SOUND:
1074
return self.validate_page_sound()
1075
elif page_num == PAGE_HOSTDEV:
1076
return self.validate_page_hostdev()
1077
elif page_num == PAGE_CHAR:
1078
return self.validate_page_char()
1079
elif page_num == PAGE_VIDEO:
1080
return self.validate_page_video()
1081
elif page_num == PAGE_WATCHDOG:
1082
return self.validate_page_watchdog()
1084
def validate_page_intro(self):
1085
if self.get_config_hardware_type() == None:
1086
return self.err.val_err(_("Hardware Type Required"),
1087
_("You must specify what type of hardware to add."))
1090
def validate_page_storage(self):
1091
bus, device = self.get_config_disk_target()
1094
if device == virtinst.VirtualDisk.DEVICE_CDROM:
1098
# This can error out
1099
diskpath, disksize, sparse = self.get_storage_info()
1101
if self.is_default_storage():
1102
# See if the ideal disk path (/default/pool/vmname.img)
1103
# exists, and if unused, prompt the use for using it
1104
ideal = util.get_ideal_path(self.conn, self.config,
1110
do_exist = virtinst.VirtualDisk.path_exists(
1111
self.conn.vmm, ideal)
1113
ret = virtinst.VirtualDisk.path_in_use_by(self.conn.vmm,
1116
logging.exception("Error checking default path usage")
1118
if do_exist and not ret:
1119
do_use = self.err.yes_no(
1120
_("The following path already exists, but is not\n"
1121
"in use by any virtual machine:\n\n%s\n\n"
1122
"Would you like to use this path?") % ideal)
1128
return self.err.val_err(_("A storage path must be specified."))
1130
disk = virtinst.VirtualDisk(conn = self.conn.vmm,
1134
readOnly = readonly,
1138
if (disk.type == virtinst.VirtualDisk.TYPE_FILE and
1139
not self.vm.is_hvm() and
1140
virtinst.util.is_blktap_capable()):
1141
disk.driver_name = virtinst.VirtualDisk.DRIVER_TAP
1143
except Exception, e:
1144
return self.err.val_err(_("Storage parameter error."), str(e))
1148
disks = (self.vm.get_disk_devices() +
1149
self.vm.get_disk_devices(inactive=True))
1153
disk.generate_target(used)
1155
isfatal, errmsg = disk.is_size_conflict()
1156
if not isfatal and errmsg:
1157
# Fatal errors are reported when setting 'size'
1158
res = self.err.ok_cancel(_("Not Enough Free Space"), errmsg)
1163
if disk.is_conflict_disk(self.conn.vmm):
1164
res = self.err.yes_no(_('Disk "%s" is already in use by another '
1165
'guest!' % disk.path),
1166
_("Do you really want to use the disk?"))
1170
uihelpers.check_path_search_for_qemu(self.topwin, self.config,
1171
self.conn, disk.path)
1177
def validate_page_network(self):
1178
nettype, devname = self.get_config_network()
1179
mac = self.get_config_macaddr()
1180
model = self.get_config_net_model()[0]
1183
return self.err.val_err(_("Network selection error."),
1184
_("A network source must be selected."))
1187
return self.err.val_err(_("Invalid MAC address"),
1188
_("A MAC address must be entered."))
1190
ret = uihelpers.validate_network(self.topwin, self.vm.get_connection(),
1191
nettype, devname, mac, model)
1197
def validate_page_input(self):
1198
ignore, inp_type, inp_bus = self.get_config_input()
1199
dev = virtinst.VirtualInputDevice(self.conn.vmm)
1205
def validate_page_graphics(self):
1206
graphics = self.get_config_graphics()
1207
if graphics == "vnc":
1208
_type = virtinst.VirtualGraphics.TYPE_VNC
1210
_type = virtinst.VirtualGraphics.TYPE_SDL
1212
self._dev = virtinst.VirtualGraphics(type=_type)
1214
self._dev.port = self.get_config_vnc_port()
1215
self._dev.passwd = self.get_config_vnc_password()
1216
self._dev.listen = self.get_config_vnc_address()
1217
self._dev.keymap = self.get_config_keymap()
1218
except ValueError, e:
1219
self.err.val_err(_("Graphics device parameter error"), str(e))
1221
def validate_page_sound(self):
1222
smodel = self.get_config_sound_model()
1224
self._dev = virtinst.VirtualAudio(model=smodel)
1225
except Exception, e:
1226
return self.err.val_err(_("Sound device parameter error"), str(e))
1228
def validate_page_hostdev(self):
1229
ignore, nodedev_name = self.get_config_host_device_info()
1231
if nodedev_name == None:
1232
return self.err.val_err(_("Physical Device Requried"),
1233
_("A device must be selected."))
1236
self._dev = virtinst.VirtualHostDevice.device_from_node(
1237
conn = self.vm.get_connection().vmm,
1238
name = nodedev_name)
1239
except Exception, e:
1240
return self.err.val_err(_("Host device parameter error"), str(e))
1242
def validate_page_char(self):
1243
chartype = self.get_char_type()
1244
devbox = self.window.get_widget("char-device-type")
1245
devtype = devbox.get_model()[devbox.get_active()][0]
1246
conn = self.vm.get_connection().vmm
1248
devclass = VirtualCharDevice.get_dev_instance(conn, chartype, devtype)
1250
source_path = self.window.get_widget("char-path").get_text()
1251
source_host = self.window.get_widget("char-host").get_text()
1252
bind_host = self.window.get_widget("char-bind-host").get_text()
1253
source_port = self.window.get_widget("char-port").get_adjustment().value
1254
bind_port = self.window.get_widget("char-bind-port").get_adjustment().value
1256
if self.window.get_widget("char-use-telnet").get_active():
1257
protocol = VirtualCharDevice.CHAR_PROTOCOL_TELNET
1259
protocol = VirtualCharDevice.CHAR_PROTOCOL_RAW
1262
"source_path" : source_path,
1263
"source_host" : source_host,
1264
"source_port" : source_port,
1265
"bind_port": bind_port,
1266
"bind_host": bind_host,
1267
"protocol": protocol,
1271
self._dev = devclass
1273
for param_name, val in value_mappings.items():
1274
if hasattr(self._dev, param_name):
1275
setattr(self._dev, param_name, val)
1277
# Dump XML for sanity checking
1278
self._dev.get_xml_config()
1279
except Exception, e:
1280
return self.err.val_err(_("%s device parameter error") %
1281
chartype.capitalize(), str(e))
1283
def validate_page_video(self):
1284
conn = self.vm.get_connection().vmm
1285
model = self.get_config_video_model()
1288
self._dev = VirtualVideoDevice(conn=conn)
1289
self._dev.model_type = model
1290
except Exception, e:
1291
return self.err.val_err(_("Video device parameter error"),
1294
def validate_page_watchdog(self):
1295
conn = self.vm.get_connection().vmm
1296
model = self.get_config_watchdog_model()
1297
action = self.get_config_watchdog_action()
1300
self._dev = VirtualWatchdog(conn=conn)
1301
self._dev.model = model
1302
self._dev.action = action
1303
except Exception, e:
1304
return self.err.val_err(_("Watchdog parameter error"),
1309
####################
1310
# Unsorted helpers #
1311
####################
1313
def _browse_file(self, textent):
1314
def set_storage_cb(src, path):
1316
textent.set_text(path)
1318
conn = self.vm.get_connection()
1319
if self.storage_browser == None:
1320
self.storage_browser = vmmStorageBrowser(self.config, conn)
1322
self.storage_browser.set_finish_cb(set_storage_cb)
1323
self.storage_browser.set_browse_reason(self.config.CONFIG_DIR_IMAGE)
1325
self.storage_browser.show(conn)
1327
def show_help(self, src):
1328
# help to show depends on the notebook page, yahoo
1329
page = self.window.get_widget("create-pages").get_current_page()
1330
if page == PAGE_INTRO:
1331
self.emit("action-show-help", "virt-manager-create-wizard")
1332
elif page == PAGE_DISK:
1333
self.emit("action-show-help", "virt-manager-storage-space")
1334
elif page == PAGE_NETWORK:
1335
self.emit("action-show-help", "virt-manager-network")
1337
gobject.type_register(vmmAddHardware)