Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fc3c860bc |
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Version can be set at build time via ldflags
|
// Version can be set at build time via ldflags
|
||||||
var Version = "1.2.1"
|
var Version = "1.3.0"
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
Use: "go-alived",
|
Use: "go-alived",
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ func runService(cmd *cobra.Command, args []string) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupNotifyScripts(vrrpMgr, cfg, log)
|
||||||
setupHealthTracking(vrrpMgr, healthMgr, log)
|
setupHealthTracking(vrrpMgr, healthMgr, log)
|
||||||
|
|
||||||
healthMgr.StartAll()
|
healthMgr.StartAll()
|
||||||
@@ -100,6 +101,27 @@ func cleanup(log *logger.Logger, vrrpMgr *vrrp.Manager, healthMgr *health.Manage
|
|||||||
vrrpMgr.StopAll()
|
vrrpMgr.StopAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupNotifyScripts(vrrpMgr *vrrp.Manager, cfg *config.Config, log *logger.Logger) {
|
||||||
|
for _, vrrpCfg := range cfg.VRRP {
|
||||||
|
if vrrpCfg.NotifyMaster == "" && vrrpCfg.NotifyBackup == "" && vrrpCfg.NotifyFault == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
inst, ok := vrrpMgr.GetInstance(vrrpCfg.Name)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
vrrp.SetupNotify(inst, &vrrp.NotifyConfig{
|
||||||
|
Name: vrrpCfg.Name,
|
||||||
|
NotifyMaster: vrrpCfg.NotifyMaster,
|
||||||
|
NotifyBackup: vrrpCfg.NotifyBackup,
|
||||||
|
NotifyFault: vrrpCfg.NotifyFault,
|
||||||
|
Log: log,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setupHealthTracking(vrrpMgr *vrrp.Manager, healthMgr *health.Manager, log *logger.Logger) {
|
func setupHealthTracking(vrrpMgr *vrrp.Manager, healthMgr *health.Manager, log *logger.Logger) {
|
||||||
instances := vrrpMgr.GetAllInstances()
|
instances := vrrpMgr.GetAllInstances()
|
||||||
|
|
||||||
|
|||||||
89
internal/vrrp/notify.go
Normal file
89
internal/vrrp/notify.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
package vrrp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/loveuer/go-alived/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
const notifyTimeout = 60 * time.Second
|
||||||
|
|
||||||
|
// NotifyConfig holds the notify script configuration for a VRRP instance.
|
||||||
|
type NotifyConfig struct {
|
||||||
|
Name string
|
||||||
|
NotifyMaster string
|
||||||
|
NotifyBackup string
|
||||||
|
NotifyFault string
|
||||||
|
Log *logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupNotify registers notify scripts as state change callbacks on the instance.
|
||||||
|
func SetupNotify(inst *Instance, cfg *NotifyConfig) {
|
||||||
|
if cfg.NotifyMaster != "" {
|
||||||
|
script := cfg.NotifyMaster
|
||||||
|
inst.OnMaster(func() {
|
||||||
|
cfg.Log.Info("[%s] executing notify_master script", cfg.Name)
|
||||||
|
go runNotifyScript(cfg.Log, cfg.Name, "notify_master", script)
|
||||||
|
})
|
||||||
|
cfg.Log.Info("[%s] registered notify_master script", cfg.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.NotifyBackup != "" {
|
||||||
|
script := cfg.NotifyBackup
|
||||||
|
inst.OnBackup(func() {
|
||||||
|
cfg.Log.Info("[%s] executing notify_backup script", cfg.Name)
|
||||||
|
go runNotifyScript(cfg.Log, cfg.Name, "notify_backup", script)
|
||||||
|
})
|
||||||
|
cfg.Log.Info("[%s] registered notify_backup script", cfg.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.NotifyFault != "" {
|
||||||
|
script := cfg.NotifyFault
|
||||||
|
inst.OnFault(func() {
|
||||||
|
cfg.Log.Info("[%s] executing notify_fault script", cfg.Name)
|
||||||
|
go runNotifyScript(cfg.Log, cfg.Name, "notify_fault", script)
|
||||||
|
})
|
||||||
|
cfg.Log.Info("[%s] registered notify_fault script", cfg.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runNotifyScript(log *logger.Logger, instName, event, script string) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), notifyTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
cmd := buildCommand(ctx, script)
|
||||||
|
cmd.Env = append(os.Environ(),
|
||||||
|
fmt.Sprintf("GO_ALIVED_INSTANCE=%s", instName),
|
||||||
|
fmt.Sprintf("GO_ALIVED_EVENT=%s", event),
|
||||||
|
)
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[%s] %s script failed: %v (output: %s)",
|
||||||
|
instName, event, err, strings.TrimSpace(string(output)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(output) > 0 {
|
||||||
|
log.Info("[%s] %s script output: %s",
|
||||||
|
instName, event, strings.TrimSpace(string(output)))
|
||||||
|
}
|
||||||
|
log.Info("[%s] %s script completed successfully", instName, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildCommand(ctx context.Context, script string) *exec.Cmd {
|
||||||
|
script = strings.TrimSpace(script)
|
||||||
|
|
||||||
|
// If the script is a path to an existing executable file, run it directly
|
||||||
|
if info, err := os.Stat(script); err == nil && !info.IsDir() {
|
||||||
|
return exec.CommandContext(ctx, script)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise treat as inline shell script
|
||||||
|
return exec.CommandContext(ctx, "sh", "-c", script)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user