diff --git a/changelogs/fragments/fix-lookup-password-lock-acquisition.yml b/changelogs/fragments/fix-lookup-password-lock-acquisition.yml new file mode 100644 index 00000000000..9152917a53b --- /dev/null +++ b/changelogs/fragments/fix-lookup-password-lock-acquisition.yml @@ -0,0 +1,2 @@ +bugfixes: + - password lookup - fix acquiring the lock when human-readable FileExistsError error message is not English. diff --git a/lib/ansible/plugins/lookup/password.py b/lib/ansible/plugins/lookup/password.py index 84894e21e9a..73b34891145 100644 --- a/lib/ansible/plugins/lookup/password.py +++ b/lib/ansible/plugins/lookup/password.py @@ -126,6 +126,7 @@ _raw: elements: str """ +import contextlib import os import string import time @@ -269,15 +270,12 @@ def _get_lock(b_path): b_pathdir = os.path.dirname(b_path) lockfile_name = to_bytes("%s.ansible_lockfile" % hashlib.sha1(b_path).hexdigest()) lockfile = os.path.join(b_pathdir, lockfile_name) - if not os.path.exists(lockfile) and b_path != to_bytes('/dev/null'): - try: - makedirs_safe(b_pathdir, mode=0o700) + if b_path != b'/dev/null': + makedirs_safe(b_pathdir, mode=0o700) + with contextlib.suppress(FileExistsError): fd = os.open(lockfile, os.O_CREAT | os.O_EXCL) os.close(fd) first_process = True - except OSError as e: - if e.strerror != 'File exists': - raise counter = 0 # if the lock is got by other process, wait until it's released diff --git a/test/units/plugins/lookup/test_password.py b/test/units/plugins/lookup/test_password.py index 46c63db6032..cd123e88c91 100644 --- a/test/units/plugins/lookup/test_password.py +++ b/test/units/plugins/lookup/test_password.py @@ -466,11 +466,16 @@ class TestLookupModuleWithoutPasslib(BaseTestLookupModule): @patch('time.sleep') def test_lock_been_held(self, mock_sleep): # pretend the lock file is here - password.os.path.exists = lambda x: True - with pytest.raises(AnsibleError): - with patch.object(builtins, 'open', mock_open(read_data=b'hunter42 salt=87654321\n')) as m: - # should timeout here - self.password_lookup.run([u'/path/to/somewhere chars=anything'], None) + def _already_exists(*args, **kwargs): + raise FileExistsError("The lock is busy, wait and try again.") + + with ( + pytest.raises(AnsibleError, match='^Password lookup cannot get the lock in 7 seconds.*'), + patch.object(password.os, 'open', _already_exists), + patch.object(password.os.path, 'exists', lambda *args, **kwargs: True), + ): + # should timeout here + self.password_lookup.run([u'/path/to/somewhere chars=anything'], None) def test_lock_not_been_held(self): # pretend now there is password file but no lock