diff --git a/lib/ansible/executor/play_iterator.py b/lib/ansible/executor/play_iterator.py index c886b46f2a..07b890c420 100644 --- a/lib/ansible/executor/play_iterator.py +++ b/lib/ansible/executor/play_iterator.py @@ -89,12 +89,12 @@ class PlayIterator: FAILED_RESCUE = 4 FAILED_ALWAYS = 8 - def __init__(self, inventory, play, connection_info, all_vars): + def __init__(self, inventory, play, play_context, all_vars): self._play = play self._blocks = [] for block in self._play.compile(): - new_block = block.filter_tagged_tasks(connection_info, all_vars) + new_block = block.filter_tagged_tasks(play_context, all_vars) if new_block.has_tasks(): self._blocks.append(new_block) @@ -103,12 +103,12 @@ class PlayIterator: self._host_states[host.name] = HostState(blocks=self._blocks) # if we're looking to start at a specific task, iterate through # the tasks for this host until we find the specified task - if connection_info.start_at_task is not None: + if play_context.start_at_task is not None: while True: (s, task) = self.get_next_task_for_host(host, peek=True) if s.run_state == self.ITERATING_COMPLETE: break - if task.get_name() != connection_info.start_at_task: + if task.get_name() != play_context.start_at_task: self.get_next_task_for_host(host) else: break diff --git a/lib/ansible/executor/process/worker.py b/lib/ansible/executor/process/worker.py index e1488ebcb1..4b2bd13b9c 100644 --- a/lib/ansible/executor/process/worker.py +++ b/lib/ansible/executor/process/worker.py @@ -94,7 +94,7 @@ class WorkerProcess(multiprocessing.Process): try: if not self._main_q.empty(): debug("there's work to be done!") - (host, task, basedir, job_vars, connection_info, shared_loader_obj) = self._main_q.get(block=False) + (host, task, basedir, job_vars, play_context, shared_loader_obj) = self._main_q.get(block=False) debug("got a task/handler to work on: %s" % task) # because the task queue manager starts workers (forks) before the @@ -111,11 +111,11 @@ class WorkerProcess(multiprocessing.Process): # apply the given task's information to the connection info, # which may override some fields already set by the play or # the options specified on the command line - new_connection_info = connection_info.set_task_and_host_override(task=task, host=host) + new_play_context = play_context.set_task_and_host_override(task=task, host=host) # execute the task and build a TaskResult from the result debug("running TaskExecutor() for %s/%s" % (host, task)) - executor_result = TaskExecutor(host, task, job_vars, new_connection_info, self._new_stdin, self._loader, shared_loader_obj).run() + executor_result = TaskExecutor(host, task, job_vars, new_play_context, self._new_stdin, self._loader, shared_loader_obj).run() debug("done running TaskExecutor() for %s/%s" % (host, task)) task_result = TaskResult(host, task, executor_result) diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py index 8393b61459..75f3d34a5c 100644 --- a/lib/ansible/executor/task_executor.py +++ b/lib/ansible/executor/task_executor.py @@ -27,7 +27,6 @@ import time from ansible import constants as C from ansible.errors import AnsibleError, AnsibleParserError -from ansible.executor.connection_info import ConnectionInformation from ansible.playbook.conditional import Conditional from ansible.playbook.task import Task from ansible.plugins import lookup_loader, connection_loader, action_loader @@ -52,11 +51,11 @@ class TaskExecutor: # the module SQUASH_ACTIONS = frozenset(('apt', 'yum', 'pkgng', 'zypper', 'dnf')) - def __init__(self, host, task, job_vars, connection_info, new_stdin, loader, shared_loader_obj): + def __init__(self, host, task, job_vars, play_context, new_stdin, loader, shared_loader_obj): self._host = host self._task = task self._job_vars = job_vars - self._connection_info = connection_info + self._play_context = play_context self._new_stdin = new_stdin self._loader = loader self._shared_loader_obj = shared_loader_obj @@ -208,11 +207,11 @@ class TaskExecutor: # fields set from the play/task may be based on variables, so we have to # do the same kind of post validation step on it here before we use it. - self._connection_info.post_validate(templar=templar) + self._play_context.post_validate(templar=templar) - # now that the connection information is finalized, we can add 'magic' + # now that the play context is finalized, we can add 'magic' # variables to the variable dictionary - self._connection_info.update_vars(variables) + self._play_context.update_vars(variables) # Evaluate the conditional (if any) for this task, which we do before running # the final task post-validation. We do this before the post validation due to @@ -362,7 +361,7 @@ class TaskExecutor: 'normal', task=async_task, connection=self._connection, - connection_info=self._connection_info, + play_context=self._play_context, loader=self._loader, templar=templar, shared_loader_obj=self._shared_loader_obj, @@ -392,16 +391,16 @@ class TaskExecutor: # FIXME: delegate_to calculation should be done here # FIXME: calculation of connection params/auth stuff should be done here - if not self._connection_info.remote_addr: - self._connection_info.remote_addr = self._host.ipv4_address + if not self._play_context.remote_addr: + self._play_context.remote_addr = self._host.ipv4_address if self._task.delegate_to is not None: self._compute_delegate(variables) - conn_type = self._connection_info.connection + conn_type = self._play_context.connection if conn_type == 'smart': conn_type = 'ssh' - if sys.platform.startswith('darwin') and self._connection_info.password: + if sys.platform.startswith('darwin') and self._play_context.password: # due to a current bug in sshpass on OSX, which can trigger # a kernel panic even for non-privileged users, we revert to # paramiko on that OS when a SSH password is specified @@ -413,7 +412,7 @@ class TaskExecutor: if "Bad configuration option" in err: conn_type = "paramiko" - connection = connection_loader.get(conn_type, self._connection_info, self._new_stdin) + connection = connection_loader.get(conn_type, self._play_context, self._new_stdin) if not connection: raise AnsibleError("the connection plugin '%s' was not found" % conn_type) @@ -437,7 +436,7 @@ class TaskExecutor: handler_name, task=self._task, connection=connection, - connection_info=self._connection_info, + play_context=self._play_context, loader=self._loader, templar=templar, shared_loader_obj=self._shared_loader_obj, @@ -458,16 +457,16 @@ class TaskExecutor: this_info = {} # get the real ssh_address for the delegate and allow ansible_ssh_host to be templated - #self._connection_info.remote_user = self._compute_delegate_user(self.delegate_to, delegate['inject']) - self._connection_info.remote_addr = this_info.get('ansible_ssh_host', self._task.delegate_to) - self._connection_info.port = this_info.get('ansible_ssh_port', self._connection_info.port) - self._connection_info.password = this_info.get('ansible_ssh_pass', self._connection_info.password) - self._connection_info.private_key_file = this_info.get('ansible_ssh_private_key_file', self._connection_info.private_key_file) - self._connection_info.connection = this_info.get('ansible_connection', C.DEFAULT_TRANSPORT) - self._connection_info.become_pass = this_info.get('ansible_sudo_pass', self._connection_info.become_pass) + #self._play_context.remote_user = self._compute_delegate_user(self.delegate_to, delegate['inject']) + self._play_context.remote_addr = this_info.get('ansible_ssh_host', self._task.delegate_to) + self._play_context.port = this_info.get('ansible_ssh_port', self._play_context.port) + self._play_context.password = this_info.get('ansible_ssh_pass', self._play_context.password) + self._play_context.private_key_file = this_info.get('ansible_ssh_private_key_file', self._play_context.private_key_file) + self._play_context.connection = this_info.get('ansible_connection', C.DEFAULT_TRANSPORT) + self._play_context.become_pass = this_info.get('ansible_sudo_pass', self._play_context.become_pass) - if self._connection_info.remote_addr in ('127.0.0.1', 'localhost'): - self._connection_info.connection = 'local' + if self._play_context.remote_addr in ('127.0.0.1', 'localhost'): + self._play_context.connection = 'local' # Last chance to get private_key_file from global variables. # this is useful if delegated host is not defined in the inventory diff --git a/lib/ansible/executor/task_queue_manager.py b/lib/ansible/executor/task_queue_manager.py index bb9d19d12f..ad112eff37 100644 --- a/lib/ansible/executor/task_queue_manager.py +++ b/lib/ansible/executor/task_queue_manager.py @@ -27,11 +27,11 @@ import sys from ansible import constants as C from ansible.errors import AnsibleError -from ansible.executor.connection_info import ConnectionInformation from ansible.executor.play_iterator import PlayIterator from ansible.executor.process.worker import WorkerProcess from ansible.executor.process.result import ResultProcess from ansible.executor.stats import AggregateStats +from ansible.playbook.play_context import PlayContext from ansible.plugins import callback_loader, strategy_loader from ansible.template import Templar @@ -236,10 +236,10 @@ class TaskQueueManager: new_play = play.copy() new_play.post_validate(templar) - connection_info = ConnectionInformation(new_play, self._options, self.passwords) + play_context = PlayContext(new_play, self._options, self.passwords) for callback_plugin in self._callback_plugins: - if hasattr(callback_plugin, 'set_connection_info'): - callback_plugin.set_connection_info(connection_info) + if hasattr(callback_plugin, 'set_play_context'): + callback_plugin.set_play_context(play_context) self.send_callback('v2_playbook_on_play_start', new_play) @@ -252,10 +252,10 @@ class TaskQueueManager: raise AnsibleError("Invalid play strategy specified: %s" % new_play.strategy, obj=play._ds) # build the iterator - iterator = PlayIterator(inventory=self._inventory, play=new_play, connection_info=connection_info, all_vars=all_vars) + iterator = PlayIterator(inventory=self._inventory, play=new_play, play_context=play_context, all_vars=all_vars) # and run the play using the strategy - return strategy.run(iterator, connection_info) + return strategy.run(iterator, play_context) def cleanup(self): debug("RUNNING CLEANUP") diff --git a/lib/ansible/playbook/base.py b/lib/ansible/playbook/base.py index d4da3dc004..3cc9c34238 100644 --- a/lib/ansible/playbook/base.py +++ b/lib/ansible/playbook/base.py @@ -295,6 +295,11 @@ class Base: for item in value: if not isinstance(item, attribute.listof): raise AnsibleParserError("the field '%s' should be a list of %s, but the item '%s' is a %s" % (name, attribute.listof, item, type(item)), obj=self.get_ds()) + elif attribute.isa == 'set': + if not isinstance(value, (list, set)): + value = [ value ] + if not isinstance(value, set): + value = set(value) elif attribute.isa == 'dict' and not isinstance(value, dict): raise TypeError("%s is not a dictionary" % value) diff --git a/lib/ansible/playbook/block.py b/lib/ansible/playbook/block.py index c20286c8d9..9b5d8805a3 100644 --- a/lib/ansible/playbook/block.py +++ b/lib/ansible/playbook/block.py @@ -301,16 +301,16 @@ class Block(Base, Become, Conditional, Taggable): return value - def filter_tagged_tasks(self, connection_info, all_vars): + def filter_tagged_tasks(self, play_context, all_vars): ''' Creates a new block, with task lists filtered based on the tags contained - within the connection_info object. + within the play_context object. ''' def evaluate_and_append_task(target): tmp_list = [] for task in target: - if task.evaluate_tags(connection_info.only_tags, connection_info.skip_tags, all_vars=all_vars): + if task.evaluate_tags(play_context.only_tags, play_context.skip_tags, all_vars=all_vars): tmp_list.append(task) return tmp_list diff --git a/lib/ansible/executor/connection_info.py b/lib/ansible/playbook/play_context.py similarity index 79% rename from lib/ansible/executor/connection_info.py rename to lib/ansible/playbook/play_context.py index 6c2676c301..5056130c39 100644 --- a/lib/ansible/executor/connection_info.py +++ b/lib/ansible/playbook/play_context.py @@ -26,11 +26,13 @@ import random import re from ansible import constants as C +from ansible.errors import AnsibleError +from ansible.playbook.attribute import Attribute, FieldAttribute +from ansible.playbook.base import Base from ansible.template import Templar from ansible.utils.boolean import boolean -from ansible.errors import AnsibleError -__all__ = ['ConnectionInformation'] +__all__ = ['PlayContext'] SU_PROMPT_LOCALIZATIONS = [ 'Password', @@ -67,7 +69,7 @@ SU_PROMPT_LOCALIZATIONS = [ ] # the magic variable mapping dictionary below is used to translate -# host/inventory variables to fields in the ConnectionInformation +# host/inventory variables to fields in the PlayContext # object. The dictionary values are tuples, to account for aliases # in variable names. @@ -131,7 +133,7 @@ SU_PROMPT_LOCALIZATIONS = [ '密碼', ] -class ConnectionInformation: +class PlayContext(Base): ''' This class is used to consolidate the connection information for @@ -139,48 +141,49 @@ class ConnectionInformation: connection/authentication information. ''' + # connection fields, some are inherited from Base: + # (connection, port, remote_user, environment, no_log) + _remote_addr = FieldAttribute(isa='string') + _password = FieldAttribute(isa='string') + _private_key_file = FieldAttribute(isa='string', default=C.DEFAULT_PRIVATE_KEY_FILE) + _timeout = FieldAttribute(isa='int', default=C.DEFAULT_TIMEOUT) + _shell = FieldAttribute(isa='string') + + # privilege escalation fields + _become = FieldAttribute(isa='bool') + _become_method = FieldAttribute(isa='string') + _become_user = FieldAttribute(isa='string') + _become_pass = FieldAttribute(isa='string') + _become_exe = FieldAttribute(isa='string') + _become_flags = FieldAttribute(isa='string') + _prompt = FieldAttribute(isa='string') + + # backwards compatibility fields for sudo/su + _sudo_exe = FieldAttribute(isa='string') + _sudo_flags = FieldAttribute(isa='string') + _sudo_pass = FieldAttribute(isa='string') + _su_exe = FieldAttribute(isa='string') + _su_flags = FieldAttribute(isa='string') + _su_pass = FieldAttribute(isa='string') + + # general flags + _verbosity = FieldAttribute(isa='int', default=0) + _only_tags = FieldAttribute(isa='set', default=set()) + _skip_tags = FieldAttribute(isa='set', default=set()) + _check_mode = FieldAttribute(isa='bool', default=False) + _force_handlers = FieldAttribute(isa='bool', default=False) + _start_at_task = FieldAttribute(isa='string') + _step = FieldAttribute(isa='bool', default=False) + def __init__(self, play=None, options=None, passwords=None): + super(PlayContext, self).__init__() + if passwords is None: passwords = {} - # connection - self.connection = None - self.remote_addr = None - self.remote_user = None - self.password = passwords.get('conn_pass','') - self.port = None - self.private_key_file = C.DEFAULT_PRIVATE_KEY_FILE - self.timeout = C.DEFAULT_TIMEOUT - self.shell = None - - # privilege escalation - self.become = None - self.become_method = None - self.become_user = None - self.become_pass = passwords.get('become_pass','') - self.become_exe = None - self.become_flags = None - self.prompt = None - self.success_key = None - - # backwards compat - self.sudo_exe = None - self.sudo_flags = None - self.sudo_pass = None - self.su_exe = None - self.su_flags = None - self.su_pass = None - - # general flags (should we move out?) - self.verbosity = 0 - self.only_tags = set() - self.skip_tags = set() - self.no_log = False - self.check_mode = False - self.force_handlers = False - self.start_at_task = None - self.step = False + self.password = passwords.get('conn_pass','') + self.become_pass = passwords.get('become_pass','') #TODO: just pull options setup to above? # set options before play to allow play to override them @@ -213,8 +216,9 @@ class ConnectionInformation: self.become_user = play.become_user # non connection related - self.no_log = play.no_log - self.environment = play.environment + self.no_log = play.no_log + self.environment = play.environment + if play.force_handlers is not None: self.force_handlers = play.force_handlers @@ -268,22 +272,22 @@ class ConnectionInformation: elif isinstance(options.skip_tags, basestring): self.skip_tags.update(options.skip_tags.split(',')) - def copy(self, ci): - ''' - Copies the connection info from another connection info object, used - when merging in data from task overrides. - ''' - - for field in self._get_fields(): - value = getattr(ci, field, None) - if isinstance(value, dict): - setattr(self, field, value.copy()) - elif isinstance(value, set): - setattr(self, field, value.copy()) - elif isinstance(value, list): - setattr(self, field, value[:]) - else: - setattr(self, field, value) + #def copy(self, ci): + # ''' + # Copies the connection info from another connection info object, used + # when merging in data from task overrides. + # ''' + # + # for field in self._get_fields(): + # value = getattr(ci, field, None) + # if isinstance(value, dict): + # setattr(self, field, value.copy()) + # elif isinstance(value, set): + # setattr(self, field, value.copy()) + # elif isinstance(value, list): + # setattr(self, field, value[:]) + # else: + # setattr(self, field, value) def set_task_and_host_override(self, task, host): ''' @@ -291,8 +295,7 @@ class ConnectionInformation: those from the play. ''' - new_info = ConnectionInformation() - new_info.copy(self) + new_info = self.copy() # loop through a subset of attributes on the task object and set # connection fields based on their values @@ -382,17 +385,17 @@ class ConnectionInformation: return cmd - def _get_fields(self): - return [i for i in self.__dict__.keys() if i[:1] != '_'] + #def _get_fields(self): + # return [i for i in self.__dict__.keys() if i[:1] != '_'] - def post_validate(self, templar): - ''' - Finalizes templated values which may be set on this objects fields. - ''' - - for field in self._get_fields(): - value = templar.template(getattr(self, field)) - setattr(self, field, value) + #def post_validate(self, templar): + # ''' + # Finalizes templated values which may be set on this objects fields. + # ''' + # + # for field in self._get_fields(): + # value = templar.template(getattr(self, field)) + # setattr(self, field, value) def update_vars(self, variables): ''' diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py index 012cd4695a..b5ed98befb 100644 --- a/lib/ansible/playbook/task.py +++ b/lib/ansible/playbook/task.py @@ -34,6 +34,7 @@ from ansible.playbook.block import Block from ansible.playbook.conditional import Conditional from ansible.playbook.role import Role from ansible.playbook.taggable import Taggable +from ansible.utils.vars import combine_vars __all__ = ['Task'] @@ -292,22 +293,38 @@ class Task(Base, Conditional, Taggable, Become): if self._task_include: self._task_include.set_loader(loader) - def _get_parent_attribute(self, attr, extend=False): + def _get_parent_attribute(self, attr, extend=False, combine=False): ''' Generic logic to get the attribute or parent attribute for a task value. ''' value = self._attributes[attr] - if self._block and (value is None or extend): + if self._block and (value is None or extend or combine): parent_value = getattr(self._block, attr) if extend: value = self._extend_value(value, parent_value) + elif combine and isinstance(parent_value, dict) and isinstance(value, dict): + value = combine_vars(parent_value, value) else: value = parent_value - if self._task_include and (value is None or extend): + if self._task_include and (value is None or extend or combine): parent_value = getattr(self._task_include, attr) if extend: value = self._extend_value(value, parent_value) + elif combine: + value = combine_vars(parent_value, value) else: value = parent_value return value + def _get_attr_environment(self): + ''' + Override for the 'tags' getattr fetcher, used from Base. + ''' + environment = self._attributes['tags'] + if environment is None: + environment = dict() + + environment = self._get_parent_attribute('environment', combine=True) + + return environment + diff --git a/lib/ansible/plugins/action/__init__.py b/lib/ansible/plugins/action/__init__.py index e47d9e7b6a..4e19aeb48f 100644 --- a/lib/ansible/plugins/action/__init__.py +++ b/lib/ansible/plugins/action/__init__.py @@ -31,7 +31,6 @@ from ansible import constants as C from ansible.errors import AnsibleError from ansible.executor.module_common import modify_module from ansible.parsing.utils.jsonify import jsonify - from ansible.utils.debug import debug from ansible.utils.unicode import to_bytes @@ -44,10 +43,10 @@ class ActionBase: action in use. ''' - def __init__(self, task, connection, connection_info, loader, templar, shared_loader_obj): + def __init__(self, task, connection, play_context, loader, templar, shared_loader_obj): self._task = task self._connection = connection - self._connection_info = connection_info + self._play_context = play_context self._loader = loader self._templar = templar self._shared_loader_obj = shared_loader_obj @@ -82,16 +81,11 @@ class ActionBase: Builds the environment string to be used when executing the remote task. ''' - enviro = {} + if self._task.environment: + if type(self._task.environment) != dict: + raise errors.AnsibleError("environment must be a dictionary, received %s" % self._task.environment) - # FIXME: not sure where this comes from, probably task but maybe also the play? - #if self.environment: - # enviro = template.template(self.basedir, self.environment, inject, convert_bare=True) - # enviro = utils.safe_eval(enviro) - # if type(enviro) != dict: - # raise errors.AnsibleError("environment must be a dictionary, received %s" % enviro) - - return self._connection._shell.env_prefix(**enviro) + return self._connection._shell.env_prefix(**self._task.environment) def _early_needs_tmp_path(self): ''' @@ -109,7 +103,7 @@ class ActionBase: if tmp and "tmp" in tmp: # tmp has already been created return False - if not self._connection.__class__.has_pipelining or not C.ANSIBLE_SSH_PIPELINING or C.DEFAULT_KEEP_REMOTE_FILES or self._connection_info.become: + if not self._connection.__class__.has_pipelining or not C.ANSIBLE_SSH_PIPELINING or C.DEFAULT_KEEP_REMOTE_FILES or self._play_context.become: # tmp is necessary to store module source code return True if not self._connection.__class__.has_pipelining: @@ -131,11 +125,11 @@ class ActionBase: basefile = 'ansible-tmp-%s-%s' % (time.time(), random.randint(0, 2**48)) use_system_tmp = False - if self._connection_info.become and self._connection_info.become_user != 'root': + if self._play_context.become and self._play_context.become_user != 'root': use_system_tmp = True tmp_mode = None - if self._connection_info.remote_user != 'root' or self._connection_info.become and self._connection_info.become_user != 'root': + if self._play_context.remote_user != 'root' or self._play_context.become and self._play_context.become_user != 'root': tmp_mode = 'a+rx' cmd = self._connection._shell.mkdtemp(basefile, use_system_tmp, tmp_mode) @@ -149,7 +143,7 @@ class ActionBase: output = 'Authentication failure.' elif result['rc'] == 255 and self._connection.transport in ('ssh',): - if self._connection_info.verbosity > 3: + if self._play_context.verbosity > 3: output = 'SSH encountered an unknown error. The output was:\n%s' % (result['stdout']+result['stderr']) else: output = 'SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue' @@ -264,8 +258,8 @@ class ActionBase: split_path = path.split(os.path.sep, 1) expand_path = split_path[0] if expand_path == '~': - if self._connection_info.become and self._connection_info.become_user: - expand_path = '~%s' % self._connection_info.become_user + if self._play_context.become and self._play_context.become_user: + expand_path = '~%s' % self._play_context.become_user cmd = self._connection._shell.expand_user(expand_path) debug("calling _low_level_execute_command to expand the remote user path") @@ -314,13 +308,13 @@ class ActionBase: module_args = self._task.args # set check mode in the module arguments, if required - if self._connection_info.check_mode and not self._task.always_run: + if self._play_context.check_mode and not self._task.always_run: if not self._supports_check_mode: raise AnsibleError("check mode is not supported for this operation") module_args['_ansible_check_mode'] = True # set no log in the module arguments, if required - if self._connection_info.no_log: + if self._play_context.no_log: module_args['_ansible_no_log'] = True debug("in _execute_module (%s, %s)" % (module_name, module_args)) @@ -344,7 +338,7 @@ class ActionBase: environment_string = self._compute_environment_string() - if tmp and "tmp" in tmp and self._connection_info.become and self._connection_info.become_user != 'root': + if tmp and "tmp" in tmp and self._play_context.become and self._play_context.become_user != 'root': # deal with possible umask issues once sudo'ed to other user self._remote_chmod(tmp, 'a+r', remote_module_path) @@ -362,7 +356,7 @@ class ActionBase: rm_tmp = None if tmp and "tmp" in tmp and not C.DEFAULT_KEEP_REMOTE_FILES and not persist_files and delete_remote_tmp: - if not self._connection_info.become or self._connection_info.become_user == 'root': + if not self._play_context.become or self._play_context.become_user == 'root': # not sudoing or sudoing to root, so can cleanup files in the same step rm_tmp = tmp @@ -380,7 +374,7 @@ class ActionBase: debug("_low_level_execute_command returned ok") if tmp and "tmp" in tmp and not C.DEFAULT_KEEP_REMOTE_FILES and not persist_files and delete_remote_tmp: - if self._connection_info.become and self._connection_info.become_user != 'root': + if self._play_context.become and self._play_context.become_user != 'root': # not sudoing to root, so maybe can't delete files as that other user # have to clean up temp files as original user in a second step cmd2 = self._connection._shell.remove(tmp, recurse=True) @@ -430,7 +424,7 @@ class ActionBase: return dict(stdout='', stderr='') if sudoable: - cmd = self._connection_info.make_become_cmd(cmd, executable=executable) + cmd = self._play_context.make_become_cmd(cmd, executable=executable) debug("executing the command %s through the connection" % cmd) rc, stdin, stdout, stderr = self._connection.exec_command(cmd, tmp, in_data=in_data, sudoable=sudoable) diff --git a/lib/ansible/plugins/action/add_host.py b/lib/ansible/plugins/action/add_host.py index d7019d0f00..12c9febe95 100644 --- a/lib/ansible/plugins/action/add_host.py +++ b/lib/ansible/plugins/action/add_host.py @@ -31,7 +31,7 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=dict()): - if self._connection_info.check_mode: + if self._play_context.check_mode: return dict(skipped=True, msg='check mode not supported for this module') # Parse out any hostname:port patterns diff --git a/lib/ansible/plugins/action/assemble.py b/lib/ansible/plugins/action/assemble.py index f4d8fe8861..454e28aa34 100644 --- a/lib/ansible/plugins/action/assemble.py +++ b/lib/ansible/plugins/action/assemble.py @@ -77,7 +77,7 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=dict()): - if self._connection_info.check_mode: + if self._play_context.check_mode: return dict(skipped=True, msg=("skipped, this module does not support check_mode.")) src = self._task.args.get('src', None) @@ -124,7 +124,7 @@ class ActionModule(ActionBase): xfered = self._transfer_data('src', resultant) # fix file permissions when the copy is done as a different user - if self._connection_info.become and self._connection_info.become_user != 'root': + if self._play_context.become and self._play_context.become_user != 'root': self._remote_chmod('a+r', xfered, tmp) # run the copy module diff --git a/lib/ansible/plugins/action/async.py b/lib/ansible/plugins/action/async.py index d7b164935a..b2fcd8756d 100644 --- a/lib/ansible/plugins/action/async.py +++ b/lib/ansible/plugins/action/async.py @@ -28,7 +28,7 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=dict()): ''' transfer the given module name, plus the async module, then run it ''' - if self._connection_info.check_mode: + if self._play_context.check_mode: return dict(skipped=True, msg='check mode not supported for this module') if not tmp: diff --git a/lib/ansible/plugins/action/copy.py b/lib/ansible/plugins/action/copy.py index b979810150..0bf19f5069 100644 --- a/lib/ansible/plugins/action/copy.py +++ b/lib/ansible/plugins/action/copy.py @@ -179,7 +179,7 @@ class ActionModule(ActionBase): # diff = {} diff = {} - if self._connection_info.check_mode: + if self._play_context.check_mode: self._remove_tempfile_if_content_defined(content, content_tempfile) # FIXME: diff stuff #diffs.append(diff) @@ -199,7 +199,7 @@ class ActionModule(ActionBase): self._remove_tempfile_if_content_defined(content, content_tempfile) # fix file permissions when the copy is done as a different user - if self._connection_info.become and self._connection_info.become_user != 'root': + if self._play_context.become and self._play_context.become_user != 'root': self._remote_chmod('a+r', tmp_src, tmp) if raw: diff --git a/lib/ansible/plugins/action/fetch.py b/lib/ansible/plugins/action/fetch.py index a00ad154cc..a239e252ac 100644 --- a/lib/ansible/plugins/action/fetch.py +++ b/lib/ansible/plugins/action/fetch.py @@ -36,7 +36,7 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=dict()): ''' handler for fetch operations ''' - if self._connection_info.check_mode: + if self._play_context.check_mode: return dict(skipped=True, msg='check mode not (yet) supported for this module') source = self._task.args.get('src', None) @@ -59,7 +59,7 @@ class ActionModule(ActionBase): # use slurp if sudo and permissions are lacking remote_data = None - if remote_checksum in ('1', '2') or self._connection_info.become: + if remote_checksum in ('1', '2') or self._play_context.become: slurpres = self._execute_module(module_name='slurp', module_args=dict(src=source), task_vars=task_vars, tmp=tmp) if slurpres.get('rc') == 0: if slurpres['encoding'] == 'base64': @@ -97,7 +97,7 @@ class ActionModule(ActionBase): if 'inventory_hostname' in task_vars: target_name = task_vars['inventory_hostname'] else: - target_name = self._connection_info.remote_addr + target_name = self._play_context.remote_addr dest = "%s/%s/%s" % (self._loader.path_dwim(dest), target_name, source_local) dest = dest.replace("//","/") diff --git a/lib/ansible/plugins/action/patch.py b/lib/ansible/plugins/action/patch.py index e50b647bcb..65417e50c3 100644 --- a/lib/ansible/plugins/action/patch.py +++ b/lib/ansible/plugins/action/patch.py @@ -50,8 +50,8 @@ class ActionModule(ActionBase): tmp_src = self._connection._shell.join_path(tmp, os.path.basename(src)) self._connection.put_file(src, tmp_src) - if self._connection_info.become and self._connection_info.become_user != 'root': - if not self._connection_info.check_mode: + if self._play_context.become and self._play_context.become_user != 'root': + if not self._play_context.check_mode: self._remote_chmod('a+r', tmp_src, tmp) new_module_args = self._task.args.copy() diff --git a/lib/ansible/plugins/action/raw.py b/lib/ansible/plugins/action/raw.py index d59be1c890..4d862d9ebb 100644 --- a/lib/ansible/plugins/action/raw.py +++ b/lib/ansible/plugins/action/raw.py @@ -26,7 +26,7 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=dict()): - if self._connection_info.check_mode: + if self._play_context.check_mode: # in --check mode, always skip this module execution return dict(skipped=True) diff --git a/lib/ansible/plugins/action/script.py b/lib/ansible/plugins/action/script.py index c377aa62fe..2392851110 100644 --- a/lib/ansible/plugins/action/script.py +++ b/lib/ansible/plugins/action/script.py @@ -28,7 +28,7 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=None): ''' handler for file transfer operations ''' - if self._connection_info.check_mode: + if self._play_context.check_mode: return dict(skipped=True, msg='check mode not supported for this module') if not tmp: @@ -73,7 +73,7 @@ class ActionModule(ActionBase): sudoable = True # set file permissions, more permissive when the copy is done as a different user - if self._connection_info.become and self._connection_info.become_user != 'root': + if self._play_context.become and self._play_context.become_user != 'root': chmod_mode = 'a+rx' sudoable = False else: diff --git a/lib/ansible/plugins/action/synchronize.py b/lib/ansible/plugins/action/synchronize.py index aa0a810a2a..1da3db50ab 100644 --- a/lib/ansible/plugins/action/synchronize.py +++ b/lib/ansible/plugins/action/synchronize.py @@ -52,7 +52,7 @@ class ActionModule(ActionBase): return path def _process_remote(self, host, path, user): - transport = self._connection_info.connection + transport = self._play_context.connection return_data = None if not host in ['127.0.0.1', 'localhost'] or transport != "local": if user: @@ -71,7 +71,7 @@ class ActionModule(ActionBase): def run(self, tmp=None, task_vars=dict()): ''' generates params and passes them on to the rsync module ''' - original_transport = task_vars.get('ansible_connection') or self._connection_info.connection + original_transport = task_vars.get('ansible_connection') or self._play_context.connection transport_overridden = False if task_vars.get('delegate_to') is None: task_vars['delegate_to'] = '127.0.0.1' @@ -79,7 +79,7 @@ class ActionModule(ActionBase): if original_transport != 'local': task_vars['ansible_connection'] = 'local' transport_overridden = True - self._connection_info.become = False + self._play_context.become = False src = self._task.args.get('src', None) dest = self._task.args.get('dest', None) @@ -130,13 +130,13 @@ class ActionModule(ActionBase): user = task_vars['hostvars'][conn.delegate].get('ansible_ssh_user') if not use_delegate or not user: - user = task_vars.get('ansible_ssh_user') or self._connection_info.remote_user + user = task_vars.get('ansible_ssh_user') or self._play_context.remote_user if use_delegate: # FIXME - private_key = task_vars.get('ansible_ssh_private_key_file') or self._connection_info.private_key_file + private_key = task_vars.get('ansible_ssh_private_key_file') or self._play_context.private_key_file else: - private_key = task_vars.get('ansible_ssh_private_key_file') or self._connection_info.private_key_file + private_key = task_vars.get('ansible_ssh_private_key_file') or self._play_context.private_key_file if private_key is not None: private_key = os.path.expanduser(private_key) @@ -159,7 +159,7 @@ class ActionModule(ActionBase): rsync_path = self._task.args.get('rsync_path', None) # If no rsync_path is set, sudo was originally set, and dest is remote then add 'sudo rsync' argument. - if not rsync_path and transport_overridden and self._connection_info.become and self._connection_info.become_method == 'sudo' and not dest_is_local: + if not rsync_path and transport_overridden and self._play_context.become and self._play_context.become_method == 'sudo' and not dest_is_local: rsync_path = 'sudo rsync' # make sure rsync path is quoted. diff --git a/lib/ansible/plugins/action/template.py b/lib/ansible/plugins/action/template.py index a3ee74e5d1..47cdc39884 100644 --- a/lib/ansible/plugins/action/template.py +++ b/lib/ansible/plugins/action/template.py @@ -142,7 +142,7 @@ class ActionModule(ActionBase): xfered = self._transfer_data(self._connection._shell.join_path(tmp, 'source'), resultant) # fix file permissions when the copy is done as a different user - if self._connection_info.become and self._connection_info.become_user != 'root': + if self._play_context.become and self._play_context.become_user != 'root': self._remote_chmod('a+r', xfered, tmp) # run the copy module diff --git a/lib/ansible/plugins/action/unarchive.py b/lib/ansible/plugins/action/unarchive.py index fca31e6b93..6a43259763 100644 --- a/lib/ansible/plugins/action/unarchive.py +++ b/lib/ansible/plugins/action/unarchive.py @@ -78,8 +78,8 @@ class ActionModule(ActionBase): # handle check mode client side # fix file permissions when the copy is done as a different user if copy: - if self._connection_info.become and self._connection_info.become_user != 'root': - if not self._connection_info.check_mode: + if self._play_context.become and self._play_context.become_user != 'root': + if not self._play_context.check_mode: self._remote_chmod(tmp, 'a+r', tmp_src) # Build temporary module_args. diff --git a/lib/ansible/plugins/callback/__init__.py b/lib/ansible/plugins/callback/__init__.py index de5a92837f..273f74e9b7 100644 --- a/lib/ansible/plugins/callback/__init__.py +++ b/lib/ansible/plugins/callback/__init__.py @@ -54,7 +54,7 @@ class CallbackBase: for warning in res['warnings']: self._display.warning(warning) - def set_connection_info(self, conn_info): + def set_play_context(self, play_context): pass def on_any(self, *args, **kwargs): diff --git a/lib/ansible/plugins/connections/__init__.py b/lib/ansible/plugins/connections/__init__.py index 1a74837e94..c53ad0dec2 100644 --- a/lib/ansible/plugins/connections/__init__.py +++ b/lib/ansible/plugins/connections/__init__.py @@ -58,14 +58,14 @@ class ConnectionBase(with_metaclass(ABCMeta, object)): has_pipelining = False become_methods = C.BECOME_METHODS - def __init__(self, connection_info, new_stdin, *args, **kwargs): + def __init__(self, play_context, new_stdin, *args, **kwargs): # All these hasattrs allow subclasses to override these parameters - if not hasattr(self, '_connection_info'): - self._connection_info = connection_info + if not hasattr(self, '_play_context'): + self._play_context = play_context if not hasattr(self, '_new_stdin'): self._new_stdin = new_stdin if not hasattr(self, '_display'): - self._display = Display(verbosity=connection_info.verbosity) + self._display = Display(verbosity=play_context.verbosity) if not hasattr(self, '_connected'): self._connected = False @@ -73,8 +73,8 @@ class ConnectionBase(with_metaclass(ABCMeta, object)): self.prompt = None # load the shell plugin for this action/connection - if connection_info.shell: - shell_type = connection_info.shell + if play_context.shell: + shell_type = play_context.shell elif hasattr(self, '_shell_type'): shell_type = getattr(self, '_shell_type') else: @@ -87,7 +87,7 @@ class ConnectionBase(with_metaclass(ABCMeta, object)): def _become_method_supported(self): ''' Checks if the current class supports this privilege escalation method ''' - if self._connection_info.become_method in self.__class__.become_methods: + if self._play_context.become_method in self.__class__.become_methods: return True raise AnsibleError("Internal Error: this connection module does not support running commands via %s" % become_method) @@ -113,7 +113,7 @@ class ConnectionBase(with_metaclass(ABCMeta, object)): """Connect to the host we've been initialized with""" # Check if PE is supported - if self._connection_info.become: + if self._play_context.become: self.__become_method_supported() @ensure_connect @@ -140,18 +140,18 @@ class ConnectionBase(with_metaclass(ABCMeta, object)): pass def check_become_success(self, output): - return self._connection_info.success_key in output + return self._play_context.success_key in output def check_password_prompt(self, output): - if self._connection_info.prompt is None: + if self._play_context.prompt is None: return False - elif isinstance(self._connection_info.prompt, basestring): - return output.endswith(self._connection_info.prompt) + elif isinstance(self._play_context.prompt, basestring): + return output.endswith(self._play_context.prompt) else: - return self._connection_info.prompt(output) + return self._play_context.prompt(output) def check_incorrect_password(self, output): - incorrect_password = gettext.dgettext(self._connection_info.become_method, C.BECOME_ERROR_STRINGS[self._connection_info.become_method]) + incorrect_password = gettext.dgettext(self._play_context.become_method, C.BECOME_ERROR_STRINGS[self._play_context.become_method]) if incorrect_password in output: - raise AnsibleError('Incorrect %s password' % self._connection_info.become_method) + raise AnsibleError('Incorrect %s password' % self._play_context.become_method) diff --git a/lib/ansible/plugins/connections/local.py b/lib/ansible/plugins/connections/local.py index 0c39e69866..d77d9484a9 100644 --- a/lib/ansible/plugins/connections/local.py +++ b/lib/ansible/plugins/connections/local.py @@ -44,7 +44,7 @@ class Connection(ConnectionBase): ''' connect to the local host; nothing to do here ''' if not self._connected: - self._display.vvv("ESTABLISH LOCAL CONNECTION FOR USER: {0}".format(self._connection_info.remote_user, host=self._connection_info.remote_addr)) + self._display.vvv("ESTABLISH LOCAL CONNECTION FOR USER: {0}".format(self._play_context.remote_user, host=self._play_context.remote_addr)) self._connected = True return self @@ -59,7 +59,7 @@ class Connection(ConnectionBase): raise AnsibleError("Internal Error: this module does not support optimized module pipelining") executable = C.DEFAULT_EXECUTABLE.split()[0] if C.DEFAULT_EXECUTABLE else None - self._display.vvv("{0} EXEC {1}".format(self._connection_info.remote_addr, cmd)) + self._display.vvv("{0} EXEC {1}".format(self._play_context.remote_addr, cmd)) # FIXME: cwd= needs to be set to the basedir of the playbook debug("opening command with Popen()") p = subprocess.Popen( @@ -72,13 +72,13 @@ class Connection(ConnectionBase): ) debug("done running command with Popen()") - if self._connection_info.prompt and self._connection_info.become_pass: + if self._play_context.prompt and self._play_context.become_pass: fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK) become_output = '' while not self.check_become_success(become_output) and not self.check_password_prompt(become_output): - rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout, p.stderr], self._connection_info.timeout) + rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout, p.stderr], self._play_context.timeout) if p.stdout in rfd: chunk = p.stdout.read() elif p.stderr in rfd: @@ -91,7 +91,7 @@ class Connection(ConnectionBase): raise AnsibleError('privilege output closed while waiting for password prompt:\n' + become_output) become_output += chunk if not self.check_become_success(become_output): - p.stdin.write(self._connection_info.become_pass + '\n') + p.stdin.write(self._play_context.become_pass + '\n') fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK) @@ -107,7 +107,7 @@ class Connection(ConnectionBase): super(Connection, self).put_file(in_path, out_path) - self._display.vvv("{0} PUT {1} TO {2}".format(self._connection_info.remote_addr, in_path, out_path)) + self._display.vvv("{0} PUT {1} TO {2}".format(self._play_context.remote_addr, in_path, out_path)) if not os.path.exists(in_path): raise AnsibleFileNotFound("file or module does not exist: {0}".format(in_path)) try: @@ -124,7 +124,7 @@ class Connection(ConnectionBase): super(Connection, self).fetch_file(in_path, out_path) - self._display.vvv("{0} FETCH {1} TO {2}".format(self._connection_info.remote_addr, in_path, out_path)) + self._display.vvv("{0} FETCH {1} TO {2}".format(self._play_context.remote_addr, in_path, out_path)) self.put_file(in_path, out_path) def close(self): diff --git a/lib/ansible/plugins/connections/paramiko_ssh.py b/lib/ansible/plugins/connections/paramiko_ssh.py index ab8d4c4d5d..d35e5e13b2 100644 --- a/lib/ansible/plugins/connections/paramiko_ssh.py +++ b/lib/ansible/plugins/connections/paramiko_ssh.py @@ -129,7 +129,7 @@ class Connection(ConnectionBase): return 'paramiko' def _cache_key(self): - return "%s__%s__" % (self._connection_info.remote_addr, self._connection_info.remote_user) + return "%s__%s__" % (self._play_context.remote_addr, self._play_context.remote_user) def _connect(self): cache_key = self._cache_key() @@ -145,8 +145,8 @@ class Connection(ConnectionBase): if not HAVE_PARAMIKO: raise AnsibleError("paramiko is not installed") - port = self._connection_info.port or 22 - self._display.vvv("ESTABLISH CONNECTION FOR USER: %s on PORT %s TO %s" % (self._connection_info.remote_user, port, self._connection_info.remote_addr), host=self._connection_info.remote_addr) + port = self._play_context.port or 22 + self._display.vvv("ESTABLISH CONNECTION FOR USER: %s on PORT %s TO %s" % (self._play_context.remote_user, port, self._play_context.remote_addr), host=self._play_context.remote_addr) ssh = paramiko.SSHClient() @@ -159,22 +159,22 @@ class Connection(ConnectionBase): allow_agent = True - if self._connection_info.password is not None: + if self._play_context.password is not None: allow_agent = False try: key_filename = None - if self._connection_info.private_key_file: - key_filename = os.path.expanduser(self._connection_info.private_key_file) + if self._play_context.private_key_file: + key_filename = os.path.expanduser(self._play_context.private_key_file) ssh.connect( - self._connection_info.remote_addr, - username=self._connection_info.remote_user, + self._play_context.remote_addr, + username=self._play_context.remote_user, allow_agent=allow_agent, look_for_keys=True, key_filename=key_filename, - password=self._connection_info.password, - timeout=self._connection_info.timeout, + password=self._play_context.password, + timeout=self._play_context.timeout, port=port, ) except Exception as e: @@ -183,7 +183,7 @@ class Connection(ConnectionBase): raise AnsibleError("paramiko version issue, please upgrade paramiko on the machine running ansible") elif "Private key file is encrypted" in msg: msg = 'ssh %s@%s:%s : %s\nTo connect as a different user, use -u .' % ( - self._connection_info.remote_user, self._connection_info.remote_addr, port, msg) + self._play_context.remote_user, self._play_context.remote_addr, port, msg) raise AnsibleConnectionFailure(msg) else: raise AnsibleConnectionFailure(msg) @@ -215,7 +215,7 @@ class Connection(ConnectionBase): if C.PARAMIKO_PTY: chan.get_pty(term=os.getenv('TERM', 'vt100'), width=int(os.getenv('COLUMNS', 0)), height=int(os.getenv('LINES', 0))) - self._display.vvv("EXEC %s" % cmd, host=self._connection_info.remote_addr) + self._display.vvv("EXEC %s" % cmd, host=self._play_context.remote_addr) no_prompt_out = '' no_prompt_err = '' @@ -223,8 +223,8 @@ class Connection(ConnectionBase): try: chan.exec_command(cmd) - if self._connection_info.prompt: - if self._connection_info.become and self._connection_info.become_pass: + if self._play_context.prompt: + if self._play_context.become and self._play_context.become_pass: while True: debug('Waiting for Privilege Escalation input') if self.check_become_success(become_output) or self.check_password_prompt(become_output): @@ -240,8 +240,8 @@ class Connection(ConnectionBase): 'closed waiting for password prompt') become_output += chunk if not self.check_become_success(become_output): - if self._connection_info.become: - chan.sendall(self._connection_info.become_pass + '\n') + if self._play_context.become: + chan.sendall(self._play_context.become_pass + '\n') else: no_prompt_out += become_output no_prompt_err += become_output @@ -258,7 +258,7 @@ class Connection(ConnectionBase): super(Connection, self).put_file(in_path, out_path) - self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._connection_info.remote_addr) + self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr) if not os.path.exists(in_path): raise AnsibleFileNotFound("file or module does not exist: %s" % in_path) @@ -275,7 +275,7 @@ class Connection(ConnectionBase): def _connect_sftp(self): - cache_key = "%s__%s__" % (self._connection_info.remote_addr, self._connection_info.remote_user) + cache_key = "%s__%s__" % (self._play_context.remote_addr, self._play_context.remote_user) if cache_key in SFTP_CONNECTION_CACHE: return SFTP_CONNECTION_CACHE[cache_key] else: @@ -287,7 +287,7 @@ class Connection(ConnectionBase): super(Connection, self).fetch_file(in_path, out_path) - self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self._connection_info.remote_addr) + self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr) try: self.sftp = self._connect_sftp() diff --git a/lib/ansible/plugins/connections/ssh.py b/lib/ansible/plugins/connections/ssh.py index d073b215da..4cf7d569a4 100644 --- a/lib/ansible/plugins/connections/ssh.py +++ b/lib/ansible/plugins/connections/ssh.py @@ -60,7 +60,7 @@ class Connection(ConnectionBase): # FIXME: make this work, should be set from connection info self._ipv6 = False - self.host = self._connection_info.remote_addr + self.host = self._play_context.remote_addr if self._ipv6: self.host = '[%s]' % self.host @@ -72,7 +72,7 @@ class Connection(ConnectionBase): def _connect(self): ''' connect to the remote host ''' - self._display.vvv("ESTABLISH SSH CONNECTION FOR USER: {0}".format(self._connection_info.remote_user), host=self._connection_info.remote_addr) + self._display.vvv("ESTABLISH SSH CONNECTION FOR USER: {0}".format(self._play_context.remote_user), host=self._play_context.remote_addr) if self._connected: return self @@ -104,20 +104,20 @@ class Connection(ConnectionBase): if not C.HOST_KEY_CHECKING: self._common_args += ("-o", "StrictHostKeyChecking=no") - if self._connection_info.port is not None: - self._common_args += ("-o", "Port={0}".format(self._connection_info.port)) - if self._connection_info.private_key_file is not None: - self._common_args += ("-o", "IdentityFile=\"{0}\"".format(os.path.expanduser(self._connection_info.private_key_file))) - if self._connection_info.password: + if self._play_context.port is not None: + self._common_args += ("-o", "Port={0}".format(self._play_context.port)) + if self._play_context.private_key_file is not None: + self._common_args += ("-o", "IdentityFile=\"{0}\"".format(os.path.expanduser(self._play_context.private_key_file))) + if self._play_context.password: self._common_args += ("-o", "GSSAPIAuthentication=no", "-o", "PubkeyAuthentication=no") else: self._common_args += ("-o", "KbdInteractiveAuthentication=no", "-o", "PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey", "-o", "PasswordAuthentication=no") - if self._connection_info.remote_user is not None and self._connection_info.remote_user != pwd.getpwuid(os.geteuid())[0]: - self._common_args += ("-o", "User={0}".format(self._connection_info.remote_user)) - self._common_args += ("-o", "ConnectTimeout={0}".format(self._connection_info.timeout)) + if self._play_context.remote_user is not None and self._play_context.remote_user != pwd.getpwuid(os.geteuid())[0]: + self._common_args += ("-o", "User={0}".format(self._play_context.remote_user)) + self._common_args += ("-o", "ConnectTimeout={0}".format(self._play_context.timeout)) self._connected = True @@ -143,7 +143,7 @@ class Connection(ConnectionBase): return (p, stdin) def _password_cmd(self): - if self._connection_info.password: + if self._play_context.password: try: p = subprocess.Popen(["sshpass"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.communicate() @@ -154,9 +154,9 @@ class Connection(ConnectionBase): return [] def _send_password(self): - if self._connection_info.password: + if self._play_context.password: os.close(self.rfd) - os.write(self.wfd, "{0}\n".format(self._connection_info.password)) + os.write(self.wfd, "{0}\n".format(self._play_context.password)) os.close(self.wfd) def _communicate(self, p, stdin, indata, sudoable=True): @@ -177,11 +177,11 @@ class Connection(ConnectionBase): rfd, wfd, efd = select.select(rpipes, [], rpipes, 1) # fail early if the become password is wrong - if self._connection_info.become and sudoable: - if self._connection_info.become_pass: + if self._play_context.become and sudoable: + if self._play_context.become_pass: self.check_incorrect_password(stdout) elif self.check_password_prompt(stdout): - raise AnsibleError('Missing %s password' % self._connection_info.become_method) + raise AnsibleError('Missing %s password' % self._play_context.become_method) if p.stderr in rfd: dat = os.read(p.stderr.fileno(), 9000) @@ -335,7 +335,7 @@ class Connection(ConnectionBase): # inside a tty automatically invokes the python interactive-mode but the modules are not # compatible with the interactive-mode ("unexpected indent" mainly because of empty lines) ssh_cmd.append("-tt") - if self._connection_info.verbosity > 3: + if self._play_context.verbosity > 3: ssh_cmd.append("-vvv") else: ssh_cmd.append("-q") @@ -358,7 +358,7 @@ class Connection(ConnectionBase): no_prompt_out = '' no_prompt_err = '' - if self._connection_info.prompt: + if self._play_context.prompt: ''' Several cases are handled for privileges with password * NOPASSWD (tty & no-tty): detect success_key on stdout @@ -369,7 +369,7 @@ class Connection(ConnectionBase): debug("Handling privilege escalation password prompt.") - if self._connection_info.become and self._connection_info.become_pass: + if self._play_context.become and self._play_context.become_pass: fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK) @@ -381,7 +381,7 @@ class Connection(ConnectionBase): if self.check_become_success(become_output) or self.check_password_prompt(become_output): break - rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout], self._connection_info.timeout) + rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout], self._play_context.timeout) if not rfd: # timeout. wrap up process communication stdout, stderr = p.communicate() @@ -401,7 +401,7 @@ class Connection(ConnectionBase): if not self.check_become_success(become_output): debug("Sending privilege escalation password.") - stdin.write(self._connection_info.become_pass + '\n') + stdin.write(self._play_context.become_pass + '\n') else: no_prompt_out = become_output no_prompt_err = become_errput @@ -491,7 +491,7 @@ class Connection(ConnectionBase): if 'ControlMaster' in self._common_args: cmd = ['ssh','-O','stop'] cmd.extend(self._common_args) - cmd.append(self._connection_info.remote_addr) + cmd.append(self._play_context.remote_addr) p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() diff --git a/lib/ansible/plugins/connections/winrm.py b/lib/ansible/plugins/connections/winrm.py index 68103cd71d..53f609df8e 100644 --- a/lib/ansible/plugins/connections/winrm.py +++ b/lib/ansible/plugins/connections/winrm.py @@ -78,28 +78,28 @@ class Connection(ConnectionBase): ''' Establish a WinRM connection over HTTP/HTTPS. ''' - port = self._connection_info.port or 5986 + port = self._play_context.port or 5986 self._display.vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % \ - (self._connection_info.remote_user, port, self._connection_info.remote_addr), host=self._connection_info.remote_addr) - netloc = '%s:%d' % (self._connection_info.remote_addr, port) + (self._play_context.remote_user, port, self._play_context.remote_addr), host=self._play_context.remote_addr) + netloc = '%s:%d' % (self._play_context.remote_addr, port) exc = None for transport, scheme in self.transport_schemes['http' if port == 5985 else 'https']: - if transport == 'kerberos' and (not HAVE_KERBEROS or not '@' in self._connection_info.remote_user): + if transport == 'kerberos' and (not HAVE_KERBEROS or not '@' in self._play_context.remote_user): continue if transport == 'kerberos': - realm = self._connection_info.remote_user.split('@', 1)[1].strip() or None + realm = self._play_context.remote_user.split('@', 1)[1].strip() or None else: realm = None endpoint = parse.urlunsplit((scheme, netloc, '/wsman', '', '')) - self._display.vvvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self._connection_info.remote_addr) + self._display.vvvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self._play_context.remote_addr) protocol = Protocol( endpoint, transport=transport, - username=self._connection_info.remote_user, - password=self._connection_info.password, + username=self._play_context.remote_user, + password=self._play_context.password, realm=realm ) @@ -117,16 +117,16 @@ class Connection(ConnectionBase): raise AnsibleError("the username/password specified for this server was incorrect") elif code == 411: return protocol - self._display.vvvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self._connection_info.remote_addr) + self._display.vvvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self._play_context.remote_addr) continue if exc: raise AnsibleError(str(exc)) def _winrm_exec(self, command, args=(), from_exec=False): if from_exec: - self._display.vvvvv("WINRM EXEC %r %r" % (command, args), host=self._connection_info.remote_addr) + self._display.vvvvv("WINRM EXEC %r %r" % (command, args), host=self._play_context.remote_addr) else: - self._display.vvvvvv("WINRM EXEC %r %r" % (command, args), host=self._connection_info.remote_addr) + self._display.vvvvvv("WINRM EXEC %r %r" % (command, args), host=self._play_context.remote_addr) if not self.protocol: self.protocol = self._winrm_connect() if not self.shell_id: @@ -136,11 +136,11 @@ class Connection(ConnectionBase): command_id = self.protocol.run_command(self.shell_id, command, args) response = Response(self.protocol.get_command_output(self.shell_id, command_id)) if from_exec: - self._display.vvvvv('WINRM RESULT %r' % response, host=self._connection_info.remote_addr) + self._display.vvvvv('WINRM RESULT %r' % response, host=self._play_context.remote_addr) else: - self._display.vvvvvv('WINRM RESULT %r' % response, host=self._connection_info.remote_addr) - self._display.vvvvvv('WINRM STDOUT %s' % response.std_out, host=self._connection_info.remote_addr) - self._display.vvvvvv('WINRM STDERR %s' % response.std_err, host=self._connection_info.remote_addr) + self._display.vvvvvv('WINRM RESULT %r' % response, host=self._play_context.remote_addr) + self._display.vvvvvv('WINRM STDOUT %s' % response.std_out, host=self._play_context.remote_addr) + self._display.vvvvvv('WINRM STDERR %s' % response.std_err, host=self._play_context.remote_addr) return response finally: if command_id: @@ -159,9 +159,9 @@ class Connection(ConnectionBase): if '-EncodedCommand' in cmd_parts: encoded_cmd = cmd_parts[cmd_parts.index('-EncodedCommand') + 1] decoded_cmd = base64.b64decode(encoded_cmd) - self._display.vvv("EXEC %s" % decoded_cmd, host=self._connection_info.remote_addr) + self._display.vvv("EXEC %s" % decoded_cmd, host=self._play_context.remote_addr) else: - self._display.vvv("EXEC %s" % cmd, host=self._connection_info.remote_addr) + self._display.vvv("EXEC %s" % cmd, host=self._play_context.remote_addr) # For script/raw support. if cmd_parts and cmd_parts[0].lower().endswith('.ps1'): script = self._shell._build_file_cmd(cmd_parts, quote_args=False) @@ -178,7 +178,7 @@ class Connection(ConnectionBase): def put_file(self, 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._connection_info.remote_addr) + self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr) if not os.path.exists(in_path): raise AnsibleFileNotFound("file or module does not exist: %s" % in_path) with open(in_path) as in_file: @@ -206,7 +206,7 @@ class Connection(ConnectionBase): out_path = out_path + '.ps1' b64_data = base64.b64encode(out_data) script = script_template % (self._shell._escape(out_path), offset, b64_data, in_size) - self._display.vvvvv("WINRM PUT %s to %s (offset=%d size=%d)" % (in_path, out_path, offset, len(out_data)), host=self._connection_info.remote_addr) + self._display.vvvvv("WINRM PUT %s to %s (offset=%d size=%d)" % (in_path, out_path, offset, len(out_data)), host=self._play_context.remote_addr) cmd_parts = self._shell._encode_script(script, as_list=True) result = self._winrm_exec(cmd_parts[0], cmd_parts[1:]) if result.status_code != 0: @@ -219,7 +219,7 @@ class Connection(ConnectionBase): super(Connection, self).fetch_file(in_path, out_path) out_path = out_path.replace('\\', '/') - self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self._connection_info.remote_addr) + self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr) buffer_size = 2**19 # 0.5MB chunks makedirs_safe(os.path.dirname(out_path)) out_file = None @@ -248,7 +248,7 @@ class Connection(ConnectionBase): Exit 1; } ''' % dict(buffer_size=buffer_size, path=self._shell._escape(in_path), offset=offset) - self._display.vvvvv("WINRM FETCH %s to %s (offset=%d)" % (in_path, out_path, offset), host=self._connection_info.remote_addr) + self._display.vvvvv("WINRM FETCH %s to %s (offset=%d)" % (in_path, out_path, offset), host=self._play_context.remote_addr) cmd_parts = self._shell._encode_script(script, as_list=True) result = self._winrm_exec(cmd_parts[0], cmd_parts[1:]) if result.status_code != 0: diff --git a/lib/ansible/plugins/strategies/__init__.py b/lib/ansible/plugins/strategies/__init__.py index 45d2000f45..abcb4e5d27 100644 --- a/lib/ansible/plugins/strategies/__init__.py +++ b/lib/ansible/plugins/strategies/__init__.py @@ -74,14 +74,14 @@ class StrategyBase: # outstanding tasks still in queue self._blocked_hosts = dict() - def run(self, iterator, connection_info, result=True): + def run(self, iterator, play_context, result=True): # save the failed/unreachable hosts, as the run_handlers() # method will clear that information during its execution failed_hosts = self._tqm._failed_hosts.keys() unreachable_hosts = self._tqm._unreachable_hosts.keys() debug("running handlers") - result &= self.run_handlers(iterator, connection_info) + result &= self.run_handlers(iterator, play_context) # now update with the hosts (if any) that failed or were # unreachable during the handler execution phase @@ -117,7 +117,7 @@ class StrategyBase: new_vars['ansible_failed_hosts'] = self.get_failed_hosts(play) return new_vars - def _queue_task(self, host, task, task_vars, connection_info): + def _queue_task(self, host, task, task_vars, play_context): ''' handles queueing the task up to be sent to a worker ''' debug("entering _queue_task() for %s/%s" % (host, task)) @@ -136,7 +136,7 @@ class StrategyBase: # way to share them with the forked processes shared_loader_obj = SharedPluginLoaderObj() - main_q.put((host, task, self._loader.get_basedir(), task_vars, connection_info, shared_loader_obj), block=False) + main_q.put((host, task, self._loader.get_basedir(), task_vars, play_context, shared_loader_obj), block=False) self._pending_results += 1 except (EOFError, IOError, AssertionError) as e: # most likely an abort @@ -406,7 +406,7 @@ class StrategyBase: return block_list - def run_handlers(self, iterator, connection_info): + def run_handlers(self, iterator, play_context): ''' Runs handlers on those hosts which have been notified. ''' @@ -427,10 +427,10 @@ class StrategyBase: # break self._tqm.send_callback('v2_playbook_on_handler_task_start', handler) for host in self._notified_handlers[handler_name]: - if not handler.has_triggered(host) and (host.name not in self._tqm._failed_hosts or connection_info.force_handlers): + if not handler.has_triggered(host) and (host.name not in self._tqm._failed_hosts or play_context.force_handlers): task_vars = self._variable_manager.get_vars(loader=self._loader, play=iterator._play, host=host, task=handler) task_vars = self.add_tqm_variables(task_vars, play=iterator._play) - self._queue_task(host, handler, task_vars, connection_info) + self._queue_task(host, handler, task_vars, play_context) #handler.flag_for_host(host) self._process_pending_results(iterator) self._wait_on_pending_results(iterator) diff --git a/lib/ansible/plugins/strategies/free.py b/lib/ansible/plugins/strategies/free.py index d0506d37dd..a9ae87b155 100644 --- a/lib/ansible/plugins/strategies/free.py +++ b/lib/ansible/plugins/strategies/free.py @@ -26,7 +26,7 @@ from ansible.utils.debug import debug class StrategyModule(StrategyBase): - def run(self, iterator, connection_info): + def run(self, iterator, play_context): ''' The "free" strategy is a bit more complex, in that it allows tasks to be sent to hosts as quickly as they can be processed. This means that @@ -97,7 +97,7 @@ class StrategyModule(StrategyBase): debug("'%s' skipped because role has already run" % task) continue - if not task.evaluate_tags(connection_info.only_tags, connection_info.skip_tags, task_vars) and task.action != 'setup': + if not task.evaluate_tags(play_context.only_tags, play_context.skip_tags, task_vars) and task.action != 'setup': debug("'%s' failed tag evaluation" % task) continue @@ -111,14 +111,14 @@ class StrategyModule(StrategyBase): elif meta_action == 'flush_handlers': # FIXME: in the 'free' mode, flushing handlers should result in # only those handlers notified for the host doing the flush - self.run_handlers(iterator, connection_info) + self.run_handlers(iterator, play_context) else: raise AnsibleError("invalid meta action requested: %s" % meta_action, obj=task._ds) self._blocked_hosts[host_name] = False else: self._tqm.send_callback('v2_playbook_on_task_start', task, is_conditional=False) - self._queue_task(host, task, task_vars, connection_info) + self._queue_task(host, task, task_vars, play_context) # move on to the next host and make sure we # haven't gone past the end of our hosts list @@ -147,5 +147,5 @@ class StrategyModule(StrategyBase): # run the base class run() method, which executes the cleanup function # and runs any outstanding handlers which have been triggered - super(StrategyModule, self).run(iterator, connection_info) + super(StrategyModule, self).run(iterator, play_context) diff --git a/lib/ansible/plugins/strategies/linear.py b/lib/ansible/plugins/strategies/linear.py index 23c1eec049..b35df337ba 100644 --- a/lib/ansible/plugins/strategies/linear.py +++ b/lib/ansible/plugins/strategies/linear.py @@ -116,7 +116,7 @@ class StrategyModule(StrategyBase): # return None for all hosts in the list return [(host, None) for host in hosts] - def run(self, iterator, connection_info): + def run(self, iterator, play_context): ''' The linear strategy is simple - get the next task and queue it for all hosts, then wait for the queue to drain before @@ -177,7 +177,7 @@ class StrategyModule(StrategyBase): # FIXME: issue a callback for the noop here? continue elif meta_action == 'flush_handlers': - self.run_handlers(iterator, connection_info) + self.run_handlers(iterator, play_context) else: raise AnsibleError("invalid meta action requested: %s" % meta_action, obj=task._ds) else: @@ -194,7 +194,7 @@ class StrategyModule(StrategyBase): callback_sent = True self._blocked_hosts[host.get_name()] = True - self._queue_task(host, task, task_vars, connection_info) + self._queue_task(host, task, task_vars, play_context) results = self._process_pending_results(iterator) host_results.extend(results) @@ -245,7 +245,7 @@ class StrategyModule(StrategyBase): for host in hosts_left: if host in included_file._hosts: task_vars = self._variable_manager.get_vars(loader=self._loader, play=iterator._play, host=host, task=included_file._task) - final_block = new_block.filter_tagged_tasks(connection_info, task_vars) + final_block = new_block.filter_tagged_tasks(play_context, task_vars) all_blocks[host].append(final_block) else: all_blocks[host].append(noop_block) @@ -262,5 +262,5 @@ class StrategyModule(StrategyBase): # run the base class run() method, which executes the cleanup function # and runs any outstanding handlers which have been triggered - return super(StrategyModule, self).run(iterator, connection_info, result) + return super(StrategyModule, self).run(iterator, play_context, result) diff --git a/samples/multi_queues.py b/samples/multi_queues.py index 9e8f22b9a9..673bb01de6 100644 --- a/samples/multi_queues.py +++ b/samples/multi_queues.py @@ -9,8 +9,8 @@ import multiprocessing from ansible.inventory import Inventory from ansible.inventory.host import Host from ansible.playbook.play import Play +from ansible.playbook.play_context import PlayContext from ansible.playbook.task import Task -from ansible.executor.connection_info import ConnectionInformation from ansible.executor.task_executor import TaskExecutor from ansible.executor.task_result import TaskResult from ansible.parsing import DataLoader @@ -144,8 +144,8 @@ inventory = Inventory(host_list='/tmp/med_inventory', loader=loader, variable_ma hosts = inventory.get_hosts()[:] debug("done loading inventory") -ci = ConnectionInformation() -ci.connection = 'local' +play_context = PlayContext() +play_context.connection = 'local' for i in range(NUM_TASKS): #for j in range(NUM_HOSTS): @@ -158,7 +158,7 @@ for i in range(NUM_TASKS): task_vars = dict() new_t = t.copy() new_t.post_validate(task_vars) - send_data((h, t, task_vars, ci)) + send_data((h, t, task_vars, play_context)) debug("done queuing %s %d" % (h, i)) _process_pending_results() debug("waiting for the results to drain...") diff --git a/test/units/executor/test_connection_information.py b/test/units/executor/test_connection_information.py deleted file mode 100644 index a0c5863bf3..0000000000 --- a/test/units/executor/test_connection_information.py +++ /dev/null @@ -1,156 +0,0 @@ -# (c) 2012-2014, Michael DeHaan -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . - -# Make coding more python3-ish -from __future__ import (absolute_import, division, print_function) -__metaclass__ = type - -import pwd -import os - -from ansible.compat.tests import unittest -from ansible.compat.tests.mock import patch, MagicMock - -from ansible import constants as C -from ansible.cli import CLI -from ansible.errors import AnsibleError, AnsibleParserError -from ansible.executor.connection_info import ConnectionInformation - -from units.mock.loader import DictDataLoader - -class TestConnectionInformation(unittest.TestCase): - - def setUp(self): - self._parser = CLI.base_parser( - runas_opts = True, - meta_opts = True, - runtask_opts = True, - vault_opts = True, - async_opts = True, - connect_opts = True, - subset_opts = True, - check_opts = True, - diff_opts = True, - ) - - def tearDown(self): - pass - - def test_connection_info(self): - (options, args) = self._parser.parse_args(['-vv', '--check']) - conn_info = ConnectionInformation(options=options) - self.assertEqual(conn_info.connection, 'smart') - self.assertEqual(conn_info.remote_addr, None) - self.assertEqual(conn_info.remote_user, pwd.getpwuid(os.geteuid())[0]) - self.assertEqual(conn_info.password, '') - self.assertEqual(conn_info.port, None) - self.assertEqual(conn_info.private_key_file, C.DEFAULT_PRIVATE_KEY_FILE) - self.assertEqual(conn_info.timeout, C.DEFAULT_TIMEOUT) - self.assertEqual(conn_info.shell, None) - self.assertEqual(conn_info.verbosity, 2) - self.assertEqual(conn_info.check_mode, True) - self.assertEqual(conn_info.no_log, False) - - mock_play = MagicMock() - mock_play.connection = 'mock' - mock_play.remote_user = 'mock' - mock_play.port = 1234 - mock_play.become = True - mock_play.become_method = 'mock' - mock_play.become_user = 'mockroot' - mock_play.no_log = True - mock_play.environment = dict(mock='mockenv') - - conn_info = ConnectionInformation(play=mock_play, options=options) - self.assertEqual(conn_info.connection, 'mock') - self.assertEqual(conn_info.remote_user, 'mock') - self.assertEqual(conn_info.password, '') - self.assertEqual(conn_info.port, 1234) - self.assertEqual(conn_info.no_log, True) - self.assertEqual(conn_info.environment, dict(mock="mockenv")) - self.assertEqual(conn_info.become, True) - self.assertEqual(conn_info.become_method, "mock") - self.assertEqual(conn_info.become_user, "mockroot") - - mock_task = MagicMock() - mock_task.connection = 'mocktask' - mock_task.remote_user = 'mocktask' - mock_task.become = True - mock_task.become_method = 'mocktask' - mock_task.become_user = 'mocktaskroot' - mock_task.become_pass = 'mocktaskpass' - mock_task.no_log = False - mock_task.environment = dict(mock='mocktaskenv') - - mock_host = MagicMock() - mock_host.get_vars.return_value = dict( - ansible_connection = 'mock_inventory', - ansible_ssh_port = 4321, - ) - - conn_info = ConnectionInformation(play=mock_play, options=options) - conn_info = conn_info.set_task_and_host_override(task=mock_task, host=mock_host) - self.assertEqual(conn_info.connection, 'mock_inventory') - self.assertEqual(conn_info.remote_user, 'mocktask') - self.assertEqual(conn_info.port, 4321) - self.assertEqual(conn_info.no_log, False) - self.assertEqual(conn_info.environment, dict(mock="mocktaskenv")) - self.assertEqual(conn_info.become, True) - self.assertEqual(conn_info.become_method, "mocktask") - self.assertEqual(conn_info.become_user, "mocktaskroot") - self.assertEqual(conn_info.become_pass, "mocktaskpass") - - def test_connection_info_make_become_cmd(self): - (options, args) = self._parser.parse_args([]) - conn_info = ConnectionInformation(options=options) - - default_cmd = "/bin/foo" - default_exe = "/bin/bash" - sudo_exe = C.DEFAULT_SUDO_EXE - sudo_flags = C.DEFAULT_SUDO_FLAGS - su_exe = C.DEFAULT_SU_EXE - su_flags = C.DEFAULT_SU_FLAGS - pbrun_exe = 'pbrun' - pbrun_flags = '' - pfexec_exe = 'pfexec' - pfexec_flags = '' - - cmd = conn_info.make_become_cmd(cmd=default_cmd, executable=default_exe) - self.assertEqual(cmd, default_cmd) - - conn_info.become = True - conn_info.become_user = 'foo' - - conn_info.become_method = 'sudo' - cmd = conn_info.make_become_cmd(cmd=default_cmd, executable="/bin/bash") - self.assertEqual(cmd, """%s -c '%s -k && %s %s -S -p "%s" -u %s %s -c '"'"'echo %s; %s'"'"''""" % (default_exe, sudo_exe, sudo_exe, sudo_flags, conn_info.prompt, conn_info.become_user, default_exe, conn_info.success_key, default_cmd)) - - conn_info.become_method = 'su' - cmd = conn_info.make_become_cmd(cmd=default_cmd, executable="/bin/bash") - self.assertEqual(cmd, """%s -c '%s %s -c "%s -c '"'"'echo %s; %s'"'"'"'""" % (default_exe, su_exe, conn_info.become_user, default_exe, conn_info.success_key, default_cmd)) - - conn_info.become_method = 'pbrun' - cmd = conn_info.make_become_cmd(cmd=default_cmd, executable="/bin/bash") - self.assertEqual(cmd, """%s -c '%s -b %s -u %s '"'"'echo %s; %s'"'"''""" % (default_exe, pbrun_exe, pbrun_flags, conn_info.become_user, conn_info.success_key, default_cmd)) - - conn_info.become_method = 'pfexec' - cmd = conn_info.make_become_cmd(cmd=default_cmd, executable="/bin/bash") - self.assertEqual(cmd, """%s -c '%s %s "'"'"'echo %s; %s'"'"'"'""" % (default_exe, pfexec_exe, pfexec_flags, conn_info.success_key, default_cmd)) - - conn_info.become_method = 'bad' - self.assertRaises(AnsibleError, conn_info.make_become_cmd, cmd=default_cmd, executable="/bin/bash") - diff --git a/test/units/executor/test_play_iterator.py b/test/units/executor/test_play_iterator.py index 7f8ed4d681..700ee4c255 100644 --- a/test/units/executor/test_play_iterator.py +++ b/test/units/executor/test_play_iterator.py @@ -23,9 +23,9 @@ from ansible.compat.tests import unittest from ansible.compat.tests.mock import patch, MagicMock from ansible.errors import AnsibleError, AnsibleParserError -from ansible.executor.connection_info import ConnectionInformation from ansible.executor.play_iterator import PlayIterator from ansible.playbook import Playbook +from ansible.playbook.play_context import PlayContext from units.mock.loader import DictDataLoader @@ -68,12 +68,12 @@ class TestPlayIterator(unittest.TestCase): inventory.get_hosts.return_value = hosts inventory.filter_hosts.return_value = hosts - connection_info = ConnectionInformation(play=p._entries[0]) + play_context = PlayContext(play=p._entries[0]) itr = PlayIterator( inventory=inventory, play=p._entries[0], - connection_info=connection_info, + play_context=play_context, all_vars=dict(), ) diff --git a/test/units/executor/test_task_executor.py b/test/units/executor/test_task_executor.py index 966be3c8c7..54febca4b7 100644 --- a/test/units/executor/test_task_executor.py +++ b/test/units/executor/test_task_executor.py @@ -23,8 +23,8 @@ from ansible.compat.tests import unittest from ansible.compat.tests.mock import patch, MagicMock from ansible.errors import AnsibleError, AnsibleParserError -from ansible.executor.connection_info import ConnectionInformation from ansible.executor.task_executor import TaskExecutor +from ansible.playbook.play_context import PlayContext from ansible.plugins import action_loader from units.mock.loader import DictDataLoader @@ -41,7 +41,7 @@ class TestTaskExecutor(unittest.TestCase): fake_loader = DictDataLoader({}) mock_host = MagicMock() mock_task = MagicMock() - mock_conn_info = MagicMock() + mock_play_context = MagicMock() mock_shared_loader = MagicMock() new_stdin = None job_vars = dict() @@ -49,7 +49,7 @@ class TestTaskExecutor(unittest.TestCase): host = mock_host, task = mock_task, job_vars = job_vars, - connection_info = mock_conn_info, + play_context = mock_play_context, new_stdin = new_stdin, loader = fake_loader, shared_loader_obj = mock_shared_loader, @@ -63,7 +63,7 @@ class TestTaskExecutor(unittest.TestCase): mock_task = MagicMock() mock_task._role._role_path = '/path/to/role/foo' - mock_conn_info = MagicMock() + mock_play_context = MagicMock() mock_shared_loader = MagicMock() @@ -74,7 +74,7 @@ class TestTaskExecutor(unittest.TestCase): host = mock_host, task = mock_task, job_vars = job_vars, - connection_info = mock_conn_info, + play_context = mock_play_context, new_stdin = new_stdin, loader = fake_loader, shared_loader_obj = mock_shared_loader, @@ -104,7 +104,7 @@ class TestTaskExecutor(unittest.TestCase): mock_task.loop = 'items' mock_task.loop_args = ['a', 'b', 'c'] - mock_conn_info = MagicMock() + mock_play_context = MagicMock() mock_shared_loader = MagicMock() @@ -115,7 +115,7 @@ class TestTaskExecutor(unittest.TestCase): host = mock_host, task = mock_task, job_vars = job_vars, - connection_info = mock_conn_info, + play_context = mock_play_context, new_stdin = new_stdin, loader = fake_loader, shared_loader_obj = mock_shared_loader, @@ -138,7 +138,7 @@ class TestTaskExecutor(unittest.TestCase): mock_task = MagicMock() mock_task.copy.side_effect = _copy - mock_conn_info = MagicMock() + mock_play_context = MagicMock() mock_shared_loader = MagicMock() @@ -149,7 +149,7 @@ class TestTaskExecutor(unittest.TestCase): host = mock_host, task = mock_task, job_vars = job_vars, - connection_info = mock_conn_info, + play_context = mock_play_context, new_stdin = new_stdin, loader = fake_loader, shared_loader_obj = mock_shared_loader, @@ -180,7 +180,7 @@ class TestTaskExecutor(unittest.TestCase): mock_task = MagicMock() mock_task.evaluate_conditional.side_effect = _evaluate_conditional - mock_conn_info = MagicMock() + mock_play_context = MagicMock() mock_shared_loader = None @@ -191,7 +191,7 @@ class TestTaskExecutor(unittest.TestCase): host = mock_host, task = mock_task, job_vars = job_vars, - connection_info = mock_conn_info, + play_context = mock_play_context, new_stdin = new_stdin, loader = fake_loader, shared_loader_obj = mock_shared_loader, @@ -220,9 +220,9 @@ class TestTaskExecutor(unittest.TestCase): mock_task.failed_when = None mock_task.post_validate.return_value = None - mock_conn_info = MagicMock() - mock_conn_info.post_validate.return_value = None - mock_conn_info.update_vars.return_value = None + mock_play_context = MagicMock() + mock_play_context.post_validate.return_value = None + mock_play_context.update_vars.return_value = None mock_connection = MagicMock() mock_connection.set_host_overrides.return_value = None @@ -238,7 +238,7 @@ class TestTaskExecutor(unittest.TestCase): host = mock_host, task = mock_task, job_vars = job_vars, - connection_info = mock_conn_info, + play_context = mock_play_context, new_stdin = new_stdin, loader = fake_loader, shared_loader_obj = shared_loader, @@ -275,7 +275,7 @@ class TestTaskExecutor(unittest.TestCase): mock_task.async = 3 mock_task.poll = 1 - mock_conn_info = MagicMock() + mock_play_context = MagicMock() mock_connection = MagicMock() @@ -289,7 +289,7 @@ class TestTaskExecutor(unittest.TestCase): host = mock_host, task = mock_task, job_vars = job_vars, - connection_info = mock_conn_info, + play_context = mock_play_context, new_stdin = new_stdin, loader = fake_loader, shared_loader_obj = shared_loader, diff --git a/test/units/playbook/test_play_context.py b/test/units/playbook/test_play_context.py new file mode 100644 index 0000000000..e077398fb8 --- /dev/null +++ b/test/units/playbook/test_play_context.py @@ -0,0 +1,156 @@ +# (c) 2012-2014, Michael DeHaan +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import pwd +import os + +from ansible.compat.tests import unittest +from ansible.compat.tests.mock import patch, MagicMock + +from ansible import constants as C +from ansible.cli import CLI +from ansible.errors import AnsibleError, AnsibleParserError +from ansible.playbook.play_context import PlayContext + +from units.mock.loader import DictDataLoader + +class TestPlayContext(unittest.TestCase): + + def setUp(self): + self._parser = CLI.base_parser( + runas_opts = True, + meta_opts = True, + runtask_opts = True, + vault_opts = True, + async_opts = True, + connect_opts = True, + subset_opts = True, + check_opts = True, + diff_opts = True, + ) + + def tearDown(self): + pass + + def test_play_context(self): + (options, args) = self._parser.parse_args(['-vv', '--check']) + play_context = PlayContext(options=options) + self.assertEqual(play_context.connection, 'smart') + self.assertEqual(play_context.remote_addr, None) + self.assertEqual(play_context.remote_user, pwd.getpwuid(os.geteuid())[0]) + self.assertEqual(play_context.password, '') + self.assertEqual(play_context.port, None) + self.assertEqual(play_context.private_key_file, C.DEFAULT_PRIVATE_KEY_FILE) + self.assertEqual(play_context.timeout, C.DEFAULT_TIMEOUT) + self.assertEqual(play_context.shell, None) + self.assertEqual(play_context.verbosity, 2) + self.assertEqual(play_context.check_mode, True) + self.assertEqual(play_context.no_log, False) + + mock_play = MagicMock() + mock_play.connection = 'mock' + mock_play.remote_user = 'mock' + mock_play.port = 1234 + mock_play.become = True + mock_play.become_method = 'mock' + mock_play.become_user = 'mockroot' + mock_play.no_log = True + mock_play.environment = dict(mock='mockenv') + + play_context = PlayContext(play=mock_play, options=options) + self.assertEqual(play_context.connection, 'mock') + self.assertEqual(play_context.remote_user, 'mock') + self.assertEqual(play_context.password, '') + self.assertEqual(play_context.port, 1234) + self.assertEqual(play_context.no_log, True) + self.assertEqual(play_context.environment, dict(mock="mockenv")) + self.assertEqual(play_context.become, True) + self.assertEqual(play_context.become_method, "mock") + self.assertEqual(play_context.become_user, "mockroot") + + mock_task = MagicMock() + mock_task.connection = 'mocktask' + mock_task.remote_user = 'mocktask' + mock_task.become = True + mock_task.become_method = 'mocktask' + mock_task.become_user = 'mocktaskroot' + mock_task.become_pass = 'mocktaskpass' + mock_task.no_log = False + mock_task.environment = dict(mock='mocktaskenv') + + mock_host = MagicMock() + mock_host.get_vars.return_value = dict( + ansible_connection = 'mock_inventory', + ansible_ssh_port = 4321, + ) + + play_context = PlayContext(play=mock_play, options=options) + play_context = play_context.set_task_and_host_override(task=mock_task, host=mock_host) + self.assertEqual(play_context.connection, 'mock_inventory') + self.assertEqual(play_context.remote_user, 'mocktask') + self.assertEqual(play_context.port, 4321) + self.assertEqual(play_context.no_log, False) + self.assertEqual(play_context.environment, dict(mock="mocktaskenv")) + self.assertEqual(play_context.become, True) + self.assertEqual(play_context.become_method, "mocktask") + self.assertEqual(play_context.become_user, "mocktaskroot") + self.assertEqual(play_context.become_pass, "mocktaskpass") + + def test_play_context_make_become_cmd(self): + (options, args) = self._parser.parse_args([]) + play_context = PlayContext(options=options) + + default_cmd = "/bin/foo" + default_exe = "/bin/bash" + sudo_exe = C.DEFAULT_SUDO_EXE + sudo_flags = C.DEFAULT_SUDO_FLAGS + su_exe = C.DEFAULT_SU_EXE + su_flags = C.DEFAULT_SU_FLAGS + pbrun_exe = 'pbrun' + pbrun_flags = '' + pfexec_exe = 'pfexec' + pfexec_flags = '' + + cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe) + self.assertEqual(cmd, default_cmd) + + play_context.become = True + play_context.become_user = 'foo' + + play_context.become_method = 'sudo' + cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash") + self.assertEqual(cmd, """%s -c '%s -k && %s %s -S -p "%s" -u %s %s -c '"'"'echo %s; %s'"'"''""" % (default_exe, sudo_exe, sudo_exe, sudo_flags, play_context.prompt, play_context.become_user, default_exe, play_context.success_key, default_cmd)) + + play_context.become_method = 'su' + cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash") + self.assertEqual(cmd, """%s -c '%s %s -c "%s -c '"'"'echo %s; %s'"'"'"'""" % (default_exe, su_exe, play_context.become_user, default_exe, play_context.success_key, default_cmd)) + + play_context.become_method = 'pbrun' + cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash") + self.assertEqual(cmd, """%s -c '%s -b %s -u %s '"'"'echo %s; %s'"'"''""" % (default_exe, pbrun_exe, pbrun_flags, play_context.become_user, play_context.success_key, default_cmd)) + + play_context.become_method = 'pfexec' + cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash") + self.assertEqual(cmd, """%s -c '%s %s "'"'"'echo %s; %s'"'"'"'""" % (default_exe, pfexec_exe, pfexec_flags, play_context.success_key, default_cmd)) + + play_context.become_method = 'bad' + self.assertRaises(AnsibleError, play_context.make_become_cmd, cmd=default_cmd, executable="/bin/bash") + diff --git a/test/units/plugins/connections/test_connection.py b/test/units/plugins/connections/test_connection.py index 0ed888ac95..aba94b5a61 100644 --- a/test/units/plugins/connections/test_connection.py +++ b/test/units/plugins/connections/test_connection.py @@ -22,7 +22,7 @@ __metaclass__ = type from six import StringIO from ansible.compat.tests import unittest -from ansible.executor.connection_info import ConnectionInformation +from ansible.playbook.play_context import PlayContext from ansible.plugins.connections import ConnectionBase #from ansible.plugins.connections.accelerate import Connection as AccelerateConnection @@ -38,7 +38,7 @@ from ansible.plugins.connections.ssh import Connection as SSHConnection class TestConnectionBaseClass(unittest.TestCase): def setUp(self): - self.conn_info = ConnectionInformation() + self.play_context = PlayContext() self.in_stream = StringIO() def tearDown(self): @@ -72,7 +72,7 @@ class TestConnectionBaseClass(unittest.TestCase): pass def close(self): pass - self.assertIsInstance(ConnectionModule3(self.conn_info, self.in_stream), ConnectionModule3) + self.assertIsInstance(ConnectionModule3(self.play_context, self.in_stream), ConnectionModule3) # def test_accelerate_connection_module(self): # self.assertIsInstance(AccelerateConnection(), AccelerateConnection) @@ -90,13 +90,13 @@ class TestConnectionBaseClass(unittest.TestCase): # self.assertIsInstance(LibvirtLXCConnection(), LibvirtLXCConnection) def test_local_connection_module(self): - self.assertIsInstance(LocalConnection(self.conn_info, self.in_stream), LocalConnection) + self.assertIsInstance(LocalConnection(self.play_context, self.in_stream), LocalConnection) def test_paramiko_connection_module(self): - self.assertIsInstance(ParamikoConnection(self.conn_info, self.in_stream), ParamikoConnection) + self.assertIsInstance(ParamikoConnection(self.play_context, self.in_stream), ParamikoConnection) def test_ssh_connection_module(self): - self.assertIsInstance(SSHConnection(self.conn_info, self.in_stream), SSHConnection) + self.assertIsInstance(SSHConnection(self.play_context, self.in_stream), SSHConnection) # def test_winrm_connection_module(self): # self.assertIsInstance(WinRmConnection(), WinRmConnection) diff --git a/test/units/plugins/strategies/test_strategy_base.py b/test/units/plugins/strategies/test_strategy_base.py index cfebeb6cd9..9b84fcba1b 100644 --- a/test/units/plugins/strategies/test_strategy_base.py +++ b/test/units/plugins/strategies/test_strategy_base.py @@ -53,18 +53,18 @@ class TestStrategyBase(unittest.TestCase): mock_iterator._play = MagicMock() mock_iterator._play.handlers = [] - mock_conn_info = MagicMock() + mock_play_context = MagicMock() mock_tqm._failed_hosts = dict() mock_tqm._unreachable_hosts = dict() strategy_base = StrategyBase(tqm=mock_tqm) - self.assertEqual(strategy_base.run(iterator=mock_iterator, connection_info=mock_conn_info), 0) - self.assertEqual(strategy_base.run(iterator=mock_iterator, connection_info=mock_conn_info, result=False), 1) + self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context), 0) + self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context, result=False), 1) mock_tqm._failed_hosts = dict(host1=True) - self.assertEqual(strategy_base.run(iterator=mock_iterator, connection_info=mock_conn_info, result=False), 2) + self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context, result=False), 2) mock_tqm._unreachable_hosts = dict(host1=True) - self.assertEqual(strategy_base.run(iterator=mock_iterator, connection_info=mock_conn_info, result=False), 3) + self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context, result=False), 3) def test_strategy_base_get_hosts(self): mock_hosts = [] @@ -114,17 +114,17 @@ class TestStrategyBase(unittest.TestCase): strategy_base = StrategyBase(tqm=mock_tqm) strategy_base._cur_worker = 0 strategy_base._pending_results = 0 - strategy_base._queue_task(host=MagicMock(), task=MagicMock(), task_vars=dict(), connection_info=MagicMock()) + strategy_base._queue_task(host=MagicMock(), task=MagicMock(), task_vars=dict(), play_context=MagicMock()) self.assertEqual(strategy_base._cur_worker, 1) self.assertEqual(strategy_base._pending_results, 1) - strategy_base._queue_task(host=MagicMock(), task=MagicMock(), task_vars=dict(), connection_info=MagicMock()) + strategy_base._queue_task(host=MagicMock(), task=MagicMock(), task_vars=dict(), play_context=MagicMock()) self.assertEqual(strategy_base._cur_worker, 2) self.assertEqual(strategy_base._pending_results, 2) - strategy_base._queue_task(host=MagicMock(), task=MagicMock(), task_vars=dict(), connection_info=MagicMock()) + strategy_base._queue_task(host=MagicMock(), task=MagicMock(), task_vars=dict(), play_context=MagicMock()) self.assertEqual(strategy_base._cur_worker, 0) self.assertEqual(strategy_base._pending_results, 3) workers[0][1].put.side_effect = EOFError - strategy_base._queue_task(host=MagicMock(), task=MagicMock(), task_vars=dict(), connection_info=MagicMock()) + strategy_base._queue_task(host=MagicMock(), task=MagicMock(), task_vars=dict(), play_context=MagicMock()) self.assertEqual(strategy_base._cur_worker, 1) self.assertEqual(strategy_base._pending_results, 3) @@ -326,7 +326,7 @@ class TestStrategyBase(unittest.TestCase): mock_tqm.get_workers.return_value = workers mock_tqm.send_callback.return_value = None - mock_conn_info = MagicMock() + mock_play_context = MagicMock() mock_handler_task = MagicMock() mock_handler_task.get_name.return_value = "test handler" @@ -357,4 +357,4 @@ class TestStrategyBase(unittest.TestCase): strategy_base._inventory = mock_inventory strategy_base._notified_handlers = {"test handler": [mock_host]} - result = strategy_base.run_handlers(iterator=mock_iterator, connection_info=mock_conn_info) + result = strategy_base.run_handlers(iterator=mock_iterator, play_context=mock_play_context)