connection: Drop netdev abstraction

Just open code it in the one place it's needed. Try to simplify some of
the netlist logic while we are at it. Should fix:

https://bugzilla.redhat.com/show_bug.cgi?id=1109574
This commit is contained in:
Cole Robinson 2014-06-17 17:04:49 -04:00
parent 4ac49a1d66
commit c78974c0d9
4 changed files with 92 additions and 211 deletions

View File

@ -38,7 +38,6 @@ from virtManager.baseclass import vmmGObject
from virtManager.domain import vmmDomain
from virtManager.interface import vmmInterface
from virtManager.mediadev import vmmMediaDevice
from virtManager.netdev import vmmNetDevice
from virtManager.network import vmmNetwork
from virtManager.nodedev import vmmNodeDevice
from virtManager.storagepool import vmmStoragePool
@ -110,8 +109,6 @@ class vmmConnection(vmmGObject):
# Physical network interfaces: name -> virtinst.NodeDevice
self._nodedevs = {}
# Physical network interfaces: name (eth0) -> vmmNetDevice
self._netdevs = {}
# Physical media devices: vmmMediaDevice.key -> vmmMediaDevice
self._mediadevs = {}
# Connection Storage pools: name -> vmmInterface
@ -126,10 +123,6 @@ class vmmConnection(vmmGObject):
self.record = []
self.hostinfo = None
self.netdev_initialized = False
self.netdev_error = ""
self.netdev_use_libvirt = False
self.mediadev_initialized = False
self.mediadev_error = ""
self.mediadev_use_libvirt = False
@ -196,31 +189,6 @@ class vmmConnection(vmmGObject):
self._backend.cb_clear_cache = clear_cache
def _init_netdev(self):
"""
Determine how we will be polling for net devices (HAL or libvirt)
"""
if self.is_nodedev_capable() and self.is_interface_capable():
try:
self._build_libvirt_netdev_list()
self.netdev_use_libvirt = True
except Exception, e:
self.netdev_error = _("Could not build physical interface "
"list via libvirt: %s") % str(e)
else:
self.netdev_error = _("Libvirt version does not support "
"physical interface listing.")
self.netdev_initialized = True
if self.netdev_error:
logging.debug(self.netdev_error)
else:
if self.netdev_use_libvirt:
logging.debug("Using libvirt API for netdev enumeration")
else:
logging.debug("Using HAL for netdev enumeration")
def _init_mediadev(self):
if self.is_nodedev_capable():
try:
@ -653,59 +621,6 @@ class vmmConnection(vmmGObject):
# Libvirt object lookup methods #
#################################
def _build_libvirt_netdev_list(self):
bridges = []
netdev_list = {}
def interface_to_netdev(interface):
name = interface.get_name()
mac = interface.get_mac()
is_bridge = interface.is_bridge()
slave_names = interface.get_slave_names()
if is_bridge and slave_names:
bridges.append((name, slave_names))
else:
netdev_list[name] = vmmNetDevice(name, mac, is_bridge, None)
def nodedev_to_netdev(nodedev):
name = nodedev.interface
mac = nodedev.address
if name not in netdev_list.keys():
netdev_list[name] = vmmNetDevice(name, mac, False, None)
else:
# Believe this info over libvirt interface APIs, since
# this comes from the hardware
if mac:
netdev_list[name].mac = mac
for name, iface in self._interfaces.items():
interface_to_netdev(iface)
for nodedev in self.get_nodedevs("net"):
nodedev_to_netdev(nodedev)
# Mark NetDevices as bridged where appropriate
for bridge_name, slave_names in bridges:
for name, netdev in netdev_list.items():
if name not in slave_names:
continue
# XXX: Can a physical device be in two bridges?
netdev.bridge = bridge_name
netdev.shared = True
break
# XXX: How to handle added/removed signals to clients?
return netdev_list
def list_netdevs(self):
# Update netdev list
if self.netdev_use_libvirt:
self._netdevs = self._build_libvirt_netdev_list()
return self._netdevs.values()
def get_vm(self, connkey):
return self._vms[connkey]
def list_vms(self):
@ -994,9 +909,6 @@ class vmmConnection(vmmGObject):
cleanup(self._nodedevs)
self._nodedevs = {}
cleanup(self._netdevs)
self._netdevs = {}
cleanup(self._mediadevs)
self._mediadevs = {}
@ -1263,10 +1175,6 @@ class vmmConnection(vmmGObject):
if pollnodedev:
self._nodedevs = nodedevs
# Make sure device polling is setup
if not self.netdev_initialized:
self._init_netdev()
if not self.mediadev_initialized:
self._init_mediadev()

