mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-05-29 12:29:10 -07:00
Port away from fail_json()
Use an exception to return failures rather than fail_json(). This way we can easily catch the failures if the calling code decides it can deal with it. This has the side effect of making it easier to unittest this code as we can catch the expected exceptions instead of having to catch the interpreter exiting and then parse stdout for the expected data.
This commit is contained in:
parent
fc57f7bd5f
commit
cac11f9b80
1 changed files with 67 additions and 32 deletions
|
@ -142,7 +142,7 @@ class AnsibleModuleError(Exception):
|
||||||
self.results = results
|
self.results = results
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
print('AnsibleModuleError({0})'.format(self.results))
|
print('AnsibleModuleError(results={0})'.format(self.results))
|
||||||
|
|
||||||
|
|
||||||
class ParameterError(AnsibleModuleError):
|
class ParameterError(AnsibleModuleError):
|
||||||
|
@ -177,8 +177,8 @@ def additional_parameter_handling(params):
|
||||||
|
|
||||||
# make sure the target path is a directory when we're doing a recursive operation
|
# make sure the target path is a directory when we're doing a recursive operation
|
||||||
if params['recurse'] and params['state'] != 'directory':
|
if params['recurse'] and params['state'] != 'directory':
|
||||||
raise ParameterError(results={"path": params["path"],
|
raise ParameterError(results={"msg": "recurse option requires state to be 'directory'",
|
||||||
"msg": "recurse option requires state to be 'directory'"})
|
"path": params["path"]})
|
||||||
|
|
||||||
|
|
||||||
def get_state(b_path):
|
def get_state(b_path):
|
||||||
|
@ -270,13 +270,14 @@ def ensure_absent(path, b_path, prev_state):
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(b_path, ignore_errors=False)
|
shutil.rmtree(b_path, ignore_errors=False)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
module.fail_json(msg="rmtree failed: %s" % to_native(e))
|
raise AnsibleModuleError(results={'msg': "rmtree failed: %s" % to_native(e)})
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
os.unlink(b_path)
|
os.unlink(b_path)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno != errno.ENOENT: # It may already have been removed
|
if e.errno != errno.ENOENT: # It may already have been removed
|
||||||
module.fail_json(path=path, msg="unlinking failed: %s " % to_native(e))
|
raise AnsibleModuleError(results={'msg': "unlinking failed: %s " % to_native(e),
|
||||||
|
'path': path})
|
||||||
|
|
||||||
diff = initial_diff(path, 'absent', prev_state)
|
diff = initial_diff(path, 'absent', prev_state)
|
||||||
result.update({'path': path, 'changed': True, 'diff': diff})
|
result.update({'path': path, 'changed': True, 'diff': diff})
|
||||||
|
@ -293,25 +294,31 @@ def execute_touch(path, b_path, prev_state, follow):
|
||||||
try:
|
try:
|
||||||
open(b_path, 'wb').close()
|
open(b_path, 'wb').close()
|
||||||
except (OSError, IOError) as e:
|
except (OSError, IOError) as e:
|
||||||
raise AnsibleModuleError(results={'path': path,
|
raise AnsibleModuleError(results={'msg': 'Error, could not touch target: %s'
|
||||||
'msg': 'Error, could not touch target: %s' % to_native(e, nonstring='simplerepr')})
|
% to_native(e, nonstring='simplerepr'),
|
||||||
|
'path': path})
|
||||||
|
|
||||||
elif prev_state in ('file', 'directory', 'hard'):
|
elif prev_state in ('file', 'directory', 'hard'):
|
||||||
# Update the timestamp if the file already existed
|
# Update the timestamp if the file already existed
|
||||||
try:
|
try:
|
||||||
os.utime(b_path, None)
|
os.utime(b_path, None)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise AnsibleModuleError(results={'path': path, 'msg': 'Error while touching existing target: %s' % to_native(e, nonstring='simplerepr')})
|
raise AnsibleModuleError(results={'msg': 'Error while touching existing target: %s'
|
||||||
|
% to_native(e, nonstring='simplerepr'),
|
||||||
|
'path': path})
|
||||||
|
|
||||||
elif prev_state == 'link' and follow:
|
elif prev_state == 'link' and follow:
|
||||||
b_link_target = os.readlink(b_path)
|
b_link_target = os.readlink(b_path)
|
||||||
try:
|
try:
|
||||||
os.utime(b_link_target, None)
|
os.utime(b_link_target, None)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise AnsibleModuleError(results={'path': path, 'msg': 'Error while touching existing target: %s' % to_native(e, nonstring='simplerepr')})
|
raise AnsibleModuleError(results={'msg': 'Error while touching existing target: %s'
|
||||||
|
% to_native(e, nonstring='simplerepr'),
|
||||||
|
'path': path})
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise AnsibleModuleError(results={'msg': 'Can only touch files, directories, and hardlinks (%s is %s)' % (path, prev_state)})
|
raise AnsibleModuleError(results={'msg': 'Can only touch files, directories, and'
|
||||||
|
' hardlinks (%s is %s)' % (path, prev_state)})
|
||||||
|
|
||||||
# Update the attributes on the file
|
# Update the attributes on the file
|
||||||
diff = initial_diff(path, 'absent', prev_state)
|
diff = initial_diff(path, 'absent', prev_state)
|
||||||
|
@ -343,7 +350,8 @@ def ensure_file_attributes(path, b_path, prev_state, follow):
|
||||||
|
|
||||||
if prev_state not in ('file', 'hard'):
|
if prev_state not in ('file', 'hard'):
|
||||||
# file is not absent and any other state is a conflict
|
# file is not absent and any other state is a conflict
|
||||||
module.fail_json(path=path, msg='file (%s) is %s, cannot continue' % (path, prev_state))
|
raise AnsibleModuleError(results={'msg': 'file (%s) is %s, cannot continue' % (path, prev_state),
|
||||||
|
'path': path})
|
||||||
|
|
||||||
diff = initial_diff(path, 'file', prev_state)
|
diff = initial_diff(path, 'file', prev_state)
|
||||||
changed = module.set_fs_attributes_if_different(file_args, False, diff, expand=False)
|
changed = module.set_fs_attributes_if_different(file_args, False, diff, expand=False)
|
||||||
|
@ -389,11 +397,14 @@ def ensure_directory(path, b_path, prev_state, follow, recurse):
|
||||||
tmp_file_args['path'] = curpath
|
tmp_file_args['path'] = curpath
|
||||||
changed = module.set_fs_attributes_if_different(tmp_file_args, changed, diff, expand=False)
|
changed = module.set_fs_attributes_if_different(tmp_file_args, changed, diff, expand=False)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
module.fail_json(path=path, msg='There was an issue creating %s as requested: %s' % (curpath, to_native(e)))
|
raise AnsibleModuleError(results={'msg': 'There was an issue creating %s as requested:'
|
||||||
|
' %s' % (curpath, to_native(e)),
|
||||||
|
'path': path})
|
||||||
|
|
||||||
# We already know prev_state is not 'absent', therefore it exists in some form.
|
# We already know prev_state is not 'absent', therefore it exists in some form.
|
||||||
elif prev_state != 'directory':
|
elif prev_state != 'directory':
|
||||||
module.fail_json(path=path, msg='%s already exists as a %s' % (path, prev_state))
|
raise AnsibleModuleError(results={'msg': '%s already exists as a %s' % (path, prev_state),
|
||||||
|
'path': path})
|
||||||
|
|
||||||
changed = module.set_fs_attributes_if_different(file_args, changed, diff, expand=False)
|
changed = module.set_fs_attributes_if_different(file_args, changed, diff, expand=False)
|
||||||
|
|
||||||
|
@ -422,16 +433,24 @@ def ensure_symlink(path, b_path, src, b_src, prev_state, follow, force):
|
||||||
absrc = os.path.join(relpath, src)
|
absrc = os.path.join(relpath, src)
|
||||||
b_absrc = to_bytes(absrc, errors='surrogate_or_strict')
|
b_absrc = to_bytes(absrc, errors='surrogate_or_strict')
|
||||||
if not force and not os.path.exists(b_absrc):
|
if not force and not os.path.exists(b_absrc):
|
||||||
module.fail_json(path=path, src=src, msg='src file does not exist, use "force=yes" if you really want to create the link: %s' % absrc)
|
raise AnsibleModuleError(results={'msg': 'src file does not exist, use "force=yes" if you'
|
||||||
|
' really want to create the link: %s' % absrc,
|
||||||
|
'path': path, 'src': src})
|
||||||
|
|
||||||
if prev_state == 'directory':
|
if prev_state == 'directory':
|
||||||
if not force:
|
if not force:
|
||||||
module.fail_json(path=path, msg='refusing to convert from %s to symlink for %s' % (prev_state, path))
|
raise AnsibleModuleError(results={'msg': 'refusing to convert from %s to symlink for %s'
|
||||||
|
% (prev_state, path),
|
||||||
|
'path': path})
|
||||||
elif os.listdir(b_path):
|
elif os.listdir(b_path):
|
||||||
# refuse to replace a directory that has files in it
|
# refuse to replace a directory that has files in it
|
||||||
module.fail_json(path=path, msg='the directory %s is not empty, refusing to convert it' % path)
|
raise AnsibleModuleError(results={'msg': 'the directory %s is not empty, refusing to'
|
||||||
|
' convert it' % path,
|
||||||
|
'path': path})
|
||||||
elif prev_state in ('file', 'hard') and not force:
|
elif prev_state in ('file', 'hard') and not force:
|
||||||
module.fail_json(path=path, msg='refusing to convert from %s to symlink for %s' % (prev_state, path))
|
raise AnsibleModuleError(results={'msg': 'refusing to convert from %s to symlink for %s'
|
||||||
|
% (prev_state, path),
|
||||||
|
'path': path})
|
||||||
|
|
||||||
diff = initial_diff(path, 'link', prev_state)
|
diff = initial_diff(path, 'link', prev_state)
|
||||||
changed = False
|
changed = False
|
||||||
|
@ -447,18 +466,21 @@ def ensure_symlink(path, b_path, src, b_src, prev_state, follow, force):
|
||||||
elif prev_state == 'hard':
|
elif prev_state == 'hard':
|
||||||
changed = True
|
changed = True
|
||||||
if not force:
|
if not force:
|
||||||
module.fail_json(dest=path, src=src, msg='Cannot link, different hard link exists at destination')
|
raise AnsibleModuleError(results={'msg': 'Cannot link, different hard link exists at destination',
|
||||||
|
'dest': path, 'src': src})
|
||||||
elif prev_state == 'file':
|
elif prev_state == 'file':
|
||||||
changed = True
|
changed = True
|
||||||
if not force:
|
if not force:
|
||||||
module.fail_json(dest=path, src=src, msg='Cannot link, %s exists at destination' % prev_state)
|
raise AnsibleModuleError(results={'msg': 'Cannot link, %s exists at destination' % prev_state,
|
||||||
|
'dest': path, 'src': src})
|
||||||
elif prev_state == 'directory':
|
elif prev_state == 'directory':
|
||||||
changed = True
|
changed = True
|
||||||
if os.path.exists(b_path):
|
if os.path.exists(b_path):
|
||||||
if not force:
|
if not force:
|
||||||
module.fail_json(dest=path, src=src, msg='Cannot link, different hard link exists at destination')
|
raise AnsibleModuleError(results={'msg': 'Cannot link, different hard link exists at destination',
|
||||||
|
'dest': path, 'src': src})
|
||||||
else:
|
else:
|
||||||
module.fail_json(dest=path, src=src, msg='unexpected position reached')
|
raise AnsibleModuleError(results={'msg': 'unexpected position reached', 'dest': path, 'src': src})
|
||||||
|
|
||||||
if changed and not module.check_mode:
|
if changed and not module.check_mode:
|
||||||
if prev_state != 'absent':
|
if prev_state != 'absent':
|
||||||
|
@ -474,12 +496,16 @@ def ensure_symlink(path, b_path, src, b_src, prev_state, follow, force):
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if os.path.exists(b_tmppath):
|
if os.path.exists(b_tmppath):
|
||||||
os.unlink(b_tmppath)
|
os.unlink(b_tmppath)
|
||||||
module.fail_json(path=path, msg='Error while replacing: %s' % to_native(e, nonstring='simplerepr'))
|
raise AnsibleModuleError(results={'msg': 'Error while replacing: %s'
|
||||||
|
% to_native(e, nonstring='simplerepr'),
|
||||||
|
'path': path})
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
os.symlink(b_src, b_path)
|
os.symlink(b_src, b_path)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
module.fail_json(path=path, msg='Error while linking: %s' % to_native(e, nonstring='simplerepr'))
|
raise AnsibleModuleError(results={'msg': 'Error while linking: %s'
|
||||||
|
% to_native(e, nonstring='simplerepr'),
|
||||||
|
'path': path})
|
||||||
|
|
||||||
if module.check_mode and not os.path.exists(b_path):
|
if module.check_mode and not os.path.exists(b_path):
|
||||||
module.exit_json(dest=path, src=src, changed=changed, diff=diff)
|
module.exit_json(dest=path, src=src, changed=changed, diff=diff)
|
||||||
|
@ -502,10 +528,10 @@ def ensure_hardlink(path, b_path, src, b_src, prev_state, follow, force):
|
||||||
# or copy module, even if this module never uses it, it is needed to key off some things
|
# or copy module, even if this module never uses it, it is needed to key off some things
|
||||||
if src is None:
|
if src is None:
|
||||||
# Note: Bug: if hard link exists, we shouldn't need to check this
|
# Note: Bug: if hard link exists, we shouldn't need to check this
|
||||||
module.fail_json(msg='src and dest are required for creating hardlinks')
|
raise AnsibleModuleError(results={'msg': 'src and dest are required for creating hardlinks'})
|
||||||
|
|
||||||
if not os.path.isabs(b_src):
|
if not os.path.isabs(b_src):
|
||||||
module.fail_json(msg="absolute paths are required")
|
raise AnsibleModuleError(results={'msg': "absolute paths are required"})
|
||||||
|
|
||||||
if not os.path.islink(b_path) and os.path.isdir(b_path):
|
if not os.path.islink(b_path) and os.path.isdir(b_path):
|
||||||
relpath = path
|
relpath = path
|
||||||
|
@ -516,7 +542,9 @@ def ensure_hardlink(path, b_path, src, b_src, prev_state, follow, force):
|
||||||
absrc = os.path.join(relpath, src)
|
absrc = os.path.join(relpath, src)
|
||||||
b_absrc = to_bytes(absrc, errors='surrogate_or_strict')
|
b_absrc = to_bytes(absrc, errors='surrogate_or_strict')
|
||||||
if not force and not os.path.exists(b_absrc):
|
if not force and not os.path.exists(b_absrc):
|
||||||
module.fail_json(path=path, src=src, msg='src file does not exist, use "force=yes" if you really want to create the link: %s' % absrc)
|
raise AnsibleModuleError(results={'msg': 'src file does not exist, use "force=yes" if you'
|
||||||
|
' really want to create the link: %s' % absrc,
|
||||||
|
'path': path, 'src': src})
|
||||||
|
|
||||||
diff = initial_diff(path, 'hard', prev_state)
|
diff = initial_diff(path, 'hard', prev_state)
|
||||||
changed = False
|
changed = False
|
||||||
|
@ -533,20 +561,23 @@ def ensure_hardlink(path, b_path, src, b_src, prev_state, follow, force):
|
||||||
if not os.stat(b_path).st_ino == os.stat(b_src).st_ino:
|
if not os.stat(b_path).st_ino == os.stat(b_src).st_ino:
|
||||||
changed = True
|
changed = True
|
||||||
if not force:
|
if not force:
|
||||||
module.fail_json(dest=path, src=src, msg='Cannot link, different hard link exists at destination')
|
raise AnsibleModuleError(results={'msg': 'Cannot link, different hard link exists at destination',
|
||||||
|
'dest': path, 'src': src})
|
||||||
elif prev_state == 'file':
|
elif prev_state == 'file':
|
||||||
changed = True
|
changed = True
|
||||||
if not force:
|
if not force:
|
||||||
module.fail_json(dest=path, src=src, msg='Cannot link, %s exists at destination' % prev_state)
|
raise AnsibleModuleError(results={'msg': 'Cannot link, %s exists at destination' % prev_state,
|
||||||
|
'dest': path, 'src': src})
|
||||||
elif prev_state == 'directory':
|
elif prev_state == 'directory':
|
||||||
changed = True
|
changed = True
|
||||||
if os.path.exists(b_path):
|
if os.path.exists(b_path):
|
||||||
if os.stat(b_path).st_ino == os.stat(b_src).st_ino:
|
if os.stat(b_path).st_ino == os.stat(b_src).st_ino:
|
||||||
module.exit_json(path=path, changed=False)
|
module.exit_json(path=path, changed=False)
|
||||||
elif not force:
|
elif not force:
|
||||||
module.fail_json(dest=path, src=src, msg='Cannot link: different hard link exists at destination')
|
raise AnsibleModuleError(results={'msg': 'Cannot link: different hard link exists at destination',
|
||||||
|
'dest': path, 'src': src})
|
||||||
else:
|
else:
|
||||||
module.fail_json(dest=path, src=src, msg='unexpected position reached')
|
raise AnsibleModuleError(results={'msg': 'unexpected position reached', 'dest': path, 'src': src})
|
||||||
|
|
||||||
if changed and not module.check_mode:
|
if changed and not module.check_mode:
|
||||||
if prev_state != 'absent':
|
if prev_state != 'absent':
|
||||||
|
@ -567,12 +598,16 @@ def ensure_hardlink(path, b_path, src, b_src, prev_state, follow, force):
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if os.path.exists(b_tmppath):
|
if os.path.exists(b_tmppath):
|
||||||
os.unlink(b_tmppath)
|
os.unlink(b_tmppath)
|
||||||
module.fail_json(path=path, msg='Error while replacing: %s' % to_native(e, nonstring='simplerepr'))
|
raise AnsibleModuleError(results={'msg': 'Error while replacing: %s'
|
||||||
|
% to_native(e, nonstring='simplerepr'),
|
||||||
|
'path': path})
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
os.link(b_src, b_path)
|
os.link(b_src, b_path)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
module.fail_json(path=path, msg='Error while linking: %s' % to_native(e, nonstring='simplerepr'))
|
raise AnsibleModuleError(results={'msg': 'Error while linking: %s'
|
||||||
|
% to_native(e, nonstring='simplerepr'),
|
||||||
|
'path': path})
|
||||||
|
|
||||||
if module.check_mode and not os.path.exists(b_path):
|
if module.check_mode and not os.path.exists(b_path):
|
||||||
module.exit_json(dest=path, src=src, changed=changed, diff=diff)
|
module.exit_json(dest=path, src=src, changed=changed, diff=diff)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue