Implements Phase 2 of the automated deployment pipeline. This commit adds a Python CLI tool that automates the creation of NixOS host configurations, eliminating manual boilerplate and reducing errors. Features: - Python CLI using typer framework with rich terminal UI - Comprehensive validation (hostname format/uniqueness, IP subnet/uniqueness) - Jinja2 templates for NixOS configurations - Automatic updates to flake.nix and terraform/vms.tf - Support for both static IP and DHCP configurations - Dry-run mode for safe previews - Packaged as Nix derivation and added to devShell Usage: create-host --hostname myhost --ip 10.69.13.50/24 The tool generates: - hosts/<hostname>/default.nix - hosts/<hostname>/configuration.nix - Updates flake.nix with new nixosConfigurations entry - Updates terraform/vms.tf with new VM definition All generated configurations include full system imports (monitoring, SOPS, autoupgrade, etc.) and are validated with nix flake check and tofu validate. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
55 lines
1.3 KiB
Python
55 lines
1.3 KiB
Python
"""Data models for host configuration."""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Optional
|
|
|
|
|
|
@dataclass
|
|
class HostConfig:
|
|
"""Configuration for a new NixOS host."""
|
|
|
|
hostname: str
|
|
ip: Optional[str] = None
|
|
cpu: int = 2
|
|
memory: int = 2048
|
|
disk: str = "20G"
|
|
|
|
@property
|
|
def is_static_ip(self) -> bool:
|
|
"""Check if host uses static IP configuration."""
|
|
return self.ip is not None
|
|
|
|
@property
|
|
def gateway(self) -> str:
|
|
"""Default gateway for the network."""
|
|
return "10.69.13.1"
|
|
|
|
@property
|
|
def nameservers(self) -> list[str]:
|
|
"""DNS nameservers for the network."""
|
|
return ["10.69.13.5", "10.69.13.6"]
|
|
|
|
@property
|
|
def domain(self) -> str:
|
|
"""Domain name for the network."""
|
|
return "home.2rjus.net"
|
|
|
|
@property
|
|
def state_version(self) -> str:
|
|
"""NixOS state version for new hosts."""
|
|
return "25.11"
|
|
|
|
def validate(self) -> None:
|
|
"""Validate configuration constraints."""
|
|
if not self.hostname:
|
|
raise ValueError("Hostname cannot be empty")
|
|
|
|
if self.cpu < 1:
|
|
raise ValueError("CPU cores must be at least 1")
|
|
|
|
if self.memory < 512:
|
|
raise ValueError("Memory must be at least 512 MB")
|
|
|
|
if not self.disk:
|
|
raise ValueError("Disk size cannot be empty")
|