mirror of https://github.com/ansible/ansible.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
5.3 KiB
Python
157 lines
5.3 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 annotations
|
|
|
|
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
|