[PATCH] virt-manager: show serial/parallel devices

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The attached patch teaches virt-manager how to parse VM
character devices, showing them in the details section.
This patch also implements removing these devices.

There are a couple quirks though:

1) All the possible character device xml properties
   aren't accounted for. This only parses target port,
   device type, and source path. I figure this covers
   the common cases, and is easily expandable.

2) Explicit entries are only set for serial and parallel
   devices, not console devices. Since by default, console
   is really just a duplicate of the first serial device,
   we try to detect this and label said serial device as
   appropriately (seen in the second screen shot).
   This simplifies things a good deal, and makes deleting
   easier, since in order to remove the console or 
   first serial device, both xml blocks need to be removed
   simultaneously (not sure if this is a libvirt bug or not).

I've posted a couple screenshots to give a better idea:

Parallel device:
http://crobinso.fedorapeople.org/virt-manager/vmm-parallel.png

Serial device that is also the console device:
http://crobinso.fedorapeople.org/virt-manager/vmm-serial.png

Thanks,
Cole
# HG changeset patch
# User "Cole Robinson <crobinso@xxxxxxxxxx>"
# Date 1216924902 14400
# Node ID 2bbb1937e47b24db7257288117f0a9c5e50ee694
# Parent  8ff3fe2b729ea60b9393dfb778067007a03e2e4b
Populate serial and parallel devices in details section. Allow deleting them as well.

diff -r 8ff3fe2b729e -r 2bbb1937e47b src/virtManager/details.py
--- a/src/virtManager/details.py	Fri Jul 18 21:34:13 2008 -0400
+++ b/src/virtManager/details.py	Thu Jul 24 14:41:42 2008 -0400
@@ -56,6 +56,7 @@
 HW_LIST_TYPE_INPUT = 5
 HW_LIST_TYPE_GRAPHICS = 6
 HW_LIST_TYPE_SOUND = 7
+HW_LIST_TYPE_CHAR = 8
 
 # Console pages
 PAGE_UNAVAILABLE = 0
@@ -254,6 +255,7 @@
             "on_config_input_remove_clicked": self.remove_input,
             "on_config_graphics_remove_clicked": self.remove_graphics,
             "on_config_sound_remove_clicked": self.remove_sound,
+            "on_config_char_remove_clicked": self.remove_char,
             "on_add_hardware_button_clicked": self.add_hardware,
 
             "on_details_menu_view_fullscreen_activate": self.toggle_fullscreen,
@@ -541,6 +543,8 @@
                 self.refresh_graphics_page()
             elif pagetype == HW_LIST_TYPE_SOUND:
                 self.refresh_sound_page()
+            elif pagetype == HW_LIST_TYPE_CHAR:
+                self.refresh_char_page()
             elif pagetype == HW_LIST_TYPE_BOOT:
                 self.refresh_boot_page()
                 self.window.get_widget("config-boot-options-apply").set_sensitive(False)
@@ -727,6 +731,8 @@
                     self.refresh_graphics_page()
                 elif pagetype == HW_LIST_TYPE_SOUND:
                     self.refresh_sound_page()
+                elif pagetype == HW_LIST_TYPE_CHAR:
+                    self.refresh_char_page()
 
     def refresh_summary(self):
         self.window.get_widget("overview-cpu-usage-text").set_text("%d %%" % self.vm.cpu_time_percentage())
@@ -911,6 +917,26 @@
             self.window.get_widget("config-sound-remove").set_sensitive(False)
         else:
             self.window.get_widget("config-sound-remove").set_sensitive(True)
+
+    def refresh_char_page(self):
+        vmlist = self.window.get_widget("hw-list")
+        selection = vmlist.get_selection()
+        active = selection.get_selected()
+        if active[1] is None:
+            return
+        char = active[0].get_value(active[1], HW_LIST_COL_DEVICE)
+        typelabel = "<b>%s Device %s</b>" % (char[0].capitalize(),
+                                             char[5] and _("(Primary Console)") or "")
+        self.window.get_widget("char-type").set_markup(typelabel)
+        self.window.get_widget("char-dev-type").set_text(char[1] or "-")
+        self.window.get_widget("char-target-port").set_text(char[2])
+        self.window.get_widget("char-source-path").set_text(char[4] or "-")
+
+        # Can't remove char dev from live guest
+        if self.vm.is_active():
+            self.window.get_widget("config-char-remove").set_sensitive(False)
+        else:
+            self.window.get_widget("config-char-remove").set_sensitive(True)
 
     def refresh_boot_page(self):
         # Refresh autostart
@@ -1330,6 +1356,20 @@
         self.remove_device(xml)
         self.refresh_resources()
 
+    def remove_char(self, src):
+        vmlist = self.window.get_widget("hw-list")
+        selection = vmlist.get_selection()
+        active = selection.get_selected()
+        if active[1] is None:
+            return
+        char = active[0].get_value(active[1], HW_LIST_COL_DEVICE)
+
+        xml = "<%s>\n" % char[0] + \
+              "  <target port='%s'/>\n" % char[2] + \
+              "</%s>" % char[0]
+        self.remove_device(xml)
+        self.refresh_resources()
+
     def prepare_hw_list(self):
         hw_list_model = gtk.ListStore(str, str, int, gtk.gdk.Pixbuf, int, gobject.TYPE_PYOBJECT)
         self.window.get_widget("hw-list").set_model(hw_list_model)
@@ -1479,6 +1519,27 @@
             if missing:
                 hw_list_model.insert(insertAt, [_("Sound: %s" % sound[3]), gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_LARGE_TOOLBAR, None, HW_LIST_TYPE_SOUND, sound])
 
+
+        # Populate list of char devices
+        currentChars = {}
+        for char in self.vm.get_char_devices():
+            missing = True
+            insertAt = 0
+            currentChars[char[3]] = 1
+            for row in hw_list_model:
+                if row[HW_LIST_COL_TYPE] == HW_LIST_TYPE_CHAR and \
+                   row[HW_LIST_COL_DEVICE][3] == char[3]:
+                    # Update metadata
+                    row[HW_LIST_COL_DEVICE] = char
+                    missing = False
+
+                if row[HW_LIST_COL_TYPE] <= HW_LIST_TYPE_CHAR:
+                    insertAt = insertAt + 1
+            # Add in row
+            if missing:
+                hw_list_model.insert(insertAt, ["%s %s" % (char[0].capitalize(), char[2]), gtk.STOCK_CONNECT, gtk.ICON_SIZE_LARGE_TOOLBAR, None, HW_LIST_TYPE_CHAR, char])
+
+
         # Now remove any no longer current devs
         devs = range(len(hw_list_model))
         devs.reverse()
@@ -1497,6 +1558,9 @@
                 removeIt = True
             elif row[HW_LIST_COL_TYPE] == HW_LIST_TYPE_SOUND and not \
                  currentSounds.has_key(row[HW_LIST_COL_DEVICE][3]):
+                removeIt = True
+            elif row[HW_LIST_COL_TYPE] == HW_LIST_TYPE_CHAR and not \
+                 currentChars.has_key(row[HW_LIST_COL_DEVICE][3]):
                 removeIt = True
 
             if removeIt:
diff -r 8ff3fe2b729e -r 2bbb1937e47b src/virtManager/domain.py
--- a/src/virtManager/domain.py	Fri Jul 18 21:34:13 2008 -0400
+++ b/src/virtManager/domain.py	Thu Jul 24 14:41:42 2008 -0400
@@ -702,6 +702,46 @@
 
         return self._parse_device_xml(_parse_sound_devs)
 
+    def get_char_devices(self):
+        def _parse_char_devs(ctx):
+            chars = []
+            devs  = []
+            cons = ctx.xpathEval("/domain/devices/console")
+            devs.extend(ctx.xpathEval("/domain/devices/parallel"))
+            devs.extend(ctx.xpathEval("/domain/devices/serial"))
+
+            # Since there is only one 'console' device ever in the xml
+            # find its port (if present)
+            cons_port = None
+            for node in cons:
+                for child in node.children:
+                    if child.name == "target":
+                        cons_port = child.prop("port")
+
+            for node in devs:
+                char_type = node.name
+                dev_type = node.prop("type")
+                target_port = None
+                source_path = None
+                console_dev = False
+
+                for child in node.children:
+                    if child.name == "target":
+                        target_port = child.prop("port")
+                    if child.name == "source":
+                        source_path = child.prop("path")
+
+                if node.name == "serial" and target_port == cons_port:
+                    # Console is just a dupe of this serial device
+                    console_dev = True
+
+                chars.append([char_type, dev_type, target_port,
+                              "%s:%s" % (char_type, target_port),
+                              source_path, console_dev])
+            return chars
+
+        return self._parse_device_xml(_parse_char_devs)
+
     def _parse_device_xml(self, parse_function):
         doc = None
         ctx = None
@@ -803,6 +843,30 @@
                 if len(model) > 0 and model[0].content != None:
                     logging.debug("Looking for type %s" % model[0].content)
                     ret = ctx.xpathEval("/domain/devices/sound[@model='%s']" % model[0].content)
