Files
boxtools/install.py
LIN SE 4ce7c3a9d3 first version of dhcp settings
create /etc/dhcp/dhcpd.conf in install.py

+ new cfg file for apuslave3
2021-11-26 15:42:42 +01:00

272 lines
8.1 KiB
Python
Executable File

#!/usr/bin/python3
"""install.py
- copy files from to_system into system directories
- set host name / network settings from aputools/servercfg file
"""
import os
import filecmp
import shutil
from glob import glob
from ipaddress import IPv4Interface
from configparser import ConfigParser
from os.path import join, getmtime, exists, basename
os.chdir('/root/aputools/to_system')
DEL = '__to_delete__'
CFGPATH = '/root/aputools/servercfg/%s_%6.6x.cfg'
TEMPLATE_CFG = """[NETWORK]
enp1s0=192.168.127.1/24
enp2s0=192.168.2.1/24
enp3s0=192.168.3.1/24
enp4s0=dhcp
[ROUTER]
3001=192.168.127.254:3001
"""
DHCP_HEADER = """
default-lease-time 600;
max-lease-time 7200;
authoritative;
"""
DHCP_ITEM = """
subnet %s netmask %s {
option routers %s;
option subnet-mask %s;
range %s %s;
}
"""
def write_when_new(filename, content, doit):
if not content.endswith('\n'):
content += '\n'
with open(filename) as fil:
old = fil.read()
if old == content:
return False
if doit:
with open(filename, 'w') as fil:
fil.write(content)
else:
print('===')
print(old)
print('---')
print(content)
print('===')
return True
def create_if(name, cfg, mac):
result = dict(
TYPE='Ethernet',
NAME=name,
DEVICE=name,
BOOTPROTO='none',
ONBOOT='yes',
PROXY_METHOD='none',
BROWSER_ONLY='no',
IPV4_FAILURE_FATAL='yes',
IPV6INIT='no')
if cfg == 'off':
result['ONBOOT']='no'
elif cfg == 'dhcp':
result['BOOTPROTO']='dhcp'
else:
error = None
cfgdict = {'own': cfg, 'prefix': '', 'other': ''}
if ':' in cfg:
for cfgitem in cfg.split(','):
k, _, v = cfgitem.partition(':')
k = k.strip()
if k not in cfgdict:
error = 'bad formed'
cfgdict[k] = v.strip()
ownip, _, prefix = cfgdict['own'].partition('/')
prefix = cfgdict['prefix'] or prefix
if prefix:
try:
prefix = int(prefix)
if not 16 <= prefix < 32:
error = 'illegal prefix in'
except ValueError:
error = 'illegal prefix in'
if error:
print('Allowed forms:\n')
print('%s=n.n.n.n/24' % name)
print('%s=prefix:24,own:n.n.n.n,other:m.m.m.m\n' % name)
raise ValueError('%s network config: %s=%s' % (error, name, cfg))
if not prefix:
interface = IPv4Interface(ownip)
if interface < IPv4Interface('128.0.0.0'):
prefix = 8
elif interface < IPv4Interface('192.0.0.0'):
prefix = 16
else:
prefix = 24
interface = IPv4Interface('%s/%d' % (ownip, prefix))
result['IPADDR'], result['NETMASK'] = interface.with_netmask.split('/')
_, result['PREFIX'] = interface.with_prefixlen.split('/')
other = cfgdict['other']
if other:
adrs = cfgdict['other'].split('-')
result['dhcprange'] = (adrs[0], adrs[-1])
return result
def walk(action):
for dirpath, _, files in os.walk('.'):
syspath = dirpath[1:] # remove leading '.'
action.dirpath = dirpath
action.syspath = syspath
if files:
match, mismatch, missing = filecmp.cmpfiles(dirpath, syspath, files)
if mismatch:
newer = [f for f in mismatch if getmtime(join(syspath, f)) > getmtime(join(dirpath, f))]
if newer:
action.newer(newer)
if len(newer) < len(mismatch):
newer = set(newer)
action.older([f for f in mismatch if f not in newer])
if missing:
if DEL in missing:
missing.remove(DEL)
with open(join(dirpath, DEL)) as fil:
to_delete = []
for f in fil:
f = f.strip()
if f and exists(join(syspath, f)):
if exists(join(dirpath, f)):
print('ERROR: %s in %s, but also in repo -> ignored' % (f, DEL))
else:
to_delete.append(f)
action.delete(to_delete)
if missing:
action.missing(missing)
class Show:
dirty = False
def show(self, title, files):
self.dirty = True
print('%s %s:\n %s' % (title, self.syspath, ' '.join(files)))
def newer(self, files):
self.show('get from', files)
def older(self, files):
self.show('replace in', files)
def missing(self, files):
self.show('install in', files)
def delete(self, files):
self.show('remove from', files)
class Do:
def newer(self, files):
for file in files:
shutil.copy(join(self.syspath, file), join(self.dirpath, file))
def older(self, files):
for file in files:
shutil.copy(join(self.dirpath, file), join(self.syspath, file))
def missing(self, files):
self.older(files)
def delete(self, files):
for file in files:
os.remove(join(self.syspath, file))
IFNAMES = ['enp%ds0' % i for i in range(1,5)]
def network(doit):
netaddr_dict = {}
for ifname in IFNAMES:
with open('/sys/class/net/%s/address' % ifname) as f:
netaddr_dict[ifname] = f.read().strip().lower()
netaddr = netaddr_dict[IFNAMES[0]]
apuid = int(''.join(netaddr.split(':')[-3:]), 16) & 0xfffffc
cfgfile = None
cfgfiles = []
for i in range(4):
# goodie: look for mac addresses of all 4 ports
cfgfiles += glob(CFGPATH % ('*', apuid + i))
with open('/etc/hostname') as f:
hostname = f.read().strip()
if not cfgfiles:
print('no cfg file found for %s' % hostname)
newname = input('enter host name: ')
if not newname:
print('no hostname given')
return False
cfgfile = CFGPATH % (newname, apuid)
with open(cfgfile, 'w') as f:
f.write(TEMPLATE_CFG)
elif len(cfgfiles) > 1:
print('ERROR: ambiguous cfg files: %s' % ', '.join(cfgfiles))
else:
cfgfile = cfgfiles[0]
if cfgfile != CFGPATH % (hostname, apuid):
if doit:
os.system('sh ../sethostname.sh')
else:
if cfgfile:
print('replace host name %r by %r' % (hostname, basename(cfgfile).rpartition('_')[0]))
show.dirty = True
if cfgfile is None:
return False
ifname = ''
parser = ConfigParser()
dh = []
try:
parser.read(cfgfile)
network = dict(parser['NETWORK'])
for ifname in IFNAMES:
content = create_if(ifname, network.get(ifname, 'off'), netaddr_dict[ifname])
dhcprange = content.pop('dhcprange', None)
if dhcprange:
ip_mask = content['IPADDR'], content['NETMASK']
dh.append(ip_mask + ip_mask + dhcprange)
content = '\n'.join('%s=%s' % kv for kv in content.items())
todo = write_when_new('/etc/sysconfig/network-scripts/ifcfg-%s' % ifname, content, doit)
if todo:
print('change ', ifname)
show.dirty = True
if dh:
content = DHCP_HEADER + '\n'.join([DHCP_ITEM % d for d in dh])
todo = write_when_new('/etc/dhcp/dhcpd.conf', content, doit)
if todo:
print('change ', ifname)
show.dirty = True
except Exception as e:
print('ERROR: can not handle %s %s: %r' % (hostname, ifname, e))
raise
return False
return True
print('---')
show = Show()
result = network(False)
walk(show)
if not result:
print('fix first above errors')
elif show.dirty:
print('---')
answer = input('do above? ')
if answer.lower().startswith('y'):
network(True)
walk(Do())
else:
print('nothing to do')