Exemple #1
0
def create_notification_on_failure_service(systempath, service_name,
                                           n_notifier, n_user, n_to, n_pw,
                                           n_msg, n_status_cmd, root):
    if n_notifier is None:
        return
    notify = get_sysdm_executable() + " notify"
    user = get_output("echo $USER")
    home = get_output("echo ~" + user)
    host = get_output("echo $HOSTNAME")
    n_msg = n_msg.format(home=home, host=host)
    exec_start = f"""/bin/bash -c "{n_status_cmd} | {notify} {n_notifier} -m {n_msg!r}"""
    if n_user is not None:
        exec_start += f" -u {n_user!r}"
    if n_to is not None:
        exec_start += f" -t {n_to!r}"
    if n_pw is not None:
        exec_start += f" -p {n_pw!r}"
    exec_start += '"'
    print("Testing notifier ({})".format(n_notifier))
    test_cmd = exec_start.replace("%i",
                                  service_name).replace("%H", host).replace(
                                      "failed on", "test succeeded on")
    print(test_cmd)
    outp = get_output(test_cmd)
    if "Fault" in outp or "invalid" in outp:
        print(outp)
        sys.exit(1)
    print("")
    print("Test succeeded.")
    service = """
    [Unit]
    Description={notify_cmd} OnFailure for %i

    [Service]
    {user_and_group}
    Type=oneshot
    ExecStart={exec_start}
    """.replace("\n    ", "\n").format(
        exec_start=exec_start,
        notify_cmd=n_notifier,
        user_and_group=user_and_group_if_sudo(root),
    )
    with open(
            os.path.join(systempath,
                         "{}[email protected]".format(n_notifier)),
            "w") as f:
        f.write(service)
Exemple #2
0
def create_mail_on_failure_service(systempath, notify_cmd, notify_cmd_args,
                                   notify_status_cmd, root):
    if notify_cmd == "-1":
        return
    notifier = get_output("which " + notify_cmd)
    user = get_output("echo $USER")
    home = get_output("echo ~" + user)
    host = get_output("echo $HOSTNAME")
    notify_cmd_args = notify_cmd_args.format(home=home, host=host)
    exec_start = """/bin/bash -c '{notify_status_cmd} | {notifier} {notify_cmd_args}' """.format(
        notify_status_cmd=notify_status_cmd,
        notifier=notifier,
        notify_cmd_args=notify_cmd_args)
    print("Testing notifier ({})".format(notify_cmd))
    test_args = (notify_cmd_args.replace("%i", notify_cmd).replace(
        "failed", "test succeeded").replace("%H", host).format(home=home,
                                                               host=host))
    test_cmd = """/bin/bash -c '{notify_status_cmd} | {notifier} {notify_cmd_args}' """.format(
        notify_status_cmd=notify_status_cmd.replace("%i", ""),
        notifier=notifier,
        notify_cmd_args=test_args,
    )
    print(get_output(test_cmd))
    print("")
    print("Test succeeded.")
    service = """
    [Unit]
    Description={notify_cmd} OnFailure for %i

    [Service]
    {user_and_group}
    Type=oneshot
    ExecStart={exec_start}
    """.replace("\n    ", "\n").format(
        exec_start=exec_start,
        notify_cmd=notify_cmd,
        user_and_group=user_and_group_if_sudo(root),
    )
    with open(
            os.path.join(systempath,
                         "{}[email protected]".format(notify_cmd)),
            "w") as f:
        f.write(service)
Exemple #3
0
def choose_unit(systempath, units):
    options = []
    ss = get_output("ss -l -p -n")
    ps_aux = get_output("ps ax -o pid,%cpu,%mem,ppid,args -ww")
    for unit in units:
        running = "✓" if is_unit_running(unit) or is_unit_running(
            unit + ".timer") else "✗"
        enabled = "✓" if is_unit_enabled(unit) or is_unit_enabled(
            unit + ".timer") else "✗"
        ps = read_ps_aux_by_unit(systempath, unit, ps_aux)
        if ps is None:
            port = ""
        else:
            pid, *_ = ps
            port = get_port_from_ps_and_ss(pid, ss)
        options.append((unit, running, enabled, port))

    pad = "{}|    {}    |    {}    |   {}"
    offset = max([len(x[0]) for x in options]) + 3
    formatted_options = [
        pad.format(x.ljust(offset), r, e, p) for x, r, e, p in options
    ]
    quit = "-- Quit --"
    formatted_options.append(" ")
    formatted_options.append(quit)
    title = "These are known units:\n\n{}| Active  | On boot |   Port".format(
        " " * (offset + 2))
    default_index = 0
    while True:
        p = Picker(formatted_options, title, default_index=default_index)
        p.register_custom_handler(ord('q'), lambda _: sys.exit(0))
        chosen, index = p.start()
        if chosen == quit:
            return None
        elif chosen == " ":
            default_index = index
            continue
        else:
            break
    return units[index]
Exemple #4
0
def user_and_group_if_sudo(args):
    global USER_AND_GROUP
    if USER_AND_GROUP is not None:
        return USER_AND_GROUP
    else:
        if IS_SUDO:
            if args.root:
                user = "******"
                user_group = get_output(
                    """getent group | grep :0: | awk -F ":" '{ print $1}'"""
                ).split("\n")[0]
            else:
                user = get_output("echo $SUDO_USER")
                user_group = get_output(
                    """getent group | grep $SUDO_GID: | awk -F ":" '{ print $1}'"""
                ).split("\n")[0]
            output = "User={user}\nGroup={user_group}".format(
                user=user, user_group=user_group)
        else:
            output = ""
    USER_AND_GROUP = output
    return output
Exemple #5
0
def get_cmd_from_filename(fname):
    cmd = None
    binary = False
    if fname.endswith(".py"):
        cmd = (get_output("which python3")
               or get_output("which python")) + " -u"
    elif fname.endswith(".sh"):
        cmd = get_output("which bash")
    elif fname.endswith(".js"):
        cmd = get_output("which node")
    else:
        if "." in fname.split("/")[-1]:
            tmpl = "WARNING: File extension of file '{}' not supported. Treating as executable."
            print(tmpl.format(fname))
        if os.path.isfile(fname):
            cmd = os.path.abspath(fname)
        else:
            cmd = get_output("which " + fname)
            if not cmd:
                print("Do not understand how to run '{}'".format(fname))
                sys.exit(1)
        binary = True
    return binary, cmd.strip()
