From f781e74d3a35d25991edc4a9b19ebec04036cd1a Mon Sep 17 00:00:00 2001 From: gyptazy Date: Mon, 3 Mar 2025 10:48:12 +0100 Subject: [PATCH] enhancement: Adjust license information, adjust class/func descriptions --- README.md | 4 +- docs/01_requirements.md | 0 docs/02_installation.md | 0 .../03_proxmox-api-user-api-token-creation.md | 0 docs/04_configuration.md | 0 docs/99-misc.md | 0 proxlb/main.py | 5 ++ proxlb/models/balancing.py | 30 ++++++++-- proxlb/models/calculations.py | 39 ++++++++++++- proxlb/models/groups.py | 20 ++++++- proxlb/models/guests.py | 13 +++++ proxlb/models/nodes.py | 18 ++++++ proxlb/models/tags.py | 37 ++++++++++--- proxlb/utils/cli_parser.py | 5 ++ proxlb/utils/config_parser.py | 17 +++++- proxlb/utils/helper.py | 21 +++++++ proxlb/utils/logger.py | 43 +++++++++++++-- proxlb/utils/proxmox_api.py | 55 +++++++++++++++---- proxlb/utils/version.py | 2 + 19 files changed, 274 insertions(+), 35 deletions(-) create mode 100644 docs/01_requirements.md create mode 100644 docs/02_installation.md create mode 100644 docs/03_proxmox-api-user-api-token-creation.md create mode 100644 docs/04_configuration.md create mode 100644 docs/99-misc.md diff --git a/README.md b/README.md index df968c4..c09e020 100644 --- a/README.md +++ b/README.md @@ -252,10 +252,10 @@ The `maintenance_nodes` option allows operators to designate one or more Proxmox Bugs can be reported via the GitHub issue tracker [here](https://github.com/gyptazy/ProxLB/issues). You may also report bugs via email or deliver PRs to fix them on your own. Therefore, you might also see the contributing chapter. ### Contributing -Feel free to add further documentation, to adjust already existing one or to contribute with code. Please take care about the style guide and naming conventions. You can find more in our [CONTRIBUTING.md](https://github.com/gyptazy/ProxLB/blob/development/CONTRIBUTING.md) file. +Feel free to add further documentation, to adjust already existing one or to contribute with code. Please take care about the style guide and naming conventions. You can find more in our [CONTRIBUTING.md](https://github.com/gyptazy/ProxLB/blob/main/CONTRIBUTING.md) file. ### Documentation -You can also find additional and more detailed documentation within the [docs/](https://github.com/gyptazy/ProxLB/tree/development/docs) directory. +You can also find additional and more detailed documentation within the [docs/](https://github.com/gyptazy/ProxLB/tree/main/docs) directory. ### Support If you need assistance or have any questions, we offer support through our dedicated [chat room](https://matrix.to/#/#proxlb:gyptazy.com) in Matrix or [Discord](https://discord.gg/JemGu7WbfQ). Join our community for real-time help, advice, and discussions. The Matrix and Discord room are bridged to ensure that the communication is not splitted - so simply feel free to join which fits most to you! diff --git a/docs/01_requirements.md b/docs/01_requirements.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/02_installation.md b/docs/02_installation.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/03_proxmox-api-user-api-token-creation.md b/docs/03_proxmox-api-user-api-token-creation.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/04_configuration.md b/docs/04_configuration.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/99-misc.md b/docs/99-misc.md new file mode 100644 index 0000000..e69de29 diff --git a/proxlb/main.py b/proxlb/main.py index b46801e..f1df87f 100644 --- a/proxlb/main.py +++ b/proxlb/main.py @@ -7,6 +7,11 @@ perform balancing actions based on the configuration provided. It also includes parser for handling command-line arguments and a custom logger for systemd integration. """ +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + import logging from utils.logger import SystemdLogger from utils.cli_parser import CliParser diff --git a/proxlb/models/balancing.py b/proxlb/models/balancing.py index b3a9feb..7a8bbfa 100644 --- a/proxlb/models/balancing.py +++ b/proxlb/models/balancing.py @@ -1,10 +1,15 @@ """ -The balancing class is responsible for processing workloads on Proxmox clusters. -The previously generated data (hold in proxlb_data) will processed and guests and -other supported types will be moved across Proxmox clusters based on the defined -values by an operator. +The Balancing class is responsible for processing workloads on Proxmox clusters. +It processes the previously generated data (held in proxlb_data) and moves guests +and other supported types across Proxmox clusters based on the defined values by an operator. """ + +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + import proxmoxer import time from utils.logger import SystemdLogger @@ -19,6 +24,23 @@ class Balancing: The previously generated data (hold in proxlb_data) will processed and guests and other supported types will be moved across Proxmox clusters based on the defined values by an operator. + + Methods: + __init__(self, proxmox_api: any, proxlb_data: Dict[str, Any]): + Initializes the Balancing class with the provided ProxLB data and initiates the rebalancing + process for guests. + + exec_rebalancing_vm(self, proxmox_api: any, proxlb_data: Dict[str, Any], guest_name: str) -> None: + Executes the rebalancing of a virtual machine (VM) to a new node within the cluster. Logs the migration + process and handles exceptions. + + exec_rebalancing_ct(self, proxmox_api: any, proxlb_data: Dict[str, Any], guest_name: str) -> None: + Executes the rebalancing of a container (CT) to a new node within the cluster. Logs the migration + process and handles exceptions. + + get_rebalancing_job_status(self, proxmox_api: any, proxlb_data: Dict[str, Any], guest_name: str, guest_current_node: str, job_id: int, retry_counter: int = 1) -> bool: + Monitors the status of a rebalancing job on a Proxmox node until it completes or a timeout + is reached. Returns True if the job completed successfully, False otherwise. """ def __init__(self, proxmox_api: any, proxlb_data: Dict[str, Any]): diff --git a/proxlb/models/calculations.py b/proxlb/models/calculations.py index 10765ae..4a973c5 100644 --- a/proxlb/models/calculations.py +++ b/proxlb/models/calculations.py @@ -1,9 +1,15 @@ """ -The calculation class is responsible for handling the balancing of virtual machines (VMs) +The Calculations class is responsible for handling the balancing of virtual machines (VMs) and containers (CTs) across all available nodes in a Proxmox cluster. It provides methods to calculate the optimal distribution of VMs and CTs based on the provided data. """ + +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + import sys from typing import Dict, Any from utils.logger import SystemdLogger @@ -16,6 +22,37 @@ class Calculations: The calculation class is responsible for handling the balancing of virtual machines (VMs) and containers (CTs) across all available nodes in a Proxmox cluster. It provides methods to calculate the optimal distribution of VMs and CTs based on the provided data. + + Methods: + __init__(proxlb_data: Dict[str, Any]): + Initializes the Calculation class with the provided ProxLB data. + + set_node_assignments(proxlb_data: Dict[str, Any]) -> Dict[str, Any]: + Sets the assigned resources of the nodes based on the current assigned + guest resources by their created groups as an initial base. + + get_balanciness(proxlb_data: Dict[str, Any]) -> Dict[str, Any]: + Gets the balanciness for further actions where the highest and lowest + usage or assignments of Proxmox nodes are compared. + + get_most_free_node(proxlb_data: Dict[str, Any], return_node: bool = False) -> Dict[str, Any]: + Gets the name of the Proxmox node in the cluster with the most free resources based on + the user-defined method (e.g., memory) and mode (e.g., used). + + relocate_guests_on_maintenance_nodes(proxlb_data: Dict[str, Any]): + Relocates guests that are currently on nodes marked for maintenance to + nodes with the most available resources. + + relocate_guests(proxlb_data: Dict[str, Any]): + Relocates guests within the provided data structure to ensure affinity groups are + placed on nodes with the most free resources. + + val_anti_affinity(proxlb_data: Dict[str, Any], guest_name: str): + Validates and assigns nodes to guests based on anti-affinity rules. + + update_node_resources(proxlb_data): + Updates the resource allocation and usage statistics for nodes when a guest + is moved from one node to another. """ def __init__(self, proxlb_data: Dict[str, Any]): diff --git a/proxlb/models/groups.py b/proxlb/models/groups.py index 1dc12de..d166b93 100644 --- a/proxlb/models/groups.py +++ b/proxlb/models/groups.py @@ -1,9 +1,15 @@ """ -The groups class is responsible for handling the correlations between the guests -and their groups like affinity and anti-affinity groups. To ensure a proper balancing -guests will ge grouped and then evaluated for further balancing. +The Groups class is responsible for handling the correlations between the guests +and their groups, such as affinity and anti-affinity groups. It ensures proper balancing +by grouping guests and evaluating them for further balancing. The class provides methods +to initialize with ProxLB data and to generate groups based on guest and node data. """ +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + from typing import Dict, Any from utils.logger import SystemdLogger from utils.helper import Helper @@ -16,6 +22,14 @@ class Groups: The groups class is responsible for handling the correlations between the guests and their groups like affinity and anti-affinity groups. To ensure a proper balancing guests will ge grouped and then evaluated for further balancing. + + Methods: + __init__(proxlb_data: Dict[str, Any]): + Initializes the Groups class. + + get_groups(guests: Dict[str, Any], nodes: Dict[str, Any]) -> Dict[str, Any]: + Generates and returns a dictionary of affinity and anti-affinity groups + based on the provided data. """ def __init__(self, proxlb_data: Dict[str, Any]): diff --git a/proxlb/models/guests.py b/proxlb/models/guests.py index b015e45..f4fbfc7 100644 --- a/proxlb/models/guests.py +++ b/proxlb/models/guests.py @@ -3,6 +3,11 @@ The Guests class retrieves all running guests on the Proxmox cluster across all It handles both VM and CT guest types, collecting their resource metrics. """ +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + from typing import Dict, Any from utils.logger import SystemdLogger from models.tags import Tags @@ -14,6 +19,14 @@ class Guests: """ The Guests class retrieves all running guests on the Proxmox cluster across all available nodes. It handles both VM and CT guest types, collecting their resource metrics. + + Methods: + __init__: + Initializes the Guests class. + + get_guests(proxmox_api: any, nodes: Dict[str, Any]) -> Dict[str, Any]: + Retrieves metrics for all running guests (both VMs and CTs) across all nodes in the Proxmox cluster. + It collects resource metrics such as CPU, memory, and disk usage, as well as tags and affinity/anti-affinity groups. """ def __init__(self): """ diff --git a/proxlb/models/nodes.py b/proxlb/models/nodes.py index e68b1e0..ceff8f5 100644 --- a/proxlb/models/nodes.py +++ b/proxlb/models/nodes.py @@ -1,8 +1,26 @@ """ The Nodes class retrieves all running nodes in a Proxmox cluster and collects their resource metrics. + +Methods: + __init__: + Initializes the Nodes class. + + get_nodes(proxmox_api: any, proxlb_config: Dict[str, Any]) -> Dict[str, Any]: + Gets metrics of all nodes in a Proxmox cluster. + + set_node_maintenance(proxlb_config: Dict[str, Any], node_name: str) -> Dict[str, Any]: + Sets Proxmox nodes to a maintenance mode if required. + + set_node_ignore(proxlb_config: Dict[str, Any], node_name: str) -> Dict[str, Any]: + Sets Proxmox nodes to be ignored if requested. """ +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + from typing import Dict, Any from utils.logger import SystemdLogger diff --git a/proxlb/models/tags.py b/proxlb/models/tags.py index f69ae4a..10a6306 100644 --- a/proxlb/models/tags.py +++ b/proxlb/models/tags.py @@ -1,9 +1,15 @@ """ -The Tags class retrieves all tags from guests of the type VM or CT running -in a Proxmox cluster and validates for affinity, anti-affinity and ignore -tags set for the guest in the Proxmox API. +The Tags class retrieves and processes tags from guests of type VM or CT running +in a Proxmox cluster. It provides methods to fetch tags from the Proxmox API and +evaluate them for affinity, anti-affinity, and ignore tags, which are used during +balancing calculations. """ +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + import time from typing import List from utils.logger import SystemdLogger @@ -13,13 +19,30 @@ logger = SystemdLogger() class Tags: """ - The Tags class retrieves all tags from guests of the type VM or CT running - in a Proxmox cluster and validates for affinity, anti-affinity and ignore - tags set for the guest in the Proxmox API. + The Tags class retrieves and processes tags from guests of type VM or CT running + in a Proxmox cluster. It provides methods to fetch tags from the Proxmox API and + evaluate them for affinity, anti-affinity, and ignore tags, which are used during + balancing calculations. + + Methods: + __init__: + Initializes the Tags class. + + get_tags_from_guests(proxmox_api: any, node: str, guest_id: int, guest_type: str) -> List[str]: + Retrieves all tags for a given guest from the Proxmox API. + + get_affinity_groups(tags: List[str]) -> List[str]: + Evaluates and returns all affinity tags from the provided list of tags. + + get_anti_affinity_groups(tags: List[str]) -> List[str]: + Evaluates and returns all anti-affinity tags from the provided list of tags. + + get_ignore(tags: List[str]) -> bool: + Evaluates and returns a boolean indicating whether the guest should be ignored based on the provided list of tags. """ def __init__(self): """ - Initializes the Tags class. + Initializes the tags class. """ @staticmethod diff --git a/proxlb/utils/cli_parser.py b/proxlb/utils/cli_parser.py index d5e6b52..eaa5738 100644 --- a/proxlb/utils/cli_parser.py +++ b/proxlb/utils/cli_parser.py @@ -2,6 +2,11 @@ The CliParser class handles the parsing of command-line interface (CLI) arguments. """ +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + import argparse import utils.version from utils.logger import SystemdLogger diff --git a/proxlb/utils/config_parser.py b/proxlb/utils/config_parser.py index 1af66ee..4e1d62c 100644 --- a/proxlb/utils/config_parser.py +++ b/proxlb/utils/config_parser.py @@ -3,6 +3,11 @@ The ConfigParser class handles the parsing of configuration file from a given YAML file from any location. """ +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + import os import sys try: @@ -24,8 +29,16 @@ logger = SystemdLogger() class ConfigParser: """ - The ConfigParser class handles the parsing of configuration file - from a given YAML file from any location. + The ConfigParser class handles the parsing of a configuration file. + + Methods: + __init__(config_path: str) + + test_config_path(config_path: str) -> None + Checks if the configuration file is present at the given config path. + + get_config() -> Dict[str, Any] + Parses and returns the configuration data from the YAML file. """ def __init__(self, config_path: str): """ diff --git a/proxlb/utils/helper.py b/proxlb/utils/helper.py index 1d6df6c..e3bbe0f 100644 --- a/proxlb/utils/helper.py +++ b/proxlb/utils/helper.py @@ -3,6 +3,11 @@ The Helper class provides some basic helper functions to not mess up the code in classes. """ +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + import uuid import sys import time @@ -17,6 +22,22 @@ class Helper: """ The Helper class provides some basic helper functions to not mess up the code in other classes. + + Methods: + __init__(): + Initializes the general Helper class. + + get_uuid_string() -> str: + Generates a random uuid and returns it as a string. + + log_node_metrics(proxlb_data: Dict[str, Any], init: bool = True) -> None: + Logs the memory, CPU, and disk usage metrics of nodes in the provided proxlb_data dictionary. + + get_version(print_version: bool = False) -> None: + Returns the current version of ProxLB and optionally prints it to stdout. + + get_daemon_mode(proxlb_config: Dict[str, Any]) -> None: + Checks if the daemon mode is active and handles the scheduling accordingly. """ def __init__(self): """ diff --git a/proxlb/utils/logger.py b/proxlb/utils/logger.py index 3ecf259..57ed0e2 100644 --- a/proxlb/utils/logger.py +++ b/proxlb/utils/logger.py @@ -1,9 +1,13 @@ """ -The SystemdLogger class provides the root logger support. It dynamically -evaluates the further usage and imports of journald and adjusts -the logger to the systems functionality where it gets executed +The SystemdLogger class provides a singleton logger that integrates with systemd's journal if available. +It dynamically evaluates the environment and adjusts the logger accordingly. """ +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + import logging try: from systemd.journal import JournalHandler @@ -14,9 +18,36 @@ except ImportError: class SystemdLogger: """ - The SystemdLogger class provides the root logger support. It dynamically - evaluates the further usage and imports of journald and adjusts - the logger to the systems functionality where it gets executed. + The SystemdLogger class provides a singleton logger that integrates with systemd's journal if available. + It dynamically evaluates the environment and adjusts the logger accordingly. + + Attributes: + instance (SystemdLogger): Singleton instance of the SystemdLogger class. + + Methods: + __new__(cls, name: str = "ProxLB", level: str = logging.INFO) -> 'SystemdLogger': + Creates a new instance of the SystemdLogger class or returns the existing instance. + + initialize_logger(self, name: str, level: str) -> None: + Initializes the logger with the given name and log level. Adds a JournalHandler if systemd is present. + + set_log_level(self, level: str) -> None: + Sets the log level for the logger and all its handlers. + + debug(self, msg: str) -> str: + Logs a message with level DEBUG. + + info(self, msg: str) -> str: + Logs a message with level INFO. + + warning(self, msg: str) -> str: + Logs a message with level WARNING. + + error(self, msg: str) -> str: + Logs a message with level ERROR. + + critical(self, msg: str) -> str: + Logs a message with level CRITICAL. """ # Create a singleton instance variable instance = None diff --git a/proxlb/utils/proxmox_api.py b/proxlb/utils/proxmox_api.py index ec277be..d9645e8 100644 --- a/proxlb/utils/proxmox_api.py +++ b/proxlb/utils/proxmox_api.py @@ -1,7 +1,18 @@ """ -Module providing a function printing python version. + The proxmox_api class manages connections to the Proxmox API by parsing the required objects + for the authentication which can be based on username/password or API tokens. + + This class provides methods to initialize the Proxmox API connection, test connectivity to + Proxmox hosts, and handle authentication using either username/password or API tokens. + It also includes functionality to distribute load across multiple Proxmox API endpoints + and manage SSL certificate validation. """ +__author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" + + try: import proxmoxer PROXMOXER_PRESENT = True @@ -42,20 +53,44 @@ logger = SystemdLogger() class ProxmoxApi: """ - Handles command-line argument parsing for ProxLB. + The proxmox_api class manages connections to the Proxmox API by parsing the required objects + for the authentication which can be based on username/password or API tokens. + + This class provides methods to initialize the Proxmox API connection, test connectivity to + Proxmox hosts, and handle authentication using either username/password or API tokens. + It also includes functionality to distribute load across multiple Proxmox API endpoints + and manage SSL certificate validation. + + Attributes: + logger (SystemdLogger): Logger instance for logging messages. + proxmox_api (proxmoxer.ProxmoxAPI): Authenticated ProxmoxAPI object. + + Methods: + __init__(proxlb_config: Dict[str, Any]) -> None: + Initializes the ProxmoxApi instance with the provided configuration. + __getattr__(name): + Delegates attribute access to the proxmox_api object. + api_connect_get_hosts(proxmox_api_endpoints: list) -> str: + Determines a working Proxmox API host from a list of endpoints. + test_api_proxmox_host(host: str) -> str: + Tests connectivity to a Proxmox host by resolving its IP address. + test_api_proxmox_host_ipv4(host: str, port: int = 8006, timeout: int = 1) -> bool: + Tests reachability of a Proxmox host on its IPv4 address. + test_api_proxmox_host_ipv6(host: str, port: int = 8006, timeout: int = 1) -> bool: + Tests reachability of a Proxmox host on its IPv6 address. + api_connect(proxlb_config: Dict[str, Any]) -> proxmoxer.ProxmoxAPI: + Establishes a connection to the Proxmox API using the provided configuration. """ def __init__(self, proxlb_config: Dict[str, Any]) -> None: """ - Initialize the ProxmoxApi instance. + Initializes the ProxmoxApi instance with the provided configuration. - This method sets up the ProxmoxApi instance by testing the required module dependencies - and establishing a connection to the Proxmox API using the provided configuration. + This constructor method sets up the Proxmox API connection by calling the + api_connect method with the given configuration dictionary. It logs the + initialization process for debugging purposes. Args: - proxlb_config (Dict[str, Any]): Configuration dictionary containing Proxmox API connection details. - - Returns: - None + proxlb_config (Dict[str, Any]): A dictionary containing the Proxmox API configuration. """ logger.debug("Starting: ProxmoxApi initialization.") self.proxmox_api = self.api_connect(proxlb_config) @@ -63,7 +98,7 @@ class ProxmoxApi: def __getattr__(self, name): """ - Delegate attribute access to proxmox_api. + Delegate attribute access to proxmox_api to the underlying proxmoxer module. """ return getattr(self.proxmox_api, name) diff --git a/proxlb/utils/version.py b/proxlb/utils/version.py index e94d60c..cad91a6 100644 --- a/proxlb/utils/version.py +++ b/proxlb/utils/version.py @@ -1,5 +1,7 @@ __app_name__ = "ProxLB" __app_desc__ = "A DRS alike loadbalancer for Proxmox clusters." __author__ = "Florian Paul Azim Hoberg " +__copyright__ = "Copyright (C) 2025 Florian Paul Azim Hoberg (@gyptazy)" +__license__ = "GPL-3.0" __version__ = "1.1.0-alpha" __url__ = "https://github.com/gyptazy/ProxLB"