ansible-test - Add Windows remote connection option

pull/81282/merge
Matt Clay 3 months ago
parent a3ee846a64
commit 81e025b414

@ -0,0 +1,2 @@
minor_changes:
- ansible-test - Connection options can be set for ansible-test managed remote Windows instances.

@ -1,6 +1,6 @@
[windows]
{% for host in vars.groups.windows %}
{{ host }} ansible_host={{ hostvars[host]['ansible_host'] }} ansible_port={{ hostvars[host]['ansible_port'] }} ansible_user={{ hostvars[host]['ansible_user'] }} ansible_password={{ hostvars[host]['ansible_password'] }}
{{ host }} ansible_host={{ hostvars[host]['ansible_host'] }}{% if hostvars[host]['ansible_connection'] != 'ssh' %} ansible_port={{ hostvars[host]['ansible_port'] }}{% endif %} ansible_user={{ hostvars[host]['ansible_user'] }} ansible_password={{ hostvars[host]['ansible_password'] | default(hostvars[host]['ansible_test_connection_password']) }}
{% endfor %}
[windows:vars]

@ -1,6 +1,6 @@
[windows]
{% for host in vars.groups.windows %}
{{ host }} ansible_host={{ hostvars[host]['ansible_host'] }} ansible_port={{ hostvars[host]['ansible_port'] }} ansible_user={{ hostvars[host]['ansible_user'] }} ansible_password={{ hostvars[host]['ansible_password'] }}
{{ host }} ansible_host={{ hostvars[host]['ansible_host'] }}{% if hostvars[host]['ansible_connection'] != 'ssh' %} ansible_port={{ hostvars[host]['ansible_port'] }}{% endif %} ansible_user={{ hostvars[host]['ansible_user'] }} ansible_password={{ hostvars[host]['ansible_password'] | default(hostvars[host]['ansible_test_connection_password']) }}
{% endfor %}
[windows:vars]

@ -1,4 +1,4 @@
windows/2016 provider=aws arch=x86_64
windows/2019 provider=aws arch=x86_64
windows/2022 provider=aws arch=x86_64
windows provider=aws arch=x86_64
windows/2016 provider=aws arch=x86_64 connection=winrm+http
windows/2019 provider=aws arch=x86_64 connection=winrm+https
windows/2022 provider=aws arch=x86_64 connection=winrm+https
windows provider=aws arch=x86_64 connection=winrm+https

@ -17,6 +17,7 @@ from ...completion import (
from ...util import (
REMOTE_ARCHITECTURES,
WINDOWS_CONNECTIONS,
)
from ...host_configs import (
@ -177,6 +178,7 @@ class WindowsRemoteKeyValueParser(KeyValueParser):
return dict(
provider=ChoicesParser(REMOTE_PROVIDERS),
arch=ChoicesParser(REMOTE_ARCHITECTURES),
connection=ChoicesParser(WINDOWS_CONNECTIONS),
)
def document(self, state: DocumentationState) -> t.Optional[str]:
@ -186,6 +188,7 @@ class WindowsRemoteKeyValueParser(KeyValueParser):
state.sections[f'target {section_name} (comma separated):'] = '\n'.join([
f' provider={ChoicesParser(REMOTE_PROVIDERS).document(state)}',
f' arch={ChoicesParser(REMOTE_ARCHITECTURES).document(state)}',
f' connection={ChoicesParser(WINDOWS_CONNECTIONS).document(state)}',
])
return f'{{{section_name}}}'

@ -246,6 +246,8 @@ class PosixRemoteCompletionConfig(RemoteCompletionConfig, PythonCompletionConfig
class WindowsRemoteCompletionConfig(RemoteCompletionConfig):
"""Configuration for remote Windows platforms."""
connection: str = ''
TCompletionConfig = t.TypeVar('TCompletionConfig', bound=CompletionConfig)

@ -399,10 +399,20 @@ class WindowsConfig(HostConfig, metaclass=abc.ABCMeta):
class WindowsRemoteConfig(RemoteConfig, WindowsConfig):
"""Configuration for a remote Windows host."""
connection: t.Optional[str] = None
def get_defaults(self, context: HostContext) -> WindowsRemoteCompletionConfig:
"""Return the default settings."""
return filter_completion(windows_completion()).get(self.name) or windows_completion().get(self.platform)
def apply_defaults(self, context: HostContext, defaults: CompletionConfig) -> None:
"""Apply default settings."""
assert isinstance(defaults, WindowsRemoteCompletionConfig)
super().apply_defaults(context, defaults)
self.connection = self.connection or defaults.connection
@dataclasses.dataclass
class WindowsInventoryConfig(InventoryConfig, WindowsConfig):

@ -56,6 +56,7 @@ from .util import (
InternalError,
HostConnectionError,
ANSIBLE_TEST_TARGET_ROOT,
WINDOWS_CONNECTION_VARIABLES,
)
from .util_common import (
@ -1367,23 +1368,18 @@ class WindowsRemoteProfile(RemoteProfile[WindowsRemoteConfig]):
connection = core_ci.connection
variables: dict[str, t.Optional[t.Union[str, int]]] = dict(
ansible_connection='winrm',
ansible_pipelining='yes',
ansible_winrm_server_cert_validation='ignore',
ansible_host=connection.hostname,
ansible_port=connection.port,
# ansible_port is intentionally not set using connection.port -- connection-specific variables can set this instead
ansible_user=connection.username,
ansible_password=connection.password,
ansible_ssh_private_key_file=core_ci.ssh_key.key,
ansible_ssh_private_key_file=core_ci.ssh_key.key, # required for scenarios which change the connection plugin to SSH
ansible_test_connection_password=connection.password, # required for scenarios which change the connection plugin to require a password
)
# HACK: force 2016 to use NTLM + HTTP message encryption
if self.config.version == '2016':
variables.update(
ansible_winrm_transport='ntlm',
ansible_winrm_scheme='http',
ansible_port='5985',
)
variables.update(ansible_connection=self.config.connection.split('+')[0])
variables.update(WINDOWS_CONNECTION_VARIABLES[self.config.connection])
if variables.pop('use_password'):
variables.update(ansible_password=connection.password)
return variables

@ -134,6 +134,46 @@ class Architecture:
REMOTE_ARCHITECTURES = list(value for key, value in Architecture.__dict__.items() if not key.startswith('__'))
WINDOWS_CONNECTION_VARIABLES: dict[str, t.Any] = {
'psrp+http': dict(
ansible_port=5985,
ansible_psrp_protocol='http',
use_password=True,
),
'psrp+https': dict(
ansible_port=5986,
ansible_psrp_protocol='https',
ansible_psrp_cert_validation='ignore',
use_password=True,
),
'ssh+key': dict(
ansible_port=22,
ansible_shell_type='powershell',
use_password=False,
),
'ssh+password': dict(
ansible_port=22,
ansible_shell_type='powershell',
use_password=True,
),
'winrm+http': dict(
ansible_port=5985,
ansible_winrm_scheme='http',
ansible_winrm_transport='ntlm',
use_password=True,
),
'winrm+https': dict(
ansible_port=5986,
ansible_winrm_scheme='https',
ansible_winrm_server_cert_validation='ignore',
use_password=True,
),
}
"""Dictionary of Windows connection types and variables required to use them."""
WINDOWS_CONNECTIONS = list(WINDOWS_CONNECTION_VARIABLES)
def is_valid_identifier(value: str) -> bool:
"""Return True if the given value is a valid non-keyword Python identifier, otherwise return False."""
return value.isidentifier() and not keyword.iskeyword(value)

Loading…
Cancel
Save