# Buggy code
def get_all_facts(module):
    setup_options = dict(module_setup=True)

    # Retrieve module parameters
    gather_subset = module.params["gather_subset"]

    # Retrieve all facts elements
    additional_subsets = set()
    exclude_subsets = set()
    for subset in gather_subset:
        if subset == "all":
            additional_subsets.update(VALID_SUBSETS)
            continue
        if subset.startswith("!"):
            subset = subset[1:]
            if subset == "all":
                exclude_subsets.update(VALID_SUBSETS)
                continue
            exclude = True
        else:
            exclude = False

        if subset not in VALID_SUBSETS:
            raise TypeError(
                "Bad subset '%s' given to Ansible. gather_subset options allowed: all, %s"
                % (subset, ", ".join(FACT_SUBSETS.keys()))
            )

        if exclude:
            exclude_subsets.add(subset)
        else:
            additional_subsets.add(subset)

    if not additional_subsets:
        additional_subsets.update(VALID_SUBSETS)

    additional_subsets.difference_update(exclude_subsets)

    # facter and ohai are given a different prefix than other subsets
    if "facter" in additional_subsets:
        additional_subsets.difference_update(("facter",))
        facter_ds = FACT_SUBSETS["facter"](module, load_on_init=False).populate()
        if facter_ds:
            for k, v in facter_ds.items():
                setup_options["facter_%s" % k.replace("-", "_")] = v

    if "ohai" in additional_subsets:
        additional_subsets.difference_update(("ohai",))
        ohai_ds = FACT_SUBSETS["ohai"](module, load_on_init=False).populate()
        if ohai_ds:
            for k, v in ohai_ds.items():
                setup_options["ohai_%s" % k.replace("-", "_")] = v

    facts = ansible_facts(module, additional_subsets)

    for k, v in facts.items():
        setup_options["ansible_%s" % k.replace("-", "_")] = v

    setup_result = {"ansible_facts": {}}

    for k, v in setup_options.items():
        if module.params["filter"] == "*" or fnmatch.fnmatch(
            k, module.params["filter"]
        ):
            setup_result["ansible_facts"][k] = v

    # hack to keep --verbose from showing all the setup module results
    setup_result["_ansible_verbose_override"] = True

    return setup_result


# Traceback (TimeoutError)
failed: [SOME_HOST] => {"cmd": "/bin/lsblk -ln --output UUID /dev/sdi2", "failed": true, "rc": 257}
msg: Traceback (most recent call last):
File "<stdin>", line 1650, in run_command
File "/usr/lib64/python2.4/subprocess.py", line 550, in __init__
errread, errwrite)
File "/usr/lib64/python2.4/subprocess.py", line 988, in _execute_child
data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
File "<stdin>", line 1796, in _handle_timeout
TimeoutError: Timer expired

# Fixed code
def get_all_facts(module):
    setup_options = dict(module_setup=True)

    # Retrieve module parameters
    gather_subset = module.params["gather_subset"]

    global GATHER_TIMEOUT
    GATHER_TIMEOUT = module.params["gather_timeout"]

    # Retrieve all facts elements
    additional_subsets = set()
    exclude_subsets = set()
    for subset in gather_subset:
        if subset == "all":
            additional_subsets.update(VALID_SUBSETS)
            continue
        if subset.startswith("!"):
            subset = subset[1:]
            if subset == "all":
                exclude_subsets.update(VALID_SUBSETS)
                continue
            exclude = True
        else:
            exclude = False

        if subset not in VALID_SUBSETS:
            raise TypeError(
                "Bad subset '%s' given to Ansible. gather_subset options allowed: all, %s"
                % (subset, ", ".join(FACT_SUBSETS.keys()))
            )

        if exclude:
            exclude_subsets.add(subset)
        else:
            additional_subsets.add(subset)

    if not additional_subsets:
        additional_subsets.update(VALID_SUBSETS)

    additional_subsets.difference_update(exclude_subsets)

    # facter and ohai are given a different prefix than other subsets
    if "facter" in additional_subsets:
        additional_subsets.difference_update(("facter",))
        facter_ds = FACT_SUBSETS["facter"](module, load_on_init=False).populate()
        if facter_ds:
            for k, v in facter_ds.items():
                setup_options["facter_%s" % k.replace("-", "_")] = v

    if "ohai" in additional_subsets:
        additional_subsets.difference_update(("ohai",))
        ohai_ds = FACT_SUBSETS["ohai"](module, load_on_init=False).populate()
        if ohai_ds:
            for k, v in ohai_ds.items():
                setup_options["ohai_%s" % k.replace("-", "_")] = v

    facts = ansible_facts(module, additional_subsets)

    for k, v in facts.items():
        setup_options["ansible_%s" % k.replace("-", "_")] = v

    setup_result = {"ansible_facts": {}}

    for k, v in setup_options.items():
        if module.params["filter"] == "*" or fnmatch.fnmatch(
            k, module.params["filter"]
        ):
            setup_result["ansible_facts"][k] = v

    # hack to keep --verbose from showing all the setup module results
    setup_result["_ansible_verbose_override"] = True

    return setup_result