fix issues with apu

rework: create utils.BoxInfo
This commit is contained in:
2024-03-20 08:47:47 +01:00
parent 9c9719bff4
commit 7f661bb314
4 changed files with 92 additions and 120 deletions

View File

@ -1,10 +1,10 @@
[NETWORK] [NETWORK]
; please refer to README.md for help ; please refer to README.md for help
eth0=192.168.127.254 eth0=wan
eth1=192.168.2.1 eth1=192.168.2.2
eth2=192.168.3.5 eth2=192.168.3.3
eth3=dhcp eth3=192.168.127.254
[ROUTER] [ROUTER]
; please refer to README.md for help ; please refer to README.md for help
5900=192.168.2.1 3001=192.168.127.254:3001

View File

@ -20,33 +20,26 @@ from glob import glob
from ipaddress import IPv4Interface from ipaddress import IPv4Interface
from configparser import ConfigParser from configparser import ConfigParser
from os.path import join, getmtime, exists, basename from os.path import join, getmtime, exists, basename
from utils import get_config from utils import BoxInfo
if os.geteuid() != 0: if os.geteuid() != 0:
exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.") exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.")
TOOLS = '/home/l_samenv/boxtools' TOOLS = BoxInfo.TOOLS
BOX_TYPES = {
'00:0d:b9': 'apu', # bare apu or control box
'b8:27:eb': 'cm3', # iono pi
'd8:3a:dd': 'cm4', # dual-eth-rpi
}
more_info = False more_info = False
DEL = '__to_delete__' DEL = '__to_delete__'
CFGPATH = f'{TOOLS}/cfg/%s_%6.6x.cfg'
STARTUP_TEXT = f'{TOOLS}/startup_display.txt' STARTUP_TEXT = f'{TOOLS}/startup_display.txt'
COMMENT = "; please refer to README.md for help" COMMENT = "; please refer to README.md for help"
CONFIG_TEMPLATE = f"""[NETWORK] CONFIG_TEMPLATE = f"""[NETWORK]
{COMMENT} {COMMENT}
eth0=192.168.127.254 eth0=wan
eth1=192.168.2.2 eth1=192.168.2.2
eth2=192.168.3.3 eth2=192.168.3.3
eth3=dhcp eth3=192.168.127.254
[ROUTER] [ROUTER]
{COMMENT} {COMMENT}
@ -115,32 +108,10 @@ pip_requirements = {
} }
net_addr = {} # dict <if name> of <ethernet address> box = BoxInfo()
dhcp_server_cfg = [] # configuration for dhcp dhcp_server_cfg = []
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
}
change_if_names = False TO_SYSTEM = f'{TOOLS}/to_{box.typ}'
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}'
if not exists(TO_SYSTEM): if not exists(TO_SYSTEM):
TO_SYSTEM = f'{TOOLS}/to_system' TO_SYSTEM = f'{TOOLS}/to_system'
os.chdir(TO_SYSTEM) os.chdir(TO_SYSTEM)
@ -172,8 +143,8 @@ def router(**opts):
def display_update(cfg): def display_update(cfg):
text = '\n'.join(cfg.get('startup_text', '').split('|')[:3]) text = '\n'.join(cfg.get('startup_text', '').split('|')[:3])
text = text.replace('HOST', main_info['hostname']) \ text = text.replace('HOST', box.hostname) \
.replace('ADDR', main_info['addr']) + '\n' .replace('ADDR', box.get_macaddr()) + '\n'
if write_when_new(STARTUP_TEXT, text): if write_when_new(STARTUP_TEXT, text):
print('change startup text') print('change startup text')
if doit: if doit:
@ -285,10 +256,10 @@ def create_if(name, cfg):
if cfg == 'off': if cfg == 'off':
result = None result = None
elif cfg.startswith('wan') or cfg == 'dhcp': 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') raise ValueError('can not have more than one WAN/DHCP port')
main_info['mainif'] = name box.main_if = name
main_info['addr'] = net_addr[name]
# default: all <= 192.0.0.0 # default: all <= 192.0.0.0
# others have to be added explicitly # others have to be added explicitly
dhcp_server_cfg.append(('0.0.0.0/128.0.0.0', [])) dhcp_server_cfg.append(('0.0.0.0/128.0.0.0', []))
@ -407,68 +378,54 @@ class Do(Walker):
def handle_config(): def handle_config():
cfgfile = None
cfgfiles = []
dhcp_server_cfg.clear() dhcp_server_cfg.clear()
for file in glob(CFGPATH % ('*', boxid)): cfgfile = box.cfgfile
cfgfiles.append(file) newhostname = box.hostname
if boxtype == 'apu': if not cfgfile:
for i in [1, 2, 3]: template = CONFIG_TEMPLATE
bad = glob(CFGPATH % ('*', boxid+i)) if box.typ == 'apu':
if bad: # determine if display is present
print('cfg files found with bad apu id (use net addr of leftmost plug)') disp = serial.Serial('/dev/ttyS1', baudrate=115200, timeout=1)
print(bad) disp.write(b'\x1b\x1b\x01\xf3')
return False display_available = disp.read(8)[0:4] == b'\x1b\x1b\x05\xf3'
newhostname = main_info['hostname'] if display_available:
if not cfgfiles: typ = 'controlbox'
# determine if display is present template = CONTROLBOX_TEMPLATE
disp = serial.Serial('/dev/ttyS1', baudrate=115200, timeout=1) else:
disp.write(b'\x1b\x1b\x01\xf3') typ = 'bare apu'
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
else: else:
# rightmost interface typ = 'rpi'
# main_info['mainif'] = sorted_if[-1] print('no cfg file found for this', typ,
typ = 'bare apu' f'with id {box.id:06x} (hostname={box.hostname})')
template = CONFIG_TEMPLATE
print('no cfg file found for this', typ, f'with id {boxid:%6.6x} (hostname={hostname})')
newhostname = input('enter host name: ') newhostname = input('enter host name: ')
if not newhostname: if not newhostname:
print('no hostname given') print('no hostname given')
return False return False
cfgfile = CFGPATH % (newhostname, boxid) cfgfile = BoxInfo.CFGPATH % (newhostname, box.id)
with open(cfgfile, 'w') as f: with open(cfgfile, 'w') as f:
f.write(template) f.write(template)
elif len(cfgfiles) > 1: if cfgfile != BoxInfo.CFGPATH % (newhostname, box.id):
print('ERROR: ambiguous cfg files: %s' % ', '.join(cfgfiles))
else:
cfgfile = cfgfiles[0]
if cfgfile != CFGPATH % (newhostname, boxid):
if cfgfile: if cfgfile:
newhostname = basename(cfgfile).rpartition('_')[0] newhostname = basename(cfgfile).rpartition('_')[0]
if doit: if doit:
os.system('sh sethostname.sh') os.system('sh sethostname.sh')
else: else:
if cfgfile: 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 show.dirty = True
main_info['hostname'] = newhostname config = box.read_config()
box.hostname = newhostname
if cfgfile is None: if cfgfile is None:
return False return False
to_start = {} to_start = {}
ifname = '' ifname = ''
config = get_config()
try: try:
netcfg = config['NETWORK'] netcfg = config['NETWORK']
for name in netcfg: 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') print(f'{name} is not a valid network interface name')
raise RuntimeError('network interface name system does not match') 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 = create_if(ifname, netcfg.get(ifname, 'off'))
# content = '\n'.join('%s=%s' % kv for kv in content.items()) # content = '\n'.join('%s=%s' % kv for kv in content.items())
todo = write_when_new(f'/etc/network/interfaces.d/{ifname}', content) todo = write_when_new(f'/etc/network/interfaces.d/{ifname}', content)
@ -517,7 +474,7 @@ def handle_config():
#with open(cfgfile, 'w') as f: #with open(cfgfile, 'w') as f:
# f.write('\n'.join(content)) # f.write('\n'.join(content))
except Exception as e: 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 raise
return False return False
@ -573,14 +530,15 @@ def handle_config():
unix_cmd('systemctl restart %s' % service) unix_cmd('systemctl restart %s' % service)
unix_cmd('systemctl enable %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: with open('/etc/default/grub') as f:
content = f.read() content = f.read()
prev = 'GRUB_CMDLINE_LINUX_DEFAULT="quiet"' prev = 'GRUB_CMDLINE_LINUX_DEFAULT="quiet"'
repl = 'GRUB_CMDLINE_LINUX_DEFAULT="quiet net.ifnames=0"' repl = 'GRUB_CMDLINE_LINUX_DEFAULT="quiet net.ifnames=0"'
newcontent = content.replace(prev, repl) newcontent = content.replace(prev, repl)
if repl not in newcontent: if repl not in content:
write_when_new('/etc/default/grub', newcontent) write_when_new('/etc/default/grub', newcontent)
unix_cmd('update-grub') unix_cmd('update-grub')

View File

@ -1,13 +1,13 @@
ETHNAME=$(cat /sys/class/net/eth0/address) ETHNAME=$(cat /sys/class/net/eth0/address)
ETHNAME=${ETHNAME//:/} ETHNAME=${ETHNAME//:/}
APUID=${ETHNAME: -6} BOXID=${ETHNAME: -6}
FOUND="$(shopt -s nullglob; echo /home/l_samenv/boxtools/cfg/*_$APUID.cfg)" FOUND="$(shopt -s nullglob; echo /home/l_samenv/boxtools/cfg/*_$BOXID.cfg)"
if [ -z "$FOUND" ]; then if [ -z "$FOUND" ]; then
HOSTNAME=apu$APUID HOSTNAME=box$BOXID
else else
FOUND=$(basename ${FOUND[0]}) # remove directory part FOUND=$(basename ${FOUND[0]}) # remove directory part
HOSTNAME=${FOUND%%.*} # remove extension HOSTNAME=${FOUND%%.*} # remove extension
if [ $HOSTNAME != "apu$APUID" ]; then if [ $HOSTNAME != "apu$BOXID" ]; then
HOSTNAME=${HOSTNAME%_*} HOSTNAME=${HOSTNAME%_*}
fi fi
echo "hostname $HOSTNAME" echo "hostname $HOSTNAME"

View File

@ -14,37 +14,51 @@ else:
os.system(cmd) os.system(cmd)
def get_config(section=None): class BoxInfo:
"""get content of box configuration 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 def __init__(self):
:return: configuration as dict self.id = None
""" self.typ = None
parser = ConfigParser() self.hostname = socket.gethostname()
cfgfiles = glob('/home/l_samenv/boxtools/cfg/%s_*.cfg' % socket.gethostname()) self.change_if_names = False
if not cfgfiles: self.cfgfile = None
# look by id self.config = None
boxid = None self.macaddr = {}
for ifname in ('enp1s0', 'eth0'): self.main_if = None
try: for ifdev in glob('/sys/class/net/*/address'):
with open(f'/sys/class/net/{ifname}/address') as f: ifname = ifdev.split('/')[-2]
addr = f.read().strip().lower() if ifname == 'lo': # do not consider loopback interface
except FileNotFoundError:
continue continue
boxid = int(''.join(addr.split(':')[-3:]), 16) & 0xffffff if ifname.startswith('enp'):
break self.change_if_names = True
if boxid: ifname = f'eth{int(ifname[3]) - 1}'
cfgfiles = glob('/home/l_samenv/boxtools/cfg/*_%6.6x.cfg' % boxid) print(ifname)
if len(cfgfiles) != 1: with open(ifdev) as f:
raise ValueError('there must be one and only one single cfgfile %r' % cfgfiles) self.macaddr[ifname] = addr = f.read().strip().lower()
parser.read(cfgfiles[0]) if ifname in ('eth0', 'enp1s0'):
try: self.id = int(''.join(addr.split(':')[-3:]), 16) & 0xffffff
result = {k: dict(parser[k]) for k in ([section] if section else parser.sections())} self.typ = self.BOX_TYPES.get(addr[:8])
except KeyError: self.main_if = ifname
return {}
if section: def get_macaddr(self):
return result[section] return self.macaddr.get(self.main_if)
return result
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): def gethostthread(ip, event, result):