[PATCH rhel7-branch 1/4] network: GUI, handle virtual devices (bond, vlan, team) properly (#1036047)

Radek Vykydal rvykydal at redhat.com
Fri Nov 29 12:17:00 UTC 2013


Resolves: rhbz#1036047

Don't crash when the device is turned off.
The items of device treeview are device configurations, not devices.
---
 pyanaconda/network.py                  |  29 +-
 pyanaconda/nm.py                       |  28 +-
 pyanaconda/ui/gui/spokes/network.glade |   2 +-
 pyanaconda/ui/gui/spokes/network.py    | 508 +++++++++++++++++++--------------
 4 files changed, 333 insertions(+), 234 deletions(-)

diff --git a/pyanaconda/network.py b/pyanaconda/network.py
index 4719450..8dc7893 100644
--- a/pyanaconda/network.py
+++ b/pyanaconda/network.py
@@ -484,7 +484,7 @@ def add_connection_for_ksdata(networkdata, devname):
             svalues.append(['connection', 'slave-type', 'bond', 's'])
             svalues.append(['connection', 'master', devname, 's'])
             svalues.append(['connection', 'type', '802-3-ethernet', 's'])
-            mac = nm.nm_device_hwaddress(slave)
+            mac = nm.nm_device_perm_hwaddress(slave)
             mac = [int(b, 16) for b in mac.split(":")]
             svalues.append(['802-3-ethernet', 'mac-address', mac, 'ay'])
 
@@ -518,7 +518,7 @@ def add_connection_for_ksdata(networkdata, devname):
             svalues.append(['connection', 'slave-type', 'team', 's'])
             svalues.append(['connection', 'master', devname, 's'])
             svalues.append(['connection', 'type', '802-3-ethernet', 's'])
-            mac = nm.nm_device_hwaddress(slave)
+            mac = nm.nm_device_perm_hwaddress(slave)
             mac = [int(b, 16) for b in mac.split(":")]
             svalues.append(['802-3-ethernet', 'mac-address', mac, 'ay'])
             svalues.append(['team-port', 'config', cfg, 's'])
@@ -547,7 +547,7 @@ def add_connection_for_ksdata(networkdata, devname):
     else:
         values.append(['connection', 'type', '802-3-ethernet', 's'])
         values.append(['connection', 'id', devname, 's'])
-        mac = nm.nm_device_hwaddress(devname)
+        mac = nm.nm_device_perm_hwaddress(devname)
         mac = [int(b, 16) for b in mac.split(":")]
         values.append(['802-3-ethernet', 'mac-address', mac, 'ay'])
         dev_spec = devname
@@ -556,20 +556,23 @@ def add_connection_for_ksdata(networkdata, devname):
     added_connections.insert(0, (con_uuid, dev_spec))
     return added_connections
 
-def ksdata_from_ifcfg(devname):
+def ksdata_from_ifcfg(devname, uuid=None):
 
     if nm.nm_device_is_slave(devname):
         return None
+    if nm.nm_device_type_is_wifi(devname):
+        # wifi from kickstart is not supported yet
+        return None
 
-    ifcfg_path = None
+    if not uuid:
+        # Find ifcfg file for the device.
+        # If the device is active, use uuid of its active connection.
+        uuid = nm.nm_device_active_con_uuid(devname)
 
-    # Find ifcfg file for the device.
-    # If the device is active, use uuid of its active connection.
-    uuid = nm.nm_device_active_con_uuid(devname)
     if uuid:
         ifcfg_path = find_ifcfg_file([("UUID", uuid)])
     else:
-        # If not, look it up by other values depending on its type
+        # look it up by other values depending on its type
         ifcfg_path = find_ifcfg_file_of_device(devname)
 
     if not ifcfg_path:
@@ -738,7 +741,7 @@ def find_ifcfg_file_of_device(devname, root_path=""):
         ifcfg_path = find_ifcfg_file([("DEVICE", devname)])
     elif nm.nm_device_type_is_ethernet(devname):
         try:
-            hwaddr = nm.nm_device_hwaddress(devname)
+            hwaddr = nm.nm_device_perm_hwaddress(devname)
         except nm.PropertyNotFoundError:
             hwaddr = None
         if hwaddr:
@@ -922,7 +925,7 @@ def ks_spec_to_device_name(ksspec=""):
         # "XX:XX:XX:XX:XX:XX" (mac address)
         elif ':' in ksdevice:
             try:
-                hwaddr = nm.nm_device_hwaddress(dev)
+                hwaddr = nm.nm_device_perm_hwaddress(dev)
             except ValueError as e:
                 log.debug("ks_spec_to_device_name: %s" % e)
                 continue
@@ -932,7 +935,7 @@ def ks_spec_to_device_name(ksspec=""):
         # "bootif" and BOOTIF==XX:XX:XX:XX:XX:XX
         elif ksdevice == 'bootif':
             try:
-                hwaddr = nm.nm_device_hwaddress(dev)
+                hwaddr = nm.nm_device_perm_hwaddress(dev)
             except ValueError as e:
                 log.debug("ks_spec_to_device_name: %s" % e)
                 continue
@@ -1146,7 +1149,7 @@ def get_device_name(devspec):
     if devname and devname not in devices:
         for d in devices:
             try:
-                hwaddr = nm.nm_device_hwaddress(d)
+                hwaddr = nm.nm_device_perm_hwaddress(d)
             except ValueError as e:
                 log.debug("get_device_name: %s" % e)
                 continue
diff --git a/pyanaconda/nm.py b/pyanaconda/nm.py
index 8f8256b..0d1d4a1 100644
--- a/pyanaconda/nm.py
+++ b/pyanaconda/nm.py
@@ -48,6 +48,11 @@ class UnmanagedDeviceError(Exception):
     def __str__(self):
         return self.__repr__()
 
+class DeviceNotActiveError(Exception):
+    """Device of specified name is not active"""
+    def __str__(self):
+        return self.__repr__()
+
 class PropertyNotFoundError(ValueError):
     """Property of NM object was not found"""
     def __str__(self):
@@ -267,6 +272,18 @@ def nm_device_hwaddress(name):
     """
     return nm_device_property(name, "HwAddress")
 
+def nm_device_perm_hwaddress(name):
+    """Return active hardware address of device ('HwAddress' property)
+
+       :param name: name of device
+       :type name: str
+       :return: active hardware address of device ('HwAddress' property)
+       :rtype: str
+       :raise UnknownDeviceError: if device is not found
+       :raise PropertyNotFoundError: if 'HwAddress' property is not found
+    """
+    return nm_device_property(name, "PermHwAddress")
+
 def nm_device_active_con_uuid(name):
     """Return uuid of device's active connection
 
@@ -433,7 +450,7 @@ def nm_hwaddr_to_device_name(hwaddr):
         :rtype: str
     """
     for device in nm_devices():
-        if nm_device_hwaddress(device).upper() == hwaddr.upper():
+        if nm_device_perm_hwaddress(device).upper() == hwaddr.upper():
             return device
     return None
 
@@ -478,7 +495,7 @@ def _device_settings(name):
         settings = _find_settings(name, 'connection', 'interface-name')
         if not settings:
             try:
-                hwaddr_str = nm_device_hwaddress(name)
+                hwaddr_str = nm_device_perm_hwaddress(name)
             except PropertyNotFoundError:
                 settings = []
             else:
@@ -618,7 +635,12 @@ def nm_disconnect_device(name):
         raise
 
     device_proxy = _get_proxy(object_path=device, interface_name="org.freedesktop.NetworkManager.Device")
-    device_proxy.Disconnect()
+    try:
+        device_proxy.Disconnect()
+    except GLib.GError as e:
+        if "org.freedesktop.NetworkManager.Device.NotActive" in e.message:
+            raise DeviceNotActiveError(name, e)
+        raise
 
 def nm_activate_device_connection(dev_name, con_uuid):
     """Activate device with specified connection.
diff --git a/pyanaconda/ui/gui/spokes/network.glade b/pyanaconda/ui/gui/spokes/network.glade
index 1b65d83..d9d945e 100644
--- a/pyanaconda/ui/gui/spokes/network.glade
+++ b/pyanaconda/ui/gui/spokes/network.glade
@@ -136,7 +136,7 @@
       <!-- column-name sort -->
       <column type="gchararray"/>
       <!-- column-name object -->
-      <column type="GObject"/>
+      <column type="PyObject"/>
     </columns>
   </object>
   <object class="GtkListStore" id="liststore_wireless_network">
diff --git a/pyanaconda/ui/gui/spokes/network.py b/pyanaconda/ui/gui/spokes/network.py
index bbfb75a..0c822b7 100644
--- a/pyanaconda/ui/gui/spokes/network.py
+++ b/pyanaconda/ui/gui/spokes/network.py
@@ -58,10 +58,6 @@ import string
 from dbus.mainloop.glib import DBusGMainLoop
 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
-import ctypes
-ctypes.cdll.LoadLibrary("libnm-util.so.2")
-nm_utils = ctypes.CDLL("libnm-util.so.2")
-
 import logging
 log = logging.getLogger("anaconda")
 
@@ -96,7 +92,9 @@ def localized_string_of_device_state(device, state):
     elif state == NetworkManager.DeviceState.UNMANAGED:
         str = _("Unmanaged")
     elif state == NetworkManager.DeviceState.UNAVAILABLE:
-        if device.get_firmware_missing():
+        if not device:
+            str = _("Unavailable")
+        elif device.get_firmware_missing():
             str = _("Firmware missing")
         elif (device.get_device_type() == NetworkManager.DeviceType.ETHERNET
               and not device.get_carrier()):
@@ -212,7 +210,65 @@ class CellRendererSecurity(Gtk.CellRendererPixbuf):
 
         self.set_property("icon-name", self.icon_name)
 
-class NetworkControlBox(object):
+class DeviceConfiguration(object):
+
+    setting_types = {
+        '802-11-wireless': NetworkManager.DeviceType.WIFI,
+        '802-3-ethernet': NetworkManager.DeviceType.ETHERNET,
+        'vlan': NetworkManager.DeviceType.VLAN,
+        'bond': NetworkManager.DeviceType.BOND,
+        'team': NetworkManager.DeviceType.TEAM,
+        }
+
+    def __init__(self, device=None, con_uuid=None):
+        self.device = device
+        self.con_uuid = con_uuid
+
+        if device:
+            self.device_type = self.device.get_device_type()
+        elif con_uuid:
+            self.device_type = self._setting_device_type(self.con_uuid)
+
+        if not self.con_uuid:
+            if self.device_type != NetworkManager.DeviceType.WIFI:
+                uuid = nm.nm_device_setting_value(device.get_iface(), "connection", "uuid")
+                settings = nm.nm_get_settings(uuid, "connection", "uuid")
+                if settings and 'slave-type' not in settings[0]['connection']:
+                    self.con_uuid = uuid
+
+    def _setting_device_type(self, uuid):
+        settings = nm.nm_get_settings(uuid, "connection", "uuid")
+        if not settings:
+            return None
+        dev_type = self.setting_types.get(settings[0]["connection"]["type"], None)
+        return dev_type
+
+    def get_iface(self):
+        if self.device:
+            iface = self.device.get_iface()
+        else:
+            iface = self.setting_value("connection", "interface-name")
+        return iface
+
+    def setting_value(self, key1, key2):
+        settings = nm.nm_get_settings(self.con_uuid, "connection", "uuid")
+        try:
+            value = settings[0][key1][key2]
+        except IndexError as e:
+            log.debug("network: can't find connection with uuid %s"
+                        % self.con_uuid)
+        except KeyError as e:
+            log.debug("network: can't find '%s' '%s' in connection %s"
+                        % (key1, key2, self.con_uuid))
+        else:
+            return value
+
+class NetworkControlBox(GObject.GObject):
+
+    __gsignals__ = {
+        "nm-state-changed": (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, []),
+        "device-state-changed": (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, [str, int, int, int]),
+    }
 
     supported_device_types = [
         NetworkManager.DeviceType.ETHERNET,
@@ -229,8 +285,24 @@ class NetworkControlBox(object):
         NetworkManager.DeviceType.VLAN,
     ]
 
+    device_type_sort_value = {
+        NetworkManager.DeviceType.ETHERNET : "1",
+        NetworkManager.DeviceType.WIFI : "2",
+    }
+
+    device_type_name = {
+        NetworkManager.DeviceType.UNKNOWN: _("Unknown"),
+        NetworkManager.DeviceType.ETHERNET: _("Ethernet"),
+        NetworkManager.DeviceType.WIFI: _("Wireless"),
+        NetworkManager.DeviceType.BOND: _("Bond"),
+        NetworkManager.DeviceType.VLAN: _("Vlan"),
+        NetworkManager.DeviceType.TEAM: _("Team"),
+    }
+
     def __init__(self, builder, spoke=None):
 
+        GObject.GObject.__init__(self)
+
         self.builder = builder
         self._running_nmce = None
         self.spoke = spoke
@@ -306,6 +378,8 @@ class NetworkControlBox(object):
                                                               self.on_edit_connection)
         self.entry_hostname = self.builder.get_object("entry_hostname")
 
