Repository: ansible/ansible

Issue:
Ansible fact gathering confused by IPv6 point-to-point link
##### ISSUE TYPE
- Bug Report
##### ANSIBLE VERSION

```
ansible 2.0.1.0
  config file = /home/dave/hack/ansible/ansible.cfg
  configured module search path = Default w/o overrides
```
##### CONFIGURATION

```
[defaults]
inventory = hosts
nocows = 1
remote_user = root
vault_password_file = .vault-key
ansible_managed = This file is managed by ansible, changes will be overwritten.

[ssh_connection]
pipelining = True
```
##### OS / ENVIRONMENT

Running from Arch Linux.
Talking to Debian Jessie.
##### SUMMARY

Ansible fails to gather facts on a machine with an IPv6 point-to-point address configured on one of its interfaces. It barfs in the fact-gathering stage, preventing anything from being run on the machine.

I have a VPN point-to-point interface with an IPv6 PtP link configured:

```
24: glanet: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
    link/ether 9e:f7:db:8d:8a:be brd ff:ff:ff:ff:ff:ff
    inet 192.168.144.67 peer 192.168.144.66/32 scope global glanet
       valid_lft forever preferred_lft forever
    inet6 2001:470:c8be:f1::2 peer 2001:470:c8be:f1::1/128 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::9cf7:dbff:fe8d:8abe/64 scope link 
       valid_lft forever preferred_lft forever
```

On this machine, Ansible fails to gather facts (and thus run anything) when the "2001:470:c8be:f1::2 peer 2001:470:c8be:f1::1/128" is present:

```
» ansible -vvv castor.home.universe.tf -m setup
Using /home/dave/hack/ansible/ansible.cfg as config file
<castor.home.universe.tf> ESTABLISH SSH CONNECTION FOR USER: root
<castor.home.universe.tf> SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=root -o ConnectTimeout=10 -o ControlPath=/home/dave/.ansible/cp/ansible-ssh-%h-%p-%r castor.home.universe.tf '/bin/sh -c '"'"'LANG=en_US.utf8 LC_ALL=en_US.utf8 LC_MESSAGES=en_US.utf8 /usr/bin/python'"'"''
An exception occurred during task execution. The full traceback is:
Traceback (most recent call last):
  File "<stdin>", line 5184, in <module>
  File "<stdin>", line 140, in main
  File "<stdin>", line 84, in run_setup
  File "<stdin>", line 5121, in ansible_facts
  File "<stdin>", line 4015, in populate
  File "<stdin>", line 4211, in get_interfaces_info
  File "<stdin>", line 4182, in parse_ip_output
ValueError: need more than 1 value to unpack

castor.home.universe.tf | FAILED! => {
    "changed": false, 
    "failed": true, 
    "invocation": {
        "module_name": "setup"
    }, 
    "parsed": false
}
```
##### STEPS TO REPRODUCE

On a target machine, configure an IPv6 point-to-point address on an interface, e.g. :

```
ip -6 addr add 2001:470:c8be:f1::2 peer 2001:470:c8be:f1::1/128 dev eth0
```

Then, try to run `ansible foo -m setup` against that host.
##### EXPECTED RESULTS

Ansible should not crash while gathering facts.
##### ACTUAL RESULTS

Ansible crashes while gathering facts.



Discussion:

Resolving patch:
diff --git a/lib/ansible/module_utils/facts.py b/lib/ansible/module_utils/facts.py
--- a/lib/ansible/module_utils/facts.py
+++ b/lib/ansible/module_utils/facts.py
@@ -2231,8 +2231,13 @@ def parse_ip_output(output, secondary=False):
                         if not address.startswith('127.'):
                             ips['all_ipv4_addresses'].append(address)
                     elif words[0] == 'inet6':
-                        address, prefix = words[1].split('/')
-                        scope = words[3]
+                        if 'peer' == words[2]:
+                            address = words[1]
+                            _, prefix = words[3].split('/')
+                            scope = words[5]
+                        else:
+                            address, prefix = words[1].split('/')
+                            scope = words[3]
                         if 'ipv6' not in interfaces[device]:
                             interfaces[device]['ipv6'] = []
                         interfaces[device]['ipv6'].append({


Test patch: