Compare commits

...

8 Commits

Author SHA1 Message Date
Florian
5542b9bc6c Merge pull request #116 from gyptazy/release/prepare-release-1.0.5
release: Create release 1.0.5
2024-10-30 17:13:06 +01:00
gyptazy
16c5ee4d74 release: Create release 1.0.5 2024-10-30 17:04:14 +01:00
Alex Shut
21a73b71df Allow migration from local disks (#113)
Add parameter `with-local-disks=1` to allow migration from local disks.
2024-10-19 08:17:10 +02:00
Elliot Nevills
d3c055cbad fix: bug to allow log_verbosity be set to DEBUG, WARN, and WARNING (#98)
* fixed bug to allow log_verbosity be set to DEBUG, WARN, and WARNING

* removed WARN logging verbosity option

* adjusted for logging verbosity options

* add to changelog

* added fix log verbosity issue to changelog
2024-10-18 21:21:35 +02:00
Florian
24b7d2c860 Merge pull request #111 from gyptazy/fix/106-fix-maintenance-node-eval
fix: Fix offline node evaluation & maintenance compare of different type objects
2024-10-18 21:20:54 +02:00
gyptazy
6e87e2d478 fix: Fix offline node evaluation & maintenance compare of different type objects
- Fix node (and its objects) evaluation when not reachable (e.g., maintenance).
  - Fix evaluation of maintenance mode where comparing list & string resulted in a crash (by @glitchvern).
  - Set ProxLB version to 1.0.5b

Fixes: #160
Fixes: #107
Contributed-by: @glitchvern
2024-10-17 13:32:47 +02:00
Florian
2593b87d3f Merge pull request #105 from gyptazy/fix/104-adjust-docs-parallel-migration
fix(docs): Change docs to make bool usage in configs more clear.
2024-10-16 08:48:56 +02:00
gyptazy
6310262e97 fix(docs): Change docs to make bool usage in configs more clear.
Fixes: #104
2024-10-16 08:19:16 +02:00
14 changed files with 188 additions and 139 deletions

View File

@@ -0,0 +1,2 @@
changed:
- Change docs to make bool usage in configs more clear (by @gyptazy). [#104]

View File

@@ -0,0 +1,2 @@
fixed:
- Fix evaluation of maintenance mode where comparing list & string resulted in a crash (by @glitchvern). [#106]

View File

@@ -0,0 +1,2 @@
fixed:
- Fix node (and its objects) evaluation when not reachable, e.g., maintenance (by @gyptazy). [#107]

View File

@@ -0,0 +1,2 @@
fixed:
- Fix migration from local disks (by @greenlogles). [#113]

View File

@@ -0,0 +1,2 @@
fixed:
- Fix allowed values (add DEBUG, WARNING) for log verbosity (by @gyptazy). [#98]

View File

@@ -0,0 +1 @@
date: 2024-10-30

View File

@@ -0,0 +1 @@
date: TBD

View File

@@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.5] - 2024-10-30
### Changed
- Change docs to make bool usage in configs more clear. [#104]
### Fixed
- Fix migration from local disks (by @greenlogles). [#113]
- Fix allowed values (add DEBUG, WARNING) for log verbosity. [#98]
- Fix node (and its objects) evaluation when not reachable (e.g., maintenance). [#107]
- Fix evaluation of maintenance mode where comparing list & string resulted in a crash (by @glitchvern). [#106]
## [1.0.4] - 2024-10-11
### Added

View File

@@ -29,7 +29,7 @@ Before submitting a pull request, ensure that your changes sucessfully perform t
1. **Install pytest if you haven't already:**
```sh
pip install fake8
pip install flake8
```
2. **Run the lintin:**
@@ -118,4 +118,4 @@ By participating in this project, you agree to abide by our [Code of Conduct](CO
If you need help or have any questions, feel free to reach out by creating an issue or by joining our [discussion forum](https://github.com/gyptazy/proxlb/discussions). You can also refer to our [documentation](https://github.com/gyptazy/ProxLB/tree/main/docs) for more information about the project or join our [chat room](https://matrix.to/#/#proxlb:gyptazy.ch) in Matrix.
Thank you for contributing to ProxLB! Together, we can enhance the efficiency and performance of Proxmox clusters.
Thank you for contributing to ProxLB! Together, we can enhance the efficiency and performance of Proxmox clusters.

View File

@@ -113,7 +113,7 @@ The following options can be set in the `proxlb.conf` file:
| `proxmox` | api_host | hypervisor01.gyptazy.com | Host or IP address (or comma separated list) of the remote Proxmox API. |
| | api_user | root@pam | Username for the API. |
| | api_pass | FooBar | Password for the API. |
| | verify_ssl | 1 | Validate SSL certificates (1) or ignore (0). (default: 1) |
| | verify_ssl | 1 | Validate SSL certificates (1) or ignore (0). (default: 1, type: bool) |
| | timeout | 10 | Timeout for the Proxmox API in sec. (default: 10) |
| `vm_balancing` | enable | 1 | Enables VM/CT balancing. |
| | method | memory | Defines the balancing method (default: memory) where you can use `memory`, `disk` or `cpu`. |
@@ -121,19 +121,19 @@ The following options can be set in the `proxlb.conf` file:
| | mode_option | byte | Rebalance by node's resources in `bytes` or `percent`. (default: bytes) |
| | type | vm | Rebalance only `vm` (virtual machines), `ct` (containers) or `all` (virtual machines & containers). (default: vm)|
| | balanciness | 10 | Value of the percentage of lowest and highest resource consumption on nodes may differ before rebalancing. (default: 10) |
| | parallel_migrations | 1 | Defines if migrations should be done parallely or sequentially. (default: 1) |
| | parallel_migrations | 1 | Defines if migrations should be done parallely or sequentially. (default: 1, type: bool) |
| | maintenance_nodes | dummynode03,dummynode04 | Defines a comma separated list of nodes to set them into maintenance mode and move VMs/CTs to other nodes. |
| | 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) |
| `storage_balancing` | enable | 0 | Enables storage balancing. |
| | balanciness | 10 | Value of the percentage of lowest and highest storage consumption may differ before rebalancing. (default: 10) |
| | parallel_migrations | 1 | Defines if migrations should be done parallely or sequentially. (default: 1) |
| `update_service` | enable | 0 | Enables the automated update service (rolling updates). |
| | parallel_migrations | 1 | Defines if migrations should be done parallely or sequentially. (default: 1, type: bool) |
| `update_service` | enable | 0 | Enables the automated update service (rolling updates). (default: 0, type: bool) |
| `api` | enable | 0 | Enables the ProxLB API. |
| `service`| daemon | 1 | Run as a daemon (1) or one-shot (0). (default: 1) |
| `service`| daemon | 1 | Run as a daemon (1) or one-shot (0). (default: 1, type: bool) |
| | schedule | 24 | Hours to rebalance in hours. (default: 24) |
| | master_only | 0 | Defines is this should only be performed (1) on the cluster master node or not (0). (default: 0) |
| | log_verbosity | INFO | Defines the log level (default: CRITICAL) where you can use `INFO`, `WARN` or `CRITICAL` |
| | master_only | 0 | Defines is this should only be performed (1) on the cluster master node or not (0). (default: 0, type: bool) |
| | log_verbosity | INFO | Defines the log level (default: CRITICAL) where you can use `DEBUG`, `INFO`, `WARNING` or `CRITICAL` |
| | config_version | 3 | Defines the current config version schema for ProxLB |
An example of the configuration file looks like:
@@ -270,8 +270,8 @@ The executable must be able to read the config file, if no dedicated config file
The easiest way to get started is by using the ready-to-use packages that I provide on my CDN and to run it on a Linux Debian based system. This can also be one of the Proxmox nodes itself.
```
wget https://cdn.gyptazy.com/files/os/debian/proxlb/proxlb_1.0.4_amd64.deb
dpkg -i proxlb_1.0.4_amd64.deb
wget https://cdn.gyptazy.com/files/os/debian/proxlb/proxlb_1.0.5_amd64.deb
dpkg -i proxlb_1.0.5_amd64.deb
# Adjust your config
vi /etc/proxlb/proxlb.conf
systemctl restart proxlb
@@ -368,6 +368,7 @@ Container Images for Podman, Docker etc., can be found at:
| Version | Image |
|------|:------:|
| latest | cr.gyptazy.com/proxlb/proxlb:latest |
| v1.0.5 | cr.gyptazy.com/proxlb/proxlb:v1.0.5 |
| v1.0.4 | cr.gyptazy.com/proxlb/proxlb:v1.0.4 |
| v1.0.3 | cr.gyptazy.com/proxlb/proxlb:v1.0.3 |
| v1.0.2 | cr.gyptazy.com/proxlb/proxlb:v1.0.2 |

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project(proxmox-rebalancing-service VERSION 1.0.4)
project(proxmox-rebalancing-service VERSION 1.0.5)
install(PROGRAMS ../proxlb DESTINATION /bin)
install(FILES ../proxlb.conf DESTINATION /etc/proxlb)
@@ -9,8 +9,8 @@ install(FILES proxlb.service DESTINATION /etc/systemd/system)
set(CPACK_PACKAGE_NAME "proxlb")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/../LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/../README.md")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Florian Paul Azim <gyptazy> Hoberg <gyptazy@gyptazy.ch>")
set(CPACK_PACKAGE_CONTACT "Florian Paul Azim Hoberg <gyptazy@gyptazy.ch>")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Florian Paul Azim <gyptazy> Hoberg <gyptazy@gyptazy.com>")
set(CPACK_PACKAGE_CONTACT "Florian Paul Azim Hoberg <gyptazy@gyptazy.com>")
set(CPACK_PACKAGE_VENDOR "gyptazy")
# RPM packaging

View File

@@ -1,3 +1,13 @@
proxlb (1.0.5) unstable; urgency=low
* Fix migration from local disks.
* Fix allowed values (add DEBUG, WARNING) for log verbosity.
* Fix node (and its objects) evaluation when not reachable (e.g., maintenance).
* Fix evaluation of maintenance mode where comparing list & string resulted in a crash.
* Change docs to make bool usage in configs more clear.
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.com> Wed, 30 Oct 2024 17:02:31 +0100
proxlb (1.0.4) unstable; urgency=low
* Add feature to make API timeout configureable.
@@ -8,7 +18,7 @@ proxlb (1.0.4) unstable; urgency=low
* Fix CPU balancing where calculations are done in float instead of int. (by @glitchvern)
* Fix documentation for the underlying infrastructure.
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.ch> Fri, 11 Oct 2024 06:14:13 +0200
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.com> Fri, 11 Oct 2024 06:14:13 +0200
proxlb (1.0.3) unstable; urgency=low
@@ -28,7 +38,7 @@ proxlb (1.0.3) unstable; urgency=low
* Fix handling of unset `ignore_nodes` and `ignore_vms` resulted in an attribute error.
* Fix anti-affinity rules not evaluating a new and different node.
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.ch> Wed, 11 Sep 2024 17:31:03 +0200
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.com> Wed, 11 Sep 2024 17:31:03 +0200
proxlb (1.0.2) unstable; urgency=low
@@ -38,16 +48,16 @@ proxlb (1.0.2) unstable; urgency=low
* Fix CMake packaging for Debian package to avoid overwriting the config file.
* Fix some wonkey code styles.
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.ch> Tue, 13 Aug 2024 17:28:14 +0200
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.com> Tue, 13 Aug 2024 17:28:14 +0200
proxlb (1.0.0) unstable; urgency=low
* Initial release of ProxLB.
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.ch> Thu, 01 Aug 2024 17:04:12 +0200
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.com> Thu, 01 Aug 2024 17:04:12 +0200
proxlb (0.9.0) unstable; urgency=low
* Initial development release of ProxLB as a tech preview.
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.ch> Sun, 07 Jul 2024 05:38:41 +0200
-- Florian Paul Azim Hoberg <gyptazy@gyptazy.com> Sun, 07 Jul 2024 05:38:41 +0200

View File

@@ -1,4 +1,11 @@
* Fri Oct 11 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.ch>
* Wed Oct 30 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.com>
- Fix migration from local disks.
- Fix allowed values (add DEBUG, WARNING) for log verbosity.
- Fix node (and its objects) evaluation when not reachable (e.g., maintenance).
- Fix evaluation of maintenance mode where comparing list & string resulted in a crash.
- Change docs to make bool usage in configs more clear.
* Fri Oct 11 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.com>
- Add feature to make API timeout configureable.
- Add maintenance mode to evacuate a node and move workloads for other nodes in the cluster.
- Add version output cli arg.
@@ -7,7 +14,7 @@
- Fix CPU balancing where calculations are done in float instead of int. (by @glitchvern)
- Fix documentation for the underlying infrastructure.
* Wed Sep 12 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.ch>
* Wed Sep 12 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.com>
- Add a convert function to cast all bool alike options from configparser to bools.
- Add a config parser options for future features.
- Add a config versio schema that must be supported by ProxLB.
@@ -24,14 +31,14 @@
- Fix handling of unset `ignore_nodes` and `ignore_vms` resulted in an attribute error.
- Fix anti-affinity rules not evaluating a new and different node.
* Tue Aug 13 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.ch>
* Tue Aug 13 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.com>
- Add option to run migration in parallel or sequentially.
- Add option to run ProxLB only on a Proxmox cluster master (req. HA feature).
- Fixed daemon timer to use hours instead of minutes.
- Fixed some wonkey code styles.
* Thu Aug 01 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.ch>
* Thu Aug 01 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.com>
- Initial release of ProxLB.
* Sun Jul 07 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.ch>
* Sun Jul 07 2024 Florian Paul Azim Hoberg <gyptazy@gyptazy.com>
- Initial development release of ProxLB as a tech preview.

235
proxlb
View File

@@ -42,9 +42,9 @@ import urllib3
# Constants
__appname__ = "ProxLB"
__version__ = "1.0.4"
__version__ = "1.0.5"
__config_version__ = 3
__author__ = "Florian Paul Azim Hoberg <gyptazy@gyptazy.ch> @gyptazy"
__author__ = "Florian Paul Azim Hoberg <gyptazy@gyptazy.com> @gyptazy"
__errors__ = False
@@ -190,7 +190,7 @@ def __validate_config_content(proxlb_config):
'vm_balancing_mode_option': ['bytes', 'percent'],
'vm_balancing_type': ['vm', 'ct', 'all'],
'storage_balancing_method': ['disk_space'],
'log_verbosity': ['INFO', 'CRITICAL']
'log_verbosity': ['DEBUG', 'INFO', 'WARNING', 'CRITICAL']
}
for string_val in validate_string_options:
@@ -543,133 +543,136 @@ def get_vm_statistics(api_object, ignore_vms, balancing_type):
for node in api_object.nodes.get():
# Add all virtual machines if type is vm or all.
if balancing_type == 'vm' or balancing_type == 'all':
for vm in api_object.nodes(node['node']).qemu.get():
# Get VM/CT objects only when the node is online and reachable.
if node['status'] == 'online':
# Get the VM tags from API.
vm_tags = __get_vm_tags(api_object, node, vm['vmid'], 'vm')
if vm_tags is not None:
group_include, group_exclude, vm_ignore = __get_proxlb_groups(vm_tags)
# Add all virtual machines if type is vm or all.
if balancing_type == 'vm' or balancing_type == 'all':
for vm in api_object.nodes(node['node']).qemu.get():
# Get wildcard match for VMs to ignore if a wildcard pattern was
# previously found. Wildcards may slow down the task when using
# many patterns in the ignore list. Therefore, run this only if
# a wildcard pattern was found. We also do not need to validate
# this if the VM is already being ignored by a defined tag.
if vm_ignore_wildcard and not vm_ignore:
vm_ignore = __check_vm_name_wildcard_pattern(vm['name'], ignore_vms_list)
# Get the VM tags from API.
vm_tags = __get_vm_tags(api_object, node, vm['vmid'], 'vm')
if vm_tags is not None:
group_include, group_exclude, vm_ignore = __get_proxlb_groups(vm_tags)
if vm['status'] == 'running' and vm['name'] not in ignore_vms_list and not vm_ignore:
vm_statistics[vm['name']] = {}
vm_statistics[vm['name']]['group_include'] = group_include
vm_statistics[vm['name']]['group_exclude'] = group_exclude
vm_statistics[vm['name']]['cpu_total'] = vm['cpus']
vm_statistics[vm['name']]['cpu_used'] = vm['cpu']
vm_statistics[vm['name']]['memory_total'] = vm['maxmem']
vm_statistics[vm['name']]['memory_used'] = vm['mem']
vm_statistics[vm['name']]['disk_total'] = vm['maxdisk']
vm_statistics[vm['name']]['disk_used'] = vm['disk']
vm_statistics[vm['name']]['vmid'] = vm['vmid']
vm_statistics[vm['name']]['node_parent'] = node['node']
vm_statistics[vm['name']]['node_rebalance'] = node['node']
vm_statistics[vm['name']]['storage'] = {}
vm_statistics[vm['name']]['type'] = 'vm'
# Get wildcard match for VMs to ignore if a wildcard pattern was
# previously found. Wildcards may slow down the task when using
# many patterns in the ignore list. Therefore, run this only if
# a wildcard pattern was found. We also do not need to validate
# this if the VM is already being ignored by a defined tag.
if vm_ignore_wildcard and not vm_ignore:
vm_ignore = __check_vm_name_wildcard_pattern(vm['name'], ignore_vms_list)
# Get disk details of the related object.
_vm_details = api_object.nodes(node['node']).qemu(vm['vmid']).config.get()
logging.info(f'{info_prefix} Getting disk information for vm {vm["name"]}.')
if vm['status'] == 'running' and vm['name'] not in ignore_vms_list and not vm_ignore:
vm_statistics[vm['name']] = {}
vm_statistics[vm['name']]['group_include'] = group_include
vm_statistics[vm['name']]['group_exclude'] = group_exclude
vm_statistics[vm['name']]['cpu_total'] = vm['cpus']
vm_statistics[vm['name']]['cpu_used'] = vm['cpu']
vm_statistics[vm['name']]['memory_total'] = vm['maxmem']
vm_statistics[vm['name']]['memory_used'] = vm['mem']
vm_statistics[vm['name']]['disk_total'] = vm['maxdisk']
vm_statistics[vm['name']]['disk_used'] = vm['disk']
vm_statistics[vm['name']]['vmid'] = vm['vmid']
vm_statistics[vm['name']]['node_parent'] = node['node']
vm_statistics[vm['name']]['node_rebalance'] = node['node']
vm_statistics[vm['name']]['storage'] = {}
vm_statistics[vm['name']]['type'] = 'vm'
for vm_detail_key, vm_detail_value in _vm_details.items():
# vm_detail_key_validator = re.sub('\d+$', '', vm_detail_key)
vm_detail_key_validator = re.sub(r'\d+$', '', vm_detail_key)
# Get disk details of the related object.
_vm_details = api_object.nodes(node['node']).qemu(vm['vmid']).config.get()
logging.info(f'{info_prefix} Getting disk information for vm {vm["name"]}.')
if vm_detail_key_validator in _vm_details_storage_allowed:
vm_statistics[vm['name']]['storage'][vm_detail_key] = {}
match = re.match(r'([^:]+):[^/]+/(.+),iothread=\d+,size=(\d+G)', _vm_details[vm_detail_key])
for vm_detail_key, vm_detail_value in _vm_details.items():
# vm_detail_key_validator = re.sub('\d+$', '', vm_detail_key)
vm_detail_key_validator = re.sub(r'\d+$', '', vm_detail_key)
# Create an efficient match group and split the strings to assign them to the storage information.
if match:
_volume = match.group(1)
_disk_name = match.group(2)
_disk_size = match.group(3)
if vm_detail_key_validator in _vm_details_storage_allowed:
vm_statistics[vm['name']]['storage'][vm_detail_key] = {}
match = re.match(r'([^:]+):[^/]+/(.+),iothread=\d+,size=(\d+G)', _vm_details[vm_detail_key])
vm_statistics[vm['name']]['storage'][vm_detail_key]['name'] = _disk_name
vm_statistics[vm['name']]['storage'][vm_detail_key]['device_name'] = vm_detail_key
vm_statistics[vm['name']]['storage'][vm_detail_key]['volume'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['storage_parent'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['storage_rebalance'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['size'] = _disk_size[:-1]
logging.info(f'{info_prefix} Added disk for {vm["name"]}: Name {_disk_name} on volume {_volume} with size {_disk_size}.')
else:
logging.info(f'{info_prefix} No (or unsupported) disk(s) for {vm["name"]} found.')
# Create an efficient match group and split the strings to assign them to the storage information.
if match:
_volume = match.group(1)
_disk_name = match.group(2)
_disk_size = match.group(3)
logging.info(f'{info_prefix} Added vm {vm["name"]}.')
vm_statistics[vm['name']]['storage'][vm_detail_key]['name'] = _disk_name
vm_statistics[vm['name']]['storage'][vm_detail_key]['device_name'] = vm_detail_key
vm_statistics[vm['name']]['storage'][vm_detail_key]['volume'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['storage_parent'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['storage_rebalance'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['size'] = _disk_size[:-1]
logging.info(f'{info_prefix} Added disk for {vm["name"]}: Name {_disk_name} on volume {_volume} with size {_disk_size}.')
else:
logging.info(f'{info_prefix} No (or unsupported) disk(s) for {vm["name"]} found.')
# Add all containers if type is ct or all.
if balancing_type == 'ct' or balancing_type == 'all':
for vm in api_object.nodes(node['node']).lxc.get():
logging.info(f'{info_prefix} Added vm {vm["name"]}.')
logging.warning(f'{warn_prefix} Rebalancing on LXC containers (CT) always requires them to shut down.')
logging.warning(f'{warn_prefix} {vm["name"]} is from type CT and cannot be live migrated!')
# Get the VM tags from API.
vm_tags = __get_vm_tags(api_object, node, vm['vmid'], 'ct')
if vm_tags is not None:
group_include, group_exclude, vm_ignore = __get_proxlb_groups(vm_tags)
# Add all containers if type is ct or all.
if balancing_type == 'ct' or balancing_type == 'all':
for vm in api_object.nodes(node['node']).lxc.get():
# Get wildcard match for VMs to ignore if a wildcard pattern was
# previously found. Wildcards may slow down the task when using
# many patterns in the ignore list. Therefore, run this only if
# a wildcard pattern was found. We also do not need to validate
# this if the VM is already being ignored by a defined tag.
if vm_ignore_wildcard and not vm_ignore:
vm_ignore = __check_vm_name_wildcard_pattern(vm['name'], ignore_vms_list)
logging.warning(f'{warn_prefix} Rebalancing on LXC containers (CT) always requires them to shut down.')
logging.warning(f'{warn_prefix} {vm["name"]} is from type CT and cannot be live migrated!')
# Get the VM tags from API.
vm_tags = __get_vm_tags(api_object, node, vm['vmid'], 'ct')
if vm_tags is not None:
group_include, group_exclude, vm_ignore = __get_proxlb_groups(vm_tags)
if vm['status'] == 'running' and vm['name'] not in ignore_vms_list and not vm_ignore:
vm_statistics[vm['name']] = {}
vm_statistics[vm['name']]['group_include'] = group_include
vm_statistics[vm['name']]['group_exclude'] = group_exclude
vm_statistics[vm['name']]['cpu_total'] = vm['cpus']
vm_statistics[vm['name']]['cpu_used'] = vm['cpu']
vm_statistics[vm['name']]['memory_total'] = vm['maxmem']
vm_statistics[vm['name']]['memory_used'] = vm['mem']
vm_statistics[vm['name']]['disk_total'] = vm['maxdisk']
vm_statistics[vm['name']]['disk_used'] = vm['disk']
vm_statistics[vm['name']]['vmid'] = vm['vmid']
vm_statistics[vm['name']]['node_parent'] = node['node']
vm_statistics[vm['name']]['node_rebalance'] = node['node']
vm_statistics[vm['name']]['storage'] = {}
vm_statistics[vm['name']]['type'] = 'ct'
# Get wildcard match for VMs to ignore if a wildcard pattern was
# previously found. Wildcards may slow down the task when using
# many patterns in the ignore list. Therefore, run this only if
# a wildcard pattern was found. We also do not need to validate
# this if the VM is already being ignored by a defined tag.
if vm_ignore_wildcard and not vm_ignore:
vm_ignore = __check_vm_name_wildcard_pattern(vm['name'], ignore_vms_list)
# Get disk details of the related object.
_vm_details = api_object.nodes(node['node']).lxc(vm['vmid']).config.get()
logging.info(f'{info_prefix} Getting disk information for vm {vm["name"]}.')
if vm['status'] == 'running' and vm['name'] not in ignore_vms_list and not vm_ignore:
vm_statistics[vm['name']] = {}
vm_statistics[vm['name']]['group_include'] = group_include
vm_statistics[vm['name']]['group_exclude'] = group_exclude
vm_statistics[vm['name']]['cpu_total'] = vm['cpus']
vm_statistics[vm['name']]['cpu_used'] = vm['cpu']
vm_statistics[vm['name']]['memory_total'] = vm['maxmem']
vm_statistics[vm['name']]['memory_used'] = vm['mem']
vm_statistics[vm['name']]['disk_total'] = vm['maxdisk']
vm_statistics[vm['name']]['disk_used'] = vm['disk']
vm_statistics[vm['name']]['vmid'] = vm['vmid']
vm_statistics[vm['name']]['node_parent'] = node['node']
vm_statistics[vm['name']]['node_rebalance'] = node['node']
vm_statistics[vm['name']]['storage'] = {}
vm_statistics[vm['name']]['type'] = 'ct'
for vm_detail_key, vm_detail_value in _vm_details.items():
# vm_detail_key_validator = re.sub('\d+$', '', vm_detail_key)
vm_detail_key_validator = re.sub(r'\d+$', '', vm_detail_key)
# Get disk details of the related object.
_vm_details = api_object.nodes(node['node']).lxc(vm['vmid']).config.get()
logging.info(f'{info_prefix} Getting disk information for vm {vm["name"]}.')
if vm_detail_key_validator in _vm_details_storage_allowed:
vm_statistics[vm['name']]['storage'][vm_detail_key] = {}
match = re.match(r'(?P<volume>[^:]+):(?P<disk_name>[^,]+),size=(?P<disk_size>\S+)', _vm_details[vm_detail_key])
for vm_detail_key, vm_detail_value in _vm_details.items():
# vm_detail_key_validator = re.sub('\d+$', '', vm_detail_key)
vm_detail_key_validator = re.sub(r'\d+$', '', vm_detail_key)
# Create an efficient match group and split the strings to assign them to the storage information.
if match:
_volume = match.group(1)
_disk_name = match.group(2)
_disk_size = match.group(3)
if vm_detail_key_validator in _vm_details_storage_allowed:
vm_statistics[vm['name']]['storage'][vm_detail_key] = {}
match = re.match(r'(?P<volume>[^:]+):(?P<disk_name>[^,]+),size=(?P<disk_size>\S+)', _vm_details[vm_detail_key])
vm_statistics[vm['name']]['storage'][vm_detail_key]['name'] = _disk_name
vm_statistics[vm['name']]['storage'][vm_detail_key]['device_name'] = vm_detail_key
vm_statistics[vm['name']]['storage'][vm_detail_key]['volume'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['storage_parent'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['storage_rebalance'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['size'] = _disk_size[:-1]
logging.info(f'{info_prefix} Added disk for {vm["name"]}: Name {_disk_name} on volume {_volume} with size {_disk_size}.')
else:
logging.info(f'{info_prefix} No disks for {vm["name"]} found.')
# Create an efficient match group and split the strings to assign them to the storage information.
if match:
_volume = match.group(1)
_disk_name = match.group(2)
_disk_size = match.group(3)
logging.info(f'{info_prefix} Added vm {vm["name"]}.')
vm_statistics[vm['name']]['storage'][vm_detail_key]['name'] = _disk_name
vm_statistics[vm['name']]['storage'][vm_detail_key]['device_name'] = vm_detail_key
vm_statistics[vm['name']]['storage'][vm_detail_key]['volume'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['storage_parent'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['storage_rebalance'] = _volume
vm_statistics[vm['name']]['storage'][vm_detail_key]['size'] = _disk_size[:-1]
logging.info(f'{info_prefix} Added disk for {vm["name"]}: Name {_disk_name} on volume {_volume} with size {_disk_size}.')
else:
logging.info(f'{info_prefix} No disks for {vm["name"]} found.')
logging.info(f'{info_prefix} Added vm {vm["name"]}.')
logging.info(f'{info_prefix} Created VM statistics.')
return vm_statistics
@@ -882,7 +885,7 @@ def balancing_vm_maintenance(proxlb_config, app_args, node_statistics, vm_statis
return node_statistics, vm_statistics
for node_name in maintenance_nodes_list:
node_vms = sorted(vm_statistics.items(), key=lambda item: item[0] if item[1]['node_parent'] == node_name else [])
node_vms = list(filter(lambda item: item[0] if item[1]['node_parent'] == node_name else [], vm_statistics.items()))
# Update resource statistics for VMs and nodes.
for vm in node_vms:
resources_node_most_free = __get_most_free_resources_node(balancing_method, balancing_mode, balancing_mode_option, node_statistics)
@@ -954,8 +957,9 @@ def __validate_balanciness(balanciness, balancing_method, balancing_mode, node_s
return False
# Add node information to resource list.
node_resource_percent_list.append(int(node_info[f'{balancing_method}_{node_resource_selector}_percent']))
logging.debug(f'{info_prefix} Node: {node_name} with values: {node_info}')
if not node_statistics[node_name]['maintenance']:
node_resource_percent_list.append(int(node_info[f'{balancing_method}_{node_resource_selector}_percent']))
logging.debug(f'{info_prefix} Node: {node_name} with values: {node_info}')
# Create a sorted list of the delta + balanciness between the node resources.
node_resource_percent_list_sorted = sorted(node_resource_percent_list)
@@ -1185,7 +1189,8 @@ def __run_vm_rebalancing(api_object, _vm_vm_statistics, app_args, parallel_migra
# Migrate type VM (live migration).
if value['type'] == 'vm':
logging.info(f'{info_prefix} Rebalancing VM {vm} from node {value["node_parent"]} to node {value["node_rebalance"]}.')
job_id = api_object.nodes(value['node_parent']).qemu(value['vmid']).migrate().post(target=value['node_rebalance'],online=1)
options = {'target': value['node_rebalance'], 'online': 1, 'with-local-disks': 1}
job_id = api_object.nodes(value['node_parent']).qemu(value['vmid']).migrate().post(**options)
# Migrate type CT (requires restart of container).
if value['type'] == 'ct':