Skip to content

Commit ca15537

Browse files
committed
20184 FIX proxmox_ve: Fix crash when monitoring an IPv6-only host via IP
Previously, monitoring a Proxmox VE host configured to connect _via IP_ crashed the special agent if the host was IPv6-only (no dual-stack), with ```InvalidURL: Failed to parse: [https://<ipv6-address>:8006/api2/json/access/ticket]``` The IPv6 address was not enclosed in square brackets as required by RFC 3986, so it couldn't be told apart from the port number. This has been fixed. CMK-37108 Change-Id: Iafe5428f6803b9d66cbbb34b0243798e8ccbe490
1 parent 7b39440 commit ca15537

3 files changed

Lines changed: 54 additions & 1 deletion

File tree

.werks/20184.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[//]: # (werk v3)
2+
# proxmox_ve: Fix crash when monitoring an IPv6-only host via IP
3+
4+
key | value
5+
---------- | ---
6+
date | 2026-08-09T13:49:40.182743+00:00
7+
version | 2.5.0p12
8+
class | fix
9+
edition | community
10+
component | checks
11+
level | 1
12+
compatible | yes
13+
14+
Previously, monitoring a Proxmox VE host configured to connect _via IP_
15+
crashed the special agent if the host was IPv6-only (no dual-stack), with
16+
17+
```InvalidURL: Failed to parse: [https://<ipv6-address>:8006/api2/json/access/ticket]```
18+
19+
The IPv6 address was not enclosed in square brackets as required by
20+
RFC 3986, so it couldn't be told apart from the port number. This has been
21+
fixed.
22+

packages/cmk-plugins/cmk/plugins/proxmox_ve/special_agent/libproxmox.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
# mypy: disable-error-code="no-untyped-call"
77

8+
import ipaddress
89
import logging
910
from collections.abc import Iterable, Mapping, Sequence
1011
from json import JSONDecodeError
@@ -22,6 +23,15 @@
2223
class CannotRecover(RuntimeError): ...
2324

2425

26+
def _host_port_for_url(host: str, port: int) -> str:
27+
"""Render host:port for use in a URL, bracketing IPv6 literals per RFC 3986."""
28+
try:
29+
is_ipv6 = ipaddress.ip_address(host).version == 6
30+
except ValueError:
31+
is_ipv6 = False
32+
return f"[{host}]:{port}" if is_ipv6 else f"{host}:{port}"
33+
34+
2535
class _ProxmoxVeSession:
2636
"""Session"""
2737

@@ -84,7 +94,7 @@ def create_session() -> requests.Session:
8494

8595
self._timeout = timeout
8696
self._verify_ssl = verify_ssl
87-
self._base_url = "https://%s:%d/" % endpoint
97+
self._base_url = f"https://{_host_port_for_url(*endpoint)}/"
8898
self._session = create_session()
8999

90100
def __enter__(self) -> Any:
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env python3
2+
# Copyright (C) 2026 Checkmk GmbH - License: GNU General Public License v2
3+
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
4+
# conditions defined in the file COPYING, which is part of this source code package.
5+
6+
import pytest
7+
8+
from cmk.plugins.proxmox_ve.special_agent.libproxmox import _host_port_for_url
9+
10+
11+
@pytest.mark.parametrize(
12+
"host, port, expected",
13+
[
14+
pytest.param("2a01:4f9:2b:1c86::2", 8006, "[2a01:4f9:2b:1c86::2]:8006", id="ipv6"),
15+
pytest.param("::1", 8006, "[::1]:8006", id="ipv6_loopback"),
16+
pytest.param("192.168.1.10", 8006, "192.168.1.10:8006", id="ipv4"),
17+
pytest.param("pve1.example.com", 8006, "pve1.example.com:8006", id="hostname"),
18+
],
19+
)
20+
def test_host_port_for_url(host: str, port: int, expected: str) -> None:
21+
assert _host_port_for_url(host, port) == expected

0 commit comments

Comments
 (0)