summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorW. Trevor King <wking@tremily.us>2018-07-05 10:57:39 -0700
committerAtomic Bot <atomic-devel@projectatomic.io>2018-07-06 17:54:32 +0000
commitb2344b83ed0bbbd1f8e3ec5efdf09c81ad169941 (patch)
treedfa39cf98c3d4d1e7f651b9e4d062a7f87fd3364
parentaaab26fd0ce812f78ef72b94d921439e7f9d9d6a (diff)
downloadpodman-b2344b83ed0bbbd1f8e3ec5efdf09c81ad169941.tar.gz
podman-b2344b83ed0bbbd1f8e3ec5efdf09c81ad169941.tar.bz2
podman-b2344b83ed0bbbd1f8e3ec5efdf09c81ad169941.zip
pkg/ctime: Factor libpod/finished* into a separate package
This removes some boilerplate from the libpod package, so we can focus on container stuff there. And it gives us a tidy sub-package for focusing on ctime extraction, so we can focus on unit testing and portability of the extraction utility there. For the unsupported implementation, I'm falling back to Go's ModTime [1]. That's obviously not the creation time, but it's likely to be closer than the uninitialized Time structure from cc6f0e85 (more changes to compile darwin, 2018-07-04, #1047). Especially for our use case in libpod/oci, where we're looking at write-once exit files. The test is more complicated than I initially expected, because on Linux filesystem timestamps come from a truncated clock without interpolation [2] (and network filesystems can be completely decoupled [3]). So even for local disks, creation times can be up to a jiffie earlier than 'before'. This test ensures at least monotonicity by creating two files and ensuring the reported creation time for the second is greater than or equal to the reported creation time for the first. It also checks that both creation times are within the window from one second earlier than 'before' through 'after'. That should be enough of a window for local disks, even if the kernel for those systems has an abnormally large jiffie. It might be ok on network filesystems, although it will not be very resilient to network clock lagging behind the local system clock. [1]: https://golang.org/pkg/os/#FileInfo [2]: https://groups.google.com/d/msg/linux.kernel/mdeXx2TBYZA/_4eJEuJoAQAJ Subject: Re: Apparent backward time travel in timestamps on file creation Date: Thu, 30 Mar 2017 20:20:02 +0200 Message-ID: <tqMPU-1Sb-21@gated-at.bofh.it> [3]: https://groups.google.com/d/msg/linux.kernel/mdeXx2TBYZA/cTKj4OBuAQAJ Subject: Re: Apparent backward time travel in timestamps on file creation Date: Thu, 30 Mar 2017 22:10:01 +0200 Message-ID: <tqOyl-36A-1@gated-at.bofh.it> Signed-off-by: W. Trevor King <wking@tremily.us> Closes: #1050 Approved by: mheon
-rw-r--r--libpod/finished_32.go16
-rw-r--r--libpod/finished_unsupported.go12
-rw-r--r--libpod/oci.go3
-rw-r--r--pkg/ctime/ctime.go12
-rw-r--r--pkg/ctime/ctime_linux_32.go14
-rw-r--r--pkg/ctime/ctime_linux_64.go (renamed from libpod/finished_64.go)6
-rw-r--r--pkg/ctime/ctime_test.go63
-rw-r--r--pkg/ctime/ctime_unsupported.go12
8 files changed, 105 insertions, 33 deletions
diff --git a/libpod/finished_32.go b/libpod/finished_32.go
deleted file mode 100644
index d66974177..000000000
--- a/libpod/finished_32.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// +build arm 386
-
-package libpod
-
-import (
- "os"
- "syscall"
- "time"
-)
-
-// Get created time of a file
-// Only works on 32-bit OSes
-func getFinishedTime(fi os.FileInfo) time.Time {
- st := fi.Sys().(*syscall.Stat_t)
- return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec))
-}
diff --git a/libpod/finished_unsupported.go b/libpod/finished_unsupported.go
deleted file mode 100644
index a893d668c..000000000
--- a/libpod/finished_unsupported.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build darwin,!linux
-
-package libpod
-
-import (
- "os"
- "time"
-)
-
-func getFinishedTime(fi os.FileInfo) time.Time {
- return time.Time{}
-}
diff --git a/libpod/oci.go b/libpod/oci.go
index fcb36241b..612935aed 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -19,6 +19,7 @@ import (
"github.com/opencontainers/selinux/go-selinux"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
+ "github.com/projectatomic/libpod/pkg/ctime"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
kwait "k8s.io/apimachinery/pkg/util/wait"
@@ -422,7 +423,7 @@ func (r *OCIRuntime) updateContainerStatus(ctr *Container) error {
return nil
}
- ctr.state.FinishedTime = getFinishedTime(fi)
+ ctr.state.FinishedTime = ctime.Created(fi)
statusCodeStr, err := ioutil.ReadFile(exitFile)
if err != nil {
return errors.Wrapf(err, "failed to read exit file for container %s", ctr.ID())
diff --git a/pkg/ctime/ctime.go b/pkg/ctime/ctime.go
new file mode 100644
index 000000000..f5c69c7e3
--- /dev/null
+++ b/pkg/ctime/ctime.go
@@ -0,0 +1,12 @@
+// Package ctime includes a utility for determining file-creation times.
+package ctime
+
+import (
+ "os"
+ "time"
+)
+
+// Created returns the file-creation time.
+func Created(fi os.FileInfo) time.Time {
+ return created(fi)
+}
diff --git a/pkg/ctime/ctime_linux_32.go b/pkg/ctime/ctime_linux_32.go
new file mode 100644
index 000000000..00c1a9a8e
--- /dev/null
+++ b/pkg/ctime/ctime_linux_32.go
@@ -0,0 +1,14 @@
+// +build arm,linux 386,linux
+
+package ctime
+
+import (
+ "os"
+ "syscall"
+ "time"
+)
+
+func created(fi os.FileInfo) time.Time {
+ st := fi.Sys().(*syscall.Stat_t)
+ return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec))
+}
diff --git a/libpod/finished_64.go b/pkg/ctime/ctime_linux_64.go
index 3688afa84..1251c1ded 100644
--- a/libpod/finished_64.go
+++ b/pkg/ctime/ctime_linux_64.go
@@ -1,6 +1,6 @@
// +build !arm,!386,linux
-package libpod
+package ctime
import (
"os"
@@ -8,9 +8,7 @@ import (
"time"
)
-// Get the created time of a file
-// Only works on 64-bit OSes
-func getFinishedTime(fi os.FileInfo) time.Time {
+func created(fi os.FileInfo) time.Time {
st := fi.Sys().(*syscall.Stat_t)
return time.Unix(st.Ctim.Sec, st.Ctim.Nsec)
}
diff --git a/pkg/ctime/ctime_test.go b/pkg/ctime/ctime_test.go
new file mode 100644
index 000000000..abfc627da
--- /dev/null
+++ b/pkg/ctime/ctime_test.go
@@ -0,0 +1,63 @@
+package ctime
+
+import (
+ "io/ioutil"
+ "os"
+ "testing"
+ "time"
+)
+
+func TestCreated(t *testing.T) {
+ before := time.Now()
+
+ fileA, err := ioutil.TempFile("", "ctime-test-")
+ if err != nil {
+ t.Error(err)
+ }
+ defer os.Remove(fileA.Name())
+
+ fileB, err := ioutil.TempFile("", "ctime-test-")
+ if err != nil {
+ t.Error(err)
+ }
+ defer os.Remove(fileB.Name())
+
+ after := time.Now()
+
+ infoA, err := fileA.Stat()
+ if err != nil {
+ t.Error(err)
+ }
+
+ err = fileA.Close()
+ if err != nil {
+ t.Error(err)
+ }
+
+ infoB, err := fileB.Stat()
+ if err != nil {
+ t.Error(err)
+ }
+
+ err = fileB.Close()
+ if err != nil {
+ t.Error(err)
+ }
+
+ createdA := Created(infoA)
+ beforeToCreateA := createdA.Sub(before)
+ if beforeToCreateA.Nanoseconds() < -1000000000 {
+ t.Errorf("created file A %s is %v nanoseconds before %s", createdA, -beforeToCreateA.Nanoseconds(), before)
+ }
+
+ createdB := Created(infoB)
+ createAToCreateB := createdB.Sub(createdA)
+ if createAToCreateB.Nanoseconds() < 0 {
+ t.Errorf("created file B %s is %v nanoseconds before file A %s", createdB, -createAToCreateB.Nanoseconds(), createdA)
+ }
+
+ createBToAfter := after.Sub(createdB)
+ if createBToAfter.Nanoseconds() < 0 {
+ t.Errorf("created file B %s is %v nanoseconds after %s", createdB, -createBToAfter.Nanoseconds(), after)
+ }
+}
diff --git a/pkg/ctime/ctime_unsupported.go b/pkg/ctime/ctime_unsupported.go
new file mode 100644
index 000000000..325731353
--- /dev/null
+++ b/pkg/ctime/ctime_unsupported.go
@@ -0,0 +1,12 @@
+// +build !linux
+
+package ctime
+
+import (
+ "os"
+ "time"
+)
+
+func created(fi os.FileInfo) time.Time {
+ return fi.ModTime()
+}