~ubuntu-branches/ubuntu/precise/virt-manager/precise-updates

« back to all changes in this revision

Viewing changes to src/virtManager/create.py

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Léonard
  • Date: 2010-03-25 09:14:38 UTC
  • mto: (1.2.1 upstream) (2.1.15 sid)
  • mto: This revision was merged to the branch mainline in revision 31.
  • Revision ID: james.westby@ubuntu.com-20100325091438-03vv382wj8jqgr26
Tags: upstream-0.8.4
Import upstream version 0.8.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import gtk
23
23
import gtk.glade
24
24
 
25
 
import os, sys, statvfs
 
25
import sys
26
26
import time
27
27
import traceback
28
28
import threading
54
54
INSTALL_PAGE_ISO = 0
55
55
INSTALL_PAGE_URL = 1
56
56
INSTALL_PAGE_PXE = 2
57
 
 
 
57
INSTALL_PAGE_IMPORT = 3
58
58
 
59
59
 
60
60
class vmmCreate(gobject.GObject):
80
80
        self.capsguest = None
81
81
        self.capsdomain = None
82
82
        self.guest = None
83
 
        self.usepool = False
84
83
        self.storage_browser = None
85
84
        self.conn_signals = []
86
85
 
100
99
 
101
100
        # Host space polling
102
101
        self.host_storage_timer = None
103
 
        self.host_storage = None
104
102
 
105
103
        # 'Configure before install' window
106
104
        self.config_window = None
124
122
            "on_install_local_cdrom_combo_changed": self.detect_media_os,
125
123
            "on_install_local_box_changed": self.detect_media_os,
126
124
            "on_install_local_browse_clicked": self.browse_iso,
 
125
            "on_install_import_browse_clicked": self.browse_import,
127
126
 
128
127
            "on_install_detect_os_toggled": self.toggle_detect_os,
129
128
            "on_install_os_type_changed": self.change_os_type,
171
170
        except:
172
171
            pass
173
172
 
174
 
    def set_conn(self, newconn):
175
 
        if self.conn == newconn:
 
173
    def set_conn(self, newconn, force_validate=False):
 
174
        if self.conn == newconn and not force_validate:
176
175
            return
177
176
 
178
177
        if self.conn:
187
186
 
188
187
    # State init methods
189
188
    def startup_error(self, error):
190
 
        self.window.get_widget("startup-error").show()
 
189
        self.window.get_widget("startup-error-box").show()
191
190
        self.window.get_widget("install-box").hide()
192
191
        self.window.get_widget("create-forward").set_sensitive(False)
193
192
 
194
193
        self.window.get_widget("startup-error").set_text("Error: %s" % error)
195
194
        return False
196
195
 
 
196
    def startup_warning(self, error):
 
197
        self.window.get_widget("startup-error-box").show()
 
198
        self.window.get_widget("startup-error").set_text("Warning: %s" %
 
199
                                                         error)
 
200
 
197
201
    def set_initial_state(self):
198
202
 
199
203
        self.window.get_widget("create-pages").set_show_tabs(False)
266
270
        # Networking
267
271
        # [ interface type, device name, label, sensitive ]
268
272
        net_list = self.window.get_widget("config-netdev")
269
 
        uihelpers.init_network_list(net_list)
 
273
        bridge_box = self.window.get_widget("config-netdev-bridge-box")
 
274
        uihelpers.init_network_list(net_list, bridge_box)
270
275
 
271
276
        # Archtecture
272
277
        archModel = gtk.ListStore(str)
284
289
        hyperList.add_attribute(text, 'sensitive', 3)
285
290
        hyperList.set_model(hyperModel)
286
291
 
 
292
        # Sparse tooltip
287
293
        sparse_info = self.window.get_widget("config-storage-nosparse-info")
