summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
authorAshley Cui <acui@redhat.com>2020-06-30 17:21:52 -0400
committerAshley Cui <acui@redhat.com>2020-07-02 13:30:59 -0400
commit9a1543caec75a7b02dd2ec9a1111756bb1716454 (patch)
treefb1223410fe7ce9e0831a39c73a70bd9efa0caee /libpod
parente84695213e35c22ba085e3831cbd025cd55a4c84 (diff)
downloadpodman-9a1543caec75a7b02dd2ec9a1111756bb1716454.tar.gz
podman-9a1543caec75a7b02dd2ec9a1111756bb1716454.tar.bz2
podman-9a1543caec75a7b02dd2ec9a1111756bb1716454.zip
Add --tz flag to create, run
--tz flag sets timezone inside container Can be set to IANA timezone as well as `local` to match host machine Signed-off-by: Ashley Cui <acui@redhat.com>
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go9
-rw-r--r--libpod/container_inspect.go2
-rw-r--r--libpod/container_internal_linux.go57
-rw-r--r--libpod/define/container_inspect.go3
-rw-r--r--libpod/options.go24
5 files changed, 95 insertions, 0 deletions
diff --git a/libpod/container.go b/libpod/container.go
index 20688e3ee..8ea25d6a0 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -424,6 +424,10 @@ type ContainerConfig struct {
// to 0, 1, 2) that will be passed to the executed process. The total FDs
// passed will be 3 + PreserveFDs.
PreserveFDs uint `json:"preserveFds,omitempty"`
+
+ // Timezone is the timezone inside the container.
+ // Local means it has the same timezone as the host machine
+ Timezone string `json:"timezone,omitempty"`
}
// ContainerNamedVolume is a named volume that will be mounted into the
@@ -1248,3 +1252,8 @@ func (c *Container) AutoRemove() bool {
}
return c.Spec().Annotations[define.InspectAnnotationAutoremove] == define.InspectResponseTrue
}
+
+func (c *Container) Timezone() string {
+ return c.config.Timezone
+
+}
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index c6d9e1a65..9fbdf2c8b 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -322,6 +322,8 @@ func (c *Container) generateInspectContainerConfig(spec *spec.Spec) *define.Insp
ctrConfig.CreateCommand = c.config.CreateCommand
+ ctrConfig.Timezone = c.config.Timezone
+
return ctrConfig
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 2c78f6bd2..d61268eab 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -1241,6 +1241,31 @@ func (c *Container) makeBindMounts() error {
c.state.BindMounts["/etc/hostname"] = hostnamePath
}
+ // Make /etc/localtime
+ if c.Timezone() != "" {
+ if _, ok := c.state.BindMounts["/etc/localtime"]; !ok {
+ var zonePath string
+ if c.Timezone() == "local" {
+ zonePath, err = filepath.EvalSymlinks("/etc/localtime")
+ if err != nil {
+ return errors.Wrapf(err, "error finding local timezone for container %s", c.ID())
+ }
+ } else {
+ zone := filepath.Join("/usr/share/zoneinfo", c.Timezone())
+ zonePath, err = filepath.EvalSymlinks(zone)
+ if err != nil {
+ return errors.Wrapf(err, "error setting timezone for container %s", c.ID())
+ }
+ }
+ localtimePath, err := c.copyTimezoneFile(zonePath)
+ if err != nil {
+ return errors.Wrapf(err, "error setting timezone for container %s", c.ID())
+ }
+ c.state.BindMounts["/etc/localtime"] = localtimePath
+
+ }
+ }
+
// Make .containerenv
// Empty file, so no need to recreate if it exists
if _, ok := c.state.BindMounts["/run/.containerenv"]; !ok {
@@ -1533,3 +1558,35 @@ func (c *Container) getOCICgroupPath() (string, error) {
return "", errors.Wrapf(define.ErrInvalidArg, "invalid cgroup manager %s requested", c.runtime.config.Engine.CgroupManager)
}
}
+
+func (c *Container) copyTimezoneFile(zonePath string) (string, error) {
+ var localtimeCopy string = filepath.Join(c.state.RunDir, "localtime")
+ file, err := os.Stat(zonePath)
+ if err != nil {
+ return "", err
+ }
+ if file.IsDir() {
+ return "", errors.New("Invalid timezone: is a directory")
+ }
+ src, err := os.Open(zonePath)
+ if err != nil {
+ return "", err
+ }
+ defer src.Close()
+ dest, err := os.Create(localtimeCopy)
+ if err != nil {
+ return "", err
+ }
+ defer dest.Close()
+ _, err = io.Copy(dest, src)
+ if err != nil {
+ return "", err
+ }
+ if err := label.Relabel(localtimeCopy, c.config.MountLabel, false); err != nil {
+ return "", err
+ }
+ if err := dest.Chown(c.RootUID(), c.RootGID()); err != nil {
+ return "", err
+ }
+ return localtimeCopy, err
+}
diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go
index 3fbeb8f0b..4e1fcca35 100644
--- a/libpod/define/container_inspect.go
+++ b/libpod/define/container_inspect.go
@@ -54,6 +54,9 @@ type InspectContainerConfig struct {
// CreateCommand is the full command plus arguments of the process the
// container has been created with.
CreateCommand []string `json:"CreateCommand,omitempty"`
+ // Timezone is the timezone inside the container.
+ // Local means it has the same timezone as the host machine
+ Timezone string `json:"Timezone,omitempty"`
}
// InspectRestartPolicy holds information about the container's restart policy.
diff --git a/libpod/options.go b/libpod/options.go
index 4041fb1cf..83d2c2e1f 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1525,6 +1525,30 @@ func withSetAnon() VolumeCreateOption {
}
}
+// WithTimezone sets the timezone in the container
+func WithTimezone(path string) CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return define.ErrCtrFinalized
+ }
+ if path != "local" {
+ zone := filepath.Join("/usr/share/zoneinfo", path)
+
+ file, err := os.Stat(zone)
+ if err != nil {
+ return err
+ }
+ //We don't want to mount a timezone directory
+ if file.IsDir() {
+ return errors.New("Invalid timezone: is a directory")
+ }
+ }
+
+ ctr.config.Timezone = path
+ return nil
+ }
+}
+
// Pod Creation Options
// WithPodName sets the name of the pod.