Migrating from 0.2 to 0.3¶
dnspatch is v0.x: the configuration format and the plugin API may change
between minor versions. This page lists what breaks in 0.3 and how to adapt.
Three things break: the [instance.retriever] table in the configuration, the
Retriever and Provider interfaces of plugin, and the required:"true"
struct tag of a plugin configuration. Everything else in 0.3 is additive.
Configuration: [instance.retriever] is now an array¶
An instance takes one or more retrievers, so the table became an array of
tables. The old form is rejected with
"retriever" must be an array of tables: [[instance.retriever]].
Before:
[[instance]]
domain = "home.example.com"
[instance.retriever]
ref = "ipify"
[[instance.provider]]
ref = "regru"
After:
[[instance]]
domain = "home.example.com"
[[instance.retriever]]
ref = "ipify"
[[instance.provider]]
ref = "regru"
Retrievers are polled in order until every address family is filled, so a
second retriever is either a fallback or the source of the other family
(dual-stack). See examples/.
Configuration: what is new and needs no action¶
typemay be set instead ofrefin[[instance.retriever]]and[[instance.provider]], which builds the plugin from that table alone. The two are mutually exclusive.- Any parameter can read a secret from a file:
${file:PATH}. A literal${is still written$${. family = "dual"onipify,icanhazip,identmeandifconfigcofetches both families with one retriever.dnspatch --check-configvalidates a configuration without starting the daemon.- New plugins: retriever
interface; providersbeget,dyndns2(and its ready-made formsdyn,dynu,nicru,noip),rfc2136,yandexcloud. dnspatch --check-configtells providers of one type apart by the parameters that differ between them.
Plugin API: Retriever¶
GetIPAddress is replaced by GetAddresses, which returns both families.
Before:
After:
plugin.Addresses is struct{ V4, V6 netip.Addr }. Fill the family you found
and leave the other at its zero value; at least one field must be valid.
A retriever that only ever knows one family does:
Plugin API: Provider¶
SetIPAddress is replaced by Update, which receives both families and the
record options.
Before:
After:
func (p *Provider) Update(ctx context.Context, addrs plugin.Addresses, opts plugin.RecordOptions) error
- An invalid (zero)
V4orV6means that family is left untouched: do not delete or change the existing record of that type. The runner sends only the families that changed since the last successful write. - Both fields can be valid in one call: write the
Aand theAAAArecord. If the service cannot do both in one request, do them one after another and return an error if either fails. opts.TTL, when positive, overrides the provider's configured TTL. A provider whose service has no TTL ignores it.
The simplest port of a single-family provider keeps the old body and calls it per family:
func (p *Provider) Update(ctx context.Context, addrs plugin.Addresses, opts plugin.RecordOptions) error {
for _, addr := range []netip.Addr{addrs.V4, addrs.V6} {
if !addr.IsValid() {
continue
}
if err := p.set(ctx, addr); err != nil {
return err
}
}
return nil
}
Tests that called SetIPAddress or GetIPAddress must be updated the same
way. Run go generate ./... afterwards if the plugin configuration changed.
Plugin API: required is an option of the toml tag¶
A required parameter is marked with an option of the toml tag, the way
encoding/json writes json:"name,omitempty". The separate required:"true"
tag is no longer read.
Before:
After:
Nothing reports the old tag: a plugin built against 0.3 that still says
required:"true" compiles, and the parameter silently becomes optional, so a
forgotten token reaches the service as an unauthorised request. Search the
plugin for required: and convert every match. An unknown or repeated option
in the toml tag stops the process at registration.
A parameter that holds a password, key, token or a URL with a login should also
carry the new secret option, toml:"token,required,secret": --check-config
prints such a value as *** instead of the value itself.