diff --git a/cfg/flame-mag_591fac.cfg b/cfg/linse-apu4_591fac.cfg similarity index 51% rename from cfg/flame-mag_591fac.cfg rename to cfg/linse-apu4_591fac.cfg index 987a381..a157bab 100644 --- a/cfg/flame-mag_591fac.cfg +++ b/cfg/linse-apu4_591fac.cfg @@ -1,10 +1,10 @@ [NETWORK] ; please refer to README.md for help -eth0=192.168.127.254 -eth1=192.168.2.1 -eth2=192.168.3.5 -eth3=dhcp +eth0=wan +eth1=192.168.2.2 +eth2=192.168.3.3 +eth3=192.168.127.254 [ROUTER] ; please refer to README.md for help -5900=192.168.2.1 +3001=192.168.127.254:3001 diff --git a/install.py b/install.py index 410564a..be15441 100755 --- a/install.py +++ b/install.py @@ -20,33 +20,26 @@ from glob import glob from ipaddress import IPv4Interface from configparser import ConfigParser from os.path import join, getmtime, exists, basename -from utils import get_config +from utils import BoxInfo if os.geteuid() != 0: exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.") -TOOLS = '/home/l_samenv/boxtools' - -BOX_TYPES = { - '00:0d:b9': 'apu', # bare apu or control box - 'b8:27:eb': 'cm3', # iono pi - 'd8:3a:dd': 'cm4', # dual-eth-rpi -} +TOOLS = BoxInfo.TOOLS more_info = False DEL = '__to_delete__' -CFGPATH = f'{TOOLS}/cfg/%s_%6.6x.cfg' STARTUP_TEXT = f'{TOOLS}/startup_display.txt' COMMENT = "; please refer to README.md for help" CONFIG_TEMPLATE = f"""[NETWORK] {COMMENT} -eth0=192.168.127.254 +eth0=wan eth1=192.168.2.2 eth2=192.168.3.3 -eth3=dhcp +eth3=192.168.127.254 [ROUTER] {COMMENT} @@ -115,32 +108,10 @@ pip_requirements = { } -net_addr = {} # dict of -dhcp_server_cfg = [] # configuration for dhcp -main_info = { # info to be determined depending on cfg - 'ifname': '', # name of interface of wan (dhcp) port - 'addr': '', # addr of wan port - 'hostname': socket.gethostname() # effective or given host name -} +box = BoxInfo() +dhcp_server_cfg = [] -change_if_names = False - -for netif in os.scandir('/sys/class/net'): - if netif.name != 'lo': # do not consider loopback interface - with open(os.path.join(netif.path, 'address')) as f: - addr = f.read().strip().lower() - n = netif.name - if n.startswith('enp'): - change_if_names = True - n = f'eth{int(n[3]) - 1}' - net_addr[n] = addr - -sorted_if = sorted(net_addr) -boxaddr = net_addr[sorted_if[0]] -boxid = int(''.join(boxaddr.split(':')[-3:]), 16) & 0xffffff -boxtype = BOX_TYPES.get(boxaddr[:8]) - -TO_SYSTEM = f'{TOOLS}/to_{boxtype}' +TO_SYSTEM = f'{TOOLS}/to_{box.typ}' if not exists(TO_SYSTEM): TO_SYSTEM = f'{TOOLS}/to_system' os.chdir(TO_SYSTEM) @@ -172,8 +143,8 @@ def router(**opts): def display_update(cfg): text = '\n'.join(cfg.get('startup_text', '').split('|')[:3]) - text = text.replace('HOST', main_info['hostname']) \ - .replace('ADDR', main_info['addr']) + '\n' + text = text.replace('HOST', box.hostname) \ + .replace('ADDR', box.get_macaddr()) + '\n' if write_when_new(STARTUP_TEXT, text): print('change startup text') if doit: @@ -285,10 +256,10 @@ def create_if(name, cfg): if cfg == 'off': result = None elif cfg.startswith('wan') or cfg == 'dhcp': - if main_info.get('mainif', name) != name: + if box.main_if != name: + print(box.main_if, name) raise ValueError('can not have more than one WAN/DHCP port') - main_info['mainif'] = name - main_info['addr'] = net_addr[name] + box.main_if = name # default: all <= 192.0.0.0 # others have to be added explicitly dhcp_server_cfg.append(('0.0.0.0/128.0.0.0', [])) @@ -407,68 +378,54 @@ class Do(Walker): def handle_config(): - cfgfile = None - cfgfiles = [] dhcp_server_cfg.clear() - for file in glob(CFGPATH % ('*', boxid)): - cfgfiles.append(file) - if boxtype == 'apu': - for i in [1, 2, 3]: - bad = glob(CFGPATH % ('*', boxid+i)) - if bad: - print('cfg files found with bad apu id (use net addr of leftmost plug)') - print(bad) - return False - newhostname = main_info['hostname'] - if not cfgfiles: - # determine if display is present - disp = serial.Serial('/dev/ttyS1', baudrate=115200, timeout=1) - disp.write(b'\x1b\x1b\x01\xf3') - display_available = disp.read(8)[0:4] == b'\x1b\x1b\x05\xf3' - if display_available: - # leftmost interface labelled 'eth0' - # main_info['mainif'] = sorted_if[0] - typ = 'controlbox' - template = CONTROLBOX_TEMPLATE + cfgfile = box.cfgfile + newhostname = box.hostname + if not cfgfile: + template = CONFIG_TEMPLATE + if box.typ == 'apu': + # determine if display is present + disp = serial.Serial('/dev/ttyS1', baudrate=115200, timeout=1) + disp.write(b'\x1b\x1b\x01\xf3') + display_available = disp.read(8)[0:4] == b'\x1b\x1b\x05\xf3' + if display_available: + typ = 'controlbox' + template = CONTROLBOX_TEMPLATE + else: + typ = 'bare apu' else: - # rightmost interface - # main_info['mainif'] = sorted_if[-1] - typ = 'bare apu' - template = CONFIG_TEMPLATE - print('no cfg file found for this', typ, f'with id {boxid:%6.6x} (hostname={hostname})') + typ = 'rpi' + print('no cfg file found for this', typ, + f'with id {box.id:06x} (hostname={box.hostname})') newhostname = input('enter host name: ') if not newhostname: print('no hostname given') return False - cfgfile = CFGPATH % (newhostname, boxid) + cfgfile = BoxInfo.CFGPATH % (newhostname, box.id) with open(cfgfile, 'w') as f: f.write(template) - elif len(cfgfiles) > 1: - print('ERROR: ambiguous cfg files: %s' % ', '.join(cfgfiles)) - else: - cfgfile = cfgfiles[0] - if cfgfile != CFGPATH % (newhostname, boxid): + if cfgfile != BoxInfo.CFGPATH % (newhostname, box.id): if cfgfile: newhostname = basename(cfgfile).rpartition('_')[0] if doit: os.system('sh sethostname.sh') else: if cfgfile: - print('replace host name %r by %r' % (main_info['hostname'], newhostname)) + print('replace host name %r by %r' % (box.hostname, newhostname)) show.dirty = True - main_info['hostname'] = newhostname + config = box.read_config() + box.hostname = newhostname if cfgfile is None: return False to_start = {} ifname = '' - config = get_config() try: netcfg = config['NETWORK'] for name in netcfg: - if name not in net_addr: + if name not in box.macaddr: print(f'{name} is not a valid network interface name') raise RuntimeError('network interface name system does not match') - for ifname in net_addr: + for ifname in box.macaddr: content = create_if(ifname, netcfg.get(ifname, 'off')) # content = '\n'.join('%s=%s' % kv for kv in content.items()) todo = write_when_new(f'/etc/network/interfaces.d/{ifname}', content) @@ -517,7 +474,7 @@ def handle_config(): #with open(cfgfile, 'w') as f: # f.write('\n'.join(content)) except Exception as e: - print('ERROR: can not handle %s %s: %r' % (main_info['hostname'], ifname, e)) + print('ERROR: can not handle %s %s: %r' % (box.hostname, ifname, e)) raise return False @@ -573,14 +530,15 @@ def handle_config(): unix_cmd('systemctl restart %s' % service) unix_cmd('systemctl enable %s' % service) - if change_if_names: + if box.change_if_names: + print('interface name system has to be changed from enp*s0 to eth*') with open('/etc/default/grub') as f: content = f.read() prev = 'GRUB_CMDLINE_LINUX_DEFAULT="quiet"' repl = 'GRUB_CMDLINE_LINUX_DEFAULT="quiet net.ifnames=0"' newcontent = content.replace(prev, repl) - if repl not in newcontent: + if repl not in content: write_when_new('/etc/default/grub', newcontent) unix_cmd('update-grub') diff --git a/sethostname.sh b/sethostname.sh index 0338922..2c59b4b 100644 --- a/sethostname.sh +++ b/sethostname.sh @@ -1,13 +1,13 @@ ETHNAME=$(cat /sys/class/net/eth0/address) ETHNAME=${ETHNAME//:/} -APUID=${ETHNAME: -6} -FOUND="$(shopt -s nullglob; echo /home/l_samenv/boxtools/cfg/*_$APUID.cfg)" +BOXID=${ETHNAME: -6} +FOUND="$(shopt -s nullglob; echo /home/l_samenv/boxtools/cfg/*_$BOXID.cfg)" if [ -z "$FOUND" ]; then - HOSTNAME=apu$APUID + HOSTNAME=box$BOXID else FOUND=$(basename ${FOUND[0]}) # remove directory part HOSTNAME=${FOUND%%.*} # remove extension - if [ $HOSTNAME != "apu$APUID" ]; then + if [ $HOSTNAME != "apu$BOXID" ]; then HOSTNAME=${HOSTNAME%_*} fi echo "hostname $HOSTNAME" diff --git a/utils.py b/utils.py index 3303ee1..b865d29 100644 --- a/utils.py +++ b/utils.py @@ -14,37 +14,51 @@ else: os.system(cmd) -def get_config(section=None): - """get content of box configuration +class BoxInfo: + TOOLS = '/home/l_samenv/boxtools' + CFGPATH = f'{TOOLS}/cfg/%s_%06x.cfg' + BOX_TYPES = { + '00:0d:b9': 'apu', # bare apu or control box + 'b8:27:eb': 'cm3', # iono pi + 'd8:3a:dd': 'cm4', # dual-eth-rpi + } - :param section: if not None, return only given section - :return: configuration as dict - """ - parser = ConfigParser() - cfgfiles = glob('/home/l_samenv/boxtools/cfg/%s_*.cfg' % socket.gethostname()) - if not cfgfiles: - # look by id - boxid = None - for ifname in ('enp1s0', 'eth0'): - try: - with open(f'/sys/class/net/{ifname}/address') as f: - addr = f.read().strip().lower() - except FileNotFoundError: + def __init__(self): + self.id = None + self.typ = None + self.hostname = socket.gethostname() + self.change_if_names = False + self.cfgfile = None + self.config = None + self.macaddr = {} + self.main_if = None + for ifdev in glob('/sys/class/net/*/address'): + ifname = ifdev.split('/')[-2] + if ifname == 'lo': # do not consider loopback interface continue - boxid = int(''.join(addr.split(':')[-3:]), 16) & 0xffffff - break - if boxid: - cfgfiles = glob('/home/l_samenv/boxtools/cfg/*_%6.6x.cfg' % boxid) - if len(cfgfiles) != 1: - raise ValueError('there must be one and only one single cfgfile %r' % cfgfiles) - parser.read(cfgfiles[0]) - try: - result = {k: dict(parser[k]) for k in ([section] if section else parser.sections())} - except KeyError: - return {} - if section: - return result[section] - return result + if ifname.startswith('enp'): + self.change_if_names = True + ifname = f'eth{int(ifname[3]) - 1}' + print(ifname) + with open(ifdev) as f: + self.macaddr[ifname] = addr = f.read().strip().lower() + if ifname in ('eth0', 'enp1s0'): + self.id = int(''.join(addr.split(':')[-3:]), 16) & 0xffffff + self.typ = self.BOX_TYPES.get(addr[:8]) + self.main_if = ifname + + def get_macaddr(self): + return self.macaddr.get(self.main_if) + + def read_config(self): + cfgfiles = glob(self.CFGPATH % ('*', self.id)) + if len(cfgfiles) != 1: + raise ValueError('there must be one and only one single cfgfile %r' % cfgfiles) + if cfgfiles: + self.cfgfile = cfgfiles[0] + parser = ConfigParser() + parser.read(self.cfgfile) + return {k: dict(parser[k]) for k in parser.sections()} def gethostthread(ip, event, result):