+
+            elif dev_type == "parallel" or dev_type == "console" or \
+                 dev_type == "serial":
+                 port = dev_ctx.xpathEval("/%s/target/@port" % dev_type)
+                 if port and len(port) > 0 and port[0].content != None:
+                    logging.debug("Looking for %s w/ port %s" % (dev_type,
+                                                                 port))
+                    ret = ctx.xpathEval("/domain/devices/%s[target/@port='%s']" % (dev_type, port[0].content))
+
+                    # If serial and console are both present, console is
+                    # probably (always?) just a dup of the 'primary' serial
+                    # device. Try and find an associated console device with
+                    # the same port and remove that as well, otherwise the
+                    # removal doesn't go through
+                    if dev_type == "serial":
+                        cons_ret = ctx.xpathEval("/domain/devices/console[target/@port='%s']" % port[0].content)
+                        if cons_ret and len(cons_ret) > 0:
+                            logging.debug("Also removing console device "
+                                          "associated with serial dev.")
+                            cons_ret[0].unlinkNode()
+                            cons_ret[0].freeNode()
+                        else:
+                            logging.debug("No console device found associated "
+                                          "with passed serial devices")
 
             else:
                 raise RuntimeError, _("Unknown device type device type '%s'" %
diff -r 8ff3fe2b729e -r 2bbb1937e47b src/vmm-details.glade
--- a/src/vmm-details.glade	Fri Jul 18 21:34:13 2008 -0400
+++ b/src/vmm-details.glade	Thu Jul 24 14:41:42 2008 -0400
@@ -1550,7 +1550,7 @@
 	    <widget class="GtkHPaned" id="hpaned1">
 	      <property name="visible">True</property>
 	      <property name="can_focus">True</property>
-	      <property name="position">200</property>
+	      <property name="position">230</property>
 
 	      <child>
 		<widget class="GtkVBox" id="vbox53">
@@ -4658,6 +4658,299 @@
 		      <property name="type">tab</property>
 		    </packing>
 		  </child>
+
+		  <child>
+		    <widget class="GtkVBox" id="vbox59">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">0</property>
+
+		      <child>
+			<widget class="GtkFrame" id="frame14">
+			  <property name="visible">True</property>
+			  <property name="label_xalign">0</property>
+			  <property name="label_yalign">0.5</property>
+			  <property name="shadow_type">GTK_SHADOW_NONE</property>
+
+			  <child>
+			    <widget class="GtkAlignment" id="alignment160">
+			      <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="table37">
+				  <property name="border_width">3</property>
+				  <property name="visible">True</property>
+				  <property name="n_rows">3</property>
+				  <property name="n_columns">2</property>
+				  <property name="homogeneous">False</property>
+				  <property name="row_spacing">3</property>
+				  <property name="column_spacing">3</property>
+
+				  <child>
+				    <widget class="GtkLabel" id="label503">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">Device Type:</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">1</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="label504">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">Target Port:</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">1</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="GtkLabel" id="label505">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">Source Path:</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">1</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">2</property>
+				      <property name="bottom_attach">3</property>
+				      <property name="x_options">fill</property>
+				      <property name="y_options"></property>
+				    </packing>
+				  </child>
+
+				  <child>
+				    <widget class="GtkLabel" id="char-dev-type">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">label506</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">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="char-target-port">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">label507</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">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>
+
+				  <child>
+				    <widget class="GtkLabel" id="char-source-path">
+				      <property name="visible">True</property>
+				      <property name="label" translatable="yes">label508</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">1</property>
+				      <property name="right_attach">2</property>
+				      <property name="top_attach">2</property>
+				      <property name="bottom_attach">3</property>
+				      <property name="x_options">fill</property>
+				      <property name="y_options"></property>
+				    </packing>
+				  </child>
+				</widget>
+			      </child>
+			    </widget>
+			  </child>
+
+			  <child>
+			    <widget class="GtkLabel" id="char-type">
+			      <property name="visible">True</property>
+			      <property name="label" translatable="yes">&lt;b&gt;insert type&lt;/b&gt;</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">15</property>
+			  <property name="expand">True</property>
+			  <property name="fill">True</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkHButtonBox" id="hbuttonbox15">
+			  <property name="border_width">6</property>
+			  <property name="visible">True</property>
+			  <property name="layout_style">GTK_BUTTONBOX_END</property>
+			  <property name="spacing">0</property>
+
+			  <child>
+			    <widget class="GtkButton" id="config-char-remove">
+			      <property name="visible">True</property>
+			      <property name="can_default">True</property>
+			      <property name="can_focus">True</property>
+			      <property name="label">gtk-remove</property>
+			      <property name="use_stock">True</property>
+			      <property name="relief">GTK_RELIEF_NORMAL</property>
+			      <property name="focus_on_click">True</property>
+			      <signal name="clicked" handler="on_config_char_remove_clicked" last_modification_time="Sat, 19 Jul 2008 01:39:51 GMT"/>
+			    </widget>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">True</property>
+			</packing>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="tab_expand">False</property>
+		      <property name="tab_fill">True</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label501">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Char</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.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">tab</property>
+		    </packing>
+		  </child>
 		</widget>
 		<packing>
 		  <property name="shrink">True</property>
_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

[Index of Archives]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux