From 00f4d8ad780001b9a3f534c32d485676bc97993a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 13 May 2018 15:48:08 +0200 Subject: T623: refactor NTP script and switch to jinja2 --- src/conf-mode/vyos-config-ntp.py | 153 ++++++++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 60 deletions(-) (limited to 'src/conf-mode/vyos-config-ntp.py') diff --git a/src/conf-mode/vyos-config-ntp.py b/src/conf-mode/vyos-config-ntp.py index b9328f3e0..061e8760e 100755 --- a/src/conf-mode/vyos-config-ntp.py +++ b/src/conf-mode/vyos-config-ntp.py @@ -18,7 +18,8 @@ import sys import os -import time + +import jinja2 import ipaddress from vyos.config import Config @@ -26,95 +27,127 @@ from vyos.util import ConfigError config_file = r'/etc/ntp.conf' +# Please be careful if you edit the template. +config_tmpl = """ +### Autogenerated by vyos-config-ntp.py ### + +# +# Non-configurable defaults +# +driftfile /var/lib/ntp/ntp.drift +# By default, only allow ntpd to query time sources, ignore any incoming requests +restrict default ignore +# Local users have unrestricted access, allowing reconfiguration via ntpdc +restrict 127.0.0.1 +restrict -6 ::1 + + +# +# Configurable section +# + +{% if servers -%} +{% for s in servers -%} +# Server configuration for: {{ s.name }} +server {{ s.name }} iburst {{ s.options | join(" ") }} + +{% endfor -%} +{% endif %} + +{% if allowed_networks -%} +{% for n in allowed_networks -%} +# Client configuration for network: {{ n.network }} +restrict {{ n.address }} mask {{ n.netmask }} nomodify notrap nopeer + +{% endfor -%} +{% endif %} + +""" + +default_config_data = { + 'servers': [], + 'allowed_networks': [] +} + def get_config(): - ntp = {} + ntp = default_config_data conf = Config() - conf.set_level('system ntp') - if not conf.exists(''): - return ntp + if not conf.exists('system ntp'): + return None + else: + conf.set_level('system ntp') if conf.exists('allow-clients address'): - ntp.setdefault('allow-networks', []) - networks = [] networks = conf.return_values('allow-clients address') - for network in networks: - ntp['allow-networks'].append(network) + for n in networks: + addr = ipaddress.ip_network(n) + net = { + "network" : n, + "address" : addr.network_address, + "netmask" : addr.netmask + } + + ntp['allowed_networks'].append(net) if conf.exists('server'): - ntp.setdefault('servers', []) for node in conf.list_nodes('server'): + options = [] server = { "name": node, - "dynamic": False, - "noselect": False, - "preempt": False, - "prefer": False, + "options": [] } if conf.exists('server {0} dynamic'.format(node)): - server['dynamic'] = True + options.append('dynamic') if conf.exists('server {0} noselect'.format(node)): - server['noselect'] = True + options.append('noselect') if conf.exists('server {0} preempt'.format(node)): - server['preempt'] = True + options.append('preempt') if conf.exists('server {0} prefer'.format(node)): - server['prefer'] = True + options.append('prefer') + server['options'] = options ntp['servers'].append(server) return ntp def verify(ntp): - if 'allow-networks' in ntp.keys(): - for network in ntp['allow-networks']: - try: - addr = ipaddress.ip_network(network) - except ValueError: - raise ConfigError("{0} does not appear to be a valid IPv4 or IPv6 network, check host bits.".format(network)) + # bail out early - looks like removal from running config + if ntp is None: + return None + + # Configuring allowed clients without a server makes no sense + if len(ntp['allowed_networks']) and not len(ntp['servers']): + raise ConfigError('NTP server not configured') + + for n in ntp['allowed_networks']: + try: + addr = ipaddress.ip_network( n['network'] ) + break + except ValueError: + raise ConfigError("{0} does not appear to be a valid IPv4 or IPv6 network, check host bits!".format(n['network'])) return None def generate(ntp): - config_header = '### Autogenerated by vyos-config-ntp.py on {tm} ###\n'.format(tm=time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())) - - # write new configuration file - f = open(config_file, 'w') - f.write(config_header) - f.write('\n') - f.write('driftfile /var/lib/ntp/ntp.drift\n') - f.write('\n') - f.write('# By default, only allow ntpd to query time sources, ignore any incoming requests\n') - f.write('restrict default ignore\n') - f.write('\n') - f.write('# Local users have unrestricted access, allowing reconfiguration via ntpdc\n') - f.write('restrict 127.0.0.1\n') - f.write('restrict -6 ::1\n') - f.write('\n') - - if 'servers' in ntp.keys(): - for server in ntp['servers']: - opt = ['dynamic', 'noselect', 'preempt', 'prefer'] - f.write('# Server configuration for: {0}\n'.format(server['name'])) - f.write('server {0} iburst {1}\n'.format(server['name'], '{0}'.format(' '.join(str(o) for o in opt if server[o])))) - f.write('restrict {0} nomodify notrap nopeer noquery\n'.format(server['name'])) - f.write('\n') - - if 'allow-networks' in ntp.keys(): - for network in ntp['allow-networks']: - addr = ipaddress.ip_network(network) - f.write('# Client configuration for network: {0}\n'.format(network)) - f.write('restrict {0} mask {1} nomodify notrap nopeer\n'.format(addr.network_address, addr.netmask)) - f.write('\n') - - f.close() + # bail out early - looks like removal from running config + if ntp is None: + return None + + tmpl = jinja2.Template(config_tmpl) + config_text = tmpl.render(ntp) + with open(config_file, 'w') as f: + f.write(config_text) + return None def apply(ntp): - if len(ntp) == 0: - cmd = "sudo /usr/sbin/invoke-rc.d ntp stop" + if ntp is not None: + os.system('sudo /usr/sbin/invoke-rc.d ntp force-reload') else: - cmd = "sudo /usr/sbin/invoke-rc.d ntp force-reload" + # NTP suuport is removed in the commit + os.system('sudo /usr/sbin/invoke-rc.d ntp stop') + os.unlink(config_file) - os.system(cmd) return None if __name__ == '__main__': -- cgit v1.2.3