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

[et-mgmt-tools] [PATCH] virt-manager: Use avahi to poll for local servers



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 redhat com>"
# 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>

PNG image


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