Skip to content

Commit e3df077

Browse files
Merge pull request #26029 from Luap99/machine-tz
pkg/machine: more timezone fixes
2 parents 344796a + ac6080b commit e3df077

File tree

3 files changed

+54
-41
lines changed

3 files changed

+54
-41
lines changed

pkg/machine/e2e/init_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,12 @@ var _ = Describe("podman machine init", func() {
279279
Expect(err).ToNot(HaveOccurred())
280280
Expect(timezoneSession).To(Exit(0))
281281
Expect(timezoneSession.outputToString()).To(ContainSubstring("HST"))
282+
283+
sshTimezone = sshMachine{}
284+
timezoneSession, err = mb.setName(name).setCmd(sshTimezone.withSSHCommand([]string{"timedatectl show --property Timezone"})).run()
285+
Expect(err).ToNot(HaveOccurred())
286+
Expect(timezoneSession).To(Exit(0))
287+
Expect(timezoneSession.outputToString()).To(ContainSubstring("Pacific/Honolulu"))
282288
})
283289

284290
It("machine init with swap", func() {

pkg/machine/ignition/ignition.go

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -143,36 +143,43 @@ func (ign *DynamicIgnition) GenerateIgnitionConfig() error {
143143

144144
// Add or set the time zone for the machine
145145
if len(ign.TimeZone) > 0 {
146-
var (
147-
err error
148-
tz string
149-
)
146+
var err error
147+
tz := ign.TimeZone
150148
// local means the same as the host
151149
// look up where it is pointing to on the host
152150
if ign.TimeZone == "local" {
153-
tz, err = getLocalTimeZone()
154-
if err != nil {
155-
return fmt.Errorf("error getting local timezone: %q", err)
151+
if env, ok := os.LookupEnv("TZ"); ok {
152+
tz = env
153+
} else {
154+
tz, err = getLocalTimeZone()
155+
if err != nil {
156+
return fmt.Errorf("error getting local timezone: %q", err)
157+
}
156158
}
157-
} else {
158-
tz = ign.TimeZone
159159
}
160-
tzLink := Link{
161-
Node: Node{
162-
Group: GetNodeGrp("root"),
163-
Path: "/etc/localtime",
164-
Overwrite: BoolToPtr(false),
165-
User: GetNodeUsr("root"),
166-
},
167-
LinkEmbedded1: LinkEmbedded1{
168-
Hard: BoolToPtr(false),
169-
// We always want this value in unix form (/path/to/something) because this is being
170-
// set in the machine OS (always Linux). However, filepath.join on windows will use a "\\"
171-
// separator; therefore we use ToSlash to convert the path to unix style
172-
Target: filepath.ToSlash(filepath.Join("/usr/share/zoneinfo", tz)),
173-
},
160+
// getLocalTimeZone() can return empty string, do not add broken symlink in that case
161+
// coreos will default to UTC
162+
if tz == "" {
163+
logrus.Info("Unable to determine local timezone, machine will default to UTC")
164+
} else {
165+
tzLink := Link{
166+
Node: Node{
167+
Group: GetNodeGrp("root"),
168+
Path: "/etc/localtime",
169+
Overwrite: BoolToPtr(false),
170+
User: GetNodeUsr("root"),
171+
},
172+
LinkEmbedded1: LinkEmbedded1{
173+
Hard: BoolToPtr(false),
174+
// We always want this value in unix form (../usr/share/zoneinfo) because this is being
175+
// set in the machine OS (always Linux) and systemd needs the relative symlink. However,
176+
// filepath.join on windows will use a "\\" separator so use path.Join() which always
177+
// uses the slash.
178+
Target: path.Join("../usr/share/zoneinfo", tz),
179+
},
180+
}
181+
ignStorage.Links = append(ignStorage.Links, tzLink)
174182
}
175-
ignStorage.Links = append(ignStorage.Links, tzLink)
176183
}
177184

178185
// This service gets environment variables that are provided
Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
package ignition
22

33
import (
4+
"errors"
45
"os"
5-
"os/exec"
6+
"path/filepath"
67
"strings"
7-
8-
"github.com/sirupsen/logrus"
98
)
109

1110
func getLocalTimeZone() (string, error) {
12-
trimTzFunc := func(s string) string {
13-
return strings.TrimPrefix(strings.TrimSuffix(s, "\n"), "Timezone=")
11+
path, err := filepath.EvalSymlinks("/etc/localtime")
12+
if err != nil {
13+
// of the path does not exist, ignore it as the code default to UTC then
14+
if errors.Is(err, os.ErrNotExist) {
15+
return "", nil
16+
}
17+
return "", err
1418
}
1519

16-
// perform a variety of ways to see if we can determine the tz
17-
output, err := exec.Command("timedatectl", "show", "--property=Timezone").Output()
18-
if err == nil {
19-
return trimTzFunc(string(output)), nil
20-
}
21-
logrus.Debugf("Timedatectl show --property=Timezone failed: %s", err)
22-
output, err = os.ReadFile("/etc/timezone")
23-
if err == nil {
24-
return trimTzFunc(string(output)), nil
20+
// Allow using TZDIR per:
21+
// https://sourceware.org/git/?p=glibc.git;a=blob;f=time/tzfile.c;h=8a923d0cccc927a106dc3e3c641be310893bab4e;hb=HEAD#l149
22+
zoneinfo := os.Getenv("TZDIR")
23+
if zoneinfo == "" {
24+
// default zoneinfo location
25+
zoneinfo = "/usr/share/zoneinfo"
2526
}
26-
logrus.Debugf("unable to read /etc/timezone, falling back to empty timezone: %s", err)
27-
// if we cannot determine the tz, return empty string
28-
return "", nil
27+
// Trim of the TZDIR part to extract the actual timezone name
28+
return strings.TrimPrefix(path, filepath.Clean(zoneinfo)+"/"), nil
2929
}

0 commit comments

Comments
 (0)