#!/usr/bin/env python # # vim:ts=2:et:sw=2:ai # Wireless Leiden configuration generator, based on yaml files' # # XXX: This should be rewritten to make use of the ipaddr.py library. # # Sample apache configuration (mind the AcceptPathInfo!) # ScriptAlias /wleiden/config /usr/local/www/genesis/tools/gformat.py # # Allow from all # AcceptPathInfo On # # # Rick van der Zwet # # Hack to make the script directory is also threated as a module search path. import sys import os import re sys.path.append(os.path.dirname(__file__)) import cgi import cgitb import copy import glob import socket import string import subprocess import time import rdnap import make_network_kml from pprint import pprint from collections import defaultdict try: import yaml except ImportError, e: print e print "[ERROR] Please install the python-yaml or devel/py-yaml package" exit(1) try: from yaml import CLoader as Loader from yaml import CDumper as Dumper except ImportError: from yaml import Loader, Dumper from jinja2 import Environment, Template def yesorno(value): return "YES" if bool(value) else "NO" env = Environment() env.filters['yesorno'] = yesorno def render_template(datadump, template): result = env.from_string(template).render(datadump) # Make it look pretty to the naked eye, as jinja templates are not so # friendly when it comes to whitespace formatting ## Remove extra whitespace at end of line lstrip() style. result = re.sub(r'\n[\ ]+','\n', result) ## Include only a single newline between an definition and a comment result = re.sub(r'(["\'])\n+([a-z]|\n#\n)',r'\1\n\2', result) ## Remove extra newlines after single comment result = re.sub(r'(#\n)\n+([a-z])',r'\1\2', result) return result import logging logging.basicConfig(format='# %(levelname)s: %(message)s' ) logger = logging.getLogger() logger.setLevel(logging.DEBUG) if os.environ.has_key('CONFIGROOT'): NODE_DIR = os.environ['CONFIGROOT'] else: NODE_DIR = os.path.abspath(os.path.dirname(__file__)) + '/../nodes' __version__ = '$Id: gformat.py 10597 2012-04-26 18:14:50Z rick $' files = [ 'authorized_keys', 'dnsmasq.conf', 'dhcpd.conf', 'rc.conf.local', 'resolv.conf', 'motd', 'wleiden.yaml', ] # Global variables uses OK = 10 DOWN = 20 UNKNOWN = 90 def get_yaml(item): """ Get configuration yaml for 'item'""" gfile = os.path.join(NODE_DIR,item,'wleiden.yaml') # Use some boring defaults datadump = { 'service_proxy_normal' : False, 'service_proxy_ileiden' : False, 'service_accesspoint' : True } f = open(gfile, 'r') datadump.update(yaml.load(f,Loader=Loader)) f.close() # Preformat certain needed variables for formatting and push those into special object datadump['autogen_iface_keys'] = get_interface_keys(datadump) wlan_count=0 for key in datadump['autogen_iface_keys']: if datadump[key]['type'] in ['11a', '11b', '11g', 'wireless']: datadump[key]['autogen_ifname'] = 'wlan%i' % wlan_count wlan_count += 1 else: datadump[key]['autogen_ifname'] = datadump[key]['interface'].split(':')[0] dhcp_interfaces = [datadump[key]['autogen_ifname'] for key in datadump['autogen_iface_keys'] if datadump[key]['dhcp']] datadump['autogen_dhcp_interfaces'] = ','.join(dhcp_interfaces) datadump['autogen_item'] = item datadump['autogen_realname'] = get_realname(datadump) datadump['autogen_domain'] = datadump['domain'] if datadump.has_key('domain') else 'wleiden.net.' datadump['autogen_fqdn'] = datadump['autogen_realname'] + '.' + datadump['autogen_domain'] return datadump def store_yaml(datadump, header=False): """ Store configuration yaml for 'item'""" item = datadump['autogen_item'] gfile = os.path.join(NODE_DIR,item,'wleiden.yaml') f = open(gfile, 'w') f.write(generate_wleiden_yaml(datadump, header)) f.close() def make_relations(): """ Process _ALL_ yaml files to get connection relations """ errors = "" poel = defaultdict(list) for host in get_hostlist(): try: datadump = get_yaml(host) for iface_key in datadump['autogen_iface_keys']: l = datadump[iface_key]['ip'] addr, mask = l.split('/') # Not parsing of these folks please if not valid_addr(addr): continue addr = parseaddr(addr) mask = int(mask) network = addr & ~((1 << (32 - mask)) - 1) poel[network] += [(host,datadump[iface_key])] except (KeyError, ValueError), e: errors += "[FOUT] in '%s' interface '%s'" % (host,iface_key) errors += e continue return (poel, errors) def get_proxylist(): """Get all available proxies proxyX sorting based on X number""" proxylist = sorted([os.path.basename(x) for x in glob.glob("%s/proxy*" % NODE_DIR)], key=lambda name: int(''.join([c for c in name if c in string.digits])), cmp=lambda x,y: x - y) + sorted([os.path.basename(x) for x in glob.glob("%s/Proxy*" % NODE_DIR)]) return proxylist def get_hybridlist(): """Get all available hybrid nodes/proxies""" hybridlist = sorted([os.path.basename(x) for x in glob.glob("%s/Hybrid*" % NODE_DIR)]) return hybridlist def valid_addr(addr): """ Show which address is valid in which are not """ return str(addr).startswith('172.') def get_nodelist(): """ Get all available nodes - sorted """ nodelist = sorted([os.path.basename(x) for x in glob.glob("%s/CNode*" % NODE_DIR)]) return nodelist def get_hostlist(): """ Combined hosts and proxy list""" return get_nodelist() + get_proxylist() + get_hybridlist() def angle_between_points(lat1,lat2,long1,long2): """ Return Angle in radians between two GPS coordinates See: http://stackoverflow.com/questions/3809179/angle-between-2-gps-coordinates """ dy = lat2 - lat1 dx = math.cos(math.pi/180*lat1)*(long2 - long1) angle = math.atan2(dy,dx) return angle def angle_to_cd(angle): """ Return Dutch Cardinal Direction estimation in 'one digit' of radian angle """ # For easy conversion get positive degree degrees = math.degrees(angle) if degrees < 0: 360 - abs(degrees) # Numbers can be confusing calculate from the 4 main directions p = 22.5 if degrees < p: return "n" elif degrees < (90 - p): return "no" elif degrees < (90 + p): return "o" elif degrees < (180 - p): return "zo" elif degrees < (180 + p): return "z" elif degrees < (270 - p): return "zw" elif degrees < (270 + p): return "w" elif degrees < (360 - p): return "nw" else: return "n" def generate_title(nodelist): """ Main overview page """ items = {'root' : "." } output = """ Wireless leiden Configurator - GFormat
""" % items for node in nodelist: items['node'] = node output += '' % items for config in files: items['config'] = config output += '' % items output += "" output += """

