Merge lp:~jtv/maas/report_missing_config_dir 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: 1834
Proposed branch: lp:~jtv/maas/report_missing_config_dir
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 112 lines (+52/-11)
2 files modified
src/provisioningserver/dns/config.py (+22/-11)
src/provisioningserver/dns/tests/test_config.py (+30/-0)
To merge this branch: bzr merge lp:~jtv/maas/report_missing_config_dir
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Review via email: mp+202443@code.launchpad.net

Commit message

New helper for writing DNS config and zone files: report_missing_config_dir.

Description of the change

This is another small step towards making small amounts of duplication of the write_config and inner_write_config methods painless. The next step is to inline the two inner_write_config implementations into small, slightly different write_config implementations — one using atomic_write and the other incremental_write to create its output file. This is a subtlety that came up late (with unexpected filesystem and BIND complications) in the development of the original code, hence the awkwardness.

With that bit of duplication-with-slight-variation, we will then be able to free ourselves of some of the forced commonality between the 6 classes that together give us the ability to write the 3 kinds of DNS files: config, forward zone, reverse zone.

Jeroen

To post a comment you must log in.
Revision history for this message
Raphaël Badin (rvb) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/provisioningserver/dns/config.py'
2--- src/provisioningserver/dns/config.py 2014-01-21 11:20:51 +0000
3+++ src/provisioningserver/dns/config.py 2014-01-21 12:19:30 +0000
4@@ -25,6 +25,7 @@
5 ABCMeta,
6 abstractproperty,
7 )
8+from contextlib import contextmanager
9 from datetime import datetime
10 import errno
11 from itertools import (
12@@ -210,6 +211,26 @@
13 raise DNSConfigFail(*error.args)
14
15
16+@contextmanager
17+def report_missing_config_dir():
18+ """Report missing DNS config dir as `DNSConfigDirectoryMissing`.
19+
20+ Use this around code that writes a new DNS configuration or zone file.
21+ It catches a "no such file or directory" error and raises a more helpful
22+ `DNSConfigDirectoryMissing` in its place.
23+ """
24+ try:
25+ yield
26+ except (IOError, OSError) as e:
27+ if e.errno == errno.ENOENT:
28+ raise DNSConfigDirectoryMissing(
29+ "The directory where the DNS config files should be "
30+ "written does not exist. Make sure the 'maas-dns' "
31+ "package is installed on this region controller.")
32+ else:
33+ raise
34+
35+
36 class DNSConfigBase:
37 __metaclass__ = ABCMeta
38
39@@ -246,18 +267,8 @@
40 "No such file or directory" error is raised because that would mean
41 that the directory containing the write to be written does not exist.
42 """
43- try:
44+ with report_missing_config_dir():
45 self.inner_write_config(overwrite=overwrite, **kwargs)
46- except OSError as exception:
47- # Only raise a DNSConfigDirectoryMissing exception if this error
48- # is a "No such file or directory" exception.
49- if exception.errno == errno.ENOENT:
50- raise DNSConfigDirectoryMissing(
51- "The directory where the DNS config files should be "
52- "written does not exist. Make sure the 'maas-dns' "
53- "package is installed on this region controller.")
54- else:
55- raise
56
57 def inner_write_config(self, overwrite=True, **kwargs):
58 """Write out this DNS config file."""
59
60=== modified file 'src/provisioningserver/dns/tests/test_config.py'
61--- src/provisioningserver/dns/tests/test_config.py 2014-01-21 11:42:40 +0000
62+++ src/provisioningserver/dns/tests/test_config.py 2014-01-21 12:19:30 +0000
63@@ -49,6 +49,7 @@
64 MAAS_NAMED_RNDC_CONF_NAME,
65 MAAS_RNDC_CONF_NAME,
66 render_dns_template,
67+ report_missing_config_dir,
68 set_up_options_conf,
69 setup_rndc,
70 shortened_reversed_ip,
71@@ -69,6 +70,7 @@
72 Not,
73 StartsWith,
74 )
75+from testtools.testcase import ExpectedException
76 from twisted.python.filepath import FilePath
77
78
79@@ -263,6 +265,34 @@
80 self.assertIn("'x' is not defined", unicode(e))
81
82
83+class TestReportMissingConfigDir(MAASTestCase):
84+ """Tests for the `report_missing_config_dir` context manager."""
85+
86+ def test_specially_reports_missing_config_dir(self):
87+ with ExpectedException(DNSConfigDirectoryMissing):
88+ with report_missing_config_dir():
89+ open(os.path.join(self.make_dir(), 'nonexistent-file.txt'))
90+
91+ def test_succeeds_if_no_exceptions(self):
92+ with report_missing_config_dir():
93+ pass
94+ # The real test is that we get here without error.
95+ pass
96+
97+ def test_passes_on_other_similar_errors(self):
98+ with ExpectedException(OSError):
99+ with report_missing_config_dir():
100+ raise OSError(errno.EACCES, "Deliberate error for testing.")
101+
102+ def test_passes_on_dissimilar_errors(self):
103+ class DeliberateError(Exception):
104+ """Deliberately induced error for testing."""
105+
106+ with ExpectedException(DeliberateError):
107+ with report_missing_config_dir():
108+ raise DeliberateError("This exception propagates unchanged.")
109+
110+
111 class TestDNSConfig(MAASTestCase):
112 """Tests for DNSConfig."""
113