diff --git a/.changelog/3e57e696039c4f37a3062043be81199c.md b/.changelog/3e57e696039c4f37a3062043be81199c.md new file mode 100644 index 0000000..56c3112 --- /dev/null +++ b/.changelog/3e57e696039c4f37a3062043be81199c.md @@ -0,0 +1,4 @@ +--- +type: minor +--- +Add trailing_dots parameter to templating processor diff --git a/octodns/processor/templating.py b/octodns/processor/templating.py index 6436f48..616a715 100644 --- a/octodns/processor/templating.py +++ b/octodns/processor/templating.py @@ -23,6 +23,10 @@ class Templating(BaseProcessor): templating: class: octodns.processor.templating.Templating + # When `trailing_dots` is disabled, trailing dots are removed from all + # built-in variables values who represent a FQDN, like `{zone_name}` + # or `{record_fqdn}`. Optional. Default to `True`. + trailing_dots: False # Any k/v present in context will be passed into the .format method and # thus be available as additional variables in the template. This is all # optional. @@ -63,16 +67,24 @@ class Templating(BaseProcessor): ''' - def __init__(self, id, *args, context={}, **kwargs): + def __init__(self, id, *args, trailing_dots=True, context={}, **kwargs): super().__init__(id, *args, **kwargs) + self.trailing_dots = trailing_dots self.context = context def process_source_zone(self, desired, sources): sources = sources or [] + zone_name = desired.decoded_name + zone_decoded_name = desired.decoded_name + zone_encoded_name = desired.name + if not self.trailing_dots: + zone_name = zone_name[:-1] + zone_decoded_name = zone_decoded_name[:-1] + zone_encoded_name = zone_encoded_name[:-1] zone_params = { - 'zone_name': desired.decoded_name, - 'zone_decoded_name': desired.decoded_name, - 'zone_encoded_name': desired.name, + 'zone_name': zone_name, + 'zone_decoded_name': zone_decoded_name, + 'zone_encoded_name': zone_encoded_name, 'zone_num_records': len(desired.records), 'zone_source_ids': ', '.join(s.id for s in sources), # add any extra context provided to us, if the value is a callable @@ -85,13 +97,20 @@ class Templating(BaseProcessor): } def build_params(record): + record_fqdn = record.decoded_fqdn + record_decoded_fqdn = record.decoded_fqdn + record_encoded_fqdn = record.fqdn + if not self.trailing_dots: + record_fqdn = record_fqdn[:-1] + record_decoded_fqdn = record_decoded_fqdn[:-1] + record_encoded_fqdn = record_encoded_fqdn[:-1] return { 'record_name': record.decoded_name, 'record_decoded_name': record.decoded_name, 'record_encoded_name': record.name, - 'record_fqdn': record.decoded_fqdn, - 'record_decoded_fqdn': record.decoded_fqdn, - 'record_encoded_fqdn': record.fqdn, + 'record_fqdn': record_fqdn, + 'record_decoded_fqdn': record_decoded_fqdn, + 'record_encoded_fqdn': record_encoded_fqdn, 'record_type': record._type, 'record_ttl': record.ttl, 'record_source_id': record.source.id if record.source else None, diff --git a/tests/test_octodns_processor_templating.py b/tests/test_octodns_processor_templating.py index 761ec06..f959964 100644 --- a/tests/test_octodns_processor_templating.py +++ b/tests/test_octodns_processor_templating.py @@ -188,6 +188,50 @@ class TemplatingTest(TestCase): mock_template.call_args, ) + @patch('octodns.record.TxtValue.template') + def test_trailing_dots(self, mock_template): + templ = Templating('test', trailing_dots=False) + + zone = Zone('unit.tests.', []) + record_source = DummySource('record') + txt = Record.new( + zone, + 'txt', + { + 'type': 'TXT', + 'ttl': 42, + 'value': 'There are {zone_num_records} record(s) in {zone_name}.', + }, + source=record_source, + ) + zone.add_record(txt) + + templ.process_source_zone( + zone, sources=[record_source, DummySource('other')] + ) + mock_template.assert_called_once() + self.assertEqual( + call( + { + 'record_name': 'txt', + 'record_decoded_name': 'txt', + 'record_encoded_name': 'txt', + 'record_fqdn': 'txt.unit.tests', + 'record_decoded_fqdn': 'txt.unit.tests', + 'record_encoded_fqdn': 'txt.unit.tests', + 'record_type': 'TXT', + 'record_ttl': 42, + 'record_source_id': 'record', + 'zone_name': 'unit.tests', + 'zone_decoded_name': 'unit.tests', + 'zone_encoded_name': 'unit.tests', + 'zone_num_records': 1, + 'zone_source_ids': 'record, other', + } + ), + mock_template.call_args, + ) + def test_context(self): templ = Templating( 'test',