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

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



Cole Robinson wrote:
> 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.
> 

Second cut of this patch. Issues resolved:

- Removed the check box, unconditionally poll for
  connections if the user selects a remote conn
  option.

- Only use advertised 'name' as the list entry.

- Don't add duplicate list entries.

- If creating the initial avahi dbus interface
  fails, just disable all polling, and never
  activate the connection list.

- Sort list entries alphabetically by default,
  and add ability to sort ascend/descend

Thanks,
Cole

diff -r 0c2ab6040585 src/virtManager/connect.py
--- a/src/virtManager/connect.py	Fri Aug 22 13:41:17 2008 -0400
+++ b/src/virtManager/connect.py	Fri Aug 22 14:51:15 2008 -0400
@@ -23,6 +23,7 @@
 import os
 import virtinst
 import logging
+import dbus
 
 HV_XEN = 0
 HV_QEMU = 1
@@ -53,6 +54,9 @@
             "on_vmm_open_connection_delete_event": self.cancel,
             })
 
+        self.browser = None
+        self.can_browse = False
+
         default = virtinst.util.default_connection()
         if default is None:
             self.window.get_widget("hypervisor").set_active(-1)
@@ -65,6 +69,29 @@
         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)
+
+        nameCol = gtk.TreeViewColumn(_("Name"))
+        name_txt = gtk.CellRendererText()
+        nameCol.pack_start(name_txt, True)
+        nameCol.add_attribute(name_txt, "text", 2)
+        nameCol.set_sort_column_id(2)
+        self.window.get_widget("conn-list").append_column(nameCol)
+        connListModel.set_sort_column_id(2, gtk.SORT_ASCENDING)
+
+        self.window.get_widget("conn-list").get_selection().connect("changed", self.conn_selected)
+
+        self.bus = dbus.SystemBus()
+        try:
+            self.server = dbus.Interface(self.bus.get_object("org.freedesktop.Avahi", "/"), "org.freedesktop.Avahi.Server")
+            self.can_browse = True
+        except Exception, e:
+            logging.debug("Couldn't contact avahi: %s" % str(e))
+            self.server = None
+            self.can_browse = False
+
+        self.reset_state()
 
 
     def cancel(self,ignore1=None,ignore2=None):
@@ -74,21 +101,112 @@
 
     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-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)
+            if self.can_browse:
+                self.window.get_widget("conn-list").set_sensitive(True)
+                self.start_browse()
         else:
+            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)
+            self.stop_browse()
+
+    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()
+            for row in model:
+                if row[2] == str(name):
+                    return
+            model.append([str(address), self.sanitize_hostname(str(host)),
+                          str(name)])
+        except Exception, e:
+            logging.exception(e)
+
+    def start_browse(self):
+        if self.browser or not self.can_browse:
+            return
+        # 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], 0)
+        host = active[0].get_value(active[1], 1)
+        host = self.sanitize_hostname(host)
+        entry = host
+        if not entry:
+            entry = ip
+        self.window.get_widget("hostname").set_text(entry)
 
     def open_connection(self, src):
         hv = self.window.get_widget("hypervisor").get_active()
@@ -125,4 +243,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 0c2ab6040585 src/vmm-open-connection.glade
--- a/src/vmm-open-connection.glade	Fri Aug 22 13:41:17 2008 -0400
+++ b/src/vmm-open-connection.glade	Fri Aug 22 14:51:15 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">5</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>
@@ -307,16 +255,49 @@
 	  </child>
 
 	  <child>
-	    <widget class="GtkLabel" id="label90">
+	    <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="label" translatable="yes">Autoconnect
-   At Startup:</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">2</property>
+	      <property name="bottom_attach">3</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">1</property>
+	      <property name="xalign">0</property>
 	      <property name="yalign">0.5</property>
 	      <property name="xpad">0</property>
 	      <property name="ypad">0</property>
@@ -330,6 +311,59 @@
 	      <property name="right_attach">1</property>
 	      <property name="top_attach">3</property>
 	      <property name="bottom_attach">4</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">3</property>
+	      <property name="bottom_attach">4</property>
+	      <property name="y_options"></property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkLabel" id="label90">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">Autoconnect
+   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">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>
@@ -350,8 +384,8 @@
 	    <packing>
 	      <property name="left_attach">1</property>
 	      <property name="right_attach">2</property>
-	      <property name="top_attach">3</property>
-	      <property name="bottom_attach">4</property>
+	      <property name="top_attach">4</property>
+	      <property name="bottom_attach">5</property>
 	      <property name="x_padding">7</property>
 	      <property name="x_options">fill</property>
 	      <property name="y_options"></property>

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