feat: initial release
This commit is contained in:
parent
a3cf21f5bd
commit
1e0ee5bffe
40 changed files with 2007 additions and 217 deletions
7
cmd/hivemind-lite/main.go
Normal file
7
cmd/hivemind-lite/main.go
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("hivemind lite")
|
||||
}
|
||||
169
cmd/hivemind/main.go
Normal file
169
cmd/hivemind/main.go
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
var (
|
||||
configFile = "/etc/hivemind/config.toml"
|
||||
registryFile = "/var/lib/hivemind/registry"
|
||||
)
|
||||
|
||||
func levelToZerolog(l config.LogLevel) zerolog.Level {
|
||||
switch l {
|
||||
case config.LogLevelDebug:
|
||||
return zerolog.DebugLevel
|
||||
case config.LogLevelInfo:
|
||||
return zerolog.InfoLevel
|
||||
case config.LogLevelWarn:
|
||||
return zerolog.WarnLevel
|
||||
case config.LogLevelError:
|
||||
return zerolog.ErrorLevel
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
|
||||
return filepath.Base(file) + ":" + strconv.Itoa(line)
|
||||
}
|
||||
log.Logger = log.With().Caller().Stack().Logger()
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
|
||||
|
||||
if e := os.Getenv("HIVEMIND_CONFIG_FILE"); e != "" {
|
||||
configFile = e
|
||||
}
|
||||
|
||||
if e := os.Getenv("HIVEMIND_REGISTRY_FILE"); e != "" {
|
||||
registryFile = e
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
config, err := config.FromFile(configFile)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("unable to read config file")
|
||||
}
|
||||
|
||||
if err := config.Validate(); err != nil {
|
||||
log.Fatal().Err(err).Msg("invalid configuration")
|
||||
}
|
||||
|
||||
zerolog.SetGlobalLevel(levelToZerolog(config.Node.LogLevel))
|
||||
|
||||
self := types.NewNode(
|
||||
fmt.Sprintf("%v:%v", config.Node.Endpoint, config.Node.Port),
|
||||
config.Node.Hostname,
|
||||
config.Roles,
|
||||
)
|
||||
|
||||
filestore := registry.NewFileStorage(registryFile)
|
||||
filestore.EnsureExists()
|
||||
registry := registry.New(filestore, self)
|
||||
|
||||
state := state.New(registry, self)
|
||||
|
||||
nodeRole := node.New(state, config.Node)
|
||||
|
||||
var builder middleware.MiddlewareBuilder
|
||||
middlewares := builder.Prepare()
|
||||
|
||||
client.Init(middlewares)
|
||||
|
||||
listenAddr := fmt.Sprintf("%v:%v", config.Node.ListenOn, config.Node.Port)
|
||||
server := server.NewServer(listenAddr, middlewares)
|
||||
|
||||
roles := make([]roles.Role, 0)
|
||||
roles = append(roles, nodeRole)
|
||||
|
||||
for _, role := range config.Roles {
|
||||
switch role {
|
||||
case types.MasterRole:
|
||||
role := master.New(state, config.Configs.Master)
|
||||
roles = append(roles, role)
|
||||
case types.DnsRole:
|
||||
role := dns.New(state, config.Configs.Dns)
|
||||
roles = append(roles, role)
|
||||
case types.HostRole:
|
||||
role := host.New(state, config.Configs.Host)
|
||||
roles = append(roles, role)
|
||||
}
|
||||
}
|
||||
|
||||
for _, role := range roles {
|
||||
role.RegisterHandlers(server)
|
||||
}
|
||||
|
||||
serverError := make(chan error)
|
||||
go func() {
|
||||
log.Info().Str("addr", listenAddr).Msg("started listening")
|
||||
serverError <- server.Listen()
|
||||
}()
|
||||
|
||||
if err := nodeRole.Join(config.Node.BootstrapMaster); err != nil {
|
||||
log.Warn().Err(err).Msg("unable to join")
|
||||
} else {
|
||||
log.Info().Msg("joined")
|
||||
}
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
for _, role := range roles {
|
||||
logger := log.With().Str("role", fmt.Sprintf("%T", role)).Logger()
|
||||
logger.Debug().Msg("running OnStartup handler")
|
||||
if err := role.OnStartup(ctx); err != nil {
|
||||
logger.Err(err).Msg("failed to initialize role")
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug().Msg("finished role startup")
|
||||
|
||||
select {
|
||||
case err := <-serverError:
|
||||
log.Err(err).Send()
|
||||
case <-ctx.Done():
|
||||
log.Info().Msg("got stop signal")
|
||||
}
|
||||
|
||||
cancel()
|
||||
|
||||
if err := server.Shutdown(context.Background()); err != nil {
|
||||
log.Err(err).Msg("error while shutting down the server")
|
||||
}
|
||||
|
||||
if err := nodeRole.Leave(); err != nil {
|
||||
log.Info().Err(err).Msg("error while sending shutdown packet")
|
||||
}
|
||||
|
||||
for _, role := range roles {
|
||||
if err := role.OnShutdown(); err != nil {
|
||||
log.Err(err).Interface("role", role).Msg("failed to shutdown role")
|
||||
}
|
||||
}
|
||||
|
||||
registry.Save()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue