diff --git a/WORKING.md b/WORKING.md index 797f026..e69de29 100644 --- a/WORKING.md +++ b/WORKING.md @@ -1,18 +0,0 @@ -# WORKING.md — Active Session Tracker - -Agent work only. The human decides when it's done. -A commit is blocked while any task below remains unchecked. - -## Current Tasks — 2026-09-02 full session (all verified; details in Redmine #682/#683) - -- [x] hap-bridge retired; unsupported fixed; ecobee multicast-reachable; daemon tests (babd6d2) -- [x] iDRAC SNMP both live; DRAC temps → 5 HA entities °F; extend shellchecked (#625 @95%) -- [x] Govee configured E2E (key+2FA+MQTT); zero cloud devices = BLE-only (#620 @60%) -- [x] Dashboards: Server-Room (views fix + rack-labeled temps), Health v2 (+Heart view), Garage (+PDU), Art Room (#618 @85%) -- [x] Fleet snmp package: unknown-render + state_class fixes (2026.8 add-time entity drop) — 22 entities live -- [x] Garage PDU → tsys-librenms relay → HA (A + W); PDU deleted from LibreNMS (authorized) -- [x] Alerts: DRACs in 104°F trigger; tsys9 dead refs dropped; sensor-watchdog automation; test-fire sent (UAT pending) -- [x] VM ingestion verified; Grafana started + datasource live; NUT add-on disabled; watchdog re-enabled -- [x] Masters #682/#683 cut + reparented; #628 plan v4 final (PBS + drive rotation); #684 PBS ticket -- [x] tsys9 upsd.users synced (founder-approved) — UPS hardware absent (founder) -- [x] Field lessons + audit #298 (#50/#53/#55/#60) + notes on #344/#618/#620/#621/#625/#627/#628/#439/#465/#682/#630 diff --git a/ca/README.md b/ca/README.md deleted file mode 100644 index abcd6ee..0000000 --- a/ca/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# ca/ — PFV fleet Certificate Authority tooling [#697] - -> Design + runbook (canonical): https://community.turnsys.com/t/320 -> Root of trust for: LDAPS, RADIUS (#476), OPNsense, k8s, iDRAC/OME, -> Wazuh/syslog TLS. HSM-backed root ceremony comes later (#697 Nitrokey). - -## Architecture (v1, software) - -- **Root CA**: RSA-4096, 10y, OFFLINE — lives only in `/root/ca-root/` on - tsys-ca (moved to Nitrokey at the #697 ceremony). Never leaves the box; - signs only the intermediate. -- **Intermediate CA**: RSA-4096, 5y, on tsys-ca at `/etc/ssl/tsys-ca/` — - signs all leaf certs. pathlen:0. -- **Leaves**: RSA-2048, ≤825 days, SAN-based (serverAuth + clientAuth). -- **No CRL/OCSP in v1** (fleet-internal); revocation = re-issue + intermediate - pinning. CRL endpoint deferred to the GLPI/ITSM pass. -- **Compat stance**: RSA+SHA-256 only — old Dell/iDRAC-era clients. - -## Files - -| File | Purpose | -|------|---------| -| `ca-init.sh` | Initialize root + intermediate dirs ON THE CA HOST (keys never leave tsys-ca) | -| `issue-cert.sh` | Issue a leaf cert: `issue-cert.sh "DNS:a,DNS:b,IP:x"` | -| `selftest.sh` | Full throwaway loop in /tmp — init, issue, chain-verify (TDD gate) | - -## Usage (on tsys-ca, as root) - -```bash -bash ca-init.sh /root/ca-root /etc/ssl/tsys-ca # once -bash issue-cert.sh tsys-wazuh.knel.net "DNS:tsys-wazuh.knel.net,DNS:tsys-siem.knel.net" -``` - -Certs/CSRs land in the intermediate dir's `certs/` + `csr/`. Private keys -stay on tsys-ca (0600); nothing in this directory is ever committed with -key material. diff --git a/ca/artifact-mirror.sh b/ca/artifact-mirror.sh deleted file mode 100644 index b1c7d24..0000000 --- a/ca/artifact-mirror.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -# -# artifact-mirror.sh — pinned artifact mirror on the tsys-ca webroot [#758] -# -# Run ON tsys-ca as root (via tests/remote.sh vm-file): -# VM_IP=tsys-ca VM_USER=root bash tests/remote.sh vm-file ca/artifact-mirror.sh -# -# Publishes under http://tsys-ca.knel.net/ca/dist/: -# dist/wazuh-agent//wazuh-agent__.deb (amd64, arm64, armhf) -# dist/wazuh-agent//SHA256SUMS -# and refreshes the top-level MANIFEST.sha256. -# -# Fleet rule: agents install from THIS mirror (DNS name), never from the -# public internet — deploys stop depending on upstream availability and -# get a stable, pinned, hash-verifiable source. Integrity = SHA256SUMS + -# the root CA fingerprint recorded on Redmine #697. -# -set -euo pipefail - -WWW="${WWW:-/var/www/html/ca}" -WZ_VER="${WZ_VER:-4.14.7-1}" -UPSTREAM="https://packages.wazuh.com/4.x/apt/pool/main/w/wazuh-agent" -DEST="$WWW/dist/wazuh-agent/$WZ_VER" - -mkdir -p "$DEST" -cd "$DEST" - -for arch in amd64 arm64 armhf; do - f="wazuh-agent_${WZ_VER}_${arch}.deb" - if [ -s "$f" ]; then - echo "have $f" - else - echo "fetching $f" - curl -fSs --retry 2 --max-time 240 -o "$f" "$UPSTREAM/$f" - fi -done - -# SHA256SUMS for this directory (regenerated every run — cheap) -sha256sum -- *.deb > SHA256SUMS.tmp && mv SHA256SUMS.tmp SHA256SUMS -cat SHA256SUMS - -# Top-level manifest rolls up the whole published tree -cd "$WWW" -find . -type f ! -name MANIFEST.sha256 -print0 | sort -z \ - | xargs -0 sha256sum > MANIFEST.sha256.tmp && mv MANIFEST.sha256.tmp MANIFEST.sha256 -echo "top-level MANIFEST.sha256 refreshed ($(wc -l < MANIFEST.sha256) files)" diff --git a/ca/ca-init.sh b/ca/ca-init.sh deleted file mode 100644 index 515b53a..0000000 --- a/ca/ca-init.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# -# ca-init.sh — initialize the fleet CA on the CA host [#697] -# Usage: ca-init.sh -# Creates: root CA (RSA-4096, 10y, offline dir) + intermediate (RSA-4096, 5y) -# signing with the root. Keys are generated locally; nothing leaves the host. -# -set -euo pipefail - -ROOT_DIR="${1:?usage: ca-init.sh }" -INT_DIR="${2:?usage: ca-init.sh }" -ROOT_KEY="$ROOT_DIR/root.key" -ROOT_CRT="$ROOT_DIR/root.crt" -INT_KEY="$INT_DIR/intermediate.key" -INT_CSR="$INT_DIR/intermediate.csr" -INT_CRT="$INT_DIR/intermediate.crt" - -if [ -s "$ROOT_CRT" ]; then - echo "root already exists at $ROOT_CRT — refusing to overwrite" >&2 - exit 1 -fi - -mkdir -p "$ROOT_DIR" "$INT_DIR/certs" "$INT_DIR/csr" -chmod 700 "$ROOT_DIR" - -# --- Root CA (offline; signs only the intermediate) --- -openssl genrsa -out "$ROOT_KEY" 4096 2>/dev/null -chmod 400 "$ROOT_KEY" -openssl req -x509 -new -key "$ROOT_KEY" -sha256 -days 3650 \ - -out "$ROOT_CRT" \ - -subj "/C=US/ST=Texas/O=Known Element Enterprises/OU=TechOps/CN=PFV Fleet Root CA" \ - -addext "basicConstraints=critical,CA:TRUE,pathlen:1" \ - -addext "keyUsage=critical,keyCertSign,cRLSign" \ - -addext "subjectKeyIdentifier=hash" -echo "root CA: $ROOT_CRT ($(openssl x509 -in "$ROOT_CRT" -noout -subject))" - -# --- Intermediate CA (signs leaves) --- -openssl genrsa -out "$INT_KEY" 4096 2>/dev/null -chmod 400 "$INT_KEY" -openssl req -new -key "$INT_KEY" -out "$INT_CSR" -sha256 \ - -subj "/C=US/ST=Texas/O=Known Element Enterprises/OU=TechOps/CN=PFV Fleet Intermediate CA" -openssl x509 -req -in "$INT_CSR" -CA "$ROOT_CRT" -CAkey "$ROOT_KEY" \ - -CAcreateserial -days 1825 -sha256 -out "$INT_CRT" \ - -extfile <(printf 'basicConstraints=critical,CA:TRUE,pathlen:0\nkeyUsage=critical,keyCertSign,cRLSign\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid:always') -echo "intermediate: $INT_CRT" - -# --- Chain file for distribution to TLS servers --- -cat "$INT_CRT" "$ROOT_CRT" > "$INT_DIR/ca-chain.crt" -openssl verify -CAfile "$ROOT_CRT" "$INT_CRT" -echo "init complete: intermediate ready at $INT_DIR" diff --git a/ca/issue-cert.sh b/ca/issue-cert.sh deleted file mode 100644 index 32941a8..0000000 --- a/ca/issue-cert.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# issue-cert.sh — issue a leaf certificate from the fleet intermediate [#697] -# Usage: issue-cert.sh "SAN list" e.g. -# issue-cert.sh tsys-wazuh.knel.net "DNS:tsys-wazuh.knel.net,DNS:tsys-siem.knel.net" -# Requires: intermediate initialized at /etc/ssl/tsys-ca (ca-init.sh). -# Output: /.crt (leaf+chain) + /.key (0600) on this host. -# -set -euo pipefail - -CN="${1:?usage: issue-cert.sh \"SAN list\"}" -SAN="${2:?usage: issue-cert.sh \"SAN list\"}" -INT_DIR="${INT_DIR:-/etc/ssl/tsys-ca}" -INT_KEY="$INT_DIR/intermediate.key" -INT_CRT="$INT_DIR/intermediate.crt" -CHAIN="$INT_DIR/ca-chain.crt" - -[ -s "$INT_CRT" ] || { echo "intermediate missing at $INT_CRT — run ca-init.sh first" >&2; exit 1; } -[ -s "$INT_KEY" ] || { echo "intermediate key missing" >&2; exit 1; } - -KEY="$INT_DIR/certs/$CN.key" -CSR="$INT_DIR/csr/$CN.csr" -CRT="$INT_DIR/certs/$CN.crt" -[ -e "$CRT" ] && { echo "cert already exists: $CRT (revoke/rename first)" >&2; exit 1; } - -openssl genrsa -out "$KEY" 2048 2>/dev/null -chmod 600 "$KEY" -openssl req -new -key "$KEY" -out "$CSR" -sha256 \ - -subj "/C=US/ST=Texas/O=Known Element Enterprises/OU=TechOps/CN=$CN" -openssl x509 -req -in "$CSR" -CA "$INT_CRT" -CAkey "$INT_KEY" \ - -CAcreateserial -days 825 -sha256 -out "$CRT" \ - -extfile <(printf 'basicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth,clientAuth\nsubjectAltName=%s\nauthorityKeyIdentifier=keyid,issuer\n' "$SAN") - -cat "$CRT" "$CHAIN" > "$INT_DIR/certs/$CN.fullchain" -openssl verify -CAfile "$CHAIN" "$CRT" -echo "issued: $CRT (+ .key, .csr, .fullchain)" diff --git a/ca/selftest.sh b/ca/selftest.sh deleted file mode 100644 index 5ff9ccc..0000000 --- a/ca/selftest.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# selftest.sh — throwaway end-to-end CA loop in /tmp [#697] -# TDD gate for the CA tooling: init -> issue -> verify chain -> negative check. -# -set -euo pipefail -T="$(mktemp -d)" -trap 'rm -rf "$T"' EXIT - -bash "$(dirname "$0")/ca-init.sh" "$T/root" "$T/int" > /dev/null -[ -s "$T/root/root.key" ] && [ -s "$T/int/intermediate.crt" ] || { echo "FAIL: init" ; exit 1; } - -INT_DIR="$T/int" bash "$(dirname "$0")/issue-cert.sh" test.knel.net "DNS:test.knel.net,IP:10.0.0.1" > /dev/null -openssl verify -CAfile "$T/root/root.crt" "$T/int/intermediate.crt" > /dev/null -openssl x509 -in "$T/int/certs/test.knel.net.crt" -noout -ext subjectAltName | grep -q "test.knel.net" -openssl x509 -in "$T/int/certs/test.knel.net.fullchain" -noout | head -1 > /dev/null -echo "SELFTEST PASS: root->intermediate->leaf chain verified with SANs" diff --git a/cmdb/seed/from-inventory.sh b/cmdb/seed/from-inventory.sh deleted file mode 100644 index 28a21a7..0000000 --- a/cmdb/seed/from-inventory.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/bash -# -# from-inventory.sh — convert the Discourse #307 system inventory (raw -# markdown of its wiki post) into the CMDB seed CSV [#705] -# -# Input: raw markdown of https://community.turnsys.com/t/307 (post 385), -# fetched e.g. via the discourse-cli raw-API escape hatch -# Output: cmdb/seed/systems.csv (normalized CI rows; v0 schema) -# -# Re-run whenever #307 changes; the CSV is the GLPI import candidate, the -# markdown topic stays the human-readable inventory. -# -set -euo pipefail - -if [ $# -ne 1 ] || [ ! -r "$1" ]; then - echo "usage: $0 systems.csv" >&2 - exit 2 -fi - -echo 'category,ci_name,host_node,vmid,specs,ts_ip,extra_ip,tuned,access,extra,status,source_section' - -awk -F'|' ' - function trim(s) { gsub(/^[ \t]+|[ \t]+$/, "", s); return s } - function strip(s) { gsub(/"/, "", s); return trim(s) } - function csv(s) { gsub(/"/, "", s); return "\"" trim(s)"\"" } - # canon(s) — apply the section-7 VM-name -> Tailscale/DNS-name map so - # ci_name always uses the canonical fleet name [#705] - function canon(s) { s = strip(s); return (s in map) ? map[s] : s } - /^## / { - sec = substr($0, 4) - sub(/\(.*/, "", sec) - gsub(/^[ \t]+|[ \t]+$/, "", sec) - next - } - /^\|/ { - # pass 1 (same file read twice): capture only the section-7 rename map - if (FNR == NR) { - if (sec ~ /^7\./) { - for (i = 1; i <= NF; i++) f[i] = trim($i) - if (f[2] == "" || f[2] ~ /^-+$/ || f[2] == "VM Name") next - key = f[2]; sub(/[ (].*/, "", key) - map[key] = trim(f[3]) - } - next - } - if (sec ~ /^7\./) next - if (sec !~ /^[1-6]\./) next - for (i = 1; i <= NF; i++) f[i] = trim($i) - if (f[2] == "" || f[2] ~ /^-+$/) next - if (f[2] == "Host" || f[2] == "VMID" || f[2] == "Name" || f[2] == "DNS Name") next - status = (index($0, "RETIRED") > 0) ? "retired" : "active" - if (sec ~ /^1\./) - printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", - "hypervisor", csv(canon(f[2])), "", "", - csv(f[3] "; CPU " f[4] "; RAM " f[5]), csv(f[6]), csv(f[8]), - csv(f[9]), csv(f[10]), csv("mgmt " f[7]), status, csv("307 s1") - else if (sec ~ /^2\./) - printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", - "vm-prod", csv(canon(f[3])), csv(f[4]), csv(f[2]), - csv("CPU " f[5] "; RAM " f[6] "; TS? " f[7]), csv(f[8]), "", - csv(f[10]), csv(f[9]), "", status, csv("307 s2") - else if (sec ~ /^3\./) - printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", - "vm-sectestbed", csv(canon(f[3])), "pfv-tsys5", csv(f[2]), "", csv(f[5]), - "", csv(f[7]), csv(f[6]), "", status, csv("307 s3") - else if (sec ~ /^4\./) - printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", - "vm-preprod", csv(canon(f[3])), "pfv-tsys5", csv(f[2]), "", csv(f[5]), - "", csv(f[7]), csv(f[6]), "", status, csv("307 s4") - else if (sec ~ /^5\./) - printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", - "physical-sbc", csv(canon(f[2])), "", "", "", csv(f[3]), "", - "", csv(f[5]), csv("dns " f[4]), status, csv("307 s5") - else if (sec ~ /^6\./) - printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", - "stale-dns-record", csv(f[2]), "", "", "", "", "", - "", "", "", "retired", csv("307 s6: " f[4]) - } -' "$1" "$1" diff --git a/cmdb/seed/software-catalog.sh b/cmdb/seed/software-catalog.sh deleted file mode 100644 index 1fcf029..0000000 --- a/cmdb/seed/software-catalog.sh +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/bash -# -# software-catalog.sh — seed the GLPI software catalog [#705] -# -# Usage: software-catalog.sh [--dry-run] -# Needs: ~/.creds/glpi.env (GLPI_URL, GLPI_APP_TOKEN, GLPI_USER_TOKEN) -# ~/.creds/wazuh.env optional (WAZUH_API_PASS) — for live agent installs -# -# Creates Software assets + SoftwareVersions and links installations to -# Computer CIs. Idempotent at all three levels (software, version, install). -# Versions are recorded ONLY where verified; unknowns say so — GLPI Agent -# auto-inventory (proposed) is the durable fix for version drift. -# -set -euo pipefail - -DRY=0 -[ "${1:-}" = "--dry-run" ] && DRY=1 - -CREDS="${HOME}/.creds/glpi.env" -# shellcheck disable=SC1090 -. "$CREDS" -: "${GLPI_URL:?}" "${GLPI_APP_TOKEN:?}" "${GLPI_USER_TOKEN:?}" -API="$GLPI_URL/apirest.php" - -api() { - local method="$1" path="$2" body="${3:-}" - if [ -n "$body" ]; then - curl -sS --max-time 30 -X "$method" -H "App-Token: $GLPI_APP_TOKEN" \ - -H "Session-Token: $SESSION" -H "Content-Type: application/json" \ - -d "$body" "$API/$path" - else - curl -sS --max-time 30 -X "$method" -H "App-Token: $GLPI_APP_TOKEN" \ - -H "Session-Token: $SESSION" "$API/$path" - fi -} - -SESSION=$(curl -sS --max-time 20 -H "Content-Type: application/json" \ - -H "App-Token: $GLPI_APP_TOKEN" \ - -H "Authorization: user_token $GLPI_USER_TOKEN" \ - "$API/initSession" | jq -re '.session_token') -echo "— session ok" - -# software_id — existing id or empty -sw_id() { - api GET "Software?searchText%5Bname%5D=$(printf %s "$1" | sed 's/ /%20/g')" \ - | jq -r --arg n "$1" '[.[] | select(.name==$n)][0].id // empty' -} - -# version_id — GLPI ignores softwares_id as a search param, -# so pull the full list and filter client-side (parent AND name) -ver_id() { - api GET "SoftwareVersion?range=0-999" \ - | jq -r --arg s "$1" --arg v "$2" \ - '[.[] | select((.softwares_id|tostring)==$s and .name==$v)][0].id // empty' -} - -# computer_id -pc_id() { - api GET "Computer?searchText%5Bname%5D=$(printf %s "$1" | sed 's/ /%20/g')" \ - | jq -r --arg n "$1" '[.[] | select(.name==$n)][0].id // empty' -} - -# install_exists -install_exists() { - api GET "Item_SoftwareVersion?range=0-4999" \ - | jq -e --arg v "$1" --arg p "$2" \ - '[.[] | select(.softwareversions_id==($v|tonumber) and .items_id==($p|tonumber) and .itemtype=="Computer")] | length > 0' \ - >/dev/null 2>&1 -} - -# ensure — '-' = catalog only -ensure() { - local sw="$1" ver="$2" targets="$3" sid vid cid - sid=$(sw_id "$sw") - if [ -z "$sid" ]; then - if [ "$DRY" = 1 ]; then echo " DRY: software '$sw'"; sid=0; else - sid=$(api POST Software "{\"input\":{\"name\":\"$sw\",\"manufacturers_id\":0,\"comment\":\"seeded by software-catalog.sh (#705)\"}}" \ - | jq -r '.id // empty') - echo " + software '$sw' (id=$sid)" - fi - else - echo " = software '$sw' (id=$sid)" - fi - [ "$sid" = 0 ] && [ "$DRY" = 1 ] && return 0 - - vid=$(ver_id "$sid" "$ver") - if [ -z "$vid" ]; then - if [ "$DRY" = 1 ]; then echo " DRY: version '$ver'"; else - vid=$(api POST SoftwareVersion "{\"input\":{\"softwares_id\":\"$sid\",\"name\":\"$ver\",\"state\":0}}" \ - | jq -r '.id // empty') - echo " + version '$ver' (id=$vid)" - fi - else - echo " = version '$ver' (id=$vid)" - fi - [ -z "$vid" ] && return 0 - - [ "$targets" = "-" ] && return 0 - local IFS=',' - for t in $targets; do - cid=$(pc_id "$t") - if [ -z "$cid" ]; then echo " ! no CI named '$t' (skipped)"; continue; fi - if install_exists "$vid" "$cid"; then echo " = installed on $t"; continue; fi - if [ "$DRY" = 1 ]; then echo " DRY: install on $t"; else - api POST Item_SoftwareVersion \ - "{\"input\":{\"itemtype\":\"Computer\",\"items_id\":\"$cid\",\"softwareversions_id\":\"$vid\"}}" \ - | jq -re 'if type=="array" or .id then empty else . end' >/dev/null 2>&1 \ - && echo " ! install POST failed on $t" || echo " + installed on $t" - fi - done -} - -echo "— catalog rows" -# name | version | targets (comma list, '-' = catalog only) -while IFS='|' read -r sw ver targets; do - [ -z "$sw" ] && continue - ensure "$(echo "$sw" | xargs)" "$(echo "$ver" | xargs)" "$(echo "$targets" | xargs)" -done < /tmp/wz-agents.txt - while IFS= read -r a; do - [ "$a" = "000" ] && continue - cid=$(pc_id "$a") - if [ -z "$cid" ]; then echo " ! agent '$a' has no CI (skipped)"; continue; fi - if install_exists "$vid" "$cid"; then echo " = $a"; continue; fi - if [ "$DRY" = 1 ]; then echo " DRY: install on $a"; else - api POST Item_SoftwareVersion \ - "{\"input\":{\"itemtype\":\"Computer\",\"items_id\":\"$cid\",\"softwareversions_id\":\"$vid\"}}" >/dev/null \ - && echo " + $a" - fi - done < /tmp/wz-agents.txt -fi - -echo "— done" diff --git a/cmdb/seed/systems.csv b/cmdb/seed/systems.csv deleted file mode 100644 index f54df7d..0000000 --- a/cmdb/seed/systems.csv +++ /dev/null @@ -1,76 +0,0 @@ -category,ci_name,host_node,vmid,specs,ts_ip,extra_ip,tuned,access,extra,status,source_section -hypervisor,"pfv-tsys1",,,"OptiPlex 9020; CPU 8c; RAM 31Gi","100.121.189.98","10.100.100.1","virtual-host","root","mgmt 192.168.3.11",active,"307 s1" -hypervisor,"pfv-tsys3",,,"Precision 7510; CPU 8c; RAM 31Gi","100.66.186.10","10.100.100.3","virtual-host","root","mgmt 192.168.2.5",active,"307 s1" -hypervisor,"pfv-tsys4",,,"Precision T1700; CPU 8c; RAM 15Gi","100.70.77.93","10.100.100.4","virtual-host","root","mgmt 192.168.3.251",active,"307 s1" -hypervisor,"pfv-tsys5",,,"Precision T7500; CPU 8c; RAM 94Gi","100.87.135.12","10.100.100.5","virtual-host","root","mgmt 192.168.3.250",active,"307 s1" -hypervisor,"pfv-tsys6",,,"PowerEdge R610; CPU 16c; RAM 125Gi","100.73.35.111","(bond)","virtual-host","root","mgmt 192.168.3.169",active,"307 s1" -hypervisor,"pfv-tsys7",,,"PowerEdge R620; CPU 24c; RAM 188Gi","100.110.146.27","10.100.100.7","virtual-host","root","mgmt 192.168.0.250",active,"307 s1" -hypervisor,"pfv-tsys9",,,"OptiPlex 7080; CPU 12c; RAM 23Gi","100.101.158.76","10.100.100.9","virtual-host","root","mgmt 192.168.3.58",active,"307 s1" -vm-prod,"pfv-bms","tsys1","100","CPU 4c; RAM 6GB; TS? Yes","100.67.108.125",,"-","SSH 22222 (LAN: pfv-bms-lan.knel.net)",,active,"307 s2" -vm-prod,"tsys-ca","tsys1","101","CPU 2c; RAM 4GB; TS? No (DNS: 100.102.96.24)","-",,"-","NO",,active,"307 s2" -vm-prod,"pfv-k8s-cnode1","tsys1","102","CPU 2c; RAM 4GB; TS? Yes","100.125.134.53",,"network-latency","localuser",,active,"307 s2" -vm-prod,"pfv-netinfra-01","tsys1","103","CPU 2c; RAM 4GB; TS? Yes","100.70.181.72",,"network-latency","localuser",,active,"307 s2" -vm-prod,"tsys-librenms","tsys1","104","CPU 2c; RAM 4GB; TS? No (DNS: 100.86.204.77)","-",,"-","NO",,active,"307 s2" -vm-prod,"tsys-proxmox-datacenter","tsys1","105","CPU 2c; RAM 2GB; TS? No (DNS: 100.125.183.68)","-",,"-","NO",,active,"307 s2" -vm-prod,"tsys-ucs-01","tsys1","108","CPU 2c; RAM 6GB; TS? No (DNS: 100.109.13.110)","-",,"-","NO",,active,"307 s2" -vm-prod,"pfv-k8s-wnode-tsys3","tsys3","313","CPU 8c; RAM 28GB; TS? Yes","100.126.9.112",,"-","localuser",,active,"307 s2" -vm-prod,"pfv-k8s-wnode-tsys5","tsys5","500","CPU 2c; RAM 12GB; TS? Yes","100.122.252.116",,"-","localuser",,retired,"307 s2" -vm-prod,"devbox-cloudron","tsys5","501","CPU 2c; RAM 4GB; TS? Yes","100.119.72.25",,"-","NO",,active,"307 s2" -vm-prod,"hfnoc-uisp-preprod","tsys5","515","CPU 2c; RAM 2GB; TS? No","-",,"-","NO",,active,"307 s2" -vm-prod,"ultix-streaming","tsys5","5111","CPU 4c; RAM 25GB; TS? Yes","100.101.187.119",,"-","NO (do-not-reboot)",,active,"307 s2" -vm-prod,"ultix-offstage","tsys5","5112","CPU 4c; RAM 22GB; TS? Yes","100.70.119.59",,"-","localuser (do-not-reboot)",,retired,"307 s2" -vm-prod,"tsys-awx","tsys6","600","CPU 2c; RAM 12GB; TS? No (DNS: 100.91.39.53)","-",,"-","NO",,active,"307 s2" -vm-prod,"pfv-k8s-wnode-tsys6","tsys6","601","CPU 2c; RAM 98GB; TS? Yes","100.83.49.75",,"-","localuser",,active,"307 s2" -vm-prod,"pfv-rr-middleware-02","tsys6","602","CPU 2c; RAM 6GB; TS? Yes","100.93.47.4",,"-","NO",,active,"307 s2" -vm-prod,"pfv-k8s-cnode3","tsys6","603","CPU 4c; RAM 4GB; TS? Yes","100.106.222.18",,"network-latency","localuser",,active,"307 s2" -vm-prod,"tsys-proxmox-mailgw-01","tsys6","604","CPU 2c; RAM 4GB; TS? No (DNS: 100.68.129.71)","-",,"-","NO",,active,"307 s2" -vm-prod,"pfv-k8s-wnode-tsys7","tsys7","701","CPU 2c; RAM 98GB; TS? Yes","100.119.240.11",,"-","localuser",,active,"307 s2" -vm-prod,"hfnoc-uisp","tsys7","702","CPU 2c; RAM 8GB; TS? Yes","100.94.188.89",,"-","NO",,active,"307 s2" -vm-prod,"pfv-rr-middleware-01","tsys7","703","CPU 2c; RAM 6GB; TS? Yes","100.106.54.59",,"-","NO",,active,"307 s2" -vm-prod,"pfv-k8s-cnode2","tsys7","705","CPU 4c; RAM 4GB; TS? Yes","100.109.34.72",,"network-latency","localuser",,active,"307 s2" -vm-prod,"kali-rd","tsys7","706","CPU 2c; RAM 6GB; TS? Yes","100.105.136.23",,"-","NO",,active,"307 s2" -vm-prod,"tsys-siem","tsys7","707","CPU 2c; RAM 8GB; TS? No (DNS: 100.72.35.113)","-",,"-","NO",,active,"307 s2" -vm-prod,"kali-tsys","tsys7","708","CPU 4c; RAM 6GB; TS? Yes","100.82.30.115",,"-","NO",,active,"307 s2" -vm-prod,"tsys-voip","tsys7","709","CPU 4c; RAM 4GB; TS? No (DNS: 100.83.126.67)","-",,"-","NO",,active,"307 s2" -vm-prod,"tsys-umbrel","tsys7","710","CPU 2c; RAM 26GB; TS? No (DNS: 100.66.182.14)","-",,"-","NO",,active,"307 s2" -vm-prod,"tsys-proxmox-mailgw-02","tsys7","711","CPU 2c; RAM 4GB; TS? No (DNS: 100.126.29.88)","-",,"-","NO",,active,"307 s2" -vm-prod,"tsys-ucs-02","tsys9","902","CPU 2c; RAM 4GB; TS? No (DNS: 100.68.10.17)","-",,"-","NO",,active,"307 s2" -vm-prod,"pfv-netinfra-02","tsys9","904","CPU 2c; RAM 4GB; TS? Yes","100.71.171.20",,"network-latency","localuser",,active,"307 s2" -vm-prod,"pfv-k8s-wnode-tsys9","tsys9","905","CPU 4c; RAM 14GB; TS? Yes","100.95.201.66",,"-","localuser",,active,"307 s2" -vm-sectestbed,"sectestbed-sandbox",pfv-tsys5,"5000",,"100.64.20.60",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-siem",pfv-tsys5,"5101",,"100.108.121.18",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-proxmox-pve",pfv-tsys5,"5102",,"100.80.72.71",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-proxmox-datacenter",pfv-tsys5,"5103",,"100.94.1.34",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-proxmox-pbs",pfv-tsys5,"5104",,"100.127.238.29",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-awx",pfv-tsys5,"5105",,"100.64.56.24",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-k8s-cnode",pfv-tsys5,"5106",,"100.68.155.111",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-k8s-wnode",pfv-tsys5,"5107",,"100.107.110.89",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-librenms",pfv-tsys5,"5108",,"100.92.94.87",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-netinfra",pfv-tsys5,"5109",,"100.100.220.117",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-cloudron",pfv-tsys5,"51011",,"100.97.140.105",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-hfnoc-uisp",pfv-tsys5,"51012",,"100.101.168.80",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-rancherplatform",pfv-tsys5,"51013",,"100.88.171.10",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-proxmox-mailgw",pfv-tsys5,"51014",,"100.117.24.21",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-ca",pfv-tsys5,"51015",,"100.113.245.124",,"-","NO",,active,"307 s3" -vm-sectestbed,"sectestbed-voip",pfv-tsys5,"51016",,"100.86.176.105",,"-","NO",,active,"307 s3" -vm-preprod,"preprod-awx",pfv-tsys5,"53100",,"100.77.216.36",,"-","NO",,active,"307 s4" -vm-preprod,"preprod-siem",pfv-tsys5,"53101",,"100.98.162.14",,"-","NO",,active,"307 s4" -vm-preprod,"preprod-rancherplatform",pfv-tsys5,"53102",,"100.126.231.121",,"-","NO",,active,"307 s4" -vm-preprod,"preprod-proxmox-mailgw",pfv-tsys5,"53103",,"100.114.9.49",,"-","NO",,active,"307 s4" -vm-preprod,"preprod-ca",pfv-tsys5,"53104",,"100.94.119.5",,"-","NO",,active,"307 s4" -vm-preprod,"preprod-proxmox-datacenter",pfv-tsys5,"53105",,"100.101.250.10",,"-","NO",,active,"307 s4" -vm-preprod,"preprod-librenms",pfv-tsys5,"53106",,"100.79.52.34",,"-","NO",,active,"307 s4" -vm-preprod,"preprod-voip",pfv-tsys5,"53107",,"100.109.99.109",,"-","NO",,active,"307 s4" -vm-preprod,"preprod-cloudron",pfv-tsys5,"53108",,"100.95.69.89",,"-","NO",,active,"307 s4" -physical-sbc,"pfvsvrpi",,,,"100.91.151.113",,,"Raspberry Pi","dns pfvsvrpi.knel.net",active,"307 s5" -physical-sbc,"pfv-jetson-nano-1",,,,"100.82.230.119",,,"NVIDIA Jetson","dns pfv-jetson-nano-1.knel.net",active,"307 s5" -physical-sbc,"subopi-dev-3",,,,"100.64.231.65",,,"SBC (Pi?)","dns subopi-dev-3.knel.net",active,"307 s5" -physical-sbc,"subopi-dev-4",,,,"-",,,"SBC","dns subopi-dev-4.knel.net (100.65.224.85)",active,"307 s5" -physical-sbc,"subopi3",,,,"-",,,"SBC","dns subopi3.knel.net (100.93.17.77)",active,"307 s5" -physical-sbc,"stlpc-artroom",,,,"100.120.77.113",,,"Linux PC","dns stlpc-artroom.knel.net",active,"307 s5" -physical-sbc,"stlpc-garage",,,,"100.72.192.22",,,"Linux PC","dns stlpc-garage.knel.net",active,"307 s5" -physical-sbc,"stlp-3dscanner",,,,"100.125.14.37",,,"OFFLINE 184d","dns stlp-3dscanner.knel.net",active,"307 s5" -physical-sbc,"tailscale-router",,,,"-",,,"**RETIRED 2026-09-02** — subnet-router role replaced by pfv-netinfra-01/02; host removed from tailnet; no DNS records remain","dns ~~tailscale-router.knel.net (100.103.48.57)~~",retired,"307 s5" -physical-sbc,"netbird",,,,"100.123.45.23",,,"NetBird VPN","dns -",active,"307 s5" -physical-sbc,"pfv-proxmox-backup-server",,,,"100.114.81.107",,,"PBS","dns pfv-proxmox-backup-server.knel.net",active,"307 s5" -physical-sbc,"stlpc-bizoffice",,,,"100.96.130.53",,,"WINDOWS (not Linux)","dns stlpc-bizoffice.knel.net",active,"307 s5" diff --git a/cmdb/seed/to-glpi.sh b/cmdb/seed/to-glpi.sh deleted file mode 100644 index e6fd428..0000000 --- a/cmdb/seed/to-glpi.sh +++ /dev/null @@ -1,104 +0,0 @@ -#!/bin/bash -# -# to-glpi.sh — seed GLPI from the CMDB CSV + create the scoped agent user [#705] -# -# Prereqs: ~/.creds/glpi.env with GLPI_URL, GLPI_APP_TOKEN, and a VALID -# GLPI_USER_TOKEN (glpi admin). Run cmdb/seed/from-inventory.sh first -# to produce systems.csv. -# -# Usage: -# to-glpi.sh [--dry-run] [systems.csv] -# -# What it does: -# 1. initSession as the admin user token. -# 2. Creates local user 'cmdb' (Read-Only profile, random password + -# random api_token) — the scoped agent identity per Charles's ruling. -# Writes ~/.creds/glpi-agent.env (0600). Skipped if the user exists. -# 3. Imports systems.csv rows as GLPI Computers (batch; skips names that -# already exist). comment carries category/specs/ts_ip provenance. -# -set -euo pipefail - -DRY=0 -[ "${1:-}" = "--dry-run" ] && { DRY=1; shift; } -CSV="${1:-$(dirname "$0")/systems.csv}" -[ -r "$CSV" ] || { echo "no CSV at $CSV" >&2; exit 2; } - -CREDS="${HOME}/.creds/glpi.env" -# shellcheck disable=SC1090 -. "$CREDS" -: "${GLPI_URL:?}" "${GLPI_APP_TOKEN:?}" "${GLPI_USER_TOKEN:?}" -API="$GLPI_URL/apirest.php" - -hdr() { printf 'Content-Type: application/json\nApp-Token: %s\nSession-Token: %s\n' "$GLPI_APP_TOKEN" "$SESSION"; } - -echo "— initSession" -SESSION=$(curl -sS --max-time 20 -H "Content-Type: application/json" \ - -H "App-Token: $GLPI_APP_TOKEN" \ - -H "Authorization: user_token $GLPI_USER_TOKEN" \ - "$API/initSession" | jq -re '.session_token') -echo " session ok (${#SESSION} chars)" - -# --- 2. scoped agent user ------------------------------------------------- -if curl -sS -H "$(hdr)" "$API/User?searchText%5Bname%5D=cmdb" | jq -e 'if type=="object" then (.totalcount > 0) else (length > 0) end' >/dev/null; then - echo "— user 'cmdb' already exists (skipping create)" -else - AGENT_PASS=$(head -c 24 /dev/urandom | base64 | tr -d '/+=') - AGENT_TOKEN=$(head -c 24 /dev/urandom | od -An -tx1 | tr -d ' \n') - if [ "$DRY" = "1" ]; then - echo "— DRY: would create user cmdb" - else - UID_JSON=$(curl -sS -X POST -H "$(hdr)" -d '{"input":{"name":"cmdb","realname":"CMDB agent (core-IT)","password":"'"$AGENT_PASS"'","api_token":"'"$AGENT_TOKEN"'"}}' "$API/User") - NEWUID=$(echo "$UID_JSON" | jq -r '.id // .users_id // empty') - echo " created users_id=$NEWUID" - PROF_ID=$(curl -sS -H "$(hdr)" "$API/Profile?range=0-50" | jq -r '.[] | select(.name=="Read-Only") | .id' | head -1) - [ -n "$PROF_ID" ] && curl -sS -X POST -H "$(hdr)" \ - -d '{"input":{"users_id":"'"$NEWUID"'","profiles_id":"'"$PROF_ID"'","entities_id":0,"is_recursive":1}}' \ - "$API/Profile_User" > /dev/null && echo " profile Read-Only ($PROF_ID) @ root entity" - umask 077 - printf 'GLPI_URL=%s\nGLPI_APP_TOKEN=%s\nGLPI_USER_TOKEN=%s\n' \ - "$GLPI_URL" "$GLPI_APP_TOKEN" "$AGENT_TOKEN" > "${HOME}/.creds/glpi-agent.env" - echo " agent creds written to ~/.creds/glpi-agent.env (0600)" - fi -fi - -# --- 3. seed import ------------------------------------------------------- -echo "— existing Computers" -EXIST=$(curl -sS -H "$(hdr)" "$API/Computer?range=0-999&is_deleted=0" | jq -r '[.[].name] | join("\n")') - -# CSV -> JSON objects (pure jq; header names become keys) -jq -Rn ' - def strip: gsub("^\"";"") | gsub("\"$";""); - (input | split(",") | map(strip)) as $keys | - [ inputs | split(",") | map(strip) as $v | - reduce range(0; ($keys | length)) as $i - ({}; . + {($keys[$i]): ($v[$i] // "")}) ] -' "$CSV" > /tmp/glpi-rows.json - -# GLPI Computer input objects; skip names already present -jq -c --arg existing "$EXIST" ' - [ .[] | select(.ci_name != "") | select(.ci_name as $n | ($existing | split("\n")) | index($n) | not)] -' /tmp/glpi-rows.json > /tmp/glpi-batch.json - -# Map to GLPI Computer fields -jq -c '[ .[] | {name: .ci_name, - comment: ((.category // "") + " | " + (.specs // "") + " | ts=" + (.ts_ip // "") + - " | " + (.extra // "") + " | src=" + (.source_section // "") + - " | status=" + (.status // ""))} ]' /tmp/glpi-batch.json > /tmp/glpi-input.json -mv /tmp/glpi-input.json /tmp/glpi-batch.json - -TOTAL=$(jq 'length' /tmp/glpi-batch.json) -skipped=$(( $(wc -l < "$CSV") - 1 - TOTAL )) -echo "— import: $TOTAL to create, $skipped already present" -if [ "$DRY" = "1" ]; then echo "— DRY: no changes made"; exit 0; fi - -# Batch-create in chunks of 25 (API limits) -SPLIT=25; i=0 -while [ "$i" -lt "$TOTAL" ]; do - jq ".[$i:$((i+SPLIT))]" /tmp/glpi-batch.json > /tmp/glpi-chunk.json - curl -sS -X POST -H "$(hdr)" \ - -d "$(jq -c '{input: .}' /tmp/glpi-chunk.json)" "$API/Computer" \ - | jq -r 'if type=="array" then " +\(length) created" else " ERR: \(tostring)" end' - i=$((i+SPLIT)) -done -echo "done — verify count via GET /Computer?range=0-200" diff --git a/dcinfra/console/README.md b/dcinfra/console/README.md deleted file mode 100644 index 1f4c39a..0000000 --- a/dcinfra/console/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# dcinfra/console/README.md - -> **Documentation moved to Discourse — the canonical source of truth.** -> -> **Serial console management (ser2net + conman)** -> -> **Read it here:** https://community.turnsys.com/t/301 -> -> *Migrated 2026-08-06. This file is kept as a pointer for git-browsing context. -> Do not update content here — edit the Discourse wiki topic instead.* diff --git a/dcinfra/console/discover.sh b/dcinfra/console/discover.sh deleted file mode 100644 index 34138b9..0000000 --- a/dcinfra/console/discover.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/bash -# shellcheck disable=SC2010,SC2012 # diagnostic script; ls|grep/ls -la on sysfs & log dirs is intentional for human-readable output -# -# console/discover.sh — READ-ONLY discovery of console setup on pfv-tsys4 -# -# Usage: PROX_HOST=pfv-tsys4 bash tests/remote.sh prox-file console/discover.sh -# -# This script is strictly read-only. No writes to the system. -# -set -uo pipefail - -echo "============================================" -echo " Console Setup Discovery" -echo " Host: $(hostname)" -echo " Date: $(date)" -echo " READ-ONLY" -echo "============================================" - -echo "" -echo "=== 1. USB devices ===" -lsusb 2>/dev/null || echo "(lsusb not available)" - -echo "" -echo "=== 2. All ttyUSB* devices (with major/minor) ===" -ls -la /dev/ttyUSB* 2>/dev/null || echo "(no /dev/ttyUSB* devices)" - -echo "" -echo "=== 3. USB-serial driver bindings ===" -echo "-- pl2303 --" -ls -la /sys/bus/usb-serial/drivers/pl2303/ 2>/dev/null | grep -v '^total\|^d\|module\|new_id\|uevent' || echo "(none)" -echo "-- cp210x --" -ls -la /sys/bus/usb-serial/drivers/cp210x/ 2>/dev/null | grep -v '^total\|^d\|module\|new_id\|uevent' || echo "(none)" -echo "-- ftdi_sio --" -ls -la /sys/bus/usb-serial/drivers/ftdi_sio/ 2>/dev/null | grep -v '^total\|^d\|module\|new_id\|uevent' || echo "(none)" -echo "-- ch341 --" -ls -la /sys/bus/usb-serial/drivers/ch341/ 2>/dev/null | grep -v '^total\|^d\|module\|new_id\|uevent' || echo "(none)" - -echo "" -echo "=== 4. USB serial adapter details (vendor/model/serial per port) ===" -for tty in /dev/ttyUSB*; do - [ -e "$tty" ] || continue - echo "--- $tty ---" - udevadm info -q all -n "$tty" 2>/dev/null | grep -E 'ID_VENDOR_ID|ID_MODEL_ID|ID_SERIAL|ID_USB_DRIVER|ID_PATH=' | sed 's/^/ /' -done - -echo "" -echo "=== 5. Existing /root/conmap ===" -if [ -f /root/conmap ]; then - cat /root/conmap -else - echo "(no /root/conmap)" -fi -ls -la /root/conmap* 2>/dev/null - -echo "" -echo "=== 6. Screen sessions (running) ===" -screen -ls 2>&1 || echo "(screen not running or not installed)" - -echo "" -echo "=== 7. Existing screen wrappers/scripts in /root ===" -ls -la /root/ 2>/dev/null | grep -iE 'screen|con|console|tty|usb' || echo "(no obvious console scripts in /root)" - -echo "" -echo "=== 8. ser2net ===" -which ser2net 2>/dev/null || echo "(ser2net not installed)" -dpkg -l ser2net 2>/dev/null | tail -2 || echo "(ser2net not in dpkg)" -cat /etc/ser2net/ser2net.yaml 2>/dev/null || cat /etc/ser2net.conf 2>/dev/null || cat /etc/ser2net/ser2net.conf 2>/dev/null || echo "(no ser2net config)" -systemctl is-active ser2net 2>/dev/null || echo "(ser2net service not found)" - -echo "" -echo "=== 9. conman ===" -which conman 2>/dev/null || echo "(conman not installed)" -which conmand 2>/dev/null || echo "(conmand not installed)" -dpkg -l conman 2>/dev/null | tail -2 || echo "(conman not in dpkg)" -echo "--- /etc/conman.conf (console lines only) ---" -grep -nE 'CONSOLE|SERVER|LOG|SERIAL|DEV|BAUD|^[^#].*name=' /etc/conman.conf 2>/dev/null | head -60 || echo "(no conman.conf or no console entries)" -echo "--- conmand service ---" -systemctl is-active conmand 2>/dev/null || echo "(conmand not running)" -systemctl is-enabled conmand 2>/dev/null || echo "(conmand not enabled)" - -echo "" -echo "=== 10. Existing console logs ===" -ls -la /var/log/conman/ 2>/dev/null | head -20 || echo "(no /var/log/conman)" -ls -la /var/consoles/ 2>/dev/null | head -20 || echo "(no /var/consoles)" - -echo "" -echo "=== 11. udev rules for ttyUSB ===" -grep -r ttyUSB /etc/udev/rules.d/ 2>/dev/null || echo "(no udev rules for ttyUSB)" -grep -r 'console' /etc/udev/rules.d/ 2>/dev/null | head -10 || true - -echo "" -echo "=== 12. expect availability ===" -command -v expect && expect -v 2>&1 || echo "expect: NOT installed" -command -v socat && socat -V 2>&1 | head -1 || echo "socat: NOT installed" - -echo "" -echo "=== 13. Ports in use (2001-2099, 7000-7999, 7820-7899) ===" -ss -tlnp 2>/dev/null | grep -E ':200[0-9]|:700[0-9]|:782[0-9]|:789[0-9]' || echo "(no relevant ports listening)" - -echo "" -echo "============================================" -echo " Discovery complete (read-only)." -echo "============================================" diff --git a/dcinfra/console/generate-config.sh b/dcinfra/console/generate-config.sh deleted file mode 100644 index c3b0ed4..0000000 --- a/dcinfra/console/generate-config.sh +++ /dev/null @@ -1,254 +0,0 @@ -#!/usr/bin/bash -# -# console/generate-config.sh — generate udev rules + ser2net.yaml + conman.conf -# -# Reads console/mapping.txt (the source of truth) and generates all three -# config files. This is the fix for the USB enumeration shift problem: -# -# 1. udev rules pin each adapter by its STABLE ID_PATH (physical USB port) -# to a named symlink like /dev/consoles/pfv-r5-core-01 -# 2. ser2net opens those stable symlinks and exposes them on TCP ports -# (2001, 2002, ...) bound to the Tailscale IP -# 3. conman connects to those TCP ports for logging + multiplexing -# -# Run this script ON the target host. It writes to: -# /etc/udev/rules.d/99-console-ports.rules -# /etc/ser2net.yaml -# /etc/conman/console-consoles.conf (included by /etc/conman.conf) -# -# Usage: -# PROX_HOST=pfv-tsys4 bash tests/remote.sh prox-file console/generate-config.sh -# -# Environment overrides: -# MAPPING_FILE — path to mapping.txt (default: auto-detect next to this script) -# TS_IP — Tailscale IP to bind ser2net on (default: auto-detect) -# CONMAN_LOGDIR — conman log directory (default: /var/log/conman) -# -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -MAPPING_FILE="${MAPPING_FILE:-$SCRIPT_DIR/mapping.txt}" -CONMAN_LOGDIR="${CONMAN_LOGDIR:-/var/log/conman}" - -UDEV_RULES="/etc/udev/rules.d/99-console-ports.rules" -SER2NET_CONF="/etc/ser2net.yaml" -CONMAN_CONF="/etc/conman.conf" - -echo "============================================" -echo " Console Config Generator" -echo " Host: $(hostname) $(date)" -echo "============================================" - -# --- Locate mapping file --- -# When run via remote.sh prox-file, $0 is bash and $SCRIPT_DIR may be wrong. -# Search common locations. -if [ ! -f "$MAPPING_FILE" ]; then - for candidate in \ - "/root/console/mapping.txt" \ - "/tmp/mapping.txt" \ - "$(dirname "$0")/mapping.txt"; do - if [ -f "$candidate" ]; then - MAPPING_FILE="$candidate" - break - fi - done -fi - -if [ ! -f "$MAPPING_FILE" ]; then - echo "FATAL: mapping file not found. Tried: $MAPPING_FILE" - echo "Copy mapping.txt to the target host first." - exit 1 -fi -echo " Mapping file: $MAPPING_FILE" - -# --- Auto-detect Tailscale IP --- -if [ -z "${TS_IP:-}" ]; then - TS_IP=$(tailscale ip -4 2>/dev/null || true) - if [ -z "$TS_IP" ]; then - echo "FATAL: could not auto-detect Tailscale IP. Set TS_IP manually." - exit 1 - fi -fi -echo " Tailscale IP: $TS_IP" -echo " ser2net will bind to: $TS_IP" - -# --- Parse mapping file (skip comments and blank lines) --- -echo "" -echo "--- Parsing mapping file ---" -ENTRIES=() -while IFS= read -r line; do - # Skip comments and blank lines - line="${line%%#*}" - line="$(echo "$line" | xargs)" # trim whitespace - [ -z "$line" ] && continue - ENTRIES+=("$line") - echo " $line" -done < "$MAPPING_FILE" - -if [ "${#ENTRIES[@]}" -eq 0 ]; then - echo "FATAL: no entries found in mapping file." - exit 1 -fi - -echo "" -echo " ${#ENTRIES[@]} console ports configured." - -# ============================================================ -# 1. Generate udev rules -# ============================================================ -echo "" -echo "--- [1/3] Generating udev rules: $UDEV_RULES ---" - -cat > "$UDEV_RULES" <<'UDEV_HEADER' -# Stable symlinks for USB-DB9 console adapters -# Generated by console/generate-config.sh -# DO NOT EDIT — edit mapping.txt and re-run generate-config.sh -# -# These rules pin each adapter to a named symlink based on its physical -# USB port path (ID_PATH), which is stable across reboots regardless of -# enumeration order. This is the fix for the "USB adapters shift on reboot" -# problem. -# -# To find the ID_PATH for a device: -# udevadm info -q all -n /dev/ttyUSBN | grep ID_PATH -UDEV_HEADER - -for entry in "${ENTRIES[@]}"; do - IFS='|' read -r tcp_port name id_path baud comment <<< "$entry" - # Build the full ID_PATH match. The mapping stores a substring like "usb-0:1.5.4.4" - # The actual ID_PATH is like "pci-0000:00:1a.0-usb-0:1.5.4.4:1.0" - # We match on the substring to be portable across PCI bus changes. - { - echo "" - echo "# $name (TCP $tcp_port): $comment" - echo "SUBSYSTEM==\"tty\", ENV{ID_PATH}==\"*$id_path*\", SYMLINK+=\"consoles/$name\"" - } >> "$UDEV_RULES" -done - -echo " Written: $UDEV_RULES" -echo " Symlinks: /dev/consoles/ for each device" - -# ============================================================ -# 2. Generate ser2net.yaml -# ============================================================ -echo "" -echo "--- [2/3] Generating ser2net config: $SER2NET_CONF ---" - -# Backup existing config if not already backed up -if [ -f "$SER2NET_CONF" ] && [ ! -f "${SER2NET_CONF}.orig" ]; then - cp "$SER2NET_CONF" "${SER2NET_CONF}.orig" - echo " Backed up original to ${SER2NET_CONF}.orig" -fi - -{ - echo "%YAML 1.1" - echo "---" - echo "# ser2net configuration for pfv-tsys4 console ports" - echo "# Generated by console/generate-config.sh on $(date)" - echo "#" - echo "# All ports use telnet(rfc2217) accepter so conman and telnet clients" - echo "# negotiate proper telnet binary mode — this prevents CR stripping" - printf '%s\n' "# and stair-stepping on devices that send \\n\\r (LF+CR) line endings." - echo "# Ports bound to Tailscale IP ($TS_IP) for secure remote access." - echo "#" - echo "# Direct telnet: telnet $TS_IP 2001" - echo "# Via conman: conman -f " - echo "" - printf '%s\n' "define: &banner \\r\\nPFV console port \\p device \\d [\\B]\\r\\n\\r\\n" - echo "" - - for entry in "${ENTRIES[@]}"; do - IFS='|' read -r tcp_port name id_path baud comment <<< "$entry" - # ser2net connection block — telnet(rfc2217) accepter so conman and - # telnet clients negotiate proper telnet binary mode. This prevents - # CR stripping that occurs with raw TCP + conman's telnet NVT. - echo "connection: &con${tcp_port}" - echo " accepter: telnet(rfc2217),tcp,${TS_IP},${tcp_port}" - echo " enable: on" - echo " options:" - echo " banner: *banner" - echo " kickolduser: true" - echo " telnet-brk-on-sync: true" - echo " connector: serialdev," - echo " /dev/consoles/${name}," - echo " ${baud},local" - echo "" - done -} > "$SER2NET_CONF" - -echo " Written: $SER2NET_CONF" -echo " ${#ENTRIES[@]} TCP ports configured ($TS_IP:2001-20XX)" - -# ============================================================ -# 3. Write conman console entries directly into conman.conf -# ============================================================ -# conman 0.3.x does NOT support the 'include' directive, so we write -# CONSOLE entries directly into /etc/conman.conf between idempotent markers. -echo "" -echo "--- [3/3] Writing conman consoles into $CONMAN_CONF ---" - -# Ensure logdir exists -mkdir -p "$CONMAN_LOGDIR" 2>/dev/null || true - -# Ensure LOGDIR is set in conman.conf (server-level directive for log file paths) -if ! grep -qiE '^\s*server\s+logdir\s*=' "$CONMAN_CONF" 2>/dev/null; then - # Insert near the top, after the first SERVER directives - sed -i "1i\\server logdir = \"$CONMAN_LOGDIR\"" "$CONMAN_CONF" - echo " Added server logdir = \"$CONMAN_LOGDIR\" to $CONMAN_CONF" -fi - -# Ensure loopback=off so conmand is reachable over Tailscale (not localhost-only) -if ! grep -qiE '^\s*server\s+loopback\s*=' "$CONMAN_CONF" 2>/dev/null; then - sed -i "/^server logdir/a server loopback=off" "$CONMAN_CONF" - echo " Added server loopback=off to $CONMAN_CONF (enables remote access)" -fi - -# Remove any previous auto-generated block (between markers) -# Then append the new block -MARKER_BEGIN="# BEGIN PFV CONSOLE DEFINITIONS (auto-generated — do not edit between markers)" -MARKER_END="# END PFV CONSOLE DEFINITIONS" - -# Strip old block if present -if grep -q "$MARKER_BEGIN" "$CONMAN_CONF" 2>/dev/null; then - sed -i "/$MARKER_BEGIN/,/$MARKER_END/d" "$CONMAN_CONF" - echo " Removed previous console definitions." -fi - -# Append new block -{ - echo "" - echo "$MARKER_BEGIN" - echo "# Generated by console/generate-config.sh on $(date)" - echo "# Each console connects to a ser2net TCP port via telnet protocol." - echo "# ser2net uses telnet(rfc2217) accepter so binary mode is negotiated" - echo "# and CR/LF translation is handled correctly by the telnet NVT layer." - echo "# Access: conman -f " - echo "" - for entry in "${ENTRIES[@]}"; do - IFS='|' read -r tcp_port name id_path baud comment <<< "$entry" - echo "CONSOLE name=\"${name}\" dev=\"${TS_IP}:${tcp_port}\" log=\"${name}.log\" logopts=\"timestamp\"" - done - echo "$MARKER_END" -} >> "$CONMAN_CONF" - -CONSOLE_COUNT=$(grep -c "^CONSOLE " "$CONMAN_CONF" 2>/dev/null || echo 0) -echo " Written $CONSOLE_COUNT CONSOLE entries to $CONMAN_CONF" - -# ============================================================ -# Summary -# ============================================================ -echo "" -echo "============================================" -echo " Configuration generated successfully." -echo "" -echo " Files written:" -echo " $UDEV_RULES ($(wc -l < "$UDEV_RULES") lines)" -echo " $SER2NET_CONF ($(wc -l < "$SER2NET_CONF") lines)" -echo " $CONMAN_CONF (CONSOLE entries appended between markers)" -echo "" -echo " Next steps:" -echo " 1. Reload udev: udevadm control --reload-rules && udevadm trigger" -echo " 2. Restart ser2net: systemctl restart ser2net" -echo " 3. Start conman: systemctl enable --now conmand" -echo " 4. Or run: bash $(basename "$0" .sh | sed 's/generate-config/setup/') .sh" -echo "============================================" diff --git a/dcinfra/console/mapping.txt b/dcinfra/console/mapping.txt deleted file mode 100644 index c1033b2..0000000 --- a/dcinfra/console/mapping.txt +++ /dev/null @@ -1,29 +0,0 @@ -# console/mapping.txt — Source of Truth for console port assignments -# -# Format: |||| -# -# Delimiter is | (pipe) because ID_PATH values contain colons. -# -# - tcp_port: TCP port ser2net listens on (also the conman console name suffix) -# - name: Device name (used for /dev/console/ symlink, conman console name) -# - id_path_substring: Stable USB physical path from `udevadm info -q all -n /dev/ttyUSBN | grep ID_PATH` -# These are STABLE across reboots as long as adapters aren't moved -# to different physical USB ports. -# - baud: Serial baud rate (9600n81 = 9600 8N1, no flow control) -# - comment: Free-form description -# -# To RE-MAP after physically moving an adapter: -# 1. Run: bash console/discover.sh (find the new ID_PATH for the device) -# 2. Update the id_path_substring in this file -# 3. Run: bash console/generate-config.sh && udevadm trigger && systemctl restart ser2net conmand -# -2001|pfv-r5-core-01|usb-0:1.5.4.4|9600n81|Dell PowerConnect 5448 (rack 5 core switch) -2002|pfv-r3-tor-mgmt-01|usb-0:1.6.3.1|9600n81|Rack 3 management TOR switch -2003|pfv-r3-tor-stor-01|usb-0:1.6.3.3.2|9600n81|Rack 3 storage TOR switch -2004|pfv-rrinfra-rtr|usb-0:1.6.3.3.1|9600n81|Cisco router (rrinfra) -2005|pfv-r2-tor-01|usb-0:1.6.3.3.3|9600n81|Rack 2 TOR switch -2006|pfv-r6-mgmt-01|usb-0:1.5.4.1|9600n81|Rack 6 management switch -# 2007|pfv-r2-sw|usb-0:1.6.3.2|9600n81|Rack 2 old Dell switch (dead, removed) -# Unassigned (no device detected): -# 2008|spare-1|usb-0:1.6.3.4|9600n81|Empty / spare -# 2009|spare-2|usb-0:1.6.3.3.4|9600n81|Empty / spare diff --git a/dcinfra/console/query-remote.sh b/dcinfra/console/query-remote.sh deleted file mode 100644 index eb5283b..0000000 --- a/dcinfra/console/query-remote.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/bash -# -# console/query-remote.sh — install conman client and connect to a console -# on pfv-tsys4 over Tailscale. -# -# Usage: -# bash console/query-remote.sh # list consoles -# bash console/query-remote.sh pfv-r5-core-01 # connect to a console -# -set -euo pipefail - -REMOTE_HOST="${REMOTE_HOST:-pfv-tsys4}" -REMOTE_PORT="${REMOTE_PORT:-7890}" - -echo "============================================" -echo " Conman Remote Console Access" -echo " Server: ${REMOTE_HOST}:${REMOTE_PORT} (Tailscale)" -echo "============================================" - -# --- 1. Install conman client if missing --- -if ! command -v conman >/dev/null 2>&1; then - echo "" - echo "--- Installing conman client ---" - if sudo -n true 2>/dev/null; then - sudo apt-get update -qq && sudo apt-get install -y -qq conman - else - echo " Passwordless sudo not available. Please run:" - echo " sudo apt-get update && sudo apt-get install -y conman" - echo " Then re-run this script." - exit 1 - fi -else - echo " conman client already installed." -fi - -# --- 2. Verify connectivity --- -echo "" -echo "--- Connectivity check ---" -if timeout 3 bash -c "echo > /dev/tcp/${REMOTE_HOST}/${REMOTE_PORT}" 2>/dev/null; then - echo " [OK] ${REMOTE_HOST}:${REMOTE_PORT} reachable" -else - echo " [FAIL] Cannot reach ${REMOTE_HOST}:${REMOTE_PORT}" - echo " Is Tailscale up? Is conmand running on ${REMOTE_HOST}?" - exit 1 -fi - -# --- 3. List or connect --- -CONSOLE="${1:-}" -if [ -z "$CONSOLE" ]; then - echo "" - echo "--- Available consoles ---" - conman -d "${REMOTE_HOST}:${REMOTE_PORT}" -q - echo "" - echo "To connect: bash $0 " - echo " e.g: bash $0 pfv-r5-core-01" -else - echo "" - echo "--- Connecting to: $CONSOLE ---" - echo " Escape sequence: &. (to disconnect)" - echo "" - conman -d "${REMOTE_HOST}:${REMOTE_PORT}" -f "$CONSOLE" -fi diff --git a/dcinfra/console/setup.sh b/dcinfra/console/setup.sh deleted file mode 100644 index 3b331bd..0000000 --- a/dcinfra/console/setup.sh +++ /dev/null @@ -1,217 +0,0 @@ -#!/usr/bin/bash -# shellcheck disable=SC2010 # diagnostic; ls|grep on /dev listing is intentional -# -# console/setup.sh — deploy console management on pfv-tsys4 -# -# Orchestrates the full setup: -# 1. Ensures ser2net + conman are installed -# 2. Copies mapping.txt to the target host (if running remotely) -# 3. Runs generate-config.sh to produce udev rules + ser2net.yaml + conman.conf -# 4. Reloads udev, creates /dev/consoles/ symlinks -# 5. Restarts ser2net (TCP ports on Tailscale IP) -# 6. Enables + starts conmand (logging + multiplexing) -# 7. Verifies -# -# This script is IDEMPOTENT — safe to run multiple times. -# -# Usage: -# PROX_HOST=pfv-tsys4 bash tests/remote.sh prox-file console/setup.sh -# -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -echo "============================================" -echo " Console Management Setup" -echo " Host: $(hostname) $(date)" -echo "============================================" - -# --- 1. Install dependencies --- -echo "" -echo "--- [1/7] Checking dependencies ---" -NEED_INSTALL=() -dpkg -l ser2net 2>/dev/null | grep -q '^ii' && echo " ser2net: installed" || NEED_INSTALL+=(ser2net) -dpkg -l conman 2>/dev/null | grep -q '^ii' && echo " conman: installed" || NEED_INSTALL+=(conman) - -if [ "${#NEED_INSTALL[@]}" -gt 0 ]; then - echo " Installing: ${NEED_INSTALL[*]}" - apt-get update -qq - apt-get install -y -qq "${NEED_INSTALL[@]}" -else - echo " All dependencies present." -fi - -# --- 2. Ensure mapping file is available --- -echo "" -echo "--- [2/7] Locating mapping file ---" - -MAPPING_FILE="" -for candidate in \ - "$SCRIPT_DIR/mapping.txt" \ - "$(dirname "$0")/mapping.txt" \ - "/root/console/mapping.txt" \ - "/tmp/mapping.txt"; do - if [ -f "$candidate" ]; then - MAPPING_FILE="$candidate" - break - fi -done - -if [ -z "$MAPPING_FILE" ]; then - echo "FATAL: mapping.txt not found. Copy it to the target host." - exit 1 -fi -echo " Using: $MAPPING_FILE" - -# --- 3. Generate configs --- -echo "" -echo "--- [3/7] Generating configs ---" -export MAPPING_FILE -bash "$(dirname "$0")/generate-config.sh" 2>&1 || bash "$SCRIPT_DIR/generate-config.sh" 2>&1 || { - echo "FATAL: generate-config.sh failed." - exit 1 -} - -# --- 4. Reload udev + create symlinks --- -echo "" -echo "--- [4/7] Reloading udev rules ---" -udevadm control --reload-rules -# Try trigger first (works on some systems) -for tty in /sys/class/tty/ttyUSB*; do - [ -e "$tty" ] && udevadm trigger --action=add "$tty" 2>/dev/null || true -done -# Also try writing to uevent (forces udev reprocessing) -for tty in /sys/class/tty/ttyUSB*; do - [ -e "$tty/uevent" ] && echo "add" > "$tty/uevent" 2>/dev/null || true -done -sleep 2 - -# FALLBACK: if udev symlinks don't exist (common when devices are already -# discovered — udev trigger doesn't always re-create symlinks for existing -# devices), create them manually by matching ID_PATH. The udev rules will -# handle future boots/hotplugs automatically. -if [ ! -d /dev/consoles ] || [ -z "$(ls /dev/consoles/ 2>/dev/null)" ]; then - echo " udev trigger didn't create symlinks. Creating manually..." - mkdir -p /dev/consoles - while IFS= read -r line; do - line="${line%%#*}" - line="$(echo "$line" | xargs)" - [ -z "$line" ] && continue - IFS='|' read -r _ name id_path _ _ <<< "$line" - # Find the ttyUSB whose ID_PATH contains the mapping's id_path substring - for tty in /dev/ttyUSB*; do - [ -e "$tty" ] || continue - DEV_IDPATH=$(udevadm info -q property -n "$tty" 2>/dev/null | grep ^ID_PATH= | cut -d= -f2) - if echo "$DEV_IDPATH" | grep -q "$id_path"; then - ln -sf "$tty" "/dev/consoles/$name" - echo " ln -s $tty -> /dev/consoles/$name" - break - fi - done - done < "$MAPPING_FILE" -fi - -echo " Stable symlinks:" -ls -la /dev/consoles/ 2>/dev/null | grep -v '^total\|^d' | sed 's/^/ /' || echo " (none created)" - -# Verify each symlink resolves -echo "" -echo " Symlink verification:" -while IFS= read -r line; do - line="${line%%#*}" - line="$(echo "$line" | xargs)" - [ -z "$line" ] && continue - IFS='|' read -r _ name id_path _ _ <<< "$line" - if [ -e "/dev/consoles/$name" ]; then - TARGET=$(readlink -f "/dev/consoles/$name") - echo " [OK] /dev/consoles/$name -> $TARGET" - else - echo " [MISSING] /dev/consoles/$name (adapter unplugged or ID_PATH changed)" - fi -done < "$MAPPING_FILE" - -# --- 5. Restart ser2net --- -echo "" -echo "--- [5/7] Restarting ser2net ---" -systemctl enable ser2net -systemctl restart ser2net -sleep 2 - -if systemctl is-active --quiet ser2net; then - echo " ser2net is running (telnet rfc2217 accepters)." - TS_IP=$(tailscale ip -4 2>/dev/null || echo "127.0.0.1") - echo " Listening ports:" - ss -tlnp | grep ser2net | grep -oE "${TS_IP}:[0-9]+" | sort -t: -k2 -n | sed 's/^/ /' -else - echo " WARNING: ser2net failed to start. Checking journal..." - journalctl -u ser2net --no-pager -n 20 -fi - -# --- 6. Enable + start conmand --- -echo "" -echo "--- [6/7] Starting conmand ---" - -# conman package on Debian may not ship a systemd unit. Create one if missing. -if ! systemctl cat conmand >/dev/null 2>&1; then - echo " No systemd unit for conmand — creating one..." - cat > /etc/systemd/system/conmand.service <<'CONMAND_UNIT' -[Unit] -Description=ConMan (Console Manager) -After=network.target ser2net.service -Requires=ser2net.service - -[Service] -Type=forking -ExecStart=/usr/sbin/conmand -c /etc/conman.conf -Restart=on-failure -RestartSec=5 - -[Install] -WantedBy=multi-user.target -CONMAND_UNIT - systemctl daemon-reload - echo " Created /etc/systemd/system/conmand.service" -fi - -# Kill any manually-started conmand first -pkill -x conmand 2>/dev/null || true -sleep 1 - -systemctl enable conmand 2>/dev/null || true -systemctl restart conmand 2>/dev/null || true -sleep 2 - -if systemctl is-active --quiet conmand; then - echo " conmand is running." - echo " Consoles:" - conman -q 2>&1 | sed 's/^/ /' || true -else - echo " WARNING: conmand failed to start. Checking journal..." - journalctl -u conmand --no-pager -n 20 2>/dev/null || true - # Try manual start as fallback - echo " Attempting manual start..." - /usr/sbin/conmand -c /etc/conman.conf 2>&1 || true -fi - -# --- 7. Summary --- -echo "" -echo "--- [7/7] Setup complete ---" -echo "" -echo " ser2net + conman architecture (telnet rfc2217):" -echo " ser2net owns serial devices, exposes telnet(rfc2217) TCP ports" -echo " conman connects via telnet for logging + multiplexing" -echo "" -echo " Connect from any Tailscale workstation:" -echo " conman -d pfv-tsys4:7890 -f pfv-r5-core-01" -echo " conman -d pfv-tsys4:7890 -q # list consoles" -echo "" -echo " Direct telnet (emergency, conflicts with conman):" -echo " ssh pfv-tsys4 'systemctl stop conmand'" -echo " telnet pfv-tsys4 2001" -echo " ssh pfv-tsys4 'systemctl start conmand'" -echo "" -echo " To regenerate after changing mapping.txt:" -echo " bash generate-config.sh" -echo " udevadm trigger" -echo " systemctl restart ser2net conmand" -echo "============================================" diff --git a/dcinfra/console/validate-conman.sh b/dcinfra/console/validate-conman.sh deleted file mode 100644 index c3a27bd..0000000 --- a/dcinfra/console/validate-conman.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/bash -# shellcheck disable=SC2012,SC2001 # diagnostic script; ls -la listings and sed line-prefixing are intentional -# -# console/validate-conman.sh — verify conman can actually reach devices via -# ser2net TCP ports and is capturing log output to files. -# -# This tests the real data path: conman → TCP 200X → ser2net → /dev/consoles/X → device -# -set -uo pipefail - -TS_IP=$(tailscale ip -4) -LOGDIR="/var/log/conman" - -echo "============================================" -echo " Conman Data Path + Log Validation" -echo " Host: $(hostname) TS IP: $TS_IP" -echo "============================================" - -echo "" -echo "--- 1. conman.conf log settings ---" -grep -E "logdir|LOGDIR|^GLOBAL LOG" /etc/conman.conf 2>/dev/null | grep -v "^#" || echo " (no explicit logdir — defaults to /var/log/conman)" -echo " Log dir: $LOGDIR" -ls -la "$LOGDIR"/ 2>/dev/null | head -15 || echo " ($LOGDIR does not exist yet)" - -echo "" -echo "--- 2. CONSOLE entries: each has a log= directive? ---" -# Extract the auto-generated block and check each CONSOLE line has log= -sed -n '/BEGIN PFV CONSOLE/,/END PFV CONSOLE/p' /etc/conman.conf | grep "^CONSOLE" | while read -r line; do - name=$(echo "$line" | sed -n 's/.*name="\([^"]*\)".*/\1/p') - if echo "$line" | grep -q 'log='; then - logfile=$(echo "$line" | sed -n 's/.*log="\([^"]*\)".*/\1/p') - echo " [OK] $name → log=$logfile" - else - echo " [FAIL] $name has NO log= directive" - fi -done - -echo "" -echo "--- 3. Trigger log capture: connect to each console briefly ---" -# conman -e changes the escape char. We use -j (join, read-only) with a timeout. -# Actually, conman doesn't have a built-in "connect for N seconds" — but conmand -# connects to each device ON STARTUP and keeps the connection open for logging. -# The log files should already be created. Let's check timestamps. - -echo " conmand connects to all consoles on startup. Checking if logs exist..." -echo "" -echo "--- 4. Log file inventory ---" -for name in pfv-r5-core-01 pfv-r3-tor-mgmt-01 pfv-r3-tor-stor-01 pfv-rrinfra-rtr pfv-r2-tor-01 pfv-r6-mgmt-01; do - logfile="$LOGDIR/${name}.log" - if [ -f "$logfile" ]; then - SIZE=$(stat -c%s "$logfile" 2>/dev/null || echo 0) - MTIME=$(stat -c%y "$logfile" 2>/dev/null | cut -d. -f1) - echo " [OK] $logfile ($SIZE bytes, modified $MTIME)" - else - echo " [MISSING] $logfile — conmand may not be writing yet" - fi -done - -echo "" -echo "--- 5. conmand connection status (journal) ---" -# conmand logs connection attempts/errors to syslog -journalctl -u conmand --no-pager -n 50 2>/dev/null | grep -iE "connect|error|fail|console|refused|timeout" | tail -15 || echo " (no relevant journal entries)" - -echo "" -echo "--- 6. Verify ser2net is proxying data (telnet rfc2217) ---" -echo " Probing TCP $TS_IP:2007 for data..." -RESPONSE=$(timeout 3 bash -c "printf '\r\r' | nc -w 2 $TS_IP 2007 2>/dev/null" | tr -cd '[:print:][:space:]' | head -5) -if [ -n "$RESPONSE" ]; then - echo " [OK] Data flowing through ser2net TCP 2007:" - echo "$RESPONSE" | sed 's/^/ /' -else - echo " (no immediate response — device may need more interaction)" -fi - -echo "" -echo "--- 7. Check if conmand has open connections to ser2net ports ---" -CONMAND_PID=$(pgrep -x conmand 2>/dev/null || echo "") -if [ -n "$CONMAND_PID" ]; then - echo " conmand PID: $CONMAND_PID" - echo " Open connections to ser2net (expect 7 to 100.x:200X):" - ss -tnp 2>/dev/null | grep "pid=$CONMAND_PID" | grep -oE "100\.[0-9.]+:200[0-9]" | sort | sed 's/^/ /' - COUNT=$(ss -tnp 2>/dev/null | grep "pid=$CONMAND_PID" | grep -c ":200") - echo " Total conmand→ser2net connections: $COUNT (expect 7)" -else - echo " [FAIL] conmand not running" -fi - -echo "" -echo "============================================" diff --git a/dcinfra/idrac/drac-extend.sh b/dcinfra/idrac/drac-extend.sh deleted file mode 100644 index 368421e..0000000 --- a/dcinfra/idrac/drac-extend.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -# drac-extend: expose iDRAC IPMI temperature SDRs via snmpd extend [#625] -# -# Deployed to /usr/local/bin/drac-extend on pfv-tsys6 / pfv-tsys7. -# Creds live in /etc/snmp/drac-env (0600 root): DRAC_HOST, IPMI_USER, IPMI_PASS. -# Output: "