2010-02-09 01:18:06 +03:00
#
# Copyright (C) 2008 Red Hat, Inc.
# Copyright (C) 2008 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 gobject
import gtk
import traceback
import logging
from virtinst import Interface
from virtManager import util
from virtManager import uihelpers
2010-12-09 01:26:19 +03:00
from virtManager . baseclass import vmmGObjectUI
2010-02-09 01:18:06 +03:00
from virtManager . asyncjob import vmmAsyncJob
from virtManager . createmeter import vmmCreateMeter
PAGE_TYPE = 0
PAGE_DETAILS = 1
DETAILS_BOND = 0
DETAILS_BRIDGE = 1
DETAILS_VLAN = 2
DETAILS_ETHERNET = 3
INTERFACE_ROW_KEY = 0
INTERFACE_ROW_SELECT = 1
INTERFACE_ROW_CANT_SELECT = 2
INTERFACE_ROW_NAME = 3
INTERFACE_ROW_TYPE = 4
INTERFACE_ROW_IS_DEFINED = 5
INTERFACE_ROW_IS_ACTIVE = 6
INTERFACE_ROW_IN_USE_BY = 7
INTERFACE_ROW_MAC = 8
BOND_PAGE_ARP = 0
BOND_PAGE_MII = 1
BOND_PAGE_DEFAULT = 2
2010-02-27 02:49:18 +03:00
IP_DHCP = 0
IP_STATIC = 1
IP_NONE = 2
2010-12-09 01:26:19 +03:00
class vmmCreateInterface ( vmmGObjectUI ) :
2010-02-09 01:18:06 +03:00
__gsignals__ = {
" action-show-help " : ( gobject . SIGNAL_RUN_FIRST ,
gobject . TYPE_NONE , [ str ] ) ,
}
2010-12-09 01:26:19 +03:00
def __init__ ( self , conn ) :
vmmGObjectUI . __init__ ( self ,
" vmm-create-interface.glade " ,
" vmm-create-interface " )
2010-02-09 01:18:06 +03:00
self . conn = conn
self . interface = None
# Bridge configuration dialog
2010-12-09 01:26:19 +03:00
self . bridge_config_win = gtk . glade . XML ( self . gladefile ,
2010-02-09 01:18:06 +03:00
" bridge-config " ,
domain = " virt-manager " )
self . bridge_config = self . bridge_config_win . get_widget (
" bridge-config " )
self . bridge_config_win . signal_autoconnect ( {
" on_bridge_config_delete_event " : self . bridge_config_finish ,
" on_bridge_ok_clicked " : self . bridge_config_finish ,
} )
# Bond configuration dialog
2010-12-09 01:26:19 +03:00
self . bond_config_win = gtk . glade . XML ( self . gladefile ,
2010-02-09 01:18:06 +03:00
" bond-config " ,
domain = " virt-manager " )
self . bond_config = self . bond_config_win . get_widget ( " bond-config " )
self . bond_config_win . signal_autoconnect ( {
" on_bond_config_delete_event " : self . bond_config_finish ,
" on_bond_ok_clicked " : self . bond_config_finish ,
" on_bond_monitor_mode_changed " : self . bond_monitor_mode_changed ,
} )
2010-12-09 01:26:19 +03:00
self . ip_config_win = gtk . glade . XML ( self . gladefile ,
2010-02-27 02:49:18 +03:00
" ip-config " ,
domain = " virt-manager " )
self . ip_config = self . ip_config_win . get_widget ( " ip-config " )
self . ip_config_win . signal_autoconnect ( {
" on_ip_config_delete_event " : self . ip_config_finish ,
" on_ip_ok_clicked " : self . ip_config_finish ,
" on_ip_copy_interface_toggled " : self . ip_copy_interface_toggled ,
" on_ipv4_mode_changed " : self . ipv4_mode_changed ,
" on_ipv6_mode_changed " : self . ipv6_mode_changed ,
" on_ipv6_address_add_clicked " : self . ipv6_address_add ,
" on_ipv6_address_remove_clicked " : self . ipv6_address_remove ,
} )
self . ip_manually_changed = False
2010-02-09 01:18:06 +03:00
self . window . signal_autoconnect ( {
" on_vmm_create_interface_delete_event " : self . close ,
" on_cancel_clicked " : self . close ,
" on_back_clicked " : self . back ,
" on_forward_clicked " : self . forward ,
" on_finish_clicked " : self . finish ,
" on_help_clicked " : self . show_help ,
" on_pages_switch_page " : self . page_changed ,
" on_bridge_config_button_clicked " : self . show_bridge_config ,
" on_bond_config_button_clicked " : self . show_bond_config ,
2010-02-27 02:49:18 +03:00
" on_ip_config_button_clicked " : self . show_ip_config ,
2010-02-09 01:18:06 +03:00
" on_vlan_tag_changed " : self . update_interface_name ,
} )
util . bind_escape_key_close ( self )
self . set_initial_state ( )
def show ( self ) :
self . reset_state ( )
self . topwin . present ( )
def show_bond_config ( self , src ) :
self . bond_config . show_all ( )
def show_bridge_config ( self , src ) :
self . bridge_config . show_all ( )
2010-02-27 02:49:18 +03:00
def show_ip_config ( self , src ) :
self . ip_manually_changed = True
self . ip_config . show_all ( )
2010-02-09 01:18:06 +03:00
def close ( self , ignore1 = None , ignore2 = None ) :
2010-12-09 22:46:15 +03:00
self . ip_config . hide ( )
self . bridge_config . hide ( )
self . bond_config . hide ( )
2010-02-09 01:18:06 +03:00
self . topwin . hide ( )
return 1
###########################
# Initialization routines #
###########################
def set_initial_state ( self ) :
self . window . get_widget ( " pages " ) . set_show_tabs ( False )
self . bond_config_win . get_widget ( " bond-pages " ) . set_show_tabs ( False )
# FIXME: Unhide this when we make some documentation
self . window . get_widget ( " help " ) . hide ( )
finish_img = gtk . image_new_from_stock ( gtk . STOCK_QUIT ,
gtk . ICON_SIZE_BUTTON )
self . window . get_widget ( " finish " ) . set_image ( finish_img )
blue = gtk . gdk . color_parse ( " #0072A8 " )
self . window . get_widget ( " header " ) . modify_bg ( gtk . STATE_NORMAL , blue )
box = self . window . get_widget ( " header-icon-box " )
image = gtk . image_new_from_icon_name ( " network-idle " ,
gtk . ICON_SIZE_DIALOG )
image . show ( )
box . pack_end ( image , False )
# Interface type
type_list = self . window . get_widget ( " interface-type " )
type_model = gtk . ListStore ( str , str )
type_list . set_model ( type_model )
text = gtk . CellRendererText ( )
type_list . pack_start ( text , True )
type_list . add_attribute ( text , ' text ' , 1 )
type_model . append ( [ Interface . Interface . INTERFACE_TYPE_BRIDGE ,
_ ( " Bridge " ) ] )
type_model . append ( [ Interface . Interface . INTERFACE_TYPE_BOND ,
_ ( " Bond " ) ] )
type_model . append ( [ Interface . Interface . INTERFACE_TYPE_ETHERNET ,
_ ( " Ethernet " ) ] )
type_model . append ( [ Interface . Interface . INTERFACE_TYPE_VLAN ,
_ ( " VLAN " ) ] )
# Start mode
uihelpers . build_startmode_combo (
self . window . get_widget ( " interface-startmode " ) )
# Parent/slave Interface list
slave_list = self . window . get_widget ( " interface-list " )
# [ vmmInterface, selected, selectabel, name, type, is defined,
# is active, in use by str, mac]
slave_model = gtk . ListStore ( object , bool , bool , str , str , bool , bool ,
str , str )
slave_list . set_model ( slave_model )
selectCol = gtk . TreeViewColumn ( )
nameCol = gtk . TreeViewColumn ( _ ( " Name " ) )
typeCol = gtk . TreeViewColumn ( _ ( " Type " ) )
useCol = gtk . TreeViewColumn ( _ ( " In use by " ) )
slave_list . append_column ( selectCol )
slave_list . append_column ( nameCol )
slave_list . append_column ( typeCol )
slave_list . append_column ( useCol )
chk = gtk . CellRendererToggle ( )
chk . connect ( " toggled " , self . interface_item_toggled , slave_list )
selectCol . pack_start ( chk , False )
selectCol . add_attribute ( chk , " active " , INTERFACE_ROW_SELECT )
selectCol . add_attribute ( chk , " inconsistent " , INTERFACE_ROW_CANT_SELECT )
selectCol . set_sort_column_id ( INTERFACE_ROW_CANT_SELECT )
txt = gtk . CellRendererText ( )
nameCol . pack_start ( txt , True )
nameCol . add_attribute ( txt , " text " , INTERFACE_ROW_NAME )
nameCol . set_sort_column_id ( INTERFACE_ROW_NAME )
txt = gtk . CellRendererText ( )
typeCol . pack_start ( txt , True )
typeCol . add_attribute ( txt , " text " , INTERFACE_ROW_TYPE )
typeCol . set_sort_column_id ( INTERFACE_ROW_TYPE )
slave_model . set_sort_column_id ( INTERFACE_ROW_CANT_SELECT ,
gtk . SORT_ASCENDING )
txt = gtk . CellRendererText ( )
useCol . pack_start ( txt , True )
useCol . add_attribute ( txt , " text " , INTERFACE_ROW_IN_USE_BY )
useCol . set_sort_column_id ( INTERFACE_ROW_IN_USE_BY )
# Bond config
mode_list = self . bond_config_win . get_widget ( " bond-mode " )
mode_model = gtk . ListStore ( str , str )
mode_list . set_model ( mode_model )
txt = gtk . CellRendererText ( )
mode_list . pack_start ( txt , True )
mode_list . add_attribute ( txt , " text " , 0 )
mode_model . append ( [ _ ( " System default " ) , None ] )
for m in Interface . InterfaceBond . INTERFACE_BOND_MODES :
mode_model . append ( [ m , m ] )
mon_list = self . bond_config_win . get_widget ( " bond-monitor-mode " )
mon_model = gtk . ListStore ( str , str )
mon_list . set_model ( mon_model )
txt = gtk . CellRendererText ( )
mon_list . pack_start ( txt , True )
mon_list . add_attribute ( txt , " text " , 0 )
mon_model . append ( [ _ ( " System default " ) , None ] )
for m in Interface . InterfaceBond . INTERFACE_BOND_MONITOR_MODES :
mon_model . append ( [ m , m ] )
validate_list = self . bond_config_win . get_widget ( " arp-validate " )
validate_model = gtk . ListStore ( str )
validate_list . set_model ( validate_model )
txt = gtk . CellRendererText ( )
validate_list . pack_start ( txt , True )
validate_list . add_attribute ( txt , " text " , 0 )
for m in Interface . InterfaceBond . INTERFACE_BOND_MONITOR_MODE_ARP_VALIDATE_MODES :
validate_model . append ( [ m ] )
carrier_list = self . bond_config_win . get_widget ( " mii-carrier " )
carrier_model = gtk . ListStore ( str )
carrier_list . set_model ( carrier_model )
txt = gtk . CellRendererText ( )
carrier_list . pack_start ( txt , True )
carrier_list . add_attribute ( txt , " text " , 0 )
for m in Interface . InterfaceBond . INTERFACE_BOND_MONITOR_MODE_MII_CARRIER_TYPES :
carrier_model . append ( [ m ] )
2010-02-27 02:49:18 +03:00
# IP config
copy_iface = self . ip_config_win . get_widget ( " ip-copy-interface-combo " )
copy_model = gtk . ListStore ( str , object , bool )
copy_iface . set_model ( copy_model )
txt = gtk . CellRendererText ( )
copy_iface . pack_start ( txt , True )
copy_iface . add_attribute ( txt , " text " , 0 )
copy_iface . add_attribute ( txt , " sensitive " , 2 )
ip_mode = self . ip_config_win . get_widget ( " ipv4-mode " )
ip_model = gtk . ListStore ( str )
ip_mode . set_model ( ip_model )
txt = gtk . CellRendererText ( )
ip_mode . pack_start ( txt , True )
ip_mode . add_attribute ( txt , " text " , 0 )
ip_model . insert ( IP_DHCP , [ " DHCP " ] )
ip_model . insert ( IP_STATIC , [ " Static " ] )
ip_model . insert ( IP_NONE , [ " No configuration " ] )
ip_mode = self . ip_config_win . get_widget ( " ipv6-mode " )
ip_model = gtk . ListStore ( str )
ip_mode . set_model ( ip_model )
txt = gtk . CellRendererText ( )
ip_mode . pack_start ( txt , True )
ip_mode . add_attribute ( txt , " text " , 0 )
ip_model . insert ( IP_DHCP , [ " DHCP " ] )
ip_model . insert ( IP_STATIC , [ " Static " ] )
ip_model . insert ( IP_NONE , [ " No configuration " ] )
v6_addr = self . ip_config_win . get_widget ( " ipv6-address-list " )
addr_model = gtk . ListStore ( str )
v6_addr . set_model ( addr_model )
txt_col = gtk . TreeViewColumn ( " " )
v6_addr . append_column ( txt_col )
txt = gtk . CellRendererText ( )
txt . set_property ( " editable " , True )
txt . connect ( " edited " , self . ipv6_address_editted )
txt_col . pack_start ( txt , True )
txt_col . add_attribute ( txt , " text " , 0 )
v6_addr . get_selection ( ) . connect ( " changed " , self . ipv6_address_selected )
2010-02-09 01:18:06 +03:00
def reset_state ( self ) :
self . window . get_widget ( " pages " ) . set_current_page ( PAGE_TYPE )
self . page_changed ( None , None , PAGE_TYPE )
self . window . get_widget ( " interface-type " ) . set_active ( 0 )
# General details
self . window . get_widget ( " interface-name-entry " ) . set_text ( " " )
self . window . get_widget ( " interface-name-label " ) . set_text ( " " )
self . window . get_widget ( " interface-startmode " ) . set_active ( 0 )
self . window . get_widget ( " interface-activate " ) . set_active ( False )
# Bridge config
self . bridge_config_win . get_widget ( " bridge-delay " ) . set_value ( 0 )
self . bridge_config_win . get_widget ( " bridge-stp " ) . set_active ( True )
# Bond config
self . bond_config_win . get_widget ( " bond-mode " ) . set_active ( 0 )
self . bond_config_win . get_widget ( " bond-monitor-mode " ) . set_active ( 0 )
self . bond_config_win . get_widget ( " arp-interval " ) . set_value ( 0 )
self . bond_config_win . get_widget ( " arp-target " ) . set_text ( " " )
self . bond_config_win . get_widget ( " arp-validate " ) . set_active ( 0 )
self . bond_config_win . get_widget ( " mii-frequency " ) . set_value ( 0 )
self . bond_config_win . get_widget ( " mii-updelay " ) . set_value ( 0 )
self . bond_config_win . get_widget ( " mii-downdelay " ) . set_value ( 0 )
self . bond_config_win . get_widget ( " mii-carrier " ) . set_active ( 0 )
2010-02-27 02:49:18 +03:00
# IP config
self . ip_manually_changed = False
self . ip_config_win . get_widget ( " ip-do-manual " ) . set_active ( True )
self . ip_config_win . get_widget ( " ip-do-manual-box " ) . set_current_page ( 0 )
self . ip_config_win . get_widget ( " ipv4-mode " ) . set_active ( IP_DHCP )
self . ip_config_win . get_widget ( " ipv4-address " ) . set_text ( " " )
self . ip_config_win . get_widget ( " ipv4-gateway " ) . set_text ( " " )
self . ip_config_win . get_widget ( " ipv6-mode " ) . set_active ( IP_NONE )
self . ip_config_win . get_widget ( " ipv6-autoconf " ) . set_active ( False )
self . ipv6_address_selected ( )
2010-02-09 01:18:06 +03:00
def populate_details_page ( self ) :
itype = self . get_config_interface_type ( )
# Set up default interface name
self . window . get_widget ( " interface-name-entry " ) . hide ( )
self . window . get_widget ( " interface-name-label " ) . hide ( )
if itype in [ Interface . Interface . INTERFACE_TYPE_BRIDGE ,
Interface . Interface . INTERFACE_TYPE_BOND ] :
widget = " interface-name-entry "
else :
widget = " interface-name-label "
self . window . get_widget ( widget ) . show ( )
default_name = self . get_default_name ( )
self . set_interface_name ( default_name )
# Make sure interface type specific fields are shown
type_dict = {
Interface . Interface . INTERFACE_TYPE_BRIDGE : " bridge " ,
Interface . Interface . INTERFACE_TYPE_BOND : " bond " ,
Interface . Interface . INTERFACE_TYPE_VLAN : " vlan " ,
}
for key , value in type_dict . items ( ) :
do_show = ( key == itype )
self . window . get_widget ( " %s -label " % value ) . set_property ( " visible " ,
do_show )
self . window . get_widget ( " %s -box " % value ) . set_property ( " visible " ,
do_show )
if itype == Interface . Interface . INTERFACE_TYPE_BRIDGE :
self . update_bridge_desc ( )
elif itype == Interface . Interface . INTERFACE_TYPE_BOND :
self . update_bond_desc ( )
# Populate device list
self . populate_interface_list ( itype )
2010-02-27 02:49:18 +03:00
self . update_ip_config ( )
def update_ip_config ( self ) :
( is_manual , current_name ,
ignore , ignore , ignore ) = self . get_config_ip_info ( )
2010-02-09 01:18:06 +03:00
itype = self . get_config_interface_type ( )
2010-02-27 02:49:18 +03:00
ifaces = self . get_config_selected_interfaces ( )
2010-02-09 01:18:06 +03:00
2010-02-27 02:49:18 +03:00
copy_radio = self . ip_config_win . get_widget ( " ip-copy-interface " )
copy_combo = self . ip_config_win . get_widget ( " ip-copy-interface-combo " )
copy_model = copy_combo . get_model ( )
2010-02-09 01:18:06 +03:00
2010-12-02 23:23:29 +03:00
# Only select 'copy from' option if using bridge/bond/vlan
2010-02-27 02:49:18 +03:00
enable_copy = ( itype in [ Interface . Interface . INTERFACE_TYPE_BRIDGE ,
2010-12-02 23:23:29 +03:00
Interface . Interface . INTERFACE_TYPE_BOND ,
Interface . Interface . INTERFACE_TYPE_VLAN ] )
2010-02-09 01:18:06 +03:00
2010-02-27 02:49:18 +03:00
# Set defaults if required
copy_model . clear ( )
active_rows = [ ]
inactive_rows = [ ]
for row in ifaces :
is_defined = row [ INTERFACE_ROW_IS_DEFINED ]
name = row [ INTERFACE_ROW_NAME ]
label = name
sensitive = False
iface_obj = None
if is_defined :
iface_obj = self . conn . get_interface ( name )
# We only want configured (aka interface API) interfaces with
# actually present <protocol> info
if not is_defined or not iface_obj :
label + = " (Not configured) "
elif not iface_obj . get_protocol_xml ( ) :
label + = " (No IP configuration) "
else :
sensitive = True
row = [ label , iface_obj , sensitive ]
if sensitive :
active_rows . append ( row )
else :
inactive_rows . append ( row )
# Make sure inactive rows are listed after active rows
for row in active_rows + inactive_rows :
copy_model . append ( row )
if len ( copy_model ) == 0 :
copy_model . append ( [ " No child interfaces selected. " , None , False ] )
if not enable_copy :
copy_model . clear ( )
copy_model . append ( [ " " , None , False ] )
# Find default model selection
have_valid_copy = bool ( active_rows )
# Re select previous selection, 0 otherwise
idx = 0
if not is_manual and current_name :
found_idx = 0
for row in copy_model :
if row [ 1 ] == current_name :
idx = found_idx
break
found_idx + = 1
copy_combo . set_active ( idx )
copy_radio . set_sensitive ( enable_copy )
if not self . ip_manually_changed :
if ( enable_copy and have_valid_copy ) :
copy_radio . set_active ( True )
else :
self . ip_config_win . get_widget ( " ip-do-manual " ) . set_active ( True )
self . update_ip_desc ( )
2010-02-09 01:18:06 +03:00
def populate_interface_list ( self , itype ) :
iface_list = self . window . get_widget ( " interface-list " )
model = iface_list . get_model ( )
model . clear ( )
ifilter = [ Interface . Interface . INTERFACE_TYPE_ETHERNET ]
msg = None
if itype == Interface . Interface . INTERFACE_TYPE_BRIDGE :
ifilter . append ( Interface . Interface . INTERFACE_TYPE_VLAN )
ifilter . append ( Interface . Interface . INTERFACE_TYPE_BOND )
msg = _ ( " Choose interface(s) to bridge: " )
elif itype == Interface . Interface . INTERFACE_TYPE_VLAN :
msg = _ ( " Choose parent interface: " )
elif itype == Interface . Interface . INTERFACE_TYPE_BOND :
msg = _ ( " Choose interfaces to bond: " )
elif itype == Interface . Interface . INTERFACE_TYPE_ETHERNET :
msg = _ ( " Choose an unconfigured interface: " )
self . window . get_widget ( " interface-list-text " ) . set_text ( msg )
iface_list = [ ]
row_dict = { }
for phys in self . conn . get_devices ( " net " ) :
row_dict [ phys . interface ] = [ phys . interface ,
False , False , phys . interface ,
" ethernet " , False , True , None ,
phys . address ]
for name in self . conn . list_interface_names ( ) :
iface = self . conn . get_interface ( name )
key = iface . interface
iface_type = iface . get_type ( )
active = iface . is_active ( )
name = iface . get_name ( )
if iface_type not in ifilter :
continue
if itype == Interface . Interface . INTERFACE_TYPE_ETHERNET :
if row_dict . has_key ( name ) :
del ( row_dict [ name ] )
# We only want 'unconfigured' interfaces here
continue
if row_dict . has_key ( name ) :
# Interface was listed via nodedev APIs
row = row_dict [ name ]
row [ INTERFACE_ROW_KEY ] = key
row [ INTERFACE_ROW_IS_DEFINED ] = True
row [ INTERFACE_ROW_IS_ACTIVE ] = True
else :
# Brand new row
row = [ key , False , False ,
iface . get_name ( ) , iface . get_type ( ) , True ,
active , None , iface . get_mac ( ) ]
row_dict [ name ] = row
for row in row_dict . values ( ) :
name = row [ INTERFACE_ROW_NAME ]
row [ INTERFACE_ROW_IN_USE_BY ] = util . iface_in_use_by ( self . conn ,
name )
for row in row_dict . values ( ) :
model . append ( row )
def get_default_name ( self ) :
itype = self . get_config_interface_type ( )
name = _ ( " No interface selected " )
if itype == Interface . Interface . INTERFACE_TYPE_BRIDGE :
name = Interface . Interface . find_free_name ( self . conn . vmm , " br " )
elif itype == Interface . Interface . INTERFACE_TYPE_BOND :
name = Interface . Interface . find_free_name ( self . conn . vmm , " bond " )
else :
ifaces = self . get_config_selected_interfaces ( )
if len ( ifaces ) > 0 :
iface = ifaces [ 0 ] [ INTERFACE_ROW_NAME ]
if itype == Interface . Interface . INTERFACE_TYPE_VLAN :
tag = self . window . get_widget ( " vlan-tag " ) . get_value ( )
name = " %s . %s " % ( iface , int ( tag ) )
elif itype == Interface . Interface . INTERFACE_TYPE_ETHERNET :
name = iface
return name
#########################
# get_config_* routines #
#########################
def get_config_interface_type ( self ) :
type_list = self . window . get_widget ( " interface-type " )
return type_list . get_model ( ) [ type_list . get_active ( ) ] [ 0 ]
def set_interface_name ( self , name ) :
if self . window . get_widget ( " interface-name-entry " ) . get_property ( " visible " ) :
widget = " interface-name-entry "
else :
widget = " interface-name-label "
self . window . get_widget ( widget ) . set_text ( name )
def get_config_interface_name ( self ) :
if self . window . get_widget ( " interface-name-entry " ) . get_property ( " visible " ) :
return self . window . get_widget ( " interface-name-entry " ) . get_text ( )
else :
return self . window . get_widget ( " interface-name-label " ) . get_text ( )
def get_config_interface_startmode ( self ) :
start_list = self . window . get_widget ( " interface-startmode " )
return start_list . get_model ( ) [ start_list . get_active ( ) ] [ 0 ]
def get_config_selected_interfaces ( self ) :
iface_list = self . window . get_widget ( " interface-list " )
model = iface_list . get_model ( )
ret = [ ]
for row in model :
active = row [ INTERFACE_ROW_SELECT ]
iobj = row [ INTERFACE_ROW_KEY ]
if active :
ret . append ( row )
return ret
def get_config_bridge_params ( self ) :
delay = self . bridge_config_win . get_widget ( " bridge-delay " ) . get_value ( )
stp = self . bridge_config_win . get_widget ( " bridge-stp " ) . get_active ( )
return [ delay , stp ]
2010-02-27 02:49:18 +03:00
def get_config_ipv6_address_selection ( self ) :
src = self . ip_config_win . get_widget ( " ipv6-address-list " )
selection = src . get_selection ( )
ignore , treepath = selection . get_selected ( )
return treepath
def get_config_ipv6_addresses ( self ) :
src = self . ip_config_win . get_widget ( " ipv6-address-list " )
model = src . get_model ( )
return map ( lambda x : x [ 0 ] , model )
2010-02-09 01:18:06 +03:00
################
# UI Listeners #
################
2010-02-27 02:49:18 +03:00
def interface_item_toggled ( self , src , index , slave_list ) :
itype = self . get_config_interface_type ( )
active = src . get_active ( )
model = slave_list . get_model ( )
if itype in [ Interface . Interface . INTERFACE_TYPE_ETHERNET ,
Interface . Interface . INTERFACE_TYPE_VLAN ] :
# Deselect any selected rows
for row in model :
if row == model [ index ] :
continue
row [ INTERFACE_ROW_SELECT ] = False
# Toggle the clicked row
model [ index ] [ INTERFACE_ROW_SELECT ] = not active
self . update_interface_name ( )
self . update_ip_config ( )
2010-02-09 01:18:06 +03:00
def update_interface_name ( self , ignore1 = None , ignore2 = None ) :
itype = self . get_config_interface_type ( )
if itype not in [ Interface . Interface . INTERFACE_TYPE_VLAN ,
Interface . Interface . INTERFACE_TYPE_ETHERNET ] :
# The rest have editable name fields, so don't overwrite
return
name = self . get_default_name ( )
self . set_interface_name ( name )
def bond_monitor_mode_changed ( self , src ) :
model = src . get_model ( )
value = model [ src . get_active ( ) ] [ 1 ]
bond_pages = self . bond_config_win . get_widget ( " bond-pages " )
if value == " arpmon " :
page = BOND_PAGE_ARP
elif value == " miimon " :
page = BOND_PAGE_MII
else :
page = BOND_PAGE_DEFAULT
bond_pages . set_current_page ( page )
2010-02-27 02:49:18 +03:00
def ip_copy_interface_toggled ( self , src ) :
active = src . get_active ( )
self . ip_config_win . get_widget ( " ip-copy-interface-box " ) . set_sensitive ( active )
self . ip_config_win . get_widget ( " ip-do-manual-box " ) . set_sensitive ( not active )
def ipv4_mode_changed ( self , src ) :
static = ( src . get_active ( ) == IP_STATIC )
self . ip_config_win . get_widget ( " ipv4-static-box " ) . set_sensitive ( static )
def ipv6_mode_changed ( self , src ) :
static = ( src . get_active ( ) == IP_STATIC )
self . ip_config_win . get_widget ( " ipv6-static-box " ) . set_sensitive ( static )
2010-02-09 01:18:06 +03:00
def update_bridge_desc ( self ) :
delay , stp = self . get_config_bridge_params ( )
txt = " STP %s " % ( stp and " on " or " off " )
txt + = " , delay %d sec " % int ( delay )
self . window . get_widget ( " bridge-config-label " ) . set_text ( txt )
def update_bond_desc ( self ) :
mode_list = self . bond_config_win . get_widget ( " bond-mode " )
model = mode_list . get_model ( )
mode = model [ mode_list . get_active ( ) ] [ 0 ]
mon_list = self . bond_config_win . get_widget ( " bond-monitor-mode " )
model = mon_list . get_model ( )
mon = model [ mon_list . get_active ( ) ] [ 1 ]
txt = mode
if mon :
txt + = " , %s " % mon
self . window . get_widget ( " bond-config-label " ) . set_text ( txt )
2010-02-27 02:49:18 +03:00
def update_ip_desc ( self ) :
is_manual , name , ipv4 , ipv6 , ignore = self . get_config_ip_info ( )
label = " "
if is_manual :
if ipv4 :
label + = " IPv4: %s " % ( ipv4 . dhcp and " DHCP " or " Static " )
if ipv6 :
if label :
label + = " , "
label + = " IPv6: "
mode_label = " "
if ipv6 . autoconf and ipv6 . dhcp :
mode_label + = " Autoconf "
if ipv6 . dhcp :
mode_label + = " DHCP "
if not mode_label :
mode_label = " Static "
label + = mode_label
else :
if name :
label = " Copy configuration from ' %s ' " % name
if not label :
label = " No configuration "
self . window . get_widget ( " ip-config-label " ) . set_text ( label )
def get_config_ip_info ( self ) :
if not self . window . get_widget ( " ip-label " ) . get_property ( " visible " ) :
return [ True , None , None , None , None ]
if not self . validate_ip_info ( ) :
return [ True , None , None , None , None ]
return self . build_ip_info ( )
def build_ip_info ( self ) :
def get_row ( widget ) :
combo = widget . get_model ( )
active = widget . get_active ( )
if active == - 1 :
return None
return combo [ active ]
def build_ip ( addr_str ) :
if not addr_str :
return None
ret = addr_str . rsplit ( " / " , 1 )
ip = Interface . InterfaceProtocolIPAddress ( ret [ 0 ] )
if len ( ret ) > 1 :
ip . prefix = ret [ 1 ]
return ip
is_manual = self . ip_config_win . get_widget ( " ip-do-manual " ) . get_active ( )
copy_row = get_row ( self . ip_config_win . get_widget ( " ip-copy-interface-combo " ) )
v4_mode = self . ip_config_win . get_widget ( " ipv4-mode " ) . get_active ( )
v4_addr = self . ip_config_win . get_widget ( " ipv4-address " ) . get_text ( )
v4_gate = self . ip_config_win . get_widget ( " ipv4-gateway " ) . get_text ( )
v6_mode = self . ip_config_win . get_widget ( " ipv6-mode " ) . get_active ( )
v6_auto = self . ip_config_win . get_widget ( " ipv6-autoconf " ) . get_active ( )
v6_gate = self . ip_config_win . get_widget ( " ipv6-gateway " ) . get_text ( )
v6_addrlist = self . get_config_ipv6_addresses ( )
copy_name = None
proto_xml = None
ipv4 = None
ipv6 = None
if not is_manual :
if copy_row [ 1 ] and copy_row [ 2 ] :
copy_name = copy_row [ 1 ] . get_name ( )
proto_xml = copy_row [ 1 ] . get_protocol_xml ( )
else :
# Build IPv4 Info
if v4_mode != IP_NONE :
ipv4 = Interface . InterfaceProtocolIPv4 ( )
ipv4 . dhcp = bool ( v4_mode == IP_DHCP )
if not ipv4 . dhcp :
if v4_addr :
ipv4 . ips . append ( build_ip ( v4_addr ) )
if v4_gate :
ipv4 . gateway = v4_gate
# Build IPv6 Info
if v6_mode != IP_NONE :
ipv6 = Interface . InterfaceProtocolIPv6 ( )
ipv6 . dhcp = bool ( v6_mode == IP_DHCP )
ipv6 . autoconf = bool ( v6_auto )
if not ipv6 . dhcp :
if v6_gate :
ipv6 . gateway = v6_gate
if v6_addrlist :
ipv6 . ips = map ( build_ip , v6_addrlist )
return [ is_manual , copy_name , ipv4 , ipv6 , proto_xml ]
def ipv6_address_add ( self , src ) :
src = self . ip_config_win . get_widget ( " ipv6-address-list " )
model = src . get_model ( )
model . append ( [ " Insert address/prefix " ] )
def ipv6_address_remove ( self , src ) :
treepath = self . get_config_ipv6_address_selection ( )
src = self . ip_config_win . get_widget ( " ipv6-address-list " )
model = src . get_model ( )
if treepath != None :
del ( model [ treepath ] )
def ipv6_address_editted ( self , src , path , new_text ) :
src = self . ip_config_win . get_widget ( " ipv6-address-list " )
model = src . get_model ( )
row = model [ path ]
row [ 0 ] = new_text
def ipv6_address_selected ( self , src = None ) :
treepath = self . get_config_ipv6_address_selection ( )
has_selection = ( treepath != None )
self . ip_config_win . get_widget ( " ipv6-address-remove " ) . set_sensitive (
has_selection )
2010-02-09 01:18:06 +03:00
#######################
# Notebook navigation #
#######################
def back ( self , src ) :
notebook = self . window . get_widget ( " pages " )
curpage = notebook . get_current_page ( )
notebook . set_current_page ( curpage - 1 )
def forward ( self , ignore ) :
notebook = self . window . get_widget ( " pages " )
curpage = notebook . get_current_page ( )
if self . validate ( notebook . get_current_page ( ) ) != True :
return
self . window . get_widget ( " forward " ) . grab_focus ( )
notebook . set_current_page ( curpage + 1 )
def page_changed ( self , ignore1 , ignore2 , pagenum ) :
next_page = pagenum + 1
# Update page number
page_lbl = ( " <span color= ' #59B0E2 ' > %s </span> " %
_ ( " Step %(current_page)d of %(max_page)d " ) %
{ ' current_page ' : next_page , ' max_page ' : PAGE_DETAILS + 1 } )
self . window . get_widget ( " header-pagenum " ) . set_markup ( page_lbl )
if pagenum == 0 :
self . window . get_widget ( " back " ) . set_sensitive ( False )
else :
self . window . get_widget ( " back " ) . set_sensitive ( True )
if pagenum == PAGE_DETAILS :
self . populate_details_page ( )
self . window . get_widget ( " forward " ) . hide ( )
self . window . get_widget ( " finish " ) . show ( )
self . window . get_widget ( " finish " ) . grab_focus ( )
else :
self . window . get_widget ( " forward " ) . show ( )
self . window . get_widget ( " finish " ) . hide ( )
def validate ( self , pagenum ) :
try :
if pagenum == PAGE_TYPE :
# Nothing to validate
return True
elif pagenum == PAGE_DETAILS :
return self . validate_details_page ( )
except Exception , e :
self . err . show_err ( _ ( " Uncaught error validating install "
" parameters: %s " ) % str ( e ) ,
" " . join ( traceback . format_exc ( ) ) )
return
def validate_details_page ( self ) :
itype = self . get_config_interface_type ( )
name = self . get_config_interface_name ( )
start = self . get_config_interface_startmode ( )
ifaces = self . get_config_selected_interfaces ( )
iclass = Interface . Interface . interface_class_for_type ( itype )
if not name :
return self . err . val_err ( _ ( " An interface name is required. " ) )
if ( itype != Interface . Interface . INTERFACE_TYPE_BRIDGE and
len ( ifaces ) == 0 ) :
return self . err . val_err ( _ ( " An interface must be selected " ) )
try :
iobj = iclass ( name , self . conn . vmm )
iobj . start_mode = start
check_conflict = False
# Pull info from selected interfaces
if hasattr ( iobj , " interfaces " ) :
iobj . interfaces = map ( lambda x : x [ INTERFACE_ROW_KEY ] , ifaces )
check_conflict = True
elif hasattr ( iobj , " parent_interface " ) :
iobj . parent_interface = ifaces [ 0 ] [ INTERFACE_ROW_KEY ]
elif itype == Interface . Interface . INTERFACE_TYPE_ETHERNET :
iobj . macaddr = ifaces [ 0 ] [ INTERFACE_ROW_MAC ]
# Warn about defined interfaces
defined_ifaces = " "
if check_conflict :
for row in ifaces :
if not row [ INTERFACE_ROW_IS_DEFINED ] :
continue
if defined_ifaces :
defined_ifaces + = " , "
defined_ifaces + = row [ INTERFACE_ROW_NAME ]
if defined_ifaces :
ret = self . err . yes_no (
_ ( " The following interface(s) are already "
" configured: \n \n %s \n \n Using these may overwrite "
" their existing configuration. Are you sure you "
" want to use the selected interface(s)? " ) %
defined_ifaces )
if not ret :
return ret
2010-02-27 02:49:18 +03:00
# Validate IP info (get_config validates for us)
( is_manual , copy_name , ipv4 ,
ipv6 , proto_xml ) = self . get_config_ip_info ( )
if is_manual :
protos = [ ]
if ipv4 :
protos . append ( ipv4 )
if ipv6 :
protos . append ( ipv6 )
iobj . protocols = protos
else :
iobj . protocol_xml = proto_xml
2010-02-09 01:18:06 +03:00
if itype == Interface . Interface . INTERFACE_TYPE_BRIDGE :
ret = self . validate_bridge ( iobj , ifaces )
elif itype == Interface . Interface . INTERFACE_TYPE_BOND :
ret = self . validate_bond ( iobj , ifaces )
elif itype == Interface . Interface . INTERFACE_TYPE_VLAN :
ret = self . validate_vlan ( iobj , ifaces )
elif itype == Interface . Interface . INTERFACE_TYPE_ETHERNET :
ret = self . validate_ethernet ( iobj , ifaces )
if not ret :
return ret
iobj . get_xml_config ( )
self . interface = iobj
except Exception , e :
return self . err . val_err ( _ ( " Error setting interface parameters. " ) ,
str ( e ) )
return True
def validate_bridge ( self , iobj , ifaces ) :
delay = self . bridge_config_win . get_widget ( " bridge-delay " ) . get_value ( )
stp = self . bridge_config_win . get_widget ( " bridge-stp " ) . get_active ( )
iobj . stp = stp
iobj . delay = int ( delay )
return True
def validate_bond ( self , iobj , ifaces ) :
mode_list = self . bond_config_win . get_widget ( " bond-mode " )
model = mode_list . get_model ( )
mode = model [ mode_list . get_active ( ) ] [ 1 ]
mon_list = self . bond_config_win . get_widget ( " bond-monitor-mode " )
model = mon_list . get_model ( )
mon = model [ mon_list . get_active ( ) ] [ 1 ]
val_list = self . bond_config_win . get_widget ( " arp-validate " )
val_model = val_list . get_model ( )
arp_val = val_model [ val_list . get_active ( ) ] [ 0 ]
car_list = self . bond_config_win . get_widget ( " mii-carrier " )
car_model = car_list . get_model ( )
mii_car = car_model [ car_list . get_active ( ) ] [ 0 ]
# ARP params
arp_int = self . bond_config_win . get_widget ( " arp-interval " ) . get_value ( )
arp_tar = self . bond_config_win . get_widget ( " arp-target " ) . get_text ( )
# MII params
mii_freq = self . bond_config_win . get_widget ( " mii-frequency " ) . get_value ( )
mii_up = self . bond_config_win . get_widget ( " mii-updelay " ) . get_value ( )
mii_down = self . bond_config_win . get_widget ( " mii-downdelay " ) . get_value ( )
iobj . bond_mode = mode
iobj . monitor_mode = mon
if not mon :
# No monitor params, just return
return True
if mon == " arpmon " :
iobj . arp_validate_mode = arp_val
iobj . arp_interval = int ( arp_int )
iobj . arp_target = arp_tar or None
elif mon == " miimon " :
iobj . mii_carrier_mode = mii_car
iobj . mii_frequency = int ( mii_freq )
iobj . mii_updelay = int ( mii_up )
iobj . mii_downdelay = int ( mii_down )
return True
def validate_vlan ( self , iobj , ifaces ) :
idx = self . window . get_widget ( " vlan-tag " ) . get_value ( )
iobj . tag = int ( idx )
return True
def validate_ethernet ( self , iobj , ifaces ) :
return True
2010-02-27 02:49:18 +03:00
def validate_ip_info ( self ) :
try :
self . build_ip_info ( )
except Exception , e :
self . err . show_err ( _ ( " Error validating IP configuration: %s " ) %
str ( e ) ,
" " . join ( traceback . format_exc ( ) ) )
return False
return True
2010-02-09 01:18:06 +03:00
####################
# Dialog callbacks #
####################
def bridge_config_finish ( self , ignore1 = None , ignore2 = None ) :
self . update_bridge_desc ( )
self . bridge_config . hide ( )
return 1
def bond_config_finish ( self , ignore1 = None , ignore2 = None ) :
self . update_bond_desc ( )
self . bond_config . hide ( )
return 1
2010-02-27 02:49:18 +03:00
def ip_config_finish ( self , ignore1 = None , ignore2 = None ) :
if not self . validate_ip_info ( ) :
return
self . update_ip_desc ( )
self . ip_config . hide ( )
return 1
2010-02-09 01:18:06 +03:00
#####################
# Creation routines #
#####################
def finish ( self , src ) :
# Validate the final page
page = self . window . get_widget ( " pages " ) . get_current_page ( )
if self . validate ( page ) != True :
return False
activate = self . window . get_widget ( " interface-activate " ) . get_active ( )
# Start the install
self . topwin . set_sensitive ( False )
self . topwin . window . set_cursor ( gtk . gdk . Cursor ( gtk . gdk . WATCH ) )
2010-12-09 20:37:48 +03:00
progWin = vmmAsyncJob ( self . do_install , [ activate ] ,
2010-02-09 01:18:06 +03:00
title = _ ( " Creating virtual interface " ) ,
text = _ ( " The virtual interface is now being "
" created. " ) )
2010-12-10 17:57:42 +03:00
error , details = progWin . run ( )
2010-02-09 01:18:06 +03:00
self . topwin . set_sensitive ( True )
self . topwin . window . set_cursor ( gtk . gdk . Cursor ( gtk . gdk . TOP_LEFT_ARROW ) )
if error :
2010-12-10 17:57:42 +03:00
error = _ ( " Error creating interface: ' %s ' " ) % error
self . err . show_err ( error , error + " \n " + details )
else :
# FIXME: Hmm, shouldn't we emit a signal here rather than do this?
self . conn . tick ( noStatsUpdate = True )
self . close ( )
2010-02-09 01:18:06 +03:00
2010-12-10 17:57:42 +03:00
def do_install ( self , asyncjob , activate ) :
2010-02-09 01:18:06 +03:00
meter = vmmCreateMeter ( asyncjob )
error = None
details = None
2010-12-10 17:57:42 +03:00
self . interface . conn = util . dup_conn ( self . conn ) . vmm
2010-02-09 01:18:06 +03:00
2010-12-10 17:57:42 +03:00
self . interface . install ( meter , create = activate )
logging . debug ( " Install completed " )
2010-02-09 01:18:06 +03:00
def show_help ( self , ignore ) :
# No help available yet.
pass
2010-12-09 01:26:19 +03:00
vmmGObjectUI . type_register ( vmmCreateInterface )