mirror of https://github.com/ansible/ansible.git
Add `use_rsa_sha2_algorithms` option for paramiko (#78789)
Fixes #76737 Fixes #77673 Co-authored-by: Matt Clay <matt@mystile.com>pull/78850/head
parent
4d25233ece
commit
76b746655a
@ -0,0 +1,5 @@
|
|||||||
|
bugfixes:
|
||||||
|
- paramiko - Add a new option to allow paramiko >= 2.9 to easily work with
|
||||||
|
all devices now that rsa-sha2 support was added to paramiko, which
|
||||||
|
prevented communication with numerous platforms.
|
||||||
|
(https://github.com/ansible/ansible/issues/76737)
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,77 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleDocFragment(object):
|
||||||
|
|
||||||
|
# Standard files documentation fragment
|
||||||
|
DOCUMENTATION = r"""
|
||||||
|
options:
|
||||||
|
import_modules:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
- Reduce CPU usage and network module execution time
|
||||||
|
by enabling direct execution. Instead of the module being packaged
|
||||||
|
and executed by the shell, it will be directly executed by the Ansible
|
||||||
|
control node using the same python interpreter as the Ansible process.
|
||||||
|
Note- Incompatible with C(asynchronous mode).
|
||||||
|
Note- Python 3 and Ansible 2.9.16 or greater required.
|
||||||
|
Note- With Ansible 2.9.x fully qualified modules names are required in tasks.
|
||||||
|
default: true
|
||||||
|
ini:
|
||||||
|
- section: ansible_network
|
||||||
|
key: import_modules
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_NETWORK_IMPORT_MODULES
|
||||||
|
vars:
|
||||||
|
- name: ansible_network_import_modules
|
||||||
|
persistent_connect_timeout:
|
||||||
|
type: int
|
||||||
|
description:
|
||||||
|
- Configures, in seconds, the amount of time to wait when trying to initially
|
||||||
|
establish a persistent connection. If this value expires before the connection
|
||||||
|
to the remote device is completed, the connection will fail.
|
||||||
|
default: 30
|
||||||
|
ini:
|
||||||
|
- section: persistent_connection
|
||||||
|
key: connect_timeout
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_PERSISTENT_CONNECT_TIMEOUT
|
||||||
|
vars:
|
||||||
|
- name: ansible_connect_timeout
|
||||||
|
persistent_command_timeout:
|
||||||
|
type: int
|
||||||
|
description:
|
||||||
|
- Configures, in seconds, the amount of time to wait for a command to
|
||||||
|
return from the remote device. If this timer is exceeded before the
|
||||||
|
command returns, the connection plugin will raise an exception and
|
||||||
|
close.
|
||||||
|
default: 30
|
||||||
|
ini:
|
||||||
|
- section: persistent_connection
|
||||||
|
key: command_timeout
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_PERSISTENT_COMMAND_TIMEOUT
|
||||||
|
vars:
|
||||||
|
- name: ansible_command_timeout
|
||||||
|
persistent_log_messages:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
- This flag will enable logging the command executed and response received from
|
||||||
|
target device in the ansible log file. For this option to work 'log_path' ansible
|
||||||
|
configuration option is required to be set to a file path with write access.
|
||||||
|
- Be sure to fully understand the security implications of enabling this
|
||||||
|
option as it could create a security vulnerability by logging sensitive information in log file.
|
||||||
|
default: False
|
||||||
|
ini:
|
||||||
|
- section: persistent_connection
|
||||||
|
key: log_messages
|
||||||
|
env:
|
||||||
|
- name: ANSIBLE_PERSISTENT_LOG_MESSAGES
|
||||||
|
vars:
|
||||||
|
- name: ansible_persistent_log_messages
|
||||||
|
"""
|
@ -0,0 +1,185 @@
|
|||||||
|
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||||||
|
# (c) 2015 Toshio Kuratomi <tkuratomi@ansible.com>
|
||||||
|
# (c) 2017, Peter Sprygada <psprygad@redhat.com>
|
||||||
|
# (c) 2017 Ansible Project
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from ansible import constants as C
|
||||||
|
from ansible.plugins.connection import ConnectionBase
|
||||||
|
from ansible.plugins.loader import connection_loader
|
||||||
|
from ansible.utils.display import Display
|
||||||
|
from ansible.utils.path import unfrackpath
|
||||||
|
|
||||||
|
display = Display()
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["NetworkConnectionBase"]
|
||||||
|
|
||||||
|
BUFSIZE = 65536
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkConnectionBase(ConnectionBase):
|
||||||
|
"""
|
||||||
|
A base class for network-style connections.
|
||||||
|
"""
|
||||||
|
|
||||||
|
force_persistence = True
|
||||||
|
# Do not use _remote_is_local in other connections
|
||||||
|
_remote_is_local = True
|
||||||
|
|
||||||
|
def __init__(self, play_context, new_stdin, *args, **kwargs):
|
||||||
|
super(NetworkConnectionBase, self).__init__(
|
||||||
|
play_context, new_stdin, *args, **kwargs
|
||||||
|
)
|
||||||
|
self._messages = []
|
||||||
|
self._conn_closed = False
|
||||||
|
|
||||||
|
self._network_os = self._play_context.network_os
|
||||||
|
|
||||||
|
self._local = connection_loader.get("local", play_context, "/dev/null")
|
||||||
|
self._local.set_options()
|
||||||
|
|
||||||
|
self._sub_plugin = {}
|
||||||
|
self._cached_variables = (None, None, None)
|
||||||
|
|
||||||
|
# reconstruct the socket_path and set instance values accordingly
|
||||||
|
self._ansible_playbook_pid = kwargs.get("ansible_playbook_pid")
|
||||||
|
self._update_connection_state()
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
try:
|
||||||
|
return self.__dict__[name]
|
||||||
|
except KeyError:
|
||||||
|
if not name.startswith("_"):
|
||||||
|
plugin = self._sub_plugin.get("obj")
|
||||||
|
if plugin:
|
||||||
|
method = getattr(plugin, name, None)
|
||||||
|
if method is not None:
|
||||||
|
return method
|
||||||
|
raise AttributeError(
|
||||||
|
"'%s' object has no attribute '%s'"
|
||||||
|
% (self.__class__.__name__, name)
|
||||||
|
)
|
||||||
|
|
||||||
|
def exec_command(self, cmd, in_data=None, sudoable=True):
|
||||||
|
return self._local.exec_command(cmd, in_data, sudoable)
|
||||||
|
|
||||||
|
def queue_message(self, level, message):
|
||||||
|
"""
|
||||||
|
Adds a message to the queue of messages waiting to be pushed back to the controller process.
|
||||||
|
|
||||||
|
:arg level: A string which can either be the name of a method in display, or 'log'. When
|
||||||
|
the messages are returned to task_executor, a value of log will correspond to
|
||||||
|
``display.display(message, log_only=True)``, while another value will call ``display.[level](message)``
|
||||||
|
"""
|
||||||
|
self._messages.append((level, message))
|
||||||
|
|
||||||
|
def pop_messages(self):
|
||||||
|
messages, self._messages = self._messages, []
|
||||||
|
return messages
|
||||||
|
|
||||||
|
def put_file(self, in_path, out_path):
|
||||||
|
"""Transfer a file from local to remote"""
|
||||||
|
return self._local.put_file(in_path, out_path)
|
||||||
|
|
||||||
|
def fetch_file(self, in_path, out_path):
|
||||||
|
"""Fetch a file from remote to local"""
|
||||||
|
return self._local.fetch_file(in_path, out_path)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""
|
||||||
|
Reset the connection
|
||||||
|
"""
|
||||||
|
if self._socket_path:
|
||||||
|
self.queue_message(
|
||||||
|
"vvvv",
|
||||||
|
"resetting persistent connection for socket_path %s"
|
||||||
|
% self._socket_path,
|
||||||
|
)
|
||||||
|
self.close()
|
||||||
|
self.queue_message("vvvv", "reset call on connection instance")
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self._conn_closed = True
|
||||||
|
if self._connected:
|
||||||
|
self._connected = False
|
||||||
|
|
||||||
|
def get_options(self, hostvars=None):
|
||||||
|
options = super(NetworkConnectionBase, self).get_options(
|
||||||
|
hostvars=hostvars
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
self._sub_plugin.get("obj")
|
||||||
|
and self._sub_plugin.get("type") != "external"
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
options.update(
|
||||||
|
self._sub_plugin["obj"].get_options(hostvars=hostvars)
|
||||||
|
)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return options
|
||||||
|
|
||||||
|
def set_options(self, task_keys=None, var_options=None, direct=None):
|
||||||
|
super(NetworkConnectionBase, self).set_options(
|
||||||
|
task_keys=task_keys, var_options=var_options, direct=direct
|
||||||
|
)
|
||||||
|
if self.get_option("persistent_log_messages"):
|
||||||
|
warning = (
|
||||||
|
"Persistent connection logging is enabled for %s. This will log ALL interactions"
|
||||||
|
% self._play_context.remote_addr
|
||||||
|
)
|
||||||
|
logpath = getattr(C, "DEFAULT_LOG_PATH")
|
||||||
|
if logpath is not None:
|
||||||
|
warning += " to %s" % logpath
|
||||||
|
self.queue_message(
|
||||||
|
"warning",
|
||||||
|
"%s and WILL NOT redact sensitive configuration like passwords. USE WITH CAUTION!"
|
||||||
|
% warning,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
self._sub_plugin.get("obj")
|
||||||
|
and self._sub_plugin.get("type") != "external"
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
self._sub_plugin["obj"].set_options(
|
||||||
|
task_keys=task_keys, var_options=var_options, direct=direct
|
||||||
|
)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _update_connection_state(self):
|
||||||
|
"""
|
||||||
|
Reconstruct the connection socket_path and check if it exists
|
||||||
|
|
||||||
|
If the socket path exists then the connection is active and set
|
||||||
|
both the _socket_path value to the path and the _connected value
|
||||||
|
to True. If the socket path doesn't exist, leave the socket path
|
||||||
|
value to None and the _connected value to False
|
||||||
|
"""
|
||||||
|
ssh = connection_loader.get("ssh", class_only=True)
|
||||||
|
control_path = ssh._create_control_path(
|
||||||
|
self._play_context.remote_addr,
|
||||||
|
self._play_context.port,
|
||||||
|
self._play_context.remote_user,
|
||||||
|
self._play_context.connection,
|
||||||
|
self._ansible_playbook_pid,
|
||||||
|
)
|
||||||
|
|
||||||
|
tmp_path = unfrackpath(C.PERSISTENT_CONTROL_PATH_DIR)
|
||||||
|
socket_path = unfrackpath(control_path % dict(directory=tmp_path))
|
||||||
|
|
||||||
|
if os.path.exists(socket_path):
|
||||||
|
self._connected = True
|
||||||
|
self._socket_path = socket_path
|
||||||
|
|
||||||
|
def _log_messages(self, message):
|
||||||
|
if self.get_option("persistent_log_messages"):
|
||||||
|
self.queue_message("log", message)
|
Loading…
Reference in New Issue