Repository: ansible/ansible

Issue:
network parse_cli filter - single match is not caught when using start_block and end_block feature
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
 - Bug Report


##### COMPONENT NAME
Network Filter Plugin (network.py)

##### ANSIBLE VERSION
```
ansible 2.4.0
  config file = None
  configured module search path = [u'/home/skamithi/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/skamithi/fix_parser/local/lib/python2.7/site-packages/ansible
  executable location = /home/skamithi/fix_parser/bin/ansible
  python version = 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609]

```

##### CONFIGURATION
Results of ``ansible-config dump --only-changed `` is empty


##### OS / ENVIRONMENT
```
NX-OSv is a demo version of the Nexus Operating System

Software
  loader:    version N/A
  kickstart: version 7.3(0)D1(1)
  system:    version 7.3(0)D1(1)
  kickstart image file is: bootflash:///titanium-d1-kickstart.7.3.0.D1.1.bin
  kickstart compile time:  1/11/2016 16:00:00 [02/11/2016 10:30:12]
  system image file is:    bootflash:///titanium-d1.7.3.0.D1.1.bin
  system compile time:     1/11/2016 16:00:00 [02/11/2016 13:08:11]


Hardware
  cisco NX-OSv Chassis ("NX-OSv Supervisor Module")
  QEMU Virtual CPU version 2.5 with 3064740 kB of memory.

```

##### SUMMARY
``parse_cli`` when using ``start_block`` and ``end_block`` fails to return a result if there is only a single result. 

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

Sample Playbook
```yaml
---
- hosts: localhost
  gather_facts: false
  connection: local
  tasks:
     - name: get show interface output
         nxos_command:
            commands: "show interface ethernet2/1"
            register: iface_output

      - set_fact:
               nxos_iface: "{{ ifaces_output.stdout[0] | parse_cli('./parsers/nxos/nxos_show_interface_parser.yml') }}"  
```

NxOS interface parser
```
vars:
  interface:
    name: "{{ item[0].name }}"
    link_protocol_state: "{{ item[0].oper }}"
    admin_state: "{{ item[5].admin }}"
    ipv4: "{{ item[1].match[0] }}"
    mtu: "{{ item[2].match[0] }}"
    port_mode: "{{ item[3].match[0] }}"
    duplex: "{{ item[4].match[0] }}"
    description: "{{ item[6].match[0] }}"

keys:
  interfaces:
    value: "{{ interface }}"
    start_block: "^Ethernet.+$"
    end_block: ".+interface reset"
    items:
      - "^(?P<name>Ethernet.+) is (?P<oper>\\w+)"
      - "\\s+Internet Address is (.+)"
      - "\\s+ MTU (\\d+)"
      - "\\s+Port mode is (\\w+)"
      - "\\s+(\\w+-duplex)"
      - "admin state is (?P<admin>\\w+)"
      - "Description: (.+)"
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
````
ok: [cisco01] => {
    "ansible_facts": {
        "nxos_interface": [
            {
                "admin_state": "up", 
                "description": null, 
                "duplex": "full-duplex", 
                "ipv4": "10.1.1.0/31", 
                "link_protocol_state": "up", 
                "mtu": 1500, 
                "name": "Ethernet2/2", 
                "port_mode": "routed"
            }
        ]
    }, 
    "changed": false, 
    "failed": false
}
````

##### ACTUAL RESULTS
```
ok: [cisco01] => {
    "ansible_facts": {
        "nxos_interface": []
    }, 
    "changed": false, 
    "failed": false
}
```



Discussion:

Resolving patch:
diff --git a/lib/ansible/plugins/filter/network.py b/lib/ansible/plugins/filter/network.py
--- a/lib/ansible/plugins/filter/network.py
+++ b/lib/ansible/plugins/filter/network.py
@@ -106,8 +106,6 @@ def parse_cli(output, tmpl):
                 match_end = end_block.match(line)
 
                 if match_start:
-                    if lines:
-                        blocks.append('\n'.join(lines))
                     lines = list()
                     lines.append(line)
                     block_started = True
@@ -115,6 +113,7 @@ def parse_cli(output, tmpl):
                 elif match_end:
                     if lines:
                         lines.append(line)
+                        blocks.append('\n'.join(lines))
                     block_started = False
 
                 elif block_started:


Test patch: