Support for Ansible 3 & 4

fixes #834

Co-authored-by: Claude Becker (@upekkha)
Co-authored-by: Dolph Mathews (@dolph)
pull/870/head
Alex Willmer 3 years ago
parent b5353aa6e0
commit c61c063b4f

@ -13,7 +13,7 @@ steps:
- script: python -mpip install tox - script: python -mpip install tox
displayName: Install tooling displayName: Install tooling
- script: tox -e $(tox.env) - script: tox -e "$(tox.env)"
displayName: "Run tests" displayName: "Run tests"
env: env:
AWS_ACCESS_KEY_ID: $(AWS_ACCESS_KEY_ID) AWS_ACCESS_KEY_ID: $(AWS_ACCESS_KEY_ID)

@ -25,14 +25,14 @@ jobs:
tox.env: py27-mode_mitogen tox.env: py27-mode_mitogen
# TODO: test python3, python3 tests are broken # TODO: test python3, python3 tests are broken
Ans210_27: Local_Py27:
python.version: '2.7' python.version: '2.7'
tox.env: py27-mode_localhost-ansible2.10 tox.env: py27-mode_localhost-ansible{2.10,3,4}
# NOTE: this hangs when ran in Ubuntu 18.04 # NOTE: this hangs when ran in Ubuntu 18.04
Vanilla_210_27: Vanilla_Py27:
python.version: '2.7' python.version: '2.7'
tox.env: py27-mode_localhost-ansible2.10 tox.env: py27-mode_localhost-ansible{2.10,3,4}
STRATEGY: linear STRATEGY: linear
ANSIBLE_SKIP_TAGS: resource_intensive ANSIBLE_SKIP_TAGS: resource_intensive
@ -45,22 +45,17 @@ jobs:
- template: azure-pipelines-steps.yml - template: azure-pipelines-steps.yml
strategy: strategy:
matrix: matrix:
Mito27Debian_27: Mito_Py27:
python.version: '2.7' python.version: '2.7'
tox.env: py27-mode_mitogen-distro_debian9 tox.env: py27-mode_mitogen-distro_{centos6,centos7,centos8,debian9,debian10,debian11,ubuntu1604,ubuntu1804,ubuntu2004}
Mito36CentOS6_26: Mito_Py36:
python.version: '3.6' python.version: '3.6'
tox.env: py36-mode_mitogen-distro_centos6 tox.env: py36-mode_mitogen-distro_{centos6,centos7,centos8,debian9,debian10,debian11,ubuntu1604,ubuntu1804,ubuntu2004}
Mito39Debian_27: Mito_Py39:
python.version: '3.9' python.version: '3.9'
tox.env: py39-mode_mitogen-distro_debian9 tox.env: py39-mode_mitogen-distro_{centos6,centos7,centos8,debian9,debian10,debian11,ubuntu1604,ubuntu1804,ubuntu2004}
#Py26CentOS7:
#python.version: '2.7'
#MODE: mitogen
#DISTRO: centos6
#DebOps_2460_27_27: #DebOps_2460_27_27:
#python.version: '2.7' #python.version: '2.7'
@ -99,14 +94,14 @@ jobs:
#DISTROS: debian #DISTROS: debian
#STRATEGY: linear #STRATEGY: linear
Ansible_210_27: Ansible_Py27:
python.version: '2.7' python.version: '2.7'
tox.env: py27-mode_ansible-ansible2.10 tox.env: py27-mode_ansible-ansible{2.10,3,4}
Ansible_210_36: Ansible_Py36:
python.version: '3.6' python.version: '3.6'
tox.env: py36-mode_ansible-ansible2.10 tox.env: py36-mode_ansible-ansible{2.10,3,4}
Ansible_210_39: Ansible_Py39:
python.version: '3.9' python.version: '3.9'
tox.env: py39-mode_ansible-ansible2.10 tox.env: py39-mode_ansible-ansible{2.10,3,4}

