From ed5991f13b1424d7b98224b814e9c518ddedb80e Mon Sep 17 00:00:00 2001 From: Derek Nola Date: Fri, 20 Aug 2021 12:34:22 -0700 Subject: [PATCH] K3s Flock Integration Test (#3887) * Upgraded flock with shared and integration test. Signed-off-by: dereknola Co-authored-by: Brian Downs --- pkg/flock/flock_int_test.go | 34 ++++++++++++++++++++++++++++++++++ pkg/flock/flock_unix.go | 28 +++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 pkg/flock/flock_int_test.go diff --git a/pkg/flock/flock_int_test.go b/pkg/flock/flock_int_test.go new file mode 100644 index 0000000000..509cda6f38 --- /dev/null +++ b/pkg/flock/flock_int_test.go @@ -0,0 +1,34 @@ +package flock_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/rancher/k3s/pkg/flock" +) + +const lockfile = "/tmp/testlock.test" + +var lock int +var _ = Describe("file locks", func() { + When("a new exclusive lock is created", func() { + It("starts up with no problems", func() { + var err error + lock, err = flock.Acquire(lockfile) + Expect(err).ToNot(HaveOccurred()) + }) + It("has a write lock on the file", func() { + Expect(flock.CheckLock(lockfile)).To(BeTrue()) + }) + It("release the lock correctly", func() { + Expect(flock.Release(lock)).To(Succeed()) + Expect(flock.CheckLock(lockfile)).To(BeFalse()) + }) + }) +}) + +func TestFlock(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Flock Suite") +} diff --git a/pkg/flock/flock_unix.go b/pkg/flock/flock_unix.go index 3dcf87dc3d..5099b557e7 100644 --- a/pkg/flock/flock_unix.go +++ b/pkg/flock/flock_unix.go @@ -18,7 +18,12 @@ limitations under the License. package flock -import "golang.org/x/sys/unix" +import ( + "os/exec" + "strings" + + "golang.org/x/sys/unix" +) // Acquire creates an exclusive lock on a file for the duration of the process, or until Release(d). // This method is reentrant. @@ -30,7 +35,28 @@ func Acquire(path string) (int, error) { return lock, unix.Flock(lock, unix.LOCK_EX) } +// AcquireShared creates a shared lock on a file for the duration of the process, or until Release(d). +// This method is reentrant. +func AcquireShared(path string) (int, error) { + lock, err := unix.Open(path, unix.O_CREAT|unix.O_RDWR, 0600) + if err != nil { + return -1, err + } + return lock, unix.Flock(lock, unix.LOCK_SH) +} + // Release removes an existing lock held by this process. func Release(lock int) error { return unix.Flock(lock, unix.LOCK_UN) } + +// CheckLock checks whether any process is using the lock +func CheckLock(path string) bool { + lockByte, _ := exec.Command("lsof", "-w", "-F", "ln", path).Output() + locks := string(lockByte) + if locks == "" { + return false + } + readWriteLock := strings.Split(locks, "\n")[2] + return readWriteLock == "lR" || readWriteLock == "lW" +}