Skip to content

Famlab CLI Architecture

Overview

The Famlab CLI is designed as a modular, extensible command-line interface for managing a Famlab deployment. It provides direct management of Proxmox VE containers.

Design Principles

  1. Modular Command Structure: Each command is a separate script for easy extension
  2. Direct Container Management: No complex orchestration dependencies
  3. Zero Configuration Overhead: Sensible defaults with optional customization
  4. Extensible Architecture: New commands can be added without modifying core router
  5. Human-oriented CLI: The interface is meant to be helpful and guided
  6. Working Directory Aware: The working directory contains the Famlab node inventory used by all commands
  7. Expected Behavior: The commands are not surprising and follow standard practices
    • -s,--silent will silence all stdout messages (keeping stderr for errors)
    • -f,--force will override and bypass any warning raised during a WRITE operation
    • -n,--dry-run will display what would have happened during a WRITE operation
    • -v, --verbose will increase the verbosity to DEBUG level (the default is INFO)
    • ambiguous state resolution should ask for confirmation and default to no destruction (-f would force a "yes", and -n would force a "no")

Typical Use

(Once the CLI is installed, see Installation Process first.)

% mkdir my-famlab
% cd my-famlab
% famlab init famlab-1 famlab-2 famlab-3]
[…]
% famlab bootstrap proxmox-ve.local
[…]
Famlab nodes 'famlab-1', 'famlab-2', 'famlab-3' bootstrapped successfully
% famlab deploy
[…]
Famlab nodes 'famlab-1', 'famlab-2', 'famlab-3' deployed successfully
% famlab ping
[…]
Famlab nodes 'famlab-1', 'famlab-2', 'famlab-3' pinged successfully
% famlab test
[…]
Famlab nodes 'famlab-1', 'famlab-2', 'famlab-3] tested successfully

Directory Structure

famlab.net/
├── bin/famlab                        # Main CLI router script
├── scripts/install.sh                # Installation script for the CLI
└── share/famlab/                     # Shared data
    ├── commands/                     # Command implementations
    │   ├── famlab-init               # Initialize configuration
    │   ├── famlab-bootstrap          # Create containers
    │   ├── famlab-deploy             # Configure services
    │   ├── famlab-ping               # Test connectivity
    │   ├── famlab-test               # Full service testing
    │   └── famlab-user               # User management
    └── lib/                          # Shared library functions
        └── famlab-core.sh            # Core functionality

Command Architecture

Main Router (bin/famlab)

  • POSIX-compatible shell script
  • Validates subcommand exists in commands/ directory
  • Routes execution to appropriate command script
  • Provides top-level help and listing of available subcommands

Individual Commands (share/famlab/commands/famlab-*)

  • Self-contained POSIX shell scripts
  • Source shared library (../lib/famlab-core.sh)
  • Implement specific functionality for Famlab management
  • Handle their own argument parsing and validation

Shared Library (share/famlab/lib/famlab-core.sh)

  • Common functions for Famlab operations
  • Logging, error handling, container operations
  • IP resolution, connectivity testing
  • SMB configuration utilities

Command Specifications

famlab init HOSTNAME...

Purpose: Initialize local configuration for Famlab deployment

Functionality:

  • Create local inventory file with specified hostnames in the current directory
  • Validate hostname format (strip .local suffixes with warning)
  • Accept plain hostnames and FQDNs, reject IP addresses

Example:

% famlab init famlab-1 famlab-2.local famlab-3.example.com
WARNING: Hostname 'famlab-2.local' is suffixed with 'local', stripping mDNS suffix ('famlab-2')
Famlab deployment initialized successfully, hosts inventory saved to 'inventory.ini'
% cat inventory.ini
; Famlab Inventory
; Generated by: famlab init famlab-1 famlab-2.local famlab-3.example.com
famlab-1
famlab-2
famlab-3.example.com

famlab bootstrap PVE [HOSTNAME...]

Purpose: Create Proxmox VE containers for Famlab nodes

Functionality:

  • SSH to Proxmox VE and create containers
  • Default configuration: 1 CPU, 512MiB RAM, 32GiB disk, DHCP IPv4
  • Install SSHd and allow current user to remote login as root
  • Warn against invalid configuration (ask for confirmation)
    • … both IPv4 and IPv6 disabled
    • … less than 8GiB disk
    • … less than 512MiB RAM
  • Optional overrides via command arguments
  • Bootstrap all hosts from inventory, unless hostnames are given as positional arguments

Arguments:

  • --cpu <cores> - Override CPU count
  • --memory <mib> - Override memory allocation
  • --disk <gib> - Override disk size
  • --ipv4 dhcp|disabled - IPv4 configuration
  • --ipv6 dhcp|disabled - IPv6 configuration
  • --storage <pool> - Proxmox storage pool
  • PVE - Proxmox VE hostname to execute remote commands from (SSH)
  • [HOSTNAME...] - Bootstrap specific hosts only

Example:

