Commit 33ba1e70 authored by ale's avatar ale

Expand list variables properly

parent cda363df
Pipeline #938 passed with stages
in 44 seconds
......@@ -16,6 +16,16 @@ the zone itself - they are usually recognizable because they're
uppercase (while normal DNS record names are lowercase).
Configuration
=============
The zone configuration is stored in YAML format, usually spread into
multiple files, one per template or zone (though it is possible to
store the configuration for more than one zone in a single YAML file).
By default, the tool scans a given directory recursively looking for
files with the ``.yml`` extension. File names are ignored and only
have a mnemonic purpose.
Record syntax
-------------
......@@ -117,4 +127,13 @@ it is then possible to define a zone as follows::
_: "$FRONTENDS"
www: "$FRONTENDS"
Note that when using this syntax, the resource record can't be a list.
The tool will try to do the right thing when expanding list variables,
whether within a list or not. For instance, a zone such as::
autistici.org:
_:
- $SERVERS
- MX 10 $SERVERS
will result in a zone containing an A record and an MX record for each
entry defined in `SERVERS`.
......@@ -133,7 +133,7 @@ class ZoneParser(object):
continue
resolved = self._resolve_references(zone_name, zone_data)
output = _render_zone(zone_name, resolved, resolved)
yield (zone_name, zone_data, output)
yield (zone_name, resolved, output)
def _resolve_references(self, zone_name, zone_data):
out = {}
......@@ -147,15 +147,38 @@ class ZoneParser(object):
except KeyError:
raise Error('undefined template "%s"' % base)
for key, value in zone_data.iteritems():
if isinstance(value, basestring) and value.startswith('$'):
var_name = value[1:]
# This will break horribly if you use more than one
# variable substitution per record (but why would you?)
var_re = re.compile(r'\$([A-Za-z0-9_]+)')
def _get_var(s):
m = var_re.search(s)
if m:
try:
out[key] = self.config[var_name]
return self.config[m.group(1)]
except KeyError:
raise Error('undefined config variable "%s"' % var_name)
raise Error('undefined config variable "%s"' % m.group(1))
def _expand_value(value):
var_value = _get_var(value)
if not var_value:
return value
elif isinstance(var_value, list):
return [var_re.sub(x, value) for x in var_value]
else:
out[key] = value
return var_re.sub(var_value, value)
for key, value in zone_data.iteritems():
if isinstance(value, basestring):
value = _expand_value(value)
elif isinstance(value, list):
tmp = []
for v in value:
tmpv = _expand_value(v)
if isinstance(tmpv, list):
tmp.extend(tmpv)
else:
tmp.append(tmpv)
value = tmp
out[key] = value
return out
......
......@@ -48,6 +48,17 @@ autistici.org:
''',
]
TEST_DATA_3 = [
'''
autistici.org:
_:
- NS $FRONTENDS
- MX 10 $FRONTENDS
- 82.94.249.234
- 82.221.99.153
''',
]
TEST_CONFIG = {
'FRONTENDS': ['82.94.249.234', '82.221.99.153'],
}
......@@ -70,6 +81,12 @@ class ZoneParserTest(unittest.TestCase):
self.assertTrue(result)
self.assertEquals('autistici.org', result[0][0])
# Verify that $FRONTENDS has been replaced correctly.
self.assertTrue(isinstance(result[0][1]['www'], list))
self.assertEquals(
sorted(result[0][1]['www']),
sorted(TEST_CONFIG['FRONTENDS']))
def test_merge(self):
self.zp.load(_loadyaml(TEST_DATA_2))
result = list(self.zp.render())
......@@ -83,6 +100,16 @@ class ZoneParserTest(unittest.TestCase):
'2a02:f48:2000:201::19', '2002:b2ff:9023::1']
self.assertEquals(expected, www)
def test_expand_list_keywords(self):
self.zp.load(_loadyaml(TEST_DATA_3))
result = list(self.zp.render())
self.assertTrue(result)
self.assertEquals('autistici.org', result[0][0])
# Count the number of NS records.
num_ns = len(filter(lambda x: x.startswith('NS '), result[0][1]['_']))
self.assertEquals(num_ns, 2)
class ZoneWriterTestBase(unittest.TestCase):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment