#!/usr/bin/env python # vim:ts=2:et:sw=2:ai ''' CLI interface which configures and makes new nodes with the most commonly used commands. Rick van der Zwet ''' import getrange import gformat import os import readline import sys import textwrap DEBUG = "-g" in sys.argv # Global variable, because this is dirty code. datadump = None def rlprompt(prompt, prefill=''): ''' Get line with some boring default ''' prompt = "%s [%s]: " % (prompt, prefill) if DEBUG: print(prompt) return prefill return input(prompt) or prefill def rlinput(prompt, prefill=''): ''' Get line with some editable boring default ''' if DEBUG: print("%s [%s]:" % (prompt, prefill)) return prefill readline.set_startup_hook(lambda: readline.insert_text(prefill)) try: return input(prompt + ": ") finally: readline.set_startup_hook() def rlinput_float(prompt, prefill=0): while True: try: prefill = rlinput(prompt, str(prefill)) return float(prefill) except ValueError: print("Invalid Number!") pass def rlinput_choices(prompt, choices, prefill=''): if DEBUG: print('%s [%s]:' % (prompt, prefill)) return prefill while True: filtered_choices = sorted(list(set([x for x in choices if (str(prefill).lower() in str(x).lower())]))) if len(filtered_choices) == 1: return filtered_choices[0] elif len(filtered_choices) == 0: filtered_choices = choices prefill = rlinput(prompt + ' ' + str(filtered_choices), prefill) if prefill in prompt: return prefill def newNode(): datadump = { 'nodename' : "New", 'location' : "1234 AB, Leiden", 'nodetype' : "Hybrid", 'latitude' : "52.", 'longitude' : "4.", } datadump['nodename'] = rlprompt("Nodename", datadump['nodename']) datadump['location'] = rlprompt("Location", datadump['location']) datadump['nodetype'] = rlprompt("Nodetype", datadump['nodetype']) datadump['latitude'] = rlinput_float("Latitude", datadump['latitude']) datadump['longitude'] = rlinput_float("Longitude", datadump['longitude']) datadump['autogen_item'] = datadump['nodetype'] + datadump['nodename'] print("Generating the Master IP range...") master_network = getrange.get_ranges(False, 24, 1)[0] master_ip = getrange.showaddr(master_network + 1) datadump['masterip'] = master_ip if os.path.exists(datadump['autogen_item']): print("Warning Node does already exists, overwriting!") # Secret global state variable newNode.if_nr = 0 def next_ifnr(): if_nr = newNode.if_nr newNode.if_nr = newNode.if_nr + 1 return if_nr def new_access_point(link_type='wireless'): if link_type == 'wireless': ifname = rlinput("Interface name", "ath0") datadump['iface_' + ifname] = { 'ip' : rlinput(" - IP", master_ip + "/26"), 'dhcp' : rlinput(" - DHCP range", "10-60"), 'ssid' : rlinput(" - SSID", "ap-WirelessLeiden-" + datadump['nodename']), 'mode' : 'ap', 'type' : '11b', 'comment' : rlinput(" - Comment", "Omni voor de Buurt"), 'sdesc': rlinput(" - Short Description", "2buurt"), 'channel' : rlprompt(" - Channel", "10"), 'status' : 'up', } elif link_type == 'wired': if_nr = next_ifnr() ifname = rlinput("Interface name", "vr%i" % if_nr) netmask = int(rlinput_float("Netmask", 24)) print("Generating the Master IP range...") link_network = getrange.get_ranges(False, netmask, 1, use_history=True)[0] datadump['iface_' + ifname] = { 'ip' : rlinput(" - IP", gformat.showaddr(link_network + 1) + "/" + str(netmask)), 'dhcp' : rlinput(" - DHCP range", "10-60"), 'ssid' : rlinput(" - SSID", "ap-WirelessLeiden-" + datadump['nodename'] + '-' + ifname), 'comment' : rlinput(" - Comment", "Omni voor de Buurt"), 'type' : 'eth', 'sdesc': rlinput(" - Short Description", "2buurt"), 'channel' : rlprompt(" - Channel", "10"), 'status' : 'up', 'mode': "ap", 'bridge_type': rlinput(' - Bridge Type', 'NanoStation5M'), 'ns_ip': rlinput(" - NS IP", getrange.showaddr(link_network + 2) + "/" + str(netmask)), 'ns_mac': rlinput(" - NS MAC", "00:27:22:"), } def new_interlink(link_type='wireless', link_mode='station'): if_nr = next_ifnr() remote_datadump = None ifname = rlinput("Interface name", "vr%i" % if_nr) netmask = 28 if link_mode == 'station': remote = rlinput_choices("Create interlink with (remote host)", gformat.get_hostlist(),'Hybrid') remote_datadump = gformat.get_yaml(remote) print("Available remote interfaces:") if_choices = [] for ifkey in remote_datadump['autogen_iface_keys']: ifdump = remote_datadump[ifkey] # Could only do this if all meta information is correct #if link_type == 'wireless' and link_mode == 'station': # basedump = remote_datadump['iface_' + ifdump['autogen_ifbase']] # if not basedump.has_key('mode') or basedump['mode'] != 'ap-wds': # continue if_choices.append(ifdump['autogen_ifbase']) print(" - %4s" % ifdump['autogen_ifbase'], '- %20s' % ifdump['ip'], '- %30s' % ifdump['comment'], end=' ') if 'ssid' in ifdump: print('-', ifdump['ssid']) else: print('') remote_ifname = rlinput_choices("Remote interface", if_choices) remote_ifdump = remote_datadump['iface_%s' % remote_ifname] #make_alias = rlprompt("Create Alias", "no") == "yes" link_network = gformat.network(remote_ifdump['ip']) elif link_mode == 'master': remote = rlinput("Interlink is planned for (remote host)", 'Unused%s' % if_nr) print("Generating the Interlink IP range...") link_network = getrange.get_ranges(True, netmask, 1, use_history=True)[0] print("Using Network %s/%s" % (gformat.showaddr(link_network), netmask)) # XXX: Create remote linking # XXX: This does not handle IP pools # Common part datadump['iface_%s' % ifname] = { 'comment': rlinput(" - Comment", "Link naar " + remote), 'sdesc': rlinput(" - Short Description", "2" + remote), 'type': "eth", 'status': 'up', 'dhcp': 'False', } if link_type == 'wireless': compass = rlprompt("Compass direction", 'n') datadump['iface_%s' % ifname].update({ 'ns_mac': rlinput(" - NS MAC", "00:27:22:"), 'bridge_type': rlinput(' - Bridge Type', 'NanoStation5M'), 'compass': compass, }) if link_mode == 'master': datadump['iface_%s' % ifname].update({ 'ssid': rlinput(" - SSID", 'il-%s.%s.wleiden.net' % (compass, datadump['nodename'])), 'ip': rlinput(" - IP", getrange.showaddr(link_network + 1) + "/" + str(netmask)), 'ns_ip': rlinput(" - NS IP", getrange.showaddr(link_network + 2) + "/" + str(netmask)), 'mode': "ap-wds", }) elif link_mode == 'station': datadump['iface_%s' % ifname].update({ 'ssid': rlinput(" - SSID", remote_ifdump['ssid']), 'ip': rlinput(" - IP", getrange.showaddr(link_network + 3) + "/" + str(netmask)), 'ns_ip': rlinput(" - NS IP", getrange.showaddr(link_network + 4) + "/" + str(netmask)), 'mode': "station-wds", }) remote_datadump['iface_' + remote_ifname]['comment'] = 'Link naar %s' % datadump['nodename'] remote_datadump['iface_' + remote_ifname]['sdesc'] = '2%s' % datadump['nodename'] elif link_type == 'wired': if link_mode == 'master': datadump['iface_%s' % ifname].update({ 'ip': rlinput(" - IP", getrange.showaddr(link_network + 1) + "/" + str(netmask)), }) elif link_mode == 'station': datadump['iface_%s' % ifname].update({ 'ip': rlinput(" - IP", getrange.showaddr(link_network + 2) + "/" + str(netmask)), }) remote_datadump['iface_' + remote_ifname]['comment'] = 'Link naar %s' % datadump['nodename'] remote_datadump['iface_' + remote_ifname]['sdesc'] = '2%s' % datadump['nodename'] if remote_datadump: # Alter remote side of interfaces gformat.store_yaml(remote_datadump) def printMenu(): print('''\ ========================================== Create new Interface: === Public Access Points === 1) Accesspoint (ath0) 2) Accesspoint with Bridge/Switch (vr0) === Wireless Interlinks === 3) Wireless Bridge (master) 4) Wireless Bridge (station) === Multiple Nodes at location === 5) Ethernet Cross-connect (master) 6) Ethernet Cross-connect (station) === When finished adding links === 9) Finish and Save ========================================== ''') choice = '' while True: printMenu() choice = int(rlprompt("Choice", choice)) if choice == 1: new_access_point('wireless') elif choice == 2: new_access_point('wired') elif choice == 3: new_interlink('wired', 'master') elif choice == 4: new_interlink('wired', 'station') elif choice == 5: new_interlink('wireless', 'master') elif choice == 6: new_interlink('wireless', 'station') elif choice == 9: break else: print("Invalid choice!") # Output final result print(datadump) if not os.path.exists(datadump['autogen_item']): os.mkdir(datadump['autogen_item']) gformat.store_yaml(datadump) print("Please check changes and commit result") def interactive(): def printMenu(): print(textwrap.dedent('''\ ========================================== Node File Editor by Rick van der Zwet 1) New Node 9) Quit ========================================== ''')) printMenu() choice = 1 while choice != 9: choice = int(rlprompt("Choice", choice)) if choice == 9: break elif choice == 1: newNode() printMenu() sys.exit(1) else: print("Invalid choice!") if __name__ == '__main__': if len(sys.argv) > 1 and sys.argv[1] == 'interactive': interactive() elif len(sys.argv) > 3 and sys.argv[1] == 'edit': host = sys.argv[2] datadump = gformat.get_yaml(host) for kv in sys.argv[3:]: key, value = kv.split('=') datadump[key] = value gformat.store_yaml(datadump) else: print("Usage: %s ")