Files
coredns/plugin/nomad/setup.go
Olli Janatuinen 83ce0baeac plugin/nomad: Add a Nomad plugin (#7467)
Signed-off-by: Olli Janatuinen <olli.janatuinen@gmail.com>
2025-09-30 09:35:32 -07:00

142 lines
3.2 KiB
Go

package nomad
import (
"fmt"
"strconv"
"strings"
"github.com/coredns/caddy"
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
nomad "github.com/hashicorp/nomad/api"
)
// init registers this plugin.
func init() { plugin.Register(pluginName, setup) }
// setup is the function that gets called when the config parser sees the token "nomad". Setup is responsible
// for parsing any extra options the nomad plugin may have. The first token this function sees is "nomad".
func setup(c *caddy.Controller) error {
n := &Nomad{
ttl: uint32(defaultTTL),
clients: make([]*nomad.Client, 0),
current: -1,
}
// Parse the configuration, including the zone argument
if err := parse(c, n); err != nil {
return plugin.Error("nomad", err)
}
c.OnStartup(func() error {
var err error
for idx, client := range n.clients {
_, err := client.Agent().Self()
if err == nil {
n.current = idx
return nil
}
}
return err
})
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
n.Next = next
return n
})
return nil
}
func parse(c *caddy.Controller, n *Nomad) error {
var token string
addresses := []string{} // Multiple addresses are stored here
// Expect the first token to be "nomad"
if !c.Next() {
return c.Err("expected 'nomad' token")
}
// Check for the zone argument
args := c.RemainingArgs()
if len(args) == 0 {
n.Zone = "service.nomad"
} else {
n.Zone = args[0]
}
// Parse the configuration block
for c.NextBlock() {
selector := strings.ToLower(c.Val())
switch selector {
case "address":
args := c.RemainingArgs()
if len(args) == 0 {
return c.Err("at least one address is required")
}
addresses = append(addresses, args...)
case "token":
args := c.RemainingArgs()
if len(args) != 1 {
return c.Err("exactly one token is required")
}
token = args[0]
case "ttl":
args := c.RemainingArgs()
if len(args) != 1 {
return c.Err("exactly one ttl value is required")
}
t, err := strconv.Atoi(args[0])
if err != nil {
return c.Err("error parsing ttl: " + err.Error())
}
if t < 0 || t > 3600 {
return c.Errf("ttl must be in range [0, 3600]: %d", t)
}
n.ttl = uint32(t)
default:
return c.Errf("unknown property '%s'", selector)
}
}
// Push an empty address to create a client solely based on the defaults.
if len(addresses) == 0 {
addresses = append(addresses, "")
}
for _, addr := range addresses {
cfg := nomad.DefaultConfig()
if len(addr) > 0 {
cfg.Address = addr
}
if len(token) > 0 {
cfg.SecretID = token
}
client, err := nomad.NewClient(cfg)
if err != nil {
return plugin.Error("nomad", err)
}
n.clients = append(n.clients, client) // Store all clients
}
return nil
}
func (n *Nomad) getClient() (*nomad.Client, error) {
// Don't bother querying Agent().Self() if there is only one client.
if len(n.clients) == 1 {
return n.clients[0], nil
}
for i := range len(n.clients) {
idx := (n.current + i) % len(n.clients)
_, err := n.clients[idx].Agent().Self()
if err == nil {
n.current = idx
return n.clients[idx], nil
}
}
return nil, fmt.Errorf("no Nomad client available")
}