Merge commit 'e334b50d9d5bc5174d1e07c83c6617db6406193e' into release-v0.3.8

pull/1093/head
Alex Willmer 4 months ago
commit d0d39cccf2

@ -6,6 +6,7 @@ import glob
import os import os
import signal import signal
import sys import sys
import textwrap
import ci_lib import ci_lib
@ -74,7 +75,15 @@ with ci_lib.Fold('job_setup'):
fp.write('\n[%s]\n' % family) fp.write('\n[%s]\n' % family)
fp.writelines('%s\n' % name for name in hostnames) fp.writelines('%s\n' % name for name in hostnames)
fp.write('\n[linux:children]\ntest-targets\n') fp.write(textwrap.dedent(
'''
[linux:children]
test-targets
[linux_containers:children]
test-targets
'''
))
ci_lib.dump_file(inventory_path) ci_lib.dump_file(inventory_path)

@ -16,32 +16,21 @@ trigger:
- docs-master - docs-master
jobs: jobs:
- job: mac11 - job: mac12
# vanilla Ansible is really slow # vanilla Ansible is really slow
timeoutInMinutes: 120 timeoutInMinutes: 120
steps: steps:
- template: azure-pipelines-steps.yml - template: azure-pipelines-steps.yml
pool: pool:
# https://github.com/actions/runner-images/blob/main/images/macos/macos-11-Readme.md # https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md
vmImage: macOS-11 vmImage: macOS-12
strategy: strategy:
matrix: matrix:
Mito_27:
tox.env: py27-mode_mitogen
Mito_312: Mito_312:
python.version: '3.12'
tox.env: py312-mode_mitogen tox.env: py312-mode_mitogen
Loc_27_210:
tox.env: py27-mode_localhost-ansible2.10
Loc_312_9: Loc_312_9:
python.version: '3.12'
tox.env: py312-mode_localhost-ansible9 tox.env: py312-mode_localhost-ansible9
Van_27_210:
tox.env: py27-mode_localhost-ansible2.10-strategy_linear
Van_312_9: Van_312_9:
python.version: '3.12'
tox.env: py312-mode_localhost-ansible9-strategy_linear tox.env: py312-mode_localhost-ansible9-strategy_linear
- job: Linux - job: Linux

@ -93,5 +93,5 @@ with ci_lib.Fold('machine_prep'):
with ci_lib.Fold('ansible'): with ci_lib.Fold('ansible'):
os.chdir(TESTS_DIR) os.chdir(TESTS_DIR)
playbook = os.environ.get('PLAYBOOK', 'all.yml') playbook = os.environ.get('PLAYBOOK', 'all.yml')
ci_lib.run('./run_ansible_playbook.py %s -l target %s', ci_lib.run('./run_ansible_playbook.py %s %s',
playbook, ' '.join(sys.argv[1:])) playbook, ' '.join(sys.argv[1:]))

@ -119,7 +119,7 @@ def _connect_ssh(spec):
""" """
Return ContextService arguments for an SSH connection. Return ContextService arguments for an SSH connection.
""" """
if C.HOST_KEY_CHECKING: if spec.host_key_checking():
check_host_keys = 'enforce' check_host_keys = 'enforce'
else: else:
check_host_keys = 'ignore' check_host_keys = 'ignore'

@ -281,11 +281,11 @@ def get_cpu_count(default=None):
class Broker(mitogen.master.Broker): class Broker(mitogen.master.Broker):
""" """
WorkerProcess maintains at most 2 file descriptors, therefore does not need WorkerProcess maintains fewer file descriptors, therefore does not need
the exuberant syscall expense of EpollPoller, so override it and restore the exuberant syscall expense of EpollPoller, so override it and restore
the poll() poller. the poll() poller.
""" """
poller_class = mitogen.core.Poller poller_class = mitogen.parent.POLLER_LIGHTWEIGHT
class Binding(object): class Binding(object):

