1
0
Fork 0

feat: initial release

This commit is contained in:
Arthur K. 2026-01-17 18:14:50 +03:00
parent a3cf21f5bd
commit 761174d035
Signed by: wzray
GPG key ID: B97F30FDC4636357
41 changed files with 2008 additions and 217 deletions

122
internal/roles/dns/dns.go Normal file
View file

@ -0,0 +1,122 @@
package dns
import (
"context"
"fmt"
"os"
"os/exec"
"strings"
"sync"
"git.wzray.com/homelab/mastermind/internal/config"
"git.wzray.com/homelab/mastermind/internal/state"
"git.wzray.com/homelab/mastermind/internal/types"
"git.wzray.com/homelab/mastermind/internal/web/client"
"github.com/rs/zerolog/log"
)
const hostsDir = "/etc/hosts.d/"
type Role struct {
state *state.RuntimeState
config config.DnsConfig
group sync.WaitGroup
}
func New(state *state.RuntimeState, config config.DnsConfig) *Role {
r := &Role{
state: state,
config: config,
}
return r
}
func (r *Role) updateDnsmasq(filename string, data []byte) error {
if err := os.WriteFile(filename, data, 0644); err != nil {
return fmt.Errorf("write endpoint file %q: %w", filename, err)
}
if err := r.reload(); err != nil {
return fmt.Errorf("reload dnsmasq: %w", err)
}
return nil
}
func parseState(state types.HostState) (string, []byte) {
var builder strings.Builder
for _, d := range state.Domains {
builder.WriteString(fmt.Sprintf("%s %s\n", state.Name, d))
}
return hostsDir + state.Endpoint, []byte(builder.String())
}
func (r *Role) OnStartup(ctx context.Context) error {
r.group.Go(func() {
r.syncFromRegistry()
})
c := r.state.Registry.OnChanged()
r.group.Go(func() {
for {
select {
case <-ctx.Done():
return
case <-c:
r.syncFromRegistry()
}
}
})
return nil
}
func (r *Role) syncFromRegistry() {
for _, n := range r.state.Registry.ByRole(types.HostRole) {
state, err := client.Get[types.HostState](n.Address, types.PathHostDns)
if err != nil {
log.Warn().Str("name", n.Name).Err(err).Msg("unable to get host config")
continue
}
filename, data := parseState(*state)
if err := r.updateDnsmasq(filename, data); err != nil {
log.Warn().Str("name", n.Name).Err(err).Msg("unable to update dnsmasq")
continue
}
}
}
func (r *Role) OnShutdown() error {
r.group.Wait()
return nil
}
func (r *Role) reload() error {
var err error
if r.config.UseSystemd {
err = exec.Command("systemctl", "reload", "dnsmasq").Run()
} else {
err = exec.Command("/etc/init.d/dnsmasq", "reload").Run()
}
return err
}
func (r *Role) onCallback(state types.HostState) (bool, error) {
filename, data := parseState(state)
if err := r.updateDnsmasq(filename, data); err != nil {
return false, err
}
return true, nil
}
func (r *Role) RegisterHandlers(rg types.Registrator) {
rg.Register(types.PostEndpoint(types.PathDnsCallback, r.onCallback))
}