Add support for avahi libvirtd advertisement.

In the 'New Connection' dialog, poll for remote connections and allow
selecting the results from a list.
This commit is contained in:
Cole Robinson 2008-09-02 11:36:56 -04:00
parent 59698423fd
commit d0fb572419
2 changed files with 228 additions and 62 deletions

View File

@ -23,6 +23,7 @@ import gtk.glade
import os
import virtinst
import logging
import dbus
HV_XEN = 0
HV_QEMU = 1
@ -53,6 +54,9 @@ class vmmConnect(gobject.GObject):
"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 @@ class vmmConnect(gobject.GObject):
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 @@ class vmmConnect(gobject.GObject):
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 @@ class vmmConnect(gobject.GObject):
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)

View File

@ -146,36 +146,12 @@
<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">
<property name="visible">True</property>
@ -200,34 +176,6 @@ Remote tunnel over SSH</property>
</packing>
</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>
@ -237,7 +185,7 @@ Remote tunnel over SSH</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>
@ -265,7 +213,7 @@ Remote tunnel over SSH</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>
@ -307,16 +255,49 @@ QEMU</property>
</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>
@ -335,6 +316,59 @@ QEMU</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>
</child>
<child>
<widget class="GtkCheckButton" id="autoconnect">
<property name="visible">True</property>
@ -350,8 +384,8 @@ QEMU</property>
<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>