[PATCH 3/3] DNFPayload: pick the right FS as package download target.

Ales Kozumplik akozumpl at redhat.com
Wed Feb 12 12:28:45 UTC 2014


From: Ales Kozumplik <ales at redhat.com>

---
 anaconda.spec.in                   |  2 +-
 pyanaconda/packaging/dnfpayload.py | 68 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/anaconda.spec.in b/anaconda.spec.in
index 2d41c5d..7215e32 100755
--- a/anaconda.spec.in
+++ b/anaconda.spec.in
@@ -23,7 +23,7 @@ Source0: %{name}-%{version}.tar.bz2
 %define intltoolver 0.31.2-3
 %define pykickstartver 1.99.46
 %define yumver 3.4.3-91
-%define dnfver 0.4.8
+%define dnfver 0.4.14
 %define partedver 1.8.1
 %define pypartedver 2.5-2
 %define pythonpyblockver 0.45
diff --git a/pyanaconda/packaging/dnfpayload.py b/pyanaconda/packaging/dnfpayload.py
index 5bcb596..f92478e 100644
--- a/pyanaconda/packaging/dnfpayload.py
+++ b/pyanaconda/packaging/dnfpayload.py
@@ -30,6 +30,7 @@ import logging
 import multiprocessing
 import pyanaconda.constants as constants
 import pyanaconda.errors as errors
+import pyanaconda.iutil
 import pyanaconda.packaging as packaging
 import sys
 import time
@@ -49,6 +50,7 @@ except ImportError as e:
 
 DEFAULT_REPOS = [constants.productName.lower(), "rawhide"]
 DNF_CACHE_DIR = '/tmp/dnf.cache'
+DNF_PACKAGE_CACHE_DIR_SUFFIX = 'dnf.package.cache'
 REPO_DIRS = ['/etc/yum.repos.d',
              '/etc/anaconda.repos.d',
              '/tmp/updates/anaconda.repos.d',
@@ -59,6 +61,46 @@ def _failure_limbo():
     while True:
         time.sleep(10000)
 
+def _df_map():
+    """Return (mountpoint -> size available) mapping."""
+    output = pyanaconda.iutil.execWithCapture('df', ['--output=target,avail'])
+    output = output.rstrip()
+    lines = output.split('\n')
+    structured = {}
+    for line in lines:
+        items = line.split()
+        key = items[0]
+        val = items[1]
+        if not key.startswith('/'):
+            continue
+        structured[key] = Size(bytes=int(val)*1024)
+    return structured
+
+def _pick_mpoint(df, requested):
+    def reasonable_mpoint(mpoint):
+        return mpoint in ['/tmp',
+                          '/',
+                          '/mnt/sysimage',
+                          '/mnt/sysimage/home',
+                          '/mnt/sysimage/tmp',
+                          '/mnt/sysimage/var',
+                          ]
+
+    # reserve extra
+    requested = requested + Size(en_spec="150 MB")
+    sufficients = {key : val for (key,val) in df.items() if val > requested
+                   and reasonable_mpoint(key)}
+    log.info('Sufficient mountpoints found: %s' % sufficients)
+
+    # prefer /tmp:
+    if '/tmp' in sufficients:
+        return '/tmp'
+    if not len(sufficients):
+        return None
+    # default to the biggest one:
+    return sorted(sufficients.iteritems(), key=operator.itemgetter(1),
+                  reverse=True)[0][0]
+
 class PayloadRPMDisplay(dnf.output.LoggingTransactionDisplay):
     def __init__(self, queue):
         super(PayloadRPMDisplay, self).__init__()
@@ -163,6 +205,15 @@ class DNFPayload(packaging.PackagePayload):
 
         conf.reposdir = REPO_DIRS
 
+    @property
+    def _download_space(self):
+        transaction = self._base.transaction
+        if transaction is None:
+            return Size(0)
+
+        size = sum(tsi.installed.downloadsize for tsi in transaction)
+        return Size(size)
+
     def _install_package(self, pkg_name):
         try:
             return self._base.install(pkg_name)
@@ -182,6 +233,20 @@ class DNFPayload(packaging.PackagePayload):
             progressQ.send_quit(1)
             sys.exit(1)
 
+    def _pick_download_location(self):
+        required = self._download_space
+        df_map = _df_map()
+        mpoint = _pick_mpoint(df_map, required)
+        log.info("Download space required: %s, use filesystem at: %s", required,
+                 mpoint)
+        if mpoint is None:
+            msg = "Not enough disk space to download the packages."
+            raise packaging.PayloadError(msg)
+
+        pkgdir = '%s/%s' % (mpoint, DNF_PACKAGE_CACHE_DIR_SUFFIX)
+        for repo in self._base.repos.iter_enabled():
+            repo.pkgdir = pkgdir
+
     def _select_group(self, group_id, default=True, optional=False):
         grp = self._base.comps.group_by_pattern(group_id)
         if grp is None:
@@ -345,7 +410,8 @@ class DNFPayload(packaging.PackagePayload):
             self._setupMedia(self.install_device)
         try:
             self.checkSoftwareSelection()
-        except packaging.DependencyError as e:
+            self._pick_download_location()
+        except packaging.PayloadError as e:
             if errors.errorHandler.cb(e) == errors.ERROR_RAISE:
                 _failure_limbo()
 
-- 
1.8.5.3



More information about the anaconda-patches mailing list