Skip to content

Commit 24132e1

Browse files
Merge pull request #302 from emersonfelipesp/v0.0.8
Release v0.0.8: multi-stage sync, vm snapshots, CI test alignment
2 parents 493b551 + 9b247a5 commit 24132e1

File tree

141 files changed

+8024
-3555
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

141 files changed

+8024
-3555
lines changed

.github/workflows/ci.yml

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,32 @@ name: CI
22

33
on:
44
push:
5-
branches: [develop, testing]
5+
branches: ['**']
66
pull_request:
7-
branches: [develop, testing]
7+
branches: ['**']
88

99
jobs:
10-
test:
10+
lint:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v6
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v6
18+
with:
19+
python-version: "3.12"
20+
cache: "pip"
21+
22+
- name: Install ruff
23+
run: pip install ruff
24+
25+
- name: Run ruff (lint + format check)
26+
run: |
27+
ruff check .
28+
ruff format --check .
29+
30+
compile:
1131
runs-on: ubuntu-latest
1232
steps:
1333
- name: Checkout
@@ -27,6 +47,24 @@ jobs:
2747
- name: Compile package
2848
run: python -m compileall netbox_proxbox tests
2949

50+
test:
51+
runs-on: ubuntu-latest
52+
needs: [lint, compile]
53+
steps:
54+
- name: Checkout
55+
uses: actions/checkout@v6
56+
57+
- name: Set up Python
58+
uses: actions/setup-python@v6
59+
with:
60+
python-version: "3.12"
61+
cache: "pip"
62+
63+
- name: Install dependencies
64+
run: |
65+
python -m pip install --upgrade pip
66+
python -m pip install -e ".[test]"
67+
3068
- name: Run mocked test suite
3169
run: pytest --cov=netbox_proxbox --cov-report=term-missing --cov-report=xml tests
3270

.pre-commit-config.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
repos:
2+
- repo: local
3+
hooks:
4+
- id: compileall
5+
name: compileall
6+
entry: python -m compileall
7+
language: system
8+
pass_filenames: true
9+
types: [python]
10+
args: ["netbox_proxbox", "tests"]
11+
12+
- id: ruff
13+
name: ruff
14+
entry: ruff
15+
language: system
16+
pass_filenames: true
17+
types: [python]
18+
args: ["check", "."]
19+
20+
- id: ruff-format
21+
name: ruff-format
22+
entry: ruff
23+
language: system
24+
pass_filenames: true
25+
types: [python]
26+
args: ["format", "--check", "."]
27+
28+
- id: pytest
29+
name: pytest
30+
entry: pytest
31+
language: system
32+
pass_filenames: false
33+
args: ["tests/"]

AGENTS.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
# Agent Entry Points
22

3+
## Pre-commit Checklist
4+
5+
**Before committing ANY change:**
6+
7+
1. Run syntax check: `python -m compileall netbox_proxbox tests`
8+
2. Run linter: `rtk ruff check .`
9+
3. Run tests: `rtk pytest tests/`
10+
11+
---
12+
13+
## Framework stack preference
14+
15+
When implementing or changing behavior, prefer solutions in this order:
16+
17+
1. **NetBox plugin idioms** — Patterns used in this plugin and in NetBox’s plugin framework (`netbox.plugins`, plugin models, views, tables, filtersets, serializers as NetBox documents them).
18+
2. **NetBox core** — Built-in modules such as `utilities.forms`, `utilities.views`, `netbox.*` model and API bases, and DRF usage aligned with upstream NetBox.
19+
3. **Django** — Standard `django.*` APIs when NetBox does not expose an equivalent.
20+
21+
Do **not** add new third-party PyPI dependencies to replace what NetBox or Django already provides (forms, widgets, routing, auth, REST patterns). Existing runtime deps in `pyproject.toml` (for example `requests`, `websockets`, optional CLI extras) are fine; avoid piling on more libraries for the same problems.
22+
23+
## Security
24+
25+
Use NetBox view mixins from `utilities.views` (`ConditionalLoginRequiredMixin`, `TokenConditionalLoginRequiredMixin`, `ContentTypePermissionRequiredMixin`) for custom routes; enforce object visibility with `QuerySet.restrict()`. Permission strings for ProxBox-specific operations are centralized in [`netbox_proxbox/views/proxbox_access.py`](./netbox_proxbox/views/proxbox_access.py). Details: [`CLAUDE.md`](./CLAUDE.md) (Security and permissions).
26+
27+
---
28+
329
Read [`CLAUDE.md`](./CLAUDE.md) first for the plugin architecture and the full documentation map. Use the lower-level `CLAUDE.md` files when working in a specific directory or when changing only one layer of the plugin.
430

531
## CLAUDE.md Index

CLAUDE.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,40 @@
11
# netbox-proxbox Codebase Guide
22

3+
## Pre-commit Checklist
4+
5+
**Before committing ANY change:**
6+
7+
1. Run syntax check: `python -m compileall netbox_proxbox tests`
8+
2. Run linter: `rtk ruff check .`
9+
3. Run tests: `rtk pytest tests/`
10+
11+
---
12+
13+
## Framework stack preference
14+
15+
Follow the same dependency order agents use (see [`AGENTS.md`](./AGENTS.md)):
16+
17+
1. **NetBox plugin layer** — Reuse this plugin’s established patterns and NetBox’s plugin APIs (registration, plugin paths, `NetBoxModel` / `NetBoxModelViewSet`, tables and filtersets consistent with other plugin code here).
18+
2. **NetBox core** — Prefer `utilities.forms.fields`, `utilities.forms.widgets`, `utilities.views`, and other `utilities.*` / `netbox.*` primitives before inventing parallel implementations.
19+
3. **Django** — Use `django.forms`, `django.http`, ORM, and related stdlib-backed APIs when NetBox does not offer a specific helper.
20+
21+
**Third-party packages:** Do not introduce new PyPI dependencies for capabilities NetBox or Django already cover. The project already declares `requests`, `websockets`, and optional CLI-related packages in [`pyproject.toml`](./pyproject.toml); add new deps only for integration needs that have no NetBox/Django path, not as shortcuts for UI or API patterns the core stack handles.
22+
23+
**Example:** NetBox may remove or rename widgets (for example legacy Select2 helpers under `utilities.forms.widgets`). Prefer current NetBox field/widget pairs such as `DynamicModelMultipleChoiceField` with API-driven multi-select rather than pulling in extra front-end or Python widget libraries. For form layout and field choices in this plugin, see [`netbox_proxbox/forms/CLAUDE.md`](./netbox_proxbox/forms/CLAUDE.md).
24+
25+
## Security and permissions
26+
27+
- **Registered CRUD** (via `register_model_view` and `netbox.views.generic`) inherits NetBox `ObjectPermissionRequiredMixin`: model permissions plus `queryset.restrict()` for object-level rules.
28+
- **Custom views** should use `utilities.views.ConditionalLoginRequiredMixin` (respects `LOGIN_REQUIRED`) instead of Django’s unconditional `login_required`, and `TokenConditionalLoginRequiredMixin` where REST tokens should authenticate browser-style endpoints.
29+
- **Operational endpoints** (sync, SSE streams, schedule job, WebSocket bridge): `ContentTypePermissionRequiredMixin` with permissions defined in [`netbox_proxbox/views/proxbox_access.py`](./netbox_proxbox/views/proxbox_access.py) — typically `change` on `FastAPIEndpoint` for backend sync, `add` on `SyncProcess` for queued jobs, `view` on `FastAPIEndpoint` for read-only WebSocket test UI.
30+
- **Dashboard and JSON helpers**: plugin home requires at least one of `view` on `ProxmoxEndpoint` / `NetBoxEndpoint` / `FastAPIEndpoint` when the user is authenticated; endpoint lists use `.restrict(request.user, "view")`. Proxmox card and keepalive JSON resolve objects through restricted querysets (`get_object_or_404(...restrict(...))`). Tagged devices and VMs use `Device.objects.restrict` / `VirtualMachine.objects.restrict` before listing.
31+
- **Plugin REST API** remains on `NetBoxModelViewSet` with standard NetBox/DRF permission classes.
32+
33+
---
34+
335
This repository packages the `netbox_proxbox` NetBox plugin. The plugin adds endpoint inventory for Proxmox, NetBox, and the companion ProxBox FastAPI backend; UI pages for sync operations and status checks; REST API endpoints for those models; and a small amount of browser-side JavaScript and styling for the plugin pages.
436

