mirror of
https://github.com/kubevirt/kubevirt.core.git
synced 2026-05-06 21:32:40 +00:00
Merge pull request #124 from 0xFelix/run-strategy
feat(kubevirt_vm): Add support for RunStrategy
This commit is contained in:
42
examples/play-create-run-strategy.yml
Normal file
42
examples/play-create-run-strategy.yml
Normal 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
|
||||||
@@ -61,8 +61,21 @@ options:
|
|||||||
running:
|
running:
|
||||||
description:
|
description:
|
||||||
- Specify whether the C(VirtualMachine) should be running or not.
|
- 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
|
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:
|
instancetype:
|
||||||
description:
|
description:
|
||||||
- Specify the C(Instancetype) matcher of the C(VirtualMachine).
|
- 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,
|
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:
|
def create_vm(params: Dict) -> Dict:
|
||||||
"""
|
"""
|
||||||
@@ -292,7 +312,6 @@ def create_vm(params: Dict) -> Dict:
|
|||||||
"namespace": params["namespace"],
|
"namespace": params["namespace"],
|
||||||
},
|
},
|
||||||
"spec": {
|
"spec": {
|
||||||
"running": params["running"],
|
|
||||||
"template": {"spec": {"domain": {"devices": {}}}},
|
"template": {"spec": {"domain": {"devices": {}}}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -312,6 +331,12 @@ def create_vm(params: Dict) -> Dict:
|
|||||||
if template_metadata:
|
if template_metadata:
|
||||||
vm["spec"]["template"]["metadata"] = 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:
|
if (instancetype := params.get("instancetype")) is not None:
|
||||||
vm["spec"]["instancetype"] = instancetype
|
vm["spec"]["instancetype"] = instancetype
|
||||||
if (preference := params.get("preference")) is not None:
|
if (preference := params.get("preference")) is not None:
|
||||||
@@ -324,6 +349,21 @@ def create_vm(params: Dict) -> Dict:
|
|||||||
return vm
|
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:
|
def arg_spec() -> Dict:
|
||||||
"""
|
"""
|
||||||
arg_spec defines the argument spec of this module.
|
arg_spec defines the argument spec of this module.
|
||||||
@@ -335,7 +375,10 @@ def arg_spec() -> Dict:
|
|||||||
"namespace": {"required": True},
|
"namespace": {"required": True},
|
||||||
"annotations": {"type": "dict"},
|
"annotations": {"type": "dict"},
|
||||||
"labels": {"type": "dict"},
|
"labels": {"type": "dict"},
|
||||||
"running": {"type": "bool", "default": True},
|
"running": {"type": "bool"},
|
||||||
|
"run_strategy": {
|
||||||
|
"choices": ["Always", "Halted", "Manual", "RerunOnFailure", "Once"]
|
||||||
|
},
|
||||||
"instancetype": {"type": "dict"},
|
"instancetype": {"type": "dict"},
|
||||||
"preference": {"type": "dict"},
|
"preference": {"type": "dict"},
|
||||||
"data_volume_templates": {"type": "list", "elements": "dict"},
|
"data_volume_templates": {"type": "list", "elements": "dict"},
|
||||||
@@ -376,6 +419,7 @@ def main() -> None:
|
|||||||
argument_spec=arg_spec(),
|
argument_spec=arg_spec(),
|
||||||
mutually_exclusive=[
|
mutually_exclusive=[
|
||||||
("name", "generate_name"),
|
("name", "generate_name"),
|
||||||
|
("running", "run_strategy"),
|
||||||
],
|
],
|
||||||
required_one_of=[
|
required_one_of=[
|
||||||
("name", "generate_name"),
|
("name", "generate_name"),
|
||||||
@@ -387,14 +431,7 @@ def main() -> None:
|
|||||||
module.params["resource_definition"] = create_vm(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"]:
|
set_wait_condition(module)
|
||||||
module.params["wait_condition"] = {"type": "Ready", "status": True}
|
|
||||||
else:
|
|
||||||
module.params["wait_condition"] = {
|
|
||||||
"type": "Ready",
|
|
||||||
"status": False,
|
|
||||||
"reason": "VMINotExists",
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
runner.run_module(module)
|
runner.run_module(module)
|
||||||
|
|||||||
@@ -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 = {
|
MODULE_PARAMS_DEFAULT = {
|
||||||
"api_version": "kubevirt.io/v1",
|
"api_version": "kubevirt.io/v1",
|
||||||
"annotations": None,
|
"annotations": None,
|
||||||
"labels": None,
|
"labels": None,
|
||||||
"running": True,
|
|
||||||
"instancetype": None,
|
"instancetype": None,
|
||||||
"preference": None,
|
"preference": None,
|
||||||
"data_volume_templates": None,
|
"data_volume_templates": None,
|
||||||
@@ -174,6 +190,12 @@ MODULE_PARAMS_STOPPED = MODULE_PARAMS_DEFAULT | {
|
|||||||
"running": False,
|
"running": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MODULE_PARAMS_HALTED = MODULE_PARAMS_DEFAULT | {
|
||||||
|
"name": "testvm",
|
||||||
|
"namespace": "default",
|
||||||
|
"run_strategy": "Halted",
|
||||||
|
}
|
||||||
|
|
||||||
MODULE_PARAMS_DELETE = MODULE_PARAMS_DEFAULT | {
|
MODULE_PARAMS_DELETE = MODULE_PARAMS_DEFAULT | {
|
||||||
"name": "testvm",
|
"name": "testvm",
|
||||||
"namespace": "default",
|
"namespace": "default",
|
||||||
@@ -183,24 +205,37 @@ MODULE_PARAMS_DELETE = MODULE_PARAMS_DEFAULT | {
|
|||||||
|
|
||||||
K8S_MODULE_PARAMS_CREATE = MODULE_PARAMS_CREATE | {
|
K8S_MODULE_PARAMS_CREATE = MODULE_PARAMS_CREATE | {
|
||||||
"generate_name": None,
|
"generate_name": None,
|
||||||
|
"running": None,
|
||||||
|
"run_strategy": None,
|
||||||
"resource_definition": VM_DEFINITION_CREATE,
|
"resource_definition": VM_DEFINITION_CREATE,
|
||||||
"wait_condition": {"type": "Ready", "status": True},
|
"wait_condition": {"type": "Ready", "status": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
K8S_MODULE_PARAMS_RUNNING = MODULE_PARAMS_RUNNING | {
|
K8S_MODULE_PARAMS_RUNNING = MODULE_PARAMS_RUNNING | {
|
||||||
"generate_name": None,
|
"generate_name": None,
|
||||||
|
"run_strategy": None,
|
||||||
"resource_definition": VM_DEFINITION_RUNNING,
|
"resource_definition": VM_DEFINITION_RUNNING,
|
||||||
"wait_condition": {"type": "Ready", "status": True},
|
"wait_condition": {"type": "Ready", "status": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
K8S_MODULE_PARAMS_STOPPED = MODULE_PARAMS_STOPPED | {
|
K8S_MODULE_PARAMS_STOPPED = MODULE_PARAMS_STOPPED | {
|
||||||
"generate_name": None,
|
"generate_name": None,
|
||||||
|
"run_strategy": None,
|
||||||
"resource_definition": VM_DEFINITION_STOPPED,
|
"resource_definition": VM_DEFINITION_STOPPED,
|
||||||
"wait_condition": {"type": "Ready", "status": False, "reason": "VMINotExists"},
|
"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 | {
|
K8S_MODULE_PARAMS_DELETE = MODULE_PARAMS_DELETE | {
|
||||||
"generate_name": None,
|
"generate_name": None,
|
||||||
|
"running": None,
|
||||||
|
"run_strategy": None,
|
||||||
"resource_definition": VM_DEFINITION_RUNNING,
|
"resource_definition": VM_DEFINITION_RUNNING,
|
||||||
"wait_condition": {"type": "Ready", "status": True},
|
"wait_condition": {"type": "Ready", "status": True},
|
||||||
}
|
}
|
||||||
@@ -227,6 +262,12 @@ K8S_MODULE_PARAMS_DELETE = MODULE_PARAMS_DELETE | {
|
|||||||
VM_DEFINITION_STOPPED,
|
VM_DEFINITION_STOPPED,
|
||||||
"update",
|
"update",
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
MODULE_PARAMS_HALTED,
|
||||||
|
K8S_MODULE_PARAMS_HALTED,
|
||||||
|
VM_DEFINITION_HALTED,
|
||||||
|
"update",
|
||||||
|
),
|
||||||
(
|
(
|
||||||
MODULE_PARAMS_DELETE,
|
MODULE_PARAMS_DELETE,
|
||||||
K8S_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 = {
|
CREATE_VM_PARAMS = {
|
||||||
"api_version": "kubevirt.io/v1",
|
"api_version": "kubevirt.io/v1",
|
||||||
"running": True,
|
|
||||||
"namespace": "default",
|
"namespace": "default",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CREATE_VM_PARAMS_RUN_STRATEGY = {
|
||||||
|
"api_version": "kubevirt.io/v1",
|
||||||
|
"namespace": "default",
|
||||||
|
"run_strategy": "Manual",
|
||||||
|
}
|
||||||
|
|
||||||
CREATE_VM_PARAMS_ANNOTATIONS = CREATE_VM_PARAMS | {
|
CREATE_VM_PARAMS_ANNOTATIONS = CREATE_VM_PARAMS | {
|
||||||
"annotations": {"test": "test"},
|
"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 = {
|
CREATED_VM_LABELS = {
|
||||||
"apiVersion": "kubevirt.io/v1",
|
"apiVersion": "kubevirt.io/v1",
|
||||||
"kind": "VirtualMachine",
|
"kind": "VirtualMachine",
|
||||||
@@ -528,6 +592,7 @@ CREATED_VM_SPECS = {
|
|||||||
"params,expected",
|
"params,expected",
|
||||||
[
|
[
|
||||||
(CREATE_VM_PARAMS, CREATED_VM),
|
(CREATE_VM_PARAMS, CREATED_VM),
|
||||||
|
(CREATE_VM_PARAMS_RUN_STRATEGY, CREATED_VM_RUN_STRATEGY),
|
||||||
(CREATE_VM_PARAMS_ANNOTATIONS, CREATED_VM_ANNOTATIONS),
|
(CREATE_VM_PARAMS_ANNOTATIONS, CREATED_VM_ANNOTATIONS),
|
||||||
(CREATE_VM_PARAMS_LABELS, CREATED_VM_LABELS),
|
(CREATE_VM_PARAMS_LABELS, CREATED_VM_LABELS),
|
||||||
(CREATE_VM_PARAMS_INSTANCETYPE, CREATED_VM_INSTANCETYPE),
|
(CREATE_VM_PARAMS_INSTANCETYPE, CREATED_VM_INSTANCETYPE),
|
||||||
@@ -540,3 +605,46 @@ CREATED_VM_SPECS = {
|
|||||||
)
|
)
|
||||||
def test_create_vm(params, expected):
|
def test_create_vm(params, expected):
|
||||||
assert kubevirt_vm.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
|
||||||
|
|||||||
Reference in New Issue
Block a user