from gi.repository import Gtk
from gi.repository import Pango
from virtinst import log
from .lib import uiutil
from .asyncjob import vmmAsyncJob
from .baseclass import vmmGObjectUI
from .createnet import vmmCreateNetwork
from .xmleditor import vmmXMLEditor
EDIT_NET_IDS = (
EDIT_NET_NAME,
EDIT_NET_AUTOSTART,
EDIT_NET_XML,
) = list(range(3))
ICON_RUNNING = "state_running"
ICON_SHUTOFF = "state_shutoff"
class vmmHostNets(vmmGObjectUI):
def __init__(self, conn, builder, topwin):
vmmGObjectUI.__init__(self, "hostnets.ui",
None, builder=builder, topwin=topwin)
self.conn = conn
self._addnet = None
self._xmleditor = None
self._active_edits = set()
self.top_box = self.widget("top-box")
self.builder.connect_signals({
"on_net_add_clicked": self._add_network_cb,
"on_net_delete_clicked": self._delete_network_cb,
"on_net_stop_clicked": self._stop_network_cb,
"on_net_start_clicked": self._start_network_cb,
"on_net_apply_clicked": (lambda *x: self._net_apply()),
"on_net_list_changed": self._net_selected_cb,
"on_net_autostart_toggled": (lambda *x:
self._enable_net_apply(EDIT_NET_AUTOSTART)),
"on_net_name_changed": (lambda *x:
self._enable_net_apply(EDIT_NET_NAME)),
})
self._init_ui()
self._populate_networks()
self._refresh_conn_state()
self.conn.connect("net-added", self._conn_nets_changed_cb)
self.conn.connect("net-removed", self._conn_nets_changed_cb)
self.conn.connect("state-changed", self._conn_state_changed_cb)
def _cleanup(self):
self.conn = None
if self._addnet:
self._addnet.cleanup()
self._addnet = None
self._xmleditor.cleanup()
self._xmleditor = None
def close(self, ignore1=None, ignore2=None):
if self._addnet:
self._addnet.close()
def _init_ui(self):
self.widget("network-pages").set_show_tabs(False)
self._xmleditor = vmmXMLEditor(self.builder, self.topwin,
self.widget("net-details-align"),
self.widget("net-details"))
self._xmleditor.connect("changed",
lambda s: self._enable_net_apply(EDIT_NET_XML))
self._xmleditor.connect("xml-requested",
self._xmleditor_xml_requested_cb)
self._xmleditor.connect("xml-reset",
self._xmleditor_xml_reset_cb)
netListModel = Gtk.ListStore(object, str, str, int, bool)
self.widget("net-list").set_model(netListModel)
sel = self.widget("net-list").get_selection()
sel.set_select_function((lambda *x: self._confirm_changes()), None)
netCol = Gtk.TreeViewColumn(_("Networks"))
netCol.set_spacing(6)
net_txt = Gtk.CellRendererText()
net_txt.set_property("ellipsize", Pango.EllipsizeMode.END)
net_img = Gtk.CellRendererPixbuf()
netCol.pack_start(net_img, False)
netCol.pack_start(net_txt, True)
netCol.add_attribute(net_txt, 'text', 1)
netCol.add_attribute(net_txt, 'sensitive', 4)
netCol.add_attribute(net_img, 'icon-name', 2)
netCol.add_attribute(net_img, 'stock-size', 3)
self.widget("net-list").append_column(netCol)
netListModel.set_sort_column_id(1, Gtk.SortType.ASCENDING)
def refresh_page(self):
self.conn.schedule_priority_tick(pollnet=True)
def _refresh_conn_state(self):
conn_active = self.conn.is_active()
self.widget("net-add").set_sensitive(conn_active and
self.conn.support.conn_network())
if conn_active and not self.conn.support.conn_network():
self._set_error_page(
_("Libvirt connection does not support virtual network "
"management."))
if conn_active:
uiutil.set_list_selection_by_number(self.widget("net-list"), 0)
return
self._populate_networks()
self._set_error_page(_("Connection not active."))
def _current_network(self):
return uiutil.get_list_selection(self.widget("net-list"))
def _set_error_page(self, msg):
self.widget("network-pages").set_current_page(1)
self.widget("network-error-label").set_text(msg)
self.widget("net-start").set_sensitive(False)
self.widget("net-stop").set_sensitive(False)
self.widget("net-delete").set_sensitive(False)
self._disable_net_apply()
def _refresh_current_network(self):
net = self._current_network()
if not net:
self._set_error_page(_("No virtual network selected."))
return
self.widget("network-pages").set_current_page(0)
try:
self._populate_net_state(net)
except Exception as e:
log.exception(e)
self._set_error_page(_("Error selecting network: %s") % e)
self._disable_net_apply()
def _populate_networks(self):
net_list = self.widget("net-list")
curnet = self._current_network()
model = net_list.get_model()
net_list.set_model(None)
try:
net_list.get_selection().unselect_all()
model.clear()
for net in self.conn.list_nets():
net.disconnect_by_obj(self)
net.connect("state-changed", self._net_state_changed_cb)
model.append([net, net.get_name(), "network-idle",
Gtk.IconSize.LARGE_TOOLBAR,
bool(net.is_active())])
finally:
net_list.set_model(model)
uiutil.set_list_selection(net_list, curnet)
def _populate_net_ipv4_state(self, net):
(netstr, (dhcpstart, dhcpend)) = net.get_ipv4_network()
self.widget("net-ipv4-expander").set_visible(bool(netstr))
if not netstr:
return
self.widget("net-ipv4-forwarding").set_text(net.pretty_forward_mode())
dhcpstr = _("Disabled")
if dhcpstart:
dhcpstr = dhcpstart + " - " + dhcpend
self.widget("net-ipv4-dhcp-range").set_text(dhcpstr)
self.widget("net-ipv4-network").set_text(netstr)
def _populate_net_ipv6_state(self, net):
(netstr, (dhcpstart, dhcpend)) = net.get_ipv6_network()
self.widget("net-ipv6-expander").set_visible(bool(netstr))
if netstr:
prettymode = _("Routed network")
elif net.get_ipv6_enabled():
prettymode = _("Isolated network, internal routing only")
else:
prettymode = _("Isolated network, routing disabled")
self.widget("net-ipv6-forwarding").set_text(prettymode)
dhcpstr = _("Disabled")
if dhcpstart:
dhcpstr = dhcpstart + " - " + dhcpend
self.widget("net-ipv6-dhcp-range").set_text(dhcpstr)
self.widget("net-ipv6-network").set_text(netstr or "")
def _populate_net_state(self, net):
active = net.is_active()
self.widget("net-details").set_sensitive(True)
self.widget("net-name").set_text(net.get_name())
self.widget("net-name").set_editable(not active)
self.widget("net-device").set_text(net.get_bridge_device() or "")
self.widget("net-name-domain").set_text(net.get_name_domain() or "")
uiutil.set_grid_row_visible(self.widget("net-name-domain"),
bool(net.get_name_domain()))
icon = (active and ICON_RUNNING or ICON_SHUTOFF)
self.widget("net-state").set_text(net.run_status())
self.widget("net-state-icon").set_from_icon_name(icon,
Gtk.IconSize.BUTTON)
self.widget("net-start").set_sensitive(not active)
self.widget("net-stop").set_sensitive(active)
self.widget("net-delete").set_sensitive(not active)
autostart = net.get_autostart()
self.widget("net-autostart").set_active(autostart)
self.widget("net-autostart").set_label(_("On Boot"))
self._populate_net_ipv4_state(net)
self._populate_net_ipv6_state(net)
self._xmleditor.set_xml_from_libvirtobject(net)
def _delete_network_cb(self, src):
net = self._current_network()
if net is None:
return
result = self.err.yes_no(_("Are you sure you want to permanently "
"delete the network %s?") % net.get_name())
if not result:
return
log.debug("Deleting network '%s'", net.get_name())
vmmAsyncJob.simple_async_noshow(net.delete, [], self,
_("Error deleting network '%s'") % net.get_name())
def _start_network_cb(self, src):
net = self._current_network()
if net is None:
return
log.debug("Starting network '%s'", net.get_name())
vmmAsyncJob.simple_async_noshow(net.start, [], self,
_("Error starting network '%s'") % net.get_name())
def _stop_network_cb(self, src):
net = self._current_network()
if net is None:
return
log.debug("Stopping network '%s'", net.get_name())
vmmAsyncJob.simple_async_noshow(net.stop, [], self,
_("Error stopping network '%s'") % net.get_name())
def _add_network_cb(self, src):
log.debug("Launching 'Add Network'")
try:
if self._addnet is None:
self._addnet = vmmCreateNetwork(self.conn)
self._addnet.show(self.topwin)
except Exception as e:
self.err.show_err(_("Error launching network wizard: %s") % str(e))
def _net_apply(self):
net = self._current_network()
if net is None:
return
log.debug("Applying changes for network '%s'", net.get_name())
try:
if EDIT_NET_AUTOSTART in self._active_edits:
auto = self.widget("net-autostart").get_active()
net.set_autostart(auto)
if EDIT_NET_NAME in self._active_edits:
net.define_name(self.widget("net-name").get_text())
self.idle_add(self._populate_networks)
if EDIT_NET_XML in self._active_edits:
net.define_xml(self._xmleditor.get_xml())
except Exception as e:
self.err.show_err(_("Error changing network settings: %s") % str(e))
return
finally:
self._disable_net_apply()
def _disable_net_apply(self):
self._active_edits = set()
self.widget("net-apply").set_sensitive(False)
self._xmleditor.details_changed = False
def _enable_net_apply(self, edittype):
self.widget("net-apply").set_sensitive(True)
self._active_edits.add(edittype)
self._xmleditor.details_changed = True
def _confirm_changes(self):
if (self.is_visible() and
self._active_edits and
self.err.confirm_unapplied_changes()):
self._net_apply()
self._disable_net_apply()
return True
def _conn_state_changed_cb(self, conn):
self._refresh_conn_state()
def _conn_nets_changed_cb(self, src, net):
self._populate_networks()
def _net_state_changed_cb(self, net):
for row in self.widget("net-list").get_model():
if row[0] == net:
row[4] = net.is_active()
curnet = self._current_network()
if curnet == net:
self._refresh_current_network()
def _net_selected_cb(self, selection):
self._refresh_current_network()
def _xmleditor_xml_requested_cb(self, src):
self._refresh_current_network()
def _xmleditor_xml_reset_cb(self, src):
self._refresh_current_network()