How ntpServerConverter.py Converts YAML to Markdown, chrony.conf, and ntp.toml

The ntpServerConverter.py script reads nts-servers.yml and generates three distinct output formats—Markdown tables for documentation, chrony.conf for the Chrony NTP daemon, and ntp.toml for ntpd-rs—using dedicated generator functions that parse hostname brackets and group servers by location.

The ntpServerConverter.py utility in the jauderho/nts-servers repository serves as a single-source-of-truth converter that transforms structured YAML data into multiple configuration and documentation formats. This Python script ensures consistency between the human-readable server list in the repository's README and the actual daemon configurations deployed in production environments.

Loading and Parsing the YAML Source

Reading nts-servers.yml with load_yaml()

The conversion process begins by ingesting the structured data file. The load_yaml() function at lines 9-12 of scripts/ntpServerConverter.py handles this operation:

def load_yaml(file_path):
    with open(file_path, "r") as file:
        return yaml.safe_load(file)

This helper reads the input file and returns a Python dictionary containing the server definitions, including hostnames, stratum levels, locations, and ownership metadata.

Extracting Clean Hostnames with extract_hostname()

NTS servers in the YAML file may be written in bracketed notation such as hostname[IP]. The extract_hostname() function at lines 14-18 uses regular expressions to strip the bracketed portion so that Chrony and TOML configurations receive plain hostnames:

def extract_hostname(hostname_field):
    match = re.search(r"\[([^\]]+)\]", hostname_field)
    if match:
        return match.group(1)
    return hostname_field

This ensures compatibility with daemon configuration formats that expect DNS names rather than bracketed IP notation.

Generating Markdown Documentation

The generate_markdown() function (lines 21-56) transforms the YAML data into a human-readable table suitable for the repository's README. This generator groups servers by geographic location and handles virtual-machine entries separately.

The function constructs a Markdown table with columns for provider, hostname, port, and key details. Entries marked with "vm": true in the YAML are placed in a distinct "Virtual Machine" section, as virtualized servers may exhibit lower time accuracy than bare-metal implementations.

When run in default mode, the script automatically replaces the existing "## The List" section in README.md with the newly generated table, ensuring documentation stays synchronized with the YAML source.

Creating chrony.conf Configuration

The generate_chrony() function at lines 59-84 produces configuration syntax for the Chrony NTP daemon. This generator iterates over data["servers"] and outputs server <hostname> nts iburst lines, prefixed with comment headings for each location.

The iburst option enables rapid initial synchronization, while nts enforces Network Time Security authentication. The function maintains the same location-based grouping as the Markdown generator, inserting blank lines and comments to create a readable, organized configuration file.

Building ntp.toml for ntpd-rs

For the Rust-based ntpd-rs daemon, the generate_toml() function (lines 86-113) emits TOML [[source]] blocks. Each server entry becomes a separate source configuration with parameters for mode (NTS), address, and certificate verification settings.

The generator preserves location grouping through TOML comments and handles the virtual-machine segregation logic consistent with the other output formats. This ensures administrators can maintain identical server lists across Chrony and ntpd-rs deployments from a single YAML definition.

Command-Line Interface and Usage Modes

The script uses argparse (lines 30-98) to support four distinct operational modes:

Default Mode (No Arguments) Updates README.md and writes both chrony.conf and ntp.toml:

python3 scripts/ntpServerConverter.py data/nts-servers.yml

Single Format Modes Generate only one specific output:


# Markdown only

python3 scripts/ntpServerConverter.py data/nts-servers.yml markdown docs/servers.md

# Chrony configuration only

python3 scripts/ntpServerConverter.py data/nts-servers.yml chrony chrony.conf

# TOML configuration only

python3 scripts/ntpServerConverter.py data/nts-servers.yml toml ntp.toml

The main() function (lines 45-99) orchestrates the workflow: loading YAML, selecting the appropriate generator based on CLI arguments, and writing output to the specified destination.

Summary

  • ntpServerConverter.py serves as the central conversion engine for the jauderho/nts-servers repository, transforming structured YAML into three distinct output formats.
  • The script uses load_yaml() and extract_hostname() to parse input data and normalize hostname formats before generation.
  • Three dedicated generators—generate_markdown(), generate_chrony(), and generate_toml()—handle format-specific syntax, location grouping, and virtual-machine segregation.
  • The CLI supports both default mode (updating README and writing all configs) and single-format mode for targeted output generation.
  • All file paths, function names, and code examples reference the actual implementation in scripts/ntpServerConverter.py.

Frequently Asked Questions

How does ntpServerConverter.py handle bracketed hostnames in the YAML file?

The script uses the extract_hostname() function with a regular expression pattern r"\[([^\]]+)\]" to detect and remove bracketed IP addresses from hostname fields. If brackets are found, the function returns only the content inside them; otherwise, it returns the original hostname unchanged. This ensures Chrony and TOML configurations receive clean DNS names compatible with NTP daemon requirements.

Can I use ntpServerConverter.py to generate only a Markdown table without updating the README?

Yes. Run the script with the markdown argument followed by your desired output file path: python3 scripts/ntpServerConverter.py data/nts-servers.yml markdown output.md. This single-format mode bypasses the README update logic and writes only the Markdown table to the specified destination, making it suitable for generating documentation fragments for external use.

What is the difference between the default mode and single-format mode in ntpServerConverter.py?

Default mode runs when you omit the output format argument, automatically updating the ## The List section in README.md and writing both chrony.conf and ntp.toml files. Single-format mode requires specifying either markdown, chrony, or toml as the second argument, which causes the script to generate only that specific format and write it to the user-provided path, without modifying the README or creating other config files.

How does ntpServerConverter.py separate virtual machine servers from bare-metal servers?

The script checks the "vm": true boolean field in each YAML entry. When generate_markdown(), generate_chrony(), or generate_toml() encounter this flag, they place those servers in a separate "Virtual Machine" section or grouping. This segregation ensures users can distinguish between potentially less accurate virtualized time sources and bare-metal NTS servers when configuring their NTP clients.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →