pythonargparsepython-daemon

python-daemon + argparse?


I made a script that takes a few arguments to run. Originally it could be run automatically with the argument 'auto', but I'm trying to daemonize it so it will run the run the script with the specified arguments as a daemon. The problem is that python-daemon and argparse don't seem to get along when it comes to deciding who parses what.

parser = argparse.ArgumentParser(usage='pyfilter.py <file> <options> <actions>')
parser.add_argument('file', help='blacklist file containing IPs', type=str)

subparsers = parser.add_subparsers(help='help', dest='action')

parser_update = subparsers.add_parser('update', help='update help')
parser_update.add_argument('-c', '--check', help="check IPs for abuse reports", dest="check", type=str, nargs=1)

parser_blacklist = subparsers.add_parser('blacklist', help='create iptables rules for malicious IPs specified'
                                                           'in the provided file')
parser_clear = subparsers.add_parser('clear', help='clear iptables')

parser_auto = subparsers.add_parser('auto', help='automatically run update and blacklist on a loop')
parser_auto.add_argument('-i', '--interval', help='specify the loop interval', dest='interval', type=int, nargs=1)
parser_auto.add_argument('-c', '--check', help="check IPs for abuse reports", dest="check", type=str, nargs=1)

parser.add_argument('-p', '--port', help='specify the port to block', type=int)
parser.add_argument('-v', '--verbose', help='write output to screen', nargs=1)
args = parser.parse_args()

. . .

class pyfilterDaemon():
    def __init__(self):
        self.stdin_path = '/dev/null'
        self.stdout_path = '/dev/tty'
        self.stderr_path = '/dev/tty'
        self.pidfile_path = '/tmp/pyfilter.pid'
        self.pidfile_timeout = 5

    def run(self):
        while True:
            update()
            blacklist()
            time.sleep(interval)
. . .

def main():
    #handle()
    d = pyfilterDaemon()
    daemon_runner = runner.DaemonRunner(d)
    daemon_runner.start()

Here's the commands I've tried to make this work:

root@tfof:~# ./pyfilter.py start
ERROR: File 'start' not found  # argparse parsed 'start' accidentally

root@tfof:~# ./pyfilter.py /etc/blacklist.lst -v yes auto
usage: checkfilter.py stop|restart|start  # now the argparse arguments are satisfied, but python-daemon is looking for its argument

root@tfof:~# ./pyfilter.py /etc/blacklist.lst -v yes auto start
usage: pyfilter.py <file> <options> <actions>
pyfilter.py: error: unrecognized arguments: start  # argparse is trying to parse 'start'

Would it be possible to pass off the 'start' argument to python-daemon or something? Or if I could just get rid of the argparsing it'd be fine, but the 'file' argument is a must.


Solution

  • Argparse takes arguments from sys.argv per default (see here). It is not surprising that the behaviour you see here is happening, as you just call the parse_args function with the default arguments. You can just pass whatever you want to parse to it, instead of sys.argv.

    See this question for an example.

    So consume whatever you need for python-deamon and then parse the remaining args with argparse.