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@xxxxxxxxxx > 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 :| _______________________________________________ et-mgmt-tools mailing list et-mgmt-tools@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/et-mgmt-tools