Writing a Custom Source ======================= Introduction ------------ Creating a custom source of record data for octoDNS is pretty simple and involves a bit of boilerplate and then filling in a single method, :py:meth:`octodns.source.base.BaseSource.populate`, with any logic required to fetch or create the desired records. In this example records will be created for the first 25 elements of the `Fibonacci Sequence`_. While contrived it should illustrate the process and requirements. .. _Fibonacci Sequence: https://en.wikipedia.org/wiki/Fibonacci_sequence Some relevant documentation for this example is in comments in the YAML configuration files and python code. * :download:`config/octodns.yaml` * :download:`config/dns.math.yaml` * :download:`fibonacci.py` From here on this README focuses on the custom source and the process of running octoDNS with access to it. Checking out the code and setting up the environment ---------------------------------------------------- You would not normally need to check out octoDNS itself, you instead would have a git repo with only your configuration files. Here we're cloning the repo only to get a copy of the example files:: $ git clone https://github.com/octodns/octodns.git $ cd octodns/examples/basic/ $ python3 -mvenv env $ source ../env.sh $ source env/bin/activate (env) $ pip install -r requirements.txt Finally check out :ref:`running-powerdns` to get a local instance of PowerDNS up and going before continuing. Running octoDNS sync -------------------- Once you have your custom source, configuration files, and octoDNS installed you're ready to run the sync command to get it to plan an initial set of changes. The main difference here compared to the :ref:`basic-setup` is setting ``PYTHONPATH`` so the source file can be located:: (env) $ export PYTHONPATH=. (env) $ octodns-sync --config-file config/octodns.yaml 2025-08-17T17:14:58 [140224800168896] INFO Manager __init__: config_file=config/octodns.yaml, (octoDNS 1.13.0) 2025-08-17T17:14:58 [140224800168896] INFO Manager _config_executor: max_workers=1 2025-08-17T17:14:58 [140224800168896] INFO Manager _config_include_meta: include_meta=False 2025-08-17T17:14:58 [140224800168896] INFO Manager _config_enable_checksum: enable_checksum=False 2025-08-17T17:14:58 [140224800168896] INFO Manager _config_auto_arpa: auto_arpa=False 2025-08-17T17:14:58 [140224800168896] INFO Manager __init__: global_processors=[] 2025-08-17T17:14:58 [140224800168896] INFO Manager __init__: global_post_processors=[] 2025-08-17T17:14:58 [140224800168896] INFO Manager __init__: provider=config (octodns.provider.yaml 1.13.0) 2025-08-17T17:14:58 [140224800168896] INFO Manager __init__: provider=powerdns (octodns_powerdns 1.0.0) 2025-08-17T17:14:58 [140224800168896] INFO Manager __init__: provider=fibonacci (fibonacci n/a) 2025-08-17T17:14:58 [140224800168896] INFO Manager sync: eligible_zones=[], eligible_targets=[], dry_run=True, force=False, plan_output_fh=, checksum=None 2025-08-17T17:14:58 [140224800168896] INFO Manager sync: zone=dns.math. 2025-08-17T17:14:58 [140224800168896] INFO Manager sync: sources=['config', 'fibonacci'] 2025-08-17T17:14:58 [140224800168896] INFO Manager sync: processors=[] 2025-08-17T17:14:58 [140224800168896] INFO Manager sync: targets=['powerdns'] 2025-08-17T17:14:58 [140224800168896] INFO YamlProvider[config] populate: found 1 records, exists=True 2025-08-17T17:14:58 [140224800168896] INFO FibonacciProvider[fibonacci] populate: found 25 records, exists=False 2025-08-17T17:14:58 [140224800168896] INFO PowerDnsProvider[powerdns] plan: desired=dns.math. 2025-08-17T17:14:58 [140224800168896] INFO PowerDnsProvider[powerdns] populate: found 1 records, exists=True 2025-08-17T17:14:58 [140224800168896] WARNING PowerDnsProvider[powerdns] root NS record supported, but no record is configured for dns.math. 2025-08-17T17:14:58 [140224800168896] INFO PowerDnsProvider[powerdns] plan: Creates=25, Updates=0, Deletes=0, Existing=1, Meta=False 2025-08-17T17:14:58 [140224800168896] INFO Plan ******************************************************************************** * dns.math. ******************************************************************************** * powerdns (PowerDnsProvider) * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Create () * Summary: Creates=25, Updates=0, Deletes=0, Existing=1, Meta=False ******************************************************************************** The log output .............. Everything here matches the output and meaning of the first run in :ref:`basic-setup`, with the important difference that both the statically configured and dynamically generated records are listed as planned changes. From here a ``--doit`` run can be executed to create the records in the PowerDNS server, which can then be queried. Viewing the results ------------------- ``dig`` can now be run to query for the records:: $ dig +short TXT dns.math. "Try querying for TXT records named fibonacci-N where N is an integer 0-25" $ dig +short TXT fibonacci-0.dns.math. "0" $ dig +short TXT fibonacci-23.dns.math. "28657" $ dig +short TXT fibonacci-99.dns.math. Next Steps ---------- If the source will only be used in a single octoDNS setup and you're OK with it living alongside your config, as was done in this example the :download:`fibonacci.py` file can be used as a starting point. It is also possible to create custom processors and providers that work in the same manner, though the details of the code involved are outside the scope of this example. If the provider will be used more widely or published for others to use, see `octodns-template`_. .. _octodns-template: https://github.com/octodns/octodns-template