1
0
Fork 0

updates the Module classes with documentation and deduplicated some code

Dieser Commit ist enthalten in:
Sebastian Tobie 2023-04-15 09:40:27 +02:00
Ursprung aa0723809a
Commit e3a4c894ea
1 geänderte Dateien mit 54 neuen und 32 gelöschten Zeilen

Datei anzeigen

@ -1,5 +1,5 @@
import pathlib
from typing import Any, Callable, ClassVar, Dict, Optional, TypeVar
from typing import Any, Callable, ClassVar, Dict, Optional, TypeVar, NoReturn, overload
import ansible.module_utils.basic as basic
from ansible.module_utils.generic import _sdict
@ -14,17 +14,24 @@ T = TypeVar("T")
class AnsibleModule(object):
"""Simple wrapper for the mo"""
"""Simple wrapper for the basic.AnsibleModule"""
#: name of the module. This is required for the generation of the Ansible documentation
name: ClassVar[str]
#: The AnsibleModule for this Module
module: basic.AnsibleModule
#: TODO
msg: str
#: The result of this Module call. It always contains the changed key, so in any case an Module can report if it changed anything
result: dict
#: the specification of the arguments. Subclasses that are usable Modules must set this value.
module_spec: ClassVar[dict]
#: This is set by classes that define common things for their subclasses, like behaviour of the run and check methods. This is used by `SystemdUnitModule`
_common_args = dict()
@property
def params(self) -> Dict[str, Any]:
"""params is an wrapper for the module.params"""
return self.module.params # type: ignore
def __init__(self):
@ -37,17 +44,26 @@ class AnsibleModule(object):
self.tmpdir = pathlib.Path(self.module.tmpdir)
def set(self, key: str, value):
"""sets an value for the result"""
self.result[key] = value
@overload
def diff(self, diff: Dict[str, str]):
pass
def diff(
self,
before,
after,
self,diff: Optional[Dict[str, str]] = None,*,
before: Optional[str] = None,
after: Optional[str] = None,
before_header: Optional[str] = None,
after_header: Optional[str] = None,
):
"""adds the special return value "diff". This allows Modules to present the changes of files to the caller. it takes care of the special semantics of the return value"""
if "diff" not in self.result:
self.result["diff"] = list()
if diff is not None and not any((before is not None, after is not None)):
pass
elif all((before is not None, after is not None, diff is None)):
diff = dict(
before=before,
after=after,
@ -56,9 +72,12 @@ class AnsibleModule(object):
diff["before_header"] = before_header
if after_header is not None:
diff["after_header"] = after_header
else:
raise TypeError("only diff or before and after can be set, not both of them")
self.result["diff"].append(diff)
def get(self, key: str, default: T = None) -> T:
"""returns an Parameter of the Module."""
if key not in self.params.keys():
return default
if self.params[key] is None and default is not None:
@ -69,10 +88,12 @@ class AnsibleModule(object):
@property
def changed(self):
"""returns if changes were detected/made"""
return self.result["changed"]
@changed.setter
def changed_set(self, value):
"""sets the changed value. this is always converted to bool"""
self.result["changed"] = not not value
def prepare(self):
@ -84,7 +105,9 @@ class AnsibleModule(object):
def run(self):
raise NotImplementedError()
def __call__(self):
def __call__(self) -> NoReturn:
"""This calls the module. first prepare is called and then check or run, depending on the check mode.
If an exception is raised this is catched and the module automatically fails with an traceback"""
self.prepare()
try:
if self.module.check_mode:
@ -102,6 +125,7 @@ class AnsibleModule(object):
@classmethod
def doc(cls) -> str:
"""this returns the documentation string of the module. If the help arguments of an Types method was given, it adds this as an helptext of this parameter"""
try:
import yaml
except ImportError:
@ -145,11 +169,14 @@ class AnsibleModule(object):
class SystemdUnitModule(AnsibleModule):
#: path of the unitfile managed by this module
unitfile: pathlib.Path
#: subclasses of this always support the file common args and the check mode
_common_args = dict(
supports_check_mode=True,
add_file_common_args=True,
)
#: if defined it will be called after run has changed the unitfile
post: Optional[Callable[[], None]]
def unit(self) -> str:
@ -163,55 +190,50 @@ class SystemdUnitModule(AnsibleModule):
self.module.set_group_if_different(path.as_posix(), "root", False)
self.module.set_mode_if_different(path.as_posix(), "0644", False)
if self.unitfile.exists():
if "diff" not in self.result:
self.result["diff"] = list()
diff = dict()
self.result["changed"] = self.module.set_owner_if_different(
self.changed = self.changed | self.module.set_owner_if_different(
self.unitfile.as_posix(),
"root",
self.result["changed"],
diff,
)
self.result["changed"] = self.module.set_group_if_different(
self.diff(diff)
diff = dict()
self.changed = self.changed | self.module.set_group_if_different(
self.unitfile.as_posix(),
"root",
self.result["changed"],
diff,
)
self.result["changed"] = self.module.set_mode_if_different(
self.diff(diff)
diff = dict()
self.changed = self.changed | self.module.set_mode_if_different(
self.unitfile.as_posix(),
"0644",
self.result["changed"],
diff,
)
self.result["diff"].append(diff)
self.diff(diff)
def check(self):
if "changed" in self.result:
changed = self.result["changed"]
else:
changed = False
self.unitfile_gen()
if not self.unitfile.exists():
self.diff("", self.unit(), self.unitfile.as_posix())
changed = True
self.diff(before="", after=self.unit(), before_header=self.unitfile.as_posix())
self.changed = True
else:
if self.module.sha256(self.unitfile.as_posix()) != self.module.sha256(
(self.tmpdir / "newunit").as_posix()
):
changed = True
self.changed = True
self.diff(
before=self.unitfile.read_text(),
after=self.unit(),
before_header=self.unitfile.as_posix(),
)
self.set("changed", changed)
if hasattr(self, "post") and self.post is not None:
self.post()
return changed
def run(self):
if not self.check():
self.check()
if not self.changed:
return
self.module.atomic_move(
src=(self.tmpdir / "newunit").as_posix(),