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
This commit is contained in:
nico 2019-06-26 11:17:56 +02:00
parent 59954bb21b
commit e245cb68de
Signed by: mightyBroccoli
GPG Key ID: EA7C31AAB1BDC1A2
2 changed files with 82 additions and 25 deletions

View File

@ -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
```

28
main.py
View File

@ -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__":