+        self.client.connect("notify::%s" % NMClient.CLIENT_STATE,
+                            self.on_nm_state_changed)
 
     @property
     def vbox(self):
@@ -340,10 +414,18 @@ class NetworkControlBox(object):
 
     def initialize(self):
         for device in self.client.get_devices():
-            device.connect("notify::ip4-config", self.on_device_config_changed)
-            device.connect("notify::ip6-config", self.on_device_config_changed)
             self.add_device_to_list(device)
 
+        for setting in nm.nm_get_all_settings():
+            uuid = setting["connection"]["uuid"]
+            log.debug("network: GUI, connection %s found" % uuid)
+            if self.dev_cfg(uuid=uuid):
+                continue
+            dev_cfg = DeviceConfiguration(con_uuid=uuid)
+            if dev_cfg.device_type in self.supported_device_types:
+                self.add_dev_cfg(dev_cfg)
+
+        # select the first device
         treeview = self.builder.get_object("treeview_devices")
         devices_store = self.builder.get_object("liststore_devices")
         selection = treeview.get_selection()
@@ -352,30 +434,28 @@ class NetworkControlBox(object):
             selection.select_iter(itr)
 
     def refresh(self):
-        device = self.selected_device()
-        self.refresh_ui(device)
+        self.refresh_ui()
 
     # Signal handlers.
