2006-06-28 23:50:17 +04:00
#
# Copyright (C) 2006 Red Hat, Inc.
# Copyright (C) 2006 Daniel P. Berrange <berrange@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
2007-11-20 19:12:20 +03:00
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
2006-06-28 23:50:17 +04:00
#
2006-06-14 22:36:26 +04:00
import gobject
2006-06-14 20:40:02 +04:00
import gtk . glade
2007-07-12 03:52:53 +04:00
import virtinst
import logging
2008-09-02 19:36:56 +04:00
import dbus
2009-03-09 23:21:21 +03:00
import socket
2007-07-12 03:52:53 +04:00
2010-08-24 21:49:44 +04:00
from virtManager . error import vmmErrorDialog
2007-07-12 03:52:53 +04:00
HV_XEN = 0
HV_QEMU = 1
2010-08-24 22:56:03 +04:00
CONN_SSH = 0
2008-01-31 19:39:10 +03:00
CONN_TCP = 1
CONN_TLS = 2
2006-06-14 18:59:40 +04:00
2010-08-24 23:36:06 +04:00
def current_user ( ) :
try :
import getpass
return getpass . getuser ( )
except :
return " "
def default_conn_user ( conn ) :
if conn == CONN_SSH :
return " root "
return current_user ( )
2006-06-14 22:36:26 +04:00
class vmmConnect ( gobject . GObject ) :
__gsignals__ = {
" completed " : ( gobject . SIGNAL_RUN_FIRST ,
2008-06-11 23:24:32 +04:00
gobject . TYPE_NONE , ( str , object , object ) ) ,
2006-06-27 18:08:55 +04:00
" cancelled " : ( gobject . SIGNAL_RUN_FIRST ,
gobject . TYPE_NONE , ( ) )
2006-06-14 22:36:26 +04:00
}
2007-07-12 03:52:53 +04:00
2006-06-14 18:59:40 +04:00
def __init__ ( self , config , engine ) :
2006-06-14 22:36:26 +04:00
self . __gobject_init__ ( )
2010-08-24 21:49:44 +04:00
self . window = gtk . glade . XML (
config . get_glade_dir ( ) + " /vmm-open-connection.glade " ,
" vmm-open-connection " , domain = " virt-manager " )
self . err = vmmErrorDialog ( self . window . get_widget ( " vmm-open-connection " ) ,
0 , gtk . MESSAGE_ERROR , gtk . BUTTONS_CLOSE ,
_ ( " Unexpected Error " ) ,
_ ( " An unexpected error occurred " ) )
2006-06-14 18:59:40 +04:00
self . engine = engine
self . window . get_widget ( " vmm-open-connection " ) . hide ( )
self . window . signal_autoconnect ( {
2010-08-24 21:49:44 +04:00
" on_hypervisor_changed " : self . hypervisor_changed ,
" on_connection_changed " : self . connection_changed ,
2010-08-22 22:10:01 +04:00
" on_hostname_combo_changed " : self . hostname_combo_changed ,
2010-08-24 22:56:03 +04:00
" on_connect_remote_toggled " : self . connect_remote_toggled ,
2010-08-24 23:36:06 +04:00
" on_username_entry_changed " : self . username_changed ,
2010-08-22 22:10:01 +04:00
2006-06-14 22:36:26 +04:00
" on_cancel_clicked " : self . cancel ,
2006-06-14 18:59:40 +04:00
" on_connect_clicked " : self . open_connection ,
2006-06-14 22:36:26 +04:00
" on_vmm_open_connection_delete_event " : self . cancel ,
2006-06-14 18:59:40 +04:00
} )
2008-09-02 19:36:56 +04:00
self . browser = None
self . can_browse = False
2009-03-09 23:21:21 +03:00
# Set this if we can't resolve 'hostname.local': means avahi
# prob isn't configured correctly, and we should strip .local
self . can_resolve_local = None
# Plain hostname resolve failed, means we should just use IP addr
self . can_resolve_hostname = None
2010-08-24 22:56:03 +04:00
self . set_initial_state ( )
2008-09-02 19:36:56 +04:00
2010-01-25 17:31:33 +03:00
self . bus = None
self . server = None
self . can_browse = False
2008-09-02 19:36:56 +04:00
try :
2010-01-25 17:31:33 +03:00
self . bus = dbus . SystemBus ( )
2010-08-22 22:10:01 +04:00
self . server = dbus . Interface (
self . bus . get_object ( " org.freedesktop.Avahi " , " / " ) ,
" org.freedesktop.Avahi.Server " )
2008-09-02 19:36:56 +04:00
self . can_browse = True
except Exception , e :
logging . debug ( " Couldn ' t contact avahi: %s " % str ( e ) )
self . reset_state ( )
2007-07-12 03:52:53 +04:00
2010-11-29 22:06:43 +03:00
def cancel ( self , ignore1 = None , ignore2 = None ) :
2006-06-14 22:36:26 +04:00
self . close ( )
2006-06-27 18:08:55 +04:00
self . emit ( " cancelled " )
2006-06-14 18:59:40 +04:00
return 1
2006-06-14 22:36:26 +04:00
def close ( self ) :
self . window . get_widget ( " vmm-open-connection " ) . hide ( )
2008-09-02 19:36:56 +04:00
self . stop_browse ( )
2006-06-14 22:36:26 +04:00
2006-06-14 18:59:40 +04:00
def show ( self ) :
win = self . window . get_widget ( " vmm-open-connection " )
win . present ( )
2008-09-02 19:36:56 +04:00
self . reset_state ( )
2010-08-24 22:56:03 +04:00
def set_initial_state ( self ) :
stock_img = gtk . image_new_from_stock ( gtk . STOCK_CONNECT ,
gtk . ICON_SIZE_BUTTON )
self . window . get_widget ( " connect " ) . set_image ( stock_img )
self . window . get_widget ( " connect " ) . grab_default ( )
# Hostname combo box entry
hostListModel = gtk . ListStore ( str , str , str )
host = self . window . get_widget ( " hostname " )
host . set_model ( hostListModel )
host . set_text_column ( 2 )
hostListModel . set_sort_column_id ( 2 , gtk . SORT_ASCENDING )
self . window . get_widget ( " hostname " ) . child . connect ( " changed " ,
self . hostname_changed )
2008-09-02 19:36:56 +04:00
def reset_state ( self ) :
2009-03-10 05:58:05 +03:00
self . set_default_hypervisor ( )
2010-08-24 22:56:03 +04:00
self . window . get_widget ( " connection " ) . set_active ( 0 )
2008-09-02 19:36:56 +04:00
self . window . get_widget ( " autoconnect " ) . set_sensitive ( True )
self . window . get_widget ( " autoconnect " ) . set_active ( True )
2010-08-22 22:10:01 +04:00
self . window . get_widget ( " hostname " ) . get_model ( ) . clear ( )
self . window . get_widget ( " hostname " ) . child . set_text ( " " )
2010-08-24 22:56:03 +04:00
self . window . get_widget ( " connect-remote " ) . set_active ( False )
2010-08-24 23:36:06 +04:00
self . window . get_widget ( " username-entry " ) . set_text ( " " )
2008-09-02 19:36:56 +04:00
self . stop_browse ( )
2010-08-24 22:56:03 +04:00
self . connect_remote_toggled ( self . window . get_widget ( " connect-remote " ) )
2010-08-24 21:49:44 +04:00
self . populate_uri ( )
2006-06-14 18:59:40 +04:00
2010-08-24 22:56:03 +04:00
def is_remote ( self ) :
# Whether user is requesting a remote connection
return self . window . get_widget ( " connect-remote " ) . get_active ( )
2009-03-10 05:58:05 +03:00
def set_default_hypervisor ( self ) :
default = virtinst . util . default_connection ( )
if default is None :
self . window . get_widget ( " hypervisor " ) . set_active ( - 1 )
elif default . startswith ( " xen " ) :
self . window . get_widget ( " hypervisor " ) . set_active ( 0 )
elif default . startswith ( " qemu " ) :
self . window . get_widget ( " hypervisor " ) . set_active ( 1 )
2008-09-02 19:36:56 +04:00
def add_service ( self , interface , protocol , name , type , domain , flags ) :
try :
# Async service resolving
res = self . server . ServiceResolverNew ( interface , protocol , name ,
type , domain , - 1 , 0 )
resint = dbus . Interface ( self . bus . get_object ( " org.freedesktop.Avahi " ,
res ) ,
" org.freedesktop.Avahi.ServiceResolver " )
resint . connect_to_signal ( " Found " , self . add_conn_to_list )
# Synchronous service resolving
#self.server.ResolveService(interface, protocol, name, type,
# domain, -1, 0)
except Exception , e :
logging . exception ( e )
def remove_service ( self , interface , protocol , name , type , domain , flags ) :
try :
2010-08-22 22:10:01 +04:00
model = self . window . get_widget ( " hostname " ) . get_model ( )
2008-09-02 19:36:56 +04:00
name = str ( name )
for row in model :
if row [ 0 ] == name :
model . remove ( row . iter )
except Exception , e :
logging . exception ( e )
def add_conn_to_list ( self , interface , protocol , name , type , domain ,
host , aprotocol , address , port , text , flags ) :
try :
2010-08-22 22:10:01 +04:00
model = self . window . get_widget ( " hostname " ) . get_model ( )
2008-09-02 19:36:56 +04:00
for row in model :
if row [ 2 ] == str ( name ) :
2009-03-09 23:21:21 +03:00
# Already present in list
2008-09-02 19:36:56 +04:00
return
2010-08-22 22:10:01 +04:00
2009-03-09 23:21:21 +03:00
host = self . sanitize_hostname ( str ( host ) )
2010-08-22 22:10:01 +04:00
model . append ( [ str ( address ) , str ( host ) , str ( name ) ] )
2008-09-02 19:36:56 +04:00
except Exception , e :
logging . exception ( e )
def start_browse ( self ) :
if self . browser or not self . can_browse :
return
# Call method to create new browser, and get back an object path for it.
interface = - 1 # physical interface to use? -1 is unspec
protocol = 0 # 0 = IPv4, 1 = IPv6, -1 = Unspecified
service = ' _libvirt._tcp ' # Service name to poll for
flags = 0 # Extra option flags
domain = " " # Domain to browse in. NULL uses default
bpath = self . server . ServiceBrowserNew ( interface , protocol , service ,
domain , flags )
# Create browser interface for the new object
self . browser = dbus . Interface ( self . bus . get_object ( " org.freedesktop.Avahi " ,
bpath ) ,
" org.freedesktop.Avahi.ServiceBrowser " )
self . browser . connect_to_signal ( " ItemNew " , self . add_service )
self . browser . connect_to_signal ( " ItemRemove " , self . remove_service )
def stop_browse ( self ) :
if self . browser :
del ( self . browser )
self . browser = None
2010-08-22 22:10:01 +04:00
def hostname_combo_changed ( self , src ) :
model = src . get_model ( )
txt = src . child . get_text ( )
row = None
for currow in model :
if currow [ 2 ] == txt :
row = currow
break
if not row :
2008-09-02 19:36:56 +04:00
return
2010-08-22 22:10:01 +04:00
ip = row [ 0 ]
host = row [ 1 ]
2008-09-02 19:36:56 +04:00
entry = host
if not entry :
entry = ip
2010-08-22 22:10:01 +04:00
self . window . get_widget ( " hostname " ) . child . set_text ( entry )
2006-06-14 18:59:40 +04:00
2010-08-24 21:49:44 +04:00
def hostname_changed ( self , src ) :
self . populate_uri ( )
def hypervisor_changed ( self , src ) :
self . populate_uri ( )
2010-08-24 23:36:06 +04:00
def username_changed ( self , src ) :
self . populate_uri ( )
2010-08-24 22:56:03 +04:00
def connect_remote_toggled ( self , src ) :
is_remote = self . is_remote ( )
2010-08-24 21:49:44 +04:00
self . window . get_widget ( " hostname " ) . set_sensitive ( is_remote )
2010-08-24 22:56:03 +04:00
self . window . get_widget ( " connection " ) . set_sensitive ( is_remote )
2010-08-24 21:49:44 +04:00
self . window . get_widget ( " autoconnect " ) . set_active ( not is_remote )
2010-08-24 23:36:06 +04:00
self . window . get_widget ( " username-entry " ) . set_sensitive ( is_remote )
2010-08-24 21:49:44 +04:00
if is_remote and self . can_browse :
self . start_browse ( )
else :
self . stop_browse ( )
2010-08-24 23:36:06 +04:00
self . populate_default_user ( )
2010-08-24 21:49:44 +04:00
self . populate_uri ( )
2010-08-24 22:56:03 +04:00
def connection_changed ( self , src ) :
2010-08-24 23:36:06 +04:00
self . populate_default_user ( )
2010-08-24 22:56:03 +04:00
self . populate_uri ( )
2010-08-24 21:49:44 +04:00
def populate_uri ( self ) :
uri = self . generate_uri ( )
self . window . get_widget ( " uri-entry " ) . set_text ( uri )
2010-08-24 23:36:06 +04:00
def populate_default_user ( self ) :
conn = self . window . get_widget ( " connection " ) . get_active ( )
default_user = default_conn_user ( conn )
self . window . get_widget ( " username-entry " ) . set_text ( default_user )
2010-08-24 21:49:44 +04:00
def generate_uri ( self ) :
2007-07-12 03:52:53 +04:00
hv = self . window . get_widget ( " hypervisor " ) . get_active ( )
conn = self . window . get_widget ( " connection " ) . get_active ( )
2010-08-22 22:10:01 +04:00
host = self . window . get_widget ( " hostname " ) . child . get_text ( )
2010-08-24 23:36:06 +04:00
user = self . window . get_widget ( " username-entry " ) . get_text ( )
2010-08-24 22:56:03 +04:00
is_remote = self . is_remote ( )
2006-06-14 18:59:40 +04:00
2010-08-24 21:49:44 +04:00
hvstr = " "
if hv == HV_XEN :
hvstr = " xen "
2008-12-07 07:06:28 +03:00
else :
2010-08-24 21:49:44 +04:00
hvstr = " qemu "
2010-08-24 23:36:06 +04:00
addrstr = " "
if user :
addrstr + = user + " @ "
addrstr + = host
2010-08-24 21:49:44 +04:00
hoststr = " "
2010-08-24 22:56:03 +04:00
if not is_remote :
2010-08-24 21:49:44 +04:00
hoststr = " :/// "
2010-08-24 23:36:06 +04:00
else :
if conn == CONN_TLS :
hoststr = " +tls:// "
if conn == CONN_SSH :
hoststr = " +ssh:// "
if conn == CONN_TCP :
hoststr = " +tcp:// "
hoststr + = addrstr + " / "
2010-08-24 21:49:44 +04:00
uri = hvstr + hoststr
if hv == HV_QEMU :
uri + = " system "
return uri
def validate ( self ) :
2010-08-24 22:56:03 +04:00
is_remote = self . is_remote ( )
2010-08-24 21:49:44 +04:00
host = self . window . get_widget ( " hostname " ) . child . get_text ( )
2010-08-24 22:56:03 +04:00
if is_remote and not host :
2010-08-24 21:49:44 +04:00
return self . err . val_err ( _ ( " A hostname is required for "
" remote connections. " ) )
return True
def open_connection ( self , ignore ) :
if not self . validate ( ) :
return
readonly = False
auto = False
if self . window . get_widget ( " autoconnect " ) . get_property ( " sensitive " ) :
auto = self . window . get_widget ( " autoconnect " ) . get_active ( )
uri = self . generate_uri ( )
logging . debug ( " Generate URI= %s , auto= %s , readonly= %s " %
( uri , auto , readonly ) )
2006-06-14 18:59:40 +04:00
self . close ( )
2010-08-24 21:49:44 +04:00
self . emit ( " completed " , uri , readonly , auto )
2006-06-14 22:36:26 +04:00
2008-09-02 19:36:56 +04:00
def sanitize_hostname ( self , host ) :
if host == " linux " or host == " localhost " :
host = " "
if host . startswith ( " linux- " ) :
tmphost = host [ 6 : ]
try :
2008-11-18 22:48:10 +03:00
long ( tmphost )
2008-09-02 19:36:56 +04:00
host = " "
except ValueError :
pass
2009-03-09 23:21:21 +03:00
if host :
host = self . check_resolve_host ( host )
return host
def check_resolve_host ( self , host ) :
# Try to resolve hostname
# XXX: Avahi always uses 'hostname.local', but for some reason
# fedora out of the box can't resolve '.local' names
# Attempt to resolve the name. If it fails, remove .local
# if present, and try again
if host . endswith ( " .local " ) :
if self . can_resolve_local == False :
host = host [ : - 6 ]
elif self . can_resolve_local == None :
try :
socket . getaddrinfo ( host , None )
except :
logging . debug ( " Couldn ' t resolve host ' %s ' . Stripping "
" ' .local ' and retrying. " % host )
self . can_resolve_local = False
host = self . check_resolve_host ( host [ : - 6 ] )
else :
self . can_resolve_local = True
else :
if self . can_resolve_hostname == False :
host = " "
elif self . can_resolve_hostname == None :
try :
socket . getaddrinfo ( host , None )
except :
logging . debug ( " Couldn ' t resolve host ' %s ' . Disabling "
" host name resolution, only using IP addr " %
host )
self . can_resolve_hostname = False
else :
self . can_resolve_hostname = True
2008-09-02 19:36:56 +04:00
return host
2009-03-09 23:21:21 +03:00
2006-06-14 22:36:26 +04:00
gobject . type_register ( vmmConnect )