#!/usr/bin/env python # # vim:ts=2:et:sw=2:ai # Wireless Leiden configuration generator, based on yaml files' # Rick van der Zwet import cgi import glob import os import socket import string import subprocess import sys import time import yaml __version__ = '$Id: gformat.py 8242 2010-08-07 14:35:43Z rick $' files = [ 'authorized_keys', 'dnsmasq.conf', 'rc.conf.local', 'resolv.conf', 'wleiden.yaml' ] def print_title(): print "Title view" print nodelist def print_node(node): print "\n".join(files) 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): f = s.split('.') return (long(f[0]) << 24L) + \ (long(f[1]) << 16L) + \ (long(f[2]) << 8L) + \ long(f[3]) def showaddr(a): return "%d.%d.%d.%d" % ((a >> 24) & 0xff, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff) def netmask2subnet(netmask): return showaddr(0xffffffff & (0xffffffff << (32 - int(netmask)))) def generate_dnsmasq_conf(datadump): output = generate_header() output += """\ # DHCP server options dhcp-authoritative dhcp-fqdn domain=dhcp.%(nodename_lower)s.%(domain)s domain-needed expand-hosts # Low memory footprint cache-size=10000 \n""" % datadump for iface_key in datadump['iface_keys']: output += "## %(interface)s %(desc)s\n" % datadump[iface_key] try: (dhcp_start, dhcp_stop) = datadump[iface]['dhcp'].split('-') (ip, netmask) = datadump[iface_key]['ip'].split('/') datadump[iface_key]['subnet'] = netmask2subnet(netmask) except AttributeError: 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,%(subnet)s,24h\n\n" % datadump[iface_key] return output def generate_rc_conf_local(datadump): output = generate_header("#"); output += """\ hostname='%(nodetype)s%(nodename)s.%(domain)s' location='%(location)s' """ % datadump # TProxy configuration output += "\n" try: if datadump['tproxy']: output += """\ tproxy_enable='YES' tproxy_range='%(tproxy)s' """ % datadump except KeyError: output += "tproxy_enable='NO'\n" output += '\n' # lo0 configuration: # - 172.32.255.1/32 is the proxy.wleiden.net deflector # - masterip is special as it needs to be assigned to at # least one interface, so if not used assign to lo0 addrs_list = { 'lo0' : ["127.0.0.1/8", "172.31.255.1/32"] } iface_map = {'lo0' : 'lo0'} if not any([datadump[iface_key]['ip'].startswith(datadump['masterip']) \ for iface_key in datadump['iface_keys']]): lo0_addrs.append(datadump['masterip'] + "/32") wlan_count = 0 for iface_key in datadump['iface_keys']: ifacedump = datadump[iface_key] interface = ifacedump['interface'] # By default no special interface mapping iface_map[interface] = interface # Add interface IP to list if addrs_list.has_key(interface): addrs_list[interface].append(ifacedump['ip']) else: addrs_list[interface] = [ifacedump['ip']] # Alias only needs IP assignment for now, this might change if we # are going to use virtual accesspoints if "alias" in iface_key: continue # XXX: Might want to deduct type directly from interface name if ifacedump['type'] in ['11a', '11b', '11g', 'wireless']: # Create wlanX interface ifacedump['wlanif'] ="wlan%i" % wlan_count iface_map[interface] = ifacedump['wlanif'] wlan_count += 1 # Default to station (client) mode ifacedump['wlanmode'] = "sta" if ifacedump['mode'] in ['master']: ifacedump['wlanmode'] = "ap" # Default to 802.11b mode ifacedump['mode'] = '11b' if ifacedump['type'] in ['11a', '11b' '11g']: ifacedump['mode'] = ifacedump['type'] if not ifacedump.has_key('channel'): if ifacedump['type'] == '11a': ifacedump['channel'] = 36 else: ifacedump['channel'] = 1 # Allow special hacks at the back like wds and stuff if not ifacedump.has_key('extra'): ifacedump['extra'] = 'regdomain ETSI country NL' output += "wlans_%(interface)s='%(wlanif)s'\n" % ifacedump output += ("create_args_%(wlanif)s='wlanmode %(wlanmode)s mode " +\ "%(mode)s ssid %(ssid)s channel %(channel)s %(extra)s'\n") % ifacedump elif ifacedump['type'] in ['ethernet', 'eth']: # No special config needed besides IP pass else: assert False, "Unknown type " + ifacedump['type'] # Print IP address which needs to be assigned over here output += "\n" for iface,addrs in sorted(addrs_list.iteritems()): output += "ipv4_addrs_%s='%s'\n" % (iface_map[iface], " ".join(addrs)) return output def get_yaml(item): gfile = item + '/wleiden.yaml' gfile = 'test.yaml' f = open(gfile, 'r') datadump = yaml.load(f) f.close() return datadump def generate_resolv_conf(datadump): output = generate_header("#"); output += """\ search wleiden.net # Try local (cache) first nameserver 127.0.0.1 # Proxies are recursive nameservers # needs to be in resolv.conf for dnsmasq as well """ % datadump # proxyX sorting based on X number proxies = sorted(glob.glob("proxy*"), key=lambda name: int(''.join([c for c in name if c in string.digits])), cmp=lambda x,y: x - y) for proxy in proxies: proxy_ip = get_yaml(proxy)['masterip'] output += "nameserver %-15s # %s\n" % (proxy_ip, proxy) return output def generate_wleiden_yaml(datadump): """ Special formatting to ensure it is editable""" output = "# Genesis config yaml style\n" output += "#\n" iface_keys = [elem for elem in datadump.keys() if elem.startswith('iface_')] for key in sorted(set(datadump.keys()) - set(iface_keys)): output += "%s: %s\n" % (key, datadump[key]) output += "\n\n" for iface_key in sorted(iface_keys): output += "%s:\n" % iface_key output += yaml.dump(datadump[iface_key], default_flow_style=False) output += "\n\n" return output def print_config(node, config): try: # Load config file datadump = get_yaml(node) if config == 'wleiden.yaml': print generate_wleiden_yaml(datadump) return # Preformat certain needed variables for formatting if not datadump.has_key('domain'): datadump['domain'] = 'wleiden.net' datadump['nodename_lower'] = datadump['nodename'].lower() datadump['iface_keys'] = sorted([elem for elem in datadump.keys() if elem.startswith('iface_')]) if config == 'authorized_keys': f = open("global_keys", 'r') print f.read() f.close() elif config == 'dnsmasq.conf': print generate_dnsmasq_conf(datadump) elif config == 'rc.conf.local': print generate_rc_conf_local(datadump) elif config == 'resolv.conf': print generate_resolv_conf(datadump) else: assert False, "Config not found!" except IOError, e: print "[ERROR] Config file not found" nodelist = glob.glob("CNode*") form = cgi.FieldStorage() if form.getvalue("action") == "update": print "Refresh: 5; url=%s" % os.environ['SCRIPT_NAME'] print "Content-type:text/plain\r\n\r\n", print "[INFO] Updating subverion, please wait..." print subprocess.Popen(['svn', 'up', '/home/rvdzwet/wleiden/genesis/nodes'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0], print "[INFO] All done, redirecting in 5 seconds" sys.exit(0) print "Content-type:text/plain\r\n\r\n", uri = os.environ['PATH_INFO'].strip('/').split('/') if not uri[0]: print_title() elif len(uri) == 1: print_node(uri[0]) elif len(uri) == 2: print_config(uri[0], uri[1]) else: assert False, "Invalid option" sys.exit(0)