|
| 1 | +# Contributing as an AI Agent to Nagstamon |
| 2 | + |
| 3 | +Nagstamon is a cross-platform PyQt6/Qt5 desktop monitoring application that aggregates status from 20+ monitoring systems (Nagios, Icinga, Zabbix, Prometheus, etc.). This guide helps AI agents understand the codebase structure and development workflows. |
| 4 | + |
| 5 | +## Architecture Overview |
| 6 | + |
| 7 | +**Three-tier structure:** |
| 8 | +1. **Configuration Layer** (`Nagstamon/config.py`): Central settings hub, loaded once at startup. Manages cross-platform specifics (Linux/macOS/Windows, desktop environments, Wayland). |
| 9 | +2. **Server Plugin System** (`Nagstamon/servers/`): Each monitoring system (Nagios, Icinga, Zabbix, etc.) extends `GenericServer`. Uses dynamic registration pattern via `SERVER_TYPES` dict and `register_server()`. |
| 10 | +3. **PyQt6 GUI Layer** (`Nagstamon/qui/`): Qt widgets, dialogs, system tray integration. Imports gui modules cause Qt initialization—avoid in non-gui code. |
| 11 | + |
| 12 | +**Data Flow:** |
| 13 | +- `nagstamon.py` (entry point) → `Nagstamon.qui` (GUI app) → `Nagstamon.servers` (status fetching) |
| 14 | +- Configuration flows from `config.py` to all server instances |
| 15 | +- Status objects (`GenericHost`, `GenericService` in `objects.py`) unify data from all server types |
| 16 | + |
| 17 | +## Server Integration Pattern |
| 18 | + |
| 19 | +**Adding a new monitoring system requires:** |
| 20 | + |
| 21 | +1. Create `Nagstamon/servers/YourServer.py` extending `GenericServer` |
| 22 | +2. Register in `Nagstamon/servers/__init__.py` by adding to `servers_list` and importing |
| 23 | +3. Implement core methods: |
| 24 | + - `init_http()`: Initialize session headers/auth |
| 25 | + - `get_status()`: Fetch and parse status, populate `self.hosts` and `self.services` |
| 26 | + - `_set_recheck()`, `_acknowledge()`: Actions (optional) |
| 27 | + |
| 28 | +**Key patterns:** |
| 29 | +- Server configuration accessed via `conf.servers[self.get_name()]` |
| 30 | +- Use `self.session` (from `GenericServer`) for HTTP; add headers in `init_http()` |
| 31 | +- Status parsing stores result in `self.hosts` and `self.services` dicts (keyed by host/service name) |
| 32 | +- Parse into `GenericHost`/`GenericService` objects with standard fields: `name`, `status` ('UP'/'DOWN'/'OK'/'CRITICAL'/etc.), `status_information`, `acknowledged`, `scheduled_downtime`, `flapping` |
| 33 | + |
| 34 | +**Examples:** |
| 35 | +- `Nagios.py`: Classic CGI API parsing |
| 36 | +- `Centreon/__init__.py`: Proxy pattern (detects version, switches to `CentreonLegacy` or `CentreonModern`) |
| 37 | +- `Alertmanager/alertmanagerserver.py`: JSON REST API with custom mapping fields (`map_to_hostname`, `map_to_status`) |
| 38 | + |
| 39 | +## Testing Pattern |
| 40 | + |
| 41 | +**Three test strategies** (see `tests/test_smoke.py`): |
| 42 | + |
| 43 | +1. **Non-GUI modules** (config, servers, helpers): Full import via `importlib` - catches all runtime errors |
| 44 | +2. **GUI modules** (Nagstamon/qui/**): Syntax-only via `py_compile` - requires display/Qt, skipped in headless CI |
| 45 | +3. **Vendored Xlib**: Syntax-only (avoid version mismatch errors with system python-xlib) |
| 46 | + |
| 47 | +**Run tests:** |
| 48 | +```bash |
| 49 | +python -m pytest tests/ |
| 50 | +``` |
| 51 | + |
| 52 | +## Configuration & Cross-Platform Handling |
| 53 | + |
| 54 | +**Key config patterns:** |
| 55 | +- Multiple config folder support (`conf.configdir`, `nagstamon.conf`, `nagstamon2.conf/`) |
| 56 | +- OS detection: `from Nagstamon.config import OS, OS_WINDOWS, OS_MACOS` |
| 57 | +- Desktop environment handling: `DESKTOP_WAYLAND`, `DESKTOP_NEEDS_FIX` for quirky desktops |
| 58 | +- Keyring support (optional, disabled on some KDE+Ubuntu combos to avoid segfaults) |
| 59 | + |
| 60 | +**Configuration object** (`conf` singleton from `config.py`): |
| 61 | +- `conf.servers` (OrderedDict of server configs) |
| 62 | +- `conf.debug_mode` (debug logging) |
| 63 | +- `conf.update_interval_seconds` (polling frequency) |
| 64 | +- Authentication state and SSL/TLS per server |
| 65 | + |
| 66 | +## Build System |
| 67 | + |
| 68 | +**Multi-platform builds** (see `build/build.py`): |
| 69 | +- **Windows**: PyInstaller → exe (optional code signing) |
| 70 | +- **macOS**: PyInstaller → app bundle or DMG |
| 71 | +- **Linux**: |
| 72 | + - Debian/Ubuntu via `setup.py` + debuild |
| 73 | + - RPM via `setup.py bdist_rpm` |
| 74 | + - DockerFiles for multiple distros (Fedora 41-45, RHEL 9, Debian) |
| 75 | + |
| 76 | +**Dependencies** managed platform-specifically: |
| 77 | +- Qt6 preferred on newer systems; Qt5 fallback on older Fedora/RHEL |
| 78 | +- Check `build/requirements/{linux,macos,windows}.txt` |
| 79 | + |
| 80 | +## Common Development Tasks |
| 81 | + |
| 82 | +**Running locally:** |
| 83 | +```bash |
| 84 | +python nagstamon.py |
| 85 | +``` |
| 86 | + |
| 87 | +**Debugging GUI issues:** |
| 88 | +- GUI requires display; use `--help` to check environment |
| 89 | +- Set `conf.debug_mode = True` in config for server debug output |
| 90 | + |
| 91 | +**Modifying server status parsing:** |
| 92 | +- Edit `get_status()` method |
| 93 | +- Test via smoke tests: `python -m pytest tests/test_smoke.py` |
| 94 | +- Populate `self.hosts` and `self.services` with correct status strings from `helpers.STATES` |
| 95 | + |
| 96 | +**Adding server config options:** |
| 97 | +- Add to server class via `__init__()` defaults |
| 98 | +- Add UI widget in `Nagstamon/qui/dialogs/server.py` `VOLATILE_WIDGETS` dict (shown/hidden per server type) |
| 99 | +- Persist via `create_server()` in `servers/__init__.py` |
| 100 | + |
| 101 | +## State Values & Severity |
| 102 | + |
| 103 | +**Standard status strings** (`helpers.STATES`): |
| 104 | +- Severity order (worst to least): `DISASTER > CRITICAL > DOWN > HIGH > AVERAGE > WARNING > UNKNOWN > INFORMATION > UP` |
| 105 | +- Different servers use different names; always normalize to above set |
| 106 | +- Example: Zabbix "Disaster" → `DISASTER`, Prometheus AlertManager severity mapping in `map_to_*` fields |
| 107 | + |
| 108 | +## Important Conventions |
| 109 | + |
| 110 | +1. **No circular imports**: GUI modules import server/config; config/servers must NOT import gui. Break cycles via local imports if needed. |
| 111 | +2. **Lock mechanism**: Single-instance check at startup via `lock_config_folder()` prevents concurrent runs on same config |
| 112 | +3. **Thread lifecycle**: Servers run in update threads; status fetching must be thread-safe, avoid gui imports |
| 113 | +4. **Debug infrastructure**: Use `self.debug(server=name, debug=msg)` for logging, routed to `debug_queue` if enabled |
| 114 | +5. **Error handling**: Catch exceptions in `get_status()`, return `Result(result=result_code, error=error_msg)` for graceful degradation |
| 115 | + |
| 116 | +## Key Files Reference |
| 117 | + |
| 118 | +- `Nagstamon/config.py` (1248 lines): AppInfo, OS detection, conf singleton, RESOURCES paths |
| 119 | +- `Nagstamon/servers/Generic.py` (1800 lines): Base class with HTTP handling, status aggregation, action methods |
| 120 | +- `Nagstamon/servers/__init__.py`: Plugin registration, server instantiation, aggregation functions |
| 121 | +- `Nagstamon/objects.py`: `GenericHost`/`GenericService` domain models |
| 122 | +- `Nagstamon/qui/__init__.py`: Qt app initialization, system tray setup |
| 123 | +- `Nagstamon/helpers.py`: Filtering (regex), STATES constant, utilities |
| 124 | + |
| 125 | +## Debugging Tips |
| 126 | + |
| 127 | +1. Enable debug mode in config to see server refresh logs |
| 128 | +2. Check `nagstamon.conf` for server credentials and URLs |
| 129 | +3. Use `python -c "import Nagstamon.servers.YourServer; print('OK')"` to test server module imports |
| 130 | +4. GUI breakpoints require Qt event loop; print debugging more reliable |
| 131 | +5. Check for `ClassServerReal` pattern—some servers proxy to real implementation after detection |
| 132 | + |
0 commit comments