diff options
-rw-r--r-- | gnome-vm-manager.glade | 330 | ||||
-rwxr-xr-x | gnome-vm-manager.py | 450 |
2 files changed, 684 insertions, 96 deletions
diff --git a/gnome-vm-manager.glade b/gnome-vm-manager.glade index 0f2e16b9..20588d15 100644 --- a/gnome-vm-manager.glade +++ b/gnome-vm-manager.glade @@ -3,7 +3,7 @@ <glade-interface> -<widget class="GtkWindow" id="vm-manager"> +<widget class="GtkWindow" id="vmm-manager"> <property name="visible">True</property> <property name="title" translatable="yes">Virtual Machine Manager</property> <property name="type">GTK_WINDOW_TOPLEVEL</property> @@ -83,7 +83,7 @@ <child> <widget class="GtkImageMenuItem" id="menu_edit_details"> <property name="visible">True</property> - <property name="label" translatable="yes">Details</property> + <property name="label" translatable="yes">VM details</property> <property name="use_underline">True</property> <signal name="activate" handler="on_menu_edit_details_activate" last_modification_time="Tue, 28 Mar 2006 17:06:34 GMT"/> @@ -109,6 +109,21 @@ <signal name="activate" handler="on_menu_edit_delete_activate" last_modification_time="Tue, 28 Mar 2006 17:06:34 GMT"/> </widget> </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator2"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="menu_edit_preferences"> + <property name="visible">True</property> + <property name="label">gtk-preferences</property> + <property name="use_stock">True</property> + <signal name="activate" handler="on_menu_edit_preferences_activate" last_modification_time="Wed, 29 Mar 2006 09:57:25 GMT"/> + </widget> + </child> </widget> </child> </widget> @@ -301,6 +316,7 @@ Inactive virtual machines</property> <child> <widget class="GtkButton" id="vm-delete"> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="can_default">True</property> <property name="can_focus">True</property> <property name="label">gtk-delete</property> @@ -327,6 +343,7 @@ Inactive virtual machines</property> <child> <widget class="GtkButton" id="vm-details"> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="can_default">True</property> <property name="can_focus">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> @@ -402,6 +419,7 @@ Inactive virtual machines</property> <child> <widget class="GtkButton" id="vm-open"> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="can_default">True</property> <property name="can_focus">True</property> <property name="label">gtk-open</property> @@ -471,9 +489,9 @@ Inactive virtual machines</property> </child> </widget> -<widget class="GtkAboutDialog" id="vm-about"> +<widget class="GtkAboutDialog" id="vmm-about"> <property name="visible">True</property> - <property name="destroy_with_parent">True</property> + <property name="destroy_with_parent">False</property> <property name="name" translatable="yes">Virtual Machine Manager</property> <property name="copyright" translatable="yes">Copyright (C) 2006 Red Hat Inc.</property> <property name="comments" translatable="yes"></property> @@ -494,9 +512,10 @@ Inactive virtual machines</property> <property name="wrap_license">False</property> <property name="authors">Daniel P. Berrange <berrange@redhat.com></property> <property name="translator_credits" translatable="yes" comments="TRANSLATORS: Replace this string with your names, one name per line.">translator-credits</property> + <signal name="delete_event" handler="on_vmm_about_delete_event" last_modification_time="Wed, 29 Mar 2006 10:31:19 GMT"/> </widget> -<widget class="GtkWindow" id="vm-details"> +<widget class="GtkWindow" id="vmm-details"> <property name="visible">True</property> <property name="title" translatable="yes">Virtual Machine Details</property> <property name="type">GTK_WINDOW_TOPLEVEL</property> @@ -1740,4 +1759,305 @@ Inactive virtual machines</property> </child> </widget> +<widget class="GtkDialog" id="vmm-preferences"> + <property name="visible">True</property> + <property name="title" translatable="yes">Virtual Machine Manager Preferences</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">False</property> + <signal name="delete_event" handler="on_vmm_preferences_delete_event" last_modification_time="Wed, 29 Mar 2006 10:12:05 GMT"/> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="helpbutton1"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-help</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-11</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="close"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-7</property> + <signal name="clicked" handler="on_close_clicked" last_modification_time="Wed, 29 Mar 2006 10:11:44 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkFrame" id="frame1"> + <property name="border_width">3</property> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> + + <child> + <widget class="GtkAlignment" id="alignment2"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">12</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkTable" id="table3"> + <property name="border_width">3</property> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">3</property> + <property name="column_spacing">3</property> + + <child> + <widget class="GtkLabel" id="label36"> + <property name="visible">True</property> + <property name="label" translatable="yes">Update status every</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label37"> + <property name="visible">True</property> + <property name="label" translatable="yes">Maintain history of</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="stats-update-interval"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_IF_VALID</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">5 1 60 1 5 5</property> + <signal name="changed" handler="on_stats_update_interval_changed" last_modification_time="Wed, 29 Mar 2006 10:12:17 GMT"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label38"> + <property name="visible">True</property> + <property name="label" translatable="yes">seconds</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label39"> + <property name="visible">True</property> + <property name="label" translatable="yes">samples</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="stats-history-length"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_IF_VALID</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">10 10 100 1 5 5</property> + <signal name="changed" handler="on_stats_history_length_changed" last_modification_time="Wed, 29 Mar 2006 10:12:22 GMT"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label35"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Status monitoring</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + </glade-interface> diff --git a/gnome-vm-manager.py b/gnome-vm-manager.py index 15f76341..e291b6b3 100755 --- a/gnome-vm-manager.py +++ b/gnome-vm-manager.py @@ -1,15 +1,17 @@ #!/usr/bin/python +import gconf import gtk import gobject import gtk.gdk import gtk.glade +from time import time import re import os import os.path import libvirt -tickrate = 5000 +gconf_dir = "/apps/gnome-virtual-manager" # Ought not to hardcode stuff as being in /usr gladedir = "/usr/share/gnome-vm-manager" @@ -20,79 +22,167 @@ if os.path.exists("./gnome-vm-manager.glade"): class vmmAbout: def __init__(self): - self.window = gtk.glade.XML(gladedir + "/gnome-vm-manager.glade", "vm-about") - self.window.get_widget("vm-about").hide() + self.window = gtk.glade.XML(gladedir + "/gnome-vm-manager.glade", "vmm-about") + self.window.get_widget("vmm-about").hide() + + self.window.signal_autoconnect({ + "on_vmm_about_delete_event": self.close, + }) def show(self): - dialog = self.window.get_widget("vm-about") + dialog = self.window.get_widget("vmm-about") dialog.set_version("0.1") dialog.show_all() + def close(self,ignore1=None,ignore2=None): + self.window.get_widget("vmm-about").hide() + return 1 + + +class vmmDetails: + def __init__(self, vmm): + self.window = gtk.glade.XML(gladedir + "/gnome-vm-manager.glade", "vmm-details") + self.vmm = vmm + + +class vmmPreferences: + def __init__(self, conf): + self.window = gtk.glade.XML(gladedir + "/gnome-vm-manager.glade", "vmm-preferences") + self.conf = conf + self.window.get_widget("vmm-preferences").hide() + + self.conf.on_stats_update_interval_changed(self.refresh_update_interval) + self.conf.on_stats_history_length_changed(self.refresh_history_length) + + self.refresh_update_interval() + self.refresh_history_length() + + self.window.signal_autoconnect({ + "on_stats_update_interval_changed": self.change_update_interval, + "on_stats_history_length_changed": self.change_history_length, + + "on_close_clicked": self.close, + "on_vmm_preferences_delete_event": self.close, + }) + + def close(self,ignore1=None,ignore2=None): + self.window.get_widget("vmm-preferences").hide() + return 1 + + def show(self): + self.window.get_widget("vmm-preferences").show_all() + + def refresh_update_interval(self, ignore1=None,ignore2=None,ignore3=None,ignore4=None): + self.window.get_widget("stats-update-interval").set_value(self.conf.get_stats_update_interval()) + + def refresh_history_length(self, ignore1=None,ignore2=None,ignore3=None,ignore4=None): + self.window.get_widget("stats-history-length").set_value(self.conf.get_stats_history_length()) + + def change_update_interval(self, src): + self.conf.set_stats_update_interval(src.get_value_as_int()) + + def change_history_length(self, src): + self.conf.set_stats_history_length(src.get_value_as_int()) + class vmmManager: def __init__(self): - self.window = gtk.glade.XML(gladedir + "/gnome-vm-manager.glade", "vm-manager") + self.window = gtk.glade.XML(gladedir + "/gnome-vm-manager.glade", "vmm-manager") + self.conf = vmmConfig() self.vmm = libvirt.openReadOnly(None) #self.vmm = libvirt.open(None) - self.stats = {} - - self.record_stats() + self.stats = vmmStats(self.vmm, self.conf) self.populate_vms() - self.tickrate = 5000 - self.about = None; - - self.timer = gobject.timeout_add(self.tickrate, self.refresh_stats) + self.about = None + self.preferences = None + + # Setup update timers + self.conf.on_stats_update_interval_changed(self.change_timer_interval) + self.schedule_timer() + + self.conf.on_vmlist_status_visible_changed(self.toggle_status_visible_widget) + self.conf.on_vmlist_cpu_usage_visible_changed(self.toggle_cpu_usage_visible_widget) + self.conf.on_vmlist_memory_usage_visible_changed(self.toggle_memory_usage_visible_widget) + self.conf.on_vmlist_disk_usage_visible_changed(self.toggle_disk_usage_visible_widget) + self.conf.on_vmlist_network_traffic_visible_changed(self.toggle_network_traffic_visible_widget) + + self.window.get_widget("menu_view_status").set_active(self.conf.is_vmlist_status_visible()) + self.window.get_widget("menu_view_cpu_usage").set_active(self.conf.is_vmlist_cpu_usage_visible()) + self.window.get_widget("menu_view_memory_usage").set_active(self.conf.is_vmlist_memory_usage_visible()) + self.window.get_widget("menu_view_disk_usage").set_active(self.conf.is_vmlist_disk_usage_visible()) + self.window.get_widget("menu_view_network_traffic").set_active(self.conf.is_vmlist_network_traffic_visible()) self.window.signal_autoconnect({ - "on_menu_view_status_activate" : self.toggle_status_column, - "on_menu_view_cpu_usage_activate" : self.toggle_cpu_column, - "on_menu_view_memory_usage_activate" : self.toggle_memory_column, - "on_menu_view_disk_usage_activate" : self.toggle_disk_column, - "on_menu_view_network_traffic_activate" : self.toggle_network_column, + "on_menu_view_status_activate" : self.toggle_status_visible_conf, + "on_menu_view_cpu_usage_activate" : self.toggle_cpu_usage_visible_conf, + "on_menu_view_memory_usage_activate" : self.toggle_memory_usage_visible_conf, + "on_menu_view_disk_usage_activate" : self.toggle_disk_usage_visible_conf, + "on_menu_view_network_traffic_activate" : self.toggle_network_traffic_visible_conf, "on_vm_manager_delete_event": self.exit_app, "on_menu_file_quit_activate": self.exit_app, "on_vmm_close_clicked": self.exit_app, + "on_menu_edit_preferences_activate": self.show_preferences, "on_menu_help_about_activate": self.show_about, }) + + self.vm_selected(None) + self.window.get_widget("vm-list").get_selection().connect("changed", self.vm_selected) + def exit_app(self, ignore=None,ignore2=None): gtk.main_quit() + def schedule_timer(self): + interval = self.conf.get_stats_update_interval() * 1000 + print "Scheduling at " + str(interval) + self.timer_started = time() * 1000 + self.timer = gobject.timeout_add(interval, self.refresh_stats) + + + def change_timer_interval(self,ignore1,ignore2,ignore3,ignore4): + print "Removing timer" + gobject.source_remove(self.timer) + self.refresh_stats() + self.schedule_timer() + + def vm_selected(self, selection): + if selection == None or selection.count_selected_rows() == 0: + self.window.get_widget("vm-delete").set_sensitive(False) + self.window.get_widget("vm-details").set_sensitive(False) + self.window.get_widget("vm-open").set_sensitive(False) + self.window.get_widget("menu_edit_delete").set_sensitive(False) + self.window.get_widget("menu_edit_details").set_sensitive(False) + else: + self.window.get_widget("vm-delete").set_sensitive(True) + self.window.get_widget("vm-details").set_sensitive(True) + self.window.get_widget("vm-open").set_sensitive(True) + self.window.get_widget("menu_edit_delete").set_sensitive(True) + self.window.get_widget("menu_edit_details").set_sensitive(True) def show_about(self, ignore=None): if self.about == None: self.about = vmmAbout() self.about.show() + def show_preferences(self, ignore=None): + if self.preferences == None: + self.preferences = vmmPreferences(self.conf) + self.preferences.show() + def refresh_stats(self): - self.record_stats() - self.timer = gobject.timeout_add(self.tickrate, self.refresh_stats) + self.stats.tick() vmlist = self.window.get_widget("vm-list") model = vmlist.get_model() - print "Refresh " + str(model.iter_n_children(None)) + for row in range(model.iter_n_children(None)): model.row_changed(str(row), model.iter_nth_child(None, row)) - - def record_stats(self): - print "Record" - doms = self.vmm.listDomainsID() - if doms != None: - for id in self.vmm.listDomainsID(): - vm = self.vmm.lookupByID(id) - info = vm.info() - name = vm.name() - if not(self.stats.has_key(name)): - self.stats[name] = [] - if len(self.stats[name]) > 4: - self.stats[name] = (self.stats[name])[1:len(self.stats[name])] - self.stats[name].append(info) - # XXX why is max-mem wrong for Domain-0 when run as root ?!?!?! - #print info + return 1 + def populate_vms(self): vmlist = self.window.get_widget("vm-list") @@ -105,7 +195,7 @@ class vmmManager: cpuUsageCol = gtk.TreeViewColumn("CPU usage") memoryUsageCol = gtk.TreeViewColumn("Memory usage") diskUsageCol = gtk.TreeViewColumn("Disk usage") - networkUsageCol = gtk.TreeViewColumn("Network traffic") + networkTrafficCol = gtk.TreeViewColumn("Network traffic") name_txt = gtk.CellRendererText() nameCol.pack_start(name_txt, True) @@ -116,27 +206,32 @@ class vmmManager: vmlist.append_column(cpuUsageCol) vmlist.append_column(memoryUsageCol) vmlist.append_column(diskUsageCol) - vmlist.append_column(networkUsageCol) + vmlist.append_column(networkTrafficCol) status_txt = gtk.CellRendererText() statusCol.pack_start(status_txt, True) statusCol.set_cell_data_func(status_txt, self.status_text, None) - + statusCol.set_visible(self.conf.is_vmlist_status_visible()) + cpuUsage_txt = gtk.CellRendererText() cpuUsageCol.pack_start(cpuUsage_txt, True) cpuUsageCol.set_cell_data_func(cpuUsage_txt, self.cpu_usage_text, None) + cpuUsageCol.set_visible(self.conf.is_vmlist_cpu_usage_visible()) memoryUsage_txt = gtk.CellRendererText() memoryUsageCol.pack_start(memoryUsage_txt, True) memoryUsageCol.set_cell_data_func(memoryUsage_txt, self.memory_usage_text, None) + memoryUsageCol.set_visible(self.conf.is_vmlist_memory_usage_visible()) diskUsage_txt = gtk.CellRendererText() diskUsageCol.pack_start(diskUsage_txt, True) diskUsageCol.set_cell_data_func(diskUsage_txt, self.disk_usage_text, None) + diskUsageCol.set_visible(self.conf.is_vmlist_disk_usage_visible()) - networkUsage_txt = gtk.CellRendererText() - networkUsageCol.pack_start(networkUsage_txt, True) - networkUsageCol.set_cell_data_func(networkUsage_txt, self.network_usage_text, None) + networkTraffic_txt = gtk.CellRendererText() + networkTrafficCol.pack_start(networkTraffic_txt, True) + networkTrafficCol.set_cell_data_func(networkTraffic_txt, self.network_usage_text, None) + networkTrafficCol.set_visible(self.conf.is_vmlist_network_traffic_visible()) doms = self.vmm.listDomainsID() if doms != None: @@ -144,79 +239,65 @@ class vmmManager: vm = self.vmm.lookupByID(id) model.append([vm.name()]) - def toggle_status_column(self,menu): + def toggle_status_visible_conf(self, menu): + self.conf.set_vmlist_status_visible(menu.get_active()) + + def toggle_status_visible_widget(self, ignore1, ignore2, ignore3, ignore4): + menu = self.window.get_widget("menu_view_status") vmlist = self.window.get_widget("vm-list") col = vmlist.get_column(1) - col.set_visible(menu.get_active()) + col.set_visible(self.conf.is_vmlist_status_visible()) - def toggle_cpu_column(self,menu): + def toggle_cpu_usage_visible_conf(self, menu): + self.conf.set_vmlist_cpu_usage_visible(menu.get_active()) + + def toggle_cpu_usage_visible_widget(self, ignore1, ignore2, ignore3, ignore4): + menu = self.window.get_widget("menu_view_cpu_usage") vmlist = self.window.get_widget("vm-list") col = vmlist.get_column(2) - col.set_visible(menu.get_active()) + col.set_visible(self.conf.is_vmlist_cpu_usage_visible()) + + def toggle_memory_usage_visible_conf(self, menu): + self.conf.set_vmlist_memory_usage_visible(menu.get_active()) - def toggle_memory_column(self,menu): + def toggle_memory_usage_visible_widget(self, ignore1, ignore2, ignore3, ignore4): + menu = self.window.get_widget("menu_view_memory_usage") vmlist = self.window.get_widget("vm-list") col = vmlist.get_column(3) - col.set_visible(menu.get_active()) + col.set_visible(self.conf.is_vmlist_memory_usage_visible()) + + def toggle_disk_usage_visible_conf(self, menu): + self.conf.set_vmlist_disk_usage_visible(menu.get_active()) - def toggle_disk_column(self,menu): + def toggle_disk_usage_visible_widget(self, ignore1, ignore2, ignore3, ignore4): + menu = self.window.get_widget("menu_view_disk_usage") vmlist = self.window.get_widget("vm-list") col = vmlist.get_column(4) - col.set_visible(menu.get_active()) + col.set_visible(self.conf.is_vmlist_disk_usage_visible()) - def toggle_network_column(self,menu): + def toggle_network_traffic_visible_conf(self, menu): + self.conf.set_vmlist_network_traffic_visible(menu.get_active()) + + def toggle_network_traffic_visible_widget(self, ignore1, ignore2, ignore3, ignore4): + menu = self.window.get_widget("menu_view_network_traffic") vmlist = self.window.get_widget("vm-list") col = vmlist.get_column(5) - col.set_visible(menu.get_active()) + col.set_visible(self.conf.is_vmlist_network_traffic_visible()) def status_text(self, column, cell, model, iter, data): name = model.get_value(iter, 0) - statusRecord = self.stats[name] - info = statusRecord[len(statusRecord)-1] - if info[0] == libvirt.VIR_DOMAIN_NOSTATE: - cell.set_property('text', "Unknown") - elif info[0] == libvirt.VIR_DOMAIN_RUNNING: - cell.set_property('text', "Running") - elif info[0] == libvirt.VIR_DOMAIN_BLOCKED: - cell.set_property('text', "Blocked") - elif info[0] == libvirt.VIR_DOMAIN_PAUSED: - cell.set_property('text', "Paused") - elif info[0] == libvirt.VIR_DOMAIN_SHUTDOWN: - cell.set_property('text', "Shutdown") - elif info[0] == libvirt.VIR_DOMAIN_SHUTOFF: - cell.set_property('text', "Shutoff") - elif info[0] == libvirt.VIR_DOMAIN_CRASHED: - cell.set_property('text', "Crashed") + cell.set_property('text', self.stats.run_status(name)) def cpu_usage_text(self, column, cell, model, iter, data): name = model.get_value(iter, 0) - statusRecord = self.stats[name] - nSample = len(statusRecord) - - if nSample < 2: - cell.set_property('text', "-") - else: - total = 0 - for dom in self.stats.keys(): - last = self.stats[dom][len(self.stats[dom])-2] - current = self.stats[dom][len(self.stats[dom])-1] - total += current[4] - last[4] - - last = statusRecord[len(statusRecord)-2] - current = statusRecord[len(statusRecord)-1] - fraction = current[4] - last[4] - - percentage = fraction * 100.0 / total - - cell.set_property('text',"%2.2f %%" % percentage) + cell.set_property('text', "%2.2f %%" % self.stats.percent_cpu_time(name)) def memory_usage_text(self, column, cell, model, iter, data): name = model.get_value(iter, 0) - statusRecord = self.stats[name] - current = statusRecord[len(statusRecord)-1] - - cell.set_property('text', "%s of %s" % (self.pretty_mem(current[2]), self.pretty_mem(current[1]))) + current = self.stats.current_memory(name) + maximum = self.stats.maximum_memory(name) + cell.set_property('text', "%s of %s" % (self.pretty_mem(current), self.pretty_mem(maximum))) #cell.set_property('text', self.pretty_mem(current[2])) def pretty_mem(self, mem): @@ -232,6 +313,193 @@ class vmmManager: def network_usage_text(self, column, cell, model, iter, data): #cell.set_property('text', "100 bytes/sec") cell.set_property('text', "-") + +class vmmConfig: + def __init__(self): + self.conf = gconf.client_get_default() + self.conf.add_dir (gconf_dir, + gconf.CLIENT_PRELOAD_NONE) + + def is_vmlist_status_visible(self): + return self.conf.get_bool(gconf_dir + "/vmlist-fields/status") + + def is_vmlist_cpu_usage_visible(self): + return self.conf.get_bool(gconf_dir + "/vmlist-fields/cpu_usage") + + def is_vmlist_memory_usage_visible(self): + return self.conf.get_bool(gconf_dir + "/vmlist-fields/memory_usage") + + def is_vmlist_disk_usage_visible(self): + return self.conf.get_bool(gconf_dir + "/vmlist-fields/disk_usage") + + def is_vmlist_network_traffic_visible(self): + return self.conf.get_bool(gconf_dir + "/vmlist-fields/network_traffic") + + + + def set_vmlist_status_visible(self, state): + self.conf.set_bool(gconf_dir + "/vmlist-fields/status", state) + + def set_vmlist_cpu_usage_visible(self, state): + self.conf.set_bool(gconf_dir + "/vmlist-fields/cpu_usage", state) + + def set_vmlist_memory_usage_visible(self, state): + self.conf.set_bool(gconf_dir + "/vmlist-fields/memory_usage", state) + + def set_vmlist_disk_usage_visible(self, state): + self.conf.set_bool(gconf_dir + "/vmlist-fields/disk_usage", state) + + def set_vmlist_network_traffic_visible(self, state): + self.conf.set_bool(gconf_dir + "/vmlist-fields/network_traffic", state) + + + + def on_vmlist_status_visible_changed(self, callback): + self.conf.notify_add(gconf_dir + "/vmlist-fields/status", callback) + + def on_vmlist_cpu_usage_visible_changed(self, callback): + self.conf.notify_add(gconf_dir + "/vmlist-fields/cpu_usage", callback) + + def on_vmlist_memory_usage_visible_changed(self, callback): + self.conf.notify_add(gconf_dir + "/vmlist-fields/memory_usage", callback) + + def on_vmlist_disk_usage_visible_changed(self, callback): + self.conf.notify_add(gconf_dir + "/vmlist-fields/disk_usage", callback) + + def on_vmlist_network_traffic_visible_changed(self, callback): + self.conf.notify_add(gconf_dir + "/vmlist-fields/network_traffic", callback) + + + + def get_stats_update_interval(self): + interval = self.conf.get_int(gconf_dir + "/stats/update-interval") + if interval < 1: + return 1 + return interval + + def get_stats_history_length(self): + history = self.conf.get_int(gconf_dir + "/stats/history-length") + if history < 10: + return 10 + return history + + + def set_stats_update_interval(self, interval): + self.conf.set_int(gconf_dir + "/stats/update-interval", interval) + + def set_stats_history_length(self, length): + self.conf.set_int(gconf_dir + "/stats/history-length", length) + + + def on_stats_update_interval_changed(self, callback): + self.conf.notify_add(gconf_dir + "/stats/update-interval", callback) + + def on_stats_history_length_changed(self, callback): + self.conf.notify_add(gconf_dir + "/stats/history-length", callback) + + +class vmmStats: + def __init__(self, vmm, conf): + self.vmm = vmm + self.vms = {} + self.conf = conf + self.callbacks = { "notify_added": [], "notify_removed": [] } + self.tick() + + def connect_to_signal(self, name, callback): + if not(self.callbacks.has_key(name)): + raise "unknown signal " + name + "requested" + + self.callbacks[name].append(callback) + + def notify_added(self, name): + for cb in self.callbacks["notify_added"]: + cb(name) + + + def notify_removed(self, name): + for cb in self.callbacks["notify_added"]: + cb(name) + + def tick(self): + doms = self.vmm.listDomainsID() + newVms = {} + if doms != None: + for id in self.vmm.listDomainsID(): + vm = self.vmm.lookupByID(id) + newVms[vm.name()] = vm + + for name in self.vms.keys(): + if not(newVms.has_key(name)): + del self.vms[name] + self.notify_removed(name) + + for name in newVms.keys(): + if not(self.vms.has_key(name)): + self.vms[name] = { "handle": newVms[name], + "stats": [] } + self.notify_added(name) + + now = time() + + totalCpuTime = 0 + for name in self.vms.keys(): + info = self.vms[name]["handle"].info() + + if len(self.vms[name]["stats"]) > self.conf.get_stats_history_length(): + self.vms[name]["stats"] = self.vms[name]["stats"][0:len(self.vms[name]["stats"])-1] + + prevCpuTime = 0 + prevTimestamp = 0 + if len(self.vms[name]["stats"]) > 0: + prevTimestamp = self.vms[name]["stats"][0]["timestamp"] + prevCpuTime = self.vms[name]["stats"][0]["absCpuTime"] + + print str(now-prevTimestamp) + print str(info[4]-prevCpuTime) + print str((now - prevTimestamp)*1000 * 1000) + print + pcentCpuTime = (info[4]-prevCpuTime) * 100 / ((now - prevTimestamp)*1000 * 1000*1000) + + newStats = [{ "timestamp": now, + "status": info[0], + "absCpuTime": info[4], + "relCpuTime": (info[4]-prevCpuTime), + "pcentCpuTime": pcentCpuTime, + "currMem": info[2], + "maxMem": info[1] }] + totalCpuTime = totalCpuTime + newStats[0]["relCpuTime"] + newStats.append(self.vms[name]["stats"]) + self.vms[name]["stats"] = newStats + + def current_memory(self, name): + return self.vms[name]["stats"][0]["currMem"] + + def maximum_memory(self, name): + return self.vms[name]["stats"][0]["maxMem"] + + def percent_cpu_time(self, name): + return self.vms[name]["stats"][0]["pcentCpuTime"] + + def run_status(self, name): + status = self.vms[name]["stats"][0]["status"] + if status == libvirt.VIR_DOMAIN_NOSTATE: + return "Idle" + elif status == libvirt.VIR_DOMAIN_RUNNING: + return "Running" + elif status == libvirt.VIR_DOMAIN_BLOCKED: + return "Blocked" + elif status == libvirt.VIR_DOMAIN_PAUSED: + return "Paused" + elif status == libvirt.VIR_DOMAIN_SHUTDOWN: + return "Shutdown" + elif status == libvirt.VIR_DOMAIN_SHUTOFF: + return "Shutoff" + elif status == libvirt.VIR_DOMAIN_CRASHED: + return "Crashed" + else: + raise "Unknown status code" + # Run me! def main(): |