From 50ceb8d7d8403616ae6e84cad87d16ea7c0fee3a Mon Sep 17 00:00:00 2001 From: "Austin S. Hemmelgarn" Date: Wed, 13 Dec 2017 12:10:19 -0500 Subject: [PATCH] wait_for: change file check to handle directories and sockets (#20979) open(path) throws an error when called on a directory or UNIX socket, and therefore a check to ensure that the path is absent will always succeed when there is a directory or file located there. This updates the check to use os.access(path, os.F_OK) instead, which instead just checks that the path exists instead of trying to open it as a file, and therefore properly handles directories and sockets. This causes a slight semantic change in how permissions are handled. The existing code will fail to work correctly if the user running the module on the managed host has no read access to the path specified. The new code will work correctly in that situation. Both versions fail if the user can't traverse the parent directory. I've also added a check to the try block to catch OSError. I've seen this call fail with an OSError on rare occasion in the face of odd extended permissions (usually MAC configuration) in cases where it should technically return False. In such cases, the file is functionally inaccessible to the user making the call, so it's essentially not there, but it can't be created by them either. I've documented this, as well as the fact that the bug this change fixes exists, and a rather nasty inconsistency involving symbloic handling that I stumbled across while testing this change. Fixes: #20870 --- lib/ansible/modules/utilities/logic/wait_for.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/ansible/modules/utilities/logic/wait_for.py b/lib/ansible/modules/utilities/logic/wait_for.py index 879b09ad46..8b0b980c9a 100644 --- a/lib/ansible/modules/utilities/logic/wait_for.py +++ b/lib/ansible/modules/utilities/logic/wait_for.py @@ -89,6 +89,12 @@ options: - This overrides the normal error message from a failure to meet the required conditions. notes: - The ability to use search_regex with a port connection was added in 1.7. + - Prior to 2.4, testing for the absense of a directory or UNIX socket did not work correctly. + - Prior to 2.4, testing for the presence of a file did not work correctly if the remote user did not have read access to that file. + - Under some circumstances when using mandatory access control, a path may always be treated as being absent even if it exists, but + can't be modified or created by the remote user either. + - When waiting for a path, symbolic links will be followed. Many other modules that manipulate files do not follow symbolic links, + so operations on the path using other modules may not work exactly as expected. - This module is also supported for Windows targets. - See also M(wait_for_connection) author: @@ -482,10 +488,12 @@ def main(): while datetime.datetime.utcnow() < end: if path: try: - f = open(path) - f.close() + if not os.access(path, os.F_OK): + break except IOError: break + except OSError: + break elif port: try: s = _create_connection(host, port, connect_timeout)