Merge pull request #124 from 0xFelix/run-strategy

feat(kubevirt_vm): Add support for RunStrategy
This commit is contained in:
kubevirt-bot
2024-07-16 13:08:55 +02:00
committed by GitHub
3 changed files with 200 additions and 13 deletions

View File

@@ -0,0 +1,42 @@
---
- name: Playbook creating a virtual machine with multus network
hosts: localhost
tasks:
- name: Create VM
kubevirt.core.kubevirt_vm:
state: present
name: testvm
namespace: default
labels:
app: test
instancetype:
name: u1.medium
preference:
name: fedora
run_strategy: Manual
spec:
domain:
devices:
interfaces:
- name: default
masquerade: {}
- name: bridge-network
bridge: {}
networks:
- name: default
pod: {}
- name: bridge-network
multus:
networkName: kindexgw
volumes:
- containerDisk:
image: quay.io/containerdisks/fedora:latest
name: containerdisk
- cloudInitNoCloud:
userData: |-
#cloud-config
# The default username is: fedora
ssh_authorized_keys:
- ssh-ed25519 AAAA...
name: cloudinit
wait: true

View File

@@ -61,8 +61,21 @@ options:
running:
description:
- Specify whether the C(VirtualMachine) should be running or not.
- Mutually exclusive with O(run_strategy).
- Defaults to O(running=yes) when O(running) and O(run_strategy) are not set.
type: bool
default: yes
run_strategy:
description:
- Specify the C(RunStrategy) of the C(VirtualMachine).
- Mutually exclusive with O(running).
type: str
choices:
- Always
- Halted
- Manual
- RerunOnFailure
- Once
version_added: 2.0.0
instancetype:
description:
- Specify the C(Instancetype) matcher of the C(VirtualMachine).
@@ -280,6 +293,13 @@ from ansible_collections.kubernetes.core.plugins.module_utils.k8s.exceptions imp
CoreException,
)
WAIT_CONDITION_READY = {"type": "Ready", "status": True}
WAIT_CONDITION_VMI_NOT_EXISTS = {
"type": "Ready",
"status": False,
"reason": "VMINotExists",
}
def create_vm(params: Dict) -> Dict:
"""
@@ -292,7 +312,6 @@ def create_vm(params: Dict) -> Dict:
"namespace": params["namespace"],
},
"spec": {
"running": params["running"],
"template": {"spec": {"domain": {"devices": {}}}},
},
}
@@ -312,6 +331,12 @@ def create_vm(params: Dict) -> Dict:
if template_metadata:
vm["spec"]["template"]["metadata"] = template_metadata
if (run_strategy := params.get("run_strategy")) is not None:
vm["spec"]["runStrategy"] = run_strategy
else:
vm["spec"]["running"] = (
running if (running := params.get("running")) is not None else True
)
if (instancetype := params.get("instancetype")) is not None:
vm["spec"]["instancetype"] = instancetype
if (preference := params.get("preference")) is not None:
@@ -324,6 +349,21 @@ def create_vm(params: Dict) -> Dict:
return vm
def set_wait_condition(module: AnsibleK8SModule) -> None:
"""
set_wait_condition sets the wait_condition to allow waiting for the ready
state of the VirtualMachine depending on the module parameters running
and run_strategy.
"""
if (
module.params["running"] is False
or (run_strategy := module.params["run_strategy"]) == "Halted"
):
module.params["wait_condition"] = WAIT_CONDITION_VMI_NOT_EXISTS
elif run_strategy != "Manual":
module.params["wait_condition"] = WAIT_CONDITION_READY
def arg_spec() -> Dict:
"""
arg_spec defines the argument spec of this module.
@@ -335,7 +375,10 @@ def arg_spec() -> Dict:
"namespace": {"required": True},
"annotations": {"type": "dict"},
"labels": {"type": "dict"},
"running": {"type": "bool", "default": True},
"running": {"type": "bool"},
"run_strategy": {
"choices": ["Always", "Halted", "Manual", "RerunOnFailure", "Once"]
},
"instancetype": {"type": "dict"},
"preference": {"type": "dict"},
"data_volume_templates": {"type": "list", "elements": "dict"},
@@ -376,6 +419,7 @@ def main() -> None:
argument_spec=arg_spec(),
mutually_exclusive=[
("name", "generate_name"),
("running", "run_strategy"),
],
required_one_of=[
("name", "generate_name"),
@@ -387,14 +431,7 @@ def main() -> None:
module.params["resource_definition"] = create_vm(module.params)
# Set wait_condition to allow waiting for the ready state of the VirtualMachine
if module.params["running"]:
module.params["wait_condition"] = {"type": "Ready", "status": True}
else:
module.params["wait_condition"] = {
"type": "Ready",
"status": False,
"reason": "VMINotExists",
}
set_wait_condition(module)
try:
runner.run_module(module)

View File

@@ -101,11 +101,27 @@ VM_DEFINITION_STOPPED = {
},
}
VM_DEFINITION_HALTED = {
"apiVersion": "kubevirt.io/v1",
"kind": "VirtualMachine",
"metadata": {
"name": "testvm",
"namespace": "default",
},
"spec": {
"runStrategy": "Halted",
"template": {
"spec": {
"domain": {"devices": {}},
},
},
},
}
MODULE_PARAMS_DEFAULT = {
"api_version": "kubevirt.io/v1",
"annotations": None,
"labels": None,
"running": True,
"instancetype": None,
"preference": None,
"data_volume_templates": None,
@@ -174,6 +190,12 @@ MODULE_PARAMS_STOPPED = MODULE_PARAMS_DEFAULT | {
"running": False,
}
MODULE_PARAMS_HALTED = MODULE_PARAMS_DEFAULT | {
"name": "testvm",
"namespace": "default",
"run_strategy": "Halted",
}
MODULE_PARAMS_DELETE = MODULE_PARAMS_DEFAULT | {
"name": "testvm",
"namespace": "default",
@@ -183,24 +205,37 @@ MODULE_PARAMS_DELETE = MODULE_PARAMS_DEFAULT | {
K8S_MODULE_PARAMS_CREATE = MODULE_PARAMS_CREATE | {
"generate_name": None,
"running": None,
"run_strategy": None,
"resource_definition": VM_DEFINITION_CREATE,
"wait_condition": {"type": "Ready", "status": True},
}
K8S_MODULE_PARAMS_RUNNING = MODULE_PARAMS_RUNNING | {
"generate_name": None,
"run_strategy": None,
"resource_definition": VM_DEFINITION_RUNNING,
"wait_condition": {"type": "Ready", "status": True},
}
K8S_MODULE_PARAMS_STOPPED = MODULE_PARAMS_STOPPED | {
"generate_name": None,
"run_strategy": None,
"resource_definition": VM_DEFINITION_STOPPED,
"wait_condition": {"type": "Ready", "status": False, "reason": "VMINotExists"},
}
K8S_MODULE_PARAMS_HALTED = MODULE_PARAMS_HALTED | {
"generate_name": None,
"running": None,
"resource_definition": VM_DEFINITION_HALTED,
"wait_condition": {"type": "Ready", "status": False, "reason": "VMINotExists"},
}
K8S_MODULE_PARAMS_DELETE = MODULE_PARAMS_DELETE | {
"generate_name": None,
"running": None,
"run_strategy": None,
"resource_definition": VM_DEFINITION_RUNNING,
"wait_condition": {"type": "Ready", "status": True},
}
@@ -227,6 +262,12 @@ K8S_MODULE_PARAMS_DELETE = MODULE_PARAMS_DELETE | {
VM_DEFINITION_STOPPED,
"update",
),
(
MODULE_PARAMS_HALTED,
K8S_MODULE_PARAMS_HALTED,
VM_DEFINITION_HALTED,
"update",
),
(
MODULE_PARAMS_DELETE,
K8S_MODULE_PARAMS_DELETE,
@@ -262,10 +303,15 @@ def test_module(mocker, module_params, k8s_module_params, vm_definition, method)
CREATE_VM_PARAMS = {
"api_version": "kubevirt.io/v1",
"running": True,
"namespace": "default",
}
CREATE_VM_PARAMS_RUN_STRATEGY = {
"api_version": "kubevirt.io/v1",
"namespace": "default",
"run_strategy": "Manual",
}
CREATE_VM_PARAMS_ANNOTATIONS = CREATE_VM_PARAMS | {
"annotations": {"test": "test"},
}
@@ -341,6 +387,24 @@ CREATED_VM = {
},
}
CREATED_VM_RUN_STRATEGY = {
"apiVersion": "kubevirt.io/v1",
"kind": "VirtualMachine",
"metadata": {
"namespace": "default",
},
"spec": {
"runStrategy": "Manual",
"template": {
"spec": {
"domain": {
"devices": {},
},
},
},
},
}
CREATED_VM_LABELS = {
"apiVersion": "kubevirt.io/v1",
"kind": "VirtualMachine",
@@ -528,6 +592,7 @@ CREATED_VM_SPECS = {
"params,expected",
[
(CREATE_VM_PARAMS, CREATED_VM),
(CREATE_VM_PARAMS_RUN_STRATEGY, CREATED_VM_RUN_STRATEGY),
(CREATE_VM_PARAMS_ANNOTATIONS, CREATED_VM_ANNOTATIONS),
(CREATE_VM_PARAMS_LABELS, CREATED_VM_LABELS),
(CREATE_VM_PARAMS_INSTANCETYPE, CREATED_VM_INSTANCETYPE),
@@ -540,3 +605,46 @@ CREATED_VM_SPECS = {
)
def test_create_vm(params, expected):
assert kubevirt_vm.create_vm(params) == expected
@pytest.mark.parametrize(
"params,expected",
[
({"running": None, "run_strategy": "Manual"}, {}),
(
{"running": None, "run_strategy": None},
{"wait_condition": kubevirt_vm.WAIT_CONDITION_READY},
),
(
{"running": True, "run_strategy": None},
{"wait_condition": kubevirt_vm.WAIT_CONDITION_READY},
),
(
{"running": None, "run_strategy": "Always"},
{"wait_condition": kubevirt_vm.WAIT_CONDITION_READY},
),
(
{"running": None, "run_strategy": "RerunOnFailure"},
{"wait_condition": kubevirt_vm.WAIT_CONDITION_READY},
),
(
{"running": None, "run_strategy": "Once"},
{"wait_condition": kubevirt_vm.WAIT_CONDITION_READY},
),
(
{"running": False, "run_strategy": None},
{"wait_condition": kubevirt_vm.WAIT_CONDITION_VMI_NOT_EXISTS},
),
(
{"running": None, "run_strategy": "Halted"},
{"wait_condition": kubevirt_vm.WAIT_CONDITION_VMI_NOT_EXISTS},
),
],
)
def test_set_wait_condition(mocker, params, expected):
module = mocker.Mock()
module.params = params
kubevirt_vm.set_wait_condition(module)
assert module.params == params | expected