mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-07 13:52:54 +00:00
Add support for Windows hosts in the SSH connection plugin (#47732)
* Add support for Windows hosts in the SSH connection plugin * fix Python 2.6 unit test and sanity issues * fix up connection tests in CI, disable SCP for now * ensure we don't pollute the existing environment during the test * Add connection_windows_ssh to classifier * use test dir for inventory file * Required powershell as default shell and fix tests * Remove exlicit become_methods on connection * clarify console encoding comment * ignore recent SCP errors in integration tests * Add cmd shell type and added more tests * Fix some doc issues * revises windows faq * add anchors for windows links * revises windows setup page * Update changelogs/fragments/windows-ssh.yaml Co-Authored-By: jborean93 <jborean93@gmail.com>
This commit is contained in:
committed by
Matt Davis
parent
cdf475e830
commit
8ef2e6da05
@@ -221,3 +221,7 @@ class ShellBase(AnsiblePlugin):
|
||||
def wrap_for_exec(self, cmd):
|
||||
"""wrap script execution with any necessary decoration (eg '&' for quoted powershell script paths)"""
|
||||
return cmd
|
||||
|
||||
def quote(self, cmd):
|
||||
"""Returns a shell-escaped string that can be safely used as one token in a shell command line"""
|
||||
return shlex_quote(cmd)
|
||||
|
||||
57
lib/ansible/plugins/shell/cmd.py
Normal file
57
lib/ansible/plugins/shell/cmd.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# Copyright (c) 2019 Ansible Project
|
||||
# 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
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: cmd
|
||||
plugin_type: shell
|
||||
version_added: '2.8'
|
||||
short_description: Windows Command Prompt
|
||||
description:
|
||||
- Used with the 'ssh' connection plugin and no C(DefaultShell) has been set on the Windows host.
|
||||
extends_documentation_fragment:
|
||||
- shell_windows
|
||||
'''
|
||||
|
||||
import re
|
||||
|
||||
from ansible.plugins.shell.powershell import ShellModule as PSShellModule
|
||||
|
||||
# these are the metachars that have a special meaning in cmd that we want to escape when quoting
|
||||
_find_unsafe = re.compile(r'[\s\(\)\%\!^\"\<\>\&\|]').search
|
||||
|
||||
|
||||
class ShellModule(PSShellModule):
|
||||
|
||||
# Common shell filenames that this plugin handles
|
||||
COMPATIBLE_SHELLS = frozenset()
|
||||
# Family of shells this has. Must match the filename without extension
|
||||
SHELL_FAMILY = 'cmd'
|
||||
|
||||
_SHELL_REDIRECT_ALLNULL = '>nul 2>&1'
|
||||
_SHELL_AND = '&&'
|
||||
|
||||
# Used by various parts of Ansible to do Windows specific changes
|
||||
_IS_WINDOWS = True
|
||||
|
||||
def quote(self, s):
|
||||
# cmd does not support single quotes that the shlex_quote uses. We need to override the quoting behaviour to
|
||||
# better match cmd.exe.
|
||||
# https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
|
||||
|
||||
# Return an empty argument
|
||||
if not s:
|
||||
return '""'
|
||||
|
||||
if _find_unsafe(s) is None:
|
||||
return s
|
||||
|
||||
# Escape the metachars as we are quoting the string to stop cmd from interpreting that metachar. For example
|
||||
# 'file &whoami.exe' would result in 'file $(whoami.exe)' instead of the literal string
|
||||
# https://stackoverflow.com/questions/3411771/multiple-character-replace-with-python
|
||||
for c in '^()%!"<>&|': # '^' must be the first char that we scan and replace
|
||||
if c in s:
|
||||
s = s.replace(c, "^" + c)
|
||||
|
||||
return '^"' + s + '^"'
|
||||
@@ -5,60 +5,26 @@ from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: powershell
|
||||
plugin_type: shell
|
||||
version_added: ""
|
||||
short_description: Windows Powershell
|
||||
description:
|
||||
- The only option when using 'winrm' as a connection plugin
|
||||
options:
|
||||
async_dir:
|
||||
description:
|
||||
- Directory in which ansible will keep async job information.
|
||||
- Before Ansible 2.8, this was set to C(remote_tmp + "\\.ansible_async").
|
||||
default: '%USERPROFILE%\\.ansible_async'
|
||||
ini:
|
||||
- section: powershell
|
||||
key: async_dir
|
||||
vars:
|
||||
- name: ansible_async_dir
|
||||
version_added: '2.8'
|
||||
remote_tmp:
|
||||
description:
|
||||
- Temporary directory to use on targets when copying files to the host.
|
||||
default: '%TEMP%'
|
||||
ini:
|
||||
- section: powershell
|
||||
key: remote_tmp
|
||||
vars:
|
||||
- name: ansible_remote_tmp
|
||||
set_module_language:
|
||||
description:
|
||||
- Controls if we set the locale for moduels when executing on the
|
||||
target.
|
||||
- Windows only supports C(no) as an option.
|
||||
type: bool
|
||||
default: 'no'
|
||||
choices:
|
||||
- 'no'
|
||||
environment:
|
||||
description:
|
||||
- Dictionary of environment variables and their values to use when
|
||||
executing commands.
|
||||
type: dict
|
||||
default: {}
|
||||
name: powershell
|
||||
plugin_type: shell
|
||||
version_added: historical
|
||||
short_description: Windows PowerShell
|
||||
description:
|
||||
- The only option when using 'winrm' or 'psrp' as a connection plugin.
|
||||
- Can also be used when using 'ssh' as a connection plugin and the C(DefaultShell) has been configured to PowerShell.
|
||||
extends_documentation_fragment:
|
||||
- shell_windows
|
||||
'''
|
||||
# FIXME: admin_users and set_module_language don't belong here but must be set
|
||||
# so they don't failk when someone get_option('admin_users') on this plugin
|
||||
|
||||
import base64
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import pkgutil
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils._text import to_bytes, to_text
|
||||
from ansible.plugins.shell import ShellBase
|
||||
|
||||
|
||||
@@ -71,6 +37,21 @@ if _powershell_version:
|
||||
_common_args = ['PowerShell', '-Version', _powershell_version] + _common_args[1:]
|
||||
|
||||
|
||||
def _parse_clixml(data, stream="Error"):
|
||||
"""
|
||||
Takes a byte string like '#< CLIXML\r\n<Objs...' and extracts the stream
|
||||
message encoded in the XML data. CLIXML is used by PowerShell to encode
|
||||
multiple objects in stderr.
|
||||
"""
|
||||
clixml = ET.fromstring(data.split(b"\r\n", 1)[-1])
|
||||
namespace_match = re.match(r'{(.*)}', clixml.tag)
|
||||
namespace = "{%s}" % namespace_match.group(1) if namespace_match else ""
|
||||
|
||||
strings = clixml.findall("./%sS" % namespace)
|
||||
lines = [e.text.replace('_x000D__x000A_', '') for e in strings if e.attrib.get('S') == stream]
|
||||
return to_bytes('\r\n'.join(lines))
|
||||
|
||||
|
||||
class ShellModule(ShellBase):
|
||||
|
||||
# Common shell filenames that this plugin handles
|
||||
@@ -80,6 +61,12 @@ class ShellModule(ShellBase):
|
||||
# Family of shells this has. Must match the filename without extension
|
||||
SHELL_FAMILY = 'powershell'
|
||||
|
||||
_SHELL_REDIRECT_ALLNULL = '> $null'
|
||||
_SHELL_AND = ';'
|
||||
|
||||
# Used by various parts of Ansible to do Windows specific changes
|
||||
_IS_WINDOWS = True
|
||||
|
||||
env = dict()
|
||||
|
||||
# We're being overly cautious about which keys to accept (more so than
|
||||
|
||||
Reference in New Issue
Block a user