@ -67,6 +67,7 @@ import ansible.utils.shlex
import ansible.constants as C import ansible.constants as C
from ansible.module_utils.six import with_metaclass from ansible.module_utils.six import with_metaclass
from ansible.module_utils.parsing.convert_bool import boolean
# this was added in Ansible >= 2.8.0; fallback to the default interpreter if necessary # this was added in Ansible >= 2.8.0; fallback to the default interpreter if necessary
try: try:
@ -79,7 +80,6 @@ try:
except ImportError: except ImportError:
from ansible.vars.unsafe_proxy import AnsibleUnsafeText from ansible.vars.unsafe_proxy import AnsibleUnsafeText
import ansible_mitogen.loaders
import mitogen.core import mitogen.core
@ -246,6 +246,12 @@ class Spec(with_metaclass(abc.ABCMeta, object)):
Path to the Python interpreter on the target machine. Path to the Python interpreter on the target machine.
""" """
@abc.abstractmethod
def host_key_checking(self):
"""
Whether or not to check the keys of the target machine
"""
@abc.abstractmethod @abc.abstractmethod
def private_key_file(self): def private_key_file(self):
""" """
@ -436,9 +442,18 @@ class PlayContextSpec(Spec):
return self._play_context.become_user return self._play_context.become_user
def become_pass(self): def become_pass(self):
become_method = self.become_method() # become_pass is owned/provided by the active become plugin. However
become_plugin = ansible_mitogen.loaders.become_loader.get(become_method) # PlayContext is intertwined with it. Known complications
become_pass = become_plugin.get_option('become_pass', hostvars=self._task_vars) # - ansible_become_password is higher priority than ansible_become_pass,
# `play_context.become_pass` doesn't obey this (atleast with Mitgeon).
# - `meta: reset_connection` runs `connection.reset()` but
# `ansible_mitogen.connection.Connection.reset()` recreates the
# connection object, setting `connection.become = None`.
become_plugin = self._connection.become
try:
become_pass = become_plugin.get_option('become_pass', playcontext=self._play_context)
except AttributeError:
become_pass = self._play_context.become_pass
return optional_secret(become_pass) return optional_secret(become_pass)
def password(self): def password(self):
@ -458,6 +473,14 @@ class PlayContextSpec(Spec):
action=self._action, action=self._action,
rediscover_python=rediscover_python) rediscover_python=rediscover_python)
def host_key_checking(self):
def candidates():
yield self._connection.get_task_var('ansible_ssh_host_key_checking')
yield self._connection.get_task_var('ansible_host_key_checking')
yield C.HOST_KEY_CHECKING
val = next((v for v in candidates() if v is not None), True)
return boolean(val)
def private_key_file(self): def private_key_file(self):
return self._play_context.private_key_file return self._play_context.private_key_file
@ -684,6 +707,14 @@ class MitogenViaSpec(Spec):
action=self._action, action=self._action,
rediscover_python=rediscover_python) rediscover_python=rediscover_python)
def host_key_checking(self):
def candidates():
yield self._host_vars.get('ansible_ssh_host_key_checking')
yield self._host_vars.get('ansible_host_key_checking')
yield C.HOST_KEY_CHECKING
val = next((v for v in candidates() if v is not None), True)
return boolean(val)
def private_key_file(self): def private_key_file(self):
# TODO: must come from PlayContext too. # TODO: must come from PlayContext too.
return ( return (

@ -247,6 +247,15 @@ Noteworthy Differences
part of the core library, and should therefore be straightforward to fix as part of the core library, and should therefore be straightforward to fix as
part of 0.2.x. part of 0.2.x.
* Connection and become timeouts are applied differently. Mitogen may consider
a connection to have timed out, when Ansible would have waited longer or
indefinately. For example if SSH authentication completes within the
timeout, but execution of login scripts exceeds it - then Mitogen will
consider the task to have timed out and that host to have failed.
..
tests/ansible/integration/ssh/timeouts.yml covers (some of) this behaviour.
.. ..
* SSH and ``become`` are treated distinctly when applying timeouts, and * SSH and ``become`` are treated distinctly when applying timeouts, and
timeouts apply up to the point when the new interpreter is ready to accept timeouts apply up to the point when the new interpreter is ready to accept

@ -18,6 +18,16 @@ To avail of fixes in an unreleased version, please download a ZIP file
`directly from GitHub <https://github.com/mitogen-hq/mitogen/>`_. `directly from GitHub <https://github.com/mitogen-hq/mitogen/>`_.
v0.3.8 (2024-07-30)
-------------------
* :gh:issue:`952` Fix Ansible `--ask-become-pass`, add test coverage
* :gh:issue:`957` Fix Ansible exception when executing against 10s of hosts
"ValueError: filedescriptor out of range in select()"
* :gh:issue:`1066` Support Ansible `ansible_host_key_checking` & `ansible_ssh_host_key_checking`
* :gh:issue:`1090` CI: Migrate macOS integration tests to macOS 12, drop Python 2.7 jobs
v0.3.7 (2024-04-08) v0.3.7 (2024-04-08)
------------------- -------------------

@ -2,7 +2,7 @@ import sys
sys.path.append('.') sys.path.append('.')
VERSION = '0.3.7' VERSION = '0.3.8'
author = u'Network Genomics' author = u'Network Genomics'
copyright = u'2021, the Mitogen authors' copyright = u'2021, the Mitogen authors'

@ -126,11 +126,13 @@ sponsorship and outstanding future-thinking of its early adopters.
<li>jgadling</li> <li>jgadling</li>
<li>John F Wall &mdash; <em>Making Ansible Great with Massive Parallelism</em></li> <li>John F Wall &mdash; <em>Making Ansible Great with Massive Parallelism</em></li>
<li>KennethC</li> <li>KennethC</li>
<li><a href="https://github.com/lberruti">Luca Berruti</li>
<li>Lewis Bellwood &mdash; <em>Happy to be apart of a great project.</em></li> <li>Lewis Bellwood &mdash; <em>Happy to be apart of a great project.</em></li>
<li>luto</li> <li>luto</li>
<li><a href="https://mayeu.me/">Mayeu a.k.a Matthieu Maury</a></li> <li><a href="https://mayeu.me/">Mayeu a.k.a Matthieu Maury</a></li>
<li><a href="https://twitter.com/nathanhruby">@nathanhruby</a></li> <li><a href="https://twitter.com/nathanhruby">@nathanhruby</a></li>
<li><a href="https://github.com/opoplawski">Orion Poplawski</a></li> <li><a href="https://github.com/opoplawski">Orion Poplawski</a></li>
<li><a href="https://github.com/philfry">Philippe Kueck</a></li>
<li><a href="http://pageflows.com/">Ramy</a></li> <li><a href="http://pageflows.com/">Ramy</a></li>
<li>Scott Vokes</li> <li>Scott Vokes</li>
<li><a href="https://twitter.com/sirtux">Tom Eichhorn</a></li> <li><a href="https://twitter.com/sirtux">Tom Eichhorn</a></li>

@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup.
#: Library version as a tuple. #: Library version as a tuple.
__version__ = (0, 3, 7) __version__ = (0, 3, 8)
#: This is :data:`False` in slave contexts. Previously it was used to prevent #: This is :data:`False` in slave contexts. Previously it was used to prevent

@ -2523,8 +2523,7 @@ class Poller(object):
""" """
A poller manages OS file descriptors the user is waiting to become A poller manages OS file descriptors the user is waiting to become
available for IO. The :meth:`poll` method blocks the calling thread available for IO. The :meth:`poll` method blocks the calling thread
until one or more become ready. The default implementation is based on until one or more become ready.
:func:`select.poll`.
Each descriptor has an associated `data` element, which is unique for each Each descriptor has an associated `data` element, which is unique for each
readiness type, and defaults to being the same as the file descriptor. The readiness type, and defaults to being the same as the file descriptor. The
@ -2546,19 +2545,13 @@ class Poller(object):
a resource leak. a resource leak.
Pollers may only be used by one thread at a time. Pollers may only be used by one thread at a time.
This implementation uses :func:`select.select` for wider platform support.
That is considered an implementation detail. Previous versions have used
:func:`select.poll`. Future versions may decide at runtime.
""" """
SUPPORTED = True SUPPORTED = True
# This changed from select() to poll() in Mitogen 0.2.4. Since poll() has
# no upper FD limit, it is suitable for use with Latch, which must handle
# FDs larger than select's limit during many-host runs. We want this
# because poll() requires no setup and teardown: just a single system call,
# which is important because Latch.get() creates a Poller on each
# invocation. In a microbenchmark, poll() vs. epoll_ctl() is 30% faster in
# this scenario. If select() must return in future, it is important
# Latch.poller_class is set from parent.py to point to the industrial
# strength poller for the OS, otherwise Latch will fail randomly.
#: Increments on every poll(). Used to version _rfds and _wfds. #: Increments on every poll(). Used to version _rfds and _wfds.
_generation = 1 _generation = 1
@ -2681,11 +2674,10 @@ class Latch(object):
See :ref:`waking-sleeping-threads` for further discussion. See :ref:`waking-sleeping-threads` for further discussion.
""" """
#: The :class:`Poller` implementation to use for waiting. Since the poller #: The :class:`Poller` implementation to use. Instances are short lived so
#: will be very short-lived, we prefer :class:`mitogen.parent.PollPoller` #: prefer :class:`mitogen.parent.PollPoller` if it's available, otherwise
#: if it is available, or :class:`mitogen.core.Poller` otherwise, since #: :class:`mitogen.core.Poller`. They don't need syscalls to create,
#: these implementations require no system calls to create, configure or #: configure, or destroy. Replaced during import of :mod:`mitogen.parent`.
#: destroy.
poller_class = Poller poller_class = Poller
#: If not :data:`None`, a function invoked as `notify(latch)` after a #: If not :data:`None`, a function invoked as `notify(latch)` after a

@ -745,8 +745,7 @@ def _upgrade_broker(broker):
broker.timers = TimerList() broker.timers = TimerList()
LOG.debug('upgraded %r with %r (new: %d readers, %d writers; ' LOG.debug('upgraded %r with %r (new: %d readers, %d writers; '
'old: %d readers, %d writers)', old, new, 'old: %d readers, %d writers)', old, new,
len(new.readers), len(new.writers), len(new._rfds), len(new._wfds), len(old._rfds), len(old._wfds))
len(old.readers), len(old.writers))
@mitogen.core.takes_econtext @mitogen.core.takes_econtext
@ -902,22 +901,18 @@ class CallSpec(object):
class PollPoller(mitogen.core.Poller): class PollPoller(mitogen.core.Poller):
""" """
Poller based on the POSIX :linux:man2:`poll` interface. Not available on Poller based on the POSIX :linux:man2:`poll` interface. Not available on
some versions of OS X, otherwise it is the preferred poller for small FD some Python/OS X combinations. Otherwise the preferred poller for small
counts, as there is no setup/teardown/configuration system call overhead. FD counts; or if many pollers are created, used once, then closed.
There there is no setup/teardown/configuration system call overhead.
""" """
SUPPORTED = hasattr(select, 'poll') SUPPORTED = hasattr(select, 'poll')
_repr = 'PollPoller()' _readmask = SUPPORTED and select.POLLIN | select.POLLHUP
def __init__(self): def __init__(self):
super(PollPoller, self).__init__() super(PollPoller, self).__init__()
self._pollobj = select.poll() self._pollobj = select.poll()
# TODO: no proof we dont need writemask too # TODO: no proof we dont need writemask too
_readmask = (
getattr(select, 'POLLIN', 0) |
getattr(select, 'POLLHUP', 0)
)
def _update(self, fd): def _update(self, fd):
mask = (((fd in self._rfds) and self._readmask) | mask = (((fd in self._rfds) and self._readmask) |
((fd in self._wfds) and select.POLLOUT)) ((fd in self._wfds) and select.POLLOUT))
@ -952,7 +947,6 @@ class KqueuePoller(mitogen.core.Poller):
Poller based on the FreeBSD/Darwin :freebsd:man2:`kqueue` interface. Poller based on the FreeBSD/Darwin :freebsd:man2:`kqueue` interface.
""" """
SUPPORTED = hasattr(select, 'kqueue') SUPPORTED = hasattr(select, 'kqueue')
_repr = 'KqueuePoller()'
def __init__(self): def __init__(self):
super(KqueuePoller, self).__init__() super(KqueuePoller, self).__init__()
@ -1030,7 +1024,7 @@ class EpollPoller(mitogen.core.Poller):
Poller based on the Linux :linux:man7:`epoll` interface. Poller based on the Linux :linux:man7:`epoll` interface.
""" """
SUPPORTED = hasattr(select, 'epoll') SUPPORTED = hasattr(select, 'epoll')
_repr = 'EpollPoller()' _inmask = SUPPORTED and select.EPOLLIN | select.EPOLLHUP
def __init__(self): def __init__(self):
super(EpollPoller, self).__init__() super(EpollPoller, self).__init__()
@ -1077,9 +1071,6 @@ class EpollPoller(mitogen.core.Poller):
self._wfds.pop(fd, None) self._wfds.pop(fd, None)
self._control(fd) self._control(fd)
_inmask = (getattr(select, 'EPOLLIN', 0) |
getattr(select, 'EPOLLHUP', 0))
def _poll(self, timeout): def _poll(self, timeout):
the_timeout = -1 the_timeout = -1
if timeout is not None: if timeout is not None:
@ -1100,18 +1091,14 @@ class EpollPoller(mitogen.core.Poller):
yield data yield data
# 2.4 and 2.5 only had select.select() and select.poll(). POLLERS = (EpollPoller, KqueuePoller, PollPoller, mitogen.core.Poller)
for _klass in mitogen.core.Poller, PollPoller, KqueuePoller, EpollPoller: PREFERRED_POLLER = next(cls for cls in POLLERS if cls.SUPPORTED)
if _klass.SUPPORTED:
PREFERRED_POLLER = _klass
# For processes that start many threads or connections, it's possible Latch # For processes that start many threads or connections, it's possible Latch
# will also get high-numbered FDs, and so select() becomes useless there too. # will also get high-numbered FDs, and so select() becomes useless there too.
# So swap in our favourite poller. POLLER_LIGHTWEIGHT = PollPoller.SUPPORTED and PollPoller or PREFERRED_POLLER
if PollPoller.SUPPORTED: mitogen.core.Latch.poller_class = POLLER_LIGHTWEIGHT
mitogen.core.Latch.poller_class = PollPoller
else:
mitogen.core.Latch.poller_class = PREFERRED_POLLER
class LineLoggingProtocolMixin(object): class LineLoggingProtocolMixin(object):

@ -1,9 +1,12 @@
[defaults] [defaults]
any_errors_fatal = true any_errors_fatal = true
# callback_whitelist naming will be deprecated in ansible-core >= 2.15. # callbacks_enabled was added in Ansible 4 (ansible-core 2.11).
# callbacks_enabled naming was added in ansible-core 2.11
# profile_tasks: Displays timing for each task and summary table of top N tasks # profile_tasks: Displays timing for each task and summary table of top N tasks
# timer: Displays "Playbook run took 0 days, 0 hours, ..." # timer: Displays "Playbook run took 0 days, 0 hours, ..."
callbacks_enabled =
profile_tasks,
timer
# callback_whitelist was deprecated in Ansible >= 8 (ansible-core >= 2.15).
callback_whitelist = callback_whitelist =
profile_tasks, profile_tasks,
timer timer
@ -37,7 +40,9 @@ no_target_syslog = True
# Required by integration/ssh/timeouts.yml # Required by integration/ssh/timeouts.yml
timeout = 30 timeout = 30
# On Travis, paramiko check fails due to host key checking enabled. # Ideally this would be true here and and overridden for hosts/groups. However
# ansible_host_key_checking don't work on Vanilla Ansible 2.10, even for
# static inventory hosts (ansible/ansible#49254, ansible/ansible#73708)
host_key_checking = False host_key_checking = False
[inventory] [inventory]

@ -1,14 +1,16 @@
- name: bench/file_transfer.yml - name: bench/file_transfer.yml
hosts: test-targets hosts: test-targets
tasks: tasks:
- name: Make 32MiB file - name: Make 32MiB file
delegate_to: localhost delegate_to: localhost
run_once: true
shell: openssl rand 33554432 > /tmp/bigfile.in shell: openssl rand 33554432 > /tmp/bigfile.in
args:
creates: /tmp/bigfile.in
- name: Make 320MiB file - name: Make 320MiB file
delegate_to: localhost delegate_to: localhost
run_once: true
shell: > shell: >
cat cat
/tmp/bigfile.in /tmp/bigfile.in
@ -22,6 +24,8 @@
/tmp/bigfile.in /tmp/bigfile.in
/tmp/bigfile.in /tmp/bigfile.in
> /tmp/bigbigfile.in > /tmp/bigbigfile.in
args:
creates: /tmp/bigbigfile.in
- name: Delete SSH file is present. - name: Delete SSH file is present.
file: file:
@ -36,17 +40,20 @@
copy: copy:
src: /tmp/bigfile.in src: /tmp/bigfile.in
dest: /tmp/bigfile.out dest: /tmp/bigfile.out
mode: ugo=rw
- name: Copy 320MiB file via SSH - name: Copy 320MiB file via SSH
copy: copy:
src: /tmp/bigbigfile.in src: /tmp/bigbigfile.in
dest: /tmp/bigbigfile.out dest: /tmp/bigbigfile.out
mode: ugo=rw
- name: Delete localhost sudo file if present. - name: Delete localhost sudo file if present.
file: file:
path: "{{item}}" path: "{{item}}"
state: absent state: absent
delegate_to: localhost delegate_to: localhost
run_once: true
become: true become: true
with_items: with_items:
- /tmp/bigfile.out - /tmp/bigfile.out
@ -56,21 +63,51 @@
- name: Copy 32MiB file via localhost sudo - name: Copy 32MiB file via localhost sudo
delegate_to: localhost delegate_to: localhost
run_once: true
become: true become: true
copy: copy:
src: /tmp/bigfile.in src: /tmp/bigfile.in
dest: /tmp/bigfile.out dest: /tmp/bigfile.out
mode: ugo=rw
tags: tags:
- requires_local_sudo - requires_local_sudo
- name: Copy 320MiB file via localhost sudo - name: Copy 320MiB file via localhost sudo
delegate_to: localhost delegate_to: localhost
run_once: true
become: true become: true
copy: copy:
src: /tmp/bigbigfile.in src: /tmp/bigbigfile.in
dest: /tmp/bigbigfile.out dest: /tmp/bigbigfile.out
mode: ugo=rw
tags: tags:
- requires_local_sudo - requires_local_sudo
- name: Local cleanup
file:
path: "{{ item.path }}"
state: absent
loop:
- /tmp/bigfile.in
- /tmp/bigfile.out
- /tmp/bigbigfile.in
- /tmp/bigbigfile.out
delegate_to: localhost
run_once: true
tags:
- cleanup_local
- cleanup
- name: Target cleanup
file:
path: "{{ item.path }}"
state: absent
loop:
- /tmp/bigfile.out
- /tmp/bigbigfile.out
tags:
- cleanup_target
- cleanup
tags: tags:
- resource_intensive - resource_intensive

@ -10,3 +10,5 @@ target ansible_host=localhost ansible_user="{{ lookup('pipe', 'whoami') }}"
[test-targets] [test-targets]
target target
[linux_containers]

@ -1,2 +1,3 @@
--- ---
pkg_mgr_python_interpreter: python pkg_mgr_python_interpreter: python
pkg_repos_overrides: []

@ -1,2 +1,28 @@
--- ---
pkg_mgr_python_interpreter: /usr/libexec/platform-python pkg_mgr_python_interpreter: /usr/libexec/platform-python
pkg_repos_overrides:
- dest: /etc/yum.repos.d/CentOS-Linux-AppStream.repo
content: |
[appstream]
name=CentOS Linux $releasever - AppStream
baseurl=http://vault.centos.org/$contentdir/$releasever/AppStream/$basearch/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
- dest: /etc/yum.repos.d/CentOS-Linux-BaseOS.repo
content: |
[baseos]
name=CentOS Linux $releasever - BaseOS
baseurl=http://vault.centos.org/$contentdir/$releasever/BaseOS/$basearch/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
- dest: /etc/yum.repos.d/CentOS-Linux-Extras.repo
content: |
[extras]
name=CentOS Linux $releasever - Extras
baseurl=http://vault.centos.org/$contentdir/$releasever/extras/$basearch/os/
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial

@ -0,0 +1,4 @@
pkg_repos_overrides:
- dest: /etc/apt/sources.list
content: |
deb http://archive.debian.org/debian stretch main contrib non-free

@ -13,6 +13,7 @@ tc_become
tc_become_method tc_become_method
tc_become_pass tc_become_pass
tc_become_user tc_become_user
tc_host_key_checking
tc_password tc_password
tc_port tc_port
tc_remote_addr tc_remote_addr
@ -74,6 +75,11 @@ tc-become-pass-password ansible_become_password=apassword
tc-become-pass-pass ansible_become_pass=apass tc-become-pass-pass ansible_become_pass=apass
tc-become-pass-both ansible_become_pass=bpass ansible_become_password=bpassword tc-become-pass-both ansible_become_pass=bpass ansible_become_password=bpassword
[tc_host_key_checking]
tc-hkc-unset
tc-hkc-host-key-checking ansible_host_key_checking=true
tc-hkc-ssh-host-key-checking ansible_ssh_host_key_checking=true
[tc_port] [tc_port]
tc-port-unset tc-port-unset
tc-port-explicit-port ansible_port=1234 tc-port-explicit-port ansible_port=1234

@ -9,6 +9,7 @@
content: content:
this is a tiny file. this is a tiny file.
delegate_to: localhost delegate_to: localhost
run_once: true
- name: Create large file - name: Create large file
copy: copy:
@ -16,6 +17,7 @@
# Must be larger than Connection.SMALL_SIZE_LIMIT. # Must be larger than Connection.SMALL_SIZE_LIMIT.
content: "{% for x in range(200000) %}x{% endfor %}" content: "{% for x in range(200000) %}x{% endfor %}"
delegate_to: localhost delegate_to: localhost
run_once: true
- name: Cleanup copied files - name: Cleanup copied files
file: file:

@ -38,6 +38,7 @@
- name: Create local weird mode file - name: Create local weird mode file
delegate_to: localhost delegate_to: localhost
run_once: true
copy: copy:
content: "weird mode" content: "weird mode"
dest: "/tmp/weird-mode" dest: "/tmp/weird-mode"

@ -24,18 +24,21 @@
path: /tmp/sync-test path: /tmp/sync-test
state: absent state: absent
delegate_to: localhost delegate_to: localhost
run_once: true
- name: Create sync-test - name: Create sync-test
file: file:
path: /tmp/sync-test path: /tmp/sync-test
state: directory state: directory
delegate_to: localhost delegate_to: localhost
run_once: true
- name: Create syn-test item - name: Create syn-test item
copy: copy:
dest: /tmp/sync-test/item dest: /tmp/sync-test/item
content: "item!" content: "item!"
delegate_to: localhost delegate_to: localhost
run_once: true
# TODO: https://github.com/dw/mitogen/issues/692 # TODO: https://github.com/dw/mitogen/issues/692
# - file: # - file:

@ -21,8 +21,7 @@
# sudo-1.8.6p3-29.el6_10.3 on RHEL & CentOS 6.10 (final release) # sudo-1.8.6p3-29.el6_10.3 on RHEL & CentOS 6.10 (final release)
# removed user/group error messages, as defence against CVE-2019-14287. # removed user/group error messages, as defence against CVE-2019-14287.
- >- - >-
'sudo: unknown user: slartibartfast' in out.module_stdout | default(out.msg) (out.module_stderr | default(out.module_stdout, true) | default(out.msg, true)) is search('sudo: unknown user:? slartibartfast')
or 'sudo: unknown user: slartibartfast' in out.module_stderr | default(out.msg)
or (ansible_facts.os_family == 'RedHat' and ansible_facts.distribution_version == '6.10') or (ansible_facts.os_family == 'RedHat' and ansible_facts.distribution_version == '6.10')
fail_msg: out={{out}} fail_msg: out={{out}}
when: when:

@ -0,0 +1,17 @@
- name: Cleanup local file
file:
path: /tmp/{{ file_name }}
state: absent
delegate_to: localhost
run_once: true
tags:
- cleanup_local
- cleanup
- name: Cleanup target file
file:
path: /tmp/{{ file_name }}.out
state: absent
tags:
- cleanup_target
- cleanup

@ -1,20 +1,21 @@
---
- name: Create {{ file_name }} - name: Create {{ file_name }}
shell: dd if=/dev/urandom of=/tmp/{{ file_name }} bs=1024 count={{ file_size }} command:
args: cmd: dd if=/dev/urandom of=/tmp/{{ file_name }} bs=1024 count={{ file_size_kib }}
creates: /tmp/{{file_name}} creates: /tmp/{{file_name}}
delegate_to: localhost delegate_to: localhost
run_once: true
- name: Copy {{ file_name }} - name: Copy {{ file_name }}
copy: copy:
dest: /tmp/{{file_name}}.out dest: /tmp/{{file_name}}.out
src: /tmp/{{file_name}} src: /tmp/{{file_name}}
mode: "{{ file_mode }}"
- name: Stat created {{ file_name }} - name: Stat created {{ file_name }}
stat: path=/tmp/{{ file_name }} stat: path=/tmp/{{ file_name }}
register: original register: original
delegate_to: localhost delegate_to: localhost
run_once: true
- name: Stat copied {{ file_name }} - name: Stat copied {{ file_name }}
stat: path=/tmp/{{ file_name }}.out stat: path=/tmp/{{ file_name }}.out

@ -10,6 +10,8 @@
- name: Run _disconnect_during_module.yml - name: Run _disconnect_during_module.yml
delegate_to: localhost delegate_to: localhost
environment:
ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}"
command: | command: |
ansible-playbook ansible-playbook
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}

