diff --git a/cmd/backup/main.go b/cmd/backup/main.go index 65eeee6..3b52056 100644 --- a/cmd/backup/main.go +++ b/cmd/backup/main.go @@ -18,6 +18,7 @@ import ( "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/client" + "github.com/gofrs/flock" "github.com/joho/godotenv" "github.com/leekchan/timeutil" minio "github.com/minio/minio-go/v7" @@ -228,7 +229,10 @@ func (s *script) stopContainersAndRun(thunk func() error) error { err, ) } - s.logger.Infof("Restarted %d container(s) and the matching service(s).", len(stoppedContainers)) + s.logger.Infof( + "Restarted %d container(s) and the matching service(s).", + len(stoppedContainers), + ) return nil }() @@ -356,7 +360,10 @@ func (s *script) pruneOldBackups() error { for candidate := range candidates { lenCandidates++ if candidate.Err != nil { - return fmt.Errorf("pruneOldBackups: error looking up candidates from remote storage: %w", candidate.Err) + return fmt.Errorf( + "pruneOldBackups: error looking up candidates from remote storage: %w", + candidate.Err, + ) } if candidate.LastModified.Before(deadline) { matches = append(matches, candidate) @@ -393,9 +400,10 @@ func (s *script) pruneOldBackups() error { ) } else if len(matches) != 0 && len(matches) == lenCandidates { s.logger.Warnf( - "The current configuration would delete all %d remote backup copies. Refusing to do so, please check your configuration.", + "The current configuration would delete all %d remote backup copies.", len(matches), ) + s.logger.Warn("Refusing to do so, please check your configuration.") } else { s.logger.Infof("None of %d remote backup(s) were pruned.", lenCandidates) } @@ -448,9 +456,10 @@ func (s *script) pruneOldBackups() error { ) } else if len(matches) != 0 && len(matches) == len(candidates) { s.logger.Warnf( - "The current configuration would delete all %d local backup copies. Refusing to do so, please check your configuration.", + "The current configuration would delete all %d local backup copies.", len(matches), ) + s.logger.Warn("Refusing to do so, please check your configuration.") } else { s.logger.Infof("None of %d local backup(s) were pruned.", len(candidates)) } @@ -472,19 +481,15 @@ func (s *script) must(err error) { // caller invokes the returned release func. When invoked while the file is // still locked the function panics. func lock(lockfile string) func() error { - lf, err := os.OpenFile(lockfile, os.O_CREATE|os.O_RDWR, os.ModeAppend) + fileLock := flock.New(lockfile) + acquired, err := fileLock.TryLock() if err != nil { panic(err) } - return func() error { - if err := lf.Close(); err != nil { - return fmt.Errorf("lock: error releasing file lock: %w", err) - } - if err := os.Remove(lockfile); err != nil { - return fmt.Errorf("lock: error removing lock file: %w", err) - } - return nil + if !acquired { + panic("unable to acquire file lock") } + return fileLock.Unlock } // copy creates a copy of the file located at `dst` at `src`. diff --git a/go.mod b/go.mod index 8ccfd39..41c432d 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.17 require ( github.com/docker/docker v20.10.8+incompatible + github.com/gofrs/flock v0.8.1 github.com/joho/godotenv v1.3.0 github.com/leekchan/timeutil v0.0.0-20150802142658-28917288c48d github.com/minio/minio-go/v7 v7.0.12 diff --git a/go.sum b/go.sum index 1bb1be4..6433a6e 100644 --- a/go.sum +++ b/go.sum @@ -274,6 +274,8 @@ github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblf github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -397,9 +399,11 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leekchan/timeutil v0.0.0-20150802142658-28917288c48d h1:2puqoOQwi3Ai1oznMOsFIbifm6kIfJaLLyYzWD4IzTs= github.com/leekchan/timeutil v0.0.0-20150802142658-28917288c48d/go.mod h1:hO90vCP2x3exaSH58BIAowSKvV+0OsY21TtzuFGHON4= @@ -907,6 +911,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=