mirror of
https://github.com/pomerium/pomerium.git
synced 2025-04-29 02:16:28 +02:00
This also replaces instances where we manually write "return ctx.Err()" with "return context.Cause(ctx)" which is functionally identical, but will also correctly propagate cause errors if present.
128 lines
3.5 KiB
Go
128 lines
3.5 KiB
Go
// Package bootstrap fetches the very initial configuration for Pomerium Core to start.
|
|
package bootstrap
|
|
|
|
/*
|
|
* Initial configuration for Pomerium start-up is obtained from the cloud.
|
|
* Some parameters are derived from the cluster token.
|
|
*
|
|
* The expectation is that if the user wishes to survive a cloud outage,
|
|
* it should be sufficient to set up Pomerium to use a durable database (Postgres)
|
|
* and receive cloud configuration once.
|
|
*
|
|
*/
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
"github.com/pomerium/pomerium/internal/log"
|
|
"github.com/pomerium/pomerium/internal/retry"
|
|
connect_mux "github.com/pomerium/pomerium/internal/zero/connect-mux"
|
|
)
|
|
|
|
const (
|
|
// DefaultCheckForUpdateIntervalWhenDisconnected is the default interval to check for updates
|
|
// if there is no connection to the update service
|
|
DefaultCheckForUpdateIntervalWhenDisconnected = 5 * time.Minute
|
|
// DefaultCheckForUpdateIntervalWhenConnected is the default interval to check for updates
|
|
// if there is a connection to the update service
|
|
DefaultCheckForUpdateIntervalWhenConnected = time.Hour
|
|
)
|
|
|
|
// Run initializes the bootstrap config source
|
|
func (svc *Source) Run(ctx context.Context) error {
|
|
svc.tryLoadFromFile(ctx)
|
|
|
|
eg, ctx := errgroup.WithContext(ctx)
|
|
eg.Go(func() error { return svc.watchUpdates(ctx) })
|
|
eg.Go(func() error { return svc.updateLoop(ctx) })
|
|
|
|
return eg.Wait()
|
|
}
|
|
|
|
func (svc *Source) watchUpdates(ctx context.Context) error {
|
|
return svc.api.Watch(ctx,
|
|
connect_mux.WithOnConnected(func(_ context.Context) {
|
|
svc.triggerUpdate(DefaultCheckForUpdateIntervalWhenConnected)
|
|
}),
|
|
connect_mux.WithOnDisconnected(func(_ context.Context) {
|
|
svc.updateInterval.Store(DefaultCheckForUpdateIntervalWhenDisconnected)
|
|
}),
|
|
connect_mux.WithOnBootstrapConfigUpdated(func(_ context.Context) {
|
|
svc.triggerUpdate(DefaultCheckForUpdateIntervalWhenConnected)
|
|
}),
|
|
)
|
|
}
|
|
|
|
func (svc *Source) updateLoop(ctx context.Context) error {
|
|
ticker := time.NewTicker(svc.updateInterval.Load())
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
err := retry.Retry(ctx,
|
|
"update bootstrap", svc.updateAndSave,
|
|
retry.WithWatch("bootstrap config updated", svc.checkForUpdate, nil),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("update bootstrap config: %w", err)
|
|
}
|
|
|
|
ticker.Reset(svc.updateInterval.Load())
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return context.Cause(ctx)
|
|
case <-svc.checkForUpdate:
|
|
case <-ticker.C:
|
|
}
|
|
}
|
|
}
|
|
|
|
// triggerUpdate triggers an update of the bootstrap config
|
|
// and sets the interval for the next update
|
|
func (svc *Source) triggerUpdate(newUpdateInterval time.Duration) {
|
|
svc.updateInterval.Store(newUpdateInterval)
|
|
|
|
select {
|
|
case svc.checkForUpdate <- struct{}{}:
|
|
default:
|
|
}
|
|
}
|
|
|
|
func (svc *Source) updateAndSave(ctx context.Context) error {
|
|
cfg, err := svc.api.GetClusterBootstrapConfig(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("load bootstrap config from API: %w", err)
|
|
}
|
|
|
|
svc.UpdateBootstrap(ctx, *cfg)
|
|
|
|
if svc.writer == nil {
|
|
return nil
|
|
}
|
|
|
|
err = SaveBootstrapConfig(ctx, svc.writer, cfg)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Err(err).
|
|
Msg("failed to save bootstrap config to file, note it may prevent Pomerium from starting up in case of connectivity issues")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (svc *Source) tryLoadFromFile(ctx context.Context) {
|
|
if svc.fileCachePath == nil {
|
|
return
|
|
}
|
|
|
|
cfg, err := LoadBootstrapConfigFromFile(*svc.fileCachePath, svc.fileCipher)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Err(err).Msg("failed to load bootstrap config from file")
|
|
return
|
|
}
|
|
|
|
svc.UpdateBootstrap(ctx, *cfg)
|
|
}
|