@ -6,9 +6,11 @@
gather_facts: no gather_facts: no
vars: vars:
file_name: large-file file_name: large-file
file_size: 512 file_size_kib: 512
file_mode: u=rw,go=
tasks: tasks:
- include_tasks: _put_file.yml - include_tasks: _put_file.yml
- include_tasks: _cleanup_file.yml
tags: tags:
- put_file - put_file
- put_large_file - put_large_file

@ -6,9 +6,11 @@
gather_facts: no gather_facts: no
vars: vars:
file_name: small-file file_name: small-file
file_size: 123 file_size_kib: 123
file_mode: u=rw,go=
tasks: tasks:
- include_tasks: _put_file.yml - include_tasks: _put_file.yml
- include_tasks: _cleanup_file.yml
tags: tags:
- put_file - put_file
- put_small_file - put_small_file

@ -29,20 +29,18 @@
special_python: "source /tmp/fake || true && python{{ ansible_facts.python.version.major }}" special_python: "source /tmp/fake || true && python{{ ansible_facts.python.version.major }}"
- name: run get_url with specially-sourced python - name: run get_url with specially-sourced python
get_url: uri:
# Plain http for wider Ansible & Python version compatibility # Plain http for wider Ansible & Python version compatibility
url: http://httpbin.org/get url: http://www.gstatic.com/generate_204
dest: "/tmp/" status_code: [204]
mode: 0644
vars: vars:
ansible_python_interpreter: "{{ special_python }}" ansible_python_interpreter: "{{ special_python }}"
- name: run get_url with specially-sourced python including jinja - name: run get_url with specially-sourced python including jinja
get_url: uri:
# Plain http for wider Ansible & Python version compatibility # Plain http for wider Ansible & Python version compatibility
url: http://httpbin.org/get url: http://www.gstatic.com/generate_204
dest: "/tmp/" status_code: [204]
mode: 0644
vars: vars:
ansible_python_interpreter: > ansible_python_interpreter: >
{% if "1" == "1" %} {% if "1" == "1" %}