View File

@ -169,9 +169,16 @@ class vmmCreateNetwork(vmmGObjectUI):
fw_model = self.widget("net-forward").get_model()
fw_model.clear()
fw_model.append([_("Any physical device"), None])
for netdev in self.conn.list_netdevs():
fw_model.append([_("Physical device %s") % (netdev.get_name()),
netdev.get_name()])
devnames = []
for nodedev in self.conn.get_nodedevs("net"):
devnames.append(nodedev.name)
for iface in self.conn.list_interfaces():
if iface.name not in devnames:
devnames.append(iface.name)
for name in devnames:
fw_model.append([_("Physical device %s") % name, name])
self.widget("net-forward").set_active(0)
self.widget("net-forward-mode").set_active(0)

View File

@ -1,49 +0,0 @@
#
# Copyright (C) 2007, 2013 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
from virtManager.baseclass import vmmGObject
class vmmNetDevice(vmmGObject):
"""
Backend indepent class for a host network device.
Filled in by a combination of interface and nodedev APIs
"""
def __init__(self, name, mac, is_shared, bridge=None):
vmmGObject.__init__(self)
self.name = name
self.mac = mac
self.shared = is_shared
self.bridge = bridge
def _cleanup(self):
pass
def get_name(self):
return self.name
def is_shared(self):
return self.shared
def get_bridge(self):
return self.bridge
def get_mac(self):
return self.mac

View File

