EventManager: allow to configure the timezone to use for the scheduler

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2024-06-30 18:52:59 +02:00
parent 97ffa0394f
commit 55be9f0b9c
No known key found for this signature in database
GPG key ID: 935D2952DEC4EECF
8 changed files with 39 additions and 6 deletions

View file

@ -170,6 +170,7 @@ func Initialize(c Configuration, isShared int) error {
isShuttingDown.Store(false) isShuttingDown.Store(false)
util.SetUmask(c.Umask) util.SetUmask(c.Umask)
version.SetConfig(c.ServerVersion) version.SetConfig(c.ServerVersion)
dataprovider.SetTZ(c.TZ)
Config = c Config = c
Config.Actions.ExecuteOn = util.RemoveDuplicates(Config.Actions.ExecuteOn, true) Config.Actions.ExecuteOn = util.RemoveDuplicates(Config.Actions.ExecuteOn, true)
Config.Actions.ExecuteSync = util.RemoveDuplicates(Config.Actions.ExecuteSync, true) Config.Actions.ExecuteSync = util.RemoveDuplicates(Config.Actions.ExecuteSync, true)
@ -588,6 +589,10 @@ type Configuration struct {
Umask string `json:"umask" mapstructure:"umask"` Umask string `json:"umask" mapstructure:"umask"`
// Defines the server version // Defines the server version
ServerVersion string `json:"server_version" mapstructure:"server_version"` ServerVersion string `json:"server_version" mapstructure:"server_version"`
// TZ defines the time zone to use for the EventManager scheduler and to
// control time-based access restrictions. Set to "local" to use the
// server's local time, otherwise UTC will be used.
TZ string `json:"tz" mapstructure:"tz"`
// Metadata configuration // Metadata configuration
Metadata MetadataConfig `json:"metadata" mapstructure:"metadata"` Metadata MetadataConfig `json:"metadata" mapstructure:"metadata"`
idleTimeoutAsDuration time.Duration idleTimeoutAsDuration time.Duration

View file

@ -19,6 +19,8 @@ import (
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"github.com/drakkan/sftpgo/v2/internal/dataprovider"
"github.com/drakkan/sftpgo/v2/internal/logger"
"github.com/drakkan/sftpgo/v2/internal/util" "github.com/drakkan/sftpgo/v2/internal/util"
) )
@ -36,7 +38,15 @@ func stopEventScheduler() {
func startEventScheduler() { func startEventScheduler() {
stopEventScheduler() stopEventScheduler()
eventScheduler = cron.New(cron.WithLocation(time.UTC), cron.WithLogger(cron.DiscardLogger)) options := []cron.Option{
cron.WithLogger(cron.DiscardLogger),
}
if !dataprovider.UseLocalTime() {
eventManagerLog(logger.LevelDebug, "use UTC time for the scheduler")
options = append(options, cron.WithLocation(time.UTC))
}
eventScheduler = cron.New(options...)
eventManager.loadRules() eventManager.loadRules()
_, err := eventScheduler.AddFunc("@every 10m", eventManager.loadRules) _, err := eventScheduler.AddFunc("@every 10m", eventManager.loadRules)
util.PanicOnError(err) util.PanicOnError(err)

View file

@ -234,6 +234,7 @@ func Init() {
RateLimitersConfig: []common.RateLimiterConfig{defaultRateLimiter}, RateLimitersConfig: []common.RateLimiterConfig{defaultRateLimiter},
Umask: "", Umask: "",
ServerVersion: "", ServerVersion: "",
TZ: "",
Metadata: common.MetadataConfig{ Metadata: common.MetadataConfig{
Read: 0, Read: 0,
}, },
@ -2007,6 +2008,7 @@ func setViperDefaults() {
viper.SetDefault("common.defender.login_delay.password_failed", globalConf.Common.DefenderConfig.LoginDelay.PasswordFailed) viper.SetDefault("common.defender.login_delay.password_failed", globalConf.Common.DefenderConfig.LoginDelay.PasswordFailed)
viper.SetDefault("common.umask", globalConf.Common.Umask) viper.SetDefault("common.umask", globalConf.Common.Umask)
viper.SetDefault("common.server_version", globalConf.Common.ServerVersion) viper.SetDefault("common.server_version", globalConf.Common.ServerVersion)
viper.SetDefault("common.tz", globalConf.Common.TZ)
viper.SetDefault("common.metadata.read", globalConf.Common.Metadata.Read) viper.SetDefault("common.metadata.read", globalConf.Common.Metadata.Read)
viper.SetDefault("acme.email", globalConf.ACME.Email) viper.SetDefault("acme.email", globalConf.ACME.Email)
viper.SetDefault("acme.key_type", globalConf.ACME.KeyType) viper.SetDefault("acme.key_type", globalConf.ACME.KeyType)

View file

@ -187,6 +187,7 @@ var (
ErrDuplicatedKey = errors.New("duplicated key not allowed") ErrDuplicatedKey = errors.New("duplicated key not allowed")
// ErrForeignKeyViolated occurs when there is a foreign key constraint violation // ErrForeignKeyViolated occurs when there is a foreign key constraint violation
ErrForeignKeyViolated = errors.New("violates foreign key constraint") ErrForeignKeyViolated = errors.New("violates foreign key constraint")
tz = ""
isAdminCreated atomic.Bool isAdminCreated atomic.Bool
validTLSUsernames = []string{string(sdk.TLSUsernameNone), string(sdk.TLSUsernameCN)} validTLSUsernames = []string{string(sdk.TLSUsernameNone), string(sdk.TLSUsernameCN)}
config Config config Config
@ -590,6 +591,16 @@ func (c *Config) doBackup() (string, error) {
return outputFile, nil return outputFile, nil
} }
// SetTZ sets the configured timezone.
func SetTZ(val string) {
tz = val
}
// UseLocalTime returns true if local time should be used instead of UTC.
func UseLocalTime() bool {
return tz == "local"
}
// ExecuteBackup executes a backup // ExecuteBackup executes a backup
func ExecuteBackup() (string, error) { func ExecuteBackup() (string, error) {
return config.doBackup() return config.doBackup()

View file

@ -342,7 +342,11 @@ func (u *User) isTimeBasedAccessAllowed(when time.Time) bool {
if when.IsZero() { if when.IsZero() {
when = time.Now() when = time.Now()
} }
if UseLocalTime() {
when = when.Local()
} else {
when = when.UTC() when = when.UTC()
}
weekDay := when.Weekday() weekDay := when.Weekday()
hhMM := when.Format("15:04") hhMM := when.Format("15:04")
for _, p := range u.Filters.AccessTime { for _, p := range u.Filters.AccessTime {

View file

@ -24,6 +24,7 @@
"allow_self_connections": 0, "allow_self_connections": 0,
"umask": "", "umask": "",
"server_version": "", "server_version": "",
"tz": "",
"metadata": { "metadata": {
"read": 0 "read": 0
}, },

View file

@ -730,7 +730,7 @@
"external_auth_cache_time": "External auth cache time", "external_auth_cache_time": "External auth cache time",
"external_auth_cache_time_help": "Cache time, in seconds, for users authenticated using an external auth hook. 0 means no cache", "external_auth_cache_time_help": "Cache time, in seconds, for users authenticated using an external auth hook. 0 means no cache",
"access_time": "Access time restrictions", "access_time": "Access time restrictions",
"access_time_help": "No restrictions means access is always allowed, the time must be set in the format HH:MM. Use UTC time" "access_time_help": "No restrictions means access is always allowed, the time must be set in the format HH:MM"
}, },
"admin": { "admin": {
"role_permissions": "A role admin cannot have the following permissions: {{val}}", "role_permissions": "A role admin cannot have the following permissions: {{val}}",
@ -1071,7 +1071,7 @@
"sync_unsupported_fs_event": "Synchronous execution is only supported for upload and pre-* filesystem events", "sync_unsupported_fs_event": "Synchronous execution is only supported for upload and pre-* filesystem events",
"only_failure_actions": "At least a non-failure action is required", "only_failure_actions": "At least a non-failure action is required",
"sync_action_required": "Event \"{{val}}\" requires at least a synchronous action", "sync_action_required": "Event \"{{val}}\" requires at least a synchronous action",
"scheduler_help": "The scheduler uses UTC time. Hours: 0-23. Day of week: 0-6 (Sun-Sat). Day of month: 1-31. Month: 1-12. Asterisk (*) indicates a match for all the values of the field. e.g. every day of week, every day of month and so on", "scheduler_help": "Hours: 0-23. Day of week: 0-6 (Sun-Sat). Day of month: 1-31. Month: 1-12. Asterisk (*) indicates a match for all the values of the field. e.g. every day of week, every day of month and so on",
"concurrent_run": "Allow concurrent execution from multiple instances", "concurrent_run": "Allow concurrent execution from multiple instances",
"protocol_filters": "Protocol filters", "protocol_filters": "Protocol filters",
"object_filters": "Object filters", "object_filters": "Object filters",

View file

@ -730,7 +730,7 @@
"external_auth_cache_time": "Cache per autenticazione esterna", "external_auth_cache_time": "Cache per autenticazione esterna",
"external_auth_cache_time_help": "Tempo di memorizzazione nella cache, in secondi, per gli utenti autenticati utilizzando un hook di autenticazione esterno. 0 significa nessuna cache", "external_auth_cache_time_help": "Tempo di memorizzazione nella cache, in secondi, per gli utenti autenticati utilizzando un hook di autenticazione esterno. 0 significa nessuna cache",
"access_time": "Limitazioni temporali all'accesso", "access_time": "Limitazioni temporali all'accesso",
"access_time_help": "Nessuna restrizione significa che l'accesso è sempre consentito, l'ora deve essere impostata nel formato HH:MM. Utilizzare l'ora UTC" "access_time_help": "Nessuna restrizione significa che l'accesso è sempre consentito, l'ora deve essere impostata nel formato HH:MM"
}, },
"admin": { "admin": {
"role_permissions": "Un amministratore di ruolo non può avere le seguenti autorizzazioni: {{val}}", "role_permissions": "Un amministratore di ruolo non può avere le seguenti autorizzazioni: {{val}}",
@ -1071,7 +1071,7 @@
"sync_unsupported_fs_event": "L'esecuzione sincrona è supporta solo per gli eventi \"upload\" e \"pre-*\"", "sync_unsupported_fs_event": "L'esecuzione sincrona è supporta solo per gli eventi \"upload\" e \"pre-*\"",
"only_failure_actions": "E' richiesta almeno un'azione che non venga eseguita su errore", "only_failure_actions": "E' richiesta almeno un'azione che non venga eseguita su errore",
"sync_action_required": "L'evento \"{{val}}\" richiede almeno un'azione da eseguire sincronamente", "sync_action_required": "L'evento \"{{val}}\" richiede almeno un'azione da eseguire sincronamente",
"scheduler_help": "Lo scheduler utilizza l'ora UTC. Orari: 0-23. Giorno della settimana: 0-6 (dom-sab). Giorno del mese: 1-31. Mese: 1-12. L'asterisco (*) indica una corrispondenza per tutti i valori del campo. per esempio. ogni giorno della settimana, ogni giorno del mese e così via", "scheduler_help": "Orari: 0-23. Giorno della settimana: 0-6 (dom-sab). Giorno del mese: 1-31. Mese: 1-12. L'asterisco (*) indica una corrispondenza per tutti i valori del campo. per esempio. ogni giorno della settimana, ogni giorno del mese e così via",
"concurrent_run": "Consentire l'esecuzione simultanea da più istanze", "concurrent_run": "Consentire l'esecuzione simultanea da più istanze",
"protocol_filters": "Filtro su protocolli", "protocol_filters": "Filtro su protocolli",
"object_filters": "Filtro su oggetti", "object_filters": "Filtro su oggetti",