/
createvm.py
2137 lines (1718 loc) · 75.2 KB
/
createvm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Copyright (C) 2008, 2013, 2014, 2015 Red Hat, Inc.
# Copyright (C) 2008 Cole Robinson <crobinso@redhat.com>
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
import importlib
import io
import os
import threading
import time
from gi.repository import Gtk
from gi.repository import Pango
import virtinst
import virtinst.generatename
from virtinst import log
from .lib import uiutil
from .asyncjob import vmmAsyncJob
from .baseclass import vmmGObjectUI
from .connmanager import vmmConnectionManager
from .device.addstorage import vmmAddStorage
from .device.mediacombo import vmmMediaCombo
from .device.netlist import vmmNetworkList
from .engine import vmmEngine
from .object.domain import vmmDomainVirtinst
from .oslist import vmmOSList
from .storagebrowse import vmmStorageBrowser
from .vmwindow import vmmVMWindow
# Number of seconds to wait for media detection
DETECT_TIMEOUT = 20
DEFAULT_MEM = 1024
(PAGE_NAME,
PAGE_INSTALL,
PAGE_MEM,
PAGE_STORAGE,
PAGE_FINISH) = range(5)
(INSTALL_PAGE_ISO,
INSTALL_PAGE_URL,
INSTALL_PAGE_MANUAL,
INSTALL_PAGE_IMPORT,
INSTALL_PAGE_CONTAINER_APP,
INSTALL_PAGE_CONTAINER_OS,
INSTALL_PAGE_VZ_TEMPLATE) = range(7)
# Column numbers for os type/version list models
(OS_COL_ID,
OS_COL_LABEL,
OS_COL_IS_SEP,
OS_COL_IS_SHOW_ALL) = range(4)
#####################
# Pretty UI helpers #
#####################
def _pretty_arch(_a):
if _a == "armv7l":
return "arm"
return _a
def _pretty_storage(size):
return _("%.1f GiB") % float(size)
def _pretty_memory(mem):
return _("%d MiB") % (mem / 1024.0)
###########################################################
# Helpers for tracking devices we create from this wizard #
###########################################################
def is_virt_bootstrap_installed(conn):
ret = importlib.util.find_spec('virtBootstrap') is not None
return ret or conn.config.CLITestOptions.fake_virtbootstrap
class _GuestData:
"""
Wrapper to hold all data that will go into the Guest object,
so we can rebuild it as needed.
"""
def __init__(self, conn, capsinfo):
self.conn = conn
self.capsinfo = capsinfo
self.failed_guest = None
self.default_graphics_type = None
self.skip_default_sound = None
self.x86_cpu_default = None
self.disk = None
self.filesystem = None
self.interface = None
self.init = None
self.machine = None
self.os_variant = None
self.uefi_requested = None
self.name = None
self.vcpus = None
self.memory = None
self.currentMemory = None
self.location = None
self.cdrom = None
self.extra_args = None
self.livecd = False
def build_installer(self):
kwargs = {}
if self.location:
kwargs["location"] = self.location
if self.cdrom:
kwargs["cdrom"] = self.cdrom
installer = virtinst.Installer(self.conn, **kwargs)
if self.extra_args:
installer.set_extra_args([self.extra_args])
if self.livecd:
installer.livecd = True
return installer
def build_guest(self):
guest = virtinst.Guest(self.conn)
guest.set_capabilities_defaults(self.capsinfo)
if self.machine:
# If no machine was explicitly selected, we don't overwrite
# it, because we want to
guest.os.machine = self.machine
if self.os_variant:
guest.set_os_name(self.os_variant)
if self.uefi_requested:
guest.uefi_requested = self.uefi_requested
if self.filesystem:
guest.add_device(self.filesystem)
if self.disk:
guest.add_device(self.disk)
if self.interface:
guest.add_device(self.interface)
if self.init:
guest.os.init = self.init
if self.name:
guest.name = self.name
if self.vcpus:
guest.vcpus = self.vcpus
if self.currentMemory:
guest.currentMemory = self.currentMemory
if self.memory:
guest.memory = self.memory
return guest
##############
# Main class #
##############
class vmmCreateVM(vmmGObjectUI):
@classmethod
def show_instance(cls, parentobj, uri=None):
try:
if not cls._instance:
cls._instance = vmmCreateVM()
cls._instance.show(parentobj and parentobj.topwin or None, uri=uri)
except Exception as e: # pragma: no cover
if not parentobj:
raise
parentobj.err.show_err(
_("Error launching create dialog: %s") % str(e))
def __init__(self):
vmmGObjectUI.__init__(self, "createvm.ui", "vmm-create")
self._cleanup_on_app_close()
self.conn = None
self._capsinfo = None
self._gdata = None
# Distro detection state variables
self._detect_os_in_progress = False
self._os_already_detected_for_media = False
self._customize_window = None
self._storage_browser = None
self._netlist = None
self._addstorage = vmmAddStorage(self.conn, self.builder, self.topwin)
self.widget("storage-align").add(self._addstorage.top_box)
def _browse_file_cb(ignore, widget):
self._browse_file(widget)
self._addstorage.connect("browse-clicked", _browse_file_cb)
self._mediacombo = vmmMediaCombo(self.conn, self.builder, self.topwin)
self._mediacombo.connect("changed", self._iso_changed_cb)
self._mediacombo.connect("activate", self._iso_activated_cb)
self._mediacombo.set_mnemonic_label(
self.widget("install-iso-label"))
self.widget("install-iso-align").add(self._mediacombo.top_box)
self.builder.connect_signals({
"on_vmm_newcreate_delete_event": self._close_requested,
"on_create_cancel_clicked": self._close_requested,
"on_create_back_clicked": self._back_clicked,
"on_create_forward_clicked": self._forward_clicked,
"on_create_finish_clicked": self._finish_clicked,
"on_create_pages_switch_page": self._page_changed,
"on_create_conn_changed": self._conn_changed,
"on_method_changed": self._method_changed,
"on_xen_type_changed": self._xen_type_changed,
"on_arch_changed": self._arch_changed,
"on_virt_type_changed": self._virt_type_changed,
"on_machine_changed": self._machine_changed,
"on_vz_virt_type_changed": self._vz_virt_type_changed,
"on_install_iso_browse_clicked": self._browse_iso,
"on_install_url_entry_changed": self._url_changed,
"on_install_url_entry_activate": self._url_activated,
"on_install_import_browse_clicked": self._browse_import,
"on_install_app_browse_clicked": self._browse_app,
"on_install_oscontainer_browse_clicked": self._browse_oscontainer,
"on_install_container_source_toggle": self._container_source_toggle,
"on_install_detect_os_toggled": self._detect_os_toggled_cb,
"on_enable_storage_toggled": self._toggle_enable_storage,
"on_create_vm_name_changed": self._name_changed,
})
self.bind_escape_key_close()
self._init_state()
###########################
# Standard window methods #
###########################
def show(self, parent, uri):
log.debug("Showing new vm wizard")
if not self.is_visible():
self._reset_state(uri)
self.topwin.set_transient_for(parent)
vmmEngine.get_instance().increment_window_counter()
self.topwin.present()
def _close(self, ignore1=None, ignore2=None):
if self.is_visible():
log.debug("Closing new vm wizard")
vmmEngine.get_instance().decrement_window_counter()
self.topwin.hide()
self._cleanup_customize_window()
if self._storage_browser:
self._storage_browser.close()
self._set_conn(None)
self._gdata = None
def _cleanup(self):
if self._storage_browser:
self._storage_browser.cleanup()
self._storage_browser = None
if self._netlist: # pragma: no cover
self._netlist.cleanup()
self._netlist = None
if self._mediacombo:
self._mediacombo.cleanup()
self._mediacombo = None
if self._addstorage:
self._addstorage.cleanup()
self._addstorage = None
self.conn = None
self._capsinfo = None
self._gdata = None
##########################
# Initial state handling #
##########################
def _show_startup_error(self, error, hideinstall=True):
self.widget("startup-error-box").show()
self.widget("create-forward").set_sensitive(False)
if hideinstall:
self.widget("install-box").hide()
self.widget("arch-expander").hide()
self.widget("startup-error").set_text(_("Error: %s") % error)
return False
def _show_startup_warning(self, error):
self.widget("startup-error-box").show()
self.widget("startup-error").set_markup(
_("<span size='small'>Warning: %s</span>") % error)
def _show_arch_warning(self, error):
self.widget("arch-warning-box").show()
self.widget("arch-warning").set_markup(
_("<span size='small'>Warning: %s</span>") % error)
def _init_state(self):
self.widget("create-pages").set_show_tabs(False)
self.widget("install-method-pages").set_show_tabs(False)
# Connection list
self.widget("create-conn-label").set_text("")
self.widget("startup-error").set_text("")
conn_list = self.widget("create-conn")
conn_model = Gtk.ListStore(str, str)
conn_list.set_model(conn_model)
text = uiutil.init_combo_text_column(conn_list, 1)
text.set_property("ellipsize", Pango.EllipsizeMode.MIDDLE)
def set_model_list(widget_id):
lst = self.widget(widget_id)
model = Gtk.ListStore(str)
lst.set_model(model)
lst.set_entry_text_column(0)
# Lists for the install urls
set_model_list("install-url-combo")
# Lists for OS container bootstrap
set_model_list("install-oscontainer-source-url-combo")
# Architecture
archList = self.widget("arch")
# [label, guest.os.arch value]
archModel = Gtk.ListStore(str, str)
archList.set_model(archModel)
uiutil.init_combo_text_column(archList, 0)
archList.set_row_separator_func(
lambda m, i, ignore: m[i][0] is None, None)
# guest.os.type value for xen (hvm vs. xen)
hyperList = self.widget("xen-type")
# [label, guest.os_type value]
hyperModel = Gtk.ListStore(str, str)
hyperList.set_model(hyperModel)
uiutil.init_combo_text_column(hyperList, 0)
# guest.os.machine value
lst = self.widget("machine")
# [machine ID]
model = Gtk.ListStore(str)
lst.set_model(model)
uiutil.init_combo_text_column(lst, 0)
lst.set_row_separator_func(lambda m, i, ignore: m[i][0] is None, None)
# guest.type value for xen (qemu vs kvm)
lst = self.widget("virt-type")
# [label, guest.type value]
model = Gtk.ListStore(str, str)
lst.set_model(model)
uiutil.init_combo_text_column(lst, 0)
# OS distro list
self._os_list = vmmOSList()
self.widget("install-os-align").add(self._os_list.search_entry)
self.widget("os-label").set_mnemonic_widget(self._os_list.search_entry)
def _reset_state(self, urihint=None):
"""
Reset all UI state to default values. Conn specific state is
populated in _populate_conn_state
"""
self.reset_finish_cursor()
self.widget("create-pages").set_current_page(PAGE_NAME)
self._page_changed(None, None, PAGE_NAME)
# Name page state
self.widget("create-vm-name").set_text("")
self.widget("method-local").set_active(True)
self.widget("create-conn").set_active(-1)
activeconn = self._populate_conn_list(urihint)
self.widget("arch-expander").set_expanded(False)
self.widget("vz-virt-type-hvm").set_active(True)
if self._set_conn(activeconn) is False:
return False
# Everything from this point forward should be connection independent
# Distro/Variant
self._os_list.reset_state()
self._os_already_detected_for_media = False
def _populate_media_model(media_model, urls):
media_model.clear()
for url in (urls or []):
media_model.append([url])
# Install local
self._mediacombo.reset_state()
# Install URL
self.widget("install-urlopts-entry").set_text("")
self.widget("install-url-entry").set_text("")
self.widget("install-url-options").set_expanded(False)
urlmodel = self.widget("install-url-combo").get_model()
_populate_media_model(urlmodel, self.config.get_media_urls())
# Install import
self.widget("install-import-entry").set_text("")
# Install container app
self.widget("install-app-entry").set_text("/bin/sh")
# Install container OS
self.widget("install-oscontainer-fs").set_text("")
self.widget("install-oscontainer-source-url-entry").set_text("")
self.widget("install-oscontainer-source-user").set_text("")
self.widget("install-oscontainer-source-passwd").set_text("")
self.widget("install-oscontainer-source-insecure").set_active(False)
self.widget("install-oscontainer-bootstrap").set_active(False)
self.widget("install-oscontainer-auth-options").set_expanded(False)
self.widget("install-oscontainer-rootpw").set_text("")
src_model = (self.widget("install-oscontainer-source-url-combo")
.get_model())
_populate_media_model(src_model, self.config.get_container_urls())
# Install VZ container from template
self.widget("install-container-template").set_text("centos-7-x86_64")
# Storage
self.widget("enable-storage").set_active(True)
self._addstorage.reset_state()
self._addstorage.widget("storage-create").set_active(True)
self._addstorage.widget("storage-entry").set_text("")
# Final page
self.widget("summary-customize").set_active(False)
def _set_caps_state(self):
"""
Set state that is dependent on when capsinfo changes
"""
self.widget("arch-warning-box").hide()
self._gdata = self._build_guestdata()
guest = self._gdata.build_guest()
# Helper state
is_local = not self.conn.is_remote()
is_storage_capable = self.conn.support.conn_storage()
can_storage = (is_local or is_storage_capable)
is_pv = guest.os.is_xenpv()
is_container_only = self.conn.is_container_only()
is_vz = self.conn.is_vz()
is_vz_container = is_vz and guest.os.is_container()
can_remote_url = self.conn.get_backend().support_remote_url_install()
installable_arch = bool(guest.os.is_x86() or
guest.os.is_ppc64() or
guest.os.is_s390x())
default_efi = (
self.config.get_default_firmware_setting() == "uefi" and
guest.os.is_x86() and
guest.os.is_hvm())
if default_efi:
log.debug("UEFI default requested via app preferences")
if guest.prefers_uefi() or default_efi:
try:
# We call this for validation
guest.enable_uefi()
self._gdata.uefi_requested = True
installable_arch = True
log.debug("UEFI found, setting it as default.")
except Exception as e:
installable_arch = False
log.debug("Error checking for UEFI default", exc_info=True)
msg = _("Failed to setup UEFI: %s\n"
"Install options are limited.") % e
self._show_arch_warning(msg)
# Install Options
method_tree = self.widget("method-tree")
method_manual = self.widget("method-manual")
method_local = self.widget("method-local")
method_import = self.widget("method-import")
method_container_app = self.widget("method-container-app")
method_tree.set_sensitive((is_local or can_remote_url) and
installable_arch)
method_local.set_sensitive(not is_pv and can_storage and
installable_arch)
method_manual.set_sensitive(not is_container_only)
method_import.set_sensitive(can_storage)
virt_methods = [method_local, method_tree,
method_manual, method_import]
local_tt = None
tree_tt = None
import_tt = None
if not is_local:
if not can_remote_url:
tree_tt = _("Libvirt version does not "
"support remote URL installs.")
if not is_storage_capable: # pragma: no cover
local_tt = _("Connection does not support storage management.")
import_tt = local_tt
if is_pv:
local_tt = _("CDROM/ISO installs not available for paravirt guests.")
if not installable_arch:
msg = (_("Architecture '%s' is not installable") %
guest.os.arch)
tree_tt = msg
local_tt = msg
if not any([w.get_active() and w.get_sensitive()
for w in virt_methods]):
for w in virt_methods:
if w.get_sensitive():
w.set_active(True)
break
if not (is_container_only or
[w for w in virt_methods if w.get_sensitive()]):
return self._show_startup_error( # pragma: no cover
_("No install methods available for this connection."),
hideinstall=False)
method_tree.set_tooltip_text(tree_tt or "")
method_local.set_tooltip_text(local_tt or "")
method_import.set_tooltip_text(import_tt or "")
# Container install options
method_container_app.set_active(True)
self.widget("container-install-box").set_visible(is_container_only)
self.widget("vz-install-box").set_visible(is_vz)
self.widget("virt-install-box").set_visible(
not is_container_only and not is_vz_container)
self.widget("kernel-info-box").set_visible(not installable_arch)
def _populate_conn_state(self):
"""
Update all state that has some dependency on the current connection
"""
self.conn.schedule_priority_tick(pollnet=True,
pollpool=True,
pollnodedev=True)
self.widget("install-box").show()
self.widget("create-forward").set_sensitive(True)
self._capsinfo = None
self.conn.invalidate_caps()
if not self.conn.caps.has_install_options():
error = _("No hypervisor options were found for this "
"connection.")
if self.conn.is_qemu():
error += "\n\n"
error += _("This usually means that QEMU or KVM is not "
"installed on your machine, or the KVM kernel "
"modules are not loaded.")
return self._show_startup_error(error)
self._change_caps()
# A bit out of order, but populate the xen/virt/arch/machine lists
# so we can work with a default.
self._populate_xen_type()
self._populate_arch()
self._populate_virt_type()
show_arch = (self.widget("xen-type").get_visible() or
self.widget("virt-type").get_visible() or
self.widget("arch").get_visible() or
self.widget("machine").get_visible())
uiutil.set_grid_row_visible(self.widget("arch-expander"), show_arch)
if self.conn.is_qemu():
if not self._capsinfo.guest.is_kvm_available():
error = _("KVM is not available. This may mean the KVM "
"package is not installed, or the KVM kernel modules "
"are not loaded. Your virtual machines may perform poorly.")
self._show_startup_warning(error)
elif self.conn.is_vz():
has_hvm_guests = False
has_exe_guests = False
for g in self.conn.caps.guests:
if g.os_type == "hvm":
has_hvm_guests = True
if g.os_type == "exe":
has_exe_guests = True
self.widget("vz-virt-type-hvm").set_sensitive(has_hvm_guests)
self.widget("vz-virt-type-exe").set_sensitive(has_exe_guests)
self.widget("vz-virt-type-hvm").set_active(has_hvm_guests)
self.widget("vz-virt-type-exe").set_active(
not has_hvm_guests and has_exe_guests)
# ISO media
# Dependent on connection so we need to do this here
self._mediacombo.set_conn(self.conn)
self._mediacombo.reset_state()
# Allow container bootstrap only for local connection and
# only if virt-bootstrap is installed. Otherwise, show message.
is_local = not self.conn.is_remote()
vb_installed = is_virt_bootstrap_installed(self.conn)
vb_enabled = is_local and vb_installed
oscontainer_widget_conf = {
"install-oscontainer-notsupport-conn": not is_local,
"install-oscontainer-notsupport": not vb_installed,
"install-oscontainer-bootstrap": vb_enabled,
"install-oscontainer-source": vb_enabled,
"install-oscontainer-rootpw-box": vb_enabled
}
for wname, val in oscontainer_widget_conf.items():
self.widget(wname).set_visible(val)
# Memory
memory = int(self.conn.host_memory_size())
mem_label = (_("Up to %(maxmem)s available on the host") %
{'maxmem': _pretty_memory(memory)})
mem_label = ("<span size='small'>%s</span>" % mem_label)
self.widget("mem").set_range(50, memory // 1024)
self.widget("phys-mem-label").set_markup(mem_label)
# CPU
phys_cpus = int(self.conn.host_active_processor_count())
cpu_label = (ngettext("Up to %(numcpus)d available",
"Up to %(numcpus)d available",
phys_cpus) %
{'numcpus': int(phys_cpus)})
cpu_label = ("<span size='small'>%s</span>" % cpu_label)
self.widget("cpus").set_range(1, max(phys_cpus, 1))
self.widget("phys-cpu-label").set_markup(cpu_label)
# Storage
self._addstorage.conn = self.conn
self._addstorage.reset_state()
# Networking
self.widget("advanced-expander").set_expanded(False)
self._netlist = vmmNetworkList(self.conn, self.builder, self.topwin)
self.widget("netdev-ui-align").add(self._netlist.top_box)
self._netlist.reset_state()
def _conn_state_changed(self, conn):
if conn.is_disconnected():
self._close()
def _set_conn(self, newconn):
self.widget("startup-error-box").hide()
self.widget("arch-warning-box").hide()
oldconn = self.conn
self.conn = newconn
if oldconn:
oldconn.disconnect_by_obj(self)
if self._netlist:
self.widget("netdev-ui-align").remove(self._netlist.top_box)
self._netlist.cleanup()
self._netlist = None
if not self.conn:
return self._show_startup_error(
_("No active connection to install on."))
self.conn.connect("state-changed", self._conn_state_changed)
try:
return self._populate_conn_state()
except Exception as e: # pragma: no cover
log.exception("Error setting create wizard conn state.")
return self._show_startup_error(str(e))
def _change_caps(self, gtype=None, arch=None, domtype=None):
"""
Change the cached capsinfo for the passed values, and trigger
all needed UI refreshing
"""
if gtype is None:
# If none specified, prefer HVM so install options aren't limited
# with a default PV choice.
for g in self.conn.caps.guests:
if g.os_type == "hvm":
gtype = "hvm"
break
capsinfo = self.conn.caps.guest_lookup(os_type=gtype,
arch=arch,
typ=domtype)
if self._capsinfo:
if (self._capsinfo.guest == capsinfo.guest and
self._capsinfo.domain == capsinfo.domain):
return
self._capsinfo = capsinfo
log.debug("Guest type set to os_type=%s, arch=%s, dom_type=%s",
self._capsinfo.os_type,
self._capsinfo.arch,
self._capsinfo.hypervisor_type)
self._populate_machine()
self._set_caps_state()
##################################################
# Helpers for populating hv/arch/machine/conn UI #
##################################################
def _populate_xen_type(self):
model = self.widget("xen-type").get_model()
model.clear()
default = 0
guests = []
if self.conn.is_xen() or self.conn.is_test():
guests = self.conn.caps.guests[:]
for guest in guests:
if not guest.domains:
continue # pragma: no cover
gtype = guest.os_type
dom = guest.domains[0]
domtype = dom.hypervisor_type
label = self.conn.pretty_hv(gtype, domtype)
# Don't add multiple rows for each arch
for m in model:
if m[0] == label:
label = None
break
if label is None:
continue
# Determine if this is the default given by guest_lookup
if (gtype == self._capsinfo.os_type and
domtype == self._capsinfo.hypervisor_type):
default = len(model)
model.append([label, gtype])
show = bool(len(model))
uiutil.set_grid_row_visible(self.widget("xen-type"), show)
if show:
self.widget("xen-type").set_active(default)
def _populate_arch(self):
model = self.widget("arch").get_model()
model.clear()
default = 0
archs = []
for guest in self.conn.caps.guests:
if guest.os_type == self._capsinfo.os_type:
archs.append(guest.arch)
# Combine x86/i686 to avoid confusion
if (self.conn.caps.host.cpu.arch == "x86_64" and
"x86_64" in archs and "i686" in archs):
archs.remove("i686")
archs.sort()
prios = ["x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le",
"s390x"]
if self.conn.caps.host.cpu.arch not in prios:
prios = [] # pragma: no cover
for p in prios[:]:
if p not in archs:
prios.remove(p)
else:
archs.remove(p)
if prios:
if archs:
prios += [None]
archs = prios + archs
default = 0
if self._capsinfo.arch in archs:
default = archs.index(self._capsinfo.arch)
for arch in archs:
model.append([_pretty_arch(arch), arch])
show = not (len(archs) < 2)
uiutil.set_grid_row_visible(self.widget("arch"), show)
self.widget("arch").set_active(default)
def _populate_virt_type(self):
model = self.widget("virt-type").get_model()
model.clear()
# Allow choosing between qemu and kvm for archs that traditionally
# have a decent amount of TCG usage, like armv7l. Also include
# aarch64 which can be used for arm32 VMs as well
domains = [d.hypervisor_type for d in self._capsinfo.guest.domains[:]]
if not self.conn.is_qemu():
domains = []
elif self._capsinfo.arch in ["i686", "x86_64", "ppc64", "ppc64le"]:
domains = []
default = 0
if self._capsinfo.hypervisor_type in domains:
default = domains.index(self._capsinfo.hypervisor_type)
prios = ["kvm"]
for domain in prios:
if domain not in domains:
continue
domains.remove(domain)
domains.insert(0, domain)
for domain in domains:
label = self.conn.pretty_hv(self._capsinfo.os_type, domain)
model.append([label, domain])
show = bool(len(model) > 1)
uiutil.set_grid_row_visible(self.widget("virt-type"), show)
self.widget("virt-type").set_active(default)
def _populate_machine(self):
model = self.widget("machine").get_model()
machines = self._capsinfo.machines[:]
if self._capsinfo.arch in ["i686", "x86_64"]:
machines = []
machines.sort()
defmachine = None
prios = []
recommended_machine = virtinst.Guest.get_recommended_machine(
self._capsinfo)
if recommended_machine:
defmachine = recommended_machine
prios = [defmachine]
for p in prios[:]:
if p not in machines:
prios.remove(p) # pragma: no cover
else:
machines.remove(p)
if prios:
machines = prios + [None] + machines
default = 0
if defmachine and defmachine in machines:
default = machines.index(defmachine)
self.widget("machine").disconnect_by_func(self._machine_changed)
try:
model.clear()
for m in machines:
model.append([m])
show = (len(machines) > 1)
uiutil.set_grid_row_visible(self.widget("machine"), show)
if show:
self.widget("machine").set_active(default)
finally:
self.widget("machine").connect("changed", self._machine_changed)
def _populate_conn_list(self, urihint=None):
conn_list = self.widget("create-conn")
model = conn_list.get_model()
model.clear()
default = -1
connmanager = vmmConnectionManager.get_instance()
for connobj in connmanager.conns.values():
if not connobj.is_active():
continue
if connobj.get_uri() == urihint:
default = len(model)
elif default < 0 and not connobj.is_remote():
# Favor local connections over remote connections
default = len(model)
model.append([connobj.get_uri(), connobj.get_pretty_desc()])
no_conns = (len(model) == 0)
if default < 0 and not no_conns:
default = 0 # pragma: no cover
activeuri = ""
activedesc = ""
activeconn = None
if not no_conns:
conn_list.set_active(default)
activeuri, activedesc = model[default]
activeconn = connmanager.conns[activeuri]
self.widget("create-conn-label").set_text(activedesc)
if len(model) <= 1:
self.widget("create-conn").hide()
self.widget("create-conn-label").show()
else:
self.widget("create-conn").show()
self.widget("create-conn-label").hide()
return activeconn
###############################
# Misc UI populating routines #
###############################
def _populate_summary_storage(self, path=None):
storagetmpl = "<span size='small'>%s</span>"
storagesize = ""
storagepath = ""
disk = self._gdata.disk
fs = self._gdata.filesystem
if disk:
if disk.wants_storage_creation():
storagesize = "%s" % _pretty_storage(disk.get_size())
if not path:
path = disk.get_source_path()
storagepath = (storagetmpl % path)
elif fs:
storagepath = storagetmpl % fs.source
else:
storagepath = _("None")
self.widget("summary-storage").set_markup(storagesize)
self.widget("summary-storage").set_visible(bool(storagesize))
self.widget("summary-storage-path").set_markup(storagepath)
def _populate_summary(self):
guest = self._gdata.build_guest()
mem = _pretty_memory(int(guest.memory))
cpu = str(int(guest.vcpus))
instmethod = self._get_config_install_page()
install = ""
if instmethod == INSTALL_PAGE_ISO:
install = _("Local CDROM/ISO")
elif instmethod == INSTALL_PAGE_URL:
install = _("URL Install Tree")
elif instmethod == INSTALL_PAGE_IMPORT:
install = _("Import existing OS image")
elif instmethod == INSTALL_PAGE_MANUAL:
install = _("Manual install")
elif instmethod == INSTALL_PAGE_CONTAINER_APP:
install = _("Application container")
elif instmethod == INSTALL_PAGE_CONTAINER_OS:
install = _("Operating system container")
elif instmethod == INSTALL_PAGE_VZ_TEMPLATE:
install = _("Virtuozzo container")
self.widget("summary-os").set_text(guest.osinfo.label)
self.widget("summary-install").set_text(install)
self.widget("summary-mem").set_text(mem)
self.widget("summary-cpu").set_text(cpu)
self._populate_summary_storage()
nsource = self._netlist.get_network_selection()[1]
if not nsource:
self.widget("advanced-expander").set_expanded(True)
################################
# UI state getters and helpers #
################################
def _get_config_name(self):
return self.widget("create-vm-name").get_text()