-    def on_device_selection_changed(self, *args):
-        device = self.selected_device()
-        if not device:
-            return
+    def on_nm_state_changed(self, *args):
+        self.emit("nm-state-changed")
 
-        log.debug("network: selected device %s" % device.get_iface())
-        self.refresh_ui(device)
+    def on_device_selection_changed(self, *args):
+        self.refresh_ui()
 
-    def on_device_state_changed(self, *args):
-        device = args[0]
-        new_state = args[1]
+    def on_device_state_changed(self, device, new_state, *args):
+        self.emit("device-state-changed", device.get_iface(), new_state, *args)
         if new_state == NetworkManager.DeviceState.SECONDARIES:
             return
         self._refresh_carrier_info()
-        if device == self.selected_device():
-            self.refresh_ui(device, new_state)
+        dev_cfg = self.selected_dev_cfg()
+        if dev_cfg and dev_cfg.device == device:
+            self.refresh_ui(state=new_state)
 
     def on_device_config_changed(self, device, *args):
-        if device == self.selected_device():
-            self.refresh_ui(device)
+        dev_cfg = self.selected_dev_cfg()
+        if dev_cfg and dev_cfg.device == device:
+            self.refresh_ui()
 
     def on_wireless_ap_changed_cb(self, combobox, *args):
         if self._updating_device:
@@ -384,13 +464,13 @@ class NetworkControlBox(object):
         if not iter:
             return
 
-        device = self.selected_device()
+        device = self.selected_dev_cfg().device
         ap_obj_path, ssid_target = combobox.get_model().get(iter, 0, 1)
         self.selected_ssid = ssid_target
         if ap_obj_path == "ap-other...":
             return
 
-        log.info("network: access point changed: %s" % ssid_target)
+        log.info("network: selected access point: %s" % ssid_target)
 
         try:
             uuid = nm.nm_ap_setting_value(ssid_target, "connection", "uuid")
@@ -409,40 +489,32 @@ class NetworkControlBox(object):
         self.remove_device(device)
 
     def on_edit_connection(self, *args):
-        device = self.selected_device()
-        if not device:
+        dev_cfg = self.selected_dev_cfg()
+        if not dev_cfg:
             return
 
-        devname = device.get_iface()
-        uuid = None
-        try:
-            uuid = nm.nm_device_active_con_uuid(devname)
-        except nm.UnknownDeviceError as e:
-            log.debug("network: on_edit_connection: %s" % e)
-        if not uuid:
-            if device.get_device_type() == NetworkManager.DeviceType.WIFI:
-                if self.selected_ssid:
-                    try:
-                        uuid = nm.nm_ap_setting_value(self.selected_ssid, "connection", "uuid")
-                    except nm.SettingsNotFoundError as e:
-                        log.debug("network: on_edit_connection: %s" % e)
-            else:
-                uuid = nm.nm_device_setting_value(devname, "connection", "uuid")
+        uuid = dev_cfg.con_uuid
+        devname = dev_cfg.get_iface()
+        activate = None
+
+        if dev_cfg.device_type == NetworkManager.DeviceType.WIFI:
+            if self.selected_ssid:
+                try:
+                    uuid = nm.nm_ap_setting_value(self.selected_ssid, "connection", "uuid")
+                except nm.SettingsNotFoundError as e:
+                    log.debug("network: on_edit_connection: %s" % e)
+                else:
+                    # 871132 auto activate wireless connection after editing if it is not
+                    # already activated (assume entering secrets)
+                    if self.selected_ssid != nm.nm_device_active_ssid(devname):
+                        activate = (uuid, devname)
 
         if not uuid:
             log.debug("network: on_edit_connection: can't find connection for device %s" % devname)
             return
 
-        # 871132 auto activate wireless connection after editing if it is not
-        # already activated (assume entering secrets)
-        activate = None
-        if (device.get_device_type() == NetworkManager.DeviceType.WIFI
-            and self.selected_ssid
-            and self.selected_ssid != nm.nm_device_active_ssid(devname)):
-            activate = (uuid, devname)
-
         log.info("network: configuring connection %s device %s ssid %s" %
-                 (uuid, devname, self.selected_ssid))
+                 uuid, devname, self.selected_ssid)
         self.kill_nmce(msg="Configure button clicked")
         proc = subprocess.Popen(["nm-connection-editor", "--edit", "%s" % uuid])
         self._running_nmce = proc
@@ -483,28 +555,29 @@ class NetworkControlBox(object):
             return
 
         active = switch.get_active()
-        device = self.selected_device()
+        dev_cfg = self.selected_dev_cfg()
 
         log.info("network: device %s switched %s" %
-                  (device.get_iface(), "on" if active else "off"))
+                   (dev_cfg.get_iface(), "on" if active else "off"))
 
-        dev_type = device.get_device_type()
-        if dev_type in self.wired_ui_device_types:
+        if dev_cfg.device_type == NetworkManager.DeviceType.WIFI:
+            self.client.wireless_set_enabled(active)
+        else:
             if active:
-                uuid = nm.nm_device_setting_value(device.get_iface(), "connection", "uuid")
-                if uuid:
-                    try:
-                        nm.nm_activate_device_connection(device.get_iface(), uuid)
-                    except nm.UnmanagedDeviceError as e:
-                        log.debug("network: on_device_off_toggled: %s" % e)
-                else:
-                    self.client.add_and_activate_connection(None, device, None,
-                                                            None, None)
+                dev_name = dev_cfg.device and dev_cfg.device.get_iface()
+                if not dev_cfg.con_uuid:
+                    log.debug("network: on_device_off_toggled: no connection for %s"
+                               % dev_name)
+                    return
+                try:
+                    nm.nm_activate_device_connection(dev_name, dev_cfg.con_uuid)
+                except (nm.UnmanagedDeviceError, nm.UnknownDeviceError) as e:
+                    log.debug("network: on_device_off_toggled: %s" % e)
             else:
