package controller import ( "context" "os/exec" "time" "git.giftfish.de/ston1th/haproxy-lb/pkg/api" "git.giftfish.de/ston1th/haproxy-lb/pkg/cluster" "git.giftfish.de/ston1th/haproxy-lb/pkg/config" "git.giftfish.de/ston1th/haproxy-lb/pkg/db" "git.giftfish.de/ston1th/haproxy-lb/pkg/haproxy" "git.giftfish.de/ston1th/haproxy-lb/pkg/vip" "github.com/go-logr/logr" ) func NewLBController(cfg *config.Config, srv *api.Server, log logr.Logger) (callbacks cluster.Callbacks, err error) { n, err := vip.NewNetworkWithLabel(cfg.VIP.Interface, cfg.VIP.Label) if err != nil { return } ha, err := haproxy.NewHAProxyManager(cfg.HAProxyConfig) if err != nil { return } callbacks = cluster.Callbacks{ Leader: func(ctx context.Context, cc cluster.CallbackContext) { db := db.New(cc) err := srv.UpdateDB(db) if err != nil { cc.Error(err, "error initialising api server as leader") cc.Fatal(err) return } t := time.NewTicker(time.Second * 10) if cfg.LeaderHook != "" { go func() { err := exec.CommandContext(ctx, cfg.LeaderHook).Run() if err != nil { cc.Error(err, "error running hook", "leaderHook", cfg.LeaderHook) } }() } for { cc.Info("leading", "id", cc.ID()) ips, err := db.GetIPs() if err != nil && err != cluster.ErrPrefixNotFound { cc.Error(err, "error reading ip list") <-t.C continue } addIPs(cc, n, ips) // TODO // deleted LB IPs need to be removed lbs, err := db.GetLBs("") if err != nil && err != cluster.ErrPrefixNotFound { cc.Error(err, "error reading lb list") <-t.C continue } lbcfg, err := haproxy.NewConfig(lbs) if err != nil { cc.Error(err, "error reading haproxy config") <-t.C continue } err = ha.UpdateConfig(ctx, lbcfg) if err != nil { cc.Error(err, "error updating haproxy config") <-t.C continue } select { case <-ctx.Done(): t.Stop() deleteIPs(cc, n, ips) cc.Info("leading canceled", "id", cc.ID()) return case <-t.C: } } }, Follower: func(ctx context.Context, cc cluster.CallbackContext) { db := db.New(cc) err := srv.UpdateDB(db) if err != nil { cc.Error(err, "error initialising api server as follower") cc.Fatal(err) return } t := time.NewTicker(time.Second * 10) if cfg.FollowerHook != "" { go func() { err := exec.CommandContext(ctx, cfg.FollowerHook).Run() if err != nil { cc.Error(err, "error running hook", "followerHook", cfg.FollowerHook) } }() } for { cc.Info("following", "id", cc.ID()) //TODO //ips, err := db.GetIPs() //if err != nil { // cc.Error("error getting config key", err) // <-t.C // continue //} //deleteIPs(cc, n, ips) select { case <-ctx.Done(): t.Stop() cc.Info("following canceled", "id", cc.ID()) return case <-t.C: } } }, Cleanup: func(ctx context.Context, cc cluster.CallbackContext) { db := db.New(cc) ips, err := db.GetIPs() if err != nil { return } deleteIPs(cc, n, ips) }, } return } func addIPs(log logr.Logger, n *vip.Network, cidrs []string) error { for _, cidr := range cidrs { err := n.AddIP(cidr) if err != nil { log.Error(err, "adding ip", "interface", n.Interface(), "ip", cidr) } } return nil } func deleteIPs(log logr.Logger, n *vip.Network, cidrs []string) error { for _, cidr := range cidrs { err := n.DeleteIP(cidr) if err != nil { log.Error(err, "deleting ip", "interface", n.Interface(), "ip", cidr) } } return nil }