@ -1,23 +1,27 @@
- name: integration/playbook_semantics/delegate_to.yml - name: integration/playbook_semantics/delegate_to.yml
hosts: test-targets hosts: test-targets
vars:
local_path: "/tmp/delegate_to.{{ inventory_hostname }}.txt"
tasks: tasks:
# #
# delegate_to, no sudo # delegate_to, no sudo
# #
- name: "delegate_to, no sudo" - name: "delegate_to, no sudo"
copy: copy:
dest: /tmp/delegate_to.yml.txt dest: "{{ local_path }}"
content: "Hello, world." content: "Hello, world."
register: out mode: u=rw,go=r
delegate_to: localhost delegate_to: localhost
- name: "delegate_to, no sudo" - name: "delegate_to, no sudo"
assert: assert:
that: "lookup('file', '/tmp/delegate_to.yml.txt') == 'Hello, world.'" that:
- lookup('file', local_path) == 'Hello, world.'
fail_msg: "{{ lookup('file', local_path) }}"
- name: "delegate_to, no sudo" - name: "delegate_to, no sudo"
file: file:
path: /tmp/delegate_to.yml.txt path: "{{ local_path }}"
state: absent state: absent
delegate_to: localhost delegate_to: localhost
@ -27,18 +31,20 @@
# #
- name: "connection:local, no sudo" - name: "connection:local, no sudo"
copy: copy:
dest: /tmp/delegate_to.yml.txt dest: "{{ local_path }}"
content: "Hello, world." content: "Hello, world."
register: out mode: u=rw,go=r
connection: local connection: local
- name: "connection:local, no sudo" - name: "connection:local, no sudo"
assert: assert:
that: "lookup('file', '/tmp/delegate_to.yml.txt') == 'Hello, world.'" that:
- lookup('file', local_path) == 'Hello, world.'
fail_msg: "{{ lookup('file', local_path) }}"
- name: "connection:local, no sudo" - name: "connection:local, no sudo"
file: file:
path: /tmp/delegate_to.yml.txt path: "{{ local_path }}"
state: absent state: absent
connection: local connection: local
@ -47,7 +53,10 @@
# delegate_to, sudo # delegate_to, sudo
# #
- name: "delegate_to, sudo" - name: "delegate_to, sudo"
shell: whoami > /tmp/delegate_to.yml.txt shell: |
whoami > "{{ local_path }}"
args:
creates: "{{ local_path }}"
delegate_to: localhost delegate_to: localhost
become: true become: true
tags: tags:
@ -55,13 +64,15 @@
- name: "delegate_to, sudo" - name: "delegate_to, sudo"
assert: assert:
that: "lookup('file', '/tmp/delegate_to.yml.txt') == 'root'" that:
- lookup('file', local_path) == 'root'
fail_msg: "{{ lookup('file', local_path) }}"
tags: tags:
- requires_local_sudo - requires_local_sudo
- name: "delegate_to, sudo" - name: "delegate_to, sudo"
file: file:
path: /tmp/delegate_to.yml.txt path: "{{ local_path }}"
state: absent state: absent
delegate_to: localhost delegate_to: localhost
become: true become: true
@ -73,7 +84,10 @@
# connection:local, sudo # connection:local, sudo
# #
- name: "connection:local, sudo" - name: "connection:local, sudo"
shell: whoami > /tmp/delegate_to.yml.txt shell: |
whoami > "{{ local_path }}"
args:
creates: "{{ local_path }}"
connection: local connection: local
become: true become: true
tags: tags:
@ -81,13 +95,15 @@
- name: "connection:local, sudo" - name: "connection:local, sudo"
assert: assert:
that: "lookup('file', '/tmp/delegate_to.yml.txt') == 'root'" that:
- lookup('file', local_path) == 'root'
fail_msg: "{{ lookup('file', local_path) }}"
tags: tags:
- requires_local_sudo - requires_local_sudo
- name: "connection:local, sudo" - name: "connection:local, sudo"
file: file:
path: /tmp/delegate_to.yml.txt path: "{{ local_path }}"
state: absent state: absent
connection: local connection: local
become: true become: true

