ansible-network / network-engine

This role provides the foundation for building network roles by providing modules and plugins that are common to all Ansible Network roles.
GNU General Public License v3.0
112 stars 53 forks source link

Error using regex branch reset group within command_parser pattern_match #228

Closed mattgmoser closed 5 years ago

mattgmoser commented 5 years ago

ISSUE TYPE

ANSIBLE VERSION

ansible 2.7.6
Ansible Tower 3.3.1
ansible-network.network-engine, v2.7.4

Network OS

SUMMARY

I am attempting to utilize network-engine's command_parser to extract key facts, such as network device version number, from the device.

Because different versions of NXOS and IOS seem to present the data in a slightly different way, I was hoping to use a regex branch reset group to apply 'OR' logic to match the different variants of how the data is displayed to the same regex group.

STEPS TO REPRODUCE

To reproduce, attempt to use a branch reset group under 'regex' within pattern_match.

`- name: MATCH PATTERN
  pattern_match:
    regex: "(?|(doggies)|(Cisco Nexus Operating))"
    match_all: yes
  register: section

- name: GENERATE JSON DATA STRUCTURE
  json_template:
    template:
      - key: "show version"
        object:
        - key: version
          value: "{{ item.matches.0 }}"
  loop: "{{ section }}"
  extend: device_facts
  export: yes
  register: device_facts`

EXPECTED RESULTS

The above should match either 'doggies' or 'Cisco Nexus Operating' to regex group 1. This works fine on online Regex editors, but throws an error when I try this through command_parser.

regex101.com: Link to expected result example

ACTUAL RESULTS

TASK [Parsing command data into JSON format: show version] *********************
task path: /var/lib/awx/projects/_69__network_data_collection/data-discovery/show-nxos.yml:30
The full traceback is:
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 140, in run
    res = self._execute()
  File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 612, in _execute
    result = self._handler.run(task_vars=variables)
  File "/var/lib/awx/projects/_69__network_data_collection/data-discovery/roles/ansible-network.network-engine/action_plugins/command_parser.py", line 187, in run
    res = self._process_directive(task)
  File "/var/lib/awx/projects/_69__network_data_collection/data-discovery/roles/ansible-network.network-engine/action_plugins/command_parser.py", line 391, in _process_directive
    return meth(**args)
  File "/var/lib/awx/projects/_69__network_data_collection/data-discovery/roles/ansible-network.network-engine/action_plugins/command_parser.py", line 406, in do_pattern_match
    return parser.match(regex, match_all, match_until, match_greedy)
  File "/var/lib/awx/projects/_69__network_data_collection/data-discovery/roles/ansible-network.network-engine/action_plugins/../lib/network_engine/plugins/parser/pattern_match.py", line 39, in match
    return self._match_all(content, regex)
  File "/var/lib/awx/projects/_69__network_data_collection/data-discovery/roles/ansible-network.network-engine/action_plugins/../lib/network_engine/plugins/parser/pattern_match.py", line 44, in _match_all
    match = self.re_matchall(pattern, content)
  File "/var/lib/awx/projects/_69__network_data_collection/data-discovery/roles/ansible-network.network-engine/action_plugins/../lib/network_engine/plugins/parser/pattern_match.py", line 153, in re_matchall
    regex = re.compile(regex)
  File "/usr/lib64/python2.7/re.py", line 190, in compile
    return _compile(pattern, flags)
  File "/usr/lib64/python2.7/re.py", line 242, in _compile
    raise error, v # invalid expression
error: unexpected end of pattern

fatal: [S022DC3N5212]: FAILED! => {
    "msg": "Unexpected failure during module execution.", 
    "stdout": ""
}
blandrew commented 5 years ago

@mattgmoser pattern_match uses the re regular expression module from the Python standard library, which doesn't appear to support branch reset groups.

If your real world use case is as simple as the example provided above, putting the OR logic within the same capture group may suffice:

>>> re.search("(doggies|Cisco Nexus Operating)", 'some text with doggies').group(1)
'doggies'
>>> re.search("(doggies|Cisco Nexus Operating)", 'Cisco Nexus Operating System').group(1)
'Cisco Nexus Operating'
mattgmoser commented 5 years ago

Thank you @blandrew , I was wondering if that was the case. I've been able to find a successful work-around, I appreciate your looking into this.

trishnaguha commented 5 years ago

Python re doesn't support branch reset which command_parser uses. 3rd party PyPi regex module supports a branch reset feature. Hence command_parser is failing. Please file a bug report if you face issue further. Thanks!