I go even further and have a MySQL db that's authoritative for all server data (it's a django app actually). Here's how I integrate them:
Node definitions
There are two possibilities. We currently use a generated manifest, that's included from site.pp containing entries like:
node "avrdb.prod.example.com" {
$sdb_status="live"
$sdb_db_type="slave"
$sdb_db_version="mysql_55"
$sdb_os="co56"
include "s_db::avrdb"
}
But soon-ish we need to switch this to an ENC as puppet doesn't support this anymore. The ENC is already written and uses almost the same template.
Server data
Some recipes, like our DNS master recipe, need extra data about servers. Like you suggest, this is done in templates. Here's an example of one such template: named.conf which needs to know all secondary nameservers. It simply uses the mysql gem to get to the database. The database structure is irrelevant of course, but a complete example is usually nice :)
<%
require 'rubygems'
require 'mysql'
dbh = Mysql.real_connect('serverdb.prod.example.com', 'user', 'pass', 'serverdb')
int_slaves = dbh.query("SELECT ip_address, name FROM network_vip WHERE name LIKE 'idns%' ORDER BY name")
int_hosts = dbh.query("SELECT i.ip_address, a.name FROM servers_interface as i LEFT JOIN servers_asset as a ON i.asset_id=a.id WHERE a.name regexp '^idns-' and i.name='eth0'");
ext_slaves = dbh.query("SELECT ip_address, name FROM network_vip WHERE name LIKE 'edns%' ORDER BY name")
ext_hosts = dbh.query("SELECT i.ip_address, a.name FROM servers_interface as i LEFT JOIN servers_asset as a ON i.asset_id=a.id WHERE a.name regexp '^edns-*' and i.name='eth0'");
%>
options {
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
allow-recursion { none; };
allow-transfer { any; };
allow-query { any; };
// default for transfers-in and transfers-out is 10
transfers-in 128;
transfers-out 128;
// default for transfers-per-ns is 2
transfers-per-ns 8;
// serial-query-rate on a master has undocumented side-effects
// of notifying slaves much faster for many zones
serial-query-rate 4096;
// resolvers or authoritatives
also-notify {
// Internal slaves
<% int_slaves.each{|slave| -%>
// <%= slave[1] %>
<%= slave[0] %>;
<% }
int_slaves.data_seek(0) -%>
// Internal dns hosts
// Needed as we move all the boxes over to HA, where they
// query from eth0, not vip
<% int_hosts.each{|slave| -%>
// <%= slave[1] %>
<%= slave[0] %>;
<% }
int_hosts.data_seek(0) -%>
// External slaves
<% ext_slaves.each{|slave| -%>
// <%= slave[1] %>
<%= slave[0] %>;
<% } -%>
<% ext_hosts.each{|slave| -%>
// <%= slave[1] %>
<%= slave[0] %>;
<% }
ext_hosts.data_seek(0) -%>
};
};
include "/etc/rndc.key";
// logging
logging {
channel default_file { file "/var/log/named/named.log" versions 10 size 100m; print-time yes; print-category yes; };
channel security_file { file "/var/log/named/security.log" versions 10 size 100m; print-time yes; print-category yes; };
channel query_file { file "/var/log/named/query.log" versions 10 size 100m; print-time yes; print-category yes; };
channel debug_default { file "/var/log/named/debug.log" versions 10 size 100m; print-time yes; print-category yes; };
category general { default_file; default_debug; };
category security { security_file; };
category default { default_file; };
category queries { query_file; };
category edns-disabled { null; };
};
statistics-channels {
inet 127.0.0.1 port 8080;
};
// Do not put any zone declarations here unless they differ between views
// Put zones with data common to all views in commonzones.conf
// This view goes to all the internal nameservers
view "internal" {
match-clients {
// Internal slaves
<% int_slaves.each{|slave| -%>
// <%= slave[1] %>
<%= slave[0] %>;
<% } -%>
// Internal ds hosts
// Safety catch in case they request an AXFR on their eth0 ip
<% int_hosts.each{|slave| -%>
// <%= slave[1] %>
<%= slave[0] %>;
<% } -%>
};
zone "example.com" IN {
type master;
file "master/example.com-internal.zone";
};
// This path relative to chroot
include "/etc/commonzones.conf";
include "/etc/zones.rfc1918";
};
// This view goes to everyone else
view "others" {
match-clients { any; };
// Special zones that differ between views
zone "example.com" IN {
type master;
file "master/example.com-external.zone";
};
// This path relative to chroot
include "/etc/commonzones.conf";
include "/etc/zones.rfc1918";
};