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
This commit is contained in:
Austin S. Hemmelgarn 2017-12-13 12:10:19 -05:00 committed by Adam Miller
parent bf29cc79a6
commit 50ceb8d7d8

View file

@ -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)