-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: Add option to run ProxLB only on the Proxmox's master node i…
…n the cluster. Fixes: #40
- Loading branch information
Showing
3 changed files
with
59 additions
and
4 deletions.
There are no files selected for viewing
2 changes: 2 additions & 0 deletions
2
.changelogs/1.1.0/40_add_option_to_run_only_on_cluster_master_node.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
added: | ||
- Add option to run ProxLB only on the Proxmox's master node in the cluster. [40] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,14 +33,15 @@ except ImportError: | |
import random | ||
import re | ||
import requests | ||
import socket | ||
import sys | ||
import time | ||
import urllib3 | ||
|
||
|
||
# Constants | ||
__appname__ = "ProxLB" | ||
__version__ = "1.0.0" | ||
__version__ = "1.1.0b" | ||
__author__ = "Florian Paul Azim Hoberg <[email protected]> @gyptazy" | ||
__errors__ = False | ||
|
||
|
@@ -187,6 +188,7 @@ def initialize_config_options(config_path): | |
ignore_nodes = config['balancing'].get('ignore_nodes', None) | ||
ignore_vms = config['balancing'].get('ignore_vms', None) | ||
# Service | ||
master_only = config['service'].get('master_only', 0) | ||
daemon = config['service'].get('daemon', 1) | ||
schedule = config['service'].get('schedule', 24) | ||
log_verbosity = config['service'].get('log_verbosity', 'CRITICAL') | ||
|
@@ -201,8 +203,8 @@ def initialize_config_options(config_path): | |
sys.exit(2) | ||
|
||
logging.info(f'{info_prefix} Configuration file loaded.') | ||
return proxmox_api_host, proxmox_api_user, proxmox_api_pass, proxmox_api_ssl_v, balancing_method, balancing_mode, \ | ||
balancing_mode_option, balancing_type, balanciness, parallel_migrations, ignore_nodes, ignore_vms, daemon, schedule, log_verbosity | ||
return proxmox_api_host, proxmox_api_user, proxmox_api_pass, proxmox_api_ssl_v, balancing_method, balancing_mode, balancing_mode_option, \ | ||
balancing_type, balanciness, parallel_migrations, ignore_nodes, ignore_vms, master_only, daemon, schedule, log_verbosity | ||
|
||
|
||
def api_connect(proxmox_api_host, proxmox_api_user, proxmox_api_pass, proxmox_api_ssl_v): | ||
|
@@ -232,6 +234,42 @@ def api_connect(proxmox_api_host, proxmox_api_user, proxmox_api_pass, proxmox_ap | |
return api_object | ||
|
||
|
||
def get_cluster_master(api_object): | ||
""" Get the current master of the Proxmox cluster. """ | ||
error_prefix = 'Error: [cluster-master-getter]:' | ||
info_prefix = 'Info: [cluster-master-getter]:' | ||
|
||
logging.info(f'{info_prefix} Getting master node from cluster.') | ||
try: | ||
ha_status_object = api_object.cluster().ha().status().manager_status().get() | ||
logging.info(f'{info_prefix} Master node: {ha_status_object["manager_status"]["master_node"]}') | ||
except urllib3.exceptions.NameResolutionError: | ||
logging.critical(f'{error_prefix} Could not resolve the given host: {proxmox_api_host}.') | ||
sys.exit(2) | ||
except requests.exceptions.ConnectTimeout: | ||
logging.critical(f'{error_prefix} Connection time out to host: {proxmox_api_host}.') | ||
sys.exit(2) | ||
except requests.exceptions.SSLError: | ||
logging.critical(f'{error_prefix} SSL certificate verification failed for host: {proxmox_api_host}.') | ||
sys.exit(2) | ||
|
||
return ha_status_object['manager_status']['master_node'] | ||
|
||
|
||
def validate_cluster_master(cluster_master): | ||
""" Validate if the current execution node is the cluster master. """ | ||
info_prefix = 'Info: [cluster-master-validator]:' | ||
|
||
node_executor_hostname = socket.gethostname() | ||
logging.info(f'{info_prefix} Node executor hostname is: {node_executor_hostname}') | ||
|
||
if node_executor_hostname != cluster_master: | ||
logging.info(f'{info_prefix} {node_executor_hostname} is not the cluster master ({cluster_master}).') | ||
return False | ||
else: | ||
return True | ||
|
||
|
||
def get_node_statistics(api_object, ignore_nodes): | ||
""" Get statistics of cpu, memory and disk for each node in the cluster. """ | ||
info_prefix = 'Info: [node-statistics]:' | ||
|
@@ -834,7 +872,7 @@ def main(): | |
|
||
# Parse global config. | ||
proxmox_api_host, proxmox_api_user, proxmox_api_pass, proxmox_api_ssl_v, balancing_method, balancing_mode, balancing_mode_option, balancing_type, \ | ||
balanciness, parallel_migrations, ignore_nodes, ignore_vms, daemon, schedule, log_verbosity = initialize_config_options(config_path) | ||
balanciness, parallel_migrations, ignore_nodes, ignore_vms, master_only, daemon, schedule, log_verbosity = initialize_config_options(config_path) | ||
|
||
# Overwrite logging handler with user defined log verbosity. | ||
initialize_logger(log_verbosity, update_log_verbosity=True) | ||
|
@@ -843,6 +881,16 @@ def main(): | |
# API Authentication. | ||
api_object = api_connect(proxmox_api_host, proxmox_api_user, proxmox_api_pass, proxmox_api_ssl_v) | ||
|
||
# Get master node of cluster and ensure that ProxLB is only performed on the | ||
# cluster master node to avoid ongoing rebalancing. | ||
if bool(int(master_only)): | ||
cluster_master_node = get_cluster_master(api_object) | ||
cluster_master = validate_cluster_master(cluster_master_node) | ||
# Validate daemon service and skip following tasks when not being the cluster master. | ||
if not cluster_master: | ||
validate_daemon(daemon, schedule) | ||
continue | ||
|
||
# Get metric & statistics for vms and nodes. | ||
node_statistics = get_node_statistics(api_object, ignore_nodes) | ||
vm_statistics = get_vm_statistics(api_object, ignore_vms, balancing_type) | ||
|