[master] Add more yum locking to yumpayload (#860022)
by Brian C. Lane
From: "Brian C. Lane" <bcl(a)redhat.com>
Yum properties have side-effects and are inconsistent in their behavior
(eg. one call may go grab something from the net, the next may just return a
list). So we need to be paranoid about wrapping self._yum usage in a
_yum_lock.
---
pyanaconda/packaging/yumpayload.py | 187 ++++++++++++++++++++-----------------
1 file changed, 101 insertions(+), 86 deletions(-)
diff --git a/pyanaconda/packaging/yumpayload.py b/pyanaconda/packaging/yumpayload.py
index e65ed5d..a657e32 100644
--- a/pyanaconda/packaging/yumpayload.py
+++ b/pyanaconda/packaging/yumpayload.py
@@ -94,8 +94,8 @@ from pykickstart.constants import KS_MISSING_IGNORE
default_repos = [productName.lower(), "rawhide"]
-from threading import Lock
-_yum_lock = Lock()
+from threading import RLock
+_yum_lock = RLock()
_yum_cache_dir = "/tmp/yum.cache"
@@ -272,6 +272,8 @@ reposdir=%s
Write out repo config files for all enabled repos, then
create a new YumBase instance with the new filesystem tree as its
install root.
+
+ This needs to be called from inside a yum_lock
"""
self._repos_dir = "/tmp/yum.repos.d"
if not os.path.isdir(self._repos_dir):
@@ -387,11 +389,12 @@ reposdir=%s
def baseRepo(self):
repo_names = [BASE_REPO_NAME] + default_repos
base_repo_name = None
- for repo_name in repo_names:
- if repo_name in self.repos and \
- self._yum.repos.getRepo(repo_name).enabled:
- base_repo_name = repo_name
- break
+ with _yum_lock:
+ for repo_name in repo_names:
+ if repo_name in self.repos and \
+ self._yum.repos.getRepo(repo_name).enabled:
+ base_repo_name = repo_name
+ break
return base_repo_name
@@ -417,9 +420,10 @@ reposdir=%s
self._configureBaseRepo(self.storage, checkmount=checkmount)
except PayloadError as e:
if not fallback:
- for repo in self._yum.repos.repos.values():
- if repo.enabled:
- self.disableRepo(repo.id)
+ with _yum_lock:
+ for repo in self._yum.repos.repos.values():
+ if repo.enabled:
+ self.disableRepo(repo.id)
raise
# this preserves the method details while disabling it
@@ -428,11 +432,12 @@ reposdir=%s
finally:
self._yumCacheDirHack()
- if BASE_REPO_NAME not in self._yum.repos.repos.keys():
- log.info("using default repos from local yum configuration")
- if self._yum.conf.yumvar['releasever'] == "rawhide" and \
- "rawhide" in self.repos:
- self.enableRepo("rawhide")
+ with _yum_lock:
+ if BASE_REPO_NAME not in self._yum.repos.repos.keys():
+ log.info("using default repos from local yum configuration")
+ if self._yum.conf.yumvar['releasever'] == "rawhide" and \
+ "rawhide" in self.repos:
+ self.enableRepo("rawhide")
# set up addon repos
# FIXME: driverdisk support
@@ -448,50 +453,52 @@ reposdir=%s
self.removeRepo(repo.name)
# now disable and/or remove any repos that don't make sense
- for repo in self._yum.repos.repos.values():
- # Rules for which repos to enable/disable/remove
- #
- # - always remove
- # - source, debuginfo
- # - disable if isFinal
- # - rawhide, development
- # - disable all other built-in repos if rawhide is enabled
- # - remove any repo when not isFinal and repo not enabled
- # - if a base repo is defined, disable any repo not defined by
- # the user that is not the base repo
- #
- # FIXME: updates needs special handling
- if repo.id in self.addOns:
- continue
+ with _yum_lock:
+ for repo in self._yum.repos.repos.values():
+ # Rules for which repos to enable/disable/remove
+ #
+ # - always remove
+ # - source, debuginfo
+ # - disable if isFinal
+ # - rawhide, development
+ # - disable all other built-in repos if rawhide is enabled
+ # - remove any repo when not isFinal and repo not enabled
+ # - if a base repo is defined, disable any repo not defined by
+ # the user that is not the base repo
+ #
+ # FIXME: updates needs special handling
+ if repo.id in self.addOns:
+ continue
- if "-source" in repo.id or "-debuginfo" in repo.id:
- self._removeYumRepo(repo.id)
- elif isFinal and ("rawhide" in repo.id or "development" in repo.id):
- # XXX the "development" part seems a bit heavy handed
- self._removeYumRepo(repo.id)
- elif self._yum.conf.yumvar['releasever'] == "rawhide" and \
- "rawhide" in self.repos and \
- self._yum.repos.getRepo("rawhide").enabled and \
- repo.id != "rawhide":
- self.disableRepo(repo.id)
- elif self.data.method.method and \
- repo.id != BASE_REPO_NAME and \
- repo.id not in [r.name for r in self.data.repo.dataList()]:
- # if a method/repo was given, disable all default repos
- self.disableRepo(repo.id)
+ if "-source" in repo.id or "-debuginfo" in repo.id:
+ self._removeYumRepo(repo.id)
+ elif isFinal and ("rawhide" in repo.id or "development" in repo.id):
+ # XXX the "development" part seems a bit heavy handed
+ self._removeYumRepo(repo.id)
+ elif self._yum.conf.yumvar['releasever'] == "rawhide" and \
+ "rawhide" in self.repos and \
+ self._yum.repos.getRepo("rawhide").enabled and \
+ repo.id != "rawhide":
+ self.disableRepo(repo.id)
+ elif self.data.method.method and \
+ repo.id != BASE_REPO_NAME and \
+ repo.id not in [r.name for r in self.data.repo.dataList()]:
+ # if a method/repo was given, disable all default repos
+ self.disableRepo(repo.id)
def gatherRepoMetadata(self):
# now go through and get metadata for all enabled repos
log.info("gathering repo metadata")
for repo_id in self.repos:
- repo = self._yum.repos.getRepo(repo_id)
- if repo.enabled:
- try:
- self._getRepoMetadata(repo)
- except PayloadError as e:
- log.error("failed to grab repo metadata for %s: %s"
- % (repo_id, e))
- self.disableRepo(repo_id)
+ with _yum_lock:
+ repo = self._yum.repos.getRepo(repo_id)
+ if repo.enabled:
+ try:
+ self._getRepoMetadata(repo)
+ except PayloadError as e:
+ log.error("failed to grab repo metadata for %s: %s"
+ % (repo_id, e))
+ self.disableRepo(repo_id)
log.info("metadata retrieval complete")
@@ -825,10 +832,11 @@ reposdir=%s
# if this is an NFS repo, we'll want to unmount the NFS mount after
# removing the repo
mountpoint = None
- yum_repo = self._yum.repos.getRepo(repo_id)
- ks_repo = self.getRepo(repo_id)
- if yum_repo and ks_repo and ks_repo.baseurl.startswith("nfs:"):
- mountpoint = yum_repo.baseurl[0][7:] # strip leading "file://"
+ with _yum_lock:
+ yum_repo = self._yum.repos.getRepo(repo_id)
+ ks_repo = self.getRepo(repo_id)
+ if yum_repo and ks_repo and ks_repo.baseurl.startswith("nfs:"):
+ mountpoint = yum_repo.baseurl[0][7:] # strip leading "file://"
self._removeYumRepo(repo_id)
super(YumPayload, self).removeRepo(repo_id)
@@ -843,13 +851,15 @@ reposdir=%s
""" Enable a repo as specified by id. """
log.debug("enabling repo %s" % repo_id)
if repo_id in self.repos:
- self._yum.repos.enableRepo(repo_id)
+ with _yum_lock:
+ self._yum.repos.enableRepo(repo_id)
def disableRepo(self, repo_id):
""" Disable a repo as specified by id. """
log.debug("disabling repo %s" % repo_id)
if repo_id in self.repos:
- self._yum.repos.disableRepo(repo_id)
+ with _yum_lock:
+ self._yum.repos.disableRepo(repo_id)
self._groups = None
self._packages = []
@@ -1134,13 +1144,14 @@ reposdir=%s
###
def _removeTxSaveFile(self):
# remove the transaction save file
- if self._yum._ts_save_file:
- try:
- os.unlink(self._yum._ts_save_file)
- except (OSError, IOError):
- pass
- else:
- self._yum._ts_save_file = None
+ with _yum_lock:
+ if self._yum._ts_save_file:
+ try:
+ os.unlink(self._yum._ts_save_file)
+ except (OSError, IOError):
+ pass
+ else:
+ self._yum._ts_save_file = None
def _handleMissing(self, exn):
if self.data.packages.handleMissing == KS_MISSING_IGNORE:
@@ -1205,7 +1216,8 @@ reposdir=%s
if self.skipBroken:
log.info("running software check with skip_broken = True")
- self._yum.conf.skip_broken = True
+ with _yum_lock:
+ self._yum.conf.skip_broken = True
self.release()
self.deleteYumTS()
@@ -1238,8 +1250,9 @@ reposdir=%s
raise DependencyError(msgs)
self.calculateSpaceNeeds()
- log.info("%d packages selected totalling %s"
- % (len(self._yum.tsInfo.getMembers()), self.spaceRequired))
+ with _yum_lock:
+ log.info("%d packages selected totalling %s"
+ % (len(self._yum.tsInfo.getMembers()), self.spaceRequired))
def selectKernelPackage(self):
kernels = self.kernelPackages
@@ -1260,11 +1273,11 @@ reposdir=%s
# select module packages for this kernel
# select the devel package if gcc will be installed
- if self._yum.tsInfo.matchNaevr(name="gcc"):
- log.info("selecting %s-devel" % kernel)
- # XXX might need explicit arch specification
- self._selectYumPackage("%s-devel" % kernel)
-
+ with _yum_lock:
+ if self._yum.tsInfo.matchNaevr(name="gcc"):
+ log.info("selecting %s-devel" % kernel)
+ # XXX might need explicit arch specification
+ self._selectYumPackage("%s-devel" % kernel)
break
if not selected:
@@ -1288,7 +1301,8 @@ reposdir=%s
if self.install_device:
self._setUpMedia(self.install_device)
- self._writeInstallConfig()
+ with _yum_lock:
+ self._writeInstallConfig()
# We have this block twice. For kickstart installs, this is the only
# place dependencies will be checked. If a dependency error is hit
@@ -1462,20 +1476,21 @@ reposdir=%s
def postInstall(self):
""" Perform post-installation tasks. """
- self._yum.close()
+ with _yum_lock:
+ self._yum.close()
- # clean up repo tmpdirs
- self._yum.cleanPackages()
- self._yum.cleanHeaders()
+ # clean up repo tmpdirs
+ self._yum.cleanPackages()
+ self._yum.cleanHeaders()
- # remove cache dirs of install-specific repos
- for repo in self._yum.repos.listEnabled():
- if repo.name == BASE_REPO_NAME or repo.id.startswith("anaconda-"):
- shutil.rmtree(repo.cachedir)
+ # remove cache dirs of install-specific repos
+ for repo in self._yum.repos.listEnabled():
+ if repo.name == BASE_REPO_NAME or repo.id.startswith("anaconda-"):
+ shutil.rmtree(repo.cachedir)
- # clean the yum cache on upgrade
- if self.data.upgrade.upgrade:
- self._yum.cleanMetadata()
+ # clean the yum cache on upgrade
+ if self.data.upgrade.upgrade:
+ self._yum.cleanMetadata()
# TODO: on preupgrade, remove the preupgrade dir
--
1.8.0.2
11 years, 4 months
[master] [PATCH] Fix the final progress message on live installations
by Vratislav Podzimek
It needs to be translated and the product name should be used.
Signed-off-by: Vratislav Podzimek <vpodzime(a)redhat.com>
---
pyanaconda/ui/gui/hubs/progress.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/pyanaconda/ui/gui/hubs/progress.py b/pyanaconda/ui/gui/hubs/progress.py
index 73597a4..7de2cff 100644
--- a/pyanaconda/ui/gui/hubs/progress.py
+++ b/pyanaconda/ui/gui/hubs/progress.py
@@ -24,6 +24,7 @@ from __future__ import division
import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
+# pylint: disable-msg=E0611
from gi.repository import GLib, Gtk
import itertools
@@ -176,8 +177,10 @@ class ProgressHub(Hub):
if flags.livecdInstall:
continueText = self.builder.get_object("rebootLabel")
- continueText.set_text("%s is now successfully installed on your system and ready "
- "for you to use! When you are ready, reboot your system to start using it!")
+ continueText.set_text(_("%s is now successfully installed on your "
+ "system and ready for you to use! When you "
+ "are ready, reboot your system to start "
+ "using it!") % productName)
self.continueButton.set_label("_Quit")
self._progressBar = self.builder.get_object("progressBar")
--
1.7.11.7
11 years, 4 months
[f18-branch/master] [PATCH] Encode unicode strings returned by pytz.country_timezones() (#887236)
by Vratislav Podzimek
pytz.country_timezones() now returns unicodes strings instead of
byte strings. Concatenating byte string and unicode string causes
traceback, so we need to encode these unicode strings as utf-8
before returning them from our function.
Signed-off-by: Vratislav Podzimek <vpodzime(a)redhat.com>
---
pyanaconda/timezone.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyanaconda/timezone.py b/pyanaconda/timezone.py
index f08f0c4..5337a21 100644
--- a/pyanaconda/timezone.py
+++ b/pyanaconda/timezone.py
@@ -134,6 +134,7 @@ def get_all_territory_timezones(territory):
except KeyError:
timezones = list()
+ timezones = [zone.encode("utf-8") for zone in timezones]
return timezones
--
1.7.11.7
11 years, 4 months
three small patches
by David Lehman
I just opened bug 888560 for patch 3 and proposed it as a blocker.
11 years, 4 months
F18 stuff
by David Lehman
Patches 1 and 3 fix tracebacks that are pretty easy to hit.
Patch 2 adds handling for systems with incomplete lvm/md devices.
11 years, 4 months
[PATCH - master] Remove some unused error handling code from old UI.
by Chris Lumens
This is a relic from when I didn't know how error handling would work in
newui. It clearly doesn't do anything anymore, and should just raise an
exception that we can handle elsewhere.
---
pyanaconda/storage/formats/fs.py | 18 +-----------------
1 file changed, 1 insertion(+), 17 deletions(-)
diff --git a/pyanaconda/storage/formats/fs.py b/pyanaconda/storage/formats/fs.py
index 505e76e..e9c8463 100644
--- a/pyanaconda/storage/formats/fs.py
+++ b/pyanaconda/storage/formats/fs.py
@@ -505,23 +505,7 @@ class FS(DeviceFormat):
{"type": self.type, "device": self.device}
msg = self._fsckErrorMessage(ret)
-
- # FIXME: Bluh?
- if False:
- help = _("Errors like this usually mean there is a problem "
- "with the filesystem that will require user "
- "interaction to repair. Before restarting "
- "installation, reboot to rescue mode or another "
- "system that allows you to repair the filesystem "
- "interactively. Restart installation after you "
- "have corrected the problems on the filesystem.")
-
- intf.messageWindow(_("Unrecoverable Error"),
- hdr + "\n\n" + msg + "\n\n" + help,
- custom_icon='error')
- sys.exit(0)
- else:
- raise FSError(hdr + msg)
+ raise FSError(hdr + msg)
def loadModule(self):
"""Load whatever kernel module is required to support this filesystem."""
--
1.7.11.2
11 years, 4 months
[PATCH] Don't resize NTFS partitions to smaller than the filesystem on them (#885912).
by Chris Lumens
Note this is a big hacky fix, while the permanent fix involves telling other
parts of the code when we change sizes via alignments.
---
pyanaconda/storage/formats/fs.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/pyanaconda/storage/formats/fs.py b/pyanaconda/storage/formats/fs.py
index 505e76e..738ef6d 100644
--- a/pyanaconda/storage/formats/fs.py
+++ b/pyanaconda/storage/formats/fs.py
@@ -1418,7 +1418,12 @@ class NTFS(FS):
def resizeArgs(self):
# You must supply at least two '-f' options to ntfsresize or
# the proceed question will be presented to you.
- targetSize = (mib / mb) * self.targetSize # convert MiB to MB
+
+ # FIXME: This -1 is because our partition alignment calculations plus
+ # converting back and forth between MiB and MB means the filesystem is
+ # getting resized to be slightly larger than the partition holding it.
+ # This hack just makes the filesystem fit.
+ targetSize = (mib / mb) * (self.targetSize-1) # convert MiB to MB
argv = ["-ff", "-s", "%dM" % (targetSize,), self.device]
return argv
--
1.7.11.2
11 years, 4 months
[PATCH][rhel6-branch] Fix handling of nompath option.
by David Lehman
Don't run identifyMultipaths if nompath was passed, for both interactive
and kickstart installs.
Related: rhbz#821042
---
kickstart.py | 12 ++++++------
storage/devicetree.py | 6 ++++--
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/kickstart.py b/kickstart.py
index 7cc8f22..e4b960a 100644
--- a/kickstart.py
+++ b/kickstart.py
@@ -22,6 +22,7 @@ from storage.deviceaction import *
from storage.devices import LUKSDevice
from storage.devicelibs.lvm import getPossiblePhysicalExtents
from storage.devicelibs.mpath import MultipathConfigWriter, identifyMultipaths
+from storage.devicelibs.mpath import writeMultipathConf
from storage.formats import getFormat
from storage.partitioning import clearPartitions
from storage.partitioning import shouldClear
@@ -63,7 +64,7 @@ from anaconda_log import logger, logLevelMap, setHandlersLevel
# deviceMatches is called early, before any multipaths can possibly be coalesced
# so it needs to know about them in some additional way
-multipaths = None
+multipaths = []
class AnacondaKSScript(Script):
def run(self, chroot, serial, intf = None):
@@ -184,11 +185,10 @@ def getEscrowCertificate(anaconda, url):
def detect_multipaths():
global multipaths
mcw = MultipathConfigWriter()
- cfg = mcw.write(friendly_names=True)
- with open("/etc/multipath.conf", "w+") as mpath_cfg:
- mpath_cfg.write(cfg)
- devices = udev_get_block_devices()
- (singles, multipaths, partitions) = identifyMultipaths(devices)
+ writeMultipathConf(writer=mcw, friendly_names=True)
+ if os.access("/etc/multipath.conf", os.R_OK):
+ devices = udev_get_block_devices()
+ (singles, multipaths, partitions) = identifyMultipaths(devices)
def deviceMatches(spec):
full_spec = spec
diff --git a/storage/devicetree.py b/storage/devicetree.py
index 6e3c6b2..ba85aab 100644
--- a/storage/devicetree.py
+++ b/storage/devicetree.py
@@ -2099,8 +2099,10 @@ class DeviceTree(object):
friendly_names=self.mpathFriendlyNames)
devices = udev_get_block_devices()
- (singles, mpaths, partitions) = devicelibs.mpath.identifyMultipaths(devices)
- devices = singles + reduce(list.__add__, mpaths, []) + partitions
+ if os.access("/etc/multipath.conf", os.R_OK):
+ (singles, mpaths, partitions) = devicelibs.mpath.identifyMultipaths(devices)
+ devices = singles + reduce(list.__add__, mpaths, []) + partitions
+
# remember all the devices idenitfyMultipaths() gave us at this point
old_devices = {}
for dev in devices:
--
1.7.7.6
11 years, 4 months
[PATCH] Set line wrap on the info bar (#888112).
by Chris Lumens
---
widgets/src/BaseWindow.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/widgets/src/BaseWindow.c b/widgets/src/BaseWindow.c
index 23b9998..f417260 100644
--- a/widgets/src/BaseWindow.c
+++ b/widgets/src/BaseWindow.c
@@ -429,6 +429,8 @@ static void anaconda_base_window_set_info_bar(AnacondaBaseWindow *win, GtkMessag
return;
label = gtk_label_new(_(msg));
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD);
gtk_widget_show(label);
win->priv->info_bar = gtk_info_bar_new();
--
1.7.11.2
11 years, 4 months