Merge lp:~jtv/maas/flatten-dnszoneconfig into lp:~maas-committers/maas/trunk

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: no longer in the source branch.
Merged at revision: 1839
Proposed branch: lp:~jtv/maas/flatten-dnszoneconfig
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 223 lines (+27/-60)
3 files modified
src/maasserver/dns.py (+1/-2)
src/provisioningserver/dns/config.py (+17/-43)
src/provisioningserver/dns/tests/test_config.py (+9/-15)
To merge this branch: bzr merge lp:~jtv/maas/flatten-dnszoneconfig
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+202509@code.launchpad.net

Commit message

Collapse DNSConfigBase into DNSZoneConfigBase.

Description of the change

Now that DNSConfig is no longer in the family, DNSConfigBase and DNSZoneConfigBase no longer need to be separate classes. This branch combines them, and some of the complexity falls out along the way. To keep refactoring work light, I hard-coded the zone files' access permissions (we never used the property) and to keep a handle on data flows, I moved dns_ip down to DNSForwardZoneConfig (the other classes make no use of it). I believe, but am not entirely certain, that the "mapping" parameter could likewise move down into DNSForwardZoneConfig.

At this point the data flows within the hierarchy become much clearer. They could be shortened a bit further still by passing the mappings and context to the base-class constructor as parameters, instead of having the base class retrieve them by calling overridable methods on itself. Delegation may be more appropriate than a common base class. The constructors for the concrete classes might be a bit easier to grasp if they named their parameters instead of accepting *args and **kwargs. Finally, I suppose shortened_reversed_ip really belongs in DNSReverseZoneConfig.

Jeroen

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

Looks good. One thing to consider.

[1]

-        networks = kwargs.pop("networks", None)
-        self.networks = [] if networks is None else networks
+        self.networks = kwargs.pop('networks', [])

This subtly changes behaviour. If kwargs["networks"] is None, this will
set self.networks to None. The original would set it to []. I'm not sure
if it's important though.

review: Approve
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

