homelab/services/device-inventory
Dan V bf7a7937e0 feat(inventory-cli): build script, manpage help, discover-only command
build-cli.sh
  Simple shell script that builds inventory-cli inside Docker and
  extracts the binary to build/ (or a custom path).  Replaces the
  need to use the heavier build-and-load.sh just to compile the CLI.

--help
  Replaced the terse usage() stub with a full UNIX man-page style
  reference covering NAME, SYNOPSIS, DESCRIPTION, GLOBAL OPTIONS,
  COMMANDS (grouped by area), PART TYPES, FIELD KEYS, EXAMPLES,
  and NOTES.

discover-only [--type <type>]
  New command that runs local hardware discovery without contacting
  the inventory server and prints results as an ASCII tree rooted at
  the hostname.  Each section (CPUs, CPU Slots, Memory Sticks, Memory
  Slots, Disks, NICs) lists discovered components with key attributes
  inline.  Useful for inspection and troubleshooting.

discovery.cpp: store interface name in K_NAME for NICs
  ifname (e.g. "nic0", "eno1") is now emitted so discover-only and
  the server-side UI can display the kernel device name.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-01 00:49:17 +02:00
..
src feat(inventory-cli): build script, manpage help, discover-only command 2026-04-01 00:49:17 +02:00
web-ui feat(device-inventory): add management web UI and pciutils for NIC discovery 2026-03-31 22:42:20 +02:00
build-and-load.sh feat(device-inventory): add hooks system and DNS updater hook 2026-03-24 14:58:36 +01:00
build-cli.sh feat(inventory-cli): build script, manpage help, discover-only command 2026-04-01 00:49:17 +02:00
CMakeLists.txt feat(device-inventory): add hooks system and DNS updater hook 2026-03-24 14:58:36 +01:00
Dockerfile feat(device-inventory): add hooks system and DNS updater hook 2026-03-24 14:58:36 +01:00
Dockerfile.cli feat(device-inventory): add management web UI and pciutils for NIC discovery 2026-03-31 22:42:20 +02:00
instructions.md feat(device-inventory): add hooks system and DNS updater hook 2026-03-24 14:58:36 +01:00
README.md feat(device-inventory): add hooks system and DNS updater hook 2026-03-24 14:58:36 +01:00

device-inventory

A lightweight hardware inventory tracker built in C++17. Uses a client/server model: the server owns the file-backed database and exposes a TCP interface on localhost; the CLI client connects to it to run commands.


Architecture

┌──────────────┐  TCP (localhost:9876)  ┌─────────────────────┐
│ inventory-cli│ ─────────────────────► │ inventory-server    │
│  (CLI client)│ ◄───────────────────── │  database ► file.db │
└──────────────┘                        └─────────────────────┘
  • inventory-server loads the inventory file on start, accepts one command per connection, and flushes changes to disk after every mutation.
  • inventory-cli a thin CLI that translates subcommands into protocol messages, connects to the server, and pretty-prints the response.

Build

Requires CMake ≥ 3.16 and a C++17-capable compiler.

cd device-inventory
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build

Binaries end up in build/inventory-server and build/inventory-cli.


Running

Start the server

./build/inventory-server                       # uses inventory.db in CWD
./build/inventory-server --port 9876 --db /var/lib/inventory/data.db

The server reloads the file every time it restarts. On the very first run the file is created automatically.

Use the CLI

# Shorthand for the examples below
cli="./build/inventory-cli"

Commands

Servers

# Add a server
$cli add-server "web01" "192.168.1.10" "Rack A" "Primary web server"

# List all servers
$cli list-servers

# Edit a field (fields: name | hostname | location | description)
$cli edit-server 1 hostname "10.0.0.1"
$cli edit-server 1 description "Retired  do not use"

Part types

# Add a part type
$cli add-part-type "RAM" "Memory modules"
$cli add-part-type "SSD" "Solid-state storage"

# List all part types
$cli list-part-types

# Edit a field (fields: name | description)
$cli edit-part-type 1 description "DDR4/DDR5 memory"

Parts

# Add a part to a server
# add-part <server_id> <part_type_id> <name> <serial> <description>
$cli add-part 1 1 "16 GB DDR4" "SN-MEM-001" "DIMM slot A1"
$cli add-part 1 2 "Samsung 870 EVO 1 TB" "SN-SSD-004" "Primary OS drive"

# List parts of a server
$cli list-parts 1

# Edit a field (fields: name | serial | description | server_id | part_type_id)
$cli edit-part 2 serial "SN-SSD-005"
$cli edit-part 2 server_id 3

Database file format

Plain text, one record per line safe to inspect or diff with standard tools.

# device-inventory database
META|<next_server_id>|<next_part_type_id>|<next_part_id>
S|<id>|<name>|<hostname>|<location>|<description>
PT|<id>|<name>|<description>
P|<id>|<server_id>|<part_type_id>|<name>|<serial>|<description>

Pipe characters and backslashes inside field values are escaped with \| and \\ respectively.


Wire protocol

Commands are newline-terminated lines; fields are separated by ASCII SOH (0x01). Each connection carries exactly one request/response pair.

Client → Server:  COMMAND\x01arg1\x01arg2\n
Server → Client:  OK\n
                  field1\x01field2\x01...\n   ← 0 or more data rows
                  END\n
         -- or --
                  ERR <message>\n