mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Tracebacks are now catchable with ignore_errors and have streamlined output. Also removes 'baby-JSON' for bash modules.
This commit is contained in:
parent
6c6a0f068e
commit
26cdddaebf
9 changed files with 32 additions and 47 deletions
|
@ -3,7 +3,7 @@ Ansible Changes By Release
|
||||||
|
|
||||||
## 1.8 "You Really Got Me" - Active Development
|
## 1.8 "You Really Got Me" - Active Development
|
||||||
|
|
||||||
New core features:
|
Major changes:
|
||||||
|
|
||||||
* fact caching support, pluggable, initially supports Redis (DOCS pending)
|
* fact caching support, pluggable, initially supports Redis (DOCS pending)
|
||||||
* 'serial' size in a rolling update can be specified as a percentage
|
* 'serial' size in a rolling update can be specified as a percentage
|
||||||
|
@ -15,6 +15,7 @@ New core features:
|
||||||
* ansible-galaxy install -f requirements.yml allows advanced options and installs from non-galaxy SCM sources and tarballs.
|
* ansible-galaxy install -f requirements.yml allows advanced options and installs from non-galaxy SCM sources and tarballs.
|
||||||
* command_warnings feature will warn about when usage of the shell/command module can be simplified to use core modules - this can be enabled in ansible.cfg
|
* command_warnings feature will warn about when usage of the shell/command module can be simplified to use core modules - this can be enabled in ansible.cfg
|
||||||
* new omit value can be used to leave off a parameter when not set, like so module_name: a=1 b={{ c | default(omit) }}, would not pass value for b (not even an empty value) if c was not set.
|
* new omit value can be used to leave off a parameter when not set, like so module_name: a=1 b={{ c | default(omit) }}, would not pass value for b (not even an empty value) if c was not set.
|
||||||
|
* developers: 'baby JSON' in module responses, originally intended for writing modules in bash, is removed as a feature to simplify logic, script module remains available for running bash scripts.
|
||||||
|
|
||||||
New Modules:
|
New Modules:
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ New Modules:
|
||||||
|
|
||||||
Some other notable changes:
|
Some other notable changes:
|
||||||
|
|
||||||
|
* if a module should ever traceback, it will return a standard error, catchable by ignore_errors, versus an 'unreachable'
|
||||||
* ec2_lc: added support for multiple new parameters like kernel_id, ramdisk_id and ebs_optimized.
|
* ec2_lc: added support for multiple new parameters like kernel_id, ramdisk_id and ebs_optimized.
|
||||||
* ec2_elb_lb: added support for the connection_draining_timeout and cross_az_load_balancing options.
|
* ec2_elb_lb: added support for the connection_draining_timeout and cross_az_load_balancing options.
|
||||||
* support for symbolic representations (ie. u+rw) for file permission modes (file/copy/template modules etc.).
|
* support for symbolic representations (ie. u+rw) for file permission modes (file/copy/template modules etc.).
|
||||||
|
|
|
@ -493,7 +493,7 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
|
||||||
if returned_msg:
|
if returned_msg:
|
||||||
display("msg: %s" % returned_msg, color='red', runner=self.runner)
|
display("msg: %s" % returned_msg, color='red', runner=self.runner)
|
||||||
if not parsed and module_msg:
|
if not parsed and module_msg:
|
||||||
display("invalid output was: %s" % module_msg, color='red', runner=self.runner)
|
display(module_msg, color='red', runner=self.runner)
|
||||||
if ignore_errors:
|
if ignore_errors:
|
||||||
display("...ignoring", color='cyan', runner=self.runner)
|
display("...ignoring", color='cyan', runner=self.runner)
|
||||||
super(PlaybookRunnerCallbacks, self).on_failed(host, results, ignore_errors=ignore_errors)
|
super(PlaybookRunnerCallbacks, self).on_failed(host, results, ignore_errors=ignore_errors)
|
||||||
|
|
|
@ -138,4 +138,10 @@ class InventoryScript(object):
|
||||||
except OSError, e:
|
except OSError, e:
|
||||||
raise errors.AnsibleError("problem running %s (%s)" % (' '.join(cmd), e))
|
raise errors.AnsibleError("problem running %s (%s)" % (' '.join(cmd), e))
|
||||||
(out, err) = sp.communicate()
|
(out, err) = sp.communicate()
|
||||||
return utils.parse_json(out)
|
if out.strip() == '':
|
||||||
|
return dict()
|
||||||
|
try:
|
||||||
|
return utils.parse_json(out)
|
||||||
|
except ValueError:
|
||||||
|
raise errors.AnsibleError("could not parse post variable response: %s, %s" % (cmd, out))
|
||||||
|
|
||||||
|
|
|
@ -539,7 +539,7 @@ class Runner(object):
|
||||||
cmd2 = conn.shell.remove(tmp, recurse=True)
|
cmd2 = conn.shell.remove(tmp, recurse=True)
|
||||||
self._low_level_exec_command(conn, cmd2, tmp, sudoable=False)
|
self._low_level_exec_command(conn, cmd2, tmp, sudoable=False)
|
||||||
|
|
||||||
data = utils.parse_json(res['stdout'], from_remote=True)
|
data = utils.parse_json(res['stdout'], from_remote=True, no_exceptions=True)
|
||||||
if 'parsed' in data and data['parsed'] == False:
|
if 'parsed' in data and data['parsed'] == False:
|
||||||
data['msg'] += res['stderr']
|
data['msg'] += res['stderr']
|
||||||
return ReturnData(conn=conn, result=data)
|
return ReturnData(conn=conn, result=data)
|
||||||
|
|
|
@ -43,7 +43,7 @@ class ReturnData(object):
|
||||||
self.diff = diff
|
self.diff = diff
|
||||||
|
|
||||||
if type(self.result) in [ str, unicode ]:
|
if type(self.result) in [ str, unicode ]:
|
||||||
self.result = utils.parse_json(self.result, from_remote=True)
|
self.result = utils.parse_json(self.result, from_remote=True, exceptions=False)
|
||||||
|
|
||||||
if self.host is None:
|
if self.host is None:
|
||||||
raise Exception("host not set")
|
raise Exception("host not set")
|
||||||
|
|
|
@ -506,7 +506,7 @@ def _clean_data_struct(orig_data, from_remote=False, from_inventory=False):
|
||||||
data = orig_data
|
data = orig_data
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def parse_json(raw_data, from_remote=False, from_inventory=False):
|
def parse_json(raw_data, from_remote=False, from_inventory=False, no_exceptions=False):
|
||||||
''' this version for module return data only '''
|
''' this version for module return data only '''
|
||||||
|
|
||||||
orig_data = raw_data
|
orig_data = raw_data
|
||||||
|
@ -517,28 +517,10 @@ def parse_json(raw_data, from_remote=False, from_inventory=False):
|
||||||
try:
|
try:
|
||||||
results = json.loads(data)
|
results = json.loads(data)
|
||||||
except:
|
except:
|
||||||
# not JSON, but try "Baby JSON" which allows many of our modules to not
|
if no_exceptions:
|
||||||
# require JSON and makes writing modules in bash much simpler
|
return dict(failed=True, parsed=False, msg=raw_data)
|
||||||
results = {}
|
else:
|
||||||
try:
|
|
||||||
tokens = shlex.split(data)
|
|
||||||
except:
|
|
||||||
print "failed to parse json: "+ data
|
|
||||||
raise
|
raise
|
||||||
for t in tokens:
|
|
||||||
if "=" not in t:
|
|
||||||
raise errors.AnsibleError("failed to parse: %s" % orig_data)
|
|
||||||
(key,value) = t.split("=", 1)
|
|
||||||
if key == 'changed' or 'failed':
|
|
||||||
if value.lower() in [ 'true', '1' ]:
|
|
||||||
value = True
|
|
||||||
elif value.lower() in [ 'false', '0' ]:
|
|
||||||
value = False
|
|
||||||
if key == 'rc':
|
|
||||||
value = int(value)
|
|
||||||
results[key] = value
|
|
||||||
if len(results.keys()) == 0:
|
|
||||||
return { "failed" : True, "parsed" : False, "msg" : orig_data }
|
|
||||||
|
|
||||||
if from_remote:
|
if from_remote:
|
||||||
results = _clean_data_struct(results, from_remote, from_inventory)
|
results = _clean_data_struct(results, from_remote, from_inventory)
|
||||||
|
|
|
@ -37,6 +37,8 @@ EXAMPLES = '''
|
||||||
ansible webservers -m ping
|
ansible webservers -m ping
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
import exceptions
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec = dict(
|
argument_spec = dict(
|
||||||
|
@ -46,6 +48,8 @@ def main():
|
||||||
)
|
)
|
||||||
result = dict(ping='pong')
|
result = dict(ping='pong')
|
||||||
if module.params['data']:
|
if module.params['data']:
|
||||||
|
if module.params['data'] == 'crash':
|
||||||
|
raise exceptions.Exception("boom")
|
||||||
result['ping'] = module.params['data']
|
result['ping'] = module.params['data']
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import traceback
|
||||||
import unittest
|
import unittest
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
@ -217,36 +218,23 @@ class TestUtils(unittest.TestCase):
|
||||||
# leading junk
|
# leading junk
|
||||||
self.assertEqual(ansible.utils.parse_json('ansible\n{"foo": "bar"}'), dict(foo="bar"))
|
self.assertEqual(ansible.utils.parse_json('ansible\n{"foo": "bar"}'), dict(foo="bar"))
|
||||||
|
|
||||||
# "baby" json
|
|
||||||
self.assertEqual(ansible.utils.parse_json('foo=bar baz=qux'), dict(foo='bar', baz='qux'))
|
|
||||||
|
|
||||||
# No closing quotation
|
# No closing quotation
|
||||||
try:
|
try:
|
||||||
ansible.utils.parse_json('foo=bar "')
|
rc = ansible.utils.parse_json('foo=bar "')
|
||||||
|
print rc
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
traceback.print_exc()
|
||||||
raise AssertionError('Incorrect exception, expected ValueError')
|
raise AssertionError('Incorrect exception, expected ValueError')
|
||||||
|
|
||||||
# Failed to parse
|
# Failed to parse
|
||||||
try:
|
try:
|
||||||
ansible.utils.parse_json('{')
|
ansible.utils.parse_json('{')
|
||||||
except ansible.errors.AnsibleError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise AssertionError('Incorrect exception, expected ansible.errors.AnsibleError')
|
raise AssertionError('Incorrect exception, expected ValueError')
|
||||||
|
|
||||||
# boolean changed/failed
|
|
||||||
self.assertEqual(ansible.utils.parse_json('changed=true'), dict(changed=True))
|
|
||||||
self.assertEqual(ansible.utils.parse_json('changed=false'), dict(changed=False))
|
|
||||||
self.assertEqual(ansible.utils.parse_json('failed=true'), dict(failed=True))
|
|
||||||
self.assertEqual(ansible.utils.parse_json('failed=false'), dict(failed=False))
|
|
||||||
|
|
||||||
# rc
|
|
||||||
self.assertEqual(ansible.utils.parse_json('rc=0'), dict(rc=0))
|
|
||||||
|
|
||||||
# Just a string
|
|
||||||
self.assertEqual(ansible.utils.parse_json('foo'), dict(failed=True, parsed=False, msg='foo'))
|
|
||||||
|
|
||||||
def test_parse_yaml(self):
|
def test_parse_yaml(self):
|
||||||
#json
|
#json
|
||||||
|
|
|
@ -34,8 +34,11 @@ if options.host is not None:
|
||||||
if options.extra:
|
if options.extra:
|
||||||
k,v = options.extra.split("=")
|
k,v = options.extra.split("=")
|
||||||
variables[options.host][k] = v
|
variables[options.host][k] = v
|
||||||
print json.dumps(variables[options.host])
|
if options.host in variables:
|
||||||
|
print json.dumps(variables[options.host])
|
||||||
|
else:
|
||||||
|
print "{}"
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
Loading…
Reference in a new issue