Repository: ansible/ansible

Issue:
iosxr_facts module crashes if IP unicast RPF check is enabled
<!---
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
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
modules/network/iosxr_facts
##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.3.1.0 (stable-2.3 5f0be9dcd0) last updated 2017/05/10 14:12:19 (GMT +000)
  config file = /root/bachelor/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609]
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
Not relevant
##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->
N/A
##### SUMMARY
<!--- Explain the problem briefly -->
If a router has IP unicast RPF check set to enabled the populate_ipv6_interfaces method will fail.
##### 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.
-->
Enable IP unicast RPF check and run the playbook below
<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: Get iosXR facts
  hosts: snmp
  connection: local
  tasks:

    - name: gather facts
      iosxr_facts:
        provider: "{{ ansible_provider }}"
        gather_subset: "interfaces"
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
I expected getting facts back.
##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
Traceback (most recent call last):
  File "/tmp/ansible_a2JeMC/ansible_module_iosxr_facts.py", line 626, in <module>
    main()
  File "/tmp/ansible_a2JeMC/ansible_module_iosxr_facts.py", line 615, in main
    module.exit_json(out=module.from_json(results))
  File "/tmp/ansible_a2JeMC/ansible_modlib.zip/ansible/module_utils/basic.py", line 1933, in from_json
  File "/usr/lib/python2.7/json/__init__.py", line 339, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python2.7/json/decoder.py", line 364, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
TypeError: expected string or buffer

2017-05-10 13:46:05,128 p=21010 u=root |  fatal: [myrouter]: FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "Traceback (most recent call last):\n  File \"/tmp/ansible_a2JeMC/ansible_module_iosxr_facts.py\", line 626, in <module>\n    main()\n  File \"/tmp/ansible_a2JeMC/ansible_module_iosxr_facts.py\", line 615, in main\n    module.exit_json(out=module.from_json(results))\n  File \"/tmp/ansible_a2JeMC/ansible_modlib.zip/ansible/module_utils/basic.py\", line 1933, in from_json\n  File \"/usr/lib/python2.7/json/__init__.py\", line 339, in loads\n    return _default_decoder.decode(s)\n  File \"/usr/lib/python2.7/json/decoder.py\", line 364, in decode\n    obj, end = self.raw_decode(s, idx=_w(s, 0).end())\nTypeError: expected string or buffer\n", 
```

It works if you change the populate_ipv6_interfaces method to look like this:
```python
    def populate_ipv6_interfaces(self, data):
        for key, value in iteritems(data):
            if not (key == 'IP' or key == 'RPF'):
                self.facts['interfaces'][key]['ipv6'] = list()
                addresses = re.findall(r'\s+(.+), subnet', value, re.M)
                subnets = re.findall(r', subnet is (.+)$', value, re.M)
                for addr, subnet in zip(addresses, subnets):
                    ipv6 = dict(address=addr.strip(), subnet=subnet.strip())
                    self.add_ip_address(addr.strip(), 'ipv6')
                    self.facts['interfaces'][key]['ipv6'].append(ipv6)
```




Discussion:
cc @privateip @rcarrillocruz
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@Akvarium Thanks for the bug report & proposed fix, as well as testing `2.3.1`

We will test this locally and and report back


Resolving patch:
diff --git a/lib/ansible/modules/network/iosxr/iosxr_facts.py b/lib/ansible/modules/network/iosxr/iosxr_facts.py
--- a/lib/ansible/modules/network/iosxr/iosxr_facts.py
+++ b/lib/ansible/modules/network/iosxr/iosxr_facts.py
@@ -239,6 +239,8 @@ def populate_interfaces(self, interfaces):
 
     def populate_ipv6_interfaces(self, data):
         for key, value in iteritems(data):
+            if key in ['No', 'RPF'] or key.startswith('IP'):
+                continue
             self.facts['interfaces'][key]['ipv6'] = list()
             addresses = re.findall(r'\s+(.+), subnet', value, re.M)
             subnets = re.findall(r', subnet is (.+)$', value, re.M)


Test patch: