# Buggy code
def read_interfaces_lines(module, line_strings):
    lines = []
    ifaces = {}
    currently_processing = None
    i = 0
    for line in line_strings:
        i += 1
        words = line.split()
        if len(words) < 1:
            lines.append(lineDict(line))
            continue
        if words[0][0] == "#":
            lines.append(lineDict(line))
            continue
        if words[0] == "mapping":
            # currmap = calloc(1, sizeof *currmap);
            lines.append(lineDict(line))
            currently_processing = "MAPPING"
        elif words[0] == "source":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        elif words[0] == "source-dir":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        elif words[0] == "iface":
            currif = {"pre-up": [], "up": [], "down": [], "post-up": []}
            iface_name, address_family_name, method_name = words[1:4]
            if len(words) != 4:
                module.fail_json(
                    msg="Incorrect number of parameters (%d) in line %d, must be exectly 3"
                    % (len(words), i)
                )
                # TODO: put line and count parameters
                return None, None

            currif["address_family"] = address_family_name
            currif["method"] = method_name

            ifaces[iface_name] = currif
            lines.append(
                {
                    "line": line,
                    "iface": iface_name,
                    "line_type": "iface",
                    "params": currif,
                }
            )
            currently_processing = "IFACE"
        elif words[0] == "auto":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        elif words[0] == "allow-":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        elif words[0] == "no-auto-down":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        elif words[0] == "no-scripts":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        else:
            if currently_processing == "IFACE":
                option_name = words[0]
                # TODO: if option_name in currif.options
                value = getValueFromLine(line)
                lines.append(optionDict(line, iface_name, option_name, value))
                if option_name in ["pre-up", "up", "down", "post-up"]:
                    currif[option_name].append(value)
                else:
                    currif[option_name] = value
            elif currently_processing == "MAPPING":
                lines.append(lineDict(line))
            elif currently_processing == "NONE":
                lines.append(lineDict(line))
            else:
                module.fail_json(msg="misplaced option %s in line %d" % (line, i))
                return None, None
    return lines, ifaces


# Traceback (nValueError)
$ ansible-playbook interfaces_test.yml -i 172.20.116.11, -u admin -vv
ansible-playbook 2.4.0.0
config file = /Users/bwatson/Projects/[removed]/ansible.cfg
configured module search path = [u'/Users/bwatson/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /Users/bwatson/Projects/[removed]/venv/lib/python2.7/site-packages/ansible
executable location = /Users/bwatson/Projects/[removed]/venv/bin/ansible-playbook
python version = 2.7.12 (default, Jun 29 2016, 14:05:02) [GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)]
Using /Users/bwatson/Projects/[removed]/ansible.cfg as config file

PLAYBOOK: interfaces_test.yml ***************************************************************************************************
1 plays in interfaces_test.yml

PLAY [all] **********************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************
ok: [172.20.116.11]
META: ran handlers

TASK [interfaces_file] **********************************************************************************************************
task path: /Users/bwatson/Projects/[removed]/interfaces_test.yml:17
fatal: [172.20.116.11]: FAILED! => {"changed": false, "failed": true, "module_stderr": "Shared connection to 172.20.116.11 closed.\r\n", "module_stdout": "Traceback (most recent call last):\r\n  File \"/tmp/ansible_GxJ8k1/ansible_module_interfaces_file.py\", line 385, in <module>\r\n    main()\r\n  File \"/tmp/ansible_GxJ8k1/ansible_module_interfaces_file.py\", line 366, in main\r\n    lines, ifaces = read_interfaces_file(module, dest)\r\n  File \"/tmp/ansible_GxJ8k1/ansible_module_interfaces_file.py\", line 177, in read_interfaces_file\r\n    return read_interfaces_lines(module, f)\r\n  File \"/tmp/ansible_GxJ8k1/ansible_module_interfaces_file.py\", line 211, in read_interfaces_lines\r\n    iface_name, address_family_name, method_name = words[1:4]\r\nValueError: need more than 1 value to unpack\r\n", "msg": "MODULE FAILURE", "rc": 0}

PLAY RECAP **********************************************************************************************************************
172.20.116.11              : ok=1    changed=0    unreachable=0    failed=1

# Fixed code
def read_interfaces_lines(module, line_strings):
    lines = []
    ifaces = {}
    currently_processing = None
    i = 0
    for line in line_strings:
        i += 1
        words = line.split()
        if len(words) < 1:
            lines.append(lineDict(line))
            continue
        if words[0][0] == "#":
            lines.append(lineDict(line))
            continue
        if words[0] == "mapping":
            # currmap = calloc(1, sizeof *currmap);
            lines.append(lineDict(line))
            currently_processing = "MAPPING"
        elif words[0] == "source":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        elif words[0] == "source-dir":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        elif words[0] == "iface":
            currif = {"pre-up": [], "up": [], "down": [], "post-up": []}
            iface_name = words[1]
            try:
                currif["address_family"] = words[2]
            except IndexError:
                currif["address_family"] = None
            try:
                currif["method"] = words[3]
            except IndexError:
                currif["method"] = None

            ifaces[iface_name] = currif
            lines.append(
                {
                    "line": line,
                    "iface": iface_name,
                    "line_type": "iface",
                    "params": currif,
                }
            )
            currently_processing = "IFACE"
        elif words[0] == "auto":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        elif words[0] == "allow-":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        elif words[0] == "no-auto-down":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        elif words[0] == "no-scripts":
            lines.append(lineDict(line))
            currently_processing = "NONE"
        else:
            if currently_processing == "IFACE":
                option_name = words[0]
                # TODO: if option_name in currif.options
                value = getValueFromLine(line)
                lines.append(optionDict(line, iface_name, option_name, value))
                if option_name in ["pre-up", "up", "down", "post-up"]:
                    currif[option_name].append(value)
                else:
                    currif[option_name] = value
            elif currently_processing == "MAPPING":
                lines.append(lineDict(line))
            elif currently_processing == "NONE":
                lines.append(lineDict(line))
            else:
                module.fail_json(msg="misplaced option %s in line %d" % (line, i))
                return None, None
    return lines, ifaces