|
| 1 | +### ProxmoxAPI Class. Examples. Advanced Concurrent Usage and Low-Level API Requests |
| 2 | + |
| 3 | + |
| 4 | +#### Example: Multiple Parallel requests with same API Instance (https in Async Mode) |
| 5 | +In this example, one API instances with reusing the same backend session are created and used in parallel for asynchronous operations: |
| 6 | +```python |
| 7 | +async def async_main(): |
| 8 | + register_backends("https") |
| 9 | + ext_api = ProxmoxAPI(backend_name="https", backend_type="async") |
| 10 | + async with ext_api as api: |
| 11 | + tasks = [] |
| 12 | + for _ in range(8): |
| 13 | + logger.info(len(tasks)) |
| 14 | + tasks.append(api.version.get(filter_keys="version")) |
| 15 | + logger.info("Waiting for results... of resources: %s", len(tasks)) |
| 16 | + results = await asyncio.gather(*tasks) |
| 17 | + logger.info(results) |
| 18 | +``` |
| 19 | +Results: |
| 20 | +```log |
| 21 | +DEBUG: Creating backend: https of type: async |
| 22 | +INFO: 0 |
| 23 | +DEBUG: NEW task_id: 4be8ee71-218d-43ff-b62a-6fb15827bfe0 |
| 24 | +INFO: 1 |
| 25 | +DEBUG: NEW task_id: a55c5863-5634-4a2f-a379-9eb73046caa0 |
| 26 | +INFO: 2 |
| 27 | +DEBUG: NEW task_id: 8399e980-a6d6-4225-902f-3bcd7a504b7c |
| 28 | +INFO: 3 |
| 29 | +DEBUG: NEW task_id: eea05041-1415-43ab-8c79-c1f48daed260 |
| 30 | +INFO: 4 |
| 31 | +DEBUG: NEW task_id: 42add8a3-e2c4-4206-ac83-ba694c3b9ed2 |
| 32 | +INFO: 5 |
| 33 | +DEBUG: NEW task_id: 4fd30c33-67c2-42f0-8150-67e27ca5ac45 |
| 34 | +INFO: 6 |
| 35 | +DEBUG: NEW task_id: 58e011e8-9eec-412b-b483-298487a002d8 |
| 36 | +INFO: 7 |
| 37 | +DEBUG: NEW task_id: 6957e51c-d8e4-4787-9adf-d5960a46f2b0 |
| 38 | +INFO: Waiting for results... of resources: 8 |
| 39 | +DEBUG: Formatted endpoint: /api2/json/version |
| 40 | +DEBUG: Formatted endpoint: /api2/json/version |
| 41 | +DEBUG: Formatted endpoint: /api2/json/version |
| 42 | +DEBUG: Formatted endpoint: /api2/json/version |
| 43 | +DEBUG: Formatted endpoint: /api2/json/version |
| 44 | +DEBUG: Formatted endpoint: /api2/json/version |
| 45 | +DEBUG: Formatted endpoint: /api2/json/version |
| 46 | +DEBUG: Formatted endpoint: /api2/json/version |
| 47 | +INFO: ['8.3.2', '8.3.2', '8.3.2', '8.3.2', '8.3.2', '8.3.2', '8.3.2', '8.3.2'] |
| 48 | +``` |
| 49 | + |
| 50 | +#### Example: Multiple Parallel with many API Instances (https in Async Mode) |
| 51 | +In this example, multiple API instances with reusing the same backend session are created and used in parallel for asynchronous operations: |
| 52 | +```python |
| 53 | +async def async_main(): |
| 54 | + register_backends("https") |
| 55 | + ext_api = ProxmoxAPI(backend_name="https", backend_type="async") |
| 56 | + async with ext_api as api: |
| 57 | + print(await api.version.get(filter_keys="version")) |
| 58 | + print(await api.cluster.ha.groups.get()) |
| 59 | + nodes = await api.nodes.get(filter_keys=["node", "status"]) |
| 60 | + if nodes: |
| 61 | + nodes = sorted([n.get("node") for n in nodes if n.get("status") == "online"]) |
| 62 | + tasks = [] |
| 63 | + backend = api.backend |
| 64 | + for node in nodes: |
| 65 | + new_api = ProxmoxAPI(backend=backend) |
| 66 | + tasks.append(new_api.nodes(node).status.get(filter_keys=["kversion", "cpuinfo", "memory.total", "uptime"])) |
| 67 | + results = await asyncio.gather(*tasks) |
| 68 | + for node, data in zip(nodes, results): |
| 69 | + print(data) |
| 70 | + |
| 71 | +asyncio.run(async_main()) |
| 72 | +``` |
| 73 | +This example demonstrates the ability to handle multiple API instances, enabling efficient parallel operations while reusing the same backend session. This approach is ideal for scenarios where data from multiple nodes needs to be fetched concurrently. |
| 74 | + |
| 75 | +#### Example of Low-Level Requests (Async) |
| 76 | + |
| 77 | +For more advanced use cases, you can perform low-level API requests directly: |
| 78 | + |
| 79 | +##### Solution 1: Prepare and Execute the Request Manually |
| 80 | + |
| 81 | +```python |
| 82 | +# Extract the request parameters for the desired endpoint |
| 83 | +params = api.version.get(get_request_param=True) |
| 84 | + |
| 85 | +# Perform the asynchronous request using the extracted parameters |
| 86 | +response = await api.async_request(**params) |
| 87 | + |
| 88 | +# Analyze the response to filter and extract specific data |
| 89 | +print(api._response_analyze(response, filter_keys="version")) |
| 90 | +``` |
| 91 | + |
| 92 | +##### Solution 2: Simplified Execution with Built-in API Method |
| 93 | +```python |
| 94 | +# Use the internal execution method directly with request parameters |
| 95 | +print(await api._async_execute(params=params, filter_keys="version")) |
| 96 | +``` |
| 97 | + |
| 98 | +#### Example of Low-Level Parallel Requests Using the Same API Instance (Async) |
| 99 | + |
| 100 | +Perform parallel requests for multiple nodes while reusing the same API instance: |
| 101 | + |
| 102 | +```python |
| 103 | +# Prepare tasks for parallel execution |
| 104 | +tasks = [] |
| 105 | +for node in nodes: |
| 106 | + print(node) # Log or display the current node |
| 107 | + params = api.nodes(node).status.get(get_request_param=True) |
| 108 | + |
| 109 | + # Add the task to the list using the internal execution method |
| 110 | + tasks.append( |
| 111 | + api._async_execute( |
| 112 | + params=params, |
| 113 | + filter_keys=["kversion", "cpuinfo", "memory.total", "uptime"], |
| 114 | + ) |
| 115 | + ) |
| 116 | + |
| 117 | +# Wait for all tasks to complete and collect results |
| 118 | +print("Waiting for results... Number of resources:", len(tasks)) |
| 119 | +results = await asyncio.gather(*tasks) |
| 120 | +``` |
| 121 | + |
| 122 | +#### Example of Parallel Requests Using the Queue of pre created API Instances in Thread Pool (Sync) |
| 123 | + |
| 124 | +```python |
| 125 | +import queue |
| 126 | +from concurrent.futures import ThreadPoolExecutor |
| 127 | + |
| 128 | +from ext_api.backends.registry import register_backends |
| 129 | +from ext_api.proxmox_api import ProxmoxAPI |
| 130 | +MAX_THREADS = 4 |
| 131 | + |
| 132 | +register_backends("https") |
| 133 | +clients = [ProxmoxAPI(backend_name="https") for _ in range(MAX_THREADS)] |
| 134 | +client_queue = queue.Queue() |
| 135 | + |
| 136 | +# Populate the queue with clients |
| 137 | +for c in clients: |
| 138 | + client_queue.put(c) |
| 139 | + |
| 140 | +def get_version(): |
| 141 | + client = client_queue.get() |
| 142 | + try: |
| 143 | + # Get an available client from the queue |
| 144 | + with client as api: |
| 145 | + response = api.version.get() |
| 146 | + return response |
| 147 | + finally: |
| 148 | + # Return the client to the queue |
| 149 | + client_queue.put(client) |
| 150 | + |
| 151 | +tasks = [] |
| 152 | +with ThreadPoolExecutor(max_workers=MAX_THREADS) as executor: |
| 153 | + for _ in range(8): |
| 154 | + print(f"Task submit: {len(tasks)}") |
| 155 | + tasks.append(executor.submit(get_version)) |
| 156 | +print("futures created") |
| 157 | +results = [task.result() for task in tasks] |
| 158 | +print(results) |
| 159 | +``` |
| 160 | +Results: |
| 161 | +```log |
| 162 | +DEBUG: Creating backend: https of type: sync |
| 163 | +DEBUG: Creating backend: https of type: sync |
| 164 | +DEBUG: Creating backend: https of type: sync |
| 165 | +DEBUG: Creating backend: https of type: sync |
| 166 | +DEBUG: Task submit: 0 |
| 167 | +DEBUG: Task submit: 1 |
| 168 | +DEBUG: Task submit: 2 |
| 169 | +DEBUG: Task submit: 3 |
| 170 | +DEBUG: Task submit: 4 |
| 171 | +DEBUG: Task submit: 5 |
| 172 | +DEBUG: Task submit: 6 |
| 173 | +DEBUG: Task submit: 7 |
| 174 | +DEBUG: NEW task_id: 6f8c5d7b-52ac-42db-bf1e-3e3314ac36a9 |
| 175 | +DEBUG: Formatted endpoint: /api2/json/version |
| 176 | +DEBUG: NEW task_id: eb986b66-77ef-41f5-9282-e627fea07407 |
| 177 | +DEBUG: NEW task_id: 61950227-42ff-4923-b16c-a565d8430394 |
| 178 | +DEBUG: NEW task_id: 45359f3c-9821-4ff4-99c1-1338b396cd48 |
| 179 | +DEBUG: Formatted endpoint: /api2/json/version |
| 180 | +DEBUG: Formatted endpoint: /api2/json/version |
| 181 | +DEBUG: Formatted endpoint: /api2/json/version |
| 182 | +DEBUG: NEW task_id: 838ab521-5687-4ae1-8c73-6bd7f9567b66 |
| 183 | +DEBUG: Formatted endpoint: /api2/json/version |
| 184 | +DEBUG: NEW task_id: 2332882c-1ab9-48da-98bf-c54295c37761 |
| 185 | +DEBUG: Formatted endpoint: /api2/json/version |
| 186 | +DEBUG: NEW task_id: 6d4770b3-0a04-4f4f-8b10-373112b1fae9 |
| 187 | +DEBUG: Formatted endpoint: /api2/json/version |
| 188 | +DEBUG: NEW task_id: d79ebba9-581e-46a0-a076-b607ae4012e4 |
| 189 | +DEBUG: Formatted endpoint: /api2/json/version |
| 190 | +futures created |
| 191 | +['8.3.2', '8.3.2', '8.3.2', '8.3.2', '8.3.2', '8.3.2', '8.3.2', '8.3.2'] |
| 192 | +``` |
| 193 | + |
| 194 | +These examples provide flexibility for advanced API usage, allowing you to control request preparation and execution explicitly, even in parallel scenarios. |
0 commit comments