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
2013-04-12 01:16:33 +04:00
# pylint: disable=E0611
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
2013-04-12 01:16:33 +04:00
# pylint: enable=E0611
2011-04-18 20:39:53 +04:00
2009-11-15 23:17:03 +03:00
import libvirt
2013-04-11 20:04:28 +04:00
from virtinst import uriutil
2009-11-15 23:17:03 +03:00
from virtManager import util
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 ) :
2012-02-02 02:26:46 +04:00
vmmGObjectUI . __init__ ( self , " vmm-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
2012-05-14 17:24:56 +04:00
blue = Gdk . color_parse ( " #0072A8 " )
self . widget ( " migrate-header " ) . modify_bg ( Gtk . StateType . NORMAL ,
2009-11-15 23:17:03 +03:00
blue )
2012-05-14 17:24:56 +04:00
image = Gtk . Image . new_from_icon_name ( " vm_clone_wizard " ,
Gtk . IconSize . DIALOG )
2009-11-15 23:17:03 +03:00
image . show ( )
2012-05-14 17:24:56 +04:00
self . widget ( " migrate-vm-icon-box " ) . pack_end ( image , False , False , False )
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 ) :
# [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 ( ) ) ) )
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-main-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
running = self . vm . is_active ( )
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-offline " ) . set_active ( not running )
self . widget ( " migrate-offline " ) . set_sensitive ( running )
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 )
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
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 ) :
active = src . get_active ( )
2013-01-13 01:13:53 +04:00
tooltip = " "
2009-11-18 21:51:36 +03:00
if active == - 1 :
tooltip = _ ( " A valid destination connection must be selected. " )
2011-07-14 21:13:13 +04:00
self . widget ( " migrate-finish " ) . set_sensitive ( active != - 1 )
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 ) :
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 ( )
if idx == - 1 :
return None
row = model [ idx ]
if not row [ 2 ] :
return None
return row [ 1 ]
2009-11-15 23:17:03 +03:00
def get_config_offline ( self ) :
2011-07-14 21:13:13 +04:00
return self . widget ( " migrate-offline " ) . get_active ( )
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
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-04-11 20:04:28 +04:00
split = list ( uriutil . 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
2009-11-18 21:51:36 +03:00
if destconn . is_local ( ) :
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
desc = destconn . get_pretty_desc_inactive ( )
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
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
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
live = not self . get_config_offline ( )
secure = self . get_config_secure ( )
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 )
2012-05-14 17:24:56 +04:00
self . topwin . get_window ( ) . set_cursor ( Gdk . Cursor . new ( Gdk . CursorType . WATCH ) )
2009-11-15 23:17:03 +03:00
2010-12-08 20:52:33 +03:00
if self . vm . getjobinfo_supported :
_cancel_back = self . cancel_migration
_cancel_args = [ self . vm ]
else :
_cancel_back = None
_cancel_args = [ None ]
2010-12-09 20:37:48 +03:00
progWin = vmmAsyncJob ( self . _async_migrate ,
2010-11-30 03:11:35 +03:00
[ self . vm , destconn , uri , rate , live , secure ,
max_downtime ] ,
2010-12-10 17:57:42 +03:00
_ ( " Migrating VM ' %s ' " % self . vm . get_name ( ) ) ,
( _ ( " Migrating VM ' %s ' from %s to %s . "
2013-04-01 23:46:30 +04:00
" This may take a while. " ) %
2010-12-10 17:57:42 +03:00
( self . vm . get_name ( ) , srchost , dsthost ) ) ,
2011-04-14 16:47:42 +04:00
self . topwin ,
2010-12-08 20:52:33 +03:00
cancel_back = _cancel_back ,
cancel_args = _cancel_args )
2010-12-10 17:57:42 +03:00
error , details = progWin . run ( )
2009-11-15 23:17:03 +03:00
self . topwin . set_sensitive ( True )
2012-05-14 17:24:56 +04:00
self . topwin . get_window ( ) . set_cursor ( Gdk . Cursor . new ( Gdk . CursorType . TOP_LEFT_ARROW ) )
2009-11-15 23:17:03 +03:00
2010-12-10 17:57:42 +03:00
if error :
error = _ ( " Unable to migrate guest: %s " ) % error
2011-04-06 19:22:03 +04:00
self . err . show_err ( error ,
2011-04-06 19:52:26 +04:00
details = details )
2010-12-10 17:57:42 +03:00
else :
2009-11-15 23:17:03 +03:00
self . conn . tick ( noStatsUpdate = True )
2009-11-18 21:51:36 +03:00
destconn . tick ( noStatsUpdate = True )
2009-11-15 23:17:03 +03:00
self . close ( )
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 ,
secure , max_downtime ) :
2012-02-10 19:24:43 +04:00
meter = asyncjob . get_meter ( )
2010-12-10 22:59:24 +03:00
2011-07-23 00:43:26 +04:00
srcconn = util . dup_conn ( origvm . conn )
2010-12-10 22:59:24 +03:00
dstconn = util . dup_conn ( origdconn )
vminst = srcconn . vmm . lookupByName ( origvm . get_name ( ) )
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
2010-12-11 00:04:42 +03:00
vm . migrate ( dstconn , migrate_uri , rate , live , secure , 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 )