-                device.disconnect(None, None)
-        elif dev_type == NetworkManager.DeviceType.WIFI:
-            self.client.wireless_set_enabled(active)
-
+                try:
+                    nm.nm_disconnect_device(dev_cfg.get_iface())
+                except (nm.UnmanagedDeviceError, nm.DeviceNotActiveError) as e:
+                    log.debug("network: on_device_off_toggled: %s" % e)
 
     def on_add_device_clicked(self, *args):
         dialog = self.builder.get_object("add_device_dialog")
@@ -532,130 +605,129 @@ class NetworkControlBox(object):
                 self._running_nmce = None
             network.logIfcfgFiles("nm-c-e run")
 
-    def selected_device(self):
+    def selected_dev_cfg(self):
         selection = self.builder.get_object("treeview_devices").get_selection()
-        (model, iter) = selection.get_selected()
+        model, iter = selection.get_selected()
         if not iter:
             return None
-        return model.get(iter, DEVICES_COLUMN_OBJECT)[0]
+        return model[iter][DEVICES_COLUMN_OBJECT]
 
-    def _device_is_stored(self, nm_device):
-        """Check that device with Udi of nm_device is already in liststore"""
-        udi = nm_device.get_udi()
-        model = self.builder.get_object("liststore_devices")
-        for row in model:
-            if udi == row[DEVICES_COLUMN_OBJECT].get_udi():
-                return True
-        return False
+    def add_dev_cfg(self, dev_cfg):
+        log.debug ("network: GUI, device configuration added: connection %s device %s"
+                     % (dev_cfg.con_uuid, dev_cfg.get_iface()))
+        self.builder.get_object("liststore_devices").append([
+            self._dev_icon_name(dev_cfg),
+            self.device_type_sort_value.get(dev_cfg.device_type, "100"),
+            self._dev_title(dev_cfg),
+            dev_cfg
+        ])
 
     def add_device_to_list(self, device):
-        if self._device_is_stored(device):
-            return
-
         if device.get_device_type() not in self.supported_device_types:
             return
 
-        device.connect("state-changed", self.on_device_state_changed)
+        try:
+            con_uuid = nm.nm_device_setting_value(device.get_iface(), "connection", "uuid")
+            dev_cfg = self.dev_cfg(uuid=con_uuid)
+        except nm.SettingsNotFoundError:
+            # wireless devices
+            dev_cfg = None
+        if dev_cfg:
+            dev_cfg.device = device
+        else:
+            dev_cfg = DeviceConfiguration(device=device)
+            self.add_dev_cfg(dev_cfg)
 
-        self.builder.get_object("liststore_devices").append([
-            self._dev_icon_name(device),
-            self._dev_type_sort_value(device),
-            self._dev_title(device),
-            device,
-        ])
+        device.connect("notify::ip4-config", self.on_device_config_changed)
+        device.connect("notify::ip6-config", self.on_device_config_changed)
+        device.connect("state-changed", self.on_device_state_changed)
 
-    def _dev_icon_name(self, device):
+    def _dev_icon_name(self, dev_cfg):
         icon_name = ""
-        dev_type = device.get_device_type()
-        if dev_type in self.wired_ui_device_types:
-            if device.get_state() == NetworkManager.DeviceState.UNAVAILABLE:
-                icon_name = "network-wired-disconnected"
+        if dev_cfg.device_type in self.wired_ui_device_types:
+            if dev_cfg.device:
+                if dev_cfg.device.get_state() == NetworkManager.DeviceState.UNAVAILABLE:
+                    icon_name = "network-wired-disconnected"
+                else:
+                    icon_name = "network-wired"
             else:
-                icon_name = "network-wired"
-        elif dev_type == NetworkManager.DeviceType.WIFI:
+                icon_name = "network-wired-disconnected"
+        elif dev_cfg.device_type == NetworkManager.DeviceType.WIFI:
             icon_name = "network-wireless"
 
         return icon_name
 
-    def _dev_type_sort_value(self, device):
-        dev_type = device.get_device_type()
-        if dev_type == NetworkManager.DeviceType.ETHERNET:
-            str = "1"
-        elif dev_type == NetworkManager.DeviceType.WIFI:
-            str = "2"
-        else:
-            str = "3"
-        return str
-
-    def _dev_title(self, device):
+    def _dev_title(self, dev_cfg):
         unplugged = ''
-        if (device.get_state() == NetworkManager.DeviceState.UNAVAILABLE
-            and device.get_device_type() == NetworkManager.DeviceType.ETHERNET
-            and not device.get_carrier()):
-            # Translators: ethernet cable is unplugged
-            unplugged = ', <i>%s</i>' % _("unplugged")
-        title = '<span size="large">%s (%s%s)</span>' % (self._dev_type_str(device),
-                                                         device.get_iface(),
-                                                         unplugged)
-        title += '\n<span size="small">%s %s</span>' % (device.get_vendor() or "",
-                                                        device.get_product() or "")
+        if dev_cfg.device:
+            if (dev_cfg.device.get_state() == NetworkManager.DeviceState.UNAVAILABLE
+                and dev_cfg.device.get_device_type() == NetworkManager.DeviceType.ETHERNET
+                and not dev_cfg.device.get_carrier()):
+                # Translators: ethernet cable is unplugged
+                unplugged = ', <i>%s</i>' % _("unplugged")
+        title = '<span size="large">%s (%s%s)</span>' % \
+                 (self.device_type_name.get(dev_cfg.device_type, ""),
+                  dev_cfg.get_iface(),
+                  unplugged)
+
+        if dev_cfg.device:
+            title += '\n<span size="small">%s %s</span>' % \
+                    (dev_cfg.device.get_vendor() or "",
+                     dev_cfg.device.get_product() or "")
         return title
 