Wireless Leiden Configurator

%(node)s%(config)s

%s
""" % __version__ return output def generate_node(node): """ Print overview of all files available for node """ return "\n".join(files) def generate_node_overview(host): """ Print overview of all files available for node """ datadump = get_yaml(host) params = { 'host' : host } output = "Back to overview
" output += "

Available files:

" # Generate and connection listing output += "

Connected To:

" output += "

MOTD details:

" + generate_motd(datadump) + "
" output += "
Back to overview" return output def generate_header(ctag="#"): return """\ %(ctag)s %(ctag)s DO NOT EDIT - Automatically generated by 'gformat' %(ctag)s Generated at %(date)s by %(host)s %(ctag)s """ % { 'ctag' : ctag, 'date' : time.ctime(), 'host' : socket.gethostname() } def parseaddr(s): """ Process IPv4 CIDR notation addr to a (binary) number """ f = s.split('.') return (long(f[0]) << 24L) + \ (long(f[1]) << 16L) + \ (long(f[2]) << 8L) + \ long(f[3]) def showaddr(a): """ Display IPv4 addr in (dotted) CIDR notation """ return "%d.%d.%d.%d" % ((a >> 24) & 0xff, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff) def is_member(ip, mask, canidate): """ Return True if canidate is part of ip/mask block""" ip_addr = gformat.parseaddr(ip) ip_canidate = gformat.parseaddr(canidate) mask = int(mask) ip_addr = ip_addr & ~((1 << (32 - mask)) - 1) ip_canidate = ip_canidate & ~((1 << (32 - mask)) - 1) return ip_addr == ip_canidate def cidr2netmask(netmask): """ Given a 'netmask' return corresponding CIDR """ return showaddr(0xffffffff & (0xffffffff << (32 - int(netmask)))) def get_network(addr, mask): return showaddr(parseaddr(addr) & ~((1 << (32 - int(mask))) - 1)) def generate_dhcpd_conf(datadump): """ Generate config file '/usr/local/etc/dhcpd.conf """ output = generate_header() output += Template("""\ # option definitions common to all supported networks... option domain-name "dhcp.{{ autogen_fqdn }}"; default-lease-time 600; max-lease-time 7200; # Use this to enble / disable dynamic dns updates globally. #ddns-update-style none; # If this DHCP server is the official DHCP server for the local # network, the authoritative directive should be uncommented. authoritative; # Use this to send dhcp log messages to a different log file (you also # have to hack syslog.conf to complete the redirection). log-facility local7; # # Interface definitions # \n""").render(datadump) for iface_key in datadump['autogen_iface_keys']: if not datadump[iface_key].has_key('comment'): datadump[iface_key]['comment'] = None output += "## %(interface)s - %(desc)s - %(comment)s\n" % datadump[iface_key] (addr, mask) = datadump[iface_key]['ip'].split('/') datadump[iface_key]['addr'] = addr datadump[iface_key]['netmask'] = cidr2netmask(mask) datadump[iface_key]['subnet'] = get_network(addr, mask) try: (dhcp_start, dhcp_stop) = datadump[iface_key]['dhcp'].split('-') except (AttributeError, ValueError): output += "subnet %(subnet)s netmask %(netmask)s {\n ### not autoritive\n}\n\n" % datadump[iface_key] continue dhcp_part = ".".join(addr.split('.')[0:3]) datadump[iface_key]['dhcp_start'] = dhcp_part + "." + dhcp_start datadump[iface_key]['dhcp_stop'] = dhcp_part + "." + dhcp_stop output += """\ subnet %(subnet)s netmask %(netmask)s { range %(dhcp_start)s %(dhcp_stop)s; option routers %(addr)s; option domain-name-servers %(addr)s; } \n""" % datadump[iface_key] return output def generate_dnsmasq_conf(datadump): """ Generate configuration file '/usr/local/etc/dnsmasq.conf' """ output = generate_header() output += Template("""\ # DHCP server options dhcp-authoritative dhcp-fqdn domain=dhcp.{{ autogen_fqdn }} domain-needed expand-hosts log-async=100 # Low memory footprint cache-size=10000 \n""").render(datadump) for iface_key in datadump['autogen_iface_keys']: if not datadump[iface_key].has_key('comment'): datadump[iface_key]['comment'] = None output += "## %(interface)s - %(desc)s - %(comment)s\n" % datadump[iface_key] try: (dhcp_start, dhcp_stop) = datadump[iface_key]['dhcp'].split('-') (ip, cidr) = datadump[iface_key]['ip'].split('/') datadump[iface_key]['netmask'] = cidr2netmask(cidr) except (AttributeError, ValueError): output += "# not autoritive\n\n" continue dhcp_part = ".".join(ip.split('.')[0:3]) datadump[iface_key]['dhcp_start'] = dhcp_part + "." + dhcp_start datadump[iface_key]['dhcp_stop'] = dhcp_part + "." + dhcp_stop output += "dhcp-range=%(interface)s,%(dhcp_start)s,%(dhcp_stop)s,%(netmask)s,24h\n\n" % datadump[iface_key] return output def generate_rc_conf_local(datadump): """ Generate configuration file '/etc/rc.conf.local' """ if not datadump.has_key('ileiden'): datadump['autogen_ileiden_enable'] = False else: datadump['autogen_ileiden_enable'] = datadump['ileiden'] datadump['autogen_ileiden_enable'] = switchFormat(datadump['autogen_ileiden_enable']) ileiden_proxies = [] normal_proxies = [] for proxy in get_proxylist(): proxydump = get_yaml(proxy) if proxydump['ileiden']: ileiden_proxies.append(proxydump) else: normal_proxies.append(proxydump) for host in get_hybridlist(): hostdump = get_yaml(host) if hostdump['service_proxy_ileiden']: ileiden_proxies.append(hostdump) if hostdump['service_proxy_normal']: normal_proxies.append(hostdump) datadump['autogen_ileiden_proxies'] = ileiden_proxies datadump['autogen_normal_proxies'] = normal_proxies datadump['autogen_ileiden_proxies_ips'] = ','.join([x['masterip'] for x in ileiden_proxies]) datadump['autogen_ileiden_proxies_names'] = ','.join([x['autogen_item'] for x in ileiden_proxies]) datadump['autogen_normal_proxies_ips'] = ','.join([x['masterip'] for x in normal_proxies]) datadump['autogen_normal_proxies_names'] = ','.join([x['autogen_item'] for x in normal_proxies]) output = generate_header("#"); output += render_template(datadump, """\ hostname='{{ autogen_fqdn }}' location='{{ location }}' nodetype="{{ nodetype }}" # # Configured listings # captive_portal_whitelist="" {% if nodetype == "Proxy" %} # # Proxy Configuration # {% if gateway -%} defaultrouter="{{ gateway }}" {% else -%} #defaultrouter="NOTSET" {% endif -%} internalif="{{ internalif }}" ileiden_enable="{{ autogen_ileiden_enable }}" gateway_enable="{{ autogen_ileiden_enable }}" pf_enable="yes" pf_rules="/etc/pf.conf" {% if autogen_ileiden_enable -%} pf_flags="-D ext_if={{ externalif }} -D int_if={{ internalif }} -D publicnat={80,443}" lvrouted_enable="{{ autogen_ileiden_enable }}" lvrouted_flags="-u -s s00p3rs3kr3t -m 28" {% else -%} pf_flags="-D ext_if={{ externalif }} -D int_if={{ internalif }} -D publicnat={0}" {% endif -%} {% if internalroute -%} static_routes="wleiden" route_wleiden="-net 172.16.0.0/12 {{ internalroute }}" {% endif -%} {% elif nodetype == "Hybrid" %} # # Hybrid Configuration # list_ileiden_proxies=`cat <> DeviceB (.3) --- SlaveB (.4) sn = lambda x: re.sub(r'(?i)^cnode','',x) # Automatic naming convention of interlinks namely 2 + remote.lower() for (key,value) in pool.iteritems(): # Make sure they are sorted from low-ip to high-ip value = sorted(value, key=lambda x: parseaddr(x[2])) if len(value) == 1: (iface_name, fqdn, ip) = value[0] wleiden_zone["2unused-%s.%s" % (iface_name, fqdn)] = ip # Device DNS names if 'cnode' in fqdn.lower(): wleiden_zone["d-at-%s.%s" % (iface_name, fqdn)] = showaddr(parseaddr(ip) + 1) wleiden_cname["d-at-%s.%s" % (iface_name,sn(fqdn))] = "d-at-%s.%s" % (iface_name, fqdn) elif len(value) == 2: (a_iface_name, a_fqdn, a_ip) = value[0] (b_iface_name, b_fqdn, b_ip) = value[1] wleiden_zone["2%s.%s" % (b_fqdn,a_fqdn)] = a_ip wleiden_zone["2%s.%s" % (a_fqdn,b_fqdn)] = b_ip # Device DNS names if 'cnode' in a_fqdn.lower() and 'cnode' in b_fqdn.lower(): wleiden_zone["d-at-%s.%s" % (a_iface_name, a_fqdn)] = showaddr(parseaddr(a_ip) + 1) wleiden_zone["d-at-%s.%s" % (b_iface_name, b_fqdn)] = showaddr(parseaddr(b_ip) - 1) wleiden_cname["d-at-%s.%s" % (a_iface_name,sn(a_fqdn))] = "d-at-%s.%s" % (a_iface_name, a_fqdn) wleiden_cname["d-at-%s.%s" % (b_iface_name,sn(b_fqdn))] = "d-at-%s.%s" % (b_iface_name, b_fqdn) wleiden_cname["d2%s.%s" % (sn(b_fqdn),sn(a_fqdn))] = "d-at-%s.%s" % (a_iface_name, a_fqdn) wleiden_cname["d2%s.%s" % (sn(a_fqdn),sn(b_fqdn))] = "d-at-%s.%s" % (b_iface_name, b_fqdn) else: pool_members = [k[1] for k in value] for item in value: (iface_name, fqdn, ip) = item pool_name = "2pool-" + showaddr(key).replace('.','-') + "-" + pool_to_name(fqdn,pool_members) wleiden_zone["%s.%s" % (pool_name, fqdn)] = ip # Include static DNS entries # XXX: Should they override the autogenerated results? # XXX: Convert input to yaml more useable. # Format: ##; this is a comment ## roomburgh=CNodeRoomburgh1 ## apkerk1.CNodeVosko=172.17.176.8 ;this as well dns = yaml.load(open(os.path.join(NODE_DIR,'../dns/staticDNS.yaml'),'r')) # Hack to allow special entries, for development wleiden_raw = dns['raw'] del dns['raw'] for comment, block in dns.iteritems(): for k,v in block.iteritems(): if valid_addr(v): wleiden_zone[k] = v else: wleiden_cname[k] = v details = dict() # 24 updates a day allowed details['serial'] = time.strftime('%Y%m%d%H') if external: dns_masters = ['siteview.wirelessleiden.nl', 'ns1.vanderzwet.net'] else: dns_masters = ['sunny.wleiden.net'] details['master'] = dns_masters[0] details['ns_servers'] = '\n'.join(['\tNS\t%s.' % x for x in dns_masters]) dns_header = ''' $TTL 3h %(zone)s. SOA %(master)s. beheer.lijst.wirelessleiden.nl. ( %(serial)s 1d 12h 1w 3h ) ; Serial, Refresh, Retry, Expire, Neg. cache TTL %(ns_servers)s \n''' if not os.path.isdir(output_dir): os.makedirs(output_dir) details['zone'] = 'wleiden.net' f = open(os.path.join(output_dir,"db." + details['zone']), "w") f.write(dns_header % details) for host,ip in wleiden_zone.iteritems(): if valid_addr(ip): f.write("%s.wleiden.net. IN A %s \n" % (host.lower(), ip)) for source,dest in wleiden_cname.iteritems(): f.write("%s.wleiden.net. IN CNAME %s.wleiden.net.\n" % (source.lower(), dest.lower())) for source, dest in wleiden_raw.iteritems(): f.write("%s.wleiden.net. %s\n" % (source, dest)) f.close() # Create whole bunch of specific sub arpa zones. To keep it compliant for s in range(16,32): details['zone'] = '%i.172.in-addr.arpa' % s f = open(os.path.join(output_dir,"db." + details['zone']), "w") f.write(dns_header % details) #XXX: Not effient, fix to proper data structure and do checks at other # stages for host,ip in wleiden_zone.iteritems(): if valid_addr(ip): if int(ip.split('.')[1]) == s: rev_ip = '.'.join(reversed(ip.split('.'))) f.write("%s.in-addr.arpa. IN PTR %s.wleiden.net.\n" % (rev_ip.lower(), host.lower())) f.close() def usage(): print """Usage: %(prog)s Argument: \tstandalone [port] = Run configurator webserver [8000] \tdns [outputdir] = Generate BIND compliant zone files in dns [./dns] \tfull-export = Generate yaml export script for heatmap. \tstatic [outputdir] = Generate all config files and store on disk \t with format .//%%NODE%%/%%FILE%% [./static] \ttest = Receive output of CGI script. \tlist = List systems which have certain status Arguments: \t = NodeName (example: HybridRick) \t = %(files)s \t = all|up|down|planned \t = systems|nodes|proxies NOTE FOR DEVELOPERS; you can test your changes like this: BEFORE any changes in this code: $ ./gformat.py static /tmp/pre AFTER the changes: $ ./gformat.py static /tmp/post VIEW differences and VERIFY all are OK: $ diff -urI 'Generated' -r /tmp/pre /tmp/post """ % { 'prog' : sys.argv[0], 'files' : '|'.join(files) } exit(0) def is_text_request(): """ Find out whether we are calling from the CLI or any text based CLI utility """ try: return os.environ['HTTP_USER_AGENT'].split()[0] in ['curl', 'fetch', 'wget'] except KeyError: return True def switchFormat(setting): if setting: return "YES" else: return "NO" def main(): """Hard working sub""" # Allow easy hacking using the CLI if not os.environ.has_key('PATH_INFO'): if len(sys.argv) < 2: usage() if sys.argv[1] == "standalone": import SocketServer import CGIHTTPServer # Hop to the right working directory. os.chdir(os.path.dirname(__file__)) try: PORT = int(sys.argv[2]) except (IndexError,ValueError): PORT = 8000 class MyCGIHTTPRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler): """ Serve this CGI from the root of the webserver """ def is_cgi(self): if "favicon" in self.path: return False self.cgi_info = (os.path.basename(__file__), self.path) self.path = '' return True handler = MyCGIHTTPRequestHandler SocketServer.TCPServer.allow_reuse_address = True httpd = SocketServer.TCPServer(("", PORT), handler) httpd.server_name = 'localhost' httpd.server_port = PORT logger.info("serving at port %s", PORT) try: httpd.serve_forever() except KeyboardInterrupt: httpd.shutdown() logger.info("All done goodbye") elif sys.argv[1] == "test": os.environ['PATH_INFO'] = "/".join(sys.argv[2:]) os.environ['SCRIPT_NAME'] = __file__ process_cgi_request() elif sys.argv[1] == "static": items = dict() items['output_dir'] = sys.argv[2] if len(sys.argv) > 2 else "./static" for node in get_hostlist(): items['node'] = node items['wdir'] = "%(output_dir)s/%(node)s" % items if not os.path.isdir(items['wdir']): os.makedirs(items['wdir']) datadump = get_yaml(node) for config in files: items['config'] = config logger.info("## Generating %(node)s %(config)s" % items) f = open("%(wdir)s/%(config)s" % items, "w") f.write(generate_config(node, config, datadump)) f.close() elif sys.argv[1] == "wind-export": items = dict() for node in get_hostlist(): datadump = get_yaml(node) sql = """INSERT IGNORE INTO nodes (name, name_ns, longitude, latitude) VALUES ('%(nodename)s', '%(nodename)s', %(latitude)s, %(longitude)s);""" % datadump; sql = """INSERT IGNORE INTO users_nodes (user_id, node_id, owner) VALUES ( (SELECT id FROM users WHERE username = 'rvdzwet'), (SELECT id FROM nodes WHERE name = '%(nodename)s'), 'Y');""" % datadump #for config in files: # items['config'] = config # print "## Generating %(node)s %(config)s" % items # f = open("%(wdir)s/%(config)s" % items, "w") # f.write(generate_config(node, config, datadump)) # f.close() for node in get_hostlist(): datadump = get_yaml(node) for iface_key in sorted([elem for elem in datadump.keys() if elem.startswith('iface_')]): ifacedump = datadump[iface_key] if ifacedump.has_key('mode') and ifacedump['mode'] == 'ap-wds': ifacedump['nodename'] = datadump['nodename'] if not ifacedump.has_key('channel') or not ifacedump['channel']: ifacedump['channel'] = 0 sql = """INSERT INTO links (node_id, type, ssid, protocol, channel, status) VALUES ((SELECT id FROM nodes WHERE name = '%(nodename)s'), 'ap', '%(ssid)s', 'IEEE 802.11b', %(channel)s, 'active');""" % ifacedump elif sys.argv[1] == "full-export": hosts = {} for node in get_hostlist(): datadump = get_yaml(node) hosts[datadump['nodename']] = datadump print yaml.dump(hosts) elif sys.argv[1] == "dns": make_dns(sys.argv[2] if len(sys.argv) > 2 else 'dns', 'external' in sys.argv) elif sys.argv[1] == "cleanup": # First generate all datadumps datadumps = dict() for host in get_hostlist(): logger.info("# Processing: %s", host) # Set some boring default values datadump = { 'board' : 'UNKNOWN' } datadump.update(get_yaml(host)) datadumps[datadump['autogen_realname']] = datadump for host,datadump in datadumps.iteritems(): # Convert all yes and no to boolean values def fix_boolean(dump): for key in dump.keys(): if type(dump[key]) == dict: dump[key] = fix_boolean(dump[key]) elif str(dump[key]).lower() in ["yes", "true"]: dump[key] = True elif str(dump[key]).lower() in ["no", "false"]: # Compass richting no (Noord Oost) is valid input if key != "compass": dump[key] = False return dump datadump = fix_boolean(datadump) if datadump['rdnap_x'] and datadump['rdnap_y']: datadump['latitude'], datadump['longitude'] = rdnap.rd2etrs(datadump['rdnap_x'], datadump['rdnap_y']) elif datadump['latitude'] and datadump['longitude']: datadump['rdnap_x'], datadump['rdnap_y'] = rdnap.etrs2rd(datadump['latitude'], datadump['longitude']) if datadump['nodename'].startswith('Proxy'): datadump['nodename'] = datadump['nodename'].lower() for iface_key in datadump['autogen_iface_keys']: # Wireless Leiden SSID have an consistent lowercase/uppercase if datadump[iface_key].has_key('ssid'): ssid = datadump[iface_key]['ssid'] prefix = 'ap-WirelessLeiden-' if ssid.lower().startswith(prefix.lower()): datadump[iface_key]['ssid'] = prefix + ssid[len(prefix)].upper() + ssid[len(prefix) + 1:] if datadump[iface_key].has_key('ns_ip') and not datadump[iface_key].has_key('mode'): datadump[iface_key]['mode'] = 'autogen-FIXME' if not datadump[iface_key].has_key('desc'): datadump[iface_key]['desc'] = 'autogen-FIXME' store_yaml(datadump) elif sys.argv[1] == "list": if len(sys.argv) < 4 or not sys.argv[2] in ["up", "down", "planned", "all"]: usage() if sys.argv[3] == "nodes": systems = get_nodelist() elif sys.argv[3] == "proxies": systems = get_proxylist() elif sys.argv[3] == "systems": systems = get_hostlist() else: usage() for system in systems: datadump = get_yaml(system) if sys.argv[2] == "all": print system elif datadump['status'] == sys.argv[2]: print system elif sys.argv[1] == "create": if sys.argv[2] == "network.kml": print make_network_kml.make_graph() else: usage() usage() else: # Do not enable debugging for config requests as it highly clutters the output if not is_text_request(): cgitb.enable() process_cgi_request() if __name__ == "__main__": main()