Merge lp:~mpontillo/maas/dns-template-changes-trunk into lp:~maas-committers/maas/trunk

Proposed by Mike Pontillo
Status: Merged
Approved by: Mike Pontillo
Approved revision: no longer in the source branch.
Merged at revision: 4082
Proposed branch: lp:~mpontillo/maas/dns-template-changes-trunk
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 351 lines (+176/-6)
8 files modified
etc/maas/templates/dns/named.conf.options.inside.maas.template (+7/-0)
src/maasserver/management/commands/edit_named_options.py (+1/-1)
src/maasserver/tests/test_commands_edit_named_options.py (+2/-2)
src/provisioningserver/dns/config.py (+38/-0)
src/provisioningserver/dns/testing.py (+2/-0)
src/provisioningserver/dns/tests/test_config.py (+117/-0)
src/provisioningserver/utils/isc.py (+3/-1)
src/provisioningserver/utils/tests/test_isc.py (+6/-2)
To merge this branch: bzr merge lp:~mpontillo/maas/dns-template-changes-trunk
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Andres Rodriguez (community) Approve
Review via email: mp+264216@code.launchpad.net

Commit message

Allow users to define allow-* parameters in named.conf.options; prevent writing them to named.conf.options.inside.maas in that case.

Description of the change

 * Add code to parse /etc/bind/named.conf.options before writing out the template and check if we're about to write duplicate options to the configuration. If so, suppress those options from being written from within the template.

 * Move ISC parsing utilities to provisioningserver so they can be used within the DNS writing code (which seems like it doesn't belong in provisioningserver in the first place, but moving that seemed more risky than moving a single utility, and the ISC parsing utilities might one day be used on the cluster.)

To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote :

lgtm! Although, I'd like someone else to review as well.

review: Approve
Revision history for this message
Raphaël Badin (rvb) wrote :

Looks good. I've got a question and a bunch of remarks but nothing major.

review: Approve
Revision history for this message
Mike Pontillo (mpontillo) wrote :

Thanks for the review. I went back and re-did this with the "bzr mv" command, and addressed your other concerns.

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (81.3 KiB)

The attempt to merge lp:~mpontillo/maas/dns-template-changes-trunk into lp:maas failed. Below is the output from the failed tests.

Ign http://security.ubuntu.com trusty-security InRelease
Get:1 http://security.ubuntu.com trusty-security Release.gpg [933 B]
Get:2 http://security.ubuntu.com trusty-security Release [63.5 kB]
Ign http://nova.clouds.archive.ubuntu.com trusty InRelease
Ign http://nova.clouds.archive.ubuntu.com trusty-updates InRelease
Get:3 http://security.ubuntu.com trusty-security/main Sources [87.9 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty Release.gpg
Get:4 http://nova.clouds.archive.ubuntu.com trusty-updates Release.gpg [933 B]
Get:5 http://security.ubuntu.com trusty-security/universe Sources [28.1 kB]
Get:6 http://security.ubuntu.com trusty-security/main amd64 Packages [309 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty Release
Get:7 http://nova.clouds.archive.ubuntu.com trusty-updates Release [63.5 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty/main Sources
Get:8 http://security.ubuntu.com trusty-security/universe amd64 Packages [111 kB]
Hit http://security.ubuntu.com trusty-security/main Translation-en
Hit http://security.ubuntu.com trusty-security/universe Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/main amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/universe amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en
Get:9 http://nova.clouds.archive.ubuntu.com trusty-updates/main Sources [213 kB]
Get:10 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Sources [125 kB]
Get:11 http://nova.clouds.archive.ubuntu.com trusty-updates/main amd64 Packages [569 kB]
Get:12 http://nova.clouds.archive.ubuntu.com trusty-updates/universe amd64 Packages [295 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/universe Translation-en
Ign http://nova.clouds.archive.ubuntu.com trusty/main Translation-en_US
Ign http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en_US
Fetched 1,867 kB in 3s (579 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
     --no-install-recommends install apache2 authbind bind9 bind9utils build-essential bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libpq-dev make nodejs-legacy npm pep8 phantomjs postgresql pyflakes python-apt python-bson python-bzrlib python-convoy python-coverage python-crochet python-cssselect python-curtin python-dev python-distro-info python-django python-django-piston python-django-south python-djorm-ext-pgarray python-docutils python-extras python-fixtures python-flake8 python-formencode python-hivex python-httplib2 python-jinja2 python-jsonschema python-lockfile python-lxml python-mock python-netaddr python-netifaces python-n...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'etc/maas/templates/dns/named.conf.options.inside.maas.template'
--- etc/maas/templates/dns/named.conf.options.inside.maas.template 2015-04-24 19:49:30 +0000
+++ etc/maas/templates/dns/named.conf.options.inside.maas.template 2015-07-09 22:46:20 +0000
@@ -8,6 +8,13 @@
88
9dnssec-validation {{dnssec_validation}};9dnssec-validation {{dnssec_validation}};
1010
11
12{{if not upstream_allow_query}}
11allow-query { any; };13allow-query { any; };
14{{endif}}
15{{if not upstream_allow_recursion}}
12allow-recursion { trusted; };16allow-recursion { trusted; };
17{{endif}}
18{{if not upstream_allow_query_cache}}
13allow-query-cache { trusted; };19allow-query-cache { trusted; };
20{{endif}}
1421
=== modified file 'src/maasserver/management/commands/edit_named_options.py'
--- src/maasserver/management/commands/edit_named_options.py 2015-07-07 20:11:36 +0000
+++ src/maasserver/management/commands/edit_named_options.py 2015-07-09 22:46:20 +0000
@@ -33,7 +33,7 @@
33 CommandError,33 CommandError,
34)34)
35from maasserver.models import Config35from maasserver.models import Config
36from maasserver.utils.isc import (36from provisioningserver.utils.isc import (
37 ISCParseException,37 ISCParseException,
38 make_isc_string,38 make_isc_string,
39 parse_isc_string,39 parse_isc_string,
4040
=== modified file 'src/maasserver/tests/test_commands_edit_named_options.py'
--- src/maasserver/tests/test_commands_edit_named_options.py 2015-07-07 22:40:48 +0000
+++ src/maasserver/tests/test_commands_edit_named_options.py 2015-07-09 22:46:20 +0000
@@ -30,12 +30,12 @@
30from maasserver.testing.factory import factory30from maasserver.testing.factory import factory
31from maasserver.testing.testcase import MAASServerTestCase31from maasserver.testing.testcase import MAASServerTestCase
32from maasserver.utils import get_one32from maasserver.utils import get_one
33from maasserver.utils.isc import (33from provisioningserver.dns.config import MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME
34from provisioningserver.utils.isc import (
34 make_isc_string,35 make_isc_string,
35 parse_isc_string,36 parse_isc_string,
36 read_isc_file,37 read_isc_file,
37)38)
38from provisioningserver.dns.config import MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME
39from testtools.matchers import (39from testtools.matchers import (
40 Contains,40 Contains,
41 Equals,41 Equals,
4242
=== modified file 'src/provisioningserver/dns/config.py'
--- src/provisioningserver/dns/config.py 2015-05-07 18:14:38 +0000
+++ src/provisioningserver/dns/config.py 2015-07-09 22:46:20 +0000
@@ -31,10 +31,12 @@
3131
32from provisioningserver.utils import locate_config32from provisioningserver.utils import locate_config
33from provisioningserver.utils.fs import atomic_write33from provisioningserver.utils.fs import atomic_write
34from provisioningserver.utils.isc import read_isc_file
34from provisioningserver.utils.shell import call_and_check35from provisioningserver.utils.shell import call_and_check
35import tempita36import tempita
3637
3738
39NAMED_CONF_OPTIONS = 'named.conf.options'
38MAAS_NAMED_CONF_NAME = 'named.conf.maas'40MAAS_NAMED_CONF_NAME = 'named.conf.maas'
39MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME = 'named.conf.options.inside.maas'41MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME = 'named.conf.options.inside.maas'
40MAAS_NAMED_RNDC_CONF_NAME = 'named.conf.rndc.maas'42MAAS_NAMED_RNDC_CONF_NAME = 'named.conf.rndc.maas'
@@ -53,6 +55,18 @@
53 return setting55 return setting
5456
5557
58def get_bind_config_dir():
59 """Location of bind configuration files."""
60 setting = os.getenv(
61 "MAAS_BIND_CONFIG_DIR",
62 locate_config(os.path.pardir, "bind"))
63 if isinstance(setting, bytes):
64 fsenc = sys.getfilesystemencoding()
65 return setting.decode(fsenc)
66 else:
67 return setting
68
69
56def get_dns_rndc_port():70def get_dns_rndc_port():
57 """RNDC port to be configured by MAAS to communicate with BIND."""71 """RNDC port to be configured by MAAS to communicate with BIND."""
58 setting = os.getenv("MAAS_DNS_RNDC_PORT", "954")72 setting = os.getenv("MAAS_DNS_RNDC_PORT", "954")
@@ -193,6 +207,25 @@
193 # template that uses this value.207 # template that uses this value.
194 kwargs.setdefault("upstream_dns")208 kwargs.setdefault("upstream_dns")
195 kwargs.setdefault("dnssec_validation", "auto")209 kwargs.setdefault("dnssec_validation", "auto")
210
211 # Parse the options file and make sure MAAS doesn't define any options
212 # that the user has already customized.
213 allow_user_override_options = [
214 "allow-query",
215 "allow-recursion",
216 "allow-query-cache",
217 ]
218
219 try:
220 parsed_options = read_isc_file(
221 compose_bind_config_path(NAMED_CONF_OPTIONS))
222 except IOError:
223 parsed_options = {}
224
225 options = parsed_options.get('options', {})
226 for option in allow_user_override_options:
227 kwargs['upstream_' + option.replace('-', '_')] = option in options
228
196 try:229 try:
197 rendered = template.substitute(kwargs)230 rendered = template.substitute(kwargs)
198 except NameError as error:231 except NameError as error:
@@ -207,6 +240,11 @@
207 return os.path.join(get_dns_config_dir(), filename)240 return os.path.join(get_dns_config_dir(), filename)
208241
209242
243def compose_bind_config_path(filename):
244 """Return the full path for a DNS config or zone file."""
245 return os.path.join(get_bind_config_dir(), filename)
246
247
210def render_dns_template(template_name, *parameters):248def render_dns_template(template_name, *parameters):
211 """Generate contents for a DNS configuration or zone file.249 """Generate contents for a DNS configuration or zone file.
212250
213251
=== modified file 'src/provisioningserver/dns/testing.py'
--- src/provisioningserver/dns/testing.py 2015-05-11 09:51:49 +0000
+++ src/provisioningserver/dns/testing.py 2015-07-09 22:46:20 +0000
@@ -32,6 +32,8 @@
32 config_dir = config_dir.encode(fsenc)32 config_dir = config_dir.encode(fsenc)
33 testcase.useFixture(33 testcase.useFixture(
34 EnvironmentVariable(b"MAAS_DNS_CONFIG_DIR", config_dir))34 EnvironmentVariable(b"MAAS_DNS_CONFIG_DIR", config_dir))
35 testcase.useFixture(
36 EnvironmentVariable(b"MAAS_BIND_CONFIG_DIR", config_dir))
35 return config_dir.decode(fsenc)37 return config_dir.decode(fsenc)
3638
3739
3840
=== modified file 'src/provisioningserver/dns/tests/test_config.py'
--- src/provisioningserver/dns/tests/test_config.py 2015-05-07 18:14:38 +0000
+++ src/provisioningserver/dns/tests/test_config.py 2015-07-09 22:46:20 +0000
@@ -39,6 +39,7 @@
39 MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME,39 MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME,
40 MAAS_NAMED_RNDC_CONF_NAME,40 MAAS_NAMED_RNDC_CONF_NAME,
41 MAAS_RNDC_CONF_NAME,41 MAAS_RNDC_CONF_NAME,
42 NAMED_CONF_OPTIONS,
42 render_dns_template,43 render_dns_template,
43 report_missing_config_dir,44 report_missing_config_dir,
44 set_up_options_conf,45 set_up_options_conf,
@@ -54,12 +55,16 @@
54 DNSReverseZoneConfig,55 DNSReverseZoneConfig,
55)56)
56from provisioningserver.utils import locate_config57from provisioningserver.utils import locate_config
58from provisioningserver.utils.isc import read_isc_file
57from testtools.matchers import (59from testtools.matchers import (
60 AllMatch,
58 Contains,61 Contains,
59 ContainsAll,62 ContainsAll,
60 EndsWith,63 EndsWith,
64 Equals,
61 FileContains,65 FileContains,
62 FileExists,66 FileExists,
67 Is,
63 IsInstance,68 IsInstance,
64 MatchesAll,69 MatchesAll,
65 Not,70 Not,
@@ -70,6 +75,47 @@
70from twisted.python.filepath import FilePath75from twisted.python.filepath import FilePath
7176
7277
78NAMED_CONF_OPTIONS_CONTENTS = dedent("""\
79 options {
80 forwarders {
81 8.8.8.8;
82 8.8.4.4;
83 };
84 dnssec-validation auto;
85 allow-query { any; };
86 allow-recursion { trusted; };
87 allow-query-cache { trusted; };
88 auth-nxdomain no;
89 listen-on-v6 { any; };
90 };
91 """)
92
93NAMED_CONF_OPTIONS_WITH_ALLOW_QUERY_CONTENTS = dedent("""\
94 options {
95 forwarders {
96 8.8.8.8;
97 8.8.4.4;
98 };
99 dnssec-validation auto;
100 allow-query { any; };
101 auth-nxdomain no;
102 listen-on-v6 { any; };
103 };
104 """)
105
106NAMED_CONF_OPTIONS_NO_ALLOW_CONTENTS = dedent("""\
107 options {
108 forwarders {
109 8.8.8.8;
110 8.8.4.4;
111 };
112 dnssec-validation auto;
113 auth-nxdomain no;
114 listen-on-v6 { any; };
115 };
116 """)
117
118
73class TestHelpers(MAASTestCase):119class TestHelpers(MAASTestCase):
74120
75 def test_get_dns_config_dir_defaults_to_etc_bind_maas(self):121 def test_get_dns_config_dir_defaults_to_etc_bind_maas(self):
@@ -90,6 +136,24 @@
90 IsInstance(unicode),136 IsInstance(unicode),
91 ))137 ))
92138
139 def test_get_bind_config_dir_defaults_to_etc_bind_maas(self):
140 self.useFixture(EnvironmentVariable("MAAS_BIND_CONFIG_DIR"))
141 self.assertThat(
142 config.get_bind_config_dir(), MatchesAll(
143 SamePath(locate_config("../bind")),
144 IsInstance(unicode),
145 ))
146
147 def test_get_bind_config_dir_checks_environ_first(self):
148 directory = self.make_dir()
149 self.useFixture(EnvironmentVariable(
150 "MAAS_BIND_CONFIG_DIR", directory.encode("ascii")))
151 self.assertThat(
152 config.get_bind_config_dir(), MatchesAll(
153 SamePath(directory),
154 IsInstance(unicode),
155 ))
156
93 def test_get_dns_root_port_defaults_to_954(self):157 def test_get_dns_root_port_defaults_to_954(self):
94 self.useFixture(EnvironmentVariable("MAAS_DNS_RNDC_PORT"))158 self.useFixture(EnvironmentVariable("MAAS_DNS_RNDC_PORT"))
95 self.assertEqual(954, config.get_dns_rndc_port())159 self.assertEqual(954, config.get_dns_rndc_port())
@@ -142,6 +206,59 @@
142 FileContains(matcher=Contains(address))206 FileContains(matcher=Contains(address))
143 for address in fake_dns)))207 for address in fake_dns)))
144208
209 def test_set_up_options_conf_write_config_assumes_no_overrides(self):
210 dns_conf_dir = patch_dns_config_path(self)
211 set_up_options_conf()
212 target_file = os.path.join(
213 dns_conf_dir, MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME)
214 target = read_isc_file(target_file)
215 self.assertThat([
216 target['allow-query']['any'],
217 target['allow-recursion']['trusted'],
218 target['allow-query-cache']['trusted'],
219 ], AllMatch(Equals(True)))
220
221 def test_set_up_options_conf_write_config_allows_overrides(self):
222 dns_conf_dir = patch_dns_config_path(self)
223 factory.make_file(
224 location=dns_conf_dir, name=NAMED_CONF_OPTIONS,
225 contents=NAMED_CONF_OPTIONS_CONTENTS)
226 set_up_options_conf()
227 target_file = os.path.join(
228 dns_conf_dir, MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME)
229 target = read_isc_file(target_file)
230 self.assertThat([
231 target.get('allow-query'),
232 target.get('allow-recursion'),
233 target.get('allow-query-cache'),
234 ], AllMatch(Is(None)))
235
236 def test_set_up_options_conf_write_config_allows_zero_overrides(self):
237 dns_conf_dir = patch_dns_config_path(self)
238 factory.make_file(
239 location=dns_conf_dir, name=NAMED_CONF_OPTIONS,
240 contents=NAMED_CONF_OPTIONS_NO_ALLOW_CONTENTS)
241 set_up_options_conf()
242 target_file = os.path.join(
243 dns_conf_dir, MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME)
244 target = read_isc_file(target_file)
245 self.assertThat([
246 target['allow-query']['any'],
247 target['allow-recursion']['trusted'],
248 target['allow-query-cache']['trusted'],
249 ], AllMatch(Equals(True)))
250
251 def test_set_up_options_conf_write_config_allows_single_override(self):
252 dns_conf_dir = patch_dns_config_path(self)
253 factory.make_file(
254 location=dns_conf_dir, name=NAMED_CONF_OPTIONS,
255 contents=NAMED_CONF_OPTIONS_WITH_ALLOW_QUERY_CONTENTS)
256 set_up_options_conf()
257 target_file = os.path.join(
258 dns_conf_dir, MAAS_NAMED_CONF_OPTIONS_INSIDE_NAME)
259 target = read_isc_file(target_file)
260 self.assertIsNone(target.get('allow-query'))
261
145 def test_set_up_options_conf_handles_no_upstream_dns(self):262 def test_set_up_options_conf_handles_no_upstream_dns(self):
146 dns_conf_dir = patch_dns_config_path(self)263 dns_conf_dir = patch_dns_config_path(self)
147 set_up_options_conf()264 set_up_options_conf()
148265
=== renamed file 'src/maasserver/utils/isc.py' => 'src/provisioningserver/utils/isc.py'
--- src/maasserver/utils/isc.py 2015-07-07 20:50:41 +0000
+++ src/provisioningserver/utils/isc.py 2015-07-09 22:46:20 +0000
@@ -144,6 +144,8 @@
144 # If there are more than 1 'keywords' at new_char_list[index]144 # If there are more than 1 'keywords' at new_char_list[index]
145 # ex - "recursion no;"145 # ex - "recursion no;"
146 elif len(new_char_list[index].split()) >= 2:146 elif len(new_char_list[index].split()) >= 2:
147 if type(dictionary_fragment) == list:
148 raise ISCParseException("Syntax error")
147 dictionary_fragment[149 dictionary_fragment[
148 new_char_list[index].split()[0]] = (150 new_char_list[index].split()[0]] = (
149 ' '.join(new_char_list[index].split()[1:]))151 ' '.join(new_char_list[index].split()[1:]))
@@ -155,7 +157,7 @@
155 elif new_char_list[index] not in ['{', ';', '}']:157 elif new_char_list[index] not in ['{', ';', '}']:
156 key = new_char_list[index]158 key = new_char_list[index]
157 if type(dictionary_fragment) == list:159 if type(dictionary_fragment) == list:
158 raise ISCParseException("Dictionary expected; got a list")160 raise ISCParseException("Syntax error")
159 dictionary_fragment[key] = ''161 dictionary_fragment[key] = ''
160 index += 1162 index += 1
161 index += 1163 index += 1
162164
=== renamed file 'src/maasserver/utils/tests/test_isc.py' => 'src/provisioningserver/utils/tests/test_isc.py'
--- src/maasserver/utils/tests/test_isc.py 2015-07-07 20:50:41 +0000
+++ src/provisioningserver/utils/tests/test_isc.py 2015-07-09 22:46:20 +0000
@@ -18,13 +18,13 @@
18from collections import OrderedDict18from collections import OrderedDict
19from textwrap import dedent19from textwrap import dedent
2020
21from maasserver.utils.isc import (21from maastesting.testcase import MAASTestCase
22from provisioningserver.utils.isc import (
22 ISCParseException,23 ISCParseException,
23 make_isc_string,24 make_isc_string,
24 parse_isc_string,25 parse_isc_string,
25 read_isc_file,26 read_isc_file,
26)27)
27from maastesting.testcase import MAASTestCase
28from testtools import ExpectedException28from testtools import ExpectedException
2929
3030
@@ -220,6 +220,10 @@
220 with ExpectedException(ISCParseException):220 with ExpectedException(ISCParseException):
221 parse_isc_string("forwarders {{}a;;b}")221 parse_isc_string("forwarders {{}a;;b}")
222222
223 def test_parse_forgotten_semicolons_throw_iscparseexception(self):
224 with ExpectedException(ISCParseException):
225 parse_isc_string("a { b; } { c; } d e;")
226
223 def test_read_isc_file(self):227 def test_read_isc_file(self):
224 testdata = dedent("""\228 testdata = dedent("""\
225 acl canonical-int-ns { 91.189.90.151; 91.189.89.192; };229 acl canonical-int-ns { 91.189.90.151; 91.189.89.192; };