Repository: ansible/ansible

Issue:
ios_command module : can not use "configure revert" commands
##### ISSUE TYPE 
- Bug Report

##### COMPONENT NAME
- ios_command

##### ANSIBLE VERSION
- 2.x

##### SUMMARY: ios_command module should not filter out all configure commands

ios_command is a wonderful module, however i found a minor issue :

On line 165 there is a sanity check that verify that the user is not sending a configuration command
 ` elif item['command'].startswith('conf'):` 

With this test, it is not possible to send the following commands :
  - configure revert timer 5
  - configure confirm
  - configure replace
  - configure network
which ARE valid exec commands and do NOT enter in configuration mode.

Hopefully (for me), a basic workaround is to insert a space (may be it is intented) :
  - [space] configure revert timer 5

I propose to change the test and use something like  (sorry i am not familiar with python) :
`   elif re.match("^\s*conf\S*\s+t", item['command']) `
just to ensure that the user has NOT entered one of various configure terminal flavors.


##### STEPS TO REPRODUCE

Use the following playbook : 

<pre> 
---
- name: try
  hosts: all
  connection: local
  gather_facts: no

  vars:
      cli:
        host: "{{ inventory_hostname }}"
        username: cisco
        password: cisco
        transport: cli

  - name: This work (note the space at the beginning of the command line)
    ios_command:
          commands:
             - clear configuration lock
             - " configure revert timer 8"

  - name: This will not work (but should)
    ios_command:
          commands:
             - clear configuration lock
             - "configure revert timer 8"
</pre> 



Discussion:
@PJO2 Greetings! Thanks for taking the time to open this issue. In order for the community to handle your issue effectively, we need a bit more information. 

Here are the items we could not find in your description:
- issue type
- ansible version
- component name

Please set the description of this issue with this template:
https://raw.githubusercontent.com/ansible/ansible/devel/.github/ISSUE_TEMPLATE.md

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: issue_missing_data --->
cc @kedarX @privateip @rcarrillocruz
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/network/ios/ios_command.py b/lib/ansible/modules/network/ios/ios_command.py
--- a/lib/ansible/modules/network/ios/ios_command.py
+++ b/lib/ansible/modules/network/ios/ios_command.py
@@ -131,6 +131,7 @@
   type: list
   sample: ['...', '...']
 """
+import re
 import time
 
 from ansible.module_utils.network.ios.ios import run_commands
@@ -156,13 +157,14 @@ def parse_commands(module, warnings):
     ), module)
     commands = command(module.params['commands'])
     for item in list(commands):
+        configure_type = re.match(r'conf(?:\w*)(?:\s+(\w+))?', item['command'])
         if module.check_mode and not item['command'].startswith('show'):
             warnings.append(
                 'only show commands are supported when using check mode, not '
                 'executing `%s`' % item['command']
             )
             commands.remove(item)
-        elif item['command'].startswith('conf'):
+        elif configure_type and configure_type.group(1) not in ('confirm', 'replace', 'revert', 'network'):
             module.fail_json(
                 msg='ios_command does not support running config mode '
                     'commands.  Please use ios_config instead'


Test patch:
diff --git a/test/units/modules/network/ios/fixtures/configure_revert_now b/test/units/modules/network/ios/fixtures/configure_revert_now
new file mode 100644
--- /dev/null
+++ b/test/units/modules/network/ios/fixtures/configure_revert_now
@@ -0,0 +1,2 @@
+%No Rollback Confirmed Change pending
+
diff --git a/test/units/modules/network/ios/test_ios_command.py b/test/units/modules/network/ios/test_ios_command.py
--- a/test/units/modules/network/ios/test_ios_command.py
+++ b/test/units/modules/network/ios/test_ios_command.py
@@ -106,3 +106,17 @@ def test_ios_command_match_all_failure(self):
         commands = ['show version', 'show version']
         set_module_args(dict(commands=commands, wait_for=wait_for, match='all'))
         self.execute_module(failed=True)
+
+    def test_ios_command_configure_error(self):
+        commands = ['configure terminal']
+        set_module_args(dict(commands=commands))
+        result = self.execute_module(failed=True)
+        self.assertEqual(
+            result['msg'],
+            'ios_command does not support running config mode commands.  Please use ios_config instead'
+        )
+
+    def test_ios_command_configure_not_error(self):
+        commands = ['configure revert now']
+        set_module_args(dict(commands=commands))
+        self.execute_module()