aboutsummaryrefslogtreecommitdiff
path: root/src/palhm
diff options
context:
space:
mode:
Diffstat (limited to 'src/palhm')
-rwxr-xr-xsrc/palhm/__main__.py220
-rw-r--r--src/palhm/conf/crontab4
-rw-r--r--src/palhm/conf/palhm-boot-report.service2
3 files changed, 223 insertions, 3 deletions
diff --git a/src/palhm/__main__.py b/src/palhm/__main__.py
new file mode 100755
index 0000000..cdb21b7
--- /dev/null
+++ b/src/palhm/__main__.py
@@ -0,0 +1,220 @@
+# Copyright (c) 2022 David Timber <dxdt@dev.snart.me>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+import importlib
+import logging
+import os
+import sys
+from abc import ABC, abstractmethod
+from getopt import getopt
+
+import palhm
+from palhm.exceptions import InvalidConfigError
+
+
+class ProgConf:
+ conf = "/etc/palhm/palhm.jsonc"
+ cmd = None
+ override_vl = None
+ ctx = None
+
+ def alloc_ctx ():
+ ProgConf.ctx = palhm.setup_conf(palhm.load_conf(ProgConf.conf))
+ if not ProgConf.override_vl is None:
+ ProgConf.ctx.l.setLevel(ProgConf.override_vl)
+
+def err_unknown_cmd ():
+ sys.stderr.write(
+ "Unknown command. Run '" + sys.executable + " -m palhm help' for usage.\n")
+ exit(2)
+
+class Cmd (ABC):
+ @abstractmethod
+ def do_cmd (self):
+ ...
+
+class ConfigCmd (Cmd):
+ def __init__ (self, *args, **kwargs):
+ pass
+
+ def do_cmd (self):
+ ProgConf.alloc_ctx()
+ print(ProgConf.ctx)
+ return 0
+
+ def print_help ():
+ print(
+"Usage: " + sys.executable + " -m palhm config" + '''
+Load and parse config. Print the structure to stdout.''')
+
+class RunCmd (Cmd):
+ def __init__ (self, optlist, args):
+ self.optlist = optlist
+ self.args = args
+
+ def do_cmd (self):
+ ProgConf.alloc_ctx()
+
+ if self.args and self.args[0]: # empty string as "default"
+ task = self.args[0]
+ else:
+ task = palhm.DEFAULT.RUN_TASK.value
+
+ ProgConf.ctx.task_map[task].run(ProgConf.ctx)
+
+ return 0
+
+ def print_help ():
+ print(
+"Usage: " + sys.executable + " -m palhm run [TASK]" + '''
+Run a task in config. Run the "''' + palhm.DEFAULT.RUN_TASK.value +
+'''" task if [TASK] is not specified.''')
+
+class ModsCmd (Cmd):
+ def __init__ (self, *args, **kwargs):
+ pass
+
+ def _walk_mods (self, path: str):
+ def is_mod_dir (path: str) -> bool:
+ try:
+ for i in os.scandir(path):
+ if i.name.startswith("__init__.py"):
+ return True
+ except NotADirectoryError:
+ pass
+ return False
+
+ def is_mod_file (path: str) -> str:
+ if not os.path.isfile(path):
+ return None
+
+ try:
+ pos = path.rindex(".")
+ if path[pos + 1:].startswith("py"):
+ return os.path.basename(path[:pos])
+ except ValueError:
+ pass
+
+ for i in os.scandir(path):
+ if i.name.startswith("_"):
+ continue
+ elif is_mod_dir(i.path):
+ print(i.name)
+ self._walk_mods(i.path)
+ else:
+ name = is_mod_file(i.path)
+ if name:
+ print(name)
+
+ def do_cmd (self):
+ for i in importlib.util.find_spec("palhm.mod").submodule_search_locations:
+ self._walk_mods(i)
+
+ return 0
+
+ def print_help ():
+ print(
+"Usage: " + sys.executable + " -m palhm mods" + '''
+Prints the available modules to stdout.''')
+
+class BootReportCmd (Cmd):
+ def __init__ (self, *args, **kwargs):
+ pass
+
+ def do_cmd (self):
+ ProgConf.alloc_ctx()
+
+ if ProgConf.ctx.boot_report is None:
+ raise InvalidConfigError("'boot-report' not configured")
+
+ return ProgConf.ctx.boot_report.do_send(ProgConf.ctx)
+
+ def print_help ():
+ print(
+"Usage: " + sys.executable + " -m palhm boot-report" + '''
+Send mail of boot report to recipients configured.''')
+
+class HelpCmd (Cmd):
+ def __init__ (self, optlist, args):
+ self.optlist = optlist
+ self.args = args
+
+ def do_cmd (self):
+ if len(self.args) >= 2:
+ if not args[0] in CmdMap:
+ err_unknown_cmd()
+ else:
+ CmdMap[self.args[0]].print_help()
+ else:
+ HelpCmd.print_help()
+
+ return 0
+
+ def print_help ():
+ print(
+"Usage: " + sys.executable + " -m palhm [options] CMD [command options ...]" + '''
+Options:
+ -q Set the verbosity level to 0(CRITIAL). Overrides config
+ -v Increase the verbosity level by 1. Overrides config
+ -f FILE Load config from FILE instead of the hard-coded default
+Config: ''' + ProgConf.conf + '''
+Commands:
+ run run a task
+ config load config and print the contents
+ help [CMD] print this message and exit normally if [CMD] is not specified.
+ Print usage of [CMD] otherwise
+ mods list available modules
+ boot-report mail boot report''')
+
+ return 0
+
+CmdMap = {
+ "config": ConfigCmd,
+ "run": RunCmd,
+ "help": HelpCmd,
+ "mods": ModsCmd,
+ "boot-report": BootReportCmd
+}
+
+optlist, args = getopt(sys.argv[1:], "qvf:")
+optkset = set()
+for p in optlist:
+ optkset.add(p[0])
+
+if "-v" in optkset and "-q" in optkset:
+ sys.stderr.write("Options -v and -q cannot not used together.\n")
+ exit(2)
+
+if not args or not args[0] in CmdMap:
+ err_unknown_cmd()
+
+for p in optlist:
+ if p[0] == "-q": ProgConf.override_vl = logging.ERROR
+ elif p[0] == "-v":
+ if ProgConf.override_vl is None:
+ ProgConf.override_vl = palhm.DEFAULT.VL.value - 10
+ else:
+ ProgConf.override_vl -= 10
+ elif p[0] == "-f": ProgConf.conf = p[1]
+
+logging.basicConfig(format = "%(name)s %(message)s")
+
+ProgConf.cmd = CmdMap[args[0]](optlist, args)
+del args[0]
+exit(ProgConf.cmd.do_cmd())
diff --git a/src/palhm/conf/crontab b/src/palhm/conf/crontab
index d0eeda6..9e59a16 100644
--- a/src/palhm/conf/crontab
+++ b/src/palhm/conf/crontab
@@ -1,6 +1,6 @@
# PALHM will produce stderr on exception. Mail the output to root
MAILTO="root"
# Run default task every Sunday at midnight
-0 0 * * sun root /var/lib/PALHM/src/palhm.py -q run
+0 0 * * sun root python -m palhm -q run
# Check dnssec validity every hour
-# 0 * * * * root systemd-run -qP -p User=palhm -p Nice=15 -p ProtectSystem=strict -p ReadOnlyPaths=/ -p PrivateDevices=true --wait /var/lib/PALHM/src/palhm.py -q run check-dnssec
+# 0 * * * * root systemd-run -qP -p User=palhm -p Nice=15 -p ProtectSystem=strict -p ReadOnlyPaths=/ -p PrivateDevices=true --wait python -m palhm -q run check-dnssec
diff --git a/src/palhm/conf/palhm-boot-report.service b/src/palhm/conf/palhm-boot-report.service
index 0b4ba67..16a7c6d 100644
--- a/src/palhm/conf/palhm-boot-report.service
+++ b/src/palhm/conf/palhm-boot-report.service
@@ -4,7 +4,7 @@ After=postfix.service sendmail.service exim.service dovecot.service network-onli
[Service]
Type=oneshot
-ExecStart=/var/lib/PALHM/src/palhm.py -q boot-report
+ExecStart=/usr/bin/python -m palhm -q boot-report
Nice=10
[Install]