@ -22,6 +22,14 @@ os.chdir(
) )
) )
_print = print
def print(*args, **kwargs):
file = kwargs.get('file', sys.stdout)
flush = kwargs.pop('flush', False)
_print(*args, **kwargs)
if flush:
file.flush()
# #
# check_output() monkeypatch cutpasted from testlib.py # check_output() monkeypatch cutpasted from testlib.py
@ -71,24 +79,22 @@ def _argv(s, *args):
def run(s, *args, **kwargs): def run(s, *args, **kwargs):
""" Run a command, with arguments, and print timing information """ Run a command, with arguments
>>> rc = run('echo "%s %s"', 'foo', 'bar') >>> rc = run('echo "%s %s"', 'foo', 'bar')
Running: ['/usr/bin/time', '--', 'echo', 'foo bar'] Running: ['echo', 'foo bar']
foo bar foo bar
0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata 1964maxresident)k Finished running: ['echo', 'foo bar']
0inputs+0outputs (0major+71minor)pagefaults 0swaps
Finished running: ['/usr/bin/time', '--', 'echo', 'foo bar']
>>> rc >>> rc
0 0
""" """
argv = ['/usr/bin/time', '--'] + _argv(s, *args) argv = _argv(s, *args)
print('Running: %s' % (argv,)) print('Running: %s' % (argv,), flush=True)
try: try:
ret = subprocess.check_call(argv, **kwargs) ret = subprocess.check_call(argv, **kwargs)
print('Finished running: %s' % (argv,)) print('Finished running: %s' % (argv,), flush=True)
except Exception: except Exception:
print('Exception occurred while running: %s' % (argv,)) print('Exception occurred while running: %s' % (argv,), file=sys.stderr, flush=True)
raise raise
return ret return ret
@ -155,7 +161,7 @@ def get_output(s, *args, **kwargs):
'foo bar\n' 'foo bar\n'
""" """
argv = _argv(s, *args) argv = _argv(s, *args)
print('Running: %s' % (argv,)) print('Running: %s' % (argv,), flush=True)
return subprocess.check_output(argv, **kwargs) return subprocess.check_output(argv, **kwargs)
@ -368,12 +374,10 @@ def start_containers(containers):
def verify_procs(hostname, old, new): def verify_procs(hostname, old, new):
oldpids = set(pid for pid, _ in old) oldpids = set(pid for pid, _ in old)
if any(pid not in oldpids for pid, _ in new): if any(pid not in oldpids for pid, _ in new):
print('%r had stray processes running:' % (hostname,)) print('%r had stray processes running:' % (hostname,), file=sys.stderr, flush=True)
for pid, line in new: for pid, line in new:
if pid not in oldpids: if pid not in oldpids:
print('New process:', line) print('New process:', line, flush=True)
print()
return False return False
return True return True
@ -397,13 +401,10 @@ def check_stray_processes(old, containers=None):
def dump_file(path): def dump_file(path):
print() print('--- %s ---' % (path,), flush=True)
print('--- %s ---' % (path,))
print()
with open(path, 'r') as fp: with open(path, 'r') as fp:
print(fp.read().rstrip()) print(fp.read().rstrip(), flush=True)
print('---') print('---', flush=True)
print()
# SSH passes these through to the container when run interactively, causing # SSH passes these through to the container when run interactively, causing

@ -1,8 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import print_function
import os import os
import shutil
import sys import sys
import ci_lib import ci_lib
@ -60,11 +58,7 @@ with ci_lib.Fold('job_setup'):
for container in containers for container in containers
) )
print() ci_lib.dump_file('ansible/inventory/hosts')
print(' echo --- ansible/inventory/hosts: ---')
ci_lib.run('cat ansible/inventory/hosts')
print('---')
print()
# Now we have real host key checking, we need to turn it off # Now we have real host key checking, we need to turn it off
os.environ['ANSIBLE_HOST_KEY_CHECKING'] = 'False' os.environ['ANSIBLE_HOST_KEY_CHECKING'] = 'False'

