From e0331e83e1067bbe0c5ae19341088e2266506769 Mon Sep 17 00:00:00 2001 From: gyptazy Date: Wed, 24 Dec 2025 08:37:15 +0100 Subject: [PATCH] Adjust the integration of node resource reservation - Renamed to set_node_resource_reservation - Immediately apply the values as maxmem for a node - Avoid recalculating percentage values - Simplified code - Adjusted debug logging --- proxlb/models/calculations.py | 4 +- proxlb/models/nodes.py | 81 +++++++++++++++++++---------------- proxlb/utils/helper.py | 27 ------------ 3 files changed, 45 insertions(+), 67 deletions(-) diff --git a/proxlb/models/calculations.py b/proxlb/models/calculations.py index 88d4065..5295abf 100644 --- a/proxlb/models/calculations.py +++ b/proxlb/models/calculations.py @@ -753,10 +753,10 @@ class Calculations: guest_disk_required = proxlb_data["guests"][guest_name]["disk_used"] if guest_memory_required < node_memory_free: - logger.debug(f"Node '{node_target}' has sufficient resources for guest '{guest_name}'.") + logger.debug(f"Node '{node_target}' has sufficient resources ({node_memory_free / (1024 ** 3):.2f} GB free) for guest '{guest_name}'.") logger.debug("Finished: validate_node_resources.") return True else: - logger.debug(f"Node '{node_target}' lacks sufficient resources for guest '{guest_name}'.") + logger.debug(f"Node '{node_target}' lacks sufficient resources ({node_memory_free / (1024 ** 3):.2f} GB free) for guest '{guest_name}'.") logger.debug("Finished: validate_node_resources.") return False diff --git a/proxlb/models/nodes.py b/proxlb/models/nodes.py index 5dabd15..e2f03b0 100644 --- a/proxlb/models/nodes.py +++ b/proxlb/models/nodes.py @@ -78,7 +78,7 @@ class Nodes: nodes["nodes"][node["node"]]["cpu_pressure_some_spikes_percent"] = Nodes.get_node_rrd_data(proxmox_api, node["node"], "cpu", "some", spikes=True) nodes["nodes"][node["node"]]["cpu_pressure_full_spikes_percent"] = Nodes.get_node_rrd_data(proxmox_api, node["node"], "cpu", "full", spikes=True) nodes["nodes"][node["node"]]["cpu_pressure_hot"] = False - nodes["nodes"][node["node"]]["memory_total"] = node["maxmem"] + nodes["nodes"][node["node"]]["memory_total"] = Nodes.set_node_resource_reservation(node["node"], node["maxmem"], proxlb_config, "memory") nodes["nodes"][node["node"]]["memory_assigned"] = 0 nodes["nodes"][node["node"]]["memory_used"] = node["mem"] nodes["nodes"][node["node"]]["memory_free"] = node["maxmem"] - node["mem"] @@ -103,7 +103,6 @@ class Nodes: nodes["nodes"][node["node"]]["disk_pressure_full_spikes_percent"] = Nodes.get_node_rrd_data(proxmox_api, node["node"], "disk", "full", spikes=True) nodes["nodes"][node["node"]]["disk_pressure_hot"] = False - Nodes.apply_resource_reservation(nodes["nodes"][node["node"]]["name"], proxlb_config, nodes["nodes"][node["node"]]) # Evaluate if node should be set to maintenance mode if Nodes.set_node_maintenance(proxmox_api, proxlb_config, node["node"]): nodes["nodes"][node["node"]]["maintenance"] = True @@ -257,51 +256,57 @@ class Nodes: return version["version"] @staticmethod - def apply_resource_reservation(node_name, proxlb_config: Dict[str, Any], node_data: Dict[str, Any]) -> None: + def set_node_resource_reservation(node_name, resource_value, proxlb_config, resource_type) -> int: """ - Check if there is a a configured resource reservation for the current nodes and apply it as needed. + Check if there is a configured resource reservation for the current node and apply it as needed. Checks for a node specific config first, then if there is any configured default and if neither then nothing is reserved. - Reservations are applied by directly modifying the data gathered from the nodes. + Reservations are applied by directly modifying the resource value. Args: - node_name: (str) the name of the node - proxlb_config (Dict[str, Any]): A dictionary containing the ProxLB configuration. - node_data: (Dict[str, Any]): Dict containing the current nodes data - Returns: none + node_name (str): The name of the node. + resource_value (int): The total resource value in bytes. + proxlb_config (Dict[str, Any]): A dictionary containing the ProxLB configuration. + resource_type (str): The type of resource ('memory', 'disk', etc.). + + Returns: + int: The resource value after applying any configured reservations. """ logger.debug(f"Starting: apply_resource_reservation") + balancing_cfg = proxlb_config.get("balancing", {}) reserve_cfg = balancing_cfg.get("node_resource_reserve", {}) - reserved_memory_gb_node = reserve_cfg.get(node_name, {}).get("memory") - reserved_memory_gb_default = reserve_cfg.get("defaults", {}).get("memory", 0) + node_resource_reservation = reserve_cfg.get(node_name, {}).get(resource_type, 0) + default_resource_reservation = reserve_cfg.get("defaults", {}).get(resource_type, 0) - # Make sure the reservation is a numeric value - check for both, default and node specific - if not isinstance(reserved_memory_gb_default, (int, float)): - if reserved_memory_gb_default is not None: - logger.info("Invalid default memory reservation: Found a string while expecting a numeric value - skipping default reservation") - reserved_memory_gb_default = 0 + # Ensure reservations are numeric values + node_resource_reservation = node_resource_reservation if isinstance(node_resource_reservation, (int, float)) else 0 + default_resource_reservation = default_resource_reservation if isinstance(default_resource_reservation, (int, float)) else 0 - if not isinstance(reserved_memory_gb_node, (int, float)): - if reserved_memory_gb_node is not None: - logger.info(f"Invalid memory reservation: Found a string while expecting a numeric value - applying current default of {reserved_memory_gb_default} Bytes") - reserved_memory_gb_node = reserved_memory_gb_default + # Apply node specific reservation if set + if node_resource_reservation > 0: + if resource_value < (node_resource_reservation * 1024 ** 3): + logger.critical(f"Configured resource reservation for node {node_name} of type {resource_type} with {node_resource_reservation} GB is higher than available resource value {resource_value / (1024 ** 3):.2f} GB. Not applying...") + return resource_value + else: + logger.debug(f"Applying node specific reservation for {node_name} of type {resource_type} with {node_resource_reservation} GB.") + resource_value_new = resource_value - (node_resource_reservation * 1024 ** 3) + logger.debug(f'Switched resource value for node {node_name} of type {resource_type} from {resource_value / (1024 ** 3):.2f} GB to {resource_value_new / (1024 ** 3):.2f} GB after applying reservation.') + logger.debug(f"Before: {resource_value} | After: {resource_value_new}") + return resource_value_new - # Make sure the reservation is positive - if reserved_memory_gb_node < 0: - logger.info(f"{nodes['nodes'][node['node']]['name']}: Invalid assigned memory reservation, applying defaults") - reserved_memory_gb_node = reserved_memory_gb_default + # Apply default reservation if set and no node specific reservation has been performed + elif default_resource_reservation > 0: + if resource_value < (default_resource_reservation * 1024 ** 3): + logger.critical(f"Configured default reservation for node {node_name} of type {resource_type} with {default_resource_reservation} GB is higher than available resource value {resource_value / (1024 ** 3):.2f} GB. Not applying...") + return resource_value + else: + logger.debug(f"Applying default reservation for {node_name} of type {resource_type} with {default_resource_reservation} GB.") + resource_value_new = resource_value - (default_resource_reservation * 1024 ** 3) + logger.debug(f'Switched resource value for node {node_name} of type {resource_type} from {resource_value / (1024 ** 3):.2f} GB to {resource_value_new / (1024 ** 3):.2f} GB after applying reservation.') + logger.debug(f"Before: {resource_value} | After: {resource_value_new}") + return resource_value_new - # Convert the reservation from GB to Bytes, get the current nodes physical memory - reserved_memory_node = int(round(reserved_memory_gb_node * 1024 ** 3)) - total_mem = node_data.get("memory_total") - - # Check if the reservation doesnt exceed the nodes total memory - if reserved_memory_node > total_mem: - logger.debug(f"Reservation of {reserved_memory_node} Bytes exceeds available memory of {total_mem} Bytes- skipping reservation") - reserved_memory_node = 0 - reserved_memory_gb_node = 0 - - logger.debug(f"Reserved Memory: {reserved_memory_gb_node} GB ({reserved_memory_node} Bytes)") - node_data["memory_total"] -= reserved_memory_node - Helper.update_node_resource_percentages(node_data) - logger.debug(f"Finished: apply_resource_reservation") + else: + logger.debug(f"No default or node specific resource reservation for node {node_name} found. Skipping...") + logger.debug(f"Finished: apply_resource_reservation") + return resource_value diff --git a/proxlb/utils/helper.py b/proxlb/utils/helper.py index 0b568cc..841c15f 100644 --- a/proxlb/utils/helper.py +++ b/proxlb/utils/helper.py @@ -335,30 +335,3 @@ class Helper: return (rc == 0, rc if rc != 0 else None) finally: test_socket.close() - - @staticmethod - def update_node_resource_percentages(node_data: Dict[str, any]) -> None: - """ - This function updates the percentages of the node's resources in its respective dict - Args: - node_data: (Dict[str, any]) dict containing the nodes data to be updated - Returns: none - """ - logger.debug(f"Starting: Update resource percentages") - logger.debug(f"node data: {node_data}") - # memory - node_data["memory_assigned_percent"] = node_data["memory_assigned"] / node_data["memory_total"] * 100 - node_data["memory_free_percent"] = node_data["memory_free"] / node_data["memory_total"] * 100 - node_data["memory_used_percent"] = node_data["memory_used"] / node_data["memory_total"] * 100 - # cpu - node_data["cpu_assigned_percent"] = node_data["cpu_assigned"] / node_data["cpu_total"] * 100 - node_data["cpu_free_percent"] = node_data["cpu_free"] / node_data["cpu_total"] * 100 - node_data["cpu_used_percent"] = node_data["cpu_used"] / node_data["cpu_total"] * 100 - # disk - node_data["disk_assigned_percent"] = node_data["disk_assigned"] / node_data["disk_total"] * 100 - node_data["disk_free_percent"] = node_data["disk_free"] / node_data["disk_total"] * 100 - node_data["disk_used_percent"] = node_data["disk_used"] / node_data["disk_total"] * 100 - - logger.debug(f"node data: {node_data}") - logger.debug(f"End: Update resource percentages") - return