@ -10,6 +10,7 @@
- shell: > - shell: >
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -c local -a whoami ansible -m shell -c local -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"

@ -1,12 +1,13 @@
- name: integration/runner/missing_module.yml - name: integration/runner/missing_module.yml
hosts: test-targets[0] hosts: test-targets[0]
connection: local connection: local
tasks: tasks:
- name: Run missing_module - name: Run missing_module
connection: local connection: local
environment:
ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}"
command: | command: |
ansible -vvv ansible
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
{% endfor %} {% endfor %}
@ -15,6 +16,8 @@
args: args:
chdir: ../.. chdir: ../..
register: out register: out
changed_when: false
check_mode: false
ignore_errors: true ignore_errors: true
- assert: - assert:

@ -1,7 +1,12 @@
# Ensure 'ssh' connections time out correctly. # Ensure 'ssh' connections time out correctly.
# mitogen__slow_user performs a long sleep in ~/.profile.
# Mitogen counts this time towards the connection timeout. Ansible doesn't.
# ansible_python_interpreter=python3000 is an optimisation, to avoid waiting
# on the timeout multiple times (e.g. interpreter discovery).
- name: integration/ssh/timeouts.yml - name: integration/ssh/timeouts.yml
hosts: test-targets hosts: test-targets
gather_facts: false
tasks: tasks:
- include_tasks: ../_mitogen_only.yml - include_tasks: ../_mitogen_only.yml
@ -9,17 +14,21 @@
connection: local connection: local
environment: environment:
ANSIBLE_SSH_TIMEOUT: 10 ANSIBLE_SSH_TIMEOUT: 10
ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}"
command: | command: |
ansible -vvv ansible
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
{% endfor %} {% endfor %}
test-targets "{{ inventory_hostname }}"
-m custom_python_detect_environment -m ping
-e ansible_user=mitogen__slow_user -e ansible_password=slow_user_password -e ansible_user=mitogen__slow_user -e ansible_password=slow_user_password
-e ansible_python_interpreter=python3000
args: args:
chdir: ../.. chdir: ../..
register: out register: out
changed_when: false
check_mode: false
ignore_errors: true ignore_errors: true
- name: Verify connection timeout occurred - name: Verify connection timeout occurred

