mirror of
https://github.com/gyptazy/ProxLB.git
synced 2026-04-05 20:31:57 +02:00
fix: Fixed pool and ha-rules based node pinning of guests.
* Fixed pool based node pinning (@gyptazy). [#395] * Add support for Proxmox's native HA (node-affinity) rules for pinning guests to nodes (@gyptazy). [#391] Fixes: #395 Fixes: #391
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
feature:
|
||||
- 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]
|
||||
|
||||
2
.changelogs/1.1.11/395_fix_pool_based_node_pinning.yml
Normal file
2
.changelogs/1.1.11/395_fix_pool_based_node_pinning.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
fixed:
|
||||
- Fixed pool based node pinning (@gyptazy). [#395]
|
||||
@@ -102,7 +102,7 @@ class Guests:
|
||||
guests['guests'][guest['name']]['affinity_groups'] = Tags.get_affinity_groups(guests['guests'][guest['name']]['tags'], guests['guests'][guest['name']]['pools'], guests['guests'][guest['name']]['ha_rules'], proxlb_config)
|
||||
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'], proxlb_config)
|
||||
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']]['type'] = 'vm'
|
||||
|
||||
logger.debug(f"Resources of Guest {guest['name']} (type VM) added: {guests['guests'][guest['name']]}")
|
||||
@@ -144,10 +144,11 @@ class Guests:
|
||||
guests['guests'][guest['name']]['pressure_hot'] = False
|
||||
guests['guests'][guest['name']]['tags'] = Tags.get_tags_from_guests(proxmox_api, node, guest['vmid'], 'ct')
|
||||
guests['guests'][guest['name']]['pools'] = Pools.get_pools_for_guest(guest['name'], pools)
|
||||
guests['guests'][guest['name']]['affinity_groups'] = Tags.get_affinity_groups(guests['guests'][guest['name']]['tags'], guests['guests'][guest['name']]['pools'], proxlb_config)
|
||||
guests['guests'][guest['name']]['anti_affinity_groups'] = Tags.get_anti_affinity_groups(guests['guests'][guest['name']]['tags'], guests['guests'][guest['name']]['pools'], proxlb_config)
|
||||
guests['guests'][guest['name']]['ha_rules'] = HaRules.get_ha_rules_for_guest(guest['name'], ha_rules, guest['vmid'])
|
||||
guests['guests'][guest['name']]['affinity_groups'] = Tags.get_affinity_groups(guests['guests'][guest['name']]['tags'], guests['guests'][guest['name']]['pools'], guests['guests'][guest['name']]['ha_rules'], proxlb_config)
|
||||
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'], proxlb_config)
|
||||
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']]['type'] = 'ct'
|
||||
|
||||
logger.debug(f"Resources of Guest {guest['name']} (type CT) added: {guests['guests'][guest['name']]}")
|
||||
|
||||
@@ -56,9 +56,15 @@ class HaRules:
|
||||
ha_rules = {"ha_rules": {}}
|
||||
|
||||
for rule in proxmox_api.cluster.ha.rules.get():
|
||||
|
||||
# Skip disabled rules (disable key exists AND is truthy)
|
||||
if rule.get("disable", 0):
|
||||
logger.debug(f"Skipping ha-rule: {rule['rule']} of type {rule['type']} affecting guests: {rule['resources']}. Rule is disabled.")
|
||||
continue
|
||||
|
||||
# Create a resource list by splitting on commas and stripping whitespace containing
|
||||
# the VM and CT IDs that are part of this HA rule
|
||||
resources_list = [int(r.split(":")[1]) for r in rule["resources"].split(",") if r.strip()]
|
||||
resources_list_guests = [int(r.split(":")[1]) for r in rule["resources"].split(",") if r.strip()]
|
||||
|
||||
# Convert the affinity field to a more descriptive type
|
||||
if rule.get("affinity", None) == "negative":
|
||||
@@ -66,11 +72,17 @@ class HaRules:
|
||||
else:
|
||||
affinity_type = "affinity"
|
||||
|
||||
# Create affected nodes list
|
||||
resources_list_nodes = []
|
||||
if rule.get("nodes", None):
|
||||
resources_list_nodes = [n for n in rule["nodes"].split(",") if n]
|
||||
|
||||
# Create the ha_rule element
|
||||
ha_rules['ha_rules'][rule['rule']] = {}
|
||||
ha_rules['ha_rules'][rule['rule']]['rule'] = rule['rule']
|
||||
ha_rules['ha_rules'][rule['rule']]['type'] = affinity_type
|
||||
ha_rules['ha_rules'][rule['rule']]['members'] = resources_list
|
||||
ha_rules['ha_rules'][rule['rule']]['nodes'] = resources_list_nodes
|
||||
ha_rules['ha_rules'][rule['rule']]['members'] = resources_list_guests
|
||||
|
||||
logger.debug(f"Got ha-rule: {rule['rule']} as type {affinity_type} affecting guests: {rule['resources']}")
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ class Tags:
|
||||
Args:
|
||||
tags (List): A list holding all defined tags for a given guest.
|
||||
pools (List): A list holding all defined pools for a given guest.
|
||||
ha_rules (List): A list holding all defined ha_rules for a given guest.
|
||||
proxlb_config (Dict): A dict holding the ProxLB configuration.
|
||||
|
||||
Returns:
|
||||
@@ -140,6 +141,7 @@ class Tags:
|
||||
Args:
|
||||
tags (List): A list holding all defined tags for a given guest.
|
||||
pools (List): A list holding all defined pools for a given guest.
|
||||
ha_rules (List): A list holding all defined ha_rules for a given guest.
|
||||
proxlb_config (Dict): A dict holding the ProxLB configuration.
|
||||
|
||||
Returns:
|
||||
@@ -203,7 +205,7 @@ class Tags:
|
||||
return ignore_tag
|
||||
|
||||
@staticmethod
|
||||
def get_node_relationships(tags: List[str], nodes: Dict[str, Any], pools: List[str], proxlb_config: Dict[str, Any]) -> str:
|
||||
def get_node_relationships(tags: List[str], nodes: Dict[str, Any], pools: List[str], ha_rules: List[str], proxlb_config: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Get a node relationship tag for a guest from the Proxmox cluster by the API to pin
|
||||
a guest to a node or by defined pools from ProxLB configuration.
|
||||
@@ -215,6 +217,7 @@ class Tags:
|
||||
tags (List): A list holding all defined tags for a given guest.
|
||||
nodes (Dict): A dictionary holding all available nodes in the cluster.
|
||||
pools (List): A list holding all defined pools for a given guest.
|
||||
ha_rules (List): A list holding all defined ha_rules for a given guest.
|
||||
proxlb_config (Dict): A dict holding the ProxLB configuration.
|
||||
|
||||
Returns:
|
||||
@@ -223,6 +226,7 @@ class Tags:
|
||||
logger.debug("Starting: get_node_relationships.")
|
||||
node_relationship_tags = []
|
||||
|
||||
# Tag based node relationship
|
||||
if len(tags) > 0:
|
||||
logger.debug("Validating node pinning by tags.")
|
||||
for tag in tags:
|
||||
@@ -237,21 +241,38 @@ class Tags:
|
||||
else:
|
||||
logger.warning(f"Tag {node_relationship_tag} is invalid! Defined node does not exist in the cluster. Not applying pinning.")
|
||||
|
||||
# Pool based node relationship
|
||||
if len(pools) > 0:
|
||||
logger.debug("Validating node pinning by pools.")
|
||||
for pool in pools:
|
||||
if pool in (proxlb_config['balancing'].get('pools') or {}):
|
||||
|
||||
node = proxlb_config['balancing']['pools'][pool].get('pin', None)
|
||||
# Validate if the node to pin is present in the cluster
|
||||
if Helper.validate_node_presence(node, nodes):
|
||||
logger.debug(f"Pool pinning tag {node} is valid! Defined node exists in the cluster.")
|
||||
logger.debug(f"Setting node relationship because of pool {pool} to {node}.")
|
||||
node_relationship_tags.append(node)
|
||||
else:
|
||||
logger.warning(f"Pool pinning tag {node} is invalid! Defined node does not exist in the cluster. Not applying pinning.")
|
||||
pool_nodes = proxlb_config['balancing']['pools'][pool].get('pin', None)
|
||||
for node in pool_nodes:
|
||||
|
||||
# Validate if the node to pin is present in the cluster
|
||||
if Helper.validate_node_presence(node, nodes):
|
||||
logger.debug(f"Pool pinning tag {node} is valid! Defined node exists in the cluster.")
|
||||
logger.debug(f"Setting node relationship because of pool {pool} to {node}.")
|
||||
node_relationship_tags.append(node)
|
||||
else:
|
||||
logger.warning(f"Pool pinning tag {node} is invalid! Defined node does not exist in the cluster. Not applying pinning.")
|
||||
|
||||
else:
|
||||
logger.debug(f"Skipping pinning for pool {pool}. Pool is not defined in ProxLB configuration.")
|
||||
|
||||
# HA rule based node relationship
|
||||
if len(ha_rules) > 0:
|
||||
logger.debug("Validating node pinning by ha-rules.")
|
||||
for ha_rule in ha_rules:
|
||||
if len(ha_rule.get("nodes", 0)) > 0:
|
||||
if ha_rule.get("type", None) == "affinity":
|
||||
logger.debug(f"ha-rule {ha_rule['rule']} is of type affinity.")
|
||||
for node in ha_rule["nodes"]:
|
||||
logger.debug(f"Adding {node} as node relationship because of ha-rule {ha_rule['rule']}.")
|
||||
node_relationship_tags.append(node)
|
||||
else:
|
||||
logger.debug(f"ha-rule {ha_rule['rule']} is of type anti-affinity. Skipping node relationship addition.")
|
||||
|
||||
logger.debug("Finished: get_node_relationships.")
|
||||
return node_relationship_tags
|
||||
|
||||
Reference in New Issue
Block a user