Compare commits

...

72 Commits

Author SHA1 Message Date
ebc8d48d34 Version bump for release 1.8.4 2015-02-19 10:29:56 -06:00
5fa7f5b2eb Submodule pointer update for 1.8.4 2015-02-19 10:29:37 -06:00
64d1249598 Removing delegate_to integration tests, since it's not enabled in devel either 2015-02-17 16:19:56 -06:00
2572038f72 Fix bad import from merge conflict resolution in filter_plugins/core.py 2015-02-17 15:37:18 -06:00
37e44bbc14 Version bump for release 1.8.3 2015-02-17 15:19:08 -06:00
cdd1cf5901 Fix the to_nice_yaml filter to always return unicode strings
Fixes #10243
2015-02-17 14:32:33 -06:00
b187676a97 Didn't port isbasestring/isunicodestring from kitchen so switch to isinstance
Conflicts:
	v2/ansible/utils/unicode.py
2015-02-17 14:32:25 -06:00
b9f2ee78c1 Set proper permissions for ansible-vault view 2015-02-17 14:30:57 -06:00
ab35504b51 Fix template module broken when modifying symlinks
Needed to clear unwanted parameters from both args and complex args when
calling file module.

Fixes #10208
2015-02-17 14:30:53 -06:00
920f49f70e fixed issue with prompt == none and su + ask_pass in ssh plugin 2015-02-17 14:30:47 -06:00
55a2d370b0 make su promt AIX compatible
$ su suuser date
suusers's Password:
2015-02-17 14:30:42 -06:00
8be7716064 Close some file handles explicitly in facts.py
Helps control open file descriptor count with pypy (which is used with
one coreos + ansible example).  Part of a fix for
https://github.com/ansible/ansible/issues/10157
2015-02-17 14:26:44 -06:00
0af7e212a8 Obfuscate passwords in more places where it is displayed
Conflicts:
	v2/ansible/module_utils/basic.py
2015-02-17 14:25:41 -06:00
1c56c6a3b7 Ignore errors from shutil.rmtree when removing temporary directory 2015-02-17 14:23:47 -06:00
8c5f7207f0 Use termios instead of stty for compatibility 2015-02-17 14:23:30 -06:00
daa3f2be55 Do not assume that stdin is a tty
This can be used from another non interactive software, see #9695
for details.
2015-02-17 14:23:27 -06:00
31978121e1 correct typo that breaks hashing on python 2.4. 2015-02-17 14:20:34 -06:00
2013d95e53 Correct filter specification 2015-02-17 14:20:29 -06:00
b30cb192e8 Wrap some filters so they return unicode.
The rules are -- if the filter returns str type and the str may contain
non-ascii characters then wrap it to convert to unicode type.  Not
needed if the function already returns unicode type or only returns
ascii characters

Conflicts:
	lib/ansible/runner/filter_plugins/core.py
2015-02-17 14:19:59 -06:00
a1a69d6dc5 Add v2's unicode.py to utils so we can use unicode_wrap in the filter_plugins 2015-02-17 14:03:42 -06:00
d615f2a076 Fix for v1 handling of unicode extra-vars 2015-02-17 14:03:39 -06:00
ad6183a322 Be explicit about unicode str transformation
Fixes #10126
2015-02-17 14:03:34 -06:00
b160026fea fix suggested by @aikomastboom 2015-02-17 14:03:31 -06:00
66e5515f88 Fix for unicode filenames for template module
Fixes #10110
2015-02-17 14:03:27 -06:00
6b315d57d6 ansible.utils to_unicode/to_bytes isn't robust in the face of
non-strings.  Do some value checking in the calling code
2015-02-17 14:03:22 -06:00
71934a118c Another place that needs to be json_dict_bytes_to_unicode
Conflicts:
	v2/ansible/inventory/script.py
2015-02-17 14:03:11 -06:00
1771413c23 Make py2.4 remote checksum large-file-enabled as well
Conflicts:
	v2/ansible/plugins/shell/sh.py
2015-02-17 14:02:02 -06:00
ac0de5a9db jinja2 cannot handle byte strs with non-ascii. So we need to transform potential byte str into unicode type. This fix is for dynamic inventory.
Fixes #10007

Conflicts:
	v2/ansible/inventory/script.py
	v2/ansible/module_utils/basic.py
2015-02-17 14:01:42 -06:00
8b8700d365 do not use with, it is not supported all the way down to 2.4
Conflicts:
	v2/ansible/plugins/shell/sh.py
2015-02-17 14:00:30 -06:00
8150b14d8d fixes #10086
Conflicts:
	v2/ansible/plugins/shell/sh.py
2015-02-17 14:00:07 -06:00
f32e9f0e54 Fix quoting of shell parameters used in remote_checksum and add integration test to detect the error
Fixes #682

Conflicts:
	test/integration/roles/test_unarchive/tasks/main.yml
	v2/ansible/plugins/shell/sh.py
2015-02-17 13:59:08 -06:00
ec2a9cbd11 Do not send stat all the parameters that unarchive received
Fixes #546
2015-02-17 13:40:14 -06:00
d5ff09659f Fix various inventory scripts to use env python
Fix https://github.com/ansible/ansible/issues/9948
2015-02-17 13:40:10 -06:00
30ef52c805 fixed bad exampel for library that was library_path, which of course did
not work
2015-02-17 13:40:07 -06:00
1f34e464ad Use send instead of sendv on the systemd.journal (fixes #9886) 2015-02-17 13:40:03 -06:00
b1f611fedb run_once tasks are skipped without checking the delegate_to host #9784 2015-02-17 13:39:59 -06:00
a16d0a8dd6 Restore json import for redis as well. Switch preference to simplejson for speed 2015-02-17 13:39:55 -06:00
bf656e35e0 facts caching: fix missing json in jsonfile caching 2015-02-17 13:39:51 -06:00
eedd659444 fixed json encoding issue with redis 2015-02-17 13:39:47 -06:00
90ac8d621c Update changelog for the git clone parameter 2015-02-17 13:39:40 -06:00
49d47a8241 git module now with clone parameter and update=no reverted
Conflicts:
	lib/ansible/modules/core
2015-02-17 13:38:49 -06:00
ad823766d2 Strip the line to filter lines composed of only whitespaces
Fix #9395
2015-02-17 13:34:56 -06:00
4fa5db9a03 Variables lookup in a template should handle properly the undefined case 2015-02-17 13:34:52 -06:00
25801f939b Allow retries to be templatable
Fixes #5865
2015-02-17 13:34:49 -06:00
573dbe1775 file does not exist is not an error when checksumming for the template modules 2015-02-17 13:34:45 -06:00
53a94a1fde Fix comment 2015-02-17 13:34:41 -06:00
f6e7f318a2 Fix remote_checksum with delegate_to and add tests for several ways that delegate_to works 2015-02-17 13:34:37 -06:00
fc638fd371 Fix template module to fail if remote checksumming failed 2015-02-17 13:34:33 -06:00
3a68c09888 Fix for delegate_to with hosts that aren't in inventory 2015-02-17 13:34:28 -06:00
dddfc0b9c5 Issue-9704 Better handling of missing python
When they python interpreter is set incorrectly for the machine the file
is being checked for (e.g. for the local or the remote), the error
manifests as a readability or directory missing error which can be very
misleading.
2015-02-17 13:34:24 -06:00
04c8ecce56 Be careful not to set the permissions of the destination of a symlink.
It's up to the module using the set_fs_attributes*/set_mode* methods to
specify the filename of the destination of the symlink if that's really
the file that should be modified.

Half of the fix for:
https://github.com/ansible/ansible-modules-core/issues/778
2015-02-17 13:26:02 -06:00
6f568bd649 Version bump for release 1.8.2 2014-12-04 17:08:36 -06:00
1545c73d27 Make test for skipping agree with the way current output formats a skip 2014-12-04 16:10:34 -06:00
bff88271ee fixed integration test as with_items always returns a list, even if
empty
2014-12-04 16:09:58 -06:00
b9f1503870 Merge pull request #9715 from bcoca/listify_revert_errorhandling
Listify revert errorhandling
2014-12-04 16:09:28 -06:00
ecdeed4342 changed plugin load priority to be path based, not suffix based. 2014-12-04 16:07:32 -06:00
e81a6da49b Fix checksum code to work with delegate_to/local_action
Fixes #9704
2014-12-04 16:02:54 -06:00
0a52913dfa Have remote_expanduser honor sudo and su users.
Fixes #9663
2014-12-04 16:00:04 -06:00
1393272632 Use more variable sources when templating the play ds
Fixes #9699
2014-12-04 15:59:14 -06:00
4cd87ec93e Revise patch from earlier using even more variable sources for HostVars
Superceeds e61e8a3

Fixes #9684
2014-12-04 15:59:09 -06:00
8dd3d84250 Fix PowerShell plugin issues affecting fetch module when used against Windows hosts. 2014-12-04 15:59:04 -06:00
e728ff97d9 Use additional vars when templating included file names
Fixes #9669
2014-12-04 15:59:00 -06:00
2f1e78ffee Use extra vars when creating HostVars
Fixes #9667
2014-12-04 15:58:55 -06:00
38e2757c85 Need to include extras in setup to accomodate future windows extras modules 2014-12-04 15:58:51 -06:00
d68add651e Make sure Windows modules are installed. 2014-12-04 15:58:46 -06:00
ad675235e2 Keep git history out of submodules when building src distribution 2014-11-27 20:08:48 -05:00
6598c83b02 Version bump for release 1.8.1 2014-11-26 21:42:25 -06:00
5b3c82f4ba fine tuned lookup/templating errors 2014-11-26 21:35:26 -06:00
e5344a7167 Integration tests for #9242 and #9640 2014-11-26 21:15:59 -06:00
7fcfc7450d Don't template play vars by themselves, it's too early 2014-11-26 21:15:43 -06:00
dece0c3f08 Version bump for 1.8.0 2014-11-25 15:58:28 -06:00
672a2cc037 Locking submodule SHAs for 1.8.0 2014-11-25 15:51:42 -06:00
57 changed files with 852 additions and 229 deletions

View File

@ -1,7 +1,31 @@
Ansible Changes By Release
==========================
## 1.8 "You Really Got Me" - Active Development
## 1.8.4 "You Really Got Me" - Feb 19, 2015
* Fixed regressions in ec2 and mount modules, introduced in 1.8.3
## 1.8.3 "You Really Got Me" - Feb 17, 2015
* Fixing a security bug related to the default permissions set on a tempoary file created when using "ansible-vault view <filename>".
* Many bug fixes, for both core code and core modules.
## 1.8.2 "You Really Got Me" - Dec 04, 2014
* Various bug fixes for packaging issues related to modules.
* Various bug fixes for lookup plugins.
* Various bug fixes for some modules (continued cleanup of postgresql issues, etc.).
* Add a clone parameter to git module that allows you to get information about a remote repo even if it doesn't exist locally.
## 1.8.1 "You Really Got Me" - Nov 26, 2014
* Various bug fixes in postgresql and mysql modules.
* Fixed a bug related to lookup plugins used within roles not finding files based on the relative paths to the roles files/ directory.
* Fixed a bug related to vars specified in plays being templated too early, resulting in incorrect variable interpolation.
* Fixed a bug related to git submodules in bare repos.
## 1.8 "You Really Got Me" - Nov 25, 2014
Major changes:

View File

@ -7,3 +7,5 @@ recursive-include docs *
include Makefile
include VERSION
include MANIFEST.in
prune lib/ansible/modules/core/.git
prune lib/ansible/modules/extras/.git

View File

@ -4,11 +4,16 @@ Ansible Releases at a Glance
Active Development
++++++++++++++++++
1.8 "You Really Got Me" ---- FALL 2014
1.9 "Dancing In the Streets" WINTER 2015
Released
++++++++
1.8.4 "You Really Got Me" ---- 02-19-2015
1.8.3 "You Really Got Me" ---- 02-17-2015
1.8.2 "You Really Got Me" ---- 12-04-2014
1.8.1 "You Really Got Me" ---- 11-26-2014
1.8 "You Really Got Me" ---- 11-25-2014
1.7.2 "Summer Nights" -------- 09-24-2014
1.7.1 "Summer Nights" -------- 08-14-2014
1.7 "Summer Nights" -------- 08-06-2014

View File

@ -1 +1 @@
1.8
1.8.4

View File

@ -25,6 +25,10 @@ import re
import optparse
import datetime
import subprocess
import fcntl
import termios
import struct
from ansible import utils
from ansible.utils import module_docs
import ansible.constants as C
@ -165,7 +169,11 @@ def get_snippet_text(doc):
return "\n".join(text)
def get_module_list_text(module_list):
columns = max(60, int(os.popen('stty size', 'r').read().split()[1]))
tty_size = 0
if os.isatty(0):
tty_size = struct.unpack('HHHH',
fcntl.ioctl(0, termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)))[1]
columns = max(60, tty_size)
displace = max(len(x) for x in module_list)
linelimit = columns - displace - 5
text = []

