mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-02-14 01:57:44 +03:00
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:
parent
59698423fd
commit
d0fb572419
@ -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)
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user