Repository: ansible/ansible

Issue:
Regression when connecting as root to network devices
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
`lib/ansible/plugins/action/__init__.py`
##### ANSIBLE VERSION
```
2.5
```


##### SUMMARY

For some of network test platforms we run Ansible as a normal user and connect to the network device as `root`

After https://github.com/ansible/ansible/pull/36755 and (stable-2.5 https://github.com/ansible/ansible/pull/39567)

This fails as we end up in the `else` case in: 

https://github.com/ansible/ansible/blob/979f1e5ed14fd13c95b3651906c4916b5bb01535/lib/ansible/plugins/action/__init__.py#L570-L575

Adding some debug shows:
```python
_remote_expand_user: expand_path=u'~'
_remote_expand_user: sudoable=False
_remote_expand_user: self._play_context.become=False
_remote_expand_user: self._play_context.become_user=u'root'
_remote_expand_user: self._play_context.remote_user=u'root'
_remote_expand_user: self._connection.default_user=None

So we end up with:
_remote_expand_user: expand_path=u'~root'
```

Which version of 2.5.x did this go into?
##### STEPS TO REPRODUCE

group_vars/junos.yaml
```yaml
netconf:
  transport: netconf

ansible_ssh_user: root
ansible_ssh_pass: Juniper
ansible_network_os: junos
```

```yaml
- name: Ensure netconf is enabled
  junos_netconf:
    state: present
  connection: network_cl
```

Looking at the code, we need to ensure we don't have a similar issue for the Network platforms that support `become`

##### EXPECTED RESULTS
```
<192.168.0.2> ESTABLISH LOCAL CONNECTION FOR USER: nodepool
<192.168.0.2> EXEC /bin/sh -c 'echo ~ && sleep 0'
<192.168.0.2> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /var/lib/nodepool/.ansible/tmp/ansible-tmp-1526470699.9-63376153535174 `" && echo ansible-tmp-1526470699.9-63376153535174="` echo /var/lib/nodepool/.ansible/tmp/ansible-tmp-1526470
699.9-63376153535174 `" ) && sleep 0'
```
##### ACTUAL RESULTS
```
<192.168.0.2> ESTABLISH LOCAL CONNECTION FOR USER: nodepool
<192.168.0.2> EXEC /bin/sh -c 'echo ~root && sleep 0'
<192.168.0.2> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1526470635.85-257180289460256 `" && echo ansible-tmp-1526470635.85-257180289460256="` echo /root/.ansible/tmp/ansible-tmp-1526470635.85-2571802894602
56 `" ) && sleep 0'
```





