# labctl Infrastructure management platform for bare-metal servers, Kubernetes clusters, and cloud resources. ## Install ```bash # From Gitea packages (Fedora/RHEL) sudo dnf config-manager --add-repo https://mysources.co.uk/michal/-/packages/rpm/ sudo dnf install labctl # From source cd bastion && pnpm install && pnpm build bun build src/cli/src/index.ts --compile --outfile dist/labctl sudo cp dist/labctl /usr/bin/labctl ``` ## Quick Start ```bash # Start the bastion (PXE provisioning server) sudo labctl init bastion standalone start # PXE boot a machine — it gets discovered automatically labctl provision list # Install Fedora on a discovered machine labctl provision install 78:55:36:08:35:14 labmaster --role infra # Reprovision (SSH reboot into PXE, preserves /home /srv /var/lib/rancher) labctl provision reprovision 78:55:36:08:35:14 labmaster --role infra ``` ## Commands ### Bastion (PXE Provisioning) ```bash # Lifecycle sudo labctl init bastion standalone start # Start bastion (daemonized) sudo labctl init bastion standalone start --foreground # Start in foreground sudo labctl init bastion standalone stop # Stop bastion labctl init bastion standalone status # Show status, PID, machine count # Options sudo labctl init bastion standalone start \ --port 8080 \ --dir /tmp/lab-bastion \ --domain ad.itaz.eu \ --dhcp-mode proxy \ --fedora 43 \ --timezone Europe/London ``` ### Provisioning ```bash # List all machines (discovered, queued, installing, installed) labctl provision list # Queue a machine for Fedora install labctl provision install --role worker # k3s worker (gets longhorn) labctl provision install --role infra # infra node (gets k3s server + /var/lib/rancher) # Reprovision — queues install, SSHes in, sets PXE boot, reboots labctl provision reprovision --role infra # Remove a machine from state labctl provision forget # Options labctl provision install \ --role worker \ --disk nvme0n1 \ --port 8080 ``` ### Server Management (planned) ```bash # List servers with filters labctl get servers labctl get servers --env production labctl get servers --cloud baremetal labctl get servers --cloud aws labctl get servers --label role=k3s-worker labctl get servers --label asg=web-servers # Detailed server info labctl describe server/puppet labctl describe server/ser9 ``` ### Remote Execution (planned) ```bash # Execute commands on servers (audited, RBAC-checked) labctl exec server/puppet -- whoami labctl exec server/puppet -- systemctl status k3s labctl exec server/puppet -it -- bash # interactive TTY labctl exec server/puppet --timeout 30s -- long-running-task ``` ### Kubernetes (planned) ```bash # Proxied kubectl — audited, RBAC-checked, no kubeconfig needed labctl kubectl --cluster lab get pods labctl kubectl --cluster lab get nodes labctl kubectl --cluster lab logs pod/nginx -f labctl kubectl --cluster lab exec pod/nginx -- bash labctl kubectl --cluster lab apply -f deployment.yaml labctl kubectl --cluster aws-prod get pods --namespace app # Cluster management labctl clusters add lab --kubeconfig ~/.kube/config labctl clusters list labctl clusters remove staging ``` ### Logs (planned) ```bash # Server logs (journalctl passthrough via agent) labctl logs server/puppet # all journal labctl logs server/puppet -f # follow (live stream) labctl logs server/puppet -n 100 # last 100 lines labctl logs server/puppet -u k3s # specific unit labctl logs server/puppet -u sshd --since "1h ago" # time range labctl logs server/puppet --since "2026-03-17" --until "2026-03-18" labctl logs server/puppet -k # kernel only labctl logs server/puppet -p err # errors only labctl logs server/puppet --file /var/log/nginx/error.log # tail a file labctl logs server/puppet --file /var/log/nginx/error.log -n 50 # App logs (k8s pod logs) labctl logs app/bastion labctl logs app/bastion -f labctl logs app/labd --container postgres # Pulumi execution logs labctl logs pulumi/run-abc123 labctl logs pulumi/run-abc123 -f # follow active run # Bastion logs labctl logs bastion/lab labctl logs bastion/lab --mac 78:55:36:08:35:14 # specific machine's install # Agent daemon logs labctl logs agent/puppet # Audit logs labctl logs audit labctl logs audit --user michal labctl logs audit --user michal --since "1h ago" labctl logs audit/michal-20260317-abc123 # specific session labctl logs audit --action kubectl --cluster lab labctl logs audit --action exec --server puppet ``` ### Apps (planned, replaces Helm) ```bash # Install Pulumi-based apps to Kubernetes labctl apps list # available apps labctl apps install bastion # deploy bastion labctl apps install bastion --set port=8080 # with overrides labctl apps install bastion -f values.yaml # from values file labctl apps install monitoring # Prometheus + Grafana # Manage deployed apps labctl apps status bastion # health, version, config labctl apps upgrade bastion # rolling upgrade labctl apps history bastion # version history labctl apps rollback bastion 2 # rollback to version 2 labctl apps uninstall bastion ``` ### Infrastructure as Code (planned) ```bash # Execute Pulumi programs via labd (RBAC-checked) labctl apply -f infra/k3s-cluster.ts --env lab labctl plan -f infra/k3s-cluster.ts --env lab # dry run labctl destroy -f infra/k3s-cluster.ts --env lab ``` ### RBAC (planned) ```bash # Roles and permissions labctl get roles labctl get users labctl create role viewer --allow "read:*:*:*" labctl create role lab-admin --allow "*:baremetal:lab:*" --deny "destroy:*:*:*" labctl bind role lab-admin --user michal labctl unbind role lab-admin --user michal # Permission model: action:cloud:environment:server # read:*:*:* — read everything # exec:baremetal:lab:* — exec on any lab server # kubectl:*:*:* — kubectl on any cluster # *:baremetal:lab:puppet — full access to puppet only # manage:*:*:* — manage apps, clusters, tokens ``` ### Environments and Clouds (planned) ```bash labctl get environments labctl get clouds labctl create environment staging --cloud aws labctl create environment lab --cloud baremetal ``` ## Partition Layout Machines installed by the bastion get this LVM layout: ### Worker role (k3s worker with Longhorn) ``` /boot/efi 600MB EFI /boot 3GB ext4 ── LVM VG: labvg ── swap 27GB (matches RAM) / 33GB xfs /var 100GB xfs /var/log 10GB xfs /home 10GB xfs ← preserved on reprovision /srv 20GB xfs ← preserved on reprovision /tmp tmpfs 4GB /var/lib/longhorn rest xfs ← preserved on reprovision (Longhorn PVC storage) ``` ### Infra role (k3s server, labmaster) ``` /boot/efi 600MB EFI /boot 3GB ext4 ── LVM VG: labvg ── swap 27GB (matches RAM) / 33GB xfs /var 100GB xfs /var/log 10GB xfs /home 10GB xfs ← preserved on reprovision /srv 20GB xfs ← preserved on reprovision /var/lib/rancher 20GB xfs ← preserved on reprovision (k3s etcd data) /tmp tmpfs 4GB ``` On reprovision, OS partitions (`/`, `/var`, `/var/log`, `swap`) are wiped. Data partitions (`/home`, `/srv`, `/var/lib/longhorn`, `/var/lib/rancher`) are preserved. ## Architecture ``` ┌──────────────────────────────────────────────────────────────┐ │ labctl CLI │ │ init | provision | get | exec | logs | apply | apps | kubectl│ └───────────────────────────┬──────────────────────────────────┘ │ mTLS ▼ ┌──────────────────────────────────────────────────────────────┐ │ labd (master daemon — stateless, on k3s) │ │ ┌─────┐ ┌──────┐ ┌──────┐ ┌────────┐ ┌──────┐ ┌────────┐ │ │ │ CA │ │ RBAC │ │ Logs │ │ Pulumi │ │ Apps │ │kubectl │ │ │ │ │ │ │ │relay │ │executor│ │ │ │ proxy │ │ │ └─────┘ └──────┘ └──────┘ └────────┘ └──────┘ └────────┘ │ │ CockroachDB │ └──────────────┬─────────────────────────┬─────────────────────┘ │ mTLS │ mTLS ┌──────────▼───────────┐ ┌──────────▼───────────┐ │ lab-agent │ │ lab-agent │ │ bare-metal server │ │ AWS EC2 / cloud VM │ │ ┌────────────────┐ │ │ ┌────────────────┐ │ │ │ heartbeat │ │ │ │ heartbeat │ │ │ │ exec handler │ │ │ │ exec handler │ │ │ │ log streamer │ │ │ │ log streamer │ │ │ │ module runner │ │ │ │ module runner │ │ │ └────────────────┘ │ │ └────────────────┘ │ └──────────────────────┘ └──────────────────────┘ ``` ## Technology Stack | Component | Technology | |-----------|-----------| | Language | TypeScript (ESM) | | CLI | Commander.js | | HTTP Server | Fastify + WebSocket | | Database | CockroachDB (PostgreSQL compatible) | | ORM | Prisma | | IaC | Pulumi (TypeScript) | | k8s CNI | Cilium | | Auth | mTLS (built-in CA) | | Packaging | nfpm (RPM/DEB), bun compile | | Containers | Podman + podman-compose | | CI/CD | Gitea Actions | | Testing | Vitest | ## Development ```bash cd bastion # Install dependencies pnpm install # Build all packages pnpm build # Run tests (30 tests) pnpm test:run # Type check pnpm typecheck # Lint pnpm lint # Generate shell completions pnpm completions:generate # Build standalone binary bun build src/cli/src/index.ts --compile --outfile dist/labctl # Build RPM/DEB packages (both architectures) bash scripts/build-rpm.sh --all # Build Docker image bash scripts/build-bastion.sh # Full release (build + publish + install) bash scripts/release.sh ``` ## Project Structure ``` bastion/ ├── src/ │ ├── shared/ # @lab/shared — types, constants │ ├── bastion/ # @lab/bastion — PXE provisioning server │ ├── cli/ # @lab/cli — CLI binary (labctl) │ ├── labd/ # @lab/labd — master daemon (planned) │ └── agent/ # @lab/agent — server agent (planned) ├── modules/ # Built-in configuration modules (planned) ├── deploy/ │ └── k3s/ # Kubernetes manifests ├── stack/ │ ├── Dockerfile │ └── docker-compose.yml ├── scripts/ # Build, publish, release scripts ├── completions/ # Generated shell completions └── ARCHITECTURE.md ``` ## License MIT