# 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)
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
_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()
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)
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()
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.
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:
"""
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)
pass
+class TransportBadGatewayError(TransportError):
+ pass
+
+
class TransportConnectionError(TransportError):
pass
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("")
import multiprocessing
import os
import socket
+import tempfile
import distro
+import shell
from i18n import _
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")
# 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)
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
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
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.
# Wait for 10 seconds.
time.sleep(10)
+ except (KeyboardInterrupt, SystemExit):
+ break
+
raise TransportMaxTriesExceededError
def escape_args(self, **kwargs):
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():
widgets = [
" ",
- "%s" % message,
+ "%-64s" % message,
" ",
- Bar(left="[", right="]"),
+ progressbar.Bar(left="[", right="]"),
" ",
]
--- /dev/null
+[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