Support reading timezone info from env (#748)

* add tzdata package

* updated timezone documentation

* add missing bind-mount from updated docs

* Add timezone deprecation warnings and related logging to backup commands

* fix lint CI job error

* Address PR comments: refactor timezone deprecation warning handling, update docs
This commit is contained in:
Mitchell Michalak
2026-04-20 08:10:00 -04:00
committed by GitHub
parent 0955d6fe80
commit 6a83ce4034
5 changed files with 141 additions and 10 deletions

View File

@@ -36,6 +36,13 @@ func (c *command) runAsCommand() error {
}
for _, config := range configurations {
warnings, warnErr := config.timezoneDeprecationWarnings()
if warnErr != nil {
return errwrap.Wrap(warnErr, "error collecting startup warnings")
}
for _, w := range warnings {
c.logger.Warn(w)
}
if err := runScript(config); err != nil {
return errwrap.Wrap(err, "error running script")
}
@@ -102,6 +109,14 @@ func (c *command) schedule(strategy configStrategy) error {
for _, cfg := range configurations {
config := cfg
warnings, warnErr := config.timezoneDeprecationWarnings()
if warnErr != nil {
return errwrap.Wrap(warnErr, "error collecting startup warnings")
}
for _, w := range warnings {
c.logger.Warn(w)
}
id, err := c.cr.AddFunc(config.BackupCronExpression, func() {
c.logger.Info(
fmt.Sprintf(

View File

@@ -4,6 +4,7 @@
package main
import (
"bufio"
"bytes"
"crypto/x509"
"encoding/pem"
@@ -97,6 +98,7 @@ type Config struct {
GoogleDriveImpersonateSubject string `split_words:"true"`
GoogleDriveEndpoint string `split_words:"true"`
GoogleDriveTokenURL string `split_words:"true"`
Timezone string `envconfig:"TZ"`
source string
additionalEnvVars map[string]string
}
@@ -322,3 +324,81 @@ func (c *Config) resolve() (reset func() error, warnings []string, err error) {
}
return
}
func mountedPaths(path string) (map[string]struct{}, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer func() { _ = file.Close() }()
mounts := make(map[string]struct{})
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
parts := strings.SplitN(line, " - ", 2)
fields := strings.Fields(parts[0])
if len(fields) < 5 {
continue
}
mounts[fields[4]] = struct{}{}
}
if err := scanner.Err(); err != nil {
return nil, err
}
return mounts, nil
}
func (c *Config) timezoneDeprecationWarnings() ([]string, error) {
mounts, err := mountedPaths("/proc/self/mountinfo")
if err != nil {
return nil, errwrap.Wrap(err, "error reading mount info")
}
deprecatedMounts := []string{
"/etc/timezone",
"/etc/localtime",
"/usr/share/zoneinfo",
}
var found []string
for _, mnt := range deprecatedMounts {
if _, ok := mounts[mnt]; ok {
found = append(found, mnt)
}
}
if len(found) == 0 {
return nil, nil
}
var warnings []string
// Primary deprecation message (compressed)
warnings = append(warnings,
fmt.Sprintf(
"Deprecated timezone bind mounts detected: %s. Support for these will be removed in a future version.",
strings.Join(found, ", "),
),
)
// Guidance based on TZ usage
if c.Timezone == "" {
warnings = append(warnings,
"Set the container timezone using the `TZ` environment variable instead.",
"Refer to the documentation for migration details.",
)
} else {
warnings = append(warnings,
fmt.Sprintf(
"`TZ=%s` is set, but deprecated timezone bind mounts are still present. Remove the bind mounts after confirming timezone handling works as expected.",
c.Timezone,
),
)
}
return warnings, nil
}

View File

@@ -34,6 +34,13 @@ func runPrintConfig() error {
for _, warning := range warnings {
fmt.Printf("warning:%s\n", warning)
}
timezoneWarnings, warnErr := config.timezoneDeprecationWarnings()
if warnErr != nil {
return errwrap.Wrap(warnErr, "error collecting timezone deprecation warnings")
}
for _, warning := range timezoneWarnings {
fmt.Printf("warning:%s\n", warning)
}
// insert line breaks before each field name, assuming field names start with uppercase letters
formatted := formatter.ReplaceAllString(fmt.Sprintf("%+v", *config), "\n$1")
fmt.Printf("%s\n", formatted)