~ubuntu-branches/ubuntu/raring/virt-manager/raring-proposed

« back to all changes in this revision

Viewing changes to src/virtManager/engine.py

  • Committer: Bazaar Package Importer
  • Author(s): Guido Günther, Laurent Léonard, Guido Günther
  • Date: 2009-10-07 14:04:03 UTC
  • mfrom: (2.3.1 experimental)
  • mto: (2.3.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 21.
  • Revision ID: james.westby@ubuntu.com-20091007140403-kl9yum4ocrar1acq
Tags: 0.8.0-2
[ Laurent Léonard ]
* [61651ae] Drop ${shlibs:Depends} from dependencies since there is no more
  C code.
* [3319434] Drop redo-patches target from debian/rules. Since gbp-pq
  is used now.
* [b04541e] Clean debian/rules. Drop commented post-patches target
  since there is no more autogen.sh.
* [145ba60] Update french translation.
* [799f18e] Update 0001-use-usr-share-gconf-for-schema-data.patch.
* [052f7bb] Remove XS-Python-Version field from debian/control. Since
  it is deprecated with pysupport.
* [bfb1611][1a66b27][a8ce142][4116d07][31ff60a] Fix some misspellings in
  french translation.
* [6e23aff] Clean build dependencies.
* [b71c8c9] Bump Debhelper version to 7.
* [c614f09] Bump Standards-Version to 3.8.3.
* [99a52c2] Clean debian/rules.
* [52f3b63] Add clean target in debian/rules. To clean automatically
  generated files: - debian/pycompat (see #424898)
* [d5e2ef7] Remove tests/Makefile in the debian/rules clean target. To get a
  clean Debian diff at rebuild time, the file is automatically generated.
* [7da6d9b] Don't close connection on all libvirt errors. Pulled from
  upstream 1c886d1863f7.

[ Guido Günther ]
* upload to unstable
* [464fb65] make package arch all since there is no more C code.
* [25f7663] switch to python-support and use python-distutils
* [c4da06a] bump python-libvirt dependency so we get all of VMs new
  features.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 
21
21
import gobject
22
22
import gtk
23
 
import sys
24
23
import libvirt
25
24
import logging
26
25
import gnome
27
26
import traceback
 
27
import threading
28
28
 
29
29
from virtManager.about import vmmAbout
 
30
from virtManager.netdevhelper import vmmNetDevHelper
 
31
from virtManager.clone import vmmCloneVM
30
32
from virtManager.connect import vmmConnect
31
33
from virtManager.connection import vmmConnection
 
34
from virtManager.createmeter import vmmCreateMeter
 
35
from virtManager.domain import vmmDomain
32
36
from virtManager.preferences import vmmPreferences
33
37
from virtManager.manager import vmmManager
34
38
from virtManager.details import vmmDetails
36
40
from virtManager.create import vmmCreate
37
41
from virtManager.host import vmmHost
38
42
from virtManager.error import vmmErrorDialog
 
43
from virtManager.systray import vmmSystray
39
44
import virtManager.util as util
40
45
 
41
46
class vmmEngine(gobject.GObject):
48
53
 
49
54
    def __init__(self, config):
50
55
        self.__gobject_init__()
 
56
 
 
57
        self.config = config
51
58
        self.windowConnect = None
52
59
        self.windowPreferences = None
53
60
        self.windowAbout = None
62
69
        self.timer = None
63
70
        self.last_timeout = 0
64
71
 
 
72
        self.systray = None
 
73
 
 
74
        self._tick_thread = None
 
75
        self._tick_thread_slow = False
 
76
        self._libvirt_support_threading = (libvirt.getVersion() >= 6000)
 
77
        if not self._libvirt_support_threading:
 
78
            logging.debug("Libvirt doesn't support threading, skipping.")
 
79
 
65
80
        # Counter keeping track of how many manager and details windows
66
81
        # are open. When it is decremented to 0, close the app
67
82
        self.windows = 0
68
83
 
69
 
        self._save_callback_info = []
 
84
        self.netdevHelper = vmmNetDevHelper(self.config)
 
85
        self.init_systray()
70
86
 
71
 
        self.config = config
72
87
        self.config.on_stats_update_interval_changed(self.reschedule_timer)
73
88
 
74
89
        self.schedule_timer()
75
90
        self.load_stored_uris()
76
91
        self.tick()
77
92
 
 
93
    def init_systray(self):
 
94
        if self.systray:
 
95
            return
 
96
 
 
97
        self.systray = vmmSystray(self.config, self)
 
98
        self.systray.connect("action-view-manager", self._do_show_manager)
 
99
        self.systray.connect("action-suspend-domain", self._do_suspend_domain)
 
100
        self.systray.connect("action-resume-domain", self._do_resume_domain)
 
101
        self.systray.connect("action-run-domain", self._do_run_domain)
 
102
        self.systray.connect("action-shutdown-domain", self._do_shutdown_domain)
 
103
        self.systray.connect("action-reboot-domain", self._do_reboot_domain)
 
104
        self.systray.connect("action-destroy-domain", self._do_destroy_domain)
 
105
        self.systray.connect("action-show-console", self._do_show_console)
 
106
        self.systray.connect("action-show-details", self._do_show_details)
 
107
        self.systray.connect("action-exit-app", self._do_exit_app)
 
108
 
78
109
    def load_stored_uris(self):
79
110
        uris = self.config.get_connections()
80
111
        if uris != None:
95
126
        self.windowConnect = None
96
127
 
97
128
        try:
98
 
            conn = self.get_connection(uri, readOnly, autoconnect)
 
129
            try:
 
130
                conn = self._lookup_connection(uri)
 
131
            except Exception, e:
 
132
                print e
 
133
                conn = self.add_connection(uri, readOnly, autoconnect)
 
134
 
99
135
            self.show_manager()
100
136
            conn.open()
101
137
            return conn
102
 
        except:
 
138
        except Exception, e:
 
139
            print e
103
140
            return None
104
141
 
105
142
    def _connect_cancelled(self, connect):
142
179
        self.timer = gobject.timeout_add(interval, self.tick)
143
180
 
144
181
    def tick(self):
145
 
        gtk.gdk.threads_enter()
146
 
        try:
 
182
        if not self._libvirt_support_threading:
147
183
            return self._tick()
148
 
        finally:
149
 
            gtk.gdk.threads_leave()
 
184
 
 
185
        if self._tick_thread and self._tick_thread.isAlive():
 
186
            if not self._tick_thread_slow:
 
187
                logging.debug("Tick is slow, not running at requested rate.")
 
188
            return 1
 
189
 
 
190
        self._tick_thread = threading.Thread(name="Tick thread",
 
191
                                            target=self._tick, args=())
 
192
        self._tick_thread.daemon = False
 
193
        self._tick_thread.start()
 
194
        return 1
150
195
 
151
196
    def _tick(self):
152
197
        for uri in self.connections.keys():
155
200
            except KeyboardInterrupt:
156
201
                raise
157
202
            except:
158
 
                logging.error(("Could not refresh connection %s\n" % (uri)) + str(sys.exc_info()[0]) + \
159
 
                              " " + str(sys.exc_info()[1]) + "\n" + \
160
 
                              traceback.format_exc(sys.exc_info()[2]))
 
203
                logging.exception("Could not refresh connection %s." % uri)
 
204
                logging.debug("Closing connection since refresh failed.")
 
205
                self.connections[uri]["connection"].close()
161
206
        return 1
162
207
 
163
208
    def change_timer_interval(self,ignore1,ignore2,ignore3,ignore4):
205
250
        self.reboot_domain(src, uri, uuid)
206
251
    def _do_migrate_domain(self, src, uri, uuid, desturi):
207
252
        self.migrate_domain(uri, uuid, desturi)
 
253
    def _do_clone_domain(self, src, uri, uuid):
 
254
        self.clone_domain(uri, uuid)
208
255
    def _do_exit_app(self, src):
209
256
        self.exit_app()
210
257
 
227
274
        self.windowPreferences.show()
228
275
 
229
276
    def show_host(self, uri):
230
 
        con = self.get_connection(uri)
 
277
        con = self._lookup_connection(uri)
231
278
 
232
279
        if self.connections[uri]["windowHost"] == None:
233
280
            manager = vmmHost(self.get_config(), con)
265
312
        win.activate_config_page()
266
313
 
267
314
    def show_details(self, uri, uuid):
268
 
        con = self.get_connection(uri)
 
315
        con = self._lookup_connection(uri)
269
316
 
270
317
        if not(self.connections[uri]["windowDetails"].has_key(uuid)):
271
318
            try:
281
328
                details.connect("action-exit-app", self._do_exit_app)
282
329
                details.connect("action-view-manager", self._do_show_manager)
283
330
                details.connect("action-migrate-domain", self._do_migrate_domain)
 
331
                details.connect("action-clone-domain", self._do_clone_domain)
284
332
 
285
333
            except Exception, e:
286
334
                self.err.show_err(_("Error bringing up domain details: %s") % str(e),
299
347
            self.windowManager.connect("action-reboot-domain", self._do_reboot_domain)
300
348
            self.windowManager.connect("action-destroy-domain", self._do_destroy_domain)
301
349
            self.windowManager.connect("action-migrate-domain", self._do_migrate_domain)
 
350
            self.windowManager.connect("action-clone-domain", self._do_clone_domain)
302
351
            self.windowManager.connect("action-show-console", self._do_show_console)
303
352
            self.windowManager.connect("action-show-details", self._do_show_details)
304
353
            self.windowManager.connect("action-show-preferences", self._do_show_preferences)
350
399
        self.windowCreate.show(uri)
351
400
 
352
401
    def add_connection(self, uri, readOnly=None, autoconnect=False):
353
 
        conn = vmmConnection(self.get_config(), uri, readOnly)
 
402
        conn = vmmConnection(self.get_config(), uri, readOnly,
 
403
                             self.netdevHelper)
354
404
        self.connections[uri] = {
355
405
            "connection": conn,
356
406
            "windowHost": None,
357
407
            "windowDetails": {},
358
408
            "windowConsole": {},
 
409
            "windowClone": None,
359
410
            }
360
411
        self.connections[uri]["connection"].connect("vm-removed", self._do_vm_removed)
361
412
        self.connections[uri]["connection"].connect("state-changed", self._do_connection_changed)
365
416
        if autoconnect:
366
417
            conn.toggle_autoconnect()
367
418
 
 
419
        return conn
 
420
 
368
421
    def remove_connection(self, uri):
369
422
        conn = self.connections[uri]["connection"]
370
423
        conn.close()
381
434
 
382
435
        return handle_id
383
436
 
384
 
    def get_connection(self, uri, readOnly=None, autoconnect=False):
385
 
        if not(self.connections.has_key(uri)):
386
 
            self.add_connection(uri, readOnly, autoconnect)
 
437
    def _lookup_connection(self, uri):
 
438
        conn = self.connections.get(uri)
 
439
        if not conn:
 
440
            raise RuntimeError(_("Unknown connection URI %s") % uri)
387
441
 
388
 
        return self.connections[uri]["connection"]
 
442
        return conn["connection"]
389
443
 
390
444
    def save_domain(self, src, uri, uuid):
391
 
        con = self.get_connection(uri, False)
392
 
        if con.is_remote():
 
445
        conn = self._lookup_connection(uri)
 
446
        if conn.is_remote():
393
447
            # FIXME: This should work with remote storage stuff
394
448
            self.err.val_err(_("Saving virtual machines over remote "
395
449
                               "connections is not yet supported."))
396
450
            return
397
451
 
398
 
        vm = con.get_vm(uuid)
 
452
        vm = conn.get_vm(uuid)
399
453
        status = vm.status()
400
454
        if status in [ libvirt.VIR_DOMAIN_SHUTDOWN,
401
455
                       libvirt.VIR_DOMAIN_SHUTOFF,
407
461
 
408
462
        path = util.browse_local(src.window.get_widget("vmm-details"),
409
463
                                 _("Save Virtual Machine"),
410
 
                                 self.config.get_default_save_dir(con),
411
 
                                 dialog_type=gtk.FILE_CHOOSER_ACTION_SAVE)
412
 
 
413
 
        if path:
414
 
            progWin = vmmAsyncJob(self.config, self._save_callback,
415
 
                                  [vm, path],
416
 
                                  _("Saving Virtual Machine"))
417
 
            progWin.run()
418
 
 
419
 
        if self._save_callback_info != []:
420
 
            self.err.show_err(_("Error saving domain: %s") %
421
 
                                self._save_callback_info[0],
422
 
                                self._save_callback_info[1])
423
 
            self._save_callback_info = []
424
 
 
425
 
    def _save_callback(self, vm, file_to_save, ignore1=None):
 
464
                                 self.config, conn,
 
465
                                 dialog_type=gtk.FILE_CHOOSER_ACTION_SAVE,
 
466
                                 browse_reason=self.config.CONFIG_DIR_SAVE)
 
467
 
 
468
        if not path:
 
469
            return
 
470
 
 
471
        progWin = vmmAsyncJob(self.config, self._save_callback, [vm, path],
 
472
                              _("Saving Virtual Machine"))
 
473
        progWin.run()
 
474
        error, details = progWin.get_error()
 
475
 
 
476
        if error is not None:
 
477
            self.err.show_err(_("Error saving domain: %s") % error, details)
 
478
 
 
479
    def _save_callback(self, vm, file_to_save, asyncjob):
426
480
        try:
427
481
            vm.save(file_to_save)
428
482
        except Exception, e:
429
 
            self._save_callback_info = [str(e), \
430
 
                                        "".join(traceback.format_exc())]
 
483
            asyncjob.set_error(str(e), "".join(traceback.format_exc()))
431
484
 
432
485
    def destroy_domain(self, src, uri, uuid):
433
 
        con = self.get_connection(uri, False)
434
 
        vm = con.get_vm(uuid)
 
486
        conn = self._lookup_connection(uri)
 
487
        vm = conn.get_vm(uuid)
435
488
        status = vm.status()
 
489
 
436
490
        if status in [ libvirt.VIR_DOMAIN_SHUTDOWN,
437
491
                       libvirt.VIR_DOMAIN_SHUTOFF ]:
438
 
            logging.warning("Destroy requested, but machine is shutdown / shutoff")
439
 
        else:
440
 
            resp = self.err.yes_no(text1=_("About to poweroff virtual machine %s" % vm.get_name()), text2=_("This will immediately poweroff the VM without shutting down the OS and may cause data loss. Are you sure?"))
441
 
            if resp:
442
 
                logging.debug("Destroying vm '%s'." % vm.get_name())
443
 
                try:
444
 
                    vm.destroy()
445
 
                except Exception, e:
446
 
                    self.err.show_err(_("Error shutting down domain: %s" % str(e)), "".join(traceback.format_exc()))
 
492
            logging.warning("Destroy requested, but machine is "
 
493
                            "shutdown/shutoff")
 
494
            return
 
495
 
 
496
        resp = self.err.yes_no(text1=_("About to poweroff virtual "
 
497
                                         "machine %s" % vm.get_name()),
 
498
                               text2=_("This will immediately poweroff the VM "
 
499
                                       "without shutting down the OS and may "
 
500
                                       "cause data loss. Are you sure?"))
 
501
        if not resp:
 
502
            return
 
503
 
 
504
        logging.debug("Destroying vm '%s'." % vm.get_name())
 
505
        try:
 
506
            vm.destroy()
 
507
        except Exception, e:
 
508
            self.err.show_err(_("Error shutting down domain: %s" % str(e)),
 
509
                              "".join(traceback.format_exc()))
447
510
 
448
511
    def suspend_domain(self, src, uri, uuid):
449
 
        con = self.get_connection(uri, False)
450
 
        vm = con.get_vm(uuid)
 
512
        conn = self._lookup_connection(uri)
 
513
        vm = conn.get_vm(uuid)
451
514
        status = vm.status()
452
 
        if status in [ libvirt.VIR_DOMAIN_SHUTDOWN, \
453
 
                       libvirt.VIR_DOMAIN_SHUTOFF, \
 
515
 
 
516
        if status in [ libvirt.VIR_DOMAIN_SHUTDOWN,
 
517
                       libvirt.VIR_DOMAIN_SHUTOFF,
454
518
                       libvirt.VIR_DOMAIN_CRASHED ]:
455
 
            logging.warning("Pause requested, but machine is shutdown / shutoff")
 
519
            logging.warning("Pause requested, but machine is shutdown/shutoff")
 
520
            return
 
521
 
456
522
        elif status in [ libvirt.VIR_DOMAIN_PAUSED ]:
457
523
            logging.warning("Pause requested, but machine is already paused")
458
 
        else:
459
 
            logging.debug("Pausing vm '%s'." % vm.get_name())
460
 
            try:
461
 
                vm.suspend()
462
 
            except Exception, e:
463
 
                self.err.show_err(_("Error pausing domain: %s" % str(e)),
464
 
                                  "".join(traceback.format_exc()))
465
 
    
 
524
            return
 
525
 
 
526
        logging.debug("Pausing vm '%s'." % vm.get_name())
 
527
        try:
 
528
            vm.suspend()
 
529
        except Exception, e:
 
530
            self.err.show_err(_("Error pausing domain: %s" % str(e)),
 
531
                              "".join(traceback.format_exc()))
 
532
 
466
533
    def resume_domain(self, src, uri, uuid):
467
 
        con = self.get_connection(uri, False)
468
 
        vm = con.get_vm(uuid)
 
534
        conn = self._lookup_connection(uri)
 
535
        vm = conn.get_vm(uuid)
469
536
        status = vm.status()
470
 
        if status in [ libvirt.VIR_DOMAIN_SHUTDOWN, \
471
 
                       libvirt.VIR_DOMAIN_SHUTOFF, \
 
537
 
 
538
        if status in [ libvirt.VIR_DOMAIN_SHUTDOWN,
 
539
                       libvirt.VIR_DOMAIN_SHUTOFF,
472
540
                       libvirt.VIR_DOMAIN_CRASHED ]:
473
 
            logging.warning("Resume requested, but machine is shutdown / shutoff")
474
 
        elif status in [ libvirt.VIR_DOMAIN_PAUSED ]:
475
 
            logging.debug("Unpausing vm '%s'." % vm.get_name())
476
 
            try:
477
 
                vm.resume()
478
 
            except Exception, e:
479
 
                self.err.show_err(_("Error unpausing domain: %s" % str(e)),
480
 
                                  "".join(traceback.format_exc()))
481
 
        else:
482
 
            logging.warning("Resume requested, but machine is already running")
483
 
    
 
541
            logging.warning("Resume requested, but machine is "
 
542
                            "shutdown/shutoff")
 
543
            return
 
544
 
 
545
        elif status not in [ libvirt.VIR_DOMAIN_PAUSED ]:
 
546
            logging.warning("Unpause requested, but machine is not paused.")
 
547
            return
 
548
 
 
549
        logging.debug("Unpausing vm '%s'." % vm.get_name())
 
550
        try:
 
551
            vm.resume()
 
552
        except Exception, e:
 
553
            self.err.show_err(_("Error unpausing domain: %s" % str(e)),
 
554
                              "".join(traceback.format_exc()))
 
555
 
484
556
    def run_domain(self, src, uri, uuid):
485
 
        con = self.get_connection(uri, False)
486
 
        vm = con.get_vm(uuid)
 
557
        conn = self._lookup_connection(uri)
 
558
        vm = conn.get_vm(uuid)
487
559
        status = vm.status()
 
560
 
488
561
        if status != libvirt.VIR_DOMAIN_SHUTOFF:
489
562
            logging.warning("Run requested, but domain isn't shutoff.")
490
 
        else:
491
 
            logging.debug("Starting vm '%s'." % vm.get_name())
492
 
            try:
493
 
                vm.startup()
494
 
            except Exception, e:
495
 
                self.err.show_err(_("Error starting domain: %s" % str(e)),
496
 
                                  "".join(traceback.format_exc()))
497
 
            
 
563
            return
 
564
 
 
565
        logging.debug("Starting vm '%s'." % vm.get_name())
 
566
        try:
 
567
            vm.startup()
 
568
        except Exception, e:
 
569
            self.err.show_err(_("Error starting domain: %s" % str(e)),
 
570
                              "".join(traceback.format_exc()))
 
571
 
498
572
    def shutdown_domain(self, src, uri, uuid):
499
 
        con = self.get_connection(uri, False)
500
 
        vm = con.get_vm(uuid)
 
573
        conn = self._lookup_connection(uri)
 
574
        vm = conn.get_vm(uuid)
501
575
        status = vm.status()
502
 
        if not(status in [ libvirt.VIR_DOMAIN_SHUTDOWN, \
503
 
                           libvirt.VIR_DOMAIN_SHUTOFF, \
504
 
                           libvirt.VIR_DOMAIN_CRASHED ]):
505
 
            logging.debug("Shutting down vm '%s'." % vm.get_name())
506
 
            try:
507
 
                vm.shutdown()
508
 
            except Exception, e:
509
 
                self.err.show_err(_("Error shutting down domain: %s" % str(e)),
510
 
                                  "".join(traceback.format_exc()))
511
 
        else:
512
 
            logging.warning("Shut down requested, but the virtual machine is already shutting down / powered off")
 
576
 
 
577
        if status in [ libvirt.VIR_DOMAIN_SHUTDOWN,
 
578
                       libvirt.VIR_DOMAIN_SHUTOFF,
 
579
                       libvirt.VIR_DOMAIN_CRASHED ]:
 
580
            logging.warning("Shut down requested, but the virtual machine is "
 
581
                            "already shutting down / powered off")
 
582
            return
 
583
 
 
584
        logging.debug("Shutting down vm '%s'." % vm.get_name())
 
585
        try:
 
586
            vm.shutdown()
 
587
        except Exception, e:
 
588
            self.err.show_err(_("Error shutting down domain: %s" % str(e)),
 
589
                              "".join(traceback.format_exc()))
513
590
 
514
591
    def reboot_domain(self, src, uri, uuid):
515
 
        con = self.get_connection(uri, False)
516
 
        vm = con.get_vm(uuid)
 
592
        conn = self._lookup_connection(uri)
 
593
        vm = conn.get_vm(uuid)
517
594
        status = vm.status()
518
 
        if not(status in [ libvirt.VIR_DOMAIN_SHUTDOWN, \
519
 
                           libvirt.VIR_DOMAIN_SHUTOFF, \
520
 
                           libvirt.VIR_DOMAIN_CRASHED ]):
521
 
            logging.debug("Rebooting vm '%s'." % vm.get_name())
522
 
            try:
523
 
                vm.reboot()
524
 
            except Exception, e:
525
 
                self.err.show_err(_("Error shutting down domain: %s" % str(e)),
526
 
                                  "".join(traceback.format_exc()))
527
 
        else:
528
 
            logging.warning("Reboot requested, but machine is already shutting down / shutoff")
529
 
 
530
 
    def migrate_domain(self, uri, uuid, desthost):
531
 
        desturi = None
532
 
        for key in self.connections.keys():
533
 
            if self.get_connection(key).get_hostname() == desthost:
534
 
                desturi = key
535
 
                break
536
 
 
537
 
        if desturi == None:
538
 
            logging.debug("Could not find dest uri for migrate hostname: %s"
539
 
                          % desthost)
 
595
 
 
596
        if status in [ libvirt.VIR_DOMAIN_SHUTDOWN,
 
597
                       libvirt.VIR_DOMAIN_SHUTOFF,
 
598
                       libvirt.VIR_DOMAIN_CRASHED ]:
 
599
            logging.warning("Reboot requested, but machine is already "
 
600
                            "shutting down / shutoff")
540
601
            return
541
602
 
542
 
        conn = self.get_connection(uri, False)
 
603
        logging.debug("Rebooting vm '%s'." % vm.get_name())
 
604
        try:
 
605
            vm.reboot()
 
606
        except Exception, e:
 
607
            self.err.show_err(_("Error shutting down domain: %s" % str(e)),
 
608
                              "".join(traceback.format_exc()))
 
609
 
 
610
    def migrate_domain(self, uri, uuid, desturi):
 
611
        conn = self._lookup_connection(uri)
543
612
        vm = conn.get_vm(uuid)
544
 
        destconn = self.get_connection(desturi, False)
545
 
        resp = self.err.yes_no(_("Are you sure you want to migrate %s from %s to %s?") % \
546
 
                    (vm.get_name(), conn.get_hostname(), destconn.get_hostname()))
547
 
        if resp:
548
 
            migrate_progress = None
 
613
        destconn = self._lookup_connection(desturi)
 
614
 
 
615
        resp = self.err.yes_no(_("Are you sure you want to migrate %s from "
 
616
                                 "%s to %s?") %
 
617
                                (vm.get_name(), conn.get_hostname(),
 
618
                                 destconn.get_hostname()))
 
619
        if not resp:
 
620
            return
 
621
 
 
622
        progWin = vmmAsyncJob(self.config, self._async_migrate, [vm, destconn],
 
623
                              title=_("Migrating VM '%s'" % vm.get_name()),
 
624
                              text=(_("Migrating VM '%s' from %s to %s. "
 
625
                                      "This may take awhile.") %
 
626
                                      (vm.get_name(), conn.get_hostname(),
 
627
                                       destconn.get_hostname())))
 
628
        progWin.run()
 
629
        error, details = progWin.get_error()
 
630
 
 
631
        if error:
 
632
            self.err.show_err(error, details)
 
633
 
 
634
        self.windowManager.conn_refresh_resources(vm.get_connection())
 
635
        self.windowManager.conn_refresh_resources(destconn)
 
636
 
 
637
    def _async_migrate(self, origvm, origdconn, asyncjob):
 
638
        errinfo = None
 
639
        try:
549
640
            try:
550
 
                # show progress dialog
551
 
                migrate_progress = self.get_migrate_progress(vm.get_name(), conn.get_short_hostname(), destconn.get_short_hostname())
552
 
                migrate_progress.show()
553
 
                while gtk.events_pending():
554
 
                    gtk.main_iteration()
555
 
                # call virDomainMigrate
556
 
                vm.migrate(destconn)
557
 
                # close progress dialog
558
 
                migrate_progress.destroy()
 
641
                ignore = vmmCreateMeter(asyncjob)
 
642
 
 
643
                srcconn = util.dup_conn(self.config, origvm.get_connection(),
 
644
                                        return_conn_class=True)
 
645
                dstconn = util.dup_conn(self.config, origdconn,
 
646
                                        return_conn_class=True)
 
647
 
 
648
                vminst = srcconn.vmm.lookupByName(origvm.get_name())
 
649
                vm = vmmDomain(self.config, srcconn, vminst, vminst.UUID())
 
650
 
 
651
                logging.debug("Migrating vm=%s from %s to %s", vm.get_name(),
 
652
                              srcconn.get_uri(), dstconn.get_uri())
 
653
                vm.migrate(dstconn)
559
654
            except Exception, e:
560
 
                migrate_progress.destroy()
561
 
                self.err.show_err(_("Error migrating domain: %s") % str(e),
562
 
                                  "".join(traceback.format_exc()))
563
 
            self.windowManager.conn_refresh_resources(conn)
564
 
            self.windowManager.conn_refresh_resources(destconn)
565
 
 
566
 
    def get_migrate_progress(self, vmname, hostname, desthostname):
567
 
        migrate_progress = None
568
 
        migrate_progress = gtk.MessageDialog(None, \
569
 
                                            gtk.DIALOG_DESTROY_WITH_PARENT, \
570
 
                                            gtk.MESSAGE_INFO, \
571
 
                                            gtk.BUTTONS_NONE, \
572
 
                                            _("%s will be migrated from %s to %s." % \
573
 
                                            (vmname, hostname, desthostname)))
574
 
        migrate_progress.set_title(" ")
575
 
        return migrate_progress
576
 
 
577
 
    def populate_migrate_menu(self, menu, migrate_func):
578
 
        conns = self.get_available_migrate_hostnames()
 
655
                errinfo = (str(e), ("Unable to migrate guest:\n %s" %
 
656
                                    "".join(traceback.format_exc())))
 
657
        finally:
 
658
            if errinfo:
 
659
                asyncjob.set_error(errinfo[0], errinfo[1])
 
660
 
 
661
 
 
662
    def populate_migrate_menu(self, menu, migrate_func, vm):
 
663
        conns = self.get_available_migrate_hostnames(vm)
579
664
 
580
665
        # Clear menu
581
666
        for item in menu:
582
667
            menu.remove(item)
583
668
 
584
669
        for ignore, val_list in conns.items():
585
 
            can_migrate, label, tooltip = val_list
 
670
            can_migrate, label, tooltip, uri = val_list
586
671
            mitem = gtk.ImageMenuItem(label)
587
672
            mitem.set_sensitive(can_migrate)
588
 
            mitem.connect("activate", migrate_func)
 
673
            mitem.connect("activate", migrate_func, uri)
589
674
            if tooltip:
590
675
                util.tooltip_wrapper(mitem, tooltip)
591
676
            mitem.show()
597
682
            mitem.show()
598
683
            menu.add(mitem)
599
684
 
600
 
    def get_available_migrate_hostnames(self):
601
 
        driver = self.windowManager.current_connection().get_driver()
602
 
        uri = self.windowManager.current_connection().get_uri()
 
685
    def get_available_migrate_hostnames(self, vm):
 
686
        driver = vm.get_connection().get_driver()
 
687
        origuri = vm.get_connection().get_uri()
603
688
        available_migrate_hostnames = {}
604
689
 
605
690
        # Returns list of lists of the form
606
691
        #   [ Can we migrate to this connection?,
607
692
        #     String to use as list entry,
608
 
        #     Tooltip reason ]
 
693
        #     Tooltip reason,
 
694
        #     Conn URI ]
609
695
 
610
696
        # 1. connected(ACTIVE, INACTIVE) host
611
697
        for key, value in self.connections.items():
616
702
            can_migrate = False
617
703
            desc = "%s (%s)" % (conn.get_hostname(), conn.get_driver())
618
704
            reason = ""
 
705
            desturi = conn.get_uri()
619
706
 
620
707
            if conn.get_driver() != driver:
621
708
                reason = _("Connection hypervisors do not match.")
622
709
            elif conn.get_state() == vmmConnection.STATE_DISCONNECTED:
623
710
                reason = _("Connection is disconnected.")
624
 
            elif key == uri:
 
711
            elif key == origuri:
625
712
                reason = _("Cannot migrate to same connection.")
626
713
 
627
714
                # Explicitly don't include this in the list
629
716
            elif conn.get_state() == vmmConnection.STATE_ACTIVE:
630
717
                # Assumably we can migrate to this connection
631
718
                can_migrate = True
632
 
 
633
 
 
634
 
            available_migrate_hostnames[key] = [can_migrate, desc, reason]
 
719
                reason = desturi
 
720
 
 
721
 
 
722
            available_migrate_hostnames[key] = [can_migrate, desc, reason,
 
723
                                                desturi]
635
724
 
636
725
        return available_migrate_hostnames
637
726
 
 
727
    def clone_domain(self, uri, uuid):
 
728
        con = self._lookup_connection(uri)
 
729
        orig_vm = con.get_vm(uuid)
 
730
        clone_window = self.connections[uri]["windowClone"]
 
731
 
 
732
        try:
 
733
            if clone_window == None:
 
734
                clone_window = vmmCloneVM(self.get_config(), orig_vm)
 
735
                clone_window.connect("action-show-help", self._do_show_help)
 
736
                self.connections[uri]["windowClone"] = clone_window
 
737
            else:
 
738
                clone_window.set_orig_vm(orig_vm)
 
739
 
 
740
            clone_window.show()
 
741
        except Exception, e:
 
742
            self.err.show_err(_("Error setting clone parameters: %s") %
 
743
                              str(e), "".join(traceback.format_exc()))
 
744
 
638
745
 
639
746
gobject.type_register(vmmEngine)