From acee4362d4e8da9edd5bb1b3a63d9182325d4f5a Mon Sep 17 00:00:00 2001 From: "J. Burfeind" Date: Thu, 9 Apr 2020 10:52:36 +0200 Subject: [PATCH] [FEATURE] multidomain-domainnames (#59) * Implemented util.read_domainfile This reads a given json file containing a dict with bat_device names as keys and domain_names as values. * Provided an example domainfile. * Added a new parameter to spcify where to read the domainfile from. It's optional. * Altered the domain_code-provider in order to support domaincode-files. Given a dcf-path, the provider tries to return the domaincode related to a batadv_dev, like trier did earlier in their code. If it cannot find a match, it returns whatever was provided as 'domaincode' via '-n' in the commandline, which makes it effectively a default value for unkown domains and a nice fallback. * updated util.read_dumainfile removed unnecessary return variable Co-Authored-By: Martin Weinelt * updated domainfile example to reflect domaincodes * util: removed redundant line * README: add domain_code-file documentation * Fixed type in 'return', however it got there. * Added per batman iface domaincode overrides * readme: reflects per batinterface domaincode * domaincodefile: changed format to one-key-dict The file now holds a key called 'domaincodes' and below the assignments. This allows a transition from domaincodefile to configfile in the future, if wanted. Co-authored-by: Martin Weinelt --- README.md | 5 +++- domainfile.json.example | 20 ++++++++++++++++ providers/nodeinfo/system/domain_code.py | 9 +++++--- respondd.py | 29 +++++++++++++++++------- util.py | 15 ++++++++++++ 5 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 domainfile.json.example diff --git a/README.md b/README.md index 2a62f0d..83a39dc 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,10 @@ optional arguments: -b batman-adv interface to answer for (default: bat0). Specify once per domain -m mesh ipv4 address - -n Gateway domain_code for nodeinfo/system/domain_code + -n (default) domain code for system/domain_code + -c + domain_code.json path (if info is not in file, + fallback to -n's value) This is a possible configuration for a site with a single domain: diff --git a/domainfile.json.example b/domainfile.json.example new file mode 100644 index 0000000..27ddec9 --- /dev/null +++ b/domainfile.json.example @@ -0,0 +1,20 @@ +{ + "domaincodes": { + "bat0": "dom0", + "bat10": "dom10", + "bat11": "dom11", + "bat12": "dom12", + "bat13": "dom13", + "bat14": "dom14", + "bat15": "dom15", + "bat16": "dom16", + "bat17": "dom17", + "bat18": "dom18", + "bat19": "dom19", + "bat20": "dom20", + "bat21": "dom21", + "bat22": "dom22", + "bat23": "dom23", + "bat99": "dom99" + } +} diff --git a/providers/nodeinfo/system/domain_code.py b/providers/nodeinfo/system/domain_code.py index 31074ae..28b2181 100644 --- a/providers/nodeinfo/system/domain_code.py +++ b/providers/nodeinfo/system/domain_code.py @@ -2,7 +2,10 @@ class Source(providers.DataSource): def required_args(self): - return ['domain_code'] + return ['batadv_dev', 'domain_code', 'known_codes'] - def call(self, domain_code): - return domain_code + def call(self, batadv_dev, domain_code, known_codes): + try: + return known_codes[batadv_dev] + except KeyError: + return domain_code diff --git a/respondd.py b/respondd.py index d5bf4fc..e27ef05 100755 --- a/respondd.py +++ b/respondd.py @@ -56,7 +56,7 @@ def handle(self): if __name__ == "__main__": parser = argparse.ArgumentParser(usage=""" %(prog)s -h - %(prog)s [-p ] [-g ] [-i [%%]] [-i [%%] ..] [-d ] [-b [:] [-n ] ..]""") + %(prog)s [-p ] [-g ] [-i [%%]] [-i [%%] ..] [-d ] [-b [:][:] [-n ] [-c ] ..]""") parser.add_argument('-p', dest='port', default=1001, type=int, metavar='', help='port number to listen on (default 1001)') @@ -79,21 +79,34 @@ def handle(self): metavar='', help='mesh ipv4 address') parser.add_argument('-n', dest='domain_code', metavar='', - help='Domain Code for system/domain_code') + help='(default) domain code for system/domain_code') + parser.add_argument('-c', dest='domain_code_file', metavar='', + help='domain_code.json path (if info is not in file, fallback to -n\'s value)') args = parser.parse_args() + # Read domain-codes from file + known_codes = util.read_domainfile(args.domain_code_file) + # Extract batman interfaces from commandline parameters + # and overwrite domain-codes from file with commandline arguments batadv_mesh_ipv4_overrides = { } batadv_ifaces = [ ] for ifspec in args.batadv_ifaces: - iface, *mesh_ipv4 = ifspec.split(':') + iface, *left_over = ifspec.split(':') batadv_ifaces.append(iface) - if mesh_ipv4: - # mesh_ipv4 list is not empty, there is an override address - batadv_mesh_ipv4_overrides[iface] = mesh_ipv4[0] - - global_handler_env = { 'domain_code': args.domain_code, 'mesh_ipv4': args.mesh_ipv4 } + try: + # if left_over list is not empty, there is at least an override address + possible_override = left_over.pop(0) + # this clause is necessary in case one does not specify an ipv4 override, but a domain-code + if '' != possible_override: + batadv_mesh_ipv4_overrides[iface] = possible_override + # if left_over list is not empty, there is a domain_code + known_codes[iface] = left_over.pop(0) + except IndexError: + continue + + global_handler_env = { 'domain_code': args.domain_code, 'known_codes': known_codes, 'mesh_ipv4': args.mesh_ipv4 } metasocketserver.MetadataUDPServer.address_family = socket.AF_INET6 metasocketserver.MetadataUDPServer.allow_reuse_address = True diff --git a/util.py b/util.py index dcc6359..a8e386c 100644 --- a/util.py +++ b/util.py @@ -1,3 +1,4 @@ +import json import os def _file_name_filter(fname): @@ -72,3 +73,17 @@ def ifindex_to_batiface(if_index, batman_ifaces): if iface in batman_ifaces or iface == None: return iface return iface_match_recursive(iface, batman_ifaces) + +def read_domainfile(dcf_path): + """Read a json file which holds all currently known assignments of + bat interfaces to domains as a dictionary within a dict and below its key 'domaincodes' + and return it as python dict. + Return an empty dict, if the given path was None. + """ + if dcf_path is None: + return {} + with open(dcf_path, "r") as dc_file: + try: + return json.load(dc_file)["domaincodes"] + except KeyError: + return {}