Add configurable Proxmox API timeout

This commit is contained in:
2026-07-10 11:14:29 +02:00
parent 847cc13a8f
commit c2276c2774
9 changed files with 75 additions and 11 deletions
+1
View File
@@ -12,3 +12,4 @@
| 0.1.7 | 4.4.0 | 4.6.x |
| 0.1.8 | 4.4.0 | 4.6.x |
| 0.2.0 | 4.4.0 | 4.6.x |
| 0.2.1 | 4.4.0 | 4.6.x |
+2
View File
@@ -52,6 +52,8 @@ sudo systemctl restart netbox netbox-rq
6. Optional Regex-Filter und Sync-Intervall setzen.
7. Auf der Detailseite `Sync jetzt starten` ausfuehren.
Bei selbstsignierten Proxmox-Zertifikaten `Validate SSL` deaktiviert lassen. Wenn Proxmox langsam antwortet, kann `API timeout` am Endpoint erhoeht werden.
Wenn `Sync interval minutes` gesetzt ist, prueft ein Systemjob alle fuenf Minuten, welche Endpoints faellig sind, und stellt die eigentlichen Sync-Jobs in die Queue.
Ab Version `0.1.8` wird beim Speichern eines Endpoints zusaetzlich ein wiederkehrender NetBox-Job fuer genau diesen Endpoint geplant. Nach einem Update vorhandene Endpoints einmal speichern oder `netbox-rq` neu starten und bis zum naechsten Systemjob-Lauf warten.
+1 -1
View File
@@ -5,7 +5,7 @@ class VMwareImporterConfig(PluginConfig):
name = "netbox_vmware_importer"
verbose_name = "Virtualization Importer"
description = "Synchronize VMware vSphere and Proxmox VE virtual machines into NetBox."
version = "0.2.0"
version = "0.2.1"
author = "Internal NetBox Team"
base_url = "vmware-importer"
min_version = "4.4.0"
+13 -1
View File
@@ -46,7 +46,18 @@ class VCenterEndpointForm(NetBoxModelForm):
fieldsets = (
FieldSet("name", "slug", "enabled", "comments", name=_("Endpoint")),
FieldSet("provider", "host", "port", "username", "auth_method", "token_name", "password", "validate_ssl", name=_("Connection")),
FieldSet(
"provider",
"host",
"port",
"username",
"auth_method",
"token_name",
"password",
"validate_ssl",
"request_timeout_seconds",
name=_("Connection"),
),
FieldSet("tenant", "site", "cluster", name=_("NetBox target")),
FieldSet(
"include_name_regex",
@@ -77,6 +88,7 @@ class VCenterEndpointForm(NetBoxModelForm):
"token_name",
"password",
"validate_ssl",
"request_timeout_seconds",
"tenant",
"site",
"cluster",
@@ -0,0 +1,23 @@
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("netbox_vmware_importer", "0003_add_proxmox_endpoint_fields"),
]
operations = [
migrations.AddField(
model_name="vcenterendpoint",
name="request_timeout_seconds",
field=models.PositiveIntegerField(
default=120,
help_text="HTTP/API read timeout in seconds.",
validators=[
django.core.validators.MinValueValidator(5),
django.core.validators.MaxValueValidator(600),
],
),
),
]
+6
View File
@@ -60,6 +60,11 @@ class VCenterEndpoint(JobsMixin, NetBoxModel):
default=False,
help_text=_("Validate the endpoint TLS certificate."),
)
request_timeout_seconds = models.PositiveIntegerField(
default=120,
validators=[MinValueValidator(5), MaxValueValidator(600)],
help_text=_("HTTP/API read timeout in seconds."),
)
tenant = models.ForeignKey(
to="tenancy.Tenant",
on_delete=models.PROTECT,
@@ -180,6 +185,7 @@ class VCenterEndpoint(JobsMixin, NetBoxModel):
"auth_method",
"token_name",
"validate_ssl",
"request_timeout_seconds",
"tenant",
"site",
"cluster",
+24 -8
View File
@@ -14,8 +14,10 @@ from .choices import EndpointAuthMethodChoices, EndpointProviderChoices
try:
import requests
from urllib3.exceptions import InsecureRequestWarning
except ImportError: # pragma: no cover - handled at runtime inside NetBox
requests = None
InsecureRequestWarning = None
try:
from pyVim.connect import Disconnect, SmartConnect
@@ -230,6 +232,7 @@ class ProxmoxClient:
self.endpoint = endpoint
self.session = None
self.base_url = f"https://{endpoint.host}:{endpoint.port}/api2/json"
self.timeout = (10, endpoint.request_timeout_seconds or 120)
def __enter__(self):
if requests is None:
@@ -237,6 +240,8 @@ class ProxmoxClient:
self.session = requests.Session()
self.session.verify = self.endpoint.validate_ssl
if not self.endpoint.validate_ssl and InsecureRequestWarning is not None:
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
if self.endpoint.auth_method == EndpointAuthMethodChoices.METHOD_API_TOKEN:
token_id = self.endpoint.token_name if "!" in self.endpoint.token_name else f"{self.endpoint.username}!{self.endpoint.token_name}"
@@ -251,15 +256,14 @@ class ProxmoxClient:
self.session.close()
def _authenticate_with_password(self):
response = self.session.post(
self._url("access/ticket"),
response = self._request(
"POST",
"access/ticket",
data={
"username": self.endpoint.username,
"password": self.endpoint.password,
},
timeout=30,
)
response.raise_for_status()
data = response.json().get("data") or {}
ticket = data.get("ticket")
csrf_token = data.get("CSRFPreventionToken")
@@ -274,9 +278,21 @@ class ProxmoxClient:
def _url(self, path):
return f"{self.base_url}/{path.strip('/')}"
def _get(self, path, params=None):
response = self.session.get(self._url(path), params=params, timeout=30)
def _request(self, method, path, **kwargs):
url = self._url(path)
try:
response = self.session.request(method, url, timeout=self.timeout, **kwargs)
response.raise_for_status()
return response
except requests.Timeout as exc:
raise ProxmoxConnectionError(
f"Proxmox API {method} {path} timed out after {self.timeout[1]} seconds."
) from exc
except requests.RequestException as exc:
raise ProxmoxConnectionError(f"Proxmox API {method} {path} failed: {exc}") from exc
def _get(self, path, params=None):
response = self._request("GET", path, params=params)
return response.json().get("data")
def iter_virtual_machines(self):
@@ -448,7 +464,7 @@ class ProxmoxClient:
def _merge_qemu_agent_interfaces(self, node, vmid, interfaces):
try:
response = self._get(f"nodes/{node}/qemu/{vmid}/agent/network-get-interfaces") or {}
except requests.RequestException:
except (requests.RequestException, ProxmoxConnectionError):
return
agent_interfaces = response.get("result") if isinstance(response, dict) else response
@@ -488,7 +504,7 @@ class ProxmoxClient:
def _get_qemu_guest_os(self, node, vmid):
try:
response = self._get(f"nodes/{node}/qemu/{vmid}/agent/get-osinfo") or {}
except requests.RequestException:
except (requests.RequestException, ProxmoxConnectionError):
return ""
result = response.get("result") if isinstance(response, dict) else None
@@ -40,6 +40,10 @@
<th scope="row">Validate SSL</th>
<td>{{ object.validate_ssl|yesno:"Yes,No" }}</td>
</tr>
<tr>
<th scope="row">API timeout</th>
<td>{{ object.request_timeout_seconds }} seconds</td>
</tr>
</table>
</div>
</div>
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "netbox-vmware-importer"
version = "0.2.0"
version = "0.2.1"
description = "NetBox plugin to synchronize VMware vSphere and Proxmox VE virtual machines into NetBox."
readme = "README.md"
requires-python = ">=3.12"