From 232eeee206df090448c3f8889b3430c6f3c42632 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Tue, 23 Mar 2021 10:27:53 -0400 Subject: [PATCH] less blocking on fact reading (#73951) * less blocking on fact reading Co-authored-by: Martin Krizek --- changelogs/fragments/less_blocks_on_facts.yml | 2 + lib/ansible/module_utils/facts/utils.py | 41 ++++++++++++++----- 2 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/less_blocks_on_facts.yml diff --git a/changelogs/fragments/less_blocks_on_facts.yml b/changelogs/fragments/less_blocks_on_facts.yml new file mode 100644 index 00000000000..68407df122d --- /dev/null +++ b/changelogs/fragments/less_blocks_on_facts.yml @@ -0,0 +1,2 @@ +bugfixes: + - Try to avoid kernel 'blocking' state on reading files while fact gathering. diff --git a/lib/ansible/module_utils/facts/utils.py b/lib/ansible/module_utils/facts/utils.py index 9fd00afd49d..08d59c036f3 100644 --- a/lib/ansible/module_utils/facts/utils.py +++ b/lib/ansible/module_utils/facts/utils.py @@ -16,26 +16,47 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +import fcntl import os def get_file_content(path, default=None, strip=True): + ''' + Return the contents of a given file path + + :args path: path to file to return contents from + :args default: value to return if we could not read file + :args strip: controls if we strip whitespace from the result or not + + :returns: String with file contents (optionally stripped) or 'default' value + ''' data = default if os.path.exists(path) and os.access(path, os.R_OK): try: + datafile = open(path) try: - datafile = open(path) - data = datafile.read() - if strip: - data = data.strip() - if len(data) == 0: - data = default - finally: - datafile.close() + # try to not enter kernel 'block' mode, which prevents timeouts + fd = datafile.fileno() + flag = fcntl.fcntl(fd, fcntl.F_GETFL) + fcntl.fcntl(fd, fcntl.F_SETFL, flag | os.O_NONBLOCK) + except Exception: + pass # not required to operate, but would have been nice! + + # actually read the data + data = datafile.read() + + if strip: + data = data.strip() + + if len(data) == 0: + data = default + except Exception: - # ignore errors as some jails/containers might have readable permissions but not allow reads to proc - # done in 2 blocks for 2.4 compat + # ignore errors as some jails/containers might have readable permissions but not allow reads pass + finally: + datafile.close() + return data