diff --git a/install.py b/install.py index 6aa25dd..a3316d5 100755 --- a/install.py +++ b/install.py @@ -7,15 +7,18 @@ if bytes == str: raise NotImplementedError('python2 not supported') +import sys import os import filecmp import shutil import time +from subprocess import Popen, PIPE from glob import glob from ipaddress import IPv4Interface from configparser import ConfigParser from os.path import join, getmtime, exists, basename +more_info = sys.argv[1] if len(sys.argv) > 1 else 'NONE' os.chdir('/root/aputools/to_system') DEL = '__to_delete__' @@ -23,7 +26,7 @@ CFGPATH = '/root/aputools/servercfg/%s_%6.6x.cfg' COMMENT = "; please refer to README.md for help" -TEMPLATE_CFG = """[NETWORK] +CONFIG_TEMPLATE = """[NETWORK] %s enp1s0=192.168.127.1/24 enp2s0=192.168.2.1/24 @@ -41,22 +44,100 @@ max-lease-time 7200; authoritative; """ -def write_when_new(filename, content, doit): - if not content.endswith('\n'): - content += '\n' - with open(filename) as fil: - old = fil.read() +ROUTER_TEMPLATE = """[Unit] +Description = Routing to locally connected hardware +After = network.target + +[Service] +ExecStart = /usr/bin/python3 /root/aputools/router.py + +[Install] +WantedBy = multi-user.target +""" + +FRAPPY_TEMPLATE = """[Unit] +Description = Running frappy server +After = network.target + +[Service] +User = l_samenv +ExecStart = /usr/bin/python3 /home/l_samenv/frappy/bin/secop-server %s + +[Install] +WantedBy = multi-user.target +""" + + +def frappy(cfg=None, port=None, **kwds): + if not cfg: + return None + if port: + cfg = '-p %s %s' % (port, cfg) + return FRAPPY_TEMPLATE % cfg + + +def router(**opts): + if not opts: + return None + return ROUTER_TEMPLATE + + +SERVICES = dict(router=router, frappy=frappy) + + +def unix_cmd(command, always=False): + if doit or always: + if not always: + print('$ %s' % command) + return Popen(command.split(), stdout=PIPE).communicate()[0].decode() + else: + print('> %s' % command) + + +def write_when_new(filename, content): + if content is None: + lines = [] + else: + if not content.endswith('\n'): + content += '\n' + lines = content.split('\n') + try: + with open(filename) as fil: + old = fil.read() + except FileNotFoundError: + old = None if old == content: return False if doit: - with open(filename, 'w') as fil: - fil.write(content) - else: - print('===') - print(old) + if lines: + with open(filename, 'w') as fil: + fil.write(content) + else: + os.remove(filename) + elif filename.endswith(more_info): + print('changes in', filename) + old = [] if old is None else old.split('\n') + top_lines = 0 # in case of empty loop + for top_lines, (ol, ll) in enumerate(zip(old, lines)): + if ol != ll: + break + bottom_lines = 0 + for bottom_lines, (ol, ll) in enumerate(zip(reversed(old[top_lines:]), reversed(lines[top_lines:]))): + if ol != ll: + break + if bottom_lines == 0: + old.append('') + lines.append('') + bottom_lines += 1 + print("===") + print('\n'.join(old[:top_lines])) + print('<<<') + print('\n'.join(old[top_lines:-bottom_lines])) print('---') - print(content) - print('===') + print('\n'.join(lines[top_lines:-bottom_lines])) + print('>>>') + print('\n'.join(old[-bottom_lines:-1])) + print("===") return True @@ -132,9 +213,22 @@ def walk(action): class Show: dirty = False - def show(self, title, files): + def diff(self, title, files): self.dirty = True - print('%s %s:\n %s' % (title, self.syspath, ' '.join(files))) + if more_info == 'NONE': + print('%s %s:\n %s' % (title, self.syspath, ' '.join(files))) + else: + for f in files: + if f.endswith(MORE_INFO): + print('diff %s %s' % (join(self.dirpath, f), join(self.syspath, f))) + + def show(self, title, dirpath, files): + if more_info == 'NONE': + print('%s %s:\n %s' % (title, self.syspath, ' '.join(files))) + else: + for f in files: + if f.endswith(MORE_INFO): + print('cat %s' % join(dirpath, f)) def newer(self, files): self.show('get from', files) @@ -143,10 +237,10 @@ class Show: self.show('replace in', files) def missing(self, files): - self.show('install in', files) + self.show('install in', self.dirpath, files) def delete(self, files): - self.show('remove from', files) + self.show('remove from', self.syspath, files) class Do: @@ -169,7 +263,7 @@ class Do: IFNAMES = ['enp%ds0' % i for i in range(1,5)] -def network(doit): +def handle_config(): netaddr_dict = {} for ifname in IFNAMES: with open('/sys/class/net/%s/address' % ifname) as f: @@ -191,7 +285,7 @@ def network(doit): return False cfgfile = CFGPATH % (newname, apuid) with open(cfgfile, 'w') as f: - f.write(TEMPLATE_CFG) + f.write(CONFIG_TEMPLATE) elif len(cfgfiles) > 1: print('ERROR: ambiguous cfg files: %s' % ', '.join(cfgfiles)) else: @@ -215,9 +309,9 @@ def network(doit): for ifname in IFNAMES: content = create_if(ifname, network.pop(ifname, 'off'), netaddr_dict[ifname], dhcp_server_cfg) 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) + todo = write_when_new('/etc/sysconfig/network-scripts/ifcfg-%s' % ifname, content) + if todo and more_info == 'NONE': + print('change', ifname) show.dirty = True if dh: content = [DHCP_HEADER] @@ -228,7 +322,7 @@ def network(doit): dh.append(' range %s %s;\n' % rng) dh.append('}\n') content = ''.join(content) - todo = write_when_new('/etc/dhcp/dhcpd.conf', content, doit) + todo = write_when_new('/etc/dhcp/dhcpd.conf', content) if todo: print('change ', ifname) show.dirty = True @@ -249,21 +343,66 @@ def network(doit): print('ERROR: can not handle %s %s: %r' % (hostname, ifname, e)) raise return False + + # pip requirements ? + + actions_dict = {} + reload_systemd = False + for service, template_func in SERVICES.items(): + sction = service.upper() + if parser.has_section(section): + template = template_func(**dict(parser[section])) + else: + template = None + result = unix_cmd('systemctl show -p WantedBy -p ActiveState %s' % service, True) + active = False + enabled = False + for line in result.split('\n'): + if line.startswith('WantedBy=m'): + enabled = True + elif line.strip() == 'ActiveState=active': + active = True + actions = set() + if template is None: + if active: + actions.add('stop') + elif enabled: + actions.add('disable') + else: + if not active: + actions.add('restart') + if not enabled: + actions.add('enable') + if write_when_new('/etc/systemd/system/%s.service' % service, template): + reload_systemd = True + if 'enable' in actions: + actions.add('restart') + actions_dict[service] = actions + + if reload_systemd: + unix_cmd('systemctl daemon-reload') + for service in SERVICES: + for action in 'stop', 'restart', 'disable', 'enable': + if action in actions_dict[service]: + show.dirty = True + unix_cmd('systemctl %s %s' % (action, service)) return True +doit = False print('---') show = Show() -result = network(False) walk(show) +result = handle_config() if not result: print('fix first above errors') -elif show.dirty: +elif show.dirty and more_info == 'NONE': print('---') answer = input('do above? ') + doit = True if answer.lower().startswith('y'): - network(True) + handle_config() walk(Do()) else: print('nothing to do') diff --git a/router.py b/router.py index 2020811..2142bc3 100644 --- a/router.py +++ b/router.py @@ -199,10 +199,5 @@ if __name__ == '__main__': if len(cfgfiles) != 1: raise ValueError('there must be one and only one single cfgfile %r' % cfgfiles) parser.read(cfgfiles[0]) - if parser.has_section('FRAPPY'): - port = parser.get('FRAPPY', 'port') - cfg = parser.get('FRAPPY', 'cfg') - cmd = ['su', '-', 'l_samenv', '-c', '/home/l_samenv/frappy/bin/secop-server -p %s %s' % (port, cfg)] - Popen(cmd, stdout=DEVNULL, stderr=DEVNULL) if parser.has_section('ROUTER'): AcceptHandler.run(parser['ROUTER']) diff --git a/servercfg/apuslave3_5a4c90.cfg b/servercfg/apuslave3_5a4c90.cfg index 9688ef1..bd6b372 100644 --- a/servercfg/apuslave3_5a4c90.cfg +++ b/servercfg/apuslave3_5a4c90.cfg @@ -2,11 +2,16 @@ ; please refer to README.md for help enp1s0=dhcp enp2s0=192.168.2.15 -enp3s0=192.168.3.3/24 +enp3s0=192.168.3.1/24 enp4s0=192.168.127.4/24 [ROUTER] ; please refer to README.md for help 3000=/dev/ttyUSB0 -5900=192.168.2.33 +5900=192.168.2.32 8080=192.168.127.254:80 + +[FRAPPY] +; please refer to README.md for help +cfg=sim_uniax +port=5000 diff --git a/to_system/etc/systemd/system/router.service b/to_system/etc/systemd/system/router.service deleted file mode 100644 index 32036ca..0000000 --- a/to_system/etc/systemd/system/router.service +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description = Routing to locally connected hardware -After = network.target - -[Service] -ExecStart = /usr/bin/python3 /root/aputools/router.py - -[Install] -WantedBy = multi-user.target -