GDNSD-PLUGIN-METAFO(8)
π gdnsd-plugin-metafo π
okay bestie, you're looking at the GDNSD-PLUGIN-METAFO(8) page from the gdnsd manual, and honestly? this one's a bop. it's the plugin that does address meta-failover. let's get into it π¦
β¨ NAME β¨
gdnsd-plugin-metafo β the gdnsd plugin for address meta-failover. periodt.
πΈ SYNOPSIS πΈ
here's a minimal lil gdnsd config file using this plugin, no cap:
plugins => {
metafo => {
resources => {
prod_www => {
datacenters => [ dc-01, dc-02, dc-03 ]
dcmap => {
dc-01 => 192.0.2.1
dc-02 => { lb01 => 192.0.2.2, lb02 => 192.0.2.3 }
dc-03 => [ 192.0.2.4, 192.0.2.5, 192.0.2.6 ]
}
},
prod_foo => {
datacenters => [ dc-01, dc-02, dc-bk ]
dcmap => {
dc-01 => { lb01 => 192.0.1.1, lb02 => 192.0.1.2 }
dc-02 => [ 192.0.5.1, 192.0.5.2, 192.0.5.3 ]
dc-bk => fallback.static.cname.example.org.
}
}
}
}
}
and here are some example zonefile RRs in zone example.com:
www 600 DYNA metafo!prod_www
www-dc01 600 DYNA metafo!prod_www/dc-01
foo 700 DYNC metafo!prod_foo
π DESCRIPTION π
gdnsd-plugin-metafo is a meta-plugin. it does static-ordered address failover between a bunch of "datacenters" β and lowkey those might or might not line up with actual physical datacenters, it's just a convenient label, iykyk. each datacenter gets defined in terms of other plugins like multifo, weighted, etc., as we get into below. π
π CONFIGURATION - TOP-LEVEL π
the top level of the metafo plugin's config (aka plugins => { metafo => { ... } }) supports literally only one fixed, required key: resources, and its value has to be a hash. inside resources, each key is one named resource, and the value defines that resource.
any other keys you put at the top level get inherited down inside every per-resource hash inside the resources stanza, acting as per-resource defaults for anything you didn't explicitly define there. we explain that below, don't worry π«Ά
π¦ CONFIGURATION - RESOURCES π¦
every key inside the resources stanza is a named resource, and those can be referenced by DYNA RRs in zonefiles, like www DYNA metafo!resource_name. each resource's value must be a key-value hash configuring the resource itself. here's a lightweight structural example:
plugins => {
metafo => {
resources => { resA => { ... }, resB => { ... } }
}
}
inside a resource, there are only three keys that are specifically meaningful:
datacenters = [ A, B, C, ... ]β array of datacenter names, required. this is the set of datacenter name labels for this resource, in the exact order they'll be checked for failover. πdcmap = { ... }β hash, required. thedcmapis a key-value hash where the keys must be exactly the list of datacenters defined in this resource'sdatacenterslist, and the values define the address config of each datacenter. another minimal structural example, down to this level:
plugins => {
metafo => {
resources => {
resA => {
datacenters => [ dc01, dc02 ],
dcmap => {
dc01 => ???
dc02 => ???
}
}
}
}
}
there are several forms those per-datacenter values (the ??? up there) can take, and we document them in the next section. stay tuned β¨
skip_first = trueβ if this boolean config flag is set, the resolver code will skip the first datacenter when resolving this resource. this is mostly useful in the context of the geoip plugin, and it's discussed in more detail over there. π
any keys other than datacenters and dcmap at the per-resource level serve as inherited defaults for each per-datacenter configuration inside of the dcmap.
π PER-DATACENTER RESOLUTION π
the value of the datacenters inside the dcmap section of a resource can take several forms. and it's super important to understand that for the most part, plugin_metafo does not deal with this level of results itself β instead it delegates the work at this scope to other plugins. those sub-plugins, in turn, also notify metafo of complete failure at their level, and that's the info metafo uses to know it should fail over to the next datacenter in the list. fr fr.
the most direct and obvious way to do this is with a direct reference of the form %plugin!resource, like this:
plugins => {
metafo => {
resources => {
resA => {
datacenters => [ dc1, dc2 ],
dcmap => {
dc1 => %multifo!res_mfo1
dc2 => %multifo!res_mfo2
}
}
}
}
multifo => {
res_mfo1 => { lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
res_mfo2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
}
}
however, to make life simpler in the simple cases, plugin_metafo can synthesize the lower-level plugin's config from a hash, like so:
plugins => {
metafo => {
resources => {
resA => {
datacenters => [ dc1, dc2 ],
dcmap => {
dc1 => { plugin => multifo, lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
# the above are effectively treated as:
# dc1 => %multifo!metafo_resA_dc1
# dc2 => %multifo!metafo_resA_dc2
}
}
}
}
# below does not exist in your configfile, but is what plugin_metafo
# synthesizes to support the above:
#multifo => {
# metafo_resA_dc1 => { lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
# metafo_resA_dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
#}
}
inside a hash like the one above, the special key plugin gets stripped out internally and used to name the plugin we synthesize the config for. plugin defaults to multifo if you don't specify it. ngl, plugin could also be specified at the resource level (just inside of the resA stanza) to change the default for all dcmap entries in one resource, and it could also be specified at the outer-most scope (just inside the metafo stanza) to change the default for all resources. π€―
the defaulted-down plugin is also the default for the direct-reference %plugin!resource form we talked about earlier. with the correct default plugin name, it can be shortened all the way down to just !resource. slay.
the same sort of key-value inheritance scheme (top-level -> per-resource level -> per-datacenter level) can also be used for any other parameter in synthesized resource configs specific to the per-datacenter plugin(s) you're using. a common example would be the service_types parameter that most plugins supporting monitored address results have. note that these other values (e.g. service_types) would only apply to synthesized resources, not to direct-references like %multifo!foo, which must be configured entirely separately within that plugin's config. π
there are three other possible shortcut values for datacenters: a single direct address, an array of addresses, or a single CNAME hostname. if a single IP address or an array of IP addresses is specified, plugin_metafo will synthesize a hash from them with the plugin forced to multifo (since it cannot know the syntax of hashes for all other plugins, which may differ), and give them address labels 1, 2, etc.
if the value for a datacenter is a single CNAME hostname, no sub-plugin is used, and that CNAME result is returned directly. note that any resource with such an entry can only be used with DYNC RRs, and not DYNA RRs (as is the case if any subplugin's configuration is capable of returning CNAME data).
a much more complete example, showing off most of the features above:
plugins => {
metafo => {
plugin => multifo # change default for all resources
service_types => [ bar ] # default service_types for synthesized below
resources => {
resA => {
plugin => multifo # change default for this resource
service_types => [foo, bar] # services types for synthesized below:
datacenters => [ dc1, dc2, dc3, dc4, dc5, dc6, dc7, dc8 ],
dcmap => {
dc1 => { plugin => multifo, lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
dc3 => %simplefo!foo
dc4 => { plugin => simplefo, primary => 192.0.2.100, secondary => 192.0.2.101 }
dc5 => !bar
dc6 => 192.0.2.150
dc7 => [ 192.0.2.180, 192.0.2.181 ]
dc8 => last.resort.example.com.
}
}
}
}
# below, commented-out sections show configuration synthesized
# by plugin_metafo, whereas the rest are direct-references that
# had to be manually specified here:
multifo => {
# metafo_resA_dc1 => { lb01 => 192.0.2.1, lb02 => 192.0.2.3, service_types => [foo, bar] }
# metafo_resA_dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113, service_types => [foo, bar] }
bar => { asd => 192.0.2.77, xyz => 192.0.2.88 }
# metafo_resA_dc6 => { 1 => 192.0.2.150, service_types => [foo, bar] }
# metafo_resA_dc7 => { 1 => 192.0.2.180, 2 => 192.0.2.181, service_types => [foo, bar] }
}
simplefo => {
foo => { primary => 192.0.2.80, secondary => 192.0.2.81 }
# metafo_resA_dc4 => { primary => 192.0.2.100, secondary => 192.0.2.101, service_types => [foo, bar] }
}
}
note that in the example above, %multifo!bar and %simplefo!foo would have had their default service_types = up rather than the one specified at the metafo level, because they were not synthesized. it would be up to you to keep all of the service_types in sync when using direct references. π
π§ SYNTHETIC PER-DATACENTER RESOURCES π§
this plugin will synthesize additional, per-datacenter resource names from your config. they're named as resname/dcname. for example, if you define a metafo resource named prodwww with the datacenter list [ pri, sec ], the resource names prodwww/pri and prodwww/sec will be synthesized and can be used in zonefile records, e.g.:
www-backup 300 DYNA metafo!prodwww/sec
when used, these per-datacenter synthetic resource names cause a given lookup to skip the normal failover process and directly return results from that particular datacenter. main character energy tbh π
β SEE ALSO β
gdnsd.config(5), gdnsd.zonefile(5), gdnsd(8)
the gdnsd manual. π«Ά
π COPYRIGHT AND LICENSE π
okay bestie, we made it to the legal bit π this is the part everyone skips but likeβ¦ don't skip it, it's short and it's literally the receipts for the whole thing.
Copyright (c) 2012 Brandon L Black <blblack@gmail.com>
that's the whole copyright line, no cap, one author, one year, one email. iconic of him honestly π
β¨ the vibe check: gdnsd is free software β¨
This file is part of gdnsd.
gdnsd is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. π
so yeah β v3 or later, your choice, both valid, periodt.
π¦ the warranty part (read this one, fr fr) π¦
gdnsd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. π
bestie this is the important one. no warranty, not for merchantability, not for fitness for a particular purpose. it's not me being dramatic, that's literally what it says. π
See the GNU General Public License for more details.
π«Ά the "where's my copy" bit π«Ά
You should have received a copy of the GNU General Public License along with gdnsd. If not, see http://www.gnu.org/licenses/. π
that's it. that's the whole license section. go get your copy, it's free, it's giving β¨ open source β¨.
π the sign-off π
This whole page β every last -a and every last --all β comes from gdnsd 3.8.3, dated 2025-02-16, and it lives under the very official name GDNSD-PLUGIN-METAFO(8). π
thanks for reading the manual, bestie, you're literally the main character for that π«Ά now go configure your resources, slay, and remember: free software, no warranty, big vibes. β¨πΈπ
π¦ where this page comes from
- debian trixie: gdnsd 3.8.3-2 Β· GPL-3.0-or-later
- ubuntu questing: gdnsd 3.8.3-2
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms