--- pyanaconda/ui/gui/spokes/network.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/network.py b/pyanaconda/ui/gui/spokes/network.py index 2beccbd..a21b0c2 100644 --- a/pyanaconda/ui/gui/spokes/network.py +++ b/pyanaconda/ui/gui/spokes/network.py @@ -125,7 +125,7 @@ we_dont_have_nm_applet_as_secrets_agent = True # so we have to disconnect from former ap before trying # to connect to new one bound to fail due to no secrets
-__all__ = ["NetworkSpoke"] +__all__ = ["NetworkSpoke", "NetworkStandaloneSpoke"]
class CellRendererSignal(Gtk.CellRendererPixbuf):
ACTIVATED state of device doesn't ensure immediate availability of its configuration (NMIP4Config object) so we might need to make more tries.
Using separate callbacks for updating just config UI connected to config property change event would be overcomplicated because we are waiting for two properties (ipv4 and ipv6), and modifications of UI of one protocol depends on values of both of them. --- pyanaconda/ui/gui/spokes/network.py | 222 +++++++++++++++++++---------------- 1 files changed, 121 insertions(+), 101 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/network.py b/pyanaconda/ui/gui/spokes/network.py index a21b0c2..dbcd8f0 100644 --- a/pyanaconda/ui/gui/spokes/network.py +++ b/pyanaconda/ui/gui/spokes/network.py @@ -28,7 +28,6 @@ # see we_dont_have_nm_applet_as_secrets_agent # - callback on NM_CLIENT_ACTIVE_CONNECTIONS # - support connection to hidden network (ap-other) -# - apply(): fill ksdata (from ifcfg files!) # - device_is_stored # - NMClient.CLIENT_WIRELESS_ENABLED callback (hw switch?) - test # - nm-c-e run: blocking? logging? @@ -245,7 +244,6 @@ class NetworkControlBox():
self.builder.get_object("notebook_types").set_show_tabs(False)
- self._refresh_idle = None # to prevent UI update signals races self._updating_device = False
@@ -330,7 +328,8 @@ class NetworkControlBox(): selection.select_iter(devices_store.get_iter_first())
def refresh(self): - self.refresh_ui() + device = self.selected_device() + self.refresh_ui(device)
def status(self): active_wired_devs = [] @@ -366,15 +365,23 @@ class NetworkControlBox(): # Signal handlers. def on_device_selection_changed(self, *args): print "DBG: on_device_selection_changed" - self.refresh_ui() + device = self.selected_device() + self.refresh_ui(device)
def on_device_state_changed(self, *args): print "DBG: on_device_state_changed" - self.refresh_ui() + device = args[0] + new_state = args[1] + self._refresh_carrier_info() + read_config_values = (new_state == NetworkManager.DeviceState.ACTIVATED) + if device == self.selected_device(): + self.refresh_ui(device, read_config_values)
+ # TODO: remove/fix def on_active_connections_changed(self, *args): print "DBG: on_active_connections_changed" - self.refresh_ui() + device = self.selected_device() + self.refresh_ui(device)
def on_wireless_ap_changed_cb(self, combobox, *args): print "DBG: on_wireles_ap_changed_cb" @@ -442,8 +449,8 @@ class NetworkControlBox(): print "DBG: off switch ignored" return
- print "DBG: off switch" active = switch.get_active() + print "DBG: off switch active: %s" % active
device = self.selected_device()
@@ -580,104 +587,49 @@ class NetworkControlBox(): for row in rows_to_remove: del(row)
- def refresh_ui(self): - if self._refresh_idle: - print "DBG: refresh_ui_idle found" - return - time.sleep(0.3) - self._refresh_idle = GLib.idle_add(self.refresh_ui_idle) - print "DBG: refresh_ui_idle planned" - - def refresh_ui_idle(self): - print "DBG: refreshing ui" - self.refresh_device_ui(self.selected_device()) - self._refresh_idle = None - - def refresh_device_ui(self, device): - if not device: - return - - notebook = self.builder.get_object("notebook_types") + def refresh_ui(self, device, read_config_values=False): + self._refresh_device_type_page(device) + self._refresh_header_ui(device) + self._refresh_speed_hwaddr(device) + self._refresh_ap(device) + if read_config_values: + num_of_tries = 3 + else: + num_of_tries = 0 + self._refresh_device_cfg((device, num_of_tries)) + + def _refresh_device_cfg(self, dev_tries): + device, num_of_tries = dev_tries + ipv4cfg = None + ipv6cfg = None + + if num_of_tries > 0: + ipv4cfg = device.get_ip4_config() + ipv6cfg = device.get_ip6_config() + if not ipv4cfg and not ipv6cfg: + GLib.timeout_add(300, self._refresh_device_cfg, (device, + num_of_tries-1)) + return False + + # We might need to wait for config objects to become available + if device.get_state() == NetworkManager.DeviceState.ACTIVATED: + # Activating device with neither ipv4 nor ipv6 configured shouldn't + # loop endlessly so set timeout + timeout = 1 + while timeout > 0 and not ipv4cfg and not ipv6cfg: + while GLib.main_context_default().iteration(False): + pass + ipv4cfg = device.get_ip4_config() + ipv6cfg = device.get_ip6_config() + time.sleep(0.3) + timeout = timeout - 0.3
dev_type = device.get_device_type() - if dev_type == NetworkManager.DeviceType.ETHERNET: - dt = "wired" - notebook.set_current_page(0) - - self._refresh_header_ui(device, dt) - - speed = device.get_speed() - if device.get_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()) - elif dev_type == NetworkManager.DeviceType.WIFI: - dt = "wireless" - notebook.set_current_page(1) - - self._refresh_header_ui(device, dt) - - speed = device.get_bitrate() - if device.get_state() == NetworkManager.DeviceState.UNAVAILABLE: - speed_str = None - elif speed: - speed_str = _("%d Mb/s") % (speed / 1000) - else: - speed_str = "" - self._set_device_info_value(dt, "speed", speed_str) - - self._set_device_info_value(dt, "mac", device.get_hw_address()) - - if device.get_state() == NetworkManager.DeviceState.UNAVAILABLE: - ap_str = None - else: - active_ap = device.get_active_access_point() - if active_ap: - active_ap_dbus = dbus.SystemBus().get_object(NM_SERVICE, - active_ap.get_path()) - ap_str = self._ap_security_string_dbus(active_ap_dbus) - # TODO NM_GI_BUGS move to gi after fixed in NM - # - NetworkManager.80211ApFlags - # - active_ap.get_flags, get_wpa_flags, get_rsn_flags - #ap_str = self._ap_security_string(active_ap) - else: - ap_str = "" - - self._set_device_info_value(dt, "security", ap_str) - - if device.get_state() == NetworkManager.DeviceState.UNAVAILABLE: - self.builder.get_object("heading_wireless_network_name").hide() - self.builder.get_object("combobox_wireless_network_name").hide() - else: - self.builder.get_object("heading_wireless_network_name").show() - self.builder.get_object("combobox_wireless_network_name").show() - - store = self.builder.get_object("liststore_wireless_network") - self._updating_device = True - store.clear() - aps = self._get_strongest_unique_aps(device.get_access_points()) - for ap in aps: - active = active_ap and active_ap.get_path() == ap.get_path() - self._add_ap(ap, active) - # TODO: add access point other... - self._updating_device = False
- else: - print ("DBG: unsupported device type in the list!") - return - - # Only dhcp info is presented for ipv4, for static go to Options...? - - ipv4cfg = device.get_ip4_config() if (ipv4cfg and device.get_state() == NetworkManager.DeviceState.ACTIVATED): addr = socket.inet_ntoa(struct.pack('=L', @@ -703,7 +655,6 @@ class NetworkControlBox():
# TODO NM_GI_BUGS - segfaults on get_addres(), get_prefix() ipv6_addr = None - ipv6cfg = device.get_ip6_config() if (ipv6cfg and device.get_state() == NetworkManager.DeviceState.ACTIVATED): config = dbus.SystemBus().get_object(NM_SERVICE, ipv6cfg.get_path()) @@ -720,13 +671,82 @@ class NetworkControlBox(): elif ipv6_addr: self.builder.get_object("heading_%s_ipv6" % dt).set_label(_("IP Address"))
- self._refresh_carrier_info() + return False + + def _refresh_ap(self, device): + if device.get_device_type() != NetworkManager.DeviceType.WIFI: + return + + if device.get_state() == NetworkManager.DeviceState.UNAVAILABLE: + ap_str = None + else: + active_ap = device.get_active_access_point() + if active_ap: + active_ap_dbus = dbus.SystemBus().get_object(NM_SERVICE, + active_ap.get_path()) + ap_str = self._ap_security_string_dbus(active_ap_dbus) + # TODO NM_GI_BUGS move to gi after fixed in NM + # - NetworkManager.80211ApFlags + # - active_ap.get_flags, get_wpa_flags, get_rsn_flags + #ap_str = self._ap_security_string(active_ap) + else: + ap_str = "" + + self._set_device_info_value("wireless", "security", ap_str) + + if device.get_state() == NetworkManager.DeviceState.UNAVAILABLE: + self.builder.get_object("heading_wireless_network_name").hide() + self.builder.get_object("combobox_wireless_network_name").hide() + else: + self.builder.get_object("heading_wireless_network_name").show() + self.builder.get_object("combobox_wireless_network_name").show() + + store = self.builder.get_object("liststore_wireless_network") + self._updating_device = True + store.clear() + aps = self._get_strongest_unique_aps(device.get_access_points()) + for ap in aps: + active = active_ap and active_ap.get_path() == ap.get_path() + self._add_ap(ap, active) + # TODO: add access point other... + self._updating_device = False + + def _refresh_speed_hwaddr(self, device): + dev_type = device.get_device_type() + if dev_type == NetworkManager.DeviceType.ETHERNET: + dt = "wired" + speed = device.get_speed() + elif dev_type == NetworkManager.DeviceType.WIFI: + dt = "wireless" + speed = device.get_bitrate() / 1000 + + if device.get_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()) + + def _refresh_device_type_page(self, device): + notebook = self.builder.get_object("notebook_types") + dev_type = device.get_device_type() + if dev_type == NetworkManager.DeviceType.ETHERNET: + notebook.set_current_page(0) + elif dev_type == NetworkManager.DeviceType.WIFI: + notebook.set_current_page(1)
def _refresh_carrier_info(self): 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, dev_type_str): + def _refresh_header_ui(self, device): + dev_type = device.get_device_type() + if dev_type == NetworkManager.DeviceType.ETHERNET: + dev_type_str = "wired" + elif dev_type == NetworkManager.DeviceType.WIFI: + dev_type_str = "wireless"
if dev_type_str == "wired": # update icon according to device status
- def _refresh_device_cfg(self, dev_tries):
device, num_of_tries = dev_tries
ipv4cfg = None
ipv6cfg = None
if num_of_tries > 0:
ipv4cfg = device.get_ip4_config()
ipv6cfg = device.get_ip6_config()
if not ipv4cfg and not ipv6cfg:
GLib.timeout_add(300, self._refresh_device_cfg, (device,
num_of_tries-1))
return False
# We might need to wait for config objects to become available
if device.get_state() == NetworkManager.DeviceState.ACTIVATED:
# Activating device with neither ipv4 nor ipv6 configured shouldn't
# loop endlessly so set timeout
timeout = 1
while timeout > 0 and not ipv4cfg and not ipv6cfg:
while GLib.main_context_default().iteration(False):
pass
I am caught in an infinite loop right here, leading to never being able to load the network spoke off the hub. Any ideas?
- Chris
--- pyanaconda/ui/gui/spokes/network.py | 13 +++++++++---- 1 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/network.py b/pyanaconda/ui/gui/spokes/network.py index dbcd8f0..c513b94 100644 --- a/pyanaconda/ui/gui/spokes/network.py +++ b/pyanaconda/ui/gui/spokes/network.py @@ -278,9 +278,8 @@ class NetworkControlBox(): self.on_device_off_toggled) self.builder.get_object("device_wireless_off_switch").connect("notify::active", self.on_device_off_toggled) - # TODO - #self.client.connect("notify::%s" % NMClient.CLIENT_WIRELESS_ENABLED, - # self._wireless_enabled_toggled) + self.client.connect("notify::%s" % NMClient.CLIENT_WIRELESS_ENABLED, + self.on_wireless_enabled)
self.builder.get_object("button_wired_options").connect("clicked", self.on_edit_connection) @@ -444,6 +443,12 @@ class NetworkControlBox():
subprocess.Popen(["nm-connection-editor", "--edit", "%s" % uuid])
+ def on_wireless_enabled(self, *args): + switch = self.builder.get_object("device_wireless_off_switch") + self._updating_device = True + switch.set_active(self.client.wireless_get_enabled()) + self._updating_device = False + def on_device_off_toggled(self, switch, *args): if self._updating_device: print "DBG: off switch ignored" @@ -775,7 +780,7 @@ class NetworkControlBox(): if not configuration_of_disconnected_devices_allowed: self.builder.get_object("button_%s_options" % dev_type_str).set_sensitive(state == NetworkManager.DeviceState.ACTIVATED) elif dev_type_str == "wireless": - switch.set_active(self.client.wireless_get_enabled()) + self.on_wireless_enabled()
def _set_device_info_value(self, dev_type_str, info, value_str): heading = self.builder.get_object("heading_%s_%s" % (dev_type_str, info))
--- pyanaconda/network.py | 148 ++++++++++++++++++----------------- pyanaconda/ui/gui/spokes/network.py | 39 +++++++++- 2 files changed, 114 insertions(+), 73 deletions(-)
diff --git a/pyanaconda/network.py b/pyanaconda/network.py index 61470c6..7e4796f 100644 --- a/pyanaconda/network.py +++ b/pyanaconda/network.py @@ -586,77 +586,7 @@ class Network:
for devName in devNames: dev = self.netdevices[devName] - - line = "network" - - # ipv4 and ipv6 - if dev.get("ONBOOT"): - line += " --onboot %s" % dev.get("ONBOOT") - line += " --device %s" % dev.iface - if dev.get('MTU') and dev.get('MTU') != "0": - line += " --mtu=%s" % dev.get('MTU') - - # ipv4 - if not dev.get('BOOTPROTO'): - line += " --noipv4" - else: - if dev.get('BOOTPROTO').lower() == 'dhcp': - line += " --bootproto dhcp" - if dev.get('DHCPCLASS'): - line += " --dhcpclass %s" % dev.get('DHCPCLASS') - elif dev.get('IPADDR'): - line += " --bootproto static --ip %s" % dev.get('IPADDR') - netmask = dev.get('NETMASK') - prefix = dev.get('PREFIX') - if not netmask and prefix: - netmask = isys.prefix2netmask(int(prefix)) - if netmask: - line += " --netmask %s" % netmask - # note that --gateway is common for ipv4 and ipv6 - if dev.get('GATEWAY'): - line += " --gateway %s" % dev.get('GATEWAY') - - # ipv6 - if (not dev.get('IPV6INIT') or - dev.get('IPV6INIT') == "no"): - line += " --noipv6" - else: - if dev.get('IPV6_AUTOCONF') == "yes": - line += " --ipv6 auto" - else: - if dev.get('IPV6ADDR'): - line += " --ipv6 %s" % dev.get('IPV6ADDR') - if dev.get('IPV6_DEFAULTGW'): - line += " --gateway %s" % dev.get('IPV6_DEFAULTGW') - if dev.get('DHCPV6') == "yes": - line += " --ipv6 dhcp" - - # ipv4 and ipv6 - dnsline = '' - for key in dev.info.keys(): - if key.upper().startswith('DNS'): - if dnsline == '': - dnsline = dev.get(key) - else: - dnsline += "," + dev.get(key) - if dnsline: - line += " --nameserver %s" % dnsline - - if dev.get("ETHTOOL_OPTS"): - line += " --ethtool %s" % dev.get("ETHTOOL_OPTS") - - if dev.get("ESSID"): - line += " --essid %s" % dev.get("ESSID") - - # hostname - if dev.get("DHCP_HOSTNAME"): - line += " --hostname %s" % dev.get("DHCP_HOSTNAME") - elif dev.get("BOOTPROTO").lower != "dhcp": - if (self.hostname and - self.hostname != "localhost.localdomain"): - line += " --hostname %s" % self.hostname - - line += "\n" + line = "%s" % kickstartNetworkData(dev, self.hostname) f.write(line)
def hasNameServers(self, hash): @@ -921,6 +851,82 @@ class Network:
return netargs
+def kickstartNetworkData(ifcfg, hostname=None): + + from pyanaconda.kickstart import NetworkData + kwargs = {} + + # ipv4 and ipv6 + if not ifcfg.get("ESSID"): + kwargs["device"] = ifcfg.iface + if ifcfg.get("ONBOOT") and ifcfg.get("ONBOOT" ) == "no": + kwargs["onboot"] = False + if ifcfg.get('MTU') and ifcfg.get('MTU') != "0": + kwargs["mtu"] = ifcfg.get('MTU') + + # ipv4 + if not ifcfg.get('BOOTPROTO'): + kwargs["noipv4"] = True + else: + if ifcfg.get('BOOTPROTO').lower() == 'dhcp': + kwargs["bootProto"] = "dhcp" + if ifcfg.get('DHCPCLASS'): + kwargs["dhcpclass"] = ifcfg.get('DHCPCLASS') + elif ifcfg.get('IPADDR'): + kwargs["bootProto"] = "static" + kwargs["ip"] = ifcfg.get('IPADDR') + netmask = ifcfg.get('NETMASK') + prefix = ifcfg.get('PREFIX') + if not netmask and prefix: + netmask = isys.prefix2netmask(int(prefix)) + if netmask: + kwargs["netmask"] = netmask + # note that --gateway is common for ipv4 and ipv6 + if ifcfg.get('GATEWAY'): + kwargs["gateway"] = ifcfg.get('GATEWAY') + + # ipv6 + if (not ifcfg.get('IPV6INIT') or + ifcfg.get('IPV6INIT') == "no"): + kwargs["noipv6"] = True + else: + if ifcfg.get('IPV6_AUTOCONF') == "yes": + kwargs["ipv6"] = "auto" + else: + if ifcfg.get('IPV6ADDR'): + kwargs["ipv6"] = ifcfg.get('IPV6ADDR') + if ifcfg.get('IPV6_DEFAULTGW'): + kwargs["gateway"] = ifcfg.get('IPV6_DEFAULTGW') + if ifcfg.get('DHCPV6') == "yes": + kwargs["ipv6"] = "dhcp" + + # ipv4 and ipv6 + dnsline = '' + for key in ifcfg.info.keys(): + if key.upper().startswith('DNS'): + if dnsline == '': + dnsline = ifcfg.get(key) + else: + dnsline += "," + ifcfg.get(key) + if dnsline: + kwargs["nameserver"] = dnsline + + if ifcfg.get("ETHTOOL_OPTS"): + kwargs["ethtool"] = ifcfg.get("ETHTOOL_OPTS") + + if ifcfg.get("ESSID"): + kwargs["essid"] = ifcfg.get("ESSID") + + # hostname + if ifcfg.get("DHCP_HOSTNAME"): + kwargs["hostname"] = ifcfg.get("DHCP_HOSTNAME") + elif ifcfg.get("BOOTPROTO").lower != "dhcp": + if (hostname and + hostname != "localhost.localdomain"): + kwargs["hostname"] = hostname + + return NetworkData(**kwargs) + def getSSIDs(devices_to_scan=None):
rv = {} diff --git a/pyanaconda/ui/gui/spokes/network.py b/pyanaconda/ui/gui/spokes/network.py index c513b94..0552650 100644 --- a/pyanaconda/ui/gui/spokes/network.py +++ b/pyanaconda/ui/gui/spokes/network.py @@ -39,6 +39,8 @@ from pyanaconda.ui.gui.spokes import NormalSpoke, StandaloneSpoke from pyanaconda.ui.gui.categories.software import SoftwareCategory from pyanaconda.ui.gui.hubs.summary import SummaryHub
+from pyanaconda.network import NetworkDevice, netscriptsDir, kickstartNetworkData, getActiveNetDevs + from gi.repository import GLib, GObject, Pango, Gio, NetworkManager, NMClient import dbus import socket @@ -923,6 +925,11 @@ class NetworkControlBox():
return sec_str
+ @property + def listed_devices(self): + return [row[DEVICES_COLUMN_OBJECT] for + row in self.builder.get_object("liststore_devices")] + class NetworkSpoke(NormalSpoke): builderObjects = ["networkWindow", "liststore_wireless_network", "liststore_devices"] mainWidgetName = "networkWindow" @@ -938,7 +945,11 @@ class NetworkSpoke(NormalSpoke): self.network_control_box = NetworkControlBox(self.builder)
def apply(self): - pass + self.data.network.network = [] + for dev in self.network_control_box.listed_devices: + network_data = getKSNetworkData(dev) + if network_data is not None: + self.data.network.network.append(network_data)
@property def completed(self): @@ -957,7 +968,6 @@ class NetworkSpoke(NormalSpoke): NormalSpoke.refresh(self) self.network_control_box.refresh()
- class NetworkStandaloneSpoke(StandaloneSpoke): builderObjects = ["networkStandaloneWindow", "networkControlBox_vbox", "liststore_wireless_network", "liststore_devices"] mainWidgetName = "networkStandaloneWindow" @@ -976,6 +986,12 @@ class NetworkStandaloneSpoke(StandaloneSpoke): self._now_available = False
def apply(self): + self.data.network.network = [] + for dev in self.network_control_box.listed_devices: + network_data = getKSNetworkData(dev) + if network_data is not None: + self.data.network.network.append(network_data) + self._now_available = self.network_control_box.status() != _("Not connected")
if not self.payload.baseRepo and not self._initially_available and self._now_available: @@ -1002,6 +1018,25 @@ class NetworkStandaloneSpoke(StandaloneSpoke): self.window.hide() Gtk.main_quit()
+def getKSNetworkData(device): + retval = None + + ifcfg_suffix = None + if device.get_device_type() == NetworkManager.DeviceType.ETHERNET: + ifcfg_suffix = device.get_iface() + elif device.get_device_type() == NetworkManager.DeviceType.WIFI: + ap = device.get_active_access_point() + if ap: + ifcfg_suffix = ap.get_ssid() + + if ifcfg_suffix: + device_cfg = NetworkDevice(netscriptsDir, ifcfg_suffix) + device_cfg.loadIfcfgFile() + retval = kickstartNetworkData(device_cfg) + if device.get_iface() in getActiveNetDevs(): + retval.activate = True + + return retval
if __name__ == "__main__":
--- pyanaconda/ui/gui/spokes/network.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/network.py b/pyanaconda/ui/gui/spokes/network.py index 0552650..0fe4295 100644 --- a/pyanaconda/ui/gui/spokes/network.py +++ b/pyanaconda/ui/gui/spokes/network.py @@ -370,9 +370,9 @@ class NetworkControlBox(): self.refresh_ui(device)
def on_device_state_changed(self, *args): - print "DBG: on_device_state_changed" device = args[0] new_state = args[1] + print "DBG: on_device_state_changed to: %d" % new_state self._refresh_carrier_info() read_config_values = (new_state == NetworkManager.DeviceState.ACTIVATED) if device == self.selected_device(): @@ -453,11 +453,11 @@ class NetworkControlBox():
def on_device_off_toggled(self, switch, *args): if self._updating_device: - print "DBG: off switch ignored" + print "DBG: on_device_off_toggled ignored" return
active = switch.get_active() - print "DBG: off switch active: %s" % active + print "DBG: on_device_off_toggled from: %s" % active
device = self.selected_device()
@@ -595,6 +595,7 @@ class NetworkControlBox(): del(row)
def refresh_ui(self, device, read_config_values=False): + print "DBG: refresh ui %s" % device self._refresh_device_type_page(device) self._refresh_header_ui(device) self._refresh_speed_hwaddr(device)
anaconda-devel@lists.stg.fedoraproject.org