]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
Merge branch 'master' of ssh://git.ipfire.org/pub/git/pakfire
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 28 Jul 2013 11:21:26 +0000 (13:21 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 28 Jul 2013 11:21:26 +0000 (13:21 +0200)
Makeconfig
Makefile
python/pakfire/builder.py
python/pakfire/daemon.py
python/pakfire/errors.py
python/pakfire/keyring.py
python/pakfire/system.py
python/pakfire/transport.py
python/pakfire/util.py
systemd/pakfire-daemon.service [new file with mode: 0644]

index 2d5434cdc8e6603e796532f6fc9a221620d0a6ee..aa3124367975cf74123850a34ebc4ed77842321b 100644 (file)
@@ -50,3 +50,6 @@ TOP := $(dir $(lastword $(MAKEFILE_LIST)))
 # A list of all files that contain translations and need to
 # be indexed.
 TRANS_FILES  = $(PYTHON_FILES) python/src/*.c
+
+# systemd unit files
+UNIT_FILES = $(wildcard systemd/*.service)
index c873463130d4d63884a985456774a49bae48ba15..2a1497be9fea4cd465d81cf7d399b00a8d89138e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -38,6 +38,13 @@ install: build
                cp -rvf examples/$${file} $(DESTDIR)/etc/pakfire/; \
        done
 
+       # Install systemd file.
+       -mkdir -pv $(DESTDIR)/usr/lib/systemd/system
+       for file in $(UNIT_FILES); do \
+               install -v -m 644 $${file} \
+                       $(DESTDIR)/usr/lib/systemd/system || exit 1; \
+       done
+
 .PHONY: check
 check: all
        PYTHONPATH=python/src/ pylint -E python/pakfire
index 944c1a03d980b5361b2e3a4597c1d9326e3473eb..ebb34e2f4137d5138264dcaabc04ae502d32aecd 100644 (file)
@@ -177,7 +177,14 @@ class BuildEnviron(object):
                        _pakfire.unshare(_pakfire.SCHED_CLONE_NEWNS)
 
                # Mount the directories.
-               self._mountall()
+               try:
+                       self._mountall()
+               except OSError, e:
+                       if e.errno == 30: # Read-only FS
+                               raise BuildError, "Buildroot is read-only: %s" % self.pakfire.path
+
+                       # Raise all other errors.
+                       raise
 
                # Lock the build environment.
                self.lock()
@@ -501,7 +508,12 @@ class BuildEnviron(object):
                for node in nodes:
                        # Stat the original node of the host system and copy it to
                        # the build chroot.
-                       node_stat = os.stat(node)
+                       try:
+                               node_stat = os.stat(node)
+
+                       # If it cannot be found, just go on.
+                       except OSError:
+                               continue
 
                        self._create_node(node, node_stat.st_mode, node_stat.st_rdev)
 
index 8c453e0c2d1f87b7d1e378260e3b87989af47436..cfd5350b92a4b5cb902128941a250f3a30116a28 100644 (file)
@@ -73,6 +73,10 @@ class PakfireDaemon(object):
                while self.__running:
                        time_started = time.time()
 
+                       # Check if keepalive process is still alive.
+                       if not self.keepalive.is_alive():
+                               self.restart_keepalive(wait=10)
+
                        # Spawn a sufficient number of worker processes.
                        self.spawn_workers_if_needed()
 
@@ -96,6 +100,29 @@ class PakfireDaemon(object):
                log.info(_("Shutting down..."))
                self.__running = False
 
+       def restart_keepalive(self, wait=None):
+               log.critical(_("Restarting keepalive process"))
+
+               # Send SIGTERM to really end the process.
+               self.keepalive.terminate()
+
+               # Wait for the process to terminate.
+               if wait:
+                       self.keepalive.join(wait)
+
+               # Remove the keepalive process from the process list.
+               try:
+                       self.__workers.remove(self.keepalive)
+               except ValueError:
+                       pass
+
+               # Create a new process and start it.
+               self.keepalive = PakfireDaemonKeepalive(self.config)
+               self.keepalive.start()
+
+               # Add the process to the process list.
+               self.__workers.append(self.keepalive)
+
        def spawn_workers_if_needed(self, *args, **kwargs):
                """
                        Spawns more workers if needed.
@@ -359,6 +386,11 @@ class PakfireWorker(multiprocessing.Process):
                self.transport = transport.PakfireHubTransport(self.config)
 
                while self.__running:
+                       # Check if the build root is file.
+                       if not self.check_buildroot():
+                               time.sleep(60)
+                               continue
+
                        # Try to get a new build job.
                        job = self.get_new_build_job()
                        if not job:
@@ -401,9 +433,30 @@ class PakfireWorker(multiprocessing.Process):
                """
                self.shutdown()
 
+       def check_buildroot(self):
+               """
+                       Checks if the buildroot is fine.
+               """
+               mp = system.get_mountpoint(BUILD_ROOT)
+
+               # Check if the mountpoint is read-only.
+               if mp.is_readonly():
+                       log.warning("Build directory is read-only: %s" % BUILD_ROOT)
+
+                       # Trying to remount.
+                       try:
+                               mp.remount("rw")
+                       except:
+                               log.warning("Remounting (rw) %s has failed" % BUILD_ROOT)
+                               return False
+                       else:
+                               log.warning("Successfully remounted as rw: %s" % BUILD_ROOT)
+
+               # Everything looks fine.
+               return True
+
        def get_new_build_job(self, timeout=600):
                log.debug("Requesting new job...")
-
                try:
                        job = self.transport.get_json("/builders/jobs/queue",
                                data={ "timeout" : timeout, }, timeout=timeout)
index 87c64e33a03a717347e6d95a5285583238fba2e5..2da38227315ec947a4c62d81291e425dca14044d 100644 (file)
@@ -102,6 +102,10 @@ class TransportError(Error):
        pass
 
 
+class TransportBadGatewayError(TransportError):
+       pass
+
+
 class TransportConnectionError(TransportError):
        pass
 
index 8fe052e9b203f6d0ae00bbafc1a3dd7efc7e6dfa..7bd54fb9fec8a3337e57045b0377397d7678cfc5 100644 (file)
@@ -71,15 +71,17 @@ class Keyring(object):
                os.chmod(filename, 600)
 
        def dump_key(self, keyfp):
-               ret = []
-
                key = self.get_key(keyfp, secret=False)
-               key_priv = self.get_key(keyfp, secret=True)
+               if not key:
+                       return ["  " + _("Not in key store: %s") % keyfp, ""]
 
+               ret = []
                for uid in key.uids:
                        ret.append(uid.uid)
 
                ret.append("  " + _("Fingerprint: %s") % keyfp)
+
+               key_priv = self.get_key(keyfp, secret=True)
                if key_priv:
                        ret.append("    " + _("Private key available!"))
                ret.append("")
index 1f0f6de6d519d0374d1b838ed83c2798e39634a9..2bba8020819bac4d942e5a110a49e9c9ce8edce7 100644 (file)
@@ -24,8 +24,10 @@ from __future__ import division
 import multiprocessing
 import os
 import socket
+import tempfile
 
 import distro
+import shell
 
 from i18n import _
 
@@ -130,17 +132,19 @@ class System(object):
        def cpu_model(self):
                cpuinfo = self.parse_cpuinfo()
 
-               ret = None
-               if self.arch.startswith("arm"):
+               ret = cpuinfo.get("model name", None)
+
+               # Some ARM platforms do not provide "model name", so we
+               # try an other way.
+               if ret is None:
                        try:
                                ret = "%(Hardware)s - %(Processor)s" % cpuinfo
                        except KeyError:
                                pass
-               else:
-                       ret = cpuinfo.get("model name", None)
 
                # Remove too many spaces.
-               ret = " ".join(ret.split())
+               if ret:
+                       ret = " ".join(ret.split())
 
                return ret or _("Could not be determined")
 
@@ -344,6 +348,9 @@ class Mountpoint(object):
                # Save the amount of data that is used or freed.
                self.disk_usage = 0
 
+       def __repr__(self):
+               return "<%s %s>" % (self.__class__.__name__, self.fullpath)
+
        def __cmp__(self, other):
                return cmp(self.fullpath, other.fullpath)
 
@@ -403,6 +410,45 @@ class Mountpoint(object):
 
                self.disk_usage -= file.size
 
+       def is_readonly(self):
+               """
+                       Returns True if the mountpoint is mounted read-only.
+                       Otherwise False.
+               """
+               # Using the statvfs output does not really work, so we use
+               # a very naive approach here, were we just try to create a
+               # new file. If that works, it's writable.
+
+               try:
+                       handle, path = tempfile.mkstemp(prefix="ro-test-", dir=self.fullpath)
+               except OSError, e:
+                       # Read-only file system.
+                       if e.errno == 30:
+                               return True
+
+                       # Raise all other exceptions.
+                       raise
+               else:
+                       # Close the file and remove it.
+                       os.close(handle)
+                       os.unlink(path)
+
+               return False
+
+       def remount(self, rorw=None):
+               options = "remount"
+               if rorw in ("ro", "rw"):
+                       options = "%s,%s" % (options, rorw)
+
+               try:
+                       shellenv = shell.ShellExecuteEnvironment(
+                               ["mount", "-o", options, self.fullpath],
+                               shell=False,
+                       )
+                       shellenv.execute()
+               except ShellEnvironmentError, e:
+                       raise OSError
+
 
 if __name__ == "__main__":
        print "Hostname", system.hostname
index 1adb1c61a508611e6253c37b0727f485d8a54a9c..7783aace149a534af4b9d2eb5050f72497bc5b23 100644 (file)
@@ -260,6 +260,8 @@ class PakfireHubTransport(object):
                                        raise TransportNotFoundError, url
                                elif e.code == 500:
                                        raise TransportInternalServerError, url
+                               elif e.code in (502, 503):
+                                       raise TransportBadGatewayError, url
                                elif e.code == 504:
                                        raise TransportConnectionTimeoutError, url
 
@@ -276,8 +278,8 @@ class PakfireHubTransport(object):
                        try:
                                return self.one_request(url, **kwargs)
 
-                       # 500 - Internal Server Error
-                       except TransportInternalServerError, e:
+                       # 500 - Internal Server Error, 502 + 503 Bad Gateway Error
+                       except (TransportInternalServerError, TransportBadGatewayError), e:
                                log.exception("%s" % e.__class__.__name__)
 
                                # Wait a minute before trying again.
@@ -290,6 +292,9 @@ class PakfireHubTransport(object):
                                # Wait for 10 seconds.
                                time.sleep(10)
 
+                       except (KeyboardInterrupt, SystemExit):
+                               break
+
                raise TransportMaxTriesExceededError
 
        def escape_args(self, **kwargs):
index 84128cd9c7418e4afbadc39e969903a57f40cd23..73c62d0660800e1c332e46e10e8226a8e4c691e0 100644 (file)
@@ -79,19 +79,6 @@ def random_string(length=20):
 
        return s
 
-
-class Bar(progressbar.Bar):
-       def update(self, pbar, width):
-               percent = pbar.percentage()
-               if pbar.finished:
-                       return " " * width
-
-               cwidth = width - len(self.left) - len(self.right)
-               marked_width = int(percent * cwidth / 100)
-               m = self._format_marker(pbar)
-               bar = (self.left + (m*marked_width).ljust(cwidth) + self.right)
-               return bar
-
 def make_progress(message, maxval, eta=True, speed=False):
        # Return nothing if stdout is not a terminal.
        if not sys.stdout.isatty():
@@ -99,9 +86,9 @@ def make_progress(message, maxval, eta=True, speed=False):
 
        widgets = [
                "  ",
-               "%s" % message,
+               "%-64s" % message,
                " ",
-               Bar(left="[", right="]"),
+               progressbar.Bar(left="[", right="]"),
                "  ",
        ]
 
diff --git a/systemd/pakfire-daemon.service b/systemd/pakfire-daemon.service
new file mode 100644 (file)
index 0000000..00e5466
--- /dev/null
@@ -0,0 +1,16 @@
+[Unit]
+Description=Pakfire Daemon
+After=network-online.target remote-fs.target
+Requires=network-online.target
+Wants=remote-fs.target
+
+[Service]
+KillMode=process
+SendSIGKILL=false
+TimeoutStopSec=0
+
+ExecStart=/usr/bin/pakfire-daemon
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target