diff --git a/cmd/hivemind/main.go b/cmd/hivemind/main.go index 7496017..e6cff3c 100644 --- a/cmd/hivemind/main.go +++ b/cmd/hivemind/main.go @@ -9,18 +9,18 @@ import ( "strconv" "syscall" - "git.wzray.com/homelab/hivemind/internal/config" - "git.wzray.com/homelab/hivemind/internal/registry" - "git.wzray.com/homelab/hivemind/internal/roles" - "git.wzray.com/homelab/hivemind/internal/roles/dns" - "git.wzray.com/homelab/hivemind/internal/roles/host" - "git.wzray.com/homelab/hivemind/internal/roles/master" - "git.wzray.com/homelab/hivemind/internal/roles/node" - "git.wzray.com/homelab/hivemind/internal/state" - "git.wzray.com/homelab/hivemind/internal/types" - "git.wzray.com/homelab/hivemind/internal/web/client" - "git.wzray.com/homelab/hivemind/internal/web/middleware" - "git.wzray.com/homelab/hivemind/internal/web/server" + "git.wzray.com/homelab/mastermind/internal/config" + "git.wzray.com/homelab/mastermind/internal/registry" + "git.wzray.com/homelab/mastermind/internal/roles" + "git.wzray.com/homelab/mastermind/internal/roles/dns" + "git.wzray.com/homelab/mastermind/internal/roles/host" + "git.wzray.com/homelab/mastermind/internal/roles/master" + "git.wzray.com/homelab/mastermind/internal/roles/node" + "git.wzray.com/homelab/mastermind/internal/state" + "git.wzray.com/homelab/mastermind/internal/types" + "git.wzray.com/homelab/mastermind/internal/web/client" + "git.wzray.com/homelab/mastermind/internal/web/middleware" + "git.wzray.com/homelab/mastermind/internal/web/server" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/rs/zerolog/pkgerrors" @@ -76,9 +76,8 @@ func main() { zerolog.SetGlobalLevel(levelToZerolog(config.Node.LogLevel)) self := types.NewNode( + fmt.Sprintf("%v:%v", config.Node.Endpoint, config.Node.Port), config.Node.Hostname, - config.Node.Address, - config.Node.Port, config.Roles, ) diff --git a/config.toml b/config.toml index 99f01dd..092bfb1 100644 --- a/config.toml +++ b/config.toml @@ -1,19 +1,19 @@ [node] log_level = "DEBUG" -address = "laptop.spb.wzray.com" -hostname = "laptop.spb.wzray.com" -bootstrap_master = "hicpu.spb.wzray.com" -keepalive_interval = 10 +hostname = "" +endpoint = "" +bootstrap_master = "" +keepalive_interval = 1 [roles.master] -observer_interval = 1 +observer_interval = 4 [roles.dns] use_systemd = false [roles.host] -domain = "traefik.wzray.com" -ip = "10.161.4.11" -local_address = "10.161.4.11" -internal_entrypoint = "https" -external_entrypoint = "ehttps" +domain = "" +ip = "" +local_address = "" +internal_entrypoint = "" +external_entrypoint = "" diff --git a/go.mod b/go.mod index eceeb1b..9923039 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module git.wzray.com/homelab/hivemind +module git.wzray.com/homelab/mastermind go 1.25.5 diff --git a/internal/config/config.go b/internal/config/config.go index 25ee12d..dafd481 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -5,7 +5,7 @@ import ( "fmt" "os" - "git.wzray.com/homelab/hivemind/internal/types" + "git.wzray.com/homelab/mastermind/internal/types" "github.com/BurntSushi/toml" ) diff --git a/internal/config/node.go b/internal/config/node.go index 4049bfe..2ffa6db 100644 --- a/internal/config/node.go +++ b/internal/config/node.go @@ -3,7 +3,6 @@ package config import ( "errors" "fmt" - "net" "strings" ) @@ -29,32 +28,27 @@ func (l *LogLevel) UnmarshalText(data []byte) error { } type NodeConfig struct { - Hostname string `toml:"hostname"` - Address string `toml:"address"` - Port int `toml:"port"` - + Hostname string `toml:"hostname"` + Endpoint string `toml:"endpoint"` KeepaliveInterval int `toml:"keepalive_interval"` LogLevel LogLevel `toml:"log_level"` BootstrapMaster string `toml:"bootstrap_master"` ListenOn string `toml:"listen_on"` + Port int `toml:"port"` } 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 && c.KeepaliveInterval != -1 { - return errors.New("invalid keepalive_interval") + if c.Endpoint == "" { + return errors.New("missing endpoint") } - if net.ParseIP(c.ListenOn) == nil { - return errors.New("invalid listen_on") + if c.KeepaliveInterval < 1 && c.KeepaliveInterval != -1 { + return errors.New("invalid keepalive_interval") } return nil @@ -65,8 +59,8 @@ func (c *NodeConfig) Merge(other NodeConfig) { c.Hostname = other.Hostname } - if other.Address != "" { - c.Address = other.Address + if other.Endpoint != "" { + c.Endpoint = other.Endpoint } if other.BootstrapMaster != "" { diff --git a/internal/registry/filestorage.go b/internal/registry/filestorage.go index 0891dda..3fe4247 100644 --- a/internal/registry/filestorage.go +++ b/internal/registry/filestorage.go @@ -8,7 +8,7 @@ import ( "sync" "time" - "git.wzray.com/homelab/hivemind/internal/types" + "git.wzray.com/homelab/mastermind/internal/types" ) type FileStorage struct { diff --git a/internal/registry/registry.go b/internal/registry/registry.go index 17f7186..d3a5a4d 100644 --- a/internal/registry/registry.go +++ b/internal/registry/registry.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "git.wzray.com/homelab/hivemind/internal/types" + "git.wzray.com/homelab/mastermind/internal/types" "github.com/rs/zerolog/log" ) @@ -36,7 +36,7 @@ func New(storage Storage, self types.Node) *Registry { r.nodes = storedData.Nodes ret: - r.nodes[self.Hostname] = self + r.nodes[self.Name] = self return r } @@ -68,7 +68,7 @@ func (r *Registry) AllNodes() []types.Node { func (r *Registry) Nodes() []types.Node { nodes := r.AllNodes() nodes = slices.DeleteFunc(nodes, func(n types.Node) bool { - return n.Hostname == r.self.Hostname + return n.Name == r.self.Name }) return nodes } @@ -79,7 +79,7 @@ func (r *Registry) ByRole(role types.Role) []types.Node { o := make([]types.Node, 0, len(r.nodes)) for _, node := range r.nodes { - if slices.Contains(node.Roles, role) && node.Hostname != r.self.Hostname { + if slices.Contains(node.Roles, role) && node.Name != r.self.Name { o = append(o, node) } } @@ -88,7 +88,7 @@ func (r *Registry) ByRole(role types.Role) []types.Node { func (r *Registry) AddNode(node types.Node) error { r.lock.Lock() - r.nodes[node.Hostname] = node + r.nodes[node.Name] = node r.LastUpdate = time.Now() snapshot := r.snapshot() r.lock.Unlock() @@ -119,7 +119,7 @@ func (r *Registry) Set(nodes []types.Node) error { r.lock.Lock() r.nodes = make(map[string]types.Node) for _, n := range nodes { - r.nodes[n.Hostname] = n + r.nodes[n.Name] = n } snapshot := r.snapshot() r.lock.Unlock() diff --git a/internal/registry/storage.go b/internal/registry/storage.go index 590a226..6f8ceab 100644 --- a/internal/registry/storage.go +++ b/internal/registry/storage.go @@ -1,6 +1,6 @@ package registry -import "git.wzray.com/homelab/hivemind/internal/types" +import "git.wzray.com/homelab/mastermind/internal/types" type Storage interface { Save(*storedConfig) error diff --git a/internal/roles/dns/dns.go b/internal/roles/dns/dns.go index d527c60..66efb45 100644 --- a/internal/roles/dns/dns.go +++ b/internal/roles/dns/dns.go @@ -8,10 +8,10 @@ import ( "strings" "sync" - "git.wzray.com/homelab/hivemind/internal/config" - "git.wzray.com/homelab/hivemind/internal/state" - "git.wzray.com/homelab/hivemind/internal/types" - "git.wzray.com/homelab/hivemind/internal/web/client" + "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" ) @@ -48,10 +48,10 @@ func parseState(state types.HostState) (string, []byte) { var builder strings.Builder for _, d := range state.Domains { - builder.WriteString(fmt.Sprintf("%s %s\n", state.Address, d)) + builder.WriteString(fmt.Sprintf("%s %s\n", state.Endpoint, d)) } - return hostsDir + state.Hostname, []byte(builder.String()) + return hostsDir + state.Name, []byte(builder.String()) } func (r *Role) OnStartup(ctx context.Context) error { @@ -76,15 +76,15 @@ func (r *Role) OnStartup(ctx context.Context) error { func (r *Role) syncFromRegistry() { for _, n := range r.state.Registry.ByRole(types.HostRole) { - state, err := client.Get[types.HostState](n.Endpoint, types.PathHostDns) + state, err := client.Get[types.HostState](n.Address, types.PathHostDns) if err != nil { - log.Warn().Str("name", n.Hostname).Err(err).Msg("unable to get host config") + 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.Hostname).Err(err).Msg("unable to update dnsmasq") + log.Warn().Str("name", n.Name).Err(err).Msg("unable to update dnsmasq") continue } } diff --git a/internal/roles/host/host.go b/internal/roles/host/host.go index 2b35181..6bdea06 100644 --- a/internal/roles/host/host.go +++ b/internal/roles/host/host.go @@ -8,19 +8,19 @@ import ( "slices" "sync" - "git.wzray.com/homelab/hivemind/internal/config" - "git.wzray.com/homelab/hivemind/internal/state" - "git.wzray.com/homelab/hivemind/internal/types" - "git.wzray.com/homelab/hivemind/internal/web/client" + "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" ) type Role struct { - state *state.RuntimeState - config config.HostConfig + state *state.RuntimeState + config config.HostConfig - client *traefikClient - tasksGroup sync.WaitGroup + client *traefikClient + tasksGroup sync.WaitGroup externalDomains []string // TODO: i don't like hardcoding external/internal logic here internalDomains []string @@ -37,15 +37,15 @@ func New(state *state.RuntimeState, config config.HostConfig) *Role { func (r *Role) sendUpdate(domains []string, role types.Role) { state := types.HostState{ Domains: domains, - Address: r.config.IpAddress, - Hostname: r.state.Self.Hostname, + Name: r.state.Self.Name, + Endpoint: r.state.Self.Address, } for _, node := range r.state.Registry.ByRole(role) { r.tasksGroup.Go(func() { - logger := log.With().Str("name", node.Hostname).Logger() + logger := log.With().Str("name", node.Name).Logger() logger.Debug().Msg("sending update") - if _, err := client.Post[any](node.Endpoint, types.PathDnsCallback, state); err != nil { + if _, err := client.Post[any](node.Address, types.PathDnsCallback, state); err != nil { logger.Warn().Err(err).Msg("unable to send dns info") } else { logger.Debug().Msg("update sent") @@ -87,8 +87,8 @@ func (r *Role) onCallback(w http.ResponseWriter, req *http.Request) { func (r *Role) getInternal() (types.HostState, error) { return types.HostState{ Domains: r.internalDomains, - Address: r.config.IpAddress, - Hostname: r.state.Self.Hostname, + Endpoint: r.config.IpAddress, + Name: r.state.Self.Name, }, nil } diff --git a/internal/roles/master/master.go b/internal/roles/master/master.go index 6d2884b..823b385 100644 --- a/internal/roles/master/master.go +++ b/internal/roles/master/master.go @@ -4,11 +4,11 @@ import ( "context" "sync" - "git.wzray.com/homelab/hivemind/internal/config" - "git.wzray.com/homelab/hivemind/internal/roles" - "git.wzray.com/homelab/hivemind/internal/state" - "git.wzray.com/homelab/hivemind/internal/types" - "git.wzray.com/homelab/hivemind/internal/web/client" + "git.wzray.com/homelab/mastermind/internal/config" + "git.wzray.com/homelab/mastermind/internal/roles" + "git.wzray.com/homelab/mastermind/internal/state" + "git.wzray.com/homelab/mastermind/internal/types" + "git.wzray.com/homelab/mastermind/internal/web/client" ) type Role struct { @@ -50,7 +50,7 @@ func (r *Role) OnShutdown() error { func (r *Role) notify(path types.Path, v any) { for _, n := range r.state.Registry.Nodes() { - addr := n.Endpoint + addr := n.Address r.tasksGroup.Go(func() { client.Post[any](addr, path, v) }) @@ -68,17 +68,17 @@ func (r *Role) onJoin(node types.Node) ([]types.Node, error) { } func (r *Role) onLeave(node types.Node) (bool, error) { - if err := r.state.Registry.RemoveNode(node.Hostname); err != nil { + if err := r.state.Registry.RemoveNode(node.Name); err != nil { return false, err } - r.notify(types.PathNodeLeave, node) + r.notify(types.PathNodeLeave, node.Name) return true, nil } func (r *Role) onKeepAlive(node types.Node) (bool, error) { - if ok := r.state.Registry.Exists(node.Hostname); !ok { + if ok := r.state.Registry.Exists(node.Name); !ok { _, err := r.onJoin(node) return true, err } diff --git a/internal/roles/master/observer.go b/internal/roles/master/observer.go index 64f69c8..f293133 100644 --- a/internal/roles/master/observer.go +++ b/internal/roles/master/observer.go @@ -4,9 +4,9 @@ import ( "context" "time" - "git.wzray.com/homelab/hivemind/internal/state" - "git.wzray.com/homelab/hivemind/internal/types" - "git.wzray.com/homelab/hivemind/internal/web/client" + "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" ) @@ -33,14 +33,14 @@ func newObserver( func (o *observer) pollNodes(ctx context.Context, onLeave func(types.Node) error) { for _, n := range o.state.Registry.Nodes() { - name := n.Hostname + name := n.Name logger := log.With().Str("name", name).Logger() logger.Debug().Msg("checking node") delay := time.Duration(o.backoff) alive := false for i := o.backoffCount; i > 0; i-- { - _, err := client.Get[any](n.Endpoint, types.PathNodeHealthcheck) + _, err := client.Get[any](n.Address, types.PathNodeHealthcheck) if err == nil { logger.Debug().Msg("node is alive") diff --git a/internal/roles/node/node.go b/internal/roles/node/node.go index 762ae4b..b795835 100644 --- a/internal/roles/node/node.go +++ b/internal/roles/node/node.go @@ -6,10 +6,10 @@ import ( "sync" "time" - "git.wzray.com/homelab/hivemind/internal/config" - "git.wzray.com/homelab/hivemind/internal/state" - "git.wzray.com/homelab/hivemind/internal/types" - "git.wzray.com/homelab/hivemind/internal/web/client" + "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" ) @@ -29,10 +29,10 @@ func New(state *state.RuntimeState, config config.NodeConfig) *Role { func (r *Role) Join(bootstrap string) error { masters := make(map[string]struct{}) for _, node := range r.state.Registry.ByRole(types.MasterRole) { - if node.Hostname == r.state.Self.Hostname { + if node.Name == r.state.Self.Name { continue } - masters[node.Endpoint] = struct{}{} + masters[node.Address] = struct{}{} } if bootstrap != "" { masters[bootstrap] = struct{}{} @@ -69,10 +69,10 @@ func (r *Role) Leave() error { sent := false for _, m := range masters { - logger := log.With().Str("name", m.Hostname).Logger() + logger := log.With().Str("name", m.Name).Logger() logger.Debug().Msg("sending leave message") - _, err := client.Post[any](m.Endpoint, types.PathMasterLeave, r.state.Self) + _, err := client.Post[any](m.Address, types.PathMasterLeave, r.state.Self) if err != nil { logger.Debug().Err(err).Msg("unable to send leave message") continue @@ -114,10 +114,10 @@ func (r *Role) keepaliveFunc(ctx context.Context) func() { sent := false for _, m := range masters { - logger := log.With().Str("name", m.Hostname).Logger() + logger := log.With().Str("name", m.Name).Logger() logger.Debug().Msg("sending keepalive packet") - if _, err := client.Post[any](m.Endpoint, types.PathMasterKeepalive, r.state.Self); err != nil { + if _, err := client.Post[any](m.Address, types.PathMasterKeepalive, r.state.Self); err != nil { continue } else { logger.Debug().Msg("keepalive packet sent") @@ -151,7 +151,7 @@ func (r *Role) onJoin(node types.Node) (bool, error) { } func (r *Role) onLeave(node types.Node) (bool, error) { - if err := r.state.Registry.RemoveNode(node.Hostname); err != nil { + if err := r.state.Registry.RemoveNode(node.Name); err != nil { return false, err } return true, nil diff --git a/internal/roles/role.go b/internal/roles/role.go index 4d42f6d..b0e9413 100644 --- a/internal/roles/role.go +++ b/internal/roles/role.go @@ -3,7 +3,7 @@ package roles import ( "context" - "git.wzray.com/homelab/hivemind/internal/types" + "git.wzray.com/homelab/mastermind/internal/types" ) type Role interface { diff --git a/internal/state/runtime.go b/internal/state/runtime.go index 334b28a..d6eb8ee 100644 --- a/internal/state/runtime.go +++ b/internal/state/runtime.go @@ -1,8 +1,8 @@ package state import ( - "git.wzray.com/homelab/hivemind/internal/registry" - "git.wzray.com/homelab/hivemind/internal/types" + "git.wzray.com/homelab/mastermind/internal/registry" + "git.wzray.com/homelab/mastermind/internal/types" ) type RuntimeState struct { diff --git a/internal/types/host.go b/internal/types/host.go index c9e2219..c483e75 100644 --- a/internal/types/host.go +++ b/internal/types/host.go @@ -2,6 +2,6 @@ package types type HostState struct { Domains []string - Address string - Hostname string + Endpoint string + Name string } diff --git a/internal/types/node.go b/internal/types/node.go index d1ed308..a01b651 100644 --- a/internal/types/node.go +++ b/internal/types/node.go @@ -1,27 +1,16 @@ package types -import "fmt" - // TODO: consider moving this type back to registry type Node struct { - Hostname string `json:"hostname"` - Address string `json:"address"` - Port int `json:"port"` - Roles []Role `json:"roles"` - Endpoint string `json:"endpoint"` + Address string `json:"address"` + Name string `json:"name"` + Roles []Role `json:"roles"` } -func NewNode( - hostname string, - address string, - port int, - roles []Role, -) Node { +func NewNode(address string, name string, roles []Role) Node { return Node{ - Hostname: hostname, - Address: address, - Port: port, - Roles: roles, - Endpoint: fmt.Sprintf("%s:%d", address, port), + Address: address, + Name: name, + Roles: roles, } } diff --git a/internal/types/rpc.go b/internal/types/rpc.go new file mode 100644 index 0000000..ab1254f --- /dev/null +++ b/internal/types/rpc.go @@ -0,0 +1 @@ +package types diff --git a/internal/types/web.go b/internal/types/web.go index 1416d6a..17ab7f9 100644 --- a/internal/types/web.go +++ b/internal/types/web.go @@ -6,8 +6,6 @@ import ( "net/http" ) -// TODO: split this up - type Path string func (p Path) String() string { diff --git a/internal/web/client/client.go b/internal/web/client/client.go index 5ea63cd..0c5f4e9 100644 --- a/internal/web/client/client.go +++ b/internal/web/client/client.go @@ -10,8 +10,8 @@ import ( "net/url" "time" - "git.wzray.com/homelab/hivemind/internal/types" - "git.wzray.com/homelab/hivemind/internal/web/middleware" + "git.wzray.com/homelab/mastermind/internal/types" + "git.wzray.com/homelab/mastermind/internal/web/middleware" ) type client struct { diff --git a/internal/web/server/server.go b/internal/web/server/server.go index 9ce1c53..e9b8e8e 100644 --- a/internal/web/server/server.go +++ b/internal/web/server/server.go @@ -5,8 +5,8 @@ import ( "io" "net/http" - "git.wzray.com/homelab/hivemind/internal/types" - "git.wzray.com/homelab/hivemind/internal/web/middleware" + "git.wzray.com/homelab/mastermind/internal/types" + "git.wzray.com/homelab/mastermind/internal/web/middleware" "github.com/rs/zerolog/log" ) diff --git a/internal/web/server/util.go b/internal/web/server/util.go index 6ba2288..78e06b8 100644 --- a/internal/web/server/util.go +++ b/internal/web/server/util.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "git.wzray.com/homelab/hivemind/internal/types" + "git.wzray.com/homelab/mastermind/internal/types" ) func fail(format string, a ...any) []byte {