mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Move uses of to_bytes, to_text, to_native to use the module_utils version (#17423)
We couldn't copy to_unicode, to_bytes, to_str into module_utils because of licensing. So once created it we had two sets of functions that did the same things but had different implementations. To remedy that, this change removes the ansible.utils.unicode versions of those functions.
This commit is contained in:
parent
7a9395b5e0
commit
4ed88512e4
89 changed files with 759 additions and 894 deletions
12
bin/ansible
12
bin/ansible
|
@ -43,7 +43,7 @@ from multiprocessing import Lock
|
||||||
import ansible.constants as C
|
import ansible.constants as C
|
||||||
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleParserError
|
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleParserError
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.module_utils._text import to_text
|
||||||
|
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
@ -97,10 +97,10 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
except AnsibleOptionsError as e:
|
except AnsibleOptionsError as e:
|
||||||
cli.parser.print_help()
|
cli.parser.print_help()
|
||||||
display.error(to_unicode(e), wrap_text=False)
|
display.error(to_text(e), wrap_text=False)
|
||||||
exit_code = 5
|
exit_code = 5
|
||||||
except AnsibleParserError as e:
|
except AnsibleParserError as e:
|
||||||
display.error(to_unicode(e), wrap_text=False)
|
display.error(to_text(e), wrap_text=False)
|
||||||
exit_code = 4
|
exit_code = 4
|
||||||
# TQM takes care of these, but leaving comment to reserve the exit codes
|
# TQM takes care of these, but leaving comment to reserve the exit codes
|
||||||
# except AnsibleHostUnreachable as e:
|
# except AnsibleHostUnreachable as e:
|
||||||
|
@ -110,16 +110,16 @@ if __name__ == '__main__':
|
||||||
# display.error(str(e))
|
# display.error(str(e))
|
||||||
# exit_code = 2
|
# exit_code = 2
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
display.error(to_unicode(e), wrap_text=False)
|
display.error(to_text(e), wrap_text=False)
|
||||||
exit_code = 1
|
exit_code = 1
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
display.error("User interrupted execution")
|
display.error("User interrupted execution")
|
||||||
exit_code = 99
|
exit_code = 99
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
have_cli_options = cli is not None and cli.options is not None
|
have_cli_options = cli is not None and cli.options is not None
|
||||||
display.error("Unexpected Exception: %s" % to_unicode(e), wrap_text=False)
|
display.error("Unexpected Exception: %s" % to_text(e), wrap_text=False)
|
||||||
if not have_cli_options or have_cli_options and cli.options.verbosity > 2:
|
if not have_cli_options or have_cli_options and cli.options.verbosity > 2:
|
||||||
display.display(u"the full traceback was:\n\n%s" % to_unicode(traceback.format_exc()))
|
display.display(u"the full traceback was:\n\n%s" % to_text(traceback.format_exc()))
|
||||||
else:
|
else:
|
||||||
display.display("to see the full traceback, use -vvv")
|
display.display("to see the full traceback, use -vvv")
|
||||||
exit_code = 250
|
exit_code = 250
|
||||||
|
|
|
@ -215,6 +215,28 @@ Python3. We'll need to gather experience to see if this is going to work out
|
||||||
well for modules as well or if we should give the module_utils API explicit
|
well for modules as well or if we should give the module_utils API explicit
|
||||||
switches so that modules can choose to operate with text type all of the time.
|
switches so that modules can choose to operate with text type all of the time.
|
||||||
|
|
||||||
|
Helpers
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
For converting between bytes, text, and native strings we have three helper
|
||||||
|
functions. These are :func:`ansible.module_utils._text.to_bytes`,
|
||||||
|
:func:`ansible.module_utils._text.to_native`, and
|
||||||
|
:func:`ansible.module_utils._text.to_text`. These are similar to using
|
||||||
|
``bytes.decode()`` and ``unicode.encode()`` with a few differences.
|
||||||
|
|
||||||
|
* By default they try very hard not to traceback.
|
||||||
|
* The default encoding is "utf-8"
|
||||||
|
* There are two error strategies that don't correspond one-to-one with
|
||||||
|
a python codec error handler. These are ``surrogate_or_strict`` and
|
||||||
|
``surrogate_or_replace``. ``surrogate_or_strict`` will use the ``surrogateescape``
|
||||||
|
error handler if available (mostly on python3) or strict if not. It is most
|
||||||
|
appropriate to use when dealing with something that needs to round trip its
|
||||||
|
value like file paths database keys, etc. Without ``surrogateescape`` the best
|
||||||
|
thing these values can do is generate a traceback that our code can catch
|
||||||
|
and decide how to show an error message. ``surrogate_or_replace`` is for
|
||||||
|
when a value is going to be displayed to the user. If the
|
||||||
|
``surrogateescape`` error handler is not present, it will replace
|
||||||
|
undecodable byte sequences with a replacement character.
|
||||||
|
|
||||||
================================
|
================================
|
||||||
Porting Core Ansible to Python 3
|
Porting Core Ansible to Python 3
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
|
@ -34,10 +35,10 @@ from collections import defaultdict
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.utils import module_docs
|
from ansible.utils import module_docs
|
||||||
from ansible.utils.vars import merge_hash
|
from ansible.utils.vars import merge_hash
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
from ansible.errors import AnsibleError
|
|
||||||
|
|
||||||
#####################################################################################
|
#####################################################################################
|
||||||
# constants and paths
|
# constants and paths
|
||||||
|
|
|
@ -33,7 +33,7 @@ import subprocess
|
||||||
from ansible.release import __version__
|
from ansible.release import __version__
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError, AnsibleOptionsError
|
from ansible.errors import AnsibleError, AnsibleOptionsError
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -109,7 +109,7 @@ class CLI(object):
|
||||||
|
|
||||||
if self.options.verbosity > 0:
|
if self.options.verbosity > 0:
|
||||||
if C.CONFIG_FILE:
|
if C.CONFIG_FILE:
|
||||||
display.display(u"Using %s as config file" % to_unicode(C.CONFIG_FILE))
|
display.display(u"Using %s as config file" % to_text(C.CONFIG_FILE))
|
||||||
else:
|
else:
|
||||||
display.display(u"No config file found; using defaults")
|
display.display(u"No config file found; using defaults")
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,13 @@ from ansible.cli import CLI
|
||||||
from ansible.errors import AnsibleError, AnsibleOptionsError
|
from ansible.errors import AnsibleError, AnsibleOptionsError
|
||||||
from ansible.executor.task_queue_manager import TaskQueueManager
|
from ansible.executor.task_queue_manager import TaskQueueManager
|
||||||
from ansible.inventory import Inventory
|
from ansible.inventory import Inventory
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.parsing.dataloader import DataLoader
|
from ansible.parsing.dataloader import DataLoader
|
||||||
from ansible.parsing.splitter import parse_kv
|
from ansible.parsing.splitter import parse_kv
|
||||||
from ansible.playbook.play import Play
|
from ansible.playbook.play import Play
|
||||||
from ansible.plugins import get_all_plugin_loaders
|
from ansible.plugins import get_all_plugin_loaders
|
||||||
from ansible.utils.vars import load_extra_vars
|
from ansible.utils.vars import load_extra_vars
|
||||||
from ansible.utils.vars import load_options_vars
|
from ansible.utils.vars import load_options_vars
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
from ansible.vars import VariableManager
|
from ansible.vars import VariableManager
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -99,7 +99,7 @@ class AdHocCLI(CLI):
|
||||||
super(AdHocCLI, self).run()
|
super(AdHocCLI, self).run()
|
||||||
|
|
||||||
# only thing left should be host pattern
|
# only thing left should be host pattern
|
||||||
pattern = to_unicode(self.args[0], errors='strict')
|
pattern = to_text(self.args[0], errors='surrogate_or_strict')
|
||||||
|
|
||||||
# ignore connection password cause we are local
|
# ignore connection password cause we are local
|
||||||
if self.options.connection == "local":
|
if self.options.connection == "local":
|
||||||
|
@ -169,7 +169,7 @@ class AdHocCLI(CLI):
|
||||||
play_ds = self._play_ds(pattern, self.options.seconds, self.options.poll_interval)
|
play_ds = self._play_ds(pattern, self.options.seconds, self.options.poll_interval)
|
||||||
play = Play().load(play_ds, variable_manager=variable_manager, loader=loader)
|
play = Play().load(play_ds, variable_manager=variable_manager, loader=loader)
|
||||||
|
|
||||||
if self.callback:
|
if self.callback:
|
||||||
cb = self.callback
|
cb = self.callback
|
||||||
elif self.options.one_line:
|
elif self.options.one_line:
|
||||||
cb = 'oneline'
|
cb = 'oneline'
|
||||||
|
|
|
@ -39,18 +39,16 @@ import sys
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.cli import CLI
|
from ansible.cli import CLI
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
|
||||||
from ansible.executor.task_queue_manager import TaskQueueManager
|
from ansible.executor.task_queue_manager import TaskQueueManager
|
||||||
from ansible.inventory import Inventory
|
from ansible.inventory import Inventory
|
||||||
|
from ansible.module_utils._text import to_native, to_text
|
||||||
from ansible.parsing.dataloader import DataLoader
|
from ansible.parsing.dataloader import DataLoader
|
||||||
from ansible.parsing.splitter import parse_kv
|
from ansible.parsing.splitter import parse_kv
|
||||||
from ansible.playbook.play import Play
|
from ansible.playbook.play import Play
|
||||||
from ansible.vars import VariableManager
|
from ansible.plugins import module_loader
|
||||||
from ansible.utils import module_docs
|
from ansible.utils import module_docs
|
||||||
from ansible.utils.color import stringc
|
from ansible.utils.color import stringc
|
||||||
from ansible.utils.unicode import to_unicode, to_str
|
from ansible.vars import VariableManager
|
||||||
from ansible.plugins import module_loader
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -152,11 +150,11 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
||||||
continue
|
continue
|
||||||
elif module.startswith('_'):
|
elif module.startswith('_'):
|
||||||
fullpath = '/'.join([path,module])
|
fullpath = '/'.join([path,module])
|
||||||
if os.path.islink(fullpath): # avoids aliases
|
if os.path.islink(fullpath): # avoids aliases
|
||||||
continue
|
continue
|
||||||
module = module.replace('_', '', 1)
|
module = module.replace('_', '', 1)
|
||||||
|
|
||||||
module = os.path.splitext(module)[0] # removes the extension
|
module = os.path.splitext(module)[0] # removes the extension
|
||||||
yield module
|
yield module
|
||||||
|
|
||||||
def default(self, arg, forceshell=False):
|
def default(self, arg, forceshell=False):
|
||||||
|
@ -192,11 +190,11 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
||||||
)
|
)
|
||||||
play = Play().load(play_ds, variable_manager=self.variable_manager, loader=self.loader)
|
play = Play().load(play_ds, variable_manager=self.variable_manager, loader=self.loader)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
display.error(u"Unable to build command: %s" % to_unicode(e))
|
display.error(u"Unable to build command: %s" % to_text(e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cb = 'minimal' #FIXME: make callbacks configurable
|
cb = 'minimal' # FIXME: make callbacks configurable
|
||||||
# now create a task queue manager to execute the play
|
# now create a task queue manager to execute the play
|
||||||
self._tqm = None
|
self._tqm = None
|
||||||
try:
|
try:
|
||||||
|
@ -225,8 +223,8 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
||||||
display.error('User interrupted execution')
|
display.error('User interrupted execution')
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
display.error(to_unicode(e))
|
display.error(to_text(e))
|
||||||
#FIXME: add traceback in very very verbose mode
|
# FIXME: add traceback in very very verbose mode
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def emptyline(self):
|
def emptyline(self):
|
||||||
|
@ -379,7 +377,7 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
||||||
else:
|
else:
|
||||||
completions = [x.name for x in self.inventory.list_hosts(self.options.cwd)]
|
completions = [x.name for x in self.inventory.list_hosts(self.options.cwd)]
|
||||||
|
|
||||||
return [to_str(s)[offs:] for s in completions if to_str(s).startswith(to_str(mline))]
|
return [to_native(s)[offs:] for s in completions if to_native(s).startswith(to_native(mline))]
|
||||||
|
|
||||||
def completedefault(self, text, line, begidx, endidx):
|
def completedefault(self, text, line, begidx, endidx):
|
||||||
if line.split()[0] in self.modules:
|
if line.split()[0] in self.modules:
|
||||||
|
@ -394,7 +392,6 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
||||||
oc, a, _ = module_docs.get_docstring(in_path)
|
oc, a, _ = module_docs.get_docstring(in_path)
|
||||||
return oc['options'].keys()
|
return oc['options'].keys()
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
super(ConsoleCLI, self).run()
|
super(ConsoleCLI, self).run()
|
||||||
|
@ -410,7 +407,6 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
||||||
self.pattern = self.args[0]
|
self.pattern = self.args[0]
|
||||||
self.options.cwd = self.pattern
|
self.options.cwd = self.pattern
|
||||||
|
|
||||||
|
|
||||||
# dynamically add modules as commands
|
# dynamically add modules as commands
|
||||||
self.modules = self.list_modules()
|
self.modules = self.list_modules()
|
||||||
for module in self.modules:
|
for module in self.modules:
|
||||||
|
@ -465,4 +461,3 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
||||||
atexit.register(readline.write_history_file, histfile)
|
atexit.register(readline.write_history_file, histfile)
|
||||||
self.set_prompt()
|
self.set_prompt()
|
||||||
self.cmdloop()
|
self.cmdloop()
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ from ansible.galaxy.role import GalaxyRole
|
||||||
from ansible.galaxy.login import GalaxyLogin
|
from ansible.galaxy.login import GalaxyLogin
|
||||||
from ansible.galaxy.token import GalaxyToken
|
from ansible.galaxy.token import GalaxyToken
|
||||||
from ansible.playbook.role.requirement import RoleRequirement
|
from ansible.playbook.role.requirement import RoleRequirement
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -47,6 +47,7 @@ except ImportError:
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
display = Display()
|
display = Display()
|
||||||
|
|
||||||
|
|
||||||
class GalaxyCLI(CLI):
|
class GalaxyCLI(CLI):
|
||||||
|
|
||||||
SKIP_INFO_KEYS = ("name", "description", "readme_html", "related", "summary_fields", "average_aw_composite", "average_aw_score", "url" )
|
SKIP_INFO_KEYS = ("name", "description", "readme_html", "related", "summary_fields", "average_aw_composite", "average_aw_score", "url" )
|
||||||
|
@ -65,7 +66,6 @@ class GalaxyCLI(CLI):
|
||||||
epilog = "\nSee '%s <command> --help' for more information on a specific command.\n\n" % os.path.basename(sys.argv[0])
|
epilog = "\nSee '%s <command> --help' for more information on a specific command.\n\n" % os.path.basename(sys.argv[0])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
self.set_action()
|
self.set_action()
|
||||||
|
|
||||||
# common
|
# common
|
||||||
|
@ -111,7 +111,7 @@ class GalaxyCLI(CLI):
|
||||||
if self.action in ['init', 'info']:
|
if self.action in ['init', 'info']:
|
||||||
self.parser.add_option( '--offline', dest='offline', default=False, action='store_true', help="Don't query the galaxy API when creating roles")
|
self.parser.add_option( '--offline', dest='offline', default=False, action='store_true', help="Don't query the galaxy API when creating roles")
|
||||||
|
|
||||||
if not self.action in ("delete","import","init","login","setup"):
|
if self.action not in ("delete","import","init","login","setup"):
|
||||||
# NOTE: while the option type=str, the default is a list, and the
|
# NOTE: while the option type=str, the default is a list, and the
|
||||||
# callback will set the value to a list.
|
# callback will set the value to a list.
|
||||||
self.parser.add_option('-p', '--roles-path', dest='roles_path', action="callback", callback=CLI.expand_paths, type=str, default=C.DEFAULT_ROLES_PATH,
|
self.parser.add_option('-p', '--roles-path', dest='roles_path', action="callback", callback=CLI.expand_paths, type=str, default=C.DEFAULT_ROLES_PATH,
|
||||||
|
@ -142,7 +142,7 @@ class GalaxyCLI(CLI):
|
||||||
|
|
||||||
def _display_role_info(self, role_info):
|
def _display_role_info(self, role_info):
|
||||||
|
|
||||||
text = [u"", u"Role: %s" % to_unicode(role_info['name'])]
|
text = [u"", u"Role: %s" % to_text(role_info['name'])]
|
||||||
text.append(u"\tdescription: %s" % role_info.get('description', ''))
|
text.append(u"\tdescription: %s" % role_info.get('description', ''))
|
||||||
|
|
||||||
for k in sorted(role_info.keys()):
|
for k in sorted(role_info.keys()):
|
||||||
|
@ -340,7 +340,7 @@ class GalaxyCLI(CLI):
|
||||||
f = open(role_file, 'r')
|
f = open(role_file, 'r')
|
||||||
if role_file.endswith('.yaml') or role_file.endswith('.yml'):
|
if role_file.endswith('.yaml') or role_file.endswith('.yml'):
|
||||||
try:
|
try:
|
||||||
required_roles = yaml.safe_load(f.read())
|
required_roles = yaml.safe_load(f.read())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError("Unable to load data from the requirements file: %s" % role_file)
|
raise AnsibleError("Unable to load data from the requirements file: %s" % role_file)
|
||||||
|
|
||||||
|
@ -502,7 +502,7 @@ class GalaxyCLI(CLI):
|
||||||
if len(self.args):
|
if len(self.args):
|
||||||
terms = []
|
terms = []
|
||||||
for i in range(len(self.args)):
|
for i in range(len(self.args)):
|
||||||
terms.append(self.args.pop())
|
terms.append(self.args.pop())
|
||||||
search = '+'.join(terms[::-1])
|
search = '+'.join(terms[::-1])
|
||||||
|
|
||||||
if not search and not self.options.platforms and not self.options.tags and not self.options.author:
|
if not search and not self.options.platforms and not self.options.tags and not self.options.author:
|
||||||
|
@ -578,8 +578,8 @@ class GalaxyCLI(CLI):
|
||||||
if len(self.args) < 2:
|
if len(self.args) < 2:
|
||||||
raise AnsibleError("Expected a github_username and github_repository. Use --help.")
|
raise AnsibleError("Expected a github_username and github_repository. Use --help.")
|
||||||
|
|
||||||
github_repo = self.args.pop()
|
github_repo = to_text(self.args.pop(), errors='surrogate_or_strict')
|
||||||
github_user = self.args.pop()
|
github_user = to_text(self.args.pop(), errors='surrogate_or_strict')
|
||||||
|
|
||||||
if self.options.check_status:
|
if self.options.check_status:
|
||||||
task = self.api.get_import_task(github_user=github_user, github_repo=github_repo)
|
task = self.api.get_import_task(github_user=github_user, github_repo=github_repo)
|
||||||
|
@ -594,7 +594,8 @@ class GalaxyCLI(CLI):
|
||||||
display.display("The following Galaxy roles are being updated:" + u'\n', color=C.COLOR_CHANGED)
|
display.display("The following Galaxy roles are being updated:" + u'\n', color=C.COLOR_CHANGED)
|
||||||
for t in task:
|
for t in task:
|
||||||
display.display('%s.%s' % (t['summary_fields']['role']['namespace'],t['summary_fields']['role']['name']), color=C.COLOR_CHANGED)
|
display.display('%s.%s' % (t['summary_fields']['role']['namespace'],t['summary_fields']['role']['name']), color=C.COLOR_CHANGED)
|
||||||
display.display(u'\n' + "To properly namespace this role, remove each of the above and re-import %s/%s from scratch" % (github_user,github_repo), color=C.COLOR_CHANGED)
|
display.display(u'\nTo properly namespace this role, remove each of the above and re-import %s/%s from scratch' % (github_user, github_repo),
|
||||||
|
color=C.COLOR_CHANGED)
|
||||||
return 0
|
return 0
|
||||||
# found a single role as expected
|
# found a single role as expected
|
||||||
display.display("Successfully submitted import request %d" % task[0]['id'])
|
display.display("Successfully submitted import request %d" % task[0]['id'])
|
||||||
|
|
|
@ -26,7 +26,7 @@ from ansible.errors import AnsibleError, AnsibleOptionsError
|
||||||
from ansible.parsing.dataloader import DataLoader
|
from ansible.parsing.dataloader import DataLoader
|
||||||
from ansible.parsing.vault import VaultEditor
|
from ansible.parsing.vault import VaultEditor
|
||||||
from ansible.cli import CLI
|
from ansible.cli import CLI
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.module_utils._text import to_text
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -163,7 +163,7 @@ class VaultCLI(CLI):
|
||||||
# unicode here because we are displaying it and therefore can make
|
# unicode here because we are displaying it and therefore can make
|
||||||
# the decision that the display doesn't have to be precisely what
|
# the decision that the display doesn't have to be precisely what
|
||||||
# the input was (leave that to decrypt instead)
|
# the input was (leave that to decrypt instead)
|
||||||
self.pager(to_unicode(self.editor.plaintext(f)))
|
self.pager(ansible.module_utils._text.to_text(self.editor.plaintext(f)))
|
||||||
|
|
||||||
def execute_rekey(self):
|
def execute_rekey(self):
|
||||||
for f in self.args:
|
for f in self.args:
|
||||||
|
|
|
@ -25,8 +25,7 @@ from ansible.errors.yaml_strings import ( YAML_POSITION_DETAILS,
|
||||||
YAML_COMMON_UNQUOTED_COLON_ERROR,
|
YAML_COMMON_UNQUOTED_COLON_ERROR,
|
||||||
YAML_COMMON_PARTIALLY_QUOTED_LINE_ERROR,
|
YAML_COMMON_PARTIALLY_QUOTED_LINE_ERROR,
|
||||||
YAML_COMMON_UNBALANCED_QUOTES_ERROR )
|
YAML_COMMON_UNBALANCED_QUOTES_ERROR )
|
||||||
|
from ansible.module_utils._text import to_native, to_text
|
||||||
from ansible.utils.unicode import to_unicode, to_str
|
|
||||||
|
|
||||||
|
|
||||||
class AnsibleError(Exception):
|
class AnsibleError(Exception):
|
||||||
|
@ -54,11 +53,11 @@ class AnsibleError(Exception):
|
||||||
if obj and isinstance(obj, AnsibleBaseYAMLObject):
|
if obj and isinstance(obj, AnsibleBaseYAMLObject):
|
||||||
extended_error = self._get_extended_error()
|
extended_error = self._get_extended_error()
|
||||||
if extended_error and not suppress_extended_error:
|
if extended_error and not suppress_extended_error:
|
||||||
self.message = '%s\n\n%s' % (to_str(message), to_str(extended_error))
|
self.message = '%s\n\n%s' % (to_native(message), to_native(extended_error))
|
||||||
else:
|
else:
|
||||||
self.message = '%s' % to_str(message)
|
self.message = '%s' % to_native(message)
|
||||||
else:
|
else:
|
||||||
self.message = '%s' % to_str(message)
|
self.message = '%s' % to_native(message)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.message
|
return self.message
|
||||||
|
@ -104,8 +103,8 @@ class AnsibleError(Exception):
|
||||||
error_message += YAML_POSITION_DETAILS % (src_file, line_number, col_number)
|
error_message += YAML_POSITION_DETAILS % (src_file, line_number, col_number)
|
||||||
if src_file not in ('<string>', '<unicode>') and self._show_content:
|
if src_file not in ('<string>', '<unicode>') and self._show_content:
|
||||||
(target_line, prev_line) = self._get_error_lines_from_file(src_file, line_number - 1)
|
(target_line, prev_line) = self._get_error_lines_from_file(src_file, line_number - 1)
|
||||||
target_line = to_unicode(target_line)
|
target_line = to_text(target_line)
|
||||||
prev_line = to_unicode(prev_line)
|
prev_line = to_text(prev_line)
|
||||||
if target_line:
|
if target_line:
|
||||||
stripped_line = target_line.replace(" ","")
|
stripped_line = target_line.replace(" ","")
|
||||||
arrow_line = (" " * (col_number-1)) + "^ here"
|
arrow_line = (" " * (col_number-1)) + "^ here"
|
||||||
|
|
|
@ -29,11 +29,10 @@ import shlex
|
||||||
import zipfile
|
import zipfile
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
# from Ansible
|
|
||||||
from ansible.release import __version__, __author__
|
from ansible.release import __version__, __author__
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
# Must import strategy and use write_locks from there
|
# Must import strategy and use write_locks from there
|
||||||
# If we import write_locks directly then we end up binding a
|
# If we import write_locks directly then we end up binding a
|
||||||
# variable to the object and then it never gets updated.
|
# variable to the object and then it never gets updated.
|
||||||
|
@ -45,6 +44,7 @@ except ImportError:
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
display = Display()
|
display = Display()
|
||||||
|
|
||||||
|
|
||||||
REPLACER = b"#<<INCLUDE_ANSIBLE_MODULE_COMMON>>"
|
REPLACER = b"#<<INCLUDE_ANSIBLE_MODULE_COMMON>>"
|
||||||
REPLACER_VERSION = b"\"<<ANSIBLE_VERSION>>\""
|
REPLACER_VERSION = b"\"<<ANSIBLE_VERSION>>\""
|
||||||
REPLACER_COMPLEX = b"\"<<INCLUDE_ANSIBLE_MODULE_COMPLEX_ARGS>>\""
|
REPLACER_COMPLEX = b"\"<<INCLUDE_ANSIBLE_MODULE_COMPLEX_ARGS>>\""
|
||||||
|
@ -239,7 +239,9 @@ def debug(command, zipped_mod, json_params):
|
||||||
else:
|
else:
|
||||||
os.environ['PYTHONPATH'] = basedir
|
os.environ['PYTHONPATH'] = basedir
|
||||||
|
|
||||||
p = subprocess.Popen([%(interpreter)s, script_path, args_path], env=os.environ, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
p = subprocess.Popen([%(interpreter)s, script_path, args_path],
|
||||||
|
env=os.environ, shell=False, stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||||
(stdout, stderr) = p.communicate()
|
(stdout, stderr) = p.communicate()
|
||||||
|
|
||||||
if not isinstance(stderr, (bytes, unicode)):
|
if not isinstance(stderr, (bytes, unicode)):
|
||||||
|
@ -328,6 +330,7 @@ if __name__ == '__main__':
|
||||||
sys.exit(exitcode)
|
sys.exit(exitcode)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def _strip_comments(source):
|
def _strip_comments(source):
|
||||||
# Strip comments and blank lines from the wrapper
|
# Strip comments and blank lines from the wrapper
|
||||||
buf = []
|
buf = []
|
||||||
|
@ -338,6 +341,7 @@ def _strip_comments(source):
|
||||||
buf.append(line)
|
buf.append(line)
|
||||||
return u'\n'.join(buf)
|
return u'\n'.join(buf)
|
||||||
|
|
||||||
|
|
||||||
if C.DEFAULT_KEEP_REMOTE_FILES:
|
if C.DEFAULT_KEEP_REMOTE_FILES:
|
||||||
# Keep comments when KEEP_REMOTE_FILES is set. That way users will see
|
# Keep comments when KEEP_REMOTE_FILES is set. That way users will see
|
||||||
# the comments with some nice usage instructions
|
# the comments with some nice usage instructions
|
||||||
|
@ -346,6 +350,7 @@ else:
|
||||||
# ANSIBALLZ_TEMPLATE stripped of comments for smaller over the wire size
|
# ANSIBALLZ_TEMPLATE stripped of comments for smaller over the wire size
|
||||||
ACTIVE_ANSIBALLZ_TEMPLATE = _strip_comments(ANSIBALLZ_TEMPLATE)
|
ACTIVE_ANSIBALLZ_TEMPLATE = _strip_comments(ANSIBALLZ_TEMPLATE)
|
||||||
|
|
||||||
|
|
||||||
class ModuleDepFinder(ast.NodeVisitor):
|
class ModuleDepFinder(ast.NodeVisitor):
|
||||||
# Caveats:
|
# Caveats:
|
||||||
# This code currently does not handle:
|
# This code currently does not handle:
|
||||||
|
@ -404,6 +409,7 @@ def _slurp(path):
|
||||||
fd.close()
|
fd.close()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def _get_shebang(interpreter, task_vars, args=tuple()):
|
def _get_shebang(interpreter, task_vars, args=tuple()):
|
||||||
"""
|
"""
|
||||||
Note not stellar API:
|
Note not stellar API:
|
||||||
|
@ -425,6 +431,7 @@ def _get_shebang(interpreter, task_vars, args=tuple()):
|
||||||
|
|
||||||
return (shebang, interpreter)
|
return (shebang, interpreter)
|
||||||
|
|
||||||
|
|
||||||
def recursive_finder(name, data, py_module_names, py_module_cache, zf):
|
def recursive_finder(name, data, py_module_names, py_module_cache, zf):
|
||||||
"""
|
"""
|
||||||
Using ModuleDepFinder, make sure we have all of the module_utils files that
|
Using ModuleDepFinder, make sure we have all of the module_utils files that
|
||||||
|
@ -529,11 +536,13 @@ def recursive_finder(name, data, py_module_names, py_module_cache, zf):
|
||||||
# Save memory; the file won't have to be read again for this ansible module.
|
# Save memory; the file won't have to be read again for this ansible module.
|
||||||
del py_module_cache[py_module_file]
|
del py_module_cache[py_module_file]
|
||||||
|
|
||||||
|
|
||||||
def _is_binary(module_data):
|
def _is_binary(module_data):
|
||||||
textchars = bytearray(set([7, 8, 9, 10, 12, 13, 27]) | set(range(0x20, 0x100)) - set([0x7f]))
|
textchars = bytearray(set([7, 8, 9, 10, 12, 13, 27]) | set(range(0x20, 0x100)) - set([0x7f]))
|
||||||
start = module_data[:1024]
|
start = module_data[:1024]
|
||||||
return bool(start.translate(None, textchars))
|
return bool(start.translate(None, textchars))
|
||||||
|
|
||||||
|
|
||||||
def _find_snippet_imports(module_name, module_data, module_path, module_args, task_vars, module_compression):
|
def _find_snippet_imports(module_name, module_data, module_path, module_args, task_vars, module_compression):
|
||||||
"""
|
"""
|
||||||
Given the source of the module, convert it to a Jinja2 template to insert
|
Given the source of the module, convert it to a Jinja2 template to insert
|
||||||
|
@ -617,9 +626,12 @@ def _find_snippet_imports(module_name, module_data, module_path, module_args, ta
|
||||||
# Create the module zip data
|
# Create the module zip data
|
||||||
zipoutput = BytesIO()
|
zipoutput = BytesIO()
|
||||||
zf = zipfile.ZipFile(zipoutput, mode='w', compression=compression_method)
|
zf = zipfile.ZipFile(zipoutput, mode='w', compression=compression_method)
|
||||||
### Note: If we need to import from release.py first,
|
# Note: If we need to import from release.py first,
|
||||||
### remember to catch all exceptions: https://github.com/ansible/ansible/issues/16523
|
# remember to catch all exceptions: https://github.com/ansible/ansible/issues/16523
|
||||||
zf.writestr('ansible/__init__.py', b'from pkgutil import extend_path\n__path__=extend_path(__path__,__name__)\n__version__="' + to_bytes(__version__) + b'"\n__author__="' + to_bytes(__author__) + b'"\n')
|
zf.writestr('ansible/__init__.py',
|
||||||
|
b'from pkgutil import extend_path\n__path__=extend_path(__path__,__name__)\n__version__="' +
|
||||||
|
to_bytes(__version__) + b'"\n__author__="' +
|
||||||
|
to_bytes(__author__) + b'"\n')
|
||||||
zf.writestr('ansible/module_utils/__init__.py', b'from pkgutil import extend_path\n__path__=extend_path(__path__,__name__)\n')
|
zf.writestr('ansible/module_utils/__init__.py', b'from pkgutil import extend_path\n__path__=extend_path(__path__,__name__)\n')
|
||||||
|
|
||||||
zf.writestr('ansible_module_%s.py' % module_name, module_data)
|
zf.writestr('ansible_module_%s.py' % module_name, module_data)
|
||||||
|
@ -655,8 +667,9 @@ def _find_snippet_imports(module_name, module_data, module_path, module_args, ta
|
||||||
try:
|
try:
|
||||||
zipdata = open(cached_module_filename, 'rb').read()
|
zipdata = open(cached_module_filename, 'rb').read()
|
||||||
except IOError:
|
except IOError:
|
||||||
raise AnsibleError('A different worker process failed to create module file. Look at traceback for that process for debugging information.')
|
raise AnsibleError('A different worker process failed to create module file.'
|
||||||
zipdata = to_unicode(zipdata, errors='strict')
|
' Look at traceback for that process for debugging information.')
|
||||||
|
zipdata = to_text(zipdata, errors='surrogate_or_strict')
|
||||||
|
|
||||||
shebang, interpreter = _get_shebang(u'/usr/bin/python', task_vars)
|
shebang, interpreter = _get_shebang(u'/usr/bin/python', task_vars)
|
||||||
if shebang is None:
|
if shebang is None:
|
||||||
|
@ -674,7 +687,7 @@ def _find_snippet_imports(module_name, module_data, module_path, module_args, ta
|
||||||
shebang=shebang,
|
shebang=shebang,
|
||||||
interpreter=interpreter,
|
interpreter=interpreter,
|
||||||
coding=ENCODING_STRING,
|
coding=ENCODING_STRING,
|
||||||
)))
|
)))
|
||||||
module_data = output.getvalue()
|
module_data = output.getvalue()
|
||||||
|
|
||||||
elif module_substyle == 'powershell':
|
elif module_substyle == 'powershell':
|
||||||
|
@ -721,12 +734,11 @@ def _find_snippet_imports(module_name, module_data, module_path, module_args, ta
|
||||||
# The main event -- substitute the JSON args string into the module
|
# The main event -- substitute the JSON args string into the module
|
||||||
module_data = module_data.replace(REPLACER_JSONARGS, module_args_json)
|
module_data = module_data.replace(REPLACER_JSONARGS, module_args_json)
|
||||||
|
|
||||||
facility = b'syslog.' + to_bytes(task_vars.get('ansible_syslog_facility', C.DEFAULT_SYSLOG_FACILITY), errors='strict')
|
facility = b'syslog.' + to_bytes(task_vars.get('ansible_syslog_facility', C.DEFAULT_SYSLOG_FACILITY), errors='surrogate_or_strict')
|
||||||
module_data = module_data.replace(b'syslog.LOG_USER', facility)
|
module_data = module_data.replace(b'syslog.LOG_USER', facility)
|
||||||
|
|
||||||
return (module_data, module_style, shebang)
|
return (module_data, module_style, shebang)
|
||||||
|
|
||||||
# ******************************************************************************
|
|
||||||
|
|
||||||
def modify_module(module_name, module_path, module_args, task_vars=dict(), module_compression='ZIP_STORED'):
|
def modify_module(module_name, module_path, module_args, task_vars=dict(), module_compression='ZIP_STORED'):
|
||||||
"""
|
"""
|
||||||
|
@ -760,7 +772,7 @@ def modify_module(module_name, module_path, module_args, task_vars=dict(), modul
|
||||||
(module_data, module_style, shebang) = _find_snippet_imports(module_name, module_data, module_path, module_args, task_vars, module_compression)
|
(module_data, module_style, shebang) = _find_snippet_imports(module_name, module_data, module_path, module_args, task_vars, module_compression)
|
||||||
|
|
||||||
if module_style == 'binary':
|
if module_style == 'binary':
|
||||||
return (module_data, module_style, to_unicode(shebang, nonstring='passthru'))
|
return (module_data, module_style, to_text(shebang, nonstring='passthru'))
|
||||||
elif shebang is None:
|
elif shebang is None:
|
||||||
lines = module_data.split(b"\n", 1)
|
lines = module_data.split(b"\n", 1)
|
||||||
if lines[0].startswith(b"#!"):
|
if lines[0].startswith(b"#!"):
|
||||||
|
@ -769,7 +781,7 @@ def modify_module(module_name, module_path, module_args, task_vars=dict(), modul
|
||||||
interpreter = args[0]
|
interpreter = args[0]
|
||||||
interpreter = to_bytes(interpreter)
|
interpreter = to_bytes(interpreter)
|
||||||
|
|
||||||
new_shebang = to_bytes(_get_shebang(interpreter, task_vars, args[1:])[0], errors='strict', nonstring='passthru')
|
new_shebang = to_bytes(_get_shebang(interpreter, task_vars, args[1:])[0], errors='surrogate_or_strict', nonstring='passthru')
|
||||||
if new_shebang:
|
if new_shebang:
|
||||||
lines[0] = shebang = new_shebang
|
lines[0] = shebang = new_shebang
|
||||||
|
|
||||||
|
@ -781,6 +793,6 @@ def modify_module(module_name, module_path, module_args, task_vars=dict(), modul
|
||||||
|
|
||||||
module_data = b"\n".join(lines)
|
module_data = b"\n".join(lines)
|
||||||
else:
|
else:
|
||||||
shebang = to_bytes(shebang, errors='strict')
|
shebang = to_bytes(shebang, errors='surrogate_or_strict')
|
||||||
|
|
||||||
return (module_data, module_style, to_unicode(shebang, nonstring='passthru'))
|
return (module_data, module_style, to_text(shebang, nonstring='passthru'))
|
||||||
|
|
|
@ -21,15 +21,13 @@ __metaclass__ = type
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ansible.compat.six import string_types
|
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.executor.task_queue_manager import TaskQueueManager
|
from ansible.executor.task_queue_manager import TaskQueueManager
|
||||||
|
from ansible.module_utils._text import to_native, to_text
|
||||||
from ansible.playbook import Playbook
|
from ansible.playbook import Playbook
|
||||||
from ansible.template import Templar
|
from ansible.template import Templar
|
||||||
from ansible.utils.helpers import pct_to_int
|
from ansible.utils.helpers import pct_to_int
|
||||||
from ansible.utils.path import makedirs_safe
|
from ansible.utils.path import makedirs_safe
|
||||||
from ansible.utils.unicode import to_unicode, to_str
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -74,7 +72,7 @@ class PlaybookExecutor:
|
||||||
pb = Playbook.load(playbook_path, variable_manager=self._variable_manager, loader=self._loader)
|
pb = Playbook.load(playbook_path, variable_manager=self._variable_manager, loader=self._loader)
|
||||||
self._inventory.set_playbook_basedir(os.path.realpath(os.path.dirname(playbook_path)))
|
self._inventory.set_playbook_basedir(os.path.realpath(os.path.dirname(playbook_path)))
|
||||||
|
|
||||||
if self._tqm is None: # we are doing a listing
|
if self._tqm is None: # we are doing a listing
|
||||||
entry = {'playbook': playbook_path}
|
entry = {'playbook': playbook_path}
|
||||||
entry['plays'] = []
|
entry['plays'] = []
|
||||||
else:
|
else:
|
||||||
|
@ -84,7 +82,7 @@ class PlaybookExecutor:
|
||||||
|
|
||||||
i = 1
|
i = 1
|
||||||
plays = pb.get_plays()
|
plays = pb.get_plays()
|
||||||
display.vv(u'%d plays in %s' % (len(plays), to_unicode(playbook_path)))
|
display.vv(u'%d plays in %s' % (len(plays), to_text(playbook_path)))
|
||||||
|
|
||||||
for play in plays:
|
for play in plays:
|
||||||
if play._included_path is not None:
|
if play._included_path is not None:
|
||||||
|
@ -110,7 +108,7 @@ class PlaybookExecutor:
|
||||||
if self._tqm:
|
if self._tqm:
|
||||||
self._tqm.send_callback('v2_playbook_on_vars_prompt', vname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
self._tqm.send_callback('v2_playbook_on_vars_prompt', vname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
||||||
play.vars[vname] = display.do_var_prompt(vname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
play.vars[vname] = display.do_var_prompt(vname, private, prompt, encrypt, confirm, salt_size, salt, default)
|
||||||
else: # we are either in --list-<option> or syntax check
|
else: # we are either in --list-<option> or syntax check
|
||||||
play.vars[vname] = default
|
play.vars[vname] = default
|
||||||
|
|
||||||
# Create a temporary copy of the play here, so we can run post_validate
|
# Create a temporary copy of the play here, so we can run post_validate
|
||||||
|
@ -156,7 +154,7 @@ class PlaybookExecutor:
|
||||||
# conditions are met, we break out, otherwise we only break out if the entire
|
# conditions are met, we break out, otherwise we only break out if the entire
|
||||||
# batch failed
|
# batch failed
|
||||||
failed_hosts_count = len(self._tqm._failed_hosts) + len(self._tqm._unreachable_hosts) - \
|
failed_hosts_count = len(self._tqm._failed_hosts) + len(self._tqm._unreachable_hosts) - \
|
||||||
(previously_failed + previously_unreachable)
|
(previously_failed + previously_unreachable)
|
||||||
|
|
||||||
if len(batch) == failed_hosts_count:
|
if len(batch) == failed_hosts_count:
|
||||||
break_play = True
|
break_play = True
|
||||||
|
@ -173,10 +171,10 @@ class PlaybookExecutor:
|
||||||
if break_play:
|
if break_play:
|
||||||
break
|
break
|
||||||
|
|
||||||
i = i + 1 # per play
|
i = i + 1 # per play
|
||||||
|
|
||||||
if entry:
|
if entry:
|
||||||
entrylist.append(entry) # per playbook
|
entrylist.append(entry) # per playbook
|
||||||
|
|
||||||
# send the stats callback for this playbook
|
# send the stats callback for this playbook
|
||||||
if self._tqm is not None:
|
if self._tqm is not None:
|
||||||
|
@ -276,7 +274,7 @@ class PlaybookExecutor:
|
||||||
for x in replay_hosts:
|
for x in replay_hosts:
|
||||||
fd.write("%s\n" % x)
|
fd.write("%s\n" % x)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
display.warning("Could not create retry file '%s'.\n\t%s" % (retry_path, to_str(e)))
|
display.warning("Could not create retry file '%s'.\n\t%s" % (retry_path, to_native(e)))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -19,16 +19,10 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
from ansible.compat.six.moves import queue
|
|
||||||
|
|
||||||
import json
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import signal
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
|
||||||
import traceback
|
import traceback
|
||||||
import zlib
|
|
||||||
|
|
||||||
from jinja2.exceptions import TemplateNotFound
|
from jinja2.exceptions import TemplateNotFound
|
||||||
|
|
||||||
|
@ -40,13 +34,10 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAS_ATFORK=False
|
HAS_ATFORK=False
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure
|
from ansible.errors import AnsibleConnectionFailure
|
||||||
from ansible.executor.task_executor import TaskExecutor
|
from ansible.executor.task_executor import TaskExecutor
|
||||||
from ansible.executor.task_result import TaskResult
|
from ansible.executor.task_result import TaskResult
|
||||||
from ansible.playbook.handler import Handler
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.playbook.task import Task
|
|
||||||
from ansible.vars.unsafe_proxy import AnsibleJSONUnsafeDecoder
|
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -144,11 +135,11 @@ class WorkerProcess(multiprocessing.Process):
|
||||||
try:
|
try:
|
||||||
self._host.vars = dict()
|
self._host.vars = dict()
|
||||||
self._host.groups = []
|
self._host.groups = []
|
||||||
task_result = TaskResult(self._host.name, self._task._uuid, dict(failed=True, exception=to_unicode(traceback.format_exc()), stdout=''))
|
task_result = TaskResult(self._host.name, self._task._uuid, dict(failed=True, exception=to_text(traceback.format_exc()), stdout=''))
|
||||||
self._rslt_q.put(task_result, block=False)
|
self._rslt_q.put(task_result, block=False)
|
||||||
except:
|
except:
|
||||||
display.debug(u"WORKER EXCEPTION: %s" % to_unicode(e))
|
display.debug(u"WORKER EXCEPTION: %s" % to_text(e))
|
||||||
display.debug(u"WORKER TRACEBACK: %s" % to_unicode(traceback.format_exc()))
|
display.debug(u"WORKER TRACEBACK: %s" % to_text(traceback.format_exc()))
|
||||||
|
|
||||||
display.debug("WORKER PROCESS EXITING")
|
display.debug("WORKER PROCESS EXITING")
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import json
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
@ -31,12 +30,12 @@ from ansible.compat.six import iteritems, string_types, binary_type
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleConnectionFailure
|
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleConnectionFailure
|
||||||
from ansible.executor.task_result import TaskResult
|
from ansible.executor.task_result import TaskResult
|
||||||
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
from ansible.playbook.conditional import Conditional
|
from ansible.playbook.conditional import Conditional
|
||||||
from ansible.playbook.task import Task
|
from ansible.playbook.task import Task
|
||||||
from ansible.template import Templar
|
from ansible.template import Templar
|
||||||
from ansible.utils.encrypt import key_for_hostname
|
from ansible.utils.encrypt import key_for_hostname
|
||||||
from ansible.utils.listify import listify_lookup_plugin_terms
|
from ansible.utils.listify import listify_lookup_plugin_terms
|
||||||
from ansible.utils.unicode import to_unicode, to_bytes
|
|
||||||
from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var
|
from ansible.vars.unsafe_proxy import UnsafeProxy, wrap_var
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -130,7 +129,7 @@ class TaskExecutor:
|
||||||
if isinstance(res, UnsafeProxy):
|
if isinstance(res, UnsafeProxy):
|
||||||
return res._obj
|
return res._obj
|
||||||
elif isinstance(res, binary_type):
|
elif isinstance(res, binary_type):
|
||||||
return to_unicode(res, errors='strict')
|
return to_text(res, errors='surrogate_or_strict')
|
||||||
elif isinstance(res, dict):
|
elif isinstance(res, dict):
|
||||||
for k in res:
|
for k in res:
|
||||||
res[k] = _clean_res(res[k])
|
res[k] = _clean_res(res[k])
|
||||||
|
@ -144,16 +143,16 @@ class TaskExecutor:
|
||||||
display.debug("done dumping result, returning")
|
display.debug("done dumping result, returning")
|
||||||
return res
|
return res
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
return dict(failed=True, msg=to_unicode(e, nonstring='simplerepr'))
|
return dict(failed=True, msg=to_text(e, nonstring='simplerepr'))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return dict(failed=True, msg='Unexpected failure during module execution.', exception=to_unicode(traceback.format_exc()), stdout='')
|
return dict(failed=True, msg='Unexpected failure during module execution.', exception=to_text(traceback.format_exc()), stdout='')
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
self._connection.close()
|
self._connection.close()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
display.debug(u"error closing connection: %s" % to_unicode(e))
|
display.debug(u"error closing connection: %s" % to_text(e))
|
||||||
|
|
||||||
def _get_loop_items(self):
|
def _get_loop_items(self):
|
||||||
'''
|
'''
|
||||||
|
@ -177,16 +176,18 @@ class TaskExecutor:
|
||||||
items = None
|
items = None
|
||||||
if self._task.loop:
|
if self._task.loop:
|
||||||
if self._task.loop in self._shared_loader_obj.lookup_loader:
|
if self._task.loop in self._shared_loader_obj.lookup_loader:
|
||||||
#TODO: remove convert_bare true and deprecate this in with_
|
# TODO: remove convert_bare true and deprecate this in with_
|
||||||
if self._task.loop == 'first_found':
|
if self._task.loop == 'first_found':
|
||||||
# first_found loops are special. If the item is undefined
|
# first_found loops are special. If the item is undefined
|
||||||
# then we want to fall through to the next value rather
|
# then we want to fall through to the next value rather
|
||||||
# than failing.
|
# than failing.
|
||||||
loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=False, convert_bare=True)
|
loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar,
|
||||||
|
loader=self._loader, fail_on_undefined=False, convert_bare=True)
|
||||||
loop_terms = [t for t in loop_terms if not templar._contains_vars(t)]
|
loop_terms = [t for t in loop_terms if not templar._contains_vars(t)]
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar, loader=self._loader, fail_on_undefined=True, convert_bare=True)
|
loop_terms = listify_lookup_plugin_terms(terms=self._task.loop_args, templar=templar,
|
||||||
|
loader=self._loader, fail_on_undefined=True, convert_bare=True)
|
||||||
except AnsibleUndefinedVariable as e:
|
except AnsibleUndefinedVariable as e:
|
||||||
display.deprecated("Skipping task due to undefined Error, in the future this will be a fatal error.: %s" % to_bytes(e))
|
display.deprecated("Skipping task due to undefined Error, in the future this will be a fatal error.: %s" % to_bytes(e))
|
||||||
return None
|
return None
|
||||||
|
@ -195,7 +196,7 @@ class TaskExecutor:
|
||||||
mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar)
|
mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar)
|
||||||
|
|
||||||
# give lookup task 'context' for subdir (mostly needed for first_found)
|
# give lookup task 'context' for subdir (mostly needed for first_found)
|
||||||
for subdir in ['template', 'var', 'file']: #TODO: move this to constants?
|
for subdir in ['template', 'var', 'file']: # TODO: move this to constants?
|
||||||
if subdir in self._task.action:
|
if subdir in self._task.action:
|
||||||
break
|
break
|
||||||
setattr(mylookup,'_subdir', subdir + 's')
|
setattr(mylookup,'_subdir', subdir + 's')
|
||||||
|
@ -239,13 +240,15 @@ class TaskExecutor:
|
||||||
label = None
|
label = None
|
||||||
loop_pause = 0
|
loop_pause = 0
|
||||||
if self._task.loop_control:
|
if self._task.loop_control:
|
||||||
# the value may be 'None', so we still need to default it back to 'item'
|
# the value may be 'None', so we still need to default it back to 'item'
|
||||||
loop_var = self._task.loop_control.loop_var or 'item'
|
loop_var = self._task.loop_control.loop_var or 'item'
|
||||||
label = self._task.loop_control.label or ('{{' + loop_var + '}}')
|
label = self._task.loop_control.label or ('{{' + loop_var + '}}')
|
||||||
loop_pause = self._task.loop_control.pause or 0
|
loop_pause = self._task.loop_control.pause or 0
|
||||||
|
|
||||||
if loop_var in task_vars:
|
if loop_var in task_vars:
|
||||||
display.warning("The loop variable '%s' is already in use. You should set the `loop_var` value in the `loop_control` option for the task to something else to avoid variable collisions and unexpected behavior." % loop_var)
|
display.warning(u"The loop variable '%s' is already in use."
|
||||||
|
u"You should set the `loop_var` value in the `loop_control` option for the task"
|
||||||
|
u" to something else to avoid variable collisions and unexpected behavior." % loop_var)
|
||||||
|
|
||||||
ran_once = False
|
ran_once = False
|
||||||
items = self._squash_items(items, loop_var, task_vars)
|
items = self._squash_items(items, loop_var, task_vars)
|
||||||
|
@ -263,7 +266,7 @@ class TaskExecutor:
|
||||||
tmp_task._parent = self._task._parent
|
tmp_task._parent = self._task._parent
|
||||||
tmp_play_context = self._play_context.copy()
|
tmp_play_context = self._play_context.copy()
|
||||||
except AnsibleParserError as e:
|
except AnsibleParserError as e:
|
||||||
results.append(dict(failed=True, msg=to_unicode(e)))
|
results.append(dict(failed=True, msg=to_text(e)))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# now we swap the internal task and play context with their copies,
|
# now we swap the internal task and play context with their copies,
|
||||||
|
@ -279,7 +282,7 @@ class TaskExecutor:
|
||||||
res[loop_var] = item
|
res[loop_var] = item
|
||||||
res['_ansible_item_result'] = True
|
res['_ansible_item_result'] = True
|
||||||
|
|
||||||
if not label is None:
|
if label is not None:
|
||||||
templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars)
|
templar = Templar(loader=self._loader, shared_loader_obj=self._shared_loader_obj, variables=self._job_vars)
|
||||||
res['_ansible_item_label'] = templar.template(label, fail_on_undefined=False)
|
res['_ansible_item_label'] = templar.template(label, fail_on_undefined=False)
|
||||||
|
|
||||||
|
@ -421,7 +424,7 @@ class TaskExecutor:
|
||||||
include_file = templar.template(include_file)
|
include_file = templar.template(include_file)
|
||||||
return dict(include=include_file, include_variables=include_variables)
|
return dict(include=include_file, include_variables=include_variables)
|
||||||
|
|
||||||
#TODO: not needed?
|
# TODO: not needed?
|
||||||
# if this task is a IncludeRole, we just return now with a success code so the main thread can expand the task list for the given host
|
# if this task is a IncludeRole, we just return now with a success code so the main thread can expand the task list for the given host
|
||||||
elif self._task.action == 'include_role':
|
elif self._task.action == 'include_role':
|
||||||
include_variables = self._task.args.copy()
|
include_variables = self._task.args.copy()
|
||||||
|
@ -482,7 +485,7 @@ class TaskExecutor:
|
||||||
try:
|
try:
|
||||||
result = self._handler.run(task_vars=variables)
|
result = self._handler.run(task_vars=variables)
|
||||||
except AnsibleConnectionFailure as e:
|
except AnsibleConnectionFailure as e:
|
||||||
return dict(unreachable=True, msg=to_unicode(e))
|
return dict(unreachable=True, msg=to_text(e))
|
||||||
display.debug("handler run complete")
|
display.debug("handler run complete")
|
||||||
|
|
||||||
# preserve no log
|
# preserve no log
|
||||||
|
@ -666,7 +669,7 @@ class TaskExecutor:
|
||||||
try:
|
try:
|
||||||
cmd = subprocess.Popen(['ssh','-o','ControlPersist'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
cmd = subprocess.Popen(['ssh','-o','ControlPersist'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
(out, err) = cmd.communicate()
|
(out, err) = cmd.communicate()
|
||||||
err = to_unicode(err)
|
err = to_text(err)
|
||||||
if u"Bad configuration option" in err or u"Usage:" in err:
|
if u"Bad configuration option" in err or u"Usage:" in err:
|
||||||
conn_type = "paramiko"
|
conn_type = "paramiko"
|
||||||
except OSError:
|
except OSError:
|
||||||
|
|
|
@ -28,21 +28,20 @@ import time
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
|
from ansible.compat.six import string_types
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.executor import action_write_locks
|
from ansible.executor import action_write_locks
|
||||||
from ansible.executor.play_iterator import PlayIterator
|
from ansible.executor.play_iterator import PlayIterator
|
||||||
from ansible.executor.process.worker import WorkerProcess
|
from ansible.executor.process.worker import WorkerProcess
|
||||||
from ansible.executor.stats import AggregateStats
|
from ansible.executor.stats import AggregateStats
|
||||||
from ansible.module_utils.facts import Facts
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.playbook.block import Block
|
from ansible.playbook.block import Block
|
||||||
from ansible.playbook.play_context import PlayContext
|
from ansible.playbook.play_context import PlayContext
|
||||||
from ansible.plugins import action_loader, callback_loader, connection_loader, filter_loader, lookup_loader, module_loader, strategy_loader, test_loader
|
from ansible.plugins import action_loader, callback_loader, connection_loader, filter_loader, lookup_loader, module_loader, strategy_loader, test_loader
|
||||||
from ansible.template import Templar
|
|
||||||
from ansible.vars.hostvars import HostVars
|
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
from ansible.template import Templar
|
||||||
from ansible.utils.helpers import pct_to_int
|
from ansible.utils.helpers import pct_to_int
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.vars.hostvars import HostVars
|
||||||
from ansible.compat.six import string_types
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -288,7 +287,8 @@ class TaskQueueManager:
|
||||||
stdout_callback_loaded = True
|
stdout_callback_loaded = True
|
||||||
elif callback_name == 'tree' and self._run_tree:
|
elif callback_name == 'tree' and self._run_tree:
|
||||||
pass
|
pass
|
||||||
elif not self._run_additional_callbacks or (callback_needs_whitelist and (C.DEFAULT_CALLBACK_WHITELIST is None or callback_name not in C.DEFAULT_CALLBACK_WHITELIST)):
|
elif not self._run_additional_callbacks or (callback_needs_whitelist and (
|
||||||
|
C.DEFAULT_CALLBACK_WHITELIST is None or callback_name not in C.DEFAULT_CALLBACK_WHITELIST)):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self._callback_plugins.append(callback_plugin())
|
self._callback_plugins.append(callback_plugin())
|
||||||
|
@ -336,8 +336,8 @@ class TaskQueueManager:
|
||||||
serial_items = [serial_items]
|
serial_items = [serial_items]
|
||||||
max_serial = max([pct_to_int(x, num_hosts) for x in serial_items])
|
max_serial = max([pct_to_int(x, num_hosts) for x in serial_items])
|
||||||
|
|
||||||
contenders = [self._options.forks, max_serial, num_hosts]
|
contenders = [self._options.forks, max_serial, num_hosts]
|
||||||
contenders = [v for v in contenders if v is not None and v > 0]
|
contenders = [v for v in contenders if v is not None and v > 0]
|
||||||
self._initialize_processes(min(contenders))
|
self._initialize_processes(min(contenders))
|
||||||
|
|
||||||
play_context = PlayContext(new_play, self._options, self.passwords, self._connection_lockfile.fileno())
|
play_context = PlayContext(new_play, self._options, self.passwords, self._connection_lockfile.fileno())
|
||||||
|
@ -446,7 +446,7 @@ class TaskQueueManager:
|
||||||
# try to find v2 method, fallback to v1 method, ignore callback if no method found
|
# try to find v2 method, fallback to v1 method, ignore callback if no method found
|
||||||
methods = []
|
methods = []
|
||||||
for possible in [method_name, 'v2_on_any']:
|
for possible in [method_name, 'v2_on_any']:
|
||||||
gotit = getattr(callback_plugin, possible, None)
|
gotit = getattr(callback_plugin, possible, None)
|
||||||
if gotit is None:
|
if gotit is None:
|
||||||
gotit = getattr(callback_plugin, possible.replace('v2_',''), None)
|
gotit = getattr(callback_plugin, possible.replace('v2_',''), None)
|
||||||
if gotit is not None:
|
if gotit is not None:
|
||||||
|
@ -468,8 +468,8 @@ class TaskQueueManager:
|
||||||
else:
|
else:
|
||||||
method(*args, **kwargs)
|
method(*args, **kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
#TODO: add config toggle to make this fatal or not?
|
# TODO: add config toggle to make this fatal or not?
|
||||||
display.warning(u"Failure using method (%s) in callback plugin (%s): %s" % (to_unicode(method_name), to_unicode(callback_plugin), to_unicode(e)))
|
display.warning(u"Failure using method (%s) in callback plugin (%s): %s" % (to_text(method_name), to_text(callback_plugin), to_text(e)))
|
||||||
from traceback import format_tb
|
from traceback import format_tb
|
||||||
from sys import exc_info
|
from sys import exc_info
|
||||||
display.debug('Callback Exception: \n' + ' '.join(format_tb(exc_info()[2])))
|
display.debug('Callback Exception: \n' + ' '.join(format_tb(exc_info()[2])))
|
||||||
|
|
|
@ -28,12 +28,12 @@ import json
|
||||||
|
|
||||||
import ansible.constants as C
|
import ansible.constants as C
|
||||||
from ansible.compat.six import string_types
|
from ansible.compat.six import string_types
|
||||||
from ansible.compat.six.moves.urllib.parse import quote as urlquote, urlencode
|
|
||||||
from ansible.compat.six.moves.urllib.error import HTTPError
|
from ansible.compat.six.moves.urllib.error import HTTPError
|
||||||
|
from ansible.compat.six.moves.urllib.parse import quote as urlquote, urlencode
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.module_utils.urls import open_url
|
|
||||||
from ansible.galaxy.token import GalaxyToken
|
from ansible.galaxy.token import GalaxyToken
|
||||||
from ansible.utils.unicode import to_str
|
from ansible.module_utils._text import to_native
|
||||||
|
from ansible.module_utils.urls import open_url
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -115,12 +115,12 @@ class GalaxyAPI(object):
|
||||||
try:
|
try:
|
||||||
return_data = open_url(url, validate_certs=self._validate_certs)
|
return_data = open_url(url, validate_certs=self._validate_certs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError("Failed to get data from the API server (%s): %s " % (url, to_str(e)))
|
raise AnsibleError("Failed to get data from the API server (%s): %s " % (url, to_native(e)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = json.load(return_data)
|
data = json.load(return_data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError("Could not process data from the API server (%s): %s " % (url, to_str(e)))
|
raise AnsibleError("Could not process data from the API server (%s): %s " % (url, to_native(e)))
|
||||||
|
|
||||||
if 'current_version' not in data:
|
if 'current_version' not in data:
|
||||||
raise AnsibleError("missing required 'current_version' from server response (%s)" % url)
|
raise AnsibleError("missing required 'current_version' from server response (%s)" % url)
|
||||||
|
|
|
@ -33,12 +33,10 @@ from ansible.errors import AnsibleError
|
||||||
from ansible.inventory.dir import InventoryDirectory, get_file_parser
|
from ansible.inventory.dir import InventoryDirectory, get_file_parser
|
||||||
from ansible.inventory.group import Group
|
from ansible.inventory.group import Group
|
||||||
from ansible.inventory.host import Host
|
from ansible.inventory.host import Host
|
||||||
from ansible.plugins import vars_loader
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
from ansible.utils.unicode import to_unicode, to_bytes
|
|
||||||
from ansible.utils.vars import combine_vars
|
|
||||||
from ansible.parsing.utils.addresses import parse_address
|
from ansible.parsing.utils.addresses import parse_address
|
||||||
|
from ansible.plugins import vars_loader
|
||||||
HOSTS_PATTERNS_CACHE = {}
|
from ansible.utils.vars import combine_vars
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -46,6 +44,10 @@ except ImportError:
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
display = Display()
|
display = Display()
|
||||||
|
|
||||||
|
|
||||||
|
HOSTS_PATTERNS_CACHE = {}
|
||||||
|
|
||||||
|
|
||||||
class Inventory(object):
|
class Inventory(object):
|
||||||
"""
|
"""
|
||||||
Host inventory for ansible.
|
Host inventory for ansible.
|
||||||
|
@ -125,7 +127,7 @@ class Inventory(object):
|
||||||
try:
|
try:
|
||||||
(host, port) = parse_address(h, allow_ranges=False)
|
(host, port) = parse_address(h, allow_ranges=False)
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
display.vvv("Unable to parse address from hostname, leaving unchanged: %s" % to_unicode(e))
|
display.vvv("Unable to parse address from hostname, leaving unchanged: %s" % to_text(e))
|
||||||
host = h
|
host = h
|
||||||
port = None
|
port = None
|
||||||
|
|
||||||
|
@ -138,7 +140,7 @@ class Inventory(object):
|
||||||
self.localhost = new_host
|
self.localhost = new_host
|
||||||
all.add_host(new_host)
|
all.add_host(new_host)
|
||||||
elif self._loader.path_exists(host_list):
|
elif self._loader.path_exists(host_list):
|
||||||
#TODO: switch this to a plugin loader and a 'condition' per plugin on which it should be tried, restoring 'inventory pllugins'
|
# TODO: switch this to a plugin loader and a 'condition' per plugin on which it should be tried, restoring 'inventory pllugins'
|
||||||
if self.is_directory(host_list):
|
if self.is_directory(host_list):
|
||||||
# Ensure basedir is inside the directory
|
# Ensure basedir is inside the directory
|
||||||
host_list = os.path.join(self.host_list, "")
|
host_list = os.path.join(self.host_list, "")
|
||||||
|
@ -151,7 +153,7 @@ class Inventory(object):
|
||||||
# should never happen, but JIC
|
# should never happen, but JIC
|
||||||
raise AnsibleError("Unable to parse %s as an inventory source" % host_list)
|
raise AnsibleError("Unable to parse %s as an inventory source" % host_list)
|
||||||
else:
|
else:
|
||||||
display.warning("Host file not found: %s" % to_unicode(host_list))
|
display.warning("Host file not found: %s" % to_text(host_list))
|
||||||
|
|
||||||
self._vars_plugins = [ x for x in vars_loader.all(self) ]
|
self._vars_plugins = [ x for x in vars_loader.all(self) ]
|
||||||
|
|
||||||
|
@ -191,7 +193,7 @@ class Inventory(object):
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def get_hosts(self, pattern="all", ignore_limits_and_restrictions=False):
|
def get_hosts(self, pattern="all", ignore_limits_and_restrictions=False):
|
||||||
"""
|
"""
|
||||||
Takes a pattern or list of patterns and returns a list of matching
|
Takes a pattern or list of patterns and returns a list of matching
|
||||||
inventory host names, taking into account any active restrictions
|
inventory host names, taking into account any active restrictions
|
||||||
or applied subsets
|
or applied subsets
|
||||||
|
@ -205,9 +207,9 @@ class Inventory(object):
|
||||||
|
|
||||||
if not ignore_limits_and_restrictions:
|
if not ignore_limits_and_restrictions:
|
||||||
if self._subset:
|
if self._subset:
|
||||||
pattern_hash += u":%s" % to_unicode(self._subset)
|
pattern_hash += u":%s" % to_text(self._subset)
|
||||||
if self._restriction:
|
if self._restriction:
|
||||||
pattern_hash += u":%s" % to_unicode(self._restriction)
|
pattern_hash += u":%s" % to_text(self._restriction)
|
||||||
|
|
||||||
if pattern_hash not in HOSTS_PATTERNS_CACHE:
|
if pattern_hash not in HOSTS_PATTERNS_CACHE:
|
||||||
|
|
||||||
|
@ -326,7 +328,7 @@ class Inventory(object):
|
||||||
return hosts
|
return hosts
|
||||||
|
|
||||||
def _match_one_pattern(self, pattern):
|
def _match_one_pattern(self, pattern):
|
||||||
"""
|
"""
|
||||||
Takes a single pattern and returns a list of matching host names.
|
Takes a single pattern and returns a list of matching host names.
|
||||||
Ignores intersection (&) and exclusion (!) specifiers.
|
Ignores intersection (&) and exclusion (!) specifiers.
|
||||||
|
|
||||||
|
@ -426,7 +428,7 @@ class Inventory(object):
|
||||||
"""
|
"""
|
||||||
Takes a list of hosts and a (start,end) tuple and returns the subset of
|
Takes a list of hosts and a (start,end) tuple and returns the subset of
|
||||||
hosts based on the subscript (which may be None to return all hosts).
|
hosts based on the subscript (which may be None to return all hosts).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not hosts or not subscript:
|
if not hosts or not subscript:
|
||||||
return hosts
|
return hosts
|
||||||
|
@ -491,7 +493,8 @@ class Inventory(object):
|
||||||
py_interp = sys.executable
|
py_interp = sys.executable
|
||||||
if not py_interp:
|
if not py_interp:
|
||||||
# sys.executable is not set in some cornercases. #13585
|
# sys.executable is not set in some cornercases. #13585
|
||||||
display.warning('Unable to determine python interpreter from sys.executable. Using /usr/bin/python default. You can correct this by setting ansible_python_interpreter for localhost')
|
display.warning('Unable to determine python interpreter from sys.executable. Using /usr/bin/python default.'
|
||||||
|
' You can correct this by setting ansible_python_interpreter for localhost')
|
||||||
py_interp = '/usr/bin/python'
|
py_interp = '/usr/bin/python'
|
||||||
new_host.set_variable("ansible_python_interpreter", py_interp)
|
new_host.set_variable("ansible_python_interpreter", py_interp)
|
||||||
self.get_group("ungrouped").add_host(new_host)
|
self.get_group("ungrouped").add_host(new_host)
|
||||||
|
@ -648,7 +651,7 @@ class Inventory(object):
|
||||||
return sorted(self.groups.keys(), key=lambda x: x)
|
return sorted(self.groups.keys(), key=lambda x: x)
|
||||||
|
|
||||||
def restrict_to_hosts(self, restriction):
|
def restrict_to_hosts(self, restriction):
|
||||||
"""
|
"""
|
||||||
Restrict list operations to the hosts given in restriction. This is used
|
Restrict list operations to the hosts given in restriction. This is used
|
||||||
to batch serial operations in main playbook code, don't use this for other
|
to batch serial operations in main playbook code, don't use this for other
|
||||||
reasons.
|
reasons.
|
||||||
|
@ -660,12 +663,12 @@ class Inventory(object):
|
||||||
self._restriction = [ h.name for h in restriction ]
|
self._restriction = [ h.name for h in restriction ]
|
||||||
|
|
||||||
def subset(self, subset_pattern):
|
def subset(self, subset_pattern):
|
||||||
"""
|
"""
|
||||||
Limits inventory results to a subset of inventory that matches a given
|
Limits inventory results to a subset of inventory that matches a given
|
||||||
pattern, such as to select a given geographic of numeric slice amongst
|
pattern, such as to select a given geographic of numeric slice amongst
|
||||||
a previous 'hosts' selection that only select roles, or vice versa.
|
a previous 'hosts' selection that only select roles, or vice versa.
|
||||||
Corresponds to --limit parameter to ansible-playbook
|
Corresponds to --limit parameter to ansible-playbook
|
||||||
"""
|
"""
|
||||||
if subset_pattern is None:
|
if subset_pattern is None:
|
||||||
self._subset = None
|
self._subset = None
|
||||||
else:
|
else:
|
||||||
|
@ -781,7 +784,7 @@ class Inventory(object):
|
||||||
path = os.path.realpath(os.path.join(basedir, 'group_vars'))
|
path = os.path.realpath(os.path.join(basedir, 'group_vars'))
|
||||||
found_vars = set()
|
found_vars = set()
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
found_vars = set(os.listdir(to_unicode(path)))
|
found_vars = set(os.listdir(to_text(path)))
|
||||||
return found_vars
|
return found_vars
|
||||||
|
|
||||||
def _find_host_vars_files(self, basedir):
|
def _find_host_vars_files(self, basedir):
|
||||||
|
@ -791,7 +794,7 @@ class Inventory(object):
|
||||||
path = os.path.realpath(os.path.join(basedir, 'host_vars'))
|
path = os.path.realpath(os.path.join(basedir, 'host_vars'))
|
||||||
found_vars = set()
|
found_vars = set()
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
found_vars = set(os.listdir(to_unicode(path)))
|
found_vars = set(os.listdir(to_text(path)))
|
||||||
return found_vars
|
return found_vars
|
||||||
|
|
||||||
def _get_hostgroup_vars(self, host=None, group=None, new_pb_basedir=False, return_results=False):
|
def _get_hostgroup_vars(self, host=None, group=None, new_pb_basedir=False, return_results=False):
|
||||||
|
@ -832,13 +835,13 @@ class Inventory(object):
|
||||||
# Before trying to load vars from file, check that the directory contains relvant file names
|
# Before trying to load vars from file, check that the directory contains relvant file names
|
||||||
if host is None and any(map(lambda ext: group.name + ext in self._group_vars_files, C.YAML_FILENAME_EXTENSIONS)):
|
if host is None and any(map(lambda ext: group.name + ext in self._group_vars_files, C.YAML_FILENAME_EXTENSIONS)):
|
||||||
# load vars in dir/group_vars/name_of_group
|
# load vars in dir/group_vars/name_of_group
|
||||||
base_path = to_unicode(os.path.abspath(os.path.join(to_bytes(basedir), b"group_vars/" + to_bytes(group.name))), errors='strict')
|
base_path = to_text(os.path.abspath(os.path.join(to_bytes(basedir), b"group_vars/" + to_bytes(group.name))), errors='surrogate_or_strict')
|
||||||
host_results = self._variable_manager.add_group_vars_file(base_path, self._loader)
|
host_results = self._variable_manager.add_group_vars_file(base_path, self._loader)
|
||||||
if return_results:
|
if return_results:
|
||||||
results = combine_vars(results, host_results)
|
results = combine_vars(results, host_results)
|
||||||
elif group is None and any(map(lambda ext: host.name + ext in self._host_vars_files, C.YAML_FILENAME_EXTENSIONS)):
|
elif group is None and any(map(lambda ext: host.name + ext in self._host_vars_files, C.YAML_FILENAME_EXTENSIONS)):
|
||||||
# same for hostvars in dir/host_vars/name_of_host
|
# same for hostvars in dir/host_vars/name_of_host
|
||||||
base_path = to_unicode(os.path.abspath(os.path.join(to_bytes(basedir), b"host_vars/" + to_bytes(host.name))), errors='strict')
|
base_path = to_text(os.path.abspath(os.path.join(to_bytes(basedir), b"host_vars/" + to_bytes(host.name))), errors='surrogate_or_strict')
|
||||||
group_results = self._variable_manager.add_host_vars_file(base_path, self._loader)
|
group_results = self._variable_manager.add_host_vars_file(base_path, self._loader)
|
||||||
if return_results:
|
if return_results:
|
||||||
results = combine_vars(results, group_results)
|
results = combine_vars(results, group_results)
|
||||||
|
|
|
@ -28,9 +28,10 @@ from ansible.inventory.host import Host
|
||||||
from ansible.inventory.group import Group
|
from ansible.inventory.group import Group
|
||||||
from ansible.inventory.expand_hosts import detect_range
|
from ansible.inventory.expand_hosts import detect_range
|
||||||
from ansible.inventory.expand_hosts import expand_hostname_range
|
from ansible.inventory.expand_hosts import expand_hostname_range
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.parsing.utils.addresses import parse_address
|
from ansible.parsing.utils.addresses import parse_address
|
||||||
from ansible.utils.shlex import shlex_split
|
from ansible.utils.shlex import shlex_split
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
|
|
||||||
class InventoryParser(object):
|
class InventoryParser(object):
|
||||||
"""
|
"""
|
||||||
|
@ -56,7 +57,7 @@ class InventoryParser(object):
|
||||||
(data, private) = loader._get_file_contents(filename)
|
(data, private) = loader._get_file_contents(filename)
|
||||||
else:
|
else:
|
||||||
with open(filename) as fh:
|
with open(filename) as fh:
|
||||||
data = to_unicode(fh.read())
|
data = to_text(fh.read())
|
||||||
data = data.split('\n')
|
data = data.split('\n')
|
||||||
|
|
||||||
self._parse(data)
|
self._parse(data)
|
||||||
|
@ -125,7 +126,7 @@ class InventoryParser(object):
|
||||||
|
|
||||||
continue
|
continue
|
||||||
elif line.startswith('[') and line.endswith(']'):
|
elif line.startswith('[') and line.endswith(']'):
|
||||||
self._raise_error("Invalid section entry: '%s'. Please make sure that there are no spaces" % line + \
|
self._raise_error("Invalid section entry: '%s'. Please make sure that there are no spaces" % line +
|
||||||
"in the section entry, and that there are no other invalid characters")
|
"in the section entry, and that there are no other invalid characters")
|
||||||
|
|
||||||
# It's not a section, so the current state tells us what kind of
|
# It's not a section, so the current state tells us what kind of
|
||||||
|
@ -188,7 +189,6 @@ class InventoryParser(object):
|
||||||
if group.depth == 0 and group.name not in ('all', 'ungrouped'):
|
if group.depth == 0 and group.name not in ('all', 'ungrouped'):
|
||||||
self.groups['all'].add_child_group(group)
|
self.groups['all'].add_child_group(group)
|
||||||
|
|
||||||
|
|
||||||
def _parse_group_name(self, line):
|
def _parse_group_name(self, line):
|
||||||
'''
|
'''
|
||||||
Takes a single line and tries to parse it as a group name. Returns the
|
Takes a single line and tries to parse it as a group name. Returns the
|
||||||
|
@ -323,7 +323,7 @@ class InventoryParser(object):
|
||||||
except SyntaxError:
|
except SyntaxError:
|
||||||
# Is this a hash with an equals at the end?
|
# Is this a hash with an equals at the end?
|
||||||
pass
|
pass
|
||||||
return to_unicode(v, nonstring='passthru', errors='strict')
|
return to_text(v, nonstring='passthru', errors='surrogate_or_strict')
|
||||||
|
|
||||||
def get_host_variables(self, host):
|
def get_host_variables(self, host):
|
||||||
return {}
|
return {}
|
||||||
|
|
|
@ -31,7 +31,7 @@ from ansible.errors import AnsibleError
|
||||||
from ansible.inventory.host import Host
|
from ansible.inventory.host import Host
|
||||||
from ansible.inventory.group import Group
|
from ansible.inventory.group import Group
|
||||||
from ansible.module_utils.basic import json_dict_bytes_to_unicode
|
from ansible.module_utils.basic import json_dict_bytes_to_unicode
|
||||||
from ansible.utils.unicode import to_str, to_unicode
|
from ansible.module_utils._text import to_native, to_text
|
||||||
|
|
||||||
|
|
||||||
class InventoryScript:
|
class InventoryScript:
|
||||||
|
@ -61,9 +61,9 @@ class InventoryScript:
|
||||||
# make sure script output is unicode so that json loader will output
|
# make sure script output is unicode so that json loader will output
|
||||||
# unicode strings itself
|
# unicode strings itself
|
||||||
try:
|
try:
|
||||||
self.data = to_unicode(stdout, errors="strict")
|
self.data = to_text(stdout, errors="strict")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError("inventory data from {0} contained characters that cannot be interpreted as UTF-8: {1}".format(to_str(self.filename), to_str(e)))
|
raise AnsibleError("inventory data from {0} contained characters that cannot be interpreted as UTF-8: {1}".format(to_native(self.filename), to_native(e)))
|
||||||
|
|
||||||
# see comment about _meta below
|
# see comment about _meta below
|
||||||
self.host_vars_from_top = None
|
self.host_vars_from_top = None
|
||||||
|
@ -78,11 +78,11 @@ class InventoryScript:
|
||||||
self.raw = self._loader.load(self.data)
|
self.raw = self._loader.load(self.data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
sys.stderr.write(err + "\n")
|
sys.stderr.write(err + "\n")
|
||||||
raise AnsibleError("failed to parse executable inventory script results from {0}: {1}".format(to_str(self.filename), to_str(e)))
|
raise AnsibleError("failed to parse executable inventory script results from {0}: {1}".format(to_native(self.filename), to_native(e)))
|
||||||
|
|
||||||
if not isinstance(self.raw, Mapping):
|
if not isinstance(self.raw, Mapping):
|
||||||
sys.stderr.write(err + "\n")
|
sys.stderr.write(err + "\n")
|
||||||
raise AnsibleError("failed to parse executable inventory script results from {0}: data needs to be formatted as a json dict".format(to_str(self.filename)))
|
raise AnsibleError("failed to parse executable inventory script results from {0}: data needs to be formatted as a json dict".format(to_native(self.filename)))
|
||||||
|
|
||||||
group = None
|
group = None
|
||||||
for (group_name, data) in self.raw.items():
|
for (group_name, data) in self.raw.items():
|
||||||
|
@ -152,7 +152,7 @@ class InventoryScript:
|
||||||
try:
|
try:
|
||||||
got = self.host_vars_from_top.get(host.name, {})
|
got = self.host_vars_from_top.get(host.name, {})
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
raise AnsibleError("Improperly formated host information for %s: %s" % (host.name,to_str(e)))
|
raise AnsibleError("Improperly formated host information for %s: %s" % (host.name,to_native(e)))
|
||||||
return got
|
return got
|
||||||
|
|
||||||
cmd = [self.filename, "--host", host.name]
|
cmd = [self.filename, "--host", host.name]
|
||||||
|
|
|
@ -32,16 +32,18 @@
|
||||||
making backwards compatibility guarantees. The API may change between
|
making backwards compatibility guarantees. The API may change between
|
||||||
releases. Do not use this unless you are willing to port your module code.
|
releases. Do not use this unless you are willing to port your module code.
|
||||||
"""
|
"""
|
||||||
|
import codecs
|
||||||
|
|
||||||
from ansible.module_utils.six import PY3, text_type, binary_type
|
from ansible.module_utils.six import PY3, text_type, binary_type
|
||||||
|
|
||||||
import codecs
|
|
||||||
try:
|
try:
|
||||||
codecs.lookup_error('surrogateescape')
|
codecs.lookup_error('surrogateescape')
|
||||||
HAS_SURROGATEESCAPE = True
|
HAS_SURROGATEESCAPE = True
|
||||||
except LookupError:
|
except LookupError:
|
||||||
HAS_SURROGATEESCAPE = False
|
HAS_SURROGATEESCAPE = False
|
||||||
|
|
||||||
|
|
||||||
def to_bytes(obj, encoding='utf-8', errors=None, nonstring='simplerepr'):
|
def to_bytes(obj, encoding='utf-8', errors=None, nonstring='simplerepr'):
|
||||||
"""Make sure that a string is a byte string
|
"""Make sure that a string is a byte string
|
||||||
|
|
||||||
|
@ -109,7 +111,14 @@ def to_bytes(obj, encoding='utf-8', errors=None, nonstring='simplerepr'):
|
||||||
# Note: We do these last even though we have to call to_bytes again on the
|
# Note: We do these last even though we have to call to_bytes again on the
|
||||||
# value because we're optimizing the common case
|
# value because we're optimizing the common case
|
||||||
if nonstring == 'simplerepr':
|
if nonstring == 'simplerepr':
|
||||||
value = str(obj)
|
try:
|
||||||
|
value = str(obj)
|
||||||
|
except UnicodeError:
|
||||||
|
try:
|
||||||
|
value = repr(obj)
|
||||||
|
except UnicodeError:
|
||||||
|
# Giving up
|
||||||
|
return to_bytes('')
|
||||||
elif nonstring == 'passthru':
|
elif nonstring == 'passthru':
|
||||||
return obj
|
return obj
|
||||||
elif nonstring == 'empty':
|
elif nonstring == 'empty':
|
||||||
|
@ -122,6 +131,7 @@ def to_bytes(obj, encoding='utf-8', errors=None, nonstring='simplerepr'):
|
||||||
|
|
||||||
return to_bytes(value, encoding, errors)
|
return to_bytes(value, encoding, errors)
|
||||||
|
|
||||||
|
|
||||||
def to_text(obj, encoding='utf-8', errors=None, nonstring='simplerepr'):
|
def to_text(obj, encoding='utf-8', errors=None, nonstring='simplerepr'):
|
||||||
"""Make sure that a string is a text string
|
"""Make sure that a string is a text string
|
||||||
|
|
||||||
|
@ -175,7 +185,14 @@ def to_text(obj, encoding='utf-8', errors=None, nonstring='simplerepr'):
|
||||||
# Note: We do these last even though we have to call to_text again on the
|
# Note: We do these last even though we have to call to_text again on the
|
||||||
# value because we're optimizing the common case
|
# value because we're optimizing the common case
|
||||||
if nonstring == 'simplerepr':
|
if nonstring == 'simplerepr':
|
||||||
value = str(obj)
|
try:
|
||||||
|
value = str(obj)
|
||||||
|
except UnicodeError:
|
||||||
|
try:
|
||||||
|
value = repr(obj)
|
||||||
|
except UnicodeError:
|
||||||
|
# Giving up
|
||||||
|
return u''
|
||||||
elif nonstring == 'passthru':
|
elif nonstring == 'passthru':
|
||||||
return obj
|
return obj
|
||||||
elif nonstring == 'empty':
|
elif nonstring == 'empty':
|
||||||
|
@ -187,6 +204,7 @@ def to_text(obj, encoding='utf-8', errors=None, nonstring='simplerepr'):
|
||||||
|
|
||||||
return to_text(value, encoding, errors)
|
return to_text(value, encoding, errors)
|
||||||
|
|
||||||
|
|
||||||
#: :py:func:`to_native`
|
#: :py:func:`to_native`
|
||||||
#: Transform a variable into the native str type for the python version
|
#: Transform a variable into the native str type for the python version
|
||||||
#:
|
#:
|
||||||
|
|
|
@ -805,7 +805,7 @@ class AnsibleModule(object):
|
||||||
if not HAVE_SELINUX or not self.selinux_enabled():
|
if not HAVE_SELINUX or not self.selinux_enabled():
|
||||||
return context
|
return context
|
||||||
try:
|
try:
|
||||||
ret = selinux.matchpathcon(to_native(path, errors='strict'), mode)
|
ret = selinux.matchpathcon(to_native(path, errors='surrogate_or_strict'), mode)
|
||||||
except OSError:
|
except OSError:
|
||||||
return context
|
return context
|
||||||
if ret[0] == -1:
|
if ret[0] == -1:
|
||||||
|
@ -820,7 +820,7 @@ class AnsibleModule(object):
|
||||||
if not HAVE_SELINUX or not self.selinux_enabled():
|
if not HAVE_SELINUX or not self.selinux_enabled():
|
||||||
return context
|
return context
|
||||||
try:
|
try:
|
||||||
ret = selinux.lgetfilecon_raw(to_native(path, errors='strict'))
|
ret = selinux.lgetfilecon_raw(to_native(path, errors='surrogate_or_strict'))
|
||||||
except OSError:
|
except OSError:
|
||||||
e = get_exception()
|
e = get_exception()
|
||||||
if e.errno == errno.ENOENT:
|
if e.errno == errno.ENOENT:
|
||||||
|
@ -2121,10 +2121,10 @@ class AnsibleModule(object):
|
||||||
to_clean_args = args
|
to_clean_args = args
|
||||||
if PY2:
|
if PY2:
|
||||||
if isinstance(args, text_type):
|
if isinstance(args, text_type):
|
||||||
to_clean_args = args.encode('utf-8')
|
to_clean_args = to_bytes(args)
|
||||||
else:
|
else:
|
||||||
if isinstance(args, binary_type):
|
if isinstance(args, binary_type):
|
||||||
to_clean_args = args.decode('utf-8', errors='replace')
|
to_clean_args = to_text(args)
|
||||||
if isinstance(args, (text_type, binary_type)):
|
if isinstance(args, (text_type, binary_type)):
|
||||||
to_clean_args = shlex.split(to_clean_args)
|
to_clean_args = shlex.split(to_clean_args)
|
||||||
|
|
||||||
|
@ -2193,11 +2193,7 @@ class AnsibleModule(object):
|
||||||
if not binary_data:
|
if not binary_data:
|
||||||
data += '\n'
|
data += '\n'
|
||||||
if isinstance(data, text_type):
|
if isinstance(data, text_type):
|
||||||
if PY3:
|
data = to_bytes(data)
|
||||||
errors = 'surrogateescape'
|
|
||||||
else:
|
|
||||||
errors = 'strict'
|
|
||||||
data = data.encode('utf-8', errors=errors)
|
|
||||||
cmd.stdin.write(data)
|
cmd.stdin.write(data)
|
||||||
cmd.stdin.close()
|
cmd.stdin.close()
|
||||||
|
|
||||||
|
|
|
@ -27,16 +27,15 @@ import tempfile
|
||||||
from yaml import YAMLError
|
from yaml import YAMLError
|
||||||
|
|
||||||
from ansible.compat.six import text_type, string_types
|
from ansible.compat.six import text_type, string_types
|
||||||
|
|
||||||
from ansible.errors import AnsibleFileNotFound, AnsibleParserError, AnsibleError
|
from ansible.errors import AnsibleFileNotFound, AnsibleParserError, AnsibleError
|
||||||
from ansible.errors.yaml_strings import YAML_SYNTAX_ERROR
|
from ansible.errors.yaml_strings import YAML_SYNTAX_ERROR
|
||||||
|
from ansible.module_utils.basic import is_executable
|
||||||
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
from ansible.parsing.vault import VaultLib
|
from ansible.parsing.vault import VaultLib
|
||||||
from ansible.parsing.quoting import unquote
|
from ansible.parsing.quoting import unquote
|
||||||
from ansible.parsing.yaml.loader import AnsibleLoader
|
from ansible.parsing.yaml.loader import AnsibleLoader
|
||||||
from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject, AnsibleUnicode
|
from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject, AnsibleUnicode
|
||||||
from ansible.module_utils.basic import is_executable
|
|
||||||
from ansible.utils.path import unfrackpath
|
from ansible.utils.path import unfrackpath
|
||||||
from ansible.utils.unicode import to_unicode, to_bytes, to_str
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -44,6 +43,7 @@ except ImportError:
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
display = Display()
|
display = Display()
|
||||||
|
|
||||||
|
|
||||||
class DataLoader():
|
class DataLoader():
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
@ -127,15 +127,15 @@ class DataLoader():
|
||||||
|
|
||||||
def path_exists(self, path):
|
def path_exists(self, path):
|
||||||
path = self.path_dwim(path)
|
path = self.path_dwim(path)
|
||||||
return os.path.exists(to_bytes(path, errors='strict'))
|
return os.path.exists(to_bytes(path, errors='surrogate_or_strict'))
|
||||||
|
|
||||||
def is_file(self, path):
|
def is_file(self, path):
|
||||||
path = self.path_dwim(path)
|
path = self.path_dwim(path)
|
||||||
return os.path.isfile(to_bytes(path, errors='strict')) or path == os.devnull
|
return os.path.isfile(to_bytes(path, errors='surrogate_or_strict')) or path == os.devnull
|
||||||
|
|
||||||
def is_directory(self, path):
|
def is_directory(self, path):
|
||||||
path = self.path_dwim(path)
|
path = self.path_dwim(path)
|
||||||
return os.path.isdir(to_bytes(path, errors='strict'))
|
return os.path.isdir(to_bytes(path, errors='surrogate_or_strict'))
|
||||||
|
|
||||||
def list_directory(self, path):
|
def list_directory(self, path):
|
||||||
path = self.path_dwim(path)
|
path = self.path_dwim(path)
|
||||||
|
@ -156,7 +156,7 @@ class DataLoader():
|
||||||
try:
|
try:
|
||||||
loader.dispose()
|
loader.dispose()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass # older versions of yaml don't have dispose function, ignore
|
pass # older versions of yaml don't have dispose function, ignore
|
||||||
|
|
||||||
def _get_file_contents(self, file_name):
|
def _get_file_contents(self, file_name):
|
||||||
'''
|
'''
|
||||||
|
@ -178,7 +178,7 @@ class DataLoader():
|
||||||
data = self._vault.decrypt(data, filename=b_file_name)
|
data = self._vault.decrypt(data, filename=b_file_name)
|
||||||
show_content = False
|
show_content = False
|
||||||
|
|
||||||
data = to_unicode(data, errors='strict')
|
data = to_text(data, errors='surrogate_or_strict')
|
||||||
return (data, show_content)
|
return (data, show_content)
|
||||||
|
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
|
@ -208,7 +208,7 @@ class DataLoader():
|
||||||
''' sets the base directory, used to find files when a relative path is given '''
|
''' sets the base directory, used to find files when a relative path is given '''
|
||||||
|
|
||||||
if basedir is not None:
|
if basedir is not None:
|
||||||
self._basedir = to_unicode(basedir)
|
self._basedir = to_text(basedir)
|
||||||
|
|
||||||
def path_dwim(self, given):
|
def path_dwim(self, given):
|
||||||
'''
|
'''
|
||||||
|
@ -216,14 +216,14 @@ class DataLoader():
|
||||||
'''
|
'''
|
||||||
|
|
||||||
given = unquote(given)
|
given = unquote(given)
|
||||||
given = to_unicode(given, errors='strict')
|
given = to_text(given, errors='surrogate_or_strict')
|
||||||
|
|
||||||
if given.startswith(u"/"):
|
if given.startswith(u"/"):
|
||||||
return os.path.abspath(given)
|
return os.path.abspath(given)
|
||||||
elif given.startswith(u"~"):
|
elif given.startswith(u"~"):
|
||||||
return os.path.abspath(os.path.expanduser(given))
|
return os.path.abspath(os.path.expanduser(given))
|
||||||
else:
|
else:
|
||||||
basedir = to_unicode(self._basedir, errors='strict')
|
basedir = to_text(self._basedir, errors='surrogate_or_strict')
|
||||||
return os.path.abspath(os.path.join(basedir, given))
|
return os.path.abspath(os.path.join(basedir, given))
|
||||||
|
|
||||||
def path_dwim_relative(self, path, dirname, source):
|
def path_dwim_relative(self, path, dirname, source):
|
||||||
|
@ -247,8 +247,8 @@ class DataLoader():
|
||||||
basedir = unfrackpath(path)
|
basedir = unfrackpath(path)
|
||||||
|
|
||||||
# is it a role and if so make sure you get correct base path
|
# is it a role and if so make sure you get correct base path
|
||||||
if path.endswith('tasks') and os.path.exists(to_bytes(os.path.join(path,'main.yml'), errors='strict')) \
|
if path.endswith('tasks') and os.path.exists(to_bytes(os.path.join(path,'main.yml'), errors='surrogate_or_strict')) \
|
||||||
or os.path.exists(to_bytes(os.path.join(path,'tasks/main.yml'), errors='strict')):
|
or os.path.exists(to_bytes(os.path.join(path,'tasks/main.yml'), errors='surrogate_or_strict')):
|
||||||
isrole = True
|
isrole = True
|
||||||
if path.endswith('tasks'):
|
if path.endswith('tasks'):
|
||||||
basedir = unfrackpath(os.path.dirname(path))
|
basedir = unfrackpath(os.path.dirname(path))
|
||||||
|
@ -271,7 +271,7 @@ class DataLoader():
|
||||||
search.append(self.path_dwim(source))
|
search.append(self.path_dwim(source))
|
||||||
|
|
||||||
for candidate in search:
|
for candidate in search:
|
||||||
if os.path.exists(to_bytes(candidate, errors='strict')):
|
if os.path.exists(to_bytes(candidate, errors='surrogate_or_strict')):
|
||||||
break
|
break
|
||||||
|
|
||||||
return candidate
|
return candidate
|
||||||
|
@ -296,19 +296,19 @@ class DataLoader():
|
||||||
elif source.startswith('~') or source.startswith(os.path.sep):
|
elif source.startswith('~') or source.startswith(os.path.sep):
|
||||||
# path is absolute, no relative needed, check existence and return source
|
# path is absolute, no relative needed, check existence and return source
|
||||||
test_path = unfrackpath(b_source)
|
test_path = unfrackpath(b_source)
|
||||||
if os.path.exists(to_bytes(test_path, errors='strict')):
|
if os.path.exists(to_bytes(test_path, errors='surrogate_or_strict')):
|
||||||
result = test_path
|
result = test_path
|
||||||
else:
|
else:
|
||||||
search = []
|
search = []
|
||||||
for path in paths:
|
for path in paths:
|
||||||
upath = unfrackpath(path)
|
upath = unfrackpath(path)
|
||||||
b_upath = to_bytes(upath, errors='strict')
|
b_upath = to_bytes(upath, errors='surrogate_or_strict')
|
||||||
b_mydir = os.path.dirname(b_upath)
|
b_mydir = os.path.dirname(b_upath)
|
||||||
|
|
||||||
# if path is in role and 'tasks' not there already, add it into the search
|
# if path is in role and 'tasks' not there already, add it into the search
|
||||||
if b_upath.endswith(b'tasks') and os.path.exists(os.path.join(b_upath, b'main.yml')) \
|
if b_upath.endswith(b'tasks') and os.path.exists(os.path.join(b_upath, b'main.yml')) \
|
||||||
or os.path.exists(os.path.join(b_upath, b'tasks/main.yml')) \
|
or os.path.exists(os.path.join(b_upath, b'tasks/main.yml')) \
|
||||||
or os.path.exists(os.path.join(b_mydir, b'tasks/main.yml')):
|
or os.path.exists(os.path.join(b_mydir, b'tasks/main.yml')):
|
||||||
if b_mydir.endswith(b'tasks'):
|
if b_mydir.endswith(b'tasks'):
|
||||||
search.append(os.path.join(os.path.dirname(b_mydir), b_dirname, b_source))
|
search.append(os.path.join(os.path.dirname(b_mydir), b_dirname, b_source))
|
||||||
search.append(os.path.join(b_mydir, b_source))
|
search.append(os.path.join(b_mydir, b_source))
|
||||||
|
@ -324,11 +324,11 @@ class DataLoader():
|
||||||
search.append(os.path.join(to_bytes(self.get_basedir()), b_dirname, b_source))
|
search.append(os.path.join(to_bytes(self.get_basedir()), b_dirname, b_source))
|
||||||
search.append(os.path.join(to_bytes(self.get_basedir()), b_source))
|
search.append(os.path.join(to_bytes(self.get_basedir()), b_source))
|
||||||
|
|
||||||
display.debug(u'search_path:\n\t%s' % to_unicode(b'\n\t'.join(search), errors='replace'))
|
display.debug(u'search_path:\n\t%s' % to_text(b'\n\t'.join(search)))
|
||||||
for b_candidate in search:
|
for b_candidate in search:
|
||||||
display.vvvvv(u'looking for "%s" at "%s"' % (source, to_unicode(b_candidate)))
|
display.vvvvv(u'looking for "%s" at "%s"' % (source, to_text(b_candidate)))
|
||||||
if os.path.exists(b_candidate):
|
if os.path.exists(b_candidate):
|
||||||
result = to_unicode(b_candidate)
|
result = to_text(b_candidate)
|
||||||
break
|
break
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -339,8 +339,8 @@ class DataLoader():
|
||||||
retrieve password from STDOUT
|
retrieve password from STDOUT
|
||||||
"""
|
"""
|
||||||
|
|
||||||
this_path = os.path.realpath(to_bytes(os.path.expanduser(vault_password_file), errors='strict'))
|
this_path = os.path.realpath(to_bytes(os.path.expanduser(vault_password_file), errors='surrogate_or_strict'))
|
||||||
if not os.path.exists(to_bytes(this_path, errors='strict')):
|
if not os.path.exists(to_bytes(this_path, errors='surrogate_or_strict')):
|
||||||
raise AnsibleFileNotFound("The vault password file %s was not found" % this_path)
|
raise AnsibleFileNotFound("The vault password file %s was not found" % this_path)
|
||||||
|
|
||||||
if self.is_executable(this_path):
|
if self.is_executable(this_path):
|
||||||
|
@ -348,7 +348,8 @@ class DataLoader():
|
||||||
# STDERR not captured to make it easier for users to prompt for input in their scripts
|
# STDERR not captured to make it easier for users to prompt for input in their scripts
|
||||||
p = subprocess.Popen(this_path, stdout=subprocess.PIPE)
|
p = subprocess.Popen(this_path, stdout=subprocess.PIPE)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise AnsibleError("Problem running vault password script %s (%s). If this is not a script, remove the executable bit from the file." % (' '.join(this_path), e))
|
raise AnsibleError("Problem running vault password script %s (%s)."
|
||||||
|
" If this is not a script, remove the executable bit from the file." % (' '.join(this_path), to_native(e)))
|
||||||
stdout, stderr = p.communicate()
|
stdout, stderr = p.communicate()
|
||||||
self.set_vault_password(stdout.strip('\r\n'))
|
self.set_vault_password(stdout.strip('\r\n'))
|
||||||
else:
|
else:
|
||||||
|
@ -381,11 +382,11 @@ class DataLoader():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not file_path or not isinstance(file_path, string_types):
|
if not file_path or not isinstance(file_path, string_types):
|
||||||
raise AnsibleParserError("Invalid filename: '%s'" % to_str(file_path))
|
raise AnsibleParserError("Invalid filename: '%s'" % to_native(file_path))
|
||||||
|
|
||||||
b_file_path = to_bytes(file_path, errors='strict')
|
b_file_path = to_bytes(file_path, errors='surrogate_or_strict')
|
||||||
if not self.path_exists(b_file_path) or not self.is_file(b_file_path):
|
if not self.path_exists(b_file_path) or not self.is_file(b_file_path):
|
||||||
raise AnsibleFileNotFound("the file_name '%s' does not exist, or is not readable" % to_str(file_path))
|
raise AnsibleFileNotFound("the file_name '%s' does not exist, or is not readable" % to_native(file_path))
|
||||||
|
|
||||||
if not self._vault:
|
if not self._vault:
|
||||||
self._vault = VaultLib(password="")
|
self._vault = VaultLib(password="")
|
||||||
|
@ -410,7 +411,7 @@ class DataLoader():
|
||||||
return real_path
|
return real_path
|
||||||
|
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
raise AnsibleParserError("an error occurred while trying to read the file '%s': %s" % (to_str(real_path), to_str(e)))
|
raise AnsibleParserError("an error occurred while trying to read the file '%s': %s" % (to_native(real_path), to_native(e)))
|
||||||
|
|
||||||
def cleanup_tmp_file(self, file_path):
|
def cleanup_tmp_file(self, file_path):
|
||||||
"""
|
"""
|
||||||
|
@ -420,11 +421,11 @@ class DataLoader():
|
||||||
"""
|
"""
|
||||||
if file_path in self._tempfiles:
|
if file_path in self._tempfiles:
|
||||||
os.unlink(file_path)
|
os.unlink(file_path)
|
||||||
self._tempfiles.remove(file_path);
|
self._tempfiles.remove(file_path)
|
||||||
|
|
||||||
def cleanup_all_tmp_files(self):
|
def cleanup_all_tmp_files(self):
|
||||||
for f in self._tempfiles:
|
for f in self._tempfiles:
|
||||||
try:
|
try:
|
||||||
self.cleanup_tmp_file(f)
|
self.cleanup_tmp_file(f)
|
||||||
except:
|
except:
|
||||||
pass #TODO: this should at least warn
|
pass # TODO: this should at least warn
|
||||||
|
|
|
@ -23,8 +23,10 @@ import re
|
||||||
import codecs
|
import codecs
|
||||||
|
|
||||||
from ansible.errors import AnsibleParserError
|
from ansible.errors import AnsibleParserError
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.parsing.quoting import unquote
|
from ansible.parsing.quoting import unquote
|
||||||
|
|
||||||
|
|
||||||
# Decode escapes adapted from rspeer's answer here:
|
# Decode escapes adapted from rspeer's answer here:
|
||||||
# http://stackoverflow.com/questions/4020539/process-escape-sequences-in-a-string-in-python
|
# http://stackoverflow.com/questions/4020539/process-escape-sequences-in-a-string-in-python
|
||||||
_HEXCHAR = '[a-fA-F0-9]'
|
_HEXCHAR = '[a-fA-F0-9]'
|
||||||
|
@ -36,12 +38,14 @@ _ESCAPE_SEQUENCE_RE = re.compile(r'''
|
||||||
| \\[\\'"abfnrtv] # Single-character escapes
|
| \\[\\'"abfnrtv] # Single-character escapes
|
||||||
)'''.format(_HEXCHAR*8, _HEXCHAR*4, _HEXCHAR*2), re.UNICODE | re.VERBOSE)
|
)'''.format(_HEXCHAR*8, _HEXCHAR*4, _HEXCHAR*2), re.UNICODE | re.VERBOSE)
|
||||||
|
|
||||||
|
|
||||||
def _decode_escapes(s):
|
def _decode_escapes(s):
|
||||||
def decode_match(match):
|
def decode_match(match):
|
||||||
return codecs.decode(match.group(0), 'unicode-escape')
|
return codecs.decode(match.group(0), 'unicode-escape')
|
||||||
|
|
||||||
return _ESCAPE_SEQUENCE_RE.sub(decode_match, s)
|
return _ESCAPE_SEQUENCE_RE.sub(decode_match, s)
|
||||||
|
|
||||||
|
|
||||||
def parse_kv(args, check_raw=False):
|
def parse_kv(args, check_raw=False):
|
||||||
'''
|
'''
|
||||||
Convert a string of key/value items to a dict. If any free-form params
|
Convert a string of key/value items to a dict. If any free-form params
|
||||||
|
@ -50,9 +54,7 @@ def parse_kv(args, check_raw=False):
|
||||||
they will simply be ignored.
|
they will simply be ignored.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
### FIXME: args should already be a unicode string
|
args = to_text(args, nonstring='passthru')
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
args = to_unicode(args, nonstring='passthru')
|
|
||||||
|
|
||||||
options = {}
|
options = {}
|
||||||
if args is not None:
|
if args is not None:
|
||||||
|
@ -60,7 +62,7 @@ def parse_kv(args, check_raw=False):
|
||||||
vargs = split_args(args)
|
vargs = split_args(args)
|
||||||
except ValueError as ve:
|
except ValueError as ve:
|
||||||
if 'no closing quotation' in str(ve).lower():
|
if 'no closing quotation' in str(ve).lower():
|
||||||
raise AnsibleParsingError("error parsing argument string, try quoting the entire line.")
|
raise AnsibleParserError("error parsing argument string, try quoting the entire line.")
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -99,6 +101,7 @@ def parse_kv(args, check_raw=False):
|
||||||
|
|
||||||
return options
|
return options
|
||||||
|
|
||||||
|
|
||||||
def _get_quote_state(token, quote_char):
|
def _get_quote_state(token, quote_char):
|
||||||
'''
|
'''
|
||||||
the goal of this block is to determine if the quoted string
|
the goal of this block is to determine if the quoted string
|
||||||
|
@ -118,6 +121,7 @@ def _get_quote_state(token, quote_char):
|
||||||
quote_char = cur_char
|
quote_char = cur_char
|
||||||
return quote_char
|
return quote_char
|
||||||
|
|
||||||
|
|
||||||
def _count_jinja2_blocks(token, cur_depth, open_token, close_token):
|
def _count_jinja2_blocks(token, cur_depth, open_token, close_token):
|
||||||
'''
|
'''
|
||||||
this function counts the number of opening/closing blocks for a
|
this function counts the number of opening/closing blocks for a
|
||||||
|
@ -132,6 +136,7 @@ def _count_jinja2_blocks(token, cur_depth, open_token, close_token):
|
||||||
cur_depth = 0
|
cur_depth = 0
|
||||||
return cur_depth
|
return cur_depth
|
||||||
|
|
||||||
|
|
||||||
def split_args(args):
|
def split_args(args):
|
||||||
'''
|
'''
|
||||||
Splits args on whitespace, but intelligently reassembles
|
Splits args on whitespace, but intelligently reassembles
|
||||||
|
@ -166,9 +171,9 @@ def split_args(args):
|
||||||
|
|
||||||
quote_char = None
|
quote_char = None
|
||||||
inside_quotes = False
|
inside_quotes = False
|
||||||
print_depth = 0 # used to count nested jinja2 {{ }} blocks
|
print_depth = 0 # used to count nested jinja2 {{ }} blocks
|
||||||
block_depth = 0 # used to count nested jinja2 {% %} blocks
|
block_depth = 0 # used to count nested jinja2 {% %} blocks
|
||||||
comment_depth = 0 # used to count nested jinja2 {# #} blocks
|
comment_depth = 0 # used to count nested jinja2 {# #} blocks
|
||||||
|
|
||||||
# now we loop over each split chunk, coalescing tokens if the white space
|
# now we loop over each split chunk, coalescing tokens if the white space
|
||||||
# split occurred within quotes or a jinja2 block of some kind
|
# split occurred within quotes or a jinja2 block of some kind
|
||||||
|
|
|
@ -29,16 +29,10 @@ from ansible.errors import AnsibleError
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
from hashlib import md5
|
||||||
try:
|
|
||||||
from __main__ import display
|
|
||||||
except ImportError:
|
|
||||||
from ansible.utils.display import Display
|
|
||||||
display = Display()
|
|
||||||
|
|
||||||
# Note: Only used for loading obsolete VaultAES files. All files are written
|
# Note: Only used for loading obsolete VaultAES files. All files are written
|
||||||
# using the newer VaultAES256 which does not require md5
|
# using the newer VaultAES256 which does not require md5
|
||||||
from hashlib import md5
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from Crypto.Hash import SHA256, HMAC
|
from Crypto.Hash import SHA256, HMAC
|
||||||
|
@ -67,6 +61,15 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAS_AES = False
|
HAS_AES = False
|
||||||
|
|
||||||
|
from ansible.compat.six import PY3
|
||||||
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
|
try:
|
||||||
|
from __main__ import display
|
||||||
|
except ImportError:
|
||||||
|
from ansible.utils.display import Display
|
||||||
|
display = Display()
|
||||||
|
|
||||||
# OpenSSL pbkdf2_hmac
|
# OpenSSL pbkdf2_hmac
|
||||||
HAS_PBKDF2HMAC = False
|
HAS_PBKDF2HMAC = False
|
||||||
try:
|
try:
|
||||||
|
@ -81,12 +84,11 @@ except Exception as e:
|
||||||
import traceback
|
import traceback
|
||||||
display.debug("Traceback from import of cryptography was {0}".format(traceback.format_exc()))
|
display.debug("Traceback from import of cryptography was {0}".format(traceback.format_exc()))
|
||||||
|
|
||||||
from ansible.compat.six import PY3
|
|
||||||
from ansible.utils.unicode import to_unicode, to_bytes
|
|
||||||
|
|
||||||
HAS_ANY_PBKDF2HMAC = HAS_PBKDF2 or HAS_PBKDF2HMAC
|
HAS_ANY_PBKDF2HMAC = HAS_PBKDF2 or HAS_PBKDF2HMAC
|
||||||
|
|
||||||
CRYPTO_UPGRADE = "ansible-vault requires a newer version of pycrypto than the one installed on your platform. You may fix this with OS-specific commands such as: yum install python-devel; rpm -e --nodeps python-crypto; pip install pycrypto"
|
CRYPTO_UPGRADE = "ansible-vault requires a newer version of pycrypto than the one installed on your platform." \
|
||||||
|
" You may fix this with OS-specific commands such as: yum install python-devel; rpm -e --nodeps python-crypto; pip install pycrypto"
|
||||||
|
|
||||||
b_HEADER = b'$ANSIBLE_VAULT'
|
b_HEADER = b'$ANSIBLE_VAULT'
|
||||||
HEADER = '$ANSIBLE_VAULT'
|
HEADER = '$ANSIBLE_VAULT'
|
||||||
|
@ -105,6 +107,7 @@ def check_prereqs():
|
||||||
class AnsibleVaultError(AnsibleError):
|
class AnsibleVaultError(AnsibleError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def is_encrypted(b_data):
|
def is_encrypted(b_data):
|
||||||
""" Test if this is vault encrypted data blob
|
""" Test if this is vault encrypted data blob
|
||||||
|
|
||||||
|
@ -116,6 +119,7 @@ def is_encrypted(b_data):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def is_encrypted_file(file_obj):
|
def is_encrypted_file(file_obj):
|
||||||
"""Test if the contents of a file obj are a vault encrypted data blob.
|
"""Test if the contents of a file obj are a vault encrypted data blob.
|
||||||
|
|
||||||
|
@ -252,7 +256,7 @@ class VaultLib:
|
||||||
|
|
||||||
b_header = HEADER.encode('utf-8')
|
b_header = HEADER.encode('utf-8')
|
||||||
header = b';'.join([b_header, self.b_version,
|
header = b';'.join([b_header, self.b_version,
|
||||||
to_bytes(self.cipher_name,'utf-8',errors='strict')])
|
to_bytes(self.cipher_name,'utf-8', errors='strict')])
|
||||||
tmpdata = [header]
|
tmpdata = [header]
|
||||||
tmpdata += [b_data[i:i + 80] for i in range(0, len(b_data), 80)]
|
tmpdata += [b_data[i:i + 80] for i in range(0, len(b_data), 80)]
|
||||||
tmpdata += [b'']
|
tmpdata += [b'']
|
||||||
|
@ -278,7 +282,7 @@ class VaultLib:
|
||||||
tmpheader = tmpdata[0].strip().split(b';')
|
tmpheader = tmpdata[0].strip().split(b';')
|
||||||
|
|
||||||
self.b_version = tmpheader[1].strip()
|
self.b_version = tmpheader[1].strip()
|
||||||
self.cipher_name = to_unicode(tmpheader[2].strip())
|
self.cipher_name = to_text(tmpheader[2].strip())
|
||||||
clean_data = b''.join(tmpdata[1:])
|
clean_data = b''.join(tmpdata[1:])
|
||||||
|
|
||||||
return clean_data
|
return clean_data
|
||||||
|
@ -306,7 +310,7 @@ class VaultEditor:
|
||||||
|
|
||||||
file_len = os.path.getsize(tmp_path)
|
file_len = os.path.getsize(tmp_path)
|
||||||
|
|
||||||
if file_len > 0: # avoid work when file was empty
|
if file_len > 0: # avoid work when file was empty
|
||||||
max_chunk_len = min(1024*1024*2, file_len)
|
max_chunk_len = min(1024*1024*2, file_len)
|
||||||
|
|
||||||
passes = 3
|
passes = 3
|
||||||
|
@ -321,7 +325,7 @@ class VaultEditor:
|
||||||
fh.write(data)
|
fh.write(data)
|
||||||
fh.write(data[:file_len % chunk_len])
|
fh.write(data[:file_len % chunk_len])
|
||||||
|
|
||||||
assert(fh.tell() == file_len) # FIXME remove this assert once we have unittests to check its accuracy
|
assert(fh.tell() == file_len) # FIXME remove this assert once we have unittests to check its accuracy
|
||||||
os.fsync(fh)
|
os.fsync(fh)
|
||||||
|
|
||||||
def _shred_file(self, tmp_path):
|
def _shred_file(self, tmp_path):
|
||||||
|
@ -528,6 +532,7 @@ class VaultEditor:
|
||||||
|
|
||||||
return editor
|
return editor
|
||||||
|
|
||||||
|
|
||||||
class VaultFile(object):
|
class VaultFile(object):
|
||||||
|
|
||||||
def __init__(self, password, filename):
|
def __init__(self, password, filename):
|
||||||
|
@ -568,6 +573,7 @@ class VaultFile(object):
|
||||||
else:
|
else:
|
||||||
return self.filename
|
return self.filename
|
||||||
|
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# CIPHERS #
|
# CIPHERS #
|
||||||
########################################
|
########################################
|
||||||
|
|
|
@ -22,12 +22,11 @@ __metaclass__ = type
|
||||||
from yaml.constructor import Constructor, ConstructorError
|
from yaml.constructor import Constructor, ConstructorError
|
||||||
from yaml.nodes import MappingNode
|
from yaml.nodes import MappingNode
|
||||||
|
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
|
from ansible.parsing.vault import VaultLib
|
||||||
from ansible.parsing.yaml.objects import AnsibleMapping, AnsibleSequence, AnsibleUnicode
|
from ansible.parsing.yaml.objects import AnsibleMapping, AnsibleSequence, AnsibleUnicode
|
||||||
from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
|
from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
|
||||||
|
|
||||||
from ansible.vars.unsafe_proxy import wrap_var
|
from ansible.vars.unsafe_proxy import wrap_var
|
||||||
from ansible.parsing.vault import VaultLib
|
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -74,7 +73,8 @@ class AnsibleConstructor(Constructor):
|
||||||
"found unacceptable key (%s)" % exc, key_node.start_mark)
|
"found unacceptable key (%s)" % exc, key_node.start_mark)
|
||||||
|
|
||||||
if key in mapping:
|
if key in mapping:
|
||||||
display.warning(u'While constructing a mapping from {1}, line {2}, column {3}, found a duplicate dict key ({0}). Using last defined value only.'.format(key, *mapping.ansible_pos))
|
display.warning(u'While constructing a mapping from {1}, line {2}, column {3}, found a duplicate dict key ({0}).'
|
||||||
|
u' Using last defined value only.'.format(key, *mapping.ansible_pos))
|
||||||
|
|
||||||
value = self.construct_object(value_node, deep=deep)
|
value = self.construct_object(value_node, deep=deep)
|
||||||
mapping[key] = value
|
mapping[key] = value
|
||||||
|
|
|
@ -22,8 +22,7 @@ __metaclass__ = type
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from ansible.compat.six import text_type
|
from ansible.compat.six import text_type
|
||||||
from ansible.errors import AnsibleError
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
|
|
||||||
class AnsibleBaseYAMLObject(object):
|
class AnsibleBaseYAMLObject(object):
|
||||||
|
|
|
@ -19,25 +19,22 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import collections
|
|
||||||
import itertools
|
import itertools
|
||||||
import operator
|
import operator
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from copy import copy as shallowcopy, deepcopy
|
from copy import copy as shallowcopy
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from inspect import getmembers
|
|
||||||
|
|
||||||
from ansible.compat.six import iteritems, string_types, with_metaclass
|
|
||||||
|
|
||||||
from jinja2.exceptions import UndefinedError
|
from jinja2.exceptions import UndefinedError
|
||||||
|
|
||||||
|
from ansible.compat.six import iteritems, string_types, with_metaclass
|
||||||
from ansible.errors import AnsibleParserError, AnsibleUndefinedVariable
|
from ansible.errors import AnsibleParserError, AnsibleUndefinedVariable
|
||||||
from ansible.parsing.dataloader import DataLoader
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.playbook.attribute import Attribute, FieldAttribute
|
from ansible.playbook.attribute import Attribute, FieldAttribute
|
||||||
|
from ansible.parsing.dataloader import DataLoader
|
||||||
from ansible.utils.boolean import boolean
|
from ansible.utils.boolean import boolean
|
||||||
from ansible.utils.vars import combine_vars, isidentifier
|
from ansible.utils.vars import combine_vars, isidentifier
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -52,6 +49,7 @@ def _generic_g(prop_name, self):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
|
raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
|
||||||
|
|
||||||
|
|
||||||
def _generic_g_method(prop_name, self):
|
def _generic_g_method(prop_name, self):
|
||||||
try:
|
try:
|
||||||
if self._squashed:
|
if self._squashed:
|
||||||
|
@ -61,6 +59,7 @@ def _generic_g_method(prop_name, self):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
|
raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, prop_name))
|
||||||
|
|
||||||
|
|
||||||
def _generic_g_parent(prop_name, self):
|
def _generic_g_parent(prop_name, self):
|
||||||
try:
|
try:
|
||||||
value = self._attributes[prop_name]
|
value = self._attributes[prop_name]
|
||||||
|
@ -74,12 +73,15 @@ def _generic_g_parent(prop_name, self):
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def _generic_s(prop_name, self, value):
|
def _generic_s(prop_name, self, value):
|
||||||
self._attributes[prop_name] = value
|
self._attributes[prop_name] = value
|
||||||
|
|
||||||
|
|
||||||
def _generic_d(prop_name, self):
|
def _generic_d(prop_name, self):
|
||||||
del self._attributes[prop_name]
|
del self._attributes[prop_name]
|
||||||
|
|
||||||
|
|
||||||
class BaseMeta(type):
|
class BaseMeta(type):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -142,6 +144,7 @@ class BaseMeta(type):
|
||||||
|
|
||||||
return super(BaseMeta, cls).__new__(cls, name, parents, dct)
|
return super(BaseMeta, cls).__new__(cls, name, parents, dct)
|
||||||
|
|
||||||
|
|
||||||
class Base(with_metaclass(BaseMeta, object)):
|
class Base(with_metaclass(BaseMeta, object)):
|
||||||
|
|
||||||
# connection/transport
|
# connection/transport
|
||||||
|
@ -376,7 +379,7 @@ class Base(with_metaclass(BaseMeta, object)):
|
||||||
# and make sure the attribute is of the type it should be
|
# and make sure the attribute is of the type it should be
|
||||||
if value is not None:
|
if value is not None:
|
||||||
if attribute.isa == 'string':
|
if attribute.isa == 'string':
|
||||||
value = to_unicode(value)
|
value = to_text(value)
|
||||||
elif attribute.isa == 'int':
|
elif attribute.isa == 'int':
|
||||||
value = int(value)
|
value = int(value)
|
||||||
elif attribute.isa == 'float':
|
elif attribute.isa == 'float':
|
||||||
|
@ -395,8 +398,8 @@ class Base(with_metaclass(BaseMeta, object)):
|
||||||
elif not isinstance(value, list):
|
elif not isinstance(value, list):
|
||||||
if isinstance(value, string_types) and attribute.isa == 'barelist':
|
if isinstance(value, string_types) and attribute.isa == 'barelist':
|
||||||
display.deprecated(
|
display.deprecated(
|
||||||
"Using comma separated values for a list has been deprecated. " \
|
"Using comma separated values for a list has been deprecated. "
|
||||||
"You should instead use the correct YAML syntax for lists. " \
|
"You should instead use the correct YAML syntax for lists. "
|
||||||
)
|
)
|
||||||
value = value.split(',')
|
value = value.split(',')
|
||||||
else:
|
else:
|
||||||
|
@ -532,4 +535,3 @@ class Base(with_metaclass(BaseMeta, object)):
|
||||||
setattr(self, '_uuid', data.get('uuid'))
|
setattr(self, '_uuid', data.get('uuid'))
|
||||||
self._finalized = data.get('finalized', False)
|
self._finalized = data.get('finalized', False)
|
||||||
self._squashed = data.get('squashed', False)
|
self._squashed = data.get('squashed', False)
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,10 @@ __metaclass__ = type
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ansible.compat.six import iteritems, string_types
|
from ansible.compat.six import iteritems, string_types
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleParserError
|
from ansible.errors import AnsibleError, AnsibleParserError
|
||||||
|
from ansible.module_utils._text import to_native
|
||||||
from ansible.parsing.mod_args import ModuleArgsParser
|
from ansible.parsing.mod_args import ModuleArgsParser
|
||||||
from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject, AnsibleMapping, AnsibleUnicode
|
from ansible.parsing.yaml.objects import AnsibleBaseYAMLObject, AnsibleMapping, AnsibleUnicode
|
||||||
|
|
||||||
from ansible.plugins import lookup_loader
|
from ansible.plugins import lookup_loader
|
||||||
from ansible.playbook.attribute import FieldAttribute
|
from ansible.playbook.attribute import FieldAttribute
|
||||||
from ansible.playbook.base import Base
|
from ansible.playbook.base import Base
|
||||||
|
@ -38,7 +36,6 @@ from ansible.playbook.loop_control import LoopControl
|
||||||
from ansible.playbook.role import Role
|
from ansible.playbook.role import Role
|
||||||
from ansible.playbook.taggable import Taggable
|
from ansible.playbook.taggable import Taggable
|
||||||
|
|
||||||
from ansible.utils.unicode import to_str
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -182,7 +179,7 @@ class Task(Base, Conditional, Taggable, Become):
|
||||||
try:
|
try:
|
||||||
(action, args, delegate_to) = args_parser.parse()
|
(action, args, delegate_to) = args_parser.parse()
|
||||||
except AnsibleParserError as e:
|
except AnsibleParserError as e:
|
||||||
raise AnsibleParserError(to_str(e), obj=ds)
|
raise AnsibleParserError(to_native(e), obj=ds)
|
||||||
|
|
||||||
# the command/shell/script modules used to support the `cmd` arg,
|
# the command/shell/script modules used to support the `cmd` arg,
|
||||||
# which corresponds to what we now call _raw_params, so move that
|
# which corresponds to what we now call _raw_params, so move that
|
||||||
|
@ -232,11 +229,11 @@ class Task(Base, Conditional, Taggable, Become):
|
||||||
|
|
||||||
def _load_loop_control(self, attr, ds):
|
def _load_loop_control(self, attr, ds):
|
||||||
if not isinstance(ds, dict):
|
if not isinstance(ds, dict):
|
||||||
raise AnsibleParserError(
|
raise AnsibleParserError(
|
||||||
"the `loop_control` value must be specified as a dictionary and cannot " \
|
"the `loop_control` value must be specified as a dictionary and cannot "
|
||||||
"be a variable itself (though it can contain variables)",
|
"be a variable itself (though it can contain variables)",
|
||||||
obj=ds,
|
obj=ds,
|
||||||
)
|
)
|
||||||
|
|
||||||
return LoopControl.load(data=ds, variable_manager=self._variable_manager, loader=self._loader)
|
return LoopControl.load(data=ds, variable_manager=self._variable_manager, loader=self._loader)
|
||||||
|
|
||||||
|
@ -267,18 +264,18 @@ class Task(Base, Conditional, Taggable, Become):
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
elif isinstance(value, list):
|
elif isinstance(value, list):
|
||||||
if len(value) == 1:
|
if len(value) == 1:
|
||||||
return templar.template(value[0], convert_bare=True)
|
return templar.template(value[0], convert_bare=True)
|
||||||
else:
|
else:
|
||||||
env = []
|
env = []
|
||||||
for env_item in value:
|
for env_item in value:
|
||||||
if isinstance(env_item, (string_types, AnsibleUnicode)) and env_item in templar._available_variables.keys():
|
if isinstance(env_item, (string_types, AnsibleUnicode)) and env_item in templar._available_variables.keys():
|
||||||
env[env_item] = templar.template(env_item, convert_bare=True)
|
env[env_item] = templar.template(env_item, convert_bare=True)
|
||||||
elif isinstance(value, dict):
|
elif isinstance(value, dict):
|
||||||
env = dict()
|
env = dict()
|
||||||
for env_item in value:
|
for env_item in value:
|
||||||
if isinstance(env_item, (string_types, AnsibleUnicode)) and env_item in templar._available_variables.keys():
|
if isinstance(env_item, (string_types, AnsibleUnicode)) and env_item in templar._available_variables.keys():
|
||||||
env[env_item] = templar.template(value[env_item], convert_bare=True)
|
env[env_item] = templar.template(value[env_item], convert_bare=True)
|
||||||
|
|
||||||
# at this point it should be a simple string
|
# at this point it should be a simple string
|
||||||
return templar.template(value, convert_bare=True)
|
return templar.template(value, convert_bare=True)
|
||||||
|
@ -436,7 +433,7 @@ class Task(Base, Conditional, Taggable, Become):
|
||||||
'''
|
'''
|
||||||
path_stack = []
|
path_stack = []
|
||||||
|
|
||||||
dep_chain = self.get_dep_chain()
|
dep_chain = self.get_dep_chain()
|
||||||
# inside role: add the dependency chain from current to dependant
|
# inside role: add the dependency chain from current to dependant
|
||||||
if dep_chain:
|
if dep_chain:
|
||||||
path_stack.extend(reversed([x._role_path for x in dep_chain]))
|
path_stack.extend(reversed([x._role_path for x in dep_chain]))
|
||||||
|
@ -452,4 +449,3 @@ class Task(Base, Conditional, Taggable, Become):
|
||||||
if self._parent:
|
if self._parent:
|
||||||
return self._parent.all_parents_static()
|
return self._parent.all_parents_static()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,8 @@ import warnings
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.module_utils._text import to_text
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -44,9 +45,11 @@ MODULE_CACHE = {}
|
||||||
PATH_CACHE = {}
|
PATH_CACHE = {}
|
||||||
PLUGIN_PATH_CACHE = {}
|
PLUGIN_PATH_CACHE = {}
|
||||||
|
|
||||||
|
|
||||||
def get_all_plugin_loaders():
|
def get_all_plugin_loaders():
|
||||||
return [(name, obj) for (name, obj) in inspect.getmembers(sys.modules[__name__]) if isinstance(obj, PluginLoader)]
|
return [(name, obj) for (name, obj) in inspect.getmembers(sys.modules[__name__]) if isinstance(obj, PluginLoader)]
|
||||||
|
|
||||||
|
|
||||||
class PluginLoader:
|
class PluginLoader:
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
@ -72,11 +75,11 @@ class PluginLoader:
|
||||||
|
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
if not class_name in MODULE_CACHE:
|
if class_name not in MODULE_CACHE:
|
||||||
MODULE_CACHE[class_name] = {}
|
MODULE_CACHE[class_name] = {}
|
||||||
if not class_name in PATH_CACHE:
|
if class_name not in PATH_CACHE:
|
||||||
PATH_CACHE[class_name] = None
|
PATH_CACHE[class_name] = None
|
||||||
if not class_name in PLUGIN_PATH_CACHE:
|
if class_name not in PLUGIN_PATH_CACHE:
|
||||||
PLUGIN_PATH_CACHE[class_name] = defaultdict(dict)
|
PLUGIN_PATH_CACHE[class_name] = defaultdict(dict)
|
||||||
|
|
||||||
self._module_cache = MODULE_CACHE[class_name]
|
self._module_cache = MODULE_CACHE[class_name]
|
||||||
|
@ -140,9 +143,9 @@ class PluginLoader:
|
||||||
results = []
|
results = []
|
||||||
results.append(dir)
|
results.append(dir)
|
||||||
for root, subdirs, files in os.walk(dir, followlinks=True):
|
for root, subdirs, files in os.walk(dir, followlinks=True):
|
||||||
if '__init__.py' in files:
|
if '__init__.py' in files:
|
||||||
for x in subdirs:
|
for x in subdirs:
|
||||||
results.append(os.path.join(root,x))
|
results.append(os.path.join(root,x))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def _get_package_paths(self):
|
def _get_package_paths(self):
|
||||||
|
@ -250,7 +253,7 @@ class PluginLoader:
|
||||||
try:
|
try:
|
||||||
full_paths = (os.path.join(path, f) for f in os.listdir(path))
|
full_paths = (os.path.join(path, f) for f in os.listdir(path))
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
display.warning("Error accessing plugin paths: %s" % to_unicode(e))
|
display.warning("Error accessing plugin paths: %s" % to_text(e))
|
||||||
|
|
||||||
for full_path in (f for f in full_paths if os.path.isfile(f) and not f.endswith('__init__.py')):
|
for full_path in (f for f in full_paths if os.path.isfile(f) and not f.endswith('__init__.py')):
|
||||||
full_name = os.path.basename(full_path)
|
full_name = os.path.basename(full_path)
|
||||||
|
@ -358,7 +361,7 @@ class PluginLoader:
|
||||||
|
|
||||||
def _display_plugin_load(self, class_name, name, searched_paths, path, found_in_cache=None, class_only=None):
|
def _display_plugin_load(self, class_name, name, searched_paths, path, found_in_cache=None, class_only=None):
|
||||||
msg = 'Loading %s \'%s\' from %s' % (class_name, os.path.basename(name), path)
|
msg = 'Loading %s \'%s\' from %s' % (class_name, os.path.basename(name), path)
|
||||||
|
|
||||||
if len(searched_paths) > 1:
|
if len(searched_paths) > 1:
|
||||||
msg = '%s (searched paths: %s)' % (msg, self.format_paths(searched_paths))
|
msg = '%s (searched paths: %s)' % (msg, self.format_paths(searched_paths))
|
||||||
|
|
||||||
|
@ -389,7 +392,7 @@ class PluginLoader:
|
||||||
try:
|
try:
|
||||||
obj = getattr(self._module_cache[path], self.class_name)
|
obj = getattr(self._module_cache[path], self.class_name)
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
display.warning("Skipping plugin (%s) as it seems to be invalid: %s" % (path, to_unicode(e)))
|
display.warning("Skipping plugin (%s) as it seems to be invalid: %s" % (path, to_text(e)))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if self.base_class:
|
if self.base_class:
|
||||||
|
@ -398,11 +401,11 @@ class PluginLoader:
|
||||||
module = __import__(self.package, fromlist=[self.base_class])
|
module = __import__(self.package, fromlist=[self.base_class])
|
||||||
# Check whether this obj has the required base class.
|
# Check whether this obj has the required base class.
|
||||||
try:
|
try:
|
||||||
plugin_class = getattr(module, self.base_class)
|
plugin_class = getattr(module, self.base_class)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
continue
|
continue
|
||||||
if not issubclass(obj, plugin_class):
|
if not issubclass(obj, plugin_class):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self._display_plugin_load(self.class_name, name, self._searched_paths, path,
|
self._display_plugin_load(self.class_name, name, self._searched_paths, path,
|
||||||
found_in_cache=found_in_cache, class_only=class_only)
|
found_in_cache=found_in_cache, class_only=class_only)
|
||||||
|
|
|
@ -35,9 +35,10 @@ from ansible.compat.six import binary_type, text_type, iteritems, with_metaclass
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure
|
from ansible.errors import AnsibleError, AnsibleConnectionFailure
|
||||||
from ansible.executor.module_common import modify_module
|
from ansible.executor.module_common import modify_module
|
||||||
from ansible.release import __version__
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
from ansible.parsing.utils.jsonify import jsonify
|
from ansible.parsing.utils.jsonify import jsonify
|
||||||
from ansible.utils.unicode import to_bytes, to_str, to_unicode
|
from ansible.release import __version__
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -86,7 +87,7 @@ class ActionBase(with_metaclass(ABCMeta, object)):
|
||||||
* Module parameters. These are stored in self._task.args
|
* Module parameters. These are stored in self._task.args
|
||||||
"""
|
"""
|
||||||
# store the module invocation details into the results
|
# store the module invocation details into the results
|
||||||
results = {}
|
results = {}
|
||||||
if self._task.async == 0:
|
if self._task.async == 0:
|
||||||
results['invocation'] = dict(
|
results['invocation'] = dict(
|
||||||
module_name = self._task.action,
|
module_name = self._task.action,
|
||||||
|
@ -146,7 +147,8 @@ class ActionBase(with_metaclass(ABCMeta, object)):
|
||||||
"run 'git submodule update --init --recursive' to correct this problem." % (module_name))
|
"run 'git submodule update --init --recursive' to correct this problem." % (module_name))
|
||||||
|
|
||||||
# insert shared code and arguments into the module
|
# insert shared code and arguments into the module
|
||||||
(module_data, module_style, module_shebang) = modify_module(module_name, module_path, module_args, task_vars=task_vars, module_compression=self._play_context.module_compression)
|
(module_data, module_style, module_shebang) = modify_module(module_name, module_path, module_args,
|
||||||
|
task_vars=task_vars, module_compression=self._play_context.module_compression)
|
||||||
|
|
||||||
return (module_style, module_shebang, module_data, module_path)
|
return (module_style, module_shebang, module_data, module_path)
|
||||||
|
|
||||||
|
@ -283,10 +285,10 @@ class ActionBase(with_metaclass(ABCMeta, object)):
|
||||||
afd, afile = tempfile.mkstemp()
|
afd, afile = tempfile.mkstemp()
|
||||||
afo = os.fdopen(afd, 'wb')
|
afo = os.fdopen(afd, 'wb')
|
||||||
try:
|
try:
|
||||||
data = to_bytes(data, errors='strict')
|
data = to_bytes(data, errors='surrogate_or_strict')
|
||||||
afo.write(data)
|
afo.write(data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError("failure writing module data to temporary file for transfer: %s" % str(e))
|
raise AnsibleError("failure writing module data to temporary file for transfer: %s" % to_native(e))
|
||||||
|
|
||||||
afo.flush()
|
afo.flush()
|
||||||
afo.close()
|
afo.close()
|
||||||
|
@ -372,17 +374,22 @@ class ActionBase(with_metaclass(ABCMeta, object)):
|
||||||
res = self._remote_chown(remote_paths, self._play_context.become_user)
|
res = self._remote_chown(remote_paths, self._play_context.become_user)
|
||||||
if res['rc'] != 0 and remote_user == 'root':
|
if res['rc'] != 0 and remote_user == 'root':
|
||||||
# chown failed even if remove_user is root
|
# chown failed even if remove_user is root
|
||||||
raise AnsibleError('Failed to change ownership of the temporary files Ansible needs to create despite connecting as root. Unprivileged become user would be unable to read the file.')
|
raise AnsibleError('Failed to change ownership of the temporary files Ansible needs to create despite connecting as root.'
|
||||||
|
' Unprivileged become user would be unable to read the file.')
|
||||||
elif res['rc'] != 0:
|
elif res['rc'] != 0:
|
||||||
if C.ALLOW_WORLD_READABLE_TMPFILES:
|
if C.ALLOW_WORLD_READABLE_TMPFILES:
|
||||||
# chown and fs acls failed -- do things this insecure
|
# chown and fs acls failed -- do things this insecure
|
||||||
# way only if the user opted in in the config file
|
# way only if the user opted in in the config file
|
||||||
display.warning('Using world-readable permissions for temporary files Ansible needs to create when becoming an unprivileged user which may be insecure. For information on securing this, see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user')
|
display.warning('Using world-readable permissions for temporary files Ansible needs to create when becoming an unprivileged user.'
|
||||||
|
' This may be insecure. For information on securing this, see'
|
||||||
|
' https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user')
|
||||||
res = self._remote_chmod(remote_paths, 'a+%s' % mode)
|
res = self._remote_chmod(remote_paths, 'a+%s' % mode)
|
||||||
if res['rc'] != 0:
|
if res['rc'] != 0:
|
||||||
raise AnsibleError('Failed to set file mode on remote files (rc: {0}, err: {1})'.format(res['rc'], res['stderr']))
|
raise AnsibleError('Failed to set file mode on remote files (rc: {0}, err: {1})'.format(res['rc'], res['stderr']))
|
||||||
else:
|
else:
|
||||||
raise AnsibleError('Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: {0}, err: {1}). For information on working around this, see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user'.format(res['rc'], res['stderr']))
|
raise AnsibleError('Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user'
|
||||||
|
' (rc: {0}, err: {1}). For information on working around this,'
|
||||||
|
' see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user'.format(res['rc'], res['stderr']))
|
||||||
elif execute:
|
elif execute:
|
||||||
# Can't depend on the file being transferred with execute
|
# Can't depend on the file being transferred with execute
|
||||||
# permissions. Only need user perms because no become was
|
# permissions. Only need user perms because no become was
|
||||||
|
@ -438,7 +445,7 @@ class ActionBase(with_metaclass(ABCMeta, object)):
|
||||||
mystat['stat']['checksum'] = '1'
|
mystat['stat']['checksum'] = '1'
|
||||||
|
|
||||||
# happens sometimes when it is a dir and not on bsd
|
# happens sometimes when it is a dir and not on bsd
|
||||||
if not 'checksum' in mystat['stat']:
|
if 'checksum' not in mystat['stat']:
|
||||||
mystat['stat']['checksum'] = ''
|
mystat['stat']['checksum'] = ''
|
||||||
|
|
||||||
return mystat['stat']
|
return mystat['stat']
|
||||||
|
@ -453,26 +460,25 @@ class ActionBase(with_metaclass(ABCMeta, object)):
|
||||||
3 = its a directory, not a file
|
3 = its a directory, not a file
|
||||||
4 = stat module failed, likely due to not finding python
|
4 = stat module failed, likely due to not finding python
|
||||||
'''
|
'''
|
||||||
x = "0" # unknown error has occured
|
x = "0" # unknown error has occured
|
||||||
try:
|
try:
|
||||||
remote_stat = self._execute_remote_stat(path, all_vars, follow=follow)
|
remote_stat = self._execute_remote_stat(path, all_vars, follow=follow)
|
||||||
if remote_stat['exists'] and remote_stat['isdir']:
|
if remote_stat['exists'] and remote_stat['isdir']:
|
||||||
x = "3" # its a directory not a file
|
x = "3" # its a directory not a file
|
||||||
else:
|
else:
|
||||||
x = remote_stat['checksum'] # if 1, file is missing
|
x = remote_stat['checksum'] # if 1, file is missing
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
errormsg = to_unicode(e)
|
errormsg = to_text(e)
|
||||||
if errormsg.endswith('Permission denied'):
|
if errormsg.endswith(u'Permission denied'):
|
||||||
x = "2" # cannot read file
|
x = "2" # cannot read file
|
||||||
elif errormsg.endswith('MODULE FAILURE'):
|
elif errormsg.endswith(u'MODULE FAILURE'):
|
||||||
x = "4" # python not found or module uncaught exception
|
x = "4" # python not found or module uncaught exception
|
||||||
finally:
|
finally:
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
||||||
def _remote_expand_user(self, path):
|
def _remote_expand_user(self, path):
|
||||||
''' takes a remote path and performs tilde expansion on the remote host '''
|
''' takes a remote path and performs tilde expansion on the remote host '''
|
||||||
if not path.startswith('~'): # FIXME: Windows paths may start with "~ instead of just ~
|
if not path.startswith('~'): # FIXME: Windows paths may start with "~ instead of just ~
|
||||||
return path
|
return path
|
||||||
|
|
||||||
# FIXME: Can't use os.path.sep for Windows paths.
|
# FIXME: Can't use os.path.sep for Windows paths.
|
||||||
|
@ -681,7 +687,8 @@ class ActionBase(with_metaclass(ABCMeta, object)):
|
||||||
tmp_rm_res = self._low_level_execute_command(tmp_rm_cmd, sudoable=False)
|
tmp_rm_res = self._low_level_execute_command(tmp_rm_cmd, sudoable=False)
|
||||||
tmp_rm_data = self._parse_returned_data(tmp_rm_res)
|
tmp_rm_data = self._parse_returned_data(tmp_rm_res)
|
||||||
if tmp_rm_data.get('rc', 0) != 0:
|
if tmp_rm_data.get('rc', 0) != 0:
|
||||||
display.warning('Error deleting remote temporary files (rc: {0}, stderr: {1})'.format(tmp_rm_res.get('rc'), tmp_rm_res.get('stderr', 'No error string available.')))
|
display.warning('Error deleting remote temporary files (rc: {0}, stderr: {1})'.format(tmp_rm_res.get('rc'),
|
||||||
|
tmp_rm_res.get('stderr', 'No error string available.')))
|
||||||
|
|
||||||
# parse the main result
|
# parse the main result
|
||||||
data = self._parse_returned_data(res)
|
data = self._parse_returned_data(res)
|
||||||
|
@ -709,7 +716,7 @@ class ActionBase(with_metaclass(ABCMeta, object)):
|
||||||
data['exception'] = res['stderr']
|
data['exception'] = res['stderr']
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _low_level_execute_command(self, cmd, sudoable=True, in_data=None, executable=None, encoding_errors='replace'):
|
def _low_level_execute_command(self, cmd, sudoable=True, in_data=None, executable=None, encoding_errors='surrogate_or_replace'):
|
||||||
'''
|
'''
|
||||||
This is the function which executes the low level shell command, which
|
This is the function which executes the low level shell command, which
|
||||||
may be commands to create/remove directories for temporary files, or to
|
may be commands to create/remove directories for temporary files, or to
|
||||||
|
@ -758,16 +765,16 @@ class ActionBase(with_metaclass(ABCMeta, object)):
|
||||||
# stdout and stderr may be either a file-like or a bytes object.
|
# stdout and stderr may be either a file-like or a bytes object.
|
||||||
# Convert either one to a text type
|
# Convert either one to a text type
|
||||||
if isinstance(stdout, binary_type):
|
if isinstance(stdout, binary_type):
|
||||||
out = to_unicode(stdout, errors=encoding_errors)
|
out = to_text(stdout, errors=encoding_errors)
|
||||||
elif not isinstance(stdout, text_type):
|
elif not isinstance(stdout, text_type):
|
||||||
out = to_unicode(b''.join(stdout.readlines()), errors=encoding_errors)
|
out = to_text(b''.join(stdout.readlines()), errors=encoding_errors)
|
||||||
else:
|
else:
|
||||||
out = stdout
|
out = stdout
|
||||||
|
|
||||||
if isinstance(stderr, binary_type):
|
if isinstance(stderr, binary_type):
|
||||||
err = to_unicode(stderr, errors=encoding_errors)
|
err = to_text(stderr, errors=encoding_errors)
|
||||||
elif not isinstance(stderr, text_type):
|
elif not isinstance(stderr, text_type):
|
||||||
err = to_unicode(b''.join(stderr.readlines()), errors=encoding_errors)
|
err = to_text(b''.join(stderr.readlines()), errors=encoding_errors)
|
||||||
else:
|
else:
|
||||||
err = stderr
|
err = stderr
|
||||||
|
|
||||||
|
@ -871,7 +878,6 @@ class ActionBase(with_metaclass(ABCMeta, object)):
|
||||||
result = self._loader.path_dwim_relative_stack(path_stack, dirname, needle)
|
result = self._loader.path_dwim_relative_stack(path_stack, dirname, needle)
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
raise AnsibleError("Unable to find '%s' in expected paths." % to_str(needle))
|
raise AnsibleError("Unable to find '%s' in expected paths." % to_native(needle))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,10 @@ import tempfile
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_native, to_text
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.boolean import boolean
|
from ansible.utils.boolean import boolean
|
||||||
from ansible.utils.hashing import checksum_s
|
from ansible.utils.hashing import checksum_s
|
||||||
from ansible.utils.unicode import to_str, to_unicode
|
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
@ -42,7 +42,7 @@ class ActionModule(ActionBase):
|
||||||
delimit_me = False
|
delimit_me = False
|
||||||
add_newline = False
|
add_newline = False
|
||||||
|
|
||||||
for f in (to_unicode(p, errors='strict') for p in sorted(os.listdir(src_path))):
|
for f in (to_text(p, errors='surrogate_or_strict') for p in sorted(os.listdir(src_path))):
|
||||||
if compiled_regexp and not compiled_regexp.search(f):
|
if compiled_regexp and not compiled_regexp.search(f):
|
||||||
continue
|
continue
|
||||||
fragment = u"%s/%s" % (src_path, f)
|
fragment = u"%s/%s" % (src_path, f)
|
||||||
|
@ -114,7 +114,7 @@ class ActionModule(ActionBase):
|
||||||
src = self._find_needle('files', src)
|
src = self._find_needle('files', src)
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
result['failed'] = True
|
result['failed'] = True
|
||||||
result['msg'] = to_str(e)
|
result['msg'] = to_native(e)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
if not os.path.isdir(src):
|
if not os.path.isdir(src):
|
||||||
|
|
|
@ -22,9 +22,10 @@ import pipes
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.plugins.action import ActionBase
|
|
||||||
from ansible.compat.six import iteritems
|
from ansible.compat.six import iteritems
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.module_utils._text import to_text
|
||||||
|
from ansible.plugins.action import ActionBase
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
|
||||||
|
@ -76,7 +77,7 @@ class ActionModule(ActionBase):
|
||||||
elif module_style == 'old':
|
elif module_style == 'old':
|
||||||
args_data = ""
|
args_data = ""
|
||||||
for k, v in iteritems(module_args):
|
for k, v in iteritems(module_args):
|
||||||
args_data += '%s="%s" ' % (k, pipes.quote(to_unicode(v)))
|
args_data += '%s="%s" ' % (k, pipes.quote(to_text(v)))
|
||||||
argsfile = self._transfer_data(self._connection._shell.join_path(tmp, 'arguments'), args_data)
|
argsfile = self._transfer_data(self._connection._shell.join_path(tmp, 'arguments'), args_data)
|
||||||
|
|
||||||
remote_paths = tmp, remote_module_path, remote_async_module_path
|
remote_paths = tmp, remote_module_path, remote_async_module_path
|
||||||
|
@ -100,7 +101,7 @@ class ActionModule(ActionBase):
|
||||||
if not self._should_remove_tmp_path(tmp):
|
if not self._should_remove_tmp_path(tmp):
|
||||||
async_cmd.append("-preserve_tmp")
|
async_cmd.append("-preserve_tmp")
|
||||||
|
|
||||||
async_cmd = " ".join([to_unicode(x) for x in async_cmd])
|
async_cmd = " ".join(to_text(x) for x in async_cmd)
|
||||||
result.update(self._low_level_execute_command(cmd=async_cmd))
|
result.update(self._low_level_execute_command(cmd=async_cmd))
|
||||||
|
|
||||||
result['changed'] = True
|
result['changed'] = True
|
||||||
|
|
|
@ -24,10 +24,10 @@ import os
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.boolean import boolean
|
from ansible.utils.boolean import boolean
|
||||||
from ansible.utils.hashing import checksum
|
from ansible.utils.hashing import checksum
|
||||||
from ansible.utils.unicode import to_bytes, to_str, to_unicode
|
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
@ -81,7 +81,7 @@ class ActionModule(ActionBase):
|
||||||
source = content_tempfile
|
source = content_tempfile
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
result['failed'] = True
|
result['failed'] = True
|
||||||
result['msg'] = "could not write content temp file: %s" % to_str(err)
|
result['msg'] = "could not write content temp file: %s" % to_native(err)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# if we have first_available_file in our vars
|
# if we have first_available_file in our vars
|
||||||
|
@ -91,19 +91,19 @@ class ActionModule(ActionBase):
|
||||||
elif remote_src:
|
elif remote_src:
|
||||||
result.update(self._execute_module(module_name='copy', module_args=self._task.args, task_vars=task_vars, delete_remote_tmp=False))
|
result.update(self._execute_module(module_name='copy', module_args=self._task.args, task_vars=task_vars, delete_remote_tmp=False))
|
||||||
return result
|
return result
|
||||||
else: # find in expected paths
|
else: # find in expected paths
|
||||||
try:
|
try:
|
||||||
source = self._find_needle('files', source)
|
source = self._find_needle('files', source)
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
result['failed'] = True
|
result['failed'] = True
|
||||||
result['msg'] = to_unicode(e)
|
result['msg'] = to_text(e)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# A list of source file tuples (full_path, relative_path) which will try to copy to the destination
|
# A list of source file tuples (full_path, relative_path) which will try to copy to the destination
|
||||||
source_files = []
|
source_files = []
|
||||||
|
|
||||||
# If source is a directory populate our list else source is a file and translate it to a tuple.
|
# If source is a directory populate our list else source is a file and translate it to a tuple.
|
||||||
if os.path.isdir(to_bytes(source, errors='strict')):
|
if os.path.isdir(to_bytes(source, errors='surrogate_or_strict')):
|
||||||
# Get the amount of spaces to remove to get the relative path.
|
# Get the amount of spaces to remove to get the relative path.
|
||||||
if source_trailing_slash:
|
if source_trailing_slash:
|
||||||
sz = len(source)
|
sz = len(source)
|
||||||
|
@ -113,7 +113,7 @@ class ActionModule(ActionBase):
|
||||||
# Walk the directory and append the file tuples to source_files.
|
# Walk the directory and append the file tuples to source_files.
|
||||||
for base_path, sub_folders, files in os.walk(to_bytes(source)):
|
for base_path, sub_folders, files in os.walk(to_bytes(source)):
|
||||||
for file in files:
|
for file in files:
|
||||||
full_path = to_unicode(os.path.join(base_path, file), errors='strict')
|
full_path = to_text(os.path.join(base_path, file), errors='surrogate_or_strict')
|
||||||
rel_path = full_path[sz:]
|
rel_path = full_path[sz:]
|
||||||
if rel_path.startswith('/'):
|
if rel_path.startswith('/'):
|
||||||
rel_path = rel_path[1:]
|
rel_path = rel_path[1:]
|
||||||
|
@ -247,7 +247,9 @@ class ActionModule(ActionBase):
|
||||||
if 'content' in new_module_args:
|
if 'content' in new_module_args:
|
||||||
del new_module_args['content']
|
del new_module_args['content']
|
||||||
|
|
||||||
module_return = self._execute_module(module_name='copy', module_args=new_module_args, task_vars=task_vars, tmp=tmp, delete_remote_tmp=delete_remote_tmp)
|
module_return = self._execute_module(module_name='copy',
|
||||||
|
module_args=new_module_args, task_vars=task_vars,
|
||||||
|
tmp=tmp, delete_remote_tmp=delete_remote_tmp)
|
||||||
module_executed = True
|
module_executed = True
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -272,7 +274,9 @@ class ActionModule(ActionBase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Execute the file module.
|
# Execute the file module.
|
||||||
module_return = self._execute_module(module_name='file', module_args=new_module_args, task_vars=task_vars, tmp=tmp, delete_remote_tmp=delete_remote_tmp)
|
module_return = self._execute_module(module_name='file',
|
||||||
|
module_args=new_module_args, task_vars=task_vars,
|
||||||
|
tmp=tmp, delete_remote_tmp=delete_remote_tmp)
|
||||||
module_executed = True
|
module_executed = True
|
||||||
|
|
||||||
if not module_return.get('checksum'):
|
if not module_return.get('checksum'):
|
||||||
|
|
|
@ -20,8 +20,8 @@ __metaclass__ = type
|
||||||
|
|
||||||
from ansible.compat.six import string_types
|
from ansible.compat.six import string_types
|
||||||
from ansible.errors import AnsibleUndefinedVariable
|
from ansible.errors import AnsibleUndefinedVariable
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
@ -66,7 +66,7 @@ class ActionModule(ActionBase):
|
||||||
|
|
||||||
if isinstance(self._task.args['var'], (list, dict)):
|
if isinstance(self._task.args['var'], (list, dict)):
|
||||||
# If var is a list or dict, use the type as key to display
|
# If var is a list or dict, use the type as key to display
|
||||||
result[to_unicode(type(self._task.args['var']))] = results
|
result[to_text(type(self._task.args['var']))] = results
|
||||||
else:
|
else:
|
||||||
result[self._task.args['var']] = results
|
result[self._task.args['var']] = results
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -21,11 +21,11 @@ import os
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.boolean import boolean
|
from ansible.utils.boolean import boolean
|
||||||
from ansible.utils.hashing import checksum, checksum_s, md5, secure_hash
|
from ansible.utils.hashing import checksum, checksum_s, md5, secure_hash
|
||||||
from ansible.utils.path import makedirs_safe
|
from ansible.utils.path import makedirs_safe
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
@ -160,7 +160,7 @@ class ActionModule(ActionBase):
|
||||||
self._connection.fetch_file(source, dest)
|
self._connection.fetch_file(source, dest)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
f = open(to_bytes(dest, errors='strict'), 'w')
|
f = open(to_bytes(dest, errors='surrogate_or_strict'), 'wb')
|
||||||
f.write(remote_data)
|
f.write(remote_data)
|
||||||
f.close()
|
f.close()
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
|
|
|
@ -22,8 +22,8 @@ from os import path, walk
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_native
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.unicode import to_str
|
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
@ -137,7 +137,7 @@ class ActionModule(ActionBase):
|
||||||
results.update(updated_results)
|
results.update(updated_results)
|
||||||
|
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
err_msg = to_str(e)
|
err_msg = to_native(e)
|
||||||
raise AnsibleError(err_msg)
|
raise AnsibleError(err_msg)
|
||||||
|
|
||||||
if self.return_results_as_name:
|
if self.return_results_as_name:
|
||||||
|
|
|
@ -26,10 +26,12 @@ import glob
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.module_utils._text import to_text
|
||||||
|
|
||||||
|
|
||||||
PRIVATE_KEYS_RE = re.compile('__.+__')
|
PRIVATE_KEYS_RE = re.compile('__.+__')
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
|
||||||
TRANSFERS_FILES = False
|
TRANSFERS_FILES = False
|
||||||
|
@ -56,7 +58,6 @@ class ActionModule(ActionBase):
|
||||||
result['__backup__'])
|
result['__backup__'])
|
||||||
result['backup_path'] = filepath
|
result['backup_path'] = filepath
|
||||||
|
|
||||||
|
|
||||||
# strip out any keys that have two leading and two trailing
|
# strip out any keys that have two leading and two trailing
|
||||||
# underscore characters
|
# underscore characters
|
||||||
for key in result.keys():
|
for key in result.keys():
|
||||||
|
@ -98,7 +99,7 @@ class ActionModule(ActionBase):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(source, 'r') as f:
|
with open(source, 'r') as f:
|
||||||
template_data = to_unicode(f.read())
|
template_data = to_text(f.read())
|
||||||
except IOError:
|
except IOError:
|
||||||
return dict(failed=True, msg='unable to load src file')
|
return dict(failed=True, msg='unable to load src file')
|
||||||
|
|
||||||
|
@ -114,5 +115,3 @@ class ActionModule(ActionBase):
|
||||||
searchpath.append(os.path.dirname(source))
|
searchpath.append(os.path.dirname(source))
|
||||||
self._templar.environment.loader.searchpath = searchpath
|
self._templar.environment.loader.searchpath = searchpath
|
||||||
self._task.args['src'] = self._templar.template(template_data)
|
self._task.args['src'] = self._templar.template(template_data)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,18 +19,18 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import glob
|
import glob
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.boolean import boolean
|
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
|
|
||||||
BOOLEANS = ('true', 'false', 'yes', 'no')
|
BOOLEANS = ('true', 'false', 'yes', 'no')
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
|
||||||
TRANSFERS_FILES = False
|
TRANSFERS_FILES = False
|
||||||
|
@ -92,7 +92,7 @@ class ActionModule(ActionBase):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(source, 'r') as f:
|
with open(source, 'r') as f:
|
||||||
template_data = to_unicode(f.read())
|
template_data = to_text(f.read())
|
||||||
except IOError:
|
except IOError:
|
||||||
return dict(failed=True, msg='unable to load src file')
|
return dict(failed=True, msg='unable to load src file')
|
||||||
|
|
||||||
|
@ -108,5 +108,3 @@ class ActionModule(ActionBase):
|
||||||
searchpath.append(os.path.dirname(source))
|
searchpath.append(os.path.dirname(source))
|
||||||
self._templar.environment.loader.searchpath = searchpath
|
self._templar.environment.loader.searchpath = searchpath
|
||||||
self._task.args['src'] = self._templar.template(template_data)
|
self._task.args['src'] = self._templar.template(template_data)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@ __metaclass__ = type
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_native
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.boolean import boolean
|
from ansible.utils.boolean import boolean
|
||||||
from ansible.errors import AnsibleError
|
|
||||||
from ansible.utils.unicode import to_str
|
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
@ -52,7 +52,7 @@ class ActionModule(ActionBase):
|
||||||
src = self._find_needle('files', src)
|
src = self._find_needle('files', src)
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
result['failed'] = True
|
result['failed'] = True
|
||||||
result['msg'] = to_str(e)
|
result['msg'] = to_native(e)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# create the remote tmp dir if needed, and put the source file there
|
# create the remote tmp dir if needed, and put the source file there
|
||||||
|
|
|
@ -19,15 +19,14 @@ __metaclass__ = type
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ansible.plugins.action import ActionBase
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.utils.unicode import to_str
|
from ansible.module_utils._text import to_native
|
||||||
|
from ansible.plugins.action import ActionBase
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
TRANSFERS_FILES = True
|
TRANSFERS_FILES = True
|
||||||
|
|
||||||
|
|
||||||
def run(self, tmp=None, task_vars=None):
|
def run(self, tmp=None, task_vars=None):
|
||||||
''' handler for file transfer operations '''
|
''' handler for file transfer operations '''
|
||||||
if task_vars is None:
|
if task_vars is None:
|
||||||
|
@ -74,7 +73,7 @@ class ActionModule(ActionBase):
|
||||||
try:
|
try:
|
||||||
source = self._loader.get_real_file(self._find_needle('files', source))
|
source = self._loader.get_real_file(self._find_needle('files', source))
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
return dict(failed=True, msg=to_str(e))
|
return dict(failed=True, msg=to_native(e))
|
||||||
|
|
||||||
# transfer the file to a remote tmp location
|
# transfer the file to a remote tmp location
|
||||||
tmp_src = self._connection._shell.join_path(tmp, os.path.basename(source))
|
tmp_src = self._connection._shell.join_path(tmp, os.path.basename(source))
|
||||||
|
|
|
@ -23,12 +23,11 @@ import pwd
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.hashing import checksum_s
|
from ansible.utils.hashing import checksum_s
|
||||||
from ansible.utils.boolean import boolean
|
from ansible.utils.boolean import boolean
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode, to_str
|
|
||||||
from ansible.errors import AnsibleError
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
@ -78,7 +77,7 @@ class ActionModule(ActionBase):
|
||||||
source = self._find_needle('templates', source)
|
source = self._find_needle('templates', source)
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
result['failed'] = True
|
result['failed'] = True
|
||||||
result['msg'] = to_str(e)
|
result['msg'] = to_native(e)
|
||||||
|
|
||||||
if 'failed' in result:
|
if 'failed' in result:
|
||||||
return result
|
return result
|
||||||
|
@ -96,7 +95,7 @@ class ActionModule(ActionBase):
|
||||||
b_source = to_bytes(source)
|
b_source = to_bytes(source)
|
||||||
try:
|
try:
|
||||||
with open(b_source, 'r') as f:
|
with open(b_source, 'r') as f:
|
||||||
template_data = to_unicode(f.read())
|
template_data = to_text(f.read())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
template_uid = pwd.getpwuid(os.stat(b_source).st_uid).pw_name
|
template_uid = pwd.getpwuid(os.stat(b_source).st_uid).pw_name
|
||||||
|
@ -163,7 +162,7 @@ class ActionModule(ActionBase):
|
||||||
if self._play_context.diff:
|
if self._play_context.diff:
|
||||||
diff = self._get_diff_data(dest, resultant, task_vars, source_file=False)
|
diff = self._get_diff_data(dest, resultant, task_vars, source_file=False)
|
||||||
|
|
||||||
if not self._play_context.check_mode: # do actual work thorugh copy
|
if not self._play_context.check_mode: # do actual work through copy
|
||||||
xfered = self._transfer_data(self._connection._shell.join_path(tmp, 'source'), resultant)
|
xfered = self._transfer_data(self._connection._shell.join_path(tmp, 'source'), resultant)
|
||||||
|
|
||||||
# fix file permissions when the copy is done as a different user
|
# fix file permissions when the copy is done as a different user
|
||||||
|
@ -176,7 +175,7 @@ class ActionModule(ActionBase):
|
||||||
dest=dest,
|
dest=dest,
|
||||||
original_basename=os.path.basename(source),
|
original_basename=os.path.basename(source),
|
||||||
follow=True,
|
follow=True,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
result.update(self._execute_module(module_name='copy', module_args=new_module_args, task_vars=task_vars, tmp=tmp, delete_remote_tmp=False))
|
result.update(self._execute_module(module_name='copy', module_args=new_module_args, task_vars=task_vars, tmp=tmp, delete_remote_tmp=False))
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,11 @@ __metaclass__ = type
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_native
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.boolean import boolean
|
from ansible.utils.boolean import boolean
|
||||||
from ansible.errors import AnsibleError
|
|
||||||
from ansible.utils.unicode import to_str
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ class ActionModule(ActionBase):
|
||||||
source = self._loader.get_real_file(self._find_needle('files', source))
|
source = self._loader.get_real_file(self._find_needle('files', source))
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
result['failed'] = True
|
result['failed'] = True
|
||||||
result['msg'] = to_str(e)
|
result['msg'] = to_native(e)
|
||||||
self._remove_tmp_path(tmp)
|
self._remove_tmp_path(tmp)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
@ -19,26 +19,24 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
from ansible.plugins.action import ActionBase
|
|
||||||
from ansible.utils.boolean import boolean
|
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
from ansible.errors import AnsibleUndefinedVariable
|
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
import traceback
|
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from ansible.plugins.action import ActionBase
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
display = Display()
|
display = Display()
|
||||||
|
|
||||||
|
|
||||||
class TimedOutException(Exception):
|
class TimedOutException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
TRANSFERS_FILES = False
|
TRANSFERS_FILES = False
|
||||||
|
|
||||||
|
@ -50,7 +48,7 @@ class ActionModule(ActionBase):
|
||||||
|
|
||||||
def do_until_success_or_timeout(self, what, timeout_sec, what_desc, fail_sleep_sec=1):
|
def do_until_success_or_timeout(self, what, timeout_sec, what_desc, fail_sleep_sec=1):
|
||||||
max_end_time = datetime.utcnow() + timedelta(seconds=timeout_sec)
|
max_end_time = datetime.utcnow() + timedelta(seconds=timeout_sec)
|
||||||
|
|
||||||
while datetime.utcnow() < max_end_time:
|
while datetime.utcnow() < max_end_time:
|
||||||
try:
|
try:
|
||||||
what()
|
what()
|
||||||
|
@ -82,7 +80,7 @@ class ActionModule(ActionBase):
|
||||||
winrm_port = self._connection._winrm_port
|
winrm_port = self._connection._winrm_port
|
||||||
|
|
||||||
result = super(ActionModule, self).run(tmp, task_vars)
|
result = super(ActionModule, self).run(tmp, task_vars)
|
||||||
|
|
||||||
# initiate reboot
|
# initiate reboot
|
||||||
(rc, stdout, stderr) = self._connection.exec_command("shutdown /r /t %d" % pre_reboot_delay_sec)
|
(rc, stdout, stderr) = self._connection.exec_command("shutdown /r /t %d" % pre_reboot_delay_sec)
|
||||||
|
|
||||||
|
@ -92,7 +90,7 @@ class ActionModule(ActionBase):
|
||||||
result['msg'] = "Shutdown command failed, error text was %s" % stderr
|
result['msg'] = "Shutdown command failed, error text was %s" % stderr
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def raise_if_port_open():
|
def raise_if_port_open():
|
||||||
try:
|
try:
|
||||||
sock = socket.create_connection((winrm_host, winrm_port), connect_timeout_sec)
|
sock = socket.create_connection((winrm_host, winrm_port), connect_timeout_sec)
|
||||||
sock.close()
|
sock.close()
|
||||||
|
@ -137,4 +135,3 @@ class ActionModule(ActionBase):
|
||||||
result['msg'] = toex.message
|
result['msg'] = toex.message
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
2
lib/ansible/plugins/cache/jsonfile.py
vendored
2
lib/ansible/plugins/cache/jsonfile.py
vendored
|
@ -31,9 +31,9 @@ except ImportError:
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.parsing.utils.jsonify import jsonify
|
from ansible.parsing.utils.jsonify import jsonify
|
||||||
from ansible.plugins.cache.base import BaseCacheModule
|
from ansible.plugins.cache.base import BaseCacheModule
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
|
|
@ -24,12 +24,10 @@ import difflib
|
||||||
import warnings
|
import warnings
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from ansible.compat.six import string_types
|
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.vars import strip_internal_keys
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.utils.color import stringc
|
from ansible.utils.color import stringc
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.vars import strip_internal_keys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display as global_display
|
from __main__ import display as global_display
|
||||||
|
@ -37,14 +35,15 @@ except ImportError:
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
global_display = Display()
|
global_display = Display()
|
||||||
|
|
||||||
__all__ = ["CallbackBase"]
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import cli
|
from __main__ import cli
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# using API w/o cli
|
# using API w/o cli
|
||||||
cli = False
|
cli = False
|
||||||
|
|
||||||
|
__all__ = ["CallbackBase"]
|
||||||
|
|
||||||
|
|
||||||
class CallbackBase:
|
class CallbackBase:
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
@ -146,8 +145,8 @@ class CallbackBase:
|
||||||
after_header = "after: %s" % diff['after_header']
|
after_header = "after: %s" % diff['after_header']
|
||||||
else:
|
else:
|
||||||
after_header = 'after'
|
after_header = 'after'
|
||||||
differ = difflib.unified_diff(to_unicode(diff['before']).splitlines(True),
|
differ = difflib.unified_diff(to_text(diff['before']).splitlines(True),
|
||||||
to_unicode(diff['after']).splitlines(True),
|
to_text(diff['after']).splitlines(True),
|
||||||
fromfile=before_header,
|
fromfile=before_header,
|
||||||
tofile=after_header,
|
tofile=after_header,
|
||||||
fromfiledate='',
|
fromfiledate='',
|
||||||
|
@ -166,7 +165,7 @@ class CallbackBase:
|
||||||
if has_diff:
|
if has_diff:
|
||||||
ret.append('\n')
|
ret.append('\n')
|
||||||
if 'prepared' in diff:
|
if 'prepared' in diff:
|
||||||
ret.append(to_unicode(diff['prepared']))
|
ret.append(to_text(diff['prepared']))
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
ret.append(">> the files are different, but the diff library cannot compare unicode strings\n\n")
|
ret.append(">> the files are different, but the diff library cannot compare unicode strings\n\n")
|
||||||
return u''.join(ret)
|
return u''.join(ret)
|
||||||
|
@ -362,4 +361,3 @@ class CallbackBase:
|
||||||
|
|
||||||
def v2_runner_retry(self, result):
|
def v2_runner_retry(self, result):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ __metaclass__ = type
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from junit_xml import TestSuite, TestCase
|
from junit_xml import TestSuite, TestCase
|
||||||
|
@ -40,6 +40,7 @@ except ImportError:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
HAS_ORDERED_DICT = False
|
HAS_ORDERED_DICT = False
|
||||||
|
|
||||||
|
|
||||||
class CallbackModule(CallbackBase):
|
class CallbackModule(CallbackBase):
|
||||||
"""
|
"""
|
||||||
This callback writes playbook output to a JUnit formatted XML file.
|
This callback writes playbook output to a JUnit formatted XML file.
|
||||||
|
@ -181,7 +182,7 @@ class CallbackModule(CallbackBase):
|
||||||
output_file = os.path.join(self._output_dir, '%s-%s.xml' % (self._playbook_name, time.time()))
|
output_file = os.path.join(self._output_dir, '%s-%s.xml' % (self._playbook_name, time.time()))
|
||||||
|
|
||||||
with open(output_file, 'wb') as xml:
|
with open(output_file, 'wb') as xml:
|
||||||
xml.write(to_bytes(report, errors='strict'))
|
xml.write(to_bytes(report, errors='surrogate_or_strict'))
|
||||||
|
|
||||||
def v2_playbook_on_start(self, playbook):
|
def v2_playbook_on_start(self, playbook):
|
||||||
self._playbook_path = playbook._file_name
|
self._playbook_path = playbook._file_name
|
||||||
|
|
|
@ -23,9 +23,10 @@ import os
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from ansible.utils.unicode import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
|
|
||||||
# NOTE: in Ansible 1.2 or later general logging is available without
|
# NOTE: in Ansible 1.2 or later general logging is available without
|
||||||
# this plugin, just set ANSIBLE_LOG_PATH as an environment variable
|
# this plugin, just set ANSIBLE_LOG_PATH as an environment variable
|
||||||
# or log_path in the DEFAULTS section of your ansible configuration
|
# or log_path in the DEFAULTS section of your ansible configuration
|
||||||
|
|
|
@ -25,9 +25,10 @@ import smtplib
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from ansible.compat.six import string_types
|
from ansible.compat.six import string_types
|
||||||
from ansible.utils.unicode import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
|
|
||||||
def mail(subject='Ansible error mail', sender=None, to=None, cc=None, bcc=None, body=None, smtphost=None):
|
def mail(subject='Ansible error mail', sender=None, to=None, cc=None, bcc=None, body=None, smtphost=None):
|
||||||
|
|
||||||
if sender is None:
|
if sender is None:
|
||||||
|
@ -84,7 +85,7 @@ class CallbackModule(CallbackBase):
|
||||||
if ignore_errors:
|
if ignore_errors:
|
||||||
return
|
return
|
||||||
sender = '"Ansible: %s" <root>' % host
|
sender = '"Ansible: %s" <root>' % host
|
||||||
attach = res._task.action
|
attach = res._task.action
|
||||||
if 'invocation' in res._result:
|
if 'invocation' in res._result:
|
||||||
attach = "%s: %s" % (res._result['invocation']['module_name'], json.dumps(res._result['invocation']['module_args']))
|
attach = "%s: %s" % (res._result['invocation']['module_name'], json.dumps(res._result['invocation']['module_args']))
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@ __metaclass__ = type
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from ansible.constants import TREE_DIR
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
from ansible.utils.path import makedirs_safe
|
from ansible.utils.path import makedirs_safe
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
from ansible.constants import TREE_DIR
|
|
||||||
|
|
||||||
|
|
||||||
class CallbackModule(CallbackBase):
|
class CallbackModule(CallbackBase):
|
||||||
|
@ -68,4 +68,3 @@ class CallbackModule(CallbackBase):
|
||||||
|
|
||||||
def v2_runner_on_unreachable(self, result):
|
def v2_runner_on_unreachable(self, result):
|
||||||
self.result_to_tree(result)
|
self.result_to_tree(result)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# (c) 2015 Toshio Kuratomi <tkuratomi@ansible.com>
|
# (c) 2015 Toshio Kuratomi <tkuratomi@ansible.com>
|
||||||
#
|
#
|
||||||
# This file is part of Ansible
|
# This file is part of Ansible
|
||||||
|
@ -32,8 +31,9 @@ from ansible.compat.six import with_metaclass
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.compat.six import string_types
|
from ansible.compat.six import string_types
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
from ansible.plugins import shell_loader
|
from ansible.plugins import shell_loader
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -138,9 +138,9 @@ class ConnectionBase(with_metaclass(ABCMeta, object)):
|
||||||
# exception, it merely mangles the output:
|
# exception, it merely mangles the output:
|
||||||
# >>> shlex.split(u't e')
|
# >>> shlex.split(u't e')
|
||||||
# ['t\x00\x00\x00', '\x00\x00\x00e\x00\x00\x00']
|
# ['t\x00\x00\x00', '\x00\x00\x00e\x00\x00\x00']
|
||||||
return [to_unicode(x.strip()) for x in shlex.split(to_bytes(argstring)) if x.strip()]
|
return [to_text(x.strip()) for x in shlex.split(to_bytes(argstring)) if x.strip()]
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return [to_unicode(x.strip()) for x in shlex.split(argstring) if x.strip()]
|
return [to_text(x.strip()) for x in shlex.split(argstring) if x.strip()]
|
||||||
|
|
||||||
@abstractproperty
|
@abstractproperty
|
||||||
def transport(self):
|
def transport(self):
|
||||||
|
|
|
@ -27,10 +27,11 @@ import time
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError, AnsibleFileNotFound, AnsibleConnectionFailure
|
from ansible.errors import AnsibleError, AnsibleFileNotFound, AnsibleConnectionFailure
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.parsing.utils.jsonify import jsonify
|
from ansible.parsing.utils.jsonify import jsonify
|
||||||
from ansible.plugins.connection import ConnectionBase
|
from ansible.plugins.connection import ConnectionBase
|
||||||
from ansible.utils.encrypt import key_for_hostname, keyczar_encrypt, keyczar_decrypt
|
from ansible.utils.encrypt import key_for_hostname, keyczar_encrypt, keyczar_decrypt
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -211,7 +212,7 @@ class Connection(ConnectionBase):
|
||||||
''' transfer a file from local to remote '''
|
''' transfer a file from local to remote '''
|
||||||
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr)
|
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr)
|
||||||
|
|
||||||
in_path = to_bytes(in_path, errors='strict')
|
in_path = to_bytes(in_path, errors='surrogate_or_strict')
|
||||||
|
|
||||||
if not os.path.exists(in_path):
|
if not os.path.exists(in_path):
|
||||||
raise AnsibleFileNotFound("file or module does not exist: %s" % in_path)
|
raise AnsibleFileNotFound("file or module does not exist: %s" % in_path)
|
||||||
|
@ -265,7 +266,7 @@ class Connection(ConnectionBase):
|
||||||
if self.send_data(data):
|
if self.send_data(data):
|
||||||
raise AnsibleError("failed to initiate the file fetch with %s" % self._play_context.remote_addr)
|
raise AnsibleError("failed to initiate the file fetch with %s" % self._play_context.remote_addr)
|
||||||
|
|
||||||
fh = open(to_bytes(out_path, errors='strict'), "w")
|
fh = open(to_bytes(out_path, errors='surrogate_or_strict'), "w")
|
||||||
try:
|
try:
|
||||||
bytes = 0
|
bytes = 0
|
||||||
while True:
|
while True:
|
||||||
|
|
|
@ -28,9 +28,10 @@ import traceback
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
|
||||||
from ansible.module_utils.basic import is_executable
|
from ansible.module_utils.basic import is_executable
|
||||||
from ansible.utils.unicode import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
|
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -93,7 +94,7 @@ class Connection(ConnectionBase):
|
||||||
local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd]
|
local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd]
|
||||||
|
|
||||||
display.vvv("EXEC %s" % (local_cmd), host=self.chroot)
|
display.vvv("EXEC %s" % (local_cmd), host=self.chroot)
|
||||||
local_cmd = [to_bytes(i, errors='strict') for i in local_cmd]
|
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||||
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
|
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
out_path = pipes.quote(self._prefix_login_path(out_path))
|
out_path = pipes.quote(self._prefix_login_path(out_path))
|
||||||
try:
|
try:
|
||||||
with open(to_bytes(in_path, errors='strict'), 'rb') as in_file:
|
with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file:
|
||||||
try:
|
try:
|
||||||
p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file)
|
p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file)
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -155,7 +156,7 @@ class Connection(ConnectionBase):
|
||||||
except OSError:
|
except OSError:
|
||||||
raise AnsibleError("chroot connection requires dd command in the chroot")
|
raise AnsibleError("chroot connection requires dd command in the chroot")
|
||||||
|
|
||||||
with open(to_bytes(out_path, errors='strict'), 'wb+') as out_file:
|
with open(to_bytes(out_path, errors='surrogate_or_strict'), 'wb+') as out_file:
|
||||||
try:
|
try:
|
||||||
chunk = p.stdout.read(BUFSIZE)
|
chunk = p.stdout.read(BUFSIZE)
|
||||||
while chunk:
|
while chunk:
|
||||||
|
|
|
@ -35,8 +35,9 @@ from distutils.version import LooseVersion
|
||||||
|
|
||||||
import ansible.constants as C
|
import ansible.constants as C
|
||||||
from ansible.errors import AnsibleError, AnsibleFileNotFound
|
from ansible.errors import AnsibleError, AnsibleFileNotFound
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -196,7 +197,7 @@ class Connection(ConnectionBase):
|
||||||
local_cmd = self._build_exec_cmd([self._play_context.executable, '-c', cmd])
|
local_cmd = self._build_exec_cmd([self._play_context.executable, '-c', cmd])
|
||||||
|
|
||||||
display.vvv("EXEC %s" % (local_cmd,), host=self._play_context.remote_addr)
|
display.vvv("EXEC %s" % (local_cmd,), host=self._play_context.remote_addr)
|
||||||
local_cmd = [to_bytes(i, errors='strict') for i in local_cmd]
|
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||||
p = subprocess.Popen(local_cmd, shell=False, stdin=subprocess.PIPE,
|
p = subprocess.Popen(local_cmd, shell=False, stdin=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
|
@ -223,7 +224,7 @@ class Connection(ConnectionBase):
|
||||||
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr)
|
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr)
|
||||||
|
|
||||||
out_path = self._prefix_login_path(out_path)
|
out_path = self._prefix_login_path(out_path)
|
||||||
if not os.path.exists(to_bytes(in_path, errors='strict')):
|
if not os.path.exists(to_bytes(in_path, errors='surrogate_or_strict')):
|
||||||
raise AnsibleFileNotFound(
|
raise AnsibleFileNotFound(
|
||||||
"file or module does not exist: %s" % in_path)
|
"file or module does not exist: %s" % in_path)
|
||||||
|
|
||||||
|
@ -233,8 +234,8 @@ class Connection(ConnectionBase):
|
||||||
# Although docker version 1.8 and later provide support, the
|
# Although docker version 1.8 and later provide support, the
|
||||||
# owner and group of the files are always set to root
|
# owner and group of the files are always set to root
|
||||||
args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s" % (out_path, BUFSIZE)])
|
args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s" % (out_path, BUFSIZE)])
|
||||||
args = [to_bytes(i, errors='strict') for i in args]
|
args = [to_bytes(i, errors='surrogate_or_strict') for i in args]
|
||||||
with open(to_bytes(in_path, errors='strict'), 'rb') as in_file:
|
with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file:
|
||||||
try:
|
try:
|
||||||
p = subprocess.Popen(args, stdin=in_file,
|
p = subprocess.Popen(args, stdin=in_file,
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
@ -256,7 +257,7 @@ class Connection(ConnectionBase):
|
||||||
out_dir = os.path.dirname(out_path)
|
out_dir = os.path.dirname(out_path)
|
||||||
|
|
||||||
args = [self.docker_cmd, "cp", "%s:%s" % (self._play_context.remote_addr, in_path), out_dir]
|
args = [self.docker_cmd, "cp", "%s:%s" % (self._play_context.remote_addr, in_path), out_dir]
|
||||||
args = [to_bytes(i, errors='strict') for i in args]
|
args = [to_bytes(i, errors='surrogate_or_strict') for i in args]
|
||||||
|
|
||||||
p = subprocess.Popen(args, stdin=subprocess.PIPE,
|
p = subprocess.Popen(args, stdin=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
|
@ -27,10 +27,9 @@ import pipes
|
||||||
import subprocess
|
import subprocess
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from ansible import constants as C
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -117,7 +116,7 @@ class Connection(ConnectionBase):
|
||||||
local_cmd += [self.jail, self._play_context.executable, '-c', set_env + cmd]
|
local_cmd += [self.jail, self._play_context.executable, '-c', set_env + cmd]
|
||||||
|
|
||||||
display.vvv("EXEC %s" % (local_cmd,), host=self.jail)
|
display.vvv("EXEC %s" % (local_cmd,), host=self.jail)
|
||||||
local_cmd = [to_bytes(i, errors='strict') for i in local_cmd]
|
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||||
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
|
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
|
@ -153,7 +152,7 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
out_path = pipes.quote(self._prefix_login_path(out_path))
|
out_path = pipes.quote(self._prefix_login_path(out_path))
|
||||||
try:
|
try:
|
||||||
with open(to_bytes(in_path, errors='strict'), 'rb') as in_file:
|
with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file:
|
||||||
try:
|
try:
|
||||||
p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file)
|
p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file)
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -179,7 +178,7 @@ class Connection(ConnectionBase):
|
||||||
except OSError:
|
except OSError:
|
||||||
raise AnsibleError("jail connection requires dd command in the jail")
|
raise AnsibleError("jail connection requires dd command in the jail")
|
||||||
|
|
||||||
with open(to_bytes(out_path, errors='strict'), 'wb+') as out_file:
|
with open(to_bytes(out_path, errors='surrogate_or_strict'), 'wb+') as out_file:
|
||||||
try:
|
try:
|
||||||
chunk = p.stdout.read(BUFSIZE)
|
chunk = p.stdout.read(BUFSIZE)
|
||||||
while chunk:
|
while chunk:
|
||||||
|
|
|
@ -29,8 +29,9 @@ import traceback
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -94,7 +95,7 @@ class Connection(ConnectionBase):
|
||||||
local_cmd += [self.lxc, '--', executable, '-c', cmd]
|
local_cmd += [self.lxc, '--', executable, '-c', cmd]
|
||||||
|
|
||||||
display.vvv("EXEC %s" % (local_cmd,), host=self.lxc)
|
display.vvv("EXEC %s" % (local_cmd,), host=self.lxc)
|
||||||
local_cmd = [to_bytes(i, errors='strict') for i in local_cmd]
|
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||||
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
|
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
out_path = pipes.quote(self._prefix_login_path(out_path))
|
out_path = pipes.quote(self._prefix_login_path(out_path))
|
||||||
try:
|
try:
|
||||||
with open(to_bytes(in_path, errors='strict'), 'rb') as in_file:
|
with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file:
|
||||||
try:
|
try:
|
||||||
p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file)
|
p = self._buffered_exec_command('dd of=%s bs=%s' % (out_path, BUFSIZE), stdin=in_file)
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -156,7 +157,7 @@ class Connection(ConnectionBase):
|
||||||
except OSError:
|
except OSError:
|
||||||
raise AnsibleError("chroot connection requires dd command in the chroot")
|
raise AnsibleError("chroot connection requires dd command in the chroot")
|
||||||
|
|
||||||
with open(to_bytes(out_path, errors='strict'), 'wb+') as out_file:
|
with open(to_bytes(out_path, errors='surrogate_or_strict'), 'wb+') as out_file:
|
||||||
try:
|
try:
|
||||||
chunk = p.stdout.read(BUFSIZE)
|
chunk = p.stdout.read(BUFSIZE)
|
||||||
while chunk:
|
while chunk:
|
||||||
|
|
|
@ -30,8 +30,9 @@ from ansible.compat.six import text_type, binary_type
|
||||||
import ansible.constants as C
|
import ansible.constants as C
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleFileNotFound
|
from ansible.errors import AnsibleError, AnsibleFileNotFound
|
||||||
|
from ansible.module_utils._text import to_bytes, to_native
|
||||||
from ansible.plugins.connection import ConnectionBase
|
from ansible.plugins.connection import ConnectionBase
|
||||||
from ansible.utils.unicode import to_bytes, to_str
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -122,14 +123,14 @@ class Connection(ConnectionBase):
|
||||||
super(Connection, self).put_file(in_path, out_path)
|
super(Connection, self).put_file(in_path, out_path)
|
||||||
|
|
||||||
display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self._play_context.remote_addr)
|
display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self._play_context.remote_addr)
|
||||||
if not os.path.exists(to_bytes(in_path, errors='strict')):
|
if not os.path.exists(to_bytes(in_path, errors='surrogate_or_strict')):
|
||||||
raise AnsibleFileNotFound("file or module does not exist: {0}".format(to_str(in_path)))
|
raise AnsibleFileNotFound("file or module does not exist: {0}".format(to_native(in_path)))
|
||||||
try:
|
try:
|
||||||
shutil.copyfile(to_bytes(in_path, errors='strict'), to_bytes(out_path, errors='strict'))
|
shutil.copyfile(to_bytes(in_path, errors='surrogate_or_strict'), to_bytes(out_path, errors='surrogate_or_strict'))
|
||||||
except shutil.Error:
|
except shutil.Error:
|
||||||
raise AnsibleError("failed to copy: {0} and {1} are the same".format(to_str(in_path), to_str(out_path)))
|
raise AnsibleError("failed to copy: {0} and {1} are the same".format(to_native(in_path), to_native(out_path)))
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
raise AnsibleError("failed to transfer file to {0}: {1}".format(to_str(out_path), to_str(e)))
|
raise AnsibleError("failed to transfer file to {0}: {1}".format(to_native(out_path), to_native(e)))
|
||||||
|
|
||||||
def fetch_file(self, in_path, out_path):
|
def fetch_file(self, in_path, out_path):
|
||||||
''' fetch a file from local to local -- for copatibility '''
|
''' fetch a file from local to local -- for copatibility '''
|
||||||
|
|
|
@ -24,10 +24,6 @@ import traceback
|
||||||
import select
|
import select
|
||||||
import fcntl
|
import fcntl
|
||||||
import errno
|
import errno
|
||||||
from ansible import errors
|
|
||||||
from ansible import constants as C
|
|
||||||
from ansible.plugins.connection import ConnectionBase
|
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
HAS_LIBLXC = False
|
HAS_LIBLXC = False
|
||||||
try:
|
try:
|
||||||
|
@ -36,6 +32,12 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
from ansible import constants as C
|
||||||
|
from ansible import errors
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
|
from ansible.plugins.connection import ConnectionBase
|
||||||
|
|
||||||
|
|
||||||
class Connection(ConnectionBase):
|
class Connection(ConnectionBase):
|
||||||
''' Local lxc based connections '''
|
''' Local lxc based connections '''
|
||||||
|
|
||||||
|
@ -102,8 +104,8 @@ class Connection(ConnectionBase):
|
||||||
''' run a command on the chroot '''
|
''' run a command on the chroot '''
|
||||||
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
|
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
|
||||||
|
|
||||||
executable = to_bytes(self._play_context.executable, errors='strict')
|
executable = to_bytes(self._play_context.executable, errors='surrogate_or_strict')
|
||||||
local_cmd = [executable, '-c', to_bytes(cmd, errors='strict')]
|
local_cmd = [executable, '-c', to_bytes(cmd, errors='surrogate_or_strict')]
|
||||||
|
|
||||||
read_stdout, write_stdout = None, None
|
read_stdout, write_stdout = None, None
|
||||||
read_stderr, write_stderr = None, None
|
read_stderr, write_stderr = None, None
|
||||||
|
@ -154,8 +156,8 @@ class Connection(ConnectionBase):
|
||||||
''' transfer a file from local to lxc '''
|
''' transfer a file from local to lxc '''
|
||||||
super(Connection, self).put_file(in_path, out_path)
|
super(Connection, self).put_file(in_path, out_path)
|
||||||
self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.container_name)
|
self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.container_name)
|
||||||
in_path = to_bytes(in_path, errors='strict')
|
in_path = to_bytes(in_path, errors='surrogate_or_strict')
|
||||||
out_path = to_bytes(out_path, errors='strict')
|
out_path = to_bytes(out_path, errors='surrogate_or_strict')
|
||||||
|
|
||||||
if not os.path.exists(in_path):
|
if not os.path.exists(in_path):
|
||||||
msg = "file or module does not exist: %s" % in_path
|
msg = "file or module does not exist: %s" % in_path
|
||||||
|
@ -182,8 +184,8 @@ class Connection(ConnectionBase):
|
||||||
''' fetch a file from lxc to local '''
|
''' fetch a file from lxc to local '''
|
||||||
super(Connection, self).fetch_file(in_path, out_path)
|
super(Connection, self).fetch_file(in_path, out_path)
|
||||||
self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.container_name)
|
self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.container_name)
|
||||||
in_path = to_bytes(in_path, errors='strict')
|
in_path = to_bytes(in_path, errors='surrogate_or_strict')
|
||||||
out_path = to_bytes(out_path, errors='strict')
|
out_path = to_bytes(out_path, errors='surrogate_or_strict')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
dst_file = open(out_path, "wb")
|
dst_file = open(out_path, "wb")
|
||||||
|
|
|
@ -23,8 +23,8 @@ from distutils.spawn import find_executable
|
||||||
from subprocess import call, Popen, PIPE
|
from subprocess import call, Popen, PIPE
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
|
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
|
||||||
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
from ansible.plugins.connection import ConnectionBase
|
from ansible.plugins.connection import ConnectionBase
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
|
||||||
|
|
||||||
|
|
||||||
class Connection(ConnectionBase):
|
class Connection(ConnectionBase):
|
||||||
|
@ -61,14 +61,14 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
local_cmd = [self._lxc_cmd, "exec", self._host, "--", self._play_context.executable, "-c", cmd]
|
local_cmd = [self._lxc_cmd, "exec", self._host, "--", self._play_context.executable, "-c", cmd]
|
||||||
|
|
||||||
local_cmd = [to_bytes(i, errors='strict') for i in local_cmd]
|
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||||
in_data = to_bytes(in_data, errors='strict', nonstring='passthru')
|
in_data = to_bytes(in_data, errors='surrogate_or_strict', nonstring='passthru')
|
||||||
|
|
||||||
process = Popen(local_cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
process = Popen(local_cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||||
stdout, stderr = process.communicate(in_data)
|
stdout, stderr = process.communicate(in_data)
|
||||||
|
|
||||||
stdout = to_unicode(stdout)
|
stdout = to_text(stdout)
|
||||||
stderr = to_unicode(stderr)
|
stderr = to_text(stderr)
|
||||||
|
|
||||||
if stderr == "error: Container is not running.\n":
|
if stderr == "error: Container is not running.\n":
|
||||||
raise AnsibleConnectionFailure("container not running: %s" % self._host)
|
raise AnsibleConnectionFailure("container not running: %s" % self._host)
|
||||||
|
@ -84,12 +84,12 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
self._display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self._host)
|
self._display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self._host)
|
||||||
|
|
||||||
if not os.path.isfile(to_bytes(in_path, errors='strict')):
|
if not os.path.isfile(to_bytes(in_path, errors='surrogate_or_strict')):
|
||||||
raise AnsibleFileNotFound("input path is not a file: %s" % in_path)
|
raise AnsibleFileNotFound("input path is not a file: %s" % in_path)
|
||||||
|
|
||||||
local_cmd = [self._lxc_cmd, "file", "push", in_path, self._host + "/" + out_path]
|
local_cmd = [self._lxc_cmd, "file", "push", in_path, self._host + "/" + out_path]
|
||||||
|
|
||||||
local_cmd = [to_bytes(i, errors='strict') for i in local_cmd]
|
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||||
|
|
||||||
call(local_cmd)
|
call(local_cmd)
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
local_cmd = [self._lxc_cmd, "file", "pull", self._host + "/" + in_path, out_path]
|
local_cmd = [self._lxc_cmd, "file", "pull", self._host + "/" + in_path, out_path]
|
||||||
|
|
||||||
local_cmd = [to_bytes(i, errors='strict') for i in local_cmd]
|
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||||
|
|
||||||
call(local_cmd)
|
call(local_cmd)
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ from ansible.compat.six.moves import input
|
||||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
|
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
|
||||||
from ansible.plugins.connection import ConnectionBase
|
from ansible.plugins.connection import ConnectionBase
|
||||||
from ansible.utils.path import makedirs_safe
|
from ansible.utils.path import makedirs_safe
|
||||||
from ansible.utils.unicode import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -52,6 +52,7 @@ except ImportError:
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
display = Display()
|
display = Display()
|
||||||
|
|
||||||
|
|
||||||
AUTHENTICITY_MSG="""
|
AUTHENTICITY_MSG="""
|
||||||
paramiko: The authenticity of host '%s' can't be established.
|
paramiko: The authenticity of host '%s' can't be established.
|
||||||
The %s key fingerprint is %s.
|
The %s key fingerprint is %s.
|
||||||
|
@ -273,7 +274,7 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
display.vvv("EXEC %s" % cmd, host=self._play_context.remote_addr)
|
display.vvv("EXEC %s" % cmd, host=self._play_context.remote_addr)
|
||||||
|
|
||||||
cmd = to_bytes(cmd, errors='strict')
|
cmd = to_bytes(cmd, errors='surrogate_or_strict')
|
||||||
|
|
||||||
no_prompt_out = b''
|
no_prompt_out = b''
|
||||||
no_prompt_err = b''
|
no_prompt_err = b''
|
||||||
|
@ -330,7 +331,7 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr)
|
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr)
|
||||||
|
|
||||||
if not os.path.exists(to_bytes(in_path, errors='strict')):
|
if not os.path.exists(to_bytes(in_path, errors='surrogate_or_strict')):
|
||||||
raise AnsibleFileNotFound("file or module does not exist: %s" % in_path)
|
raise AnsibleFileNotFound("file or module does not exist: %s" % in_path)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -339,7 +340,7 @@ class Connection(ConnectionBase):
|
||||||
raise AnsibleError("failed to open a SFTP connection (%s)" % e)
|
raise AnsibleError("failed to open a SFTP connection (%s)" % e)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.sftp.put(to_bytes(in_path, errors='strict'), to_bytes(out_path, errors='strict'))
|
self.sftp.put(to_bytes(in_path, errors='surrogate_or_strict'), to_bytes(out_path, errors='surrogate_or_strict'))
|
||||||
except IOError:
|
except IOError:
|
||||||
raise AnsibleError("failed to transfer file to %s" % out_path)
|
raise AnsibleError("failed to transfer file to %s" % out_path)
|
||||||
|
|
||||||
|
@ -365,7 +366,7 @@ class Connection(ConnectionBase):
|
||||||
raise AnsibleError("failed to open a SFTP connection (%s)", e)
|
raise AnsibleError("failed to open a SFTP connection (%s)", e)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.sftp.get(to_bytes(in_path, errors='strict'), to_bytes(out_path, errors='strict'))
|
self.sftp.get(to_bytes(in_path, errors='surrogate_or_strict'), to_bytes(out_path, errors='surrogate_or_strict'))
|
||||||
except IOError:
|
except IOError:
|
||||||
raise AnsibleError("failed to transfer file from %s" % in_path)
|
raise AnsibleError("failed to transfer file from %s" % in_path)
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,11 @@ import subprocess
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
|
from ansible.compat.six import text_type, binary_type
|
||||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
|
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
|
||||||
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
from ansible.plugins.connection import ConnectionBase
|
from ansible.plugins.connection import ConnectionBase
|
||||||
from ansible.utils.path import unfrackpath, makedirs_safe
|
from ansible.utils.path import unfrackpath, makedirs_safe
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode, to_str
|
|
||||||
from ansible.compat.six import text_type, binary_type
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -107,7 +107,7 @@ class Connection(ConnectionBase):
|
||||||
explanation of why they were added.
|
explanation of why they were added.
|
||||||
"""
|
"""
|
||||||
self._command += args
|
self._command += args
|
||||||
display.vvvvv('SSH: ' + explanation + ': (%s)' % ')('.join(map(to_unicode, args)), host=self._play_context.remote_addr)
|
display.vvvvv('SSH: ' + explanation + ': (%s)' % ')('.join(map(to_text, args)), host=self._play_context.remote_addr)
|
||||||
|
|
||||||
def _build_command(self, binary, *other_args):
|
def _build_command(self, binary, *other_args):
|
||||||
'''
|
'''
|
||||||
|
@ -222,7 +222,7 @@ class Connection(ConnectionBase):
|
||||||
# The directory must exist and be writable.
|
# The directory must exist and be writable.
|
||||||
makedirs_safe(b_cpdir, 0o700)
|
makedirs_safe(b_cpdir, 0o700)
|
||||||
if not os.access(b_cpdir, os.W_OK):
|
if not os.access(b_cpdir, os.W_OK):
|
||||||
raise AnsibleError("Cannot write to ControlPath %s" % to_str(cpdir))
|
raise AnsibleError("Cannot write to ControlPath %s" % to_native(cpdir))
|
||||||
|
|
||||||
args = ("-o", "ControlPath=" + C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=cpdir))
|
args = ("-o", "ControlPath=" + C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=cpdir))
|
||||||
self._add_args("found only ControlPersist; added ControlPath", args)
|
self._add_args("found only ControlPersist; added ControlPath", args)
|
||||||
|
@ -275,7 +275,7 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
output = []
|
output = []
|
||||||
for b_line in b_chunk.splitlines(True):
|
for b_line in b_chunk.splitlines(True):
|
||||||
display_line = to_unicode(b_line, errors='replace').rstrip('\r\n')
|
display_line = to_text(b_line).rstrip('\r\n')
|
||||||
suppress_output = False
|
suppress_output = False
|
||||||
|
|
||||||
#display.debug("Examining line (source=%s, state=%s): '%s'" % (source, state, display_line))
|
#display.debug("Examining line (source=%s, state=%s): '%s'" % (source, state, display_line))
|
||||||
|
@ -314,7 +314,7 @@ class Connection(ConnectionBase):
|
||||||
Starts the command and communicates with it until it ends.
|
Starts the command and communicates with it until it ends.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
display_cmd = list(map(pipes.quote, map(to_unicode, cmd)))
|
display_cmd = list(map(pipes.quote, map(to_text, cmd)))
|
||||||
display.vvv(u'SSH: EXEC {0}'.format(u' '.join(display_cmd)), host=self.host)
|
display.vvv(u'SSH: EXEC {0}'.format(u' '.join(display_cmd)), host=self.host)
|
||||||
|
|
||||||
# Start the given command. If we don't need to pipeline data, we can try
|
# Start the given command. If we don't need to pipeline data, we can try
|
||||||
|
@ -424,7 +424,7 @@ class Connection(ConnectionBase):
|
||||||
if p.poll() is not None:
|
if p.poll() is not None:
|
||||||
break
|
break
|
||||||
self._terminate_process(p)
|
self._terminate_process(p)
|
||||||
raise AnsibleError('Timeout (%ds) waiting for privilege escalation prompt: %s' % (timeout, to_str(b_stdout)))
|
raise AnsibleError('Timeout (%ds) waiting for privilege escalation prompt: %s' % (timeout, to_native(b_stdout)))
|
||||||
|
|
||||||
# Read whatever output is available on stdout and stderr, and stop
|
# Read whatever output is available on stdout and stderr, and stop
|
||||||
# listening to the pipe if it's been closed.
|
# listening to the pipe if it's been closed.
|
||||||
|
@ -434,14 +434,14 @@ class Connection(ConnectionBase):
|
||||||
if b_chunk == b'':
|
if b_chunk == b'':
|
||||||
rpipes.remove(p.stdout)
|
rpipes.remove(p.stdout)
|
||||||
b_tmp_stdout += b_chunk
|
b_tmp_stdout += b_chunk
|
||||||
display.debug("stdout chunk (state=%s):\n>>>%s<<<\n" % (state, to_unicode(b_chunk, errors='replace')))
|
display.debug("stdout chunk (state=%s):\n>>>%s<<<\n" % (state, to_text(b_chunk)))
|
||||||
|
|
||||||
if p.stderr in rfd:
|
if p.stderr in rfd:
|
||||||
b_chunk = p.stderr.read()
|
b_chunk = p.stderr.read()
|
||||||
if b_chunk == b'':
|
if b_chunk == b'':
|
||||||
rpipes.remove(p.stderr)
|
rpipes.remove(p.stderr)
|
||||||
b_tmp_stderr += b_chunk
|
b_tmp_stderr += b_chunk
|
||||||
display.debug("stderr chunk (state=%s):\n>>>%s<<<\n" % (state, to_unicode(b_chunk, errors='replace')))
|
display.debug("stderr chunk (state=%s):\n>>>%s<<<\n" % (state, to_text(b_chunk)))
|
||||||
|
|
||||||
# We examine the output line-by-line until we have negotiated any
|
# We examine the output line-by-line until we have negotiated any
|
||||||
# privilege escalation prompt and subsequent success/error message.
|
# privilege escalation prompt and subsequent success/error message.
|
||||||
|
@ -631,8 +631,8 @@ class Connection(ConnectionBase):
|
||||||
super(Connection, self).put_file(in_path, out_path)
|
super(Connection, self).put_file(in_path, out_path)
|
||||||
|
|
||||||
display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self.host)
|
display.vvv(u"PUT {0} TO {1}".format(in_path, out_path), host=self.host)
|
||||||
if not os.path.exists(to_bytes(in_path, errors='strict')):
|
if not os.path.exists(to_bytes(in_path, errors='surrogate_or_strict')):
|
||||||
raise AnsibleFileNotFound("file or module does not exist: {0}".format(to_str(in_path)))
|
raise AnsibleFileNotFound("file or module does not exist: {0}".format(to_native(in_path)))
|
||||||
|
|
||||||
# scp and sftp require square brackets for IPv6 addresses, but
|
# scp and sftp require square brackets for IPv6 addresses, but
|
||||||
# accept them for hostnames and IPv4 addresses too.
|
# accept them for hostnames and IPv4 addresses too.
|
||||||
|
@ -649,7 +649,7 @@ class Connection(ConnectionBase):
|
||||||
(returncode, stdout, stderr) = self._run(cmd, in_data)
|
(returncode, stdout, stderr) = self._run(cmd, in_data)
|
||||||
|
|
||||||
if returncode != 0:
|
if returncode != 0:
|
||||||
raise AnsibleError("failed to transfer file to {0}:\n{1}\n{2}".format(to_str(out_path), to_str(stdout), to_str(stderr)))
|
raise AnsibleError("failed to transfer file to {0}:\n{1}\n{2}".format(to_native(out_path), to_native(stdout), to_native(stderr)))
|
||||||
|
|
||||||
def fetch_file(self, in_path, out_path):
|
def fetch_file(self, in_path, out_path):
|
||||||
''' fetch a file from remote to local '''
|
''' fetch a file from remote to local '''
|
||||||
|
|
|
@ -26,9 +26,21 @@ import shlex
|
||||||
import traceback
|
import traceback
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
HAVE_KERBEROS = False
|
||||||
|
try:
|
||||||
|
import kerberos
|
||||||
|
HAVE_KERBEROS = True
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
from ansible.compat.six import string_types
|
from ansible.compat.six import string_types
|
||||||
from ansible.compat.six.moves.urllib.parse import urlunsplit
|
from ansible.compat.six.moves.urllib.parse import urlunsplit
|
||||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure
|
from ansible.errors import AnsibleError, AnsibleConnectionFailure
|
||||||
|
from ansible.errors import AnsibleFileNotFound
|
||||||
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
|
from ansible.plugins.connection import ConnectionBase
|
||||||
|
from ansible.utils.hashing import secure_hash
|
||||||
|
from ansible.utils.path import makedirs_safe
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import winrm
|
import winrm
|
||||||
|
@ -42,25 +54,13 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise AnsibleError("xmltodict is not installed")
|
raise AnsibleError("xmltodict is not installed")
|
||||||
|
|
||||||
HAVE_KERBEROS = False
|
|
||||||
try:
|
|
||||||
import kerberos
|
|
||||||
HAVE_KERBEROS = True
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
from ansible.errors import AnsibleFileNotFound
|
|
||||||
from ansible.plugins.connection import ConnectionBase
|
|
||||||
from ansible.utils.hashing import secure_hash
|
|
||||||
from ansible.utils.path import makedirs_safe
|
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode, to_str
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
display = Display()
|
display = Display()
|
||||||
|
|
||||||
|
|
||||||
class Connection(ConnectionBase):
|
class Connection(ConnectionBase):
|
||||||
'''WinRM connections over HTTP/HTTPS.'''
|
'''WinRM connections over HTTP/HTTPS.'''
|
||||||
|
|
||||||
|
@ -156,10 +156,10 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
return protocol
|
return protocol
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
err_msg = to_unicode(e).strip()
|
err_msg = to_text(e).strip()
|
||||||
if re.search(to_unicode(r'Operation\s+?timed\s+?out'), err_msg, re.I):
|
if re.search(to_text(r'Operation\s+?timed\s+?out'), err_msg, re.I):
|
||||||
raise AnsibleError('the connection attempt timed out')
|
raise AnsibleError('the connection attempt timed out')
|
||||||
m = re.search(to_unicode(r'Code\s+?(\d{3})'), err_msg)
|
m = re.search(to_text(r'Code\s+?(\d{3})'), err_msg)
|
||||||
if m:
|
if m:
|
||||||
code = int(m.groups()[0])
|
code = int(m.groups()[0])
|
||||||
if code == 401:
|
if code == 401:
|
||||||
|
@ -167,9 +167,9 @@ class Connection(ConnectionBase):
|
||||||
elif code == 411:
|
elif code == 411:
|
||||||
return protocol
|
return protocol
|
||||||
errors.append(u'%s: %s' % (transport, err_msg))
|
errors.append(u'%s: %s' % (transport, err_msg))
|
||||||
display.vvvvv(u'WINRM CONNECTION ERROR: %s\n%s' % (err_msg, to_unicode(traceback.format_exc())), host=self._winrm_host)
|
display.vvvvv(u'WINRM CONNECTION ERROR: %s\n%s' % (err_msg, to_text(traceback.format_exc())), host=self._winrm_host)
|
||||||
if errors:
|
if errors:
|
||||||
raise AnsibleConnectionFailure(', '.join(map(to_str, errors)))
|
raise AnsibleConnectionFailure(', '.join(map(to_native, errors)))
|
||||||
else:
|
else:
|
||||||
raise AnsibleError('No transport found for WinRM connection')
|
raise AnsibleError('No transport found for WinRM connection')
|
||||||
|
|
||||||
|
@ -220,12 +220,12 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
# TODO: check result from response and set stdin_push_failed if we have nonzero
|
# TODO: check result from response and set stdin_push_failed if we have nonzero
|
||||||
if from_exec:
|
if from_exec:
|
||||||
display.vvvvv('WINRM RESULT %r' % to_unicode(response), host=self._winrm_host)
|
display.vvvvv('WINRM RESULT %r' % to_text(response), host=self._winrm_host)
|
||||||
else:
|
else:
|
||||||
display.vvvvvv('WINRM RESULT %r' % to_unicode(response), host=self._winrm_host)
|
display.vvvvvv('WINRM RESULT %r' % to_text(response), host=self._winrm_host)
|
||||||
|
|
||||||
display.vvvvvv('WINRM STDOUT %s' % to_unicode(response.std_out), host=self._winrm_host)
|
display.vvvvvv('WINRM STDOUT %s' % to_text(response.std_out), host=self._winrm_host)
|
||||||
display.vvvvvv('WINRM STDERR %s' % to_unicode(response.std_err), host=self._winrm_host)
|
display.vvvvvv('WINRM STDERR %s' % to_text(response.std_err), host=self._winrm_host)
|
||||||
|
|
||||||
if stdin_push_failed:
|
if stdin_push_failed:
|
||||||
raise AnsibleError('winrm send_input failed; \nstdout: %s\nstderr %s' % (response.std_out, response.std_err))
|
raise AnsibleError('winrm send_input failed; \nstdout: %s\nstderr %s' % (response.std_out, response.std_err))
|
||||||
|
@ -250,7 +250,7 @@ class Connection(ConnectionBase):
|
||||||
def exec_command(self, cmd, in_data=None, sudoable=True):
|
def exec_command(self, cmd, in_data=None, sudoable=True):
|
||||||
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
|
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
|
||||||
cmd_parts = shlex.split(to_bytes(cmd), posix=False)
|
cmd_parts = shlex.split(to_bytes(cmd), posix=False)
|
||||||
cmd_parts = map(to_unicode, cmd_parts)
|
cmd_parts = map(to_text, cmd_parts)
|
||||||
script = None
|
script = None
|
||||||
cmd_ext = cmd_parts and self._shell._unquote(cmd_parts[0]).lower()[-4:] or ''
|
cmd_ext = cmd_parts and self._shell._unquote(cmd_parts[0]).lower()[-4:] or ''
|
||||||
# Support running .ps1 files (via script/raw).
|
# Support running .ps1 files (via script/raw).
|
||||||
|
@ -266,7 +266,7 @@ class Connection(ConnectionBase):
|
||||||
cmd_parts = self._shell._encode_script(script, as_list=True, strict_mode=False)
|
cmd_parts = self._shell._encode_script(script, as_list=True, strict_mode=False)
|
||||||
if '-EncodedCommand' in cmd_parts:
|
if '-EncodedCommand' in cmd_parts:
|
||||||
encoded_cmd = cmd_parts[cmd_parts.index('-EncodedCommand') + 1]
|
encoded_cmd = cmd_parts[cmd_parts.index('-EncodedCommand') + 1]
|
||||||
decoded_cmd = to_unicode(base64.b64decode(encoded_cmd).decode('utf-16-le'))
|
decoded_cmd = to_text(base64.b64decode(encoded_cmd).decode('utf-16-le'))
|
||||||
display.vvv("EXEC %s" % decoded_cmd, host=self._winrm_host)
|
display.vvv("EXEC %s" % decoded_cmd, host=self._winrm_host)
|
||||||
else:
|
else:
|
||||||
display.vvv("EXEC %s" % cmd, host=self._winrm_host)
|
display.vvv("EXEC %s" % cmd, host=self._winrm_host)
|
||||||
|
@ -300,9 +300,9 @@ class Connection(ConnectionBase):
|
||||||
|
|
||||||
# FUTURE: determine buffer size at runtime via remote winrm config?
|
# FUTURE: determine buffer size at runtime via remote winrm config?
|
||||||
def _put_file_stdin_iterator(self, in_path, out_path, buffer_size=250000):
|
def _put_file_stdin_iterator(self, in_path, out_path, buffer_size=250000):
|
||||||
in_size = os.path.getsize(to_bytes(in_path, errors='strict'))
|
in_size = os.path.getsize(to_bytes(in_path, errors='surrogate_or_strict'))
|
||||||
offset = 0
|
offset = 0
|
||||||
with open(to_bytes(in_path, errors='strict'), 'rb') as in_file:
|
with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file:
|
||||||
for out_data in iter((lambda:in_file.read(buffer_size)), ''):
|
for out_data in iter((lambda:in_file.read(buffer_size)), ''):
|
||||||
offset += len(out_data)
|
offset += len(out_data)
|
||||||
self._display.vvvvv('WINRM PUT "%s" to "%s" (offset=%d size=%d)' % (in_path, out_path, offset, len(out_data)), host=self._winrm_host)
|
self._display.vvvvv('WINRM PUT "%s" to "%s" (offset=%d size=%d)' % (in_path, out_path, offset, len(out_data)), host=self._winrm_host)
|
||||||
|
@ -318,7 +318,7 @@ class Connection(ConnectionBase):
|
||||||
super(Connection, self).put_file(in_path, out_path)
|
super(Connection, self).put_file(in_path, out_path)
|
||||||
out_path = self._shell._unquote(out_path)
|
out_path = self._shell._unquote(out_path)
|
||||||
display.vvv('PUT "%s" TO "%s"' % (in_path, out_path), host=self._winrm_host)
|
display.vvv('PUT "%s" TO "%s"' % (in_path, out_path), host=self._winrm_host)
|
||||||
if not os.path.exists(to_bytes(in_path, errors='strict')):
|
if not os.path.exists(to_bytes(in_path, errors='surrogate_or_strict')):
|
||||||
raise AnsibleFileNotFound('file or module does not exist: "%s"' % in_path)
|
raise AnsibleFileNotFound('file or module does not exist: "%s"' % in_path)
|
||||||
|
|
||||||
script_template = u'''
|
script_template = u'''
|
||||||
|
@ -357,7 +357,7 @@ class Connection(ConnectionBase):
|
||||||
result = self._winrm_exec(cmd_parts[0], cmd_parts[1:], stdin_iterator=self._put_file_stdin_iterator(in_path, out_path))
|
result = self._winrm_exec(cmd_parts[0], cmd_parts[1:], stdin_iterator=self._put_file_stdin_iterator(in_path, out_path))
|
||||||
# TODO: improve error handling
|
# TODO: improve error handling
|
||||||
if result.status_code != 0:
|
if result.status_code != 0:
|
||||||
raise AnsibleError(to_str(result.std_err))
|
raise AnsibleError(to_native(result.std_err))
|
||||||
|
|
||||||
put_output = json.loads(result.std_out)
|
put_output = json.loads(result.std_out)
|
||||||
remote_sha1 = put_output.get("sha1")
|
remote_sha1 = put_output.get("sha1")
|
||||||
|
@ -368,7 +368,7 @@ class Connection(ConnectionBase):
|
||||||
local_sha1 = secure_hash(in_path)
|
local_sha1 = secure_hash(in_path)
|
||||||
|
|
||||||
if not remote_sha1 == local_sha1:
|
if not remote_sha1 == local_sha1:
|
||||||
raise AnsibleError("Remote sha1 hash {0} does not match local hash {1}".format(to_str(remote_sha1), to_str(local_sha1)))
|
raise AnsibleError("Remote sha1 hash {0} does not match local hash {1}".format(to_native(remote_sha1), to_native(local_sha1)))
|
||||||
|
|
||||||
def fetch_file(self, in_path, out_path):
|
def fetch_file(self, in_path, out_path):
|
||||||
super(Connection, self).fetch_file(in_path, out_path)
|
super(Connection, self).fetch_file(in_path, out_path)
|
||||||
|
@ -407,7 +407,7 @@ class Connection(ConnectionBase):
|
||||||
cmd_parts = self._shell._encode_script(script, as_list=True)
|
cmd_parts = self._shell._encode_script(script, as_list=True)
|
||||||
result = self._winrm_exec(cmd_parts[0], cmd_parts[1:])
|
result = self._winrm_exec(cmd_parts[0], cmd_parts[1:])
|
||||||
if result.status_code != 0:
|
if result.status_code != 0:
|
||||||
raise IOError(to_str(result.std_err))
|
raise IOError(to_native(result.std_err))
|
||||||
if result.std_out.strip() == '[DIR]':
|
if result.std_out.strip() == '[DIR]':
|
||||||
data = None
|
data = None
|
||||||
else:
|
else:
|
||||||
|
@ -418,9 +418,9 @@ class Connection(ConnectionBase):
|
||||||
else:
|
else:
|
||||||
if not out_file:
|
if not out_file:
|
||||||
# If out_path is a directory and we're expecting a file, bail out now.
|
# If out_path is a directory and we're expecting a file, bail out now.
|
||||||
if os.path.isdir(to_bytes(out_path, errors='strict')):
|
if os.path.isdir(to_bytes(out_path, errors='surrogate_or_strict')):
|
||||||
break
|
break
|
||||||
out_file = open(to_bytes(out_path, errors='strict'), 'wb')
|
out_file = open(to_bytes(out_path, errors='surrogate_or_strict'), 'wb')
|
||||||
out_file.write(data)
|
out_file.write(data)
|
||||||
if len(data) < buffer_size:
|
if len(data) < buffer_size:
|
||||||
break
|
break
|
||||||
|
|
|
@ -31,7 +31,8 @@ import traceback
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
from ansible.plugins.connection import ConnectionBase, BUFSIZE
|
||||||
from ansible.utils.unicode import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import base64
|
import base64
|
||||||
import itertools
|
import itertools
|
||||||
|
@ -39,15 +38,6 @@ import uuid
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from jinja2.filters import environmentfilter
|
from jinja2.filters import environmentfilter
|
||||||
from ansible.compat.six import iteritems, string_types
|
|
||||||
|
|
||||||
from ansible import errors
|
|
||||||
from ansible.parsing.yaml.dumper import AnsibleDumper
|
|
||||||
from ansible.utils.hashing import md5s, checksum_s
|
|
||||||
from ansible.utils.unicode import unicode_wrap, to_unicode
|
|
||||||
from ansible.utils.vars import merge_hash
|
|
||||||
from ansible.vars.hostvars import HostVars
|
|
||||||
from ansible.compat.six.moves import reduce
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import passlib.hash
|
import passlib.hash
|
||||||
|
@ -55,6 +45,16 @@ try:
|
||||||
except:
|
except:
|
||||||
HAS_PASSLIB = False
|
HAS_PASSLIB = False
|
||||||
|
|
||||||
|
from ansible import errors
|
||||||
|
from ansible.compat.six import iteritems, string_types
|
||||||
|
from ansible.compat.six.moves import reduce
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
|
from ansible.parsing.yaml.dumper import AnsibleDumper
|
||||||
|
from ansible.utils.hashing import md5s, checksum_s
|
||||||
|
from ansible.utils.unicode import unicode_wrap
|
||||||
|
from ansible.utils.vars import merge_hash
|
||||||
|
from ansible.vars.hostvars import HostVars
|
||||||
|
|
||||||
|
|
||||||
UUID_NAMESPACE_ANSIBLE = uuid.UUID('361E6D51-FAEC-444A-9079-341386DA8E2E')
|
UUID_NAMESPACE_ANSIBLE = uuid.UUID('361E6D51-FAEC-444A-9079-341386DA8E2E')
|
||||||
|
|
||||||
|
@ -72,12 +72,12 @@ class AnsibleJSONEncoder(json.JSONEncoder):
|
||||||
def to_yaml(a, *args, **kw):
|
def to_yaml(a, *args, **kw):
|
||||||
'''Make verbose, human readable yaml'''
|
'''Make verbose, human readable yaml'''
|
||||||
transformed = yaml.dump(a, Dumper=AnsibleDumper, allow_unicode=True, **kw)
|
transformed = yaml.dump(a, Dumper=AnsibleDumper, allow_unicode=True, **kw)
|
||||||
return to_unicode(transformed)
|
return to_text(transformed)
|
||||||
|
|
||||||
def to_nice_yaml(a, indent=4, *args, **kw):
|
def to_nice_yaml(a, indent=4, *args, **kw):
|
||||||
'''Make verbose, human readable yaml'''
|
'''Make verbose, human readable yaml'''
|
||||||
transformed = yaml.dump(a, Dumper=AnsibleDumper, indent=indent, allow_unicode=True, default_flow_style=False, **kw)
|
transformed = yaml.dump(a, Dumper=AnsibleDumper, indent=indent, allow_unicode=True, default_flow_style=False, **kw)
|
||||||
return to_unicode(transformed)
|
return to_text(transformed)
|
||||||
|
|
||||||
def to_json(a, *args, **kw):
|
def to_json(a, *args, **kw):
|
||||||
''' Convert the value to JSON '''
|
''' Convert the value to JSON '''
|
||||||
|
@ -132,7 +132,7 @@ def fileglob(pathname):
|
||||||
def regex_replace(value='', pattern='', replacement='', ignorecase=False):
|
def regex_replace(value='', pattern='', replacement='', ignorecase=False):
|
||||||
''' Perform a `re.sub` returning a string '''
|
''' Perform a `re.sub` returning a string '''
|
||||||
|
|
||||||
value = to_unicode(value, errors='strict', nonstring='simplerepr')
|
value = to_text(value, errors='surrogate_or_strict', nonstring='simplerepr')
|
||||||
|
|
||||||
if ignorecase:
|
if ignorecase:
|
||||||
flags = re.I
|
flags = re.I
|
||||||
|
|
|
@ -98,8 +98,8 @@ class LookupBase(with_metaclass(ABCMeta, object)):
|
||||||
must be converted into python's unicode type as the strings will be run
|
must be converted into python's unicode type as the strings will be run
|
||||||
through jinja2 which has this requirement. You can use::
|
through jinja2 which has this requirement. You can use::
|
||||||
|
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.module_utils._text import to_text
|
||||||
result_string = to_unicode(result_string)
|
result_string = to_text(result_string)
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,8 @@ import csv
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.plugins.lookup import LookupBase
|
from ansible.plugins.lookup import LookupBase
|
||||||
from ansible.utils.unicode import to_bytes, to_str, to_unicode
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
|
|
||||||
|
|
||||||
class CSVRecoder:
|
class CSVRecoder:
|
||||||
"""
|
"""
|
||||||
|
@ -49,7 +50,7 @@ class CSVReader:
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
row = self.reader.next()
|
row = self.reader.next()
|
||||||
return [to_unicode(s) for s in row]
|
return [to_text(s) for s in row]
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
|
@ -66,7 +67,7 @@ class LookupModule(LookupBase):
|
||||||
if row[0] == key:
|
if row[0] == key:
|
||||||
return row[int(col)]
|
return row[int(col)]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise AnsibleError("csvfile: %s" % to_str(e))
|
raise AnsibleError("csvfile: %s" % to_native(e))
|
||||||
|
|
||||||
return dflt
|
return dflt
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,8 @@ import glob
|
||||||
|
|
||||||
from ansible.plugins.lookup import LookupBase
|
from ansible.plugins.lookup import LookupBase
|
||||||
from ansible.errors import AnsibleFileNotFound
|
from ansible.errors import AnsibleFileNotFound
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
|
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
|
|
||||||
|
@ -36,6 +37,6 @@ class LookupModule(LookupBase):
|
||||||
except AnsibleFileNotFound:
|
except AnsibleFileNotFound:
|
||||||
dwimmed_path = None
|
dwimmed_path = None
|
||||||
if dwimmed_path:
|
if dwimmed_path:
|
||||||
globbed = glob.glob(to_bytes(os.path.join(dwimmed_path, term_file), errors='strict'))
|
globbed = glob.glob(to_bytes(os.path.join(dwimmed_path, term_file), errors='surrogate_or_strict'))
|
||||||
ret.extend(to_unicode(g, errors='strict') for g in globbed if os.path.isfile(g))
|
ret.extend(to_text(g, errors='surrogate_or_strict') for g in globbed if os.path.isfile(g))
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -22,12 +22,6 @@ import pwd
|
||||||
import grp
|
import grp
|
||||||
import stat
|
import stat
|
||||||
|
|
||||||
from ansible.plugins.lookup import LookupBase
|
|
||||||
from ansible.utils.unicode import to_str
|
|
||||||
|
|
||||||
from __main__ import display
|
|
||||||
warning = display.warning
|
|
||||||
|
|
||||||
HAVE_SELINUX=False
|
HAVE_SELINUX=False
|
||||||
try:
|
try:
|
||||||
import selinux
|
import selinux
|
||||||
|
@ -35,6 +29,11 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
from ansible.plugins.lookup import LookupBase
|
||||||
|
from ansible.module_utils._text import to_native
|
||||||
|
|
||||||
|
from __main__ import display
|
||||||
|
|
||||||
|
|
||||||
# If selinux fails to find a default, return an array of None
|
# If selinux fails to find a default, return an array of None
|
||||||
def selinux_context(path):
|
def selinux_context(path):
|
||||||
|
@ -43,7 +42,7 @@ def selinux_context(path):
|
||||||
try:
|
try:
|
||||||
# note: the selinux module uses byte strings on python2 and text
|
# note: the selinux module uses byte strings on python2 and text
|
||||||
# strings on python3
|
# strings on python3
|
||||||
ret = selinux.lgetfilecon_raw(to_str(path))
|
ret = selinux.lgetfilecon_raw(to_native(path))
|
||||||
except OSError:
|
except OSError:
|
||||||
return context
|
return context
|
||||||
if ret[0] != -1:
|
if ret[0] != -1:
|
||||||
|
@ -60,7 +59,7 @@ def file_props(root, path):
|
||||||
try:
|
try:
|
||||||
st = os.lstat(abspath)
|
st = os.lstat(abspath)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
warning('filetree: Error using stat() on path %s (%s)' % (abspath, e))
|
display.warning('filetree: Error using stat() on path %s (%s)' % (abspath, e))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
ret = dict(root=root, path=path)
|
ret = dict(root=root, path=path)
|
||||||
|
@ -74,7 +73,7 @@ def file_props(root, path):
|
||||||
ret['state'] = 'file'
|
ret['state'] = 'file'
|
||||||
ret['src'] = abspath
|
ret['src'] = abspath
|
||||||
else:
|
else:
|
||||||
warning('filetree: Error file type of %s is not supported' % abspath)
|
display.warning('filetree: Error file type of %s is not supported' % abspath)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
ret['uid'] = st.st_uid
|
ret['uid'] = st.st_uid
|
||||||
|
|
|
@ -30,7 +30,7 @@ except ImportError:
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.plugins.lookup import LookupBase
|
from ansible.plugins.lookup import LookupBase
|
||||||
from ansible.utils.unicode import to_bytes
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
|
|
||||||
def _parse_params(term):
|
def _parse_params(term):
|
||||||
|
@ -59,13 +59,15 @@ class LookupModule(LookupBase):
|
||||||
|
|
||||||
def read_properties(self, filename, key, dflt, is_regexp):
|
def read_properties(self, filename, key, dflt, is_regexp):
|
||||||
config = StringIO()
|
config = StringIO()
|
||||||
config.write(u'[java_properties]\n' + open(to_bytes(filename, errors='strict')).read())
|
current_cfg_file = open(to_bytes(filename, errors='surrogate_or_strict'), 'rb')
|
||||||
|
|
||||||
|
config.write(u'[java_properties]\n' + to_text(current_cfg_file.read(), errors='surrogate_or_strict'))
|
||||||
config.seek(0, os.SEEK_SET)
|
config.seek(0, os.SEEK_SET)
|
||||||
self.cp.readfp(config)
|
self.cp.readfp(config)
|
||||||
return self.get_value(key, 'java_properties', dflt, is_regexp)
|
return self.get_value(key, 'java_properties', dflt, is_regexp)
|
||||||
|
|
||||||
def read_ini(self, filename, key, section, dflt, is_regexp):
|
def read_ini(self, filename, key, section, dflt, is_regexp):
|
||||||
self.cp.readfp(open(to_bytes(filename, errors='strict')))
|
self.cp.readfp(open(to_bytes(filename, errors='surrogate_or_strict')))
|
||||||
return self.get_value(key, section, dflt, is_regexp)
|
return self.get_value(key, section, dflt, is_regexp)
|
||||||
|
|
||||||
def get_value(self, key, section, dflt, is_regexp):
|
def get_value(self, key, section, dflt, is_regexp):
|
||||||
|
|
|
@ -21,11 +21,11 @@ import shelve
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.plugins.lookup import LookupBase
|
from ansible.plugins.lookup import LookupBase
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
|
|
||||||
class LookupModule(LookupBase):
|
class LookupModule(LookupBase):
|
||||||
|
|
||||||
|
|
||||||
def read_shelve(self, shelve_filename, key):
|
def read_shelve(self, shelve_filename, key):
|
||||||
"""
|
"""
|
||||||
Read the value of "key" from a shelve file
|
Read the value of "key" from a shelve file
|
||||||
|
@ -66,7 +66,7 @@ class LookupModule(LookupBase):
|
||||||
if res is None:
|
if res is None:
|
||||||
raise AnsibleError("Key %s not found in shelve file %s" % (key, file))
|
raise AnsibleError("Key %s not found in shelve file %s" % (key, file))
|
||||||
# Convert the value read to string
|
# Convert the value read to string
|
||||||
ret.append(to_unicode(res))
|
ret.append(to_text(res))
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise AnsibleError("Could not locate shelve file in lookup: %s" % file)
|
raise AnsibleError("Could not locate shelve file in lookup: %s" % file)
|
||||||
|
|
|
@ -21,7 +21,7 @@ import os
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.plugins.lookup import LookupBase
|
from ansible.plugins.lookup import LookupBase
|
||||||
from ansible.utils.unicode import to_unicode, to_bytes
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -43,8 +43,8 @@ class LookupModule(LookupBase):
|
||||||
lookupfile = self.find_file_in_search_path(variables, 'templates', term)
|
lookupfile = self.find_file_in_search_path(variables, 'templates', term)
|
||||||
display.vvvv("File lookup using %s as file" % lookupfile)
|
display.vvvv("File lookup using %s as file" % lookupfile)
|
||||||
if lookupfile:
|
if lookupfile:
|
||||||
with open(to_bytes(lookupfile, errors='strict'), 'r') as f:
|
with open(to_bytes(lookupfile, errors='surrogate_or_strict'), 'rb') as f:
|
||||||
template_data = to_unicode(f.read())
|
template_data = to_text(f.read(), errors='surrogate_or_strict')
|
||||||
|
|
||||||
# set jinja2 internal search path for includes
|
# set jinja2 internal search path for includes
|
||||||
if 'ansible_search_path' in variables:
|
if 'ansible_search_path' in variables:
|
||||||
|
|
|
@ -18,11 +18,11 @@ from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
|
||||||
from ansible.plugins.lookup import LookupBase
|
|
||||||
from ansible.module_utils.urls import open_url, ConnectionError, SSLValidationError
|
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
from ansible.compat.six.moves.urllib.error import HTTPError, URLError
|
from ansible.compat.six.moves.urllib.error import HTTPError, URLError
|
||||||
|
from ansible.errors import AnsibleError
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
|
from ansible.module_utils.urls import open_url, ConnectionError, SSLValidationError
|
||||||
|
from ansible.plugins.lookup import LookupBase
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -52,5 +52,5 @@ class LookupModule(LookupBase):
|
||||||
raise AnsibleError("Error connecting to %s: %s" % (term, str(e)))
|
raise AnsibleError("Error connecting to %s: %s" % (term, str(e)))
|
||||||
|
|
||||||
for line in response.read().splitlines():
|
for line in response.read().splitlines():
|
||||||
ret.append(to_unicode(line))
|
ret.append(to_text(line))
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -22,9 +22,9 @@ import os
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
|
|
||||||
from ansible.compat.six import text_type
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
|
|
||||||
_common_args = ['PowerShell', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Unrestricted']
|
_common_args = ['PowerShell', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Unrestricted']
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ _powershell_version = os.environ.get('POWERSHELL_VERSION', None)
|
||||||
if _powershell_version:
|
if _powershell_version:
|
||||||
_common_args = ['PowerShell', '-Version', _powershell_version] + _common_args[1:]
|
_common_args = ['PowerShell', '-Version', _powershell_version] + _common_args[1:]
|
||||||
|
|
||||||
|
|
||||||
class ShellModule(object):
|
class ShellModule(object):
|
||||||
|
|
||||||
# Common shell filenames that this plugin handles
|
# Common shell filenames that this plugin handles
|
||||||
|
@ -60,7 +61,7 @@ class ShellModule(object):
|
||||||
raise AnsibleError("PowerShell environment value for key '%s' exceeds 32767 characters in length" % key)
|
raise AnsibleError("PowerShell environment value for key '%s' exceeds 32767 characters in length" % key)
|
||||||
# powershell single quoted literals need single-quote doubling as their only escaping
|
# powershell single quoted literals need single-quote doubling as their only escaping
|
||||||
value = value.replace("'", "''")
|
value = value.replace("'", "''")
|
||||||
return text_type(value)
|
return to_text(value, errors='surrogate_or_strict')
|
||||||
|
|
||||||
def env_prefix(self, **kwargs):
|
def env_prefix(self, **kwargs):
|
||||||
env = self.env.copy()
|
env = self.env.copy()
|
||||||
|
@ -164,7 +165,7 @@ class ShellModule(object):
|
||||||
|
|
||||||
def build_module_command(self, env_string, shebang, cmd, arg_path=None, rm_tmp=None):
|
def build_module_command(self, env_string, shebang, cmd, arg_path=None, rm_tmp=None):
|
||||||
cmd_parts = shlex.split(to_bytes(cmd), posix=False)
|
cmd_parts = shlex.split(to_bytes(cmd), posix=False)
|
||||||
cmd_parts = map(to_unicode, cmd_parts)
|
cmd_parts = map(to_text, cmd_parts)
|
||||||
if shebang and shebang.lower() == '#!powershell':
|
if shebang and shebang.lower() == '#!powershell':
|
||||||
if not self._unquote(cmd_parts[0]).lower().endswith('.ps1'):
|
if not self._unquote(cmd_parts[0]).lower().endswith('.ps1'):
|
||||||
cmd_parts[0] = '"%s.ps1"' % self._unquote(cmd_parts[0])
|
cmd_parts[0] = '"%s.ps1"' % self._unquote(cmd_parts[0])
|
||||||
|
@ -219,7 +220,7 @@ class ShellModule(object):
|
||||||
|
|
||||||
def _unquote(self, value):
|
def _unquote(self, value):
|
||||||
'''Remove any matching quotes that wrap the given value.'''
|
'''Remove any matching quotes that wrap the given value.'''
|
||||||
value = to_unicode(value or '')
|
value = to_text(value or '')
|
||||||
m = re.match(r'^\s*?\'(.*?)\'\s*?$', value)
|
m = re.match(r'^\s*?\'(.*?)\'\s*?$', value)
|
||||||
if m:
|
if m:
|
||||||
return m.group(1)
|
return m.group(1)
|
||||||
|
@ -244,7 +245,7 @@ class ShellModule(object):
|
||||||
|
|
||||||
def _encode_script(self, script, as_list=False, strict_mode=True):
|
def _encode_script(self, script, as_list=False, strict_mode=True):
|
||||||
'''Convert a PowerShell script to a single base64-encoded command.'''
|
'''Convert a PowerShell script to a single base64-encoded command.'''
|
||||||
script = to_unicode(script)
|
script = to_text(script)
|
||||||
if strict_mode:
|
if strict_mode:
|
||||||
script = u'Set-StrictMode -Version Latest\r\n%s' % script
|
script = u'Set-StrictMode -Version Latest\r\n%s' % script
|
||||||
script = '\n'.join([x.strip() for x in script.splitlines() if x.strip()])
|
script = '\n'.join([x.strip() for x in script.splitlines() if x.strip()])
|
||||||
|
|
|
@ -19,18 +19,11 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
import zlib
|
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
from jinja2.exceptions import UndefinedError
|
from jinja2.exceptions import UndefinedError
|
||||||
|
|
||||||
from ansible.compat.six.moves import queue as Queue
|
from ansible.compat.six.moves import queue as Queue
|
||||||
from ansible.compat.six import iteritems, text_type, string_types
|
from ansible.compat.six import iteritems, string_types
|
||||||
from ansible import constants as C
|
|
||||||
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable
|
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable
|
||||||
from ansible.executor.play_iterator import PlayIterator
|
|
||||||
from ansible.executor.task_result import TaskResult
|
from ansible.executor.task_result import TaskResult
|
||||||
from ansible.inventory.host import Host
|
from ansible.inventory.host import Host
|
||||||
from ansible.inventory.group import Group
|
from ansible.inventory.group import Group
|
||||||
|
@ -38,11 +31,10 @@ from ansible.playbook.helpers import load_list_of_blocks
|
||||||
from ansible.playbook.included_file import IncludedFile
|
from ansible.playbook.included_file import IncludedFile
|
||||||
from ansible.playbook.task_include import TaskInclude
|
from ansible.playbook.task_include import TaskInclude
|
||||||
from ansible.playbook.role_include import IncludeRole
|
from ansible.playbook.role_include import IncludeRole
|
||||||
from ansible.plugins import action_loader, connection_loader, filter_loader, lookup_loader, module_loader, test_loader
|
from ansible.plugins import action_loader
|
||||||
from ansible.template import Templar
|
from ansible.template import Templar
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
from ansible.vars.unsafe_proxy import wrap_var
|
|
||||||
from ansible.vars import combine_vars, strip_internal_keys
|
from ansible.vars import combine_vars, strip_internal_keys
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -138,7 +130,7 @@ class StrategyBase:
|
||||||
ret_results = []
|
ret_results = []
|
||||||
|
|
||||||
def get_original_host(host_name):
|
def get_original_host(host_name):
|
||||||
host_name = to_unicode(host_name)
|
host_name = to_text(host_name)
|
||||||
if host_name in self._inventory._hosts_cache:
|
if host_name in self._inventory._hosts_cache:
|
||||||
return self._inventory._hosts_cache[host_name]
|
return self._inventory._hosts_cache[host_name]
|
||||||
else:
|
else:
|
||||||
|
@ -161,7 +153,7 @@ class StrategyBase:
|
||||||
target_handler_name = templar.template(handler_task.get_name())
|
target_handler_name = templar.template(handler_task.get_name())
|
||||||
if target_handler_name == handler_name:
|
if target_handler_name == handler_name:
|
||||||
return handler_task
|
return handler_task
|
||||||
except (UndefinedError, AnsibleUndefinedVariable) as e:
|
except (UndefinedError, AnsibleUndefinedVariable):
|
||||||
# We skip this handler due to the fact that it may be using
|
# We skip this handler due to the fact that it may be using
|
||||||
# a variable in the name that was conditionally included via
|
# a variable in the name that was conditionally included via
|
||||||
# set_fact or some other method, and we don't want to error
|
# set_fact or some other method, and we don't want to error
|
||||||
|
@ -182,7 +174,7 @@ class StrategyBase:
|
||||||
target_handler_name = templar.template(target_handler.get_name())
|
target_handler_name = templar.template(target_handler.get_name())
|
||||||
if target_handler_name == handler_name:
|
if target_handler_name == handler_name:
|
||||||
return True
|
return True
|
||||||
except (UndefinedError, AnsibleUndefinedVariable) as e:
|
except (UndefinedError, AnsibleUndefinedVariable):
|
||||||
pass
|
pass
|
||||||
return parent_handler_match(target_handler._parent, handler_name)
|
return parent_handler_match(target_handler._parent, handler_name)
|
||||||
else:
|
else:
|
||||||
|
@ -567,14 +559,13 @@ class StrategyBase:
|
||||||
# mark all of the hosts including this file as failed, send callbacks,
|
# mark all of the hosts including this file as failed, send callbacks,
|
||||||
# and increment the stats for this host
|
# and increment the stats for this host
|
||||||
for host in included_file._hosts:
|
for host in included_file._hosts:
|
||||||
tr = TaskResult(host=host, task=included_file._task, return_data=dict(failed=True, reason=to_unicode(e)))
|
tr = TaskResult(host=host, task=included_file._task, return_data=dict(failed=True, reason=to_text(e)))
|
||||||
iterator.mark_host_failed(host)
|
iterator.mark_host_failed(host)
|
||||||
self._tqm._failed_hosts[host.name] = True
|
self._tqm._failed_hosts[host.name] = True
|
||||||
self._tqm._stats.increment('failures', host.name)
|
self._tqm._stats.increment('failures', host.name)
|
||||||
self._tqm.send_callback('v2_runner_on_failed', tr)
|
self._tqm.send_callback('v2_runner_on_failed', tr)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
# finally, send the callback and return the list of blocks loaded
|
# finally, send the callback and return the list of blocks loaded
|
||||||
self._tqm.send_callback('v2_playbook_on_include', included_file)
|
self._tqm.send_callback('v2_playbook_on_include', included_file)
|
||||||
display.debug("done processing included file")
|
display.debug("done processing included file")
|
||||||
|
|
|
@ -26,7 +26,8 @@ from ansible.playbook.included_file import IncludedFile
|
||||||
from ansible.plugins import action_loader
|
from ansible.plugins import action_loader
|
||||||
from ansible.plugins.strategy import StrategyBase
|
from ansible.plugins.strategy import StrategyBase
|
||||||
from ansible.template import Templar
|
from ansible.template import Templar
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.module_utils._text import to_text
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -66,8 +67,7 @@ class StrategyModule(StrategyBase):
|
||||||
break
|
break
|
||||||
|
|
||||||
work_to_do = False # assume we have no more work to do
|
work_to_do = False # assume we have no more work to do
|
||||||
starting_host = last_host # save current position so we know when we've
|
starting_host = last_host # save current position so we know when we've looped back around and need to break
|
||||||
# looped back around and need to break
|
|
||||||
|
|
||||||
# try and find an unblocked host with a task to run
|
# try and find an unblocked host with a task to run
|
||||||
host_results = []
|
host_results = []
|
||||||
|
@ -109,7 +109,7 @@ class StrategyModule(StrategyBase):
|
||||||
display.debug("done getting variables")
|
display.debug("done getting variables")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
task.name = to_unicode(templar.template(task.name, fail_on_undefined=False), nonstring='empty')
|
task.name = to_text(templar.template(task.name, fail_on_undefined=False), nonstring='empty')
|
||||||
display.debug("done templating")
|
display.debug("done templating")
|
||||||
except:
|
except:
|
||||||
# just ignore any errors during task name templating,
|
# just ignore any errors during task name templating,
|
||||||
|
@ -120,10 +120,10 @@ class StrategyModule(StrategyBase):
|
||||||
run_once = templar.template(task.run_once) or action and getattr(action, 'BYPASS_HOST_LOOP', False)
|
run_once = templar.template(task.run_once) or action and getattr(action, 'BYPASS_HOST_LOOP', False)
|
||||||
if run_once:
|
if run_once:
|
||||||
if action and getattr(action, 'BYPASS_HOST_LOOP', False):
|
if action and getattr(action, 'BYPASS_HOST_LOOP', False):
|
||||||
raise AnsibleError("The '%s' module bypasses the host loop, which is currently not supported in the free strategy " \
|
raise AnsibleError("The '%s' module bypasses the host loop, which is currently not supported in the free strategy "
|
||||||
"and would instead execute for every host in the inventory list." % task.action, obj=task._ds)
|
"and would instead execute for every host in the inventory list." % task.action, obj=task._ds)
|
||||||
else:
|
else:
|
||||||
display.warning("Using run_once with the free strategy is not currently supported. This task will still be " \
|
display.warning("Using run_once with the free strategy is not currently supported. This task will still be "
|
||||||
"executed for every host in the inventory list.")
|
"executed for every host in the inventory list.")
|
||||||
|
|
||||||
# check to see if this task should be skipped, due to it being a member of a
|
# check to see if this task should be skipped, due to it being a member of a
|
||||||
|
@ -143,7 +143,8 @@ class StrategyModule(StrategyBase):
|
||||||
# handle step if needed, skip meta actions as they are used internally
|
# handle step if needed, skip meta actions as they are used internally
|
||||||
if not self._step or self._take_step(task, host_name):
|
if not self._step or self._take_step(task, host_name):
|
||||||
if task.any_errors_fatal:
|
if task.any_errors_fatal:
|
||||||
display.warning("Using any_errors_fatal with the free strategy is not supported, as tasks are executed independently on each host")
|
display.warning("Using any_errors_fatal with the free strategy is not supported,"
|
||||||
|
" as tasks are executed independently on each host")
|
||||||
self._tqm.send_callback('v2_playbook_on_task_start', task, is_conditional=False)
|
self._tqm.send_callback('v2_playbook_on_task_start', task, is_conditional=False)
|
||||||
self._queue_task(host, task, task_vars, play_context)
|
self._queue_task(host, task, task_vars, play_context)
|
||||||
del task_vars
|
del task_vars
|
||||||
|
|
|
@ -29,7 +29,8 @@ from ansible.playbook.task import Task
|
||||||
from ansible.plugins import action_loader
|
from ansible.plugins import action_loader
|
||||||
from ansible.plugins.strategy import StrategyBase
|
from ansible.plugins.strategy import StrategyBase
|
||||||
from ansible.template import Templar
|
from ansible.template import Templar
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.module_utils._text import to_text
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -243,7 +244,7 @@ class StrategyModule(StrategyBase):
|
||||||
saved_name = task.name
|
saved_name = task.name
|
||||||
display.debug("done copying, going to template now")
|
display.debug("done copying, going to template now")
|
||||||
try:
|
try:
|
||||||
task.name = to_unicode(templar.template(task.name, fail_on_undefined=False), nonstring='empty')
|
task.name = to_text(templar.template(task.name, fail_on_undefined=False), nonstring='empty')
|
||||||
display.debug("done templating")
|
display.debug("done templating")
|
||||||
except:
|
except:
|
||||||
# just ignore any errors during task name templating,
|
# just ignore any errors during task name templating,
|
||||||
|
@ -368,7 +369,7 @@ class StrategyModule(StrategyBase):
|
||||||
for host in included_file._hosts:
|
for host in included_file._hosts:
|
||||||
self._tqm._failed_hosts[host.name] = True
|
self._tqm._failed_hosts[host.name] = True
|
||||||
iterator.mark_host_failed(host)
|
iterator.mark_host_failed(host)
|
||||||
display.error(to_unicode(e), wrap_text=False)
|
display.error(to_text(e), wrap_text=False)
|
||||||
include_failure = True
|
include_failure = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
from numbers import Number
|
||||||
|
|
||||||
from ansible.compat.six import string_types, text_type, binary_type
|
|
||||||
from jinja2 import Environment
|
from jinja2 import Environment
|
||||||
from jinja2.loaders import FileSystemLoader
|
from jinja2.loaders import FileSystemLoader
|
||||||
from jinja2.exceptions import TemplateSyntaxError, UndefinedError
|
from jinja2.exceptions import TemplateSyntaxError, UndefinedError
|
||||||
|
@ -34,19 +34,20 @@ from jinja2.utils import concat as j2_concat
|
||||||
from jinja2.runtime import StrictUndefined
|
from jinja2.runtime import StrictUndefined
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
|
from ansible.compat.six import string_types, text_type
|
||||||
from ansible.errors import AnsibleError, AnsibleFilterError, AnsibleUndefinedVariable
|
from ansible.errors import AnsibleError, AnsibleFilterError, AnsibleUndefinedVariable
|
||||||
from ansible.plugins import filter_loader, lookup_loader, test_loader
|
from ansible.plugins import filter_loader, lookup_loader, test_loader
|
||||||
from ansible.template.safe_eval import safe_eval
|
from ansible.template.safe_eval import safe_eval
|
||||||
from ansible.template.template import AnsibleJ2Template
|
from ansible.template.template import AnsibleJ2Template
|
||||||
from ansible.template.vars import AnsibleJ2Vars
|
from ansible.template.vars import AnsibleJ2Vars
|
||||||
from ansible.utils.unicode import to_unicode, to_str
|
from ansible.module_utils._text import to_native, to_text
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from sha import sha as sha1
|
from sha import sha as sha1
|
||||||
|
|
||||||
from numbers import Number
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -107,6 +108,7 @@ def _escape_backslashes(data, jinja_env):
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def _count_newlines_from_end(in_str):
|
def _count_newlines_from_end(in_str):
|
||||||
'''
|
'''
|
||||||
Counts the number of newlines at the end of a string. This is used during
|
Counts the number of newlines at the end of a string. This is used during
|
||||||
|
@ -255,10 +257,10 @@ class Templar:
|
||||||
if prev_idx is not None:
|
if prev_idx is not None:
|
||||||
# replace the opening
|
# replace the opening
|
||||||
data.seek(prev_idx, os.SEEK_SET)
|
data.seek(prev_idx, os.SEEK_SET)
|
||||||
data.write(to_unicode(self.environment.comment_start_string))
|
data.write(to_text(self.environment.comment_start_string))
|
||||||
# replace the closing
|
# replace the closing
|
||||||
data.seek(token_start, os.SEEK_SET)
|
data.seek(token_start, os.SEEK_SET)
|
||||||
data.write(to_unicode(self.environment.comment_end_string))
|
data.write(to_text(self.environment.comment_end_string))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise AnsibleError("Error while cleaning data for safety: unhandled regex match")
|
raise AnsibleError("Error while cleaning data for safety: unhandled regex match")
|
||||||
|
@ -293,7 +295,7 @@ class Templar:
|
||||||
return self._clean_data(variable)
|
return self._clean_data(variable)
|
||||||
else:
|
else:
|
||||||
# Do we need to convert these into text_type as well?
|
# Do we need to convert these into text_type as well?
|
||||||
# return self._clean_data(to_unicode(variable._obj, nonstring='passthru'))
|
# return self._clean_data(to_text(variable._obj, nonstring='passthru'))
|
||||||
return self._clean_data(variable._obj)
|
return self._clean_data(variable._obj)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -330,7 +332,7 @@ class Templar:
|
||||||
if convert_data and not self._no_type_regex.match(variable):
|
if convert_data and not self._no_type_regex.match(variable):
|
||||||
# if this looks like a dictionary or list, convert it to such using the safe_eval method
|
# if this looks like a dictionary or list, convert it to such using the safe_eval method
|
||||||
if (result.startswith("{") and not result.startswith(self.environment.variable_start_string)) or \
|
if (result.startswith("{") and not result.startswith(self.environment.variable_start_string)) or \
|
||||||
result.startswith("[") or result in ("True", "False"):
|
result.startswith("[") or result in ("True", "False"):
|
||||||
eval_results = safe_eval(result, locals=self._available_variables, include_exceptions=True)
|
eval_results = safe_eval(result, locals=self._available_variables, include_exceptions=True)
|
||||||
if eval_results[1] is None:
|
if eval_results[1] is None:
|
||||||
result = eval_results[0]
|
result = eval_results[0]
|
||||||
|
@ -383,7 +385,7 @@ class Templar:
|
||||||
returns True if the data contains a variable pattern
|
returns True if the data contains a variable pattern
|
||||||
'''
|
'''
|
||||||
if isinstance(data, string_types):
|
if isinstance(data, string_types):
|
||||||
for marker in [self.environment.block_start_string, self.environment.variable_start_string, self.environment.comment_start_string]:
|
for marker in (self.environment.block_start_string, self.environment.variable_start_string, self.environment.comment_start_string):
|
||||||
if marker in data:
|
if marker in data:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
@ -399,8 +401,9 @@ class Templar:
|
||||||
first_part = variable.split("|")[0].split(".")[0].split("[")[0]
|
first_part = variable.split("|")[0].split(".")[0].split("[")[0]
|
||||||
if (contains_filters or first_part in self._available_variables) and self.environment.variable_start_string not in variable:
|
if (contains_filters or first_part in self._available_variables) and self.environment.variable_start_string not in variable:
|
||||||
if bare_deprecated:
|
if bare_deprecated:
|
||||||
display.deprecated("Using bare variables is deprecated. Update your playbooks so that the environment value uses the full variable syntax ('%s%s%s')" %
|
display.deprecated("Using bare variables is deprecated."
|
||||||
(self.environment.variable_start_string, variable, self.environment.variable_end_string))
|
" Update your playbooks so that the environment value uses the full variable syntax ('%s%s%s')" %
|
||||||
|
(self.environment.variable_start_string, variable, self.environment.variable_end_string))
|
||||||
return "%s%s%s" % (self.environment.variable_start_string, variable, self.environment.variable_end_string)
|
return "%s%s%s" % (self.environment.variable_start_string, variable, self.environment.variable_end_string)
|
||||||
|
|
||||||
# the variable didn't meet the conditions to be converted,
|
# the variable didn't meet the conditions to be converted,
|
||||||
|
@ -485,10 +488,10 @@ class Templar:
|
||||||
try:
|
try:
|
||||||
t = myenv.from_string(data)
|
t = myenv.from_string(data)
|
||||||
except TemplateSyntaxError as e:
|
except TemplateSyntaxError as e:
|
||||||
raise AnsibleError("template error while templating string: %s. String: %s" % (to_str(e), to_str(data)))
|
raise AnsibleError("template error while templating string: %s. String: %s" % (to_native(e), to_native(data)))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if 'recursion' in to_str(e):
|
if 'recursion' in to_native(e):
|
||||||
raise AnsibleError("recursive loop detected in template string: %s" % to_str(data))
|
raise AnsibleError("recursive loop detected in template string: %s" % to_native(data))
|
||||||
else:
|
else:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -503,13 +506,13 @@ class Templar:
|
||||||
try:
|
try:
|
||||||
res = j2_concat(rf)
|
res = j2_concat(rf)
|
||||||
except TypeError as te:
|
except TypeError as te:
|
||||||
if 'StrictUndefined' in to_str(te):
|
if 'StrictUndefined' in to_native(te):
|
||||||
errmsg = "Unable to look up a name or access an attribute in template string (%s).\n" % to_str(data)
|
errmsg = "Unable to look up a name or access an attribute in template string (%s).\n" % to_native(data)
|
||||||
errmsg += "Make sure your variable name does not contain invalid characters like '-': %s" % to_str(te)
|
errmsg += "Make sure your variable name does not contain invalid characters like '-': %s" % to_native(te)
|
||||||
raise AnsibleUndefinedVariable(errmsg)
|
raise AnsibleUndefinedVariable(errmsg)
|
||||||
else:
|
else:
|
||||||
display.debug("failing because of a type error, template data is: %s" % to_str(data))
|
display.debug("failing because of a type error, template data is: %s" % to_native(data))
|
||||||
raise AnsibleError("Unexpected templating type error occurred on (%s): %s" % (to_str(data),to_str(te)))
|
raise AnsibleError("Unexpected templating type error occurred on (%s): %s" % (to_native(data),to_native(te)))
|
||||||
|
|
||||||
if preserve_trailing_newlines:
|
if preserve_trailing_newlines:
|
||||||
# The low level calls above do not preserve the newline
|
# The low level calls above do not preserve the newline
|
||||||
|
@ -534,4 +537,3 @@ class Templar:
|
||||||
else:
|
else:
|
||||||
#TODO: return warning about undefined var
|
#TODO: return warning about undefined var
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,8 @@ __metaclass__ = type
|
||||||
|
|
||||||
from ansible.compat.six import iteritems
|
from ansible.compat.six import iteritems
|
||||||
from jinja2.utils import missing
|
from jinja2.utils import missing
|
||||||
from ansible.utils.unicode import to_unicode
|
from ansible.module_utils._text import to_native
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['AnsibleJ2Vars']
|
__all__ = ['AnsibleJ2Vars']
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ class AnsibleJ2Vars:
|
||||||
try:
|
try:
|
||||||
value = self._templar.template(variable)
|
value = self._templar.template(variable)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise type(e)(to_unicode(variable) + ': ' + e.message)
|
raise type(e)(to_native(variable) + ': ' + e.message)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def add_locals(self, locals):
|
def add_locals(self, locals):
|
||||||
|
@ -99,4 +100,3 @@ class AnsibleJ2Vars:
|
||||||
if locals is None:
|
if locals is None:
|
||||||
return self
|
return self
|
||||||
return AnsibleJ2Vars(self._templar, self._globals, locals=locals, *self._extras)
|
return AnsibleJ2Vars(self._templar, self._globals, locals=locals, *self._extras)
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,8 @@ from termios import TIOCGWINSZ
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.utils.color import stringc
|
from ansible.utils.color import stringc
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Python 2
|
# Python 2
|
||||||
|
@ -45,7 +46,6 @@ except NameError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logger = None
|
logger = None
|
||||||
#TODO: make this a logging callback instead
|
#TODO: make this a logging callback instead
|
||||||
if C.DEFAULT_LOG_PATH:
|
if C.DEFAULT_LOG_PATH:
|
||||||
|
@ -105,7 +105,7 @@ class Display:
|
||||||
""" Display a message to the user
|
""" Display a message to the user
|
||||||
|
|
||||||
Note: msg *must* be a unicode string to prevent UnicodeError tracebacks.
|
Note: msg *must* be a unicode string to prevent UnicodeError tracebacks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# FIXME: this needs to be implemented
|
# FIXME: this needs to be implemented
|
||||||
#msg = utils.sanitize_output(msg)
|
#msg = utils.sanitize_output(msg)
|
||||||
|
@ -124,7 +124,7 @@ class Display:
|
||||||
# Convert back to text string on python3
|
# Convert back to text string on python3
|
||||||
# We first convert to a byte string so that we get rid of
|
# We first convert to a byte string so that we get rid of
|
||||||
# characters that are invalid in the user's locale
|
# characters that are invalid in the user's locale
|
||||||
msg2 = to_unicode(msg2, self._output_encoding(stderr=stderr))
|
msg2 = to_text(msg2, self._output_encoding(stderr=stderr))
|
||||||
|
|
||||||
if not stderr:
|
if not stderr:
|
||||||
fileobj = sys.stdout
|
fileobj = sys.stdout
|
||||||
|
@ -149,7 +149,7 @@ class Display:
|
||||||
# Convert back to text string on python3
|
# Convert back to text string on python3
|
||||||
# We first convert to a byte string so that we get rid of
|
# We first convert to a byte string so that we get rid of
|
||||||
# characters that are invalid in the user's locale
|
# characters that are invalid in the user's locale
|
||||||
msg2 = to_unicode(msg2, self._output_encoding(stderr=stderr))
|
msg2 = to_text(msg2, self._output_encoding(stderr=stderr))
|
||||||
|
|
||||||
if color == C.COLOR_ERROR:
|
if color == C.COLOR_ERROR:
|
||||||
logger.error(msg2)
|
logger.error(msg2)
|
||||||
|
@ -279,7 +279,7 @@ class Display:
|
||||||
if sys.version_info >= (3,):
|
if sys.version_info >= (3,):
|
||||||
# Convert back into text on python3. We do this double conversion
|
# Convert back into text on python3. We do this double conversion
|
||||||
# to get rid of characters that are illegal in the user's locale
|
# to get rid of characters that are illegal in the user's locale
|
||||||
prompt_string = to_unicode(prompt_string)
|
prompt_string = to_text(prompt_string)
|
||||||
|
|
||||||
if private:
|
if private:
|
||||||
return getpass.getpass(msg)
|
return getpass.getpass(msg)
|
||||||
|
@ -323,7 +323,7 @@ class Display:
|
||||||
result = do_encrypt(result, encrypt, salt_size, salt)
|
result = do_encrypt(result, encrypt, salt_size, salt)
|
||||||
|
|
||||||
# handle utf-8 chars
|
# handle utf-8 chars
|
||||||
result = to_unicode(result, errors='strict')
|
result = to_text(result, errors='surrogate_or_strict')
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -39,14 +39,14 @@ except ImportError:
|
||||||
_md5 = None
|
_md5 = None
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.utils.unicode import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
|
|
||||||
|
|
||||||
def secure_hash_s(data, hash_func=sha1):
|
def secure_hash_s(data, hash_func=sha1):
|
||||||
''' Return a secure hash hex digest of data. '''
|
''' Return a secure hash hex digest of data. '''
|
||||||
|
|
||||||
digest = hash_func()
|
digest = hash_func()
|
||||||
data = to_bytes(data, errors='strict')
|
data = to_bytes(data, errors='surrogate_or_strict')
|
||||||
digest.update(data)
|
digest.update(data)
|
||||||
return digest.hexdigest()
|
return digest.hexdigest()
|
||||||
|
|
||||||
|
@ -54,12 +54,12 @@ def secure_hash_s(data, hash_func=sha1):
|
||||||
def secure_hash(filename, hash_func=sha1):
|
def secure_hash(filename, hash_func=sha1):
|
||||||
''' Return a secure hash hex digest of local file, None if file is not present or a directory. '''
|
''' Return a secure hash hex digest of local file, None if file is not present or a directory. '''
|
||||||
|
|
||||||
if not os.path.exists(to_bytes(filename, errors='strict')) or os.path.isdir(to_bytes(filename, errors='strict')):
|
if not os.path.exists(to_bytes(filename, errors='surrogate_or_strict')) or os.path.isdir(to_bytes(filename, errors='strict')):
|
||||||
return None
|
return None
|
||||||
digest = hash_func()
|
digest = hash_func()
|
||||||
blocksize = 64 * 1024
|
blocksize = 64 * 1024
|
||||||
try:
|
try:
|
||||||
infile = open(to_bytes(filename, errors='strict'), 'rb')
|
infile = open(to_bytes(filename, errors='surrogate_or_strict'), 'rb')
|
||||||
block = infile.read(blocksize)
|
block = infile.read(blocksize)
|
||||||
while block:
|
while block:
|
||||||
digest.update(block)
|
digest.update(block)
|
||||||
|
|
|
@ -20,11 +20,12 @@ __metaclass__ = type
|
||||||
import os
|
import os
|
||||||
from errno import EEXIST
|
from errno import EEXIST
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.utils.unicode import to_bytes, to_str, to_unicode
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
from ansible.compat.six import PY2
|
|
||||||
|
|
||||||
__all__ = ['unfrackpath', 'makedirs_safe']
|
__all__ = ['unfrackpath', 'makedirs_safe']
|
||||||
|
|
||||||
|
|
||||||
def unfrackpath(path):
|
def unfrackpath(path):
|
||||||
'''
|
'''
|
||||||
Returns a path that is free of symlinks, environment
|
Returns a path that is free of symlinks, environment
|
||||||
|
@ -40,10 +41,9 @@ def unfrackpath(path):
|
||||||
example::
|
example::
|
||||||
'$HOME/../../var/mail' becomes '/var/spool/mail'
|
'$HOME/../../var/mail' becomes '/var/spool/mail'
|
||||||
'''
|
'''
|
||||||
canonical_path = os.path.normpath(os.path.realpath(os.path.expanduser(os.path.expandvars(to_bytes(path, errors='strict')))))
|
canonical_path = os.path.normpath(os.path.realpath(os.path.expanduser(os.path.expandvars(to_bytes(path, errors='surrogate_or_strict')))))
|
||||||
if PY2:
|
return to_text(canonical_path, errors='surrogate_or_strict')
|
||||||
return to_unicode(canonical_path, errors='strict')
|
|
||||||
return to_unicode(canonical_path, errors='surrogateescape')
|
|
||||||
|
|
||||||
def makedirs_safe(path, mode=None):
|
def makedirs_safe(path, mode=None):
|
||||||
'''Safe way to create dirs in muliprocess/thread environments.
|
'''Safe way to create dirs in muliprocess/thread environments.
|
||||||
|
@ -64,4 +64,4 @@ def makedirs_safe(path, mode=None):
|
||||||
os.makedirs(b_rpath)
|
os.makedirs(b_rpath)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno != EEXIST:
|
if e.errno != EEXIST:
|
||||||
raise AnsibleError("Unable to create local directories(%s): %s" % (to_str(rpath), to_str(e)))
|
raise AnsibleError("Unable to create local directories(%s): %s" % (to_native(rpath), to_native(e)))
|
||||||
|
|
|
@ -21,8 +21,7 @@ __metaclass__ = type
|
||||||
|
|
||||||
import shlex
|
import shlex
|
||||||
from ansible.compat.six import PY3
|
from ansible.compat.six import PY3
|
||||||
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
if PY3:
|
||||||
|
@ -31,5 +30,5 @@ if PY3:
|
||||||
else:
|
else:
|
||||||
# shlex.split() wants bytes (i.e. ``str``) input on Python 2
|
# shlex.split() wants bytes (i.e. ``str``) input on Python 2
|
||||||
def shlex_split(s, comments=False, posix=True):
|
def shlex_split(s, comments=False, posix=True):
|
||||||
return map(to_unicode, shlex.split(to_bytes(s), comments, posix))
|
return map(to_text, shlex.split(to_bytes(s), comments, posix))
|
||||||
shlex_split.__doc__ = shlex.split.__doc__
|
shlex_split.__doc__ = shlex.split.__doc__
|
||||||
|
|
|
@ -19,264 +19,48 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
from ansible.compat.six import string_types, text_type, binary_type, PY3
|
from ansible.module_utils._text import to_bytes as _to_bytes, to_text, to_native
|
||||||
|
|
||||||
# to_bytes and to_unicode were written by Toshio Kuratomi for the
|
try:
|
||||||
# python-kitchen library https://pypi.python.org/pypi/kitchen
|
from __main__ import display
|
||||||
# They are licensed in kitchen under the terms of the GPLv2+
|
except ImportError:
|
||||||
# They were copied and modified for use in ansible by Toshio in Jan 2015
|
from ansible.utils.display import Display
|
||||||
# (simply removing the deprecated features)
|
display = Display()
|
||||||
|
|
||||||
#: Aliases for the utf-8 codec
|
|
||||||
_UTF8_ALIASES = frozenset(('utf-8', 'UTF-8', 'utf8', 'UTF8', 'utf_8', 'UTF_8',
|
__all__ = ('to_bytes', 'to_unicode', 'to_str', 'unicode_wrap')
|
||||||
'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',
|
### Backwards compat
|
||||||
'ISO8859-1', 'iso-8859-1', 'ISO-8859-1'))
|
###
|
||||||
|
|
||||||
# EXCEPTION_CONVERTERS is defined below due to using to_unicode
|
def to_bytes(*args, **kwargs):
|
||||||
|
display.deprecated(u'ansible.utils.unicode.to_bytes is deprecated. Use ansible.module_utils._text.to_bytes instead', version=u'2.4')
|
||||||
def to_unicode(obj, encoding='utf-8', errors='replace', nonstring=None):
|
if 'errors' not in kwargs:
|
||||||
'''Convert an object into a :class:`unicode` string
|
kwargs['errors'] = 'replace'
|
||||||
|
return _to_bytes(*args, **kwargs)
|
||||||
: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.
|
def to_unicode(*args, **kwargs):
|
||||||
Defaults to :term:`utf-8`
|
display.deprecated(u'ansible.utils.unicode.to_unicode is deprecated. Use ansible.module_utils._text.to_text instead', version=u'2.4')
|
||||||
:kwarg errors: If errors are found while decoding, perform this action.
|
if 'errors' not in kwargs:
|
||||||
Defaults to ``replace`` which replaces the invalid bytes with
|
kwargs['errors'] = 'replace'
|
||||||
a character that means the bytes were unable to be decoded. Other
|
return to_text(*args, **kwargs)
|
||||||
values are the same as the error handling schemes in the `codec base
|
|
||||||
classes
|
|
||||||
<http://docs.python.org/library/codecs.html#codec-base-classes>`_.
|
def to_str(*args, **kwargs):
|
||||||
For instance ``strict`` which raises an exception and ``ignore`` which
|
display.deprecated(u'ansible.utils.unicode.to_str is deprecated. Use ansible.module_utils._text.to_native instead', version=u'2.4')
|
||||||
simply omits the non-decodable characters.
|
if 'errors' not in kwargs:
|
||||||
:kwarg nonstring: How to treat nonstring values. Possible values are:
|
kwargs['errors'] = 'replace'
|
||||||
|
return to_native(*args, **kwargs)
|
||||||
:simplerepr: Attempt to call the object's "simple representation"
|
|
||||||
method and return that value. Python-2.3+ has two methods that
|
### End Backwards compat
|
||||||
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, text_type):
|
|
||||||
return obj
|
|
||||||
if isinstance(obj, binary_type):
|
|
||||||
if encoding in _UTF8_ALIASES:
|
|
||||||
return text_type(obj, 'utf-8', errors)
|
|
||||||
if encoding in _LATIN1_ALIASES:
|
|
||||||
return text_type(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 = text_type(obj)
|
|
||||||
except UnicodeError:
|
|
||||||
try:
|
|
||||||
simple = obj.__str__()
|
|
||||||
except (UnicodeError, AttributeError):
|
|
||||||
simple = u''
|
|
||||||
if isinstance(simple, binary_type):
|
|
||||||
return text_type(simple, encoding, errors)
|
|
||||||
return simple
|
|
||||||
elif nonstring in ('repr', 'strict'):
|
|
||||||
obj_repr = repr(obj)
|
|
||||||
if isinstance(obj_repr, binary_type):
|
|
||||||
obj_repr = text_type(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, binary_type):
|
|
||||||
return obj
|
|
||||||
if isinstance(obj, text_type):
|
|
||||||
return obj.encode(encoding, errors)
|
|
||||||
if not nonstring:
|
|
||||||
nonstring = 'simplerepr'
|
|
||||||
|
|
||||||
if nonstring == 'empty':
|
|
||||||
return b''
|
|
||||||
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 = b''
|
|
||||||
if isinstance(simple, text_type):
|
|
||||||
simple = simple.encode(encoding, 'replace')
|
|
||||||
return simple
|
|
||||||
elif nonstring in ('repr', 'strict'):
|
|
||||||
try:
|
|
||||||
obj_repr = obj.__repr__()
|
|
||||||
except (AttributeError, UnicodeError):
|
|
||||||
obj_repr = b''
|
|
||||||
if isinstance(obj_repr, text_type):
|
|
||||||
obj_repr = obj_repr.encode(encoding, errors)
|
|
||||||
else:
|
|
||||||
obj_repr = binary_type(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):
|
def unicode_wrap(func, *args, **kwargs):
|
||||||
return to_unicode(func(*args, **kwargs), nonstring='passthru')
|
"""If a function returns a string, force it to be a text string.
|
||||||
|
|
||||||
|
Use with partial to ensure that filter plugins will return text values.
|
||||||
# Alias for converting to native strings.
|
"""
|
||||||
# Native strings are the default string type for the particular version of
|
return to_text(func(*args, **kwargs), nonstring='passthru')
|
||||||
# python. The objects are called "str" in both py2 and py3 but they mean
|
|
||||||
# different things. In py2, it's a byte string like in C. In py3 it's an
|
|
||||||
# abstract text type (like py2's unicode type).
|
|
||||||
#
|
|
||||||
# Use this when raising exceptions and wanting to get the string
|
|
||||||
# representation of an object for the exception message. For example:
|
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# do_something()
|
|
||||||
# except Exception as e:
|
|
||||||
# raise AnsibleError(to_str(e))
|
|
||||||
#
|
|
||||||
# Note that this is because python's exception handling expects native strings
|
|
||||||
# and doe the wrong thing if given the other sort of string (in py2, if given
|
|
||||||
# unicode strings, it could traceback or omit the message. in py3, if given
|
|
||||||
# byte strings it prints their repr (so the message ends up as b'message').
|
|
||||||
#
|
|
||||||
# If you use ansible's API instead of re-raising an exception, use to_unicode
|
|
||||||
# instead:
|
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# do_something()
|
|
||||||
# except Exception as e:
|
|
||||||
# display.warn(to_unicode(e))
|
|
||||||
if PY3:
|
|
||||||
to_str = to_unicode
|
|
||||||
else:
|
|
||||||
to_str = to_bytes
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ from ansible.compat.six import iteritems, string_types
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.parsing.splitter import parse_kv
|
from ansible.parsing.splitter import parse_kv
|
||||||
from ansible.utils.unicode import to_unicode, to_str
|
from ansible.module_utils._text import to_native, to_text
|
||||||
|
|
||||||
|
|
||||||
def _validate_mutable_mappings(a, b):
|
def _validate_mutable_mappings(a, b):
|
||||||
|
@ -49,11 +49,12 @@ def _validate_mutable_mappings(a, b):
|
||||||
try:
|
try:
|
||||||
myvars.append(dumps(x))
|
myvars.append(dumps(x))
|
||||||
except:
|
except:
|
||||||
myvars.append(to_str(x))
|
myvars.append(to_native(x))
|
||||||
raise AnsibleError("failed to combine variables, expected dicts but got a '{0}' and a '{1}': \n{2}\n{3}".format(
|
raise AnsibleError("failed to combine variables, expected dicts but got a '{0}' and a '{1}': \n{2}\n{3}".format(
|
||||||
a.__class__.__name__, b.__class__.__name__, myvars[0], myvars[1])
|
a.__class__.__name__, b.__class__.__name__, myvars[0], myvars[1])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def combine_vars(a, b):
|
def combine_vars(a, b):
|
||||||
"""
|
"""
|
||||||
Return a copy of dictionaries of variables based on configured hash behavior
|
Return a copy of dictionaries of variables based on configured hash behavior
|
||||||
|
@ -68,6 +69,7 @@ def combine_vars(a, b):
|
||||||
result.update(b)
|
result.update(b)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def merge_hash(a, b):
|
def merge_hash(a, b):
|
||||||
"""
|
"""
|
||||||
Recursively merges hash b into a so that keys from b take precedence over keys from a
|
Recursively merges hash b into a so that keys from b take precedence over keys from a
|
||||||
|
@ -95,10 +97,11 @@ def merge_hash(a, b):
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def load_extra_vars(loader, options):
|
def load_extra_vars(loader, options):
|
||||||
extra_vars = {}
|
extra_vars = {}
|
||||||
for extra_vars_opt in options.extra_vars:
|
for extra_vars_opt in options.extra_vars:
|
||||||
extra_vars_opt = to_unicode(extra_vars_opt, errors='strict')
|
extra_vars_opt = to_text(extra_vars_opt, errors='surrogate_or_strict')
|
||||||
if extra_vars_opt.startswith(u"@"):
|
if extra_vars_opt.startswith(u"@"):
|
||||||
# Argument is a YAML file (JSON is a subset of YAML)
|
# Argument is a YAML file (JSON is a subset of YAML)
|
||||||
data = loader.load_from_file(extra_vars_opt[1:])
|
data = loader.load_from_file(extra_vars_opt[1:])
|
||||||
|
@ -111,6 +114,7 @@ def load_extra_vars(loader, options):
|
||||||
extra_vars = combine_vars(extra_vars, data)
|
extra_vars = combine_vars(extra_vars, data)
|
||||||
return extra_vars
|
return extra_vars
|
||||||
|
|
||||||
|
|
||||||
def load_options_vars(options):
|
def load_options_vars(options):
|
||||||
options_vars = {}
|
options_vars = {}
|
||||||
# For now only return check mode, but we can easily return more
|
# For now only return check mode, but we can easily return more
|
||||||
|
@ -118,6 +122,7 @@ def load_options_vars(options):
|
||||||
options_vars['ansible_check_mode'] = options.check
|
options_vars['ansible_check_mode'] = options.check
|
||||||
return options_vars
|
return options_vars
|
||||||
|
|
||||||
|
|
||||||
def isidentifier(ident):
|
def isidentifier(ident):
|
||||||
"""
|
"""
|
||||||
Determines, if string is valid Python identifier using the ast module.
|
Determines, if string is valid Python identifier using the ast module.
|
||||||
|
@ -148,4 +153,3 @@ def isidentifier(ident):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -54,18 +54,21 @@ from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from ansible.utils.unicode import to_unicode
|
|
||||||
from ansible.compat.six import string_types, text_type
|
from ansible.compat.six import string_types, text_type
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['UnsafeProxy', 'AnsibleUnsafe', 'AnsibleJSONUnsafeEncoder', 'AnsibleJSONUnsafeDecoder', 'wrap_var']
|
__all__ = ['UnsafeProxy', 'AnsibleUnsafe', 'AnsibleJSONUnsafeEncoder', 'AnsibleJSONUnsafeDecoder', 'wrap_var']
|
||||||
|
|
||||||
|
|
||||||
class AnsibleUnsafe(object):
|
class AnsibleUnsafe(object):
|
||||||
__UNSAFE__ = True
|
__UNSAFE__ = True
|
||||||
|
|
||||||
|
|
||||||
class AnsibleUnsafeText(text_type, AnsibleUnsafe):
|
class AnsibleUnsafeText(text_type, AnsibleUnsafe):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UnsafeProxy(object):
|
class UnsafeProxy(object):
|
||||||
def __new__(cls, obj, *args, **kwargs):
|
def __new__(cls, obj, *args, **kwargs):
|
||||||
# In our usage we should only receive unicode strings.
|
# In our usage we should only receive unicode strings.
|
||||||
|
@ -73,10 +76,11 @@ class UnsafeProxy(object):
|
||||||
# we're given but we may want to take it out for testing and sanitize
|
# we're given but we may want to take it out for testing and sanitize
|
||||||
# our input instead.
|
# our input instead.
|
||||||
if isinstance(obj, string_types):
|
if isinstance(obj, string_types):
|
||||||
obj = to_unicode(obj, errors='strict')
|
obj = to_text(obj, errors='surrogate_or_strict')
|
||||||
return AnsibleUnsafeText(obj)
|
return AnsibleUnsafeText(obj)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
class AnsibleJSONUnsafeEncoder(json.JSONEncoder):
|
class AnsibleJSONUnsafeEncoder(json.JSONEncoder):
|
||||||
def encode(self, obj):
|
def encode(self, obj):
|
||||||
if isinstance(obj, AnsibleUnsafe):
|
if isinstance(obj, AnsibleUnsafe):
|
||||||
|
@ -84,6 +88,7 @@ class AnsibleJSONUnsafeEncoder(json.JSONEncoder):
|
||||||
else:
|
else:
|
||||||
return super(AnsibleJSONUnsafeEncoder, self).encode(obj)
|
return super(AnsibleJSONUnsafeEncoder, self).encode(obj)
|
||||||
|
|
||||||
|
|
||||||
class AnsibleJSONUnsafeDecoder(json.JSONDecoder):
|
class AnsibleJSONUnsafeDecoder(json.JSONDecoder):
|
||||||
def decode(self, obj):
|
def decode(self, obj):
|
||||||
value = super(AnsibleJSONUnsafeDecoder, self).decode(obj)
|
value = super(AnsibleJSONUnsafeDecoder, self).decode(obj)
|
||||||
|
@ -92,6 +97,7 @@ class AnsibleJSONUnsafeDecoder(json.JSONDecoder):
|
||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def _wrap_dict(v):
|
def _wrap_dict(v):
|
||||||
for k in v.keys():
|
for k in v.keys():
|
||||||
if v[k] is not None:
|
if v[k] is not None:
|
||||||
|
@ -115,4 +121,3 @@ def wrap_var(v):
|
||||||
if v is not None and not isinstance(v, AnsibleUnsafe):
|
if v is not None and not isinstance(v, AnsibleUnsafe):
|
||||||
v = UnsafeProxy(v)
|
v = UnsafeProxy(v)
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ from contextlib import contextmanager
|
||||||
from io import BytesIO, StringIO
|
from io import BytesIO, StringIO
|
||||||
from ansible.compat.six import PY3
|
from ansible.compat.six import PY3
|
||||||
from ansible.compat.tests import unittest
|
from ansible.compat.tests import unittest
|
||||||
from ansible.utils.unicode import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def swap_stdin_and_argv(stdin_data='', argv_data=tuple()):
|
def swap_stdin_and_argv(stdin_data='', argv_data=tuple()):
|
||||||
|
@ -48,6 +49,7 @@ def swap_stdin_and_argv(stdin_data='', argv_data=tuple()):
|
||||||
sys.stdin = real_stdin
|
sys.stdin = real_stdin
|
||||||
sys.argv = real_argv
|
sys.argv = real_argv
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def swap_stdout():
|
def swap_stdout():
|
||||||
"""
|
"""
|
||||||
|
@ -62,6 +64,7 @@ def swap_stdout():
|
||||||
yield fake_stream
|
yield fake_stream
|
||||||
sys.stdout = old_stdout
|
sys.stdout = old_stdout
|
||||||
|
|
||||||
|
|
||||||
class ModuleTestCase(unittest.TestCase):
|
class ModuleTestCase(unittest.TestCase):
|
||||||
def setUp(self, module_args=None):
|
def setUp(self, module_args=None):
|
||||||
if module_args is None:
|
if module_args is None:
|
||||||
|
|
|
@ -30,11 +30,12 @@ from binascii import hexlify
|
||||||
from nose.plugins.skip import SkipTest
|
from nose.plugins.skip import SkipTest
|
||||||
|
|
||||||
from ansible.compat.tests import unittest
|
from ansible.compat.tests import unittest
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
|
||||||
|
|
||||||
from ansible import errors
|
from ansible import errors
|
||||||
from ansible.parsing.vault import VaultLib
|
from ansible.parsing.vault import VaultLib
|
||||||
from ansible.parsing import vault
|
from ansible.parsing import vault
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
|
|
||||||
|
|
||||||
# Counter import fails for 2.0.1, requires >= 2.6.1 from pip
|
# Counter import fails for 2.0.1, requires >= 2.6.1 from pip
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -27,11 +27,12 @@ from nose.plugins.skip import SkipTest
|
||||||
|
|
||||||
from ansible.compat.tests import unittest
|
from ansible.compat.tests import unittest
|
||||||
from ansible.compat.tests.mock import patch
|
from ansible.compat.tests.mock import patch
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
|
||||||
|
|
||||||
from ansible import errors
|
from ansible import errors
|
||||||
from ansible.parsing.vault import VaultLib
|
from ansible.parsing.vault import VaultLib
|
||||||
from ansible.parsing.vault import VaultEditor
|
from ansible.parsing.vault import VaultEditor
|
||||||
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
|
||||||
|
|
||||||
# Counter import fails for 2.0.1, requires >= 2.6.1 from pip
|
# Counter import fails for 2.0.1, requires >= 2.6.1 from pip
|
||||||
try:
|
try:
|
||||||
|
@ -66,6 +67,7 @@ v11_data = """$ANSIBLE_VAULT;1.1;AES256
|
||||||
3631633031323837340a396530313963373030343933616133393566366137363761373930663833
|
3631633031323837340a396530313963373030343933616133393566366137363761373930663833
|
||||||
3739"""
|
3739"""
|
||||||
|
|
||||||
|
|
||||||
class TestVaultEditor(unittest.TestCase):
|
class TestVaultEditor(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -121,20 +123,19 @@ class TestVaultEditor(unittest.TestCase):
|
||||||
error_hit = False
|
error_hit = False
|
||||||
try:
|
try:
|
||||||
ve.decrypt_file(v10_file.name)
|
ve.decrypt_file(v10_file.name)
|
||||||
except errors.AnsibleError as e:
|
except errors.AnsibleError:
|
||||||
error_hit = True
|
error_hit = True
|
||||||
|
|
||||||
# verify decrypted content
|
# verify decrypted content
|
||||||
f = open(v10_file.name, "rb")
|
f = open(v10_file.name, "rb")
|
||||||
fdata = to_unicode(f.read())
|
fdata = to_text(f.read())
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
os.unlink(v10_file.name)
|
os.unlink(v10_file.name)
|
||||||
|
|
||||||
assert error_hit == False, "error decrypting 1.0 file"
|
assert error_hit is False, "error decrypting 1.0 file"
|
||||||
assert fdata.strip() == "foo", "incorrect decryption of 1.0 file: %s" % fdata.strip()
|
assert fdata.strip() == "foo", "incorrect decryption of 1.0 file: %s" % fdata.strip()
|
||||||
|
|
||||||
|
|
||||||
def test_decrypt_1_1(self):
|
def test_decrypt_1_1(self):
|
||||||
if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
||||||
raise SkipTest
|
raise SkipTest
|
||||||
|
@ -149,20 +150,19 @@ class TestVaultEditor(unittest.TestCase):
|
||||||
error_hit = False
|
error_hit = False
|
||||||
try:
|
try:
|
||||||
ve.decrypt_file(v11_file.name)
|
ve.decrypt_file(v11_file.name)
|
||||||
except errors.AnsibleError as e:
|
except errors.AnsibleError:
|
||||||
error_hit = True
|
error_hit = True
|
||||||
|
|
||||||
# verify decrypted content
|
# verify decrypted content
|
||||||
f = open(v11_file.name, "rb")
|
f = open(v11_file.name, "rb")
|
||||||
fdata = to_unicode(f.read())
|
fdata = to_text(f.read())
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
os.unlink(v11_file.name)
|
os.unlink(v11_file.name)
|
||||||
|
|
||||||
assert error_hit == False, "error decrypting 1.0 file"
|
assert error_hit is False, "error decrypting 1.0 file"
|
||||||
assert fdata.strip() == "foo", "incorrect decryption of 1.0 file: %s" % fdata.strip()
|
assert fdata.strip() == "foo", "incorrect decryption of 1.0 file: %s" % fdata.strip()
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.version_info[0] >= 3, "VaultAES still needs to be ported to Python 3")
|
@unittest.skipIf(sys.version_info[0] >= 3, "VaultAES still needs to be ported to Python 3")
|
||||||
def test_rekey_migration(self):
|
def test_rekey_migration(self):
|
||||||
"""
|
"""
|
||||||
|
@ -182,7 +182,7 @@ class TestVaultEditor(unittest.TestCase):
|
||||||
error_hit = False
|
error_hit = False
|
||||||
try:
|
try:
|
||||||
ve.rekey_file(v10_file.name, 'ansible2')
|
ve.rekey_file(v10_file.name, 'ansible2')
|
||||||
except errors.AnsibleError as e:
|
except errors.AnsibleError:
|
||||||
error_hit = True
|
error_hit = True
|
||||||
|
|
||||||
# verify decrypted content
|
# verify decrypted content
|
||||||
|
@ -190,7 +190,7 @@ class TestVaultEditor(unittest.TestCase):
|
||||||
fdata = f.read()
|
fdata = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
assert error_hit == False, "error rekeying 1.0 file to 1.1"
|
assert error_hit is False, "error rekeying 1.0 file to 1.1"
|
||||||
|
|
||||||
# ensure filedata can be decrypted, is 1.1 and is AES256
|
# ensure filedata can be decrypted, is 1.1 and is AES256
|
||||||
vl = VaultLib("ansible2")
|
vl = VaultLib("ansible2")
|
||||||
|
@ -198,13 +198,11 @@ class TestVaultEditor(unittest.TestCase):
|
||||||
error_hit = False
|
error_hit = False
|
||||||
try:
|
try:
|
||||||
dec_data = vl.decrypt(fdata)
|
dec_data = vl.decrypt(fdata)
|
||||||
except errors.AnsibleError as e:
|
except errors.AnsibleError:
|
||||||
error_hit = True
|
error_hit = True
|
||||||
|
|
||||||
os.unlink(v10_file.name)
|
os.unlink(v10_file.name)
|
||||||
|
|
||||||
assert vl.cipher_name == "AES256", "wrong cipher name set after rekey: %s" % vl.cipher_name
|
assert vl.cipher_name == "AES256", "wrong cipher name set after rekey: %s" % vl.cipher_name
|
||||||
assert error_hit == False, "error decrypting migrated 1.0 file"
|
assert error_hit is False, "error decrypting migrated 1.0 file"
|
||||||
assert dec_data.strip() == "foo", "incorrect decryption of rekeyed/migrated file: %s" % dec_data
|
assert dec_data.strip() == "foo", "incorrect decryption of rekeyed/migrated file: %s" % dec_data
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,6 @@ from ansible.parsing.yaml.loader import AnsibleLoader
|
||||||
from ansible.parsing import vault
|
from ansible.parsing import vault
|
||||||
from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
|
from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
|
||||||
from ansible.parsing.yaml.dumper import AnsibleDumper
|
from ansible.parsing.yaml.dumper import AnsibleDumper
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
from units.mock.yaml_helper import YamlTestUtils
|
from units.mock.yaml_helper import YamlTestUtils
|
||||||
|
|
||||||
|
@ -41,6 +40,7 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from yaml.parser import ParserError
|
from yaml.parser import ParserError
|
||||||
|
|
||||||
|
|
||||||
class NameStringIO(StringIO):
|
class NameStringIO(StringIO):
|
||||||
"""In py2.6, StringIO doesn't let you set name because a baseclass has it
|
"""In py2.6, StringIO doesn't let you set name because a baseclass has it
|
||||||
as readonly property"""
|
as readonly property"""
|
||||||
|
@ -49,6 +49,7 @@ class NameStringIO(StringIO):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(NameStringIO, self).__init__(*args, **kwargs)
|
super(NameStringIO, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class TestAnsibleLoaderBasic(unittest.TestCase):
|
class TestAnsibleLoaderBasic(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -283,6 +284,7 @@ class TestAnsibleLoaderVault(unittest.TestCase, YamlTestUtils):
|
||||||
self.assertFalse(plaintext_var != vault_string)
|
self.assertFalse(plaintext_var != vault_string)
|
||||||
self.assertFalse(vault_string != plaintext_var)
|
self.assertFalse(vault_string != plaintext_var)
|
||||||
|
|
||||||
|
|
||||||
class TestAnsibleLoaderPlay(unittest.TestCase):
|
class TestAnsibleLoaderPlay(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import ast
|
|
||||||
import json
|
|
||||||
import pipes
|
import pipes
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -33,7 +31,6 @@ except ImportError:
|
||||||
|
|
||||||
from nose.tools import eq_, raises
|
from nose.tools import eq_, raises
|
||||||
|
|
||||||
from ansible.release import __version__ as ansible_version
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.compat.six import text_type
|
from ansible.compat.six import text_type
|
||||||
from ansible.compat.tests import unittest
|
from ansible.compat.tests import unittest
|
||||||
|
@ -41,12 +38,12 @@ from ansible.compat.tests.mock import patch, MagicMock, mock_open
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.playbook.play_context import PlayContext
|
from ansible.playbook.play_context import PlayContext
|
||||||
from ansible.plugins import PluginLoader
|
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.template import Templar
|
from ansible.template import Templar
|
||||||
from ansible.utils.unicode import to_bytes
|
|
||||||
|
|
||||||
from units.mock.loader import DictDataLoader
|
from units.mock.loader import DictDataLoader
|
||||||
|
from ansible.module_utils._text import to_bytes
|
||||||
|
|
||||||
|
|
||||||
python_module_replacers = b"""
|
python_module_replacers = b"""
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
@ -67,11 +64,13 @@ WINDOWS_ARGS = "<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>"
|
||||||
|
|
||||||
class DerivedActionBase(ActionBase):
|
class DerivedActionBase(ActionBase):
|
||||||
TRANSFERS_FILES = False
|
TRANSFERS_FILES = False
|
||||||
|
|
||||||
def run(self, tmp=None, task_vars=None):
|
def run(self, tmp=None, task_vars=None):
|
||||||
# We're not testing the plugin run() method, just the helper
|
# We're not testing the plugin run() method, just the helper
|
||||||
# methods ActionBase defines
|
# methods ActionBase defines
|
||||||
return super(DerivedActionBase, self).run(tmp=tmp, task_vars=task_vars)
|
return super(DerivedActionBase, self).run(tmp=tmp, task_vars=task_vars)
|
||||||
|
|
||||||
|
|
||||||
class TestActionBase(unittest.TestCase):
|
class TestActionBase(unittest.TestCase):
|
||||||
|
|
||||||
def test_action_base_run(self):
|
def test_action_base_run(self):
|
||||||
|
@ -144,7 +143,7 @@ class TestActionBase(unittest.TestCase):
|
||||||
self.assertRaises(AnsibleError, action_base._configure_module, 'badmodule', mock_task.args)
|
self.assertRaises(AnsibleError, action_base._configure_module, 'badmodule', mock_task.args)
|
||||||
|
|
||||||
# test powershell module formatting
|
# test powershell module formatting
|
||||||
with patch.object(builtins, 'open', mock_open(read_data=to_bytes(powershell_module_replacers.strip(), encoding='utf-8'))) as m:
|
with patch.object(builtins, 'open', mock_open(read_data=to_bytes(powershell_module_replacers.strip(), encoding='utf-8'))):
|
||||||
mock_task.action = 'win_copy'
|
mock_task.action = 'win_copy'
|
||||||
mock_task.args = dict(b=2)
|
mock_task.args = dict(b=2)
|
||||||
mock_connection.module_implementation_preferences = ('.ps1',)
|
mock_connection.module_implementation_preferences = ('.ps1',)
|
||||||
|
@ -497,7 +496,10 @@ class TestActionBase(unittest.TestCase):
|
||||||
action_base._connection.has_pipelining = True
|
action_base._connection.has_pipelining = True
|
||||||
action_base._low_level_execute_command.return_value = dict(stdout='{"rc": 0, "stdout": "ok"}')
|
action_base._low_level_execute_command.return_value = dict(stdout='{"rc": 0, "stdout": "ok"}')
|
||||||
self.assertEqual(action_base._execute_module(module_name=None, module_args=None), dict(_ansible_parsed=True, rc=0, stdout="ok", stdout_lines=['ok']))
|
self.assertEqual(action_base._execute_module(module_name=None, module_args=None), dict(_ansible_parsed=True, rc=0, stdout="ok", stdout_lines=['ok']))
|
||||||
self.assertEqual(action_base._execute_module(module_name='foo', module_args=dict(z=9, y=8, x=7), task_vars=dict(a=1)), dict(_ansible_parsed=True, rc=0, stdout="ok", stdout_lines=['ok']))
|
self.assertEqual(action_base._execute_module(module_name='foo',
|
||||||
|
module_args=dict(z=9, y=8, x=7), task_vars=dict(a=1)),
|
||||||
|
dict(_ansible_parsed=True, rc=0, stdout="ok",
|
||||||
|
stdout_lines=['ok']))
|
||||||
|
|
||||||
# test with needing/removing a remote tmp path
|
# test with needing/removing a remote tmp path
|
||||||
action_base._configure_module.return_value = ('old', '#!/usr/bin/python', 'this is the module data', 'path')
|
action_base._configure_module.return_value = ('old', '#!/usr/bin/python', 'this is the module data', 'path')
|
||||||
|
@ -555,6 +557,7 @@ class TestActionBase(unittest.TestCase):
|
||||||
finally:
|
finally:
|
||||||
C.BECOME_ALLOW_SAME_USER = become_allow_same_user
|
C.BECOME_ALLOW_SAME_USER = become_allow_same_user
|
||||||
|
|
||||||
|
|
||||||
# Note: Using nose's generator test cases here so we can't inherit from
|
# Note: Using nose's generator test cases here so we can't inherit from
|
||||||
# unittest.TestCase
|
# unittest.TestCase
|
||||||
class TestFilterNonJsonLines(object):
|
class TestFilterNonJsonLines(object):
|
||||||
|
@ -592,4 +595,3 @@ class TestFilterNonJsonLines(object):
|
||||||
def test_unparsable_filter_non_json_lines(self):
|
def test_unparsable_filter_non_json_lines(self):
|
||||||
for stdout_line in self.unparsable_cases:
|
for stdout_line in self.unparsable_cases:
|
||||||
yield self.check_unparsable_filter_non_json_lines, stdout_line
|
yield self.check_unparsable_filter_non_json_lines, stdout_line
|
||||||
|
|
||||||
|
|
|
@ -22,17 +22,17 @@ from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import pipes
|
import pipes
|
||||||
import sys
|
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
from ansible.compat.tests import unittest
|
from ansible.compat.tests import unittest
|
||||||
from ansible.compat.tests.mock import patch, MagicMock, mock_open
|
from ansible.compat.tests.mock import patch, MagicMock
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
|
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
|
||||||
from ansible.playbook.play_context import PlayContext
|
from ansible.playbook.play_context import PlayContext
|
||||||
from ansible.plugins.connection import ssh
|
from ansible.plugins.connection import ssh
|
||||||
from ansible.utils.unicode import to_bytes, to_unicode
|
from ansible.module_utils._text import to_bytes
|
||||||
|
|
||||||
|
|
||||||
class TestConnectionBaseClass(unittest.TestCase):
|
class TestConnectionBaseClass(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -277,20 +277,22 @@ class TestConnectionBaseClass(unittest.TestCase):
|
||||||
C.ANSIBLE_SSH_RETRIES = 9
|
C.ANSIBLE_SSH_RETRIES = 9
|
||||||
|
|
||||||
# test a regular, successful execution
|
# test a regular, successful execution
|
||||||
conn._exec_command.return_value = (0, 'stdout', '')
|
conn._exec_command.return_value = (0, b'stdout', b'')
|
||||||
res = conn.exec_command('ssh', 'some data')
|
res = conn.exec_command('ssh', 'some data')
|
||||||
|
self.assertEquals(res, (0, b'stdout', b''), msg='exec_command did not return what the _exec_command helper returned')
|
||||||
|
|
||||||
# test a retry, followed by success
|
# test a retry, followed by success
|
||||||
conn._exec_command.return_value = None
|
conn._exec_command.return_value = None
|
||||||
conn._exec_command.side_effect = [(255, '', ''), (0, 'stdout', '')]
|
conn._exec_command.side_effect = [(255, '', ''), (0, b'stdout', b'')]
|
||||||
res = conn.exec_command('ssh', 'some data')
|
res = conn.exec_command('ssh', 'some data')
|
||||||
|
self.assertEquals(res, (0, b'stdout', b''), msg='exec_command did not return what the _exec_command helper returned')
|
||||||
|
|
||||||
# test multiple failures
|
# test multiple failures
|
||||||
conn._exec_command.side_effect = [(255, '', '')]*10
|
conn._exec_command.side_effect = [(255, b'', b'')] * 10
|
||||||
self.assertRaises(AnsibleConnectionFailure, conn.exec_command, 'ssh', 'some data')
|
self.assertRaises(AnsibleConnectionFailure, conn.exec_command, 'ssh', 'some data')
|
||||||
|
|
||||||
# test other failure from exec_command
|
# test other failure from exec_command
|
||||||
conn._exec_command.side_effect = [Exception('bad')]*10
|
conn._exec_command.side_effect = [Exception('bad')] * 10
|
||||||
self.assertRaises(Exception, conn.exec_command, 'ssh', 'some data')
|
self.assertRaises(Exception, conn.exec_command, 'ssh', 'some data')
|
||||||
|
|
||||||
@patch('os.path.exists')
|
@patch('os.path.exists')
|
||||||
|
@ -308,20 +310,22 @@ class TestConnectionBaseClass(unittest.TestCase):
|
||||||
|
|
||||||
# test with C.DEFAULT_SCP_IF_SSH enabled
|
# test with C.DEFAULT_SCP_IF_SSH enabled
|
||||||
C.DEFAULT_SCP_IF_SSH = True
|
C.DEFAULT_SCP_IF_SSH = True
|
||||||
res = conn.put_file('/path/to/in/file', '/path/to/dest/file')
|
conn.put_file('/path/to/in/file', '/path/to/dest/file')
|
||||||
conn._run.assert_called_with('some command to run', None)
|
conn._run.assert_called_with('some command to run', None)
|
||||||
|
|
||||||
res = conn.put_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩')
|
conn.put_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩')
|
||||||
conn._run.assert_called_with('some command to run', None)
|
conn._run.assert_called_with('some command to run', None)
|
||||||
|
|
||||||
# test with C.DEFAULT_SCP_IF_SSH disabled
|
# test with C.DEFAULT_SCP_IF_SSH disabled
|
||||||
C.DEFAULT_SCP_IF_SSH = False
|
C.DEFAULT_SCP_IF_SSH = False
|
||||||
expected_in_data = b' '.join((b'put', to_bytes(pipes.quote('/path/to/in/file')), to_bytes(pipes.quote('/path/to/dest/file')))) + b'\n'
|
expected_in_data = b' '.join((b'put', to_bytes(pipes.quote('/path/to/in/file')), to_bytes(pipes.quote('/path/to/dest/file')))) + b'\n'
|
||||||
res = conn.put_file('/path/to/in/file', '/path/to/dest/file')
|
conn.put_file('/path/to/in/file', '/path/to/dest/file')
|
||||||
conn._run.assert_called_with('some command to run', expected_in_data)
|
conn._run.assert_called_with('some command to run', expected_in_data)
|
||||||
|
|
||||||
expected_in_data = b' '.join((b'put', to_bytes(pipes.quote('/path/to/in/file/with/unicode-fö〩')), to_bytes(pipes.quote('/path/to/dest/file/with/unicode-fö〩')))) + b'\n'
|
expected_in_data = b' '.join((b'put',
|
||||||
res = conn.put_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩')
|
to_bytes(pipes.quote('/path/to/in/file/with/unicode-fö〩')),
|
||||||
|
to_bytes(pipes.quote('/path/to/dest/file/with/unicode-fö〩')))) + b'\n'
|
||||||
|
conn.put_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩')
|
||||||
conn._run.assert_called_with('some command to run', expected_in_data)
|
conn._run.assert_called_with('some command to run', expected_in_data)
|
||||||
|
|
||||||
# test that a non-zero rc raises an error
|
# test that a non-zero rc raises an error
|
||||||
|
@ -346,23 +350,24 @@ class TestConnectionBaseClass(unittest.TestCase):
|
||||||
|
|
||||||
# test with C.DEFAULT_SCP_IF_SSH enabled
|
# test with C.DEFAULT_SCP_IF_SSH enabled
|
||||||
C.DEFAULT_SCP_IF_SSH = True
|
C.DEFAULT_SCP_IF_SSH = True
|
||||||
res = conn.fetch_file('/path/to/in/file', '/path/to/dest/file')
|
conn.fetch_file('/path/to/in/file', '/path/to/dest/file')
|
||||||
conn._run.assert_called_with('some command to run', None)
|
conn._run.assert_called_with('some command to run', None)
|
||||||
|
|
||||||
res = conn.fetch_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩')
|
conn.fetch_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩')
|
||||||
conn._run.assert_called_with('some command to run', None)
|
conn._run.assert_called_with('some command to run', None)
|
||||||
|
|
||||||
# test with C.DEFAULT_SCP_IF_SSH disabled
|
# test with C.DEFAULT_SCP_IF_SSH disabled
|
||||||
C.DEFAULT_SCP_IF_SSH = False
|
C.DEFAULT_SCP_IF_SSH = False
|
||||||
expected_in_data = b' '.join((b'get', to_bytes(pipes.quote('/path/to/in/file')), to_bytes(pipes.quote('/path/to/dest/file')))) + b'\n'
|
expected_in_data = b' '.join((b'get', to_bytes(pipes.quote('/path/to/in/file')), to_bytes(pipes.quote('/path/to/dest/file')))) + b'\n'
|
||||||
res = conn.fetch_file('/path/to/in/file', '/path/to/dest/file')
|
conn.fetch_file('/path/to/in/file', '/path/to/dest/file')
|
||||||
conn._run.assert_called_with('some command to run', expected_in_data)
|
conn._run.assert_called_with('some command to run', expected_in_data)
|
||||||
|
|
||||||
expected_in_data = b' '.join((b'get', to_bytes(pipes.quote('/path/to/in/file/with/unicode-fö〩')), to_bytes(pipes.quote('/path/to/dest/file/with/unicode-fö〩')))) + b'\n'
|
expected_in_data = b' '.join((b'get',
|
||||||
res = conn.fetch_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩')
|
to_bytes(pipes.quote('/path/to/in/file/with/unicode-fö〩')),
|
||||||
|
to_bytes(pipes.quote('/path/to/dest/file/with/unicode-fö〩')))) + b'\n'
|
||||||
|
conn.fetch_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩')
|
||||||
conn._run.assert_called_with('some command to run', expected_in_data)
|
conn._run.assert_called_with('some command to run', expected_in_data)
|
||||||
|
|
||||||
# test that a non-zero rc raises an error
|
# test that a non-zero rc raises an error
|
||||||
conn._run.return_value = (1, 'stdout', 'some errors')
|
conn._run.return_value = (1, 'stdout', 'some errors')
|
||||||
self.assertRaises(AnsibleError, conn.fetch_file, '/path/to/bad/file', '/remote/path/to/file')
|
self.assertRaises(AnsibleError, conn.fetch_file, '/path/to/bad/file', '/remote/path/to/file')
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue