package gateway import ( "context" "forge.cadoles.com/Cadoles/emissary/internal/agent" "forge.cadoles.com/Cadoles/emissary/internal/spec/gateway" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) type Controller struct { proxies map[gateway.ID]*ReverseProxy currentSpecRevision int } // Name implements node.Controller. func (c *Controller) Name() string { return "gateway-controller" } // Reconcile implements node.Controller. func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error { gatewaySpec := gateway.NewSpec() if err := state.GetSpec(gateway.NameGateway, gatewaySpec); err != nil { if errors.Is(err, agent.ErrSpecNotFound) { logger.Info(ctx, "could not find gateway spec, stopping all remaining proxies") c.stopAllProxies(ctx) return nil } return errors.WithStack(err) } logger.Info(ctx, "retrieved spec", logger.F("spec", gatewaySpec.SpecName()), logger.F("revision", gatewaySpec.SpecRevision())) if c.currentSpecRevision == gatewaySpec.SpecRevision() { logger.Info(ctx, "spec revision did not change, doing nothing") return nil } c.updateProxies(ctx, gatewaySpec) c.currentSpecRevision = gatewaySpec.SpecRevision() logger.Info(ctx, "updating current spec revision", logger.F("revision", c.currentSpecRevision)) return nil } func (c *Controller) stopAllProxies(ctx context.Context) { for gatewayID, proxy := range c.proxies { logger.Info(ctx, "stopping proxy", logger.F("gatewayID", gatewayID)) if err := proxy.Stop(); err != nil { logger.Error( ctx, "error while stopping proxy", logger.F("gatewayID", gatewayID), logger.E(errors.WithStack(err)), ) delete(c.proxies, gatewayID) } } } func (c *Controller) updateProxies(ctx context.Context, spec *gateway.Spec) { // Stop and remove obsolete gateways for gatewayID, proxy := range c.proxies { if _, exists := spec.Gateways[gatewayID]; exists { continue } logger.Info(ctx, "stopping proxy", logger.F("gatewayID", gatewayID)) if err := proxy.Stop(); err != nil { logger.Error( ctx, "error while stopping proxy", logger.F("gatewayID", gatewayID), logger.E(errors.WithStack(err)), ) delete(c.proxies, gatewayID) } } // (Re)start gateways for gatewayID, gatewaySpec := range spec.Gateways { proxy, exists := c.proxies[gatewayID] if !exists { proxy = NewReverseProxy() c.proxies[gatewayID] = proxy } logger.Info( ctx, "starting proxy", logger.F("gatewayID", gatewayID), logger.F("addr", gatewaySpec.Address), logger.F("target", gatewaySpec.Target), ) if err := proxy.Start(ctx, gatewaySpec.Address, gatewaySpec.Target); err != nil { logger.Error( ctx, "error while starting proxy", logger.F("gatewayID", gatewayID), logger.E(errors.WithStack(err)), ) delete(c.proxies, gatewayID) } } } func NewController() *Controller { return &Controller{ proxies: make(map[gateway.ID]*ReverseProxy), currentSpecRevision: -1, } } var _ agent.Controller = &Controller{}