288
 
        sparse_str = _("Fully allocating storage will take longer now, "
289
 
                       "but the OS install phase will be quicker. \n\n"
290
 
                       "Skipping allocation can also cause space issues on "
291
 
                       "the host machine, if the maximum image size exceeds "
292
 
                       "available storage space.")
293
 
        util.tooltip_wrapper(sparse_info, sparse_str)
 
294
        uihelpers.set_sparse_tooltip(sparse_info)
294
295
 
295
296
    def reset_state(self, urihint=None):
296
297
 
297
298
        self.failed_guest = None
298
299
        self.window.get_widget("create-pages").set_current_page(PAGE_NAME)
299
300
        self.page_changed(None, None, PAGE_NAME)
300
 
        self.window.get_widget("startup-error").hide()
 
301
        self.window.get_widget("startup-error-box").hide()
301
302
        self.window.get_widget("install-box").show()
302
303
 
303
304
        # Name page state
306
307
        self.window.get_widget("method-local").set_active(True)
307
308
        self.window.get_widget("create-conn").set_active(-1)
308
309
        activeconn = self.populate_conn_list(urihint)
309
 
        self.set_conn(activeconn)
 
310
 
 
311
        try:
 
312
            self.set_conn(activeconn, force_validate=True)
 
313
        except Exception, e:
 
314
            logging.exception("Error setting create wizard conn state.")
 
315
            return self.startup_error(str(e))
 
316
 
310
317
        if not activeconn:
311
 
            return self.startup_error(_("No active connection to install on."))
 
318
            return self.startup_error(
 
319
                                _("No active connection to install on."))
312
320
 
313
321
        # Everything from this point forward should be connection independent
314
322
 
331
339
        self.populate_media_model(urlmodel, self.config.get_media_urls())
332
340
        self.populate_media_model(ksmodel, self.config.get_kickstart_urls())
333
341
 
 
342
        # Install import
 
343
        self.window.get_widget("install-import-entry").set_text("")
 
344
 
334
345
        # Mem / CPUs
335
346
        self.window.get_widget("config-mem").set_value(512)
336
347
        self.window.get_widget("config-cpus").set_value(1)
337
348
 
338
349
        # Storage
 
350
        label_widget = self.window.get_widget("phys-hd-label")
339
351
        if not self.host_storage_timer:
340
 
            self.host_storage_timer = gobject.timeout_add(3 * 1000,
341
 
                                                          self.host_space_tick)
 
352
            self.host_storage_timer = util.safe_timeout_add(3 * 1000,
 
353
                                                    uihelpers.host_space_tick,
 
354
                                                    self.conn, self.config,
 
355
                                                    label_widget)
342
356
        self.window.get_widget("enable-storage").set_active(True)
343
357
        self.window.get_widget("config-storage-create").set_active(True)
344
358
        self.window.get_widget("config-storage-size").set_value(8)
346
360
        self.window.get_widget("config-storage-nosparse").set_active(True)
347
361
 
348
362
        # Final page
349
 
        self.window.get_widget("config-advanced-expander").set_expanded(False)
350
363
        self.window.get_widget("summary-customize").set_active(False)
351
364
 
 
365
 
352
366
    def set_conn_state(self):
353
367
        # Update all state that has some dependency on the current connection
354
368
 
357
371
        if self.conn.is_read_only():
358
372
            return self.startup_error(_("Connection is read only."))
359
373
 
 
374
        if self.conn.no_install_options():
 
375
            error = _("No hypervisor options were found for this\n"
 
376
                      "connection.")
 
377
 
 
378
            if self.conn.is_qemu():
 
379
                error += "\n\n"
 
380
                error += _("This usually means that qemu or kvm is not\n"
 
381
                           "installed on your machine. Please ensure they\n"
 
382
                           "are installed as intended.")
 
383
            return self.startup_error(error)
 
384
 
360
385
        # A bit out of order, but populate arch + hv lists so we can
361
386
        # determine a default
362
387
        self.caps = self.conn.get_capabilities()
363
 
 
364
 
        try:
