diff --git a/ansible_mitogen/connection.py b/ansible_mitogen/connection.py index 21836cae..ced67ac0 100644 --- a/ansible_mitogen/connection.py +++ b/ansible_mitogen/connection.py @@ -348,10 +348,14 @@ class Connection(ansible.plugins.connection.ConnectionBase): #: presently always the connection multiplexer process. parent = None - #: mitogen.parent.Context connected to the target user account on the - #: target machine (i.e. possibly via sudo). + #: mitogen.parent.Context for the target account on the target, possibly + #: reached via become. context = None + #: mitogen.parent.Context for the login account on the target. This is + #: always the login account, even when become=True. + login_context = None + #: mitogen.parent.Context connected to the fork parent process in the #: target user account. fork_context = None @@ -529,6 +533,11 @@ class Connection(ansible.plugins.connection.ConnectionBase): raise ansible.errors.AnsibleConnectionFailure(dct['msg']) self.context = dct['context'] + if self._play_context.become: + self.login_context = dct['via'] + else: + self.login_context = self.context + self.fork_context = dct['init_child_result']['fork_context'] self.home_dir = dct['init_child_result']['home_dir'] @@ -546,6 +555,8 @@ class Connection(ansible.plugins.connection.ConnectionBase): ) self.context = None + self.fork_context = None + self.login_context = None if self.broker and not new_task: self.broker.shutdown() self.broker.join() @@ -556,11 +567,18 @@ class Connection(ansible.plugins.connection.ConnectionBase): """ Start a function call to the target. + :param bool use_login_context: + If present and :data:`True`, send the call to the login account + context rather than the optional become user context. :returns: mitogen.core.Receiver that receives the function call result. """ self._connect() - return self.context.call_async(func, *args, **kwargs) + if kwargs.pop('use_login_context', None): + call_context = self.login_context + else: + call_context = self.context + return call_context.call_async(func, *args, **kwargs) def call(self, func, *args, **kwargs): """ diff --git a/ansible_mitogen/mixins.py b/ansible_mitogen/mixins.py index 86b9fdd5..5b8b90dd 100644 --- a/ansible_mitogen/mixins.py +++ b/ansible_mitogen/mixins.py @@ -200,9 +200,10 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase): # _make_tmp_path() is basically a global stashed away as Shell.tmpdir. # The copy action plugin violates layering and grabs this attribute # directly. - self._connection._shell.tmpdir = self.call( + self._connection._shell.tmpdir = self._connection.call( ansible_mitogen.target.make_temp_directory, base_dir=self._get_remote_tmp(), + use_login_context=True, ) LOG.debug('Temporary directory: %r', self._connection._shell.tmpdir) self._cleanup_remote_tmp = True diff --git a/ansible_mitogen/services.py b/ansible_mitogen/services.py index 8bdb9b9d..a7bb7db1 100644 --- a/ansible_mitogen/services.py +++ b/ansible_mitogen/services.py @@ -267,6 +267,7 @@ class ContextService(mitogen.service.Service): { 'context': mitogen.core.Context or None, + 'via': mitogen.core.Context or None, 'init_child_result': { 'fork_context': mitogen.core.Context, 'home_dir': str or None, @@ -308,6 +309,7 @@ class ContextService(mitogen.service.Service): self._refs_by_context[context] = 0 return { 'context': context, + 'via': via, 'init_child_result': init_child_result, 'msg': None, } diff --git a/tests/ansible/integration/action/make_tmp_path.yml b/tests/ansible/integration/action/make_tmp_path.yml index 603ebd09..83261208 100644 --- a/tests/ansible/integration/action/make_tmp_path.yml +++ b/tests/ansible/integration/action/make_tmp_path.yml @@ -2,8 +2,21 @@ - name: integration/action/make_tmp_path.yml hosts: test-targets any_errors_fatal: true - gather_facts: true tasks: + - name: "Find out root's homedir." + # Runs first because it blats regular Ansible facts with junk, so + # non-become run fixes that up. + setup: gather_subset=min + become: true + register: root_facts + + - name: "Find regular homedir" + setup: gather_subset=min + register: user_facts + + # + # non-become + # - action_passthrough: method: _make_tmp_path @@ -11,7 +24,32 @@ - assert: # This string must match ansible.cfg::remote_tmp - that: out.result.startswith("{{ansible_user_dir}}/.ansible/mitogen-tests/") + that: out.result.startswith("{{user_facts.ansible_facts.ansible_user_dir}}/.ansible/mitogen-tests/") + + - stat: + path: "{{out.result}}" + register: st + + - assert: + that: st.stat.exists and st.stat.isdir and st.stat.mode == "0700" + + - file: + path: "{{out.result}}" + state: absent + + # + # become. make_tmp_path() must evaluate HOME in the context of the SSH + # user, not the become user. + # + + - action_passthrough: + method: _make_tmp_path + register: out + become: true + + - assert: + # This string must match ansible.cfg::remote_tmp + that: out.result.startswith("{{user_facts.ansible_facts.ansible_user_dir}}/.ansible/mitogen-tests/") - stat: path: "{{out.result}}" diff --git a/tests/ansible/integration/action/remote_expand_user.yml b/tests/ansible/integration/action/remote_expand_user.yml index 632e9492..813fbace 100644 --- a/tests/ansible/integration/action/remote_expand_user.yml +++ b/tests/ansible/integration/action/remote_expand_user.yml @@ -4,27 +4,46 @@ - name: integration/action/remote_expand_user.yml hosts: test-targets any_errors_fatal: true - gather_facts: true tasks: + - name: "Find out root's homedir." + # Runs first because it blats regular Ansible facts with junk, so + # non-become run fixes that up. + setup: gather_subset=min + become: true + register: root_facts - # Expand ~/foo - - action_passthrough: + - name: "Find regular homedir" + setup: gather_subset=min + register: user_facts + + - name: "Expand ~/foo" + action_passthrough: method: _remote_expand_user args: ['~/foo'] register: out - assert: - that: out.result == '{{ansible_user_dir}}/foo' + that: out.result == '{{user_facts.ansible_facts.ansible_user_dir}}/foo' - # Expand ~user/foo - - action_passthrough: + - name: "Expand ~/foo with become active. ~ is become_user's home." + action_passthrough: + method: _remote_expand_user + args: ['~/foo'] + register: out + become: true + + - assert: + that: out.result == '{{root_facts.ansible_facts.ansible_user_dir}}/foo' + + - name: "Expand ~user/foo" + action_passthrough: method: _remote_expand_user args: ['~{{ansible_user_id}}/foo'] register: out - assert: - that: out.result == '{{ansible_user_dir}}/foo' + that: out.result == '{{user_facts.ansible_facts.ansible_user_dir}}/foo' - # Expanding $HOME/foo has no effect. - - action_passthrough: + - name: "Expanding $HOME/foo has no effect." + action_passthrough: method: _remote_expand_user args: ['$HOME/foo'] register: out