From e245cb68de0a832ef233a623a2bf392fef782bd0 Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 26 Jun 2019 11:17:56 +0200 Subject: Quality of Life changes + add help output if script arguments are invalid + add custom exit codes to highlight invalid arguments * update code comments * major README rework --- README.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++--------------- main.py | 28 ++++++++++++++++------ 2 files changed, 82 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 2d2ff33..63dea51 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,74 @@ ## Blacklist import script -### ejabberd config -To use this script properly, a separate `yml` file is necessary, as the script will overwrite the file. To further -protect the config the `allow_only` sections defines only `acl` rules. +### installation +Python 3 virtual environment +```bash +virtualenv -p python3 +pip install -r requirements.txt +``` + +### usage main.py +``` +usage: main.py [-h] [-o OUTFILE] [-dr] + +optional arguments: + -h, --help show this help message and exit + -o OUTFILE, --outfile OUTFILE + set path to output file + -dr, --dry-run perform a dry run +``` + +#### without any arguments +Running `main.py` without any arguments, will cause the script to update the local cache and the corresponding `.etag` +file. After that the script will output the error and the help message to stderr, before exiting with error code `2` + +```bash +no outfile assigned +... +``` + +#### dry run +If `main.py` is executed with `-dr` or `--dry-run` as argument the output would look like this. The script will check + the blacklist repository and output everything to stdout without touching any system file. +```bash +$ /path/blacklist_import: python main.py --dr +outfile selected: None +acl: + spamblacklist: + server: + - "a-server.tld" + - "b-server.tld" +``` + +#### --outfile /path/ +Run without the `--dry-run` argument and a valid outfile, the script will return nothing and do its thing. + +##### *ejabberd reload_config* +The ejabberd instance will be reloaded automatically, but only if changes in the `outfile` occured. + +## configuration +### ejabberd +To use this script properly, you need to add this line to the `ACL` section of your ejabberd instance. Furthermore a +separate `yml` file is necessary, as the script will overwrite the file. To further protect the integrity of your +config the `allow_only` sections defines only `acl` rules. ```yaml "/etc/ejabberd/blacklist.yml": allow_only: - acl ``` -### script configuration - +### script itself The script is meant to be used in an automatic fashion. -Arguments: -- -dr , --dry-run : perform a dry run. `blacklist.txt` and `.etag` are written but no yaml file is overwritten. -- -o , --outfile filepath : set path to output file +For example the script could be executed every day at 00:01 to automatically add and remove affected servers from the + blacklist file. -The dry-run argument will output the file path, if set, in addition to the contents of the yaml file which would have be produced. +```cron +# jabber blacklist update -### script workflow -1. check if `.etag` file is present -2. HEAD request - 2.1 requests etag and `.etag` are equal - ​ 2.1.1 use local `blacklist.txt` file - 2.2 requests etag and `.etag` are _not_ equal - ​ 2.2.1 request new `blacklist.txt` - ​ 2.2.2 save new `.etag` and `blacklist.txt` file -3. process `blacklist.txt` and parse output file +# with virtualenv enabled +1 0 * * * /path/blacklist_import/venv/bin/python /path/blacklist_import/main.py -o /etc/ejabberd/config/blacklist.yml +# without virtualenv +1 0 * * * python3 /path/blacklist_import/main.py -o /etc/ejabberd/config/blacklist.yml +``` diff --git a/main.py b/main.py index 481f266..a8be9b8 100644 --- a/main.py +++ b/main.py @@ -67,11 +67,11 @@ class BlacklistImporter: # first check if blacklist is updated self.request() + # only output the selected outfile if self.dryrun: - # only output the selected software and outfile print("outfile selected: %s" % self.outfile) - # select ejabberd processing + # blacklist processing self.process() # reload config if changes have been applied @@ -86,7 +86,7 @@ class BlacklistImporter: # init new YAML variable local_file = YAML(typ="safe") - # prevent None errors + # None catch if self.outfile is not None: # prevent FileNotFoundError on first run or file missing if os.path.isfile(self.outfile): @@ -110,14 +110,28 @@ class BlacklistImporter: yml.indent(offset=2) yml.default_flow_style = False + # if dry-run true print expected content if self.dryrun: - # if dryrun true print expected content yml.dump(remote_file, sys.stdout) + # only if the local_file and remote_file are unequal write new file elif local_file != remote_file: - self.change = True - # only if the local_file and remote_file are unequal write new file - yml.dump(remote_file, open(self.outfile, "w")) + + # prevent FileNotFoundError if self.outfile is not assigned + if self.outfile is None: + print("no outfile assigned", file=sys.stderr) + print(parser.format_help(), file=sys.stderr) + sys.exit(2) + + # proceed to update the defined outfile + elif self.outfile is not None: + self.change = True + yml.dump(remote_file, open(self.outfile, "w")) + + # if that's impossible break and display help message + else: + print(parser.format_help(), file=sys.stderr) + sys.exit(1) if __name__ == "__main__": -- cgit v1.2.3-18-g5258