View File

@ -380,7 +380,7 @@ def scm_archive_role(scm, role_url, role_version, role_name):
print " in directory %s" % tempdir
return False
shutil.rmtree(tempdir)
shutil.rmtree(tempdir, ignore_errors=True)
return temp_file.name

View File

@ -39,6 +39,7 @@ import ansible.utils.template
from ansible import errors
from ansible import callbacks
from ansible import utils
from ansible.utils import to_unicode
from ansible.color import ANSIBLE_COLOR, stringc
from ansible.callbacks import display
@ -136,10 +137,11 @@ def main(args):
extra_vars = {}
for extra_vars_opt in options.extra_vars:
if extra_vars_opt.startswith("@"):
extra_vars_opt = to_unicode(extra_vars_opt)
if extra_vars_opt.startswith(u"@"):
# Argument is a YAML file (JSON is a subset of YAML)
extra_vars = utils.combine_vars(extra_vars, utils.parse_yaml_from_file(extra_vars_opt[1:], vault_password=vault_pass))
elif extra_vars_opt and extra_vars_opt[0] in '[{':
elif extra_vars_opt and extra_vars_opt[0] in u'[{':
# Arguments as YAML
extra_vars = utils.combine_vars(extra_vars, utils.parse_yaml(extra_vars_opt))
else:

View File

@ -12,7 +12,7 @@
# some basic default values...
hostfile = /etc/ansible/hosts
# library_path = /usr/share/my_modules/
#library = /usr/share/my_modules/
remote_tmp = $HOME/.ansible/tmp
pattern = *
forks = 5

View File

@ -14,5 +14,5 @@
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
__version__ = '1.8'
__version__ = '1.8.4'
__author__ = 'Michael DeHaan'

View File

@ -20,6 +20,11 @@ import time
import json
import errno
try:
import simplejson as json
except ImportError:
import json
from ansible import constants as C
from ansible import utils
from ansible.cache.base import BaseCacheModule

View File

@ -20,9 +20,14 @@ import collections
# FIXME: can we store these as something else before we ship it?
import sys
import time
import json
try:
import simplejson as json
except ImportError:
import json
from ansible import constants as C
from ansible.utils import jsonify
from ansible.cache.base import BaseCacheModule
try:
@ -65,7 +70,7 @@ class CacheModule(BaseCacheModule):
return json.loads(value)
def set(self, key, value):
value2 = json.dumps(value)
value2 = jsonify(value)
if self._timeout > 0: # a timeout of 0 is handled as meaning 'never expire'
self._cache.setex(self._make_key(key), int(self._timeout), value2)
else:

View File

@ -27,6 +27,7 @@ import fcntl
import constants
import locale
from ansible.color import stringc
from ansible.module_utils import basic
import logging
if constants.DEFAULT_LOG_PATH != '':
@ -456,6 +457,12 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
item = None
if type(results) == dict:
item = results.get('item', None)
if isinstance(item, unicode):
item = utils.to_bytes(item)
results = basic.json_dict_unicode_to_bytes(results)
else:
results = utils.to_bytes(results)
host = utils.to_bytes(host)
if item:
msg = "fatal: [%s] => (item=%s) => %s" % (host, item, results)
else:
@ -622,7 +629,13 @@ class PlaybookCallbacks(object):
if hasattr(self, 'start_at'): # we still have start_at so skip the task
self.skip_task = True
elif hasattr(self, 'step') and self.step:
msg = ('Perform task: %s (y/n/c): ' % name).encode(sys.stdout.encoding)
if isinstance(name, str):
name = utils.to_unicode(name)
msg = u'Perform task: %s (y/n/c): ' % name
if sys.stdout.encoding:
msg = msg.encode(sys.stdout.encoding, errors='replace')
else:
msg = msg.encode('utf-8')
resp = raw_input(msg)
if resp.lower() in ['y','yes']:
self.skip_task = False

View File

@ -22,7 +22,7 @@ import subprocess
import ansible.constants as C
from ansible.inventory.host import Host
from ansible.inventory.group import Group
from ansible.module_utils.basic import json_dict_unicode_to_bytes
from ansible.module_utils.basic import json_dict_bytes_to_unicode
from ansible import utils
from ansible import errors
import sys
@ -55,7 +55,7 @@ class InventoryScript(object):
# not passing from_remote because data from CMDB is trusted
self.raw = utils.parse_json(self.data)
self.raw = json_dict_unicode_to_bytes(self.raw)
self.raw = json_dict_bytes_to_unicode(self.raw)
all = Group('all')
groups = dict(all=all)
@ -144,7 +144,7 @@ class InventoryScript(object):
if out.strip() == '':
return dict()
try:
return json_dict_unicode_to_bytes(utils.parse_json(out))
return json_dict_bytes_to_unicode(utils.parse_json(out))
except ValueError:
raise errors.AnsibleError("could not parse post variable response: %s, %s" % (cmd, out))

View File

@ -171,6 +171,7 @@ FILE_COMMON_ARGUMENTS=dict(
directory_mode = dict(), # used by copy
)
PASSWD_ARG_RE = re.compile(r'^[-]{0,2}pass[-]?(word|wd)?')
def get_platform():
''' what's the platform? example: Linux is a platform. '''
@ -251,6 +252,83 @@ def json_dict_unicode_to_bytes(d):
else:
return d
def json_dict_bytes_to_unicode(d):
''' Recursively convert dict keys and values to byte str
Specialized for json return because this only handles, lists, tuples,
and dict container types (the containers that the json module returns)
'''
if isinstance(d, str):
return unicode(d, 'utf-8')
elif isinstance(d, dict):
return dict(map(json_dict_bytes_to_unicode, d.iteritems()))
elif isinstance(d, list):
return list(map(json_dict_bytes_to_unicode, d))
elif isinstance(d, tuple):
return tuple(map(json_dict_bytes_to_unicode, d))
else:
return d
def heuristic_log_sanitize(data):
''' Remove strings that look like passwords from log messages '''
# Currently filters:
# user:pass@foo/whatever and http://username:pass@wherever/foo
# This code has false positives and consumes parts of logs that are
# not passwds
# begin: start of a passwd containing string
# end: end of a passwd containing string
# sep: char between user and passwd
# prev_begin: where in the overall string to start a search for
# a passwd
# sep_search_end: where in the string to end a search for the sep
output = []
begin = len(data)
prev_begin = begin
sep = 1
while sep:
# Find the potential end of a passwd
try:
end = data.rindex('@', 0, begin)
except ValueError:
# No passwd in the rest of the data
output.insert(0, data[0:begin])
break
# Search for the beginning of a passwd
sep = None
sep_search_end = end
while not sep:
# URL-style username+password
try:
begin = data.rindex('://', 0, sep_search_end)
except ValueError:
# No url style in the data, check for ssh style in the
# rest of the string
begin = 0
# Search for separator
try:
sep = data.index(':', begin + 3, end)
except ValueError:
# No separator; choices:
if begin == 0:
# Searched the whole string so there's no password
# here. Return the remaining data
output.insert(0, data[0:begin])
break
# Search for a different beginning of the password field.
sep_search_end = begin
continue
if sep:
# Password was found; remove it.
output.insert(0, data[end:prev_begin])
output.insert(0, '********')
output.insert(0, data[begin:sep + 1])
prev_begin = begin
return ''.join(output)
class AnsibleModule(object):
@ -578,14 +656,25 @@ class AnsibleModule(object):
# FIXME: comparison against string above will cause this to be executed
# every time
try:
if 'lchmod' in dir(os):
if hasattr(os, 'lchmod'):
os.lchmod(path, mode)
else:
os.chmod(path, mode)
if not os.path.islink(path):
os.chmod(path, mode)
else:
# Attempt to set the perms of the symlink but be
# careful not to change the perms of the underlying
# file while trying
underlying_stat = os.stat(path)
os.chmod(path, mode)
new_underlying_stat = os.stat(path)
if underlying_stat.st_mode != new_underlying_stat.st_mode:
os.chmod(path, stat.S_IMODE(underlying_stat.st_mode))
q_stat = os.stat(path)
except OSError, e:
if os.path.islink(path) and e.errno == errno.EPERM: # Can't set mode on symbolic links
pass
elif e.errno == errno.ENOENT: # Can't set mode on broken symbolic links
elif e.errno in (errno.ENOENT, errno.ELOOP): # Can't set mode on broken symbolic links
pass
else:
raise e
@ -1001,65 +1090,6 @@ class AnsibleModule(object):
params2.update(params)
return (params2, args)
def _heuristic_log_sanitize(self, data):
''' Remove strings that look like passwords from log messages '''
# Currently filters:
# user:pass@foo/whatever and http://username:pass@wherever/foo
# This code has false positives and consumes parts of logs that are
# not passwds
# begin: start of a passwd containing string
# end: end of a passwd containing string
# sep: char between user and passwd
# prev_begin: where in the overall string to start a search for
# a passwd
# sep_search_end: where in the string to end a search for the sep
output = []
begin = len(data)
prev_begin = begin
sep = 1
while sep:
# Find the potential end of a passwd
try:
end = data.rindex('@', 0, begin)
except ValueError:
# No passwd in the rest of the data
output.insert(0, data[0:begin])
break
# Search for the beginning of a passwd
sep = None
sep_search_end = end
while not sep:
# URL-style username+password
try:
begin = data.rindex('://', 0, sep_search_end)
except ValueError:
# No url style in the data, check for ssh style in the
# rest of the string
begin = 0
# Search for separator
try:
sep = data.index(':', begin + 3, end)
except ValueError:
# No separator; choices:
if begin == 0:
# Searched the whole string so there's no password
# here. Return the remaining data
output.insert(0, data[0:begin])
break
# Search for a different beginning of the password field.
sep_search_end = begin
continue
if sep:
# Password was found; remove it.
output.insert(0, data[end:prev_begin])
output.insert(0, '********')
output.insert(0, data[begin:sep + 1])
prev_begin = begin
return ''.join(output)
def _log_invocation(self):
''' log that ansible ran the module '''
# TODO: generalize a separate log function and make log_invocation use it
@ -1082,7 +1112,7 @@ class AnsibleModule(object):
param_val = str(param_val)
elif isinstance(param_val, unicode):
param_val = param_val.encode('utf-8')
log_args[param] = self._heuristic_log_sanitize(param_val)
log_args[param] = heuristic_log_sanitize(param_val)
module = 'ansible-%s' % os.path.basename(__file__)
msg = []
@ -1104,12 +1134,11 @@ class AnsibleModule(object):
msg = msg.encode('utf-8')
if (has_journal):
journal_args = ["MESSAGE=%s %s" % (module, msg)]
journal_args.append("MODULE=%s" % os.path.basename(__file__))
journal_args = [("MODULE", os.path.basename(__file__))]
for arg in log_args:
journal_args.append(arg.upper() + "=" + str(log_args[arg]))
journal_args.append((arg.upper(), str(log_args[arg])))
try:
journal.sendv(*journal_args)
journal.send("%s %s" % (module, msg), **dict(journal_args))
except IOError, e:
# fall back to syslog since logging to journal failed
syslog.openlog(str(module), 0, syslog.LOG_USER)
@ -1427,27 +1456,27 @@ class AnsibleModule(object):
# create a printable version of the command for use
# in reporting later, which strips out things like
# passwords from the args list
if isinstance(args, list):
clean_args = " ".join(pipes.quote(arg) for arg in args)
if isinstance(args, basestring):
to_clean_args = shlex.split(args.encode('utf-8'))
else:
clean_args = args
to_clean_args = args
# all clean strings should return two match groups,
# where the first is the CLI argument and the second
# is the password/key/phrase that will be hidden
clean_re_strings = [
# this removes things like --password, --pass, --pass-wd, etc.
# optionally followed by an '=' or a space. The password can
# be quoted or not too, though it does not care about quotes
# that are not balanced
# source: http://blog.stevenlevithan.com/archives/match-quoted-string
r'([-]{0,2}pass[-]?(?:word|wd)?[=\s]?)((?:["\'])?(?:[^\s])*(?:\1)?)',
r'^(?P<before>.*:)(?P<password>.*)(?P<after>\@.*)$',
# TODO: add more regex checks here
]
for re_str in clean_re_strings:
r = re.compile(re_str)
clean_args = r.sub(r'\1********', clean_args)
clean_args = []
is_passwd = False
for arg in to_clean_args:
if is_passwd:
is_passwd = False
clean_args.append('********')
continue
if PASSWD_ARG_RE.match(arg):
sep_idx = arg.find('=')
if sep_idx > -1:
clean_args.append('%s=********' % arg[:sep_idx])
continue
else:
is_passwd = True
clean_args.append(heuristic_log_sanitize(arg))
clean_args = ' '.join(pipes.quote(arg) for arg in clean_args)
if data:
st_in = subprocess.PIPE
@ -1532,7 +1561,7 @@ class AnsibleModule(object):
self.fail_json(rc=257, msg=traceback.format_exc(), cmd=clean_args)
if rc != 0 and check_rc:
msg = stderr.rstrip()
msg = heuristic_log_sanitize(stderr.rstrip())
self.fail_json(cmd=clean_args, rc=rc, stdout=stdout, stderr=stderr, msg=msg)
# reset the pwd

View File

@ -2381,9 +2381,13 @@ class SunOSVirtual(Virtual):
def get_file_content(path, default=None):
data = default
if os.path.exists(path) and os.access(path, os.R_OK):
data = open(path).read().strip()
if len(data) == 0:
data = default
try:
datafile = open(path)
data = datafile.read().strip()
if len(data) == 0:
data = default
finally:
datafile.close()
return data
def ansible_facts(module):

View File

@ -88,13 +88,6 @@ class Play(object):
if self.playbook.inventory.src() is not None:
load_vars['inventory_file'] = self.playbook.inventory.src()
# template the play vars with themselves and the extra vars
# from the playbook, to make sure they're correct
all_vars = utils.combine_vars(self.vars, self.playbook.extra_vars)
all_vars = utils.combine_vars(all_vars, load_vars)
self.vars = template(basedir, self.vars, all_vars)
self.vars = utils.combine_vars(self.vars, load_vars)
# We first load the vars files from the datastructure
# so we have the default variables to pass into the roles
self.vars_files = ds.get('vars_files', [])
@ -115,10 +108,16 @@ class Play(object):
self._update_vars_files_for_host(None)
# template everything to be efficient, but do not pre-mature template
# tasks/handlers as they may have inventory scope overrides
# tasks/handlers as they may have inventory scope overrides. We also
# create a set of temporary variables for templating, so we don't
# trample on the existing vars structures
_tasks = ds.pop('tasks', [])
_handlers = ds.pop('handlers', [])
ds = template(basedir, ds, self.vars)
temp_vars = utils.merge_hash(self.vars, self.vars_file_vars)
temp_vars = utils.merge_hash(temp_vars, self.playbook.extra_vars)
ds = template(basedir, ds, temp_vars)
ds['tasks'] = _tasks
ds['handlers'] = _handlers
@ -626,8 +625,14 @@ class Play(object):
dirname = self.basedir
if original_file:
dirname = os.path.dirname(original_file)
include_file = template(dirname, tokens[0], mv)
# temp vars are used here to avoid trampling on the existing vars structures
temp_vars = utils.merge_hash(self.vars, self.vars_file_vars)
temp_vars = utils.merge_hash(temp_vars, mv)
temp_vars = utils.merge_hash(temp_vars, self.playbook.extra_vars)
include_file = template(dirname, tokens[0], temp_vars)
include_filename = utils.path_dwim(dirname, include_file)
data = utils.parse_yaml_from_file(include_filename, vault_password=self.vault_password)
if 'role_name' in x and data is not None:
for y in data:

View File

@ -667,8 +667,22 @@ class Runner(object):
def _executor_internal(self, host, new_stdin):
''' executes any module one or more times '''
# We build the proper injected dictionary for all future
# templating operations in this run
inject = self.get_inject_vars(host)
hostvars = HostVars(inject['combined_cache'], self.inventory, vault_password=self.vault_pass)
# Then we selectively merge some variable dictionaries down to a
# single dictionary, used to template the HostVars for this host
temp_vars = self.inventory.get_variables(host, vault_password=self.vault_pass)
temp_vars = utils.merge_hash(temp_vars, inject['combined_cache'])
temp_vars = utils.merge_hash(temp_vars, self.play_vars)
temp_vars = utils.merge_hash(temp_vars, self.play_file_vars)
temp_vars = utils.merge_hash(temp_vars, self.extra_vars)
hostvars = HostVars(temp_vars, self.inventory, vault_password=self.vault_pass)
# and we save the HostVars in the injected dictionary so they
# may be referenced from playbooks/templates
inject['hostvars'] = hostvars
host_connection = inject.get('ansible_connection', self.transport)
@ -719,6 +733,10 @@ class Runner(object):
result = utils.jsonify(dict(changed=False, skipped=True))
self.callbacks.on_skipped(host, None)
return ReturnData(host=host, result=result)
except errors.AnsibleError, e:
raise
except Exception, e:
raise errors.AnsibleError("Unexpected error while executing task: %s" % str(e))
# strip out any jinja2 template syntax within
# the data returned by the lookup plugin
@ -912,6 +930,8 @@ class Runner(object):
actual_private_key_file = delegate['private_key_file']
self.sudo_pass = delegate['sudo_pass']
inject = delegate['inject']
# set resolved delegate_to into inject so modules can call _remote_checksum
inject['delegate_to'] = self.delegate_to
# user/pass may still contain variables at this stage
actual_user = template.template(self.basedir, actual_user, inject)
@ -1012,7 +1032,7 @@ class Runner(object):
cond = template.template(self.basedir, until, inject, expand_lists=False)
if not utils.check_conditional(cond, self.basedir, inject, fail_on_undefined=self.error_on_undefined_vars):
retries = self.module_vars.get('retries')
retries = template.template(self.basedir, self.module_vars.get('retries'), inject, expand_lists=False)
delay = self.module_vars.get('delay')
for x in range(1, int(retries) + 1):
# template the delay, cast to float and sleep
@ -1182,8 +1202,16 @@ class Runner(object):
''' takes a remote path and performs tilde expansion on the remote host '''
if not path.startswith('~'):
return path
split_path = path.split(os.path.sep, 1)
cmd = conn.shell.expand_user(split_path[0])
expand_path = split_path[0]
if expand_path == '~':
if self.sudo and self.sudo_user:
expand_path = '~%s' % self.sudo_user
elif self.su and self.su_user:
expand_path = '~%s' % self.su_user
cmd = conn.shell.expand_user(expand_path)
data = self._low_level_exec_command(conn, cmd, tmp, sudoable=False, su=False)
initial_fragment = utils.last_non_blank_line(data['stdout'])
@ -1193,7 +1221,7 @@ class Runner(object):
return path
if len(split_path) > 1:
return os.path.join(initial_fragment, *split_path[1:])
return conn.shell.join_path(initial_fragment, *split_path[1:])
else:
return initial_fragment
@ -1201,7 +1229,28 @@ class Runner(object):
def _remote_checksum(self, conn, tmp, path, inject):
''' takes a remote checksum and returns 1 if no file '''
python_interp = inject['hostvars'][inject['inventory_hostname']].get('ansible_python_interpreter', 'python')
# Lookup the python interp from the host or delegate
# host == inven_host when there is no delegate
host = inject['inventory_hostname']
if 'delegate_to' in inject:
delegate = inject['delegate_to']
if delegate:
# host == None when the delegate is not in inventory
host = None
# delegate set, check whether the delegate has inventory vars
delegate = template.template(self.basedir, delegate, inject)
if delegate in inject['hostvars']:
# host == delegate if we need to lookup the
# python_interpreter from the delegate's inventory vars
host = delegate
if host:
python_interp = inject['hostvars'][host].get('ansible_python_interpreter', 'python')
else:
python_interp = 'python'
cmd = conn.shell.checksum(path, python_interp)
data = self._low_level_exec_command(conn, cmd, tmp, sudoable=True)
data2 = utils.last_non_blank_line(data['stdout'])
@ -1414,9 +1463,15 @@ class Runner(object):
# Expose the current hostgroup to the bypassing plugins
self.host_set = hosts
# We aren't iterating over all the hosts in this
# group. So, just pick the first host in our group to
# group. So, just choose the "delegate_to" host if that is defined and is
# one of the targeted hosts, otherwise pick the first host in our group to
# construct the conn object with.
result_data = self._executor(hosts[0], None).result
if self.delegate_to is not None and self.delegate_to in hosts:
host = self.delegate_to
else:
host = hosts[0]
result_data = self._executor(host, None).result
# Create a ResultData item for each host in this group
# using the returned result. If we didn't do this we would
# get false reports of dark hosts.

View File

@ -192,8 +192,12 @@ class ActionModule(object):
dest_file = conn.shell.join_path(dest, source_rel)
remote_checksum = self.runner._remote_checksum(conn, tmp_path, dest_file, inject)
if remote_checksum == '4':
result = dict(msg="python isn't present on the system. Unable to compute checksum", failed=True)
return ReturnData(conn=conn, result=result)
if remote_checksum != '1' and not force:
# remote_file does not exist so continue to next iteration.
# remote_file exists so continue to next iteration.
continue
if local_checksum != remote_checksum:

View File

@ -129,7 +129,7 @@ class ActionModule(object):
elif remote_checksum == '3':
result = dict(msg="remote file is a directory, fetch cannot work on directories", file=source, changed=False)
elif remote_checksum == '4':
result = dict(msg="python isn't present on the remote system. Unable to fetch file", file=source, changed=False)
result = dict(msg="python isn't present on the system. Unable to compute checksum", file=source, changed=False)
return ReturnData(conn=conn, result=result)
# calculate checksum for the local file

View File

@ -92,6 +92,13 @@ class ActionModule(object):
local_checksum = utils.checksum_s(resultant)
remote_checksum = self.runner._remote_checksum(conn, tmp, dest, inject)
if remote_checksum in ('0', '2', '3', '4'):
# Note: 1 means the file is not present which is fine; template
# will create it
result = dict(failed=True, msg="failed to checksum remote file."
" Checksum error code: %s" % remote_checksum)
return ReturnData(conn=conn, comm_ok=True, result=result)
if local_checksum != remote_checksum:
# template is different from the remote value
@ -138,6 +145,7 @@ class ActionModule(object):
# the module to follow links. When doing that, we have to set
# original_basename to the template just in case the dest is
# a directory.
module_args = ''
new_module_args = dict(
src=None,
original_basename=os.path.basename(source),
@ -147,6 +155,6 @@ class ActionModule(object):
# rely on the file module to report its changed status
if self.runner.noop_on_check(inject):
new_module_args['CHECKMODE'] = True
module_args = utils.merge_module_args(module_args, new_module_args)
return self.runner._execute_module(conn, tmp, 'file', module_args, inject=inject, complex_args=complex_args)
options.update(new_module_args)
return self.runner._execute_module(conn, tmp, 'file', module_args, inject=inject, complex_args=options)

View File

@ -59,9 +59,10 @@ class ActionModule(object):
# do not run the command if the line contains creates=filename
# and the filename already exists. This allows idempotence
# of command executions.
module_args_tmp = "path=%s" % creates
module_args_tmp = ""
complex_args_tmp = dict(path=creates, get_md5=False, get_checksum=False)
module_return = self.runner._execute_module(conn, tmp, 'stat', module_args_tmp, inject=inject,
complex_args=complex_args, persist_files=True)
complex_args=complex_args_tmp, persist_files=True)
stat = module_return.result.get('stat', None)
if stat and stat.get('exists', False):
return ReturnData(
@ -83,6 +84,9 @@ class ActionModule(object):
source = utils.path_dwim(self.runner.basedir, source)
remote_checksum = self.runner._remote_checksum(conn, tmp, dest, inject)
if remote_checksum == '4':
result = dict(failed=True, msg="python isn't present on the system. Unable to compute checksum")
return ReturnData(conn=conn, result=result)
if remote_checksum != '3':
result = dict(failed=True, msg="dest '%s' must be an existing dir" % dest)
return ReturnData(conn=conn, result=result)

View File

@ -230,6 +230,7 @@ class Connection(object):
host_fh.close()
for line in data.split("\n"):
line = line.strip()
if line is None or " " not in line:
continue
tokens = line.split()
@ -334,7 +335,7 @@ class Connection(object):
"sudo", "Sorry, try again.")
if sudo_errput.strip().endswith("%s%s" % (prompt, incorrect_password)):
raise errors.AnsibleError('Incorrect sudo password')
elif sudo_errput.endswith(prompt):
elif prompt and sudo_errput.endswith(prompt):
stdin.write(self.runner.sudo_pass + '\n')
if p.stdout in rfd:

View File

