Repository: ansible/ansible

Issue:
iosxr_template & iosxr_config: unable to enter configuration mode
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
iosxr_config
iosxr_template

##### ANSIBLE VERSION
```
ansible 2.3.0 (iosxr_tests ebc2716be7) last updated 2017/02/27 12:09:47 (GMT +100)
```


##### SUMMARY
`"unable to enter configuration mode"` with `iosxr_config` and `iosxr_template`

##### STEPS TO REPRODUCE
`time ANSIBLE_ROLES_PATH=targets  ansible-playbook -vvvvv  -i  inventory.network iosxr.yaml  -e "limit_to=iosxr_config" -u root -k`

`time ANSIBLE_ROLES_PATH=targets  ansible-playbook -vvvvv  -i  inventory.networ iosxr.yaml  -e "limit_to=iosxr_template" -u root -k`


```yaml
- name: setup
  iosxr_config:
    commands:
      - no description
      - no shutdown
    parents:
      - interface Loopback999
    match: none

- name: configure device with config
  iosxr_config:
    src: basic/config.j2
  register: result
```

**basic/config.j2**
```yaml
interface Loopback999
 description this is a test
 shutdown

```

##### EXPECTED RESULTS

##### ACTUAL RESULTS
```yaml
TASK [iosxr_config : configure device with config] ***********************************************************************************************************************************************************************************************
task path: /home/johnb/git/ansible-inc/ansible-workspace-2/test/integration/targets/iosxr_config/tests/cli/src_basic.yaml:13
Using module file /home/johnb/git/ansible-inc/ansible-workspace-2/lib/ansible/modules/network/iosxr/iosxr_config.py
<iosxr01> ESTABLISH LOCAL CONNECTION FOR USER: johnb
<iosxr01> EXEC /bin/sh -c 'echo ~ && sleep 0'
<iosxr01> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/johnb/.ansible/tmp/ansible-tmp-1488202112.61-275083561754384 `" && echo ansible-tmp-1488202112.61-275083561754384="` echo /home/johnb/.ansible/tmp/ansible-tmp-1488202112.61-275083561754384 `" ) && sleep 0'
<iosxr01> PUT /tmp/tmplhB6gE TO /home/johnb/.ansible/tmp/ansible-tmp-1488202112.61-275083561754384/iosxr_config.py
<iosxr01> EXEC /bin/sh -c 'chmod u+x /home/johnb/.ansible/tmp/ansible-tmp-1488202112.61-275083561754384/ /home/johnb/.ansible/tmp/ansible-tmp-1488202112.61-275083561754384/iosxr_config.py && sleep 0'
<iosxr01> EXEC /bin/sh -c 'python /home/johnb/.ansible/tmp/ansible-tmp-1488202112.61-275083561754384/iosxr_config.py; rm -rf "/home/johnb/.ansible/tmp/ansible-tmp-1488202112.61-275083561754384/" > /dev/null 2>&1 && sleep 0'
fatal: [iosxr01]: FAILED! => {
    "changed": false, 
    "err": "configure terminal\r\n\r                                    ^\r\n% Invalid input detected at '^' marker.\r\nRP/0/0/CPU0:iosxr01(config)#", 
    "failed": true, 
    "invocation": {
        "module_args": {
            "after": null, 
            "backup": false, 
            "before": null, 
            "comment": "configured by iosxr_config", 
            "config": null, 
            "force": false, 
            "host": null, 
            "lines": null, 
            "match": "line", 
            "parents": null, 
            "password": null, 
            "port": null, 
            "provider": null, 
            "replace": "line", 
            "src": "interface Loopback999\n description this is a test\n shutdown\n\n", 
            "ssh_keyfile": null, 
            "timeout": null, 
            "username": null
        }
    }, 
    "msg": "unable to enter configuration mode"
}
	
```



Discussion:
cc @rcarrillocruz @privateip @Qalthos
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Can repro this, pasting run with ANSIBLE_LOG_PATH:

```
2017-02-28 14:27:21,479 p=7611 u=ricky |  Using /home/ricky/devel/playbooks/ansible.cfg as config file
2017-02-28 14:27:23,210 p=7611 u=ricky |  Loading callback plugin default of type stdout, v2.0 from /home/ricky/devel/ansible/lib/ansible/plugins/callback/__init__.pyc
2017-02-28 14:27:23,218 p=7611 u=ricky |  PLAYBOOK: issue_21994.yaml *******************************************************************************************************************************************************************
2017-02-28 14:27:23,218 p=7611 u=ricky |  1 plays in iosxr/issue_21994.yaml
2017-02-28 14:27:23,220 p=7611 u=ricky |  PLAY [iosxr] *********************************************************************************************************************************************************************************
2017-02-28 14:27:23,238 p=7611 u=ricky |  TASK [Gathering Facts] ***********************************************************************************************************************************************************************
2017-02-28 14:27:23,454 p=7611 u=ricky |  Using module file /home/ricky/devel/ansible/lib/ansible/modules/system/setup.py
2017-02-28 14:27:23,865 p=7611 u=ricky |  ok: [iosxr01]
2017-02-28 14:27:23,866 p=7611 u=ricky |  META: ran handlers
2017-02-28 14:27:23,869 p=7611 u=ricky |  TASK [setup] *********************************************************************************************************************************************************************************
2017-02-28 14:27:23,869 p=7611 u=ricky |  task path: /home/ricky/devel/playbooks/iosxr/issue_21994.yaml:6
<iosxr01> starting new persistent socket with path /home/ricky/.ansible/pc/6cfd6ab3ae
<iosxr01> using connection plugin network_cli
<iosxr01> ESTABLISH CONNECTION FOR USER: cisco on PORT 22 TO iosxr01
<iosxr01> ssh connection done, setting terminal
<iosxr01> ssh connection has completed successfully
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 1833
<iosxr01> socket operation is CONTEXT
<iosxr01> updating play_context for connection
<iosxr01> received data on socket with len 18
<iosxr01> socket operation is EXEC
<iosxr01> attempting to open shell to device
<iosxr01> shell successfully opened
<iosxr01> socket operation completed with rc 0
2017-02-28 14:27:30,700 p=7611 u=ricky |  Using module file /home/ricky/devel/ansible/lib/ansible/modules/network/iosxr/iosxr_config.py
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 24
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 27
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 20
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 17
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 30
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 47
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 1833
<iosxr01> socket operation is CONTEXT
<iosxr01> updating play_context for connection
<iosxr01> received data on socket with len 14
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 1833
<iosxr01> socket operation is CONTEXT
<iosxr01> updating play_context for connection
<iosxr01> received data on socket with len 10
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
2017-02-28 14:27:35,436 p=7611 u=ricky |  changed: [iosxr01] => {
    "changed": true, 
    "commands": [
        "interface Loopback999", 
        "no description", 
        "no shutdown"
    ], 
    "diff": {
        "prepared": "Building configuration...\n!! IOS XR Configuration 6.1.2\nend"
    }, 
    "invocation": {
        "module_args": {
            "after": null, 
            "backup": false, 
            "before": null, 
            "commands": [
                "no description", 
                "no shutdown"
            ], 
            "comment": "configured by iosxr_config", 
            "config": null, 
            "force": false, 
            "host": null, 
            "lines": [
                "no description", 
                "no shutdown"
            ], 
            "match": "none", 
            "parents": [
                "interface Loopback999"
            ], 
            "password": null, 
            "port": null, 
            "provider": null, 
            "replace": "line", 
            "src": null, 
            "ssh_keyfile": null, 
            "timeout": null, 
            "username": null
        }
    }
}
2017-02-28 14:27:35,440 p=7611 u=ricky |  TASK [configure device with config] **********************************************************************************************************************************************************
2017-02-28 14:27:35,440 p=7611 u=ricky |  task path: /home/ricky/devel/playbooks/iosxr/issue_21994.yaml:15
2017-02-28 14:27:35,476 p=7611 u=ricky |  Using module file /home/ricky/devel/ansible/lib/ansible/modules/network/iosxr/iosxr_config.py
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 25
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 24
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 1
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 1833
<iosxr01> socket operation is CONTEXT
<iosxr01> updating play_context for connection
<iosxr01> received data on socket with len 14
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 1833
<iosxr01> socket operation is CONTEXT
<iosxr01> updating play_context for connection
<iosxr01> received data on socket with len 10
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
2017-02-28 14:27:38,388 p=7611 u=ricky |  fatal: [iosxr01]: FAILED! => {
    "changed": false, 
    "err": "configure terminal\r\n\r                                    ^\r\n% Invalid input detected at '^' marker.\r\nRP/0/0/CPU0:iosxr01(config)#", 
    "failed": true, 
    "invocation": {
        "module_args": {
            "after": null, 
            "backup": false, 
            "before": null, 
            "comment": "configured by iosxr_config", 
            "config": null, 
            "force": false, 
            "host": null, 
            "lines": null, 
            "match": "line", 
            "parents": null, 
            "password": null, 
            "port": null, 
            "provider": null, 
            "replace": "line", 
            "src": "hostname iosxr01\n!\ninterface Loopback999\n description this is a test\n shutdown\n", 
            "ssh_keyfile": null, 
            "timeout": null, 
            "username": null
        }
    }, 
    "msg": "unable to enter configuration mode"
}
2017-02-28 14:27:38,390 p=7611 u=ricky |  	to retry, use: --limit @/home/ricky/devel/playbooks/iosxr/issue_21994.retry

2017-02-28 14:27:38,390 p=7611 u=ricky |  PLAY RECAP ***********************************************************************************************************************************************************************************
2017-02-28 14:27:38,390 p=7611 u=ricky |  iosxr01                    : ok=2    changed=1    unreachable=0    failed=1   
<iosxr01> closing shell due to sigalarm
<iosxr01> closing shell on device
<iosxr01> shutting down control socket, connection was active for 0:00:44.188675 secs
<iosxr01> closing connection
<iosxr01> closing shell on device
2017-02-28 14:56:11,517 p=8746 u=ricky |  Using /home/ricky/devel/playbooks/ansible.cfg as config file
2017-02-28 14:56:13,317 p=8746 u=ricky |  Loading callback plugin default of type stdout, v2.0 from /home/ricky/devel/ansible/lib/ansible/plugins/callback/__init__.pyc
2017-02-28 14:56:13,325 p=8746 u=ricky |  PLAYBOOK: issue_21994.yaml *******************************************************************************************************************************************************************
2017-02-28 14:56:13,325 p=8746 u=ricky |  1 plays in iosxr/issue_21994.yaml
2017-02-28 14:56:13,328 p=8746 u=ricky |  PLAY [iosxr] *********************************************************************************************************************************************************************************
2017-02-28 14:56:13,345 p=8746 u=ricky |  TASK [Gathering Facts] ***********************************************************************************************************************************************************************
2017-02-28 14:56:13,567 p=8746 u=ricky |  Using module file /home/ricky/devel/ansible/lib/ansible/modules/system/setup.py
2017-02-28 14:56:14,403 p=8746 u=ricky |  ok: [iosxr01]
2017-02-28 14:56:14,403 p=8746 u=ricky |  META: ran handlers
2017-02-28 14:56:14,406 p=8746 u=ricky |  TASK [setup] *********************************************************************************************************************************************************************************
2017-02-28 14:56:14,407 p=8746 u=ricky |  task path: /home/ricky/devel/playbooks/iosxr/issue_21994.yaml:6
<iosxr01> starting new persistent socket with path /home/ricky/.ansible/pc/6cfd6ab3ae
<iosxr01> using connection plugin network_cli
<iosxr01> ESTABLISH CONNECTION FOR USER: cisco on PORT 22 TO iosxr01
<iosxr01> ssh connection done, setting terminal
<iosxr01> ssh connection has completed successfully
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 1833
<iosxr01> socket operation is CONTEXT
<iosxr01> updating play_context for connection
<iosxr01> received data on socket with len 18
<iosxr01> socket operation is EXEC
<iosxr01> attempting to open shell to device
<iosxr01> shell successfully opened
<iosxr01> socket operation completed with rc 0
2017-02-28 14:56:20,913 p=8746 u=ricky |  Using module file /home/ricky/devel/ansible/lib/ansible/modules/network/iosxr/iosxr_config.py
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 24
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 27
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 20
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 17
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 30
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 47
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 1833
<iosxr01> socket operation is CONTEXT
<iosxr01> updating play_context for connection
<iosxr01> received data on socket with len 14
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 1833
<iosxr01> socket operation is CONTEXT
<iosxr01> updating play_context for connection
<iosxr01> received data on socket with len 10
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
2017-02-28 14:56:25,169 p=8746 u=ricky |  changed: [iosxr01] => {
    "changed": true, 
    "commands": [
        "interface Loopback999", 
        "no description", 
        "no shutdown"
    ], 
    "diff": {
        "prepared": "Building configuration...\n!! IOS XR Configuration 6.1.2\nend"
    }, 
    "invocation": {
        "module_args": {
            "after": null, 
            "backup": false, 
            "before": null, 
            "commands": [
                "no description", 
                "no shutdown"
            ], 
            "comment": "configured by iosxr_config", 
            "config": null, 
            "force": false, 
            "host": null, 
            "lines": [
                "no description", 
                "no shutdown"
            ], 
            "match": "none", 
            "parents": [
                "interface Loopback999"
            ], 
            "password": null, 
            "port": null, 
            "provider": null, 
            "replace": "line", 
            "src": null, 
            "ssh_keyfile": null, 
            "timeout": null, 
            "username": null
        }
    }
}
2017-02-28 14:56:25,173 p=8746 u=ricky |  TASK [configure device with config] **********************************************************************************************************************************************************
2017-02-28 14:56:25,173 p=8746 u=ricky |  task path: /home/ricky/devel/playbooks/iosxr/issue_21994.yaml:15
2017-02-28 14:56:25,211 p=8746 u=ricky |  Using module file /home/ricky/devel/ansible/lib/ansible/modules/network/iosxr/iosxr_config.py
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 25
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 24
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 1
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 1833
<iosxr01> socket operation is CONTEXT
<iosxr01> updating play_context for connection
<iosxr01> received data on socket with len 14
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
<iosxr01> incoming request accepted on persistent socket
<iosxr01> received data on socket with len 1833
<iosxr01> socket operation is CONTEXT
<iosxr01> updating play_context for connection
<iosxr01> received data on socket with len 10
<iosxr01> socket operation is EXEC
<iosxr01> socket operation completed with rc 0
2017-02-28 14:56:28,095 p=8746 u=ricky |  fatal: [iosxr01]: FAILED! => {
    "changed": false, 
    "err": "configure terminal\r\n\r                                    ^\r\n% Invalid input detected at '^' marker.\r\nRP/0/0/CPU0:iosxr01(config)#", 
    "failed": true, 
    "invocation": {
        "module_args": {
            "after": null, 
            "backup": false, 
            "before": null, 
            "comment": "configured by iosxr_config", 
            "config": null, 
            "force": false, 
            "host": null, 
            "lines": null, 
            "match": "line", 
            "parents": null, 
            "password": null, 
            "port": null, 
            "provider": null, 
            "replace": "line", 
            "src": "hostname iosxr01\n!\ninterface Loopback999\n description this is a test\n shutdown\n", 
            "ssh_keyfile": null, 
            "timeout": null, 
            "username": null
        }
    }, 
    "msg": "unable to enter configuration mode"
}
2017-02-28 14:56:28,096 p=8746 u=ricky |  	to retry, use: --limit @/home/ricky/devel/playbooks/iosxr/issue_21994.retry

2017-02-28 14:56:28,096 p=8746 u=ricky |  PLAY RECAP ***********************************************************************************************************************************************************************************
2017-02-28 14:56:28,097 p=8746 u=ricky |  iosxr01                    : ok=2    changed=1    unreachable=0    failed=1   
<iosxr01> closing shell due to sigalarm
<iosxr01> closing shell on device
<iosxr01> shutting down control socket, connection was active for 0:00:43.259523 secs
<iosxr01> closing connection
<iosxr01> closing shell on device
```

Resolving patch:
diff --git a/lib/ansible/plugins/action/iosxr.py b/lib/ansible/plugins/action/iosxr.py
--- a/lib/ansible/plugins/action/iosxr.py
+++ b/lib/ansible/plugins/action/iosxr.py
@@ -64,19 +64,23 @@ def run(self, tmp=None, task_vars=None):
         socket_path = self._get_socket_path(pc)
         if not os.path.exists(socket_path):
             # start the connection if it isn't started
+            display.vvvv('calling open_shell()', pc.remote_addr)
             rc, out, err = connection.exec_command('open_shell()')
             if rc != 0:
                 return {'failed': True, 'msg': 'unable to open shell', 'rc': rc}
+        else:
+            # make sure we are in the right cli context which should be
+            # enable mode and not config module
+            rc, out, err = connection.exec_command('prompt()')
+            while str(out).strip().endswith(')#'):
+                display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
+                connection.exec_command('exit')
+                rc, out, err = connection.exec_command('prompt()')
 
         task_vars['ansible_socket'] = socket_path
 
         result = super(ActionModule, self).run(tmp, task_vars)
 
-        # need to make sure to leave config mode if the module didn't clean up
-        rc, out, err = connection.exec_command('prompt()')
-        if str(out).strip().endswith(')#'):
-            connection.exec_command('exit')
-
         return result
 
     def _get_socket_path(self, play_context):


Test patch: