134 lines
3.4 KiB
Go
134 lines
3.4 KiB
Go
package cmd
|
|
|
|
import (
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
"github.com/loveuer/go-alived/internal/health"
|
|
"github.com/loveuer/go-alived/internal/vrrp"
|
|
"github.com/loveuer/go-alived/pkg/config"
|
|
"github.com/loveuer/go-alived/pkg/logger"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var (
|
|
configFile string
|
|
debug bool
|
|
)
|
|
|
|
var runCmd = &cobra.Command{
|
|
Use: "run",
|
|
Short: "Run the VRRP service",
|
|
Long: `Start the go-alived VRRP service with health checking.`,
|
|
Run: runService,
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(runCmd)
|
|
|
|
runCmd.Flags().StringVarP(&configFile, "config", "c", "/etc/go-alived/config.yaml", "path to configuration file")
|
|
runCmd.Flags().BoolVarP(&debug, "debug", "d", false, "enable debug mode")
|
|
}
|
|
|
|
func runService(cmd *cobra.Command, args []string) {
|
|
log := logger.New(debug)
|
|
|
|
log.Info("starting go-alived...")
|
|
log.Info("loading configuration from: %s", configFile)
|
|
|
|
cfg, err := config.Load(configFile)
|
|
if err != nil {
|
|
log.Error("failed to load configuration: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
log.Info("configuration loaded successfully")
|
|
log.Debug("config: %+v", cfg)
|
|
|
|
healthMgr, err := health.LoadFromConfig(cfg, log)
|
|
if err != nil {
|
|
log.Error("failed to load health check configuration: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
vrrpMgr := vrrp.NewManager(log)
|
|
if err := vrrpMgr.LoadFromConfig(cfg); err != nil {
|
|
log.Error("failed to load VRRP configuration: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
setupHealthTracking(vrrpMgr, healthMgr, log)
|
|
|
|
healthMgr.StartAll()
|
|
|
|
if err := vrrpMgr.StartAll(); err != nil {
|
|
log.Error("failed to start VRRP instances: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
|
|
|
for {
|
|
sig := <-sigChan
|
|
switch sig {
|
|
case syscall.SIGHUP:
|
|
log.Info("received SIGHUP, reloading configuration...")
|
|
newCfg, err := config.Load(configFile)
|
|
if err != nil {
|
|
log.Error("failed to reload configuration: %v", err)
|
|
continue
|
|
}
|
|
if err := vrrpMgr.Reload(newCfg); err != nil {
|
|
log.Error("failed to reload VRRP: %v", err)
|
|
continue
|
|
}
|
|
cfg = newCfg
|
|
log.Info("configuration reloaded successfully")
|
|
case syscall.SIGINT, syscall.SIGTERM:
|
|
log.Info("received signal %v, shutting down...", sig)
|
|
cleanup(log, vrrpMgr, healthMgr)
|
|
os.Exit(0)
|
|
}
|
|
}
|
|
}
|
|
|
|
func cleanup(log *logger.Logger, vrrpMgr *vrrp.Manager, healthMgr *health.Manager) {
|
|
log.Info("cleaning up resources...")
|
|
healthMgr.StopAll()
|
|
vrrpMgr.StopAll()
|
|
}
|
|
|
|
func setupHealthTracking(vrrpMgr *vrrp.Manager, healthMgr *health.Manager, log *logger.Logger) {
|
|
instances := vrrpMgr.GetAllInstances()
|
|
|
|
for _, inst := range instances {
|
|
for _, trackScript := range inst.TrackScripts {
|
|
monitor, ok := healthMgr.GetMonitor(trackScript)
|
|
if !ok {
|
|
log.Warn("[%s] track_script '%s' not found in health checkers", inst.Name, trackScript)
|
|
continue
|
|
}
|
|
|
|
instanceName := inst.Name
|
|
monitor.OnStateChange(func(checkerName string, oldHealthy, newHealthy bool) {
|
|
vrrpInst, ok := vrrpMgr.GetInstance(instanceName)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
if newHealthy && !oldHealthy {
|
|
log.Info("[%s] health check '%s' recovered, resetting priority", instanceName, checkerName)
|
|
vrrpInst.ResetPriority()
|
|
} else if !newHealthy && oldHealthy {
|
|
log.Warn("[%s] health check '%s' failed, decreasing priority", instanceName, checkerName)
|
|
vrrpInst.AdjustPriority(-10)
|
|
}
|
|
})
|
|
|
|
log.Info("[%s] tracking health check: %s", inst.Name, trackScript)
|
|
}
|
|
}
|
|
}
|