Move module dependency functions outside of module (#342)

Move module dependency functions outside of module

SUMMARY

This moves the has_at_least and requires functions that had been on the
module to top level functions. The functions on the module now call
these with a few added bits of functionality.
Moving these functions to the top level and removing their requirement
on having a module makes them usable in situations where we may not yet
have a module, such as during client creation.

ISSUE TYPE

COMPONENT NAME

ADDITIONAL INFORMATION

Reviewed-by: Alina Buzachis <None>
Reviewed-by: None <None>
This commit is contained in:
Mike Graves
2022-01-24 10:42:40 -05:00
parent 8171c994df
commit 08a3d951d0
3 changed files with 83 additions and 72 deletions

View File

@@ -3,7 +3,6 @@
import os import os
import hashlib import hashlib
from distutils.version import LooseVersion
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
from ansible.module_utils.six import iteritems, string_types from ansible.module_utils.six import iteritems, string_types
@@ -13,6 +12,7 @@ from ansible_collections.kubernetes.core.plugins.module_utils.args_common import
AUTH_ARG_SPEC, AUTH_ARG_SPEC,
AUTH_PROXY_HEADERS_SPEC, AUTH_PROXY_HEADERS_SPEC,
) )
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.core import requires
try: try:
from ansible_collections.kubernetes.core.plugins.module_utils import ( from ansible_collections.kubernetes.core.plugins.module_utils import (
@@ -40,20 +40,9 @@ except ImportError:
pass pass
module = None
_pool = {} _pool = {}
def _requires_kubernetes_at_least(version: str):
if module:
module.requires("kubernetes", version)
else:
if LooseVersion(kubernetes.__version__) < LooseVersion(version):
raise Exception(
f"kubernetes >= {version} is required to use in-memory kubeconfig."
)
def _create_auth_spec(module=None, **kwargs) -> Dict: def _create_auth_spec(module=None, **kwargs) -> Dict:
auth: Dict = {} auth: Dict = {}
# If authorization variables aren't defined, look for them in environment variables # If authorization variables aren't defined, look for them in environment variables
@@ -97,7 +86,6 @@ def _load_config(auth: Dict) -> None:
if isinstance(kubeconfig, string_types): if isinstance(kubeconfig, string_types):
kubernetes.config.load_kube_config(config_file=kubeconfig, **optional_arg) kubernetes.config.load_kube_config(config_file=kubeconfig, **optional_arg)
elif isinstance(kubeconfig, dict): elif isinstance(kubeconfig, dict):
_requires_kubernetes_at_least("17.17.0")
kubernetes.config.load_kube_config_from_dict( kubernetes.config.load_kube_config_from_dict(
config_dict=kubeconfig, **optional_arg config_dict=kubeconfig, **optional_arg
) )
@@ -241,6 +229,11 @@ class K8SClient:
def get_api_client(module=None, **kwargs: Optional[Any]) -> K8SClient: def get_api_client(module=None, **kwargs: Optional[Any]) -> K8SClient:
auth_spec = _create_auth_spec(module, **kwargs) auth_spec = _create_auth_spec(module, **kwargs)
if isinstance(auth_spec.get("kubeconfig"), dict):
if module:
module.requires("kubernetes", "17.17.0", "to use in-memory config")
else:
requires("kubernetes", "17.17.0", "to use in-memory config")
configuration = _create_configuration(auth_spec) configuration = _create_configuration(auth_spec)
client = create_api_client(configuration) client = create_api_client(configuration)

View File

@@ -3,6 +3,7 @@ from typing import Optional
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_text
class AnsibleK8SModule: class AnsibleK8SModule:
@@ -68,7 +69,31 @@ class AnsibleK8SModule:
def fail_json(self, *args, **kwargs): def fail_json(self, *args, **kwargs):
return self._module.fail_json(*args, **kwargs) return self._module.fail_json(*args, **kwargs)
def _gather_versions(self) -> dict: def has_at_least(
self, dependency: str, minimum: Optional[str] = None, warn: bool = False
) -> bool:
supported = has_at_least(dependency, minimum)
if not supported and warn:
self.warn(
"{0}<{1} is not supported or tested. Some features may not work.".format(
dependency, minimum
)
)
return supported
def requires(
self,
dependency: str,
minimum: Optional[str] = None,
reason: Optional[str] = None,
) -> None:
try:
requires(dependency, minimum, reason=reason)
except Exception as e:
self.fail_json(msg=to_text(e))
def gather_versions() -> dict:
versions = {} versions = {}
try: try:
import jsonpatch import jsonpatch
@@ -93,42 +118,35 @@ class AnsibleK8SModule:
return versions return versions
def has_at_least(
self, dependency: str, minimum: Optional[str] = None, warn: bool = False def has_at_least(dependency: str, minimum: Optional[str] = None) -> bool:
) -> bool:
"""Check if a specific dependency is present at a minimum version. """Check if a specific dependency is present at a minimum version.
If a minimum version is not specified it will check only that the If a minimum version is not specified it will check only that the
dependency is present. Additionally, if ``warn`` is ``True``, a warning dependency is present.
will be emitted if the actual version is less than the specified
minimum version.
""" """
dependencies = self._gather_versions() dependencies = gather_versions()
current = dependencies.get(dependency) current = dependencies.get(dependency)
if current is not None: if current is not None:
if minimum is None: if minimum is None:
return True return True
supported = LooseVersion(current) >= LooseVersion(minimum) supported = LooseVersion(current) >= LooseVersion(minimum)
if not supported and warn:
self.warn(
"{0}<{1} is not supported or tested. Some features may not work.".format(
dependency, minimum
)
)
return supported return supported
return False return False
def requires(self, dependency: str, minimum: Optional[str] = None) -> None:
def requires(
dependency: str, minimum: Optional[str] = None, reason: Optional[str] = None
) -> None:
"""Fail if a specific dependency is not present at a minimum version. """Fail if a specific dependency is not present at a minimum version.
If a minimum version is not specified it will require only that the If a minimum version is not specified it will require only that the
dependency is present. This function calls ``fail_json()`` when the dependency is present. This function raises an exception when the
dependency is not found at the required version and will stop module dependency is not found at the required version.
execution.
""" """
if not self.has_at_least(dependency, minimum): if not has_at_least(dependency, minimum):
if minimum is not None: if minimum is not None:
lib = "{0}>={1}".format(dependency, minimum) lib = "{0}>={1}".format(dependency, minimum)
else: else:
lib = dependency lib = dependency
self._module.fail_json(msg=missing_required_lib(lib)) raise Exception(missing_required_lib(lib, reason=reason))

View File

@@ -201,7 +201,7 @@
- name: assert that task failed with proper message - name: assert that task failed with proper message
assert: assert:
that: that:
- '"kubernetes >= 17.17.0 is required" in _result.module_stderr' - '"This is required to use in-memory config." in _result.msg'
when: when:
- _stat.stat.exists - _stat.stat.exists
- _stat.stat.readable - _stat.stat.readable