Compare commits
1 Commits
master
...
e4573e0835
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4573e0835
|
21
LICENSE
21
LICENSE
@@ -1,21 +0,0 @@
|
|||||||
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.
|
|
||||||
12
flake.lock
generated
12
flake.lock
generated
@@ -3,11 +3,11 @@
|
|||||||
"debBundler": {
|
"debBundler": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1746317543,
|
"lastModified": 1725149456,
|
||||||
"narHash": "sha256-1Xph5g1Lazzkc9XuY1nOkG5Fn7+lmSdldAC91boDawY=",
|
"narHash": "sha256-rRrSD7itoPm+VIT4bIzSupQ7jw+H4eOjxRiRA89Kxb4=",
|
||||||
"owner": "illustris",
|
"owner": "illustris",
|
||||||
"repo": "flake",
|
"repo": "flake",
|
||||||
"rev": "e86bd104d76d22b2ba36fede405e7bff290ef489",
|
"rev": "257a6c986cb9a67c4d6d0e0363507cab7f958b63",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -18,11 +18,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1746663147,
|
"lastModified": 1725103162,
|
||||||
"narHash": "sha256-Ua0drDHawlzNqJnclTJGf87dBmaO/tn7iZ+TCkTRpRc=",
|
"narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "dda3dcd3fe03e991015e9a74b22d35950f264a54",
|
"rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ rec {
|
|||||||
packages.x86_64-linux = with nixpkgs.legacyPackages.x86_64-linux; rec {
|
packages.x86_64-linux = with nixpkgs.legacyPackages.x86_64-linux; rec {
|
||||||
pvemon = python3Packages.buildPythonApplication {
|
pvemon = python3Packages.buildPythonApplication {
|
||||||
pname = "pvemon";
|
pname = "pvemon";
|
||||||
version = "1.3.3";
|
version = "1.2.0";
|
||||||
src = ./src;
|
src = ./src;
|
||||||
propagatedBuildInputs = with python3Packages; [
|
propagatedBuildInputs = with python3Packages; [
|
||||||
pexpect
|
pexpect
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ pool_cache = {
|
|||||||
DEFAULT_PORT = 9116
|
DEFAULT_PORT = 9116
|
||||||
DEFAULT_INTERVAL = 10
|
DEFAULT_INTERVAL = 10
|
||||||
DEFAULT_PREFIX = "pve"
|
DEFAULT_PREFIX = "pve"
|
||||||
DEFAULT_HOST = "0.0.0.0"
|
|
||||||
|
|
||||||
gauge_settings = [
|
gauge_settings = [
|
||||||
('kvm_cpu', 'CPU time for VM', ['id', 'mode']),
|
('kvm_cpu', 'CPU time for VM', ['id', 'mode']),
|
||||||
@@ -354,7 +353,6 @@ class PVECollector(object):
|
|||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='PVE metrics exporter for Prometheus')
|
parser = argparse.ArgumentParser(description='PVE metrics exporter for Prometheus')
|
||||||
parser.add_argument('--port', type=int, default=DEFAULT_PORT, help='Port for the exporter to listen on')
|
parser.add_argument('--port', type=int, default=DEFAULT_PORT, help='Port for the exporter to listen on')
|
||||||
parser.add_argument('--host', type=str, default=DEFAULT_HOST, help='Host address to bind the exporter to')
|
|
||||||
parser.add_argument('--interval', type=int, default=DEFAULT_INTERVAL, help='THIS OPTION DOES NOTHING')
|
parser.add_argument('--interval', type=int, default=DEFAULT_INTERVAL, help='THIS OPTION DOES NOTHING')
|
||||||
parser.add_argument('--collect-running-vms', type=str, default='true', help='Enable or disable collecting running VMs metric (true/false)')
|
parser.add_argument('--collect-running-vms', type=str, default='true', help='Enable or disable collecting running VMs metric (true/false)')
|
||||||
parser.add_argument('--collect-storage', type=str, default='true', help='Enable or disable collecting storage info (true/false)')
|
parser.add_argument('--collect-storage', type=str, default='true', help='Enable or disable collecting storage info (true/false)')
|
||||||
@@ -390,7 +388,7 @@ def main():
|
|||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
REGISTRY.register(PVECollector())
|
REGISTRY.register(PVECollector())
|
||||||
start_http_server(cli_args.port, addr=cli_args.host)
|
start_http_server(cli_args.port)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
time.sleep(100)
|
time.sleep(100)
|
||||||
|
|||||||
@@ -65,15 +65,9 @@ def parse_storage_cfg(file_path='/etc/pve/storage.cfg'):
|
|||||||
else:
|
else:
|
||||||
# Parse key-value pairs within the current storage
|
# Parse key-value pairs within the current storage
|
||||||
if current_storage:
|
if current_storage:
|
||||||
parts = line.split(None, 1)
|
key, value = line.split(None, 1)
|
||||||
key = parts[0].strip()
|
sanitized_key = sanitize_key(key.strip())
|
||||||
sanitized_key = sanitize_key(key)
|
current_storage[sanitized_key] = value.strip()
|
||||||
if len(parts) > 1:
|
|
||||||
# Regular key-value pair
|
|
||||||
current_storage[sanitized_key] = parts[1].strip()
|
|
||||||
else:
|
|
||||||
# Key with no value, set it to True
|
|
||||||
current_storage[sanitized_key] = True
|
|
||||||
|
|
||||||
# Append the last storage section to the list if any
|
# Append the last storage section to the list if any
|
||||||
if current_storage:
|
if current_storage:
|
||||||
@@ -87,53 +81,15 @@ def parse_storage_cfg(file_path='/etc/pve/storage.cfg'):
|
|||||||
|
|
||||||
def get_storage_size(storage):
|
def get_storage_size(storage):
|
||||||
try:
|
try:
|
||||||
if storage["type"] == "zfspool":
|
if storage["type"] in ["dir", "nfs", "cephfs", "zfspool"]:
|
||||||
if "pool" not in storage:
|
if storage["type"] == "zfspool":
|
||||||
logging.debug(f"ZFS pool {storage['name']} has no pool name configured")
|
path = storage["mountpoint"]
|
||||||
return None
|
else:
|
||||||
|
path = storage["path"]
|
||||||
# Extract the pool name (could be in format like rpool/data)
|
# Get filesystem statistics
|
||||||
pool_name = storage["pool"].split("/")[0]
|
|
||||||
|
|
||||||
# Use zpool command to get accurate size information
|
|
||||||
import subprocess
|
|
||||||
try:
|
|
||||||
result = subprocess.run(
|
|
||||||
["zpool", "list", pool_name, "-p"],
|
|
||||||
capture_output=True,
|
|
||||||
text=True,
|
|
||||||
check=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Parse the output
|
|
||||||
lines = result.stdout.strip().split("\n")
|
|
||||||
if len(lines) < 2:
|
|
||||||
logging.warn(f"Unexpected zpool list output format for {pool_name}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Extract values from the second line (the data line)
|
|
||||||
values = lines[1].split()
|
|
||||||
if len(values) < 4:
|
|
||||||
logging.warn(f"Insufficient data in zpool list output for {pool_name}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Values are: NAME SIZE ALLOC FREE ...
|
|
||||||
# We need the SIZE and FREE values (index 1 and 3)
|
|
||||||
total_size = int(values[1])
|
|
||||||
free_space = int(values[3])
|
|
||||||
|
|
||||||
return {
|
|
||||||
"total": total_size,
|
|
||||||
"free": free_space
|
|
||||||
}
|
|
||||||
except (subprocess.SubprocessError, ValueError, IndexError) as e:
|
|
||||||
logging.warn(f"Error running zpool list for {pool_name}: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
elif storage["type"] in ["dir", "nfs", "cephfs"]:
|
|
||||||
# For non-ZFS storage, use statvfs
|
|
||||||
path = storage["path"]
|
|
||||||
stats = os.statvfs(path)
|
stats = os.statvfs(path)
|
||||||
|
# Calculate total size and free space in bytes
|
||||||
|
# TODO: find an alternative way to calculate total_size for ZFS
|
||||||
total_size = stats.f_frsize * stats.f_blocks
|
total_size = stats.f_frsize * stats.f_blocks
|
||||||
free_space = stats.f_frsize * stats.f_bavail
|
free_space = stats.f_frsize * stats.f_bavail
|
||||||
return {
|
return {
|
||||||
@@ -164,12 +120,7 @@ def collect_storage_metrics():
|
|||||||
|
|
||||||
storage_pools = parse_storage_cfg()
|
storage_pools = parse_storage_cfg()
|
||||||
for storage in storage_pools:
|
for storage in storage_pools:
|
||||||
# Convert any non-string values to strings for InfoMetricFamily
|
info_dict["node_storage"].add_metric([], storage)
|
||||||
storage_info = {}
|
|
||||||
for key, value in storage.items():
|
|
||||||
storage_info[key] = str(value) if not isinstance(value, str) else value
|
|
||||||
|
|
||||||
info_dict["node_storage"].add_metric([], storage_info)
|
|
||||||
size = get_storage_size(storage)
|
size = get_storage_size(storage)
|
||||||
if size != None:
|
if size != None:
|
||||||
gauge_dict["node_storage_size"].add_metric([storage["name"], storage["type"]], size["total"])
|
gauge_dict["node_storage_size"].add_metric([storage["name"], storage["type"]], size["total"])
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='pvemon',
|
name='pvemon',
|
||||||
version = "1.3.3",
|
version = "1.2.0",
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
entry_points={
|
entry_points={
|
||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
|
|||||||
Reference in New Issue
Block a user