first commit
This commit is contained in:
55
.devcontainer/.env.example
Normal file
55
.devcontainer/.env.example
Normal file
@@ -0,0 +1,55 @@
|
||||
# NetBox Development Environment Variables
|
||||
# Copy this file to .env and customize as needed
|
||||
|
||||
# NetBox Version to install (latest, v4.1-3.3.0, v4.0-3.3.0, snapshot)
|
||||
NETBOX_VERSION=latest
|
||||
|
||||
# Database Configuration
|
||||
DB_HOST=postgres
|
||||
DB_NAME=netbox
|
||||
DB_USER=netbox
|
||||
DB_PASSWORD=netbox
|
||||
|
||||
# Redis Configuration
|
||||
REDIS_HOST=redis
|
||||
REDIS_PASSWORD=
|
||||
|
||||
# Development Settings
|
||||
DEBUG=True
|
||||
DEVELOPER=True
|
||||
SECRET_KEY=dev-secret-key-not-for-production-use-12345678901234
|
||||
|
||||
# Superuser Configuration (auto-created on first run)
|
||||
SUPERUSER_NAME=admin
|
||||
SUPERUSER_EMAIL=admin@example.com
|
||||
SUPERUSER_PASSWORD=admin
|
||||
|
||||
# Auto-creation control
|
||||
SKIP_SUPERUSER=false
|
||||
|
||||
# Plugins are configured only in:
|
||||
# .devcontainer/plugin-config.py.example → .devcontainer/plugin-config.py
|
||||
# Advanced NetBox configuration (optional):
|
||||
# .devcontainer/extra-configuration.py.example → .devcontainer/extra-configuration.py
|
||||
|
||||
# Proxy Configuration (optional, for corporate networks with MITM proxies)
|
||||
# Uncomment and set these if you're behind a proxy
|
||||
# HTTP_PROXY=http://proxy.example.com:8080
|
||||
# HTTPS_PROXY=http://proxy.example.com:8080
|
||||
# NO_PROXY=localhost,127.0.0.1,postgres,redis
|
||||
#
|
||||
# CA bundle configuration:
|
||||
# Normally you SHOULD NOT set REQUESTS_CA_BUNDLE, SSL_CERT_FILE, or CURL_CA_BUNDLE here.
|
||||
# Instead, place a ca-bundle.crt file in the workspace root and setup.sh will install it
|
||||
# into the system trust store and set these variables automatically to:
|
||||
# /etc/ssl/certs/ca-certificates.crt
|
||||
# Only set the following manually for custom CA setups that cannot use the automatic
|
||||
# configuration provided by setup.sh.
|
||||
# REQUESTS_CA_BUNDLE=/custom/path/to/ca-bundle.crt
|
||||
# SSL_CERT_FILE=/custom/path/to/ca-bundle.crt
|
||||
# CURL_CA_BUNDLE=/custom/path/to/ca-bundle.crt
|
||||
|
||||
# Git SSL verification override (default: false)
|
||||
# Only set to true if behind a MITM proxy and you cannot provide a CA bundle.
|
||||
# Prefer placing a ca-bundle.crt in the workspace root instead.
|
||||
# ALLOW_GIT_SSL_DISABLE=false
|
||||
396
.devcontainer/README.md
Normal file
396
.devcontainer/README.md
Normal file
@@ -0,0 +1,396 @@
|
||||
# NetBox LibreNMS Plugin - Development Container
|
||||
|
||||
The Dev container was created to help aid with development without the need for a full NetBox installation locally. It provides a complete development environment using the official NetBox Docker images with PostgreSQL and Redis.
|
||||
|
||||
This directory contains the development container configuration for the NetBox LibreNMS Plugin.
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [Prerequisites](#-prerequisites)
|
||||
- [Quick Start](#-quick-start)
|
||||
- [Out-of-the-box defaults](#out-of-the-box-defaults)
|
||||
- [Configuration](#-configuration)
|
||||
- [NetBox Version and Environment](#netbox-version-and-environment-use-devcontainerenv)
|
||||
- [Changing NetBox Versions](#-changing-netbox-versions)
|
||||
- [Other environment variables](#other-environment-variables)
|
||||
- [Other configurations](#other-configurations)
|
||||
- [NetBox Configuration](#netbox-configuration)
|
||||
- [Additional packages](#additional-packages-including-other-netbox-plugins)
|
||||
- [Git Setup](#-git-setup)
|
||||
- [Commands](#-commands-aliases)
|
||||
- [Troubleshooting](#-troubleshooting)
|
||||
- [Cleanup](#-cleanup-remove-the-dev-containers)
|
||||
|
||||
## 📋 Prerequisites
|
||||
|
||||
### For Local Development (VS Code)
|
||||
|
||||
To use this dev container locally, you need:
|
||||
|
||||
- **[Docker](https://docs.docker.com/get-docker/)** (Docker Engine + Docker Compose)
|
||||
- **[Visual Studio Code](https://code.visualstudio.com/)**
|
||||
- **[Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)** for VS Code
|
||||
|
||||
### For GitHub Codespaces
|
||||
|
||||
If using GitHub Codespaces, all prerequisites are automatically available - just click "Code" → "Create codespace" in the GitHub repository.
|
||||
|
||||
**⚠️ Network Limitation with Codespaces:** GitHub Codespaces runs in the cloud and can only access publicly available LibreNMS servers.
|
||||
|
||||
If you need to test with a LibreNMS instance on a private network (local lab, corporate network, etc.), you'll need to use the local dev container instead.
|
||||
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
1. Fork and Clone: fork the plugin repo in Github and clone locally
|
||||
2. Open in VS Code and choose "Reopen in Container" (or Ctrl+Shift+P → Dev Containers: Reopen in Container)
|
||||
2. Wait for setup (~5min on first run or when new NetBox image is used). The container will install the plugin and prep NetBox
|
||||
3. Set up GitHub access: `gh auth login` (for pushing/pulling code changes)
|
||||
4. Create your plugin config — see [Plugin configuration](#plugin-configuration):
|
||||
- `cp .devcontainer/config/plugin-config.py.example .devcontainer/config/plugin-config.py`
|
||||
- Edit it with your server details (tokens/URLs)
|
||||
5. Start NetBox with `netbox-run` (or `netbox-run-bg` in background) (see [Commands](#-commands-aliases))
|
||||
6. Access NetBox at http://localhost:8000
|
||||
- Username: `admin`
|
||||
- Password: `admin`
|
||||
|
||||
### 🔄 Code changes and Committing
|
||||
8. Edit code in the repo root. Check out [contributing docs](../docs/contributing.md)
|
||||
9. Use `netbox-logs` to follow log output on screen
|
||||
6. Commit changes and contribute as normal by submitting a PR on GitHub.
|
||||
|
||||
### Quick Tips
|
||||
- **Auto-reload**: Works for most code changes when `DEBUG=True`
|
||||
- **Config changes**: Always restart NetBox after changing plugin settings
|
||||
- **GitHub CLI**: Automatically configured for easy PR submission
|
||||
- **Logs**: Use `netbox-logs` to debug issues in real-time
|
||||
|
||||
|
||||
### 📡 LibreNMS Server Configuration
|
||||
|
||||
You need a LibreNMS instance to use this plugin. Configure your LibreNMS server(s) in `plugin-config.py`:
|
||||
|
||||
1. Copy the example config:
|
||||
|
||||
```bash
|
||||
cp .devcontainer/config/plugin-config.py.example .devcontainer/config/plugin-config.py
|
||||
```
|
||||
|
||||
2. Edit it with your LibreNMS server URL(s) and API token(s)
|
||||
3. Restart NetBox: `netbox-restart`
|
||||
|
||||
## Out-of-the-box defaults
|
||||
|
||||
Below are the dev container defaults. The field name to change these defaults is listed below each line.
|
||||
|
||||
- NetBox image: `netboxcommunity/netbox:${NETBOX_VERSION:-latest}` (default `latest`)
|
||||
- .env: `NETBOX_VERSION`
|
||||
- DB: PostgreSQL 15 (db: `netbox`, user: `netbox`, password: `netbox`)
|
||||
- .env: `DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`
|
||||
- Redis: 7-alpine
|
||||
- .env: `REDIS_HOST`, `REDIS_PASSWORD`
|
||||
- NetBox DEBUG: `True` (dev only)
|
||||
- .env: `DEBUG`
|
||||
- Secret key: dev placeholder (not for production)
|
||||
- .env: `SECRET_KEY` (optional). If unset, a dev-safe default is used inside the container.
|
||||
- Superuser: `admin` / `admin`
|
||||
- .env: `SUPERUSER_NAME`, `SUPERUSER_EMAIL`, `SUPERUSER_PASSWORD`, `SKIP_SUPERUSER`
|
||||
- Plugin loader: enabled; reads `.devcontainer/config/plugin-config.py` if present
|
||||
- If `plugin-config.py` is missing: plugin is enabled with empty config (features won’t work until configured)
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### NetBox Version and Environment (use .devcontainer/.env)
|
||||
|
||||
The default NetBox docker image version is set to `latest`.
|
||||
|
||||
To update the NetBox image version create `.devcontainer/.env` using `NETBOX_VERSION` Example:
|
||||
|
||||
If you don’t have an env file yet, create it in the `.devcontainer/` folder from the example and customize:
|
||||
|
||||
```bash
|
||||
cp .devcontainer/.env.example .devcontainer/.env
|
||||
```
|
||||
|
||||
Change the NetBox image version in the `.env` file:
|
||||
```bash
|
||||
# .devcontainer/.env
|
||||
NETBOX_VERSION=v4.2-3.3.4
|
||||
```
|
||||
|
||||
After changing `.devcontainer/.env`, rebuild the dev container to apply it (Command Palette → Dev Containers: Rebuild Container).
|
||||
|
||||
See NetBox Docker tag docs for available tags:
|
||||
https://hub.docker.com/r/netboxcommunity/netbox/#container-image-tags
|
||||
|
||||
### 🔄 Changing NetBox Versions
|
||||
|
||||
You might experience issues with database schemas and migrations when changing NetBox version. Since this is a development container, the simplest way to handle NetBox version changes is to reset the database completely.
|
||||
|
||||
**To change NetBox versions:**
|
||||
|
||||
1. **Update the version** in `.devcontainer/.env`:
|
||||
```bash
|
||||
NETBOX_VERSION=v4.1-3.1.1 # or whatever version you need
|
||||
```
|
||||
|
||||
2. **Reset the development environment:**
|
||||
```bash
|
||||
# Stop containers and remove volumes (removes all dev data)
|
||||
docker compose down -v
|
||||
|
||||
# Rebuild container with new NetBox version
|
||||
# VS Code: Ctrl+Shift+P → "Dev Containers: Rebuild Container"
|
||||
```
|
||||
|
||||
3. **Start fresh:** The container will automatically set up the new NetBox version with a clean database.
|
||||
|
||||
**Note:** This removes all development data (test devices, configurations, etc.), but that's typically fine for development and testing scenarios.
|
||||
|
||||
### Other environment variables:
|
||||
|
||||
- Core: `NETBOX_VERSION`, `DEBUG`, `SECRET_KEY`
|
||||
- Database: `DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`
|
||||
- Redis: `REDIS_HOST`, `REDIS_PASSWORD`
|
||||
- Superuser: `SUPERUSER_NAME`, `SUPERUSER_EMAIL`, `SUPERUSER_PASSWORD`, `SKIP_SUPERUSER`
|
||||
- Proxy: `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, `REQUESTS_CA_BUNDLE`, `SSL_CERT_FILE`, `CURL_CA_BUNDLE`
|
||||
|
||||
### 🌐 Proxy Configuration (MITM Proxies)
|
||||
|
||||
If you're behind a corporate proxy or MITM proxy (like Zscaler, BlueCoat, etc.), you need to configure the proxy at two levels: the Docker client (for building) and the container runtime (for package installation inside the container).
|
||||
|
||||
**Step 1: Configure Docker client proxy** (`~/.docker/config.json`)
|
||||
|
||||
This is **required** so that `apt-get`, `curl`, etc. work during the container image build (e.g., when installing devcontainer features like `git` and `github-cli`).
|
||||
|
||||
Create or edit `~/.docker/config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"proxies": {
|
||||
"default": {
|
||||
"httpProxy": "http://proxy.example.com:8080",
|
||||
"httpsProxy": "http://proxy.example.com:8080",
|
||||
"noProxy": "localhost,127.0.0.1,postgres,redis"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Docker automatically injects these as environment variables into every `RUN` instruction during `docker build`. No VS Code restart is needed — this takes effect immediately.
|
||||
|
||||
> **Docker Desktop users:** You can configure the same settings via Docker Desktop Settings → Resources → Proxies, which writes this file for you.
|
||||
|
||||
**Step 2: Create `.devcontainer/.env`** (for container runtime)
|
||||
|
||||
```bash
|
||||
cp .devcontainer/.env.example .devcontainer/.env
|
||||
```
|
||||
|
||||
Add your proxy settings to `.devcontainer/.env`:
|
||||
|
||||
```bash
|
||||
# Proxy Configuration
|
||||
HTTP_PROXY=http://proxy.example.com:8080
|
||||
HTTPS_PROXY=http://proxy.example.com:8080
|
||||
NO_PROXY=localhost,127.0.0.1,postgres,redis
|
||||
```
|
||||
|
||||
> **Note:** You do **not** need to set `REQUESTS_CA_BUNDLE`, `SSL_CERT_FILE`, or `CURL_CA_BUNDLE` manually. When a `ca-bundle.crt` file is present in the workspace root, `setup.sh` automatically installs it into the system trust store and sets these variables to `/etc/ssl/certs/ca-certificates.crt`.
|
||||
|
||||
**Step 3: Add your CA certificate** (optional, only if your proxy intercepts TLS):
|
||||
- Export your proxy's CA certificate (usually available from your IT department or browser)
|
||||
- Save it as `ca-bundle.crt` in the root of your workspace
|
||||
- `setup.sh` will automatically install it and configure CA bundle environment variables
|
||||
|
||||
**Step 4: Rebuild the container**:
|
||||
- VS Code: Ctrl+Shift+P → "Dev Containers: Rebuild Container"
|
||||
|
||||
**What gets configured:**
|
||||
- `~/.docker/config.json` → proxy for Docker build steps (devcontainer features, apt in Dockerfile)
|
||||
- `.devcontainer/.env` → proxy for running containers (apt, pip, curl at runtime)
|
||||
- `setup.sh` auto-configures apt proxy and git SSL settings inside the container
|
||||
|
||||
**Important Notes:**
|
||||
- The `.env` file is ignored by git, so your proxy credentials stay private
|
||||
- `~/.docker/config.json` is a per-user file outside the repo
|
||||
- Add internal service names to `NO_PROXY` to avoid routing internal Docker traffic through the proxy
|
||||
- **Proxy authentication:** Embedding credentials directly in the proxy URL (e.g., `http://username:password@proxy.example.com:8080`) is insecure — credentials can be visible in process listings, environment dumps, `docker inspect` output, and logs. Prefer safer alternatives such as Docker's `config.json` with `credsStore` or a secret manager for storing proxy credentials securely.
|
||||
|
||||
**Common Issues:**
|
||||
|
||||
*"Could not connect to archive.ubuntu.com" during build*
|
||||
- → `~/.docker/config.json` is missing or has wrong proxy URL
|
||||
|
||||
*"SSL certificate errors" during build*
|
||||
- → Your proxy uses a MITM certificate. Export it and add it to the system trust store, or set `SSL_CERT_FILE` in `.env`
|
||||
|
||||
*Container builds but apt/pip fails inside*
|
||||
- → .env file is missing or has wrong proxy settings. Check .env matches Docker Desktop settings
|
||||
|
||||
|
||||
After any `.env` change, rebuild the dev container to apply environment updates.
|
||||
- VS Code: “Dev Containers: Rebuild Container” (from the Command Palette)
|
||||
|
||||
|
||||
## Other configurations
|
||||
|
||||
### NetBox Configuration:
|
||||
- Create `.devcontainer/config/extra-configuration.py` for additional NetBox settings (TIME_ZONE, banners, logging, etc)
|
||||
- After changes: run `netbox-restart` (see [Commands](#-commands-aliases))
|
||||
|
||||
### Additional packages (including other netbox plugins)
|
||||
- Create `.devcontainer/extra-requirements.txt` for extra Python packages. Example: `.devcontainer/extra-requirements.txt.example`.
|
||||
- After changes: run `plugins-install` to install packages, then `netbox-restart` (see [Commands](#-commands-aliases))
|
||||
|
||||
## 🔧 Git Setup
|
||||
|
||||
The dev container includes Git and GitHub CLI pre-installed. You'll need to configure authentication for commits and pushes.
|
||||
|
||||
### Important: SSH vs HTTPS Remote URLs
|
||||
|
||||
**Common Issue**: If you cloned this repository using SSH (`git@github.com:...`), you may encounter authentication errors when pushing changes. This is because:
|
||||
- Dev containers don't have SSH keys by default
|
||||
- GitHub CLI authentication uses HTTPS protocol
|
||||
|
||||
**Solution**: The setup script automatically converts SSH remote URLs to HTTPS. If you encounter issues, manually fix with:
|
||||
```bash
|
||||
# Check current remote URL
|
||||
git remote -v
|
||||
|
||||
# If it shows git@github.com:..., convert to HTTPS
|
||||
git remote set-url origin https://github.com/bonzo81/netbox-librenms-plugin.git
|
||||
```
|
||||
|
||||
### Recommended: GitHub CLI (Easiest)
|
||||
```bash
|
||||
# Authenticate with GitHub (handles Git credentials automatically)
|
||||
gh auth login
|
||||
|
||||
# Verify authentication
|
||||
gh auth status
|
||||
```
|
||||
|
||||
The GitHub CLI automatically configures Git to use your GitHub credentials for this repository.
|
||||
|
||||
### GitHub Codespaces
|
||||
In Codespaces, GitHub authentication is often pre-configured, but you can verify with:
|
||||
```bash
|
||||
# Check current status
|
||||
gh auth status
|
||||
|
||||
# If needed, authenticate
|
||||
gh auth login
|
||||
```
|
||||
|
||||
### Manual Git Setup (Alternative)
|
||||
If you prefer manual setup or need non-GitHub authentication:
|
||||
|
||||
#### Local Dev Container
|
||||
```bash
|
||||
# Set your Git identity
|
||||
git config --global user.name "Your Name"
|
||||
git config --global user.email "your.email@example.com"
|
||||
|
||||
# Optional: Set default branch name
|
||||
git config --global init.defaultBranch main
|
||||
```
|
||||
|
||||
#### SSH Key Setup (for private repositories)
|
||||
```bash
|
||||
# Generate SSH key (if you don't have one)
|
||||
ssh-keygen -t ed25519 -C "your.email@example.com"
|
||||
|
||||
# Add to SSH agent
|
||||
eval "$(ssh-agent -s)"
|
||||
ssh-add ~/.ssh/id_ed25519
|
||||
|
||||
# Display public key to add to GitHub
|
||||
cat ~/.ssh/id_ed25519.pub
|
||||
```
|
||||
|
||||
> **💡 Authentication Persistence:**
|
||||
> - **GitHub CLI**: Authentication persists across container rebuilds (stored in persistent volume)
|
||||
> - **Manual Git Config**: Git identity settings are **NOT persistent** across rebuilds
|
||||
> - **GitHub Codespaces**: Authentication is automatically handled by the Codespaces platform
|
||||
>
|
||||
> **Recommendation**: Use `gh auth login` for the best experience - it's persistent and handles everything automatically.
|
||||
|
||||
## 📋 Commands (aliases)
|
||||
|
||||
- `netbox-run-bg` - start NetBox and RQ worker in background
|
||||
- `netbox-run` - start NetBox and RQ worker in foreground (with Django logs showing)
|
||||
- `netbox-stop` - stop both NetBox and RQ worker
|
||||
- `netbox-restart` - restart NetBox and RQ worker
|
||||
- `netbox-reload` - reinstall plugin and restart
|
||||
- `netbox-status` - show server and RQ worker status
|
||||
- `netbox-logs` - tail NetBox server logs
|
||||
- `rq-status` - check RQ worker status
|
||||
- `rq-logs` - tail RQ worker logs
|
||||
- `netbox-shell` - Django shell
|
||||
- `netbox-manage` - Django manage.py
|
||||
- `netbox-test` - run tests
|
||||
- `plugin-install` - reinstall plugin
|
||||
- `ruff-check|format|fix` - Ruff helpers
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Git Authentication Issues
|
||||
|
||||
**Problem**: `Permission denied (publickey)` or authentication errors when pushing
|
||||
```
|
||||
git@github.com: Permission denied (publickey).
|
||||
fatal: Could not read from remote repository.
|
||||
```
|
||||
|
||||
**Solutions**:
|
||||
1. **Check remote URL** - should use HTTPS, not SSH:
|
||||
```bash
|
||||
git remote -v
|
||||
# Should show: https://github.com/bonzo81/netbox-librenms-plugin.git
|
||||
# NOT: git@github.com:bonzo81/netbox-librenms-plugin.git
|
||||
```
|
||||
|
||||
2. **Fix SSH remote URL**:
|
||||
```bash
|
||||
git remote set-url origin https://github.com/bonzo81/netbox-librenms-plugin.git
|
||||
```
|
||||
|
||||
3. **Authenticate with GitHub CLI**:
|
||||
```bash
|
||||
gh auth login
|
||||
gh auth setup-git # Optional: explicitly setup Git integration
|
||||
```
|
||||
|
||||
### Other Issues
|
||||
|
||||
- Rebuild container if setup fails (Ctrl+Shift+P → Rebuild Container)
|
||||
- Check logs `docker-compose logs postgres redis devcontainer`
|
||||
- Ensure plugin is importable inside container: `python -c "import netbox_librenms_plugin"`
|
||||
- Run `diagnose` to see whether `plugin-config.py` was detected and the NetBox config path
|
||||
|
||||
## 🧹 Cleanup: remove the dev containers
|
||||
|
||||
Data warning: removing volumes deletes all dev data (PostgreSQL DB, Redis AOF, NetBox media/static).
|
||||
|
||||
1) Close the VS Code Dev Container session first (Command Palette → Dev Containers: Close Remote)
|
||||
2) From the repo root:
|
||||
|
||||
```bash
|
||||
# Stop and remove containers
|
||||
docker compose -f .devcontainer/docker-compose.yml down
|
||||
|
||||
# Also remove named volumes (DB/media/static) — irreversible
|
||||
docker compose -f .devcontainer/docker-compose.yml down -v
|
||||
|
||||
# Optional: reclaim image space built/pulled for this project
|
||||
docker compose -f .devcontainer/docker-compose.yml down --rmi local -v
|
||||
```
|
||||
|
||||
Alternatively, run from inside the .devcontainer folder without -f:
|
||||
|
||||
```bash
|
||||
cd .devcontainer
|
||||
docker compose down # containers only
|
||||
docker compose down -v # containers + volumes
|
||||
```
|
||||
30
.devcontainer/config/codespaces-configuration.py
Normal file
30
.devcontainer/config/codespaces-configuration.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# GitHub Codespaces NetBox Configuration
|
||||
# CSRF/hosts setup for Codespaces URLs
|
||||
|
||||
import os
|
||||
|
||||
codespace_name = os.environ.get("CODESPACE_NAME")
|
||||
port_domain = os.environ.get("GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN", "app.github.dev")
|
||||
|
||||
if codespace_name:
|
||||
codespaces_url = f"https://{codespace_name}-8000.{port_domain}"
|
||||
CSRF_TRUSTED_ORIGINS = [
|
||||
codespaces_url,
|
||||
"http://localhost:8000",
|
||||
"http://127.0.0.1:8000",
|
||||
]
|
||||
ALLOWED_HOSTS = [
|
||||
f"{codespace_name}-8000.{port_domain}",
|
||||
"localhost",
|
||||
"127.0.0.1",
|
||||
"*",
|
||||
]
|
||||
print(f"🔗 Codespaces detected: {codespace_name}")
|
||||
print(f"🔒 CSRF Trusted Origins: {CSRF_TRUSTED_ORIGINS}")
|
||||
print(f"🌐 Allowed Hosts: {ALLOWED_HOSTS}")
|
||||
else:
|
||||
CSRF_TRUSTED_ORIGINS = [
|
||||
"http://localhost:8000",
|
||||
"http://127.0.0.1:8000",
|
||||
]
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
49
.devcontainer/config/extra-configuration.py.example
Normal file
49
.devcontainer/config/extra-configuration.py.example
Normal file
@@ -0,0 +1,49 @@
|
||||
# Example: Extra NetBox Configuration
|
||||
# Copy to 'extra-configuration.py' and customize
|
||||
|
||||
import os
|
||||
|
||||
# Example: Custom logging configuration
|
||||
# LOGGING = {
|
||||
# 'version': 1,
|
||||
# 'disable_existing_loggers': False,
|
||||
# 'handlers': {
|
||||
# 'file': {
|
||||
# 'level': 'INFO',
|
||||
# 'class': 'logging.FileHandler',
|
||||
# 'filename': '/opt/netbox/logs/netbox.log',
|
||||
# },
|
||||
# },
|
||||
# 'loggers': {
|
||||
# 'netbox_librenms_plugin': {
|
||||
# 'handlers': ['file'],
|
||||
# 'level': 'DEBUG',
|
||||
# 'propagate': True,
|
||||
# },
|
||||
# },
|
||||
# }
|
||||
|
||||
# Example: Time zone
|
||||
# TIME_ZONE = os.environ.get('TIME_ZONE', 'UTC')
|
||||
|
||||
# Example: Auth backends
|
||||
# AUTHENTICATION_BACKENDS = [
|
||||
# 'django.contrib.auth.backends.RemoteUserBackend',
|
||||
# 'django.contrib.auth.backends.ModelBackend',
|
||||
# ]
|
||||
|
||||
# Example: Paths
|
||||
# MEDIA_ROOT = '/opt/netbox/netbox/media'
|
||||
# STATIC_ROOT = '/opt/netbox/netbox/static'
|
||||
|
||||
# Dev banners
|
||||
BANNER_TOP = "Development Environment"
|
||||
BANNER_BOTTOM = "NetBox LibreNMS Plugin Dev Container"
|
||||
BANNER_LOGIN = "NetBox LibreNMS Plugin Development access only"
|
||||
|
||||
# Plugin-specific configuration
|
||||
# PLUGINS_CONFIG = {
|
||||
# 'netbox_librenms_plugin': {
|
||||
# 'debug_logging': True,
|
||||
# },
|
||||
# }
|
||||
0
.devcontainer/config/extra-plugins.py.example
Normal file
0
.devcontainer/config/extra-plugins.py.example
Normal file
46
.devcontainer/config/plugin-config.py.example
Normal file
46
.devcontainer/config/plugin-config.py.example
Normal file
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Default plugin configuration for the NetBox LibreNMS Plugin in the dev container.
|
||||
|
||||
- This file is an example of Plugin configuration
|
||||
- Copy this file to .devcontainer/plugin-config.py
|
||||
- Edit values as needed.
|
||||
|
||||
- Add config for all other plugins here if any.
|
||||
"""
|
||||
|
||||
# Ensure our plugin is enabled in dev (the loader sets this as a default too)
|
||||
PLUGINS = [
|
||||
"netbox_librenms_plugin",
|
||||
]
|
||||
|
||||
# Sample configuration with example servers
|
||||
PLUGINS_CONFIG = {
|
||||
"netbox_librenms_plugin": {
|
||||
"servers": {
|
||||
"production": {
|
||||
"display_name": "Production LibreNMS",
|
||||
"librenms_url": "https://librenms-prod.example.com",
|
||||
"api_token": "your-prod-token",
|
||||
"cache_timeout": 300,
|
||||
"verify_ssl": True,
|
||||
"interface_name_field": "ifDescr",
|
||||
},
|
||||
"testing": {
|
||||
"display_name": "Test LibreNMS",
|
||||
"librenms_url": "https://librenms-test.example.com",
|
||||
"api_token": "your_test_token",
|
||||
"cache_timeout": 300,
|
||||
"verify_ssl": False,
|
||||
"interface_name_field": "ifName",
|
||||
},
|
||||
"development": {
|
||||
"display_name": "Dev LibreNMS",
|
||||
"librenms_url": "https://librenms-dev.example.com",
|
||||
"api_token": "your_dev_token",
|
||||
"cache_timeout": 180,
|
||||
"verify_ssl": False,
|
||||
"interface_name_field": "ifDescr",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
82
.devcontainer/devcontainer.json
Normal file
82
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "NetBox LibreNMS Plugin Dev",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "devcontainer",
|
||||
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||
"forwardPorts": [
|
||||
8000
|
||||
],
|
||||
"portsAttributes": {
|
||||
"8000": {
|
||||
"label": "NetBox Web Interface",
|
||||
"protocol": "http",
|
||||
"requireLocalPort": false,
|
||||
"elevateIfNeeded": false
|
||||
}
|
||||
},
|
||||
"otherPortsAttributes": {
|
||||
"onAutoForward": "ignore"
|
||||
},
|
||||
"hostRequirements": {
|
||||
"memory": "4gb",
|
||||
"storage": "32gb"
|
||||
},
|
||||
"containerEnv": {
|
||||
"NETBOX_VERSION": "${localEnv:NETBOX_VERSION:latest}",
|
||||
"DEBUG": "${localEnv:DEBUG:True}",
|
||||
"DEVELOPER": "${localEnv:DEVELOPER:True}",
|
||||
"DB_HOST": "${localEnv:DB_HOST:postgres}",
|
||||
"DB_NAME": "${localEnv:DB_NAME:netbox}",
|
||||
"DB_USER": "${localEnv:DB_USER:netbox}",
|
||||
"DB_PASSWORD": "${localEnv:DB_PASSWORD:netbox}",
|
||||
"REDIS_HOST": "${localEnv:REDIS_HOST:redis}",
|
||||
"REDIS_PASSWORD": "${localEnv:REDIS_PASSWORD:}",
|
||||
"SUPERUSER_NAME": "${localEnv:SUPERUSER_NAME:admin}",
|
||||
"SUPERUSER_EMAIL": "${localEnv:SUPERUSER_EMAIL:admin@example.com}",
|
||||
"SUPERUSER_PASSWORD": "${localEnv:SUPERUSER_PASSWORD:admin}",
|
||||
"SKIP_SUPERUSER": "${localEnv:SKIP_SUPERUSER:false}",
|
||||
"HTTP_PROXY": "${localEnv:HTTP_PROXY}",
|
||||
"HTTPS_PROXY": "${localEnv:HTTPS_PROXY}",
|
||||
"http_proxy": "${localEnv:HTTP_PROXY}",
|
||||
"https_proxy": "${localEnv:HTTPS_PROXY}",
|
||||
"NO_PROXY": "${localEnv:NO_PROXY}",
|
||||
"no_proxy": "${localEnv:NO_PROXY}",
|
||||
"REQUESTS_CA_BUNDLE": "${localEnv:REQUESTS_CA_BUNDLE}",
|
||||
"SSL_CERT_FILE": "${localEnv:SSL_CERT_FILE}",
|
||||
"CURL_CA_BUNDLE": "${localEnv:CURL_CA_BUNDLE}",
|
||||
"ALLOW_GIT_SSL_DISABLE": "${localEnv:ALLOW_GIT_SSL_DISABLE:false}"
|
||||
},
|
||||
"features": {},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-python.python",
|
||||
"charliermarsh.ruff",
|
||||
"ms-vscode.vscode-json",
|
||||
"ms-vscode-remote.remote-containers"
|
||||
],
|
||||
"settings": {
|
||||
"python.defaultInterpreterPath": "/opt/netbox/venv/bin/python",
|
||||
"python.linting.enabled": false,
|
||||
"python.formatting.provider": "none",
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "charliermarsh.ruff",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit",
|
||||
"source.fixAll.ruff": "explicit"
|
||||
}
|
||||
},
|
||||
"ruff.organizeImports": true,
|
||||
"ruff.fixAll": true,
|
||||
"editor.formatOnSave": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"editor.rulers": [
|
||||
88
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"postCreateCommand": "bash .devcontainer/scripts/setup.sh",
|
||||
"postAttachCommand": "bash .devcontainer/scripts/welcome.sh",
|
||||
"remoteUser": "root"
|
||||
}
|
||||
74
.devcontainer/docker-compose.yml
Normal file
74
.devcontainer/docker-compose.yml
Normal file
@@ -0,0 +1,74 @@
|
||||
services:
|
||||
devcontainer:
|
||||
image: netboxcommunity/netbox:${NETBOX_VERSION:-latest}
|
||||
volumes:
|
||||
- ../..:/workspaces:cached
|
||||
- netbox_media:/opt/netbox/netbox/media
|
||||
- netbox_static:/opt/netbox/netbox/static
|
||||
- gh_config:/root/.config/gh
|
||||
command: sleep infinity
|
||||
environment:
|
||||
NETBOX_VERSION: ${NETBOX_VERSION:-latest}
|
||||
DEBUG: ${DEBUG:-True}
|
||||
DEVELOPER: ${DEVELOPER:-True}
|
||||
DB_HOST: ${DB_HOST:-postgres}
|
||||
DB_NAME: ${DB_NAME:-netbox}
|
||||
DB_USER: ${DB_USER:-netbox}
|
||||
DB_PASSWORD: ${DB_PASSWORD:-netbox}
|
||||
REDIS_HOST: ${REDIS_HOST:-redis}
|
||||
REDIS_PASSWORD: ${REDIS_PASSWORD:-}
|
||||
SECRET_KEY: ${SECRET_KEY:-dummydummydummydummydummydummydummydummydummydummydummydummy}
|
||||
SUPERUSER_NAME: ${SUPERUSER_NAME:-admin}
|
||||
SUPERUSER_EMAIL: ${SUPERUSER_EMAIL:-admin@example.com}
|
||||
SUPERUSER_PASSWORD: ${SUPERUSER_PASSWORD:-admin}
|
||||
SKIP_SUPERUSER: ${SKIP_SUPERUSER:-false}
|
||||
# Proxy settings (optional)
|
||||
HTTP_PROXY: ${HTTP_PROXY:-}
|
||||
HTTPS_PROXY: ${HTTPS_PROXY:-}
|
||||
http_proxy: ${HTTP_PROXY:-}
|
||||
https_proxy: ${HTTPS_PROXY:-}
|
||||
NO_PROXY: ${NO_PROXY:-}
|
||||
no_proxy: ${NO_PROXY:-}
|
||||
REQUESTS_CA_BUNDLE: ${REQUESTS_CA_BUNDLE:-}
|
||||
SSL_CERT_FILE: ${SSL_CERT_FILE:-}
|
||||
CURL_CA_BUNDLE: ${CURL_CA_BUNDLE:-}
|
||||
ALLOW_GIT_SSL_DISABLE: ${ALLOW_GIT_SSL_DISABLE:-false}
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
postgres:
|
||||
image: postgres:15
|
||||
environment:
|
||||
POSTGRES_DB: ${DB_NAME:-netbox}
|
||||
POSTGRES_USER: ${DB_USER:-netbox}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-netbox}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-netbox}"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
command: redis-server --appendonly yes
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
netbox_media:
|
||||
netbox_static:
|
||||
gh_config:
|
||||
27
.devcontainer/extra-requirements.txt.example
Normal file
27
.devcontainer/extra-requirements.txt.example
Normal file
@@ -0,0 +1,27 @@
|
||||
# Example: Extra Python Requirements
|
||||
# Copy this file to 'extra-requirements.txt' and customize as needed
|
||||
|
||||
# Example NetBox plugins (uncomment to install)
|
||||
# netbox-secrets>=1.9.0
|
||||
# netbox-topology-views>=3.8.0
|
||||
# netbox-dns>=1.1.0
|
||||
# netbox-documents>=0.6.0
|
||||
|
||||
# Example development/debugging tools
|
||||
# ipython>=8.0.0
|
||||
# django-debug-toolbar>=4.0.0
|
||||
# django-extensions>=3.2.0
|
||||
|
||||
# Example testing tools
|
||||
# factory-boy>=3.3.0
|
||||
# faker>=22.0.0
|
||||
# responses>=0.24.0
|
||||
|
||||
# Example monitoring
|
||||
# django-prometheus>=2.3.0
|
||||
# sentry-sdk>=1.40.0
|
||||
|
||||
# Example additional network libs
|
||||
# netaddr>=0.10.0
|
||||
# dnspython>=2.4.0
|
||||
# pysnmp>=5.0.0
|
||||
65
.devcontainer/scripts/diagnose.sh
Executable file
65
.devcontainer/scripts/diagnose.sh
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "🔍 DevContainer Startup Diagnostics"
|
||||
echo "=================================="
|
||||
|
||||
PLUGIN_WS_DIR="${PLUGIN_DIR:-$(cd "$(dirname "$0")/../.." && pwd)}"
|
||||
echo "📍 Current working directory: $(pwd)"
|
||||
echo "👤 Current user: $(whoami)"
|
||||
echo "🆔 User ID: $(id)"
|
||||
|
||||
echo ""
|
||||
echo "🐳 Container Environment:"
|
||||
echo " - NETBOX_VERSION: ${NETBOX_VERSION:-not set}"
|
||||
echo " - DEBUG: ${DEBUG:-not set}"
|
||||
echo " - SECRET_KEY: ${SECRET_KEY:0:20}... (truncated)"
|
||||
echo " - DB_HOST: ${DB_HOST:-not set}"
|
||||
echo " - DB_NAME: ${DB_NAME:-not set}"
|
||||
echo " - DB_USER: ${DB_USER:-not set}"
|
||||
echo " - REDIS_HOST: ${REDIS_HOST:-not set}"
|
||||
echo " - SUPERUSER_NAME: ${SUPERUSER_NAME:-not set}"
|
||||
|
||||
echo ""
|
||||
echo "🔗 Service Connectivity:"
|
||||
echo " - PostgreSQL: $(timeout 3 bash -c 'cat < /dev/null > /dev/tcp/postgres/5432' 2>/dev/null && echo 'Connected' || echo 'Not reachable')"
|
||||
echo " - Redis: $(timeout 3 bash -c 'cat < /dev/null > /dev/tcp/redis/6379' 2>/dev/null && echo 'Connected' || echo 'Not reachable')"
|
||||
|
||||
echo ""
|
||||
echo "🗂️ File System:"
|
||||
echo " - NetBox venv: $(test -f /opt/netbox/venv/bin/activate && echo 'Exists' || echo 'Missing')"
|
||||
echo " - Plugin directory: $(test -d "$PLUGIN_WS_DIR" && echo 'Exists' || echo 'Missing')"
|
||||
echo " - Setup script: $(test -f "$PLUGIN_WS_DIR/.devcontainer/scripts/setup.sh" && echo 'Exists' || echo 'Missing')"
|
||||
echo " - Start script: $(test -f "$PLUGIN_WS_DIR/.devcontainer/scripts/start-netbox.sh" && echo 'Exists' || echo 'Missing')"
|
||||
echo " - Start script executable: $(test -x "$PLUGIN_WS_DIR/.devcontainer/scripts/start-netbox.sh" && echo 'Yes' || echo 'No')"
|
||||
echo " - Plugin config: $(test -f "$PLUGIN_WS_DIR/.devcontainer/config/plugin-config.py" && echo 'Found' || echo 'Missing (using defaults)')"
|
||||
echo " - NetBox config path: /opt/netbox/netbox/netbox/configuration.py"
|
||||
|
||||
echo ""
|
||||
echo "🚀 Process Status:"
|
||||
if [ -f /tmp/netbox.pid ]; then
|
||||
PID=$(cat /tmp/netbox.pid)
|
||||
if [ -z "$PID" ]; then
|
||||
echo " - NetBox server: PID file exists but is empty"
|
||||
elif kill -0 "$PID" 2>/dev/null; then
|
||||
echo " - NetBox server: Running (PID: $PID)"
|
||||
else
|
||||
echo " - NetBox server: PID file exists but process not running"
|
||||
echo " (PID $PID is dead - NetBox may have crashed)"
|
||||
fi
|
||||
else
|
||||
echo " - NetBox server: Not started"
|
||||
fi
|
||||
|
||||
# Check port listening
|
||||
echo ""
|
||||
echo "🌍 Port Check:"
|
||||
if command -v netstat >/dev/null 2>&1; then
|
||||
echo " - Port 8000: $(netstat -tuln 2>/dev/null | grep :8000 >/dev/null && echo 'Listening' || echo 'Not listening')"
|
||||
elif command -v ss >/dev/null 2>&1; then
|
||||
echo " - Port 8000: $(ss -tuln 2>/dev/null | grep :8000 >/dev/null && echo 'Listening' || echo 'Not listening')"
|
||||
else
|
||||
echo " - Port 8000: $(cat /proc/net/tcp 2>/dev/null | awk '$2 ~ /:1F40$/ {print "Listening"; exit}' | grep -q "Listening" && echo 'Listening' || echo 'Not listening')"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ Diagnostic complete!"
|
||||
224
.devcontainer/scripts/load-aliases.sh
Executable file
224
.devcontainer/scripts/load-aliases.sh
Executable file
@@ -0,0 +1,224 @@
|
||||
#!/bin/bash
|
||||
# Quick alias loader for current session
|
||||
# Usage: source .devcontainer/scripts/load-aliases.sh
|
||||
|
||||
export PATH="/opt/netbox/venv/bin:$PATH"
|
||||
export DEBUG="${DEBUG:-True}"
|
||||
PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
|
||||
# Clean up empty CA bundle vars (Compose/devcontainer inject "" when host var is
|
||||
# unset, which breaks requests/curl). When setup.sh has installed custom CAs
|
||||
# into the system trust store, point to it instead.
|
||||
for _ca_var in REQUESTS_CA_BUNDLE SSL_CERT_FILE CURL_CA_BUNDLE; do
|
||||
_val="${!_ca_var}"
|
||||
if [ -z "$_val" ]; then
|
||||
if [ -f /etc/ssl/certs/ca-certificates.crt ]; then
|
||||
declare -x "$_ca_var=/etc/ssl/certs/ca-certificates.crt"
|
||||
else
|
||||
unset "$_ca_var"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
unset _ca_var _val
|
||||
|
||||
# Load shared process management helpers
|
||||
if ! source "$PLUGIN_DIR/.devcontainer/scripts/process-helpers.sh"; then
|
||||
printf '%s\n' "Failed to load process-helpers.sh" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
netbox-run-bg() { "$PLUGIN_DIR/.devcontainer/scripts/start-netbox.sh" --background; }
|
||||
netbox-run() { "$PLUGIN_DIR/.devcontainer/scripts/start-netbox.sh"; }
|
||||
|
||||
# Robust stop command that kills both tracked and orphaned processes
|
||||
netbox-stop() {
|
||||
echo "🛑 Stopping NetBox and RQ workers..."
|
||||
if [ -f /tmp/netbox.pid ]; then
|
||||
local PID
|
||||
PID=$(cat /tmp/netbox.pid 2>/dev/null)
|
||||
if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then
|
||||
if is_expected_pid "$PID" "python.*runserver.*8000"; then
|
||||
graceful_kill_pid "$PID"
|
||||
echo " Stopped NetBox (PID: $PID)"
|
||||
else
|
||||
echo " Skipping stale /tmp/netbox.pid (PID $PID is not NetBox runserver)"
|
||||
fi
|
||||
fi
|
||||
rm -f /tmp/netbox.pid
|
||||
fi
|
||||
if [ -f /tmp/rqworker.pid ]; then
|
||||
local PID
|
||||
PID=$(cat /tmp/rqworker.pid 2>/dev/null)
|
||||
if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then
|
||||
if is_expected_pid "$PID" "python.*rqworker"; then
|
||||
graceful_kill_pid "$PID"
|
||||
echo " Stopped RQ worker (PID: $PID)"
|
||||
else
|
||||
echo " Skipping stale /tmp/rqworker.pid (PID $PID is not rqworker)"
|
||||
fi
|
||||
fi
|
||||
rm -f /tmp/rqworker.pid
|
||||
fi
|
||||
if pgrep -f "python.*rqworker" >/dev/null 2>&1; then
|
||||
local ORPHAN_COUNT
|
||||
ORPHAN_COUNT=$(pgrep -cf "python.*rqworker" 2>/dev/null || echo 0)
|
||||
graceful_kill_pattern "python.*rqworker"
|
||||
echo " Killed $ORPHAN_COUNT orphaned RQ worker(s)"
|
||||
fi
|
||||
if pgrep -f "python.*runserver.*8000" >/dev/null 2>&1; then
|
||||
graceful_kill_pattern "python.*runserver.*8000"
|
||||
echo " Killed orphaned NetBox server(s)"
|
||||
fi
|
||||
echo "✅ All processes stopped"
|
||||
}
|
||||
|
||||
netbox-restart() {
|
||||
netbox-stop && sleep 1 && netbox-run-bg
|
||||
}
|
||||
|
||||
netbox-reload() {
|
||||
cd "$PLUGIN_DIR" || return 1
|
||||
if command -v uv >/dev/null 2>&1; then
|
||||
uv pip install -e . || return 1
|
||||
else
|
||||
pip install -e . || return 1
|
||||
fi
|
||||
netbox-restart
|
||||
}
|
||||
|
||||
alias netbox-logs="tail -f /tmp/netbox.log"
|
||||
alias rq-logs="tail -f /tmp/rqworker.log"
|
||||
|
||||
netbox-status() {
|
||||
local PID
|
||||
if [ -f /tmp/netbox.pid ]; then
|
||||
PID=$(cat /tmp/netbox.pid 2>/dev/null)
|
||||
if [ -n "$PID" ] && is_expected_pid "$PID" "python.*runserver.*8000"; then
|
||||
echo "NetBox is running (PID: $PID)"
|
||||
else
|
||||
echo "NetBox is not running"
|
||||
fi
|
||||
else
|
||||
echo "NetBox is not running"
|
||||
fi
|
||||
if [ -f /tmp/rqworker.pid ]; then
|
||||
PID=$(cat /tmp/rqworker.pid 2>/dev/null)
|
||||
if [ -n "$PID" ] && is_expected_pid "$PID" "python.*rqworker"; then
|
||||
echo "RQ worker is running (PID: $PID)"
|
||||
else
|
||||
echo "RQ worker is not running"
|
||||
fi
|
||||
else
|
||||
echo "RQ worker is not running"
|
||||
fi
|
||||
}
|
||||
|
||||
rq-status() {
|
||||
local PID
|
||||
if [ -f /tmp/rqworker.pid ]; then
|
||||
PID=$(cat /tmp/rqworker.pid 2>/dev/null)
|
||||
if [ -n "$PID" ] && is_expected_pid "$PID" "python.*rqworker"; then
|
||||
echo "RQ worker is running (PID: $PID)"
|
||||
else
|
||||
echo "RQ worker is not running"
|
||||
fi
|
||||
else
|
||||
echo "RQ worker is not running"
|
||||
fi
|
||||
}
|
||||
|
||||
netbox-shell() {
|
||||
cd /opt/netbox/netbox && source /opt/netbox/venv/bin/activate && python manage.py shell
|
||||
}
|
||||
|
||||
netbox-test() {
|
||||
cd "$PLUGIN_DIR" && source /opt/netbox/venv/bin/activate && python -m pytest "$@"
|
||||
}
|
||||
|
||||
netbox-manage() {
|
||||
cd /opt/netbox/netbox && source /opt/netbox/venv/bin/activate && python manage.py "$@"
|
||||
}
|
||||
|
||||
plugin-install() {
|
||||
cd "$PLUGIN_DIR" || return 1
|
||||
if command -v uv >/dev/null 2>&1; then
|
||||
uv pip install -e .
|
||||
else
|
||||
pip install -e .
|
||||
fi
|
||||
}
|
||||
|
||||
plugins-install() {
|
||||
if [ -f "$PLUGIN_DIR/.devcontainer/extra-requirements.txt" ]; then
|
||||
source /opt/netbox/venv/bin/activate && pip install -r "$PLUGIN_DIR/.devcontainer/extra-requirements.txt"
|
||||
else
|
||||
echo "No .devcontainer/extra-requirements.txt found"
|
||||
fi
|
||||
}
|
||||
|
||||
ruff-check() { cd "$PLUGIN_DIR" && command ruff check .; }
|
||||
ruff-format() { cd "$PLUGIN_DIR" && command ruff format .; }
|
||||
ruff-fix() { cd "$PLUGIN_DIR" && command ruff check --fix .; }
|
||||
|
||||
diagnose() { "$PLUGIN_DIR/.devcontainer/scripts/diagnose.sh"; }
|
||||
|
||||
# RQ job inspection commands
|
||||
rq-stats() {
|
||||
cd /opt/netbox/netbox && source /opt/netbox/venv/bin/activate && python manage.py rqstats
|
||||
}
|
||||
|
||||
rq-jobs() {
|
||||
cd /opt/netbox/netbox && source /opt/netbox/venv/bin/activate && python manage.py shell -c \
|
||||
"from django_rq import get_queue; q = get_queue('default'); print(f'Jobs in queue: {len(q)}'); [print(f' {job.id[:8]}: {job.func_name} - {job.get_status()}') for job in q.jobs[:10]]"
|
||||
}
|
||||
|
||||
rq-failed() {
|
||||
cd /opt/netbox/netbox && source /opt/netbox/venv/bin/activate && python manage.py shell -c \
|
||||
"from django_rq import get_failed_queue; q = get_failed_queue(); print(f'Failed jobs: {len(q)}'); [print(f' {job.id[:8]}: {job.func_name}') for job in q.jobs[:10]]"
|
||||
}
|
||||
|
||||
rq-recent() {
|
||||
cd /opt/netbox/netbox && source /opt/netbox/venv/bin/activate && python manage.py shell -c \
|
||||
"from core.models import Job; jobs = Job.objects.all().order_by('-created')[:10]; [print(f'{j.id}: {j.name[:50]} - {getattr(j.status, \"value\", j.status)} ({j.user})') for j in jobs]"
|
||||
}
|
||||
|
||||
# Help
|
||||
dev-help() {
|
||||
echo "🎯 NetBox LibreNMS Plugin Development Commands:"
|
||||
echo ""
|
||||
echo "📊 NetBox Server Management:"
|
||||
echo " netbox-run-bg : Start NetBox in background"
|
||||
echo " netbox-run : Start NetBox in foreground (for debugging)"
|
||||
echo " netbox-stop : Stop NetBox and RQ worker"
|
||||
echo " netbox-restart : Restart NetBox and RQ worker"
|
||||
echo " netbox-reload : Reinstall plugin and restart NetBox"
|
||||
echo " netbox-status : Check if NetBox and RQ worker are running"
|
||||
echo " netbox-logs : View NetBox server logs"
|
||||
echo ""
|
||||
echo "⚙️ Background Jobs (RQ Worker):"
|
||||
echo " rq-status : Check if RQ worker is running"
|
||||
echo " rq-logs : View RQ worker logs"
|
||||
echo " rq-stats : Show RQ queue statistics"
|
||||
echo " rq-jobs : List jobs in default queue"
|
||||
echo " rq-failed : List failed jobs"
|
||||
echo " rq-recent : Show recent NetBox jobs"
|
||||
echo ""
|
||||
echo "🛠️ Development Tools:"
|
||||
echo " netbox-shell : Open NetBox Django shell"
|
||||
echo " netbox-test : Run plugin tests"
|
||||
echo " netbox-manage : Run Django management commands"
|
||||
echo " plugin-install : Reinstall plugin in development mode"
|
||||
echo ""
|
||||
echo "🧹 Code Quality:"
|
||||
echo " ruff-check : Check code with Ruff"
|
||||
echo " ruff-format : Format code with Ruff"
|
||||
echo " ruff-fix : Auto-fix code issues with Ruff"
|
||||
echo ""
|
||||
echo "🔎 Diagnostics:"
|
||||
echo " diagnose : Run startup diagnostics"
|
||||
echo " dev-help : Show this help message"
|
||||
echo ""
|
||||
echo "📖 NetBox available at: http://localhost:8000 (admin/admin)"
|
||||
}
|
||||
|
||||
echo "✅ Dev helpers loaded! Try: rq-status, rq-stats, rq-recent, dev-help"
|
||||
24
.devcontainer/scripts/process-helpers.sh
Executable file
24
.devcontainer/scripts/process-helpers.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Shared process management helpers.
|
||||
# Sourced by load-aliases.sh and start-netbox.sh.
|
||||
|
||||
# Graceful termination: SIGTERM, wait, then SIGKILL if still alive.
|
||||
graceful_kill_pid() {
|
||||
local pid="$1"
|
||||
kill -15 "$pid" 2>/dev/null || true
|
||||
sleep 2
|
||||
kill -0 "$pid" 2>/dev/null && kill -9 "$pid" 2>/dev/null || true
|
||||
}
|
||||
|
||||
graceful_kill_pattern() {
|
||||
local pattern="$1"
|
||||
pkill -15 -f "$pattern" 2>/dev/null || true
|
||||
sleep 2
|
||||
pgrep -f "$pattern" >/dev/null 2>&1 && pkill -9 -f "$pattern" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Verify a PID matches the expected process before killing it
|
||||
is_expected_pid() {
|
||||
local pid="$1" pattern="$2"
|
||||
ps -p "$pid" -o args= 2>/dev/null | grep -Eq "$pattern"
|
||||
}
|
||||
329
.devcontainer/scripts/setup.sh
Executable file
329
.devcontainer/scripts/setup.sh
Executable file
@@ -0,0 +1,329 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🚀 Setting up NetBox LibreNMS Plugin development environment..."
|
||||
echo "📍 Current working directory: $(pwd)"
|
||||
echo "👤 Current user: $(whoami)"
|
||||
NETBOX_VERSION=${NETBOX_VERSION:-"latest"}
|
||||
echo "📦 Using NetBox Docker image: netboxcommunity/netbox:${NETBOX_VERSION}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Detect plugin workspace directory (must contain pyproject.toml).
|
||||
# Prints the resolved path to stdout on success, or an empty string on
|
||||
# failure. Always exits 0 — callers must check for an empty result.
|
||||
# ---------------------------------------------------------------------------
|
||||
detect_plugin_workspace() {
|
||||
if [ -f "$PWD/pyproject.toml" ]; then
|
||||
echo "$PWD"
|
||||
elif [ -d "/workspaces/netbox-librenms-plugin" ] && [ -f "/workspaces/netbox-librenms-plugin/pyproject.toml" ]; then
|
||||
echo "/workspaces/netbox-librenms-plugin"
|
||||
else
|
||||
local candidate
|
||||
candidate=$(find /workspaces -maxdepth 2 -type f -name pyproject.toml 2>/dev/null | head -n1 | xargs -r dirname || true)
|
||||
if [ -n "$candidate" ] && [ -f "$candidate/pyproject.toml" ]; then
|
||||
echo "$candidate"
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Clean up empty CA bundle vars (Compose injects "" when host var is unset)
|
||||
for _ca_var in REQUESTS_CA_BUNDLE SSL_CERT_FILE CURL_CA_BUNDLE; do
|
||||
_val="${!_ca_var}"
|
||||
[ -z "$_val" ] && unset "$_ca_var"
|
||||
done
|
||||
unset _ca_var _val
|
||||
|
||||
# Configure proxy for apt and pip if proxy environment variables are set
|
||||
if [ -n "$HTTP_PROXY" ] || [ -n "$HTTPS_PROXY" ]; then
|
||||
echo "🌐 Configuring proxy settings..."
|
||||
|
||||
# Configure apt proxy
|
||||
if [ -n "$HTTP_PROXY" ]; then
|
||||
echo "Acquire::http::Proxy \"$HTTP_PROXY\";" > /etc/apt/apt.conf.d/80proxy
|
||||
SAFE_HTTP_PROXY=$(echo "$HTTP_PROXY" | sed 's|://[^@]*@|://***:***@|')
|
||||
echo " ✓ apt HTTP proxy: $SAFE_HTTP_PROXY"
|
||||
fi
|
||||
if [ -n "$HTTPS_PROXY" ]; then
|
||||
echo "Acquire::https::Proxy \"$HTTPS_PROXY\";" >> /etc/apt/apt.conf.d/80proxy
|
||||
SAFE_HTTPS_PROXY=$(echo "$HTTPS_PROXY" | sed 's|://[^@]*@|://***:***@|')
|
||||
echo " ✓ apt HTTPS proxy: $SAFE_HTTPS_PROXY"
|
||||
fi
|
||||
|
||||
# Configure pip proxy via environment (already set, but ensure it's exported)
|
||||
export HTTP_PROXY HTTPS_PROXY http_proxy https_proxy NO_PROXY no_proxy
|
||||
|
||||
# Install custom CA certificate into the system trust store (for MITM proxies)
|
||||
PLUGIN_WS_DIR_EARLY="$(detect_plugin_workspace)"
|
||||
[ -z "$PLUGIN_WS_DIR_EARLY" ] && PLUGIN_WS_DIR_EARLY="/workspaces/netbox-librenms-plugin"
|
||||
CA_BUNDLE_SRC="$PLUGIN_WS_DIR_EARLY/ca-bundle.crt"
|
||||
if [ -f "$CA_BUNDLE_SRC" ]; then
|
||||
echo "🔐 Installing custom CA certificate into system trust store..."
|
||||
cert_count=$(grep -c '-----BEGIN CERTIFICATE-----' "$CA_BUNDLE_SRC" 2>/dev/null || true)
|
||||
if [ "${cert_count:-0}" -eq 0 ]; then
|
||||
echo " ⚠️ ca-bundle.crt does not contain any PEM certificate blocks; skipping CA install."
|
||||
else
|
||||
mkdir -p /usr/local/share/ca-certificates/proxy
|
||||
# Remove stale split fragments so they don't accumulate across rebuilds
|
||||
find /usr/local/share/ca-certificates/proxy -maxdepth 1 -name 'cert-*' -delete 2>/dev/null || true
|
||||
# Split the bundle into individual certs — update-ca-certificates needs one
|
||||
# cert per file and skips non-CA leaf certs, so extract each PEM block as
|
||||
# a separate .crt file.
|
||||
csplit -z -f /usr/local/share/ca-certificates/proxy/cert- \
|
||||
"$CA_BUNDLE_SRC" '/-----BEGIN CERTIFICATE-----/' '{*}' \
|
||||
>/dev/null 2>&1
|
||||
CSPLIT_STATUS=$?
|
||||
if [ "$CSPLIT_STATUS" -ne 0 ]; then
|
||||
echo " ⚠️ Failed to split ca-bundle.crt (csplit exit code: $CSPLIT_STATUS). Skipping CA install."
|
||||
elif compgen -G "/usr/local/share/ca-certificates/proxy/cert-*" > /dev/null; then
|
||||
# Rename split fragments to .crt
|
||||
for f in /usr/local/share/ca-certificates/proxy/cert-*; do
|
||||
mv "$f" "${f}.crt" 2>/dev/null || true
|
||||
done
|
||||
update-ca-certificates 2>/dev/null
|
||||
echo " ✓ CA certificate installed into system trust store ($cert_count cert(s))"
|
||||
else
|
||||
echo " ⚠️ No certificate fragments were generated from ca-bundle.crt; skipping CA install."
|
||||
fi
|
||||
fi
|
||||
# Point environment variables to the system bundle
|
||||
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
|
||||
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
export CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
|
||||
export GIT_SSL_CAINFO=/etc/ssl/certs/ca-certificates.crt
|
||||
# Configure pip globally so isolated virtualenvs (e.g. pre-commit) also
|
||||
# use the system CA bundle instead of their bundled certifi.
|
||||
pip config set global.cert /etc/ssl/certs/ca-certificates.crt 2>/dev/null || true
|
||||
else
|
||||
echo " ℹ️ No ca-bundle.crt found at $CA_BUNDLE_SRC, skipping CA install"
|
||||
# Only disable git SSL verification if explicitly opted-in via ALLOW_GIT_SSL_DISABLE.
|
||||
# Silently disabling SSL is a security risk; prefer providing a CA bundle instead.
|
||||
if [ "${ALLOW_GIT_SSL_DISABLE:-false}" = "true" ]; then
|
||||
git config --global http.sslVerify false
|
||||
echo " ⚠️ git SSL verification disabled globally (ALLOW_GIT_SSL_DISABLE=true)"
|
||||
else
|
||||
echo " ⚠️ No CA bundle found and git SSL verification was NOT disabled."
|
||||
echo " If you need to disable it, set ALLOW_GIT_SSL_DISABLE=true in .devcontainer/.env"
|
||||
echo " Preferred: provide a ca-bundle.crt in the workspace root instead."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Verify NetBox virtual environment exists
|
||||
if [ ! -f "/opt/netbox/venv/bin/activate" ]; then
|
||||
echo "❌ NetBox virtual environment not found at /opt/netbox/venv/"
|
||||
echo "This might indicate an issue with the NetBox Docker image."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🐍 Activating NetBox virtual environment..."
|
||||
source /opt/netbox/venv/bin/activate
|
||||
|
||||
# Choose installer (uv if available, else pip)
|
||||
if command -v uv >/dev/null 2>&1; then
|
||||
PIP_CMD="uv pip"
|
||||
else
|
||||
PIP_CMD="pip"
|
||||
fi
|
||||
|
||||
# Install dev tools
|
||||
echo "🔧 Installing development dependencies..."
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq net-tools git
|
||||
$PIP_CMD install pytest pytest-django ruff pre-commit
|
||||
|
||||
# Install GitHub CLI (gh)
|
||||
# NOTE: The chained && commands below mean a partial failure (e.g. wget succeeds
|
||||
# but apt-get install gh fails) may leave artifacts (keyring, sources list, temp
|
||||
# file). This is acceptable here because it only runs during container build —
|
||||
# a rebuild will retry from scratch. If this block is ever moved to a runtime
|
||||
# script, consider adding a trap or explicit cleanup on error.
|
||||
if ! command -v gh >/dev/null 2>&1; then
|
||||
echo "🔧 Installing GitHub CLI..."
|
||||
(type -p wget >/dev/null || apt-get install -y -qq wget) \
|
||||
&& install -d -m 755 /etc/apt/keyrings \
|
||||
&& out=$(mktemp) \
|
||||
&& wget -qO "$out" https://cli.github.com/packages/githubcli-archive-keyring.gpg \
|
||||
&& cat "$out" | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
|
||||
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
||||
&& apt-get update -qq \
|
||||
&& apt-get install -y -qq gh \
|
||||
&& rm -f "$out" \
|
||||
&& echo " ✓ GitHub CLI installed: $(gh --version | head -1)" \
|
||||
|| echo "⚠️ GitHub CLI installation failed (non-fatal)"
|
||||
fi
|
||||
|
||||
# Detect plugin workspace directory using the shared helper
|
||||
PLUGIN_WS_DIR="$(detect_plugin_workspace)"
|
||||
if [ -z "$PLUGIN_WS_DIR" ]; then
|
||||
echo "❌ Could not locate plugin workspace directory (pyproject.toml not found)."
|
||||
echo " Checked: $PWD and /workspaces/*"
|
||||
exit 1
|
||||
fi
|
||||
echo "📂 Plugin workspace: $PLUGIN_WS_DIR"
|
||||
|
||||
# Install this plugin in development mode
|
||||
echo "📦 Installing plugin in development mode from: $PLUGIN_WS_DIR"
|
||||
if [ ! -f "$PLUGIN_WS_DIR/pyproject.toml" ] && [ ! -f "$PLUGIN_WS_DIR/setup.py" ]; then
|
||||
echo "❌ Neither pyproject.toml nor setup.py found in $PLUGIN_WS_DIR"
|
||||
ls -la "$PLUGIN_WS_DIR" || true
|
||||
exit 2
|
||||
fi
|
||||
cd "$PLUGIN_WS_DIR"
|
||||
$PIP_CMD install -e .
|
||||
|
||||
CONF_FILE="/opt/netbox/netbox/netbox/configuration.py"
|
||||
|
||||
# Optional extras
|
||||
if [ -f "$PLUGIN_WS_DIR/.devcontainer/extra-requirements.txt" ]; then
|
||||
echo "📦 Installing extra packages from extra-requirements.txt..."
|
||||
$PIP_CMD install -r "$PLUGIN_WS_DIR/.devcontainer/extra-requirements.txt"
|
||||
fi
|
||||
|
||||
|
||||
# Inject plugin loader into standard NetBox configuration if present
|
||||
if [ -f "$CONF_FILE" ]; then
|
||||
if ! grep -q "# Devcontainer Plugins Loader" "$CONF_FILE" 2>/dev/null; then
|
||||
{
|
||||
echo "";
|
||||
echo "# Devcontainer Plugins Loader";
|
||||
echo "# Import PLUGINS/PLUGINS_CONFIG and optional extras dynamically from the workspace";
|
||||
echo "import importlib.util, os";
|
||||
echo "PLUGINS = ['netbox_librenms_plugin']";
|
||||
echo "PLUGINS_CONFIG = {'netbox_librenms_plugin': {}}";
|
||||
echo "_pc_path = '$PLUGIN_WS_DIR/.devcontainer/config/plugin-config.py'";
|
||||
echo "if os.path.isfile(_pc_path):";
|
||||
echo " _spec = importlib.util.spec_from_file_location('workspace_plugin_config', _pc_path)";
|
||||
echo " _mod = importlib.util.module_from_spec(_spec)";
|
||||
echo " try:";
|
||||
echo " _spec.loader.exec_module(_mod) # type: ignore[attr-defined]";
|
||||
echo " PLUGINS = getattr(_mod, 'PLUGINS', PLUGINS)";
|
||||
echo " PLUGINS_CONFIG = getattr(_mod, 'PLUGINS_CONFIG', PLUGINS_CONFIG)";
|
||||
echo " except Exception as e:";
|
||||
echo " print(f'⚠️ Failed to load plugin-config.py: {e}')";
|
||||
echo "else:";
|
||||
echo " print('ℹ️ plugin-config.py not found; using defaults')";
|
||||
|
||||
echo "# Import optional extra NetBox configuration (uppercase settings)";
|
||||
echo "_xc_path = '$PLUGIN_WS_DIR/.devcontainer/config/extra-configuration.py'";
|
||||
echo "if os.path.isfile(_xc_path):";
|
||||
echo " _xc_spec = importlib.util.spec_from_file_location('workspace_extra_configuration', _xc_path)";
|
||||
echo " _xc_mod = importlib.util.module_from_spec(_xc_spec)";
|
||||
echo " try:";
|
||||
echo " _xc_spec.loader.exec_module(_xc_mod) # type: ignore[attr-defined]";
|
||||
echo " for _name in dir(_xc_mod):";
|
||||
echo " if _name.isupper():";
|
||||
echo " globals()[_name] = getattr(_xc_mod, _name)";
|
||||
echo " except Exception as e:";
|
||||
echo " print(f'⚠️ Failed to apply extra-configuration.py: {e}')";
|
||||
|
||||
echo "# Import Codespaces configuration when applicable (uppercase settings)";
|
||||
echo "_cs_path = '$PLUGIN_WS_DIR/.devcontainer/config/codespaces-configuration.py'";
|
||||
echo "if os.environ.get('CODESPACES') == 'true' and os.path.isfile(_cs_path):";
|
||||
echo " _cs_spec = importlib.util.spec_from_file_location('workspace_codespaces_configuration', _cs_path)";
|
||||
echo " _cs_mod = importlib.util.module_from_spec(_cs_spec)";
|
||||
echo " try:";
|
||||
echo " _cs_spec.loader.exec_module(_cs_mod) # type: ignore[attr-defined]";
|
||||
echo " for _name in dir(_cs_mod):";
|
||||
echo " if _name.isupper():";
|
||||
echo " globals()[_name] = getattr(_cs_mod, _name)";
|
||||
echo " except Exception as e:";
|
||||
echo " print(f'⚠️ Failed to apply codespaces-configuration.py: {e}')";
|
||||
|
||||
echo "# Ensure SECRET_KEY exists: prefer environment, fallback to a dev placeholder";
|
||||
echo "if 'SECRET_KEY' not in globals() or not SECRET_KEY:";
|
||||
echo " SECRET_KEY = os.environ.get('SECRET_KEY', 'dummydummydummydummydummydummydummydummydummydummydummydummy')";
|
||||
} >> "$CONF_FILE"
|
||||
fi
|
||||
|
||||
if grep -q "netbox_librenms_plugin" "$CONF_FILE" 2>/dev/null; then
|
||||
echo "✅ Plugin configuration exists in NetBox settings"
|
||||
fi
|
||||
|
||||
|
||||
else
|
||||
echo "⚠️ Warning: $CONF_FILE not found"
|
||||
echo "Plugin configuration may need to be added manually"
|
||||
fi
|
||||
|
||||
# Run migrations and collectstatic
|
||||
cd /opt/netbox/netbox
|
||||
|
||||
# Wait briefly for DB (compose healthchecks should ensure availability)
|
||||
export DEBUG="${DEBUG:-True}"
|
||||
|
||||
echo "🗃️ Applying database migrations..."
|
||||
python manage.py migrate 2>&1 | grep -E "(Operations to perform|Running migrations|Apply all migrations|No migrations to apply|\s+Applying|\s+OK)" || true
|
||||
|
||||
echo "🔐 Creating superuser (if not exists)..."
|
||||
echo " Credentials are read from environment variables (see .devcontainer/.env)"
|
||||
python manage.py shell -c "
|
||||
import os
|
||||
from django.contrib.auth import get_user_model
|
||||
User = get_user_model()
|
||||
username = (os.environ.get('SUPERUSER_NAME') or '').strip() or 'admin'
|
||||
email = (os.environ.get('SUPERUSER_EMAIL') or '').strip() or 'admin@example.com'
|
||||
password = (os.environ.get('SUPERUSER_PASSWORD') or '').strip() or 'admin'
|
||||
if not User.objects.filter(username=username).exists():
|
||||
User.objects.create_superuser(username, email, password)
|
||||
print(f'Created superuser: {username}')
|
||||
else:
|
||||
print(f'Superuser {username} already exists')
|
||||
" 2>/dev/null || true
|
||||
|
||||
echo "📊 Collecting static files..."
|
||||
python manage.py collectstatic --noinput >/dev/null 2>&1 || true
|
||||
|
||||
# Set up pre-commit hooks
|
||||
echo "🪝 Installing pre-commit hooks..."
|
||||
cd "$PLUGIN_WS_DIR"
|
||||
git config --global --add safe.directory "$PLUGIN_WS_DIR"
|
||||
pre-commit install --install-hooks 2>/dev/null || echo "⚠️ Pre-commit hook installation failed (may already be installed)"
|
||||
|
||||
# Ensure scripts are executable
|
||||
chmod +x "$PLUGIN_WS_DIR/.devcontainer/scripts/start-netbox.sh" || true
|
||||
chmod +x "$PLUGIN_WS_DIR/.devcontainer/scripts/diagnose.sh" || true
|
||||
chmod +x "$PLUGIN_WS_DIR/.devcontainer/scripts/load-aliases.sh" || true
|
||||
|
||||
# Load aliases and welcome message from the canonical source (load-aliases.sh).
|
||||
# Appended to .bashrc so every interactive shell gets them automatically.
|
||||
# Guard with a sentinel so rerunning setup.sh doesn't create duplicate entries.
|
||||
BASHRC_SENTINEL="# NetBox LibreNMS Plugin — source aliases from the single canonical file"
|
||||
if ! grep -qF "$BASHRC_SENTINEL" ~/.bashrc 2>/dev/null; then
|
||||
cat >> ~/.bashrc << EOF
|
||||
$BASHRC_SENTINEL
|
||||
source "$PLUGIN_WS_DIR/.devcontainer/scripts/load-aliases.sh"
|
||||
|
||||
# Show welcome message for new terminals
|
||||
bash "$PLUGIN_WS_DIR/.devcontainer/scripts/welcome.sh"
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Fix Git remote URLs for dev container compatibility
|
||||
echo "🔧 Checking Git remote configuration..."
|
||||
cd "$PLUGIN_WS_DIR"
|
||||
CURRENT_REMOTE=$(git remote get-url origin 2>/dev/null || echo "")
|
||||
if [[ "$CURRENT_REMOTE" == git@github.com:* ]]; then
|
||||
# Convert SSH URL to HTTPS for dev container compatibility
|
||||
HTTPS_URL=$(echo "$CURRENT_REMOTE" | sed 's|git@github.com:|https://github.com/|')
|
||||
git remote set-url origin "$HTTPS_URL"
|
||||
echo "✅ Converted Git remote from SSH to HTTPS: $HTTPS_URL"
|
||||
echo " This ensures compatibility with GitHub CLI authentication in dev containers"
|
||||
elif [[ "$CURRENT_REMOTE" == https://github.com/* ]]; then
|
||||
echo "✅ Git remote already uses HTTPS: $CURRENT_REMOTE"
|
||||
else
|
||||
echo "ℹ️ Git remote URL: $CURRENT_REMOTE (no changes needed)"
|
||||
fi
|
||||
|
||||
# Final validation
|
||||
cd /opt/netbox/netbox
|
||||
if python -c "import netbox_librenms_plugin; print('✅ Plugin import successful')" 2>/dev/null | grep -q "✅ Plugin import successful"; then
|
||||
echo "✅ Plugin is properly installed and importable"
|
||||
else
|
||||
echo "⚠️ Warning: Plugin may not be properly installed"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🚀 NetBox LibreNMS Plugin Dev Environment Ready!"
|
||||
107
.devcontainer/scripts/start-netbox.sh
Executable file
107
.devcontainer/scripts/start-netbox.sh
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if we should run in background or foreground
|
||||
BACKGROUND=false
|
||||
if [ "$1" = "--background" ] || [ "$1" = "-b" ]; then
|
||||
BACKGROUND=true
|
||||
fi
|
||||
|
||||
echo "🌐 Starting NetBox development server..."
|
||||
|
||||
# Set required environment variables
|
||||
export DEBUG="${DEBUG:-True}"
|
||||
|
||||
# Detect Codespaces and set access URL
|
||||
if [ "$CODESPACES" = "true" ] && [ -n "$CODESPACE_NAME" ]; then
|
||||
GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN="${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN:-app.github.dev}"
|
||||
ACCESS_URL="https://${CODESPACE_NAME}-8000.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}"
|
||||
echo "🔗 GitHub Codespaces detected"
|
||||
else
|
||||
ACCESS_URL="http://localhost:8000"
|
||||
echo "🐛 Debug: ACCESS_URL is set to: $ACCESS_URL"
|
||||
fi
|
||||
|
||||
# Load shared process management helpers
|
||||
if ! source "$(dirname "$0")/process-helpers.sh"; then
|
||||
echo "ERROR: Failed to load process-helpers.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Kill any orphaned processes (not tracked by PID file)
|
||||
echo "🧹 Cleaning up orphaned processes..."
|
||||
if pgrep -f "python.*rqworker" >/dev/null 2>&1; then
|
||||
echo " Found orphaned RQ workers, killing..."
|
||||
graceful_kill_pattern "python.*rqworker"
|
||||
fi
|
||||
|
||||
if pgrep -f "python.*runserver.*8000" >/dev/null 2>&1; then
|
||||
echo " Found orphaned NetBox servers, killing..."
|
||||
graceful_kill_pattern "python.*runserver.*8000"
|
||||
fi
|
||||
|
||||
# Stop any tracked processes from PID files
|
||||
if [ -f /tmp/netbox.pid ]; then
|
||||
OLD_PID=$(cat /tmp/netbox.pid 2>/dev/null)
|
||||
if [ -n "$OLD_PID" ] && kill -0 "$OLD_PID" 2>/dev/null; then
|
||||
if is_expected_pid "$OLD_PID" "python.*runserver.*8000"; then
|
||||
graceful_kill_pid "$OLD_PID"
|
||||
else
|
||||
echo "⚠️ Skipping stale /tmp/netbox.pid (PID $OLD_PID is not NetBox runserver)"
|
||||
fi
|
||||
fi
|
||||
rm -f /tmp/netbox.pid
|
||||
fi
|
||||
|
||||
if [ -f /tmp/rqworker.pid ]; then
|
||||
OLD_PID=$(cat /tmp/rqworker.pid 2>/dev/null)
|
||||
if [ -n "$OLD_PID" ] && kill -0 "$OLD_PID" 2>/dev/null; then
|
||||
if is_expected_pid "$OLD_PID" "python.*rqworker"; then
|
||||
graceful_kill_pid "$OLD_PID"
|
||||
else
|
||||
echo "⚠️ Skipping stale /tmp/rqworker.pid (PID $OLD_PID is not rqworker)"
|
||||
fi
|
||||
fi
|
||||
rm -f /tmp/rqworker.pid
|
||||
fi
|
||||
|
||||
# Activate NetBox virtual environment
|
||||
source /opt/netbox/venv/bin/activate
|
||||
|
||||
# Navigate to NetBox directory
|
||||
cd /opt/netbox/netbox
|
||||
|
||||
# Start RQ worker in background
|
||||
echo "⚙️ Starting RQ worker..."
|
||||
(
|
||||
source /opt/netbox/venv/bin/activate
|
||||
cd /opt/netbox/netbox
|
||||
python manage.py rqworker --verbosity=1
|
||||
) > /tmp/rqworker.log 2>&1 &
|
||||
|
||||
RQ_PID=$!
|
||||
echo $RQ_PID > /tmp/rqworker.pid
|
||||
echo "✅ RQ worker started (PID: $RQ_PID)"
|
||||
|
||||
if [ "$BACKGROUND" = true ]; then
|
||||
echo "🚀 Starting NetBox in background"
|
||||
(
|
||||
export DEBUG="${DEBUG:-True}"
|
||||
source /opt/netbox/venv/bin/activate
|
||||
cd /opt/netbox/netbox
|
||||
python manage.py runserver 0.0.0.0:8000 --verbosity=0
|
||||
) > /tmp/netbox.log 2>&1 &
|
||||
|
||||
NETBOX_PID=$!
|
||||
echo $NETBOX_PID > /tmp/netbox.pid
|
||||
echo "✅ NetBox started in background (PID: $NETBOX_PID)"
|
||||
echo "📍 Access NetBox at: $ACCESS_URL"
|
||||
echo "💡 If clicking the URL opens 0.0.0.0:8000, manually type: localhost:8000"
|
||||
echo "📄 View logs with: netbox-logs"
|
||||
echo "🛑 Stop NetBox with: netbox-stop"
|
||||
else
|
||||
echo "🌍 Starting NetBox in foreground"
|
||||
echo "📍 Access NetBox at: $ACCESS_URL"
|
||||
echo "💡 If clicking the URL opens 0.0.0.0:8000, manually type: localhost:8000"
|
||||
echo ""
|
||||
python manage.py runserver 0.0.0.0:8000
|
||||
fi
|
||||
56
.devcontainer/scripts/welcome.sh
Executable file
56
.devcontainer/scripts/welcome.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Ensure aliases are available in the postAttach terminal session
|
||||
source "$(dirname "$0")/load-aliases.sh" 2>/dev/null
|
||||
|
||||
echo ""
|
||||
echo "🎯 NetBox LibreNMS Plugin Development Environment"
|
||||
|
||||
PLUGIN_WS_DIR="${PLUGIN_DIR:-$(cd "$(dirname "$0")/../.." && pwd)}"
|
||||
if [ ! -f "$PLUGIN_WS_DIR/.devcontainer/config/plugin-config.py" ]; then
|
||||
echo ""
|
||||
echo "⚠️ Plugin configuration not found: .devcontainer/config/plugin-config.py"
|
||||
echo " Create it first: cp .devcontainer/config/plugin-config.py.example .devcontainer/config/plugin-config.py"
|
||||
echo " Then edit it and set your plugin values (e.g. LibreNMS server URL/token)"
|
||||
fi
|
||||
|
||||
# Check GitHub CLI authentication status
|
||||
echo ""
|
||||
if command -v gh >/dev/null 2>&1; then
|
||||
if gh auth status >/dev/null 2>&1; then
|
||||
# Get the authenticated user info
|
||||
GH_USER=$(gh api user --jq '.login' 2>/dev/null || echo "unknown")
|
||||
echo "✅ GitHub authenticated as: $GH_USER"
|
||||
echo " Git is configured for GitHub operations"
|
||||
else
|
||||
echo "🔑 GitHub CLI available but not authenticated"
|
||||
echo " Run 'gh auth login' to authenticate with GitHub"
|
||||
echo " This will automatically configure Git for pushing/pulling"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ GitHub CLI not available"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [ -n "$CODESPACES" ]; then
|
||||
echo "🌐 GitHub Codespaces Environment:"
|
||||
echo " NetBox will be available via automatic port forwarding"
|
||||
echo " Check the 'Ports' panel for the forwarded port labeled 'NetBox Web Interface'"
|
||||
if [ -n "$CODESPACE_NAME" ]; then
|
||||
# Try to construct the likely URL (GitHub Codespaces pattern)
|
||||
CODESPACE_URL="https://${CODESPACE_NAME}-8000.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN:-preview.app.github.dev}"
|
||||
echo " Expected URL: $CODESPACE_URL"
|
||||
fi
|
||||
echo " 💡 Click the link in the Ports panel or look for the 'Open in Browser' button"
|
||||
else
|
||||
echo "🖥️ Local Development Environment:"
|
||||
echo " NetBox will be available at: http://localhost:8000 (paste into you browser)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🚀 Quick start:"
|
||||
echo " • Type 'netbox-run' to start the development server"
|
||||
echo " • Type 'netbox-restart' to restart NetBox (after config changes)"
|
||||
echo " • Type 'dev-help' to see all available commands"
|
||||
echo " • Edit code in the workspace - auto-reload is enabled"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user