@ -193,7 +193,7 @@ class Connection(object):
def fetch_file(self, in_path, out_path):
out_path = out_path.replace('\\', '/')
vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host)
buffer_size = 2**20 # 1MB chunks
buffer_size = 2**19 # 0.5MB chunks
if not os.path.exists(os.path.dirname(out_path)):
os.makedirs(os.path.dirname(out_path))
out_file = None

View File

@ -24,17 +24,22 @@ import pipes
import glob
import re
import collections
from functools import partial
import operator as py_operator
from ansible import errors
from ansible.utils import md5s, checksum_s
from distutils.version import LooseVersion, StrictVersion
from random import SystemRandom, shuffle
from jinja2.filters import environmentfilter
from distutils.version import LooseVersion, StrictVersion
from ansible import errors
from ansible.utils import md5s, checksum_s
from ansible.utils.unicode import unicode_wrap, to_unicode
def to_nice_yaml(*a, **kw):
'''Make verbose, human readable yaml'''
return yaml.safe_dump(*a, indent=4, allow_unicode=True, default_flow_style=False, **kw)
transformed = yaml.safe_dump(*a, indent=4, allow_unicode=True, default_flow_style=False, **kw)
return to_unicode(transformed)
def to_json(a, *args, **kw):
''' Convert the value to JSON '''
@ -249,8 +254,8 @@ class FilterModule(object):
def filters(self):
return {
# base 64
'b64decode': base64.b64decode,
'b64encode': base64.b64encode,
'b64decode': partial(unicode_wrap, base64.b64decode),
'b64encode': partial(unicode_wrap, base64.b64encode),
# json
'to_json': to_json,
@ -263,11 +268,11 @@ class FilterModule(object):
'from_yaml': yaml.safe_load,
# path
'basename': os.path.basename,
'dirname': os.path.dirname,
'expanduser': os.path.expanduser,
'realpath': os.path.realpath,
'relpath': os.path.relpath,
'basename': partial(unicode_wrap, os.path.basename),
'dirname': partial(unicode_wrap, os.path.dirname),
'expanduser': partial(unicode_wrap, os.path.expanduser),
'realpath': partial(unicode_wrap, os.path.realpath),
'relpath': partial(unicode_wrap, os.path.relpath),
# failure testing
'failed' : failed,

View File

@ -50,7 +50,7 @@ class LookupModule(object):
if isinstance(term, basestring):
# convert a variable to a list
term2 = utils.listify_lookup_plugin_terms(term, self.basedir, inject, fail_on_undefined=False)
term2 = utils.listify_lookup_plugin_terms(term, self.basedir, inject)
# but avoid converting a plain string to a list of one string
if term2 != [ term ]:
term = term2
@ -59,7 +59,7 @@ class LookupModule(object):
# if it's a list, check recursively for items that are a list
term = self.flatten(term, inject)
ret.extend(term)
else:
else:
ret.append(term)
return ret

View File

@ -84,12 +84,24 @@ class ShellModule(object):
# FIXME: Support system temp path!
return _encode_script('''(New-Item -Type Directory -Path $env:temp -Name "%s").FullName | Write-Host -Separator '';''' % basefile)
def md5(self, path):
def expand_user(self, user_home_path):
# PowerShell only supports "~" (not "~username"). Resolve-Path ~ does
# not seem to work remotely, though by default we are always starting
# in the user's home directory.
if user_home_path == '~':
script = 'Write-Host (Get-Location).Path'
elif user_home_path.startswith('~\\'):
script = 'Write-Host ((Get-Location).Path + "%s")' % _escape(user_home_path[1:])
else:
script = 'Write-Host "%s"' % _escape(user_home_path)
return _encode_script(script)
def checksum(self, path, python_interp):
path = _escape(path)
script = '''
If (Test-Path -PathType Leaf "%(path)s")
{
$sp = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider;
$sp = new-object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider;
$fp = [System.IO.File]::Open("%(path)s", [System.IO.Filemode]::Open, [System.IO.FileAccess]::Read);
[System.BitConverter]::ToString($sp.ComputeHash($fp)).Replace("-", "").ToLower();
$fp.Dispose();

View File

@ -79,7 +79,6 @@ class ShellModule(object):
return 'echo %s' % user_home_path
def checksum(self, path, python_interp):
path = pipes.quote(path)
# The following test needs to be SH-compliant. BASH-isms will
# not work if /bin/sh points to a non-BASH shell.
#
@ -97,14 +96,14 @@ class ShellModule(object):
# 0. This logic is added to the end of the cmd at the bottom of this
# function.
test = "rc=flag; [ -r \"%(p)s\" ] || rc=2; [ -f \"%(p)s\" ] || rc=1; [ -d \"%(p)s\" ] && rc=3; %(i)s -V 2>/dev/null || rc=4; [ x\"$rc\" != \"xflag\" ] && echo \"${rc} %(p)s\" && exit 0" % dict(p=path, i=python_interp)
test = "rc=flag; [ -r \'%(p)s\' ] || rc=2; [ -f \'%(p)s\' ] || rc=1; [ -d \'%(p)s\' ] && rc=3; %(i)s -V 2>/dev/null || rc=4; [ x\"$rc\" != \"xflag\" ] && echo \"${rc}\"\' %(p)s\' && exit 0" % dict(p=path, i=python_interp)
csums = [
"(%s -c 'import hashlib; print(hashlib.sha1(open(\"%s\", \"rb\").read()).hexdigest())' 2>/dev/null)" % (python_interp, path), # Python > 2.4 (including python3)
"(%s -c 'import sha; print(sha.sha(open(\"%s\", \"rb\").read()).hexdigest())' 2>/dev/null)" % (python_interp, path), # Python == 2.4
"(%s -c 'import hashlib; BLOCKSIZE = 65536; hasher = hashlib.sha1();\nafile = open(\"%s\", \"rb\")\nbuf = afile.read(BLOCKSIZE)\nwhile len(buf) > 0:\n\thasher.update(buf)\n\tbuf = afile.read(BLOCKSIZE)\nafile.close()\nprint(hasher.hexdigest())' 2>/dev/null)" % (python_interp, path), # Python > 2.4 (including python3)
"(%s -c 'import sha; BLOCKSIZE = 65536; hasher = sha.sha();\nafile = open(\"%s\", \"rb\")\nbuf = afile.read(BLOCKSIZE)\nwhile len(buf) > 0:\n\thasher.update(buf)\n\tbuf = afile.read(BLOCKSIZE)\nafile.close()\nprint(hasher.hexdigest())' 2>/dev/null)" % (python_interp, path), # Python == 2.4
]
cmd = " || ".join(csums)
cmd = "%s; %s || (echo \"0 %s\")" % (test, cmd, path)
cmd = "%s; %s || (echo \'0 %s\')" % (test, cmd, path)
return cmd
def build_module_command(self, env_string, shebang, cmd, rm_tmp=None):

View File

@ -31,6 +31,7 @@ from ansible.utils.plugins import *
from ansible.utils.su_prompts import *
from ansible.callbacks import display
from ansible.module_utils.splitter import split_args, unquote
from ansible.module_utils.basic import heuristic_log_sanitize
import ansible.constants as C
import ast
import time
@ -45,10 +46,8 @@ import warnings
import traceback
import getpass
import sys
import json
import subprocess
import contextlib
import jinja2.exceptions
from vault import VaultLib
@ -64,9 +63,10 @@ CODE_REGEX = re.compile(r'(?:{%|%})')
try:
import json
except ImportError:
# simplejson can be much faster if it's available
import simplejson as json
except ImportError:
import json
# Note, sha1 is the only hash algorithm compatible with python2.4 and with
# FIPS-140 mode (as of 11-2014)
@ -999,34 +999,18 @@ def sanitize_output(str):
private_keys = ['password', 'login_password']
filter_re = [
# filter out things like user:pass@foo/whatever
# and http://username:pass@wherever/foo
re.compile('^(?P<before>.*:)(?P<password>.*)(?P<after>\@.*)$'),
]
parts = parse_kv(str)
output = []
for (k, v) in parts.items():
if k in private_keys:
output.append("%s=VALUE_HIDDEN" % k)
continue
else:
v = heuristic_log_sanitize(v)
output.append('%s=%s' % (k, v))
output = ' '.join(output)
return output
parts = str.split()
output = ''
for part in parts:
try:
(k,v) = part.split('=', 1)
if k in private_keys:
output += " %s=VALUE_HIDDEN" % k
else:
found = False
for filter in filter_re:
m = filter.match(v)
if m:
d = m.groupdict()
output += " %s=%s" % (k, d['before'] + "********" + d['after'])
found = True
break
if not found:
output += " %s" % part
except:
output += " %s" % part
return output.strip()
####################################################################
# option handling code for /usr/bin/ansible and ansible-playbook
@ -1451,7 +1435,7 @@ def safe_eval(expr, locals={}, include_exceptions=False):
return expr
def listify_lookup_plugin_terms(terms, basedir, inject, fail_on_undefined=C.DEFAULT_UNDEFINED_VAR_BEHAVIOR):
def listify_lookup_plugin_terms(terms, basedir, inject):
from ansible.utils import template
@ -1469,13 +1453,11 @@ def listify_lookup_plugin_terms(terms, basedir, inject, fail_on_undefined=C.DEFA
# if not already a list, get ready to evaluate with Jinja2
# not sure why the "/" is in above code :)
try:
new_terms = template.template(basedir, "{{%s}}" % terms, inject, convert_bare=True, fail_on_undefined=fail_on_undefined)
new_terms = template.template(basedir, "{{ %s }}" % terms, inject)
if isinstance(new_terms, basestring) and "{{" in new_terms:
pass
else:
terms = new_terms
except jinja2.exceptions.UndefinedError, e:
raise errors.AnsibleUndefinedVariable('undefined variable in items: %s' % e)
except:
pass

View File

@ -167,17 +167,20 @@ class PluginLoader(object):
else:
suffixes = ['.py', '']
for suffix in suffixes:
full_name = '%s%s' % (name, suffix)
if full_name in self._plugin_path_cache:
return self._plugin_path_cache[full_name]
# loop over paths and then loop over suffixes to find plugin
for i in self._get_paths():
for suffix in suffixes:
full_name = '%s%s' % (name, suffix)
if full_name in self._plugin_path_cache:
return self._plugin_path_cache[full_name]
for i in self._get_paths():
path = os.path.join(i, full_name)
if os.path.isfile(path):
self._plugin_path_cache[full_name] = path
return path
# if nothing is found, try finding alias/deprecated
if not name.startswith('_'):
return self.find_plugin('_' + name, suffixes, transport)

View File

@ -53,7 +53,7 @@ SU_PROMPT_LOCALIZATIONS = [
'密碼',
]
SU_PROMPT_LOCALIZATIONS_RE = re.compile("|".join([x + ' ?: ?' for x in SU_PROMPT_LOCALIZATIONS]), flags=re.IGNORECASE)
SU_PROMPT_LOCALIZATIONS_RE = re.compile("|".join(['(\w+\'s )?' + x + ' ?: ?' for x in SU_PROMPT_LOCALIZATIONS]), flags=re.IGNORECASE)
def check_su_prompt(data):
return bool(SU_PROMPT_LOCALIZATIONS_RE.match(data))

View File

@ -33,6 +33,7 @@ import ast
import traceback
from ansible.utils.string_functions import count_newlines_from_end
from ansible.utils import to_bytes
class Globals(object):
@ -86,14 +87,17 @@ JINJA2_ALLOWED_OVERRIDES = ['trim_blocks', 'lstrip_blocks', 'newline_sequence',
def lookup(name, *args, **kwargs):
from ansible import utils
instance = utils.plugins.lookup_loader.get(name.lower(), basedir=kwargs.get('basedir',None))
vars = kwargs.get('vars', None)
tvars = kwargs.get('vars', None)
if instance is not None:
# safely catch run failures per #5059
try:
ran = instance.run(*args, inject=vars, **kwargs)
ran = instance.run(*args, inject=tvars, **kwargs)
except errors.AnsibleError:
raise
except jinja2.exceptions.UndefinedError, e:
raise errors.AnsibleUndefinedVariable("One or more undefined variables: %s" % str(e))
except Exception, e:
ran = None
raise errors.AnsibleError('Unexpected error in during lookup: %s' % e)
if ran:
ran = ",".join(ran)
return ran
@ -269,7 +273,7 @@ def template_from_file(basedir, path, vars, vault_password=None):
managed_str = managed_default.format(
host = vars['template_host'],
uid = vars['template_uid'],
file = vars['template_path']
file = to_bytes(vars['template_path'])
)
vars['ansible_managed'] = time.strftime(
managed_str,

View File

@ -0,0 +1,248 @@
# (c) 2012-2014, Toshio Kuraotmi <a.badger@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
# to_bytes and to_unicode were written by Toshio Kuratomi for the
# python-kitchen library https://pypi.python.org/pypi/kitchen
# They are licensed in kitchen under the terms of the GPLv2+
# They were copied and modified for use in ansible by Toshio in Jan 2015
# (simply removing the deprecated features)
#: Aliases for the utf-8 codec
_UTF8_ALIASES = frozenset(('utf-8', 'UTF-8', 'utf8', 'UTF8', 'utf_8', 'UTF_8',
'utf', 'UTF', 'u8', 'U8'))
#: Aliases for the latin-1 codec
_LATIN1_ALIASES = frozenset(('latin-1', 'LATIN-1', 'latin1', 'LATIN1',
'latin', 'LATIN', 'l1', 'L1', 'cp819', 'CP819', '8859', 'iso8859-1',
'ISO8859-1', 'iso-8859-1', 'ISO-8859-1'))
# EXCEPTION_CONVERTERS is defined below due to using to_unicode
def to_unicode(obj, encoding='utf-8', errors='replace', nonstring=None):
'''Convert an object into a :class:`unicode` string
:arg obj: Object to convert to a :class:`unicode` string. This should
normally be a byte :class:`str`
:kwarg encoding: What encoding to try converting the byte :class:`str` as.
Defaults to :term:`utf-8`
:kwarg errors: If errors are found while decoding, perform this action.
Defaults to ``replace`` which replaces the invalid bytes with
a character that means the bytes were unable to be decoded. Other
values are the same as the error handling schemes in the `codec base
classes
<http://docs.python.org/library/codecs.html#codec-base-classes>`_.
For instance ``strict`` which raises an exception and ``ignore`` which
simply omits the non-decodable characters.
:kwarg nonstring: How to treat nonstring values. Possible values are:
:simplerepr: Attempt to call the object's "simple representation"
method and return that value. Python-2.3+ has two methods that
try to return a simple representation: :meth:`object.__unicode__`
and :meth:`object.__str__`. We first try to get a usable value
from :meth:`object.__unicode__`. If that fails we try the same
with :meth:`object.__str__`.
:empty: Return an empty :class:`unicode` string
:strict: Raise a :exc:`TypeError`
:passthru: Return the object unchanged
:repr: Attempt to return a :class:`unicode` string of the repr of the
object
Default is ``simplerepr``
:raises TypeError: if :attr:`nonstring` is ``strict`` and
a non-:class:`basestring` object is passed in or if :attr:`nonstring`
is set to an unknown value
:raises UnicodeDecodeError: if :attr:`errors` is ``strict`` and
:attr:`obj` is not decodable using the given encoding
:returns: :class:`unicode` string or the original object depending on the
value of :attr:`nonstring`.
Usually this should be used on a byte :class:`str` but it can take both
byte :class:`str` and :class:`unicode` strings intelligently. Nonstring
objects are handled in different ways depending on the setting of the
:attr:`nonstring` parameter.
The default values of this function are set so as to always return
a :class:`unicode` string and never raise an error when converting from
a byte :class:`str` to a :class:`unicode` string. However, when you do
not pass validly encoded text (or a nonstring object), you may end up with
output that you don't expect. Be sure you understand the requirements of
your data, not just ignore errors by passing it through this function.
'''
# Could use isbasestring/isunicode here but we want this code to be as
# fast as possible
if isinstance(obj, basestring):
if isinstance(obj, unicode):
return obj
if encoding in _UTF8_ALIASES:
return unicode(obj, 'utf-8', errors)
if encoding in _LATIN1_ALIASES:
return unicode(obj, 'latin-1', errors)
return obj.decode(encoding, errors)
if not nonstring:
nonstring = 'simplerepr'
if nonstring == 'empty':
return u''
elif nonstring == 'passthru':
return obj
elif nonstring == 'simplerepr':
try:
simple = obj.__unicode__()
except (AttributeError, UnicodeError):
simple = None
if not simple:
try:
simple = str(obj)
except UnicodeError:
try:
simple = obj.__str__()
except (UnicodeError, AttributeError):
simple = u''
if isinstance(simple, str):
return unicode(simple, encoding, errors)
return simple
elif nonstring in ('repr', 'strict'):
obj_repr = repr(obj)
if isinstance(obj_repr, str):
obj_repr = unicode(obj_repr, encoding, errors)
if nonstring == 'repr':
return obj_repr
raise TypeError('to_unicode was given "%(obj)s" which is neither'
' a byte string (str) or a unicode string' %
{'obj': obj_repr.encode(encoding, 'replace')})
raise TypeError('nonstring value, %(param)s, is not set to a valid'
' action' % {'param': nonstring})
def to_bytes(obj, encoding='utf-8', errors='replace', nonstring=None):
'''Convert an object into a byte :class:`str`
:arg obj: Object to convert to a byte :class:`str`. This should normally
be a :class:`unicode` string.
:kwarg encoding: Encoding to use to convert the :class:`unicode` string
into a byte :class:`str`. Defaults to :term:`utf-8`.
:kwarg errors: If errors are found while encoding, perform this action.
Defaults to ``replace`` which replaces the invalid bytes with
a character that means the bytes were unable to be encoded. Other
values are the same as the error handling schemes in the `codec base
classes
<http://docs.python.org/library/codecs.html#codec-base-classes>`_.
For instance ``strict`` which raises an exception and ``ignore`` which
simply omits the non-encodable characters.
:kwarg nonstring: How to treat nonstring values. Possible values are:
:simplerepr: Attempt to call the object's "simple representation"
method and return that value. Python-2.3+ has two methods that
try to return a simple representation: :meth:`object.__unicode__`
and :meth:`object.__str__`. We first try to get a usable value
from :meth:`object.__str__`. If that fails we try the same
with :meth:`object.__unicode__`.
:empty: Return an empty byte :class:`str`
:strict: Raise a :exc:`TypeError`
:passthru: Return the object unchanged
:repr: Attempt to return a byte :class:`str` of the :func:`repr` of the
object
Default is ``simplerepr``.
:raises TypeError: if :attr:`nonstring` is ``strict`` and
a non-:class:`basestring` object is passed in or if :attr:`nonstring`
is set to an unknown value.
:raises UnicodeEncodeError: if :attr:`errors` is ``strict`` and all of the
bytes of :attr:`obj` are unable to be encoded using :attr:`encoding`.
:returns: byte :class:`str` or the original object depending on the value
of :attr:`nonstring`.
.. warning::
If you pass a byte :class:`str` into this function the byte
:class:`str` is returned unmodified. It is **not** re-encoded with
the specified :attr:`encoding`. The easiest way to achieve that is::
to_bytes(to_unicode(text), encoding='utf-8')
The initial :func:`to_unicode` call will ensure text is
a :class:`unicode` string. Then, :func:`to_bytes` will turn that into
a byte :class:`str` with the specified encoding.
Usually, this should be used on a :class:`unicode` string but it can take
either a byte :class:`str` or a :class:`unicode` string intelligently.
Nonstring objects are handled in different ways depending on the setting
of the :attr:`nonstring` parameter.
The default values of this function are set so as to always return a byte
:class:`str` and never raise an error when converting from unicode to
bytes. However, when you do not pass an encoding that can validly encode
the object (or a non-string object), you may end up with output that you
don't expect. Be sure you understand the requirements of your data, not
just ignore errors by passing it through this function.
'''
# Could use isbasestring, isbytestring here but we want this to be as fast
# as possible
if isinstance(obj, basestring):
if isinstance(obj, str):
return obj
return obj.encode(encoding, errors)
if not nonstring:
nonstring = 'simplerepr'
if nonstring == 'empty':
return ''
elif nonstring == 'passthru':
return obj
elif nonstring == 'simplerepr':
try:
simple = str(obj)
except UnicodeError:
try:
simple = obj.__str__()
except (AttributeError, UnicodeError):
simple = None
if not simple:
try:
simple = obj.__unicode__()
except (AttributeError, UnicodeError):
simple = ''
if isinstance(simple, unicode):
simple = simple.encode(encoding, 'replace')
return simple
elif nonstring in ('repr', 'strict'):
try:
obj_repr = obj.__repr__()
except (AttributeError, UnicodeError):
obj_repr = ''
if isinstance(obj_repr, unicode):
obj_repr = obj_repr.encode(encoding, errors)
else:
obj_repr = str(obj_repr)
if nonstring == 'repr':
return obj_repr
raise TypeError('to_bytes was given "%(obj)s" which is neither'
' a unicode string or a byte string (str)' % {'obj': obj_repr})
raise TypeError('nonstring value, %(param)s, is not set to a valid'
' action' % {'param': nonstring})
# force the return value of a function to be unicode. Use with partial to
# ensure that a filter will return unicode values.
def unicode_wrap(func, *args, **kwargs):
return to_unicode(func(*args, **kwargs), nonstring='passthru')

View File

@ -278,8 +278,10 @@ class VaultEditor(object):
tmpdata = self.read_data(self.filename)
this_vault = VaultLib(self.password)
dec_data = this_vault.decrypt(tmpdata)
old_umask = os.umask(0o077)
_, tmp_path = tempfile.mkstemp()
self.write_data(dec_data, tmp_path)
os.umask(old_umask)
# drop the user into pager on the tmp file
call(self._pager_shell_command(tmp_path))

View File

@ -1,8 +1,32 @@
ansible (1.8) unstable; urgency=low
ansible (1.8.4) unstable; urgency=low
* 1.8 release (PENDING)
* 1.8.4
-- Michael DeHaan <michael@ansible.com> Wed, 21 Oct 2015 04:29:00 -0500
-- Ansible, Inc. <supoort@ansible.com> Thu, 19 Feb 2015 12:00:00 -0500
ansible (1.8.3) unstable; urgency=low
* 1.8.3
-- Ansible, Inc. <supoort@ansible.com> Tue, 17 Feb 2015 16:00:00 -0500
ansible (1.8.2) unstable; urgency=low
* 1.8.2
-- Michael DeHaan <michael@ansible.com> Thu, 04 Dec 2014 17:00:00 -0500
ansible (1.8.1) unstable; urgency=low
* 1.8.1
-- Michael DeHaan <michael@ansible.com> Wed, 26 Nov 2014 23:00:00 -0500
ansible (1.8.0) unstable; urgency=low
* 1.8.0
-- Michael DeHaan <michael@ansible.com> Tue, 25 Nov 2014 17:00:00 -0500
ansible (1.7.2) unstable; urgency=low

View File

@ -110,6 +110,21 @@ rm -rf %{buildroot}
%changelog
* Thu Feb 19 2015 Ansible, Inc. <support@ansible.com> - 1.8.4
- Release 1.8.4
* Tue Feb 17 2015 Ansible, Inc. <support@ansible.com> - 1.8.3
- Release 1.8.3
* Thu Dec 04 2014 Michael DeHaan <michael@ansible.com> - 1.8.2
- Release 1.8.2
* Wed Nov 26 2014 Michael DeHaan <michael@ansible.com> - 1.8.1
- Release 1.8.1
* Tue Nov 25 2014 Michael DeHaan <michael@ansible.com> - 1.8.0
- Release 1.8.0
* Wed Sep 24 2014 Michael DeHaan <michael@ansible.com> - 1.7.2
- Release 1.7.2

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python
"""
Cobbler external inventory script

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python
import json
from ipalib import api

View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python
# Copyright 2013 Google Inc.
#
# This file is part of Ansible

View File

@ -24,7 +24,7 @@ setup(name='ansible',
package_dir={ 'ansible': 'lib/ansible' },
packages=find_packages('lib'),
package_data={
'': ['module_utils/*.ps1'],
'': ['module_utils/*.ps1', 'modules/core/windows/*.ps1', 'modules/extras/windows/*.ps1'],
},
scripts=[
'bin/ansible',

View File

@ -33,7 +33,7 @@ includes:
ansible-playbook test_includes.yml -i $(INVENTORY) -e @$(VARS_FILE) $(CREDENTIALS_ARG) $(TEST_FLAGS)
unicode:
ansible-playbook unicode.yml -i $(INVENTORY) -e @$(VARS_FILE) -v $(TEST_FLAGS)
ansible-playbook unicode.yml -i $(INVENTORY) -e @$(VARS_FILE) -v $(TEST_FLAGS) -e 'extra_var=café'
# Test the start-at-task flag #9571
ansible-playbook unicode.yml -i $(INVENTORY) -e @$(VARS_FILE) -v --start-at-task '*¶' -e 'start_at_task=True' $(TEST_FLAGS)
@ -57,7 +57,7 @@ test_hash:
ANSIBLE_HASH_BEHAVIOUR=merge ansible-playbook test_hash.yml -i $(INVENTORY) $(CREDENTIALS_ARG) -v -e '{"test_hash":{"extra_args":"this is an extra arg"}}'
test_var_precedence:
ansible-playbook test_var_precedence.yml -i $(INVENTORY) $(CREDENTIALS_ARG) -v -e 'extra_var=extra_var'
ansible-playbook test_var_precedence.yml -i $(INVENTORY) $(CREDENTIALS_ARG) -v -e 'extra_var=extra_var' -e 'extra_var_override=extra_var_override'
test_vault:
ansible-playbook test_vault.yml -i $(INVENTORY) $(CREDENTIALS_ARG) -v $(TEST_FLAGS) --vault-password-file $(VAULT_PASSWORD_FILE) --list-tasks
@ -65,6 +65,9 @@ test_vault:
ansible-playbook test_vault.yml -i $(INVENTORY) $(CREDENTIALS_ARG) -v $(TEST_FLAGS) --vault-password-file $(VAULT_PASSWORD_FILE) --syntax-check
ansible-playbook test_vault.yml -i $(INVENTORY) $(CREDENTIALS_ARG) -v $(TEST_FLAGS) --vault-password-file $(VAULT_PASSWORD_FILE)
test_delegate_to:
ansible-playbook test_delegate_to.yml -i $(INVENTORY) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)
test_winrm:
ansible-playbook test_winrm.yml -i inventory.winrm -e @$(VARS_FILE) $(CREDENTIALS_ARG) -v $(TEST_FLAGS)

View File

@ -1,6 +1,8 @@
- hosts: testhost
gather_facts: True
roles:
# In destructive because it creates and removes a user
- { role: test_sudo, tags: test_sudo}
- { role: test_service, tags: test_service }
# Current pip unconditionally uses md5. We can re-enable if pip switches
# to a different hash or allows us to not check md5

View File

@ -1,6 +1,9 @@
[local]
testhost ansible_ssh_host=127.0.0.1 ansible_connection=local
testhost2 ansible_ssh_host=127.0.0.1 ansible_connection=local
# For testing delegate_to
testhost3 ansible_ssh_host=127.0.0.3
testhost4 ansible_ssh_host=127.0.0.4
# the following inline declarations are accompanied
# by (preferred) group_vars/ and host_vars/ variables
@ -9,6 +12,10 @@ testhost2 ansible_ssh_host=127.0.0.1 ansible_connection=local
[inven_overridehosts]
invenoverride ansible_ssh_host=127.0.0.1 ansible_connection=local
[all:vars]
extra_var_override=FROM_INVENTORY
inven_var=inventory_var
[inven_overridehosts:vars]
foo=foo
var_dir=vars

View File

@ -276,8 +276,9 @@
- name: assert the task was skipped
assert:
that:
- "'skipped' in result"
- result.skipped
- "result.results|length == 1"
- "'skipped' in result.results[0]"
- "result.results[0].skipped == True"
- name: test a with_items loop skipping a single item
debug: var=item

View File

@ -146,6 +146,7 @@
git:
repo: '{{ repo_format1 }}'
update: no
clone: no
accept_hostkey: yes
register: git_result

View File

@ -0,0 +1,44 @@
- include_vars: default.yml
- name: Create test user
user:
name: "{{ sudo_test_user }}"
- name: tilde expansion honors sudo in file
sudo: True
sudo_user: "{{ sudo_test_user }}"
file:
path: "~/foo.txt"
state: touch
- name: check that the path in the user's home dir was created
stat:
path: "~{{ sudo_test_user }}/foo.txt"
register: results
- assert:
that:
- "results.stat.exists == True"
- name: tilde expansion honors sudo in template
sudo: True
sudo_user: "{{ sudo_test_user }}"
template:
src: "bar.j2"
dest: "~/bar.txt"
- name: check that the path in the user's home dir was created
stat:
path: "~{{ sudo_test_user }}/bar.txt"
register: results
- assert:
that:
- "results.stat.exists == True"
- name: Remove test user and their home dir
user:
name: "{{ sudo_test_user }}"
state: "absent"
remove: "yes"

View File

@ -0,0 +1 @@
{{ sudo_test_user }}

View File

@ -0,0 +1 @@
sudo_test_user: ansibletest1

View File

@ -96,3 +96,42 @@
- "dir_attrs.stat.uid != 0"
- "dir_attrs.stat.pw_name == 'nobody'"
- "dir_attrs.stat.mode == '0755'"
- name: make a symlink to the templated file
file:
path: '{{ output_dir }}/foo.symlink'
src: '{{ output_dir }}/foo.templated'
state: link
- name: check that templating the symlink results in the file being templated
template:
src: foo.j2
dest: '{{output_dir}}/foo.symlink'
mode: 0600
follow: True
register: template_result
- assert:
that:
- "template_result.changed == True"
- name: check that the file has the correct attributes
stat: path={{output_dir | expanduser}}/template-dir/foo.j2
register: file_attrs
- assert:
that:
- "file_attrs.stat.mode == '0600'"
- name: check that templating the symlink again makes no changes
template:
src: foo.j2
dest: '{{output_dir}}/foo.symlink'
mode: 0600
follow: True
register: template_result
- assert:
that:
- "template_result.changed == False"

View File

@ -136,3 +136,4 @@
- name: remove our unarchive destination
file: path=/tmp/foo-unarchive.txt state=absent

View File

@ -18,11 +18,11 @@
- name: clean out the test directory
local_action: file name={{ output_dir|mandatory }} state=absent
tags: me
run_once: true
- name: create the test directory
local_action: file name={{ output_dir }} state=directory
tags: me
run_once: true
- name: fetch a small file
fetch: src="C:/Windows/win.ini" dest={{ output_dir }}
@ -145,7 +145,7 @@
- "not fetch_missing_nofail|changed"
- name: attempt to fetch a non-existent file - fail on missing
fetch: src="C:/this_file_should_not_exist.txt" dest={{ output_dir }} fail_on_missing=yes
fetch: src="~/this_file_should_not_exist.txt" dest={{ output_dir }} fail_on_missing=yes
register: fetch_missing
ignore_errors: true
@ -164,5 +164,6 @@
- name: check fetch directory result
assert:
that:
- "fetch_dir|failed"
# Doesn't fail anymore, only returns a message.
- "not fetch_dir|changed"
- "fetch_dir.msg"

View File

@ -0,0 +1,50 @@
- hosts: testhost3
roles:
- { role: prepare_tests }
vars:
- template_role: ./roles/test_template
- templated_var: foo
tasks:
- name: Test no delegate_to
setup:
register: setup_results
- assert:
that:
- '"127.0.0.3" in setup_results.ansible_facts.ansible_env["SSH_CONNECTION"]'
- name: Test delegate_to with host in inventory
setup:
register: setup_results
delegate_to: testhost4
- assert:
that:
- '"127.0.0.4" in setup_results.ansible_facts.ansible_env["SSH_CONNECTION"]'
- name: Test delegate_to with host not in inventory
setup:
register: setup_results
delegate_to: 127.0.0.254
- assert:
that:
- '"127.0.0.254" in setup_results.ansible_facts.ansible_env["SSH_CONNECTION"]'
#
# Smoketest some other modules do not error as a canary
#
- name: Test file works with delegate_to and a host in inventory
file: path={{ output_dir }}/foo.txt mode=0644 state=touch
delegate_to: testhost4
- name: Test file works with delegate_to and a host not in inventory
file: path={{ output_dir }}/test_follow_link mode=0644 state=touch
delegate_to: 127.0.0.254
- name: Test template works with delegate_to and a host in inventory
template: src={{ template_role }}/templates/foo.j2 dest={{ output_dir }}/foo.txt
delegate_to: testhost4
- name: Test template works with delegate_to and a host not in inventory
template: src={{ template_role }}/templates/foo.j2 dest={{ output_dir }}/foo.txt
delegate_to: 127.0.0.254

View File

@ -4,6 +4,8 @@
- vars_var: "vars_var"
- param_var: "BAD!"
- vars_files_var: "BAD!"
- extra_var_override_once_removed: "{{ extra_var_override }}"
- from_inventory_once_removed: "{{ inven_var | default('BAD!') }}"
vars_files:
- vars/test_var_precedence.yml
roles:
@ -15,17 +17,22 @@
- name: use set_fact to override the registered_var
set_fact: registered_var="this is from set_fact"
- debug: var=extra_var
- debug: var=extra_var_override_once_removed
- debug: var=vars_var
- debug: var=vars_files_var
- debug: var=vars_files_var_role
- debug: var=registered_var
- debug: var=from_inventory_once_removed
- assert:
that:
- 'extra_var == "extra_var"'
- 'extra_var_override == "extra_var_override"'
- 'extra_var_override_once_removed == "extra_var_override"'
- 'vars_var == "vars_var"'
- 'vars_files_var == "vars_files_var"'
- 'vars_files_var_role == "vars_files_var_role3"'
- 'registered_var == "this is from set_fact"'
- 'from_inventory_once_removed == "inventory_var"'
- hosts: inven_overridehosts
vars_files:

View File

@ -35,6 +35,10 @@
host_id: '{{item}}'
with_sequence: start=1 end={{num_hosts}} format=%d
- name: 'A task with unicode extra vars'
debug: var=extra_var
- name: 'A play for hosts in group: ĪīĬĭ'
hosts: 'ĪīĬĭ'
gather_facts: true

View File

@ -7,6 +7,7 @@ from nose.tools import timed
from ansible import errors
from ansible.module_common import ModuleReplacer
from ansible.module_utils.basic import heuristic_log_sanitize
from ansible.utils import checksum as utils_checksum
TEST_MODULE_DATA = """
@ -264,23 +265,23 @@ class TestModuleUtilsBasicHelpers(unittest.TestCase):
@timed(5)
def test_log_sanitize_speed_many_url(self):
self.module._heuristic_log_sanitize(self.many_url)
heuristic_log_sanitize(self.many_url)
@timed(5)
def test_log_sanitize_speed_many_ssh(self):
self.module._heuristic_log_sanitize(self.many_ssh)
heuristic_log_sanitize(self.many_ssh)
@timed(5)
def test_log_sanitize_speed_one_url(self):
self.module._heuristic_log_sanitize(self.one_url)
heuristic_log_sanitize(self.one_url)
@timed(5)
def test_log_sanitize_speed_one_ssh(self):
self.module._heuristic_log_sanitize(self.one_ssh)
heuristic_log_sanitize(self.one_ssh)
@timed(5)
def test_log_sanitize_speed_zero_secrets(self):
self.module._heuristic_log_sanitize(self.zero_secrets)
heuristic_log_sanitize(self.zero_secrets)
#
# Test that the password obfuscation sanitizes somewhat cleanly.
@ -290,8 +291,8 @@ class TestModuleUtilsBasicHelpers(unittest.TestCase):
url_data = repr(self._gen_data(3, True, True, self.URL_SECRET))
ssh_data = repr(self._gen_data(3, True, True, self.SSH_SECRET))
url_output = self.module._heuristic_log_sanitize(url_data)
ssh_output = self.module._heuristic_log_sanitize(ssh_data)
url_output = heuristic_log_sanitize(url_data)
ssh_output = heuristic_log_sanitize(ssh_data)
# Basic functionality: Successfully hid the password
try:

View File

@ -566,17 +566,9 @@ class TestUtils(unittest.TestCase):
def test_listify_lookup_plugin_terms(self):
basedir = os.path.dirname(__file__)
# Straight lookups
self.assertEqual(ansible.utils.listify_lookup_plugin_terms('things', basedir, dict(things=[])), [])
self.assertEqual(ansible.utils.listify_lookup_plugin_terms('things', basedir, dict(things=['one', 'two'])), ['one', 'two'])
# Variable interpolation
self.assertEqual(ansible.utils.listify_lookup_plugin_terms('things', basedir, dict(things=['{{ foo }}', '{{ bar }}'], foo="hello", bar="world")),
['hello', 'world'])
with self.assertRaises(ansible.errors.AnsibleError) as ex:
ansible.utils.listify_lookup_plugin_terms('things', basedir, dict(things=['{{ foo }}', '{{ bar_typo }}'], foo="hello", bar="world"))
self.assertTrue("undefined variable in items: 'bar_typo'" in ex.exception.msg)
#self.assertEqual(ansible.utils.listify_lookup_plugin_terms('things', basedir, dict(things=[])), [])
#self.assertEqual(ansible.utils.listify_lookup_plugin_terms('things', basedir, dict(things=['one', 'two'])), ['one', 'two'])
def test_deprecated(self):
sys_stderr = sys.stderr