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

Daniel P. Berrange berrange at redhat.com
Tue Jul 29 08:39:33 UTC 2008


On Mon, Jul 28, 2008 at 11:51:49AM -0400, Cole Robinson wrote:
> 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 think that is probably a bug. Can you re-test with the latest
CVS snapshot of libvirt where I've changed the handling a little
bit. Basically you should never need to add or remove a 'console'
device explicitly. Either it is there permanently (eg, Xen PV
always has a console), or it is automatically added/removed when
the first serial device is added or removed. 


> 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"><b>insert type</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">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 at redhat.com
> https://www.redhat.com/mailman/listinfo/et-mgmt-tools

-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the et-mgmt-tools mailing list