365
 
            self.change_caps()
366
 
        except Exception, e:
367
 
            logging.exception("Error determining default hypervisor")
368
 
            return self.startup_error(_("No guests are supported for this"
369
 
                                        " connection."))
 
388
        self.change_caps()
370
389
        self.populate_hv()
371
390
 
 
391
        if self.conn.is_xen():
 
392
            if self.conn.hw_virt_supported():
 
393
                if self.conn.is_bios_virt_disabled():
 
394
                    error = _("Host supports full virtualization, but\n"
 
395
                              "no related install options are available.\n"
 
396
                              "This may mean support is disabled in your\n"
 
397
                              "system BIOS.")
 
398
                    self.startup_warning(error)
 
399
 
 
400
            else:
 
401
                error = _("Host does not appear to support hardware\n"
 
402
                          "virtualization. Install options may be limited.")
 
403
                self.startup_warning(error)
 
404
 
 
405
        elif self.conn.is_qemu():
 
406
            if not self.conn.is_kvm_supported():
 
407
                error = _("KVM is not available. This may mean the KVM\n"
 
408
                 "package is not installed, or the KVM kernel modules \n"
 
409
                 "are not loaded. Your virtual machines may perform poorly.")
 
410
                self.startup_warning(error)
 
411
 
372
412
        is_local = not self.conn.is_remote()
373
413
        is_storage_capable = self.conn.is_storage_capable()
374
414
        is_pv = (self.capsguest.os_type == "xen")
412
452
        util.tooltip_wrapper(method_local, local_tt)
413
453
        util.tooltip_wrapper(method_pxe, pxe_tt)
414
454
 
415
 
        # Attempt to create the default pool
416
 
        self.usepool = False
417
 
        try:
418
 
            if is_storage_capable:
419
 
                # FIXME: Emit 'pool-added' or something?
420
 
                util.build_default_pool(self.conn.vmm)
421
 
                self.usepool = True
422
 
        except Exception, e:
423
 
            logging.debug("Building default pool failed: %s" % str(e))
424
 
 
425
 
 
426
455
        # Install local
427
456
        iso_option = self.window.get_widget("install-local-iso")
428
457
        cdrom_option = self.window.get_widget("install-local-cdrom")
502
531
        util.tooltip_wrapper(storage_area, storage_tooltip)
503
532
 
504
533
        # Networking
 
534
        net_expander = self.window.get_widget("config-advanced-expander")
 
535
        net_expander.hide()
505
536
        net_list = self.window.get_widget("config-netdev")
506
537
        net_warn = self.window.get_widget("config-netdev-warn")
507
 
        uihelpers.populate_network_list(net_list, self.conn)
 
538
        do_warn = uihelpers.populate_network_list(net_list, self.conn)
508
539
 
509
 
        if self.conn.netdev_error:
 
540
        if self.conn.netdev_error or do_warn:
510
541
            net_warn.show()
511
 
            util.tooltip_wrapper(net_warn, self.conn.netdev_error)
 
542
            net_expander.set_expanded(True)
 
543
 
 
544
            if self.conn.netdev_error:
 
545
                util.tooltip_wrapper(net_warn, self.conn.netdev_error)
512
546
        else:
513
547
            net_warn.hide()
 
548
            net_expander.set_expanded(False)
514
549
 
515
550
        newmac = uihelpers.generate_macaddr(self.conn)
516
551
        self.window.get_widget("config-set-macaddr").set_active(bool(newmac))
546
581
                if gtype == "xen":
547
582
                    if (instmethod == INSTALL_PAGE_PXE or
548
583
                        instmethod == INSTALL_PAGE_ISO):
549
 
                        tooltip = _("Only URL installs are supported for "
550
 
                                    "paravirt.")
 
584
                        tooltip = _("Only URL or import installs are supported "
 
585
                                    "for paravirt.")
551
586
 
552
587
                model.append([label, gtype, domtype, not bool(tooltip)])