% famlab bootstrap proxmox-ve.local
Remote logging to 'root@proxmox-ve.local' successful
famlab-1: container created
famlab-1: container booted
famlab-1: resolved to 192.168.0.101
famlab-2: container created
famlab-2: container booted
famlab-2: resolved to 192.168.0.102
famlab-3.example.com: container created
famlab-3.example.com: container booted
famlab-3.example.com: resolved to 192.168.0.103
Famlab nodes 'famlab-1', 'famlab-2', 'famlab-3.example.com' bootstrapped successfully

famlab deploy [HOSTNAME...]

Purpose: Configure existing containers as home backup servers

Functionality:

  • Install and configure: Samba, Avahi, unattended-upgrades
  • Configure mDNS resolution
  • Set up basic SMB shares (homes, anonymous backup share) without users
  • Configure SMB to automatically create corresponding host users when SMB users are created
  • Handle re-runs gracefully (e.g. update existing configuration in-place rather than appending)
  • Deploy all hosts from inventory, unless hostnames are given as positional arguments

Arguments:

  • [HOSTNAME...] - Deploy specific hosts only

Example:

% famlab deploy
famlab-1: packages installed
famlab-1: Samba configured
famlab-1: unattended-upgrades configured
famlab-2: packages installed
famlab-2: Samba configured
famlab-2: unattended-upgrades configured
famlab-3.example.com: packages installed
famlab-3.example.com: Samba configured
famlab-3.example.com: unattended-upgrades configured
Famlab nodes 'famlab-1', 'famlab-2', 'famlab-3.example.com' deployed successfully

famlab ping [HOSTNAME...]

Purpose: Test network connectivity of containers

Functionality:

  • Test network connectivity and hostname resolution via ping
  • Display resolved IP addresses
  • Ping all hosts from inventory, unless hostnames are given as positional arguments

Arguments:

  • [HOSTNAME...] - Ping specific hosts only

Example:

% famlab ping famlab-1 famlab-3.example.com
famlab-1: network connectivity tested
famlab-1: resolved to 192.168.0.101
famlab-3.example.com: network connectivity tested
famlab-3.example.com: resolved to 192.168.0.103
Famlab nodes 'famlab-1', 'famlab-2', 'famlab-3.example.com' pinged successfully

famlab test [HOSTNAME...]

Purpose: Test services of Famlab nodes

Functionality:

  • Test remote login as root with SSH
  • Test SMB service availability and configuration
  • Test mDNS resolution
  • Check basic SMB functionality (without user-specific tests)
  • Test all hosts from inventory, unless hostnames are given as positional arguments

Arguments:

  • [HOSTNAME...] - Test specific hosts only

Example:

% famlab test famlab-1
famlab-1: remote logging as root successful
famlab-1: SMB is available and configured
famlab-1: anonymous SMB share is readable and writable
famlab-1: personal SMB share is readable and writable
famlab-1: mDNS resolved to 192.168.0.101
Famlab node 'famlab-1' tested successfully

famlab user HOSTNAME OPERATION

Purpose: Manage SMB/host user accounts on a Famlab node

Functionality:

  • Manage SMB user accounts
  • Set default password to username

Arguments:

  • HOSTNAME - Target Famlab node
  • OPERATION - Where operation is one of: list (list existing users), add USERNAME (create a new SMB user), remove USERNAME (remove an SMB user)

Example:

% famlab user famlab-1 list
Famlab node 'famlab-1' has no SMB users
% famlab user famlab-1 add borjan
New user 'borjan' created on Famlab node 'famlab-1'
% famlab user famlab-1 list
Famlab node 'famlab-1' has 1 SMB user: 'borjan'

Installation Process

scripts/install.sh

  1. Copy bin/famlab to $HOME/.local/bin/famlab with executable permissions
  2. Recursively copy share/famlab/ to ${XDG_DATA_HOME:-$HOME/.local/share}/famlab/
  3. Ensure $HOME/.local/bin is in PATH (warn if not)
  4. Set executable permissions on all command scripts

Paths

  • Main CLI: $HOME/.local/bin/famlab
  • Commands: ${XDG_DATA_HOME:-$HOME/.local/share}/famlab/commands/
  • Library: ${XDG_DATA_HOME:-$HOME/.local/share}/famlab/lib/

Configuration File Format

Inventory File (inventory.ini)

Simple format for storing Famlab node information:

; Famlab Inventory
; Generated by: famlab init
famlab-1
famlab-2
famlab-3.example.com

Format Rules:

  • One hostname per line
  • Comments start with ;
  • Empty lines ignored
  • No .local suffixes stored
  • FQDNs stored as-is

Implementation Notes

Exit Codes

  • 0 - Success
  • 1 - General error
  • 2 - Invalid arguments
  • 3 - Missing dependencies

Extension Points

Adding New Commands

  1. Create share/famlab/commands/famlab-<newcommand>
  2. Source ../lib/famlab-core.sh
  3. Implement functionality
  4. Add help text and argument parsing
  5. Command automatically available via router

Library Extension

  • Add new shared functions to famlab-core.sh
  • Maintain backward compatibility
  • Follow established naming conventions