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]
def delete(unit, systempath): service_name = unit.replace(".", "_") path = systempath + "/" + service_name for s in [ service_name, service_name + "_monitor", service_name + ".timer" ]: if is_unit_enabled(s): _ = systemctl("disable {}".format(s)) print("Disabled unit {}".format(s)) else: print("Unit {} was not enabled so no need to disable it".format(s)) if is_unit_running(s): _ = systemctl("stop {}".format(s)) print("Stopped unit {}".format(s)) else: print("Unit {} was not started so no need to stop it".format(s)) _ = systemctl("daemon-reload") o = run_quiet("rm {}".format(path + ".service")) o = run_quiet("rm {}".format(path + "_monitor.service")) o = run_quiet("rm {}".format(path + ".timer")) print("Deleted {}".format(path + ".service")) print("Deleted {}".format(path + "_monitor.service")) print("Deleted {}".format(path + ".timer")) print("Delete Succeeded!")
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())