chore: use go generate to create Validate and Merge funcs on RoleConfigs
This commit is contained in:
parent
28b7993be4
commit
c9e93802eb
10 changed files with 236 additions and 200 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
||||||
/build/
|
/build/
|
||||||
|
*_gen.go
|
||||||
|
|
|
||||||
10
Makefile
10
Makefile
|
|
@ -1,13 +1,15 @@
|
||||||
|
|
||||||
all: hivemind hivemind-musl
|
all: hivemind hivemind-musl
|
||||||
|
|
||||||
hivemind:
|
codegen:
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
hivemind: codegen
|
||||||
go build -o build/hivemind ./cmd/hivemind
|
go build -o build/hivemind ./cmd/hivemind
|
||||||
|
|
||||||
hivemind-musl:
|
hivemind-musl: codegen
|
||||||
CC=musl-gcc go build \
|
CC=musl-gcc go build \
|
||||||
-ldflags="-linkmode external -extldflags '-static'" \
|
-ldflags="-linkmode external -extldflags '-static'" \
|
||||||
-o build/hivemind-musl \
|
-o build/hivemind-musl \
|
||||||
./cmd/hivemind
|
./cmd/hivemind
|
||||||
|
|
||||||
.phony: all hivemind hivemind-musl
|
.phony: all codegen hivemind hivemind-musl
|
||||||
|
|
|
||||||
7
go.mod
7
go.mod
|
|
@ -3,13 +3,16 @@ module git.wzray.com/homelab/hivemind
|
||||||
go 1.25.5
|
go 1.25.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/rs/zerolog v1.34.0
|
|
||||||
github.com/BurntSushi/toml v1.6.0
|
github.com/BurntSushi/toml v1.6.0
|
||||||
|
github.com/rs/zerolog v1.34.0
|
||||||
|
golang.org/x/tools v0.41.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
golang.org/x/sys v0.39.0 // indirect
|
golang.org/x/mod v0.32.0 // indirect
|
||||||
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
12
go.sum
12
go.sum
|
|
@ -2,6 +2,8 @@ github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk
|
||||||
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
|
|
@ -14,8 +16,14 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||||
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
||||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||||
|
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
|
||||||
|
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
|
||||||
|
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
|
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
|
||||||
|
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
|
||||||
|
|
|
||||||
196
internal/codegen/roleconfig/main.go
Normal file
196
internal/codegen/roleconfig/main.go
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
"golang.org/x/tools/imports"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultMerge = `
|
||||||
|
if s.%[1]s != %[2]s {
|
||||||
|
s.%[1]s = other.%[1]s
|
||||||
|
}
|
||||||
|
`
|
||||||
|
defaultValidator = `
|
||||||
|
if s.%[1]s == %[2]s {
|
||||||
|
return errors.New("missing %[3]s")
|
||||||
|
}
|
||||||
|
`
|
||||||
|
ipValidator = `
|
||||||
|
if net.ParseIP(s.%[1]s) == nil {
|
||||||
|
return fmt.Errorf("invalid %[3]s: %%q", s.%[1]s)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
positiveValidator = `
|
||||||
|
if s.%[1]s < 1 {
|
||||||
|
return fmt.Errorf("invalid %[3]s: %%q", s.%[1]s)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
structName string
|
||||||
|
packageName string
|
||||||
|
fileName string
|
||||||
|
)
|
||||||
|
|
||||||
|
type Validator struct {
|
||||||
|
code string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Field struct {
|
||||||
|
name string
|
||||||
|
prettyName string
|
||||||
|
defaultValue string
|
||||||
|
validators []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewField(name, prettyName, defaultValue, tag string) *Field {
|
||||||
|
validators := make([]string, 0, 2)
|
||||||
|
|
||||||
|
switch tag {
|
||||||
|
case "":
|
||||||
|
validators = append(validators, defaultValidator)
|
||||||
|
case "ip":
|
||||||
|
validators = append(validators, defaultValidator, ipValidator)
|
||||||
|
case "positive":
|
||||||
|
validators = append(validators, positiveValidator)
|
||||||
|
case "no":
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("invalid tag %v", tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Field{
|
||||||
|
name: name,
|
||||||
|
prettyName: prettyName,
|
||||||
|
defaultValue: defaultValue,
|
||||||
|
validators: validators,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
namePtr := flag.String("name", "", "name of the struct")
|
||||||
|
flag.Parse()
|
||||||
|
if namePtr == nil || *namePtr == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "Invalid name")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
structName = *namePtr
|
||||||
|
|
||||||
|
packageName = os.Getenv("GOPACKAGE")
|
||||||
|
|
||||||
|
fileName = fmt.Sprintf("%s_gen.go", strings.TrimSuffix(os.Getenv("GOFILE"), ".go"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultValue(t types.Type) string {
|
||||||
|
b, ok := t.Underlying().(*types.Basic)
|
||||||
|
if !ok {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch b.Kind() {
|
||||||
|
case types.Int, types.Int8, types.Int16, types.Int32, types.Int64,
|
||||||
|
types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64:
|
||||||
|
return "0"
|
||||||
|
case types.String:
|
||||||
|
return `""`
|
||||||
|
case types.Bool:
|
||||||
|
return "false"
|
||||||
|
default:
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Package struct {
|
||||||
|
fields []*Field
|
||||||
|
imports map[string]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func enumerateFields(root *types.Struct) []*Field {
|
||||||
|
fields := make([]*Field, 0, 16)
|
||||||
|
|
||||||
|
for i := range root.NumFields() {
|
||||||
|
field := root.Field(i)
|
||||||
|
tag := reflect.StructTag(root.Tag(i))
|
||||||
|
|
||||||
|
extraValidators := tag.Get("gen")
|
||||||
|
prettyName := tag.Get("toml")
|
||||||
|
if embed, ok := field.Type().Underlying().(*types.Struct); ok {
|
||||||
|
fields = append(fields, enumerateFields(embed)...)
|
||||||
|
} else {
|
||||||
|
fields = append(fields, NewField(field.Name(), prettyName, defaultValue(field.Type()), extraValidators))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeMerge(w io.Writer, name string, fields []*Field) {
|
||||||
|
fmt.Fprintf(w, "func (s *%[1]s) Merge(other %[1]s) {", name)
|
||||||
|
for _, f := range fields {
|
||||||
|
fmt.Fprintf(w, defaultMerge, f.name, f.defaultValue)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "}\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeValidators(w io.Writer, name string, fields []*Field) {
|
||||||
|
fmt.Fprintf(w, "func (s %s) Validate() error {", name)
|
||||||
|
for _, f := range fields {
|
||||||
|
for _, v := range f.validators {
|
||||||
|
fmt.Fprintf(w, v, f.name, f.defaultValue, f.prettyName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "\nreturn nil\n}\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg := &packages.Config{
|
||||||
|
Mode: packages.NeedName |
|
||||||
|
packages.NeedTypes |
|
||||||
|
packages.NeedTypesInfo |
|
||||||
|
packages.NeedSyntax |
|
||||||
|
packages.NeedFiles,
|
||||||
|
}
|
||||||
|
pkgs, _ := packages.Load(cfg, ".")
|
||||||
|
config := *pkgs[0]
|
||||||
|
for _, v := range config.Syntax {
|
||||||
|
ast.Inspect(v, func(node ast.Node) bool {
|
||||||
|
decl, ok := node.(*ast.GenDecl)
|
||||||
|
if !ok || decl.Tok != token.TYPE {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, spec := range decl.Specs {
|
||||||
|
ts := spec.(*ast.TypeSpec)
|
||||||
|
if ts.Name.String() != structName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
t := config.TypesInfo.TypeOf(ts.Type.(*ast.StructType)).(*types.Struct)
|
||||||
|
fields := enumerateFields(t)
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(make([]byte, 0))
|
||||||
|
fmt.Fprintf(buf, "// Code generated by roleconfig; DO NOT EDIT.\n\npackage %s\n", packageName)
|
||||||
|
writeValidators(buf, structName, fields)
|
||||||
|
writeMerge(buf, structName, fields)
|
||||||
|
x, _ := imports.Process(fileName, buf.Bytes(), nil)
|
||||||
|
os.WriteFile(fileName, x, 0644)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,20 +1,8 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
//go:generate -command roleconfig go run git.wzray.com/homelab/hivemind/internal/codegen/roleconfig
|
||||||
|
//go:generate roleconfig -name DnsConfig
|
||||||
type DnsConfig struct {
|
type DnsConfig struct {
|
||||||
UseSystemd bool `toml:"use_systemd"`
|
UseSystemd bool `toml:"use_systemd" gen:"no"`
|
||||||
baseRoleConfig
|
baseRoleConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c DnsConfig) Validate() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *DnsConfig) Merge(other DnsConfig) {
|
|
||||||
if other.set {
|
|
||||||
c.set = other.set
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.UseSystemd {
|
|
||||||
c.UseSystemd = other.UseSystemd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,13 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
//go:generate -command roleconfig go run git.wzray.com/homelab/hivemind/internal/codegen/roleconfig
|
||||||
"errors"
|
//go:generate roleconfig -name HostConfig
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HostConfig struct {
|
type HostConfig struct {
|
||||||
Domain string `toml:"domain"`
|
Domain string `toml:"domain"`
|
||||||
IpAddress string `toml:"ip"`
|
IpAddress string `toml:"ip" gen:"ip"`
|
||||||
LocalAddress string `toml:"local_address"`
|
LocalAddress string `toml:"local_address"`
|
||||||
InternalEntrypoint string `toml:"internal_entrypoint"`
|
InternalEntrypoint string `toml:"internal_entrypoint"`
|
||||||
ExternalEntrypoint string `toml:"external_entrypoint"`
|
ExternalEntrypoint string `toml:"external_entrypoint"`
|
||||||
ListenAddress string `toml:"listen_address"`
|
ListenAddress string `toml:"listen_address"`
|
||||||
baseRoleConfig
|
baseRoleConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c HostConfig) Validate() error {
|
|
||||||
if c.Domain == "" {
|
|
||||||
return errors.New("missing domain")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.IpAddress == "" {
|
|
||||||
return errors.New("missing ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
if net.ParseIP(c.IpAddress) == nil {
|
|
||||||
return fmt.Errorf("invalid ip: %q", c.IpAddress)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.LocalAddress == "" {
|
|
||||||
return errors.New("missing local_address")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.InternalEntrypoint == "" {
|
|
||||||
return errors.New("missing internal_entrypoint")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.ExternalEntrypoint == "" {
|
|
||||||
return errors.New("missing external_entrypoint")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.ListenAddress == "" {
|
|
||||||
return errors.New("missing listen_address")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *HostConfig) Merge(other HostConfig) {
|
|
||||||
if other.set {
|
|
||||||
c.set = other.set
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.Domain != "" {
|
|
||||||
c.Domain = other.Domain
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.IpAddress != "" {
|
|
||||||
c.IpAddress = other.IpAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.LocalAddress != "" {
|
|
||||||
c.LocalAddress = other.LocalAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.InternalEntrypoint != "" {
|
|
||||||
c.InternalEntrypoint = other.InternalEntrypoint
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.ExternalEntrypoint != "" {
|
|
||||||
c.ExternalEntrypoint = other.ExternalEntrypoint
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.ListenAddress != "" {
|
|
||||||
c.ListenAddress = other.ListenAddress
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,12 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import "errors"
|
//go:generate -command roleconfig go run git.wzray.com/homelab/hivemind/internal/codegen/roleconfig
|
||||||
|
//go:generate roleconfig -name MasterConfig
|
||||||
type MasterConfig struct {
|
type MasterConfig struct {
|
||||||
ObserverInterval int `toml:"observer_interval"`
|
ObserverInterval int `toml:"observer_interval" gen:"positive"`
|
||||||
BackoffSeconds int `toml:"backoff_seconds"`
|
BackoffSeconds int `toml:"backoff_seconds" gen:"positive"`
|
||||||
BackoffCount int `toml:"backoff_count"`
|
BackoffCount int `toml:"backoff_count" gen:"positive"`
|
||||||
NodeTimeout int `toml:"node_timeout"`
|
NodeTimeout int `toml:"node_timeout" gen:"positive"`
|
||||||
|
|
||||||
baseRoleConfig
|
baseRoleConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c MasterConfig) Validate() error {
|
|
||||||
if c.ObserverInterval < 1 {
|
|
||||||
return errors.New("invalid observer_interval")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.BackoffSeconds < 1 {
|
|
||||||
return errors.New("invalid backoff_seconds")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.BackoffCount < 1 {
|
|
||||||
return errors.New("invalid backoff_count")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.NodeTimeout < 1 {
|
|
||||||
return errors.New("invalid node_timeout")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MasterConfig) Merge(other MasterConfig) {
|
|
||||||
if other.set {
|
|
||||||
c.set = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.ObserverInterval != 0 {
|
|
||||||
c.ObserverInterval = other.ObserverInterval
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.BackoffSeconds != 0 {
|
|
||||||
c.BackoffSeconds = other.BackoffSeconds
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.BackoffCount != 0 {
|
|
||||||
c.BackoffCount = other.BackoffCount
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.NodeTimeout != 0 {
|
|
||||||
c.NodeTimeout = other.NodeTimeout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -28,68 +26,16 @@ func (l *LogLevel) UnmarshalText(data []byte) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:generate -command roleconfig go run git.wzray.com/homelab/hivemind/internal/codegen/roleconfig
|
||||||
|
//go:generate roleconfig -name NodeConfig
|
||||||
type NodeConfig struct {
|
type NodeConfig struct {
|
||||||
Hostname string `toml:"hostname"`
|
Hostname string `toml:"hostname"`
|
||||||
Address string `toml:"address"`
|
Address string `toml:"address"`
|
||||||
Port int `toml:"port"`
|
Port int `toml:"port"`
|
||||||
|
|
||||||
KeepaliveInterval int `toml:"keepalive_interval"`
|
KeepaliveInterval int `toml:"keepalive_interval" gen:"positive"`
|
||||||
LogLevel LogLevel `toml:"log_level"`
|
LogLevel LogLevel `toml:"log_level"`
|
||||||
|
|
||||||
BootstrapMaster string `toml:"bootstrap_master"`
|
BootstrapMaster string `toml:"bootstrap_master" gen:"no"`
|
||||||
ListenOn string `toml:"listen_on"`
|
ListenOn string `toml:"listen_on" gen:"ip"`
|
||||||
}
|
|
||||||
|
|
||||||
func (c NodeConfig) Validate() error {
|
|
||||||
if c.Address == "" {
|
|
||||||
return errors.New("missing address")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Hostname == "" {
|
|
||||||
return errors.New("missing hostname")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.KeepaliveInterval < 1 {
|
|
||||||
return errors.New("invalid keepalive_interval")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.ListenOn == "" {
|
|
||||||
return errors.New("missing listen_on")
|
|
||||||
}
|
|
||||||
|
|
||||||
if net.ParseIP(c.ListenOn) == nil {
|
|
||||||
return fmt.Errorf("invalid listen_on: %v", c.ListenOn)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *NodeConfig) Merge(other NodeConfig) {
|
|
||||||
if other.Hostname != "" {
|
|
||||||
c.Hostname = other.Hostname
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.Address != "" {
|
|
||||||
c.Address = other.Address
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.BootstrapMaster != "" {
|
|
||||||
c.BootstrapMaster = other.BootstrapMaster
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.ListenOn != "" {
|
|
||||||
c.ListenOn = other.ListenOn
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.Port != 0 {
|
|
||||||
c.Port = other.Port
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.KeepaliveInterval != 0 {
|
|
||||||
c.KeepaliveInterval = other.KeepaliveInterval
|
|
||||||
}
|
|
||||||
|
|
||||||
if other.LogLevel != "" {
|
|
||||||
c.LogLevel = other.LogLevel
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
type baseRoleConfig struct {
|
type baseRoleConfig struct {
|
||||||
set bool
|
set bool `gen:"no"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue