created an ansible module with module utils

Dieser Commit ist enthalten in:
Sebastian Tobie 2024-02-11 20:32:38 +01:00
Ursprung 5b9dd8df0b
Commit 768713aadc
22 geänderte Dateien mit 194 neuen und 296 gelöschten Zeilen

14
CHANGELOG.rst Normale Datei
Datei anzeigen

@ -0,0 +1,14 @@
============================
Sebastian.Base Release Notes
============================
.. contents:: Topics
v0.2.0
======
Release Summary
---------------
change the module to an ansible module

21
Makefile Normale Datei
Datei anzeigen

@ -0,0 +1,21 @@
format:
black .
isort .
changelog:
antsibull-changelog generate
docs: format
update-doc
clean-dist:
rm -rf dist
hatch-release:
hatch build
galaxy-release: clean-dist changelog
ansible-galaxy collection build --output-path dist
upload: galaxy-release hatch-release
./upload.sh

Datei anzeigen

@ -1,18 +1,3 @@
# Ansible module
# Ansible Collection - sebastian.base
-----
**Table of Contents**
- [Installation](#installation)
- [License](#license)
## Installation
```console
pip install ansible-module
```
## License
`ansible-module` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
Documentation for the collection.

Datei anzeigen

@ -0,0 +1,19 @@
objects:
role: {}
plugins:
become: {}
cache: {}
callback: {}
cliconf: {}
connection: {}
filter: {}
httpapi: {}
inventory: {}
lookup: {}
module: {}
netconf: {}
shell: {}
strategy: {}
test: {}
vars: {}
version: 0.2.0

8
changelogs/changelog.yaml Normale Datei
Datei anzeigen

@ -0,0 +1,8 @@
ancestor: null
releases:
0.2.0:
changes:
release_summary: change the module to an ansible module
fragments:
- base_release.yml
release_date: '2024-02-11'

32
changelogs/config.yaml Normale Datei
Datei anzeigen

@ -0,0 +1,32 @@
changelog_filename_template: ../CHANGELOG.rst
changelog_filename_version_depth: 0
changes_file: changelog.yaml
changes_format: combined
ignore_other_fragment_extensions: true
keep_fragments: false
mention_ancestor: true
new_plugins_after_name: removed_features
notesdir: fragments
prelude_section_name: release_summary
prelude_section_title: Release Summary
sanitize_changelog: true
sections:
- - major_changes
- Major Changes
- - minor_changes
- Minor Changes
- - breaking_changes
- Breaking Changes / Porting Guide
- - deprecated_features
- Deprecated Features
- - removed_features
- Removed Features (previously deprecated)
- - security_fixes
- Security Fixes
- - bugfixes
- Bugfixes
- - known_issues
- Known Issues
title: Sebastian.Base
trivial_section_name: trivial
use_fqcn: true

34
galaxy.yml Normale Datei
Datei anzeigen

@ -0,0 +1,34 @@
---
namespace: sebastian
name: base
version: 0.2.0
readme: README.md
authors:
- Sebastian Tobie
description: >
The base of my ansible collections. It provides the nessesary tools for my modules
license_file: LICENSE
tags:
- linux
- systemd
dependencies: {}
repository: https://gitea.sebastian-tobie.de/ansible/ansible-module.git
# documentation: https://gitea.sebastian-tobie.de/ansible/ansible-module
homepage: https://gitea.sebastian-tobie.de/ansible/ansible-module
issues: https://gitea.sebastian-tobie.de/ansible/ansible-module/issues
build_ignore:
- "*.gz"
- ".*"
- Makefile
- pyproject.toml
- upload.sh
- htmlcov
- changelogs
- docs
- src
- "coverage.*"
- dist

4
meta/runtime.yml Normale Datei
Datei anzeigen

@ -0,0 +1,4 @@
---
# Collections must specify a minimum required ansible version to upload
# to galaxy
requires_ansible: '>=2.9.10'

31
plugins/README.md Normale Datei
Datei anzeigen

@ -0,0 +1,31 @@
# Collections Plugins Directory
This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that
is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that
would contain module utils and modules respectively.
Here is an example directory of the majority of plugins currently supported by Ansible:
```
└── plugins
├── action
├── become
├── cache
├── callback
├── cliconf
├── connection
├── filter
├── httpapi
├── inventory
├── lookup
├── module_utils
├── modules
├── netconf
├── shell
├── strategy
├── terminal
├── test
└── vars
```
A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible-core/2.16/plugins/plugins.html).

Datei anzeigen

@ -5,7 +5,7 @@ from typing import (Any, Callable, ClassVar, Dict, NoReturn, Optional, Type,
import ansible.module_utils.basic as basic
from ansible_module.generic import AnsibleParameter, Types, systemdbool
from .generic import AnsibleParameter, Types, systemdbool
__all__ = (
"AnsibleModule",

Datei anzeigen

Datei anzeigen

@ -32,6 +32,9 @@ Source = "https://github.com/unknown/ansible-module"
[project.scripts]
update-doc = "ansible_module.update_doc:main"
[tool.hatch.build.targets.wheel.force-include]
"plugins/module_utils" = "ansible_module/module_utils"
[tool.hatch.version]
path = "src/ansible_module/__init__.py"
@ -135,7 +138,12 @@ ansible_module = ["src/ansible_module", "*/ansible-module/src/ansible_module"]
tests = ["tests", "*/ansible-module/tests"]
[tool.coverage.report]
exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:", "pragma: nocover"]
exclude_lines = [
"no cov",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
"pragma: nocover",
]
[tool.mypy]
python_version = "3.11"
@ -148,13 +156,11 @@ ignore_missing_imports = true
[tool.pytest.ini_options]
addopts = [
"--cov-report", "json",
"--cov-report", "term-missing:skip-covered",
"--cov-report",
"json",
"--cov-report",
"term-missing:skip-covered",
"--cov",
]
pythonpath = ["src"]
required_plugins = [
"pytest-cov",
"pytest-isort",
"pytest-mypy"
]
required_plugins = ["pytest-cov", "pytest-isort", "pytest-mypy"]

Datei anzeigen

@ -1 +1 @@
__version__ = "0.1.3"
__version__ = "0.2.0"

Datei anzeigen

@ -1,6 +1,4 @@
from . import update_doc
if __name__ == "__main__":
update_doc.main()

Datei anzeigen

@ -1,76 +0,0 @@
from typing import Any, Dict, Optional, Type, Union
from _typeshed import Incomplete
SYSTEMD_CONFIG_ROOT: Incomplete
SYSTEMD_NETWORK_CONFIG: Incomplete
SYSTEMD_SERVICE_CONFIG: Incomplete
AnsibleParameter = Dict[str, Any]
class Types:
def list(
elements: Union[Type[object], str, AnsibleParameter], required: bool = False, help: Optional[str] = None
) -> AnsibleParameter: ...
def dict(required: bool = False, help: Optional[str] = None, **options: dict) -> AnsibleParameter: ...
def str(
required: bool = False,
help: Optional[str] = None,
choices: Optional[Sequence] = None,
default: Optional[Any] = None,
) -> AnsibleParameter: ...
def bool(
required: bool = False,
help: Optional[str] = None,
choices: Optional[Sequence] = None,
default: Optional[Any] = None,
) -> AnsibleParameter: ...
def int(
required: bool = False,
help: Optional[str] = None,
choices: Optional[Sequence] = None,
default: Optional[Any] = None,
) -> AnsibleParameter: ...
def float(
required: bool = False,
help: Optional[str] = None,
choices: Optional[Sequence] = None,
default: Optional[Any] = None,
) -> AnsibleParameter: ...
def path(
required: bool = False,
help: Optional[str] = None,
choices: Optional[Sequence] = None,
default: Optional[Any] = None,
) -> AnsibleParameter: ...
def raw(
required: bool = False,
help: Optional[str] = None,
choices: Optional[Sequence] = None,
default: Optional[Any] = None,
) -> AnsibleParameter: ...
def jsonarg(
required: bool = False,
help: Optional[str] = None,
choices: Optional[Sequence] = None,
default: Optional[Any] = None,
) -> AnsibleParameter: ...
def json(
required: bool = False,
help: Optional[str] = None,
choices: Optional[Sequence] = None,
default: Optional[Any] = None,
) -> AnsibleParameter: ...
def bytes(
required: bool = False,
help: Optional[str] = None,
choices: Optional[Sequence] = None,
default: Optional[Any] = None,
) -> AnsibleParameter: ...
def bits(
required: bool = False,
help: Optional[str] = None,
choices: Optional[Sequence] = None,
default: Optional[Any] = None,
) -> AnsibleParameter: ...
def systemdbool(b: Union[bool, str]) -> str: ...

Datei anzeigen

@ -1,60 +0,0 @@
import pathlib
from typing import (Any, Callable, ClassVar, Dict, NoReturn, Optional, Type,
TypeVar, overload)
import ansible.module_utils.basic as basic
from _typeshed import Incomplete
T = TypeVar('T')
class AnsibleModule:
name: ClassVar[str]
module: basic.AnsibleModule
result: dict
module_spec: ClassVar[dict]
@property
def params(self) -> Dict[str, Any]: ...
tmpdir: Incomplete
def __init__(self) -> None: ...
def set(self, key: str, value): ...
@overload
def diff(self, diff: Dict[str, str]): ...
@overload
def diff(
self,
before: Optional[str] = ...,
after: Optional[str] = ...,
before_header: Optional[str] = ...,
after_header: Optional[str] = ...,
): ...
def get(self, key: str, default: Optional[T] = ...) -> T: ...
def changed_get(self): ...
def changed_set(self, value) -> None: ...
changed: Incomplete
def prepare(self) -> None: ...
def check(self) -> None: ...
def run(self) -> None: ...
def __call__(self) -> NoReturn: ...
@classmethod
def doc(cls) -> str: ...
class SystemdUnitModule(AnsibleModule):
unitfile: pathlib.Path
post: Optional[Callable[[], None]]
install: ClassVar[Optional[Callable[[SystemdUnitModule], str]]]
def unit(self) -> str: ...
def header(self) -> str: ...
def map_param(self, **parammap: str): ...
changed: Incomplete
def unitfile_gen(self) -> None: ...
def check(self) -> None: ...
def run(self) -> None: ...
def installable(_class: Type[SystemdUnitModule]): ...
class SystemdReloadMixin:
module: basic.AnsibleModule
unitfile: pathlib.Path
restartable: bool
changed: bool
def post(self) -> None: ...

0
src/ansible_module/py.typed Normale Datei
Datei anzeigen

Datei anzeigen

@ -1,3 +0,0 @@
# SPDX-FileCopyrightText: 2023-present Sebastian Tobie <sebastian@sebastian-tobie.de>
#
# SPDX-License-Identifier: MIT

Datei anzeigen

@ -1,57 +0,0 @@
import os
import unittest
from ansible_module.generic import Types, joindict, systemdbool
class TestTypes(unittest.TestCase):
"""tests the Types class"""
def testsimpletype(self):
"""this tests if an simple type is correctly build"""
output = Types.str(required=True, help="test", choices=("a", "1"), default="1")
self.assertIn("type", output)
self.assertIn("required", output)
self.assertIn("default", output)
self.assertIn("choices", output)
self.assertEqual(output["type"], "str")
self.assertEqual(Types.str.__name__, "str")
self.assertEqual(output["required"], True)
self.assertEqual(output["default"], "1")
self.assertTupleEqual(output["choices"], ("a", "1"))
Types.str()
def testlisttype(self):
"""this tests if the special type list is correctly build"""
output = Types.list(str)
Types.list("str")
self.assertIn("type", output)
self.assertIn("elements", output)
self.assertIn("required", output)
self.assertEqual(output["type"], "list")
self.assertEqual(output["required"], False)
self.assertEqual(output["elements"], "str")
Types.list(Types.dict(a=Types.str(help="")), help="")
Types.list("str")
def testdicttype(self):
output = Types.dict(help="HILFE")
self.assertIn("type", output)
self.assertIn("required", output)
self.assertIn("description", output)
self.assertIn("option", output)
class TestFuncs(unittest.TestCase):
def testsystemdbool(self):
self.assertEqual("Text", systemdbool("Text"))
self.assertEqual("no", systemdbool(False))
self.assertEqual("yes", systemdbool(True))
def testjoindict(self):
dicts = (
dict(a=1, b=2),
dict(b=3, c=4),
)
output = dict(a=1, b=3, c=4)
self.assertDictEqual(output, joindict(*dicts))

Datei anzeigen

@ -1,71 +0,0 @@
import sys
import unittest
from ansible_module.generic import modspec
from ansible_module.module import SystemdUnitModule, docify
class ModuleMock(SystemdUnitModule):
name = "mock"
module_spec = modspec({})
class TestSystemdUnitModule(unittest.TestCase):
def setUp(self):
sys.argv = [sys.argv[0], '{"ANSIBLE_MODULE_ARGS":{}}']
self.mod = ModuleMock()
def test_header(self):
self.assertEqual("[Unit]\n", self.mod.header())
def test_doc(self):
ModuleMock.doc()
def test_params(self):
self.mod.module.params = dict(ok="ok", none=None, true=True, false=False, list=("item1", "item2"))
self.assertEqual("ok", self.mod.get("ok"))
self.assertEqual("default", self.mod.get("none", "default"))
self.assertRaises(KeyError, self.mod.get, "none", None)
self.assertListEqual(
['TRUE=yes\n', "FALSE=no\n", "OK=ok\n", "LIST=item1\n", "LIST=item2\n"],
self.mod.map_param(true="TRUE", false="FALSE", ok="OK", list="LIST"),
)
self.assertRaises(TypeError, self.mod.diff, diff=dict(), before=True, after=False)
self.mod.diff(before="a", after="b", before_header="a", after_header="b")
self.mod.diff(dict(before="c", after="d"))
def test_result(self):
self.assertFalse(self.mod.changed)
self.mod.changed = 5
self.assertTrue(self.mod.changed)
self.mod.set("key", "value")
self.assertDictEqual(
dict(
changed=True,
key="value",
),
self.mod.result,
)
class TestFunctions(unittest.TestCase):
def test_docify(self):
input = dict(
item1=dict(type="str", description=""),
item2=dict(required=True, type="int", default=5),
item3=dict(type="list", required=False, elements="int"),
item4=dict(type="list", required=True, elements="int"),
item5=dict(type="str", choices=["a", "b", "c"]),
item6=dict(type="dict", options=dict(a=dict(type="str"))),
)
expected = dict(
item1=dict(required=False, type="str", description=[""]),
item2=dict(required=True, type="int", default=5),
item3=dict(type="list", required=False, elements="int", default=[]),
item4=dict(type="list", required=True, elements="int"),
item5=dict(type="str", required=False, choices=("a", "b", "c")),
item6=dict(type="dict", required=False, options=dict(a=dict(type="str", required=False))),
)
output = docify(input)
for key, value in input.items():
self.assertDictEqual(expected[key], output[key])

13
upload.sh Ausführbare Datei
Datei anzeigen

@ -0,0 +1,13 @@
#!/bin/bash
user=$(yq -r .namespace galaxy.yml)
package=$(yq -r .name galaxy.yml)
version=$(yq -r .version galaxy.yml)
printf "Namespace: %s\nPackage: %s\nVersion: %s\n" $user $package $version
upload(){
name=$(basename "$1")
printf "uploading: %s as %s\n" "$1" "$name"
curl -u sebastian --upload-file "$1" "https://gitea.sebastian-tobie.de/api/packages/ansible/generic/${package}/${version}/$name"
}
for file in dist/* ; do
upload "$file"
done