9a21e24778
Since moving to distro, it is possible to return this information for all platforms, not just Linux. Also return version information for all platfrom not just Linux. Update unit tests. Remove some duplicate unit tests though I think there are more to remove. * Fix docstring formatting * Minor docstring changes * Mock distro.id for Solaris service test * Update comment
158 lines
5.4 KiB
Python
158 lines
5.4 KiB
Python
# Copyright (c), Michael DeHaan <michael.dehaan@gmail.com>, 2012-2013
|
|
# Copyright (c), Toshio Kuratomi <tkuratomi@ansible.com> 2016
|
|
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
__metaclass__ = type
|
|
|
|
import platform
|
|
|
|
from ansible.module_utils import distro
|
|
from ansible.module_utils.common._utils import get_all_subclasses
|
|
|
|
|
|
__all__ = ('get_distribution', 'get_distribution_version', 'get_platform_subclass')
|
|
|
|
|
|
def get_distribution():
|
|
'''
|
|
Return the name of the distribution the module is running on.
|
|
|
|
:rtype: NativeString or None
|
|
:returns: Name of the distribution the module is running on
|
|
|
|
This function attempts to determine what distribution the code is running
|
|
on and return a string representing that value. If the platform is Linux
|
|
and the distribution cannot be determined, it returns ``OtherLinux``.
|
|
'''
|
|
distribution = distro.id().capitalize()
|
|
|
|
if platform.system() == 'Linux':
|
|
if distribution == 'Amzn':
|
|
distribution = 'Amazon'
|
|
elif distribution == 'Rhel':
|
|
distribution = 'Redhat'
|
|
elif not distribution:
|
|
distribution = 'OtherLinux'
|
|
|
|
return distribution
|
|
|
|
|
|
def get_distribution_version():
|
|
'''
|
|
Get the version of the distribution the code is running on
|
|
|
|
:rtype: NativeString or None
|
|
:returns: A string representation of the version of the distribution. If it
|
|
cannot determine the version, it returns an empty string. If this is not run on
|
|
a Linux machine it returns None.
|
|
'''
|
|
version = None
|
|
|
|
needs_best_version = frozenset((
|
|
u'centos',
|
|
u'debian',
|
|
))
|
|
|
|
version = distro.version()
|
|
distro_id = distro.id()
|
|
|
|
if version is not None:
|
|
if distro_id in needs_best_version:
|
|
version_best = distro.version(best=True)
|
|
|
|
# CentoOS maintainers believe only the major version is appropriate
|
|
# but Ansible users desire minor version information, e.g., 7.5.
|
|
# https://github.com/ansible/ansible/issues/50141#issuecomment-449452781
|
|
if distro_id == u'centos':
|
|
version = u'.'.join(version_best.split(u'.')[:2])
|
|
|
|
# Debian does not include minor version in /etc/os-release.
|
|
# Bug report filed upstream requesting this be added to /etc/os-release
|
|
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=931197
|
|
if distro_id == u'debian':
|
|
version = version_best
|
|
|
|
else:
|
|
version = u''
|
|
|
|
return version
|
|
|
|
|
|
def get_distribution_codename():
|
|
'''
|
|
Return the code name for this Linux Distribution
|
|
|
|
:rtype: NativeString or None
|
|
:returns: A string representation of the distribution's codename or None if not a Linux distro
|
|
'''
|
|
codename = None
|
|
if platform.system() == 'Linux':
|
|
# Until this gets merged and we update our bundled copy of distro:
|
|
# https://github.com/nir0s/distro/pull/230
|
|
# Fixes Fedora 28+ not having a code name and Ubuntu Xenial Xerus needing to be "xenial"
|
|
os_release_info = distro.os_release_info()
|
|
codename = os_release_info.get('version_codename')
|
|
|
|
if codename is None:
|
|
codename = os_release_info.get('ubuntu_codename')
|
|
|
|
if codename is None and distro.id() == 'ubuntu':
|
|
lsb_release_info = distro.lsb_release_info()
|
|
codename = lsb_release_info.get('codename')
|
|
|
|
if codename is None:
|
|
codename = distro.codename()
|
|
if codename == u'':
|
|
codename = None
|
|
|
|
return codename
|
|
|
|
|
|
def get_platform_subclass(cls):
|
|
'''
|
|
Finds a subclass implementing desired functionality on the platform the code is running on
|
|
|
|
:arg cls: Class to find an appropriate subclass for
|
|
:returns: A class that implements the functionality on this platform
|
|
|
|
Some Ansible modules have different implementations depending on the platform they run on. This
|
|
function is used to select between the various implementations and choose one. You can look at
|
|
the implementation of the Ansible :ref:`User module<user_module>` module for an example of how to use this.
|
|
|
|
This function replaces ``basic.load_platform_subclass()``. When you port code, you need to
|
|
change the callers to be explicit about instantiating the class. For instance, code in the
|
|
Ansible User module changed from::
|
|
|
|
.. code-block:: python
|
|
|
|
# Old
|
|
class User:
|
|
def __new__(cls, args, kwargs):
|
|
return load_platform_subclass(User, args, kwargs)
|
|
|
|
# New
|
|
class User:
|
|
def __new__(cls, *args, **kwargs):
|
|
new_cls = get_platform_subclass(User)
|
|
return super(cls, new_cls).__new__(new_cls)
|
|
'''
|
|
this_platform = platform.system()
|
|
distribution = get_distribution()
|
|
|
|
subclass = None
|
|
|
|
# get the most specific superclass for this platform
|
|
if distribution is not None:
|
|
for sc in get_all_subclasses(cls):
|
|
if sc.distribution is not None and sc.distribution == distribution and sc.platform == this_platform:
|
|
subclass = sc
|
|
if subclass is None:
|
|
for sc in get_all_subclasses(cls):
|
|
if sc.platform == this_platform and sc.distribution is None:
|
|
subclass = sc
|
|
if subclass is None:
|
|
subclass = cls
|
|
|
|
return subclass
|