2006-06-29 03:50:17 +08:00
|
|
|
#
|
2008-04-09 02:30:47 +08:00
|
|
|
# Copyright (C) 2006-2008 Red Hat, Inc.
|
2006-06-29 03:50:17 +08:00
|
|
|
# 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-21 00:12:20 +08:00
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
# MA 02110-1301 USA.
|
2006-06-29 03:50:17 +08:00
|
|
|
#
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-02-01 07:16:54 +08:00
|
|
|
import logging
|
2012-01-15 05:19:12 +08:00
|
|
|
import re
|
2012-02-01 07:16:54 +08:00
|
|
|
|
2013-04-12 05:16:33 +08:00
|
|
|
# pylint: disable=E0611
|
2012-05-14 21:24:56 +08:00
|
|
|
from gi.repository import GObject
|
|
|
|
from gi.repository import Gtk
|
|
|
|
from gi.repository import Gdk
|
|
|
|
from gi.repository import GdkPixbuf
|
2013-04-12 05:16:33 +08:00
|
|
|
# pylint: enable=E0611
|
2011-04-19 00:39:53 +08:00
|
|
|
|
2012-07-09 03:38:52 +08:00
|
|
|
from virtManager import packageutils
|
|
|
|
from virtManager import uihelpers
|
2007-09-10 10:57:24 +08:00
|
|
|
from virtManager.connection import vmmConnection
|
2010-12-09 06:26:19 +08:00
|
|
|
from virtManager.baseclass import vmmGObjectUI
|
2009-03-10 04:17:09 +08:00
|
|
|
from virtManager.delete import vmmDeleteDialog
|
2009-07-22 22:21:33 +08:00
|
|
|
from virtManager.graphwidgets import CellRendererSparkline
|
2009-01-27 00:12:43 +08:00
|
|
|
from virtManager import util as util
|
2006-07-20 23:16:07 +08:00
|
|
|
|
2013-02-17 02:54:45 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
# Number of data points for performance graphs
|
|
|
|
GRAPH_LEN = 40
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2007-08-29 05:57:25 +08:00
|
|
|
# fields in the tree model data set
|
2007-08-28 10:22:18 +08:00
|
|
|
ROW_HANDLE = 0
|
|
|
|
ROW_NAME = 1
|
2009-07-29 07:21:56 +08:00
|
|
|
ROW_MARKUP = 2
|
|
|
|
ROW_STATUS = 3
|
|
|
|
ROW_STATUS_ICON = 4
|
|
|
|
ROW_KEY = 5
|
|
|
|
ROW_HINT = 6
|
|
|
|
ROW_IS_CONN = 7
|
|
|
|
ROW_IS_CONN_CONNECTED = 8
|
|
|
|
ROW_IS_VM = 9
|
|
|
|
ROW_IS_VM_RUNNING = 10
|
2009-11-11 04:42:07 +08:00
|
|
|
ROW_COLOR = 11
|
2011-07-19 02:53:56 +08:00
|
|
|
ROW_INSPECTION_OS_ICON = 12
|
2007-08-28 10:22:18 +08:00
|
|
|
|
|
|
|
# Columns in the tree view
|
|
|
|
COL_NAME = 0
|
2011-07-12 20:49:47 +08:00
|
|
|
COL_GUEST_CPU = 1
|
|
|
|
COL_HOST_CPU = 2
|
|
|
|
COL_DISK = 3
|
|
|
|
COL_NETWORK = 4
|
2007-08-28 10:22:18 +08:00
|
|
|
|
2013-04-21 00:52:53 +08:00
|
|
|
def _style_get_prop(widget, propname):
|
|
|
|
value = GObject.Value()
|
|
|
|
value.init(GObject.TYPE_INT)
|
|
|
|
widget.style_get_property(propname, value)
|
|
|
|
return value.get_int()
|
|
|
|
|
2013-02-17 02:54:45 +08:00
|
|
|
|
|
|
|
try:
|
|
|
|
import gi
|
|
|
|
gi.check_version("3.7.4")
|
|
|
|
can_set_row_none = True
|
2013-03-11 16:21:46 +08:00
|
|
|
except (ValueError, AttributeError):
|
2013-02-17 02:54:45 +08:00
|
|
|
can_set_row_none = False
|
|
|
|
|
|
|
|
|
2013-04-21 00:52:25 +08:00
|
|
|
def _style_get_prop(widget, propname):
|
|
|
|
value = GObject.Value()
|
|
|
|
value.init(GObject.TYPE_INT)
|
|
|
|
widget.style_get_property(propname, value)
|
|
|
|
return value.get_int()
|
2009-07-27 04:15:05 +08:00
|
|
|
|
|
|
|
|
2010-12-09 06:26:19 +08:00
|
|
|
class vmmManager(vmmGObjectUI):
|
2012-05-14 21:24:56 +08:00
|
|
|
__gsignals__ = {
|
|
|
|
"action-show-connect": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
"action-show-vm": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-show-about": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
"action-show-host": (GObject.SignalFlags.RUN_FIRST, None, [str]),
|
|
|
|
"action-show-preferences": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
"action-show-create": (GObject.SignalFlags.RUN_FIRST, None, [str]),
|
|
|
|
"action-suspend-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-resume-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-run-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-shutdown-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-reset-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-reboot-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-destroy-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-save-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-migrate-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-clone-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
"manager-closed": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
"manager-opened": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
"remove-conn": (GObject.SignalFlags.RUN_FIRST, None, [str]),
|
|
|
|
"add-default-conn": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
}
|
|
|
|
|
2011-07-23 01:42:20 +08:00
|
|
|
def __init__(self):
|
2012-02-02 06:26:46 +08:00
|
|
|
vmmGObjectUI.__init__(self, "vmm-manager.ui", "vmm-manager")
|
2010-12-01 03:33:21 +08:00
|
|
|
|
2009-03-10 04:17:09 +08:00
|
|
|
self.delete_dialog = None
|
2009-07-27 04:15:05 +08:00
|
|
|
self.ignore_pause = False
|
2009-03-10 04:17:09 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
# Mapping of VM UUID -> tree model rows to
|
|
|
|
# allow O(1) access instead of O(n)
|
|
|
|
self.rows = {}
|
|
|
|
|
2009-11-29 10:00:46 +08:00
|
|
|
w, h = self.config.get_manager_window_size()
|
2010-02-24 03:18:12 +08:00
|
|
|
self.topwin.set_default_size(w or 550, h or 550)
|
2010-12-14 06:48:19 +08:00
|
|
|
self.prev_position = None
|
2009-11-29 10:00:46 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
self.vmmenu = Gtk.Menu()
|
|
|
|
self.vmmenushutdown = Gtk.Menu()
|
2009-11-29 09:49:44 +08:00
|
|
|
self.vmmenu_items = {}
|
|
|
|
self.vmmenushutdown_items = {}
|
2012-05-14 21:24:56 +08:00
|
|
|
self.connmenu = Gtk.Menu()
|
2009-11-29 09:49:44 +08:00
|
|
|
self.connmenu_items = {}
|
2011-04-13 21:27:02 +08:00
|
|
|
|
|
|
|
# There seem to be ref counting issues with calling
|
|
|
|
# list.get_column, so avoid it
|
|
|
|
self.diskcol = None
|
|
|
|
self.netcol = None
|
2011-07-12 20:49:47 +08:00
|
|
|
self.guestcpucol = None
|
|
|
|
self.hostcpucol = None
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2013-02-17 02:31:46 +08:00
|
|
|
self.builder.connect_signals({
|
2011-07-12 20:49:47 +08:00
|
|
|
"on_menu_view_guest_cpu_usage_activate":
|
2012-05-14 21:24:56 +08:00
|
|
|
self.toggle_stats_visible_guest_cpu,
|
2011-07-12 20:49:47 +08:00
|
|
|
"on_menu_view_host_cpu_usage_activate":
|
2012-05-14 21:24:56 +08:00
|
|
|
self.toggle_stats_visible_host_cpu,
|
2011-07-12 20:49:47 +08:00
|
|
|
"on_menu_view_disk_io_activate" :
|
2012-05-14 21:24:56 +08:00
|
|
|
self.toggle_stats_visible_disk,
|
2011-07-12 20:49:47 +08:00
|
|
|
"on_menu_view_network_traffic_activate":
|
2012-05-14 21:24:56 +08:00
|
|
|
self.toggle_stats_visible_network,
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
"on_vm_manager_delete_event": self.close,
|
2009-11-29 10:00:46 +08:00
|
|
|
"on_vmm_manager_configure_event": self.window_resized,
|
2011-07-23 04:43:26 +08:00
|
|
|
"on_menu_file_add_connection_activate": self.new_conn,
|
2009-11-29 09:49:44 +08:00
|
|
|
"on_menu_file_quit_activate": self.exit_app,
|
|
|
|
"on_menu_file_close_activate": self.close,
|
|
|
|
"on_vmm_close_clicked": self.close,
|
2011-06-09 04:33:20 +08:00
|
|
|
"on_vm_open_clicked": self.show_vm,
|
2009-11-29 09:49:44 +08:00
|
|
|
"on_vm_run_clicked": self.start_vm,
|
|
|
|
"on_vm_new_clicked": self.new_vm,
|
|
|
|
"on_vm_shutdown_clicked": self.poweroff_vm,
|
|
|
|
"on_vm_pause_clicked": self.pause_vm_button,
|
2011-06-09 04:33:20 +08:00
|
|
|
"on_menu_edit_details_activate": self.show_vm,
|
2009-11-29 09:49:44 +08:00
|
|
|
"on_menu_edit_delete_activate": self.do_delete,
|
|
|
|
"on_menu_host_details_activate": self.show_host,
|
|
|
|
|
2011-06-09 04:33:20 +08:00
|
|
|
"on_vm_list_row_activated": self.show_vm,
|
2009-11-29 09:49:44 +08:00
|
|
|
"on_vm_list_button_press_event": self.popup_vm_menu_button,
|
|
|
|
"on_vm_list_key_press_event": self.popup_vm_menu_key,
|
|
|
|
|
|
|
|
"on_menu_edit_preferences_activate": self.show_preferences,
|
|
|
|
"on_menu_help_about_activate": self.show_about,
|
2011-04-13 21:27:02 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
self.init_vmlist()
|
|
|
|
self.init_stats()
|
|
|
|
self.init_toolbar()
|
|
|
|
self.init_context_menus()
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
self.vm_selected()
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-list").get_selection().connect("changed",
|
|
|
|
self.vm_selected)
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2011-07-26 03:09:42 +08:00
|
|
|
self.max_disk_rate = 10.0
|
|
|
|
self.max_net_rate = 10.0
|
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
# Initialize stat polling columns based on global polling
|
|
|
|
# preferences (we want signal handlers for this)
|
2013-04-18 05:39:25 +08:00
|
|
|
self.enable_polling(COL_DISK)
|
|
|
|
self.enable_polling(COL_NETWORK)
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
# Select first list entry
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2010-03-04 05:58:50 +08:00
|
|
|
if len(vmlist.get_model()) != 0:
|
|
|
|
vmlist.get_selection().select_iter(
|
|
|
|
vmlist.get_model().get_iter_first())
|
|
|
|
|
|
|
|
# Queue up the default connection detector
|
2011-07-23 04:43:26 +08:00
|
|
|
self.idle_emit("add-default-conn")
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
##################
|
|
|
|
# Common methods #
|
|
|
|
##################
|
|
|
|
|
|
|
|
def show(self):
|
2012-02-01 07:16:54 +08:00
|
|
|
logging.debug("Showing manager")
|
2010-12-09 06:26:19 +08:00
|
|
|
vis = self.is_visible()
|
2010-02-24 03:18:12 +08:00
|
|
|
self.topwin.present()
|
2010-12-09 06:26:19 +08:00
|
|
|
if vis:
|
|
|
|
return
|
2010-02-24 03:18:12 +08:00
|
|
|
|
2010-12-14 06:48:19 +08:00
|
|
|
if self.prev_position:
|
|
|
|
self.topwin.move(*self.prev_position)
|
|
|
|
self.prev_position = None
|
2011-04-13 22:47:31 +08:00
|
|
|
|
|
|
|
self.emit("manager-opened")
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def close(self, src_ignore=None, src2_ignore=None):
|
2012-02-01 07:16:54 +08:00
|
|
|
logging.debug("Closing manager")
|
2010-12-09 06:26:19 +08:00
|
|
|
if not self.is_visible():
|
|
|
|
return
|
|
|
|
|
2010-12-14 06:48:19 +08:00
|
|
|
self.prev_position = self.topwin.get_position()
|
2010-12-09 06:26:19 +08:00
|
|
|
self.topwin.hide()
|
2011-04-13 22:47:31 +08:00
|
|
|
self.emit("manager-closed")
|
|
|
|
|
2010-12-09 06:26:19 +08:00
|
|
|
return 1
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2011-07-24 09:16:54 +08:00
|
|
|
def _cleanup(self):
|
|
|
|
self.rows = None
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2011-07-24 09:16:54 +08:00
|
|
|
self.diskcol = None
|
|
|
|
self.guestcpucol = None
|
|
|
|
self.hostcpucol = None
|
|
|
|
self.netcol = None
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2011-07-24 09:16:54 +08:00
|
|
|
if self.delete_dialog:
|
|
|
|
self.delete_dialog.cleanup()
|
|
|
|
self.delete_dialog = None
|
|
|
|
|
|
|
|
self.vmmenu.destroy()
|
|
|
|
self.vmmenu = None
|
|
|
|
self.vmmenu_items = None
|
|
|
|
self.vmmenushutdown.destroy()
|
|
|
|
self.vmmenushutdown = None
|
|
|
|
self.vmmenushutdown_items = None
|
|
|
|
self.connmenu.destroy()
|
|
|
|
self.connmenu = None
|
|
|
|
self.connmenu_items = None
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
def is_visible(self):
|
2012-05-14 21:24:56 +08:00
|
|
|
return bool(self.topwin.get_visible())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2010-03-03 09:35:54 +08:00
|
|
|
def set_startup_error(self, msg):
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-notebook").set_current_page(1)
|
|
|
|
self.widget("startup-error-label").set_text(msg)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
################
|
|
|
|
# Init methods #
|
|
|
|
################
|
|
|
|
|
|
|
|
def init_stats(self):
|
2011-04-13 21:27:02 +08:00
|
|
|
self.add_gconf_handle(
|
2011-07-12 20:49:47 +08:00
|
|
|
self.config.on_vmlist_guest_cpu_usage_visible_changed(
|
|
|
|
self.toggle_guest_cpu_usage_visible_widget))
|
|
|
|
self.add_gconf_handle(
|
|
|
|
self.config.on_vmlist_host_cpu_usage_visible_changed(
|
|
|
|
self.toggle_host_cpu_usage_visible_widget))
|
2011-04-13 21:27:02 +08:00
|
|
|
self.add_gconf_handle(
|
|
|
|
self.config.on_vmlist_disk_io_visible_changed(
|
2011-07-12 20:49:47 +08:00
|
|
|
self.toggle_disk_io_visible_widget))
|
2011-04-13 21:27:02 +08:00
|
|
|
self.add_gconf_handle(
|
|
|
|
self.config.on_vmlist_network_traffic_visible_changed(
|
|
|
|
self.toggle_network_traffic_visible_widget))
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2008-12-18 04:27:06 +08:00
|
|
|
# Register callbacks with the global stats enable/disable values
|
|
|
|
# that disable the associated vmlist widgets if reporting is disabled
|
2011-04-13 21:27:02 +08:00
|
|
|
self.add_gconf_handle(
|
|
|
|
self.config.on_stats_enable_disk_poll_changed(self.enable_polling,
|
2011-07-12 20:49:47 +08:00
|
|
|
COL_DISK))
|
2011-04-13 21:27:02 +08:00
|
|
|
self.add_gconf_handle(
|
|
|
|
self.config.on_stats_enable_net_poll_changed(self.enable_polling,
|
2011-07-12 20:49:47 +08:00
|
|
|
COL_NETWORK))
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2008-12-18 04:27:06 +08:00
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("menu_view_stats_guest_cpu").set_active(
|
2011-07-12 20:49:47 +08:00
|
|
|
self.config.is_vmlist_guest_cpu_usage_visible())
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("menu_view_stats_host_cpu").set_active(
|
2011-07-12 20:49:47 +08:00
|
|
|
self.config.is_vmlist_host_cpu_usage_visible())
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("menu_view_stats_disk").set_active(
|
2009-11-29 09:49:44 +08:00
|
|
|
self.config.is_vmlist_disk_io_visible())
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("menu_view_stats_network").set_active(
|
2009-11-29 09:49:44 +08:00
|
|
|
self.config.is_vmlist_network_traffic_visible())
|
2009-11-12 00:02:57 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
def init_toolbar(self):
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-new").set_icon_name("vm_new")
|
|
|
|
self.widget("vm-open").set_icon_name("icon_console")
|
|
|
|
uihelpers.build_shutdown_button_menu(self.widget("vm-shutdown"),
|
|
|
|
self.poweroff_vm,
|
|
|
|
self.reboot_vm,
|
2013-03-17 05:59:32 +08:00
|
|
|
self.reset_vm,
|
2011-07-15 01:13:13 +08:00
|
|
|
self.destroy_vm,
|
|
|
|
self.save_vm)
|
|
|
|
|
|
|
|
tool = self.widget("vm-toolbar")
|
2012-05-14 21:24:56 +08:00
|
|
|
tool.set_property("icon-size", Gtk.IconSize.LARGE_TOOLBAR)
|
2009-11-11 01:57:28 +08:00
|
|
|
for c in tool.get_children():
|
2009-07-27 04:25:01 +08:00
|
|
|
c.set_homogeneous(False)
|
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
def init_context_menus(self):
|
2009-11-18 05:20:23 +08:00
|
|
|
def build_icon(name):
|
2012-05-14 21:24:56 +08:00
|
|
|
return Gtk.Image.new_from_icon_name(name, Gtk.IconSize.MENU)
|
2009-11-18 05:20:23 +08:00
|
|
|
|
|
|
|
def build_stock(name):
|
2012-05-14 21:24:56 +08:00
|
|
|
return Gtk.Image.new_from_stock(name, Gtk.IconSize.MENU)
|
2009-11-18 05:20:23 +08:00
|
|
|
|
2013-01-14 03:41:25 +08:00
|
|
|
shutdownmenu_icon = build_icon("system-shutdown")
|
|
|
|
reboot_icon = build_icon("system-shutdown")
|
|
|
|
shutdown_icon = build_icon("system-shutdown")
|
|
|
|
destroy_icon = build_icon("system-shutdown")
|
|
|
|
reset_icon = build_icon("system-shutdown")
|
2012-05-14 21:24:56 +08:00
|
|
|
run_icon = build_stock(Gtk.STOCK_MEDIA_PLAY)
|
|
|
|
pause_icon = build_stock(Gtk.STOCK_MEDIA_PAUSE)
|
|
|
|
save_icon = build_stock(Gtk.STOCK_SAVE)
|
|
|
|
resume_icon = build_stock(Gtk.STOCK_MEDIA_PAUSE)
|
|
|
|
delete_icon = build_stock(Gtk.STOCK_DELETE)
|
2007-03-09 03:39:22 +08:00
|
|
|
|
2010-05-13 03:31:36 +08:00
|
|
|
def add_to_menu(menu, items, idx, text, icon, cb):
|
2012-05-14 21:24:56 +08:00
|
|
|
if text[0:3] == 'gtk':
|
|
|
|
item = Gtk.ImageMenuItem.new_from_stock(text, None)
|
|
|
|
else:
|
|
|
|
item = Gtk.ImageMenuItem.new_with_mnemonic(text)
|
2010-05-13 03:31:36 +08:00
|
|
|
if icon:
|
|
|
|
item.set_image(icon)
|
|
|
|
item.show()
|
|
|
|
if cb:
|
|
|
|
item.connect("activate", cb)
|
|
|
|
menu.add(item)
|
|
|
|
items[idx] = item
|
|
|
|
|
|
|
|
def add_vm_menu(idx, text, icon, cb):
|
|
|
|
add_to_menu(self.vmmenu, self.vmmenu_items, idx, text, icon, cb)
|
|
|
|
def add_shutdown_menu(idx, text, icon, cb):
|
|
|
|
add_to_menu(self.vmmenushutdown, self.vmmenushutdown_items,
|
|
|
|
idx, text, icon, cb)
|
|
|
|
def add_conn_menu(idx, text, icon, cb):
|
|
|
|
add_to_menu(self.connmenu, self.connmenu_items,
|
|
|
|
idx, text, icon, cb)
|
|
|
|
def add_sep(menu, items, idx):
|
2012-05-14 21:24:56 +08:00
|
|
|
sep = Gtk.SeparatorMenuItem()
|
2010-05-13 03:31:36 +08:00
|
|
|
sep.show()
|
|
|
|
menu.add(sep)
|
|
|
|
items[idx] = sep
|
|
|
|
|
|
|
|
# Build VM context menu
|
|
|
|
add_vm_menu("run", _("_Run"), run_icon, self.start_vm)
|
|
|
|
add_vm_menu("pause", _("_Pause"), pause_icon, self.pause_vm)
|
|
|
|
add_vm_menu("resume", _("R_esume"), resume_icon, self.resume_vm)
|
|
|
|
|
|
|
|
add_vm_menu("shutdown", _("_Shut Down"), shutdownmenu_icon, None)
|
2008-05-14 03:59:25 +08:00
|
|
|
self.vmmenu_items["shutdown"].set_submenu(self.vmmenushutdown)
|
2010-05-13 03:31:36 +08:00
|
|
|
add_shutdown_menu("reboot", _("_Reboot"), reboot_icon, self.reboot_vm)
|
|
|
|
add_shutdown_menu("poweroff", _("_Shut Down"), shutdown_icon,
|
|
|
|
self.poweroff_vm)
|
2013-03-17 05:59:32 +08:00
|
|
|
add_shutdown_menu("forcereset", _("_Force Reset"), reset_icon,
|
|
|
|
self.reset_vm)
|
2010-05-13 03:31:36 +08:00
|
|
|
add_shutdown_menu("forcepoweroff", _("_Force Off"), destroy_icon,
|
|
|
|
self.destroy_vm)
|
|
|
|
add_sep(self.vmmenushutdown, self.vmmenushutdown_items, "sep")
|
|
|
|
add_shutdown_menu("save", _("Sa_ve"), save_icon, self.save_vm)
|
|
|
|
|
|
|
|
add_sep(self.vmmenu, self.vmmenu_items, "hsep1")
|
|
|
|
add_vm_menu("clone", _("_Clone..."), None, self.open_clone_window)
|
|
|
|
add_vm_menu("migrate", _("_Migrate..."), None, self.migrate_vm)
|
|
|
|
add_vm_menu("delete", _("_Delete"), delete_icon, self.do_delete)
|
|
|
|
|
|
|
|
add_sep(self.vmmenu, self.vmmenu_items, "hsep2")
|
2012-05-14 21:24:56 +08:00
|
|
|
add_vm_menu("open", Gtk.STOCK_OPEN, None, self.show_vm)
|
2007-03-09 03:39:22 +08:00
|
|
|
self.vmmenu.show()
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2010-05-13 03:31:36 +08:00
|
|
|
# Build connection context menu
|
2012-05-14 21:24:56 +08:00
|
|
|
add_conn_menu("create", Gtk.STOCK_NEW, None, self.new_vm)
|
|
|
|
add_conn_menu("connect", Gtk.STOCK_CONNECT, None, self.open_conn)
|
|
|
|
add_conn_menu("disconnect", Gtk.STOCK_DISCONNECT, None,
|
2011-07-23 04:43:26 +08:00
|
|
|
self.close_conn)
|
2010-05-13 03:31:36 +08:00
|
|
|
add_sep(self.connmenu, self.connmenu_items, "hsep1")
|
2012-05-14 21:24:56 +08:00
|
|
|
add_conn_menu("delete", Gtk.STOCK_DELETE, None, self.do_delete)
|
2010-05-13 03:31:36 +08:00
|
|
|
add_sep(self.connmenu, self.connmenu_items, "hsep2")
|
2011-07-13 07:20:58 +08:00
|
|
|
add_conn_menu("details", _("D_etails"), None, self.show_host)
|
2007-08-14 05:13:39 +08:00
|
|
|
self.connmenu.show()
|
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
def init_vmlist(self):
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
|
|
|
self.widget("vm-notebook").set_show_tabs(False)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-07-12 23:50:11 +08:00
|
|
|
# Handle, name, markup, status, status icon name, key/uuid, hint,
|
2011-07-19 02:53:56 +08:00
|
|
|
# is conn, is conn connected, is vm, is vm running, fg color,
|
|
|
|
# inspection icon
|
2012-05-14 21:24:56 +08:00
|
|
|
model = Gtk.TreeStore(object, str, str, str, str, str, str,
|
|
|
|
bool, bool, bool, bool, Gdk.Color,
|
|
|
|
GdkPixbuf.Pixbuf)
|
2009-11-29 09:49:44 +08:00
|
|
|
vmlist.set_model(model)
|
2012-02-02 06:26:46 +08:00
|
|
|
vmlist.set_tooltip_column(ROW_HINT)
|
2009-11-29 09:49:44 +08:00
|
|
|
vmlist.set_headers_visible(True)
|
2013-04-21 00:52:53 +08:00
|
|
|
vmlist.set_level_indentation(
|
|
|
|
-(_style_get_prop(vmlist, "expander-size") + 3))
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
nameCol = Gtk.TreeViewColumn(_("Name"))
|
2009-11-29 09:49:44 +08:00
|
|
|
nameCol.set_expand(True)
|
|
|
|
nameCol.set_spacing(6)
|
2006-11-06 23:34:54 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
statusCol = nameCol
|
|
|
|
vmlist.append_column(nameCol)
|
2008-12-18 04:27:06 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
status_icon = Gtk.CellRendererPixbuf()
|
|
|
|
status_icon.set_property("stock-size", Gtk.IconSize.DND)
|
2009-11-29 09:49:44 +08:00
|
|
|
statusCol.pack_start(status_icon, False)
|
2011-07-12 23:50:11 +08:00
|
|
|
statusCol.add_attribute(status_icon, 'icon-name', ROW_STATUS_ICON)
|
2009-11-29 09:49:44 +08:00
|
|
|
statusCol.add_attribute(status_icon, 'visible', ROW_IS_VM)
|
2009-03-10 04:22:03 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
inspection_os_icon = Gtk.CellRendererPixbuf()
|
2011-07-19 02:53:56 +08:00
|
|
|
statusCol.pack_start(inspection_os_icon, False)
|
|
|
|
statusCol.add_attribute(inspection_os_icon, 'pixbuf',
|
|
|
|
ROW_INSPECTION_OS_ICON)
|
|
|
|
statusCol.add_attribute(inspection_os_icon, 'visible', ROW_IS_VM)
|
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
name_txt = Gtk.CellRendererText()
|
2009-11-29 09:49:44 +08:00
|
|
|
nameCol.pack_start(name_txt, True)
|
|
|
|
nameCol.add_attribute(name_txt, 'markup', ROW_MARKUP)
|
|
|
|
nameCol.add_attribute(name_txt, 'foreground-gdk', ROW_COLOR)
|
|
|
|
nameCol.set_sort_column_id(COL_NAME)
|
2007-09-10 10:57:24 +08:00
|
|
|
|
2011-07-12 20:49:47 +08:00
|
|
|
def make_stats_column(title, datafunc, is_visible, colnum):
|
2012-05-14 21:24:56 +08:00
|
|
|
col = Gtk.TreeViewColumn(title)
|
2011-07-12 20:49:47 +08:00
|
|
|
col.set_min_width(140)
|
2012-05-14 21:24:56 +08:00
|
|
|
txt = Gtk.CellRendererText()
|
2013-04-21 01:43:21 +08:00
|
|
|
txt.set_property("ypad", 4)
|
2011-07-12 20:49:47 +08:00
|
|
|
img = CellRendererSparkline()
|
|
|
|
img.set_property("xpad", 6)
|
|
|
|
img.set_property("ypad", 12)
|
|
|
|
img.set_property("reversed", True)
|
|
|
|
col.pack_start(img, True)
|
2013-04-21 01:43:21 +08:00
|
|
|
col.pack_start(txt, True)
|
2011-07-12 20:49:47 +08:00
|
|
|
col.add_attribute(img, 'visible', ROW_IS_VM)
|
|
|
|
col.add_attribute(txt, 'visible', ROW_IS_CONN)
|
|
|
|
col.set_cell_data_func(img, datafunc, None)
|
|
|
|
col.set_visible(is_visible)
|
|
|
|
col.set_sort_column_id(colnum)
|
|
|
|
vmlist.append_column(col)
|
|
|
|
return col
|
|
|
|
|
|
|
|
self.guestcpucol = make_stats_column(_("CPU usage"),
|
|
|
|
self.guest_cpu_usage_img,
|
|
|
|
self.config.is_vmlist_guest_cpu_usage_visible(),
|
|
|
|
COL_GUEST_CPU)
|
|
|
|
self.hostcpucol = make_stats_column(_("Host CPU usage"),
|
|
|
|
self.host_cpu_usage_img,
|
|
|
|
self.config.is_vmlist_host_cpu_usage_visible(),
|
|
|
|
COL_HOST_CPU)
|
|
|
|
self.diskcol = make_stats_column(_("Disk I/O"),
|
|
|
|
self.disk_io_img,
|
|
|
|
self.config.is_vmlist_disk_io_visible(),
|
|
|
|
COL_DISK)
|
|
|
|
self.netcol = make_stats_column(_("Network I/O"),
|
|
|
|
self.network_traffic_img,
|
|
|
|
self.config.is_vmlist_network_traffic_visible(),
|
|
|
|
COL_NETWORK)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
model.set_sort_func(COL_NAME, self.vmlist_name_sorter)
|
2011-07-12 20:49:47 +08:00
|
|
|
model.set_sort_func(COL_GUEST_CPU, self.vmlist_guest_cpu_usage_sorter)
|
|
|
|
model.set_sort_func(COL_HOST_CPU, self.vmlist_host_cpu_usage_sorter)
|
2009-11-29 09:49:44 +08:00
|
|
|
model.set_sort_func(COL_DISK, self.vmlist_disk_io_sorter)
|
|
|
|
model.set_sort_func(COL_NETWORK, self.vmlist_network_usage_sorter)
|
2012-05-14 21:24:56 +08:00
|
|
|
model.set_sort_column_id(COL_NAME, Gtk.SortType.ASCENDING)
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
##################
|
|
|
|
# Helper methods #
|
|
|
|
##################
|
|
|
|
|
|
|
|
def current_row(self):
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2009-11-29 09:49:44 +08:00
|
|
|
selection = vmlist.get_selection()
|
|
|
|
active = selection.get_selected()
|
|
|
|
|
|
|
|
treestore, treeiter = active
|
2012-11-08 21:15:02 +08:00
|
|
|
if treeiter is not None:
|
2009-11-29 09:49:44 +08:00
|
|
|
return treestore[treeiter]
|
|
|
|
return None
|
|
|
|
|
|
|
|
def current_vm(self):
|
|
|
|
row = self.current_row()
|
|
|
|
if not row or row[ROW_IS_CONN]:
|
|
|
|
return None
|
|
|
|
|
|
|
|
return row[ROW_HANDLE]
|
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def current_conn(self):
|
2009-11-29 09:49:44 +08:00
|
|
|
row = self.current_row()
|
|
|
|
if not row:
|
|
|
|
return None
|
|
|
|
|
|
|
|
handle = row[ROW_HANDLE]
|
|
|
|
if row[ROW_IS_CONN]:
|
|
|
|
return handle
|
|
|
|
else:
|
2011-07-23 04:43:26 +08:00
|
|
|
return handle.conn
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def current_vmuuid(self):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is None:
|
|
|
|
return None
|
|
|
|
return vm.get_uuid()
|
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def current_conn_uri(self, default_selection=False):
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2010-08-23 00:50:31 +08:00
|
|
|
model = vmlist.get_model()
|
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
conn = self.current_conn()
|
2010-08-23 00:50:31 +08:00
|
|
|
if conn is None and default_selection:
|
|
|
|
# Nothing selected, use first connection row
|
|
|
|
for row in model:
|
|
|
|
if row[ROW_IS_CONN]:
|
|
|
|
conn = row[ROW_HANDLE]
|
|
|
|
break
|
|
|
|
|
|
|
|
if conn:
|
|
|
|
return conn.get_uri()
|
|
|
|
return None
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
####################
|
|
|
|
# Action listeners #
|
|
|
|
####################
|
2006-11-03 23:02:02 +08:00
|
|
|
|
2009-11-29 10:00:46 +08:00
|
|
|
def window_resized(self, ignore, event):
|
|
|
|
# Sometimes dimensions change when window isn't visible
|
|
|
|
if not self.is_visible():
|
|
|
|
return
|
|
|
|
|
|
|
|
self.config.set_manager_window_size(event.width, event.height)
|
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def exit_app(self, src_ignore=None, src2_ignore=None):
|
2008-06-14 02:40:26 +08:00
|
|
|
self.emit("action-exit-app")
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def new_conn(self, src_ignore=None):
|
2006-06-28 02:16:13 +08:00
|
|
|
self.emit("action-show-connect")
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def new_vm(self, src_ignore=None):
|
2011-07-23 04:43:26 +08:00
|
|
|
self.emit("action-show-create", self.current_conn_uri())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def show_about(self, src_ignore):
|
2009-11-29 09:49:44 +08:00
|
|
|
self.emit("action-show-about")
|
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def show_preferences(self, src_ignore):
|
2009-11-29 09:49:44 +08:00
|
|
|
self.emit("action-show-preferences")
|
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def show_host(self, src_ignore):
|
2011-07-23 04:43:26 +08:00
|
|
|
uri = self.current_conn_uri(default_selection=True)
|
2010-08-23 00:50:31 +08:00
|
|
|
self.emit("action-show-host", uri)
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2011-06-09 04:33:20 +08:00
|
|
|
def show_vm(self, ignore, ignore2=None, ignore3=None):
|
2011-07-23 04:43:26 +08:00
|
|
|
conn = self.current_conn()
|
2011-06-09 04:33:20 +08:00
|
|
|
vm = self.current_vm()
|
|
|
|
if conn is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
if vm:
|
|
|
|
self.emit("action-show-vm", conn.get_uri(), vm.get_uuid())
|
|
|
|
else:
|
2011-07-23 04:43:26 +08:00
|
|
|
if not self.open_conn():
|
2011-06-09 04:33:20 +08:00
|
|
|
self.emit("action-show-host", conn.get_uri())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def open_clone_window(self, ignore1=None, ignore2=None, ignore3=None):
|
|
|
|
if self.current_vmuuid():
|
2011-07-23 04:43:26 +08:00
|
|
|
self.emit("action-clone-domain", self.current_conn_uri(),
|
2009-11-29 09:49:44 +08:00
|
|
|
self.current_vmuuid())
|
|
|
|
|
|
|
|
def do_delete(self, ignore=None):
|
2011-07-23 04:43:26 +08:00
|
|
|
conn = self.current_conn()
|
2009-11-29 09:49:44 +08:00
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is None:
|
2011-07-23 04:43:26 +08:00
|
|
|
self._do_delete_conn(conn)
|
2009-11-29 09:49:44 +08:00
|
|
|
else:
|
|
|
|
self._do_delete_vm(vm)
|
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def _do_delete_conn(self, conn):
|
2009-11-29 09:49:44 +08:00
|
|
|
if conn is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
result = self.err.yes_no(_("This will remove the connection:\n\n%s\n\n"
|
|
|
|
"Are you sure?") % conn.get_uri())
|
|
|
|
if not result:
|
|
|
|
return
|
2011-07-23 01:42:20 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
self.emit("remove-conn", conn.get_uri())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def _do_delete_vm(self, vm):
|
|
|
|
if vm.is_active():
|
|
|
|
return
|
|
|
|
|
|
|
|
if not self.delete_dialog:
|
2011-04-12 04:14:23 +08:00
|
|
|
self.delete_dialog = vmmDeleteDialog()
|
2011-04-14 20:47:42 +08:00
|
|
|
self.delete_dialog.show(vm, self.topwin)
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def set_pause_state(self, state):
|
2011-07-15 01:13:13 +08:00
|
|
|
src = self.widget("vm-pause")
|
2009-11-29 09:49:44 +08:00
|
|
|
try:
|
|
|
|
self.ignore_pause = True
|
|
|
|
src.set_active(state)
|
|
|
|
finally:
|
|
|
|
self.ignore_pause = False
|
|
|
|
|
|
|
|
def pause_vm_button(self, src):
|
|
|
|
if self.ignore_pause:
|
|
|
|
return
|
|
|
|
|
|
|
|
do_pause = src.get_active()
|
|
|
|
|
2011-04-16 02:49:58 +08:00
|
|
|
# Set button state back to original value: just let the status
|
|
|
|
# update function fix things for us
|
|
|
|
self.set_pause_state(not do_pause)
|
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
if do_pause:
|
|
|
|
self.pause_vm(None)
|
|
|
|
else:
|
|
|
|
self.resume_vm(None)
|
|
|
|
|
|
|
|
def start_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-run-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def reboot_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-reboot-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def poweroff_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-shutdown-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def destroy_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-destroy-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2013-03-17 05:59:32 +08:00
|
|
|
def reset_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-reset-domain",
|
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
|
|
|
|
2010-05-12 23:42:59 +08:00
|
|
|
def save_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-save-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2010-05-12 23:42:59 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
def pause_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-suspend-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def resume_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-resume-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def migrate_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-migrate-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def close_conn(self, ignore):
|
|
|
|
conn = self.current_conn()
|
2009-11-29 09:49:44 +08:00
|
|
|
if conn.get_state() != vmmConnection.STATE_DISCONNECTED:
|
|
|
|
conn.close()
|
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def open_conn(self, ignore=None):
|
|
|
|
conn = self.current_conn()
|
2009-11-29 09:49:44 +08:00
|
|
|
if conn.get_state() == vmmConnection.STATE_DISCONNECTED:
|
|
|
|
conn.open()
|
|
|
|
return True
|
|
|
|
|
2012-02-03 05:45:18 +08:00
|
|
|
def _connect_error(self, conn, errmsg, tb, warnconsole):
|
|
|
|
errmsg = errmsg.strip(" \n")
|
2012-01-28 07:31:21 +08:00
|
|
|
tb = tb.strip(" \n")
|
2012-02-03 05:45:18 +08:00
|
|
|
hint = ""
|
|
|
|
show_errmsg = True
|
|
|
|
|
|
|
|
if conn.is_remote():
|
|
|
|
logging.debug(conn.get_transport())
|
|
|
|
if re.search(r"nc: .* -- 'U'", tb):
|
|
|
|
hint += _("The remote host requires a version of netcat/nc\n"
|
|
|
|
"which supports the -U option.")
|
|
|
|
show_errmsg = False
|
2012-07-09 03:38:52 +08:00
|
|
|
elif (conn.get_transport()[0] == "ssh" and
|
|
|
|
re.search(r"ssh-askpass", tb)):
|
|
|
|
|
|
|
|
if self.config.askpass_package:
|
|
|
|
ret = packageutils.check_packagekit(
|
|
|
|
self.err,
|
|
|
|
self.config.askpass_package,
|
|
|
|
False)
|
|
|
|
if ret:
|
|
|
|
conn.open()
|
|
|
|
return
|
|
|
|
|
|
|
|
hint += _("You need to install openssh-askpass or "
|
|
|
|
"similar\nto connect to this host.")
|
2012-02-03 05:45:18 +08:00
|
|
|
show_errmsg = False
|
|
|
|
else:
|
|
|
|
hint += _("Verify that the 'libvirtd' daemon is running\n"
|
|
|
|
"on the remote host.")
|
2012-01-28 07:31:21 +08:00
|
|
|
|
2012-02-03 05:45:18 +08:00
|
|
|
elif conn.is_xen():
|
|
|
|
hint += _("Verify that:\n"
|
|
|
|
" - A Xen host kernel was booted\n"
|
|
|
|
" - The Xen service has been started")
|
2012-01-28 07:31:21 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
else:
|
2012-01-28 07:31:21 +08:00
|
|
|
if warnconsole:
|
2012-02-03 05:45:18 +08:00
|
|
|
hint += _("Could not detect a local session: if you are \n"
|
|
|
|
"running virt-manager over ssh -X or VNC, you \n"
|
|
|
|
"may not be able to connect to libvirt as a \n"
|
|
|
|
"regular user. Try running as root.")
|
|
|
|
show_errmsg = False
|
|
|
|
elif re.search(r"libvirt-sock", tb):
|
|
|
|
hint += _("Verify that the 'libvirtd' daemon is running.")
|
|
|
|
show_errmsg = False
|
|
|
|
|
|
|
|
msg = _("Unable to connect to libvirt.")
|
|
|
|
if show_errmsg:
|
|
|
|
msg += "\n\n%s" % errmsg
|
|
|
|
if hint:
|
|
|
|
msg += "\n\n%s" % hint
|
|
|
|
|
|
|
|
msg = msg.strip("\n")
|
|
|
|
details = msg
|
|
|
|
details += "\n\n"
|
|
|
|
details += "Libvirt URI is: %s\n\n" % conn.get_uri()
|
|
|
|
details += tb
|
|
|
|
|
|
|
|
self.err.show_err(msg, details, title=_("Virtual Machine Manager Connection Failure"))
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
|
|
|
|
####################################
|
|
|
|
# VM add/remove management methods #
|
|
|
|
####################################
|
|
|
|
|
|
|
|
def vm_row_key(self, vm):
|
2011-07-23 04:43:26 +08:00
|
|
|
return vm.get_uuid() + ":" + vm.conn.get_uri()
|
2006-07-20 23:16:07 +08:00
|
|
|
|
2011-07-23 01:54:40 +08:00
|
|
|
def vm_added(self, conn, vmuuid):
|
|
|
|
vm = conn.get_vm(vmuuid)
|
2006-10-11 05:24:59 +08:00
|
|
|
vm.connect("status-changed", self.vm_status_changed)
|
|
|
|
vm.connect("resources-sampled", self.vm_resources_sampled)
|
2011-07-16 03:38:59 +08:00
|
|
|
vm.connect("config-changed", self.vm_resources_sampled, True)
|
2011-07-19 02:53:56 +08:00
|
|
|
vm.connect("inspection-changed", self.vm_inspection_changed)
|
2006-06-15 05:52:49 +08:00
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2006-10-11 05:24:59 +08:00
|
|
|
model = vmlist.get_model()
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-07-23 01:54:40 +08:00
|
|
|
self._append_vm(model, vm, conn)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-07-23 01:54:40 +08:00
|
|
|
def vm_removed(self, conn, vmuuid):
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2009-11-29 09:49:44 +08:00
|
|
|
model = vmlist.get_model()
|
|
|
|
|
2011-07-23 01:54:40 +08:00
|
|
|
parent = self.rows[conn.get_uri()].iter
|
2009-11-29 09:49:44 +08:00
|
|
|
for row in range(model.iter_n_children(parent)):
|
|
|
|
vm = model.get_value(model.iter_nth_child(parent, row), ROW_HANDLE)
|
|
|
|
if vm.get_uuid() == vmuuid:
|
|
|
|
model.remove(model.iter_nth_child(parent, row))
|
|
|
|
del self.rows[self.vm_row_key(vm)]
|
|
|
|
break
|
|
|
|
|
2009-10-21 22:36:58 +08:00
|
|
|
def _build_conn_hint(self, conn):
|
|
|
|
hint = conn.get_uri()
|
|
|
|
if conn.state == conn.STATE_DISCONNECTED:
|
|
|
|
hint += " (%s)" % _("Double click to connect")
|
|
|
|
return hint
|
|
|
|
|
2009-09-18 00:35:41 +08:00
|
|
|
def _build_conn_markup(self, conn, row):
|
2011-08-30 00:11:43 +08:00
|
|
|
name = util.xml_escape(row[ROW_NAME])
|
|
|
|
text = name
|
2009-09-18 00:35:41 +08:00
|
|
|
if conn.state == conn.STATE_DISCONNECTED:
|
2011-08-30 00:11:43 +08:00
|
|
|
text += " - " + _("Not Connected")
|
2009-11-11 04:42:07 +08:00
|
|
|
elif conn.state == conn.STATE_CONNECTING:
|
2011-08-30 00:11:43 +08:00
|
|
|
text += " - " + _("Connecting...")
|
2010-12-02 04:22:38 +08:00
|
|
|
|
|
|
|
markup = "<span size='smaller'>%s</span>" % text
|
2009-09-18 00:35:41 +08:00
|
|
|
return markup
|
|
|
|
|
2009-11-11 04:42:07 +08:00
|
|
|
def _build_conn_color(self, conn):
|
2012-05-14 21:24:56 +08:00
|
|
|
color = Gdk.Color(0, 0, 0)
|
2011-07-13 09:32:56 +08:00
|
|
|
if conn.state == conn.STATE_DISCONNECTED:
|
2009-12-03 23:21:39 +08:00
|
|
|
# Color code #5b5b5b
|
2012-05-14 21:24:56 +08:00
|
|
|
color = Gdk.Color(23296, 23296, 23296)
|
2009-11-11 04:42:07 +08:00
|
|
|
return color
|
|
|
|
|
2011-07-16 03:38:59 +08:00
|
|
|
def _build_vm_markup(self, row):
|
2010-12-02 04:22:38 +08:00
|
|
|
domtext = ("<span size='smaller' weight='bold'>%s</span>" %
|
2011-08-30 00:11:43 +08:00
|
|
|
util.xml_escape(row[ROW_NAME]))
|
2010-12-02 04:22:38 +08:00
|
|
|
statetext = "<span size='smaller'>%s</span>" % row[ROW_STATUS]
|
|
|
|
return domtext + "\n" + statetext
|
2009-09-18 00:35:41 +08:00
|
|
|
|
2011-03-24 04:56:12 +08:00
|
|
|
def _build_vm_row(self, vm):
|
2007-08-28 10:22:18 +08:00
|
|
|
row = []
|
2011-09-26 23:05:55 +08:00
|
|
|
|
2007-08-28 10:22:18 +08:00
|
|
|
row.insert(ROW_HANDLE, vm)
|
|
|
|
row.insert(ROW_NAME, vm.get_name())
|
2009-09-18 00:35:41 +08:00
|
|
|
row.insert(ROW_MARKUP, "")
|
2007-08-28 10:22:18 +08:00
|
|
|
row.insert(ROW_STATUS, vm.run_status())
|
2011-07-12 23:50:11 +08:00
|
|
|
row.insert(ROW_STATUS_ICON, vm.run_status_icon_name())
|
2007-08-28 10:22:18 +08:00
|
|
|
row.insert(ROW_KEY, vm.get_uuid())
|
2012-01-18 04:31:20 +08:00
|
|
|
row.insert(ROW_HINT, util.xml_escape(vm.get_description()))
|
2009-07-29 07:21:56 +08:00
|
|
|
row.insert(ROW_IS_CONN, False)
|
|
|
|
row.insert(ROW_IS_CONN_CONNECTED, True)
|
2009-07-27 04:25:01 +08:00
|
|
|
row.insert(ROW_IS_VM, True)
|
|
|
|
row.insert(ROW_IS_VM_RUNNING, vm.is_active())
|
2011-07-13 09:32:56 +08:00
|
|
|
row.insert(ROW_COLOR, None)
|
2011-07-19 02:53:56 +08:00
|
|
|
row.insert(ROW_INSPECTION_OS_ICON,
|
|
|
|
self.get_inspection_icon_pixbuf(vm, 16, 16))
|
2008-03-24 23:57:48 +08:00
|
|
|
|
2011-07-16 03:38:59 +08:00
|
|
|
row[ROW_MARKUP] = self._build_vm_markup(row)
|
2009-09-18 00:35:41 +08:00
|
|
|
|
2011-03-24 04:56:12 +08:00
|
|
|
return row
|
|
|
|
|
|
|
|
def _append_vm(self, model, vm, conn):
|
|
|
|
row_key = self.vm_row_key(vm)
|
|
|
|
if row_key in self.rows:
|
|
|
|
return
|
|
|
|
|
|
|
|
row = self._build_vm_row(vm)
|
|
|
|
parent = self.rows[conn.get_uri()].iter
|
|
|
|
|
2008-11-19 04:42:51 +08:00
|
|
|
_iter = model.append(parent, row)
|
|
|
|
path = model.get_path(_iter)
|
2009-11-19 02:51:36 +08:00
|
|
|
self.rows[row_key] = model[path]
|
2011-03-24 04:56:12 +08:00
|
|
|
|
2007-08-15 00:31:24 +08:00
|
|
|
# Expand a connection when adding a vm to it
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-list").expand_row(model.get_path(parent), False)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2013-04-21 01:43:52 +08:00
|
|
|
def _build_conn_row(self, conn):
|
2007-08-28 10:22:18 +08:00
|
|
|
row = []
|
2007-09-10 10:57:24 +08:00
|
|
|
row.insert(ROW_HANDLE, conn)
|
2009-07-29 07:21:56 +08:00
|
|
|
row.insert(ROW_NAME, conn.get_pretty_desc_inactive(False))
|
2009-09-18 00:35:41 +08:00
|
|
|
row.insert(ROW_MARKUP, self._build_conn_markup(conn, row))
|
2010-12-02 04:22:38 +08:00
|
|
|
row.insert(ROW_STATUS, ("<span size='smaller'>%s</span>" %
|
2009-07-29 07:21:56 +08:00
|
|
|
conn.get_state_text()))
|
2007-08-28 10:22:18 +08:00
|
|
|
row.insert(ROW_STATUS_ICON, None)
|
2007-09-10 10:57:24 +08:00
|
|
|
row.insert(ROW_KEY, conn.get_uri())
|
2009-10-21 22:36:58 +08:00
|
|
|
row.insert(ROW_HINT, self._build_conn_hint(conn))
|
2009-07-29 07:21:56 +08:00
|
|
|
row.insert(ROW_IS_CONN, True)
|
|
|
|
row.insert(ROW_IS_CONN_CONNECTED,
|
|
|
|
conn.state != conn.STATE_DISCONNECTED)
|
2009-07-27 04:25:01 +08:00
|
|
|
row.insert(ROW_IS_VM, False)
|
|
|
|
row.insert(ROW_IS_VM_RUNNING, False)
|
2009-11-11 04:42:07 +08:00
|
|
|
row.insert(ROW_COLOR, self._build_conn_color(conn))
|
2011-07-19 02:53:56 +08:00
|
|
|
row.insert(ROW_INSPECTION_OS_ICON, None)
|
2008-03-24 23:57:48 +08:00
|
|
|
|
2013-04-21 01:43:52 +08:00
|
|
|
return row
|
|
|
|
|
|
|
|
def _append_conn(self, model, conn):
|
|
|
|
row = self._build_conn_row(conn)
|
|
|
|
|
2008-11-19 04:42:51 +08:00
|
|
|
_iter = model.append(None, row)
|
|
|
|
path = model.get_path(_iter)
|
2007-09-10 10:57:24 +08:00
|
|
|
self.rows[conn.get_uri()] = model[path]
|
2009-02-16 06:36:36 +08:00
|
|
|
return _iter
|
2007-08-10 04:19:41 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def add_conn(self, engine_ignore, conn):
|
2010-03-03 09:35:54 +08:00
|
|
|
# Make sure error page isn't showing
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-notebook").set_current_page(0)
|
2010-03-03 09:35:54 +08:00
|
|
|
|
2010-12-11 00:47:07 +08:00
|
|
|
if conn.get_uri() in self.rows:
|
2009-11-29 09:49:44 +08:00
|
|
|
return
|
|
|
|
|
|
|
|
conn.connect("vm-added", self.vm_added)
|
|
|
|
conn.connect("vm-removed", self.vm_removed)
|
2011-07-26 03:09:42 +08:00
|
|
|
conn.connect("resources-sampled", self.conn_resources_sampled)
|
2009-11-29 09:49:44 +08:00
|
|
|
conn.connect("state-changed", self.conn_state_changed)
|
|
|
|
conn.connect("connect-error", self._connect_error)
|
|
|
|
|
|
|
|
# add the connection to the treeModel
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2011-07-23 04:43:26 +08:00
|
|
|
row = self._append_conn(vmlist.get_model(), conn)
|
2009-11-29 09:49:44 +08:00
|
|
|
vmlist.get_selection().select_iter(row)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2010-12-12 12:51:20 +08:00
|
|
|
# Try to make sure that 2 row descriptions don't collide
|
|
|
|
connrows = []
|
|
|
|
descs = []
|
|
|
|
for row in self.rows.values():
|
|
|
|
if row[ROW_IS_CONN]:
|
|
|
|
connrows.append(row)
|
|
|
|
for row in connrows:
|
|
|
|
descs.append(row[ROW_NAME])
|
|
|
|
|
|
|
|
for row in connrows:
|
|
|
|
conn = row[ROW_HANDLE]
|
|
|
|
name = row[ROW_NAME]
|
|
|
|
if descs.count(name) <= 1:
|
|
|
|
continue
|
|
|
|
|
|
|
|
newname = conn.get_pretty_desc_inactive(False, True)
|
2011-07-26 03:09:42 +08:00
|
|
|
self.conn_resources_sampled(conn, newname)
|
2010-12-12 12:51:20 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def remove_conn(self, engine_ignore, uri):
|
2011-07-15 01:13:13 +08:00
|
|
|
model = self.widget("vm-list").get_model()
|
2011-04-12 23:50:10 +08:00
|
|
|
parent = self.rows[uri].iter
|
|
|
|
|
|
|
|
if parent is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
child = model.iter_children(parent)
|
|
|
|
while child is not None:
|
|
|
|
del self.rows[self.vm_row_key(model.get_value(child, ROW_HANDLE))]
|
|
|
|
model.remove(child)
|
2009-11-29 09:49:44 +08:00
|
|
|
child = model.iter_children(parent)
|
2011-04-12 23:50:10 +08:00
|
|
|
model.remove(parent)
|
|
|
|
|
|
|
|
del self.rows[uri]
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
|
|
|
|
#############################
|
|
|
|
# State/UI updating methods #
|
|
|
|
#############################
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-04-16 02:13:05 +08:00
|
|
|
def vm_status_changed(self, vm, oldstatus, newstatus):
|
|
|
|
ignore = newstatus
|
2011-04-16 02:43:52 +08:00
|
|
|
ignore = oldstatus
|
2011-07-23 04:43:26 +08:00
|
|
|
parent = self.rows[vm.conn.get_uri()].iter
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2006-10-11 05:24:59 +08:00
|
|
|
model = vmlist.get_model()
|
|
|
|
|
|
|
|
missing = True
|
2007-08-10 04:19:41 +08:00
|
|
|
for row in range(model.iter_n_children(parent)):
|
2008-11-19 04:42:51 +08:00
|
|
|
_iter = model.iter_nth_child(parent, row)
|
|
|
|
if model.get_value(_iter, ROW_KEY) == vm.get_uuid():
|
2009-07-27 04:12:39 +08:00
|
|
|
missing = False
|
2006-10-11 05:24:59 +08:00
|
|
|
break
|
|
|
|
|
2009-07-27 04:12:39 +08:00
|
|
|
if missing:
|
2011-07-23 04:43:26 +08:00
|
|
|
self._append_vm(model, vm, vm.conn)
|
2006-06-15 06:42:04 +08:00
|
|
|
|
2009-07-27 04:15:05 +08:00
|
|
|
# Update run/shutdown/pause button states
|
|
|
|
self.vm_selected()
|
2011-04-16 02:14:12 +08:00
|
|
|
self.vm_resources_sampled(vm)
|
2006-06-15 06:42:04 +08:00
|
|
|
|
2011-07-16 03:38:59 +08:00
|
|
|
def vm_resources_sampled(self, vm, config_changed=False):
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2006-06-14 22:59:40 +08:00
|
|
|
model = vmlist.get_model()
|
|
|
|
|
2010-12-11 00:47:07 +08:00
|
|
|
if self.vm_row_key(vm) not in self.rows:
|
2006-11-14 04:38:10 +08:00
|
|
|
return
|
|
|
|
|
2008-10-23 23:45:27 +08:00
|
|
|
row = self.rows[self.vm_row_key(vm)]
|
2011-03-24 04:56:12 +08:00
|
|
|
row[ROW_NAME] = vm.get_name()
|
2007-08-28 10:22:18 +08:00
|
|
|
row[ROW_STATUS] = vm.run_status()
|
2011-07-12 23:50:11 +08:00
|
|
|
row[ROW_STATUS_ICON] = vm.run_status_icon_name()
|
2009-07-27 04:25:01 +08:00
|
|
|
row[ROW_IS_VM_RUNNING] = vm.is_active()
|
2011-07-16 03:38:59 +08:00
|
|
|
row[ROW_MARKUP] = self._build_vm_markup(row)
|
|
|
|
|
|
|
|
if config_changed:
|
2013-02-17 02:54:45 +08:00
|
|
|
desc = vm.get_description()
|
|
|
|
if not can_set_row_none:
|
|
|
|
desc = desc or ""
|
|
|
|
row[ROW_HINT] = util.xml_escape(desc)
|
2011-07-16 03:38:59 +08:00
|
|
|
|
2006-10-13 02:02:45 +08:00
|
|
|
model.row_changed(row.path, row.iter)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-07-19 02:53:56 +08:00
|
|
|
def vm_inspection_changed(self, vm):
|
2012-02-02 06:26:46 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2011-07-19 02:53:56 +08:00
|
|
|
model = vmlist.get_model()
|
|
|
|
|
|
|
|
if self.vm_row_key(vm) not in self.rows:
|
|
|
|
return
|
|
|
|
|
|
|
|
row = self.rows[self.vm_row_key(vm)]
|
|
|
|
row[ROW_INSPECTION_OS_ICON] = \
|
|
|
|
self.get_inspection_icon_pixbuf(vm, 16, 16)
|
|
|
|
model.row_changed(row.path, row.iter)
|
|
|
|
|
|
|
|
def get_inspection_icon_pixbuf(self, vm, w, h):
|
|
|
|
# libguestfs gives us the PNG data as a string.
|
|
|
|
png_data = vm.inspection.icon
|
2012-11-08 21:15:02 +08:00
|
|
|
if png_data is None:
|
2011-07-19 02:53:56 +08:00
|
|
|
return None
|
|
|
|
try:
|
2012-05-14 21:24:56 +08:00
|
|
|
pb = GdkPixbuf.PixbufLoader(image_type="png")
|
2011-07-19 02:53:56 +08:00
|
|
|
pb.set_size(w, h)
|
|
|
|
pb.write(png_data)
|
|
|
|
pb.close()
|
|
|
|
return pb.get_pixbuf()
|
|
|
|
except:
|
|
|
|
return None
|
|
|
|
|
2007-09-10 10:57:24 +08:00
|
|
|
def conn_state_changed(self, conn):
|
2011-07-26 03:09:42 +08:00
|
|
|
self.conn_resources_sampled(conn)
|
2009-07-27 04:15:05 +08:00
|
|
|
self.vm_selected()
|
2008-01-03 06:55:26 +08:00
|
|
|
|
2011-07-26 03:09:42 +08:00
|
|
|
def conn_resources_sampled(self, conn, newname=None):
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2007-08-15 00:31:24 +08:00
|
|
|
model = vmlist.get_model()
|
2007-09-10 10:57:24 +08:00
|
|
|
row = self.rows[conn.get_uri()]
|
2009-07-29 07:21:56 +08:00
|
|
|
|
2010-12-12 12:51:20 +08:00
|
|
|
if newname:
|
|
|
|
row[ROW_NAME] = newname
|
2009-09-18 00:35:41 +08:00
|
|
|
row[ROW_MARKUP] = self._build_conn_markup(conn, row)
|
2010-12-02 04:22:38 +08:00
|
|
|
row[ROW_STATUS] = ("<span size='smaller'>%s</span>" %
|
|
|
|
conn.get_state_text())
|
2009-07-29 07:21:56 +08:00
|
|
|
row[ROW_IS_CONN_CONNECTED] = conn.state != conn.STATE_DISCONNECTED
|
2009-11-29 09:49:44 +08:00
|
|
|
row[ROW_COLOR] = self._build_conn_color(conn)
|
2011-07-16 03:38:59 +08:00
|
|
|
row[ROW_HINT] = self._build_conn_hint(conn)
|
2006-08-09 05:02:15 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
if conn.get_state() in [vmmConnection.STATE_DISCONNECTED,
|
|
|
|
vmmConnection.STATE_CONNECTING]:
|
|
|
|
# Connection went inactive, delete any VM child nodes
|
|
|
|
parent = self.rows[conn.get_uri()].iter
|
|
|
|
if parent is not None:
|
|
|
|
child = model.iter_children(parent)
|
|
|
|
while child is not None:
|
2011-07-26 03:09:42 +08:00
|
|
|
del self.rows[self.vm_row_key(model.get_value(child,
|
|
|
|
ROW_HANDLE))]
|
2009-11-29 09:49:44 +08:00
|
|
|
model.remove(child)
|
|
|
|
child = model.iter_children(parent)
|
2011-07-26 03:09:42 +08:00
|
|
|
|
|
|
|
self.max_disk_rate = max(self.max_disk_rate, conn.disk_io_max_rate())
|
|
|
|
self.max_net_rate = max(self.max_net_rate,
|
|
|
|
conn.network_traffic_max_rate())
|
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
model.row_changed(row.path, row.iter)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2010-05-13 00:57:32 +08:00
|
|
|
def change_run_text(self, can_restore):
|
|
|
|
if can_restore:
|
|
|
|
text = _("_Restore")
|
|
|
|
else:
|
|
|
|
text = _("_Run")
|
|
|
|
strip_text = text.replace("_", "")
|
|
|
|
|
|
|
|
self.vmmenu_items["run"].get_child().set_label(text)
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-run").set_label(strip_text)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2009-07-27 04:15:05 +08:00
|
|
|
def vm_selected(self, ignore=None):
|
2011-07-23 04:43:26 +08:00
|
|
|
conn = self.current_conn()
|
2007-08-10 04:19:41 +08:00
|
|
|
vm = self.current_vm()
|
2009-07-27 04:15:05 +08:00
|
|
|
|
|
|
|
show_open = bool(vm)
|
|
|
|
show_details = bool(vm)
|
2010-08-23 00:50:31 +08:00
|
|
|
host_details = bool(len(self.rows))
|
|
|
|
|
2009-08-31 22:19:49 +08:00
|
|
|
delete = bool((vm and vm.is_runable()) or
|
|
|
|
(not vm and conn))
|
2009-07-27 04:15:05 +08:00
|
|
|
show_run = bool(vm and vm.is_runable())
|
|
|
|
is_paused = bool(vm and vm.is_paused())
|
|
|
|
if is_paused:
|
|
|
|
show_pause = bool(vm and vm.is_unpauseable())
|
2007-08-10 04:19:41 +08:00
|
|
|
else:
|
2009-07-27 04:15:05 +08:00
|
|
|
show_pause = bool(vm and vm.is_pauseable())
|
|
|
|
show_shutdown = bool(vm and vm.is_stoppable())
|
|
|
|
|
2010-05-13 00:57:32 +08:00
|
|
|
if vm and vm.managedsave_supported:
|
|
|
|
self.change_run_text(vm.hasSavedImage())
|
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-open").set_sensitive(show_open)
|
|
|
|
self.widget("vm-run").set_sensitive(show_run)
|
|
|
|
self.widget("vm-shutdown").set_sensitive(show_shutdown)
|
2009-07-27 04:15:05 +08:00
|
|
|
self.set_pause_state(is_paused)
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-pause").set_sensitive(show_pause)
|
2009-07-27 04:15:05 +08:00
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("menu_edit_details").set_sensitive(show_details)
|
|
|
|
self.widget("menu_host_details").set_sensitive(host_details)
|
|
|
|
self.widget("menu_edit_delete").set_sensitive(delete)
|
2009-07-27 04:15:05 +08:00
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def popup_vm_menu_key(self, widget_ignore, event):
|
2012-05-14 21:24:56 +08:00
|
|
|
if Gdk.keyval_name(event.keyval) != "Menu":
|
2009-11-11 22:49:34 +08:00
|
|
|
return False
|
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2009-11-11 22:49:34 +08:00
|
|
|
treeselection = vmlist.get_selection()
|
|
|
|
model, _iter = treeselection.get_selected()
|
|
|
|
self.popup_vm_menu(model, _iter, event)
|
|
|
|
return True
|
2007-08-14 05:13:39 +08:00
|
|
|
|
2009-11-11 22:49:34 +08:00
|
|
|
def popup_vm_menu_button(self, widget, event):
|
2009-11-11 05:01:56 +08:00
|
|
|
if event.button != 3:
|
|
|
|
return False
|
|
|
|
|
2008-11-19 04:42:51 +08:00
|
|
|
tup = widget.get_path_at_pos(int(event.x), int(event.y))
|
2012-11-08 21:15:02 +08:00
|
|
|
if tup is None:
|
2007-08-24 05:46:30 +08:00
|
|
|
return False
|
2008-11-19 04:42:51 +08:00
|
|
|
path = tup[0]
|
2007-08-24 05:46:30 +08:00
|
|
|
model = widget.get_model()
|
2008-11-19 04:42:51 +08:00
|
|
|
_iter = model.get_iter(path)
|
2009-11-11 05:01:56 +08:00
|
|
|
|
2009-11-11 22:49:34 +08:00
|
|
|
self.popup_vm_menu(model, _iter, event)
|
2009-12-10 00:28:38 +08:00
|
|
|
return False
|
2009-11-11 22:49:34 +08:00
|
|
|
|
|
|
|
def popup_vm_menu(self, model, _iter, event):
|
2012-11-08 21:15:02 +08:00
|
|
|
if model.iter_parent(_iter) is not None:
|
2009-11-11 05:01:56 +08:00
|
|
|
# Popup the vm menu
|
2008-11-19 04:42:51 +08:00
|
|
|
vm = model.get_value(_iter, ROW_HANDLE)
|
2009-11-11 05:01:56 +08:00
|
|
|
|
|
|
|
destroy = vm.is_destroyable()
|
|
|
|
run = vm.is_runable()
|
|
|
|
stop = vm.is_stoppable()
|
|
|
|
paused = vm.is_paused()
|
|
|
|
ro = vm.is_read_only()
|
|
|
|
|
|
|
|
self.vmmenu_items["run"].set_sensitive(run)
|
|
|
|
self.vmmenu_items["shutdown"].set_sensitive(stop)
|
|
|
|
self.vmmenu_items["pause"].set_property("visible", not paused)
|
|
|
|
self.vmmenu_items["pause"].set_sensitive(stop)
|
|
|
|
self.vmmenu_items["resume"].set_property("visible", paused)
|
|
|
|
self.vmmenu_items["resume"].set_sensitive(paused)
|
2009-11-16 04:29:42 +08:00
|
|
|
self.vmmenu_items["migrate"].set_sensitive(stop)
|
2009-11-11 05:01:56 +08:00
|
|
|
self.vmmenu_items["clone"].set_sensitive(not ro)
|
2009-11-11 23:05:34 +08:00
|
|
|
self.vmmenu_items["delete"].set_sensitive(run)
|
2009-11-11 05:01:56 +08:00
|
|
|
|
|
|
|
self.vmmenushutdown_items["poweroff"].set_sensitive(stop)
|
|
|
|
self.vmmenushutdown_items["reboot"].set_sensitive(stop)
|
|
|
|
self.vmmenushutdown_items["forcepoweroff"].set_sensitive(destroy)
|
2010-05-12 23:42:59 +08:00
|
|
|
self.vmmenushutdown_items["save"].set_sensitive(destroy)
|
2012-05-14 21:24:56 +08:00
|
|
|
self.vmmenu.popup(None, None, None, None, 0, event.time)
|
2007-08-24 05:46:30 +08:00
|
|
|
else:
|
2009-11-11 05:01:56 +08:00
|
|
|
# Pop up connection menu
|
2008-11-19 04:42:51 +08:00
|
|
|
conn = model.get_value(_iter, ROW_HANDLE)
|
2009-11-11 05:01:56 +08:00
|
|
|
disconn = (conn.get_state() == vmmConnection.STATE_DISCONNECTED)
|
|
|
|
conning = (conn.get_state() == vmmConnection.STATE_CONNECTING)
|
|
|
|
|
|
|
|
self.connmenu_items["create"].set_sensitive(not disconn)
|
|
|
|
self.connmenu_items["disconnect"].set_sensitive(not (disconn or
|
|
|
|
conning))
|
|
|
|
self.connmenu_items["connect"].set_sensitive(disconn)
|
2009-11-17 05:35:34 +08:00
|
|
|
self.connmenu_items["delete"].set_sensitive(disconn)
|
2009-11-11 05:01:56 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
self.connmenu.popup(None, None, None, None, 0, event.time)
|
2009-11-11 05:01:56 +08:00
|
|
|
|
2009-11-12 00:02:57 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
#################
|
|
|
|
# Stats methods #
|
|
|
|
#################
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def vmlist_name_sorter(self, model, iter1, iter2, ignore):
|
2009-07-29 07:21:56 +08:00
|
|
|
return cmp(model.get_value(iter1, ROW_NAME),
|
|
|
|
model.get_value(iter2, ROW_NAME))
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def vmlist_guest_cpu_usage_sorter(self, model, iter1, iter2, ignore):
|
2011-07-12 20:49:47 +08:00
|
|
|
obj1 = model.get_value(iter1, ROW_HANDLE)
|
|
|
|
obj2 = model.get_value(iter2, ROW_HANDLE)
|
|
|
|
|
|
|
|
return cmp(obj1.guest_cpu_time_percentage(),
|
|
|
|
obj2.guest_cpu_time_percentage())
|
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def vmlist_host_cpu_usage_sorter(self, model, iter1, iter2, ignore):
|
2011-07-12 09:22:50 +08:00
|
|
|
obj1 = model.get_value(iter1, ROW_HANDLE)
|
|
|
|
obj2 = model.get_value(iter2, ROW_HANDLE)
|
|
|
|
|
|
|
|
return cmp(obj1.host_cpu_time_percentage(),
|
|
|
|
obj2.host_cpu_time_percentage())
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def vmlist_disk_io_sorter(self, model, iter1, iter2, ignore):
|
2011-07-12 09:22:50 +08:00
|
|
|
obj1 = model.get_value(iter1, ROW_HANDLE)
|
|
|
|
obj2 = model.get_value(iter2, ROW_HANDLE)
|
|
|
|
|
|
|
|
return cmp(obj1.disk_io_rate(), obj2.disk_io_rate())
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def vmlist_network_usage_sorter(self, model, iter1, iter2, ignore):
|
2011-07-12 09:22:50 +08:00
|
|
|
obj1 = model.get_value(iter1, ROW_HANDLE)
|
|
|
|
obj2 = model.get_value(iter2, ROW_HANDLE)
|
|
|
|
|
|
|
|
return cmp(obj1.network_traffic_rate(), obj2.network_traffic_rate())
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2013-04-18 05:39:25 +08:00
|
|
|
def enable_polling(self, column):
|
|
|
|
if column == COL_DISK:
|
2009-07-27 04:15:28 +08:00
|
|
|
widgn = "menu_view_stats_disk"
|
2013-04-18 05:39:25 +08:00
|
|
|
do_enable = self.config.get_stats_enable_disk_poll()
|
|
|
|
elif column == COL_NETWORK:
|
2009-07-27 04:15:28 +08:00
|
|
|
widgn = "menu_view_stats_network"
|
2013-04-18 05:39:25 +08:00
|
|
|
do_enable = self.config.get_stats_enable_net_poll()
|
2011-07-15 01:13:13 +08:00
|
|
|
widget = self.widget(widgn)
|
2008-12-18 04:27:06 +08:00
|
|
|
|
2009-01-27 00:12:43 +08:00
|
|
|
tool_text = ""
|
2010-12-14 05:24:49 +08:00
|
|
|
|
2013-04-18 05:39:25 +08:00
|
|
|
if do_enable:
|
2008-12-18 04:27:06 +08:00
|
|
|
widget.set_sensitive(True)
|
|
|
|
else:
|
|
|
|
if widget.get_active():
|
|
|
|
widget.set_active(False)
|
|
|
|
widget.set_sensitive(False)
|
2009-01-27 00:12:43 +08:00
|
|
|
tool_text = _("Disabled in preferences dialog.")
|
|
|
|
|
2012-02-02 06:26:46 +08:00
|
|
|
widget.set_tooltip_text(tool_text)
|
2011-02-16 00:38:35 +08:00
|
|
|
|
2012-02-02 06:26:46 +08:00
|
|
|
disabled_text = _(" (disabled)")
|
|
|
|
current_text = widget.get_label().strip(disabled_text)
|
|
|
|
if tool_text:
|
|
|
|
current_text = current_text + disabled_text
|
|
|
|
widget.set_label(current_text)
|
2008-12-18 04:27:06 +08:00
|
|
|
|
2013-04-18 05:39:25 +08:00
|
|
|
def toggle_network_traffic_visible_widget(self):
|
2011-07-12 20:49:47 +08:00
|
|
|
val = self.config.is_vmlist_network_traffic_visible()
|
|
|
|
self.netcol.set_visible(val)
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("menu_view_stats_network").set_active(val)
|
2009-07-27 04:15:28 +08:00
|
|
|
|
2013-04-18 05:39:25 +08:00
|
|
|
def toggle_disk_io_visible_widget(self):
|
2011-07-12 20:49:47 +08:00
|
|
|
val = self.config.is_vmlist_disk_io_visible()
|
|
|
|
self.diskcol.set_visible(val)
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("menu_view_stats_disk").set_active(val)
|
2011-07-12 20:49:47 +08:00
|
|
|
|
2013-04-18 05:39:25 +08:00
|
|
|
def toggle_guest_cpu_usage_visible_widget(self):
|
2011-07-12 20:49:47 +08:00
|
|
|
val = self.config.is_vmlist_guest_cpu_usage_visible()
|
|
|
|
self.guestcpucol.set_visible(val)
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("menu_view_stats_guest_cpu").set_active(val)
|
2009-07-27 04:15:28 +08:00
|
|
|
|
2013-04-18 05:39:25 +08:00
|
|
|
def toggle_host_cpu_usage_visible_widget(self):
|
2011-07-12 20:49:47 +08:00
|
|
|
val = self.config.is_vmlist_host_cpu_usage_visible()
|
|
|
|
self.hostcpucol.set_visible(val)
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("menu_view_stats_host_cpu").set_active(val)
|
2009-11-12 00:02:57 +08:00
|
|
|
|
|
|
|
def toggle_stats_visible(self, src, stats_id):
|
|
|
|
visible = src.get_active()
|
|
|
|
set_stats = {
|
2011-07-12 20:49:47 +08:00
|
|
|
COL_GUEST_CPU: self.config.set_vmlist_guest_cpu_usage_visible,
|
|
|
|
COL_HOST_CPU: self.config.set_vmlist_host_cpu_usage_visible,
|
|
|
|
COL_DISK: self.config.set_vmlist_disk_io_visible,
|
|
|
|
COL_NETWORK: self.config.set_vmlist_network_traffic_visible,
|
2009-11-12 00:02:57 +08:00
|
|
|
}
|
|
|
|
set_stats[stats_id](visible)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def toggle_stats_visible_guest_cpu(self, src):
|
|
|
|
self.toggle_stats_visible(src, COL_GUEST_CPU)
|
|
|
|
def toggle_stats_visible_host_cpu(self, src):
|
|
|
|
self.toggle_stats_visible(src, COL_HOST_CPU)
|
|
|
|
def toggle_stats_visible_disk(self, src):
|
|
|
|
self.toggle_stats_visible(src, COL_DISK)
|
|
|
|
def toggle_stats_visible_network(self, src):
|
|
|
|
self.toggle_stats_visible(src, COL_NETWORK)
|
|
|
|
|
2011-07-12 20:49:47 +08:00
|
|
|
def guest_cpu_usage_img(self, column_ignore, cell, model, _iter, data):
|
|
|
|
obj = model.get_value(_iter, ROW_HANDLE)
|
2012-05-14 21:24:56 +08:00
|
|
|
if obj is None or not hasattr(obj, "conn"):
|
2011-07-12 20:49:47 +08:00
|
|
|
return
|
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
data = obj.guest_cpu_time_vector_limit(GRAPH_LEN)
|
2011-07-12 20:49:47 +08:00
|
|
|
cell.set_property('data_array', data)
|
|
|
|
|
|
|
|
def host_cpu_usage_img(self, column_ignore, cell, model, _iter, data):
|
2011-07-12 09:22:50 +08:00
|
|
|
obj = model.get_value(_iter, ROW_HANDLE)
|
2012-05-14 21:24:56 +08:00
|
|
|
if obj is None or not hasattr(obj, "conn"):
|
2007-08-15 04:28:36 +08:00
|
|
|
return
|
2011-07-12 09:22:50 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
data = obj.host_cpu_time_vector_limit(GRAPH_LEN)
|
2008-10-19 03:28:57 +08:00
|
|
|
cell.set_property('data_array', data)
|
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def disk_io_img(self, column_ignore, cell, model, _iter, data):
|
2011-07-12 09:22:50 +08:00
|
|
|
obj = model.get_value(_iter, ROW_HANDLE)
|
2012-05-14 21:24:56 +08:00
|
|
|
if obj is None or not hasattr(obj, "conn"):
|
2011-07-26 03:09:42 +08:00
|
|
|
return
|
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
data = obj.disk_io_vector_limit(GRAPH_LEN, self.max_disk_rate)
|
2008-10-19 03:28:57 +08:00
|
|
|
cell.set_property('data_array', data)
|
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def network_traffic_img(self, column_ignore, cell, model, _iter, data):
|
2011-07-12 09:22:50 +08:00
|
|
|
obj = model.get_value(_iter, ROW_HANDLE)
|
2012-05-14 21:24:56 +08:00
|
|
|
if obj is None or not hasattr(obj, "conn"):
|
2011-07-26 03:09:42 +08:00
|
|
|
return
|
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
data = obj.network_traffic_vector_limit(GRAPH_LEN, self.max_net_rate)
|
2006-06-27 05:17:45 +08:00
|
|
|
cell.set_property('data_array', data)
|