214 lines
6.2 KiB
Python
Executable File
214 lines
6.2 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
|
|
"""
|
|
|
|
|
|
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)
|
|
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:
|
|
interface = IPv4Interface(cfg)
|
|
if '/' not in cfg:
|
|
if interface < IPv4Interface('128.0.0.0'):
|
|
cfg += '/8'
|
|
elif interface < IPv4Interface('192.0.0.0'):
|
|
cfg += '/16'
|
|
else:
|
|
cfg += '/24'
|
|
interface = IPv4Interface(cfg)
|
|
result['IPADDR'], result['NETMASK'] = interface.with_netmask.split('/')
|
|
_, result['PREFIX'] = interface.with_prefixlen.split('/')
|
|
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()
|
|
try:
|
|
parser.read(cfgfile)
|
|
network = dict(parser['NETWORK'])
|
|
for ifname in IFNAMES:
|
|
content = create_if(ifname, network.get(ifname, 'off'), netaddr_dict[ifname])
|
|
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
|
|
except Exception as e:
|
|
print('ERROR: can not handle %s %s: %r' % (hostname, ifname, e))
|
|
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')
|