2009-11-15 23:17:03 +03:00
#
2013-04-01 23:46:30 +04:00
# Copyright (C) 2009, 2013 Red Hat, Inc.
2009-11-15 23:17:03 +03:00
# Copyright (C) 2009 Cole Robinson <crobinso@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
import traceback
import logging
2010-11-30 03:11:35 +03:00
import threading
2009-11-15 23:17:03 +03:00
2012-05-14 17:24:56 +04:00
from gi . repository import Gdk
2013-02-16 23:03:30 +04:00
from gi . repository import GLib
from gi . repository import Gtk
2011-04-18 20:39:53 +04:00
2009-11-15 23:17:03 +03:00
import libvirt
2013-08-09 17:23:01 +04:00
from virtinst import util
2009-11-15 23:17:03 +03:00
2014-01-27 05:21:12 +04:00
from virtManager import uiutil
2010-12-09 01:26:19 +03:00
from virtManager . baseclass import vmmGObjectUI
2009-11-15 23:17:03 +03:00
from virtManager . asyncjob import vmmAsyncJob
from virtManager . domain import vmmDomain
2013-04-13 22:34:52 +04:00
2009-11-15 23:17:03 +03:00
def uri_join ( uri_tuple ) :
scheme , user , host , path , query , fragment = uri_tuple
user = ( user and ( user + " @ " ) or " " )
host = host or " "
path = path or " / "
query = ( query and ( " ? " + query ) or " " )
fragment = ( fragment and ( " # " + fragment ) or " " )
return " %s :// %s %s %s %s %s " % ( scheme , user , host , path , fragment , query )
2010-12-09 01:26:19 +03:00
class vmmMigrateDialog ( vmmGObjectUI ) :
2010-12-09 19:22:35 +03:00
def __init__ ( self , vm , engine ) :
2013-09-23 00:10:16 +04:00
vmmGObjectUI . __init__ ( self , " migrate.ui " , " vmm-migrate " )
2009-11-15 23:17:03 +03:00
self . vm = vm
2011-07-23 00:43:26 +04:00
self . conn = vm . conn
2009-11-18 21:51:36 +03:00
self . engine = engine
2009-11-15 23:17:03 +03:00
2009-11-18 21:51:36 +03:00
self . destconn_rows = [ ]
2013-02-16 22:31:46 +04:00
self . builder . connect_signals ( {
2009-11-15 23:17:03 +03:00
" on_vmm_migrate_delete_event " : self . close ,
" on_migrate_cancel_clicked " : self . close ,
" on_migrate_finish_clicked " : self . finish ,
2009-11-18 21:51:36 +03:00
" on_migrate_dest_changed " : self . destconn_changed ,
2009-11-15 23:17:03 +03:00
" on_migrate_set_rate_toggled " : self . toggle_set_rate ,
" on_migrate_set_interface_toggled " : self . toggle_set_interface ,
" on_migrate_set_port_toggled " : self . toggle_set_port ,
2010-11-30 03:11:35 +03:00
" on_migrate_set_maxdowntime_toggled " : self . toggle_set_maxdowntime ,
2009-11-15 23:17:03 +03:00
} )
2011-04-18 19:25:28 +04:00
self . bind_escape_key_close ( )
2009-11-15 23:17:03 +03:00
2009-11-18 21:51:36 +03:00
self . init_state ( )
2011-04-14 16:47:42 +04:00
def show ( self , parent ) :
2012-02-01 03:16:54 +04:00
logging . debug ( " Showing migrate wizard " )
2009-11-15 23:17:03 +03:00
self . reset_state ( )
2011-07-19 21:56:27 +04:00
self . topwin . resize ( 1 , 1 )
2011-04-14 16:47:42 +04:00
self . topwin . set_transient_for ( parent )
2009-11-15 23:17:03 +03:00
self . topwin . present ( )
def close ( self , ignore1 = None , ignore2 = None ) :
2012-02-01 03:16:54 +04:00
logging . debug ( " Closing migrate wizard " )
2009-11-15 23:17:03 +03:00
self . topwin . hide ( )
2011-07-19 21:56:27 +04:00
# If we only do this at show time, operation takes too long and
# user actually sees the expander close.
self . widget ( " migrate-advanced-expander " ) . set_expanded ( False )
2009-11-15 23:17:03 +03:00
return 1
2011-07-24 05:16:54 +04:00
def _cleanup ( self ) :
2011-04-13 17:27:02 +04:00
self . vm = None
self . conn = None
self . engine = None
self . destconn_rows = None
# Not sure why we need to do this manually, but it matters
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-dest " ) . get_model ( ) . clear ( )
2011-04-13 17:27:02 +04:00
2009-11-18 21:51:36 +03:00
def init_state ( self ) :
2013-09-27 18:26:43 +04:00
blue = Gdk . color_parse ( " #0072A8 " )
self . widget ( " header " ) . modify_bg ( Gtk . StateType . NORMAL , blue )
2009-11-18 21:51:36 +03:00
# [hostname, conn, can_migrate, tooltip]
2012-05-14 17:24:56 +04:00
dest_model = Gtk . ListStore ( str , object , bool , str )
2011-07-14 21:13:13 +04:00
dest_combo = self . widget ( " migrate-dest " )
2009-11-18 21:51:36 +03:00
dest_combo . set_model ( dest_model )
2012-05-14 17:24:56 +04:00
text = Gtk . CellRendererText ( )
2009-11-18 21:51:36 +03:00
dest_combo . pack_start ( text , True )
dest_combo . add_attribute ( text , ' text ' , 0 )
dest_combo . add_attribute ( text , ' sensitive ' , 2 )
2012-05-14 17:24:56 +04:00
dest_model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
2009-11-18 21:51:36 +03:00
# Hook up signals to get connection listing
2011-07-23 00:43:26 +04:00
self . engine . connect ( " conn-added " , self . dest_add_conn )
self . engine . connect ( " conn-removed " , self . dest_remove_conn )
2009-11-18 21:51:36 +03:00
self . destconn_changed ( dest_combo )
2009-11-15 23:17:03 +03:00
2009-11-18 21:51:36 +03:00
def reset_state ( self ) :
2009-11-15 23:17:03 +03:00
title_str = ( " <span size= ' large ' color= ' white ' > %s ' %s ' </span> " %
2011-08-29 20:11:43 +04:00
( _ ( " Migrate " ) , util . xml_escape ( self . vm . get_name ( ) ) ) )
2013-09-27 18:26:43 +04:00
self . widget ( " header-label " ) . set_markup ( title_str )
2009-11-15 23:17:03 +03:00
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-cancel " ) . grab_focus ( )
2009-12-15 00:48:35 +03:00
2009-11-15 23:17:03 +03:00
name = self . vm . get_name ( )
srchost = self . conn . get_hostname ( )
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-label-name " ) . set_text ( name )
self . widget ( " migrate-label-src " ) . set_text ( srchost )
2009-11-15 23:17:03 +03:00
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-set-interface " ) . set_active ( False )
self . widget ( " migrate-set-rate " ) . set_active ( False )
self . widget ( " migrate-set-port " ) . set_active ( False )
self . widget ( " migrate-set-maxdowntime " ) . set_active ( False )
self . widget ( " migrate-max-downtime " ) . set_value ( 30 )
2009-11-15 23:17:03 +03:00
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-rate " ) . set_value ( 0 )
self . widget ( " migrate-secure " ) . set_active ( False )
2013-12-11 01:33:12 +04:00
self . widget ( " migrate-unsafe " ) . set_active ( False )
2009-11-15 23:17:03 +03:00
2011-07-14 21:13:13 +04:00
downtime_box = self . widget ( " migrate-maxdowntime-box " )
2010-11-30 18:52:11 +03:00
support_downtime = self . vm . support_downtime ( )
downtime_tooltip = " "
if not support_downtime :
downtime_tooltip = _ ( " Libvirt version does not support setting "
" downtime. " )
downtime_box . set_sensitive ( support_downtime )
2012-05-14 17:24:56 +04:00
downtime_box . set_tooltip_text ( downtime_tooltip )
2010-11-30 18:52:11 +03:00
2009-11-15 23:17:03 +03:00
if self . conn . is_xen ( ) :
# Default xen port is 8002
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-port " ) . set_value ( 8002 )
2009-11-15 23:17:03 +03:00
else :
# QEMU migrate port range is 49152+64
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-port " ) . set_value ( 49152 )
2009-11-15 23:17:03 +03:00
2011-07-14 21:13:13 +04:00
secure_box = self . widget ( " migrate-secure-box " )
2009-11-15 23:17:03 +03:00
support_secure = hasattr ( libvirt , " VIR_MIGRATE_TUNNELLED " )
secure_tooltip = " "
if not support_secure :
secure_tooltip = _ ( " Libvirt version does not support tunnelled "
" migration. " )
secure_box . set_sensitive ( support_secure )
2012-05-14 17:24:56 +04:00
secure_box . set_tooltip_text ( secure_tooltip )
2009-11-15 23:17:03 +03:00
2013-12-11 01:33:12 +04:00
unsafe_box = self . widget ( " migrate-unsafe-box " )
support_unsafe = hasattr ( libvirt , " VIR_MIGRATE_UNSAFE " )
unsafe_tooltip = " "
if not support_unsafe :
unsafe_tooltip = _ ( " Libvirt version does not support unsafe "
" migration. " )
unsafe_box . set_sensitive ( support_unsafe )
unsafe_box . set_tooltip_text ( unsafe_tooltip )
2009-11-18 21:51:36 +03:00
self . rebuild_dest_rows ( )
def set_state ( self , vm ) :
2009-11-15 23:17:03 +03:00
self . vm = vm
2011-07-23 00:43:26 +04:00
self . conn = vm . conn
2009-11-15 23:17:03 +03:00
self . reset_state ( )
2009-11-18 21:51:36 +03:00
def destconn_changed ( self , src ) :
2014-04-03 18:53:54 +04:00
row = uiutil . get_list_selection ( src , None )
2013-01-13 01:13:53 +04:00
tooltip = " "
2014-01-27 05:21:12 +04:00
if row :
2009-11-18 21:51:36 +03:00
tooltip = _ ( " A valid destination connection must be selected. " )
2014-01-27 05:21:12 +04:00
self . widget ( " migrate-finish " ) . set_sensitive ( bool ( row ) )
2012-05-14 17:24:56 +04:00
self . widget ( " migrate-finish " ) . set_tooltip_text ( tooltip )
2009-11-18 21:51:36 +03:00
2009-11-15 23:17:03 +03:00
def toggle_set_rate ( self , src ) :
enable = src . get_active ( )
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-rate " ) . set_sensitive ( enable )
2009-11-15 23:17:03 +03:00
def toggle_set_interface ( self , src ) :
enable = src . get_active ( )
2011-07-14 21:13:13 +04:00
port_enable = self . widget ( " migrate-set-port " ) . get_active ( )
self . widget ( " migrate-interface " ) . set_sensitive ( enable )
self . widget ( " migrate-set-port " ) . set_sensitive ( enable )
self . widget ( " migrate-port " ) . set_sensitive ( enable and port_enable )
2009-11-15 23:17:03 +03:00
2010-11-30 03:11:35 +03:00
def toggle_set_maxdowntime ( self , src ) :
enable = src . get_active ( )
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-max-downtime " ) . set_sensitive ( enable )
2010-11-30 03:11:35 +03:00
2009-11-15 23:17:03 +03:00
def toggle_set_port ( self , src ) :
enable = src . get_active ( )
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-port " ) . set_sensitive ( enable )
2009-11-15 23:17:03 +03:00
2009-11-18 21:51:36 +03:00
def get_config_destconn ( self ) :
2014-04-03 18:53:54 +04:00
row = uiutil . get_list_selection ( self . widget ( " migrate-dest " ) , None )
2014-01-27 05:21:12 +04:00
if not row or not row [ 2 ] :
2009-11-18 21:51:36 +03:00
return None
return row [ 1 ]
2010-11-30 03:11:35 +03:00
def get_config_max_downtime ( self ) :
if not self . get_config_max_downtime_enabled ( ) :
return 0
2011-07-14 21:13:13 +04:00
return int ( self . widget ( " migrate-max-downtime " ) . get_value ( ) )
2010-11-30 03:11:35 +03:00
2009-11-15 23:17:03 +03:00
def get_config_secure ( self ) :
2011-07-14 21:13:13 +04:00
return self . widget ( " migrate-secure " ) . get_active ( )
2009-11-15 23:17:03 +03:00
2013-12-11 01:33:12 +04:00
def get_config_unsafe ( self ) :
return self . widget ( " migrate-unsafe " ) . get_active ( )
2010-11-30 03:11:35 +03:00
def get_config_max_downtime_enabled ( self ) :
2012-11-09 15:13:22 +04:00
return self . widget ( " migrate-max-downtime " ) . get_sensitive ( )
2010-11-30 03:11:35 +03:00
2009-11-15 23:17:03 +03:00
def get_config_rate_enabled ( self ) :
2012-11-09 15:13:22 +04:00
return self . widget ( " migrate-rate " ) . get_sensitive ( )
2009-11-15 23:17:03 +03:00
def get_config_rate ( self ) :
if not self . get_config_rate_enabled ( ) :
return 0
2011-07-14 21:13:13 +04:00
return int ( self . widget ( " migrate-rate " ) . get_value ( ) )
2009-11-15 23:17:03 +03:00
def get_config_interface_enabled ( self ) :
2012-11-09 15:13:22 +04:00
return self . widget ( " migrate-interface " ) . get_sensitive ( )
2009-11-15 23:17:03 +03:00
def get_config_interface ( self ) :
if not self . get_config_interface_enabled ( ) :
return None
2011-07-14 21:13:13 +04:00
return self . widget ( " migrate-interface " ) . get_text ( )
2009-11-15 23:17:03 +03:00
def get_config_port_enabled ( self ) :
2012-11-09 15:13:22 +04:00
return self . widget ( " migrate-port " ) . get_sensitive ( )
2009-11-15 23:17:03 +03:00
def get_config_port ( self ) :
if not self . get_config_port_enabled ( ) :
return 0
2011-07-14 21:13:13 +04:00
return int ( self . widget ( " migrate-port " ) . get_value ( ) )
2009-11-15 23:17:03 +03:00
2011-10-14 00:13:36 +04:00
def build_localhost_uri ( self , destconn , srcuri ) :
2009-11-18 21:51:36 +03:00
desthost = destconn . get_qualified_hostname ( )
2009-11-15 23:17:03 +03:00
if desthost == " localhost " :
2010-01-27 18:34:10 +03:00
# We couldn't find a host name for the destination machine
# that is accessible from the source machine.
# /etc/hosts is likely borked and the only hostname it will
# give us is localhost. Remember, the dest machine can actually
# be our local machine so we may not already know its hostname
2009-11-15 23:17:03 +03:00
raise RuntimeError ( _ ( " Could not determine remotely accessible "
" hostname for destination connection. " ) )
2011-10-14 00:13:36 +04:00
# Since the connection started as local, we have no clue about
# how to access it remotely. Assume users have a uniform access
# setup and use the same credentials as the remote source URI
return self . edit_uri ( srcuri , desthost , None )
2009-11-15 23:17:03 +03:00
2011-07-19 21:51:42 +04:00
def edit_uri ( self , uri , hostname , port ) :
2013-08-09 17:23:01 +04:00
split = list ( util . uri_split ( uri ) )
2011-07-19 21:51:42 +04:00
hostname = hostname or split [ 2 ]
if port :
if hostname . count ( " : " ) :
hostname = hostname . split ( " : " ) [ 0 ]
hostname + = " : %s " % port
split [ 2 ] = hostname
return uri_join ( tuple ( split ) )
2011-10-14 00:13:36 +04:00
def build_migrate_uri ( self , destconn , srcuri ) :
2009-11-15 23:17:03 +03:00
conn = self . conn
interface = self . get_config_interface ( )
port = self . get_config_port ( )
secure = self . get_config_secure ( )
2011-07-19 21:51:42 +04:00
if not interface and not secure :
return None
if secure :
# P2P migration uri is a libvirt connection uri, e.g.
# qemu+ssh://root@foobar/system
2009-11-15 23:17:03 +03:00
# For secure migration, we need to make sure we aren't migrating
# to the local connection, because libvirt will pull try to use
# 'qemu:///system' as the migrate URI which will deadlock
2013-07-06 04:36:28 +04:00
if destconn . get_uri_hostname ( ) == " localhost " :
2011-10-14 00:13:36 +04:00
uri = self . build_localhost_uri ( destconn , srcuri )
2011-07-19 21:51:42 +04:00
else :
uri = destconn . get_uri ( )
2009-11-15 23:17:03 +03:00
2011-07-19 21:51:42 +04:00
uri = self . edit_uri ( uri , interface , port )
2009-11-15 23:17:03 +03:00
else :
2011-07-19 21:51:42 +04:00
# Regular migration URI is HV specific
uri = " "
if conn . is_xen ( ) :
uri = " xenmigr:// %s " % interface
2009-11-15 23:17:03 +03:00
2011-07-19 21:51:42 +04:00
else :
uri = " tcp: %s " % interface
if port :
uri + = " : %s " % port
2009-11-15 23:17:03 +03:00
2011-07-19 21:51:42 +04:00
return uri or None
2009-11-15 23:17:03 +03:00
2009-11-18 21:51:36 +03:00
def rebuild_dest_rows ( self ) :
newrows = [ ]
for row in self . destconn_rows :
newrows . append ( self . build_dest_row ( row [ 1 ] ) )
self . destconn_rows = newrows
self . populate_dest_combo ( )
def populate_dest_combo ( self ) :
2011-07-14 21:13:13 +04:00
combo = self . widget ( " migrate-dest " )
2009-11-18 21:51:36 +03:00
model = combo . get_model ( )
idx = combo . get_active ( )
idxconn = None
if idx != - 1 :
idxconn = model [ idx ] [ 1 ]
rows = [ [ _ ( " No connections available. " ) , None , False , None ] ]
if self . destconn_rows :
rows = self . destconn_rows
model . clear ( )
for r in rows :
# Don't list the current connection
if r [ 1 ] == self . conn :
continue
model . append ( r )
# Find old index
idx = - 1
for i in range ( len ( model ) ) :
row = model [ i ]
conn = row [ 1 ]
if idxconn :
if conn == idxconn and row [ 2 ] :
idx = i
break
else :
if row [ 2 ] :
idx = i
break
combo . set_active ( idx )
2011-07-23 00:43:26 +04:00
def dest_add_conn ( self , engine_ignore , conn ) :
2011-07-14 21:13:13 +04:00
combo = self . widget ( " migrate-dest " )
2009-11-18 21:51:36 +03:00
model = combo . get_model ( )
newrow = self . build_dest_row ( conn )
# Make sure connection isn't already present
for row in model :
if row [ 1 ] and row [ 1 ] . get_uri ( ) == newrow [ 1 ] . get_uri ( ) :
return
conn . connect ( " state-changed " , self . destconn_state_changed )
self . destconn_rows . append ( newrow )
self . populate_dest_combo ( )
2011-07-23 00:43:26 +04:00
def dest_remove_conn ( self , engine_ignore , uri ) :
2009-11-18 21:51:36 +03:00
# Make sure connection isn't already present
for row in self . destconn_rows :
2011-04-12 19:50:10 +04:00
if row [ 1 ] and row [ 1 ] . get_uri ( ) == uri :
2009-11-18 21:51:36 +03:00
self . destconn_rows . remove ( row )
self . populate_dest_combo ( )
def destconn_state_changed ( self , conn ) :
for row in self . destconn_rows :
if row [ 1 ] == conn :
self . destconn_rows . remove ( row )
self . destconn_rows . append ( self . build_dest_row ( conn ) )
self . populate_dest_combo ( )
def build_dest_row ( self , destconn ) :
driver = self . conn . get_driver ( )
origuri = self . conn . get_uri ( )
can_migrate = False
2014-07-05 02:20:08 +04:00
desc = destconn . get_pretty_desc ( )
2009-11-18 21:51:36 +03:00
reason = " "
desturi = destconn . get_uri ( )
if destconn . get_driver ( ) != driver :
reason = _ ( " Connection hypervisors do not match. " )
elif destconn . get_state ( ) == destconn . STATE_DISCONNECTED :
reason = _ ( " Connection is disconnected. " )
elif destconn . get_uri ( ) == origuri :
# Same connection
pass
elif destconn . get_state ( ) == destconn . STATE_ACTIVE :
# Assumably we can migrate to this connection
can_migrate = True
reason = desturi
return [ desc , destconn , can_migrate , reason ]
2009-11-15 23:17:03 +03:00
def validate ( self ) :
interface = self . get_config_interface ( )
rate = self . get_config_rate ( )
port = self . get_config_port ( )
2010-11-30 03:11:35 +03:00
max_downtime = self . get_config_max_downtime ( )
if self . get_config_max_downtime_enabled ( ) and max_downtime == 0 :
return self . err . val_err ( _ ( " max downtime must be greater than 0. " ) )
2009-11-15 23:17:03 +03:00
2012-11-08 17:15:02 +04:00
if self . get_config_interface_enabled ( ) and interface is None :
2009-11-15 23:17:03 +03:00
return self . err . val_err ( _ ( " An interface must be specified. " ) )
if self . get_config_rate_enabled ( ) and rate == 0 :
return self . err . val_err ( _ ( " Transfer rate must be greater than 0. " ) )
if self . get_config_port_enabled ( ) and port == 0 :
return self . err . val_err ( _ ( " Port must be greater than 0. " ) )
return True
2013-09-07 04:59:01 +04:00
def _finish_cb ( self , error , details , destconn ) :
self . topwin . set_sensitive ( True )
self . topwin . get_window ( ) . set_cursor (
Gdk . Cursor . new ( Gdk . CursorType . TOP_LEFT_ARROW ) )
if error :
error = _ ( " Unable to migrate guest: %s " ) % error
self . err . show_err ( error ,
details = details )
else :
self . conn . schedule_priority_tick ( pollvm = True )
destconn . schedule_priority_tick ( pollvm = True )
self . close ( )
2010-12-09 19:22:35 +03:00
def finish ( self , src_ignore ) :
2009-11-15 23:17:03 +03:00
try :
if not self . validate ( ) :
return
2014-02-02 03:17:17 +04:00
live = True
2009-11-18 21:51:36 +03:00
destconn = self . get_config_destconn ( )
2011-10-14 00:13:36 +04:00
srcuri = self . vm . conn . get_uri ( )
2011-07-23 00:43:26 +04:00
srchost = self . vm . conn . get_hostname ( )
2009-11-18 21:51:36 +03:00
dsthost = destconn . get_qualified_hostname ( )
2010-11-30 03:11:35 +03:00
max_downtime = self . get_config_max_downtime ( )
2009-11-15 23:17:03 +03:00
secure = self . get_config_secure ( )
2013-12-11 01:33:12 +04:00
unsafe = self . get_config_unsafe ( )
2011-10-14 00:13:36 +04:00
uri = self . build_migrate_uri ( destconn , srcuri )
2009-11-15 23:17:03 +03:00
rate = self . get_config_rate ( )
if rate :
rate = int ( rate )
except Exception , e :
details = " " . join ( traceback . format_exc ( ) )
self . err . show_err ( ( _ ( " Uncaught error validating input: %s " ) %
2011-04-06 19:22:03 +04:00
str ( e ) ) ,
details = details )
2009-11-15 23:17:03 +03:00
return
self . topwin . set_sensitive ( False )
2013-09-07 04:59:01 +04:00
self . topwin . get_window ( ) . set_cursor (
Gdk . Cursor . new ( Gdk . CursorType . WATCH ) )
2009-11-15 23:17:03 +03:00
2013-06-14 01:05:33 +04:00
cancel_cb = None
2010-12-08 20:52:33 +03:00
if self . vm . getjobinfo_supported :
2013-06-14 01:05:33 +04:00
cancel_cb = ( self . cancel_migration , self . vm )
2010-12-08 20:52:33 +03:00
2013-09-07 04:59:01 +04:00
progWin = vmmAsyncJob (
self . _async_migrate ,
2013-12-11 01:33:12 +04:00
[ self . vm , destconn , uri , rate , live , secure , unsafe , max_downtime ] ,
2013-09-07 04:59:01 +04:00
self . _finish_cb , [ destconn ] ,
_ ( " Migrating VM ' %s ' " % self . vm . get_name ( ) ) ,
( _ ( " Migrating VM ' %s ' from %s to %s . This may take a while. " ) %
( self . vm . get_name ( ) , srchost , dsthost ) ) ,
self . topwin , cancel_cb = cancel_cb )
progWin . run ( )
2009-11-15 23:17:03 +03:00
2010-11-30 03:11:35 +03:00
def _async_set_max_downtime ( self , vm , max_downtime , migrate_thread ) :
if not migrate_thread . isAlive ( ) :
return False
try :
vm . migrate_set_max_downtime ( max_downtime , 0 )
return False
except libvirt . libvirtError , e :
if ( isinstance ( e , libvirt . libvirtError ) and
e . get_error_code ( ) == libvirt . VIR_ERR_OPERATION_INVALID ) :
# migration has not been started, wait 100 milliseconds
return True
2012-01-17 07:04:40 +04:00
logging . warning ( " Error setting migrate downtime: %s " , e )
2010-11-30 03:11:35 +03:00
return False
2010-12-10 17:57:42 +03:00
def cancel_migration ( self , asyncjob , vm ) :
2010-12-08 22:14:38 +03:00
logging . debug ( " Cancelling migrate job " )
2010-12-08 20:52:33 +03:00
if not vm :
return
try :
vm . abort_job ( )
except Exception , e :
2010-12-08 22:14:38 +03:00
logging . exception ( " Error cancelling migrate job " )
asyncjob . show_warning ( _ ( " Error cancelling migrate job: %s " ) % e )
2010-12-08 20:52:33 +03:00
return
asyncjob . job_canceled = True
return
2010-12-10 17:57:42 +03:00
def _async_migrate ( self , asyncjob ,
origvm , origdconn , migrate_uri , rate , live ,
2013-12-11 01:33:12 +04:00
secure , unsafe , max_downtime ) :
2012-02-10 19:24:43 +04:00
meter = asyncjob . get_meter ( )
2010-12-10 22:59:24 +03:00
2013-07-05 16:59:58 +04:00
srcconn = origvm . conn
dstconn = origdconn
2010-12-10 22:59:24 +03:00
2013-07-05 16:59:58 +04:00
vminst = srcconn . get_backend ( ) . lookupByName ( origvm . get_name ( ) )
2010-12-10 22:59:24 +03:00
vm = vmmDomain ( srcconn , vminst , vminst . UUID ( ) )
logging . debug ( " Migrating vm= %s from %s to %s " , vm . get_name ( ) ,
srcconn . get_uri ( ) , dstconn . get_uri ( ) )
timer = None
if max_downtime != 0 :
# 0 means that the spin box migrate-max-downtime does not
# be enabled.
current_thread = threading . currentThread ( )
2012-02-10 23:07:51 +04:00
timer = self . timeout_add ( 100 , self . _async_set_max_downtime ,
vm , max_downtime , current_thread )
2010-12-10 22:59:24 +03:00
2013-12-11 01:33:12 +04:00
vm . migrate ( dstconn , migrate_uri , rate , live , secure , unsafe , meter = meter )
2010-12-10 22:59:24 +03:00
if timer :
2013-02-16 23:03:30 +04:00
self . idle_add ( GLib . source_remove , timer )