Repository: ansible/ansible

Issue:
module_utils/eos.py does not handle error when maximux sessions reached
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
eos_command

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.4.3.0
  config file = /home/user/.ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/user/soft/ansible/lib/python3.6/site-packages/ansible
  executable location = /home/user/bin/ansible
  python version = 3.6.1 (default, Jun  2 2017, 15:55:17) [GCC 4.8.4]
```

##### CONFIGURATION
N/A

##### OS / ENVIRONMENT
N/A

##### SUMMARY
module_utils/eos.py does not handle error when maximux sessions reached and config commands are being sent in exec mode.

##### STEPS TO REPRODUCE
Run 5 configuraion sessions (or other maximum your switch have). Try to use eos_command plugin on switch (even with check mode).

##### EXPECTED RESULTS
Error is noticed before configuration commands are sent to switch.

##### ACTUAL RESULTS
It does not notice an error and that switch haven't entered configuration mode and tries to run configuration commands in exec mode. Even in check mode it could potentially input something that would make somethin unexpected to the switch.
```
TASK [testrole : testtask] ****************************************************
fatal: [switch]: FAILED! => {"changed": false, "commands": ["...", "..."], "msg": "...\r\n% Invalid input\r\nswitch#...\r\n% Invalid input\r\nswitch#"}
```

Here is the piece of code from module_utils/eos.py that tries to create a configure session:
```
        rc, out, err = self.exec_command('configure session %s' % session)
        if rc != 0:
            self._module.fail_json(msg='unable to enter configuration mode', output=to_text(err, errors='surrogate_then_replace'))
```
In case of error we actually receive:
```
rc=0
out=% Maximum number of pending sessions has been reached. Please commit or abort previous sessions before creating a new one.
err=0
```

I tracked down where the command actually executed (plugins/connection/network_cli.py) and it turns out that it always return rc == 0:
```
    def exec_command(self, cmd):
...
            out = self.send(obj['command'], obj.get('prompt'), obj.get('answer'), obj.get('sendonly'))
            signal.alarm(0)
            return 0, out, b''
```


Discussion:
Files identified in the description:
* [lib/ansible/modules/network/eos/eos_command.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/network/eos/eos_command.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 @privateip @trishnaguha
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
> and it turns out that it always return rc == 0:

But I may be not correct here. I do not fully understand all the internals. May be rc != 0 is possible, but error is not checked correctly somewhere.
not looked at this yet, will do after RC2

Resolving patch:
diff --git a/lib/ansible/module_utils/network/eos/eos.py b/lib/ansible/module_utils/network/eos/eos.py
--- a/lib/ansible/module_utils/network/eos/eos.py
+++ b/lib/ansible/module_utils/network/eos/eos.py
@@ -205,7 +205,7 @@ def load_config(self, commands, commit=False, replace=False):
             return conn.load_config(commands, commit, replace)
         except ConnectionError as exc:
             message = getattr(exc, 'err', exc)
-            self._module.fail_json(msg="Error on executing commands %s" % commands, data=to_text(message, errors='surrogate_then_replace'))
+            self._module.fail_json(msg="%s" % message, data=to_text(message, errors='surrogate_then_replace'))
 
 
 class Eapi:
diff --git a/lib/ansible/plugins/terminal/eos.py b/lib/ansible/plugins/terminal/eos.py
--- a/lib/ansible/plugins/terminal/eos.py
+++ b/lib/ansible/plugins/terminal/eos.py
@@ -45,7 +45,8 @@ class TerminalModule(TerminalBase):
         re.compile(br"[^\r\n]+ not found", re.I),
         re.compile(br"'[^']' +returned error code: ?\d+"),
         re.compile(br"[^\r\n]\/bin\/(?:ba)?sh"),
-        re.compile(br"% More than \d+ OSPF instance", re.I)
+        re.compile(br"% More than \d+ OSPF instance", re.I),
+        re.compile(br"Maximum number of pending sessions has been reached")
     ]
 
     def on_open_shell(self):


Test patch: