mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-05-08 05:52:37 +00:00
k8s runner (#309)
k8s runner SUMMARY k8s runner Requires: #307 ISSUE TYPE New Module Pull Request Reviewed-by: Abhijeet Kasurde <None> Reviewed-by: Alina Buzachis <None> Reviewed-by: Mike Graves <mgraves@redhat.com> Reviewed-by: None <None>
This commit is contained in:
committed by
Mike Graves
parent
e2f54d3431
commit
d68da5bbdd
112
plugins/module_utils/k8s/runner.py
Normal file
112
plugins/module_utils/k8s/runner.py
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# Copyright: (c) 2021, Red Hat | Ansible
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.client import (
|
||||||
|
get_api_client,
|
||||||
|
)
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.resource import (
|
||||||
|
create_definitions,
|
||||||
|
)
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.service import (
|
||||||
|
K8sService,
|
||||||
|
)
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions import (
|
||||||
|
CoreException,
|
||||||
|
)
|
||||||
|
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.selector import (
|
||||||
|
LabelSelectorFilter,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def validate(client, module, resource):
|
||||||
|
def _prepend_resource_info(resource, msg):
|
||||||
|
return "%s %s: %s" % (resource["kind"], resource["metadata"]["name"], msg)
|
||||||
|
|
||||||
|
module.requires("kubernetes-validate")
|
||||||
|
|
||||||
|
warnings, errors = client.validate(
|
||||||
|
resource,
|
||||||
|
module.params["validate"].get("version"),
|
||||||
|
module.params["validate"].get("strict"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if errors and module.params["validate"]["fail_on_error"]:
|
||||||
|
module.fail_json(
|
||||||
|
msg="\n".join([_prepend_resource_info(resource, error) for error in errors])
|
||||||
|
)
|
||||||
|
return [_prepend_resource_info(resource, msg) for msg in warnings + errors]
|
||||||
|
|
||||||
|
|
||||||
|
def run_module(module) -> None:
|
||||||
|
results = []
|
||||||
|
|
||||||
|
client = get_api_client(module)
|
||||||
|
svc = K8sService(client, module)
|
||||||
|
definitions = create_definitions(module.params)
|
||||||
|
|
||||||
|
for definition in definitions:
|
||||||
|
module.warnings = []
|
||||||
|
|
||||||
|
if module.params["validate"] is not None:
|
||||||
|
module.warnings = validate(client, module, definition)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = perform_action(svc, definition, module.params)
|
||||||
|
except CoreException as e:
|
||||||
|
if module.warnings:
|
||||||
|
e["msg"] += "\n" + "\n ".join(module.warnings)
|
||||||
|
if module.params.get("continue_on_error"):
|
||||||
|
result = {"error": "{0}".format(e)}
|
||||||
|
else:
|
||||||
|
module.fail_json(msg=e)
|
||||||
|
if module.warnings:
|
||||||
|
result["warnings"] = module.warnings
|
||||||
|
|
||||||
|
results.append(result)
|
||||||
|
|
||||||
|
module.exit_json(**results)
|
||||||
|
|
||||||
|
|
||||||
|
def perform_action(svc, definition: Dict, params: Dict) -> Dict:
|
||||||
|
origin_name = definition["metadata"].get("name")
|
||||||
|
namespace = definition["metadata"].get("namespace")
|
||||||
|
label_selectors = params.get("label_selectors")
|
||||||
|
state = params.get("state", None)
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
resource = svc.find_resource(definition)
|
||||||
|
existing = svc.retrieve(resource, definition)
|
||||||
|
|
||||||
|
if state == "absent":
|
||||||
|
result = svc.delete(resource, definition, existing)
|
||||||
|
result["method"] = "delete"
|
||||||
|
else:
|
||||||
|
if label_selectors:
|
||||||
|
filter_selector = LabelSelectorFilter(label_selectors)
|
||||||
|
if not filter_selector.isMatching(definition):
|
||||||
|
result["changed"] = False
|
||||||
|
result["msg"] = (
|
||||||
|
"resource 'kind={kind},name={name},namespace={namespace}' "
|
||||||
|
"filtered by label_selectors.".format(
|
||||||
|
kind=definition["kind"], name=origin_name, namespace=namespace,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
if params.get("apply"):
|
||||||
|
result = svc.apply(resource, definition, existing)
|
||||||
|
result["method"] = "apply"
|
||||||
|
elif not existing:
|
||||||
|
result = svc.create(resource, definition)
|
||||||
|
result["method"] = "create"
|
||||||
|
elif params.get("force", False):
|
||||||
|
result = svc.replace(resource, definition, existing)
|
||||||
|
result["method"] = "replace"
|
||||||
|
else:
|
||||||
|
result = svc.update(resource, definition, existing)
|
||||||
|
result["method"] = "update"
|
||||||
|
|
||||||
|
return result
|
||||||
53
tests/unit/module_utils/test_runner.py
Normal file
53
tests/unit/module_utils/test_runner.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import pytest
|
||||||
|
from unittest.mock import MagicMock, call
|
||||||
|
|
||||||
|
from ansible_collections.kubernetes.core.plugins.module_utils.k8s.runner import (
|
||||||
|
perform_action,
|
||||||
|
)
|
||||||
|
|
||||||
|
definition = {
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Pod",
|
||||||
|
"metadata": {
|
||||||
|
"name": "foo",
|
||||||
|
"labels": {"environment": "production", "app": "nginx"},
|
||||||
|
"namespace": "foo",
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [
|
||||||
|
{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:1.14.2",
|
||||||
|
"command": ["/bin/sh", "-c", "sleep 10"],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"params, expected",
|
||||||
|
[
|
||||||
|
({"state": "absent"}, call.__setitem__("method", "delete")),
|
||||||
|
({"apply": True}, call.__setitem__("method", "apply")),
|
||||||
|
({"force": True}, call.__setitem__("method", "replace")),
|
||||||
|
({"apply": False}, call.__setitem__("method", "update")),
|
||||||
|
({}, call.__setitem__("method", "update")),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_perform_action(params, expected):
|
||||||
|
module = MagicMock()
|
||||||
|
module.params = params
|
||||||
|
|
||||||
|
result = perform_action(MagicMock(), definition, module.params)
|
||||||
|
result.assert_has_calls([expected], any_order=True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_perform_action_create():
|
||||||
|
spec = {"retrieve.side_effect": [{}]}
|
||||||
|
svc = MagicMock(**spec)
|
||||||
|
module = MagicMock()
|
||||||
|
module.params = {}
|
||||||
|
|
||||||
|
result = perform_action(svc, definition, module.params)
|
||||||
|
result.assert_has_calls([call.__setitem__("method", "create")], any_order=True)
|
||||||
Reference in New Issue
Block a user