# -*- coding: utf-8 -*- # Copyright: (c) Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import (absolute_import, division, print_function) __metaclass__ = type import os import platform import re import ansible.module_utils.compat.typing as t from ansible.module_utils.common.sys_info import get_distribution, get_distribution_version, \ get_distribution_codename from ansible.module_utils.facts.utils import get_file_content, get_file_lines from ansible.module_utils.facts.collector import BaseFactCollector def get_uname(module, flags=('-v')): if isinstance(flags, str): flags = flags.split() command = ['uname'] command.extend(flags) rc, out, err = module.run_command(command) if rc == 0: return out return None def _file_exists(path, allow_empty=False): # not finding the file, exit early if not os.path.exists(path): return False # if just the path needs to exists (ie, it can be empty) we are done if allow_empty: return True # file exists but is empty and we dont allow_empty if os.path.getsize(path) == 0: return False # file exists with some content return True class DistributionFiles: '''has-a various distro file parsers (os-release, etc) and logic for finding the right one.''' # every distribution name mentioned here, must have one of # - allowempty == True # - be listed in SEARCH_STRING # - have a function get_distribution_DISTNAME implemented # keep names in sync with Conditionals page of docs OSDIST_LIST = ( {'path': '/etc/altlinux-release', 'name': 'Altlinux'}, {'path': '/etc/oracle-release', 'name': 'OracleLinux'}, {'path': '/etc/slackware-version', 'name': 'Slackware'}, {'path': '/etc/centos-release', 'name': 'CentOS'}, {'path': '/etc/redhat-release', 'name': 'RedHat'}, {'path': '/etc/vmware-release', 'name': 'VMwareESX', 'allowempty': True}, {'path': '/etc/openwrt_release', 'name': 'OpenWrt'}, {'path': '/etc/os-release', 'name': 'Amazon'}, {'path': '/etc/system-release', 'name': 'Amazon'}, {'path': '/etc/alpine-release', 'name': 'Alpine'}, {'path': '/etc/arch-release', 'name': 'Archlinux', 'allowempty': True}, {'path': '/etc/os-release', 'name': 'Archlinux'}, {'path': '/etc/os-release', 'name': 'SUSE'}, {'path': '/etc/SuSE-release', 'name': 'SUSE'}, {'path': '/etc/gentoo-release', 'name': 'Gentoo'}, {'path': '/etc/os-release', 'name': 'Debian'}, {'path': '/etc/lsb-release', 'name': 'Debian'}, {'path': '/etc/lsb-release', 'name': 'Mandriva'}, {'path': '/etc/sourcemage-release', 'name': 'SMGL'}, {'path': '/usr/lib/os-release', 'name': 'ClearLinux'}, {'path': '/etc/coreos/update.conf', 'name': 'Coreos'}, {'path': '/etc/os-release', 'name': 'Flatcar'}, {'path': '/etc/os-release', 'name': 'NA'}, ) SEARCH_STRING = { 'OracleLinux': 'Oracle Linux', 'RedHat': 'Red Hat', 'Altlinux': 'ALT', 'SMGL': 'Source Mage GNU/Linux', } # We can't include this in SEARCH_STRING because a name match on its keys # causes a fallback to using the first whitespace separated item from the file content # as the name. For os-release, that is in form 'NAME=Arch' OS_RELEASE_ALIAS = { 'Archlinux': 'Arch Linux' } STRIP_QUOTES = r'\'\"\\' def __init__(self, module): self.module = module def _get_file_content(self, path): return get_file_content(path) def _get_dist_file_content(self, path, allow_empty=False): # cant find that dist file or it is incorrectly empty if not _file_exists(path, allow_empty=allow_empty): return False, None data = self._get_file_content(path) return True, data def _parse_dist_file(self, name, dist_file_content, path, collected_facts): dist_file_dict = {} dist_file_content = dist_file_content.strip(DistributionFiles.STRIP_QUOTES) if name in self.SEARCH_STRING: # look for the distribution string in the data and replace according to RELEASE_NAME_MAP # only the distribution name is set, the version is assumed to be correct from distro.linux_distribution() if self.SEARCH_STRING[name] in dist_file_content: # this sets distribution=RedHat if 'Red Hat' shows up in data dist_file_dict['distribution'] = name dist_file_dict['distribution_file_search_string'] = self.SEARCH_STRING[name] else: # this sets distribution to what's in the data, e.g. CentOS, Scientific, ... dist_file_dict['distribution'] = dist_file_content.split()[0] return True, dist_file_dict if name in self.OS_RELEASE_ALIAS: if self.OS_RELEASE_ALIAS[name] in dist_file_content: dist_file_dict['distribution'] = name return True, dist_file_dict return False, dist_file_dict # call a dedicated function for parsing the file content # TODO: replace with a map or a class try: # FIXME: most of these dont actually look at the dist file contents, but random other stuff distfunc_name = 'parse_distribution_file_' + name distfunc = getattr(self, distfunc_name) parsed, dist_file_dict = distfunc(name, dist_file_content, path, collected_facts) return parsed, dist_file_dict except AttributeError as exc: self.module.debug('exc: %s' % exc) # this should never happen, but if it does fail quietly and not with a traceback return False, dist_file_dict return True, dist_file_dict # to debug multiple matching release files, one can use: # self.facts['distribution_debug'].append({path + ' ' + name: # (parsed, # self.facts['distribution'], # self.facts['distribution_version'], # self.facts['distribution_release'], # )}) def _guess_distribution(self): # try to find out which linux distribution this is dist = (get_distribution(), get_distribution_version(), get_distribution_codename()) distribution_guess = { 'distribution': dist[0] or 'NA', 'distribution_version': dist[1] or 'NA', # distribution_release can be the empty string 'distribution_release': 'NA' if dist[2] is None else dist[2] } distribution_guess['distribution_major_version'] = distribution_guess['distribution_version'].split('.')[0] or 'NA' return distribution_guess def process_dist_files(self): # Try to handle the exceptions now ... # self.facts['distribution_debug'] = [] dist_file_facts = {} dist_guess = self._guess_distribution() dist_file_facts.update(dist_guess) for ddict in self.OSDIST_LIST: name = ddict['name'] path = ddict['path'] allow_empty = ddict.get('allowempty', False) has_dist_file, dist_file_content = self._get_dist_file_content(path, allow_empty=allow_empty) # but we allow_empty. For example, ArchLinux with an empty /etc/arch-release and a # /etc/os-release with a different name if has_dist_file and allow_empty: dist_file_facts['distribution'] = name dist_file_facts['distribution_file_path'] = path dist_file_facts['distribution_file_variety'] = name break if not has_dist_file: # keep looking continue parsed_dist_file, parsed_dist_file_facts = self._parse_dist_file(name, dist_file_content, path, dist_file_facts) # finally found the right os dist file and were able to parse it if parsed_dist_file: dist_file_facts['distribution'] = name dist_file_facts['distribution_file_path'] = path # distribution and file_variety are the same here, but distribution # will be changed/mapped to a more specific name. # ie, dist=Fedora, file_variety=RedHat dist_file_facts['distribution_file_variety'] = name dist_file_facts['distribution_file_parsed'] = parsed_dist_file dist_file_facts.update(parsed_dist_file_facts) break return dist_file_facts # TODO: FIXME: split distro file parsing into its own module or class def parse_distribution_file_Slackware(self, name, data, path, collected_facts): slackware_facts = {} if 'Slackware' not in data: return False, slackware_facts # TODO: remove slackware_facts['distribution'] = name version = re.findall(r'\w+[.]\w+\+?', data) if version: slackware_facts['distribution_version'] = version[0] return True, slackware_facts def parse_distribution_file_Amazon(self, name, data, path, collected_facts): amazon_facts = {} if 'Amazon' not in data: return False, amazon_facts amazon_facts['distribution'] = 'Amazon' if path == '/etc/os-release': version = re.search(r"VERSION_ID=\"(.*)\"", data) if version: distribution_version = version.group(1) amazon_facts['distribution_version'] = distribution_version version_data = distribution_version.split(".") if len(version_data) > 1: major, minor = version_data else: major, minor = version_data[0], 'NA' amazon_facts['distribution_major_version'] = major amazon_facts['distribution_minor_version'] = minor else: version = [n for n in data.split() if n.isdigit()] version = version[0] if version else 'NA' amazon_facts['distribution_version'] = version return True, amazon_facts def parse_distribution_file_OpenWrt(self, name, data, path, collected_facts): openwrt_facts = {} if 'OpenWrt' not in data: return False, openwrt_facts # TODO: remove openwrt_facts['distribution'] = name version = re.search('DISTRIB_RELEASE="(.*)"', data) if version: openwrt_facts['distribution_version'] = version.groups()[0] release = re.search('DISTRIB_CODENAME="(.*)"', data) if release: openwrt_facts['distribution_release'] = release.groups()[0] return True, openwrt_facts def parse_distribution_file_Alpine(self, name, data, path, collected_facts): alpine_facts = {} alpine_facts['distribution'] = 'Alpine' alpine_facts['distribution_version'] = data return True, alpine_facts def parse_distribution_file_SUSE(self, name, data, path, collected_facts): suse_facts = {} if 'suse' not in data.lower(): return False, suse_facts # TODO: remove if tested without this if path == '/etc/os-release': for line in data.splitlines(): distribution = re.search("^NAME=(.*)", line) if distribution: suse_facts['distribution'] = distribution.group(1).strip('"') # example pattern are 13.04 13.0 13 distribution_version = re.search(r'^VERSION_ID="?([0-9]+\.?[0-9]*)"?', line) if distribution_version: suse_facts['distribution_version'] = distribution_version.group(1) suse_facts['distribution_major_version'] = distribution_version.group(1).split('.')[0] if 'open' in data.lower(): release = re.search(r'^VERSION_ID="?[0-9]+\.?([0-9]*)"?', line) if release: suse_facts['distribution_release'] = release.groups()[0] elif 'enterprise' in data.lower() and 'VERSION_ID' in line: # SLES doesn't got funny release names release = re.search(r'^VERSION_ID="?[0-9]+\.?([0-9]*)"?', line) if release.group(1): release = release.group(1) else: release = "0" # no minor number, so it is the first release suse_facts['distribution_release'] = release elif path == '/etc/SuSE-release': if 'open' in data.lower(): data = data.splitlines() distdata = get_file_content(path).splitlines()[0] suse_facts['distribution'] = distdata.split()[0] for line in data: release = re.search('CODENAME *= *([^\n]+)', line) if release: suse_facts['distribution_release'] = release.groups()[0].strip() elif 'enterprise' in data.lower(): lines = data.splitlines() distribution = lines[0].split()[0] if "Server" in data: suse_facts['distribution'] = "SLES" elif "Desktop" in data: suse_facts['distribution'] = "SLED" for line in lines: release = re.search('PATCHLEVEL = ([0-9]+)', line) # SLES doesn't got funny release names if release: suse_facts['distribution_release'] = release.group(1) suse_facts['distribution_version'] = collected_facts['distribution_version'] + '.' + release.group(1) # See https://www.suse.com/support/kb/doc/?id=000019341 for SLES for SAP if os.path.islink('/etc/products.d/baseproduct') and os.path.realpath('/etc/products.d/baseproduct').endswith('SLES_SAP.prod'): suse_facts['distribution'] = 'SLES_SAP' return True, suse_facts def parse_distribution_file_Debian(self, name, data, path, collected_facts): debian_facts = {} if 'Debian' in data or 'Raspbian' in data: debian_facts['distribution'] = 'Debian' release = re.search(r"PRETTY_NAME=[^(]+ \(?([^)]+?)\)", data) if release: debian_facts['distribution_release'] = release.groups()[0] # Last resort: try to find release from tzdata as either lsb is missing or this is very old debian if collected_facts['distribution_release'] == 'NA' and 'Debian' in data: dpkg_cmd = self.module.get_bin_path('dpkg') if dpkg_cmd: cmd = "%s --status tzdata|grep Provides|cut -f2 -d'-'" % dpkg_cmd rc, out, err = self.module.run_command(cmd) if rc == 0: debian_facts['distribution_release'] = out.strip() debian_version_path = '/etc/debian_version' distdata = get_file_lines(debian_version_path) for line in distdata: m = re.search(r'(\d+)\.(\d+)', line.strip()) if m: debian_facts['distribution_minor_version'] = m.groups()[1] elif 'Ubuntu' in data: debian_facts['distribution'] = 'Ubuntu' # nothing else to do, Ubuntu gets correct info from python functions elif 'SteamOS' in data: debian_facts['distribution'] = 'SteamOS' # nothing else to do, SteamOS gets correct info from python functions elif path in ('/etc/lsb-release', '/etc/os-release') and ('Kali' in data or 'Parrot' in data): if 'Kali' in data: # Kali does not provide /etc/lsb-release anymore debian_facts['distribution'] = 'Kali' elif 'Parrot' in data: debian_facts['distribution'] = 'Parrot' release = re.search('DISTRIB_RELEASE=(.*)', data) if release: debian_facts['distribution_release'] = release.groups()[0] elif 'Devuan' in data: debian_facts['distribution'] = 'Devuan' release = re.search(r"PRETTY_NAME=\"?[^(\"]+ \(?([^) \"]+)\)?", data) if release: debian_facts['distribution_release'] = release.groups()[0] version = re.search(r"VERSION_ID=\"(.*)\"", data) if version: debian_facts['distribution_version'] = version.group(1) debian_facts['distribution_major_version'] = version.group(1) elif 'Cumulus' in data: debian_facts['distribution'] = 'Cumulus Linux' version = re.search(r"VERSION_ID=(.*)", data) if version: major, _minor, _dummy_ver = version.group(1).split(".") debian_facts['distribution_version'] = version.group(1) debian_facts['distribution_major_version'] = major release = re.search(r'VERSION="(.*)"', data) if release: debian_facts['distribution_release'] = release.groups()[0] elif "Mint" in data: debian_facts['distribution'] = 'Linux Mint' version = re.search(r"VERSION_ID=\"(.*)\"", data) if version: debian_facts['distribution_version'] = version.group(1) debian_facts['distribution_major_version'] = version.group(1).split('.')[0] elif 'UOS' in data or 'Uos' in data or 'uos' in data: debian_facts['distribution'] = 'Uos' release = re.search(r"VERSION_CODENAME=\"?([^\"]+)\"?", data) if release: debian_facts['distribution_release'] = release.groups()[0] version = re.search(r"VERSION_ID=\"(.*)\"", data) if version: debian_facts['distribution_version'] = version.group(1) debian_facts['distribution_major_version'] = version.group(1).split('.')[0] elif 'Deepin' in data or 'deepin' in data: debian_facts['distribution'] = 'Deepin' release = re.search(r"VERSION_CODENAME=\"?([^\"]+)\"?", data) if release: debian_facts['distribution_release'] = release.groups()[0] version = re.search(r"VERSION_ID=\"(.*)\"", data) if version: debian_facts['distribution_version'] = version.group(1) debian_facts['distribution_major_version'] = version.group(1).split('.')[0] else: return False, debian_facts return True, debian_facts def parse_distribution_file_Mandriva(self, name, data, path, collected_facts): mandriva_facts = {} if 'Mandriva' in data: mandriva_facts['distribution'] = 'Mandriva' version = re.search('DISTRIB_RELEASE="(.*)"', data) if version: mandriva_facts['distribution_version'] = version.groups()[0] release = re.search('DISTRIB_CODENAME="(.*)"', data) if release: mandriva_facts['distribution_release'] = release.groups()[0] mandriva_facts['distribution'] = name else: return False, mandriva_facts return True, mandriva_facts def parse_distribution_file_NA(self, name, data, path, collected_facts): na_facts = {} for line in data.splitlines(): distribution = re.search("^NAME=(.*)", line) if distribution and name == 'NA': na_facts['distribution'] = distribution.group(1).strip('"') version = re.search("^VERSION=(.*)", line) if version and collected_facts['distribution_version'] == 'NA': na_facts['distribution_version'] = version.group(1).strip('"') return True, na_facts def parse_distribution_file_Coreos(self, name, data, path, collected_facts): coreos_facts = {} # FIXME: pass in ro copy of facts for this kind of thing distro = get_distribution() if distro.lower() == 'coreos': if not data: # include fix from #15230, #15228 # TODO: verify this is ok for above bugs return False, coreos_facts release = re.search("^GROUP=(.*)", data) if release: coreos_facts['distribution_release'] = release.group(1).strip('"') else: return False, coreos_facts # TODO: remove if tested without this return True, coreos_facts def parse_distribution_file_Flatcar(self, name, data, path, collected_facts): flatcar_facts = {} distro = get_distribution() if distro.lower() != 'flatcar': return False, flatcar_facts if not data: return False, flatcar_facts version = re.search("VERSION=(.*)", data) if version: flatcar_facts['distribution_major_version'] = version.group(1).strip('"').split('.')[0] flatcar_facts['distribution_version'] = version.group(1).strip('"') return True, flatcar_facts def parse_distribution_file_ClearLinux(self, name, data, path, collected_facts): clear_facts = {} if "clearlinux" not in name.lower(): return False, clear_facts pname = re.search('NAME="(.*)"', data) if pname: if 'Clear Linux' not in pname.groups()[0]: return False, clear_facts clear_facts['distribution'] = pname.groups()[0] version = re.search('VERSION_ID=(.*)', data) if version: clear_facts['distribution_major_version'] = version.groups()[0] clear_facts['distribution_version'] = version.groups()[0] release = re.search('ID=(.*)', data) if release: clear_facts['distribution_release'] = release.groups()[0] return True, clear_facts def parse_distribution_file_CentOS(self, name, data, path, collected_facts): centos_facts = {} if 'CentOS Stream' in data: centos_facts['distribution_release'] = 'Stream' return True, centos_facts if "TencentOS Server" in data: centos_facts['distribution'] = 'TencentOS' return True, centos_facts return False, centos_facts class Distribution(object): """ This subclass of Facts fills the distribution, distribution_version and distribution_release variables To do so it checks the existence and content of typical files in /etc containing distribution information This is unit tested. Please extend the tests to cover all distributions if you have them available. """ # keep keys in sync with Conditionals page of docs OS_FAMILY_MAP = {'RedHat': ['RedHat', 'RHEL', 'Fedora', 'CentOS', 'Scientific', 'SLC', 'Ascendos', 'CloudLinux', 'PSBM', 'OracleLinux', 'OVS', 'OEL', 'Amazon', 'Virtuozzo', 'XenServer', 'Alibaba', 'EulerOS', 'openEuler', 'AlmaLinux', 'Rocky', 'TencentOS', 'EuroLinux', 'Kylin Linux Advanced Server'], 'Debian': ['Debian', 'Ubuntu', 'Raspbian', 'Neon', 'KDE neon', 'Linux Mint', 'SteamOS', 'Devuan', 'Kali', 'Cumulus Linux', 'Pop!_OS', 'Parrot', 'Pardus GNU/Linux', 'Uos', 'Deepin', 'OSMC'], 'Suse': ['SuSE', 'SLES', 'SLED', 'openSUSE', 'openSUSE Tumbleweed', 'SLES_SAP', 'SUSE_LINUX', 'openSUSE Leap'], 'Archlinux': ['Archlinux', 'Antergos', 'Manjaro'], 'Mandrake': ['Mandrake', 'Mandriva'], 'Solaris': ['Solaris', 'Nexenta', 'OmniOS', 'OpenIndiana', 'SmartOS'], 'Slackware': ['Slackware'], 'Altlinux': ['Altlinux'], 'SGML': ['SGML'], 'Gentoo': ['Gentoo', 'Funtoo'], 'Alpine': ['Alpine'], 'AIX': ['AIX'], 'HP-UX': ['HPUX'], 'Darwin': ['MacOSX'], 'FreeBSD': ['FreeBSD', 'TrueOS'], 'ClearLinux': ['Clear Linux OS', 'Clear Linux Mix'], 'DragonFly': ['DragonflyBSD', 'DragonFlyBSD', 'Gentoo/DragonflyBSD', 'Gentoo/DragonFlyBSD'], 'NetBSD': ['NetBSD'], } OS_FAMILY = {} for family, names in OS_FAMILY_MAP.items(): for name in names: OS_FAMILY[name] = family def __init__(self, module): self.module = module def get_distribution_facts(self): distribution_facts = {} # The platform module provides information about the running # system/distribution. Use this as a baseline and fix buggy systems # afterwards system = platform.system() distribution_facts['distribution'] = system distribution_facts['distribution_release'] = platform.release() distribution_facts['distribution_version'] = platform.version() systems_implemented = ('AIX', 'HP-UX', 'Darwin', 'FreeBSD', 'OpenBSD', 'SunOS', 'DragonFly', 'NetBSD') if system in systems_implemented: cleanedname = system.replace('-', '') distfunc = getattr(self, 'get_distribution_' + cleanedname) dist_func_facts = distfunc() distribution_facts.update(dist_func_facts) elif system == 'Linux': distribution_files = DistributionFiles(module=self.module) # linux_distribution_facts = LinuxDistribution(module).get_distribution_facts() dist_file_facts = distribution_files.process_dist_files() distribution_facts.update(dist_file_facts) distro = distribution_facts['distribution'] # look for a os family alias for the 'distribution', if there isnt one, use 'distribution' distribution_facts['os_family'] = self.OS_FAMILY.get(distro, None) or distro return distribution_facts def get_distribution_AIX(self): aix_facts = {} rc, out, err = self.module.run_command("/usr/bin/oslevel") data = out.split('.') aix_facts['distribution_major_version'] = data[0] if len(data) > 1: aix_facts['distribution_version'] = '%s.%s' % (data[0], data[1]) aix_facts['distribution_release'] = data[1] else: aix_facts['distribution_version'] = data[0] return aix_facts def get_distribution_HPUX(self): hpux_facts = {} rc, out, err = self.module.run_command(r"/usr/sbin/swlist |egrep 'HPUX.*OE.*[AB].[0-9]+\.[0-9]+'", use_unsafe_shell=True) data = re.search(r'HPUX.*OE.*([AB].[0-9]+\.[0-9]+)\.([0-9]+).*', out) if data: hpux_facts['distribution_version'] = data.groups()[0] hpux_facts['distribution_release'] = data.groups()[1] return hpux_facts def get_distribution_Darwin(self): darwin_facts = {} darwin_facts['distribution'] = 'MacOSX' rc, out, err = self.module.run_command("/usr/bin/sw_vers -productVersion") data = out.split()[-1] if data: darwin_facts['distribution_major_version'] = data.split('.')[0] darwin_facts['distribution_version'] = data return darwin_facts def get_distribution_FreeBSD(self): freebsd_facts = {} freebsd_facts['distribution_release'] = platform.release() data = re.search(r'(\d+)\.(\d+)-(RELEASE|STABLE|CURRENT|RC|PRERELEASE).*', freebsd_facts['distribution_release']) if 'trueos' in platform.version(): freebsd_facts['distribution'] = 'TrueOS' if data: freebsd_facts['distribution_major_version'] = data.group(1) freebsd_facts['distribution_version'] = '%s.%s' % (data.group(1), data.group(2)) return freebsd_facts def get_distribution_OpenBSD(self): openbsd_facts = {} openbsd_facts['distribution_version'] = platform.release() rc, out, err = self.module.run_command("/sbin/sysctl -n kern.version") match = re.match(r'OpenBSD\s[0-9]+.[0-9]+-(\S+)\s.*', out) if match: openbsd_facts['distribution_release'] = match.groups()[0] else: openbsd_facts['distribution_release'] = 'release' return openbsd_facts def get_distribution_DragonFly(self): dragonfly_facts = { 'distribution_release': platform.release() } rc, out, dummy = self.module.run_command("/sbin/sysctl -n kern.version") match = re.search(r'v(\d+)\.(\d+)\.(\d+)-(RELEASE|STABLE|CURRENT).*', out) if match: dragonfly_facts['distribution_major_version'] = match.group(1) dragonfly_facts['distribution_version'] = '%s.%s.%s' % match.groups()[:3] return dragonfly_facts def get_distribution_NetBSD(self): netbsd_facts = {} platform_release = platform.release() netbsd_facts['distribution_release'] = platform_release rc, out, dummy = self.module.run_command("/sbin/sysctl -n kern.version") match = re.match(r'NetBSD\s(\d+)\.(\d+)\s\((GENERIC)\).*', out) if match: netbsd_facts['distribution_major_version'] = match.group(1) netbsd_facts['distribution_version'] = '%s.%s' % match.groups()[:2] else: netbsd_facts['distribution_major_version'] = platform_release.split('.')[0] netbsd_facts['distribution_version'] = platform_release return netbsd_facts def get_distribution_SMGL(self): smgl_facts = {} smgl_facts['distribution'] = 'Source Mage GNU/Linux' return smgl_facts def get_distribution_SunOS(self): sunos_facts = {} data = get_file_content('/etc/release').splitlines()[0] if 'Solaris' in data: # for solaris 10 uname_r will contain 5.10, for solaris 11 it will have 5.11 uname_r = get_uname(self.module, flags=['-r']) ora_prefix = '' if 'Oracle Solaris' in data: data = data.replace('Oracle ', '') ora_prefix = 'Oracle ' sunos_facts['distribution'] = data.split()[0] sunos_facts['distribution_version'] = data.split()[1] sunos_facts['distribution_release'] = ora_prefix + data sunos_facts['distribution_major_version'] = uname_r.split('.')[1].rstrip() return sunos_facts uname_v = get_uname(self.module, flags=['-v']) distribution_version = None if 'SmartOS' in data: sunos_facts['distribution'] = 'SmartOS' if _file_exists('/etc/product'): product_data = dict([l.split(': ', 1) for l in get_file_content('/etc/product').splitlines() if ': ' in l]) if 'Image' in product_data: distribution_version = product_data.get('Image').split()[-1] elif 'OpenIndiana' in data: sunos_facts['distribution'] = 'OpenIndiana' elif 'OmniOS' in data: sunos_facts['distribution'] = 'OmniOS' distribution_version = data.split()[-1] elif uname_v is not None and 'NexentaOS_' in uname_v: sunos_facts['distribution'] = 'Nexenta' distribution_version = data.split()[-1].lstrip('v') if sunos_facts.get('distribution', '') in ('SmartOS', 'OpenIndiana', 'OmniOS', 'Nexenta'): sunos_facts['distribution_release'] = data.strip() if distribution_version is not None: sunos_facts['distribution_version'] = distribution_version elif uname_v is not None: sunos_facts['distribution_version'] = uname_v.splitlines()[0].strip() return sunos_facts return sunos_facts class DistributionFactCollector(BaseFactCollector): name = 'distribution' _fact_ids = set(['distribution_version', 'distribution_release', 'distribution_major_version', 'os_family']) # type: t.Set[str] def collect(self, module=None, collected_facts=None): collected_facts = collected_facts or {} facts_dict = {} if not module: return facts_dict distribution = Distribution(module=module) distro_facts = distribution.get_distribution_facts() return distro_facts