@ -20,6 +20,7 @@
ANSIBLE_ANY_ERRORS_FATAL=false ANSIBLE_ANY_ERRORS_FATAL=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -a whoami ansible -m shell -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
@ -36,6 +37,7 @@
ANSIBLE_ANY_ERRORS_FATAL=false ANSIBLE_ANY_ERRORS_FATAL=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -a whoami ansible -m shell -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
@ -43,6 +45,7 @@
test-targets test-targets
-e ansible_ssh_user=mitogen__has_sudo -e ansible_ssh_user=mitogen__has_sudo
-e ansible_ssh_pass=wrong_password -e ansible_ssh_pass=wrong_password
-e ansible_python_interpreter=python3000
args: args:
chdir: ../.. chdir: ../..
register: out register: out
@ -59,6 +62,7 @@
ANSIBLE_ANY_ERRORS_FATAL=false ANSIBLE_ANY_ERRORS_FATAL=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -a whoami ansible -m shell -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
@ -75,6 +79,7 @@
ANSIBLE_ANY_ERRORS_FATAL=false ANSIBLE_ANY_ERRORS_FATAL=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -a whoami ansible -m shell -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
@ -82,6 +87,7 @@
test-targets test-targets
-e ansible_user=mitogen__has_sudo -e ansible_user=mitogen__has_sudo
-e ansible_ssh_pass=wrong_password -e ansible_ssh_pass=wrong_password
-e ansible_python_interpreter=python3000
args: args:
chdir: ../.. chdir: ../..
register: out register: out
@ -98,6 +104,7 @@
ANSIBLE_ANY_ERRORS_FATAL=false ANSIBLE_ANY_ERRORS_FATAL=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -a whoami ansible -m shell -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
@ -114,6 +121,7 @@
ANSIBLE_ANY_ERRORS_FATAL=false ANSIBLE_ANY_ERRORS_FATAL=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -a whoami ansible -m shell -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
@ -121,6 +129,7 @@
test-targets test-targets
-e ansible_user=mitogen__has_sudo -e ansible_user=mitogen__has_sudo
-e ansible_password=wrong_password -e ansible_password=wrong_password
-e ansible_python_interpreter=python3000
args: args:
chdir: ../.. chdir: ../..
register: out register: out
@ -142,6 +151,7 @@
ANSIBLE_ANY_ERRORS_FATAL=false ANSIBLE_ANY_ERRORS_FATAL=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -a whoami ansible -m shell -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
@ -158,6 +168,7 @@
ANSIBLE_ANY_ERRORS_FATAL=false ANSIBLE_ANY_ERRORS_FATAL=false
ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_STRATEGY=mitogen_linear
ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa"
ANSIBLE_VERBOSITY="{{ ansible_verbosity }}"
ansible -m shell -a whoami ansible -m shell -a whoami
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
@ -165,6 +176,7 @@
test-targets test-targets
-e ansible_user=mitogen__has_sudo -e ansible_user=mitogen__has_sudo
-e ansible_ssh_private_key_file=/dev/null -e ansible_ssh_private_key_file=/dev/null
-e ansible_python_interpreter=python3000
args: args:
chdir: ../.. chdir: ../..
register: out register: out

@ -3,24 +3,26 @@
hosts: test-targets[0] hosts: test-targets[0]
tasks: tasks:
- connection: local - connection: local
environment:
ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}"
command: | command: |
ansible-playbook ansible-playbook
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
{% endfor %} {% endfor %}
-vvv
integration/strategy/_mixed_mitogen_vanilla.yml integration/strategy/_mixed_mitogen_vanilla.yml
args: args:
chdir: ../.. chdir: ../..
register: out register: out
- connection: local - connection: local
environment:
ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}"
command: | command: |
ansible-playbook ansible-playbook
{% for inv in ansible_inventory_sources %} {% for inv in ansible_inventory_sources %}
-i "{{ inv }}" -i "{{ inv }}"
{% endfor %} {% endfor %}
-vvv
integration/strategy/_mixed_vanilla_mitogen.yml integration/strategy/_mixed_vanilla_mitogen.yml
args: args:
chdir: ../.. chdir: ../..

@ -12,6 +12,8 @@
- include_tasks: _end_play_if_not_sudo_linux.yml - include_tasks: _end_play_if_not_sudo_linux.yml
- name: Run stub-lxc-info.py - name: Run stub-lxc-info.py
environment:
ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}"
command: | command: |
sudo -nE "{{lookup('env', 'VIRTUAL_ENV')}}/bin/ansible" sudo -nE "{{lookup('env', 'VIRTUAL_ENV')}}/bin/ansible"
-i localhost, -i localhost,

@ -12,6 +12,8 @@
- include_tasks: _end_play_if_not_sudo_linux.yml - include_tasks: _end_play_if_not_sudo_linux.yml
- name: Run ansible stub-lxc.py - name: Run ansible stub-lxc.py
environment:
ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}"
command: | command: |
sudo -nE "{{lookup('env', 'VIRTUAL_ENV')}}/bin/ansible" sudo -nE "{{lookup('env', 'VIRTUAL_ENV')}}/bin/ansible"
-i localhost, -i localhost,

@ -2,6 +2,7 @@
- import_playbook: become_pass.yml - import_playbook: become_pass.yml
- import_playbook: become_user.yml - import_playbook: become_user.yml
- import_playbook: become.yml - import_playbook: become.yml
- import_playbook: host_key_checking.yml
- import_playbook: password.yml - import_playbook: password.yml
- import_playbook: port.yml - import_playbook: port.yml
- import_playbook: python_path.yml - import_playbook: python_path.yml

@ -143,8 +143,9 @@
- out.result|length == 2 - out.result|length == 2
- out.result[0].method == "ssh" - out.result[0].method == "ssh"
- out.result[1].method == "sudo" - out.result[1].method == "sudo"
# Ansible >= 2.10 builtin become plugins (e.g. sudo, su) give priority # Ansible <= 2.9.1 prioritises ansible_become_password.
# to ansible_become_pass over ansible_become_password. # Ansible >= 2.9.2 prioritises ansible_become_pass.
# https://github.com/ansible/ansible/commit/480b106d6535978ae6ecab68b40942ca4fa914a0
- out.result[1].kwargs.password == "bpass" - out.result[1].kwargs.password == "bpass"
fail_msg: out={{out}} fail_msg: out={{out}}
tags: tags:

@ -0,0 +1,94 @@
# Each case is followed by mitogen_via= case to test hostvars method.
- name: integration/transport_config/host_key_checking.yml
hosts: tc-hkc-unset
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 1
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "ignore"
fail_msg: out={{ out }}
tags:
- mitogen_only
- hosts: tc-hkc-unset
vars:
mitogen_via: tc-hkc-host-key-checking
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 2
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "enforce"
- out.result[1].method == "ssh"
- out.result[1].kwargs.check_host_keys == "ignore"
fail_msg: out={{ out }}
tags:
- mitogen_only
- hosts: tc-hkc-host-key-checking
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 1
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "enforce"
fail_msg: out={{ out }}
tags:
- mitogen_only
- hosts: tc-hkc-host-key-checking
vars:
mitogen_via: tc-hkc-unset
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 2
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "ignore"
- out.result[1].method == "ssh"
- out.result[1].kwargs.check_host_keys == "enforce"
fail_msg: out={{ out }}
tags:
- mitogen_only
- hosts: tc-hkc-ssh-host-key-checking
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 1
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "enforce"
fail_msg: out={{ out }}
tags:
- mitogen_only
- hosts: tc-hkc-ssh-host-key-checking
vars:
mitogen_via: tc-hkc-unset
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 2
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "ignore"
- out.result[1].method == "ssh"
- out.result[1].kwargs.check_host_keys == "enforce"
fail_msg: out={{ out }}
tags:
- mitogen_only

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python
# I am an Ansible Python JSONARGS module. I should receive an encoding string. # I am an Ansible Python JSONARGS module. I should receive an encoding string.
json_arguments = """<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>""" json_arguments = """<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>"""

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python
# #591: call os.getcwd() before AnsibleModule ever gets a chance to fix up the # #591: call os.getcwd() before AnsibleModule ever gets a chance to fix up the
# process environment. # process environment.

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python
# I am an Ansible Python WANT_JSON module. I should receive a JSON-encoded file. # I am an Ansible Python WANT_JSON module. I should receive a JSON-encoded file.
import json import json

@ -14,3 +14,5 @@
- import_playbook: issue_615__streaming_transfer.yml - import_playbook: issue_615__streaming_transfer.yml
- import_playbook: issue_655__wait_for_connection_error.yml - import_playbook: issue_655__wait_for_connection_error.yml
- import_playbook: issue_776__load_plugins_called_twice.yml - import_playbook: issue_776__load_plugins_called_twice.yml
- import_playbook: issue_952__ask_become_pass.yml
- import_playbook: issue_1066__add_host__host_key_checking.yml

