Update configuration files, templates, and internal documentation for the provisioning repository system. Configuration Updates: - KMS configuration modernization - Plugin system settings - Service port mappings - Test cluster topologies - Installation configuration examples - VM configuration defaults - Cedar authorization policies Documentation Updates: - Library module documentation - Extension API guides - AI system documentation - Service management guides - Test environment setup - Plugin usage guides - Validator configuration documentation All changes are backward compatible.
972 lines
40 KiB
HTML
972 lines
40 KiB
HTML
<!DOCTYPE HTML>
|
||
<html lang="en" class="ayu sidebar-visible" dir="ltr">
|
||
<head>
|
||
<!-- Book generated using mdBook -->
|
||
<meta charset="UTF-8">
|
||
<title>CoreDNS Guide - Provisioning Platform Documentation</title>
|
||
|
||
|
||
<!-- Custom HTML head -->
|
||
|
||
<meta name="description" content="Complete documentation for the Provisioning Platform - Infrastructure automation with Nushell, KCL, and Rust">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="theme-color" content="#ffffff">
|
||
|
||
<link rel="icon" href="../favicon.svg">
|
||
<link rel="shortcut icon" href="../favicon.png">
|
||
<link rel="stylesheet" href="../css/variables.css">
|
||
<link rel="stylesheet" href="../css/general.css">
|
||
<link rel="stylesheet" href="../css/chrome.css">
|
||
<link rel="stylesheet" href="../css/print.css" media="print">
|
||
|
||
<!-- Fonts -->
|
||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
||
<link rel="stylesheet" href="../fonts/fonts.css">
|
||
|
||
<!-- Highlight.js Stylesheets -->
|
||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
||
|
||
<!-- Custom theme stylesheets -->
|
||
|
||
|
||
<!-- Provide site root and default themes to javascript -->
|
||
<script>
|
||
const path_to_root = "../";
|
||
const default_light_theme = "ayu";
|
||
const default_dark_theme = "navy";
|
||
</script>
|
||
<!-- Start loading toc.js asap -->
|
||
<script src="../toc.js"></script>
|
||
</head>
|
||
<body>
|
||
<div id="mdbook-help-container">
|
||
<div id="mdbook-help-popup">
|
||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
||
<div>
|
||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
||
<p>Press <kbd>?</kbd> to show this help</p>
|
||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="body-container">
|
||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||
<script>
|
||
try {
|
||
let theme = localStorage.getItem('mdbook-theme');
|
||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
||
|
||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||
}
|
||
|
||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||
}
|
||
} catch (e) { }
|
||
</script>
|
||
|
||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||
<script>
|
||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
||
let theme;
|
||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||
const html = document.documentElement;
|
||
html.classList.remove('ayu')
|
||
html.classList.add(theme);
|
||
html.classList.add("js");
|
||
</script>
|
||
|
||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||
|
||
<!-- Hide / unhide sidebar before it is displayed -->
|
||
<script>
|
||
let sidebar = null;
|
||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||
if (document.body.clientWidth >= 1080) {
|
||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||
sidebar = sidebar || 'visible';
|
||
} else {
|
||
sidebar = 'hidden';
|
||
}
|
||
sidebar_toggle.checked = sidebar === 'visible';
|
||
html.classList.remove('sidebar-visible');
|
||
html.classList.add("sidebar-" + sidebar);
|
||
</script>
|
||
|
||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||
<!-- populated by js -->
|
||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
||
<noscript>
|
||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
||
</noscript>
|
||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||
<div class="sidebar-resize-indicator"></div>
|
||
</div>
|
||
</nav>
|
||
|
||
<div id="page-wrapper" class="page-wrapper">
|
||
|
||
<div class="page">
|
||
<div id="menu-bar-hover-placeholder"></div>
|
||
<div id="menu-bar" class="menu-bar sticky">
|
||
<div class="left-buttons">
|
||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||
<i class="fa fa-bars"></i>
|
||
</label>
|
||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||
<i class="fa fa-paint-brush"></i>
|
||
</button>
|
||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||
</ul>
|
||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
||
<i class="fa fa-search"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<h1 class="menu-title">Provisioning Platform Documentation</h1>
|
||
|
||
<div class="right-buttons">
|
||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
||
<i id="print-button" class="fa fa-print"></i>
|
||
</a>
|
||
<a href="https://github.com/provisioning/provisioning-platform" title="Git repository" aria-label="Git repository">
|
||
<i id="git-repository-button" class="fa fa-github"></i>
|
||
</a>
|
||
<a href="https://github.com/provisioning/provisioning-platform/edit/main/provisioning/docs/src/user/COREDNS_GUIDE.md" title="Suggest an edit" aria-label="Suggest an edit">
|
||
<i id="git-edit-button" class="fa fa-edit"></i>
|
||
</a>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div id="search-wrapper" class="hidden">
|
||
<form id="searchbar-outer" class="searchbar-outer">
|
||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||
</form>
|
||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||
<div id="searchresults-header" class="searchresults-header"></div>
|
||
<ul id="searchresults">
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||
<script>
|
||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||
});
|
||
</script>
|
||
|
||
<div id="content" class="content">
|
||
<main>
|
||
<h1 id="coredns-integration-guide"><a class="header" href="#coredns-integration-guide">CoreDNS Integration Guide</a></h1>
|
||
<p><strong>Version</strong>: 1.0.0
|
||
<strong>Date</strong>: 2025-10-06
|
||
<strong>Author</strong>: CoreDNS Integration Agent</p>
|
||
<h2 id="table-of-contents"><a class="header" href="#table-of-contents">Table of Contents</a></h2>
|
||
<ol>
|
||
<li><a href="#overview">Overview</a></li>
|
||
<li><a href="#installation">Installation</a></li>
|
||
<li><a href="#configuration">Configuration</a></li>
|
||
<li><a href="#cli-commands">CLI Commands</a></li>
|
||
<li><a href="#zone-management">Zone Management</a></li>
|
||
<li><a href="#record-management">Record Management</a></li>
|
||
<li><a href="#docker-deployment">Docker Deployment</a></li>
|
||
<li><a href="#integration">Integration</a></li>
|
||
<li><a href="#troubleshooting">Troubleshooting</a></li>
|
||
<li><a href="#advanced-topics">Advanced Topics</a></li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
|
||
<p>The CoreDNS integration provides comprehensive DNS management capabilities for the provisioning system. It supports:</p>
|
||
<ul>
|
||
<li><strong>Local DNS service</strong> - Run CoreDNS as binary or Docker container</li>
|
||
<li><strong>Dynamic DNS updates</strong> - Automatic registration of infrastructure changes</li>
|
||
<li><strong>Multi-zone support</strong> - Manage multiple DNS zones</li>
|
||
<li><strong>Provider integration</strong> - Seamless integration with orchestrator</li>
|
||
<li><strong>REST API</strong> - Programmatic DNS management</li>
|
||
<li><strong>Docker deployment</strong> - Containerized CoreDNS with docker-compose</li>
|
||
</ul>
|
||
<h3 id="key-features"><a class="header" href="#key-features">Key Features</a></h3>
|
||
<p>✅ <strong>Automatic Server Registration</strong> - Servers automatically registered in DNS on creation
|
||
✅ <strong>Zone File Management</strong> - Create, update, and manage zone files programmatically
|
||
✅ <strong>Multiple Deployment Modes</strong> - Binary, Docker, remote, or hybrid
|
||
✅ <strong>Health Monitoring</strong> - Built-in health checks and metrics
|
||
✅ <strong>CLI Interface</strong> - Comprehensive command-line tools
|
||
✅ <strong>API Integration</strong> - REST API for external integration</p>
|
||
<hr />
|
||
<h2 id="installation"><a class="header" href="#installation">Installation</a></h2>
|
||
<h3 id="prerequisites"><a class="header" href="#prerequisites">Prerequisites</a></h3>
|
||
<ul>
|
||
<li><strong>Nushell 0.107+</strong> - For CLI and scripts</li>
|
||
<li><strong>Docker</strong> (optional) - For containerized deployment</li>
|
||
<li><strong>dig</strong> (optional) - For DNS queries</li>
|
||
</ul>
|
||
<h3 id="install-coredns-binary"><a class="header" href="#install-coredns-binary">Install CoreDNS Binary</a></h3>
|
||
<pre><code class="language-bash"># Install latest version
|
||
provisioning dns install
|
||
|
||
# Install specific version
|
||
provisioning dns install 1.11.1
|
||
|
||
# Check mode
|
||
provisioning dns install --check
|
||
</code></pre>
|
||
<p>The binary will be installed to <code>~/.provisioning/bin/coredns</code>.</p>
|
||
<h3 id="verify-installation"><a class="header" href="#verify-installation">Verify Installation</a></h3>
|
||
<pre><code class="language-bash"># Check CoreDNS version
|
||
~/.provisioning/bin/coredns -version
|
||
|
||
# Verify installation
|
||
ls -lh ~/.provisioning/bin/coredns
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="configuration"><a class="header" href="#configuration">Configuration</a></h2>
|
||
<h3 id="kcl-configuration-schema"><a class="header" href="#kcl-configuration-schema">KCL Configuration Schema</a></h3>
|
||
<p>Add CoreDNS configuration to your infrastructure config:</p>
|
||
<pre><code class="language-kcl"># In workspace/infra/{name}/config.k
|
||
import provisioning.coredns as dns
|
||
|
||
coredns_config: dns.CoreDNSConfig = {
|
||
mode = "local"
|
||
|
||
local = {
|
||
enabled = True
|
||
deployment_type = "binary" # or "docker"
|
||
binary_path = "~/.provisioning/bin/coredns"
|
||
config_path = "~/.provisioning/coredns/Corefile"
|
||
zones_path = "~/.provisioning/coredns/zones"
|
||
port = 5353
|
||
auto_start = True
|
||
zones = ["provisioning.local", "workspace.local"]
|
||
}
|
||
|
||
dynamic_updates = {
|
||
enabled = True
|
||
api_endpoint = "http://localhost:9090/dns"
|
||
auto_register_servers = True
|
||
auto_unregister_servers = True
|
||
ttl = 300
|
||
}
|
||
|
||
upstream = ["8.8.8.8", "1.1.1.1"]
|
||
default_ttl = 3600
|
||
enable_logging = True
|
||
enable_metrics = True
|
||
metrics_port = 9153
|
||
}
|
||
</code></pre>
|
||
<h3 id="configuration-modes"><a class="header" href="#configuration-modes">Configuration Modes</a></h3>
|
||
<h4 id="local-mode-binary"><a class="header" href="#local-mode-binary">Local Mode (Binary)</a></h4>
|
||
<p>Run CoreDNS as a local binary process:</p>
|
||
<pre><code class="language-kcl">coredns_config: CoreDNSConfig = {
|
||
mode = "local"
|
||
local = {
|
||
deployment_type = "binary"
|
||
auto_start = True
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h4 id="local-mode-docker"><a class="header" href="#local-mode-docker">Local Mode (Docker)</a></h4>
|
||
<p>Run CoreDNS in Docker container:</p>
|
||
<pre><code class="language-kcl">coredns_config: CoreDNSConfig = {
|
||
mode = "local"
|
||
local = {
|
||
deployment_type = "docker"
|
||
docker = {
|
||
image = "coredns/coredns:1.11.1"
|
||
container_name = "provisioning-coredns"
|
||
restart_policy = "unless-stopped"
|
||
}
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h4 id="remote-mode"><a class="header" href="#remote-mode">Remote Mode</a></h4>
|
||
<p>Connect to external CoreDNS service:</p>
|
||
<pre><code class="language-kcl">coredns_config: CoreDNSConfig = {
|
||
mode = "remote"
|
||
remote = {
|
||
enabled = True
|
||
endpoints = ["https://dns1.example.com", "https://dns2.example.com"]
|
||
zones = ["production.local"]
|
||
verify_tls = True
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h4 id="disabled-mode"><a class="header" href="#disabled-mode">Disabled Mode</a></h4>
|
||
<p>Disable CoreDNS integration:</p>
|
||
<pre><code class="language-kcl">coredns_config: CoreDNSConfig = {
|
||
mode = "disabled"
|
||
}
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="cli-commands"><a class="header" href="#cli-commands">CLI Commands</a></h2>
|
||
<h3 id="service-management"><a class="header" href="#service-management">Service Management</a></h3>
|
||
<pre><code class="language-bash"># Check status
|
||
provisioning dns status
|
||
|
||
# Start service
|
||
provisioning dns start
|
||
|
||
# Start in foreground (for debugging)
|
||
provisioning dns start --foreground
|
||
|
||
# Stop service
|
||
provisioning dns stop
|
||
|
||
# Restart service
|
||
provisioning dns restart
|
||
|
||
# Reload configuration (graceful)
|
||
provisioning dns reload
|
||
|
||
# View logs
|
||
provisioning dns logs
|
||
|
||
# Follow logs
|
||
provisioning dns logs --follow
|
||
|
||
# Show last 100 lines
|
||
provisioning dns logs --lines 100
|
||
</code></pre>
|
||
<h3 id="health--monitoring"><a class="header" href="#health--monitoring">Health & Monitoring</a></h3>
|
||
<pre><code class="language-bash"># Check health
|
||
provisioning dns health
|
||
|
||
# View configuration
|
||
provisioning dns config show
|
||
|
||
# Validate configuration
|
||
provisioning dns config validate
|
||
|
||
# Generate new Corefile
|
||
provisioning dns config generate
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="zone-management"><a class="header" href="#zone-management">Zone Management</a></h2>
|
||
<h3 id="list-zones"><a class="header" href="#list-zones">List Zones</a></h3>
|
||
<pre><code class="language-bash"># List all zones
|
||
provisioning dns zone list
|
||
</code></pre>
|
||
<p><strong>Output:</strong></p>
|
||
<pre><code>DNS Zones
|
||
=========
|
||
• provisioning.local ✓
|
||
• workspace.local ✓
|
||
</code></pre>
|
||
<h3 id="create-zone"><a class="header" href="#create-zone">Create Zone</a></h3>
|
||
<pre><code class="language-bash"># Create new zone
|
||
provisioning dns zone create myapp.local
|
||
|
||
# Check mode
|
||
provisioning dns zone create myapp.local --check
|
||
</code></pre>
|
||
<h3 id="show-zone-details"><a class="header" href="#show-zone-details">Show Zone Details</a></h3>
|
||
<pre><code class="language-bash"># Show all records in zone
|
||
provisioning dns zone show provisioning.local
|
||
|
||
# JSON format
|
||
provisioning dns zone show provisioning.local --format json
|
||
|
||
# YAML format
|
||
provisioning dns zone show provisioning.local --format yaml
|
||
</code></pre>
|
||
<h3 id="delete-zone"><a class="header" href="#delete-zone">Delete Zone</a></h3>
|
||
<pre><code class="language-bash"># Delete zone (with confirmation)
|
||
provisioning dns zone delete myapp.local
|
||
|
||
# Force deletion (skip confirmation)
|
||
provisioning dns zone delete myapp.local --force
|
||
|
||
# Check mode
|
||
provisioning dns zone delete myapp.local --check
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="record-management"><a class="header" href="#record-management">Record Management</a></h2>
|
||
<h3 id="add-records"><a class="header" href="#add-records">Add Records</a></h3>
|
||
<h4 id="a-record-ipv4"><a class="header" href="#a-record-ipv4">A Record (IPv4)</a></h4>
|
||
<pre><code class="language-bash">provisioning dns record add server-01 A 10.0.1.10
|
||
|
||
# With custom TTL
|
||
provisioning dns record add server-01 A 10.0.1.10 --ttl 600
|
||
|
||
# With comment
|
||
provisioning dns record add server-01 A 10.0.1.10 --comment "Web server"
|
||
|
||
# Different zone
|
||
provisioning dns record add server-01 A 10.0.1.10 --zone myapp.local
|
||
</code></pre>
|
||
<h4 id="aaaa-record-ipv6"><a class="header" href="#aaaa-record-ipv6">AAAA Record (IPv6)</a></h4>
|
||
<pre><code class="language-bash">provisioning dns record add server-01 AAAA 2001:db8::1
|
||
</code></pre>
|
||
<h4 id="cname-record"><a class="header" href="#cname-record">CNAME Record</a></h4>
|
||
<pre><code class="language-bash">provisioning dns record add web CNAME server-01.provisioning.local
|
||
</code></pre>
|
||
<h4 id="mx-record"><a class="header" href="#mx-record">MX Record</a></h4>
|
||
<pre><code class="language-bash">provisioning dns record add @ MX mail.example.com --priority 10
|
||
</code></pre>
|
||
<h4 id="txt-record"><a class="header" href="#txt-record">TXT Record</a></h4>
|
||
<pre><code class="language-bash">provisioning dns record add @ TXT "v=spf1 mx -all"
|
||
</code></pre>
|
||
<h3 id="remove-records"><a class="header" href="#remove-records">Remove Records</a></h3>
|
||
<pre><code class="language-bash"># Remove record
|
||
provisioning dns record remove server-01
|
||
|
||
# Different zone
|
||
provisioning dns record remove server-01 --zone myapp.local
|
||
|
||
# Check mode
|
||
provisioning dns record remove server-01 --check
|
||
</code></pre>
|
||
<h3 id="update-records"><a class="header" href="#update-records">Update Records</a></h3>
|
||
<pre><code class="language-bash"># Update record value
|
||
provisioning dns record update server-01 A 10.0.1.20
|
||
|
||
# With new TTL
|
||
provisioning dns record update server-01 A 10.0.1.20 --ttl 1800
|
||
</code></pre>
|
||
<h3 id="list-records"><a class="header" href="#list-records">List Records</a></h3>
|
||
<pre><code class="language-bash"># List all records in zone
|
||
provisioning dns record list
|
||
|
||
# Different zone
|
||
provisioning dns record list --zone myapp.local
|
||
|
||
# JSON format
|
||
provisioning dns record list --format json
|
||
|
||
# YAML format
|
||
provisioning dns record list --format yaml
|
||
</code></pre>
|
||
<p><strong>Example Output:</strong></p>
|
||
<pre><code>DNS Records - Zone: provisioning.local
|
||
|
||
╭───┬──────────────┬──────┬─────────────┬─────╮
|
||
│ # │ name │ type │ value │ ttl │
|
||
├───┼──────────────┼──────┼─────────────┼─────┤
|
||
│ 0 │ server-01 │ A │ 10.0.1.10 │ 300 │
|
||
│ 1 │ server-02 │ A │ 10.0.1.11 │ 300 │
|
||
│ 2 │ db-01 │ A │ 10.0.2.10 │ 300 │
|
||
│ 3 │ web │ CNAME│ server-01 │ 300 │
|
||
╰───┴──────────────┴──────┴─────────────┴─────╯
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="docker-deployment"><a class="header" href="#docker-deployment">Docker Deployment</a></h2>
|
||
<h3 id="prerequisites-1"><a class="header" href="#prerequisites-1">Prerequisites</a></h3>
|
||
<p>Ensure Docker and docker-compose are installed:</p>
|
||
<pre><code class="language-bash">docker --version
|
||
docker-compose --version
|
||
</code></pre>
|
||
<h3 id="start-coredns-in-docker"><a class="header" href="#start-coredns-in-docker">Start CoreDNS in Docker</a></h3>
|
||
<pre><code class="language-bash"># Start CoreDNS container
|
||
provisioning dns docker start
|
||
|
||
# Check mode
|
||
provisioning dns docker start --check
|
||
</code></pre>
|
||
<h3 id="manage-docker-container"><a class="header" href="#manage-docker-container">Manage Docker Container</a></h3>
|
||
<pre><code class="language-bash"># Check status
|
||
provisioning dns docker status
|
||
|
||
# View logs
|
||
provisioning dns docker logs
|
||
|
||
# Follow logs
|
||
provisioning dns docker logs --follow
|
||
|
||
# Restart container
|
||
provisioning dns docker restart
|
||
|
||
# Stop container
|
||
provisioning dns docker stop
|
||
|
||
# Check health
|
||
provisioning dns docker health
|
||
</code></pre>
|
||
<h3 id="update-docker-image"><a class="header" href="#update-docker-image">Update Docker Image</a></h3>
|
||
<pre><code class="language-bash"># Pull latest image
|
||
provisioning dns docker pull
|
||
|
||
# Pull specific version
|
||
provisioning dns docker pull --version 1.11.1
|
||
|
||
# Update and restart
|
||
provisioning dns docker update
|
||
</code></pre>
|
||
<h3 id="remove-container"><a class="header" href="#remove-container">Remove Container</a></h3>
|
||
<pre><code class="language-bash"># Remove container (with confirmation)
|
||
provisioning dns docker remove
|
||
|
||
# Remove with volumes
|
||
provisioning dns docker remove --volumes
|
||
|
||
# Force remove (skip confirmation)
|
||
provisioning dns docker remove --force
|
||
|
||
# Check mode
|
||
provisioning dns docker remove --check
|
||
</code></pre>
|
||
<h3 id="view-configuration"><a class="header" href="#view-configuration">View Configuration</a></h3>
|
||
<pre><code class="language-bash"># Show docker-compose config
|
||
provisioning dns docker config
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="integration"><a class="header" href="#integration">Integration</a></h2>
|
||
<h3 id="automatic-server-registration"><a class="header" href="#automatic-server-registration">Automatic Server Registration</a></h3>
|
||
<p>When dynamic DNS is enabled, servers are automatically registered:</p>
|
||
<pre><code class="language-bash"># Create server (automatically registers in DNS)
|
||
provisioning server create web-01 --infra myapp
|
||
|
||
# Server gets DNS record: web-01.provisioning.local -> <server-ip>
|
||
</code></pre>
|
||
<h3 id="manual-registration"><a class="header" href="#manual-registration">Manual Registration</a></h3>
|
||
<pre><code class="language-nushell">use lib_provisioning/coredns/integration.nu *
|
||
|
||
# Register server
|
||
register-server-in-dns "web-01" "10.0.1.10"
|
||
|
||
# Unregister server
|
||
unregister-server-from-dns "web-01"
|
||
|
||
# Bulk register
|
||
bulk-register-servers [
|
||
{hostname: "web-01", ip: "10.0.1.10"}
|
||
{hostname: "web-02", ip: "10.0.1.11"}
|
||
{hostname: "db-01", ip: "10.0.2.10"}
|
||
]
|
||
</code></pre>
|
||
<h3 id="sync-infrastructure-with-dns"><a class="header" href="#sync-infrastructure-with-dns">Sync Infrastructure with DNS</a></h3>
|
||
<pre><code class="language-bash"># Sync all servers in infrastructure with DNS
|
||
provisioning dns sync myapp
|
||
|
||
# Check mode
|
||
provisioning dns sync myapp --check
|
||
</code></pre>
|
||
<h3 id="service-registration"><a class="header" href="#service-registration">Service Registration</a></h3>
|
||
<pre><code class="language-nushell">use lib_provisioning/coredns/integration.nu *
|
||
|
||
# Register service
|
||
register-service-in-dns "api" "10.0.1.10"
|
||
|
||
# Unregister service
|
||
unregister-service-from-dns "api"
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="query-dns"><a class="header" href="#query-dns">Query DNS</a></h2>
|
||
<h3 id="using-cli"><a class="header" href="#using-cli">Using CLI</a></h3>
|
||
<pre><code class="language-bash"># Query A record
|
||
provisioning dns query server-01
|
||
|
||
# Query specific type
|
||
provisioning dns query server-01 --type AAAA
|
||
|
||
# Query different server
|
||
provisioning dns query server-01 --server 8.8.8.8 --port 53
|
||
|
||
# Query from local CoreDNS
|
||
provisioning dns query server-01 --server 127.0.0.1 --port 5353
|
||
</code></pre>
|
||
<h3 id="using-dig"><a class="header" href="#using-dig">Using dig</a></h3>
|
||
<pre><code class="language-bash"># Query from local CoreDNS
|
||
dig @127.0.0.1 -p 5353 server-01.provisioning.local
|
||
|
||
# Query CNAME
|
||
dig @127.0.0.1 -p 5353 web.provisioning.local CNAME
|
||
|
||
# Query MX
|
||
dig @127.0.0.1 -p 5353 example.com MX
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="troubleshooting"><a class="header" href="#troubleshooting">Troubleshooting</a></h2>
|
||
<h3 id="coredns-not-starting"><a class="header" href="#coredns-not-starting">CoreDNS Not Starting</a></h3>
|
||
<p><strong>Symptoms:</strong> <code>dns start</code> fails or service doesn’t respond</p>
|
||
<p><strong>Solutions:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>Check if port is in use:</strong></p>
|
||
<pre><code class="language-bash">lsof -i :5353
|
||
netstat -an | grep 5353
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Validate Corefile:</strong></p>
|
||
<pre><code class="language-bash">provisioning dns config validate
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Check logs:</strong></p>
|
||
<pre><code class="language-bash">provisioning dns logs
|
||
tail -f ~/.provisioning/coredns/coredns.log
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Verify binary exists:</strong></p>
|
||
<pre><code class="language-bash">ls -lh ~/.provisioning/bin/coredns
|
||
provisioning dns install
|
||
</code></pre>
|
||
</li>
|
||
</ol>
|
||
<h3 id="dns-queries-not-working"><a class="header" href="#dns-queries-not-working">DNS Queries Not Working</a></h3>
|
||
<p><strong>Symptoms:</strong> <code>dig</code> returns SERVFAIL or timeout</p>
|
||
<p><strong>Solutions:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>Check CoreDNS is running:</strong></p>
|
||
<pre><code class="language-bash">provisioning dns status
|
||
provisioning dns health
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Verify zone file exists:</strong></p>
|
||
<pre><code class="language-bash">ls -lh ~/.provisioning/coredns/zones/
|
||
cat ~/.provisioning/coredns/zones/provisioning.local.zone
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Test with dig:</strong></p>
|
||
<pre><code class="language-bash">dig @127.0.0.1 -p 5353 provisioning.local SOA
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Check firewall:</strong></p>
|
||
<pre><code class="language-bash"># macOS
|
||
sudo pfctl -sr | grep 5353
|
||
|
||
# Linux
|
||
sudo iptables -L -n | grep 5353
|
||
</code></pre>
|
||
</li>
|
||
</ol>
|
||
<h3 id="zone-file-validation-errors"><a class="header" href="#zone-file-validation-errors">Zone File Validation Errors</a></h3>
|
||
<p><strong>Symptoms:</strong> <code>dns config validate</code> shows errors</p>
|
||
<p><strong>Solutions:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>Backup zone file:</strong></p>
|
||
<pre><code class="language-bash">cp ~/.provisioning/coredns/zones/provisioning.local.zone \
|
||
~/.provisioning/coredns/zones/provisioning.local.zone.backup
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Regenerate zone:</strong></p>
|
||
<pre><code class="language-bash">provisioning dns zone create provisioning.local --force
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Check syntax manually:</strong></p>
|
||
<pre><code class="language-bash">cat ~/.provisioning/coredns/zones/provisioning.local.zone
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Increment serial:</strong></p>
|
||
<ul>
|
||
<li>Edit zone file manually</li>
|
||
<li>Increase serial number in SOA record</li>
|
||
</ul>
|
||
</li>
|
||
</ol>
|
||
<h3 id="docker-container-issues"><a class="header" href="#docker-container-issues">Docker Container Issues</a></h3>
|
||
<p><strong>Symptoms:</strong> Docker container won’t start or crashes</p>
|
||
<p><strong>Solutions:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>Check Docker logs:</strong></p>
|
||
<pre><code class="language-bash">provisioning dns docker logs
|
||
docker logs provisioning-coredns
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Verify volumes exist:</strong></p>
|
||
<pre><code class="language-bash">ls -lh ~/.provisioning/coredns/
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Check container status:</strong></p>
|
||
<pre><code class="language-bash">provisioning dns docker status
|
||
docker ps -a | grep coredns
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Recreate container:</strong></p>
|
||
<pre><code class="language-bash">provisioning dns docker stop
|
||
provisioning dns docker remove --volumes
|
||
provisioning dns docker start
|
||
</code></pre>
|
||
</li>
|
||
</ol>
|
||
<h3 id="dynamic-updates-not-working"><a class="header" href="#dynamic-updates-not-working">Dynamic Updates Not Working</a></h3>
|
||
<p><strong>Symptoms:</strong> Servers not auto-registered in DNS</p>
|
||
<p><strong>Solutions:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>Check if enabled:</strong></p>
|
||
<pre><code class="language-bash">provisioning dns config show | grep -A 5 dynamic_updates
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Verify orchestrator running:</strong></p>
|
||
<pre><code class="language-bash">curl http://localhost:9090/health
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Check logs for errors:</strong></p>
|
||
<pre><code class="language-bash">provisioning dns logs | grep -i error
|
||
</code></pre>
|
||
</li>
|
||
<li>
|
||
<p><strong>Test manual registration:</strong></p>
|
||
<pre><code class="language-nushell">use lib_provisioning/coredns/integration.nu *
|
||
register-server-in-dns "test-server" "10.0.0.1"
|
||
</code></pre>
|
||
</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="advanced-topics"><a class="header" href="#advanced-topics">Advanced Topics</a></h2>
|
||
<h3 id="custom-corefile-plugins"><a class="header" href="#custom-corefile-plugins">Custom Corefile Plugins</a></h3>
|
||
<p>Add custom plugins to Corefile:</p>
|
||
<pre><code class="language-nushell">use lib_provisioning/coredns/corefile.nu *
|
||
|
||
# Add plugin to zone
|
||
add-corefile-plugin \
|
||
"~/.provisioning/coredns/Corefile" \
|
||
"provisioning.local" \
|
||
"cache 30"
|
||
</code></pre>
|
||
<h3 id="backup-and-restore"><a class="header" href="#backup-and-restore">Backup and Restore</a></h3>
|
||
<pre><code class="language-bash"># Backup configuration
|
||
tar czf coredns-backup.tar.gz ~/.provisioning/coredns/
|
||
|
||
# Restore configuration
|
||
tar xzf coredns-backup.tar.gz -C ~/
|
||
</code></pre>
|
||
<h3 id="zone-file-backup"><a class="header" href="#zone-file-backup">Zone File Backup</a></h3>
|
||
<pre><code class="language-nushell">use lib_provisioning/coredns/zones.nu *
|
||
|
||
# Backup zone
|
||
backup-zone-file "provisioning.local"
|
||
|
||
# Creates: ~/.provisioning/coredns/zones/provisioning.local.zone.YYYYMMDD-HHMMSS.bak
|
||
</code></pre>
|
||
<h3 id="metrics-and-monitoring"><a class="header" href="#metrics-and-monitoring">Metrics and Monitoring</a></h3>
|
||
<p>CoreDNS exposes Prometheus metrics on port 9153:</p>
|
||
<pre><code class="language-bash"># View metrics
|
||
curl http://localhost:9153/metrics
|
||
|
||
# Common metrics:
|
||
# - coredns_dns_request_duration_seconds
|
||
# - coredns_dns_requests_total
|
||
# - coredns_dns_responses_total
|
||
</code></pre>
|
||
<h3 id="multi-zone-setup"><a class="header" href="#multi-zone-setup">Multi-Zone Setup</a></h3>
|
||
<pre><code class="language-kcl">coredns_config: CoreDNSConfig = {
|
||
local = {
|
||
zones = [
|
||
"provisioning.local",
|
||
"workspace.local",
|
||
"dev.local",
|
||
"staging.local",
|
||
"prod.local"
|
||
]
|
||
}
|
||
}
|
||
</code></pre>
|
||
<h3 id="split-horizon-dns"><a class="header" href="#split-horizon-dns">Split-Horizon DNS</a></h3>
|
||
<p>Configure different zones for internal/external:</p>
|
||
<pre><code class="language-kcl">coredns_config: CoreDNSConfig = {
|
||
local = {
|
||
zones = ["internal.local"]
|
||
port = 5353
|
||
}
|
||
remote = {
|
||
zones = ["external.com"]
|
||
endpoints = ["https://dns.external.com"]
|
||
}
|
||
}
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="configuration-reference"><a class="header" href="#configuration-reference">Configuration Reference</a></h2>
|
||
<h3 id="corednsconfig-fields"><a class="header" href="#corednsconfig-fields">CoreDNSConfig Fields</a></h3>
|
||
<div class="table-wrapper"><table><thead><tr><th>Field</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody>
|
||
<tr><td><code>mode</code></td><td><code>"local" | "remote" | "hybrid" | "disabled"</code></td><td><code>"local"</code></td><td>Deployment mode</td></tr>
|
||
<tr><td><code>local</code></td><td><code>LocalCoreDNS?</code></td><td>-</td><td>Local config (required for local mode)</td></tr>
|
||
<tr><td><code>remote</code></td><td><code>RemoteCoreDNS?</code></td><td>-</td><td>Remote config (required for remote mode)</td></tr>
|
||
<tr><td><code>dynamic_updates</code></td><td><code>DynamicDNS</code></td><td>-</td><td>Dynamic DNS configuration</td></tr>
|
||
<tr><td><code>upstream</code></td><td><code>[str]</code></td><td><code>["8.8.8.8", "1.1.1.1"]</code></td><td>Upstream DNS servers</td></tr>
|
||
<tr><td><code>default_ttl</code></td><td><code>int</code></td><td><code>300</code></td><td>Default TTL (seconds)</td></tr>
|
||
<tr><td><code>enable_logging</code></td><td><code>bool</code></td><td><code>True</code></td><td>Enable query logging</td></tr>
|
||
<tr><td><code>enable_metrics</code></td><td><code>bool</code></td><td><code>True</code></td><td>Enable Prometheus metrics</td></tr>
|
||
<tr><td><code>metrics_port</code></td><td><code>int</code></td><td><code>9153</code></td><td>Metrics port</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<h3 id="localcoredns-fields"><a class="header" href="#localcoredns-fields">LocalCoreDNS Fields</a></h3>
|
||
<div class="table-wrapper"><table><thead><tr><th>Field</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody>
|
||
<tr><td><code>enabled</code></td><td><code>bool</code></td><td><code>True</code></td><td>Enable local CoreDNS</td></tr>
|
||
<tr><td><code>deployment_type</code></td><td><code>"binary" | "docker"</code></td><td><code>"binary"</code></td><td>How to deploy</td></tr>
|
||
<tr><td><code>binary_path</code></td><td><code>str</code></td><td><code>"~/.provisioning/bin/coredns"</code></td><td>Path to binary</td></tr>
|
||
<tr><td><code>config_path</code></td><td><code>str</code></td><td><code>"~/.provisioning/coredns/Corefile"</code></td><td>Corefile path</td></tr>
|
||
<tr><td><code>zones_path</code></td><td><code>str</code></td><td><code>"~/.provisioning/coredns/zones"</code></td><td>Zones directory</td></tr>
|
||
<tr><td><code>port</code></td><td><code>int</code></td><td><code>5353</code></td><td>DNS listening port</td></tr>
|
||
<tr><td><code>auto_start</code></td><td><code>bool</code></td><td><code>True</code></td><td>Auto-start on boot</td></tr>
|
||
<tr><td><code>zones</code></td><td><code>[str]</code></td><td><code>["provisioning.local"]</code></td><td>Managed zones</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<h3 id="dynamicdns-fields"><a class="header" href="#dynamicdns-fields">DynamicDNS Fields</a></h3>
|
||
<div class="table-wrapper"><table><thead><tr><th>Field</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody>
|
||
<tr><td><code>enabled</code></td><td><code>bool</code></td><td><code>True</code></td><td>Enable dynamic updates</td></tr>
|
||
<tr><td><code>api_endpoint</code></td><td><code>str</code></td><td><code>"http://localhost:9090/dns"</code></td><td>Orchestrator API</td></tr>
|
||
<tr><td><code>auto_register_servers</code></td><td><code>bool</code></td><td><code>True</code></td><td>Auto-register on create</td></tr>
|
||
<tr><td><code>auto_unregister_servers</code></td><td><code>bool</code></td><td><code>True</code></td><td>Auto-unregister on delete</td></tr>
|
||
<tr><td><code>ttl</code></td><td><code>int</code></td><td><code>300</code></td><td>TTL for dynamic records</td></tr>
|
||
<tr><td><code>update_strategy</code></td><td><code>"immediate" | "batched" | "scheduled"</code></td><td><code>"immediate"</code></td><td>Update strategy</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<hr />
|
||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
||
<h3 id="complete-setup-example"><a class="header" href="#complete-setup-example">Complete Setup Example</a></h3>
|
||
<pre><code class="language-bash"># 1. Install CoreDNS
|
||
provisioning dns install
|
||
|
||
# 2. Generate configuration
|
||
provisioning dns config generate
|
||
|
||
# 3. Start service
|
||
provisioning dns start
|
||
|
||
# 4. Create custom zone
|
||
provisioning dns zone create myapp.local
|
||
|
||
# 5. Add DNS records
|
||
provisioning dns record add web-01 A 10.0.1.10
|
||
provisioning dns record add web-02 A 10.0.1.11
|
||
provisioning dns record add api CNAME web-01.myapp.local --zone myapp.local
|
||
|
||
# 6. Query records
|
||
provisioning dns query web-01 --server 127.0.0.1 --port 5353
|
||
|
||
# 7. Check status
|
||
provisioning dns status
|
||
provisioning dns health
|
||
</code></pre>
|
||
<h3 id="docker-deployment-example"><a class="header" href="#docker-deployment-example">Docker Deployment Example</a></h3>
|
||
<pre><code class="language-bash"># 1. Start CoreDNS in Docker
|
||
provisioning dns docker start
|
||
|
||
# 2. Check status
|
||
provisioning dns docker status
|
||
|
||
# 3. View logs
|
||
provisioning dns docker logs --follow
|
||
|
||
# 4. Add records (container must be running)
|
||
provisioning dns record add server-01 A 10.0.1.10
|
||
|
||
# 5. Query
|
||
dig @127.0.0.1 -p 5353 server-01.provisioning.local
|
||
|
||
# 6. Stop
|
||
provisioning dns docker stop
|
||
</code></pre>
|
||
<hr />
|
||
<h2 id="best-practices"><a class="header" href="#best-practices">Best Practices</a></h2>
|
||
<ol>
|
||
<li><strong>Use TTL wisely</strong> - Lower TTL (300s) for frequently changing records, higher (3600s) for stable</li>
|
||
<li><strong>Enable logging</strong> - Essential for troubleshooting</li>
|
||
<li><strong>Regular backups</strong> - Backup zone files before major changes</li>
|
||
<li><strong>Validate before reload</strong> - Always run <code>dns config validate</code> before reloading</li>
|
||
<li><strong>Monitor metrics</strong> - Track DNS query rates and error rates</li>
|
||
<li><strong>Use comments</strong> - Add comments to records for documentation</li>
|
||
<li><strong>Separate zones</strong> - Use different zones for different environments (dev, staging, prod)</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
||
<ul>
|
||
<li><a href="../architecture/coredns-architecture.html">Architecture Documentation</a></li>
|
||
<li><a href="../api/dns-api.html">API Reference</a></li>
|
||
<li><a href="../integration/orchestrator-dns.html">Orchestrator Integration</a></li>
|
||
<li><a href="../../provisioning/kcl/coredns.k">KCL Schema Reference</a></li>
|
||
</ul>
|
||
<hr />
|
||
<p><strong>Last Updated</strong>: 2025-10-06
|
||
<strong>Version</strong>: 1.0.0</p>
|
||
|
||
</main>
|
||
|
||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||
<!-- Mobile navigation buttons -->
|
||
<a rel="prev" href="../user/workspace-guide.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||
<i class="fa fa-angle-left"></i>
|
||
</a>
|
||
|
||
<a rel="next prefetch" href="../user/SERVICE_MANAGEMENT_GUIDE.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||
<i class="fa fa-angle-right"></i>
|
||
</a>
|
||
|
||
<div style="clear: both"></div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||
<a rel="prev" href="../user/workspace-guide.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||
<i class="fa fa-angle-left"></i>
|
||
</a>
|
||
|
||
<a rel="next prefetch" href="../user/SERVICE_MANAGEMENT_GUIDE.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||
<i class="fa fa-angle-right"></i>
|
||
</a>
|
||
</nav>
|
||
|
||
</div>
|
||
|
||
<!-- Livereload script (if served using the cli tool) -->
|
||
<script>
|
||
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
|
||
const socket = new WebSocket(wsAddress);
|
||
socket.onmessage = function (event) {
|
||
if (event.data === "reload") {
|
||
socket.close();
|
||
location.reload();
|
||
}
|
||
};
|
||
|
||
window.onbeforeunload = function() {
|
||
socket.close();
|
||
}
|
||
</script>
|
||
|
||
|
||
|
||
<script>
|
||
window.playground_copyable = true;
|
||
</script>
|
||
|
||
|
||
<script src="../elasticlunr.min.js"></script>
|
||
<script src="../mark.min.js"></script>
|
||
<script src="../searcher.js"></script>
|
||
|
||
<script src="../clipboard.min.js"></script>
|
||
<script src="../highlight.js"></script>
|
||
<script src="../book.js"></script>
|
||
|
||
<!-- Custom JS scripts -->
|
||
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|