2023-12-21 16:04:04 +00:00
package server
import (
2024-12-21 14:11:13 +00:00
"database/sql"
"embed"
2024-01-24 22:21:48 +00:00
"errors"
2023-12-21 16:04:04 +00:00
"fmt"
2024-01-25 18:57:41 +00:00
"git.myservermanager.com/varakh/upda/util"
2024-12-21 14:11:13 +00:00
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database"
migratepostgres "github.com/golang-migrate/migrate/v4/database/postgres"
"github.com/golang-migrate/migrate/v4/source"
"github.com/golang-migrate/migrate/v4/source/iofs"
_ "github.com/golang-migrate/migrate/v4/source/iofs"
2023-12-21 16:04:04 +00:00
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gorm.io/driver/postgres"
"gorm.io/gorm"
2024-01-24 22:21:48 +00:00
"gorm.io/gorm/logger"
2023-12-21 16:04:04 +00:00
"log"
"moul.io/zapgorm2"
"os"
2024-01-25 18:57:41 +00:00
"path/filepath"
2023-12-21 16:04:04 +00:00
"strconv"
2024-04-26 18:24:47 +00:00
"strings"
2023-12-21 16:04:04 +00:00
"time"
)
2024-12-21 14:11:13 +00:00
//go:embed migrations_postgres/*.sql
var migrationPostgresFS embed . FS
2023-12-21 16:04:04 +00:00
type appConfig struct {
2024-01-24 22:21:48 +00:00
timeZone string
isDevelopment bool
isDebug bool
2023-12-21 16:04:04 +00:00
}
2024-10-25 14:12:35 +00:00
type webConfig struct {
title string
apiUrl string
}
2023-12-21 16:04:04 +00:00
type serverConfig struct {
2024-06-10 18:03:25 +00:00
port int
listen string
tlsEnabled bool
tlsCertPath string
tlsKeyPath string
timeout time . Duration
corsAllowCredentials bool
corsAllowOrigins [ ] string
corsAllowMethods [ ] string
corsAllowHeaders [ ] string
corsExposeHeaders [ ] string
2023-12-21 16:04:04 +00:00
}
type authConfig struct {
2024-04-26 18:24:47 +00:00
authMethod string
basicAuthUser string
basicAuthPassword string
basicAuthCredentials map [ string ] string
2023-12-21 16:04:04 +00:00
}
type taskConfig struct {
updateCleanStaleEnabled bool
2024-05-16 07:33:32 +00:00
updateCleanStaleInterval time . Duration
2023-12-21 16:04:04 +00:00
updateCleanStaleMaxAge time . Duration
eventCleanStaleEnabled bool
2024-05-16 07:33:32 +00:00
eventCleanStaleInterval time . Duration
2023-12-21 16:04:04 +00:00
eventCleanStaleMaxAge time . Duration
2024-04-26 12:37:50 +00:00
actionsEnqueueEnabled bool
2024-05-16 07:33:32 +00:00
actionsEnqueueInterval time . Duration
2024-04-26 12:37:50 +00:00
actionsEnqueueBatchSize int
actionsInvokeEnabled bool
2024-05-16 07:33:32 +00:00
actionsInvokeInterval time . Duration
2024-04-26 12:37:50 +00:00
actionsInvokeBatchSize int
actionsInvokeMaxRetries int
actionsCleanStaleEnabled bool
2024-05-16 07:33:32 +00:00
actionsCleanStaleInterval time . Duration
2024-04-26 12:37:50 +00:00
actionsCleanStaleMaxAge time . Duration
2024-05-16 07:33:32 +00:00
prometheusRefreshInterval time . Duration
2023-12-22 12:13:44 +00:00
}
type lockConfig struct {
redisEnabled bool
redisUrl string
2023-12-21 16:04:04 +00:00
}
type webhookConfig struct {
tokenLength int
}
type prometheusConfig struct {
enabled bool
path string
secureTokenEnabled bool
secureToken string
}
type Environment struct {
appConfig * appConfig
2024-10-25 14:12:35 +00:00
webConfig * webConfig
2023-12-21 16:04:04 +00:00
authConfig * authConfig
serverConfig * serverConfig
taskConfig * taskConfig
2023-12-22 12:13:44 +00:00
lockConfig * lockConfig
2023-12-21 16:04:04 +00:00
webhookConfig * webhookConfig
prometheusConfig * prometheusConfig
db * gorm . DB
}
func bootstrapEnvironment ( ) * Environment {
var err error
2024-01-24 22:21:48 +00:00
// bootstrap logging (configured independently and required before any other action)
loggingLevel := os . Getenv ( envLoggingLevel )
if loggingLevel == "" {
if err = os . Setenv ( envLoggingLevel , loggingLevelDefault ) ; err != nil {
log . Fatalf ( "Cannot set logging level: %v" , err )
2023-12-21 16:04:04 +00:00
}
2024-01-24 22:21:48 +00:00
loggingLevel = os . Getenv ( envLoggingLevel )
}
var level zap . AtomicLevel
if level , err = zap . ParseAtomicLevel ( loggingLevel ) ; err != nil {
log . Fatalf ( "Cannot parse logging level: %v" , err )
}
loggingEncoding := os . Getenv ( envLoggingEncoding )
if loggingEncoding == "" {
if err = os . Setenv ( envLoggingEncoding , loggingEncodingDefault ) ; err != nil {
log . Fatalf ( "Cannot set logging encoding: %v" , err )
}
loggingEncoding = os . Getenv ( envLoggingEncoding )
}
if loggingEncoding != "json" && loggingEncoding != "console" {
log . Fatalf ( "Cannot parse logging level: %v" , errors . New ( "only 'json' and 'console' are allowed logging encodings" ) )
}
isDebug := level . Level ( ) == zap . DebugLevel
isDevelopment := os . Getenv ( envDevelopment ) == "true"
var loggingEncoderConfig zapcore . EncoderConfig
if loggingEncoding == "json" {
loggingEncoderConfig = zap . NewProductionEncoderConfig ( )
} else {
loggingEncoderConfig = zap . NewDevelopmentEncoderConfig ( )
2023-12-21 16:04:04 +00:00
}
2024-01-25 18:57:41 +00:00
logPaths := [ ] string { "stderr" }
loggingDirectory := os . Getenv ( envLoggingDirectory )
if loggingDirectory != "" {
logFile := filepath . Join ( loggingDirectory , loggingFileNameDefault )
if err = util . CreateFileWithParent ( logFile ) ; err != nil {
log . Fatalf ( "Log file '%s' cannot be created: %v" , loggingDirectory , err )
}
logPaths = append ( logPaths , logFile )
}
2024-01-24 22:21:48 +00:00
var zapConfig * zap . Config
if isDebug {
zapConfig = & zap . Config {
Level : level ,
Development : isDevelopment ,
Encoding : loggingEncoding ,
EncoderConfig : loggingEncoderConfig ,
2024-01-25 18:57:41 +00:00
OutputPaths : logPaths ,
ErrorOutputPaths : logPaths ,
2024-01-24 22:21:48 +00:00
}
} else {
zapConfig = & zap . Config {
Level : level ,
Development : isDevelopment ,
Sampling : & zap . SamplingConfig {
Initial : 100 ,
Thereafter : 100 ,
} ,
Encoding : loggingEncoding ,
EncoderConfig : loggingEncoderConfig ,
2024-01-25 18:57:41 +00:00
OutputPaths : logPaths ,
ErrorOutputPaths : logPaths ,
2024-01-24 22:21:48 +00:00
}
2023-12-21 16:04:04 +00:00
}
2024-01-24 22:21:48 +00:00
zapLogger := zap . Must ( zapConfig . Build ( ) )
2024-06-03 19:11:33 +00:00
defer func ( zapLogger * zap . Logger ) {
_ = zapLogger . Sync ( )
} ( zapLogger )
2024-01-24 22:21:48 +00:00
zap . ReplaceGlobals ( zapLogger )
2023-12-21 16:04:04 +00:00
// assign defaults from given environment variables and validate
bootstrapFromEnvironmentAndValidate ( )
// parse environment variables in actual configuration structs
// app config
2024-01-24 22:21:48 +00:00
ac := & appConfig {
timeZone : os . Getenv ( envTZ ) ,
isDebug : isDebug ,
isDevelopment : isDevelopment ,
2023-12-21 16:04:04 +00:00
}
2024-10-25 14:12:35 +00:00
// web config
var webC * webConfig
webC = & webConfig {
title : os . Getenv ( envWebTitle ) ,
apiUrl : os . Getenv ( envWebApiUrl ) ,
}
2023-12-21 16:04:04 +00:00
// server config
var sc * serverConfig
var serverPort int
if serverPort , err = strconv . Atoi ( os . Getenv ( envServerPort ) ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Invalid server port. Reason: %v" , err )
}
serverTlsEnabled := os . Getenv ( envServerTlsEnabled ) == "true"
if serverTlsEnabled {
failIfEnvKeyNotPresent ( envServerTlsCertPath )
failIfEnvKeyNotPresent ( envServerTlsKeyPath )
}
var serverTimeout time . Duration
var errParse error
if serverTimeout , errParse = time . ParseDuration ( os . Getenv ( envServerTimeout ) ) ; errParse != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not parse timeout. Reason: %s" , errParse . Error ( ) )
}
sc = & serverConfig {
2024-06-10 18:03:25 +00:00
port : serverPort ,
timeout : serverTimeout ,
listen : os . Getenv ( envServerListen ) ,
tlsEnabled : serverTlsEnabled ,
tlsCertPath : os . Getenv ( envServerTlsCertPath ) ,
tlsKeyPath : os . Getenv ( envServerTlsKeyPath ) ,
corsAllowCredentials : os . Getenv ( envCorsAllowCredentials ) == "true" ,
corsExposeHeaders : [ ] string { os . Getenv ( envCorsExposeHeaders ) } ,
corsAllowOrigins : [ ] string { os . Getenv ( envCorsAllowOrigins ) } ,
corsAllowMethods : [ ] string { os . Getenv ( envCorsAllowMethods ) } ,
corsAllowHeaders : [ ] string { os . Getenv ( envCorsAllowHeaders ) } ,
2023-12-21 16:04:04 +00:00
}
2024-04-26 18:24:47 +00:00
authMode := os . Getenv ( envAuthMode )
if authMode != authModeBasicSingle && authMode != authModeBasicCredentials {
zap . L ( ) . Sugar ( ) . Fatalln ( "Invalid auth mode. Reason: must be one of ['basic_single','basic_credentials'" )
}
2024-01-24 22:21:48 +00:00
authC := & authConfig {
2024-04-26 18:24:47 +00:00
authMethod : authMode ,
}
if authModeBasicSingle == authMode {
failIfEnvKeyNotPresent ( envBasicAuthUser )
failIfEnvKeyNotPresent ( envBasicAuthPassword )
authC . basicAuthUser = os . Getenv ( envBasicAuthUser )
authC . basicAuthPassword = os . Getenv ( envBasicAuthPassword )
}
if authModeBasicCredentials == authMode {
failIfEnvKeyNotPresent ( envBasicAuthCredentials )
authC . basicAuthCredentials = parseBasicAuthCredentials ( envBasicAuthCredentials )
2023-12-21 16:04:04 +00:00
}
// task config
var tc * taskConfig
2024-05-16 07:33:32 +00:00
updateCleanStaleInterval := parseDuration ( envTaskUpdateCleanStaleInterval )
updateCleanStaleMaxAge := parseDuration ( envTaskUpdateCleanStaleMaxAge )
eventCleanStaleMaxAge := parseDuration ( envTaskEventCleanStaleMaxAge )
actionsCleanStaleMaxAge := parseDuration ( envTaskActionsCleanStaleMaxAge )
eventCleanStaleInterval := parseDuration ( envTaskEventCleanStaleInterval )
actionsEnqueueInterval := parseDuration ( envTaskActionsEnqueueInterval )
actionsInvokeInterval := parseDuration ( envTaskActionsInvokeInterval )
actionsCleanStaleInterval := parseDuration ( envTaskActionsCleanStaleInterval )
prometheusRefreshInterval := parseDuration ( envTaskPrometheusRefreshInterval )
2023-12-21 16:04:04 +00:00
2024-04-26 12:37:50 +00:00
var actionsEnqueueBatchSize int
if actionsEnqueueBatchSize , err = strconv . Atoi ( os . Getenv ( envTaskActionsEnqueueBatchSize ) ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Invalid actions enqueue batch size. Reason: %v" , err )
}
if actionsEnqueueBatchSize <= 0 {
zap . L ( ) . Sugar ( ) . Fatalf ( "Invalid actions enqueue batch size, must be a positive number." )
}
var actionsInvokeBatchSize int
if actionsInvokeBatchSize , err = strconv . Atoi ( os . Getenv ( envTaskActionsInvokeBatchSize ) ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Invalid actions invoke batch size. Reason: %v" , err )
}
if actionsInvokeBatchSize <= 0 {
zap . L ( ) . Sugar ( ) . Fatalf ( "Invalid actions invoke batch size, must be a positive number." )
}
var actionsInvokeMaxRetries int
if actionsInvokeMaxRetries , err = strconv . Atoi ( os . Getenv ( envTaskActionsInvokeMaxRetries ) ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Invalid actions invoke max retries. Reason: %v" , err )
}
if actionsInvokeMaxRetries <= 0 {
zap . L ( ) . Sugar ( ) . Fatalf ( "Invalid actions invoke max retries, must be a positive number." )
}
2023-12-21 16:04:04 +00:00
tc = & taskConfig {
updateCleanStaleEnabled : os . Getenv ( envTaskUpdateCleanStaleEnabled ) == "true" ,
2024-05-16 07:33:32 +00:00
updateCleanStaleInterval : updateCleanStaleInterval ,
2023-12-21 16:04:04 +00:00
updateCleanStaleMaxAge : updateCleanStaleMaxAge ,
eventCleanStaleEnabled : os . Getenv ( envTaskEventCleanStaleEnabled ) == "true" ,
2024-05-16 07:33:32 +00:00
eventCleanStaleInterval : eventCleanStaleInterval ,
2023-12-21 16:04:04 +00:00
eventCleanStaleMaxAge : eventCleanStaleMaxAge ,
2024-04-26 12:37:50 +00:00
actionsEnqueueEnabled : os . Getenv ( envTaskActionsEnqueueEnabled ) == "true" ,
2024-05-16 07:33:32 +00:00
actionsEnqueueInterval : actionsEnqueueInterval ,
2024-04-26 12:37:50 +00:00
actionsEnqueueBatchSize : actionsEnqueueBatchSize ,
actionsInvokeEnabled : os . Getenv ( envTaskActionsInvokeEnabled ) == "true" ,
2024-05-16 07:33:32 +00:00
actionsInvokeInterval : actionsInvokeInterval ,
2024-04-26 12:37:50 +00:00
actionsInvokeBatchSize : actionsInvokeBatchSize ,
actionsInvokeMaxRetries : actionsInvokeMaxRetries ,
actionsCleanStaleEnabled : os . Getenv ( envTaskActionsCleanStaleEnabled ) == "true" ,
2024-05-16 07:33:32 +00:00
actionsCleanStaleInterval : actionsCleanStaleInterval ,
2024-04-26 12:37:50 +00:00
actionsCleanStaleMaxAge : actionsCleanStaleMaxAge ,
2024-05-16 07:33:32 +00:00
prometheusRefreshInterval : prometheusRefreshInterval ,
2023-12-22 12:13:44 +00:00
}
var lc * lockConfig
lc = & lockConfig {
redisEnabled : os . Getenv ( envLockRedisEnabled ) == "true" ,
redisUrl : os . Getenv ( envLockRedisUrl ) ,
2023-12-21 16:04:04 +00:00
}
webhookTokenLength := 32
if webhookTokenLength , err = strconv . Atoi ( os . Getenv ( envWebhooksTokenLength ) ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Invalid webhook token length. Reason: %v" , err )
}
if webhookTokenLength <= 0 {
zap . L ( ) . Sugar ( ) . Fatalln ( "Invalid webhook token length. Reason: must be a positive number" )
}
2024-01-24 22:21:48 +00:00
wc := & webhookConfig {
2023-12-21 16:04:04 +00:00
tokenLength : webhookTokenLength ,
}
2024-01-24 22:21:48 +00:00
pc := & prometheusConfig {
2023-12-21 16:04:04 +00:00
enabled : os . Getenv ( envPrometheusEnabled ) == "true" ,
path : os . Getenv ( envPrometheusMetricsPath ) ,
secureTokenEnabled : os . Getenv ( envPrometheusSecureTokenEnabled ) == "true" ,
secureToken : os . Getenv ( envPrometheusSecureToken ) ,
}
2024-01-24 22:21:48 +00:00
if pc . enabled && pc . secureTokenEnabled {
2023-12-21 16:04:04 +00:00
failIfEnvKeyNotPresent ( envPrometheusSecureToken )
}
// database setup
2024-01-24 22:21:48 +00:00
gormConfig := & gorm . Config { Logger : logger . Default . LogMode ( logger . Silent ) }
if isDebug && isDevelopment {
gormZapLogger := zap . Must ( zapConfig . Build ( ) )
2024-06-03 19:11:33 +00:00
defer func ( gormZapLogger * zap . Logger ) {
_ = gormZapLogger . Sync ( )
} ( gormZapLogger )
2024-01-24 22:21:48 +00:00
gormLogger := zapgorm2 . New ( gormZapLogger )
gormConfig = & gorm . Config { Logger : gormLogger }
}
2023-12-21 16:04:04 +00:00
var db * gorm . DB
2024-12-21 14:11:13 +00:00
var migrationDriver database . Driver
var migrationDatabaseName string
var migrationFS source . Driver
2024-01-25 18:57:41 +00:00
2024-12-21 14:11:13 +00:00
zap . L ( ) . Sugar ( ) . Infof ( "Using database type '%s'" , os . Getenv ( envDbType ) )
2023-12-21 16:04:04 +00:00
2024-12-21 14:11:13 +00:00
if os . Getenv ( envDbType ) == dbTypePostgres {
2023-12-21 16:04:04 +00:00
host := os . Getenv ( envDbPostgresHost )
port := os . Getenv ( envDbPostgresPort )
dbUser := os . Getenv ( envDbPostgresUser )
dbPass := os . Getenv ( envDbPostgresPassword )
dbName := os . Getenv ( envDbPostgresName )
dbTZ := os . Getenv ( envDbPostgresTimeZone )
2024-12-21 14:11:13 +00:00
migrationDatabaseName = dbName
2023-12-21 16:04:04 +00:00
if host == "" || port == "" || dbUser == "" || dbPass == "" || dbName == "" || dbTZ == "" {
zap . L ( ) . Sugar ( ) . Fatalf ( "Some configuration for database type '%s' is missing" , os . Getenv ( envDbType ) )
}
dsn := fmt . Sprintf ( "host=%v user=%v password=%v dbname=%v port=%v sslmode=disable TimeZone=%v" , host , dbUser , dbPass , dbName , port , dbTZ )
2024-01-24 22:21:48 +00:00
if db , err = gorm . Open ( postgres . Open ( dsn ) , gormConfig ) ; err != nil {
2023-12-21 16:04:04 +00:00
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not setup database: %v" , err )
}
2024-12-21 14:11:13 +00:00
var sqlDb * sql . DB
if sqlDb , err = db . DB ( ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not retrieve database: %v" , err )
}
if err = sqlDb . Ping ( ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not connect to database: %v" , err )
}
if migrationDriver , err = migratepostgres . WithInstance ( sqlDb , & migratepostgres . Config { } ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not create migration driver: %v" , err )
}
if migrationFS , err = iofs . New ( migrationPostgresFS , "migrations_postgres" ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not create migration source: %v" , err )
}
2023-12-21 16:04:04 +00:00
} else {
2024-12-21 14:11:13 +00:00
zap . L ( ) . Sugar ( ) . Fatalf ( "Database type '%s' is required" , dbTypePostgres )
2023-12-21 16:04:04 +00:00
}
if db == nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not setup database" )
}
2024-01-24 22:21:48 +00:00
env := & Environment { appConfig : ac ,
2024-10-25 14:12:35 +00:00
webConfig : webC ,
2024-01-24 22:21:48 +00:00
authConfig : authC ,
2023-12-21 16:04:04 +00:00
serverConfig : sc ,
taskConfig : tc ,
2023-12-22 12:13:44 +00:00
lockConfig : lc ,
2024-01-24 22:21:48 +00:00
webhookConfig : wc ,
prometheusConfig : pc ,
2023-12-21 16:04:04 +00:00
db : db }
2024-12-21 14:11:13 +00:00
migrationEnabled := os . Getenv ( envDbMigrationEnabled ) == "true"
if ! migrationEnabled {
zap . L ( ) . Warn ( "Database schema migration is disabled and not executed automatically. Make sure to run them manually, otherwise the application might misbehave. You can safely ignore this warning if application is started in high availability mode and you're sure necessary database schema already exists." )
} else {
var migrator * migrate . Migrate
if migrator , err = migrate . NewWithInstance ( "iofs" , migrationFS , migrationDatabaseName , migrationDriver ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not create database migration instance: %v" , err )
}
var migrationVersion uint
var migrationVersionDirty bool
if migrationVersion , migrationVersionDirty , err = migrator . Version ( ) ; err != nil {
if errors . Is ( err , migrate . ErrNilVersion ) {
zap . L ( ) . Info ( "Database migration schema is uninitialized" )
} else {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not retrieve database migration version: %v" , err )
}
} else {
zap . L ( ) . Sugar ( ) . Infof ( "Previous database migration version is '%d' (dirty '%v')" , migrationVersion , migrationVersionDirty )
}
zap . L ( ) . Info ( "Applying necessary database migration steps..." )
if err = migrator . Up ( ) ; err != nil {
if errors . Is ( err , migrate . ErrNoChange ) {
zap . L ( ) . Info ( "No database schema changes detected" )
} else {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not migrate database schema: %v" , err )
}
}
zap . L ( ) . Info ( "Applied all necessary database migration steps successfully" )
2023-12-21 16:04:04 +00:00
}
2024-12-21 14:11:13 +00:00
zap . L ( ) . Sugar ( ) . Infof ( "AppConfig %+v" , env . appConfig )
zap . L ( ) . Sugar ( ) . Infof ( "WebConfig %+v" , env . webConfig )
zap . L ( ) . Info ( "AuthConfig ***REDACTED***" )
zap . L ( ) . Sugar ( ) . Infof ( "ServerConfig %+v" , env . serverConfig )
zap . L ( ) . Sugar ( ) . Infof ( "TaskConfig %+v" , env . taskConfig )
zap . L ( ) . Info ( "LockConfig ***REDACTED***" )
zap . L ( ) . Sugar ( ) . Infof ( "WebhookConfig %+v" , env . webhookConfig )
zap . L ( ) . Info ( "PrometheusConfig ***REDACTED***" )
2023-12-21 16:04:04 +00:00
return env
}
func bootstrapFromEnvironmentAndValidate ( ) {
2024-04-26 18:24:47 +00:00
failIfEnvKeyNotPresent ( envSecret )
// auth mode
setEnvKeyDefault ( envAuthMode , authModeDefault )
2023-12-21 16:04:04 +00:00
// app
setEnvKeyDefault ( envTZ , tzDefault )
2024-10-25 14:12:35 +00:00
// web
setEnvKeyDefault ( envWebTitle , webTitleDefault )
setEnvKeyDefault ( envWebApiUrl , webApiUrlDefault )
2023-12-21 16:04:04 +00:00
// webhook
setEnvKeyDefault ( envWebhooksTokenLength , webhooksTokenLengthDefault )
2023-12-22 12:13:44 +00:00
// lock
setEnvKeyDefault ( envLockRedisEnabled , redisEnabledDefault )
2023-12-21 16:04:04 +00:00
// task
setEnvKeyDefault ( envTaskUpdateCleanStaleEnabled , taskUpdateCleanStaleEnabledDefault )
setEnvKeyDefault ( envTaskUpdateCleanStaleInterval , taskUpdateCleanStaleIntervalDefault )
setEnvKeyDefault ( envTaskUpdateCleanStaleMaxAge , taskUpdateCleanStaleMaxAgeDefault )
setEnvKeyDefault ( envTaskEventCleanStaleEnabled , taskEventCleanStaleEnabledDefault )
setEnvKeyDefault ( envTaskEventCleanStaleInterval , taskEventCleanStaleIntervalDefault )
setEnvKeyDefault ( envTaskEventCleanStaleMaxAge , taskEventCleanStaleMaxAgeDefault )
2024-04-26 12:37:50 +00:00
setEnvKeyDefault ( envTaskActionsEnqueueEnabled , taskActionsEnqueueEnabledDefault )
setEnvKeyDefault ( envTaskActionsEnqueueInterval , taskActionsEnqueueIntervalDefault )
setEnvKeyDefault ( envTaskActionsEnqueueBatchSize , taskActionsEnqueueBatchSizeDefault )
setEnvKeyDefault ( envTaskActionsInvokeEnabled , taskActionsInvokeEnabledDefault )
setEnvKeyDefault ( envTaskActionsInvokeInterval , taskActionsInvokeIntervalDefault )
setEnvKeyDefault ( envTaskActionsInvokeBatchSize , taskActionsInvokeBatchSizeDefault )
setEnvKeyDefault ( envTaskActionsInvokeMaxRetries , taskActionsInvokeMaxRetriesDefault )
setEnvKeyDefault ( envTaskActionsCleanStaleEnabled , taskActionsCleanStaleEnabledDefault )
setEnvKeyDefault ( envTaskActionsCleanStaleInterval , taskActionsCleanStaleIntervalDefault )
setEnvKeyDefault ( envTaskActionsCleanStaleMaxAge , taskActionsCleanStaleMaxAgeDefault )
2023-12-21 16:04:04 +00:00
setEnvKeyDefault ( envTaskPrometheusRefreshInterval , taskPrometheusRefreshDefault )
// prometheus
setEnvKeyDefault ( envPrometheusEnabled , prometheusEnabledDefault )
setEnvKeyDefault ( envPrometheusMetricsPath , prometheusMetricsPathDefault )
setEnvKeyDefault ( envPrometheusSecureTokenEnabled , prometheusSecureTokenEnabledDefault )
// db
2024-12-21 14:11:13 +00:00
setEnvKeyDefault ( envDbType , dbTypePostgres )
setEnvKeyDefault ( envDbMigrationEnabled , dbMigrationEnabledDefault )
2023-12-21 16:04:04 +00:00
if os . Getenv ( envDbType ) == dbTypePostgres {
setEnvKeyDefault ( envDbPostgresHost , dbTypePostgresHostDefault )
setEnvKeyDefault ( envDbPostgresPort , dbTypePostgresPortDefault )
setEnvKeyDefault ( envDbPostgresTimeZone , dbTypePostgresTZDefault )
}
// server
setEnvKeyDefault ( envServerPort , serverPortDefault )
setEnvKeyDefault ( envServerListen , serverListenDefault )
setEnvKeyDefault ( envServerTlsEnabled , serverTlsEnabledDefault )
2024-06-10 18:03:25 +00:00
setEnvKeyDefault ( envCorsAllowOrigins , corsAllowOriginsDefault )
2023-12-21 16:04:04 +00:00
setEnvKeyDefault ( envCorsAllowMethods , corsAllowMethodsDefault )
setEnvKeyDefault ( envCorsAllowHeaders , corsAllowHeadersDefault )
2024-06-10 18:03:25 +00:00
setEnvKeyDefault ( envCorsAllowCredentials , corsAllowCredentialsDefault )
setEnvKeyDefault ( envCorsExposeHeaders , corsExposeHeadersDefault )
2023-12-21 16:04:04 +00:00
setEnvKeyDefault ( envServerTimeout , serverTimeoutDefault )
}
func failIfEnvKeyNotPresent ( key string ) {
if os . Getenv ( key ) == "" {
zap . L ( ) . Sugar ( ) . Fatalf ( "Not all required ENV variables given. Please set '%s'" , key )
}
}
func setEnvKeyDefault ( key string , defaultValue string ) {
var err error
if os . Getenv ( key ) == "" {
if err = os . Setenv ( key , defaultValue ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not set default value for ENV variable '%s'" , key )
}
zap . L ( ) . Sugar ( ) . Infof ( "Set '%s' to '%s'" , key , defaultValue )
}
}
2024-04-26 18:24:47 +00:00
2024-05-16 07:33:32 +00:00
func parseDuration ( envProperty string ) time . Duration {
var duration time . Duration
var err error
if duration , err = time . ParseDuration ( os . Getenv ( envProperty ) ) ; err != nil {
zap . L ( ) . Sugar ( ) . Fatalf ( "Could not parse duration for '%s'. Reason: %s" , envProperty , err . Error ( ) )
}
return duration
}
2024-04-26 18:24:47 +00:00
func parseBasicAuthCredentials ( envProperty string ) map [ string ] string {
if envProperty == "" {
zap . L ( ) . Sugar ( ) . Fatalln ( "Invalid env for parsing basic auth credentials" )
}
credentialsFromEnv := os . Getenv ( envProperty )
var credentials [ ] string
credentials = strings . Split ( credentialsFromEnv , "," )
basicAuthCredentials := make ( map [ string ] string )
for _ , c := range credentials {
pair := strings . Split ( c , "=" )
if len ( pair ) != 2 {
zap . L ( ) . Sugar ( ) . Fatalln ( "Invalid basic auth credentials. Reason: credentials must be specified with the = separator per credential entry" )
}
if pair [ 0 ] == "" {
zap . L ( ) . Sugar ( ) . Fatalln ( "Invalid basic auth credentials. Reason: username must not be blank" )
}
if pair [ 1 ] == "" {
zap . L ( ) . Sugar ( ) . Fatalln ( "Invalid basic auth credentials. Reason: password must not be blank" )
}
basicAuthCredentials [ pair [ 0 ] ] = pair [ 1 ]
}
return basicAuthCredentials
}