diff --git a/.changelogs/1.1.6/296_fix_validate_node_presence_when_pinning_guests.yml b/.changelogs/1.1.6/296_fix_validate_node_presence_when_pinning_guests.yml new file mode 100644 index 0000000..3a0782c --- /dev/null +++ b/.changelogs/1.1.6/296_fix_validate_node_presence_when_pinning_guests.yml @@ -0,0 +1,3 @@ +fixed: + - Validate for node presence when pinning guests to avoid crashing (@gyptazy). [#296] + \ No newline at end of file diff --git a/proxlb/models/guests.py b/proxlb/models/guests.py index 2bf7d61..c3a9fb5 100644 --- a/proxlb/models/guests.py +++ b/proxlb/models/guests.py @@ -107,7 +107,7 @@ class Guests: guests['guests'][guest['name']]['affinity_groups'] = Tags.get_affinity_groups(guests['guests'][guest['name']]['tags']) guests['guests'][guest['name']]['anti_affinity_groups'] = Tags.get_anti_affinity_groups(guests['guests'][guest['name']]['tags']) 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']) + guests['guests'][guest['name']]['node_relationships'] = Tags.get_node_relationships(guests['guests'][guest['name']]['tags'], nodes) 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/tags.py b/proxlb/models/tags.py index 1317cc7..2bc891a 100644 --- a/proxlb/models/tags.py +++ b/proxlb/models/tags.py @@ -12,7 +12,9 @@ __license__ = "GPL-3.0" import time from typing import List +from typing import Dict, Any from utils.logger import SystemdLogger +from utils.helper import Helper logger = SystemdLogger() @@ -153,7 +155,7 @@ class Tags: return ignore_tag @staticmethod - def get_node_relationships(tags: List[str]) -> str: + def get_node_relationships(tags: List[str], nodes: 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. @@ -163,6 +165,7 @@ class Tags: Args: tags (List): A list holding all defined tags for a given guest. + nodes (Dict): A dictionary holding all available nodes in the cluster. Returns: Str: The related hypervisor node name. @@ -174,7 +177,13 @@ class Tags: for tag in tags: if tag.startswith("plb_pin"): node_relationship_tag = tag.replace("plb_pin_", "") - node_relationship_tags.append(node_relationship_tag) + + # Validate if the node to pin is present in the cluster + if Helper.validate_node_presence(node_relationship_tag, nodes): + logger.info(f"Tag {node_relationship_tag} is valid! Defined node exists in the cluster.") + node_relationship_tags.append(node_relationship_tag) + else: + logger.warning(f"Tag {node_relationship_tag} is invalid! Defined node does not exist in the cluster. Not applying pinning.") logger.debug("Finished: get_node_relationships.") return node_relationship_tags diff --git a/proxlb/utils/helper.py b/proxlb/utils/helper.py index 7fff9f1..7bdda17 100644 --- a/proxlb/utils/helper.py +++ b/proxlb/utils/helper.py @@ -265,3 +265,27 @@ class Helper: return parts[0], port except ValueError: return host_object, 8006 + + @staticmethod + def validate_node_presence(node: str, nodes: Dict[str, Any]) -> bool: + """ + Validates whether a given node exists in the provided cluster nodes dictionary. + + Args: + node (str): The name of the node to validate. + nodes (Dict[str, Any]): A dictionary containing cluster information. + Must include a "nodes" key mapping to a dict of available nodes. + + Returns: + bool: True if the node exists in the cluster, False otherwise. + """ + logger.debug("Starting: validate_node_presence.") + + if node in nodes["nodes"].keys(): + logger.info(f"Node {node} found in cluster. Applying pinning.") + logger.debug("Finished: validate_node_presence.") + return True + else: + logger.warning(f"Node {node} not found in cluster. Not applying pinning!") + logger.debug("Finished: validate_node_presence.") + return False