0
0
mirror of https://github.com/openwrt/luci.git synced 2025-07-20 15:59:17 +00:00
Files
Paul Donald c5736a30da luci-app-chrony: allow non NTS variant also
Closes #7857

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
2025-07-08 01:32:39 +02:00

248 lines
8.0 KiB
JavaScript

'use strict';
'require form';
'require fs';
'require uci';
'require view';
'require tools.widgets as widgets';
return view.extend({
load() {
return fs.exec_direct('/usr/sbin/chronyd', ['-v']).then(output => {
const flags = ['IPv6', 'NTP', 'NTS', 'RTC'];
const features = Object.fromEntries(
flags.map(flag => [flag.toLowerCase(), output.includes(`+${flag}`)])
);
return features;
});
},
render(features) {
const docUrl = 'https://chrony-project.org/documentation.html';
let m, s, o;
m = new form.Map('chrony', _('Chrony NTP/NTS daemon'),
'%s'.format('<a id="docUrl" href="%s" target="_blank" rel="noreferrer">%s</a>'
.format(docUrl, _('Documentation'))));
// Interface
s = m.section(form.NamedSection, 'allow', 'allow', _('Allow'), _('An allow range permits access for chronyc from specific IPs to chronyd.') + '<br/>' +
_('Delete this section to allow all local IPs.'));
s.anonymous = true;
s.addremove = true;
o = s.option(widgets.NetworkSelect, 'interface', _('Interface'),
_('Choose IP ranges from this interface to set them as allowed ranges.') + '<br/>' +
_('Choose a wan interface to allow from all IPs.') + '<br/>' +
_('Additional firewall configuration is required if you intend wan access.'));
o.nocreate = true;
o.rmempty = false;
if (features.nts) {
// NTS
s = m.section(form.NamedSection, 'nts', 'nts', _('Network Time Security (NTS)'));
s.anonymous = true;
s.addremove = true;
o = s.option(form.Flag, 'rtccheck', _('RTC Check'),
_('Check for the presence of %s.'.format('<code>/dev/rtc0</code>'), 'Check for RTC character device') + '<br/>' +
_('Disables certificate time checks via %s if RTC is absent.'.format('<code>nocerttimecheck</code>') ) );
o.default = o.disabled;
o = s.option(form.Flag, 'systemcerts', _('Use system CA bundle'));
o.default = o.enabled;
o = s.option(form.FileUpload, 'trustedcerts', _('Trusted certificates'));
o.optional = true;
o.root_directory = '/etc';
}
// Stepping
s = m.section(form.NamedSection, 'makestep', 'makestep', _('Stepping'),
_('Corrects the system clock by stepping immediately when it is so far adrift that the slewing process would take a very long time.'));
s.anonymous = true;
s.addremove = true;
s.singular = true;
o = s.option(form.Value, 'threshold', _('Trigger Amount Threshold'),
_('Seconds float value.'));
o.datatype = 'float';
o.optional = true;
o = s.option(form.Value, 'limit', _('Limit'),
_('First x clock updates'));
o.datatype = 'integer';
o.optional = true;
// Logging
s = m.section(form.NamedSection, 'logging', 'logging', _('Logging'));
s.anonymous = true;
s.addremove = true;
o = s.option(form.Value, 'logchange', _('Log any change more than'),
_('Seconds threshold for the adjustment of the system clock that will generate a syslog message.'));
o.datatype = 'float';
o.placeholder = '1';
o.optional = true;
// System Clock
s = m.section(form.NamedSection, 'systemclock', 'systemclock', _('System Clock'));
s.anonymous = true;
s.addremove = true;
o = s.option(form.Value, 'precision', _('Precision'),
_('Precision of the system clock (in seconds).'));
o.datatype = 'string';
o.placeholder = _('8e-6 (8 microseconds)');
o.optional = true;
o = s.option(form.ListValue, 'leapsecmode', _('Leap second mode'),
_('Strategy to reconcile leap seconds in UTC with solar time.'));
o.value('', _('(default)'))
o.value('system')
o.value('step')
o.value('slew')
o.value('ignore')
o.optional = true;
// Smoothing
s = m.section(form.NamedSection, 'smoothtime', 'smoothtime', _('Smoothing'),
_('Use only when the clients are not configured to poll another NTP server also, because they could reject this server as a falseticker or fail to select a source completely.'));
s.anonymous = true;
s.addremove = true;
o = s.option(form.Value, 'maxppm', _('Max PPM'),
_('Maximum frequency offset of the smoothed time to the tracked NTP time (in ppm).'));
o.datatype = 'uinteger';
o.placeholder = '400';
o.optional = false;
o = s.option(form.Value, 'maxwander', _('Max wander'),
_('Maximum rate at which the frequency offset is allowed to change (in ppm per second).'));
o.datatype = 'float';
o.placeholder = '0.01';
o.optional = false;
o = s.option(form.Flag, 'leaponly', _('Leap seconds only'),
_('Only leap seconds are smoothed out; ignore normal offset and frequency changes.'));
o.default = o.disabled;
// Server entries
s = m.section(form.TypedSection, 'server', _('Server'),
_('Remote NTP servers for your chronyd'));
s.anonymous = true;
s.addremove = true;
insertTypedSectionOptions(m, s, o, 'server', features);
// Pool entries
s = m.section(form.TypedSection, 'pool', _('Pool'),
_('Specifies a pool of NTP servers rather than a single NTP server.') + '<br/>' +
_('The pool name is expected to resolve to multiple addresses which might change over time.'));
s.anonymous = true;
s.addremove = true;
insertTypedSectionOptions(m, s, o, 'pool', features);
// Peer entries
s = m.section(form.TypedSection, 'peer', _('Peer'),
_('Specifies a symmetric association with an NTP peer.') + '<br/>' +
_('A single symmetric association allows the peers to be both servers and clients to each other.'));
s.anonymous = true;
s.addremove = true;
insertTypedSectionOptions(m, s, o, 'peer', features);
// Servers assigned (to us) via DHCP
s = m.section(form.NamedSection, 'dhcp_ntp_server', 'dhcp_ntp_server', _('DHCP(v6)'),
_('Options for servers provided to this host via DHCP(v6) (via the WAN for example).'));
s.anonymous = true;
insertTypedSectionOptions(m, s, o, 'dhcp_ntp_server', features);
return m.render();
}
});
function insertTypedSectionOptions(m, s, o, type, features) {
o = s.option(form.Flag, 'disabled', _('Disabled'));
o.default = o.disabled; // disabled default is disabled i.e., enabled
if (type != 'dhcp_ntp_server') {
o = s.option(form.Value, 'hostname', _('Hostname'));
o.optional = false;
o.depends('disabled', '0');
}
if (type != 'peer') {
o = s.option(form.Flag, 'iburst', _('iburst'));
o.rmempty = true;
o.default = o.disabled
o.depends('disabled', '0');
if (features.nts) {
o = s.option(form.Flag, 'nts', _('NTS'));
o.rmempty = true;
o.default = o.disabled
o.depends('disabled', '0');
}
}
o = s.option(form.Flag, 'prefer', _('Prefer'));
o.default = o.disabled;
o = s.option(form.Flag, 'xleave', _('Interleave'));
o.default = o.disabled;
o = s.option(form.RangeSliderValue, 'minpoll', _('Minimum poll'),
_('(Log_2 i.e. y=2^x) interval between readings of the NIC clock.'));
o.min = -7;
o.max = 24;
o.step = 1;
o.default = 4;
o.calculate = (val) => {
return 2**Number(val);
};
o.calcunits = _('seconds')
o.depends('disabled', '0');
o = s.option(form.RangeSliderValue, 'maxpoll', _('Maximum poll'),
_('(Log_2 i.e. y=2^x) interval between readings of the NIC clock.'));
o.min = -7;
o.max = 24;
o.step = 1;
o.default = 4;
o.calculate = (val) => {
return 2**Number(val);
};
o.calcunits = _('seconds');
o.depends('disabled', '0');
o = s.option(form.Value, 'mindelay', _('Minimum delay'),
_('A fixed round-trip delay in seconds to be used instead of that of the previous measurements.') + '<br/>' +
_('Exponential and decimal notation are allowed.'));
o.placeholder = '1e-4'
o.depends('disabled', '0');
o = s.option(form.Value, 'maxdelay', _('Maximum delay'),
_('A fixed round-trip delay in seconds to be used instead of that of the previous measurements.') + '<br/>' +
_('Exponential and decimal notation are allowed.'));
o.placeholder = '3';
o.depends('disabled', '0');
o = s.option(form.RangeSliderValue, 'minsamples', _('Minimum samples'));
o.min = 4;
o.max = 64;
o.step = 1;
o.default = 6;
o.depends('disabled', '0');
o = s.option(form.RangeSliderValue, 'maxsamples', _('Maximum samples'),
_('Number of samples that chronyd should keep for each source.'));
o.min = 4;
o.max = 64;
o.step = 1;
o.default = 6;
o.depends('disabled', '0');
}