[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