Browse Source

Merge pull request #585 from phelpsw/environmentvar_txt_support

Adding environment variable record injection
pull/588/head
Ross McFarland 5 years ago
committed by GitHub
parent
commit
53194bd360
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 142 additions and 0 deletions
  1. +1
    -0
      README.md
  2. +100
    -0
      octodns/source/envvar.py
  3. +41
    -0
      tests/test_octodns_source_envvar.py

+ 1
- 0
README.md View File

@ -187,6 +187,7 @@ The above command pulled the existing data out of Route53 and placed the results
| [DnsimpleProvider](/octodns/provider/dnsimple.py) | | All | No | CAA tags restricted |
| [DynProvider](/octodns/provider/dyn.py) | dyn | All | Both | |
| [EtcHostsProvider](/octodns/provider/etc_hosts.py) | | A, AAAA, ALIAS, CNAME | No | |
| [EnvVarSource](/octodns/source/envvar.py) | | TXT | No | read-only environment variable injection |
| [GoogleCloudProvider](/octodns/provider/googlecloud.py) | google-cloud-dns | A, AAAA, CAA, CNAME, MX, NAPTR, NS, PTR, SPF, SRV, TXT | No | |
| [MythicBeastsProvider](/octodns/provider/mythicbeasts.py) | Mythic Beasts | A, AAAA, ALIAS, CNAME, MX, NS, SRV, SSHFP, CAA, TXT | No | |
| [Ns1Provider](/octodns/provider/ns1.py) | ns1-python | All | Yes | No CNAME support, missing `NA` geo target |


+ 100
- 0
octodns/source/envvar.py View File

@ -0,0 +1,100 @@
import logging
import os
from ..record import Record
from .base import BaseSource
class EnvVarSourceException(Exception):
pass
class EnvironmentVariableNotFoundException(EnvVarSourceException):
def __init__(self, data):
super(EnvironmentVariableNotFoundException, self).__init__(
'Unknown environment variable {}'.format(data))
class EnvVarSource(BaseSource):
'''
This source allows for environment variables to be embedded at octodns
execution time into zones. Intended to capture artifacts of deployment to
facilitate operational objectives.
The TXT record generated will only have a single value.
The record name cannot conflict with any other co-existing sources. If
this occurs, an exception will be thrown.
Possible use cases include:
- Embedding a version number into a TXT record to monitor update
propagation across authoritative providers.
- Capturing identifying information about the deployment process to
record where and when the zone was updated.
version:
class: octodns.source.envvar.EnvVarSource
# The environment variable in question, in this example the username
# currently executing octodns
variable: USER
# The TXT record name to embed the value found at the above
# environment variable
name: deployuser
# The TTL of the TXT record (optional, default 60)
ttl: 3600
This source is then combined with other sources in the octodns config
file:
zones:
netflix.com.:
sources:
- yaml
- version
targets:
- ultra
- ns1
'''
SUPPORTS_GEO = False
SUPPORTS_DYNAMIC = False
SUPPORTS = set(('TXT'))
DEFAULT_TTL = 60
def __init__(self, id, variable, name, ttl=DEFAULT_TTL):
self.log = logging.getLogger('{}[{}]'.format(
self.__class__.__name__, id))
self.log.debug('__init__: id=%s, variable=%s, name=%s, '
'ttl=%d', id, variable, name, ttl)
super(EnvVarSource, self).__init__(id)
self.envvar = variable
self.name = name
self.ttl = ttl
def _read_variable(self):
value = os.environ.get(self.envvar)
if value is None:
raise EnvironmentVariableNotFoundException(self.envvar)
self.log.debug('_read_variable: successfully loaded var=%s val=%s',
self.envvar, value)
return value
def populate(self, zone, target=False, lenient=False):
self.log.debug('populate: name=%s, target=%s, lenient=%s', zone.name,
target, lenient)
before = len(zone.records)
value = self._read_variable()
# We don't need to worry about conflicting records here because the
# manager will deconflict sources on our behalf.
payload = {'ttl': self.ttl, 'type': 'TXT', 'values': [value]}
record = Record.new(zone, self.name, payload, source=self,
lenient=lenient)
zone.add_record(record, lenient=lenient)
self.log.info('populate: found %s records, exists=False',
len(zone.records) - before)

+ 41
- 0
tests/test_octodns_source_envvar.py View File

@ -0,0 +1,41 @@
from six import text_type
from unittest import TestCase
from unittest.mock import patch
from octodns.source.envvar import EnvVarSource
from octodns.source.envvar import EnvironmentVariableNotFoundException
from octodns.zone import Zone
class TestEnvVarSource(TestCase):
def test_read_variable(self):
envvar = 'OCTODNS_TEST_ENVIRONMENT_VARIABLE'
source = EnvVarSource('testid', envvar, 'recordname', ttl=120)
with self.assertRaises(EnvironmentVariableNotFoundException) as ctx:
source._read_variable()
msg = 'Unknown environment variable {}'.format(envvar)
self.assertEquals(msg, text_type(ctx.exception))
with patch.dict('os.environ', {envvar: 'testvalue'}):
value = source._read_variable()
self.assertEquals(value, 'testvalue')
def test_populate(self):
envvar = 'TEST_VAR'
value = 'somevalue'
name = 'testrecord'
zone_name = 'unit.tests.'
source = EnvVarSource('testid', envvar, name)
zone = Zone(zone_name, [])
with patch.dict('os.environ', {envvar: value}):
source.populate(zone)
self.assertEquals(1, len(zone.records))
record = list(zone.records)[0]
self.assertEquals(name, record.name)
self.assertEquals('{}.{}'.format(name, zone_name), record.fqdn)
self.assertEquals('TXT', record._type)
self.assertEquals(1, len(record.values))
self.assertEquals(value, record.values[0])

Loading…
Cancel
Save