William Petit
82c93d3f1e
All checks were successful
Cadoles/bouncer/pipeline/head This commit looks good
123 lines
3.6 KiB
Go
123 lines
3.6 KiB
Go
package admin
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"forge.cadoles.com/cadoles/bouncer/internal/config"
|
|
"forge.cadoles.com/cadoles/bouncer/internal/lock/redis"
|
|
"forge.cadoles.com/cadoles/bouncer/internal/schema"
|
|
"forge.cadoles.com/cadoles/bouncer/internal/setup"
|
|
"forge.cadoles.com/cadoles/bouncer/internal/store"
|
|
"github.com/pkg/errors"
|
|
"gitlab.com/wpetit/goweb/logger"
|
|
)
|
|
|
|
func (s *Server) bootstrapProxies(ctx context.Context) error {
|
|
if err := s.validateBootstrap(ctx); err != nil {
|
|
return errors.Wrap(err, "could not validate bootstrapped proxies")
|
|
}
|
|
|
|
proxyRepo := s.proxyRepository
|
|
layerRepo := s.layerRepository
|
|
|
|
lockTimeout := time.Duration(s.bootstrapConfig.LockTimeout)
|
|
locker := redis.NewLocker(s.redisClient, int(s.bootstrapConfig.MaxConnectionRetries))
|
|
|
|
err := locker.WithLock(ctx, "bouncer-admin-bootstrap", lockTimeout, func(ctx context.Context) error {
|
|
logger.Info(ctx, "bootstrapping proxies")
|
|
|
|
for proxyName, proxyConfig := range s.bootstrapConfig.Proxies {
|
|
loopCtx := logger.With(ctx, logger.F("proxyName", proxyName), logger.F("proxyFrom", proxyConfig.From), logger.F("proxyTo", proxyConfig.To))
|
|
|
|
_, err := s.proxyRepository.GetProxy(ctx, proxyName)
|
|
if !errors.Is(err, store.ErrNotFound) {
|
|
if err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
if proxyConfig.Recreate {
|
|
logger.Info(loopCtx, "force recreating proxy")
|
|
|
|
if err := s.deleteProxyAndLayers(ctx, proxyName); err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
} else {
|
|
logger.Info(loopCtx, "ignoring existing proxy")
|
|
continue
|
|
}
|
|
}
|
|
|
|
logger.Info(loopCtx, "creating proxy")
|
|
|
|
if _, err := proxyRepo.CreateProxy(ctx, proxyName, string(proxyConfig.To), proxyConfig.From...); err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
_, err = proxyRepo.UpdateProxy(
|
|
ctx, proxyName,
|
|
store.WithProxyUpdateEnabled(bool(proxyConfig.Enabled)),
|
|
store.WithProxyUpdateWeight(int(proxyConfig.Weight)),
|
|
)
|
|
if err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
for layerName, layerConfig := range proxyConfig.Layers {
|
|
layerType := store.LayerType(layerConfig.Type)
|
|
layerOptions := store.LayerOptions(layerConfig.Options.Data)
|
|
|
|
if _, err := layerRepo.CreateLayer(ctx, proxyName, layerName, layerType, layerOptions); err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
_, err := layerRepo.UpdateLayer(
|
|
ctx,
|
|
proxyName, layerName,
|
|
store.WithLayerUpdateEnabled(bool(layerConfig.Enabled)),
|
|
store.WithLayerUpdateOptions(layerOptions),
|
|
store.WithLayerUpdateWeight(int(layerConfig.Weight)),
|
|
)
|
|
if err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
const validateErrMessage = "could not validate proxy '%s': could not validate layer '%s'"
|
|
|
|
func (s *Server) validateBootstrap(ctx context.Context) error {
|
|
for proxyName, proxyConf := range s.bootstrapConfig.Proxies {
|
|
for layerName, layerConf := range proxyConf.Layers {
|
|
layerType := store.LayerType(layerConf.Type)
|
|
if !setup.LayerTypeExists(layerType) {
|
|
return errors.Errorf(validateErrMessage+": could not find layer type '%s'", proxyName, layerName, layerType)
|
|
}
|
|
|
|
layerOptionsSchema, err := setup.GetLayerOptionsSchema(layerType)
|
|
if err != nil {
|
|
return errors.Wrapf(err, validateErrMessage, proxyName, layerName)
|
|
}
|
|
|
|
rawOptions := func(opts config.InterpolatedMap) map[string]any {
|
|
return opts.Data
|
|
}(layerConf.Options)
|
|
|
|
if err := schema.Validate(ctx, layerOptionsSchema, rawOptions); err != nil {
|
|
return errors.Wrapf(err, validateErrMessage, proxyName, layerName)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|