diff --git a/.changelogs/1.1.11/391_add_native_proxmox_ha_rules_support.yml b/.changelogs/1.1.11/391_add_native_proxmox_ha_rules_support.yml index d9a07dc..0f7ff28 100644 --- a/.changelogs/1.1.11/391_add_native_proxmox_ha_rules_support.yml +++ b/.changelogs/1.1.11/391_add_native_proxmox_ha_rules_support.yml @@ -1,3 +1,3 @@ -feature: +added: - Add support for Proxmox's native HA (affinity/anti-affinity) rules (@gyptazy). [#391] - Add support for Proxmox's native HA (node-affinity) rules for pinning guests to nodes (@gyptazy). [#391] diff --git a/.changelogs/1.1.11/406_add_stricness_for_node_pinning_of_pools.yml b/.changelogs/1.1.11/406_add_stricness_for_node_pinning_of_pools.yml new file mode 100644 index 0000000..8a97c76 --- /dev/null +++ b/.changelogs/1.1.11/406_add_stricness_for_node_pinning_of_pools.yml @@ -0,0 +1,2 @@ +added: + - Add support for configuring node-pinning strictness (default: true) within pools (@gyptazy). [#406] diff --git a/README.md b/README.md index d9d8932..77ee792 100644 --- a/README.md +++ b/README.md @@ -393,6 +393,7 @@ balancing: pin: - virt66 - virt77 + strict: False service: daemon: True diff --git a/config/proxlb_example.yaml b/config/proxlb_example.yaml index 5390edc..a7632b2 100644 --- a/config/proxlb_example.yaml +++ b/config/proxlb_example.yaml @@ -74,6 +74,7 @@ balancing: pin: # Define a pinning og guests to specific node(s) - virt66 - virt77 + strict: False # Disable strict mode of node pinning for this pool service: daemon: True diff --git a/proxlb/models/calculations.py b/proxlb/models/calculations.py index 2bd8e86..c03ebb5 100644 --- a/proxlb/models/calculations.py +++ b/proxlb/models/calculations.py @@ -519,8 +519,20 @@ class Calculations: if len(proxlb_data["guests"][guest_name]["node_relationships"]) > 0: logger.debug(f"Guest '{guest_name}' has relationships defined to node(s): {','.join(proxlb_data['guests'][guest_name]['node_relationships'])}. Pinning to node.") - # Get the node with the most free resources of the group + # Get the list of nodes that are defined as relationship for the guest guest_node_relation_list = proxlb_data["guests"][guest_name]["node_relationships"] + + # Validate if strict relationships are defined. If not, we prefer + # the most free node in addition to the relationship list. + if proxlb_data["guests"][guest_name]["node_relationships_strict"]: + logger.debug(f"Guest '{guest_name}' has strict node relationships defined. Only nodes in the relationship list will be considered for pinning.") + else: + logger.debug(f"Guest '{guest_name}' has non-strict node relationships defined. Prefering nodes in the relationship list for pinning.") + Calculations.get_most_free_node(proxlb_data) + most_free_node = proxlb_data["meta"]["balancing"]["balance_next_node"] + guest_node_relation_list.append(most_free_node) + + # Get the most free node from the relationship list, or the most free node overall Calculations.get_most_free_node(proxlb_data, False, guest_node_relation_list) # Validate if the specified node name is really part of the cluster diff --git a/proxlb/models/guests.py b/proxlb/models/guests.py index 84f7ce9..8e1c22c 100644 --- a/proxlb/models/guests.py +++ b/proxlb/models/guests.py @@ -103,6 +103,7 @@ class Guests: guests['guests'][guest['name']]['anti_affinity_groups'] = Tags.get_anti_affinity_groups(guests['guests'][guest['name']]['tags'], guests['guests'][guest['name']]['pools'], guests['guests'][guest['name']]['ha_rules'], proxlb_config) guests['guests'][guest['name']]['ignore'] = Tags.get_ignore(guests['guests'][guest['name']]['tags']) guests['guests'][guest['name']]['node_relationships'] = Tags.get_node_relationships(guests['guests'][guest['name']]['tags'], nodes, guests['guests'][guest['name']]['pools'], guests['guests'][guest['name']]['ha_rules'], proxlb_config) + guests['guests'][guest['name']]['node_relationships_strict'] = Pools.get_pool_node_affinity_strictness(proxlb_config, guests['guests'][guest['name']]['pools']) guests['guests'][guest['name']]['type'] = 'vm' logger.debug(f"Resources of Guest {guest['name']} (type VM) added: {guests['guests'][guest['name']]}") @@ -149,6 +150,7 @@ class Guests: guests['guests'][guest['name']]['anti_affinity_groups'] = Tags.get_anti_affinity_groups(guests['guests'][guest['name']]['tags'], guests['guests'][guest['name']]['pools'], guests['guests'][guest['name']]['ha_rules'], proxlb_config) guests['guests'][guest['name']]['ignore'] = Tags.get_ignore(guests['guests'][guest['name']]['tags']) guests['guests'][guest['name']]['node_relationships'] = Tags.get_node_relationships(guests['guests'][guest['name']]['tags'], nodes, guests['guests'][guest['name']]['pools'], guests['guests'][guest['name']]['ha_rules'], proxlb_config) + guests['guests'][guest['name']]['node_relationships_strict'] = Pools.get_pool_node_affinity_strictness(proxlb_config, guests['guests'][guest['name']]['pools']) guests['guests'][guest['name']]['type'] = 'ct' logger.debug(f"Resources of Guest {guest['name']} (type CT) added: {guests['guests'][guest['name']]}") diff --git a/proxlb/models/pools.py b/proxlb/models/pools.py index 2faa2c8..6757ec9 100644 --- a/proxlb/models/pools.py +++ b/proxlb/models/pools.py @@ -115,3 +115,29 @@ class Pools: logger.debug("Finished: get_pools_for_guests.") return guest_pools + + @staticmethod + def get_pool_node_affinity_strictness(proxlb_config: Dict[str, Any], guest_pools: list) -> bool: + """ + Retrieve the node affinity strictness setting for a guest across its pools. + + Queries the ProxLB configuration to determine the node affinity strictness + level for the specified guest based on its pool memberships. Returns the + strictness setting from the first matching pool configuration. + + Args: + proxlb_config (Dict[str, Any]): ProxLB configuration dictionary. + guest_pools (list): List of pool names the guest belongs to. + + Returns: + bool: Node affinity strictness setting (default True if not specified). + """ + logger.debug("Starting: get_pool_node_affinity_strictness.") + + node_strictness = True + for pool in guest_pools: + pool_settings = proxlb_config.get("balancing", {}).get("pools", {}).get(pool, {}) + node_strictness = pool_settings.get("strict", True) + + logger.debug("Finished: get_pool_node_affinity_strictness.") + return node_strictness