-    def _dev_type_str(self, device):
-        dev_type = device.get_device_type()
-        if dev_type == NetworkManager.DeviceType.UNKNOWN:
-            title = _("Unknown")
-        elif dev_type == NetworkManager.DeviceType.ETHERNET:
-            title = _("Ethernet")
-        elif dev_type == NetworkManager.DeviceType.WIFI:
-            title = _("Wireless")
-        elif dev_type == NetworkManager.DeviceType.BOND:
-            title = _("Bond")
-        elif dev_type == NetworkManager.DeviceType.VLAN:
-            title = _("Vlan")
-        elif dev_type == NetworkManager.DeviceType.TEAM:
-            title = _("Team")
-        else:
-            title = ""
-        return title
+    def dev_cfg(self, uuid=None, device=None):
+        model = self.builder.get_object("liststore_devices")
+        for row in model:
+            dev_cfg = row[DEVICES_COLUMN_OBJECT]
+            if uuid:
+                if uuid != dev_cfg.con_uuid:
+                    continue
+            if device:
+                if not dev_cfg.device \
+                   or dev_cfg.device.get_udi() != device.get_udi():
+                    continue
+            return dev_cfg
+        return None
 
     def remove_device(self, device):
         # This should not concern wifi and ethernet devices,
         # just virtual devices e.g. vpn probably
-        # TODO test!, remove perhaps
-        model = self.builder.get_object("liststore_devices")
-        rows_to_remove = []
-        for row in model:
-            if (device.get_udi() == row[DEVICES_COLUMN_OBJECT].get_udi()):
-                rows_to_remove.append(row)
-        for row in rows_to_remove:
-            del(row)
+        log.debug("network: GUI, device removed: %s" % (device.get_iface()))
+        self.dev_cfg(device=device).device = None
 
-    def refresh_ui(self, device, state=None):
+    def refresh_ui(self, state=None):
 
-        if not device:
+        dev_cfg = self.selected_dev_cfg()
+        if not dev_cfg:
+            # the list is empty (no supported devices)
             notebook = self.builder.get_object("notebook_types")
             notebook.set_current_page(5)
             return
 
-        self._refresh_device_type_page(device)
-        self._refresh_header_ui(device, state)
-        self._refresh_slaves(device)
-        self._refresh_parent_vlanid(device)
-        self._refresh_speed_hwaddr(device, state)
-        self._refresh_ap(device, state)
-        self._refresh_device_cfg(device)
+        self._refresh_device_type_page(dev_cfg.device_type)
+        self._refresh_header_ui(dev_cfg, state)
+        self._refresh_slaves(dev_cfg)
+        self._refresh_parent_vlanid(dev_cfg)
+        self._refresh_speed_hwaddr(dev_cfg, state)
+        self._refresh_ap(dev_cfg, state)
+        self._refresh_device_cfg(dev_cfg)
 
-    def _refresh_device_cfg(self, device):
+    def _refresh_device_cfg(self, dev_cfg):
 
-        dev_type = device.get_device_type()
-        if dev_type in self.wired_ui_device_types:
+        if dev_cfg.device_type in self.wired_ui_device_types:
             dt = "wired"
-        elif dev_type == NetworkManager.DeviceType.WIFI:
+        elif dev_cfg.device_type == NetworkManager.DeviceType.WIFI:
             dt = "wireless"
 
-        ipv4cfg = nm.nm_device_ip_config(device.get_iface(), version=4)
-        ipv6cfg = nm.nm_device_ip_config(device.get_iface(), version=6)
+        if dev_cfg.device:
+            try:
+                ipv4cfg = nm.nm_device_ip_config(dev_cfg.device.get_iface(), version=4)
+                ipv6cfg = nm.nm_device_ip_config(dev_cfg.device.get_iface(), version=6)
+            except nm.UnknownDeviceError:
+                ipv4cfg = ipv6cfg = None
+        else:
+            ipv4cfg = ipv6cfg = None
 
         if ipv4cfg and ipv4cfg[0]:
             addr_str, prefix, gateway_str = ipv4cfg[0][0]
@@ -689,16 +761,16 @@ class NetworkControlBox(object):
 
         return False
 
-    def _refresh_ap(self, device, state=None):
-        if device.get_device_type() != NetworkManager.DeviceType.WIFI:
+    def _refresh_ap(self, dev_cfg, state=None):
+        if dev_cfg.device_type != NetworkManager.DeviceType.WIFI:
             return
 
         if state is None:
-            state = device.get_state()
+            state = dev_cfg.device.get_state()
         if state == NetworkManager.DeviceState.UNAVAILABLE:
             ap_str = None
         else:
-            active_ap = device.get_active_access_point()
+            active_ap = dev_cfg.device.get_active_access_point()
             if active_ap:
                 active_ap_dbus = dbus.SystemBus().get_object(NM_SERVICE,
                                                              active_ap.get_path())
