Skip to content

Commit dbc96a6

Browse files
committed
controller_async
1 parent da5ee7c commit dbc96a6

File tree

7 files changed

+269
-67
lines changed

7 files changed

+269
-67
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import logging
2+
import tomllib
3+
from pathlib import Path
4+
import asyncio
5+
6+
from cluster_tasks.configure_logging import config_logger
7+
from cluster_tasks.tasks.node_tasks_async import NodeTasksAsync
8+
from config.config import ConfigLoader
9+
from ext_api.backends.registry import register_backends
10+
from ext_api.proxmox_api import ProxmoxAPI
11+
from loader_scene import ScenarioFactory
12+
13+
14+
logger = logging.getLogger("CT")
15+
config_logger(logger)
16+
17+
18+
async def main():
19+
config_file = Path(__file__).parent / "scenarios_configs.yaml"
20+
scenarios_config = ConfigLoader(file_path=config_file).settings.copy()
21+
# Iterate over the scenarios and run them asynchronously
22+
logger.debug(f"Scenarios config: {scenarios_config}")
23+
24+
register_backends(["https"])
25+
26+
# Change the API backend to async
27+
ext_api = ProxmoxAPI(
28+
backend_name="https", backend_type="async"
29+
) # Assuming you have async support in ProxmoxAPI
30+
31+
# Create an instance of the async NodeTasks class
32+
33+
# Run through scenarios
34+
async with ext_api as api:
35+
node_tasks = NodeTasksAsync(api=api) # Pass the api instance to NodeTasksAsync
36+
for k, v in scenarios_config.get("Scenarios").items():
37+
scenario_file = v.get("file")
38+
config = v.get("config")
39+
40+
# Create scenario instance using the factory
41+
scenario = ScenarioFactory.create_scenario(scenario_file, config, "async")
42+
43+
# Run the scenario asynchronously
44+
await scenario.run(node_tasks) # Assuming `run` is now an async method
45+
46+
47+
if __name__ == "__main__":
48+
asyncio.run(main()) # Start the event loop and run the main function asynchronously
Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from pathlib import Path
44

55
from cluster_tasks.configure_logging import config_logger
6+
from cluster_tasks.tasks.node_tasks_sync import NodeTasksSync
67
from config.config import ConfigLoader
78
from ext_api.backends.registry import register_backends
89
from ext_api.proxmox_api import ProxmoxAPI
@@ -20,16 +21,18 @@ def main():
2021
logger.debug(f"Scenarios config: {scenarios_config}")
2122

2223
register_backends(["https"])
23-
api = ProxmoxAPI(backend_name="https", backend_type="sync")
24-
for k, v in scenarios_config.get("Scenarios").items():
25-
scenario_file = v.get("file")
26-
config = v.get("config")
27-
28-
# Create scenario instance using the factory
29-
scenario = ScenarioFactory.create_scenario(scenario_file, api, config)
30-
31-
# Run the scenario
32-
scenario.run()
24+
ext_api = ProxmoxAPI(backend_name="https", backend_type="sync")
25+
with ext_api as api:
26+
node_tasks = NodeTasksSync(api=api) # Pass the api instance to NodeTasksAsync
27+
for k, v in scenarios_config.get("Scenarios").items():
28+
scenario_file = v.get("file")
29+
config = v.get("config")
30+
31+
# Create scenario instance using the factory
32+
scenario = ScenarioFactory.create_scenario(scenario_file, config)
33+
34+
# Run the scenario
35+
scenario.run(node_tasks)
3336

3437

3538
if __name__ == "__main__":

src/cluster_tasks/loader_scene.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
class ScenarioFactory:
77
base_module = "scenarios"
8-
prefix_file = "scenario_"
98
prefix_class = "Scenario"
9+
suffix_file = {"sync": "_sync", "async": "_async"}
1010

1111
@staticmethod
1212
def convert_to_class_name(file_name: str) -> str:
@@ -21,14 +21,18 @@ def load_class(cls, module_name: str, class_name: str):
2121
return getattr(module, class_name)
2222

2323
@classmethod
24-
def create_scenario(cls, scenario_file: str, api: ProxmoxAPI, config: dict = None):
24+
def create_scenario(
25+
cls, scenario_file: str, config: dict = None, run_type: str = "sync"
26+
):
2527
# Dynamically load the scenario class based on the name
26-
scenario_file = f"{cls.prefix_file}{scenario_file}"
28+
scenario_file = f"{scenario_file}{cls.suffix_file.get(run_type)}"
2729
module_name = f"{cls.base_module}.{scenario_file}"
2830
scenario_name = cls.convert_to_class_name(scenario_file)
2931

