mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-04-08 03:01:29 -07:00
Merge pull request #1340 from adamoutler/devcontainer-devices
Devcontainer-devices
This commit is contained in:
78
.devcontainer/scripts/load-devices.sh
Executable file
78
.devcontainer/scripts/load-devices.sh
Executable file
@@ -0,0 +1,78 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||||
|
if [ -n "${CSV_PATH:-}" ]; then
|
||||||
|
: # user provided CSV_PATH
|
||||||
|
else
|
||||||
|
# Portable mktemp fallback: try GNU coreutils first, then busybox-style
|
||||||
|
if mktemp --version >/dev/null 2>&1; then
|
||||||
|
CSV_PATH="$(mktemp --tmpdir netalertx-devices-XXXXXX.csv 2>/dev/null || mktemp /tmp/netalertx-devices-XXXXXX.csv)"
|
||||||
|
else
|
||||||
|
CSV_PATH="$(mktemp -t netalertx-devices.XXXXXX 2>/dev/null || mktemp /tmp/netalertx-devices-XXXXXX.csv)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
DEVICE_COUNT="${DEVICE_COUNT:-255}"
|
||||||
|
SEED="${SEED:-20211}"
|
||||||
|
NETWORK_CIDR="${NETWORK_CIDR:-192.168.50.0/22}"
|
||||||
|
DB_DIR="${NETALERTX_DB:-/data/db}"
|
||||||
|
DB_FILE="${DB_DIR%/}/app.db"
|
||||||
|
|
||||||
|
# Ensure we are inside the devcontainer
|
||||||
|
"${SCRIPT_DIR}/isDevContainer.sh" >/dev/null
|
||||||
|
|
||||||
|
if [ ! -f "${DB_FILE}" ]; then
|
||||||
|
echo "[load-devices] Database not found at ${DB_FILE}. Is the devcontainer initialized?" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v sqlite3 >/dev/null 2>&1; then
|
||||||
|
echo "[load-devices] sqlite3 is required but not installed." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! command -v python3 >/dev/null 2>&1; then
|
||||||
|
echo "[load-devices] python3 is required but not installed." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! command -v curl >/dev/null 2>&1; then
|
||||||
|
echo "[load-devices] curl is required but not installed." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate synthetic device inventory CSV
|
||||||
|
python3 "${REPO_ROOT}/scripts/generate-device-inventory.py" \
|
||||||
|
--output "${CSV_PATH}" \
|
||||||
|
--devices "${DEVICE_COUNT}" \
|
||||||
|
--seed "${SEED}" \
|
||||||
|
--network "${NETWORK_CIDR}" >/dev/null
|
||||||
|
|
||||||
|
echo "[load-devices] CSV generated at ${CSV_PATH} (devices=${DEVICE_COUNT}, seed=${SEED})"
|
||||||
|
|
||||||
|
API_TOKEN="$(sqlite3 "${DB_FILE}" "SELECT setValue FROM Settings WHERE setKey='API_TOKEN';")"
|
||||||
|
GRAPHQL_PORT="$(sqlite3 "${DB_FILE}" "SELECT setValue FROM Settings WHERE setKey='GRAPHQL_PORT';")"
|
||||||
|
|
||||||
|
if [ -z "${API_TOKEN}" ] || [ -z "${GRAPHQL_PORT}" ]; then
|
||||||
|
echo "[load-devices] Failed to read API_TOKEN or GRAPHQL_PORT from ${DB_FILE}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IMPORT_URL="http://localhost:${GRAPHQL_PORT}/devices/import"
|
||||||
|
|
||||||
|
HTTP_CODE=$(curl -sS -o /tmp/load-devices-response.json -w "%{http_code}" \
|
||||||
|
-X POST "${IMPORT_URL}" \
|
||||||
|
-H "Authorization: Bearer ${API_TOKEN}" \
|
||||||
|
-F "file=@${CSV_PATH}")
|
||||||
|
|
||||||
|
if [ "${HTTP_CODE}" != "200" ]; then
|
||||||
|
echo "[load-devices] Import failed with HTTP ${HTTP_CODE}. Response:" >&2
|
||||||
|
cat /tmp/load-devices-response.json >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fetch totals for a quick sanity check
|
||||||
|
TOTALS=$(curl -sS -H "Authorization: Bearer ${API_TOKEN}" "http://localhost:${GRAPHQL_PORT}/devices/totals" || true)
|
||||||
|
|
||||||
|
echo "[load-devices] Import succeeded (HTTP ${HTTP_CODE})."
|
||||||
|
echo "[load-devices] Devices totals: ${TOTALS}"
|
||||||
|
echo "[load-devices] Done. CSV kept at ${CSV_PATH}"
|
||||||
27
.vscode/tasks.json
vendored
27
.vscode/tasks.json
vendored
@@ -21,7 +21,6 @@
|
|||||||
"showReuseMessage": false,
|
"showReuseMessage": false,
|
||||||
"group": "POSIX Tasks"
|
"group": "POSIX Tasks"
|
||||||
},
|
},
|
||||||
|
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
@@ -59,6 +58,31 @@
|
|||||||
"color": "terminal.ansiRed"
|
"color": "terminal.ansiRed"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "[Dev Container] Load Sample Devices",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "./isDevContainer.sh || exit 1; ./load-devices.sh",
|
||||||
|
"detail": "Generates a synthetic device inventory and imports it into the devcontainer database via /devices/import.",
|
||||||
|
"options": {
|
||||||
|
"cwd": "/workspaces/NetAlertX/.devcontainer/scripts",
|
||||||
|
"env": {
|
||||||
|
"CSV_PATH": "/tmp/netalertx-devices.csv"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared",
|
||||||
|
"showReuseMessage": false,
|
||||||
|
"clear": false,
|
||||||
|
"group": "Devcontainer"
|
||||||
|
},
|
||||||
|
"problemMatcher": [],
|
||||||
|
"icon": {
|
||||||
|
"id": "cloud-upload",
|
||||||
|
"color": "terminal.ansiYellow"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "[Dev Container] Re-Run Startup Script",
|
"label": "[Dev Container] Re-Run Startup Script",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
@@ -73,7 +97,6 @@
|
|||||||
"panel": "shared",
|
"panel": "shared",
|
||||||
"showReuseMessage": false
|
"showReuseMessage": false
|
||||||
},
|
},
|
||||||
|
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"icon": {
|
"icon": {
|
||||||
"id": "beaker",
|
"id": "beaker",
|
||||||
|
|||||||
@@ -162,8 +162,9 @@ def build_row(
|
|||||||
now: dt.datetime,
|
now: dt.datetime,
|
||||||
) -> dict[str, str]:
|
) -> dict[str, str]:
|
||||||
comments = "Synthetic device generated for testing."
|
comments = "Synthetic device generated for testing."
|
||||||
first_seen = random_time(now)
|
t1 = random_time(now)
|
||||||
last_seen = random_time(now)
|
t2 = random_time(now)
|
||||||
|
first_seen, last_seen = (t1, t2) if t1 <= t2 else (t2, t1)
|
||||||
fqdn = f"{name.lower().replace(' ', '-')}.{site}" if name else ""
|
fqdn = f"{name.lower().replace(' ', '-')}.{site}" if name else ""
|
||||||
|
|
||||||
# Minimal fields set; missing ones default to empty string for CSV compatibility.
|
# Minimal fields set; missing ones default to empty string for CSV compatibility.
|
||||||
@@ -215,6 +216,7 @@ def generate_rows(args: argparse.Namespace, header: list[str]) -> list[dict[str,
|
|||||||
|
|
||||||
rows: list[dict[str, str]] = []
|
rows: list[dict[str, str]] = []
|
||||||
|
|
||||||
|
# Include one Internet root device that anchors the tree; it does not consume an IP.
|
||||||
required_devices = 1 + args.switches + args.aps + args.devices
|
required_devices = 1 + args.switches + args.aps + args.devices
|
||||||
if required_devices > len(ip_pool):
|
if required_devices > len(ip_pool):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@@ -227,6 +229,30 @@ def generate_rows(args: argparse.Namespace, header: list[str]) -> list[dict[str,
|
|||||||
ip_pool.remove(choice)
|
ip_pool.remove(choice)
|
||||||
return choice
|
return choice
|
||||||
|
|
||||||
|
# Root "Internet" device (no parent, no IP) so the topology has a defined root.
|
||||||
|
root_row = build_row(
|
||||||
|
name="Internet",
|
||||||
|
dev_type="Gateway",
|
||||||
|
vendor="NetAlertX",
|
||||||
|
mac="Internet",
|
||||||
|
parent_mac="",
|
||||||
|
ip="",
|
||||||
|
header=header,
|
||||||
|
owner=args.owner,
|
||||||
|
site=args.site,
|
||||||
|
ssid=args.ssid,
|
||||||
|
now=now,
|
||||||
|
)
|
||||||
|
root_row["devComments"] = "Synthetic root device representing the Internet."
|
||||||
|
root_row["devParentRelType"] = "Root"
|
||||||
|
root_row["devStaticIP"] = "0"
|
||||||
|
root_row["devScan"] = "0"
|
||||||
|
root_row["devAlertEvents"] = "0"
|
||||||
|
root_row["devAlertDown"] = "0"
|
||||||
|
root_row["devLogEvents"] = "0"
|
||||||
|
root_row["devPresentLastScan"] = "0"
|
||||||
|
rows.append(root_row)
|
||||||
|
|
||||||
router_mac = random_mac(macs)
|
router_mac = random_mac(macs)
|
||||||
router_ip = take_ip()
|
router_ip = take_ip()
|
||||||
rows.append(
|
rows.append(
|
||||||
|
|||||||
Reference in New Issue
Block a user