5-
The current plugin config lives in [`netbox_proxbox/__init__.py`](./netbox_proxbox/__init__.py). It declares plugin version `0.0.7` and NetBox compatibility `4.5.0` through `4.5.99`.
37+
The current plugin config lives in [`netbox_proxbox/__init__.py`](./netbox_proxbox/__init__.py). It declares plugin version `0.0.8` and NetBox compatibility `4.5.0` through `4.5.99`.
638

739
## Architecture Summary
840

@@ -15,6 +47,16 @@ The current plugin config lives in [`netbox_proxbox/__init__.py`](./netbox_proxb
1547
- Browser updates can flow over SSE streams or the existing WebSocket channel.
1648
- Templates and static assets are conventional Django plugin assets under `netbox_proxbox/templates/` and `netbox_proxbox/static/`.
1749

50+
## Backend integration notes
51+
52+
- **Single FastAPI row:** HTTP and WebSocket helpers such as `get_fastapi_request_context()` in [`netbox_proxbox/services/backend_proxy.py`](./netbox_proxbox/services/backend_proxy.py), `websocket_client`, and several dashboard views resolve the backend via `FastAPIEndpoint.objects.first()` (or the first row from a restricted queryset). If multiple FastAPI endpoints exist, whichever row sorts first is used; plan automation and operator docs accordingly.
53+
- **Background Proxbox sync jobs (RQ):** `ProxboxSyncJob` enqueues on NetBox’s **`default`** RQ queue (`RQ_QUEUE_DEFAULT`) so a stock **`manage.py rqworker`** (no queue arguments) picks them up. NetBox’s default worker only listens to **`high`**, **`default`**, and **`low`**; the extra django-rq queue **`netbox_proxbox.sync`** is still registered for the plugin but is no longer the enqueue target. Older Job rows may still show **`netbox_proxbox.sync`** in **Queue**; cancel/RQ lookup uses the stored name. Jobs call proxbox-api **SSE** via [`run_sync_stream`](./netbox_proxbox/services/backend_proxy.py) until a terminal `complete` event.
54+
- **RQ timeout vs HTTP stream:** NetBox’s default **`RQ_DEFAULT_TIMEOUT`** (often **300s** via `configuration.py`) applies to RQ jobs unless overridden. Long syncs were previously killed by RQ while `requests` was still reading the SSE body. The plugin sets a default **`job_timeout`** of **`PROXBOX_SYNC_JOB_TIMEOUT`** (7200s) in [`ProxboxSyncJob.enqueue`](./netbox_proxbox/jobs.py); pass a larger `job_timeout=` to `enqueue()` if needed. That is separate from the HTTP **between-chunk read** timeout (3600s) inside [`run_sync_stream`](./netbox_proxbox/services/backend_proxy.py).
55+
- **When a job looks “stuck”:** **pending** usually means **no RQ worker** is running (or it does not listen to **`default`**). **running** for a long time usually means proxbox-api is still syncing or the stream is slow/buffered; **errored** with **`JobTimeoutException`** means RQ’s wall-clock limit was hit—increase `job_timeout` or `PROXBOX_SYNC_JOB_TIMEOUT`. Inspect the job **log** and **error** fields before changing code.
56+
- **Cancel on Job detail:** For Proxbox Sync rows in **pending**, **scheduled**, or **running** state, the plugin adds **Cancel job** (POST to `proxbox-cancel`). It requires **delete** permission on the core **Job** model, cancels or stops the linked RQ job when possible, then marks the NetBox job **failed** with a “Cancelled by user.” message. Stopping a **running** job is best-effort (RQ stop + long HTTP reads may not abort instantly).
57+
- **Run now on Job detail:** Shown only when the job is in a **terminal** state (**completed**, **errored**, or **failed**), including after **Cancel** (failed). It is **not** shown for **pending**, **scheduled**, or **running**—use **Cancel** first if a queued run should be abandoned, then **Run now** on the finished row to queue a new sync with the same parameters.
58+
- **Full update (UI vs jobs):** The plugin home may still use non-streaming helpers such as [`sync_full_update_resource`](./netbox_proxbox/services/backend_proxy.py) for JSON/redirect flows. Scheduled or immediate **Proxbox Sync** jobs use **`full-update/stream`** on proxbox-api (devices then VMs in one stream; no backups in that stream). Run a **VM backups** sync type when backups are required.
59+
1860
## How To Navigate
1961

2062
- Start with [`netbox_proxbox/CLAUDE.md`](./netbox_proxbox/CLAUDE.md) for the package-level map.

0 commit comments

Comments
 (0)