mirror of
https://github.com/gyptazy/ProxLB.git
synced 2026-04-06 04:41:58 +02:00
Merge pull request #43 from gyptazy/feature/40-option-run-only-on-master-node
feature: Add option to run ProxLB only on the Proxmox's master node in the cluster.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
added:
|
||||
- Add option to run ProxLB only on the Proxmox's master node in the cluster. [40]
|
||||
@@ -112,6 +112,7 @@ The following options can be set in the `proxlb.conf` file:
|
||||
| parallel_migrations | 1 | Defines if migrations should be done parallely or sequentially. (default: 1) |
|
||||
| ignore_nodes | dummynode01,dummynode02,test* | Defines a comma separated list of nodes to exclude. |
|
||||
| ignore_vms | testvm01,testvm02 | Defines a comma separated list of VMs to exclude. (`*` as suffix wildcard or tags are also supported) |
|
||||
| master_only | 0 | Defines is this should only be performed (1) on the cluster master node or not (0). (default: 0) |
|
||||
| daemon | 1 | Run as a daemon (1) or one-shot (0). (default: 1) |
|
||||
| schedule | 24 | Hours to rebalance in hours. (default: 24) |
|
||||
| log_verbosity | INFO | Defines the log level (default: CRITICAL) where you can use `INFO`, `WARN` or `CRITICAL` |
|
||||
@@ -140,6 +141,10 @@ parallel_migrations: 1
|
||||
ignore_nodes: dummynode01,dummynode02
|
||||
ignore_vms: testvm01,testvm02
|
||||
[service]
|
||||
# The master_only option might be usuful if running ProxLB on all nodes in a cluster
|
||||
# but only a single one should do the balancing. The master node is obtained from the Proxmox
|
||||
# HA status.
|
||||
master_only: 0
|
||||
daemon: 1
|
||||
```
|
||||
|
||||
|
||||
56
proxlb
56
proxlb
@@ -33,6 +33,7 @@ except ImportError:
|
||||
import random
|
||||
import re
|
||||
import requests
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
import urllib3
|
||||
@@ -40,7 +41,7 @@ import urllib3
|
||||
|
||||
# Constants
|
||||
__appname__ = "ProxLB"
|
||||
__version__ = "1.0.0"
|
||||
__version__ = "1.1.0b"
|
||||
__author__ = "Florian Paul Azim Hoberg <gyptazy@gyptazy.ch> @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 API.')
|
||||
sys.exit(2)
|
||||
except requests.exceptions.ConnectTimeout:
|
||||
logging.critical(f'{error_prefix} Connection time out to API.')
|
||||
sys.exit(2)
|
||||
except requests.exceptions.SSLError:
|
||||
logging.critical(f'{error_prefix} SSL certificate verification failed for API.')
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user