[rhel7 2/2] Make _yum.preconf setup atomic (#882279)
Brian C. Lane
bcl at redhat.com
Sat Nov 23 01:46:41 UTC 2013
From: "Brian C. Lane" <bcl at redhat.com>
All _yum.preconf operations should be inside of _resetYum, inside a
_yum_lock. In order to do this we need to pass the releasever to the
reset method. I broke up _configureBaseRepo so that it gets the
releasever first, resets the yum object, and then tries to setup the
base repo. The second call to _setupInstallDevice is needed because the
payload.reset tears down the mount. You can't skip doing this without
causing problems switching between an ISO and a http source.
This should eliminate the possibility of other threads calling _yum.conf
while _yum.preconf still needs releasever set.
It is *very* important that _yum.preconf not be touched outside of the
_resetYum method's _yum_lock block.
Resolves: rhbz#882279
---
pyanaconda/packaging/yumpayload.py | 130 ++++++++++++++++---------------------
1 file changed, 57 insertions(+), 73 deletions(-)
diff --git a/pyanaconda/packaging/yumpayload.py b/pyanaconda/packaging/yumpayload.py
index 90c79c8..0232636 100644
--- a/pyanaconda/packaging/yumpayload.py
+++ b/pyanaconda/packaging/yumpayload.py
@@ -149,7 +149,7 @@ class YumPayload(PackagePayload):
self.reset()
- def reset(self, root=None):
+ def reset(self, root=None, releasever=None):
""" Reset this instance to its initial (unconfigured) state. """
# cdrom: install_device.teardown (INSTALL_TREE)
@@ -186,7 +186,7 @@ class YumPayload(PackagePayload):
self._groups = None
self._packages = []
- self._resetYum(root=root)
+ self._resetYum(root=root, releasever=releasever)
def setup(self, storage):
super(YumPayload, self).setup(storage)
@@ -201,8 +201,11 @@ class YumPayload(PackagePayload):
# have group info ready.
self.gatherRepoMetadata()
- def _resetYum(self, root=None, keep_cache=False):
- """ Delete and recreate the payload's YumBase instance. """
+ def _resetYum(self, root=None, keep_cache=False, releasever=None):
+ """ Delete and recreate the payload's YumBase instance.
+
+ Setup _yum.preconf -- DO NOT TOUCH IT OUTSIDE THIS METHOD
+ """
import shutil
if root is None:
root = self._root_dir
@@ -230,9 +233,10 @@ class YumPayload(PackagePayload):
self._yum.preconf.enabled_plugins = YUM_PLUGINS
self._yum.preconf.fn = "/tmp/anaconda-yum.conf"
self._yum.preconf.root = root
- # set this now to the best default we've got ; we'll update it if/when
- # we get a base repo set up
- self._yum.preconf.releasever = self._getReleaseVersion(None)
+ if releasever is None:
+ self._yum.preconf.releasever = self._getReleaseVersion(None)
+ else:
+ self._yum.preconf.releasever = releasever
self.txID = None
@@ -357,10 +361,8 @@ reposdir=%s
releasever = self._yum.conf.yumvar['releasever']
self._writeYumConfig()
self._writeLangpacksConfig()
- self._resetYum(root=ROOT_PATH, keep_cache=True)
log.debug("setting releasever to previous value of %s" % releasever)
- self._yum.preconf.releasever = releasever
-
+ self._resetYum(root=ROOT_PATH, keep_cache=True, releasever=releasever)
self._yumCacheDirHack()
self.gatherRepoMetadata()
@@ -453,41 +455,64 @@ reposdir=%s
- Get metadata for all enabled repos, disabling those for which the
retrieval fails.
"""
- log.info("updating base repo")
+ log.info("configuring base repo")
+ url, mirrorlist, sslverify = self._setupInstallDevice(self.storage, checkmount)
- # start with a fresh YumBase instance
- self.reset(root=root)
+ releasever = None
+ method = self.data.method
+ if method.method:
+ try:
+ releasever = self._getReleaseVersion(url)
+ log.debug("releasever from %s is %s", url, releasever)
+ except MissingSectionHeaderError as e:
+ log.error("couldn't set releasever from base repo (%s): %s",
+ method.method, e)
+
+ # start with a fresh YumBase instance & tear down old install device
+ self.reset(root=root, releasever=releasever)
+ self._yumCacheDirHack()
+
+ # This needs to be done again, reset tore it down.
+ url, mirrorlist, sslverify = self._setupInstallDevice(self.storage, checkmount)
# If this is a kickstart install and no method has been set up, or
# askmethod was given on the command line, we don't want to do
# anything. Just disable all repos and return. This should avoid
# metadata fetching.
- if (not self.data.method.method and flags.automatedInstall) or \
+ if (not method.method and flags.automatedInstall) or \
flags.askmethod:
with _yum_lock:
for repo in self._yum.repos.repos.values():
self.disableRepo(repo.id)
-
- self._yumCacheDirHack()
return
- # see if we can get a usable base repo from self.data.method
- try:
- self._configureBaseRepo(self.storage, checkmount=checkmount)
- except (MetadataError, PayloadError) as e:
- if not fallback:
- with _yum_lock:
- for repo in self._yum.repos.repos.values():
- if repo.enabled:
- self.disableRepo(repo.id)
+ # see if we can get a usable base repo from method.method
+ if method.method:
+ try:
+ if releasever is None:
+ raise PayloadSetupError("base repo is unusable")
- return
+ if hasattr(method, "proxy"):
+ proxyurl = method.proxy
+ else:
+ proxyurl = None
- # this preserves the method details while disabling it
- self.data.method.method = None
- self.install_device = None
- finally:
- self._yumCacheDirHack()
+ self._addYumRepo(BASE_REPO_NAME, url, mirrorlist=mirrorlist,
+ proxyurl=proxyurl, sslverify=sslverify)
+ except (MetadataError, PayloadError) as e:
+ log.error("base repo (%s/%s) not valid -- removing it",
+ method.method, url)
+ self._removeYumRepo(BASE_REPO_NAME)
+ if not fallback:
+ with _yum_lock:
+ for repo in self._yum.repos.repos.values():
+ if repo.enabled:
+ self.disableRepo(repo.id)
+ return
+
+ # this preserves the method details while disabling it
+ method.method = None
+ self.install_device = None
with _yum_lock:
if BASE_REPO_NAME not in self._yum.repos.repos.keys():
@@ -539,7 +564,7 @@ reposdir=%s
self._yum.repos.getRepo("rawhide").enabled and \
repo.id != "rawhide":
self.disableRepo(repo.id)
- elif self.data.method.method and \
+ elif 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
@@ -763,47 +788,6 @@ reposdir=%s
return url, mirrorlist, sslverify
- def _configureBaseRepo(self, storage, checkmount=True):
- """ Configure the base repo.
-
- If self.data.method.method is set, failure to configure a base repo
- should generate a PayloadError exception.
-
- If self.data.method.method is unset, no exception should be raised
- and no repo should be configured.
-
- If checkmount is true, check the dracut mount to see if we have
- usable media mounted.
- """
- log.info("configuring base repo")
- url, mirrorlist, sslverify = self._setupInstallDevice(storage, checkmount)
- method = self.data.method
- if method.method:
- with _yum_lock:
- try:
- self._yum.preconf.releasever = self._getReleaseVersion(url)
- except MissingSectionHeaderError as e:
- log.error("couldn't set releasever from base repo (%s): %s"
- % (method.method, e))
- self._removeYumRepo(BASE_REPO_NAME)
- raise PayloadSetupError("base repo is unusable")
-
- self._yumCacheDirHack()
-
- if hasattr(method, "proxy"):
- proxyurl = method.proxy
- else:
- proxyurl = None
-
- try:
- self._addYumRepo(BASE_REPO_NAME, url, mirrorlist=mirrorlist,
- proxyurl=proxyurl, sslverify=sslverify)
- except MetadataError as e:
- log.error("base repo (%s/%s) not valid -- removing it"
- % (method.method, url))
- self._removeYumRepo(BASE_REPO_NAME)
- raise
-
def configureAddOnRepo(self, repo):
""" Configure a single ksdata repo. """
url = repo.baseurl
--
1.8.3.1
More information about the anaconda-patches
mailing list