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 hashlib
from distutils.version import LooseVersion
from typing import Any, Dict, List, Optional
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_PROXY_HEADERS_SPEC,
)
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.core import requires
try:
from ansible_collections.kubernetes.core.plugins.module_utils import (
@@ -40,20 +40,9 @@ except ImportError:
pass
module = None
_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:
auth: Dict = {}
# 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):
kubernetes.config.load_kube_config(config_file=kubeconfig, **optional_arg)
elif isinstance(kubeconfig, dict):
_requires_kubernetes_at_least("17.17.0")
kubernetes.config.load_kube_config_from_dict(
config_dict=kubeconfig, **optional_arg
)
@@ -241,6 +229,11 @@ class K8SClient:
def get_api_client(module=None, **kwargs: Optional[Any]) -> K8SClient:
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)
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 missing_required_lib
from ansible.module_utils.common.text.converters import to_text
class AnsibleK8SModule:
@@ -68,67 +69,84 @@ class AnsibleK8SModule:
def fail_json(self, *args, **kwargs):
return self._module.fail_json(*args, **kwargs)
def _gather_versions(self) -> dict:
versions = {}
try:
import jsonpatch
versions["jsonpatch"] = jsonpatch.__version__
except ImportError:
pass
try:
import kubernetes
versions["kubernetes"] = kubernetes.__version__
except ImportError:
pass
try:
import yaml
versions["pyyaml"] = yaml.__version__
except ImportError:
pass
return versions
def has_at_least(
self, dependency: str, minimum: Optional[str] = None, warn: bool = False
) -> bool:
"""Check if a specific dependency is present at a minimum version.
If a minimum version is not specified it will check only that the
dependency is present. Additionally, if ``warn`` is ``True``, a warning
will be emitted if the actual version is less than the specified
minimum version.
"""
dependencies = self._gather_versions()
current = dependencies.get(dependency)
if current is not None:
if minimum is None:
return True
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
)
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
return False
)
return supported
def requires(self, dependency: str, minimum: Optional[str] = None) -> None:
"""Fail if a specific dependency is not present at a minimum version.
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))
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 not found at the required version and will stop module
execution.
"""
if not self.has_at_least(dependency, minimum):
if minimum is not None:
lib = "{0}>={1}".format(dependency, minimum)
else:
lib = dependency
self._module.fail_json(msg=missing_required_lib(lib))
def gather_versions() -> dict:
versions = {}
try:
import jsonpatch
versions["jsonpatch"] = jsonpatch.__version__
except ImportError:
pass
try:
import kubernetes
versions["kubernetes"] = kubernetes.__version__
except ImportError:
pass
try:
import yaml
versions["pyyaml"] = yaml.__version__
except ImportError:
pass
return versions
def has_at_least(dependency: str, minimum: Optional[str] = None) -> bool:
"""Check if a specific dependency is present at a minimum version.
If a minimum version is not specified it will check only that the
dependency is present.
"""
dependencies = gather_versions()
current = dependencies.get(dependency)
if current is not None:
if minimum is None:
return True
supported = LooseVersion(current) >= LooseVersion(minimum)
return supported
return False
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.
If a minimum version is not specified it will require only that the
dependency is present. This function raises an exception when the
dependency is not found at the required version.
"""
if not has_at_least(dependency, minimum):
if minimum is not None:
lib = "{0}>={1}".format(dependency, minimum)
else:
lib = dependency
raise Exception(missing_required_lib(lib, reason=reason))

View File

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