30-
scenario_class = cls.load_class(module_name, scenario_name)
32+
scenario_class = cls.load_class(
33+
module_name, f"{cls.prefix_class}{scenario_name}"
34+
)
3135

32-
scenario_instance = scenario_class(api)
36+
scenario_instance = scenario_class()
3337
scenario_instance.configure(config)
3438
return scenario_instance
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import logging
2+
import asyncio
3+
4+
from cluster_tasks.scenarios.scenario_base import ScenarioBase
5+
from cluster_tasks.tasks.node_tasks_async import (
6+
NodeTasksAsync,
7+
) # Assuming there's an async version of NodeTasks
8+
9+
logger = logging.getLogger("CT.{__name__}")
10+
11+
12+
class ScenarioCloneTemplateVmAsync(ScenarioBase):
13+
"""
14+
Scenario for cloning a VM from a template in a Proxmox environment.
15+
16+
This scenario checks if the VM with the target ID already exists. If it does, the VM is deleted
17+
before cloning the template to the new VM ID. This class interacts with the Proxmox API to
18+
manage VM operations such as checking VM status, deleting an existing VM, and cloning a VM.
19+
20+
Attributes:
21+
node (str): The Proxmox node where the VM resides.
22+
vmid (int): The ID of the VM to clone.
23+
newid (str): The ID of the new VM being created from the template.
24+
name (str): The name to assign to the new VM.
25+
full (int): Flag indicating whether to clone the full VM or just the template.
26+
"""
27+
28+
def __init__(self):
29+
"""
30+
Initializes the ScenarioCloneTemplateVmAsync class.
31+
32+
This constructor calls the base class constructor to set up the necessary
33+
components for the scenario.
34+
"""
35+
super().__init__()
36+
37+
def configure(self, config):
38+
"""
39+
Configures the scenario with the provided settings.
40+
41+
This method reads configuration values and sets up the necessary attributes for
42+
the scenario to run.
43+
44+
Args:
45+
config (dict): The configuration dictionary containing the necessary settings
46+
for the scenario, including node, vmid, newid, name, and full.
47+
48+
Attributes:
49+
node (str): The Proxmox node where the VM resides.
50+
vmid (int): The ID of the VM to clone.
51+
newid (str): The ID of the new VM to create.
52+
name (str): The name for the new VM.
53+
full (int): Flag indicating whether to clone the full VM or just the template.
54+
"""
55+
self.node = config.get("node")
56+
self.vmid = int(config.get("vmid", 0))
57+
self.newid = config.get("newid")
58+
self.name = config.get("name")
59+
self.full = int(config.get("full", True))
60+
61+
async def run(self, node_tasks: NodeTasksAsync, *args, **kwargs):
62+
"""
63+
Runs the scenario of cloning a VM from a template asynchronously.
64+
65+
This method checks if the new VM already exists, deletes it if it does, and then
66+
proceeds to clone the VM from the template. All operations are performed asynchronously.
67+
68+
Args:
69+
node_tasks (NodeTasksAsync): The object responsible for performing the async operations
70+
like checking VM status, deleting a VM, and cloning a VM.
71+
*args: Additional positional arguments.
72+
**kwargs: Additional keyword arguments.
73+
74+
Raises:
75+
Exception: If the VM already exists and deletion fails, or if cloning fails.
76+
"""
77+
print(f"Running Scenario Template VM Clone: {self.scenario_name}")
78+
# Perform the specific API logic for this scenario
79+
try:
80+
# Open a connection session of the Proxmox API
81+
# Check if the VM already exists asynchronously
82+
present = await node_tasks.vm_status(self.node, self.newid)
83+
if present:
84+
# If VM already exists, delete it asynchronously
85+
logger.info(f"VM {self.newid} already exists - Deleting...")
86+
is_deleted = await node_tasks.vm_delete(self.node, self.newid)
87+
if is_deleted:
88+
logger.info(f"VM {self.newid} deleted successfully")
89+
else:
90+
raise Exception(f"Failed to delete VM {self.newid}")
91+
# Clone the VM from the template asynchronously
92+
data = {"newid": int(self.newid), "name": self.name, "full": self.full}
93+
is_created = await node_tasks.vm_clone(self.node, self.vmid, data)
94+
if is_created:
95+
logger.info(f"VM {self.newid} cloned successfully")
96+
else:
97+
raise Exception(f"Failed to clone VM {self.newid}")
98+
except Exception as e:
99+
logger.error(f"Failed to run scenario: {e}")
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import logging
2+
3+
from cluster_tasks.scenarios.scenario_base import ScenarioBase
4+
from cluster_tasks.tasks.node_tasks_sync import NodeTasksSync
5+
6+
logger = logging.getLogger("CT.{__name__}")
7+
8+
9+
class ScenarioCloneTemplateVmSync(ScenarioBase):
10+
"""
11+
Scenario for cloning a VM from a template in a Proxmox environment.
12+
13+
This scenario checks if the VM with the target ID already exists. If it does, the VM is deleted
14+
before cloning the template to the new VM ID. This class interacts with the Proxmox API to
15+
manage VM operations such as checking VM status, deleting an existing VM, and cloning a VM.
16+
17+
Attributes:
18+
node (str): The Proxmox node where the VM resides.
19+
vmid (int): The ID of the VM to clone.
20+
newid (str): The ID of the new VM being created from the template.
21+
name (str): The name to assign to the new VM.
22+
full (int): Flag indicating whether to clone the full VM or just the template.
23+
"""
24+
25+
def __init__(self):
26+
"""
27+
Initializes the ScenarioCloneTemplateVm class.
28+
29+
This constructor calls the base class constructor to set up the necessary
30+
components for the scenario.
31+
"""
32+
super().__init__()
33+
34+
def configure(self, config):
35+
"""
36+
Configures the scenario with the provided settings.
37+
38+
This method reads configuration values and sets up the necessary attributes for
39+
the scenario to run.
40+
41+
Args:
42+
config (dict): The configuration dictionary containing the necessary settings
43+
for the scenario, including node, vmid, newid, name, and full.
44+
45+
Attributes:
46+
node (str): The Proxmox node where the VM resides.
47+
vmid (int): The ID of the VM to clone.
48+
newid (str): The ID of the new VM to create.
49+
name (str): The name for the new VM.
50+
full (int): Flag indicating whether to clone the full VM or just the template.
51+
"""
52+
self.node = config.get("node")
53+
self.vmid = int(config.get("vmid", 0))
54+
self.newid = config.get("newid")
55+
self.name = config.get("name")
56+
self.full = int(config.get("full", True))
57+
58+
def run(self, node_tasks: NodeTasksSync, *args, **kwargs):
59+
"""
60+
Runs the scenario of cloning a VM from a template.
61+
62+
This method checks if the new VM already exists, deletes it if it does, and then
63+
proceeds to clone the VM from the template.
64+
65+
Args:
66+
node_tasks (NodeTasksSync): The object responsible for performing the sync operations
67+
like checking VM status, deleting a VM, and cloning a VM.
68+
*args: Additional positional arguments.
69+
**kwargs: Additional keyword arguments.
70+
71+
Raises:
72+
Exception: If the VM already exists and deletion fails, or if cloning fails.
73+
"""
74+
print(f"Running Scenario Template VM Clone: {self.scenario_name}")
75+
# Perform the specific API logic for this scenario
76+
try:
77+
# Open a connection session of the Proxmox API
78+
# Check if the VM already exists
79+
present = node_tasks.vm_status(self.node, self.newid)
80+
if present:
81+
# If VM already exists, delete it
82+
logger.info(f"VM {self.newid} already exists - Deleting...")
83+
is_deleted = node_tasks.vm_delete(self.node, self.newid)
84+
if is_deleted:
85+
logger.info(f"VM {self.newid} deleted successfully")
86+
else:
87+
raise Exception(f"Failed to delete VM {self.newid}")
88+
# Clone the VM from the template
89+
data = {"newid": int(self.newid), "name": self.name, "full": self.full}
90+
is_created = node_tasks.vm_clone(self.node, self.vmid, data)
91+
if is_created:
92+
logger.info(f"VM {self.newid} cloned successfully")
93+
else:
94+
raise Exception(f"Failed to clone VM {self.newid}")
95+
except Exception as e:
96+
logger.error(f"Failed to run scenario: {e}")

src/cluster_tasks/scenarios/scenario_base.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
import logging
22
from abc import ABC, abstractmethod
33

4+
from cluster_tasks.tasks.node_tasks_base import NodeTasksBase
45
from ext_api.proxmox_api import ProxmoxAPI
56
from cluster_tasks.tasks.node_tasks_sync import NodeTasksSync
67

78
logger = logging.getLogger("CT.{__name__}")
89

910

1011
class ScenarioBase(ABC):
11-
def __init__(self, api: ProxmoxAPI):
12-
self.name = self.__class__.__name__
13-
self.api: ProxmoxAPI = api
14-
self.node_tasks = NodeTasksSync(api)
12+
def __init__(self):
13+
self.scenario_name = self.__class__.__name__
1514

1615
@abstractmethod
17-
def run(self):
16+
def run(self, node_tasks: NodeTasksBase, *args, **kwargs):
1817
"""Method to execute the scenario"""
1918
...
2019

src/cluster_tasks/scenarios/scenario_clone_template_vm.py

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)