Compare commits

...

3 Commits

Author SHA1 Message Date
illustris
066753ebc7
Bump version to 1.3.0 2025-03-08 15:08:56 +05:30
illustris
46bd7d67d2
Add pool information to VM metrics
- Parse /etc/pve/user.cfg to extract pool membership for VMs
- Add pool-related labels to pve_kvm info metrics:
  - pool: Full hierarchical pool name
  - pool_levels: Number of pool hierarchy levels
  - pool1/pool2/pool3: Individual pool hierarchy levels
- Cache pool data based on file modification time to avoid repeated reads
2025-03-08 15:07:02 +05:30
illustris
7923d425a5
Create LICENSE 2024-09-09 01:06:49 +05:30
4 changed files with 114 additions and 4 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Harikrishnan R
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -14,7 +14,7 @@ rec {
packages.x86_64-linux = with nixpkgs.legacyPackages.x86_64-linux; rec {
pvemon = python3Packages.buildPythonApplication {
pname = "pvemon";
version = "1.2.0";
version = "1.3.0";
src = ./src;
propagatedBuildInputs = with python3Packages; [
pexpect

View File

@ -24,6 +24,13 @@ import qmblock
import builtins
# Cache for pool data
pool_cache = {
'last_mtime': 0,
'vm_pool_map': {},
'pools': {}
}
DEFAULT_PORT = 9116
DEFAULT_INTERVAL = 10
DEFAULT_PREFIX = "pve"
@ -135,6 +142,67 @@ def read_interface_stats(ifname):
pass
return stats
def get_pool_info():
"""
Read pool information from /etc/pve/user.cfg, caching based on file modification time.
Returns a tuple of (vm_to_pool_map, pool_info) where:
- vm_to_pool_map maps VM IDs to their pool names
- pool_info contains details about each pool (levels, etc.)
"""
pool_cfg_path = '/etc/pve/user.cfg'
try:
# Check modification time
current_mtime = os.path.getmtime(pool_cfg_path)
# If file hasn't changed, return cached data
if current_mtime <= pool_cache['last_mtime'] and pool_cache['vm_pool_map']:
return pool_cache['vm_pool_map'], pool_cache['pools']
# File has changed or first run, parse it
logging.debug(f"Reading pool configuration from {pool_cfg_path}")
vm_pool_map = {}
pools = {}
with open(pool_cfg_path, 'r') as f:
for line in f:
if line.startswith('pool:'):
parts = line.strip().split(':')
if len(parts) < 3:
continue
pool_name = parts[1]
vm_list = parts[3] if len(parts) > 3 else ''
# Store pool info
pool_parts = pool_name.split('/')
pool_level_count = len(pool_parts)
pools[pool_name] = {
'level_count': pool_level_count,
'level1': pool_parts[0] if pool_level_count > 0 else '',
'level2': pool_parts[1] if pool_level_count > 1 else '',
'level3': pool_parts[2] if pool_level_count > 2 else ''
}
# Map VMs to this pool
if vm_list:
for vm_id in vm_list.split(','):
if vm_id.strip():
vm_pool_map[vm_id.strip()] = pool_name
# Update cache
pool_cache['last_mtime'] = current_mtime
pool_cache['vm_pool_map'] = vm_pool_map
pool_cache['pools'] = pools
return vm_pool_map, pools
except (FileNotFoundError, PermissionError) as e:
logging.warning(f"Could not read pool configuration: {e}")
return {}, {}
def collect_kvm_metrics():
logging.debug("collect_kvm_metrics() called")
gauge_dict = {}
@ -170,13 +238,34 @@ def collect_kvm_metrics():
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
continue
# Try to find ID to pool mapping here
# Get VM to pool mapping
vm_pool_map, pools = get_pool_info()
for proc, cmdline, id in procs:
# Extract vm labels from cmdline
info_label_dict = {get_label_name(l): flag_to_label_value(cmdline,l) for l in label_flags}
info_label_dict['pid']=str(proc.pid)
info_label_dict['pid'] = str(proc.pid)
logging.debug(f"got PID: {proc.pid}")
# Add pool information if available
if id in vm_pool_map:
pool_name = vm_pool_map[id]
pool_info = pools[pool_name]
info_label_dict['pool'] = pool_name
info_label_dict['pool_levels'] = str(pool_info['level_count'])
info_label_dict['pool1'] = pool_info['level1']
info_label_dict['pool2'] = pool_info['level2']
info_label_dict['pool3'] = pool_info['level3']
logging.debug(f"VM {id} belongs to pool {pool_name}")
else:
# VM not in any pool
info_label_dict['pool'] = ''
info_label_dict['pool_levels'] = '0'
info_label_dict['pool1'] = ''
info_label_dict['pool2'] = ''
info_label_dict['pool3'] = ''
info_dict["kvm"].add_metric([], info_label_dict)
d = {

View File

@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup(
name='pvemon',
version = "1.2.0",
version = "1.3.0",
packages=find_packages(),
entry_points={
'console_scripts': [