I know, thanks.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/dns.py'
--- src/maasserver/dns.py 2014-01-20 07:54:17 +0000
+++ src/maasserver/dns.py 2014-01-21 16:57:51 +0000
@@ -229,11 +229,10 @@
229 def _gen_reverse_zones(nodegroups, serial, mappings, networks):229 def _gen_reverse_zones(nodegroups, serial, mappings, networks):
230 """Generator of reverse zones, sorted by network."""230 """Generator of reverse zones, sorted by network."""
231 get_domain = lambda nodegroup: nodegroup.name231 get_domain = lambda nodegroup: nodegroup.name
232 dns_ip = get_dns_server_address()
233 reverse_nodegroups = sorted(nodegroups, key=networks.get)232 reverse_nodegroups = sorted(nodegroups, key=networks.get)
234 for nodegroup in reverse_nodegroups:233 for nodegroup in reverse_nodegroups:
235 yield DNSReverseZoneConfig(234 yield DNSReverseZoneConfig(
236 get_domain(nodegroup), serial=serial, dns_ip=dns_ip,235 get_domain(nodegroup), serial=serial,
237 mapping=mappings[nodegroup], network=networks[nodegroup])236 mapping=mappings[nodegroup], network=networks[nodegroup])
238237
239 def __iter__(self):238 def __iter__(self):
240239
=== modified file 'src/provisioningserver/dns/config.py'
--- src/provisioningserver/dns/config.py 2014-01-21 13:21:42 +0000
+++ src/provisioningserver/dns/config.py 2014-01-21 16:57:51 +0000
@@ -23,6 +23,7 @@
2323
24from abc import (24from abc import (
25 ABCMeta,25 ABCMeta,
26 abstractmethod,
26 abstractproperty,27 abstractproperty,
27 )28 )
28from contextlib import contextmanager29from contextlib import contextmanager
@@ -231,36 +232,6 @@
231 raise232 raise
232233
233234
234class DNSConfigBase:
235 __metaclass__ = ABCMeta
236
237 @abstractproperty
238 def template_path(self):
239 """Return the full path of the template to be used."""
240
241 @abstractproperty
242 def target_path(self):
243 """Return the full path of the target file to be written."""
244
245 @property
246 def template_dir(self):
247 return locate_config(TEMPLATES_DIR)
248
249 @property
250 def access_permissions(self):
251 """The access permissions for the config file."""
252 return 0644
253
254 @property
255 def target_dir(self):
256 return conf.DNS_CONFIG_DIR
257
258 def get_context(self):
259 """Dictionary containing parameters to be included in the
260 parameters used when rendering the template."""
261 return {}
262
263
264class DNSConfig:235class DNSConfig:
265 """A DNS configuration file.236 """A DNS configuration file.
266237
@@ -316,26 +287,24 @@
316 return '.'.join(imap(unicode, significant_octets))287 return '.'.join(imap(unicode, significant_octets))
317288
318289
319class DNSZoneConfigBase(DNSConfigBase):290class DNSZoneConfigBase:
320 """Base class for zone writers."""291 """Base class for zone writers."""
321292
293 __metaclass__ = ABCMeta
294
322 template_file_name = 'zone.template'295 template_file_name = 'zone.template'
323296
324 def __init__(self, domain, serial=None, mapping=None, dns_ip=None):297 def __init__(self, domain, serial=None, mapping=None):
325 """298 """
326 :param domain: The domain name of the forward zone.299 :param domain: The domain name of the forward zone.
327 :param serial: The serial to use in the zone file. This must increment300 :param serial: The serial to use in the zone file. This must increment
328 on each change.301 on each change.
329 :param mapping: A hostname:ip-address mapping for all known hosts in302 :param mapping: A hostname:ip-address mapping for all known hosts in
330 the zone.303 the zone.
331 :param dns_ip: The IP address of the DNS server authoritative for this
332 zone.
333 """304 """
334 super(DNSZoneConfigBase, self).__init__()
335 self.domain = domain305 self.domain = domain
336 self.serial = serial306 self.serial = serial
337 self.mapping = {} if mapping is None else mapping307 self.mapping = {} if mapping is None else mapping
338 self.dns_ip = dns_ip
339308
340 @abstractproperty309 @abstractproperty
341 def zone_name(self):310 def zone_name(self):
@@ -343,13 +312,17 @@
343312
344 @property313 @property
345 def template_path(self):314 def template_path(self):
346 return os.path.join(self.template_dir, self.template_file_name)315 return locate_config(TEMPLATES_DIR, self.template_file_name)
347316
348 @property317 @property
349 def target_path(self):318 def target_path(self):
350 """Return the full path of the DNS zone file."""319 """Return the full path of the DNS zone file."""
351 return os.path.join(320 return compose_config_path('zone.%s' % self.zone_name)
352 self.target_dir, 'zone.%s' % self.zone_name)321
322 @abstractmethod
323 def get_context(self):
324 """Dictionary containing parameters to be included in the
325 parameters used when rendering the template."""
353326
354 def write_config(self):327 def write_config(self):
355 """Write out this DNS zone file.328 """Write out this DNS zone file.
@@ -361,8 +334,7 @@
361 """334 """
362 content = render_dns_template(self.template_path, self.get_context())335 content = render_dns_template(self.template_path, self.get_context())
363 with report_missing_config_dir():336 with report_missing_config_dir():
364 incremental_write(337 incremental_write(content, self.target_path, mode=0644)
365 content, self.target_path, mode=self.access_permissions)
366338
367339
368class DNSForwardZoneConfig(DNSZoneConfigBase):340class DNSForwardZoneConfig(DNSZoneConfigBase):
@@ -373,9 +345,11 @@
373345
374 :param networks: The networks that the mapping exists within.346 :param networks: The networks that the mapping exists within.
375 :type networks: Sequence of :class:`netaddr.IPNetwork`347 :type networks: Sequence of :class:`netaddr.IPNetwork`
348 :param dns_ip: The IP address of the DNS server authoritative for this
349 zone.
376 """350 """
377 networks = kwargs.pop("networks", None)351 self.networks = kwargs.pop('networks', [])
378 self.networks = [] if networks is None else networks352 self.dns_ip = kwargs.pop('dns_ip', None)
379 super(DNSForwardZoneConfig, self).__init__(*args, **kwargs)353 super(DNSForwardZoneConfig, self).__init__(*args, **kwargs)
380354
381 @property355 @property
382356
=== modified file 'src/provisioningserver/dns/tests/test_config.py'
--- src/provisioningserver/dns/tests/test_config.py 2014-01-21 13:13:53 +0000
+++ src/provisioningserver/dns/tests/test_config.py 2014-01-21 16:57:51 +0000
@@ -298,8 +298,8 @@
298298
299 def test_write_config_DNSConfigDirectoryMissing_if_dir_missing(self):299 def test_write_config_DNSConfigDirectoryMissing_if_dir_missing(self):
300 dnsconfig = DNSConfig()300 dnsconfig = DNSConfig()
301 dir_name = factory.make_name('nonesuch')301 dir_name = patch_dns_config_path(self)
302 self.patch(DNSConfig, 'target_dir', dir_name)302 os.rmdir(dir_name)
303 self.assertRaises(DNSConfigDirectoryMissing, dnsconfig.write_config)303 self.assertRaises(DNSConfigDirectoryMissing, dnsconfig.write_config)
304304
305 def test_write_config_errors_if_unexpected_exception(self):305 def test_write_config_errors_if_unexpected_exception(self):
@@ -503,8 +503,7 @@
503 )503 )
504504
505 def test_writes_dns_zone_config(self):505 def test_writes_dns_zone_config(self):
506 target_dir = self.make_dir()506 target_dir = patch_dns_config_path(self)
507 self.patch(DNSForwardZoneConfig, 'target_dir', target_dir)
508 domain = factory.getRandomString()507 domain = factory.getRandomString()
509 hostname = factory.getRandomString()508 hostname = factory.getRandomString()
510 network = factory.getRandomNetwork()509 network = factory.getRandomNetwork()
@@ -523,8 +522,7 @@
523 ])))522 ])))
524523
525 def test_writes_dns_zone_config_with_NS_record(self):524 def test_writes_dns_zone_config_with_NS_record(self):
526 target_dir = self.make_dir()525 target_dir = patch_dns_config_path(self)
527 self.patch(DNSForwardZoneConfig, 'target_dir', target_dir)
528 network = factory.getRandomNetwork()526 network = factory.getRandomNetwork()
529 dns_ip = factory.getRandomIPAddress()527 dns_ip = factory.getRandomIPAddress()
530 dns_zone_config = DNSForwardZoneConfig(528 dns_zone_config = DNSForwardZoneConfig(
@@ -541,7 +539,7 @@
541 ])))539 ])))
542540
543 def test_config_file_is_world_readable(self):541 def test_config_file_is_world_readable(self):
544 self.patch(DNSForwardZoneConfig, 'target_dir', self.make_dir())542 patch_dns_config_path(self)
545 network = factory.getRandomNetwork()543 network = factory.getRandomNetwork()
546 dns_zone_config = DNSForwardZoneConfig(544 dns_zone_config = DNSForwardZoneConfig(
547 factory.getRandomString(), serial=random.randint(1, 100),545 factory.getRandomString(), serial=random.randint(1, 100),
@@ -637,13 +635,11 @@
637 )635 )
638636
639 def test_writes_dns_zone_config_with_NS_record(self):637 def test_writes_dns_zone_config_with_NS_record(self):
640 target_dir = self.make_dir()638 target_dir = patch_dns_config_path(self)
641 self.patch(DNSReverseZoneConfig, 'target_dir', target_dir)
642 network = factory.getRandomNetwork()639 network = factory.getRandomNetwork()
643 dns_ip = factory.getRandomIPAddress()
644 dns_zone_config = DNSReverseZoneConfig(640 dns_zone_config = DNSReverseZoneConfig(
645 factory.getRandomString(), serial=random.randint(1, 100),641 factory.getRandomString(), serial=random.randint(1, 100),
646 dns_ip=dns_ip, network=network)642 network=network)
647 dns_zone_config.write_config()643 dns_zone_config.write_config()
648 self.assertThat(644 self.assertThat(
649 os.path.join(645 os.path.join(
@@ -652,8 +648,7 @@
652 matcher=Contains('IN NS %s.' % dns_zone_config.domain)))648 matcher=Contains('IN NS %s.' % dns_zone_config.domain)))
653649
654 def test_writes_reverse_dns_zone_config(self):650 def test_writes_reverse_dns_zone_config(self):
655 target_dir = self.make_dir()651 target_dir = patch_dns_config_path(self)
656 self.patch(DNSReverseZoneConfig, 'target_dir', target_dir)
657 domain = factory.getRandomString()652 domain = factory.getRandomString()
658 network = IPNetwork('192.168.0.1/22')653 network = IPNetwork('192.168.0.1/22')
659 dns_zone_config = DNSReverseZoneConfig(654 dns_zone_config = DNSReverseZoneConfig(
@@ -667,10 +662,9 @@
667 FileContains(matcher=expected))662 FileContains(matcher=expected))
668663
669 def test_reverse_config_file_is_world_readable(self):664 def test_reverse_config_file_is_world_readable(self):
670 self.patch(DNSReverseZoneConfig, 'target_dir', self.make_dir())665 patch_dns_config_path(self)
671 dns_zone_config = DNSReverseZoneConfig(666 dns_zone_config = DNSReverseZoneConfig(
672 factory.getRandomString(), serial=random.randint(1, 100),667 factory.getRandomString(), serial=random.randint(1, 100),
673 dns_ip=factory.getRandomIPAddress(),
674 network=factory.getRandomNetwork())668 network=factory.getRandomNetwork())
675 dns_zone_config.write_config()669 dns_zone_config.write_config()
676 filepath = FilePath(dns_zone_config.target_path)670 filepath = FilePath(dns_zone_config.target_path)