@@ -722,7 +794,7 @@ class NetworkControlBox(object):
             store = self.builder.get_object("liststore_wireless_network")
             self._updating_device = True
             store.clear()
-            aps = self._get_strongest_unique_aps(device.get_access_points())
+            aps = self._get_strongest_unique_aps(dev_cfg.device.get_access_points())
             for ap in aps:
                 active = active_ap and active_ap.get_path() == ap.get_path()
                 self._add_ap(ap, active)
@@ -736,47 +808,53 @@ class NetworkControlBox(object):
                         break
             self._updating_device = False
 
-    def _refresh_slaves(self, device):
-        dev_type = device.get_device_type()
-        if dev_type in [NetworkManager.DeviceType.BOND,
-                        NetworkManager.DeviceType.TEAM]:
-            slaves = ",".join(s.get_iface()
-                for s in device.get_slaves())
+    def _refresh_slaves(self, dev_cfg):
+        if dev_cfg.device_type in [NetworkManager.DeviceType.BOND,
+                                   NetworkManager.DeviceType.TEAM]:
+            slaves = ""
+            if dev_cfg.device:
+                slaves = ",".join(s.get_iface() for s in dev_cfg.device.get_slaves())
             self._set_device_info_value("wired", "slaves", slaves)
 
-    def _refresh_parent_vlanid(self, device):
-        dev_type = device.get_device_type()
-        if dev_type == NetworkManager.DeviceType.VLAN:
-            self._set_device_info_value("wired", "vlanid", str(device.get_vlan_id()))
-            parent = nm.nm_device_setting_value(device.get_iface(), "vlan", "parent")
-            self._set_device_info_value("wired", "parent", parent)
+    def _refresh_parent_vlanid(self, dev_cfg):
+        if dev_cfg.device_type == NetworkManager.DeviceType.VLAN:
+            if dev_cfg.device:
+                vlanid = dev_cfg.device.get_vlan_id()
+            else:
+                vlanid = dev_cfg.setting_value("vlan", "id")
+            parent = dev_cfg.setting_value("vlan", "parent")
+            self._set_device_info_value("wired", "vlanid", str(vlanid))
 
-    def _refresh_speed_hwaddr(self, device, state=None):
-        dev_type = device.get_device_type()
+    def _refresh_speed_hwaddr(self, dev_cfg, state=None):
+        dev_type = dev_cfg.device_type
         if dev_type in self.wired_ui_device_types:
             dt = "wired"
         elif dev_type == NetworkManager.DeviceType.WIFI:
             dt = "wireless"
-        speed = None
-        if dev_type == NetworkManager.DeviceType.ETHERNET:
-            speed = device.get_speed()
-        elif dev_type == NetworkManager.DeviceType.WIFI:
-            speed = device.get_bitrate() / 1000
 
-        if state is None:
-            state = device.get_state()
-        if state == NetworkManager.DeviceState.UNAVAILABLE:
+        # Speed
+        speed = None
+        if dev_cfg.device:
+            if dev_type == NetworkManager.DeviceType.ETHERNET:
+                speed = dev_cfg.device.get_speed()
+            elif dev_type == NetworkManager.DeviceType.WIFI:
+                speed = dev_cfg.device.get_bitrate() / 1000
+            if state is None:
+                state = dev_cfg.device.get_state()
+
+        if not dev_cfg.device or state == NetworkManager.DeviceState.UNAVAILABLE:
             speed_str = None
         elif speed:
             speed_str = _("%d Mb/s") % speed
         else:
             speed_str = ""
         self._set_device_info_value(dt, "speed", speed_str)
-        self._set_device_info_value(dt, "mac", device.get_hw_address())
+        # Hardware address
+        hwaddr = dev_cfg.device and dev_cfg.device.get_hw_address()
+        self._set_device_info_value(dt, "mac", hwaddr)
 
-    def _refresh_device_type_page(self, device):
+    def _refresh_device_type_page(self, dev_type):
         notebook = self.builder.get_object("notebook_types")
-        dev_type = device.get_device_type()
         if dev_type == NetworkManager.DeviceType.ETHERNET:
             notebook.set_current_page(0)
             self.builder.get_object("heading_wired_slaves").hide()
@@ -798,10 +876,10 @@ class NetworkControlBox(object):
             notebook.set_current_page(0)
             self.builder.get_object("heading_wired_slaves").hide()
             self.builder.get_object("label_wired_slaves").hide()
-            self.builder.get_object("heading_wired_vlanid").hide()
-            self.builder.get_object("label_wired_vlanid").hide()
-            self.builder.get_object("heading_wired_parent").hide()
-            self.builder.get_object("label_wired_parent").hide()
+            self.builder.get_object("heading_wired_vlanid").show()
+            self.builder.get_object("label_wired_vlanid").show()
+            self.builder.get_object("heading_wired_parent").show()
+            self.builder.get_object("label_wired_parent").show()
         elif dev_type == NetworkManager.DeviceType.WIFI:
             notebook.set_current_page(1)
             self.builder.get_object("button_wireless_options").set_sensitive(self.selected_ssid is not None)
@@ -810,29 +888,29 @@ class NetworkControlBox(object):
         for i in self.builder.get_object("liststore_devices"):
             i[DEVICES_COLUMN_TITLE] = self._dev_title(i[DEVICES_COLUMN_OBJECT])
 
-    def _refresh_header_ui(self, device, state=None):
-        dev_type = device.get_device_type()
-        if dev_type in (NetworkManager.DeviceType.ETHERNET,
-                        NetworkManager.DeviceType.TEAM,
-                        NetworkManager.DeviceType.BOND,
-                        NetworkManager.DeviceType.VLAN):
+    def _refresh_header_ui(self, dev_cfg, state=None):
+        if dev_cfg.device_type in self.wired_ui_device_types:
             dev_type_str = "wired"
-        elif dev_type == NetworkManager.DeviceType.WIFI:
+        elif dev_cfg.device_type == NetworkManager.DeviceType.WIFI:
             dev_type_str = "wireless"
 
         if dev_type_str == "wired":
             # update icon according to device status
             img = self.builder.get_object("image_wired_device")
-            img.set_from_icon_name(self._dev_icon_name(device), Gtk.IconSize.DIALOG)
+            img.set_from_icon_name(self._dev_icon_name(dev_cfg), Gtk.IconSize.DIALOG)
 
         # TODO: is this necessary? Isn't it static from glade?
         self.builder.get_object("label_%s_device" % dev_type_str).set_label(
-            "%s (%s)" % (self._dev_type_str(device), device.get_iface()))
+            "%s (%s)" % (self.device_type_name.get(dev_cfg.device_type, ""), dev_cfg.get_iface()))
 
         if state is None:
-            state = device.get_state()
+            if not dev_cfg.device:
+                state = NetworkManager.DeviceState.DISCONNECTED
+            else:
+                state = dev_cfg.device.get_state()
+
         self.builder.get_object("label_%s_status" % dev_type_str).set_label(
-            localized_string_of_device_state(device, state))
+            localized_string_of_device_state(dev_cfg.device, state))
 
         switch = self.builder.get_object("device_%s_off_switch" % dev_type_str)
         if dev_type_str == "wired":
@@ -987,7 +1065,7 @@ class NetworkControlBox(object):
         return sec_str
 
     @property
-    def listed_devices(self):
+    def dev_cfgs(self):
         return [row[DEVICES_COLUMN_OBJECT] for
                 row in self.builder.get_object("liststore_devices")]
 
@@ -1195,11 +1273,10 @@ class NetworkSpoke(FirstbootSpokeMixIn, NormalSpoke):
         NormalSpoke.__init__(self, *args, **kwargs)
         self.network_control_box = NetworkControlBox(self.builder, spoke=self)
         self.network_control_box.hostname = self.data.network.hostname
-        self.network_control_box.client.connect("notify::%s" %
-                                                NMClient.CLIENT_STATE,
-                                                self.on_nm_state_changed)
-        for device in self.network_control_box.client.get_devices():
-            device.connect("state-changed", self.on_device_state_changed)
+        self.network_control_box.connect("nm-state-changed",
+                                         self.on_nm_state_changed)
+        self.network_control_box.connect("device-state-changed",
+                                         self.on_device_state_changed)
 
     def apply(self):
         _update_network_data(self.data, self.network_control_box)
@@ -1243,8 +1320,7 @@ class NetworkSpoke(FirstbootSpokeMixIn, NormalSpoke):
         gtk_call_once(self._update_status)
         gtk_call_once(self._update_hostname)
 
-    def on_device_state_changed(self, *args):
-        new_state = args[1]
+    def on_device_state_changed(self, source, device, new_state, *args):
         if new_state in (NetworkManager.DeviceState.ACTIVATED,
                          NetworkManager.DeviceState.DISCONNECTED,
                          NetworkManager.DeviceState.UNAVAILABLE):
@@ -1288,9 +1364,8 @@ class NetworkStandaloneSpoke(StandaloneSpoke):
         parent = self.builder.get_object("AnacondaStandaloneWindow-action_area5")
         parent.add(self.network_control_box.vbox)
 
-        self.network_control_box.client.connect("notify::%s" %
-                                                NMClient.CLIENT_STATE,
-                                                self.on_nm_state_changed)
+        self.network_control_box.connect("nm-state-changed",
+                                         self.on_nm_state_changed)
 
         self._initially_available = self.completed
         log.debug("network standalone spoke (init): completed: %s" % self._initially_available)
@@ -1353,9 +1428,9 @@ class NetworkStandaloneSpoke(StandaloneSpoke):
 
 def _update_network_data(data, ncb):
     data.network.network = []
-    for dev in ncb.listed_devices:
-        devname = dev.get_iface()
-        nd = network.ksdata_from_ifcfg(devname)
+    for dev_cfg in ncb.dev_cfgs:
+        devname = dev_cfg.get_iface()
+        nd = network.ksdata_from_ifcfg(devname, dev_cfg.con_uuid)
         if not nd:
             continue
         if devname in nm.nm_activated_devices():
@@ -1365,7 +1440,6 @@ def _update_network_data(data, ncb):
     network.update_hostname_data(data, hostname)
 
 if __name__ == "__main__":
-
     win = Gtk.Window()
     win.connect("delete-event", Gtk.main_quit)
 
-- 
1.7.11.7



More information about the anaconda-patches mailing list