@ -33,15 +33,19 @@ with ci_lib.Fold('job_setup'):
with ci_lib.Fold('machine_prep'): with ci_lib.Fold('machine_prep'):
# generate a new ssh key for localhost ssh # generate a new ssh key for localhost ssh
os.system("ssh-keygen -P '' -m pem -f ~/.ssh/id_rsa") if not os.path.exists(os.path.expanduser("~/.ssh/id_rsa")):
os.system("cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys") os.system("ssh-keygen -P '' -m pem -f ~/.ssh/id_rsa")
os.system("cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys")
# also generate it for the sudo user # also generate it for the sudo user
os.system("sudo ssh-keygen -P '' -m pem -f /var/root/.ssh/id_rsa") if os.system("sudo [ -f /var/root/.ssh/id_rsa ]") != 0:
os.system("sudo cat /var/root/.ssh/id_rsa.pub | sudo tee -a /var/root/.ssh/authorized_keys") os.system("sudo ssh-keygen -P '' -m pem -f /var/root/.ssh/id_rsa")
os.system("sudo cat /var/root/.ssh/id_rsa.pub | sudo tee -a /var/root/.ssh/authorized_keys")
os.chmod(os.path.expanduser('~/.ssh'), int('0700', 8)) os.chmod(os.path.expanduser('~/.ssh'), int('0700', 8))
os.chmod(os.path.expanduser('~/.ssh/authorized_keys'), int('0600', 8)) os.chmod(os.path.expanduser('~/.ssh/authorized_keys'), int('0600', 8))
# run chmod through sudo since it's owned by root # run chmod through sudo since it's owned by root
os.system('sudo chmod 600 /var/root/.ssh') os.system('sudo chmod 700 /var/root/.ssh')
os.system('sudo chmod 600 /var/root/.ssh/authorized_keys') os.system('sudo chmod 600 /var/root/.ssh/authorized_keys')
if os.path.expanduser('~mitogen__user1') == '~mitogen__user1': if os.path.expanduser('~mitogen__user1') == '~mitogen__user1':

