From: Douglas Bagnall Date: Mon, 19 Apr 2021 12:07:50 +0000 (+1200) Subject: samba-tool: add dns zoneoptions for aging control X-Git-Tag: tevent-0.11.0~1055 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0f29b8c2fee0d6bcc5b83ef237518539179de465;p=thirdparty%2Fsamba.git samba-tool: add dns zoneoptions for aging control This adds a subcommand for altering zone parameters. At the moment the only options are related to record aging (a.k.a scavenging). The code is structured to make it easy to add more integer or boolean options, but it is not clear that this would be useful; many other parameters are not used or would only have deleterious effects. Signed-off-by: Douglas Bagnall Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Wed Apr 21 10:04:14 UTC 2021 on sn-devel-184 --- diff --git a/python/samba/netcmd/dns.py b/python/samba/netcmd/dns.py index a267c4105b5..11ca90b1f3e 100644 --- a/python/samba/netcmd/dns.py +++ b/python/samba/netcmd/dns.py @@ -505,6 +505,94 @@ class cmd_serverinfo(Command): print_serverinfo(self.outf, typeid, res) +def _add_integer_options(table, takes_options, integer_properties): + """Generate options for cmd_zoneoptions""" + for k, doc, _min, _max in table: + o = '--' + k.lower() + opt = Option(o, + help=f"{doc} [{_min}-{_max}]", + type="int", + dest=k) + takes_options.append(opt) + integer_properties.append((k, _min, _max, o)) + + +class cmd_zoneoptions(Command): + """Change zone aging options.""" + + synopsis = '%prog [options]' + + takes_args = ['server', 'zone'] + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + "credopts": options.CredentialsOptions, + } + + takes_options = [ + Option('--client-version', help='Client Version', + default='longhorn', metavar='w2k|dotnet|longhorn', + choices=['w2k', 'dotnet', 'longhorn'], dest='cli_ver'), + ] + + integer_properties = [] + # Any zone parameter that is stored as an integer (which is most of + # them) can be added to this table. The name should be the dnsp + # mixed case name, which will get munged into a lowercase name for + # the option. (e.g. "Aging" becomes "--aging"). + # + # Note: just because we add a name here doesn't mean we will use + # it. + _add_integer_options([ + # ( name, help-string, min, max ) + ('Aging', 'Enable record aging', 0, 1), + ('NoRefreshInterval', + 'Aging no refresh interval in hours (0: use default)', + 0, 10 * 365 * 24), + ('RefreshInterval', + 'Aging refresh interval in hours (0: use default)', + 0, 10 * 365 * 24), + ], + takes_options, + integer_properties) + + def run(self, server, zone, cli_ver, sambaopts=None, credopts=None, + versionopts=None, **kwargs): + self.lp = sambaopts.get_loadparm() + self.creds = credopts.get_credentials(self.lp) + dns_conn = dns_connect(server, self.lp, self.creds) + + client_version = dns_client_version(cli_ver) + nap_type = dnsserver.DNSSRV_TYPEID_NAME_AND_PARAM + + for k, _min, _max, o in self.integer_properties: + if kwargs.get(k) is None: + continue + v = kwargs[k] + if _min is not None and v < _min: + raise CommandError(f"{o} must be at least {_min}") + if _max is not None and v > _max: + raise CommandError(f"{o} can't exceed {_max}") + + name_param = dnsserver.DNS_RPC_NAME_AND_PARAM() + name_param.dwParam = v + name_param.pszNodeName = k + try: + dns_conn.DnssrvOperation2(client_version, + 0, + server, + zone, + 0, + 'ResetDwordProperty', + nap_type, + name_param) + except WERRORError as e: + raise CommandError(f"Could not set {k} to {v}") from None + + print(f"Set {k} to {v}", file=self.outf) + + class cmd_zoneinfo(Command): """Query for zone information.""" @@ -1065,6 +1153,7 @@ class cmd_dns(SuperCommand): subcommands = {} subcommands['serverinfo'] = cmd_serverinfo() + subcommands['zoneoptions'] = cmd_zoneoptions() subcommands['zoneinfo'] = cmd_zoneinfo() subcommands['zonelist'] = cmd_zonelist() subcommands['zonecreate'] = cmd_zonecreate() diff --git a/python/samba/tests/samba_tool/dnscmd.py b/python/samba/tests/samba_tool/dnscmd.py index 356b2c46d05..0048e390ce5 100644 --- a/python/samba/tests/samba_tool/dnscmd.py +++ b/python/samba/tests/samba_tool/dnscmd.py @@ -17,6 +17,7 @@ import os import ldb +import re from samba.auth import system_session from samba.samdb import SamDB @@ -910,3 +911,56 @@ class DnsCmdTestCase(SambaToolCmdTest): err, "Failed to print zoneinfo") self.assertTrue(out != '') + + def test_zoneoptions(self): + for options, vals, error in ( + (['--aging=1'], {'fAging': 'TRUE'}, False), + (['--aging=0'], {'fAging': 'FALSE'}, False), + (['--aging=-1'], {'fAging': 'FALSE'}, True), + (['--aging=2'], {}, True), + (['--aging=2', '--norefreshinterval=1'], {}, True), + (['--aging=1', '--norefreshinterval=1'], + {'fAging': 'TRUE', 'dwNoRefreshInterval': '1'}, False), + (['--aging=1', '--norefreshinterval=0'], + {'fAging': 'TRUE', 'dwNoRefreshInterval': '0'}, False), + (['--aging=0', '--norefreshinterval=99', '--refreshinterval=99'], + {'fAging': 'FALSE', + 'dwNoRefreshInterval': '99', + 'dwRefreshInterval': '99'}, False), + (['--aging=0', '--norefreshinterval=-99', '--refreshinterval=99'], + {}, True), + (['--refreshinterval=9999999'], {}, True), + (['--norefreshinterval=9999999'], {}, True), + ): + result, out, err = self.runsubcmd("dns", + "zoneoptions", + os.environ["SERVER"], + self.zone, + self.creds_string, + *options) + if error: + self.assertCmdFail(result, "zoneoptions should fail") + else: + self.assertCmdSuccess(result, + out, + err, + "zoneoptions shouldn't fail") + + + info_r, info_out, info_err = self.runsubcmd("dns", + "zoneinfo", + os.environ["SERVER"], + self.zone, + self.creds_string) + + self.assertCmdSuccess(info_r, + info_out, + info_err, + "zoneinfo shouldn't fail after zoneoptions") + + info = {k: v for k, v in re.findall(r'^\s*(\w+)\s*:\s*(\w+)\s*$', + info_out, + re.MULTILINE)} + for k, v in vals.items(): + self.assertIn(k, info) + self.assertEqual(v, info[k])