From: Alex Willmer <alex@moreati.org.uk>
Date: Mon, 12 Sep 2022 14:11:00 +0200
Subject: Ansible 6 support

fixes #929

Bug-Upstream: https://github.com/mitogen-hq/mitogen/issues/929
Bug-Debian: https://bugs.debian.org/1019501
Origin: upstream, https://github.com/mitogen-hq/mitogen/pull/933
---
 .ci/azure-pipelines.yml                            | 60 ++--------------------
 ansible_mitogen/loaders.py                         |  4 +-
 ansible_mitogen/transport_config.py                | 10 ++--
 docs/ansible_detailed.rst                          |  2 +-
 mitogen/master.py                                  |  2 +-
 tests/ansible/hosts/transport_config.hosts         |  2 +-
 .../integration/transport_config/become_pass.yml   |  9 ++--
 tox.ini                                            | 18 +++----
 8 files changed, 28 insertions(+), 79 deletions(-)

diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml
index 6f45397..98f4805 100644
--- a/.ci/azure-pipelines.yml
+++ b/.ci/azure-pipelines.yml
@@ -33,9 +33,6 @@ jobs:
       Loc_27_210:
         python.version: '2.7'
         tox.env: py27-mode_localhost-ansible2.10
-      Loc_27_3:
-        python.version: '2.7'
-        tox.env: py27-mode_localhost-ansible3
       Loc_27_4:
         python.version: '2.7'
         tox.env: py27-mode_localhost-ansible4
@@ -46,11 +43,6 @@ jobs:
         tox.env: py27-mode_localhost-ansible2.10
         STRATEGY: linear
         ANSIBLE_SKIP_TAGS: resource_intensive
-      Van_27_3:
-        python.version: '2.7'
-        tox.env: py27-mode_localhost-ansible3
-        STRATEGY: linear
-        ANSIBLE_SKIP_TAGS: resource_intensive
       Van_27_4:
         python.version: '2.7'
         tox.env: py27-mode_localhost-ansible4
@@ -79,8 +71,6 @@ jobs:
       # TODO: test python3, python3 tests are broken
       Loc_27_210:
         tox.env: py27-mode_localhost-ansible2.10
-      Loc_27_3:
-        tox.env: py27-mode_localhost-ansible3
       Loc_27_4:
         tox.env: py27-mode_localhost-ansible4
 
@@ -89,10 +79,6 @@ jobs:
         tox.env: py27-mode_localhost-ansible2.10
         STRATEGY: linear
         ANSIBLE_SKIP_TAGS: resource_intensive
-      Van_27_3:
-        tox.env: py27-mode_localhost-ansible3
-        STRATEGY: linear
-        ANSIBLE_SKIP_TAGS: resource_intensive
       Van_27_4:
         tox.env: py27-mode_localhost-ansible4
         STRATEGY: linear
@@ -190,49 +176,9 @@ jobs:
         python.version: '3.10'
         tox.env: py310-mode_mitogen-distro_ubuntu2004
 
-      #DebOps_2460_27_27:
-        #python.version: '2.7'
-        #MODE: debops_common
-        #VER: 2.4.6.0
-
-      #DebOps_262_36_27:
-        #python.version: '3.6'
-        #MODE: debops_common
-        #VER: 2.6.2
-
-      #Ansible_2460_26:
-        #python.version: '2.7'
-        #MODE: ansible
-        #VER: 2.4.6.0
-
-      #Ansible_262_26:
-        #python.version: '2.7'
-        #MODE: ansible
-        #VER: 2.6.2
-
-      #Ansible_2460_36:
-        #python.version: '3.6'
-        #MODE: ansible
-        #VER: 2.4.6.0
-
-      #Ansible_262_36:
-        #python.version: '3.6'
-        #MODE: ansible
-        #VER: 2.6.2
-
-      #Vanilla_262_27:
-        #python.version: '2.7'
-        #MODE: ansible
-        #VER: 2.6.2
-        #DISTROS: debian
-        #STRATEGY: linear
-
       Ans_27_210:
         python.version: '2.7'
         tox.env: py27-mode_ansible-ansible2.10
-      Ans_27_3:
-        python.version: '2.7'
-        tox.env: py27-mode_ansible-ansible3
       Ans_27_4:
         python.version: '2.7'
         tox.env: py27-mode_ansible-ansible4
@@ -240,9 +186,6 @@ jobs:
       Ans_36_210:
         python.version: '3.6'
         tox.env: py36-mode_ansible-ansible2.10