Discussion:
Files identified in the description:
* [lib/ansible/plugins/action/__init__.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/__init__.py)
* [lib/ansible/plugins/action/add_host.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/add_host.py)
* [lib/ansible/plugins/action/aireos.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/aireos.py)
* [lib/ansible/plugins/action/aireos_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/aireos_config.py)
* [lib/ansible/plugins/action/aruba.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/aruba.py)
* [lib/ansible/plugins/action/aruba_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/aruba_config.py)
* [lib/ansible/plugins/action/asa.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/asa.py)
* [lib/ansible/plugins/action/asa_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/asa_config.py)
* [lib/ansible/plugins/action/assemble.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/assemble.py)
* [lib/ansible/plugins/action/assert.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/assert.py)
* [lib/ansible/plugins/action/aws_s3.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/aws_s3.py)
* [lib/ansible/plugins/action/bigip.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/bigip.py)
* [lib/ansible/plugins/action/bigiq.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/bigiq.py)
* [lib/ansible/plugins/action/ce.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/ce.py)
* [lib/ansible/plugins/action/ce_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/ce_config.py)
* [lib/ansible/plugins/action/ce_template.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/ce_template.py)
* [lib/ansible/plugins/action/command.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/command.py)
* [lib/ansible/plugins/action/copy.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/copy.py)
* [lib/ansible/plugins/action/debug.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/debug.py)
* [lib/ansible/plugins/action/dellos10.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/dellos10.py)
* [lib/ansible/plugins/action/dellos10_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/dellos10_config.py)
* [lib/ansible/plugins/action/dellos6.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/dellos6.py)
* [lib/ansible/plugins/action/dellos6_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/dellos6_config.py)
* [lib/ansible/plugins/action/dellos9.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/dellos9.py)
* [lib/ansible/plugins/action/dellos9_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/dellos9_config.py)
* [lib/ansible/plugins/action/edgeos_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/edgeos_config.py)
* [lib/ansible/plugins/action/enos.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/enos.py)
* [lib/ansible/plugins/action/enos_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/enos_config.py)
* [lib/ansible/plugins/action/eos.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/eos.py)
* [lib/ansible/plugins/action/eos_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/eos_config.py)
* [lib/ansible/plugins/action/fail.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/fail.py)
* [lib/ansible/plugins/action/fetch.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/fetch.py)
* [lib/ansible/plugins/action/fortios_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/fortios_config.py)
* [lib/ansible/plugins/action/group_by.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/group_by.py)
* [lib/ansible/plugins/action/include_vars.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/include_vars.py)
* [lib/ansible/plugins/action/ios.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/ios.py)
* [lib/ansible/plugins/action/ios_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/ios_config.py)
* [lib/ansible/plugins/action/iosxr.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/iosxr.py)
* [lib/ansible/plugins/action/iosxr_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/iosxr_config.py)
* [lib/ansible/plugins/action/ironware.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/ironware.py)
* [lib/ansible/plugins/action/ironware_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/ironware_config.py)
* [lib/ansible/plugins/action/junos.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/junos.py)
* [lib/ansible/plugins/action/junos_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/junos_config.py)
* [lib/ansible/plugins/action/net_banner.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_banner.py)
* [lib/ansible/plugins/action/net_base.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_base.py)
* [lib/ansible/plugins/action/net_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_config.py)
* [lib/ansible/plugins/action/net_interface.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_interface.py)
* [lib/ansible/plugins/action/net_l2_interface.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_l2_interface.py)
* [lib/ansible/plugins/action/net_l3_interface.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_l3_interface.py)
* [lib/ansible/plugins/action/net_linkagg.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_linkagg.py)
* [lib/ansible/plugins/action/net_lldp.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_lldp.py)
* [lib/ansible/plugins/action/net_lldp_interface.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_lldp_interface.py)
* [lib/ansible/plugins/action/net_logging.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_logging.py)
* [lib/ansible/plugins/action/net_ping.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_ping.py)
* [lib/ansible/plugins/action/net_static_route.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_static_route.py)
* [lib/ansible/plugins/action/net_system.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_system.py)
* [lib/ansible/plugins/action/net_user.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_user.py)
* [lib/ansible/plugins/action/net_vlan.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_vlan.py)
* [lib/ansible/plugins/action/net_vrf.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/net_vrf.py)
* [lib/ansible/plugins/action/netconf_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/netconf_config.py)
* [lib/ansible/plugins/action/network_get.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/network_get.py)
* [lib/ansible/plugins/action/network_put.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/network_put.py)
* [lib/ansible/plugins/action/normal.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/normal.py)
* [lib/ansible/plugins/action/nxos.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/nxos.py)
* [lib/ansible/plugins/action/nxos_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/nxos_config.py)
* [lib/ansible/plugins/action/onyx_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/onyx_config.py)
* [lib/ansible/plugins/action/ops_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/ops_config.py)
* [lib/ansible/plugins/action/package.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/package.py)
* [lib/ansible/plugins/action/patch.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/patch.py)
* [lib/ansible/plugins/action/pause.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/pause.py)
* [lib/ansible/plugins/action/raw.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/raw.py)
* [lib/ansible/plugins/action/script.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/script.py)
* [lib/ansible/plugins/action/service.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/service.py)
* [lib/ansible/plugins/action/set_fact.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/set_fact.py)
* [lib/ansible/plugins/action/set_stats.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/set_stats.py)
* [lib/ansible/plugins/action/shell.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/shell.py)
* [lib/ansible/plugins/action/sros.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/sros.py)
* [lib/ansible/plugins/action/sros_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/sros_config.py)
* [lib/ansible/plugins/action/synchronize.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/synchronize.py)
* [lib/ansible/plugins/action/telnet.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/telnet.py)
* [lib/ansible/plugins/action/template.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/template.py)
* [lib/ansible/plugins/action/unarchive.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/unarchive.py)
* [lib/ansible/plugins/action/vyos.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/vyos.py)
* [lib/ansible/plugins/action/vyos_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/vyos_config.py)
* [lib/ansible/plugins/action/wait_for_connection.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/wait_for_connection.py)
* [lib/ansible/plugins/action/win_copy.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/win_copy.py)
* [lib/ansible/plugins/action/win_reboot.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/win_reboot.py)
* [lib/ansible/plugins/action/win_template.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/win_template.py)
* [lib/ansible/plugins/action/win_updates.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/win_updates.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @Qalthos @gdpak @jmighion @ogenstad @paulquack @privateip @rcarrillocruz @samerd @trishnaguha
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/plugins/action/__init__.py b/lib/ansible/plugins/action/__init__.py
--- a/lib/ansible/plugins/action/__init__.py
+++ b/lib/ansible/plugins/action/__init__.py
@@ -246,7 +246,13 @@ def _make_tmp_path(self, remote_user=None):
         # deal with tmpdir creation
         basefile = 'ansible-tmp-%s-%s' % (time.time(), random.randint(0, 2**48))
         use_system_tmp = bool(self._play_context.become and self._play_context.become_user not in admin_users)
-        tmpdir = self._remote_expand_user(remote_tmp, sudoable=False)
+        # Network connection plugins (network_cli, netconf, etc.) execute on the controller, rather than the remote host.
+        # As such, we want to avoid using remote_user for paths  as remote_user may not line up with the local user
+        # This is a hack and should be solved by more intelligent handling of remote_tmp in 2.7
+        if getattr(self._connection, '_remote_is_local', False):
+            tmpdir = C.DEFAULT_LOCAL_TMP
+        else:
+            tmpdir = self._remote_expand_user(remote_tmp, sudoable=False)
         cmd = self._connection._shell.mkdtemp(basefile=basefile, system=use_system_tmp, tmpdir=tmpdir)
         result = self._low_level_execute_command(cmd, sudoable=False)
 
@@ -568,7 +574,12 @@ def _remote_expand_user(self, path, sudoable=True, pathsep=None):
         expand_path = split_path[0]
 
         if expand_path == '~':
-            if sudoable and self._play_context.become and self._play_context.become_user:
+            # Network connection plugins (network_cli, netconf, etc.) execute on the controller, rather than the remote host.
+            # As such, we want to avoid using remote_user for paths  as remote_user may not line up with the local user
+            # This is a hack and should be solved by more intelligent handling of remote_tmp in 2.7
+            if getattr(self._connection, '_remote_is_local', False):
+                pass
+            elif sudoable and self._play_context.become and self._play_context.become_user:
                 expand_path = '~%s' % self._play_context.become_user
             else:
                 # use remote user instead, if none set default to current user
diff --git a/lib/ansible/plugins/connection/netconf.py b/lib/ansible/plugins/connection/netconf.py
--- a/lib/ansible/plugins/connection/netconf.py
+++ b/lib/ansible/plugins/connection/netconf.py
@@ -169,6 +169,8 @@ class Connection(ConnectionBase):
     transport = 'netconf'
     has_pipelining = False
     force_persistence = True
+    # Do not use _remote_is_local in other connections
+    _remote_is_local = True
 
     def __init__(self, play_context, new_stdin, *args, **kwargs):
         super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
diff --git a/lib/ansible/plugins/connection/network_cli.py b/lib/ansible/plugins/connection/network_cli.py
--- a/lib/ansible/plugins/connection/network_cli.py
+++ b/lib/ansible/plugins/connection/network_cli.py
@@ -188,6 +188,8 @@ class Connection(ConnectionBase):
     transport = 'network_cli'
     has_pipelining = True
     force_persistence = True
+    # Do not use _remote_is_local in other connections
+    _remote_is_local = True
 
     def __init__(self, play_context, new_stdin, *args, **kwargs):
         super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)


Test patch: