From a86495ea6fdd56519afc65586c0f7f9c0f4f5ab2 Mon Sep 17 00:00:00 2001 From: Brent Baude Date: Tue, 14 Dec 2021 14:16:09 -0600 Subject: [PATCH] Set machine timezone Added an option to podman machine init to declare the timezone of the resulting machine. the default is to use the value of the host name or else a given timezone name like America/Chicago. Fixes: #11895 Signed-off-by: Brent Baude [NO NEW TESTS NEEDED] Signed-off-by: Brent Baude --- cmd/podman/machine/init.go | 8 ++++- docs/source/markdown/podman-machine-init.1.md | 6 ++++ pkg/machine/config.go | 1 + pkg/machine/ignition.go | 33 +++++++++++++++++++ pkg/machine/ignition_darwin.go | 16 +++++++++ pkg/machine/ignition_linux.go | 15 +++++++++ pkg/machine/qemu/machine.go | 2 ++ 7 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 pkg/machine/ignition_darwin.go create mode 100644 pkg/machine/ignition_linux.go diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go index adde887f74..bee6844df8 100644 --- a/cmd/podman/machine/init.go +++ b/cmd/podman/machine/init.go @@ -38,7 +38,6 @@ func init() { }) flags := initCmd.Flags() cfg := registry.PodmanConfig() - cpusFlagName := "cpus" flags.Uint64Var( &initOpts.CPUS, @@ -69,6 +68,13 @@ func init() { "now", false, "Start machine now", ) + timezoneFlagName := "timezone" + defaultTz := cfg.TZ() + if len(defaultTz) < 1 { + defaultTz = "local" + } + flags.StringVar(&initOpts.TimeZone, timezoneFlagName, defaultTz, "Set timezone") + _ = initCmd.RegisterFlagCompletionFunc(timezoneFlagName, completion.AutocompleteDefault) ImagePathFlagName := "image-path" flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Machine.Image, "Path to qcow image") diff --git a/docs/source/markdown/podman-machine-init.1.md b/docs/source/markdown/podman-machine-init.1.md index 3abc7c9ea5..aead6c695e 100644 --- a/docs/source/markdown/podman-machine-init.1.md +++ b/docs/source/markdown/podman-machine-init.1.md @@ -55,6 +55,12 @@ Memory (in MB). Start the virtual machine immediately after it has been initialized. +#### **--timezone** + +Set the timezone for the machine and containers. Valid values are `local` or +a `timezone` such as `America/Chicago`. A value of `local`, which is the default, +means to use the timezone of the machine host. + #### **--help** Print usage statement. diff --git a/pkg/machine/config.go b/pkg/machine/config.go index 55d5dd7b4d..e5e7013036 100644 --- a/pkg/machine/config.go +++ b/pkg/machine/config.go @@ -21,6 +21,7 @@ type InitOptions struct { IsDefault bool Memory uint64 Name string + TimeZone string URI url.URL Username string } diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go index 5c465d37dc..9368cc8ed3 100644 --- a/pkg/machine/ignition.go +++ b/pkg/machine/ignition.go @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" "net/url" + "path/filepath" ) /* @@ -44,6 +45,7 @@ func getNodeGrp(grpName string) NodeGroup { type DynamicIgnition struct { Name string Key string + TimeZone string VMName string WritePath string } @@ -76,6 +78,37 @@ func NewIgnitionFile(ign DynamicIgnition) error { Links: getLinks(ign.Name), } + // Add or set the time zone for the machine + if len(ign.TimeZone) > 0 { + var ( + err error + tz string + ) + // local means the same as the host + // lookup where it is pointing to on the host + if ign.TimeZone == "local" { + tz, err = getLocalTimeZone() + if err != nil { + return err + } + } else { + tz = ign.TimeZone + } + tzLink := Link{ + Node: Node{ + Group: getNodeGrp("root"), + Path: "/etc/localtime", + Overwrite: boolToPtr(false), + User: getNodeUsr("root"), + }, + LinkEmbedded1: LinkEmbedded1{ + Hard: boolToPtr(false), + Target: filepath.Join("/usr/share/zoneinfo", tz), + }, + } + ignStorage.Links = append(ignStorage.Links, tzLink) + } + // ready is a unit file that sets up the virtual serial device // where when the VM is done configuring, it will send an ack // so a listening host knows it can being interacting with it diff --git a/pkg/machine/ignition_darwin.go b/pkg/machine/ignition_darwin.go new file mode 100644 index 0000000000..9ede4b026e --- /dev/null +++ b/pkg/machine/ignition_darwin.go @@ -0,0 +1,16 @@ +//+build darwin + +package machine + +import ( + "os" + "strings" +) + +func getLocalTimeZone() (string, error) { + tzPath, err := os.Readlink("/etc/localtime") + if err != nil { + return "", err + } + return strings.TrimPrefix(tzPath, "/var/db/timezone/zoneinfo"), nil +} diff --git a/pkg/machine/ignition_linux.go b/pkg/machine/ignition_linux.go new file mode 100644 index 0000000000..6db5a8e7a9 --- /dev/null +++ b/pkg/machine/ignition_linux.go @@ -0,0 +1,15 @@ +package machine + +import ( + "os/exec" + "strings" +) + +func getLocalTimeZone() (string, error) { + output, err := exec.Command("timedatectl", "show", "--property=Timezone").Output() + if err != nil { + return "", err + } + // Remove prepended field and the newline + return strings.TrimPrefix(strings.TrimSuffix(string(output), "\n"), "Timezone="), nil +} diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index 57c32bf748..19cd131e1e 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -145,6 +145,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) error { // Get image as usual v.ImageStream = opts.ImagePath dd, err := machine.NewFcosDownloader(vmtype, v.Name, opts.ImagePath) + if err != nil { return err } @@ -235,6 +236,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) error { Name: opts.Username, Key: key, VMName: v.Name, + TimeZone: opts.TimeZone, WritePath: v.IgnitionFilePath, } return machine.NewIgnitionFile(ign)