summaryrefslogtreecommitdiff
path: root/subplot/daemon.py
blob: e223505ebd891258bbc301d60d61dcd3545990cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#############################################################################
# Start and stop daemons, or background processes.


import logging
import os
import signal
import time


# Start a process in the background.
def start_daemon(ctx, name, argv):
    runcmd = globals()["runcmd"]
    exit_code_is = globals()["exit_code_is"]

    logging.debug(f"Starting daemon {name}")
    logging.debug(f"  ctx={ctx.as_dict()}")
    logging.debug(f"  name={name}")
    logging.debug(f"  argv={argv}")

    if "daemon" not in ctx.as_dict():
        ctx["daemon"] = {}
    assert name not in ctx["daemon"]
    this = ctx["daemon"][name] = {
        "pid-file": f"{name}.pid",
        "stderr": f"{name}.stderr",
        "stdout": f"{name}.stdout",
    }
    runcmd(
        ctx,
        [
            "/usr/sbin/daemonize",
            "-c",
            os.getcwd(),
            "-p",
            this["pid-file"],
            "-e",
            this["stderr"],
            "-o",
            this["stdout"],
        ]
        + argv,
    )

    # Wait for a bit for daemon to start and maybe find a problem and die.
    time.sleep(3)
    if ctx["exit"] != 0:
        logging.error(f"obnam-server stderr: {ctx['stderr']}")

    exit_code_is(ctx, 0)
    this["pid"] = int(open(this["pid-file"]).read().strip())
    assert process_exists(this["pid"])

    logging.debug(f"Started daemon {name}")
    logging.debug(f"  ctx={ctx.as_dict()}")


# Stop a daemon.
def stop_daemon(ctx, name):
    logging.debug(f"Stopping daemon {name}")
    logging.debug(f"  ctx={ctx.as_dict()}")
    logging.debug(f"  ctx['daemon']={ctx.as_dict()['daemon']}")

    this = ctx["daemon"][name]
    terminate_process(this["pid"], signal.SIGKILL)


# Does a process exist?
def process_exists(pid):
    try:
        os.kill(pid, 0)
    except ProcessLookupError:
        return False
    return True


# Terminate process.
def terminate_process(pid, signalno):
    logging.debug(f"Terminating process {pid} with signal {signalno}")
    try:
        os.kill(pid, signalno)
    except ProcessLookupError:
        logging.debug("Process did not actually exist (anymore?)")
        pass