From 3ed0ef34589a49b32db8601a1b784dbbfe7d92c8 Mon Sep 17 00:00:00 2001 From: "berrange@roquette.boston.redhat.com" Date: Tue, 28 Mar 2006 12:13:50 -0500 Subject: [PATCH] Initial commit of manager app --- gnome-vm-manager.glade | 1743 ++++++++++++++++++++++++++++++++++++++++ gnome-vm-manager.py | 242 ++++++ 2 files changed, 1985 insertions(+) create mode 100644 gnome-vm-manager.glade create mode 100755 gnome-vm-manager.py diff --git a/gnome-vm-manager.glade b/gnome-vm-manager.glade new file mode 100644 index 00000000..0f2e16b9 --- /dev/null +++ b/gnome-vm-manager.glade @@ -0,0 +1,1743 @@ + + + + + + + True + Virtual Machine Manager + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 600 + 500 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + True + False + 0 + + + + True + GTK_PACK_DIRECTION_LTR + GTK_PACK_DIRECTION_LTR + + + + True + _File + True + + + + + + + True + gtk-new + True + + + + + + + True + + + + + + True + gtk-quit + True + + + + + + + + + + + True + _Edit + True + + + + + + + True + Details + True + + + + + True + gtk-properties + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + gtk-delete + True + + + + + + + + + + + True + _View + True + + + + + + + True + Status + True + True + + + + + + + True + CPU usage + True + True + + + + + + + True + Memory usage + True + True + + + + + + + True + Disk usage + True + True + + + + + + + True + Network traffic + True + True + + + + + + + + + + + True + _Help + True + + + + + + + True + gtk-about + True + + + + + + + + + + 0 + False + False + + + + + + 3 + True + False + 0 + + + + True + _View: + True + False + GTK_JUSTIFY_RIGHT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + + True + All virtual machines +Active virtual machines +Inactive virtual machines + False + True + + + 0 + False + True + + + + + 0 + False + True + + + + + + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + False + True + False + False + False + + + + + 0 + True + True + + + + + + 3 + True + GTK_BUTTONBOX_END + 3 + + + + True + True + True + gtk-delete + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + gtk-new + True + GTK_RELIEF_NORMAL + True + + + + + + + True + True + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-dialog-info + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Details + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + True + True + True + gtk-open + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + True + + + + + + True + + + 10 + False + True + + + + + + 3 + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + gtk-help + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + False + True + + + + + + + + True + True + Virtual Machine Manager + Copyright (C) 2006 Red Hat Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + False + Daniel P. Berrange <berrange@redhat.com> + translator-credits + + + + True + Virtual Machine Details + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + True + True + + + + True + Run + True + gtk-media-play + True + True + False + + + False + True + + + + + + True + gtk-media-pause + True + True + False + + + False + True + + + + + + True + Shutdown + True + gtk-stop + True + True + False + + + False + True + + + + + + True + True + True + True + + + False + False + + + + + + True + Launch console + True + gtk-dnd + True + True + False + + + False + True + + + + + + True + Take snapshot + True + gtk-media-record + True + True + False + + + False + True + + + + + 0 + False + True + + + + + + True + True + True + True + GTK_POS_TOP + False + False + + + + True + 8 + 3 + False + 3 + 3 + + + + True + <b>Basic Details:</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 3 + 0 + 1 + + + + + + + True + Name: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 10 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + False + True + False + True + 0 + + True + + False + + + 1 + 2 + 1 + 2 + + + + + + + True + Status: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 10 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + CPU usage: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 10 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 4 + 5 + fill + + + + + + + True + Memory usage: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 10 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 5 + 6 + fill + + + + + + + True + Network usage: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 10 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 6 + 7 + fill + + + + + + + True + Disk usage: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 10 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 7 + 8 + fill + + + + + + + True + <b>Performance:</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 3 + 3 + 4 + fill + + + + + + + True + 18% + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 4 + 5 + fill + + + + + + + True + 30 MB of 128 MB + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 5 + 6 + fill + + + + + + + True + 20 bits/sec + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 6 + 7 + fill + + + + + + + True + 80 MB of 1 GB + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 7 + 8 + fill + + + + + + + True + False + 0 + + + + True + gtk-stop + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + True + + + + + + True + Shut down + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + True + True + + + + + 1 + 2 + 2 + 3 + fill + fill + + + + + + True + 0 + 1 + 0 + 1 + + + 1 + 2 + 4 + 5 + fill + fill + + + + + + True + 0 + 1 + 0 + 1 + + + 1 + 2 + 5 + 6 + fill + fill + + + + + + True + 0 + 1 + 0 + 1 + + + 1 + 2 + 6 + 7 + fill + fill + + + + + + True + GTK_PROGRESS_LEFT_TO_RIGHT + 0.119999997318 + 0.10000000149 + PANGO_ELLIPSIZE_NONE + + + 1 + 2 + 7 + 8 + fill + + + + + + False + True + + + + + + True + Overview + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + True + False + 0 + + + + True + GTK_ORIENTATION_VERTICAL + GTK_TOOLBAR_BOTH + True + True + + + + True + CPU + True + gtk-refresh + True + True + False + True + + + False + True + + + + + + True + Memory + True + gtk-justify-fill + True + True + False + False + radiotoolbutton5 + + + False + True + + + + + + True + Ethernet + True + gtk-network + True + True + False + False + radiotoolbutton5 + + + False + True + + + + + + True + Hard drive + True + gtk-harddisk + True + True + False + False + radiotoolbutton5 + + + False + True + + + + + + True + Add hardware + True + gtk-add + True + True + False + False + radiotoolbutton5 + + + False + True + + + + + 0 + False + False + + + + + + True + False + True + GTK_POS_TOP + False + False + + + + + + + + True + label22 + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + True + False + 3 + + + + True + <b>Memory</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + True + + + + + + True + What is the maximum amount of memory this VM should be able to use? + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + GTK_POS_TOP + 1 + GTK_UPDATE_CONTINUOUS + False + 0 0 0 0 0 0 + + + 0 + False + True + + + + + + True + 2 + 2 + False + 3 + 3 + + + + True + Current usage: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + Total memory on host machine: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + 30 MB + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 0 + 1 + fill + + + + + + + True + 1 GB + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 1 + 2 + fill + + + + + + 0 + False + False + + + + + False + True + + + + + + True + label23 + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + + + + + True + label24 + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + + + + + True + label25 + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + + + + + True + label26 + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + 0 + True + True + + + + + False + True + + + + + + True + Hardware + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + 0 + True + True + + + + + + True + False + 0 + + + + 3 + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + True + True + gtk-help + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + True + + + + + + 3 + True + GTK_BUTTONBOX_END + 3 + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + + + + + 0 + True + True + + + + + 0 + False + True + + + + + + + diff --git a/gnome-vm-manager.py b/gnome-vm-manager.py new file mode 100755 index 00000000..15f76341 --- /dev/null +++ b/gnome-vm-manager.py @@ -0,0 +1,242 @@ +#!/usr/bin/python + +import gtk +import gobject +import gtk.gdk +import gtk.glade +import re +import os +import os.path +import libvirt + +tickrate = 5000 + +# Ought not to hardcode stuff as being in /usr +gladedir = "/usr/share/gnome-vm-manager" + +# Hack for dev purposes +if os.path.exists("./gnome-vm-manager.glade"): + gladedir = "." + +class vmmAbout: + def __init__(self): + self.window = gtk.glade.XML(gladedir + "/gnome-vm-manager.glade", "vm-about") + self.window.get_widget("vm-about").hide() + + def show(self): + dialog = self.window.get_widget("vm-about") + dialog.set_version("0.1") + dialog.show_all() + + +class vmmManager: + def __init__(self): + self.window = gtk.glade.XML(gladedir + "/gnome-vm-manager.glade", "vm-manager") + self.vmm = libvirt.openReadOnly(None) + #self.vmm = libvirt.open(None) + + self.stats = {} + + self.record_stats() + self.populate_vms() + self.tickrate = 5000 + self.about = None; + + self.timer = gobject.timeout_add(self.tickrate, self.refresh_stats) + + 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_vm_manager_delete_event": self.exit_app, + "on_menu_file_quit_activate": self.exit_app, + "on_vmm_close_clicked": self.exit_app, + + "on_menu_help_about_activate": self.show_about, + }) + + def exit_app(self, ignore=None,ignore2=None): + gtk.main_quit() + + + def show_about(self, ignore=None): + if self.about == None: + self.about = vmmAbout() + self.about.show() + + def refresh_stats(self): + self.record_stats() + self.timer = gobject.timeout_add(self.tickrate, self.refresh_stats) + + 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 + + def populate_vms(self): + vmlist = self.window.get_widget("vm-list") + + model = gtk.ListStore(str) + vmlist.set_model(model) + + nameCol = gtk.TreeViewColumn("Name") + statusCol = gtk.TreeViewColumn("Status") + cpuUsageCol = gtk.TreeViewColumn("CPU usage") + memoryUsageCol = gtk.TreeViewColumn("Memory usage") + diskUsageCol = gtk.TreeViewColumn("Disk usage") + networkUsageCol = gtk.TreeViewColumn("Network traffic") + + name_txt = gtk.CellRendererText() + nameCol.pack_start(name_txt, True) + nameCol.add_attribute(name_txt, 'text', 0) + + vmlist.append_column(nameCol) + vmlist.append_column(statusCol) + vmlist.append_column(cpuUsageCol) + vmlist.append_column(memoryUsageCol) + vmlist.append_column(diskUsageCol) + vmlist.append_column(networkUsageCol) + + status_txt = gtk.CellRendererText() + statusCol.pack_start(status_txt, True) + statusCol.set_cell_data_func(status_txt, self.status_text, None) + + cpuUsage_txt = gtk.CellRendererText() + cpuUsageCol.pack_start(cpuUsage_txt, True) + cpuUsageCol.set_cell_data_func(cpuUsage_txt, self.cpu_usage_text, None) + + memoryUsage_txt = gtk.CellRendererText() + memoryUsageCol.pack_start(memoryUsage_txt, True) + memoryUsageCol.set_cell_data_func(memoryUsage_txt, self.memory_usage_text, None) + + diskUsage_txt = gtk.CellRendererText() + diskUsageCol.pack_start(diskUsage_txt, True) + diskUsageCol.set_cell_data_func(diskUsage_txt, self.disk_usage_text, None) + + networkUsage_txt = gtk.CellRendererText() + networkUsageCol.pack_start(networkUsage_txt, True) + networkUsageCol.set_cell_data_func(networkUsage_txt, self.network_usage_text, None) + + doms = self.vmm.listDomainsID() + if doms != None: + for id in self.vmm.listDomainsID(): + vm = self.vmm.lookupByID(id) + model.append([vm.name()]) + + def toggle_status_column(self,menu): + vmlist = self.window.get_widget("vm-list") + col = vmlist.get_column(1) + col.set_visible(menu.get_active()) + + def toggle_cpu_column(self,menu): + vmlist = self.window.get_widget("vm-list") + col = vmlist.get_column(2) + col.set_visible(menu.get_active()) + + def toggle_memory_column(self,menu): + vmlist = self.window.get_widget("vm-list") + col = vmlist.get_column(3) + col.set_visible(menu.get_active()) + + def toggle_disk_column(self,menu): + vmlist = self.window.get_widget("vm-list") + col = vmlist.get_column(4) + col.set_visible(menu.get_active()) + + def toggle_network_column(self,menu): + vmlist = self.window.get_widget("vm-list") + col = vmlist.get_column(5) + col.set_visible(menu.get_active()) + + + 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") + + 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) + + 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]))) + #cell.set_property('text', self.pretty_mem(current[2])) + + def pretty_mem(self, mem): + if mem > (1024*1024): + return "%2.2f GB" % (mem/(1024.0*1024.0)) + else: + return "%2.2f MB" % (mem/1024.0) + + def disk_usage_text(self, column, cell, model, iter, data): + #cell.set_property('text', "600 MB of 1 GB") + cell.set_property('text', "-") + + def network_usage_text(self, column, cell, model, iter, data): + #cell.set_property('text', "100 bytes/sec") + cell.set_property('text', "-") + +# Run me! +def main(): + window = vmmManager() + gtk.main() + +if __name__ == "__main__": + main()