-      Ans_36_3:
-        python.version: '3.6'
-        tox.env: py36-mode_ansible-ansible3
       Ans_36_4:
         python.version: '3.6'
         tox.env: py36-mode_ansible-ansible4
@@ -259,3 +202,6 @@ jobs:
       Ans_310_5:
         python.version: '3.10'
         tox.env: py310-mode_ansible-ansible5
+      Ans_310_6:
+        python.version: '3.10'
+        tox.env: py310-mode_ansible-ansible6
diff --git a/ansible_mitogen/loaders.py b/ansible_mitogen/loaders.py
index cd05fea..1f4d8fc 100644
--- a/ansible_mitogen/loaders.py
+++ b/ansible_mitogen/loaders.py
@@ -39,6 +39,7 @@ import ansible_mitogen.utils
 
 __all__ = [
     'action_loader',
+    'become_loader',
     'connection_loader',
     'module_loader',
     'module_utils_loader',
@@ -48,7 +49,7 @@ __all__ = [
 
 
 ANSIBLE_VERSION_MIN = (2, 10)
-ANSIBLE_VERSION_MAX = (2, 12)
+ANSIBLE_VERSION_MAX = (2, 13)
 
 NEW_VERSION_MSG = (
     "Your Ansible version (%s) is too recent. The most recent version\n"
@@ -90,6 +91,7 @@ assert_supported_release()
 
 
 from ansible.plugins.loader import action_loader
+from ansible.plugins.loader import become_loader
 from ansible.plugins.loader import connection_loader
 from ansible.plugins.loader import module_loader
 from ansible.plugins.loader import module_utils_loader
diff --git a/ansible_mitogen/transport_config.py b/ansible_mitogen/transport_config.py
index b488b85..cc4e4a7 100644
--- a/ansible_mitogen/transport_config.py
+++ b/ansible_mitogen/transport_config.py
@@ -79,6 +79,7 @@ try:
 except ImportError:
     from ansible.vars.unsafe_proxy import AnsibleUnsafeText
 
+import ansible_mitogen.loaders
 import mitogen.core
 
 
@@ -435,7 +436,10 @@ class PlayContextSpec(Spec):
         return self._play_context.become_user
 
     def become_pass(self):
-        return optional_secret(self._play_context.become_pass)
+        become_method = self.become_method()
+        become_plugin = ansible_mitogen.loaders.become_loader.get(become_method)
+        become_pass = become_plugin.get_option('become_pass', hostvars=self._task_vars)
+        return optional_secret(become_pass)
 
     def password(self):
         return optional_secret(self._play_context.password)
@@ -652,8 +656,8 @@ class MitogenViaSpec(Spec):
 
     def become_pass(self):
         return optional_secret(
-            self._host_vars.get('ansible_become_password') or
-            self._host_vars.get('ansible_become_pass')
+            self._host_vars.get('ansible_become_pass') or
+            self._host_vars.get('ansible_become_password')
         )
 
     def password(self):
diff --git a/docs/ansible_detailed.rst b/docs/ansible_detailed.rst
index d329807..dd569a7 100644
--- a/docs/ansible_detailed.rst
+++ b/docs/ansible_detailed.rst
@@ -148,7 +148,7 @@ Noteworthy Differences
 * Mitogen 0.2.x supports Ansible 2.3-2.9; with Python 2.6, 2.7, or 3.6.
   Mitogen 0.3.1+ supports
     - Ansible 2.10, 3, and 4; with Python 2.7, or 3.6-3.10
-    - Ansible 5; with Python 3.8-3.10
+    - Ansible 5 and 6; with Python 3.8-3.10
   Verify your installation is running one of these versions by checking
   ``ansible --version`` output.
 
diff --git a/mitogen/master.py b/mitogen/master.py
index 3a163a8..4fb535f 100644
--- a/mitogen/master.py
+++ b/mitogen/master.py
@@ -536,7 +536,7 @@ class PkgutilMethod(FinderMethod):
 
         try:
             path = loader.get_filename(fullname)
-        except (AttributeError, ImportError):
+        except (AttributeError, ImportError, ValueError):
             # - get_filename() may throw ImportError if pkgutil.find_loader()
             #   picks a "parent" package's loader for some crap that's been
             #   stuffed in sys.modules, for example in the case of urllib3:
diff --git a/tests/ansible/hosts/transport_config.hosts b/tests/ansible/hosts/transport_config.hosts
index 856c6a0..a96b3bd 100644
--- a/tests/ansible/hosts/transport_config.hosts
+++ b/tests/ansible/hosts/transport_config.hosts
@@ -41,7 +41,7 @@ tc-become-user-set ansible_become_user=ansi-become-user
 tc-become-pass-unset
 tc-become-pass-password ansible_become_password=apassword
 tc-become-pass-pass ansible_become_pass=apass
-tc-become-pass-both ansible_become_password=a.b.c ansible_become_pass=c.b.a
+tc-become-pass-both ansible_become_pass=bpass ansible_become_password=bpassword
 
 # port()
 tc-port-unset
diff --git a/tests/ansible/integration/transport_config/become_pass.yml b/tests/ansible/integration/transport_config/become_pass.yml
index 6287e70..03f7cbc 100644
--- a/tests/ansible/integration/transport_config/become_pass.yml
+++ b/tests/ansible/integration/transport_config/become_pass.yml
@@ -119,9 +119,6 @@
       fail_msg: out={{out}}
 
 
-
-# ansible_become_pass & ansible_become_password set, password used to take precedence
-# but it's possible since https://github.com/ansible/ansible/pull/69629/files#r428376864, now it doesn't
 - hosts: tc-become-pass-both
   become: true
   tasks:
@@ -132,7 +129,9 @@
       - out.result|length == 2
       - out.result[0].method == "ssh"
       - out.result[1].method == "sudo"
-      - out.result[1].kwargs.password == "c.b.a"
+      # Ansible >= 2.10 builtin become plugins (e.g. sudo, su) give priority
+      # to ansible_become_pass over ansible_become_password.
+      - out.result[1].kwargs.password == "bpass"
       fail_msg: out={{out}}
 
 
@@ -147,6 +146,6 @@
       - out.result|length == 3
       - out.result[0].method == "ssh"
       - out.result[1].method == "sudo"
-      - out.result[1].kwargs.password == "a.b.c"
+      - out.result[1].kwargs.password == "bpass"
       - out.result[2].method == "ssh"
       fail_msg: out={{out}}
diff --git a/tox.ini b/tox.ini
index 6b2addc..5b01516 100644
--- a/tox.ini
+++ b/tox.ini
@@ -26,6 +26,7 @@
 # ansible == 3.*     ansible-base ~= 2.10.0
 # ansible == 4.*     ansible-core ~= 2.11.0
 # ansible == 5.*     ansible-core ~= 2.12.0
+# ansible == 6.*     ansible-core ~= 2.13.0
 
 # pip --no-python-version-warning
 # pip --disable-pip-version-check
@@ -36,7 +37,7 @@
 envlist =
     init,
     py{27,36}-mode_ansible-ansible{2.10,3,4},
-    py{310}-mode_ansible-ansible{2.10,3,4,5},
+    py{310}-mode_ansible-ansible{2.10,3,4,5,6},
     py{27,36,310}-mode_mitogen-distro_centos{6,7,8},
     py{27,36,310}-mode_mitogen-distro_debian{9,10,11},
     py{27,36,310}-mode_mitogen-distro_ubuntu{1604,1804,2004},
@@ -57,16 +58,11 @@ basepython =
 deps =
     -r{toxinidir}/tests/requirements.txt
     mode_ansible: -r{toxinidir}/tests/ansible/requirements.txt
-    ansible2.3: ansible==2.3.3.0
-    ansible2.4: ansible==2.4.6.0
-    ansible2.8: ansible==2.8.3
-    ansible2.9: ansible==2.9.6
-    ansible2.10: ansible-base<2.10.14
-    ansible2.10: ansible==2.10.0
-    ansible3: ansible-base<2.10.14
+    ansible2.10: ansible==2.10.7
     ansible3: ansible==3.4.0
-    ansible4: ansible==4.8.0
-    ansible5: ansible==5.0.1
+    ansible4: ansible==4.10.0
+    ansible5: ansible==5.8.0
+    ansible6: ansible==6.0.0
 install_command =
     python -m pip --no-python-version-warning --disable-pip-version-check install {opts} {packages}
 commands_pre =
@@ -102,6 +98,8 @@ setenv =
     distro_ubuntu1804: DISTRO=ubuntu1804
     distro_ubuntu2004: DISTRO=ubuntu2004
     # Note the plural, only applicable to MODE=ansible
+    # Ansible 6 (ansible-core 2.13) requires Python >= 2.7 or >= 3.5 on targets
+    ansible6: DISTROS=centos7 centos8 debian9 debian10 debian11 ubuntu1604 ubuntu1804 ubuntu2004
     distros_centos: DISTROS=centos6 centos7 centos8
     distros_centos5: DISTROS=centos5
     distros_centos6: DISTROS=centos6