553
588
 
658
693
                    break
659
694
 
660
695
        (newg,
661
 
         newdom) = virtinst.CapabilitiesParser.guest_lookup(conn=self.conn.vmm,
662
 
                                                            caps=self.caps,
663
 
                                                            os_type = gtype,
664
 
                                                            type = dtype,
665
 
                                                            accelerated=True,
666
 
                                                            arch=arch)
 
696
         newdom) = virtinst.CapabilitiesParser.guest_lookup(
 
697
                                                        conn=self.conn.vmm,
 
698
                                                        caps=self.caps,
 
699
                                                        os_type = gtype,
 
700
                                                        type = dtype,
 
701
                                                        accelerated=True,
 
702
                                                        arch=arch)
667
703
 
668
704
        if (self.capsguest and self.capsdomain and
669
705
            (newg.arch == self.capsguest.arch and
691
727
            install = _("URL Install Tree")
692
728
        elif instmethod == INSTALL_PAGE_PXE:
693
729
            install = _("PXE Install")
 
730
        elif instmethod == INSTALL_PAGE_IMPORT:
 
731
            install = _("Import existing OS image")
694
732
 
695
733
        if len(self.guest.disks) == 0:
696
734
            storage = _("None")
729
767
            return INSTALL_PAGE_URL
730
768
        elif self.window.get_widget("method-pxe").get_active():
731
769
            return INSTALL_PAGE_PXE
 
770
        elif self.window.get_widget("method-import").get_active():
 
771
            return INSTALL_PAGE_IMPORT
732
772
 
733
773
    def get_config_os_info(self):
734
774
        d_list = self.window.get_widget("install-os-type")
764
804
            media = self.get_config_local_media()
765
805
        elif instpage == INSTALL_PAGE_URL:
766
806
            media = self.window.get_widget("install-url-box").get_active_text()
 
807
        elif instpage == INSTALL_PAGE_IMPORT:
 
808
            media = self.window.get_widget("install-import-entry").get_text()
767
809
 
768
810
        return media
769
811
 
779
821
 
780
822
        return (media.strip(), extra.strip(), ks.strip())
781
823
 
 
824
    def get_config_import_path(self):
 
825
        return self.window.get_widget("install-import-entry").get_text()
 
826
 
 
827
    def get_default_path(self, name):
 
828
        # Don't generate a new path if the install failed
 
829
        if self.failed_guest:
 
830
            if len(self.failed_guest.disks) > 0:
 
831
                return self.failed_guest.disks[0].path
 
832
 
 
833
        return util.get_default_path(self.conn, self.config, name)
 
834
 
 
835
    def is_default_storage(self):
 
836
        return self.window.get_widget("config-storage-create").get_active()
 
837
 
782
838
    def get_storage_info(self):
783
839
        path = None
784
840
        size = self.window.get_widget("config-storage-size").get_value()
785
841
        sparse = not self.window.get_widget("config-storage-nosparse").get_active()
786
 
        if self.window.get_widget("config-storage-create").get_active():
 
842
 
 
843
        if self.get_config_install_page() == INSTALL_PAGE_IMPORT:
 
844
            path = self.get_config_import_path()
 
845
            size = None
 
846
            sparse = False
 
847
 
 
848
        elif self.is_default_storage():
787
849
            path = self.get_default_path(self.guest.name)
788
850
            logging.debug("Default storage path is: %s" % path)
789
851
        else:
791
853
 
792
854
        return (path, size, sparse)
793
855
 
794
 
    def get_default_path(self, name):
795
 
        path = ""
796
 
 
797
 
        # Don't generate a new path if the install failed
798
 
        if self.failed_guest:
799
 
            if len(self.failed_guest.disks) > 0:
800
 
                return self.failed_guest.disks[0].path
801
 
 
802
 
        if not self.usepool:
803
 
 
804
 
            # Use old generating method
805
 
            d = self.config.get_default_image_dir(self.conn)
806
 
            origf = os.path.join(d, name + ".img")
807
 
            f = origf
808
 
 
809
 
            n = 1
810
 
            while os.path.exists(f) and n < 100:
811
 
                f = os.path.join(d, self.get_config_name() +
812
 
                                    "-" + str(n) + ".img")
813
 
                n += 1
814
 
            if os.path.exists(f):
815
 
                f = origf
816
 
 
817
 
            path = f
818
 
        else:
819
 
            pool = self.conn.vmm.storagePoolLookupByName(util.DEFAULT_POOL_NAME)
820
 
            path = virtinst.Storage.StorageVolume.find_free_name(name,
821
 
                            pool_object=pool, suffix=".img")
822
 
 
823
 
            path = os.path.join(util.DEFAULT_POOL_PATH, path)
824
 
 
825
 
        return path
826
 
 
827
 
    def host_disk_space(self, path=None):
828
 
        if not path:
829
 
            path = util.DEFAULT_POOL_PATH
830
 
 
831
 
        avail = 0
832
 
        if self.usepool:
833
 
            # FIXME: make sure not inactive?
834
 
            # FIXME: use a conn specific function after we send pool-added
835
 
            pool = virtinst.util.lookup_pool_by_path(self.conn.vmm, path)
836
 
            if pool:
837
 
                pool.refresh(0)
838
 
                avail = int(virtinst.util.get_xml_path(pool.XMLDesc(0),
839
 
                                                       "/pool/available"))
840
 
 
841
 
        if not avail and not self.conn.is_remote():
842
 
            vfs = os.statvfs(os.path.dirname(path))
843
 
            avail = vfs[statvfs.F_FRSIZE] * vfs[statvfs.F_BAVAIL]
844
 
 
845
 
        return float(avail / 1024.0 / 1024.0 / 1024.0)
846
 
 
847
 
    def host_space_tick(self):
848
 
        max_storage = self.host_disk_space()
849
 
        if self.host_storage == max_storage:
850
 
            return 1
851
 
        self.host_storage = max_storage
852
 
 
853
 
        hd_label = ("%s available in the default location" %
854
 
                    self.pretty_storage(max_storage))
855
 
        hd_label = ("<span color='#484848'>%s</span>" % hd_label)
856
 
        self.window.get_widget("phys-hd-label").set_markup(hd_label)
857
 
        self.window.get_widget("config-storage-size").set_range(1, self.host_storage)
858
 
 
859
 
        return 1
860
 
 
861
856
    def get_config_network_info(self):
862
 
        netidx = self.window.get_widget("config-netdev").get_active()
863
 
        netinfo = self.window.get_widget("config-netdev").get_model()[netidx]
 
857
        net_list = self.window.get_widget("config-netdev")
 
858
        bridge_ent = self.window.get_widget("config-netdev-bridge")
864
859
        macaddr = self.window.get_widget("config-macaddr").get_text()
865
860
 
866
 
        return netinfo[0], netinfo[1], macaddr.strip()
 
861
        net_type, net_src = uihelpers.get_network_selection(net_list,
 
862
                                                            bridge_ent)
 
863
 
 
864
        return net_type, net_src, macaddr.strip()
867
865
 
868
866
    def get_config_sound(self):
869
867
        if self.conn.is_remote():
883
881
        model = src.get_model()
884
882
 
885
883
        if idx < 0:
886
 
            self.set_conn(None)
 
884
            conn = None
 
885
        else:
 
886
            uri = model[idx][0]
 
887
            conn = self.engine.connections[uri]["connection"]
 
888
 
 
889
        # If we aren't visible, let reset_state handle this for us, which
 
890
        # has a better chance of reporting error
 
891
        if not self.is_visible():
887
892
            return
888
893
 
889
 
        uri = model[idx][0]
890
 
        conn = self.engine.connections[uri]["connection"]
891
894
        self.set_conn(conn)
892
895
 
893
896
    def hv_changed(self, src):
974
977
        else:
975
978
            nodetect_label.show()
976
979
 
 
980
    def browse_import(self, ignore1=None, ignore2=None):
 
981
        def set_import_path(ignore, path):
 
982
            self.window.get_widget("install-import-entry").set_text(path)
 
983
 
 
984
        self._browse_file(set_import_path, is_media=False)
 
985
 
977
986
    def browse_iso(self, ignore1=None, ignore2=None):
978
 
        self._browse_file(self.set_iso_storage_path,
979
 
                          is_media=True)
 
987
        def set_iso_storage_path(ignore, path):
 
988
            self.window.get_widget("install-local-box").child.set_text(path)
 
989
 
 
990
        self._browse_file(set_iso_storage_path, is_media=True)
980
991
        self.window.get_widget("install-local-box").activate()
981
992
 
982
993
    def toggle_enable_storage(self, src):
983
994
        self.window.get_widget("config-storage-box").set_sensitive(src.get_active())
984
995
 
985
996
    def browse_storage(self, ignore1):
986
 
        self._browse_file(self.set_disk_storage_path,
 
997
        def set_disk_storage_path(ignore, path):
 
998
            self.window.get_widget("config-storage-entry").set_text(path)
 
999
 
 
1000
        self._browse_file(set_disk_storage_path,
987
1001
                          is_media=False)
988
1002
 
989
1003
    def toggle_storage_select(self, src):
993
1007
    def toggle_macaddr(self, src):
994
1008
        self.window.get_widget("config-macaddr").set_sensitive(src.get_active())
995
1009
 
996
 
    def set_iso_storage_path(self, ignore, path):
997
 
        self.window.get_widget("install-local-box").child.set_text(path)
998
 
 
999
 
    def set_disk_storage_path(self, ignore, path):
1000
 
        self.window.get_widget("config-storage-entry").set_text(path)
1001
 
 
1002
1010
    # Navigation methods
1003
1011
    def set_install_page(self):
1004
1012
        instnotebook = self.window.get_widget("install-method-pages")
1035
1043
    def forward(self, ignore):
1036
1044
        notebook = self.window.get_widget("create-pages")
1037
1045
        curpage = notebook.get_current_page()
 
1046
        is_import = (self.get_config_install_page() == INSTALL_PAGE_IMPORT)
1038
1047
 
1039
1048
        if self.validate(notebook.get_current_page()) != True:
1040
1049
            return
1042
1051
        if curpage == PAGE_NAME:
1043
1052
            self.set_install_page()
1044
1053
            # See if we need to alter our default HV based on install method
1045
 
            # FIXME: URL installs also come into play with whether we want
1046
 
            # PV or FV
1047
1054
            self.guest_from_install_type()
1048
1055
 
 
1056
        next_page = curpage + 1
 
1057
        if next_page == PAGE_STORAGE and is_import:
 
1058
            # Skip storage page for import installs
 
1059
            next_page += 1
 
1060
 
1049
1061
        self.window.get_widget("create-forward").grab_focus()
1050
 
        notebook.set_current_page(curpage + 1)
 
1062
        notebook.set_current_page(next_page)
1051
1063
 
1052
1064
    def page_changed(self, ignore1, ignore2, pagenum):
1053
1065
 
1067
1079
            self.detect_media_os()
1068
1080
 
1069
1081
        if pagenum == PAGE_FINISH:
 
1082
            # This is hidden in reset_state, so that it doesn't distort
 
1083
            # the size of the wizard if it is expanded by default due to
 
1084
            # error
 
1085
            self.window.get_widget("config-advanced-expander").show()
 
1086
 
1070
1087
            self.window.get_widget("create-forward").hide()
1071
1088
            self.window.get_widget("create-finish").show()
1072
1089
            self.window.get_widget("create-finish").grab_focus()
1094
1111
        # Set up graphics device
1095
1112
        try:
1096
1113
            guest._graphics_dev = virtinst.VirtualGraphics(type=virtinst.VirtualGraphics.TYPE_VNC)
 
1114
            guest.add_device(virtinst.VirtualVideoDevice(conn=guest.conn))
1097
1115
        except Exception, e:
1098
1116
            self.err.show_err(_("Error setting up graphics device:") + str(e),
1099
1117
                              "".join(traceback.format_exc()))
1103
1121
        guest.sound_devs = []
1104
1122
        try:
1105
1123
            if self.get_config_sound():
1106
 
                guest.sound_devs.append(virtinst.VirtualAudio(model="es1370"))
 
1124
                guest.sound_devs.append(virtinst.VirtualAudio())
1107
1125
        except Exception, e:
1108
1126
            self.err.show_err(_("Error setting up sound device:") + str(e),
1109
1127
                              "".join(traceback.format_exc()))
1168
1186
        extra = None
1169
1187
        ks = None
1170
1188
        cdrom = False
 
1189
        is_import = False
1171
1190
        distro, variant, ignore1, ignore2 = self.get_config_os_info()
1172
1191
 
1173
1192
 
1198
1217
        elif instmethod == INSTALL_PAGE_PXE:
1199
1218
            instclass = virtinst.PXEInstaller
1200
1219
 
 
1220
        elif instmethod == INSTALL_PAGE_IMPORT:
 
1221
            instclass = virtinst.ImportInstaller
 
1222
            is_import = True
 
1223
 
 
1224
            import_path = self.get_config_import_path()
 
1225
            if not import_path:
 
1226
                return self.verr(_("A storage path to import is required."))
1201
1227
 
1202
1228
        # Build the installer and Guest instance
1203
1229
        try:
1238
1264
            return self.err.val_err(_("Error setting OS information."),
1239
1265
                                    str(e))
1240
1266
 
 
1267
        # Kind of wonky, run storage validation now, which will assign
 
1268
        # the import path. Import installer skips the storage page.
 
1269
        if is_import:
 
1270
            if not self.validate_storage_page(revalidate):
 
1271
                return False
 
1272
 
1241
1273
        if not revalidate:
1242
1274
            if self.guest.installer.scratchdir_required():
1243
1275
                path = self.guest.installer.scratchdir
1290
1322
            # This can error out
1291
1323
            diskpath, disksize, sparse = self.get_storage_info()
1292
1324
 
 
1325
            if self.is_default_storage() and not revalidate:
 
1326
                # See if the ideal disk path (/default/pool/vmname.img)
 
1327
                # exists, and if unused, prompt the use for using it
 
1328
                ideal = util.get_ideal_path(self.conn, self.config,
 
1329
                                            self.guest.name)
 
1330
                do_exist = False
 
1331
                ret = True
 
1332
 
 
1333
                try:
 
1334
                    do_exist = virtinst.VirtualDisk.path_exists(
 
1335
                                                        self.conn.vmm, ideal)
 
1336
 
 
1337
                    ret = virtinst.VirtualDisk.path_in_use_by(self.conn.vmm,
 
1338
                                                              ideal)
 
1339
                except:
 
1340
                    logging.exception("Error checking default path usage")
 
1341
 
 
1342
                if do_exist and not ret:
 
1343
                    do_use = self.err.yes_no(
 
1344
                        _("The following path already exists, but is not\n"
 
1345
                          "in use by any virtual machine:\n\n%s\n\n"
 
1346
                          "Would you like to use this path?") % ideal)
 
1347
 
 
1348
                    if do_use:
 
1349
                        diskpath = ideal
 
1350
 
1293
1351
            if not diskpath:
1294
1352
                return self.verr(_("A storage path must be specified."))
1295
1353
 
1467
1525
            self.failed_guest = self.guest
1468
1526
            return
1469
1527
 
1470
 
        # Ensure new VM is loaded
1471
 
        # FIXME: Hmm, shouldn't we emit a signal here rather than do this?
1472
 
        self.conn.tick(noStatsUpdate=True)
 
1528
        vm = self.conn.get_vm(guest.uuid)
1473
1529
 
1474
1530
        if self.config.get_console_popup() == 1:
1475
1531
            # user has requested console on new created vms only
1476
 
            vm = self.conn.get_vm(guest.uuid)
1477
 
            (gtype, ignore, ignore, ignore, ignore) = vm.get_graphics_console()
 
1532
            gtype = vm.get_graphics_console()[0]
1478
1533
            if gtype == "vnc":
1479
1534
                self.emit("action-show-console", self.conn.get_uri(),
1480
1535
                          guest.uuid)
1492
1547
            logging.debug("Starting background install process")
1493
1548
 
1494
1549
            guest.conn = util.dup_conn(self.config, self.conn)
1495
 
            # FIXME: This is why we need a more unified virtinst device API: so
1496
 
            #        we can do things like swap out the connection on all
1497
 
            #        devices for a forked one. At least we should get a helper
1498
 
            #        method in the Guest API.
1499
 
            for disk in guest.disks:
1500
 
                disk.conn = guest.conn
 
1550
            for dev in guest.get_all_devices():
 
1551
                dev.conn = guest.conn
1501
1552
 
1502
1553
            dom = guest.start_install(False, meter = meter)
1503
1554
            if dom == None:
1506
1557
                logging.error("Guest install did not return a domain")
1507
1558
            else:
1508
1559
                logging.debug("Install completed")
 
1560
 
 
1561
            # Make sure we pick up the domain object
 
1562
            self.conn.tick(noStatsUpdate=True)
 
1563
            vm = self.conn.get_vm(guest.uuid)
 
1564
 
 
1565
            if vm.is_shutoff():
 
1566
                # Domain is already shutdown, but no error was raised.
 
1567
                # Probably means guest had no 'install' phase, as in
 
1568
                # for live cds. Try to restart the domain.
 
1569
                vm.startup()
 
1570
            else:
 
1571
                # Register a status listener, which will restart the
 
1572
                # guest after the install has finished
 
1573
                util.connect_opt_out(vm, "status-changed",
 
1574
                                     self.check_install_status, guest)
 
1575
 
1509
1576
        except:
1510
1577
            (_type, value, stacktrace) = sys.exc_info ()
1511
1578
 
1518
1585
        if error:
1519
1586
            asyncjob.set_error(error, details)
1520
1587
 
 
1588
    def check_install_status(self, vm, ignore1, ignore2, virtinst_guest=None):
 
1589
        if vm.is_crashed():
 
1590
            logging.debug("VM crashed, cancelling install plans.")
 
1591
            return True
 
1592
 
 
1593
        if not vm.is_shutoff():
 
1594
            return
 
1595
 
 
1596
        try:
 
1597
            if virtinst_guest:
 
1598
                continue_inst = virtinst_guest.get_continue_inst()
 
1599
 
 
1600
                if continue_inst:
 
1601
                    logging.debug("VM needs a 2 stage install, continuing.")
 
1602
                    # Continue the install, then reconnect this opt
 
1603
                    # out handler, removing the virtinst_guest which
 
1604
                    # will force one final restart.
 
1605
                    virtinst_guest.continue_install()
 
1606
                    util.connect_opt_out(vm, "status-changed",
 
1607
                                         self.check_install_status, None)
 
1608
                    return True
 
1609
 
 
1610
            logging.debug("Install should be completed, starting VM.")
 
1611
            vm.startup()
 
1612
        except Exception, e:
 
1613
            self.err.show_err(_("Error continue install: %s") % str(e),
 
1614
                              "".join(traceback.format_exc()))
 
1615
 
 
1616
        return True
 
1617
 
1521
1618
    def pretty_storage(self, size):
1522
1619
        return "%.1f Gb" % float(size)
1523
1620