The attached patch adds support for avahi polling to the virt-manager 'Open Connection' dialog. libvirtd advertises itself via avahi so we get the hard stuff for free :). To test this you will need to make sure Multicast DNS (mDNS, port 5353 udp) is open on your machine. I had a few more screenshots but fedorapeople isn't responding. The basic flow is: 'Open Conn' defaults to selecting a local connection, so the 'browse' checkbox and list are inactive. If a remote conn type is selected, the 'browse' checkbox and 'hostname' field become active, but we don't immediately default to actually browsing the network. Once the 'browse' checkbox is clicked the list becomes active and starts asynchronously populating. When an entry in the list is selected its hostname (or IP address if the hostname wasn't resolved) is placed in the "hostname" field. Thanks, Cole
# HG changeset patch # User "Cole Robinson <crobinso@xxxxxxxxxx>" # Date 1219071936 14400 # Node ID 19528b5595715d4d2779097a44c283d7e214e725 # Parent da5c4a5581fee539ff6bf99b1edc74d16438a279 Add avahi browsing to 'Open Connection' dialog. diff -r da5c4a5581fe -r 19528b559571 src/virtManager/connect.py --- a/src/virtManager/connect.py Mon Aug 18 11:02:56 2008 -0400 +++ b/src/virtManager/connect.py Mon Aug 18 11:05:36 2008 -0400 @@ -23,6 +23,7 @@ import os import virtinst import logging +import dbus HV_XEN = 0 HV_QEMU = 1 @@ -48,6 +49,7 @@ self.window.signal_autoconnect({ "on_connection_changed": self.update_widget_states, + "on_conn_browse_toggled": self.browse_toggled, "on_cancel_clicked": self.cancel, "on_connect_clicked": self.open_connection, "on_vmm_open_connection_delete_event": self.cancel, @@ -65,6 +67,31 @@ self.window.get_widget("connect").grab_default() self.window.get_widget("autoconnect").set_active(True) + connListModel = gtk.ListStore(str, str, str) + self.window.get_widget("conn-list").set_model(connListModel) + + ipCol = gtk.TreeViewColumn(_("IP Address")) + ip_txt = gtk.CellRendererText() + ipCol.pack_start(ip_txt, True) + ipCol.add_attribute(ip_txt, "text", 1) + ipCol.set_expand(True) + self.window.get_widget("conn-list").append_column(ipCol) + + hostCol = gtk.TreeViewColumn(_("Hostname")) + host_txt = gtk.CellRendererText() + hostCol.pack_start(host_txt, True) + hostCol.add_attribute(host_txt, "text", 2) + hostCol.set_expand(True) + self.window.get_widget("conn-list").append_column(hostCol) + + self.window.get_widget("conn-list").get_selection().connect("changed", self.conn_selected) + + self.browser = None + self.bus = dbus.SystemBus() + self.server = dbus.Interface(self.bus.get_object("org.freedesktop.Avahi", "/") + , "org.freedesktop.Avahi.Server") + + self.reset_state() def cancel(self,ignore1=None,ignore2=None): @@ -74,21 +101,119 @@ def close(self): self.window.get_widget("vmm-open-connection").hide() + self.stop_browse() def show(self): win = self.window.get_widget("vmm-open-connection") win.show_all() win.present() + self.reset_state() + + def reset_state(self): + self.window.get_widget("hypervisor").set_active(0) + self.window.get_widget("autoconnect").set_sensitive(True) + self.window.get_widget("autoconnect").set_active(True) + self.window.get_widget("conn-browse").set_active(False) + self.window.get_widget("conn-browse").set_sensitive(False) + self.window.get_widget("conn-list").set_sensitive(False) + self.window.get_widget("conn-list").get_model().clear() + self.window.get_widget("hostname").set_text("") + self.stop_browse() def update_widget_states(self, src): if src.get_active() > 0: self.window.get_widget("hostname").set_sensitive(True) self.window.get_widget("autoconnect").set_active(False) - self.window.get_widget("autoconnect").set_sensitive(False) + self.window.get_widget("autoconnect").set_sensitive(True) + self.window.get_widget("conn-browse").set_sensitive(True) + if self.window.get_widget("conn-browse").get_active(): + self.window.get_widget("conn-list").set_sensitive(True) else: + self.window.get_widget("conn-browse").set_sensitive(False) + self.window.get_widget("conn-list").set_sensitive(False) self.window.get_widget("hostname").set_sensitive(False) + self.window.get_widget("hostname").set_text("") self.window.get_widget("autoconnect").set_sensitive(True) self.window.get_widget("autoconnect").set_active(True) + + def add_service(self, interface, protocol, name, type, domain, flags): + try: + # Async service resolving + res = self.server.ServiceResolverNew(interface, protocol, name, + type, domain, -1, 0) + resint = dbus.Interface(self.bus.get_object("org.freedesktop.Avahi", + res), + "org.freedesktop.Avahi.ServiceResolver") + resint.connect_to_signal("Found", self.add_conn_to_list) + # Synchronous service resolving + #self.server.ResolveService(interface, protocol, name, type, + # domain, -1, 0) + except Exception, e: + logging.exception(e) + + def remove_service(self, interface, protocol, name, type, domain, flags): + try: + model = self.window.get_widget("conn-list").get_model() + name = str(name) + for row in model: + if row[0] == name: + model.remove(row.iter) + except Exception, e: + logging.exception(e) + + def add_conn_to_list(self, interface, protocol, name, type, domain, + host, aprotocol, address, port, text, flags): + try: + model = self.window.get_widget("conn-list").get_model() + model.append([str(name), str(address), + self.sanitize_hostname(str(host))]) + except Exception, e: + logging.exception(e) + + def start_browse(self): + # Call method to create new browser, and get back an object path for it. + interface = -1 # physical interface to use? -1 is unspec + protocol = 0 # 0 = IPv4, 1 = IPv6, -1 = Unspecified + service = '_libvirt._tcp' # Service name to poll for + flags = 0 # Extra option flags + domain = "" # Domain to browse in. NULL uses default + bpath = self.server.ServiceBrowserNew(interface, protocol, service, + domain, flags) + + # Create browser interface for the new object + self.browser = dbus.Interface(self.bus.get_object("org.freedesktop.Avahi", + bpath), + "org.freedesktop.Avahi.ServiceBrowser") + + self.browser.connect_to_signal("ItemNew", self.add_service) + self.browser.connect_to_signal("ItemRemove", self.remove_service) + + def stop_browse(self): + if self.browser: + del(self.browser) + self.browser = None + + def conn_selected(self, src): + active = src.get_selected() + if active[1] == None: + return + ip = active[0].get_value(active[1], 1) + host = active[0].get_value(active[1], 2) + host = self.sanitize_hostname(host) + entry = host + if not entry: + entry = ip + self.window.get_widget("hostname").set_text(entry) + + def browse_toggled(self, src): + active = src.get_active() + if active: + self.window.get_widget("conn-list").set_sensitive(True) + self.start_browse() + else: + self.stop_browse() + self.window.get_widget("conn-list").set_sensitive(False) + self.window.get_widget("conn-list").get_model().clear() def open_connection(self, src): hv = self.window.get_widget("hypervisor").get_active() @@ -125,4 +250,18 @@ self.close() self.emit("completed", uri, readOnly, auto) + def sanitize_hostname(self, host): + if host.endswith(".local"): + host = host[:-6] + if host == "linux" or host == "localhost": + host = "" + if host.startswith("linux-"): + tmphost = host[6:] + try: + tmp = long(tmphost) + host = "" + except ValueError: + pass + return host + gobject.type_register(vmmConnect) diff -r da5c4a5581fe -r 19528b559571 src/vmm-open-connection.glade --- a/src/vmm-open-connection.glade Mon Aug 18 11:02:56 2008 -0400 +++ b/src/vmm-open-connection.glade Mon Aug 18 11:05:36 2008 -0400 @@ -146,35 +146,11 @@ <widget class="GtkTable" id="table1"> <property name="border_width">6</property> <property name="visible">True</property> - <property name="n_rows">4</property> + <property name="n_rows">6</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="GtkEntry" id="hostname"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="editable">True</property> - <property name="visibility">True</property> - <property name="max_length">0</property> - <property name="text" translatable="yes"></property> - <property name="has_frame">True</property> - <property name="invisible_char">â?¢</property> - <property name="activates_default">False</property> - <accessibility> - <atkproperty name="AtkObject::accessible_name" translatable="yes">Hostname Field</atkproperty> - </accessibility> - </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="y_options"></property> - </packing> - </child> <child> <widget class="GtkComboBox" id="connection"> @@ -201,34 +177,6 @@ </child> <child> - <widget class="GtkLabel" id="label89"> - <property name="visible">True</property> - <property name="label" translatable="yes">Hostname:</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="label88"> <property name="visible">True</property> <property name="label" translatable="yes">Connection:</property> @@ -237,7 +185,7 @@ <property name="justify">GTK_JUSTIFY_LEFT</property> <property name="wrap">False</property> <property name="selectable">False</property> - <property name="xalign">1</property> + <property name="xalign">0</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> @@ -265,7 +213,7 @@ <property name="justify">GTK_JUSTIFY_LEFT</property> <property name="wrap">False</property> <property name="selectable">False</property> - <property name="xalign">1</property> + <property name="xalign">0</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> @@ -310,13 +258,13 @@ <widget class="GtkLabel" id="label90"> <property name="visible">True</property> <property name="label" translatable="yes">Autoconnect - At Startup:</property> + at Startup:</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="xalign">0</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> @@ -328,8 +276,8 @@ <packing> <property name="left_attach">0</property> <property name="right_attach">1</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> <property name="x_options">fill</property> <property name="y_options"></property> </packing> @@ -350,9 +298,118 @@ <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> + <property name="x_padding">7</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="hostname"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">â?¢</property> + <property name="activates_default">False</property> + <accessibility> + <atkproperty name="AtkObject::accessible_name" translatable="yes">Hostname Field</atkproperty> + </accessibility> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="border_width">3</property> + <property name="width_request">70</property> + <property name="height_request">220</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="conn-list"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">2</property> <property name="top_attach">3</property> <property name="bottom_attach">4</property> - <property name="x_padding">7</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label91"> + <property name="visible">True</property> + <property name="label" translatable="yes">Hostname:</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">0</property> + <property name="right_attach">1</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="conn-browse"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Browse Connections</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_conn_browse_toggled" last_modification_time="Mon, 18 Aug 2008 01:30:24 GMT"/> + </widget> + <packing> + <property name="left_attach">0</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>
_______________________________________________ et-mgmt-tools mailing list et-mgmt-tools@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/et-mgmt-tools