From 58ba518baeb3bd8dbaa8a215bae902be6a36bed3 Mon Sep 17 00:00:00 2001 From: Lars Kiesow Date: Wed, 27 Sep 2023 18:24:25 +0200 Subject: [PATCH] Switch from argparse to click This patch switches from argparse to click for handling command line arguments in preparation to introducing multiple command line argument groups. This patch does not change the functionality. The CLI still only handles DNS modifications. But this is now in its own group and we can easily add another one, for example, to handle IP address registration. --- README.md | 17 +++++-- proteuscmd/__main__.py | 102 ++++++++++++++++++++++++++++------------- proteuscmd/api.py | 5 +- requirements.txt | 1 + 4 files changed, 87 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 6e5f34f..28bc541 100644 --- a/README.md +++ b/README.md @@ -36,25 +36,32 @@ This can be useful if, for example, all your domains also have an alternate doma ``` ❯ proteuscmd -usage: proteuscmd [-h] [--view {all,intern,extern}] {get,set,delete} domain [target] +Usage: python -m proteuscmd [OPTIONS] COMMAND [ARGS]... + +Options: + --help Show this message and exit. + +Commands: + dns Get information about or update DNS entries. + ip Register IP addresses. ``` Get information about a DNS record: ``` -❯ proteuscmd get lktest.uni-osnabrueck.de +❯ proteuscmd dns get lktest.uni-osnabrueck.de ``` Set an alias record: ``` -❯ proteuscmd set lktest.uni-osnabrueck.de vm123.rz.uni-osnabrueck.de +❯ proteuscmd dns set lktest.uni-osnabrueck.de vm123.rz.uni-osnabrueck.de ``` Set a host record: ``` -❯ proteuscmd set lktest.uni-osnabrueck.de 131.12.65.123 +❯ proteuscmd dns set lktest.uni-osnabrueck.de 131.12.65.123 ``` Delete a record: ``` -❯ proteuscmd delete lktest.uni-osnabrueck.de +❯ proteuscmd dns delete lktest.uni-osnabrueck.de ``` diff --git a/proteuscmd/__main__.py b/proteuscmd/__main__.py index 3ca408d..78db6b6 100644 --- a/proteuscmd/__main__.py +++ b/proteuscmd/__main__.py @@ -1,43 +1,83 @@ -import argparse +import click +import json +from functools import wraps from proteuscmd.config import proteus_from_config -__config = None +__views = click.Choice(('intern', 'extern', 'all'), case_sensitive=False) -def main(): - parser = argparse.ArgumentParser(description='Proteus DNS command line') - parser.add_argument('--view', - choices=('all', 'intern', 'extern'), - default='all', - help='View to operate on') - parser.add_argument('operation', - choices=('get', 'set', 'delete'), - help='Operation to perform on domain') - parser.add_argument('domain', - help='Domain to operate on') - parser.add_argument('target', - nargs='?', - help='Target of the DNS record') +def with_proteus(f): + '''Provide a Proteus client as first parameter of the wraped function. + Print the result if one exists. + ''' + @wraps(f) + def decorated(*args, **kwargs): + with proteus_from_config() as proteus: + data = f(proteus, *args, **kwargs) + if data: + print(json.dumps(data, indent=2)) + return decorated - args = parser.parse_args() - if args.operation == 'set' and not args.target: - parser.error("set requires a target.") +@click.group() +def cli(): + pass - # Interaction with Proteus - with proteus_from_config() as proteus: - views = proteus.get_requested_views(args.view) - for name, view in views: - print(name) - if args.operation == 'get': - print('\n'.join(proteus.get_record(view, args.domain))) - elif args.operation == 'set': - print(proteus.set_record(view, args.domain, args.target)) - elif args.operation == 'delete': - print(proteus.delete_record(view, args.domain)) +@cli.group() +def dns(): + '''Get information about or update DNS entries. + ''' + pass + + +@cli.group() +def ip(): + '''Register IP addresses. + Not implemented yet. + ''' + pass + + +@dns.command() +@click.option('--view', default='all', type=__views) +@click.argument('domain') +@with_proteus +def get(proteus, view, domain): + '''Get information about a DNS entry. + ''' + views = proteus.get_requested_views(view) + return {name: proteus.get_record(view, domain) for name, view in views} + + +@dns.command() +@click.option('--view', default='all', type=__views) +@click.argument('domain') +@click.argument('target') +@with_proteus +def set(proteus, view, domain, target): + '''Set DNS entry in Proteus + ''' + views = proteus.get_requested_views(view) + result = {} + for name, view in views: + proteus.set_record(view, domain, target) + result[name] = proteus.get_record(view, domain) + return result + + +@dns.command() +@click.option('--view', default='all', type=__views) +@click.argument('domain') +@with_proteus +def delete(proteus, view, domain): + '''Delete DNS record in Proteus + ''' + views = proteus.get_requested_views(view) + for name, view in views: + proteus.delete_record(view, domain) if __name__ == '__main__': - main() + cli() diff --git a/proteuscmd/api.py b/proteuscmd/api.py index 70bf247..6edfdfe 100644 --- a/proteuscmd/api.py +++ b/proteuscmd/api.py @@ -171,8 +171,9 @@ def get_record(self, view, domain): + self.get_entities_by_name(host, parent, 'AliasRecord') for record in data: properties = record['properties'].split('|') - return [prop for prop in filter(bool, properties)] - return [] + properties = [prop.split('=', 1) for prop in properties if prop] + return {prop[0]: prop[1] for prop in properties} + return {} def set_record(self, view, domain, target): diff --git a/requirements.txt b/requirements.txt index f229360..b070841 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ requests +Click