Exemple #6
0
def monitor(unit, systempath):
    t = Terminal()
    print(t.enter_fullscreen())

    mapping = [
        "[R] Restart service                                                   ",
        "[S] Stop service                                                      ",
        "[T] Enable on startup           [b] Back                              ",
        "[g] Grep (filter) a pattern      [q] Quit view                        ",
    ]

    OFFSET = 12

    resized = [True]
    signal.signal(signal.SIGWINCH, lambda *args: resized.append(True))

    logo = "[sysdm]"
    # seen = set()

    Y_BANNER_OFFSET = len(mapping) + 1 + 2  # mapping, banner, in between lines

    grep = ""

    x_banner_offset = 0
    left_offset = 0
    log_offset = 0
    timer = None

    with t.hidden_cursor():
        try:
            while True:
                print(t.move(0, 0))
                y, x = t.get_location()
                if resized:
                    print(t.clear())
                    resized = []
                    timed = is_unit_running(unit + ".timer")
                    is_running = is_unit_running(unit) or timed
                    is_enabled = is_unit_enabled(unit)
                    if timed:
                        timer_text = ""
                        while not timer_text:
                            status = systemctl("list-timers " + unit + ".timer")
                            timer_text = status.split("\n")[1][4 : status.index("LEFT") - 2]
                        status = "Next: " + t.green(timer_text)
                        timer = datetime.strptime(timer_text[:19], "%Y-%m-%d %H:%M:%S")
                    else:
                        status = "Active: " + (t.green("✓") if is_running else t.red("✗"))
                    with t.location(OFFSET, 0):
                        enabled = t.green("✓") if is_enabled else t.red("✗")
                        line = "Unit: {} {} On Startup: {}".format(t.bold(unit), status, enabled)
                        x_banner_offset = len(line)
                        print(line)

                    with t.location(t.width - len(logo), 0):
                        print(t.bold(logo))

                    with t.location(0, 1):
                        print(t.center("-" * (t.width - 16)))

                    for num, line in enumerate(mapping):
                        with t.location(0, num + 2):
                            if not is_running:
                                line = line.replace("Stop service ", "Start service")
                            if is_enabled:
                                line = line.replace("Enable on startup", "Disable on startup")
                            line = line.replace("[", "[" + t.green).replace("]", t.normal + "]")
                            print(" " * OFFSET + (line + " " * t.width)[: t.width + 3])

                    with t.location(0, 6):
                        print(t.center("-" * (t.width - 16)))

                # if timer just expired, refresh to get the new date
                if timer is not None and datetime.now() > timer:
                    resized = [True]
                if t.width - x_banner_offset > 50:
                    res = "| {} |".format(time.asctime())
                    if is_running:
                        ps_aux = get_output("ps ax -o pid,%cpu,%mem,ppid,args -ww")
                        ps_info = read_ps_aux_by_unit(systempath, unit, ps_aux)
                        if ps_info is not None:
                            res = "| {} | PID={} | CPU {:>4}% | MEM {:>4}%".format(
                                time.asctime(), *ps_info
                            )
                    with t.location(x_banner_offset, 0):
                        print(res)

                with t.location(0, Y_BANNER_OFFSET):
                    n = t.height - Y_BANNER_OFFSET - 1
                    w = t.width
                    g = "--grep " + grep if grep else ""
                    u_sep = "-u" if IS_SUDO else "--user-unit"
                    output = journalctl(
                        "journalctl {u_sep} {u} {u_sep} {u}_monitor {u_sep} {u}.timer -n {n} --no-pager {g}".format(
                            u=unit, n=n + log_offset + 100, g=g, u_sep=u_sep
                        )
                    )
                    outp = []
                    for line in output.split("\n"):
                        # replace e.g. python[pidnum123]: real output
                        line = re.sub("(?<=:\d\d ).+?\[\d+\]: ", "| ", line)
                        if grep:
                            rmatch = re.search(grep, line)
                            if rmatch is not None:
                                s = rmatch.start()
                                e = rmatch.end()
                                line = line[:s] + t.red(line[s:e]) + line[e:]
                        l = (line + " " * 200)[left_offset : w + left_offset - 5]
                        if "Stopped" in l:
                            l = t.bold(l)
                        if "Started" in l:
                            if timed:
                                ln = len(l)
                                white = " " * 200
                                l = (l.split("|")[0] + "| Succesfully ran on timer" + white)[:ln]
                            l = t.green(l)
                        if "WARNING: " in l:
                            l = t.yellow(l)
                        if "ERROR: " in l:
                            l = t.red(l)
                        if "Failed to start " in l:
                            l = t.red(l)
                        if "Triggering OnFailure= " in l:
                            l = t.yellow(l)
                        outp.append(l)
                    if log_offset:
                        print("\n".join(outp[-n - log_offset + 1 : -log_offset]))
                    else:
                        print("\n".join(outp[-n - log_offset + 1 :]))

                with t.cbreak():
                    inp = t.inkey(0.3)

                if inp == "q":
                    if grep:
                        grep = ""
                    else:
                        print(t.clear())
                        sys.exit(0)
                elif inp == "S":
                    print(t.clear())
                    if is_running:
                        print("Stopping unit {unit}".format(unit=unit))
                        systemctl("stop {unit}".format(unit=unit))
                        systemctl("stop {unit}.timer".format(unit=unit))
                    else:
                        print("Starting unit {unit}".format(unit=unit))
                        systemctl("start --no-block {unit}".format(unit=unit))
                        systemctl("start {unit}.timer".format(unit=unit))
                    resized = [True]
                elif inp == "R":
                    print(t.clear())
                    print("Restarting unit {unit}".format(unit=unit))
                    systemctl("restart {unit}".format(unit=unit))
                    resized = [True]
                elif inp == "b" or inp.name == "KEY_DELETE":
                    return
                elif inp == "T":
                    print(t.clear())
                    if is_enabled:
                        print("Disabling unit {unit} on startup".format(unit=unit))
                        systemctl("disable {unit}".format(unit=unit))
                        systemctl("disable {unit}.timer".format(unit=unit))
                    else:
                        print("Enabling unit {unit} on startup".format(unit=unit))
                        systemctl("enable {unit}".format(unit=unit))
                        systemctl("enable {unit}.timer".format(unit=unit))
                    resized = [True]
                elif inp == " ":
                    print(t.clear())
                    resized = [True]
                elif inp == "g":
                    print(t.clear())
                    if grep:
                        grep = ""
                    else:
                        grep = input(
                            "Grep pattern to search for (leave blank for cancel): "
                        ).strip()
                    resized = [True]
                elif inp.name == "KEY_RIGHT":
                    print(t.erase())
                    left_offset = min(left_offset + 5, t.width)
                elif inp.name == "KEY_LEFT":
                    print(t.erase())
                    left_offset = max(0, left_offset - 5)
                elif inp.name == "KEY_UP":
                    print(t.erase())
                    log_offset = min(log_offset + 5, t.height)
                elif inp.name == "KEY_DOWN":
                    print(t.erase())
                    log_offset = max(0, log_offset - 5)
                else:
                    print(t.erase())
        except KeyboardInterrupt:
            pass
        print(t.clear())
Exemple #7
0
 def home(self):
     return get_output("echo ~" + self.user)
Exemple #8
0
 def user(self):
     return get_output("echo $USER")
Exemple #9
0
def get_version_tuple(py):
    out = get_output(f"{py} --version")
    if out.startswith("Python"):
        return tuple(int(x) for x in out.split()[-1].split("."))
    return (0, 0, 0)
Exemple #10
0
def contains_python(fname):
    fname_cmd = get_output("which " + fname)
    if os.path.exists(fname_cmd):
        with open(fname_cmd) as f:
            return "python" in f.read()
    return False