@ -128,17 +128,16 @@ class vmmNetworkList(vmmGObjectUI):
return ret
def _build_source_row(self, nettype, name,
def _build_source_row(self, nettype, source_name,
label, is_sensitive, is_running, manual_bridge=False, key=None):
return [nettype, name, label,
return [nettype, source_name, label,
is_sensitive, is_running, manual_bridge,
key]
def _find_virtual_networks(self):
vnet_dict = {}
rows = []
vnet_bridges = []
hasNet = False
netIdxLabel = None
default_label = None
for net in self.conn.list_nets():
nettype = virtinst.VirtualNetworkInterface.TYPE_VIRTUAL
@ -147,15 +146,12 @@ class vmmNetworkList(vmmGObjectUI):
if not net.is_active():
label += " (%s)" % _("Inactive")
hasNet = True
# FIXME: Should we use 'default' even if it's inactive?
# FIXME: This preference should be configurable
if net.get_name() == "default":
netIdxLabel = label
default_label = label
vnet_dict[label] = self._build_source_row(
rows.append(self._build_source_row(
nettype, net.get_name(), label, True,
net.is_active(), key=net.get_connkey())
net.is_active(), key=net.get_connkey()))
# Build a list of vnet bridges, so we know not to list them
# in the physical interface list
@ -163,74 +159,80 @@ class vmmNetworkList(vmmGObjectUI):
if vnet_bridge:
vnet_bridges.append(vnet_bridge)
if not hasNet:
if not rows:
label = _("No virtual networks available")
vnet_dict[label] = self._build_source_row(
None, None, label, False, False)
rows.append(self._build_source_row(
None, None, label, False, False))
return vnet_dict, vnet_bridges, netIdxLabel
return rows, vnet_bridges, default_label
def _find_physical_devices(self, vnet_bridges):
rows = []
can_default = False
default_label = None
skip_ifaces = ["lo"]
vnet_taps = []
for vm in self.conn.list_vms():
for nic in vm.get_network_devices(refresh_if_nec=False):
if nic.target_dev and nic.target_dev not in vnet_taps:
vnet_taps.append(nic.target_dev)
bridge_dict = {}
iface_dict = {}
hasShared = False
brIdxLabel = None
skip_ifaces = ["lo"]
netdevs = {}
for iface in self.conn.list_interfaces():
netdevs[iface.get_name()] = [
iface.get_name(), iface.is_bridge(), iface.get_slave_names()]
for nodedev in self.conn.get_nodedevs("net"):
if nodedev.interface not in netdevs:
netdevs[nodedev.interface] = [nodedev.interface, False, []]
for br in self.conn.list_netdevs():
name = br.name
bridge_name = br.get_bridge()
nettype = virtinst.VirtualNetworkInterface.TYPE_BRIDGE
# For every bridge used by a virtual network, and any slaves of
# those devices, don't list them.
for vnet_bridge in vnet_bridges:
slave_names = netdevs.pop(vnet_bridge, [None, None, []])[2]
for slave in slave_names:
netdevs.pop(slave, None)
if ((bridge_name in vnet_bridges) or
(br.get_name() in vnet_bridges) or
(br.get_name() in vnet_taps) or
(br.get_name() in [v + "-nic" for v in vnet_bridges]) or
(br.get_name() in skip_ifaces)):
for name, is_bridge, slave_names in netdevs.values():
if ((name in vnet_taps) or
(name in [v + "-nic" for v in vnet_bridges]) or
(name in skip_ifaces)):
# Don't list this, as it is basically duplicating
# virtual net info
continue
if br.is_shared():
sensitive = True
if br.get_bridge():
hasShared = True
brlabel = "(%s)" % self._pretty_network_desc(nettype,
bridge_name)
sensitive = True
source_name = name
label = _("Host device %s") % (name)
if is_bridge:
nettype = virtinst.VirtualNetworkInterface.TYPE_BRIDGE
if slave_names:
extra = ("(%s)" % _("Host device %s") % slave_names[0])
can_default = True
else:
bridge_name = name
brlabel = _("(Empty bridge)")
else:
if self.conn.check_support(
extra = _("(Empty bridge)")
label = _("Bridge %s %s") % (name, extra)
elif self.conn.check_support(
self.conn.SUPPORT_CONN_DIRECT_INTERFACE):
sensitive = True
nettype = virtinst.VirtualNetworkInterface.TYPE_DIRECT
bridge_name = name
brlabel = ": %s" % _("macvtap")
else:
sensitive = False
brlabel = "(%s)" % _("Not bridged")
nettype = virtinst.VirtualNetworkInterface.TYPE_DIRECT
label += (": %s" % _("macvtap"))
label = _("Host device %s %s") % (br.get_name(), brlabel)
if hasShared and not brIdxLabel:
brIdxLabel = label
row = self._build_source_row(
nettype, bridge_name, label, sensitive, True,
key=br.get_name())
if sensitive:
bridge_dict[label] = row
else:
iface_dict[label] = row
nettype = None
sensitive = False
source_name = None
label += (" (%s)" % _("Not bridged"))
return bridge_dict, iface_dict, brIdxLabel
if can_default and not default_label:
default_label = label
rows.append(self._build_source_row(
nettype, source_name, label, sensitive, True,
key=name))
return rows, default_label
def _populate_network_list(self):
net_list = self.widget("net-source")
@ -246,22 +248,30 @@ class vmmNetworkList(vmmGObjectUI):
net_list.set_active(0)
return
(vnet_dict, vnet_bridges, netIdxLabel) = self._find_virtual_networks()
(bridge_dict, iface_dict, brIdxLabel) = self._find_physical_devices(
(vnets, vnet_bridges, default_net) = self._find_virtual_networks()
(iface_rows, default_bridge) = self._find_physical_devices(
vnet_bridges)
for indict in [bridge_dict, vnet_dict, iface_dict]:
keylist = indict.keys()
keylist.sort()
rowlist = [indict[k] for k in keylist]
for row in rowlist:
# Sorting is:
# 1) Bridges
# 2) Virtual networks
# 3) direct/macvtap
# 4) Disabled list entries
# Each category sorted alphabetically
bridges = [row for row in iface_rows if row[0] == "bridge"]
direct = [row for row in iface_rows if row[0] == "direct"]
disabled = [row for row in iface_rows if row[0] is None]
for rows in [bridges, vnets, direct, disabled]:
rows.sort(key=lambda r: r[2])
for row in rows:
model.append(row)
# If there is a bridge device, default to that
# If not, use 'default' network
# If not present, use first list entry
# If list empty, use no network devices
label = brIdxLabel or netIdxLabel
label = default_bridge or default_net
default = 0
if not len(model):
@ -394,8 +404,13 @@ class vmmNetworkList(vmmGObjectUI):
def reset_state(self):
self._populate_network_list()
net_err = None
if (not self.conn.is_nodedev_capable() or
not self.conn.is_interface_capable()):
net_err = _("Libvirt version does not support "
"physical interface listing.")
net_warn = self.widget("net-source-warn")
net_err = self.conn.netdev_error
net_warn.set_visible(bool(net_err))
net_warn.set_tooltip_text(net_err or "")