|
|
|
@ -32,7 +32,17 @@ BOOLEANS_TRUE = ['y', 'yes', 'on', '1', 'true', 1, True]
|
|
|
|
|
BOOLEANS_FALSE = ['n', 'no', 'off', '0', 'false', 0, False]
|
|
|
|
|
BOOLEANS = BOOLEANS_TRUE + BOOLEANS_FALSE
|
|
|
|
|
|
|
|
|
|
SIZE_RANGES = { 'Y': 1<<80, 'Z': 1<<70, 'E': 1<<60, 'P': 1<<50, 'T': 1<<40, 'G': 1<<30, 'M': 1<<20, 'K': 1<<10, 'B': 1 }
|
|
|
|
|
SIZE_RANGES = {
|
|
|
|
|
'Y': 1 << 80,
|
|
|
|
|
'Z': 1 << 70,
|
|
|
|
|
'E': 1 << 60,
|
|
|
|
|
'P': 1 << 50,
|
|
|
|
|
'T': 1 << 40,
|
|
|
|
|
'G': 1 << 30,
|
|
|
|
|
'M': 1 << 20,
|
|
|
|
|
'K': 1 << 10,
|
|
|
|
|
'B': 1,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FILE_ATTRIBUTES = {
|
|
|
|
|
'A': 'noatime',
|
|
|
|
@ -161,8 +171,16 @@ except ImportError:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
from ansible.module_utils.pycompat24 import get_exception, literal_eval
|
|
|
|
|
from ansible.module_utils.six import (PY2, PY3, b, binary_type, integer_types,
|
|
|
|
|
iteritems, text_type, string_types)
|
|
|
|
|
from ansible.module_utils.six import (
|
|
|
|
|
PY2,
|
|
|
|
|
PY3,
|
|
|
|
|
b,
|
|
|
|
|
binary_type,
|
|
|
|
|
integer_types,
|
|
|
|
|
iteritems,
|
|
|
|
|
string_types,
|
|
|
|
|
text_type,
|
|
|
|
|
)
|
|
|
|
|
from ansible.module_utils.six.moves import map, reduce, shlex_quote
|
|
|
|
|
from ansible.module_utils._text import to_native, to_bytes, to_text
|
|
|
|
|
|
|
|
|
@ -242,6 +260,7 @@ def get_platform():
|
|
|
|
|
''' what's the platform? example: Linux is a platform. '''
|
|
|
|
|
return platform.system()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_distribution():
|
|
|
|
|
''' return the distribution name '''
|
|
|
|
|
if platform.system() == 'Linux':
|
|
|
|
@ -261,6 +280,7 @@ def get_distribution():
|
|
|
|
|
distribution = None
|
|
|
|
|
return distribution
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_distribution_version():
|
|
|
|
|
''' return the distribution version '''
|
|
|
|
|
if platform.system() == 'Linux':
|
|
|
|
@ -275,6 +295,7 @@ def get_distribution_version():
|
|
|
|
|
distribution_version = None
|
|
|
|
|
return distribution_version
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_all_subclasses(cls):
|
|
|
|
|
'''
|
|
|
|
|
used by modules like Hardware or Network fact classes to retrieve all subclasses of a given class.
|
|
|
|
@ -338,6 +359,7 @@ def json_dict_unicode_to_bytes(d, encoding='utf-8', errors='surrogate_or_strict'
|
|
|
|
|
else:
|
|
|
|
|
return d
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def json_dict_bytes_to_unicode(d, encoding='utf-8', errors='surrogate_or_strict'):
|
|
|
|
|
''' Recursively convert dict keys and values to byte str
|
|
|
|
|
|
|
|
|
@ -357,6 +379,7 @@ def json_dict_bytes_to_unicode(d, encoding='utf-8', errors='surrogate_or_strict'
|
|
|
|
|
else:
|
|
|
|
|
return d
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def return_values(obj):
|
|
|
|
|
""" Return native stringified values from datastructures.
|
|
|
|
|
|
|
|
|
@ -381,6 +404,7 @@ def return_values(obj):
|
|
|
|
|
else:
|
|
|
|
|
raise TypeError('Unknown parameter type: %s, %s' % (type(obj), obj))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def remove_values(value, no_log_strings):
|
|
|
|
|
""" Remove strings in no_log_strings from value. If value is a container
|
|
|
|
|
type, then remove a lot more"""
|
|
|
|
@ -489,6 +513,7 @@ def heuristic_log_sanitize(data, no_log_values=None):
|
|
|
|
|
output = remove_values(output, no_log_values)
|
|
|
|
|
return output
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bytes_to_human(size, isbits=False, unit=None):
|
|
|
|
|
|
|
|
|
|
base = 'Bytes'
|
|
|
|
@ -507,6 +532,7 @@ def bytes_to_human(size, isbits=False, unit=None):
|
|
|
|
|
|
|
|
|
|
return '%.2f %s' % (float(size) / limit, suffix)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def human_to_bytes(number, default_unit=None, isbits=False):
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
@ -555,6 +581,7 @@ def human_to_bytes(number, default_unit=None, isbits=False):
|
|
|
|
|
|
|
|
|
|
return int(round(num * limit))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_executable(path):
|
|
|
|
|
'''is the given path executable?
|
|
|
|
|
|
|
|
|
@ -568,6 +595,7 @@ def is_executable(path):
|
|
|
|
|
# execute bits are set.
|
|
|
|
|
return ((stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) & os.stat(path)[stat.ST_MODE])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _load_params():
|
|
|
|
|
''' read the modules parameters and store them globally.
|
|
|
|
|
|
|
|
|
@ -623,6 +651,7 @@ def _load_params():
|
|
|
|
|
'"failed": true}')
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def env_fallback(*args, **kwargs):
|
|
|
|
|
''' Load value from environment '''
|
|
|
|
|
for arg in args:
|
|
|
|
@ -631,6 +660,7 @@ def env_fallback(*args, **kwargs):
|
|
|
|
|
else:
|
|
|
|
|
raise AnsibleFallbackNotFound
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _lenient_lowercase(lst):
|
|
|
|
|
"""Lowercase elements of a list.
|
|
|
|
|
|
|
|
|
@ -644,6 +674,7 @@ def _lenient_lowercase(lst):
|
|
|
|
|
lowered.append(value)
|
|
|
|
|
return lowered
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def format_attributes(attributes):
|
|
|
|
|
attribute_list = []
|
|
|
|
|
for attr in attributes:
|
|
|
|
@ -651,6 +682,7 @@ def format_attributes(attributes):
|
|
|
|
|
attribute_list.append(FILE_ATTRIBUTES[attr])
|
|
|
|
|
return attribute_list
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_flags_from_attributes(attributes):
|
|
|
|
|
flags = []
|
|
|
|
|
for key, attr in FILE_ATTRIBUTES.items():
|
|
|
|
@ -658,6 +690,7 @@ def get_flags_from_attributes(attributes):
|
|
|
|
|
flags.append(key)
|
|
|
|
|
return ''.join(flags)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AnsibleFallbackNotFound(Exception):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
@ -834,7 +867,6 @@ class AnsibleModule(object):
|
|
|
|
|
selevel=selevel, secontext=secontext, attributes=attributes,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Detect whether using selinux that is MLS-aware.
|
|
|
|
|
# While this means you can set the level/range with
|
|
|
|
|
# selinux.lsetfilecon(), it may or may not mean that you
|
|
|
|
@ -1194,7 +1226,6 @@ class AnsibleModule(object):
|
|
|
|
|
pass
|
|
|
|
|
return output
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _symbolic_mode_to_octal(self, path_stat, symbolic_mode):
|
|
|
|
|
new_mode = stat.S_IMODE(path_stat.st_mode)
|
|
|
|
|
|
|
|
|
@ -1247,13 +1278,13 @@ class AnsibleModule(object):
|
|
|
|
|
X_perms = {
|
|
|
|
|
'u': {'X': stat.S_IXUSR},
|
|
|
|
|
'g': {'X': stat.S_IXGRP},
|
|
|
|
|
'o': {'X': stat.S_IXOTH}
|
|
|
|
|
'o': {'X': stat.S_IXOTH},
|
|
|
|
|
}
|
|
|
|
|
else:
|
|
|
|
|
X_perms = {
|
|
|
|
|
'u': {'X': 0},
|
|
|
|
|
'g': {'X': 0},
|
|
|
|
|
'o': {'X': 0}
|
|
|
|
|
'o': {'X': 0},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
user_perms_to_modes = {
|
|
|
|
@ -1265,7 +1296,8 @@ class AnsibleModule(object):
|
|
|
|
|
't': 0,
|
|
|
|
|
'u': prev_mode & stat.S_IRWXU,
|
|
|
|
|
'g': (prev_mode & stat.S_IRWXG) << 3,
|
|
|
|
|
'o': (prev_mode & stat.S_IRWXO) << 6 },
|
|
|
|
|
'o': (prev_mode & stat.S_IRWXO) << 6,
|
|
|
|
|
},
|
|
|
|
|
'g': {
|
|
|
|
|
'r': stat.S_IRGRP,
|
|
|
|
|
'w': stat.S_IWGRP,
|
|
|
|
@ -1274,7 +1306,8 @@ class AnsibleModule(object):
|
|
|
|
|
't': 0,
|
|
|
|
|
'u': (prev_mode & stat.S_IRWXU) >> 3,
|
|
|
|
|
'g': prev_mode & stat.S_IRWXG,
|
|
|
|
|
'o': (prev_mode & stat.S_IRWXO) << 3 },
|
|
|
|
|
'o': (prev_mode & stat.S_IRWXO) << 3,
|
|
|
|
|
},
|
|
|
|
|
'o': {
|
|
|
|
|
'r': stat.S_IROTH,
|
|
|
|
|
'w': stat.S_IWOTH,
|
|
|
|
@ -1283,14 +1316,17 @@ class AnsibleModule(object):
|
|
|
|
|
't': stat.S_ISVTX,
|
|
|
|
|
'u': (prev_mode & stat.S_IRWXU) >> 6,
|
|
|
|
|
'g': (prev_mode & stat.S_IRWXG) >> 3,
|
|
|
|
|
'o': prev_mode & stat.S_IRWXO }
|
|
|
|
|
'o': prev_mode & stat.S_IRWXO,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Insert X_perms into user_perms_to_modes
|
|
|
|
|
for key, value in X_perms.items():
|
|
|
|
|
user_perms_to_modes[key].update(value)
|
|
|
|
|
|
|
|
|
|
or_reduce = lambda mode, perm: mode | user_perms_to_modes[user][perm]
|
|
|
|
|
def or_reduce(mode, perm):
|
|
|
|
|
return mode | user_perms_to_modes[user][perm]
|
|
|
|
|
|
|
|
|
|
return reduce(or_reduce, perms, 0)
|
|
|
|
|
|
|
|
|
|
def set_fs_attributes_if_different(self, file_args, changed, diff=None, expand=True):
|
|
|
|
@ -1703,14 +1739,12 @@ class AnsibleModule(object):
|
|
|
|
|
def _check_type_raw(self, value):
|
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _check_type_bytes(self, value):
|
|
|
|
|
try:
|
|
|
|
|
self.human_to_bytes(value)
|
|
|
|
|
except ValueError:
|
|
|
|
|
raise TypeError('%s cannot be converted to a Byte value' % type(value))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _check_type_bits(self, value):
|
|
|
|
|
try:
|
|
|
|
|
self.human_to_bytes(value, isbits=True)
|
|
|
|
@ -1773,7 +1807,7 @@ class AnsibleModule(object):
|
|
|
|
|
self.params[k] = default
|
|
|
|
|
|
|
|
|
|
def _set_fallbacks(self):
|
|
|
|
|
for k,v in self.argument_spec.items():
|
|
|
|
|
for (k, v) in self.argument_spec.items():
|
|
|
|
|
fallback = v.get('fallback', (None,))
|
|
|
|
|
fallback_strategy = fallback[0]
|
|
|
|
|
fallback_args = []
|
|
|
|
@ -1863,9 +1897,7 @@ class AnsibleModule(object):
|
|
|
|
|
if self.boolean(no_log):
|
|
|
|
|
log_args[param] = 'NOT_LOGGING_PARAMETER'
|
|
|
|
|
# try to capture all passwords/passphrase named fields missed by no_log
|
|
|
|
|
elif PASSWORD_MATCH.search(param) and \
|
|
|
|
|
arg_opts.get('type', 'str') != 'bool' and \
|
|
|
|
|
not arg_opts.get('choices', False):
|
|
|
|
|
elif PASSWORD_MATCH.search(param) and arg_opts.get('type', 'str') != 'bool' and not arg_opts.get('choices', False):
|
|
|
|
|
# skip boolean and enums as they are about 'password' state
|
|
|
|
|
log_args[param] = 'NOT_LOGGING_PASSWORD'
|
|
|
|
|
self.warn('Module did not set no_log for %s' % param)
|
|
|
|
@ -1885,7 +1917,6 @@ class AnsibleModule(object):
|
|
|
|
|
|
|
|
|
|
self.log(msg, log_args=log_args)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _set_cwd(self):
|
|
|
|
|
try:
|
|
|
|
|
cwd = os.getcwd()
|
|
|
|
@ -2011,7 +2042,7 @@ class AnsibleModule(object):
|
|
|
|
|
def exit_json(self, **kwargs):
|
|
|
|
|
''' return from the module, without error '''
|
|
|
|
|
|
|
|
|
|
if not 'changed' in kwargs:
|
|
|
|
|
if 'changed' not in kwargs:
|
|
|
|
|
kwargs['changed'] = False
|
|
|
|
|
|
|
|
|
|
self.do_cleanup_files()
|
|
|
|
@ -2024,7 +2055,7 @@ class AnsibleModule(object):
|
|
|
|
|
assert 'msg' in kwargs, "implementation error -- msg to explain the error is required"
|
|
|
|
|
kwargs['failed'] = True
|
|
|
|
|
|
|
|
|
|
if not 'changed' in kwargs:
|
|
|
|
|
if 'changed' not in kwargs:
|
|
|
|
|
kwargs['changed'] = False
|
|
|
|
|
|
|
|
|
|
self.do_cleanup_files()
|
|
|
|
@ -2261,7 +2292,6 @@ class AnsibleModule(object):
|
|
|
|
|
e = get_exception()
|
|
|
|
|
self.fail_json(msg='Could not write data to file (%s) from (%s): %s' % (dest, src, e), exception=traceback.format_exc())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _read_from_pipes(self, rpipes, rfds, file_descriptor):
|
|
|
|
|
data = b('')
|
|
|
|
|
if file_descriptor in rfds:
|
|
|
|
@ -2387,9 +2417,9 @@ class AnsibleModule(object):
|
|
|
|
|
# Clean out python paths set by ansiballz
|
|
|
|
|
if 'PYTHONPATH' in os.environ:
|
|
|
|
|
pypaths = os.environ['PYTHONPATH'].split(':')
|
|
|
|
|
pypaths = [x for x in pypaths \
|
|
|
|
|
if not x.endswith('/ansible_modlib.zip') \
|
|
|
|
|
and not x.endswith('/debug_dir')]
|
|
|
|
|
pypaths = [x for x in pypaths
|
|
|
|
|
if not x.endswith('/ansible_modlib.zip') and
|
|
|
|
|
not x.endswith('/debug_dir')]
|
|
|
|
|
os.environ['PYTHONPATH'] = ':'.join(pypaths)
|
|
|
|
|
if not os.environ['PYTHONPATH']:
|
|
|
|
|
del os.environ['PYTHONPATH']
|
|
|
|
|