@ -45,7 +45,7 @@ __all__ = [
import ansible import ansible
ANSIBLE_VERSION_MIN = (2, 10) ANSIBLE_VERSION_MIN = (2, 10)
ANSIBLE_VERSION_MAX = (2, 10) ANSIBLE_VERSION_MAX = (2, 11)
NEW_VERSION_MSG = ( NEW_VERSION_MSG = (
"Your Ansible version (%s) is too recent. The most recent version\n" "Your Ansible version (%s) is too recent. The most recent version\n"
@ -79,7 +79,7 @@ def assert_supported_release():
if v[:2] > ANSIBLE_VERSION_MAX: if v[:2] > ANSIBLE_VERSION_MAX:
raise ansible.errors.AnsibleError( raise ansible.errors.AnsibleError(
NEW_VERSION_MSG % (ansible.__version__, ANSIBLE_VERSION_MAX) NEW_VERSION_MSG % (v, ANSIBLE_VERSION_MAX)
) )

@ -451,7 +451,7 @@ class PlayContextSpec(Spec):
return self._play_context.private_key_file return self._play_context.private_key_file
def ssh_executable(self): def ssh_executable(self):
return self._play_context.ssh_executable return C.config.get_config_value("ssh_executable", plugin_type="connection", plugin_name="ssh", variables=self._task_vars.get("vars", {}))
def timeout(self): def timeout(self):
return self._play_context.timeout return self._play_context.timeout
@ -467,9 +467,9 @@ class PlayContextSpec(Spec):
return [ return [
mitogen.core.to_text(term) mitogen.core.to_text(term)
for s in ( for s in (
getattr(self._play_context, 'ssh_args', ''), C.config.get_config_value("ssh_args", plugin_type="connection", plugin_name="ssh", variables=self._task_vars.get("vars", {})),
getattr(self._play_context, 'ssh_common_args', ''), C.config.get_config_value("ssh_common_args", plugin_type="connection", plugin_name="ssh", variables=self._task_vars.get("vars", {})),
getattr(self._play_context, 'ssh_extra_args', '') C.config.get_config_value("ssh_extra_args", plugin_type="connection", plugin_name="ssh", variables=self._task_vars.get("vars", {}))
) )
for term in ansible.utils.shlex.shlex_split(s or '') for term in ansible.utils.shlex.shlex_split(s or '')
] ]
@ -679,10 +679,7 @@ class MitogenViaSpec(Spec):
) )
def ssh_executable(self): def ssh_executable(self):
return ( return C.config.get_config_value("ssh_executable", plugin_type="connection", plugin_name="ssh", variables=self._task_vars.get("vars", {}))
self._host_vars.get('ansible_ssh_executable') or
C.ANSIBLE_SSH_EXECUTABLE
)
def timeout(self): def timeout(self):
# TODO: must come from PlayContext too. # TODO: must come from PlayContext too.
@ -699,22 +696,9 @@ class MitogenViaSpec(Spec):
return [ return [
mitogen.core.to_text(term) mitogen.core.to_text(term)
for s in ( for s in (
( C.config.get_config_value("ssh_args", plugin_type="connection", plugin_name="ssh", variables=self._task_vars.get("vars", {})),
self._host_vars.get('ansible_ssh_args') or C.config.get_config_value("ssh_common_args", plugin_type="connection", plugin_name="ssh", variables=self._task_vars.get("vars", {})),
getattr(C, 'ANSIBLE_SSH_ARGS', None) or C.config.get_config_value("ssh_extra_args", plugin_type="connection", plugin_name="ssh", variables=self._task_vars.get("vars", {}))
os.environ.get('ANSIBLE_SSH_ARGS')
# TODO: ini entry. older versions.
),
(
self._host_vars.get('ansible_ssh_common_args') or
os.environ.get('ANSIBLE_SSH_COMMON_ARGS')
# TODO: ini entry.
),
(
self._host_vars.get('ansible_ssh_extra_args') or
os.environ.get('ANSIBLE_SSH_EXTRA_ARGS')
# TODO: ini entry.
),
) )
for term in ansible.utils.shlex.shlex_split(s) for term in ansible.utils.shlex.shlex_split(s)
if s if s

@ -145,9 +145,10 @@ Testimonials
Noteworthy Differences Noteworthy Differences
---------------------- ----------------------
* Ansible 2.3-2.9 are supported along with Python 2.6, 2.7, 3.6 and 3.7. Verify * Mitogen 0.2.x supports Ansible 2.3-2.9; with Python 2.6, 2.7, or 3.6.
your installation is running one of these versions by checking ``ansible Mitogen 0.3.1+ supports Ansible 2.10, 3, and 4; with Python 2.7, or 3.6-3.9.
--version`` output. Verify your installation is running one of these versions by checking
``ansible --version`` output.
* The ``raw`` action executes as a regular Mitogen connection, which requires * The ``raw`` action executes as a regular Mitogen connection, which requires
Python on the target, precluding its use for installing Python. This will be Python on the target, precluding its use for installing Python. This will be

@ -21,6 +21,7 @@ To avail of fixes in an unreleased version, please download a ZIP file
v0.3.1.dev0 (unreleased) v0.3.1.dev0 (unreleased)
------------------------ ------------------------
* :gh:issue:`834` Support for Ansible 3 and 4 (ansible-core 2.11)
* :gh:issue:`869` Continuous Integration tests are now run with Tox * :gh:issue:`869` Continuous Integration tests are now run with Tox
* :gh:issue:`869` Continuous Integration tests now cover CentOS 6 & 8, Debian 9 & 11, Ubuntu 16.04 & 20.04 * :gh:issue:`869` Continuous Integration tests now cover CentOS 6 & 8, Debian 9 & 11, Ubuntu 16.04 & 20.04
* :gh:issue:`860` Add initial support for podman connection (w/o Ansible support yet) * :gh:issue:`860` Add initial support for podman connection (w/o Ansible support yet)

@ -64,6 +64,7 @@ setup(
zip_safe = False, zip_safe = False,
classifiers = [ classifiers = [
'Environment :: Console', 'Environment :: Console',
'Frameworks :: Ansible',
'Intended Audience :: System Administrators', 'Intended Audience :: System Administrators',
'License :: OSI Approved :: BSD License', 'License :: OSI Approved :: BSD License',
'Operating System :: MacOS :: MacOS X', 'Operating System :: MacOS :: MacOS X',

@ -30,7 +30,10 @@
- async_out.invocation.module_args.creates == None - async_out.invocation.module_args.creates == None
- async_out.invocation.module_args.executable == None - async_out.invocation.module_args.executable == None
- async_out.invocation.module_args.removes == None - async_out.invocation.module_args.removes == None
- async_out.invocation.module_args.warn == True # In Ansible 4 (ansible-core 2.11) the warn parameter is deprecated and defaults to false.
# It's scheduled for removal in ansible-core 2.13.
- (ansible_version.full is version("2.11", "<", strict=True) and async_out.invocation.module_args.warn == True)
or (ansible_version.full is version("2.11", ">=", strict=True) and async_out.invocation.module_args.warn == False)
- async_out.rc == 0 - async_out.rc == 0
- async_out.start.startswith("20") - async_out.start.startswith("20")
- async_out.stderr == "there" - async_out.stderr == "there"

@ -15,12 +15,12 @@
assert: assert:
that: that:
- out.failed - out.failed
- | - >-
('sudo: no such option: --derps' in out.msg) or 'sudo: no such option: --derps' in out.msg
("sudo: invalid option -- '-'" in out.module_stderr) or or out.module_stdout is match("sudo: invalid option -- '-'")
("sudo: unrecognized option `--derps'" in out.module_stderr) or or out.module_stderr is match("sudo: invalid option -- '-'")
("sudo: unrecognized option `--derps'" in out.module_stdout) or or out.module_stdout is match("sudo: unrecognized option [`']--derps'")
("sudo: unrecognized option '--derps'" in out.module_stderr) or out.module_stderr is match("sudo: unrecognized option [`']--derps'")
fail_msg: out={{out}} fail_msg: out={{out}}
tags: tags:
- sudo - sudo

@ -22,8 +22,8 @@
# 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_stderr | default(out.msg)) 'sudo: unknown user: slartibartfast' in out.module_stdout | default(out.msg)
or ('chown: slartibartfast: illegal user name' in out.module_stderr | default(out.msg)) 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:

@ -9,16 +9,23 @@
# Last version to support each python version # Last version to support each python version
# #
# tox vir'env pip ansible ansible coverage # Python tox virt'env pip A cntllr A target coverage
# control target
# ========== ======== ======== ======== ======== ======== ======== # ========== ======== ======== ======== ======== ======== ========
# python2.4 1.4 1.8 1.1 2.3? # python2.4 1.4 1.8 1.1 2.3?
# python2.5 1.6.1 1.9.1 1.3.1 ??? # python2.5 1.6.1 1.9.1 1.3.1 ???
# python2.6 2.9.1 15.2.0 9.0.3 2.6.20 4.5.4 # python2.6 2.9.1 15.2.0 9.0.3 2.6.20 2.13 4.5.4
# python2.7 20.3 2.10 # python2.7 20.3 2.11
# python3.5 2.10 # python3.5 2.11
# python3.6 2.10 # python3.6 2.11
# python3.7 2.10 # python3.7 2.11
# Ansible Dependency
# ================== ======================
# ansible <= 2.9
# ansible == 2.10.* ansible-base ~= 2.10.0
# ansible == 3.* ansible-base ~= 2.10.0
# ansible == 4.* ansible-core ~= 2.11.0
# ansible == 5.* ansible-core ~= 2.12.0
# pip --no-python-version-warning # pip --no-python-version-warning
# pip --disable-pip-version-check # pip --disable-pip-version-check
@ -28,7 +35,7 @@
[tox] [tox]
envlist = envlist =
init, init,
py{27,36,39}-mode_ansible-ansible2.10, py{27,36,39}-mode_ansible-ansible{2.10,3,4},
py{27,36,39}-mode_mitogen-distro_centos{6,7,8}, py{27,36,39}-mode_mitogen-distro_centos{6,7,8},
py{27,36,39}-mode_mitogen-distro_debian{9,10,11}, py{27,36,39}-mode_mitogen-distro_debian{9,10,11},
py{27,36,39}-mode_mitogen-distro_ubuntu{1604,1804,2004}, py{27,36,39}-mode_mitogen-distro_ubuntu{1604,1804,2004},
@ -54,6 +61,9 @@ deps =
ansible2.9: ansible=2.9.6 ansible2.9: ansible=2.9.6
ansible2.10: ansible-base<2.10.14 ansible2.10: ansible-base<2.10.14
ansible2.10: ansible==2.10.0 ansible2.10: ansible==2.10.0
ansible3: ansible-base<2.10.14
ansible3: ansible==3.4.0
ansible4: ansible==4.8.0
install_command = install_command =
python -m pip --no-python-version-warning install {opts} {packages} python -m pip --no-python-version-warning install {opts} {packages}
commands_pre = commands_pre =

Loading…
Cancel
Save