[PATCH 0/2] bugfix anaconda-20.25.1-1
by Gene Czarcinski
A couple of little agrravations which came up with 20.25.1 and
Beta-TC5. The first fixes it so that the existing BTRFS subvolume
actually will be added to fstab. The second will add (existing)
noformat swap regular partition or logical volumes to fstab. An
updates img was created and tested with TC5.
Gene Czarcinski (2):
fix support existing btrfs subvolumes
fix swaps added to fstab for noformat
pyanaconda/kickstart.py | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
--
1.8.3.1
10 years, 8 months
[PATCH rhel7-branch] network gui: make Configure button insensitive when no ap is selected (#1015212)
by Radek Vykydal
For not connected wireless AP combobox has no AP selected initially.
Allow configuration only when an AP to be configured had been chosen.
Resolves: rhbz#1015212
---
pyanaconda/ui/gui/spokes/network.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyanaconda/ui/gui/spokes/network.py b/pyanaconda/ui/gui/spokes/network.py
index 9887130..dc4499c 100644
--- a/pyanaconda/ui/gui/spokes/network.py
+++ b/pyanaconda/ui/gui/spokes/network.py
@@ -873,6 +873,7 @@ class NetworkControlBox(object):
self.builder.get_object("label_wired_parent").hide()
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)
def _refresh_carrier_info(self):
for i in self.builder.get_object("liststore_devices"):
--
1.7.11.7
10 years, 8 months
[blivet master] initial aarch64 support
by Dennis Gilmore
I think that this should be sufficient for aarch64 as we intend to only support UEFI.
There should be no need for a aarch64 class, we can just reuse the existing EFI code.
Dennis
10 years, 8 months
[master] Add translation contexts
by David Shea
I tried to explain the reason for this in the first commit message, but this is
admitedly kind of a confusing topic. Let me know if you have any questions, and
I'll try to add answers to them in the forthcoming wiki edit about contexts.
This also has the side-effect of de-translating a good chunk of anaconda, since
msgids with new contexts will be marked as "fuzzy" until translators go in and
accept the changes. Once this is implemented, translators will actually have
the tools to do something about some of things that the translated keyboard
accelerator check finds.
10 years, 8 months
[PATCH rhel7-branch] network kickstart: add support for devices configured in %pre (#1019796)
by Radek Vykydal
Resolves: rhbz#1019796
Eg %include configuration creted dynamically in %pre
---
pyanaconda/network.py | 264 +++++++++++++++++++++++++++++++++++++++-----------
pyanaconda/nm.py | 114 +++++++++++++++++++---
2 files changed, 309 insertions(+), 69 deletions(-)
diff --git a/pyanaconda/network.py b/pyanaconda/network.py
index 79f609f..ef50a27 100644
--- a/pyanaconda/network.py
+++ b/pyanaconda/network.py
@@ -34,6 +34,7 @@ import tempfile
import simpleconfig
import re
import IPy
+import uuid
from flags import flags
import itertools
@@ -216,10 +217,11 @@ def _ifcfg_files(directory):
def logIfcfgFiles(message=""):
ifcfglog.debug("content of files (%s):" % message)
for path in _ifcfg_files(netscriptsDir):
+ ifcfglog.debug("%s:" % path)
with open(path, "r") as f:
- content = f.read()
- ifcfglog.debug("%s:\n%s" % (path, content))
-
+ for line in f.readlines():
+ ifcfglog.debug(" %s" % line.strip())
+ ifcfglog.debug("all settings: %s" % nm.nm_get_all_settings())
class IfcfgFile(SimpleConfigFile):
def __init__(self, filename):
@@ -269,10 +271,10 @@ def dumpMissingDefaultIfcfgs():
and dump its ifcfg file. (For server, default auto connections will
be turned off in NetworkManager.conf.)
The connection id (and consequently ifcfg file) is set to device name.
- Returns True if any ifcfg file was dumped.
+ Returns list of devices for which ifcfg file was dumped.
"""
- rv = False
+ rv = []
for devname in nm.nm_devices():
# for each ethernet device
@@ -285,7 +287,7 @@ def dumpMissingDefaultIfcfgs():
con_uuid = nm.nm_device_setting_value(devname, "connection", "uuid")
except nm.SettingsNotFoundError:
continue
- if find_ifcfg_file([("UUID", con_uuid)], root_path=""):
+ if find_ifcfg_file_of_device(devname):
continue
try:
@@ -295,7 +297,7 @@ def dumpMissingDefaultIfcfgs():
log.debug("network: setting autoconnect of %s to False" % devname)
except nm.SettingsNotFoundError:
log.debug("network: no ifcfg file for %s" % devname)
- rv = True
+ rv.append(devname)
return rv
@@ -382,33 +384,34 @@ def dracutBootArguments(devname, ifcfg, storage_ipaddr, hostname=None):
return netargs
-def update_settings_with_ksdata(devname, networkdata):
-
- new_values = []
+def _get_ip_setting_values_from_ksdata(networkdata):
+ values = []
# ipv4 settings
method4 = "auto"
if networkdata.bootProto == "static":
method4 = "manual"
- new_values.append(["ipv4", "method", method4, "s"])
+ values.append(["ipv4", "method", method4, "s"])
if method4 == "manual":
addr4 = nm.nm_ipv4_to_dbus_int(networkdata.ip)
gateway4 = nm.nm_ipv4_to_dbus_int(networkdata.gateway)
prefix4 = netmask2prefix(networkdata.netmask)
- new_values.append(["ipv4", "addresses", [[addr4, prefix4, gateway4]], "aau"])
+ values.append(["ipv4", "addresses", [[addr4, prefix4, gateway4]], "aau"])
# ipv6 settings
if networkdata.noipv6:
method6 = "ignore"
else:
- if networkdata.ipv6 == "auto":
+ if not networkdata.ipv6:
+ method6 = "auto"
+ elif networkdata.ipv6 == "auto":
method6 = "auto"
elif networkdata.ipv6 == "dhcp":
method6 = "dhcp"
else:
method6 = "manual"
- new_values.append(["ipv6", "method", method6, "s"])
+ values.append(["ipv6", "method", method6, "s"])
if method6 == "manual":
addr6, _slash, prefix6 = networkdata.ipv6.partition("/")
@@ -421,7 +424,7 @@ def update_settings_with_ksdata(devname, networkdata):
gateway6 = nm.nm_ipv6_to_dbus_ay(networkdata.ipv6gateway)
else:
gateway6 = [0] * 16
- new_values.append(["ipv6", "addresses", [(addr6, prefix6, gateway6)], "a(ayuay)"])
+ values.append(["ipv6", "addresses", [(addr6, prefix6, gateway6)], "a(ayuay)"])
# nameservers
nss4 = []
@@ -432,13 +435,91 @@ def update_settings_with_ksdata(devname, networkdata):
nss6.append(nm.nm_ipv6_to_dbus_ay(ns))
else:
nss4.append(nm.nm_ipv4_to_dbus_int(ns))
- new_values.append(["ipv4", "dns", nss4, "au"])
- new_values.append(["ipv6", "dns", nss6, "aay"])
+ values.append(["ipv4", "dns", nss4, "au"])
+ values.append(["ipv6", "dns", nss6, "aay"])
- # onboot
- new_values.append(['connection', 'autoconnect', networkdata.onboot, None])
+ return values
+def update_settings_with_ksdata(devname, networkdata):
+ new_values = _get_ip_setting_values_from_ksdata(networkdata)
+ new_values.append(['connection', 'autoconnect', networkdata.onboot, None])
+ uuid = nm.nm_device_setting_value(devname, "connection", "uuid")
nm.nm_update_settings_of_device(devname, new_values)
+ return uuid
+
+def bond_options_ksdata_to_dbus(opts_str):
+ retval = {}
+ for option in opts_str.split(";" if ';' in opts_str else ","):
+ key, _sep, value = option.partition("=")
+ retval[key] = value
+ return retval
+
+def add_connection_for_ksdata(networkdata, devname):
+
+ added_connections = []
+ con_uuid = str(uuid.uuid4())
+ values = _get_ip_setting_values_from_ksdata(networkdata)
+ # HACK preventing NM to autoactivate the connection
+ #values.append(['connection', 'autoconnect', networkdata.onboot, 'b'])
+ values.append(['connection', 'autoconnect', False, 'b'])
+ values.append(['connection', 'uuid', con_uuid, 's'])
+
+ # type "bond"
+ if networkdata.bondslaves:
+ # bond connection is autoactivated
+ values.append(['connection', 'type', 'bond', 's'])
+ values.append(['connection', 'id', devname, 's'])
+ values.append(['bond', 'interface-name', devname, 's'])
+ options = bond_options_ksdata_to_dbus(networkdata.bondopts)
+ values.append(['bond', 'options', options, 'a{ss}'])
+ for i, slave in enumerate(networkdata.bondslaves.split(","), 1):
+
+ #slave_name = "%s slave %d" % (devname, i)
+ slave_name = slave
+
+ svalues = []
+ suuid = str(uuid.uuid4())
+ svalues.append(['connection', 'uuid', suuid, 's'])
+ svalues.append(['connection', 'id', slave_name, 's'])
+ 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 = [int(b, 16) for b in mac.split(":")]
+ svalues.append(['802-3-ethernet', 'mac-address', mac, 'ay'])
+
+ # disconnect slaves
+ if networkdata.activate:
+ nm.nm_disconnect_device(slave)
+ # remove ifcfg file
+ ifcfg_path = find_ifcfg_file_of_device(slave)
+ if ifcfg_path and os.access(ifcfg_path, os.R_OK):
+ os.unlink(ifcfg_path)
+
+ nm.nm_add_connection(svalues)
+ added_connections.append((suuid, slave))
+ dev_spec = None
+ # type "vlan"
+ elif networkdata.vlanid:
+ parent, _sep, _vlanid = devname.partition(".")
+ values.append(['vlan', 'parent', parent, 's'])
+ values.append(['connection', 'type', 'vlan', 's'])
+ values.append(['connection', 'id', devname, 's'])
+ values.append(['vlan', 'interface-name', devname, 's'])
+ values.append(['vlan', 'id', int(networkdata.vlanid), 'u'])
+ dev_spec = None
+ # type "802-3-ethernet"
+ else:
+ values.append(['connection', 'type', '802-3-ethernet', 's'])
+ values.append(['connection', 'id', devname, 's'])
+ mac = nm.nm_device_hwaddress(devname)
+ mac = [int(b, 16) for b in mac.split(":")]
+ values.append(['802-3-ethernet', 'mac-address', mac, 'ay'])
+ dev_spec = devname
+
+ nm.nm_add_connection(values)
+ added_connections.insert(0, (con_uuid, dev_spec))
+ return added_connections
def ksdata_from_ifcfg(devname):
@@ -454,16 +535,7 @@ def ksdata_from_ifcfg(devname):
ifcfg_path = find_ifcfg_file([("UUID", uuid)])
else:
# If not, look it up by other values depending on its type
- if nm.nm_device_type_is_ethernet(devname):
- ifcfg_path = find_ifcfg_file_of_device(devname)
- elif nm.nm_device_type_is_wifi(devname):
- ssid = nm.nm_device_active_ssid(devname)
- if ssid:
- ifcfg_path = find_ifcfg_file([("ESSID", ssid)])
- elif nm.nm_device_type_is_bond(devname):
- ifcfg_path = find_ifcfg_file([("DEVICE", devname)])
- elif nm.nm_device_type_is_vlan(devname):
- ifcfg_path = find_ifcfg_file([("DEVICE", devname)])
+ ifcfg_path = find_ifcfg_file_of_device(devname)
if not ifcfg_path:
return None
@@ -599,21 +671,34 @@ def hostname_ksdata(hostname):
def find_ifcfg_file_of_device(devname, root_path=""):
ifcfg_path = None
- try:
- hwaddr = nm.nm_device_hwaddress(devname)
- except nm.PropertyNotFoundError:
- hwaddr = None
- if hwaddr:
- hwaddr_check = lambda mac: mac.upper() == hwaddr.upper()
- nonempty = lambda x: x
- # slave configration created in GUI takes precedence
- ifcfg_path = find_ifcfg_file([("HWADDR", hwaddr_check),
- ("MASTER", nonempty)],
- root_path)
+ if devname not in nm.nm_devices():
+ return None
+
+ if nm.nm_device_type_is_wifi(devname):
+ ssid = nm.nm_device_active_ssid(devname)
+ if ssid:
+ ifcfg_path = find_ifcfg_file([("ESSID", ssid)])
+ elif nm.nm_device_type_is_bond(devname):
+ ifcfg_path = find_ifcfg_file([("DEVICE", devname)])
+ elif nm.nm_device_type_is_vlan(devname):
+ ifcfg_path = find_ifcfg_file([("DEVICE", devname)])
+ elif nm.nm_device_type_is_ethernet(devname):
+ try:
+ hwaddr = nm.nm_device_hwaddress(devname)
+ except nm.PropertyNotFoundError:
+ hwaddr = None
+ if hwaddr:
+ hwaddr_check = lambda mac: mac.upper() == hwaddr.upper()
+ nonempty = lambda x: x
+ # slave configration created in GUI takes precedence
+ ifcfg_path = find_ifcfg_file([("HWADDR", hwaddr_check),
+ ("MASTER", nonempty)],
+ root_path)
+ if not ifcfg_path:
+ ifcfg_path = find_ifcfg_file([("HWADDR", hwaddr_check)], root_path)
if not ifcfg_path:
- ifcfg_path = find_ifcfg_file([("HWADDR", hwaddr_check)], root_path)
- if not ifcfg_path:
- ifcfg_path = find_ifcfg_file([("DEVICE", devname)], root_path)
+ ifcfg_path = find_ifcfg_file([("DEVICE", devname)], root_path)
+
return ifcfg_path
def find_ifcfg_file(values, root_path=""):
@@ -720,7 +805,7 @@ def copyDhclientConfFiles(destPath):
dhclientfile = os.path.join("/etc/dhcp/dhclient-%s.conf" % devName)
copyFileToPath(dhclientfile, destPath)
-def get_ksdevice_name(ksspec=""):
+def ks_spec_to_device_name(ksspec=""):
if not ksspec:
ksspec = flags.cmdline.get('ksdevice', "")
@@ -738,7 +823,7 @@ def get_ksdevice_name(ksspec=""):
try:
link_up = nm.nm_device_carrier(dev)
except ValueError as e:
- log.debug("get_ksdevice_name: %s" % e)
+ log.debug("ks_spec_to_device_name: %s" % e)
continue
if link_up:
ksdevice = dev
@@ -748,7 +833,7 @@ def get_ksdevice_name(ksspec=""):
try:
hwaddr = nm.nm_device_hwaddress(dev)
except ValueError as e:
- log.debug("get_ksdevice_name: %s" % e)
+ log.debug("ks_spec_to_device_name: %s" % e)
continue
if ksdevice.lower() == hwaddr.lower():
ksdevice = dev
@@ -758,7 +843,7 @@ def get_ksdevice_name(ksspec=""):
try:
hwaddr = nm.nm_device_hwaddress(dev)
except ValueError as e:
- log.debug("get_ksdevice_name: %s" % e)
+ log.debug("ks_spec_to_device_name: %s" % e)
continue
if bootif_mac.lower() == hwaddr.lower():
ksdevice = dev
@@ -930,7 +1015,7 @@ def get_device_name(devspec):
if not devspec:
if "ksdevice" in flags.cmdline:
msg = "ksdevice boot parameter"
- devname = get_ksdevice_name(flags.cmdline["ksdevice"])
+ devname = ks_spec_to_device_name(flags.cmdline["ksdevice"])
elif nm.nm_is_connected():
# device activated in stage 1 by network kickstart command
msg = "first active device"
@@ -983,18 +1068,71 @@ def get_device_name(devspec):
return devname
def setOnboot(ksdata):
+ updated_devices = []
for network_data in ksdata.network.network:
- devname = get_device_name(network_data.device)
- if not devname:
- log.error("Kickstart: The provided network interface %s does not exist" % network_data.device)
- continue
+ # vlan
+ if network_data.vlanid:
+ physdev = get_device_name(network_data.device) or network_data.device
+ devname = "%s.%s" % (physdev, network_data.vlanid)
+ # bond
+ elif network_data.bondslaves:
+ devname = network_data.device
+ # ethernet
+ else:
+ devname = get_device_name(network_data.device)
+ if not devname:
+ log.warning("Kickstart: The provided network interface %s does not exist" % network_data.device)
+ continue
+ updated_devices.append(devname)
try:
nm.nm_update_settings_of_device(devname, [['connection', 'autoconnect', network_data.onboot, None]])
- ifcfglog.debug("setting autoconnect (ONBOOT) of %s to %s" % (devname, network_data.onboot))
- except nm.SettingsNotFoundError as e:
+ except (nm.SettingsNotFoundError, nm.UnknownDeviceError) as e:
log.debug("setOnboot: %s" % e)
+ return updated_devices
+
+def apply_kickstart_from_pre_section(ksdata):
+ applied_devices = []
+
+ for network_data in ksdata.network.network:
+
+ # TODO: wireless not supported yet
+ if network_data.essid:
+ continue
+
+ # get device name for device specified by MAC, link, bootif, etc...
+ dev_name = ks_spec_to_device_name(network_data.device)
+ if not dev_name:
+ log.error("Kickstart: The provided network interface %s does not exist" % network_data.device)
+ continue
+
+ if network_data.vlanid:
+ dev_name = "%s.%s" % (dev_name, network_data.vlanid)
+
+ ifcfg_path = find_ifcfg_file_of_device(dev_name)
+ # if the device was already configured in intramfs by kickstart ignore it
+ if ifcfg_path:
+ with open(ifcfg_path, 'r') as f:
+ if "parse-kickstart" in f.read():
+ continue
+
+ applied_devices.append(dev_name)
+ if ifcfg_path:
+ # if the device was already configured in initramfs update the settings
+ log.debug("network: pre kickstart - updating settings of device %s" % dev_name)
+ con_uuid = update_settings_with_ksdata(dev_name, network_data)
+ added_connections = [(con_uuid, dev_name)]
+ else:
+ log.debug("network: pre kickstart - adding connection for %s" % dev_name)
+ # Virtual devices (eg vlan, bond) return dev_name == None
+ added_connections = add_connection_for_ksdata(network_data, dev_name)
+
+ if network_data.activate:
+ for con_uuid, dev_name in added_connections:
+ nm.nm_activate_device_connection(dev_name, con_uuid)
+
+ return applied_devices
def networkInitialize(ksdata):
@@ -1002,13 +1140,25 @@ def networkInitialize(ksdata):
logIfcfgFiles("network initialization")
if not flags.imageInstall:
- if dumpMissingDefaultIfcfgs():
- logIfcfgFiles("ifcfgs created")
+ devnames = apply_kickstart_from_pre_section(ksdata)
+ if devnames:
+ msg = "kickstart pre section applied for devices %s" % devnames
+ log.debug("network: %s" % msg)
+ logIfcfgFiles(msg)
+ devnames = dumpMissingDefaultIfcfgs()
+ if devnames:
+ msg = "missing ifcfgs created for devices %s" % devnames
+ log.debug("network: %s" % msg)
+ logIfcfgFiles(msg)
# For kickstart network --activate option we set ONBOOT=yes
# in dracut to get devices activated by NM. The real network --onboot
# value is set here.
- setOnboot(ksdata)
+ devnames = setOnboot(ksdata)
+ if devnames:
+ msg = "setting real kickstart ONBOOT value for devices %s" % devnames
+ log.debug("network: %s" % msg)
+ logIfcfgFiles(msg)
if ksdata.network.hostname is None:
hostname = getHostname()
diff --git a/pyanaconda/nm.py b/pyanaconda/nm.py
index b08d4ca..9325339 100644
--- a/pyanaconda/nm.py
+++ b/pyanaconda/nm.py
@@ -357,8 +357,6 @@ def nm_device_ip_config(name, version=4):
UnknownDeviceError if device is not found
PropertyNotFoundError if ip configuration is not found
"""
- retval = []
-
state = nm_device_property(name, "State")
if state != NetworkManager.DeviceState.ACTIVATED:
return []
@@ -535,6 +533,31 @@ def _find_settings(value, key1, key2, format_value=lambda x:x):
return retval
+def nm_get_all_settings():
+ """Return all settings for logging."""
+ retval = []
+
+ proxy = _get_proxy(object_path="/org/freedesktop/NetworkManager/Settings", interface_name="org.freedesktop.NetworkManager.Settings")
+
+ args = None
+ connections = proxy.call_sync("ListConnections",
+ args,
+ Gio.DBusCallFlags.NONE,
+ DEFAULT_DBUS_TIMEOUT,
+ None)
+
+ for con in connections.unpack()[0]:
+ proxy = _get_proxy(object_path=con, interface_name="org.freedesktop.NetworkManager.Settings.Connection")
+ args = None
+ settings = proxy.call_sync("GetSettings",
+ args,
+ Gio.DBusCallFlags.NONE,
+ DEFAULT_DBUS_TIMEOUT,
+ None)
+ retval.append(settings)
+
+ return retval
+
def nm_device_setting_value(name, key1, key2):
"""Return value of device's setting specified by key1 and key2.
@@ -599,17 +622,13 @@ def nm_ap_setting_value(ssid, key1, key2):
value = None
return value
+def nm_disconnect_device(name):
+ """Disconnect the device.
-def nm_activate_device_connection(dev_name, con_uuid):
- """Activate device with specified connection.
-
- Exceptions:
- UnknownDeviceError - device was not found
-
+ :raise UnknownDeviceError: if device is not found
"""
-
proxy = _get_proxy()
- args = GLib.Variant('(s)', (dev_name,))
+ args = GLib.Variant('(s)', (name,))
try:
device = proxy.call_sync("GetDeviceByIpIface",
args,
@@ -618,10 +637,48 @@ def nm_activate_device_connection(dev_name, con_uuid):
None)
except GLib.GError as e:
if "org.freedesktop.NetworkManager.UnknownDevice" in e.message:
- raise UnknownDeviceError(dev_name, e)
+ raise UnknownDeviceError(name, e)
raise
- device_path = device.unpack()[0]
+ device = device.unpack()[0]
+ device_proxy = _get_proxy(object_path=device, interface_name="org.freedesktop.NetworkManager.Device")
+ args = None
+ device_proxy.call_sync("Disconnect",
+ args,
+ Gio.DBusCallFlags.NONE,
+ DEFAULT_DBUS_TIMEOUT,
+ None)
+
+def nm_activate_device_connection(dev_name, con_uuid):
+ """Activate device with specified connection.
+
+ :param dev_name: name of device or None for virtual devices
+ :type dev_name: str or None
+ :param con_uuid: uuid of connection to be activated on device
+ :type con_uuid: str
+ :raise UnknownDeviceError: if device is not found
+ :raise UnmanagedDeviceError: if device is not managed by NM
+ or unavailable
+ """
+
+ if dev_name is None:
+ # virtual devices (eg bond, vlan)
+ device_path = "/"
+ else:
+ proxy = _get_proxy()
+ args = GLib.Variant('(s)', (dev_name,))
+ try:
+ device = proxy.call_sync("GetDeviceByIpIface",
+ args,
+ Gio.DBusCallFlags.NONE,
+ DEFAULT_DBUS_TIMEOUT,
+ None)
+ except Exception as e:
+ if "org.freedesktop.NetworkManager.UnknownDevice" in e.message:
+ raise UnknownDeviceError(dev_name, e)
+ raise
+
+ device_path = device.unpack()[0]
con_path = _find_settings(con_uuid, 'connection', 'uuid')
@@ -638,6 +695,39 @@ def nm_activate_device_connection(dev_name, con_uuid):
raise UnmanagedDeviceError(dev_name, e)
raise
+def nm_add_connection(values):
+ """Add new connection specified by values.
+
+ :param values: list of settings with new values and its types
+ [[key1, key2, value, type_str], ...]
+ key1: first-level key of setting (eg "connection")
+ key2: second-level key of setting (eg "uuid")
+ value: new value
+ type_str: dbus type of new value (eg "ay")
+ :type values: [[key1, key2, value, type_str], ...]
+ key1: str
+ key2: str
+ value: object
+ type_str: str
+ """
+
+ settings = {}
+ for key1, key2, value, type_str in values:
+ gvalue = GLib.Variant(type_str, value)
+ if key1 not in settings:
+ settings[key1] = {}
+ settings[key1][key2] = gvalue
+ gsettings = GLib.Variant("(a{sa{sv}})", (settings,))
+
+ proxy = _get_proxy(object_path="/org/freedesktop/NetworkManager/Settings",
+ interface_name="org.freedesktop.NetworkManager.Settings")
+ connection = proxy.call_sync("AddConnection",
+ gsettings,
+ Gio.DBusCallFlags.NONE,
+ DEFAULT_DBUS_TIMEOUT,
+ None)
+ return connection.unpack()
+
def nm_update_settings_of_device(name, new_values):
"""Update setting of device.
--
1.7.11.7
10 years, 8 months
[rhel7 0/3] Recreate initrd after configuration files are written
by Brian C. Lane
From: "Brian C. Lane" <bcl(a)redhat.com>
Ends up we need the patches that move initrd generation to after the config
files have been written. All of these are slightly modified versions of the
patches from master.
Brian C. Lane (3):
Always regenerate initramfs (#1019970)
Correctly generate rescue initrd (#1019970)
Turn spinner back on for configuration (#1019970)
pyanaconda/install.py | 7 +++++--
pyanaconda/packaging/__init__.py | 17 ++++++++++-------
pyanaconda/packaging/livepayload.py | 11 +++++++++--
pyanaconda/ui/gui/hubs/progress.py | 8 ++++++++
4 files changed, 32 insertions(+), 11 deletions(-)
--
1.8.3.1
10 years, 8 months
[PATCH] Reset checks on both password fields. (#1020580)
by David Shea
When something occurs to reset the state of the password validity
checks, the checks on both the password input and the confirmation input
need to be updated.
---
pyanaconda/ui/gui/spokes/password.py | 1 +
pyanaconda/ui/gui/spokes/user.py | 2 ++
2 files changed, 3 insertions(+)
diff --git a/pyanaconda/ui/gui/spokes/password.py b/pyanaconda/ui/gui/spokes/password.py
index 703e726..700755f 100644
--- a/pyanaconda/ui/gui/spokes/password.py
+++ b/pyanaconda/ui/gui/spokes/password.py
@@ -104,6 +104,7 @@ class PasswordSpoke(FirstbootSpokeMixIn, NormalSpoke):
self.pw.grab_focus()
self.pw.emit("changed")
+ self.confirm.emit("changed")
@property
def status(self):
diff --git a/pyanaconda/ui/gui/spokes/user.py b/pyanaconda/ui/gui/spokes/user.py
index 591f65b..b2f4cca 100644
--- a/pyanaconda/ui/gui/spokes/user.py
+++ b/pyanaconda/ui/gui/spokes/user.py
@@ -431,6 +431,7 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke):
# Re-check the password
self.pw.emit("changed")
+ self.confirm.emit("changed")
def password_changed(self, editable=None, data=None):
"""Update the password strength level bar"""
@@ -451,6 +452,7 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke):
# Re-run the password checks against the new username
self.pw.emit("changed")
+ self.confirm.emit("changed")
def full_name_changed(self, editable = None, data = None):
"""Called by Gtk callback when the full name field changes.
--
1.8.3.1
10 years, 8 months
[master/rhel7-branch] Don't ask to start vnc if user specifies text mode. (#959119)
by Samantha N. Bueno
Set flags.vncquestion to False if user specifies text mode, otherwise
they will be asked again later.
Resolves: rhbz#959119
---
anaconda | 3 +++
1 file changed, 3 insertions(+)
diff --git a/anaconda b/anaconda
index 899e7d0..48a9eed 100755
--- a/anaconda
+++ b/anaconda
@@ -528,6 +528,9 @@ def setupDisplay(anaconda, opts, addon_paths=None):
anaconda.displayMode = 'g'
flags.usevnc = 1
vncS.password = anaconda.ksdata.vnc.password
+ else:
+ # user has explicitly specified text mode
+ flags.vncquestion = False
log.info("Display mode = %s" % anaconda.displayMode)
check_memory(anaconda, opts)
--
1.8.3.1
10 years, 8 months
[PATCH master/rhel7-branch 1/2] Adds additional debug logging to yumpayload.py.
by Anne Mulhern
It is sometimes useful to log creation of yum .repo files.
Signed-off-by: mulhern <amulhern(a)redhat.com>
---
pyanaconda/packaging/yumpayload.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyanaconda/packaging/yumpayload.py b/pyanaconda/packaging/yumpayload.py
index f14bd62..923324d 100644
--- a/pyanaconda/packaging/yumpayload.py
+++ b/pyanaconda/packaging/yumpayload.py
@@ -303,6 +303,7 @@ reposdir=%s
for repo in self._yum.repos.listEnabled():
cfg_path = "%s/%s.repo" % (self._repos_dir, repo.id)
+ log.debug("writing repository file %s for repository %s" % (cfg_path, repo.id))
ks_repo = self.getAddOnRepo(repo.id)
with open(cfg_path, "w") as f:
f.write("[%s]\n" % repo.id)
--
1.8.3.1
10 years, 8 months
[PATCH] Add storage tests.
by Chris Lumens
These kind of fit into a weird area - they're blivet, but they're also
kickstart. Thus, this seems like the best place for them. You have to be
root to run them but if you're not root, "make check" will just skip over
them and not fail the test process.
The idea here is small, focused tests that verify anaconda behaves in a certain
way. This includes checking that anaconda fails like it should in some cases,
and succeeds in others. For now, we cannot verify that what was made matches
what we wanted. That may come later, if needed.
---
tests/Makefile.am | 2 +
tests/storage/cases/__init__.py | 242 +++++++++++++++++++++++++++++++++++++
tests/storage/cases/bz1014545.py | 110 +++++++++++++++++
tests/storage/run_storage_tests.py | 14 +++
4 files changed, 368 insertions(+)
create mode 100644 tests/storage/cases/__init__.py
create mode 100644 tests/storage/cases/bz1014545.py
create mode 100755 tests/storage/run_storage_tests.py
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3a0fc94..10374b4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -42,9 +42,11 @@ dist_check_SCRIPTS = accelerators/check_accelerators.py \
pylint/runpylint.sh \
testenv.sh \
gettext/gettext_warnings.sh \
+ storage/run_storage_tests.py \
$(srcdir)/*_tests/*.py
TESTS = nosetests.sh \
pylint/runpylint.sh \
gettext/gettext_warnings.sh \
+ storage/run_storage_tests.py \
accelerators/run_check_accelerators.sh
diff --git a/tests/storage/cases/__init__.py b/tests/storage/cases/__init__.py
new file mode 100644
index 0000000..1ea2f17
--- /dev/null
+++ b/tests/storage/cases/__init__.py
@@ -0,0 +1,242 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Chris Lumens <clumens(a)redhat.com>
+
+import logging
+import os, sys
+import re
+
+# Can't import from a directory with a dash in its name. This is good enough.
+execfile("/usr/share/doc/python-blivet/examples/common.py")
+
+# Set up logging before blivet or anaconda are imported.
+# pylint: disable-msg=E0602
+set_up_logging()
+blivet_log = logging.getLogger("blivet")
+blivet_log.info(sys.argv[0])
+
+import blivet
+
+from pyanaconda.installclass import DefaultInstall
+from pyanaconda.kickstart import AnacondaKSHandler, AnacondaKSParser, doKickstartStorage
+from pykickstart.errors import KickstartError
+
+class FailedTest(Exception):
+ def __init__(self, got, expected):
+ Exception.__init__(self)
+ self.got = got
+ self.expected = expected
+
+class TestCase(object):
+ """A TestCase is a way of grouping related TestCaseComponent objects
+ together into a single place. It provides a way of iterating through
+ all these components, running each, and tabulating the results. If any
+ component fails, the entire TestCase fails.
+
+ Class attributes:
+
+ components -- A list of TestCaseComponent classes.
+ desc -- A description of what this test is supposed to be
+ testing.
+ name -- An identifying string given to this TestCase.
+ platforms -- A list of blivet.platform.Platform subclasses that this
+ TestCase is valid for. This TestCase will only run on
+ matching platforms. If the list is empty, it is assumed
+ to be valid for all platforms.
+ """
+ components = []
+ desc = ""
+ name = ""
+ platforms = []
+
+ def __init__(self):
+ pass
+
+ def run(self):
+ """Iterate over all components, running each, and collecting the
+ results.
+ """
+ successes = 0
+ failures = 0
+
+ if self.platforms and blivet.platform.getPlatform().__class__.__name__ not in self.platforms:
+ print "Test %s skipped: not valid for this platform" % self.name
+ return
+
+ for c in self.components:
+ obj = c()
+
+ try:
+ obj._run()
+ except FailedTest as e:
+ print "Test %s-%s failed:\n\tExpected: %s\n\tGot: %s" % (self.name, obj.name, e.expected, e.got)
+ failures += 1
+ continue
+
+ print "Test %s-%s succeeded" % (self.name, obj.name)
+ successes += 1
+
+ print "Test %s summary:" % self.name
+ print "\tSuccesses: %s" % successes
+ print "\tFailures: %s" % failures
+ return failures
+
+class TestCaseComponent(object):
+ """A TestCaseComponent is one individual test that runs as part of a TestCase.
+ It consists of a set of disk images provided by self.disksToCreate, a
+ kickstart storage snippet provided by self.ks, and an expected error
+ condition provided by self.expectedExceptionType and self.expectedExceptionText.
+ If the TestCaseComponent is expected to succeed, these latter two should
+ just be set to None.
+
+ A TestCaseComponent succeeds in the following cases:
+
+ * No exception is encountered, and self.expectedExceptionType is None.
+
+ A TestCaseComponent fails in all other cases.
+
+ Class attributes:
+
+ name -- An identifying string given to this TestCaseComponent.
+ """
+ name = ""
+
+ def __init__(self):
+ """Create a new TestCaseComponent instance. This __init__ method should
+ typically do very little. However, subclasses must be sure to set
+ self.disksToCreate. This attribute is a list of (disk name, size in MB)
+ tuples that will be used in this test. Disks given in this list will
+ be automatically created by setupDisks and destroyed by tearDownDisks.
+ """
+ self._disks = {}
+ self._blivet = None
+
+ self.disksToCreate = []
+
+ @property
+ def ks(self):
+ """Return the storage-specific portion of a kickstart file used for
+ performing this test. The kickstart snippet must be provided as
+ text. Only storage commands will be tested. No bootloader actions
+ will be performed.
+ """
+ return ""
+
+ def setupDisks(self):
+ """Create all disk images given by self.disksToCreate and initialize
+ the storage module. Subclasses may override this method, but they
+ should be sure to call the base method as well.
+ """
+ self._blivet = blivet.Blivet()
+
+ # blivet only sets up the bootloader in installer_mode. We don't
+ # want installer_mode, though, because that involves running lots
+ # of programs on the host and setting up all sorts of other things.
+ # Thus, we set it up manually.
+ from pyanaconda.bootloader import get_bootloader
+ self._blivet._bootloader = get_bootloader()
+
+ for (name, size) in self.disksToCreate:
+ self._disks[name] = create_sparse_file(self._blivet, name, size)
+ self._blivet.config.diskImages[name] = self._disks[name]
+
+ self._blivet.reset()
+
+ def tearDownDisks(self):
+ """Disable any disk images used by this test component and remove their
+ image files from the host system. Subclasses may override this
+ method, but they should call the base method as well to make sure
+ the images get destroyed.
+ """
+ # pylint: disable-msg=E0602
+ tear_down_disk_images(self._blivet)
+
+ for d in self._disks.values():
+ os.unlink(d)
+
+ @property
+ def expectedExceptionType(self):
+ """Should this test component be expected to fail, this property returns
+ the exception type. If this component is expected to fail, this
+ property returns None. All components that are expected to fail
+ should override this property.
+ """
+ return None
+
+ @property
+ def expectedExceptionText(self):
+ """Should this test component be expected to fail, this property returns
+ a regular expression that the raised exception's text must match.
+ Otherwise, this property returns None. All components that are
+ expected to fail should override this property.
+ """
+ return None
+
+ def _text_matches(self, s):
+ prog = re.compile(self.expectedExceptionText)
+
+ for line in s.splitlines():
+ match = prog.match(line)
+ if match:
+ return match
+
+ return None
+
+ def _run(self):
+ from blivet.errors import StorageError
+
+ # Set up disks/blivet.
+ try:
+ self.setupDisks()
+
+ # Parse the kickstart using anaconda's parser, since it has more
+ # advanced error detection. This also requires having storage set
+ # up first.
+ parser = AnacondaKSParser(AnacondaKSHandler())
+ parser.readKickstartFromString(self.ks)
+
+ instClass = DefaultInstall()
+
+ doKickstartStorage(self._blivet, parser.handler, instClass)
+ self._blivet.updateKSData()
+ self._blivet.doIt()
+ except (KickstartError, StorageError) as e:
+ # anaconda handles expected kickstart errors (like parsing busted
+ # input files) by printing the error and quitting. For testing, an
+ # error might be expected so we should compare the result here with
+ # what is expected.
+ if self.expectedExceptionType and isinstance(e, self.expectedExceptionType):
+ # We expected an exception, and we got one of the correct type.
+ # If it also contains the string we were expecting, then the
+ # test case passes. Otherwise, it's a failure.
+ if self.expectedExceptionText and self._text_matches(str(e)):
+ return
+ else:
+ raise FailedTest(str(e), self.expectedExceptionText)
+ else:
+ # We either got an exception when we were not expecting one,
+ # or we got one of a type other than what we were expecting.
+ # Either of these cases indicates a failure of the test case.
+ raise FailedTest(e, self.expectedExceptionType)
+ finally:
+ self.tearDownDisks()
+
+ if self.expectedExceptionType:
+ raise FailedTest(None, self.expectedExceptionType)
+
+ return
diff --git a/tests/storage/cases/bz1014545.py b/tests/storage/cases/bz1014545.py
new file mode 100644
index 0000000..26e1f2e
--- /dev/null
+++ b/tests/storage/cases/bz1014545.py
@@ -0,0 +1,110 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Chris Lumens <clumens(a)redhat.com>
+
+# pylint: disable-msg=E0611
+from . import TestCase, TestCaseComponent, create_sparse_file
+
+from pykickstart.errors import KickstartValueError
+
+class BTRFSOnNonBTRFSComponent(TestCaseComponent):
+ name = "BTRFSOnNonBTRFS"
+
+ def __init__(self, *args, **kwargs):
+ TestCaseComponent.__init__(self, *args, **kwargs)
+ self.disksToCreate = [("anatest-disk1", 1000)]
+
+ @property
+ def ks(self):
+ return """
+zerombr
+clearpart --all --initlabel
+btrfs none --data=0 --metadata=1 anatest-disk1
+"""
+
+ @property
+ def expectedExceptionType(self):
+ return KickstartValueError
+
+ @property
+ def expectedExceptionText(self):
+ return "BTRFS partition .* has incorrect format"
+
+class VolGroupOnNonPVsComponent(TestCaseComponent):
+ name = "VolGroupOnNonPVs"
+
+ def __init__(self, *args, **kwargs):
+ TestCaseComponent.__init__(self, *args, **kwargs)
+ self.disksToCreate = [("anatest-disk1", 1000)]
+
+ @property
+ def ks(self):
+ return """
+zerombr
+clearpart --all --initlabel
+volgroup myvg anatest-disk1
+"""
+
+ @property
+ def expectedExceptionType(self):
+ return KickstartValueError
+
+ @property
+ def expectedExceptionText(self):
+ return "Physical Volume .* has incorrect format"
+
+class RaidOnNonRaidMembersComponent(TestCaseComponent):
+ name = "RaidOnNonRaidMembers"
+
+ def __init__(self, *args, **kwargs):
+ TestCaseComponent.__init__(self, *args, **kwargs)
+ self.disksToCreate = [("anatest-disk1", 1000),
+ ("anatest-disk2", 1000)]
+
+ @property
+ def ks(self):
+ return """
+zerombr
+clearpart --all --initlabel
+raid / --level=1 --device=md0 anatest-disk1 anatest-disk2
+"""
+
+ @property
+ def expectedExceptionType(self):
+ return KickstartValueError
+
+ @property
+ def expectedExceptionText(self):
+ return "RAID member .* has incorrect format"
+
+class BZ1014545_TestCase(TestCase):
+ components = [BTRFSOnNonBTRFSComponent,
+ RaidOnNonRaidMembersComponent,
+ VolGroupOnNonPVsComponent]
+ name = "1014545"
+ desc = """The members of various commands must have the correct format.
+For instance, raid members must have mdmember, and volgroup members must have
+lvmpv. If they do not have this format, a KickstartValueError should be raised
+during storage execution time.
+
+Note that this is different from the error condition described in the bug.
+There, anaconda was letting the invalid format go and then hitting errors
+much further in installation - during bootloader installation. The real
+bug is that this condition should be detected when the kickstart storage
+commands are being converted to actions.
+"""
diff --git a/tests/storage/run_storage_tests.py b/tests/storage/run_storage_tests.py
new file mode 100755
index 0000000..e8c50b1
--- /dev/null
+++ b/tests/storage/run_storage_tests.py
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+
+import os, sys
+
+if os.geteuid() != 0:
+ sys.stderr.write("You must be root to run the storage tests; skipping.\n")
+ # This return code tells GNU make that this test was skipped.
+ os._exit(77)
+
+from cases.bz1014545 import BZ1014545_TestCase
+tc = BZ1014545_TestCase()
+failures = tc.run()
+
+os._exit(failures)
--
1.8.3.1
10 years, 8 months