Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package opentofu for openSUSE:Factory checked in at 2025-08-04 15:22:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/opentofu (Old) and /work/SRC/openSUSE:Factory/.opentofu.new.1085 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "opentofu" Mon Aug 4 15:22:43 2025 rev:36 rq:1297239 version:1.10.5 Changes: -------- --- /work/SRC/openSUSE:Factory/opentofu/opentofu.changes 2025-08-02 00:44:36.709674773 +0200 +++ /work/SRC/openSUSE:Factory/.opentofu.new.1085/opentofu.changes 2025-08-04 15:23:28.658588092 +0200 @@ -1,0 +2,11 @@ +Sun Aug 03 11:30:39 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 1.10.5: + * BUG FIXES: + - Fixed issue where usage of TF_PLUGIN_CACHE_DIR could result + in unexpected lock contention errors (#3090) + NOTE: It is still highly recommended to have valid + .terraform.lock.hcl files in projects using + TF_PLUGIN_CACHE_DIR + +------------------------------------------------------------------- Old: ---- opentofu-1.10.4.obscpio New: ---- opentofu-1.10.5.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ opentofu.spec ++++++ --- /var/tmp/diff_new_pack.PykhKy/_old 2025-08-04 15:23:30.894683408 +0200 +++ /var/tmp/diff_new_pack.PykhKy/_new 2025-08-04 15:23:30.894683408 +0200 @@ -1,7 +1,7 @@ # # spec file for package opentofu # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2025 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %define executable_name tofu Name: opentofu -Version: 1.10.4 +Version: 1.10.5 Release: 0 Summary: Declaratively manage your cloud infrastructure License: MPL-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.PykhKy/_old 2025-08-04 15:23:30.930684942 +0200 +++ /var/tmp/diff_new_pack.PykhKy/_new 2025-08-04 15:23:30.934685113 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/opentofu/opentofu/</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v1.10.4</param> + <param name="revision">v1.10.5</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.PykhKy/_old 2025-08-04 15:23:30.958686135 +0200 +++ /var/tmp/diff_new_pack.PykhKy/_new 2025-08-04 15:23:30.962686306 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/opentofu/opentofu/</param> - <param name="changesrevision">6d6c2fa96497c15fd8d0b46dc8db0e6877a88b1b</param></service></servicedata> + <param name="changesrevision">20e08688ca2891c0d9398fbc3714aa4847f2cfb3</param></service></servicedata> (No newline at EOF) ++++++ opentofu-1.10.4.obscpio -> opentofu-1.10.5.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentofu-1.10.4/CHANGELOG.md new/opentofu-1.10.5/CHANGELOG.md --- old/opentofu-1.10.4/CHANGELOG.md 2025-07-31 15:22:01.000000000 +0200 +++ new/opentofu-1.10.5/CHANGELOG.md 2025-08-01 16:20:32.000000000 +0200 @@ -1,6 +1,13 @@ -## 1.10.4 (unreleased) +## 1.10.6 (unreleased) -## 1.10.3 +## 1.10.5 + +BUG FIXES: + +- Fixed issue where usage of TF_PLUGIN_CACHE_DIR could result in unexpected lock contention errors ([#3090](https://github.com/opentofu/opentofu/pull/3090)) + - NOTE: It is still highly recommended to have valid .terraform.lock.hcl files in projects using TF_PLUGIN_CACHE_DIR + +## 1.10.4 BUG FIXES: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentofu-1.10.4/internal/command/init.go new/opentofu-1.10.5/internal/command/init.go --- old/opentofu-1.10.4/internal/command/init.go 2025-07-31 15:22:01.000000000 +0200 +++ new/opentofu-1.10.5/internal/command/init.go 2025-08-01 16:20:32.000000000 +0200 @@ -905,6 +905,9 @@ c.Ui.Info(fmt.Sprintf("- Installed %s v%s (%s%s)", provider.ForDisplay(), version, authResult, keyID)) } }, + CacheDirLockContended: func(cacheDir string) { + c.Ui.Info(fmt.Sprintf("- Waiting for lock on cache directory %s", cacheDir)) + }, ProvidersLockUpdated: func(provider addrs.Provider, version getproviders.Version, localHashes []getproviders.Hash, signedHashes []getproviders.Hash, priorHashes []getproviders.Hash) { // We're going to use this opportunity to track if we have any // "incomplete" installs of providers. An incomplete install is diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentofu-1.10.4/internal/flock/filesystem_lock_unix.go new/opentofu-1.10.5/internal/flock/filesystem_lock_unix.go --- old/opentofu-1.10.4/internal/flock/filesystem_lock_unix.go 2025-07-31 15:22:01.000000000 +0200 +++ new/opentofu-1.10.5/internal/flock/filesystem_lock_unix.go 2025-08-01 16:20:32.000000000 +0200 @@ -9,6 +9,8 @@ package flock import ( + "context" + "fmt" "io" "os" "syscall" @@ -27,6 +29,66 @@ return syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, flock) } +// LockBlocking is like Lock except that if the lock is currently contended +// then it blocks until it becomes available. +// +// If the given context is cancelled then it returns early with the cancellation +// error. +func LockBlocking(ctx context.Context, f *os.File) error { + flock := &syscall.Flock_t{ + Type: syscall.F_RDLCK | syscall.F_WRLCK, + Whence: int16(io.SeekStart), + Start: 0, + Len: 0, + } + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + c := make(chan error) + go func() { + for { + err := syscall.FcntlFlock(f.Fd(), syscall.F_SETLKW, flock) + if err == syscall.EINTR { + // We'll get here if our process gets any signal at all, but + // not all signals represent cancellation. + if ctxErr := ctx.Err(); ctxErr != nil { + err = ctxErr // return the cancellation error instead of generic EINTR + } else { + continue // not cancelled yet + } + } + c <- err + close(c) + return + } + }() + + for { + select { + case err := <-c: + return err + case <-ctx.Done(): + // We will get here if the cancellation is caused by anything other + // than a Unix signal, in which case we'll send a signal ourselves + // to force the waiting goroutine to exit. + // We use SIGUSR1 here on the assumption that nothing else in + // OpenTofu uses it. We're sending this to the current pid + // explicitly because we might have other processes, such as + // plugins, also running in our process group (which is what we'd + // signal if using pid 0 here). + err := syscall.Kill(syscall.Getpid(), syscall.SIGUSR1) + if err != nil { + // This should not fail, but if it does then we'd otherwise + // get hung up here and so we'll return an error and accept + // that our background goroutine is going to just hang around + // until another signal shows up or the program exits. + return fmt.Errorf("failed canceling lock acquisition: %w", err) + } + } + } +} + func Unlock(f *os.File) error { flock := &syscall.Flock_t{ Type: syscall.F_UNLCK, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentofu-1.10.4/internal/flock/filesystem_lock_windows.go new/opentofu-1.10.5/internal/flock/filesystem_lock_windows.go --- old/opentofu-1.10.4/internal/flock/filesystem_lock_windows.go 2025-07-31 15:22:01.000000000 +0200 +++ new/opentofu-1.10.5/internal/flock/filesystem_lock_windows.go 2025-08-01 16:20:32.000000000 +0200 @@ -9,9 +9,12 @@ package flock import ( + "context" + "errors" "math" "os" "syscall" + "time" "unsafe" ) @@ -26,6 +29,8 @@ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx _LOCKFILE_FAIL_IMMEDIATELY = 1 _LOCKFILE_EXCLUSIVE_LOCK = 2 + // https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- + ERROR_LOCK_VIOLATION = 33 ) // This still alows the file handle to be opened by another process for competing locks on the same file. @@ -48,6 +53,44 @@ ) } +// This is a poor implementation of blocking locks, but it a somewhat function patch for the moment. +// This should eventually be tweaked to use native windows locking. +// See https://github.com/opentofu/opentofu/issues/3089 for more details. +func LockBlocking(ctx context.Context, f *os.File) error { + resultChan := make(chan error) + + go func() { + for { + err := Lock(f) + if err == nil { + // Lock succeeded + resultChan <- nil + return + } + + select { + case <-ctx.Done(): + // Lock cancelled, so return cancellation error + resultChan <- ctx.Err() + return + default: + // LockFileEx returns this error when the lock is contended. + var errno syscall.Errno + ok := errors.As(err, &errno) + if ok && errno == ERROR_LOCK_VIOLATION { + // Chill for a bit before trying again + time.Sleep(100 * time.Millisecond) + continue + } + // All other errors are fatal. + resultChan <- err + } + } + }() + + return <-resultChan +} + func Unlock(*os.File) error { // the lock is released when Close() is called return nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentofu-1.10.4/internal/providercache/dir_modify.go new/opentofu-1.10.5/internal/providercache/dir_modify.go --- old/opentofu-1.10.4/internal/providercache/dir_modify.go 2025-07-31 15:22:01.000000000 +0200 +++ new/opentofu-1.10.5/internal/providercache/dir_modify.go 2025-08-01 16:20:32.000000000 +0200 @@ -151,34 +151,25 @@ return nil, err } - // Wait for the file lock for up to 60s. Might make sense to have the timeout be configurable for different network conditions / package sizes. - for timeout := time.After(time.Second * 60); ; { - // We have a valid file handle, let's try to lock it (nonblocking) - err := flock.Lock(f) - if err == nil { - // Lock succeeded - break - } - - select { - case <-timeout: - if f != nil { - f.Close() - } - return nil, fmt.Errorf("unable to acquire file lock on %q: %w", lockFile, err) - case <-ctx.Done(): - if f != nil { - f.Close() - } - return nil, ctx.Err() - default: - // Chill for a bit before trying again - time.Sleep(100 * time.Millisecond) - } - + // If the callers InstallerEvents has a hook function for + // CacheDirLockContended then we'll notify it if we take more than five + // seconds to acquire the lock, to give some feedback about what's causing + // delay here. 5 seconds is an arbitrary amount that's short enough to + // give relatively prompt feedback but long enough to be reasonably + // confident that a delay here is caused by lock contention. + evts := installerEventsForContext(ctx) + if evts.CacheDirLockContended != nil { + cancelWhenSlow := whenSlow(5*time.Second, func() { + evts.CacheDirLockContended(d.BasePath()) + }) + defer cancelWhenSlow() } - log.Printf("[TRACE] Acquired global provider lock %s", lockFile) + err = flock.LockBlocking(ctx, f) + if err != nil { + // Ensure that we are not in a partially failed state + return nil, fmt.Errorf("unable to acquire file lock on %q: %w", lockFile, err) + } return func() error { log.Printf("[TRACE] Releasing global provider lock %s", lockFile) @@ -193,3 +184,17 @@ return unlockErr }, nil } + +func whenSlow(dur time.Duration, f func()) (cancel func()) { + cancelCh := make(chan struct{}) + go func() { + select { + case <-cancelCh: + case <-time.After(dur): + f() + } + }() + return func() { + close(cancelCh) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentofu-1.10.4/internal/providercache/installer_events.go new/opentofu-1.10.5/internal/providercache/installer_events.go --- old/opentofu-1.10.4/internal/providercache/installer_events.go 2025-07-31 15:22:01.000000000 +0200 +++ new/opentofu-1.10.5/internal/providercache/installer_events.go 2025-08-01 16:20:32.000000000 +0200 @@ -112,6 +112,11 @@ FetchPackageSuccess func(provider addrs.Provider, version getproviders.Version, localDir string, authResult *getproviders.PackageAuthenticationResult) FetchPackageFailure func(provider addrs.Provider, version getproviders.Version, err error) + // CacheDirLockContended is called if acquiring a lock on the specified + // cache directory takes more than a few seconds, suggesting that some + // other process is already holding a lock. + CacheDirLockContended func(cacheDir string) + // The ProvidersLockUpdated event is called whenever the lock file will be // updated. It provides the following information: // diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opentofu-1.10.4/version/VERSION new/opentofu-1.10.5/version/VERSION --- old/opentofu-1.10.4/version/VERSION 2025-07-31 15:22:01.000000000 +0200 +++ new/opentofu-1.10.5/version/VERSION 2025-08-01 16:20:32.000000000 +0200 @@ -1 +1 @@ -1.10.4 +1.10.5 ++++++ opentofu.obsinfo ++++++ --- /var/tmp/diff_new_pack.PykhKy/_old 2025-08-04 15:23:33.074776336 +0200 +++ /var/tmp/diff_new_pack.PykhKy/_new 2025-08-04 15:23:33.078776506 +0200 @@ -1,5 +1,5 @@ name: opentofu -version: 1.10.4 -mtime: 1753968121 -commit: 6d6c2fa96497c15fd8d0b46dc8db0e6877a88b1b +version: 1.10.5 +mtime: 1754058032 +commit: 20e08688ca2891c0d9398fbc3714aa4847f2cfb3 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/opentofu/vendor.tar.gz /work/SRC/openSUSE:Factory/.opentofu.new.1085/vendor.tar.gz differ: char 20, line 1