Skip to content

Commit

Permalink
EventManager: allow to configure the timezone to use for the scheduler
Browse files Browse the repository at this point in the history
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
  • Loading branch information
drakkan committed Jun 30, 2024
1 parent 97ffa03 commit 55be9f0
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 6 deletions.
5 changes: 5 additions & 0 deletions internal/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ func Initialize(c Configuration, isShared int) error {
isShuttingDown.Store(false)
util.SetUmask(c.Umask)
version.SetConfig(c.ServerVersion)
dataprovider.SetTZ(c.TZ)
Config = c
Config.Actions.ExecuteOn = util.RemoveDuplicates(Config.Actions.ExecuteOn, true)
Config.Actions.ExecuteSync = util.RemoveDuplicates(Config.Actions.ExecuteSync, true)
Expand Down Expand Up @@ -588,6 +589,10 @@ type Configuration struct {
Umask string `json:"umask" mapstructure:"umask"`
// Defines the 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 MetadataConfig `json:"metadata" mapstructure:"metadata"`
idleTimeoutAsDuration time.Duration
Expand Down
12 changes: 11 additions & 1 deletion internal/common/eventscheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (

"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"
)

Expand All @@ -36,7 +38,15 @@ func stopEventScheduler() {
func startEventScheduler() {
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()
_, err := eventScheduler.AddFunc("@every 10m", eventManager.loadRules)
util.PanicOnError(err)
Expand Down
2 changes: 2 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ func Init() {
RateLimitersConfig: []common.RateLimiterConfig{defaultRateLimiter},
Umask: "",
ServerVersion: "",
TZ: "",
Metadata: common.MetadataConfig{
Read: 0,
},
Expand Down Expand Up @@ -2007,6 +2008,7 @@ func setViperDefaults() {
viper.SetDefault("common.defender.login_delay.password_failed", globalConf.Common.DefenderConfig.LoginDelay.PasswordFailed)
viper.SetDefault("common.umask", globalConf.Common.Umask)
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("acme.email", globalConf.ACME.Email)
viper.SetDefault("acme.key_type", globalConf.ACME.KeyType)
Expand Down
11 changes: 11 additions & 0 deletions internal/dataprovider/dataprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ var (
ErrDuplicatedKey = errors.New("duplicated key not allowed")
// ErrForeignKeyViolated occurs when there is a foreign key constraint violation
ErrForeignKeyViolated = errors.New("violates foreign key constraint")
tz = ""
isAdminCreated atomic.Bool
validTLSUsernames = []string{string(sdk.TLSUsernameNone), string(sdk.TLSUsernameCN)}
config Config
Expand Down Expand Up @@ -590,6 +591,16 @@ func (c *Config) doBackup() (string, error) {
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
func ExecuteBackup() (string, error) {
return config.doBackup()
Expand Down
6 changes: 5 additions & 1 deletion internal/dataprovider/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,11 @@ func (u *User) isTimeBasedAccessAllowed(when time.Time) bool {
if when.IsZero() {
when = time.Now()
}
when = when.UTC()
if UseLocalTime() {
when = when.Local()
} else {
when = when.UTC()
}
weekDay := when.Weekday()
hhMM := when.Format("15:04")
for _, p := range u.Filters.AccessTime {
Expand Down
1 change: 1 addition & 0 deletions sftpgo.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"allow_self_connections": 0,
"umask": "",
"server_version": "",
"tz": "",
"metadata": {
"read": 0
},
Expand Down
4 changes: 2 additions & 2 deletions static/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@
"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",
"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": {
"role_permissions": "A role admin cannot have the following permissions: {{val}}",
Expand Down Expand Up @@ -1071,7 +1071,7 @@
"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",
"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",
"protocol_filters": "Protocol filters",
"object_filters": "Object filters",
Expand Down
4 changes: 2 additions & 2 deletions static/locales/it/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@
"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",
"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": {
"role_permissions": "Un amministratore di ruolo non può avere le seguenti autorizzazioni: {{val}}",
Expand Down Expand Up @@ -1071,7 +1071,7 @@
"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",
"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",
"protocol_filters": "Filtro su protocolli",
"object_filters": "Filtro su oggetti",
Expand Down

0 comments on commit 55be9f0

Please sign in to comment.