mirror of
https://github.com/kubevirt/kubevirt.core.git
synced 2026-03-26 19:03:16 +00:00
cleanup(kubevirt_vm): Drop dependency on Jinja2
Drop the dependency on Jinja2 in the kubevirt_vm module by using dicts to construct a VM instead of rendering jinja templates internally. Signed-off-by: Felix Matouschek <fmatouschek@redhat.com>
This commit is contained in:
@@ -55,7 +55,6 @@ ansible-galaxy collection install -r requirements.yml
|
|||||||
|
|
||||||
#### Python libraries
|
#### Python libraries
|
||||||
|
|
||||||
- jinja2
|
|
||||||
- jsonpatch
|
- jsonpatch
|
||||||
- kubernetes>=28.1.0
|
- kubernetes>=28.1.0
|
||||||
- PyYAML>=3.11
|
- PyYAML>=3.11
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ requirements:
|
|||||||
- "kubernetes >= 28.1.0"
|
- "kubernetes >= 28.1.0"
|
||||||
- "PyYAML >= 3.11"
|
- "PyYAML >= 3.11"
|
||||||
- "jsonpatch"
|
- "jsonpatch"
|
||||||
- "jinja2"
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
@@ -263,7 +262,6 @@ result:
|
|||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
import traceback
|
|
||||||
|
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.ansiblemodule import (
|
from ansible_collections.kubernetes.core.plugins.module_utils.ansiblemodule import (
|
||||||
AnsibleModule,
|
AnsibleModule,
|
||||||
@@ -282,91 +280,48 @@ from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions imp
|
|||||||
CoreException,
|
CoreException,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
|
||||||
import yaml
|
|
||||||
except ImportError:
|
|
||||||
HAS_YAML = False
|
|
||||||
YAML_IMPORT_ERROR = traceback.format_exc()
|
|
||||||
else:
|
|
||||||
HAS_YAML = True
|
|
||||||
YAML_IMPORT_ERROR = None
|
|
||||||
|
|
||||||
try:
|
def create_vm(params: Dict) -> Dict:
|
||||||
from jinja2 import Environment
|
|
||||||
except ImportError:
|
|
||||||
HAS_JINJA = False
|
|
||||||
JINJA_IMPORT_ERROR = traceback.format_exc()
|
|
||||||
else:
|
|
||||||
HAS_JINJA = True
|
|
||||||
JINJA_IMPORT_ERROR = None
|
|
||||||
|
|
||||||
|
|
||||||
VM_TEMPLATE = """
|
|
||||||
apiVersion: {{ api_version }}
|
|
||||||
kind: VirtualMachine
|
|
||||||
metadata:
|
|
||||||
{% if name %}
|
|
||||||
name: {{ name }}
|
|
||||||
{% endif %}
|
|
||||||
{% if generate_name %}
|
|
||||||
generateName: {{ generate_name }}
|
|
||||||
{% endif %}
|
|
||||||
namespace: {{ namespace }}
|
|
||||||
{% if annotations %}
|
|
||||||
annotations:
|
|
||||||
{{ annotations | to_yaml | indent(4) }}
|
|
||||||
{%- endif %}
|
|
||||||
{% if labels %}
|
|
||||||
labels:
|
|
||||||
{{ labels | to_yaml | indent(4) }}
|
|
||||||
{%- endif %}
|
|
||||||
spec:
|
|
||||||
running: {{ running | lower }}
|
|
||||||
{% if instancetype %}
|
|
||||||
instancetype:
|
|
||||||
{{ instancetype | to_yaml | indent(4) }}
|
|
||||||
{%- endif %}
|
|
||||||
{% if preference %}
|
|
||||||
preference:
|
|
||||||
{{ preference | to_yaml | indent(4) }}
|
|
||||||
{%- endif %}
|
|
||||||
{% if data_volume_templates %}
|
|
||||||
dataVolumeTemplates:
|
|
||||||
{{ data_volume_templates | to_yaml | indent(2) }}
|
|
||||||
{%- endif %}
|
|
||||||
template:
|
|
||||||
{% if annotations or labels %}
|
|
||||||
metadata:
|
|
||||||
{% if annotations %}
|
|
||||||
annotations:
|
|
||||||
{{ annotations | to_yaml | indent(8) }}
|
|
||||||
{%- endif %}
|
|
||||||
{% if labels %}
|
|
||||||
labels:
|
|
||||||
{{ labels | to_yaml | indent(8) }}
|
|
||||||
{%- endif %}
|
|
||||||
{% endif %}
|
|
||||||
spec:
|
|
||||||
{% if spec %}
|
|
||||||
{{ spec | to_yaml | indent (6) }}
|
|
||||||
{%- else %}
|
|
||||||
domain:
|
|
||||||
devices: {}
|
|
||||||
{% endif %}
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def render_template(params: Dict) -> str:
|
|
||||||
"""
|
"""
|
||||||
render_template uses Jinja2 to render the VM_TEMPLATE into a string.
|
create_vm constructs a VM from the module parameters.
|
||||||
"""
|
"""
|
||||||
env = Environment(autoescape=False, trim_blocks=True, lstrip_blocks=True)
|
vm = {
|
||||||
env.filters["to_yaml"] = lambda data, *_, **kw: yaml.dump(
|
"apiVersion": params["api_version"],
|
||||||
data, allow_unicode=True, default_flow_style=False, **kw
|
"kind": "VirtualMachine",
|
||||||
)
|
"metadata": {
|
||||||
|
"namespace": params["namespace"],
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"running": params["running"],
|
||||||
|
"template": {"spec": {"domain": {"devices": {}}}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
template = env.from_string(VM_TEMPLATE.strip())
|
if (name := params.get("name")) is not None:
|
||||||
return template.render(params)
|
vm["metadata"]["name"] = name
|
||||||
|
if (generate_name := params.get("generate_name")) is not None:
|
||||||
|
vm["metadata"]["generateName"] = generate_name
|
||||||
|
|
||||||
|
template_metadata = {}
|
||||||
|
if (annotations := params.get("annotations")) is not None:
|
||||||
|
vm["metadata"]["annotations"] = annotations
|
||||||
|
template_metadata["annotations"] = annotations
|
||||||
|
if (labels := params.get("labels")) is not None:
|
||||||
|
vm["metadata"]["labels"] = labels
|
||||||
|
template_metadata["labels"] = labels
|
||||||
|
if template_metadata:
|
||||||
|
vm["spec"]["template"]["metadata"] = template_metadata
|
||||||
|
|
||||||
|
if (instancetype := params.get("instancetype")) is not None:
|
||||||
|
vm["spec"]["instancetype"] = instancetype
|
||||||
|
if (preference := params.get("preference")) is not None:
|
||||||
|
vm["spec"]["preference"] = preference
|
||||||
|
if (data_volume_templates := params.get("data_volume_templates")) is not None:
|
||||||
|
vm["spec"]["dataVolumeTemplates"] = data_volume_templates
|
||||||
|
if (spec := params.get("spec")) is not None:
|
||||||
|
vm["spec"]["template"]["spec"] = spec
|
||||||
|
|
||||||
|
return vm
|
||||||
|
|
||||||
|
|
||||||
def arg_spec() -> Dict:
|
def arg_spec() -> Dict:
|
||||||
@@ -428,8 +383,8 @@ def main() -> None:
|
|||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set resource_definition to our rendered template
|
# Set resource_definition to our constructed VM
|
||||||
module.params["resource_definition"] = render_template(module.params)
|
module.params["resource_definition"] = create_vm(module.params)
|
||||||
|
|
||||||
# Set wait_condition to allow waiting for the ready state of the VirtualMachine
|
# Set wait_condition to allow waiting for the ready state of the VirtualMachine
|
||||||
if module.params["running"]:
|
if module.params["running"]:
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
jinja2
|
|
||||||
jsonpatch
|
jsonpatch
|
||||||
kubernetes>=28.1.0
|
kubernetes>=28.1.0
|
||||||
PyYAML>=3.11
|
PyYAML>=3.11
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ __metaclass__ = type
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from yaml import dump
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible_collections.kubernetes.core.plugins.module_utils.k8s import runner
|
from ansible_collections.kubernetes.core.plugins.module_utils.k8s import runner
|
||||||
from ansible_collections.kubevirt.core.plugins.modules import kubevirt_vm
|
from ansible_collections.kubevirt.core.plugins.modules import kubevirt_vm
|
||||||
@@ -204,7 +202,7 @@ def module_params_delete(module_params_default):
|
|||||||
def k8s_module_params_create(module_params_create, vm_definition_create):
|
def k8s_module_params_create(module_params_create, vm_definition_create):
|
||||||
return module_params_create | {
|
return module_params_create | {
|
||||||
"generate_name": None,
|
"generate_name": None,
|
||||||
"resource_definition": dump(vm_definition_create, sort_keys=False),
|
"resource_definition": vm_definition_create,
|
||||||
"wait_condition": {"type": "Ready", "status": True},
|
"wait_condition": {"type": "Ready", "status": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +211,7 @@ def k8s_module_params_create(module_params_create, vm_definition_create):
|
|||||||
def k8s_module_params_running(module_params_running, vm_definition_running):
|
def k8s_module_params_running(module_params_running, vm_definition_running):
|
||||||
return module_params_running | {
|
return module_params_running | {
|
||||||
"generate_name": None,
|
"generate_name": None,
|
||||||
"resource_definition": dump(vm_definition_running, sort_keys=False),
|
"resource_definition": vm_definition_running,
|
||||||
"wait_condition": {"type": "Ready", "status": True},
|
"wait_condition": {"type": "Ready", "status": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +220,7 @@ def k8s_module_params_running(module_params_running, vm_definition_running):
|
|||||||
def k8s_module_params_stopped(module_params_stopped, vm_definition_stopped):
|
def k8s_module_params_stopped(module_params_stopped, vm_definition_stopped):
|
||||||
return module_params_stopped | {
|
return module_params_stopped | {
|
||||||
"generate_name": None,
|
"generate_name": None,
|
||||||
"resource_definition": dump(vm_definition_stopped, sort_keys=False),
|
"resource_definition": vm_definition_stopped,
|
||||||
"wait_condition": {"type": "Ready", "status": False, "reason": "VMINotExists"},
|
"wait_condition": {"type": "Ready", "status": False, "reason": "VMINotExists"},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +229,7 @@ def k8s_module_params_stopped(module_params_stopped, vm_definition_stopped):
|
|||||||
def k8s_module_params_delete(module_params_delete, vm_definition_running):
|
def k8s_module_params_delete(module_params_delete, vm_definition_running):
|
||||||
return module_params_delete | {
|
return module_params_delete | {
|
||||||
"generate_name": None,
|
"generate_name": None,
|
||||||
"resource_definition": dump(vm_definition_running, sort_keys=False),
|
"resource_definition": vm_definition_running,
|
||||||
"wait_condition": {"type": "Ready", "status": True},
|
"wait_condition": {"type": "Ready", "status": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +303,7 @@ def test_module(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def render_template_params():
|
def create_vm_params():
|
||||||
return {
|
return {
|
||||||
"api_version": "kubevirt.io/v1",
|
"api_version": "kubevirt.io/v1",
|
||||||
"running": True,
|
"running": True,
|
||||||
@@ -314,36 +312,36 @@ def render_template_params():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def render_template_params_annotations(render_template_params):
|
def create_vm_params_annotations(create_vm_params):
|
||||||
return render_template_params | {
|
return create_vm_params | {
|
||||||
"annotations": {"test": "test"},
|
"annotations": {"test": "test"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def render_template_params_labels(render_template_params):
|
def create_vm_params_labels(create_vm_params):
|
||||||
return render_template_params | {
|
return create_vm_params | {
|
||||||
"labels": {"test": "test"},
|
"labels": {"test": "test"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def render_template_params_instancetype(render_template_params):
|
def create_vm_params_instancetype(create_vm_params):
|
||||||
return render_template_params | {
|
return create_vm_params | {
|
||||||
"instancetype": {"name": "u1.medium"},
|
"instancetype": {"name": "u1.medium"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def render_template_params_preference(render_template_params):
|
def create_vm_params_preference(create_vm_params):
|
||||||
return render_template_params | {
|
return create_vm_params | {
|
||||||
"preference": {"name": "fedora"},
|
"preference": {"name": "fedora"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def render_template_params_datavolumetemplate(render_template_params):
|
def create_vm_params_datavolumetemplate(create_vm_params):
|
||||||
return render_template_params | {
|
return create_vm_params | {
|
||||||
"data_volume_templates": [
|
"data_volume_templates": [
|
||||||
{
|
{
|
||||||
"metadata": {"name": "testdv"},
|
"metadata": {"name": "testdv"},
|
||||||
@@ -364,22 +362,22 @@ def render_template_params_datavolumetemplate(render_template_params):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def render_template_params_name(render_template_params):
|
def create_vm_params_name(create_vm_params):
|
||||||
return render_template_params | {
|
return create_vm_params | {
|
||||||
"name": "testvm",
|
"name": "testvm",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def render_template_params_generate_name(render_template_params):
|
def create_vm_params_generate_name(create_vm_params):
|
||||||
return render_template_params | {
|
return create_vm_params | {
|
||||||
"generate_name": "testvm-1234",
|
"generate_name": "testvm-1234",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def render_template_params_specs(render_template_params):
|
def create_vm_params_specs(create_vm_params):
|
||||||
return render_template_params | {
|
return create_vm_params | {
|
||||||
"spec": {
|
"spec": {
|
||||||
"domain": {
|
"domain": {
|
||||||
"devices": {
|
"devices": {
|
||||||
@@ -395,7 +393,7 @@ def render_template_params_specs(render_template_params):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def vm_template():
|
def created_vm():
|
||||||
return {
|
return {
|
||||||
"apiVersion": "kubevirt.io/v1",
|
"apiVersion": "kubevirt.io/v1",
|
||||||
"kind": "VirtualMachine",
|
"kind": "VirtualMachine",
|
||||||
@@ -416,7 +414,7 @@ def vm_template():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def vm_template_labels():
|
def created_vm_labels():
|
||||||
return {
|
return {
|
||||||
"apiVersion": "kubevirt.io/v1",
|
"apiVersion": "kubevirt.io/v1",
|
||||||
"kind": "VirtualMachine",
|
"kind": "VirtualMachine",
|
||||||
@@ -443,7 +441,7 @@ def vm_template_labels():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def vm_template_annotations():
|
def created_vm_annotations():
|
||||||
return {
|
return {
|
||||||
"apiVersion": "kubevirt.io/v1",
|
"apiVersion": "kubevirt.io/v1",
|
||||||
"kind": "VirtualMachine",
|
"kind": "VirtualMachine",
|
||||||
@@ -470,7 +468,7 @@ def vm_template_annotations():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def vm_template_instancetype():
|
def created_vm_instancetype():
|
||||||
return {
|
return {
|
||||||
"apiVersion": "kubevirt.io/v1",
|
"apiVersion": "kubevirt.io/v1",
|
||||||
"kind": "VirtualMachine",
|
"kind": "VirtualMachine",
|
||||||
@@ -492,7 +490,7 @@ def vm_template_instancetype():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def vm_template_preference():
|
def created_vm_preference():
|
||||||
return {
|
return {
|
||||||
"apiVersion": "kubevirt.io/v1",
|
"apiVersion": "kubevirt.io/v1",
|
||||||
"kind": "VirtualMachine",
|
"kind": "VirtualMachine",
|
||||||
@@ -514,7 +512,7 @@ def vm_template_preference():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def vm_template_datavolumetemplate():
|
def created_vm_datavolumetemplate():
|
||||||
return {
|
return {
|
||||||
"apiVersion": "kubevirt.io/v1",
|
"apiVersion": "kubevirt.io/v1",
|
||||||
"kind": "VirtualMachine",
|
"kind": "VirtualMachine",
|
||||||
@@ -551,7 +549,7 @@ def vm_template_datavolumetemplate():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def vm_template_name():
|
def created_vm_name():
|
||||||
return {
|
return {
|
||||||
"apiVersion": "kubevirt.io/v1",
|
"apiVersion": "kubevirt.io/v1",
|
||||||
"kind": "VirtualMachine",
|
"kind": "VirtualMachine",
|
||||||
@@ -573,7 +571,7 @@ def vm_template_name():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def vm_template_generate_name():
|
def created_vm_generate_name():
|
||||||
return {
|
return {
|
||||||
"apiVersion": "kubevirt.io/v1",
|
"apiVersion": "kubevirt.io/v1",
|
||||||
"kind": "VirtualMachine",
|
"kind": "VirtualMachine",
|
||||||
@@ -595,7 +593,7 @@ def vm_template_generate_name():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def vm_template_specs():
|
def created_vm_specs():
|
||||||
return {
|
return {
|
||||||
"apiVersion": "kubevirt.io/v1",
|
"apiVersion": "kubevirt.io/v1",
|
||||||
"kind": "VirtualMachine",
|
"kind": "VirtualMachine",
|
||||||
@@ -622,20 +620,20 @@ def vm_template_specs():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"params,rendered_template",
|
"params,expected",
|
||||||
[
|
[
|
||||||
("render_template_params", "vm_template"),
|
("create_vm_params", "created_vm"),
|
||||||
("render_template_params_annotations", "vm_template_annotations"),
|
("create_vm_params_annotations", "created_vm_annotations"),
|
||||||
("render_template_params_labels", "vm_template_labels"),
|
("create_vm_params_labels", "created_vm_labels"),
|
||||||
("render_template_params_instancetype", "vm_template_instancetype"),
|
("create_vm_params_instancetype", "created_vm_instancetype"),
|
||||||
("render_template_params_preference", "vm_template_preference"),
|
("create_vm_params_preference", "created_vm_preference"),
|
||||||
("render_template_params_datavolumetemplate", "vm_template_datavolumetemplate"),
|
("create_vm_params_datavolumetemplate", "created_vm_datavolumetemplate"),
|
||||||
("render_template_params_name", "vm_template_name"),
|
("create_vm_params_name", "created_vm_name"),
|
||||||
("render_template_params_generate_name", "vm_template_generate_name"),
|
("create_vm_params_generate_name", "created_vm_generate_name"),
|
||||||
("render_template_params_specs", "vm_template_specs"),
|
("create_vm_params_specs", "created_vm_specs"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_render_template(request, params, rendered_template):
|
def test_create_vm(request, params, expected):
|
||||||
assert kubevirt_vm.render_template(request.getfixturevalue(params)) == dump(
|
assert kubevirt_vm.create_vm(
|
||||||
request.getfixturevalue(rendered_template), sort_keys=False
|
request.getfixturevalue(params)
|
||||||
)
|
) == request.getfixturevalue(expected)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
# This file is required by ansible-test units
|
# This file is required by ansible-test units
|
||||||
jinja2
|
|
||||||
jsonpatch
|
jsonpatch
|
||||||
kubernetes>=28.1.0
|
kubernetes>=28.1.0
|
||||||
PyYAML>=3.11
|
PyYAML>=3.11
|
||||||
|
|||||||
Reference in New Issue
Block a user