From c50cf22d521d4d2efcdf45283f868f035ff44cef Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Mon, 17 Apr 2017 15:44:19 -0400 Subject: [PATCH] deal with null/none connections fixes #23621 pushed 'connection resolution' to play_context override fieldattribute getter --- lib/ansible/executor/task_executor.py | 24 ++++--------------- lib/ansible/playbook/play_context.py | 30 +++++++++++++++++++++++- lib/ansible/plugins/strategy/__init__.py | 10 +++++--- test/units/playbook/test_play_context.py | 2 +- 4 files changed, 41 insertions(+), 25 deletions(-) diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py index a983c8aec6f..0ff1345998f 100644 --- a/lib/ansible/executor/task_executor.py +++ b/lib/ansible/executor/task_executor.py @@ -20,7 +20,6 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type import base64 -import sys import time import traceback @@ -722,27 +721,12 @@ class TaskExecutor: if isinstance(i, string_types) and i.startswith("ansible_") and i.endswith("_interpreter"): variables[i] = delegated_vars[i] - conn_type = self._play_context.connection - if conn_type == 'smart': - conn_type = 'ssh' - 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 - conn_type = "paramiko" - else: - # see if SSH can support ControlPersist if not use paramiko - if not check_for_controlpersist(self._play_context.ssh_executable): - conn_type = "paramiko" - - # if someone did `connection: persistent`, default it to using a persistent paramiko connection to avoid problems - if conn_type == 'persistent': - self._play_context.connection = 'paramiko' - - # if using persistent connections (or the action has set the FORCE_PERSISTENT_CONNECTION attribute to True), + # if using persistent paramiko connections (or the action has set the FORCE_PERSISTENT_CONNECTION attribute to True), # then we use the persistent connection plugion. Otherwise load the requested connection plugin - elif C.USE_PERSISTENT_CONNECTIONS or getattr(self, 'FORCE_PERSISTENT_CONNECTION', False): + if C.USE_PERSISTENT_CONNECTIONS or getattr(self, 'FORCE_PERSISTENT_CONNECTION', False): conn_type == 'persistent' + else: + conn_type = self._play_context.connection connection = self._shared_loader_obj.connection_loader.get(conn_type, self._play_context, self._new_stdin) diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py index f9e6276bad8..b8503f6ffaf 100644 --- a/lib/ansible/playbook/play_context.py +++ b/lib/ansible/playbook/play_context.py @@ -26,14 +26,16 @@ import pwd import random import re import string +import sys from ansible import constants as C from ansible.errors import AnsibleError -from ansible.module_utils.six import iteritems, string_types +from ansible.module_utils.six import iteritems from ansible.module_utils.six.moves import shlex_quote from ansible.module_utils._text import to_bytes from ansible.playbook.attribute import FieldAttribute from ansible.playbook.base import Base +from ansible.utils.ssh_functions import check_for_controlpersist boolean = C.mk_boolean @@ -241,6 +243,7 @@ class PlayContext(Base): if play: self.set_play(play) + def set_play(self, play): ''' Configures this connection information instance with data from @@ -611,3 +614,28 @@ class PlayContext(Base): variables[var_opt] = var_val except AttributeError: continue + + def _get_attr_connection(self): + ''' connections are special, this takes care of responding correctly ''' + conn_type = None + if self._attributes['connection'] == 'smart': + conn_type = 'ssh' + if sys.platform.startswith('darwin') and self.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 + conn_type = "paramiko" + else: + # see if SSH can support ControlPersist if not use paramiko + if not check_for_controlpersist(self.ssh_executable): + conn_type = "paramiko" + + # if someone did `connection: persistent`, default it to using a persistent paramiko connection to avoid problems + elif self._attributes['connection'] == 'persistent': + conn_type = 'paramiko' + + if conn_type: + self.connection = conn_type + + return self._attributes['connection'] + diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index 99d65ff3853..630ebfe140b 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -19,6 +19,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +import os import threading import time @@ -903,9 +904,12 @@ class StrategyBase: iterator._host_states[host.name].run_state = iterator.ITERATING_COMPLETE msg="ending play" elif meta_action == 'reset_connection': - connection = connection_loader.get(play_context.connection, play_context, '/dev/null') - connection.reset() - msg= 'reset connection' + connection = connection_loader.get(play_context.connection, play_context, os.devnull) + if connection: + connection.reset() + msg= 'reset connection' + else: + msg= 'no connection, nothing to reset' else: raise AnsibleError("invalid meta action requested: %s" % meta_action, obj=task._ds) diff --git a/test/units/playbook/test_play_context.py b/test/units/playbook/test_play_context.py index ce8322f4c4f..7889a8347df 100644 --- a/test/units/playbook/test_play_context.py +++ b/test/units/playbook/test_play_context.py @@ -53,7 +53,7 @@ class TestPlayContext(unittest.TestCase): def test_play_context(self): (options, args) = self._parser.parse_args(['-vv', '--check']) play_context = PlayContext(options=options) - self.assertEqual(play_context.connection, C.DEFAULT_TRANSPORT) + self.assertEqual(play_context._attributes['connection'], C.DEFAULT_TRANSPORT) self.assertEqual(play_context.remote_addr, None) self.assertEqual(play_context.remote_user, None) self.assertEqual(play_context.password, '')