Beispiel #1
0
 def ls(self):
     """ Interactively show units and allow viewing them """
     while True:
         units = ls(self.systempath)
         if units:
             unit = choose_unit(self.systempath, units)
             if unit is None:
                 sys.exit()
             monitor(unit, self.systempath)
         else:
             print(
                 "sysdm knows of no units. Why don't you make one? `sysdm create file_i_want_as_service.py`"
             )
             break
Beispiel #2
0
    def view(self, unit: str):
        """
        Monitor a unit

        :param unit: File/cmd/unit to observe. Dots will be replaced with _ automatically
        """
        service_name = to_sn(unit)
        if not os.path.exists(self.systempath + "/" + service_name +
                              ".service"):
            print(
                "Service file does not exist. You can start by running:\n\n    sysdm create {}\n\nto create a service or run:\n\n    sysdm ls\n\nto see the services already created by sysdm."
                .format(unit))
            sys.exit(1)
        monitor(service_name, self.systempath)
Beispiel #3
0
    def create(
        self,
        fname_or_cmd: str,
        restart=True,
        timer: str = None,
        killaftertimeout=90,
        delay=0.2,
        extensions=[],
        exclude_patterns=[],
        ls=True,
        root=False,
        notify_cmd="-1",
        notify_status_cmd="systemctl --user status -l -n 1000 %i",
        notify_cmd_args='-s "%i failed on %H"',
    ):
        """
        Create a systemd unit file

        :param fname_or_cmd: File/cmd to run
        :param restart: Whether to prevent auto restart on error
        :param timer: Used to set timer. Checked to be valid. E.g. *-*-* 03:00:00 for daily at 3 am.
        :param killaftertimeout: Time before sending kill signal if unresponsive when try to restart
        :param delay: Set a delay in the unit file before attempting restart
        :param extensions: Patterns of files to watch (by default inferred)
        :param exclude_patterns: Patterns of files to ignore (by default inferred)
        :param ls: Only create but do not list
        :param root: Only possible when using sudo
        :param notify_cmd: Binary command that will notify. -1 will add no notifier. Possible: e.g. yagmail
        :param notify_status_cmd: Command that echoes output to the notifier on failure
        :param notify_cmd_args: Arguments passed to notify command.
        """
        print("Creating systemd unit...")
        service_name, service = create_service_template(
            fname_or_cmd, notify_cmd, timer, delay, root, killaftertimeout)
        try:
            with open(
                    os.path.join(self.systempath, service_name) + ".service",
                    "w") as f:
                print(service)
                f.write(service)
        except PermissionError:
            print("Need sudo to create systemd unit service file.")
            sys.exit(1)
        create_mail_on_failure_service(self.systempath, notify_cmd,
                                       notify_status_cmd, notify_status_cmd,
                                       root)
        _ = systemctl("daemon-reload")
        create_timer = create_timer_service(self.systempath, service_name,
                                            timer)
        if create_timer:
            _ = systemctl("enable {}.timer".format(service_name))
            _ = systemctl("start {}.timer".format(service_name))
        else:
            _ = systemctl("enable {}".format(service_name))
            monitor_str = create_service_monitor_template(
                service_name, fname_or_cmd, extensions, exclude_patterns, root)
            with open(
                    os.path.join(self.systempath, service_name) +
                    "_monitor.service", "w") as f:
                f.write(monitor_str)
            _ = systemctl("start --no-block {}".format(service_name))
            _ = systemctl("enable {}_monitor".format(service_name))
            _ = systemctl("start {}_monitor".format(service_name))
        print(linger())
        print("Done")
        if ls:
            monitor(service_name, self.systempath)
Beispiel #4
0
    def create(self,
               fname_or_cmd: str,
               restart=True,
               timer: str = None,
               killaftertimeout=90,
               delay=0.2,
               extensions=[],
               exclude_patterns=[],
               ls=True,
               root=False,
               n_notifier: Optional[str] = None,
               n_user: Optional[str] = None,
               n_to: Optional[Union[str, int]] = None,
               n_pw: Optional[str] = None,
               n_msg: Optional[str] = "%i failed on %H",
               n_status_cmd="journalctl {user} --no-pager -n 1000",
               workdir: str = "",
               env_vars: list[str] = []):
        """
        Create a systemd unit file

        :param fname_or_cmd: File/cmd to run
        :param restart: Whether to prevent auto restart on error
        :param timer: Used to set timer. Checked to be valid. E.g. *-*-* 03:00:00 for daily at 3 am.
        :param killaftertimeout: Time before sending kill signal if unresponsive when try to restart
        :param delay: Set a delay in the unit file before attempting restart
        :param extensions: Patterns of files to watch (by default inferred)
        :param exclude_patterns: Patterns of files to ignore (by default inferred)
        :param ls: Only create but do not list
        :param root: Only possible when using sudo
        :param notify_cmd: Binary command that will notify. -1 will add no notifier. Possible: e.g. yagmail
        :param notify_status_cmd: Command that echoes output to the notifier on failure
        :param notify_cmd_args: Arguments passed to notify command.
        :param workdir: Location from which command is run
        :param env_vars: can be passed like FOO=1 or FOO (which would inherit FOO current shell)
        """
        if n_notifier is not None:
            install_notifier_dependencies(n_notifier)
        print("Creating systemd unit...")
        service_name, service = create_service_template(
            fname_or_cmd, n_notifier, timer, delay, root, killaftertimeout,
            restart, workdir, env_vars)
        user = "******" if IS_SUDO else "--user-unit %i"
        n_status_cmd = n_status_cmd.format(user=user)
        try:
            with open(
                    os.path.join(self.systempath, service_name) + ".service",
                    "w") as f:
                print(service)
                f.write(service)
        except PermissionError:
            print("Need sudo to create systemd unit service file.")
            sys.exit(1)
        create_notification_on_failure_service(self.systempath, service_name,
                                               n_notifier, n_user, n_to, n_pw,
                                               n_msg, n_status_cmd, root)
        _ = systemctl("daemon-reload")
        create_timer = create_timer_service(self.systempath, service_name,
                                            timer)
        if create_timer:
            _ = systemctl("enable {}.timer".format(service_name))
            _ = systemctl("start {}.timer".format(service_name))
        else:
            _ = systemctl("enable {}".format(service_name))
            monitor_str = create_service_monitor_template(
                service_name, fname_or_cmd, extensions, exclude_patterns, root)
            with open(
                    os.path.join(self.systempath, service_name) +
                    "_monitor.service", "w") as f:
                f.write(monitor_str)
            _ = systemctl("start --no-block {}".format(service_name))
            _ = systemctl("enable {}_monitor".format(service_name))
            _ = systemctl("start {}_monitor".format(service_name))
        print(linger())
        print("Done")
        if ls:
            monitor(service_name, self.systempath)
Beispiel #5
0
def _main():
    parser, args = get_argparser()
    try:
        if args.systempath is None:
            args.systempath = "/etc/systemd/system" if IS_SUDO else "~/.config/systemd/user"
        args.systempath = os.path.expanduser(args.systempath)
        args.systempath = args.systempath.rstrip("/")
        try:
            os.makedirs(args.systempath)
        except FileExistsError:
            pass
    except AttributeError:
        # most commands have it, but not all
        pass
    if args.command == "create":
        print("Creating systemd unit...")
        service_name = install(args)
        print("Done")
        if not args.nolist:
            monitor(service_name, args.systempath)
    elif args.command == "view":
        service_name = to_sn(args.unit)
        if not os.path.exists(args.systempath + "/" + service_name +
                              ".service"):
            print(
                "Service file does not exist. You can start by running:\n\n    sysdm create {}\n\nto create a service or run:\n\n    sysdm ls\n\nto see the services already created by sysdm."
                .format(args.unit))
            sys.exit(1)
        monitor(service_name, args.systempath)
    elif args.command == "run":
        if args.unit is None:
            units = ls(args)
            unit = choose_unit(args.systempath, units)
            if unit is None:
                sys.exit()
        else:
            unit = args.unit
        with open(args.systempath + "/" + unit + ".service") as f:
            for line in f:
                line = line.strip()
                if line.startswith("ExecStart="):
                    cmd = line.split("ExecStart=")[1]
                    if args.debug:
                        cmd = cmd.replace("python3 -u", "python3 -u -m pdb")
                        cmd = cmd.replace("python -u", "python -u -m pdb")
                elif line.startswith("WorkingDirectory="):
                    cwd = line.split("WorkingDirectory=")[1]
            os.system("cd {!r} && {}".format(cwd, cmd))
    elif args.command == "show_unit":
        show(args)
    elif args.command == "reload":
        systemctl("daemon-reload")
    elif args.command == "watch":
        watch(args)
    elif args.command == "delete":
        if args.unit is None:
            units = ls(args)
            unit = choose_unit(args.systempath, units)
            if unit is None:
                sys.exit()
            inp = input(
                "Are you sure you want to delete '{}'? [y/N]: ".format(unit))
            if inp.lower().strip() != "y":
                print("Aborting")
                return
        else:
            unit = args.unit
        delete(unit, args.systempath)
    elif args.command == "edit":
        if args.unit is None:
            units = ls(args)
            unit = choose_unit(args.systempath, units)
            if unit is None:
                sys.exit()
        else:
            unit = args.unit
        unit = unit if unit.endswith(".service") else unit + ".service"
        os.system("$EDITOR {}/{}".format(args.systempath, unit))
    elif args.command == "ls":
        while True:
            units = ls(args)
            if units:
                unit = choose_unit(args.systempath, units)
                if unit is None:
                    sys.exit()
                monitor(unit, args.systempath)
            else:
                print(
                    "sysdm knows of no units. Why don't you make one? `sysdm create file_i_want_as_service.py`"
                )
                break
    else:
        parser.print_help(sys.stderr)
        sys.exit(1)