Repository: ansible/ansible

Issue:
Add get_distribution_Archlinux
##### ISSUE TYPE
- Bugfix Pull Request
##### ANSIBLE VERSION

```
ansible 2.2.0 (devel c42501cfe7) last updated 2016/05/03 11:02:47 (GMT +200)
  lib/ansible/modules/core: (detached HEAD e78ee3b128) last updated 2016/04/29 10:01:41 (GMT +200)
  lib/ansible/modules/extras: (detached HEAD ca310f3d15) last updated 2016/04/29 10:01:41 (GMT +200)
  config file = /home/jpic/.ansible.cfg
  configured module search path = ['/home/jpic/ansible/library', '/usr/share/ansible']
```
##### SUMMARY

Ansible would raise an exception on Archlinux hosts:

```
<!-- Paste verbatim command output here, e.g. before and after your change -->
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: AttributeError: 'Distribution' object has no attribute 'get_distribution_Archlinux'
fatal: [localhost]: FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "Traceback (most recent call last):\n  File \"/tmp/ansible_vJU6O6/ansible_module_setup.py\", line 127, in <module>\n    main()\n  File \"/tmp/ansible_vJU6O6/ansible_module_setup.py\", line 119, in main\n    data = get_all_facts(module)\n  File \"/home/jpic/env/src/ansible/lib/ansible/module_utils/facts.py\", line 3230, in get_all_facts\n    facts = ansible_facts(module, additional_subsets)\n  File \"/home/jpic/env/src/ansible/lib/ansible/module_utils/facts.py\", line 3174, in ansible_facts\n    facts.update(Facts(module).populate())\n  File \"/home/jpic/env/src/ansible/lib/ansible/module_utils/facts.py\", line 182, in __init__\n    self.facts.update(Distribution().populate())\n  File \"/home/jpic/env/src/ansible/lib/ansible/module_utils/facts.py\", line 652, in populate\n    self.get_distribution_facts()\n  File \"/home/jpic/env/src/ansible/lib/ansible/module_utils/facts.py\", line 710, in get_distribution_facts\n    distfunc = getattr(self, 'get_distribution_' + name)\nAttributeError: 'Distribution' object has no attribute 'get_distribution_Archlinux'\n", 
    "module_stdout": "", 
    "parsed": false
}

```

This patch fixes it.



Discussion:
This reflects deeper issue, if distro is missing function we should have fallback (not stopper for this PR, just note that this will happen with other distros).

Merged this commit.  Pinged @robinro on irc about the deeper issue.  I'll open a bug if robinro doesn't figure out a fix sooner.


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
@@ -604,6 +604,10 @@ class Distribution(object):
     This is unit tested. Please extend the tests to cover all distributions if you have them available.
     """
 
+    # every distribution name mentioned here, must have one of
+    #  - allowempty == True
+    #  - be listed in SEARCH_STRING
+    #  - have a function get_distribution_DISTNAME implemented
     OSDIST_LIST = (
         {'path': '/etc/oracle-release', 'name': 'OracleLinux'},
         {'path': '/etc/slackware-version', 'name': 'Slackware'},
@@ -687,12 +691,12 @@ def get_distribution_facts(self):
 
                 if not os.path.exists(path):
                     continue
+                # if allowempty is set, we only check for file existance but not content
+                if 'allowempty' in ddict and ddict['allowempty']:
+                    self.facts['distribution'] = name
+                    break
                 if os.path.getsize(path) == 0:
-                    if 'allowempty' in ddict and ddict['allowempty']:
-                        self.facts['distribution'] = name
-                        break
-                    else:
-                        continue
+                    continue
 
                 data = get_file_content(path)
                 if name in self.SEARCH_STRING:
@@ -707,13 +711,19 @@ def get_distribution_facts(self):
                     break
                 else:
                     # call a dedicated function for parsing the file content
-                    distfunc = getattr(self, 'get_distribution_' + name)
-                    parsed = distfunc(name, data, path)
-                    if parsed is None or parsed:
-                        # distfunc return False if parsing failed
-                        # break only if parsing was succesful
-                        # otherwise continue with other distributions
-                        break
+                    try:
+                        distfunc = getattr(self, 'get_distribution_' + name)
+                        parsed = distfunc(name, data, path)
+                        if parsed is None or parsed:
+                            # distfunc return False if parsing failed
+                            # break only if parsing was succesful
+                            # otherwise continue with other distributions
+                            break
+                    except AttributeError:
+                        # this should never happen, but if it does fail quitely and not with a traceback
+                        pass
+
+
 
                     # to debug multiple matching release files, one can use:
                     # self.facts['distribution_debug'].append({path + ' ' + name:
@@ -780,10 +790,6 @@ def get_distribution_OpenWrt(self, name, data, path):
         if release:
             self.facts['distribution_release'] = release.groups()[0]
 
-    def get_distribution_Archlinux(self, name, data, path):
-        self.facts['distribution'] = 'Archlinux'
-        self.facts['distribution_version'] = data
-
     def get_distribution_Alpine(self, name, data, path):
         self.facts['distribution'] = 'Alpine'
         self.facts['distribution_version'] = data


Test patch: