[PATCH rhel7-branch] Fix iscsi target selection checkbox in GUI (#1058653)
by Radek Vykydal
Resolves: rhbz#1058653
---
pyanaconda/ui/gui/spokes/advstorage/iscsi.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/advstorage/iscsi.py b/pyanaconda/ui/gui/spokes/advstorage/iscsi.py
index ac2051e..5c8cad0 100644
--- a/pyanaconda/ui/gui/spokes/advstorage/iscsi.py
+++ b/pyanaconda/ui/gui/spokes/advstorage/iscsi.py
@@ -150,7 +150,8 @@ class ISCSIDialog(GUIObject):
self._loginAuthTypeCombo.set_active(0)
- self.builder.get_object("nodeStoreFiltered").set_visible_column(1)
+ self._storeFilter = self.builder.get_object("nodeStoreFiltered")
+ self._storeFilter.set_visible_column(1)
self._initiatorEntry = self.builder.get_object("initiatorEntry")
self._initiatorEntry.set_text(self.iscsi.initiator)
@@ -326,7 +327,8 @@ class ISCSIDialog(GUIObject):
return
# Then, go back and mark just this row as selected.
- itr = self._store.get_iter(path)
+ itr = self._storeFilter.get_iter(path)
+ itr = self._storeFilter.convert_iter_to_child_iter(itr)
self._store[itr][0] = not self._store[itr][0]
def _login(self, credentials):
--
1.7.11.7
10 years, 3 months
[anaconda:rhel7/master] --image documentation (v2)
by Anne Mulhern
It would really be better to get the help text out of the source code
and in to a text file that we then read and use programmatically, so that's
what this patch does.
If the data file is not installed, then there will be no help text, but there
should be no other problems.
mulhern (1):
Add option help text for --image and --dirinstall flags (#1056791)
anaconda | 8 +++--
data/Makefile.am | 3 ++
data/anaconda_options.txt | 17 +++++++++++
pyanaconda/anaconda_optparse.py | 66 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 92 insertions(+), 2 deletions(-)
create mode 100644 data/anaconda_options.txt
--
1.8.3.1
10 years, 3 months
[PATCH] Remove all dependent devices of san device becoming multipath (#1058939)
by Radek Vykydal
Also change the format to multipath after the devices are removed,
not before.
This should fix also bug #1058681.
I am starting to wonder whether we can really manage populate after adding
new san device (iSCSI, FCoE, zFCP) in GUI making a device already in tree
multipath member - without resetting storage.
Resolves: rhbz#1058939
---
blivet/devicetree.py | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/blivet/devicetree.py b/blivet/devicetree.py
index 5f7832b..8a79f14 100644
--- a/blivet/devicetree.py
+++ b/blivet/devicetree.py
@@ -332,6 +332,17 @@ class DeviceTree(object):
# Do we care about garbage collection? At all?
parent.removeChild()
+ def _removeChildrenFromTree(self, device):
+ devs_to_remove = self.getDependentDevices(device)
+ while devs_to_remove:
+ leaves = [d for d in devs_to_remove if d.isleaf]
+ for leaf in leaves:
+ self._removeDevice(leaf, moddisk=False)
+ devs_to_remove.remove(leaf)
+ if len(devs_to_remove) == 1 and devs_to_remove[0].isExtended:
+ self._removeDevice(devs_to_remove[0], force=True, moddisk=False)
+ break
+
def registerAction(self, action):
""" Register an action to be performed at a later time.
@@ -1023,9 +1034,9 @@ class DeviceTree(object):
# newly added device (eg iSCSI) could make this one a multipath member
if device.format and device.format.type != "multipath_member":
log.debug("%s newly detected as multipath member, dropping old format and removing kids" % device.name)
+ # remove children from tree so that we don't stumble upon them later
+ self._removeChildrenFromTree(device)
device.format = formats.DeviceFormat()
- for d in self.getChildren(device):
- self._removeDevice(d, moddisk=False)
#
# The first step is to either look up or create the device
--
1.7.11.7
10 years, 3 months
[PATCH] Another cut at better stage1 bootloader errors
by Adam Williamson
So this time I defined a new property for the error message (so we're not
reading an internal attribute), made the UEFI error message state that the
ESP must be on GPT (as we've decided we're not going to allow it to be on
MBR after all), added error messages for all the other platforms based on
the constraints as expressed in platform.py, and tweaked the generic error
a bit more.
The second patch makes the stage2 missing error not show if stage1 is also
missing. I think stage2 will never be set if stage1 is missing, even if
there actually is a valid stage2 device - I've been testing this by creating
a layout for a UEFI install with a /boot, a swap, and a /, but no ESP. Without
this second patch, you see the "You have not created a bootable partition."
error, even though you have. I tested, and this patch seems to do the trick:
if I create a /boot partition but no ESP, I just get the generic and platform-
specific stage1 missing errors; if I create an ESP but no /boot or / partition,
I see the missing stage2 error - "You have not created a bootable partition." -
but no missing stage1 error. (And, of course, if I do everything right, no
errors and install can proceed: I did think to check that too :>)
10 years, 3 months
[blivet:rhel7/master 1/2] Use os.path.isabs to check whether path name is absolute (#982164)
by Anne Mulhern
Related: rhbz#982164
Just to be proper.
Signed-off-by: mulhern <amulhern(a)redhat.com>
---
blivet/devices.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/blivet/devices.py b/blivet/devices.py
index ccbb857..846a6b4 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -3820,7 +3820,7 @@ class FileDevice(StorageDevice):
parents -- a list of required devices (Device instances)
exists -- indicates whether this is an existing device
"""
- if not path.startswith("/"):
+ if not os.path.isabs(path):
raise ValueError("FileDevice requires an absolute path")
StorageDevice.__init__(self, path, format=format, size=size,
--
1.8.3.1
10 years, 3 months
[lorax/master] Install aajohan-comfortaa-fonts (#1047430)
by Brian C. Lane
---
share/runtime-install.tmpl | 1 +
1 file changed, 1 insertion(+)
diff --git a/share/runtime-install.tmpl b/share/runtime-install.tmpl
index 889e6c9..e4c0336 100644
--- a/share/runtime-install.tmpl
+++ b/share/runtime-install.tmpl
@@ -127,6 +127,7 @@ installpkg wqy-microhei-fonts
installpkg sil-abyssinica-fonts
installpkg xorg-x11-fonts-misc
installpkg gnome-themes-standard gnome-icon-theme-legacy
+installpkg aajohan-comfortaa-fonts
## branding & logos
installpkg fedora-gnome-theme fedora-icon-theme
--
1.8.4.2
10 years, 3 months
[rhel7-branch/master][PATCH] Make sure directory for DD extraction exists
by Vratislav Podzimek
Otherwise dd_extract binary fails if the directory doesn't exist.
Related: rhbz#1016004
Signed-off-by: Vratislav Podzimek <vpodzime(a)redhat.com>
---
dracut/driver-updates | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/dracut/driver-updates b/dracut/driver-updates
index c62e46a..7840e2e 100755
--- a/dracut/driver-updates
+++ b/dracut/driver-updates
@@ -388,6 +388,11 @@ def dd_extract(driver, dest_path="/updates/", kernel_ver=None):
cmd += driver.args
cmd += ["--rpm", driver.rpm, "--directory", dest_path]
log.info("Extracting files from %s" % driver.rpm)
+
+ # make sure the to be used directory exists
+ if not os.path.isdir(dest_path):
+ os.makedirs(dest_path)
+
try:
run_cmd(cmd)
except (OSError, RunCmdError):
--
1.8.5.3
10 years, 3 months
[rhel7-branch/master][PATCH] Fix target partition selection for standard partitions
by Martin Kolman
While I have not been able to track down the one mysterious on_selected_clicked callback
that was wiping out the users disk choice, just saving the results once the disk is selected
also solves the issues and saves the user the need to click on the "Update Settings" button.
Hopefully this won't trigger something else in the custom partitioning minefield.
Martin Kolman (1):
Fix disk selection for standard partitions (#1029798)
pyanaconda/ui/gui/spokes/custom.py | 7 +++++++
1 file changed, 7 insertions(+)
--
1.8.5.3
10 years, 3 months
[anaconda:rhel7/master] Handle --image arguments more thoroughly (#982164, #994488)
by Anne Mulhern
Resolves: rhbz#982164, rhbz#994488
Sanitizes and post-processes --image arguments. Moves functionality
into a separate method.
Two problems fixed are:
994488 --- convert relative to absolute path
982164 --- check that path actually exists
Other differences from previous semantics are:
* Raises an exception if the name specified by the user contains a "/",
previously it just synthesized a name
* Certainly avoids name conflicts, previously just avoided likely ones
Signed-off-by: mulhern <amulhern(a)redhat.com>
---
anaconda | 27 ++++++++++-----------
pyanaconda/anaconda_optparse.py | 52 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+), 15 deletions(-)
diff --git a/anaconda b/anaconda
index 8ec0363..677e818 100755
--- a/anaconda
+++ b/anaconda
@@ -1004,22 +1004,19 @@ if __name__ == "__main__":
if anaconda.displayMode == 'c':
flags.ksprompt = False
- image_count = 0
- for image in opts.images:
- image_spec = image.rsplit(":", 1)
- path = image_spec[0]
- if len(image_spec) == 2 and image_spec[1].strip():
- name = image_spec[1].strip()
- else:
- name = os.path.splitext(os.path.basename(path))[0]
+ from pyanaconda.anaconda_optparse import name_path_pairs
- if "/" in name or name in anaconda.storage.config.diskImages.keys():
- name = "diskimg%d" % image_count
-
- log.info("naming disk image '%s' '%s'" % (path, name))
- anaconda.storage.config.diskImages[name] = path
- image_count += 1
- flags.imageInstall = True
+ image_count = 0
+ try:
+ disk_image_counter = 0
+ for (name, path) in name_path_pairs(opts.images):
+ log.info("naming disk image '%s' '%s'" % (path, name))
+ anaconda.storage.config.diskImages[name] = path
+ image_count += 1
+ flags.imageInstall = True
+ except ValueError as e:
+ stdoutLog.error("error specifying image file: %s" % e)
+ sys.exit(0)
if image_count:
anaconda.storage.setupDiskImages()
diff --git a/pyanaconda/anaconda_optparse.py b/pyanaconda/anaconda_optparse.py
index 37f4b86..bcaab81 100644
--- a/pyanaconda/anaconda_optparse.py
+++ b/pyanaconda/anaconda_optparse.py
@@ -19,6 +19,9 @@
# Authors:
# Will Woods <wwoods(a)redhat.com>
+import itertools
+import os
+
from flags import BootArgs
from optparse import OptionParser, OptionConflictError
@@ -124,3 +127,52 @@ class AnacondaOptionParser(OptionParser):
values = self.get_default_values()
v = self.parse_boot_cmdline(cmdline, values)
return OptionParser.parse_args(self, args, v)
+
+def name_path_pairs(image_specs):
+ """Processes and verifies image file specifications. Generates pairs
+ of names and paths.
+
+ If no name given in specification, synthesizes name from basename
+ of path. Since two distinct paths may have the same basename, handles
+ name collisions by synthesizing a different name for the colliding
+ name.
+
+ :param image_specs: a list of image specifications
+ :type image_specs: list of str
+
+ Raises an exception if:
+ * A path is empty
+ * A path specifies a non-existant file
+ * A path specifies a directory
+ * Duplicate paths are specified
+ * A name contains a "/"
+ """
+ image_specs = (spec.rsplit(":", 1) for spec in image_specs)
+ path_name_pairs = ((image_spec[0], image_spec[1].strip() if len(image_spec) == 2 else None) for image_spec in image_specs)
+
+ paths_seen = []
+ names_seen = []
+ for (path, name) in path_name_pairs:
+ if path == "":
+ raise ValueError("empty path specified for image file")
+ path = os.path.abspath(path)
+ if not os.path.exists(path):
+ raise ValueError("non-existant path %s specified for image file" % path)
+ if os.path.isdir(path):
+ raise ValueError("directory path %s specified for image file" % path)
+ if path in paths_seen:
+ raise ValueError("path %s specified twice for image file" % path)
+ paths_seen.append(path)
+
+ if name and "/" in name:
+ raise ValueError("improperly formatted image file name %s, includes slashes" % name)
+
+ if not name:
+ name = os.path.splitext(os.path.basename(path))[0]
+
+ if name in names_seen:
+ names = ("%s_%d" % (name, n) for n in itertools.count())
+ name = itertools.dropwhile(lambda n: n in names_seen, names).next()
+ names_seen.append(name)
+
+ yield name, path
--
1.8.3.1
10 years, 3 months
[PATCH rhel7-branch] Display custom part warnings/errors on the spoke itself (#975840).
by Chris Lumens
This works similarly to how the password spokes do: If the user does
something incorrect, the info bar displays a message and the user can
click on it to see the problem. If they really want to, they can click
done again to go back to the hub.
Note that in the case of errors, the user will still have to do something
about them even if they do leave the custom part spoke. But, we don't
want to trap them.
---
pyanaconda/ui/gui/spokes/custom.py | 71 +++++++++++++++++++++++++++-----------
1 file changed, 51 insertions(+), 20 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
index 2c3aed7..7560b31 100644
--- a/pyanaconda/ui/gui/spokes/custom.py
+++ b/pyanaconda/ui/gui/spokes/custom.py
@@ -1,6 +1,6 @@
# Custom partitioning classes.
#
-# Copyright (C) 2012, 2013 Red Hat, Inc.
+# Copyright (C) 2012-2014 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
@@ -650,6 +650,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
def __init__(self, data, storage, payload, instclass):
NormalSpoke.__init__(self, data, storage, payload, instclass)
+ self._back_already_clicked = False
+
self._current_selector = None
self._when_create_text = ""
self._devices = []
@@ -678,15 +680,6 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
for disk in reversed(self._media_disks):
self.__storage.devicetree.unhide(disk)
- # We can't overwrite the main Storage instance because all the other
- # spokes have references to it that would get invalidated, but we can
- # achieve the same effect by updating/replacing a few key attributes.
- self.storage.devicetree._devices = self.__storage.devicetree._devices
- self.storage.devicetree._actions = self.__storage.devicetree._actions
- self.storage.devicetree._hidden = self.__storage.devicetree._hidden
- self.storage.devicetree.names = self.__storage.devicetree.names
- self.storage.roots = self.__storage.roots
-
# update the global passphrase
self.data.autopart.passphrase = self.passphrase
@@ -698,16 +691,6 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
self.storage.savePassphrase(device)
- StorageChecker.errors = []
- # set up bootloader and check the configuration
- try:
- self.storage.setUpBootLoader()
- except BootLoaderError as e:
- log.error("storage configuration failed: %s" % e)
- StorageChecker.errors = str(e).split("\n")
- self.data.bootloader.bootDrive = ""
-
- StorageChecker.run(self)
hubQ.send_ready("StorageSpoke", True)
@property
@@ -878,6 +861,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
for thread_name in [THREAD_EXECUTE_STORAGE, THREAD_STORAGE]:
threadMgr.wait(thread_name)
+ self._back_already_clicked = False
+
self.passphrase = self.data.autopart.passphrase
self._reset_storage()
self._do_refresh()
@@ -1942,6 +1927,42 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
if isinstance(window.get_focus(), MountpointSelector):
self._removeButton.emit("clicked")
+ def _do_check(self):
+ self.clear_errors()
+ StorageChecker.errors = []
+ StorageChecker.warnings = []
+
+ # We can't overwrite the main Storage instance because all the other
+ # spokes have references to it that would get invalidated, but we can
+ # achieve the same effect by updating/replacing a few key attributes.
+ self.storage.devicetree._devices = self.__storage.devicetree._devices
+ self.storage.devicetree._actions = self.__storage.devicetree._actions
+ self.storage.devicetree._hidden = self.__storage.devicetree._hidden
+ self.storage.devicetree.names = self.__storage.devicetree.names
+ self.storage.roots = self.__storage.roots
+
+ # set up bootloader and check the configuration
+ try:
+ self.storage.setUpBootLoader()
+ except BootLoaderError as e:
+ log.error("storage configuration failed: %s" % e)
+ StorageChecker.errors = str(e).split("\n")
+ self.data.bootloader.bootDrive = ""
+
+ StorageChecker.checkStorage(self)
+
+ if self.errors:
+ self.set_warning(_("Error checking storage configuration. Click for details or press Done again to continue."))
+ elif self.warnings:
+ self.set_warning(_("Warning checking storage configuration. Click for details or press Done again to continue."))
+
+ # on_info_bar_clicked requires self._error to be set, so set it to the
+ # list of all errors and warnings that storage checking found.
+ self.window.show_all()
+ self._error = "\n".join(self.errors + self.warnings)
+
+ return bool(self._error == "")
+
def on_back_clicked(self, button):
# First, save anything from the currently displayed mountpoint.
self._save_right_side(self._current_selector)
@@ -1951,6 +1972,13 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
self.__storage.devicetree.pruneActions()
self.__storage.devicetree.sortActions()
+ # If back has been clicked on once already and no other changes made on the screen,
+ # run the storage check now. This handles displaying any errors in the info bar.
+ if not self._back_already_clicked:
+ self._back_already_clicked = True
+ if not self._do_check():
+ return
+
if len(self.__storage.devicetree.findActions()) > 0:
dialog = ActionSummaryDialog(self.data)
with enlightbox(self.window, dialog.window):
@@ -1980,6 +2008,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
def on_add_clicked(self, button):
self._save_right_side(self._current_selector)
+ self._back_already_clicked = False
dialog = AddDialog(self.data,
mountpoints=self.__storage.mountpoints.keys())
@@ -2473,6 +2502,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
log.debug("notebook page = %s" % nb_page)
if nb_page == NOTEBOOK_DETAILS_PAGE:
self._save_right_side(self._current_selector)
+ self._back_already_clicked = False
self._clear_current_selector()
@@ -2857,6 +2887,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
def on_apply_clicked(self, button):
""" call _save_right_side, then, perhaps, populate_right_side. """
self._save_right_side(self._current_selector)
+ self._back_already_clicked = False
self._applyButton.set_sensitive(False)
def on_unlock_clicked(self, button):
--
1.8.3.1
10 years, 3 months