From bf6607e27e01d22c1a45b4f5c7ecbdc589eac732 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Fri, 11 Oct 2024 15:50:09 +0100 Subject: [PATCH] ansible_mitogen: Support templated become_user This reads the become username from the `become_user` attribute of the play context, to the `"become_user"` option of the loaded become plugin. This has been supported by vanilla Ansible since Ansible 2.10 (ansible-base 2.10). To support this I've also switched from using the `play_context.become` (a bool), to `connection.become` (an instance of the appropriate) become plugin. New tests have been added, modelled on those for templated connection parameters (see #1147, #1153, #1159). See - https://github.com/ansible/ansible/commit/480b106d6535978ae6ecab68b40942ca4fa914a0 refs #1083 Co-authored-by: mordek --- ansible_mitogen/connection.py | 4 +-- ansible_mitogen/mixins.py | 2 +- ansible_mitogen/transport_config.py | 8 ++++-- docs/changelog.rst | 1 + docs/contributors.rst | 1 + tests/ansible/hosts/default.hosts | 14 ++++++++++ tests/ansible/integration/become/all.yml | 4 +++ .../integration/become/templated_by_inv.yml | 14 ++++++++++ .../become/templated_by_play_keywords.yml | 16 +++++++++++ .../become/templated_by_play_vars.yml | 16 +++++++++++ .../become/templated_by_task_keywords.yml | 27 +++++++++++++++++++ tests/ansible/templates/test-targets.j2 | 20 ++++++++++++++ 12 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 tests/ansible/integration/become/templated_by_inv.yml create mode 100644 tests/ansible/integration/become/templated_by_play_keywords.yml create mode 100644 tests/ansible/integration/become/templated_by_play_vars.yml create mode 100644 tests/ansible/integration/become/templated_by_task_keywords.yml diff --git a/ansible_mitogen/connection.py b/ansible_mitogen/connection.py index a715b2b0..4c1df1bd 100644 --- a/ansible_mitogen/connection.py +++ b/ansible_mitogen/connection.py @@ -814,7 +814,7 @@ class Connection(ansible.plugins.connection.ConnectionBase): self.context = dct['context'] self.chain = CallChain(self, self.context, pipelined=True) - if self._play_context.become: + if self.become: self.login_context = dct['via'] else: self.login_context = self.context @@ -926,7 +926,7 @@ class Connection(ansible.plugins.connection.ConnectionBase): self.close() inventory_name, stack = self._build_stack() - if self._play_context.become: + if self.become: stack = stack[:-1] worker_model = ansible_mitogen.process.get_worker_model() diff --git a/ansible_mitogen/mixins.py b/ansible_mitogen/mixins.py index 1b6512e8..3953eb52 100644 --- a/ansible_mitogen/mixins.py +++ b/ansible_mitogen/mixins.py @@ -294,7 +294,7 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase): if not path.startswith('~'): # /home/foo -> /home/foo return path - if sudoable or not self._play_context.become: + if sudoable or not self._connection.become: if path == '~': # ~ -> /home/dmw return self._connection.homedir diff --git a/ansible_mitogen/transport_config.py b/ansible_mitogen/transport_config.py index a9f67209..708c2897 100644 --- a/ansible_mitogen/transport_config.py +++ b/ansible_mitogen/transport_config.py @@ -417,6 +417,10 @@ class PlayContextSpec(Spec): # used to run interpreter discovery self._action = connection._action + def _become_option(self, name): + plugin = self._connection.become + return plugin.get_option(name, self._task_vars, self._play_context) + def _connection_option(self, name): try: return self._connection.get_option(name, hostvars=self._task_vars) @@ -437,13 +441,13 @@ class PlayContextSpec(Spec): return self._connection_option('remote_user') def become(self): - return self._play_context.become + return self._connection.become def become_method(self): return self._play_context.become_method def become_user(self): - return self._play_context.become_user + return self._become_option('become_user') def become_pass(self): # become_pass is owned/provided by the active become plugin. However diff --git a/docs/changelog.rst b/docs/changelog.rst index 1fad75a5..8ab68d97 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -23,6 +23,7 @@ In progress (unreleased) * :gh:issue:`1159` CI: Reduce number of Jobs by parameterizing Mitogen Docker SSH tests +* :gh:issue:`1083` :mod:`ansible_mitogen`: Support templated become username. v0.3.13 (2024-10-09) diff --git a/docs/contributors.rst b/docs/contributors.rst index 69dc1e76..ad35f91c 100644 --- a/docs/contributors.rst +++ b/docs/contributors.rst @@ -134,6 +134,7 @@ sponsorship and outstanding future-thinking of its early adopters.
  • luto
  • Mayeu a.k.a Matthieu Maury
  • Michael D'Silva
  • +
  • mordek
  • @nathanhruby
  • Orion Poplawski
  • Philippe Kueck
  • diff --git a/tests/ansible/hosts/default.hosts b/tests/ansible/hosts/default.hosts index bebe90df..ef05803e 100644 --- a/tests/ansible/hosts/default.hosts +++ b/tests/ansible/hosts/default.hosts @@ -25,6 +25,20 @@ tt-bare [tt_targets_bare:vars] ansible_host=localhost +[tt_become_bare] +tt-become-bare + +[tt_become_bare:vars] +ansible_host=localhost +ansible_user="{{ lookup('pipe', 'whoami') }}" + +[tt_become_by_inv] +tt-become-user ansible_become=true ansible_become_user="{{ 'root' | trim }}" + +[tt_become_by_inv:vars] +ansible_host=localhost +ansible_user="{{ lookup('pipe', 'whoami') }}" + [tt_targets_inventory] tt-password ansible_password="{{ 'has_sudo_nopw_password' | trim }}" ansible_user=mitogen__has_sudo_nopw tt-port ansible_password=has_sudo_nopw_password ansible_port="{{ 22 | int }}" ansible_user=mitogen__has_sudo_nopw diff --git a/tests/ansible/integration/become/all.yml b/tests/ansible/integration/become/all.yml index c9c331dd..1b507e16 100644 --- a/tests/ansible/integration/become/all.yml +++ b/tests/ansible/integration/become/all.yml @@ -5,3 +5,7 @@ - import_playbook: sudo_nopassword.yml - import_playbook: sudo_password.yml - import_playbook: sudo_requiretty.yml +- import_playbook: templated_by_inv.yml +- import_playbook: templated_by_play_keywords.yml +- import_playbook: templated_by_play_vars.yml +- import_playbook: templated_by_task_keywords.yml diff --git a/tests/ansible/integration/become/templated_by_inv.yml b/tests/ansible/integration/become/templated_by_inv.yml new file mode 100644 index 00000000..98b68f05 --- /dev/null +++ b/tests/ansible/integration/become/templated_by_inv.yml @@ -0,0 +1,14 @@ +- name: integration/become/templated_by_inv.yml + hosts: tt_become_by_inv + gather_facts: false + tasks: + - meta: reset_connection + - name: Templated become in inventory + command: + cmd: whoami + changed_when: false + check_mode: false + register: become_templated_by_inv_whoami + failed_when: + - become_templated_by_inv_whoami is failed + or become_templated_by_inv_whoami.stdout != 'root' diff --git a/tests/ansible/integration/become/templated_by_play_keywords.yml b/tests/ansible/integration/become/templated_by_play_keywords.yml new file mode 100644 index 00000000..e588c18f --- /dev/null +++ b/tests/ansible/integration/become/templated_by_play_keywords.yml @@ -0,0 +1,16 @@ +- name: integration/become/templated_by_play_keywords.yml + hosts: tt_become_bare + gather_facts: false + become: true + become_user: "{{ 'root' | trim }}" + tasks: + - meta: reset_connection + - name: Templated become by play keywords + command: + cmd: whoami + changed_when: false + check_mode: false + register: become_templated_by_play_keywords_whoami + failed_when: + - become_templated_by_play_keywords_whoami is failed + or become_templated_by_play_keywords_whoami.stdout != 'root' diff --git a/tests/ansible/integration/become/templated_by_play_vars.yml b/tests/ansible/integration/become/templated_by_play_vars.yml new file mode 100644 index 00000000..5618f7cc --- /dev/null +++ b/tests/ansible/integration/become/templated_by_play_vars.yml @@ -0,0 +1,16 @@ +- name: integration/become/templated_by_play_vars.yml + hosts: tt_become_bare + gather_facts: false + vars: + ansible_become: true + ansible_become_user: "{{ 'root' | trim }}" + tasks: + - name: Templated become by play vars + command: + cmd: whoami + changed_when: false + check_mode: false + register: become_templated_by_play_vars_whoami + failed_when: + - become_templated_by_play_vars_whoami is failed + or become_templated_by_play_vars_whoami.stdout != 'root' diff --git a/tests/ansible/integration/become/templated_by_task_keywords.yml b/tests/ansible/integration/become/templated_by_task_keywords.yml new file mode 100644 index 00000000..52fda111 --- /dev/null +++ b/tests/ansible/integration/become/templated_by_task_keywords.yml @@ -0,0 +1,27 @@ +- name: integration/become/templated_by_task_keywords.yml + hosts: tt_become_bare + gather_facts: false + # FIXME Resetting the connection shouldn't require credentials + # https://github.com/mitogen-hq/mitogen/issues/1132 + become: true + become_user: "{{ 'root' | trim }}" + tasks: + - name: Reset connection to target that will be delegate_to + meta: reset_connection + +- name: Test connection template by task keywords, with delegate_to + hosts: test-targets[0] + gather_facts: false + tasks: + - name: Templated become by task keywords, with delegate_to + become: true + become_user: "{{ 'root' | trim }}" + delegate_to: "{{ groups.tt_become_bare[0] }}" + command: + cmd: whoami + changed_when: false + check_mode: false + register: become_templated_by_task_with_delegate_to_whoami + failed_when: + - become_templated_by_task_with_delegate_to_whoami is failed + or become_templated_by_task_with_delegate_to_whoami.stdout != 'root' diff --git a/tests/ansible/templates/test-targets.j2 b/tests/ansible/templates/test-targets.j2 index 0fdef20b..47f2ccd4 100644 --- a/tests/ansible/templates/test-targets.j2 +++ b/tests/ansible/templates/test-targets.j2 @@ -48,6 +48,26 @@ ansible_host={{ tt.hostname }} ansible_port={{ tt.port }} ansible_python_interpreter={{ tt.python_path }} +[tt_become_bare] +tt-become-bare + +[tt_become_bare:vars] +ansible_host={{ tt.hostname }} +ansible_password=has_sudo_nopw_password +ansible_port={{ tt.port }} +ansible_python_interpreter={{ tt.python_path }} +ansible_user=mitogen__has_sudo_nopw + +[tt_become_by_inv] +tt-become-user ansible_become=true ansible_become_user="{{ '{{' }} 'root' | trim {{ '}}' }}" + +[tt_become_by_inv:vars] +ansible_host={{ tt.hostname }} +ansible_password=has_sudo_nopw_password +ansible_port={{ tt.port }} +ansible_python_interpreter={{ tt.python_path }} +ansible_user=mitogen__has_sudo_nopw + [tt_targets_inventory] tt-password ansible_password="{{ '{{' }} 'has_sudo_nopw_password' | trim {{ '}}' }}" ansible_port={{ tt.port }} ansible_user=mitogen__has_sudo_nopw tt-port ansible_password=has_sudo_nopw_password ansible_port="{{ '{{' }} {{ tt.port }} | int {{ '}}' }}" ansible_user=mitogen__has_sudo_nopw