@ -0,0 +1,9 @@
- name: regression/become_test.yml
hosts: test-targets:&linux_containers
become: true
become_user: mitogen__pw_required
strategy: mitogen_linear
tasks:
- command: whoami
changed_when: false
check_mode: false

@ -0,0 +1,67 @@
- name: regression/issue_1066__add_host__host_key_checking.yml
hosts: test-targets[0]
gather_facts: false
become: false
tasks:
- name: Add hosts dynamically
add_host:
name: "{{ item.name }}"
ansible_host_key_checking: "{{ item.host_key_checking | default(omit) }}"
ansible_ssh_host_key_checking: "{{ item.host_ssh_key_checking | default(omit) }}"
ansible_host: "{{ hostvars[inventory_hostname].ansible_host | default(omit) }}"
ansible_password: "{{ hostvars[inventory_hostname].ansible_password | default(omit) }}"
ansible_port: "{{ hostvars[inventory_hostname].ansible_port | default(omit) }}"
ansible_python_interpreter: "{{ hostvars[inventory_hostname].ansible_python_interpreter | default(omit) }}"
ansible_user: "{{ hostvars[inventory_hostname].ansible_user | default(omit) }}"
loop:
- {name: issue-1066-host-hkc-false, host_key_checking: false}
- {name: issue-1066-host-hkc-true, host_key_checking: true}
- {name: issue-1066-host-hskc-false, host_ssh_key_checking: false}
- {name: issue-1066-host-hskc-true, host_ssh_key_checking: true}
delegate_to: localhost
tags:
- issue_1066
- name: regression/issue_1066__add_host__host_key_checking.yml
hosts: issue-1066-host-*
gather_facts: false
become: false
serial: 1
tasks:
- meta: reset_connection
# The host key might be in ~/.ssh/known_hosts. If it's removed then no
# problem - test-targets hosts have host_key_checking=false.
- name: Remove existing host keys
known_hosts:
name: "{{ ansible_host }}"
state: absent
delegate_to: localhost
- name: Ping dynamically added hosts
ping:
ignore_errors: true
ignore_unreachable: true
register: issue_1066_ping
- debug:
var: issue_1066_ping
- name: Confirm dynamically added hosts are/are not reachable
vars:
expected:
issue-1066-host-hkc-false: {}
issue-1066-host-hkc-true: {unreachable: true}
issue-1066-host-hskc-false: {}
issue-1066-host-hskc-true: {unreachable: true}
assert:
that:
- issue_1066_ping.unreachable is defined == expected[inventory_hostname].unreachable is defined
- issue_1066_ping.unreachable | default(42) == expected[inventory_hostname].unreachable | default(42)
# ansible_host_key_checking don't work on Vanilla Ansible 2.10, even for
# static inventory hosts (ansible/ansible#49254, ansible/ansible#73708).
when:
- ansible_version.full is version('2.11', '>=', strict=True)
or is_mitogen
tags:
- issue_1066

@ -8,6 +8,7 @@
- name: Create file tree - name: Create file tree
connection: local connection: local
run_once: true
shell: > shell: >
mkdir /tmp/filetree.in; mkdir /tmp/filetree.in;
seq -f /tmp/filetree.in/%g 1 1000 | xargs touch; seq -f /tmp/filetree.in/%g 1 1000 | xargs touch;
@ -21,17 +22,30 @@
file: file:
state: directory state: directory
path: /tmp/filetree.out path: /tmp/filetree.out
mode: u=rwx,go=rx
- name: Trigger nasty process pileup - name: Trigger nasty process pileup
copy: copy:
src: "{{item.src}}" src: "{{item.src}}"
dest: "/tmp/filetree.out/{{item.path}}" dest: "/tmp/filetree.out/{{item.path}}"
mode: 0644 mode: u=rw,go=r
with_filetree: /tmp/filetree.in with_filetree: /tmp/filetree.in
when: item.state == 'file' when: item.state == 'file'
loop_control: loop_control:
label: "/tmp/filetree.out/{{ item.path }}" label: "/tmp/filetree.out/{{ item.path }}"
- name: Cleanup local file tree
connection: local
run_once: true
file:
path: /tmp/filetree.in
state: absent
- name: Cleanup remote file tree
file:
path: /tmp/filetree.out
state: absent
tags: tags:
- resource_intensive - resource_intensive
- issue_140 - issue_140

@ -4,10 +4,9 @@
# can test for. # can test for.
- name: regression/issue_152__local_action_wrong_interpreter.yml - name: regression/issue_152__local_action_wrong_interpreter.yml
hosts: test-targets hosts: test-targets[0]
connection: local connection: local
tasks: tasks:
- name: Create /tmp/issue_152_interpreter.sh - name: Create /tmp/issue_152_interpreter.sh
copy: copy:
dest: /tmp/issue_152_interpreter.sh dest: /tmp/issue_152_interpreter.sh

@ -19,9 +19,6 @@
# Will crash if process has a nonexistent CWD. # Will crash if process has a nonexistent CWD.
- custom_python_os_getcwd: - custom_python_os_getcwd:
script: |
import os
self._connection.get_chain().call(os.getcwd)
tags: tags:
- issue_591 - issue_591
- mitogen_only - mitogen_only

@ -14,11 +14,14 @@
shell: | shell: |
dd if=/dev/zero of=/tmp/512mb.zero bs=1048576 count=512; dd if=/dev/zero of=/tmp/512mb.zero bs=1048576 count=512;
chmod go= /tmp/512mb.zero chmod go= /tmp/512mb.zero
args:
creates: /tmp/512mb.zero
- name: Fetch /tmp/512mb.zero - name: Fetch /tmp/512mb.zero
fetch: fetch:
src: /tmp/512mb.zero src: /tmp/512mb.zero
dest: /tmp/fetch-out dest: /tmp/fetch-{{ inventory_hostname }}-512mb.zero
flat: true
- name: Cleanup /tmp/512mb.zero - name: Cleanup /tmp/512mb.zero
file: file:
@ -27,11 +30,10 @@
- name: Cleanup fetched file - name: Cleanup fetched file
file: file:
path: /tmp/fetch-out path: /tmp/fetch-{{ inventory_hostname }}-512mb.zero
state: absent state: absent
become: false become: false
delegate_to: localhost delegate_to: localhost
run_once: true
tags: tags:
- issue_615 - issue_615
- mitogen_only - mitogen_only

@ -4,11 +4,18 @@
# since things are ran on localhost; Azure DevOps loses connection and fails # since things are ran on localhost; Azure DevOps loses connection and fails
# TODO: do we want to install docker a different way to be able to do this for other tests too # TODO: do we want to install docker a different way to be able to do this for other tests too
--- ---
- name: regression/issue_655_wait_for_connection_error.yml - name: regression/issue_655__wait_for_connection_error.yml
hosts: localhost hosts: localhost
gather_facts: yes gather_facts: yes
become: no become: no
tasks: tasks:
- meta: end_play
when:
# TODO CI currently runs on macOS 12 & which isn't supported by Podman
# version available in Homebrew.
- ansible_facts.system == 'Darwin'
- ansible_facts.distribution_version is version('13.0', '<', strict=True)
- name: set up test container and run tests inside it - name: set up test container and run tests inside it
block: block:
- name: install deps - name: install deps

@ -10,21 +10,14 @@
ansible_python_interpreter: "{{ pkg_mgr_python_interpreter }}" ansible_python_interpreter: "{{ pkg_mgr_python_interpreter }}"
package: rsync # Chosen to exist in all tested distros/package managers package: rsync # Chosen to exist in all tested distros/package managers
tasks: tasks:
- name: Switch to centos-stream - name: Switch to archived package repositories
command: dnf --assumeyes --disablerepo="*" --enablerepo=extras swap centos-linux-repos centos-stream-repos
when:
- ansible_facts.pkg_mgr in ["dnf"]
- name: Switch to archive.debian.org
# Debian 9 has been archived https://lists.debian.org/debian-devel-announce/2023/03/msg00006.html
copy: copy:
content: | dest: "{{ item.dest }}"
deb http://archive.debian.org/debian stretch main contrib non-free content: "{{ item.content }}"
dest: /etc/apt/sources.list
mode: u=rw,go=r mode: u=rw,go=r
when: loop: "{{ pkg_repos_overrides }}"
- ansible_facts.distribution == "Debian" loop_control:
- ansible_facts.distribution_major_version == "9" label: "{{ item.dest }}"
- name: Add signing keys - name: Add signing keys
copy: copy:

@ -0,0 +1,23 @@
- name: regression/issue_952__ask_become_pass.yml
hosts: test-targets[0]:&linux_containers
gather_facts: false
tags:
- issue_952
tasks:
- name: Test --ask-become-pass
delegate_to: localhost
environment:
ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}"
expect:
command: >
ansible-playbook
{% for inv in ansible_inventory_sources %}
-i "{{ inv }}"
{% endfor %}
--ask-become-pass
regression/become_test.yml
chdir: ../
responses:
'BECOME password:': pw_required_password
changed_when: false
check_mode: false

@ -1,4 +1,7 @@
paramiko==2.3.2 # Last 2.6-compat version. paramiko==2.3.2 # Last 2.6-compat version.
# Incompatible with pip >= 72, due to removal of `setup.py test`:
# ModuleNotFoundError: No module named 'setuptools.command.test'
# https://github.com/pypa/setuptools/issues/4519
hdrhistogram==0.6.1 hdrhistogram==0.6.1
PyYAML==3.11; python_version < '2.7' PyYAML==3.11; python_version < '2.7'
PyYAML==5.3.1; python_version >= '2.7' # Latest release (Jan 2021) PyYAML==5.3.1; python_version >= '2.7' # Latest release (Jan 2021)

@ -1,5 +1,5 @@
- name: Report controller parameters - name: Report controller parameters
hosts: localhost hosts: test-targets[0]
gather_facts: false gather_facts: false
tasks: tasks:
- debug: - debug:
@ -9,9 +9,11 @@
- $(groups): "{{ lookup('pipe', 'groups') }}" - $(groups): "{{ lookup('pipe', 'groups') }}"
- $(pwd): "{{ lookup('pipe', 'pwd') }}" - $(pwd): "{{ lookup('pipe', 'pwd') }}"
- $(whoami): "{{ lookup('pipe', 'whoami') }}" - $(whoami): "{{ lookup('pipe', 'whoami') }}"
- ansible_inventory_sources: "{{ ansible_inventory_sources | default('<unset>') }}"
- ansible_run_tags: "{{ ansible_run_tags | default('<unset>') }}" - ansible_run_tags: "{{ ansible_run_tags | default('<unset>') }}"
- ansible_playbook_python: "{{ ansible_playbook_python | default('<unset>') }}" - ansible_playbook_python: "{{ ansible_playbook_python | default('<unset>') }}"
- ansible_skip_tags: "{{ ansible_skip_tags | default('<unset>') }}" - ansible_skip_tags: "{{ ansible_skip_tags | default('<unset>') }}"
- ansible_version.full: "{{ ansible_version.full | default('<unset>') }}" - ansible_version.full: "{{ ansible_version.full | default('<unset>') }}"
- is_mitogen: "{{ is_mitogen | default('<unset>') }}" - is_mitogen: "{{ is_mitogen | default('<unset>') }}"
- playbook_dir: "{{ playbook_dir | default('<unset>') }}" - playbook_dir: "{{ playbook_dir | default('<unset>') }}"
delegate_to: localhost

@ -0,0 +1,3 @@
# Setuptools 72 removed `setup.py test`. hdrhistogram 0.6.1 still depends on it.
# TODO Bump dependencies and unconstrain Pip.
setuptools<72

@ -12,6 +12,8 @@ Django==3.2.20; python_version >= '3.6'
mock==3.0.5; python_version == '2.7' mock==3.0.5; python_version == '2.7'
mock==5.1.0; python_version >= '3.6' mock==5.1.0; python_version >= '3.6'
pexpect==4.8
psutil==5.9.8 psutil==5.9.8
pytest==4.6.11; python_version == '2.7' pytest==4.6.11; python_version == '2.7'

@ -1,3 +1,6 @@
import os
import unittest
import mitogen.core import mitogen.core
import testlib import testlib
@ -7,6 +10,10 @@ import simple_pkg.ping
# TODO: this is a joke. 2/3 interop is one of the hardest bits to get right. # TODO: this is a joke. 2/3 interop is one of the hardest bits to get right.
# There should be 100 tests in this file. # There should be 100 tests in this file.
@unittest.skipIf(
os.uname()[0] == 'Darwin' and int(os.uname()[2].partition('.')[0]) >= 21,
"Python 2.x not shipped on macOS 12.3+ (Darwin 21.4+, Monterey)",
)
class TwoThreeCompatTest(testlib.RouterMixin, testlib.TestCase): class TwoThreeCompatTest(testlib.RouterMixin, testlib.TestCase):
if mitogen.core.PY3: if mitogen.core.PY3:
python_path = 'python2' python_path = 'python2'

@ -3,7 +3,7 @@
# #
# sudo add-apt-repository ppa:deadsnakes/ppa # sudo add-apt-repository ppa:deadsnakes/ppa
# sudo apt update # sudo apt update
# sudo apt install awscli lib{ldap2,sasl2,ssl}-dev python2.7 python3.{6..13}{,-venv} python-is-python3 sshpass tox # sudo apt install awscli lib{ldap2,sasl2,ssl}-dev python{2,2.7,3} python3.{6..13}{,-venv} python-is-python3 sshpass tox
# Py A cntrllr A target coverage Django Jinja2 pip psutil pytest tox virtualenv # Py A cntrllr A target coverage Django Jinja2 pip psutil pytest tox virtualenv
# ==== ========== ========== ========== ========== ========== ========== ========== ========== ========== ========== # ==== ========== ========== ========== ========== ========== ========== ========== ========== ========== ==========
@ -109,6 +109,7 @@ setenv =
ANSIBLE_STRATEGY = mitogen_linear ANSIBLE_STRATEGY = mitogen_linear
NOCOVERAGE_ERASE = 1 NOCOVERAGE_ERASE = 1
NOCOVERAGE_REPORT = 1 NOCOVERAGE_REPORT = 1
PIP_CONSTRAINT={toxinidir}/tests/constraints.txt
# Only applicable to MODE=mitogen # Only applicable to MODE=mitogen
distro_centos5: DISTRO=centos5 distro_centos5: DISTRO=centos5
distro_centos6: DISTRO=centos6 distro_centos6: DISTRO=centos6
@ -142,6 +143,8 @@ setenv =
distros_ubuntu2004: DISTROS=ubuntu2004 distros_ubuntu2004: DISTROS=ubuntu2004
mode_ansible: MODE=ansible mode_ansible: MODE=ansible
mode_ansible: ANSIBLE_SKIP_TAGS=resource_intensive mode_ansible: ANSIBLE_SKIP_TAGS=resource_intensive
mode_ansible: ANSIBLE_CALLBACK_WHITELIST=profile_tasks
mode_ansible: ANSIBLE_CALLBACKS_ENABLED=profile_tasks
mode_debops_common: MODE=debops_common mode_debops_common: MODE=debops_common
mode_localhost: ANSIBLE_SKIP_TAGS=issue_776,resource_intensive mode_localhost: ANSIBLE_SKIP_TAGS=issue_776,resource_intensive
mode_mitogen: MODE=mitogen mode_mitogen: MODE=mitogen

Loading…
Cancel
Save