From e071937cf15ab05ae18c9a368b33fe332218b380 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 10 Dec 2024 04:13:10 -0800 Subject: [PATCH] (feat): drastic improvements to automation of LXC configuration with scaffolding in place for automating VM and LXC build downloads --- .gitignore | 2 + .repo-to-text-settings.yaml | 16 +++++ config-nixos-lxc.sh | 122 ---------------------------------- configuration.nix | 64 ------------------ nix-config/configuration.nix | 42 ++++++++++++ nix-config/lxc.nix | 23 +++++++ nix-config/network.nix | 20 ++++++ nix-config/user-config.nix | 20 ++++++ nix-config/users.nix | 18 +++++ scripts/create.sh | 2 + scripts/get-latest.sh | 25 +++++++ scripts/list-lxcs.sh | 49 ++++++++++++++ scripts/mount-nixos-config.sh | 39 +++++++++++ scripts/post-deploy.sh | 10 +++ scripts/rebuild-nixos.sh | 17 +++++ scripts/setup-lxc-terminal.sh | 37 +++++++++++ setup.sh | 65 ++++++++++++++++++ 17 files changed, 385 insertions(+), 186 deletions(-) create mode 100644 .gitignore create mode 100644 .repo-to-text-settings.yaml delete mode 100644 config-nixos-lxc.sh delete mode 100644 configuration.nix create mode 100644 nix-config/configuration.nix create mode 100644 nix-config/lxc.nix create mode 100644 nix-config/network.nix create mode 100644 nix-config/user-config.nix create mode 100644 nix-config/users.nix create mode 100644 scripts/create.sh create mode 100644 scripts/get-latest.sh create mode 100644 scripts/list-lxcs.sh create mode 100644 scripts/mount-nixos-config.sh create mode 100644 scripts/post-deploy.sh create mode 100644 scripts/rebuild-nixos.sh create mode 100644 scripts/setup-lxc-terminal.sh create mode 100755 setup.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b98c350 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +repo-to* +build/ diff --git a/.repo-to-text-settings.yaml b/.repo-to-text-settings.yaml new file mode 100644 index 0000000..ec769d9 --- /dev/null +++ b/.repo-to-text-settings.yaml @@ -0,0 +1,16 @@ +# Details: https://github.com/kirill-markin/repo-to-text +# Syntax: gitignore rules + +# Ignore files and directories for all sections from gitignore file +# Default: True +gitignore-import-and-ignore: True + +# Ignore files and directories for tree +# and "Contents of ..." sections +ignore-tree-and-content: + - ".repo-to-text-settings.yaml" + +# Ignore files and directories for "Contents of ..." section +ignore-content: + - "README.md" + - "LICENSE" diff --git a/config-nixos-lxc.sh b/config-nixos-lxc.sh deleted file mode 100644 index 6f8c2a0..0000000 --- a/config-nixos-lxc.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash - -set -e - -# Function to display usage -usage() { - echo "Usage: $0 --ssh-key --ip --gateway --user " - echo " : ID of the container (100-999)" - echo " --ssh-key: SSH public key for the user" - echo " --ip: IP address for the container" - echo " --gateway: Gateway IP address" - echo " --user: Username for the admin user (default: admin)" - exit 1 -} - -# Function to validate IP address format -validate_ip() { - if [[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then - return 0 - fi - return 1 -} - -# Parse command-line arguments -CTID=$1 -shift - -while [[ $# -gt 0 ]]; do - case $1 in - --ssh-key) SSH_KEY="$2"; shift 2 ;; - --ip) IP_ADDRESS="$2"; shift 2 ;; - --gateway) GATEWAY="$2"; shift 2 ;; - --user) USERNAME="$2"; shift 2 ;; - *) echo "Unknown option: $1"; usage ;; - esac -done - -# Validate inputs -[[ ! $CTID =~ ^[1-9][0-9]{2}$ ]] && { echo "Error: Invalid container ID"; usage; } -[[ -z $SSH_KEY ]] && { echo "Error: SSH key is required"; usage; } -[[ -z $IP_ADDRESS ]] && { echo "Error: IP address is required"; usage; } -[[ -z $GATEWAY ]] && { echo "Error: Gateway is required"; usage; } -validate_ip "$IP_ADDRESS" || { echo "Error: Invalid IP address"; usage; } -validate_ip "$GATEWAY" || { echo "Error: Invalid gateway"; usage; } -USERNAME=${USERNAME:-admin} - -# Function to generate NixOS configuration -generate_nixos_config() { - cat << EOF -{ modulesPath, config, pkgs, ... }: -{ - imports = [ "\${modulesPath}/virtualisation/lxc-container.nix" ]; - boot.isContainer = true; - - systemd.suppressedSystemUnits = [ - "dev-mqueue.mount" - "sys-kernel-debug.mount" - "sys-fs-fuse-connections.mount" - ]; - - environment.systemPackages = with pkgs; [ openssh binutils man git ]; - - users.users.${USERNAME} = { - isNormalUser = true; - extraGroups = [ "wheel" ]; - openssh.authorizedKeys.keys = [ "${SSH_KEY}" ]; - }; - - security.sudo.wheelNeedsPassword = false; - - programs.nix-ld.enable = true; - - services.openssh = { - enable = true; - settings = { - AllowUsers = ["${USERNAME}"]; - PasswordAuthentication = false; - PermitRootLogin = "no"; - }; - }; - - networking = { - dhcpcd.enable = false; - useDHCP = false; - useHostResolvConf = false; - defaultGateway = "${GATEWAY}"; - nameservers = [ "8.8.8.8" "8.8.4.4" ]; - interfaces.eth0.ipv4.addresses = [{ - address = "${IP_ADDRESS}"; - prefixLength = 24; - }]; - }; - - system.stateVersion = "24.05"; -} -EOF -} - -# Main execution -if ! pct status "$CTID" >/dev/null 2>&1; then - echo "Error: Container $CTID does not exist" - exit 1 -fi - -CONFIG_CONTENT=$(generate_nixos_config) - -pct start ${CTID} -sleep 10 - -pct enter ${CTID} << EOF -/run/current-system/sw/bin/bash << 'INNEREOF' -export PATH=/run/current-system/sw/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:\$PATH -source /etc/profile -mkdir -p /etc/nixos -cat > /etc/nixos/configuration.nix << 'CONFIGEOF' -${CONFIG_CONTENT} -CONFIGEOF -nixos-rebuild switch -INNEREOF -EOF - -echo "Configuration applied successfully!" \ No newline at end of file diff --git a/configuration.nix b/configuration.nix deleted file mode 100644 index e6b15d3..0000000 --- a/configuration.nix +++ /dev/null @@ -1,64 +0,0 @@ -{ modulesPath, config, pkgs, ... }: - -{ - imports = - [ - # Default path for lxc/lxd configuration - "${modulesPath}/virtualisation/lxc-container.nix" - ]; - boot.isContainer = true; - - systemd.suppressedSystemUnits = [ - "dev-mqueue.mount" - "sys-kernel-debug.mount" - "sys-fs-fuse-connections.mount" - ]; - - # Essential packages - environment.systemPackages = with pkgs; [ - openssh - binutils - man - git - ]; - - # Administrative sudo user - users.users.admin = { - isNormalUser = true; - extraGroups = [ "wheel" ]; # wheel group is sudo access - }; - - security.sudo.wheelNeedsPassword = true; - - # Facilitates access via VS Code Remote Explorer - programs.nix-ld.enable = true; - - # Enable password-based SSH login for admin user - services.openssh = { - enable = true; - settings = { - AllowUsers = ["admin"]; # everyone - PasswordAuthentication = true; - PermitRootLogin = "no"; - }; - }; - - networking = { - dhcpcd.enable = false; - useDHCP = false; - useHostResolvConf = false; - }; - - systemd.network = { - enable = true; - networks."50-eth0" = { - matchConfig.Name = "eth0"; - networkConfig = { - DHCP = "ipv4"; - IPv6AcceptRA = true; - }; - linkConfig.RequiredForOnline = "routable"; - }; - }; - system.stateVersion = "24.05"; # Did you read the comment? -} \ No newline at end of file diff --git a/nix-config/configuration.nix b/nix-config/configuration.nix new file mode 100644 index 0000000..e7dccc7 --- /dev/null +++ b/nix-config/configuration.nix @@ -0,0 +1,42 @@ +{ modulesPath, config, pkgs, ... }: +{ + imports = [ + ./lxc.nix + ./users.nix + ./network.nix + ]; + + # Nix settings + nix = { + settings = { + auto-optimise-store = true; + experimental-features = [ "nix-command" "flakes" ]; + allowed-users = [ "@wheel" ]; + }; + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; + }; + + # Allow unfree packages + nixpkgs.config.allowUnfree = true; + + # Set NIX_PATH + nix.nixPath = [ + "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos" + "nixos-config=/etc/nixos/configuration.nix" + "/nix/var/nix/profiles/per-user/root/channels" + ]; + + # Auto upgrades + system.autoUpgrade = { + enable = true; + dates = "04:00"; + randomizedDelaySec = "45min"; + persistent = true; + }; + + system.stateVersion = "24.05"; +} \ No newline at end of file diff --git a/nix-config/lxc.nix b/nix-config/lxc.nix new file mode 100644 index 0000000..ce40b59 --- /dev/null +++ b/nix-config/lxc.nix @@ -0,0 +1,23 @@ +{ modulesPath, config, pkgs, ... }: +{ + imports = [ + "${modulesPath}/virtualisation/lxc-container.nix" + ]; + + boot.isContainer = true; + + systemd.suppressedSystemUnits = [ + "dev-mqueue.mount" + "sys-kernel-debug.mount" + "sys-fs-fuse-connections.mount" + ]; + + environment.systemPackages = with pkgs; [ + openssh + binutils + man + git + ]; + + programs.nix-ld.enable = true; +} \ No newline at end of file diff --git a/nix-config/network.nix b/nix-config/network.nix new file mode 100644 index 0000000..aadc5fd --- /dev/null +++ b/nix-config/network.nix @@ -0,0 +1,20 @@ +{ config, pkgs, ... }: +{ + networking = { + dhcpcd.enable = false; + useDHCP = false; + useHostResolvConf = false; + }; + + systemd.network = { + enable = true; + networks."50-eth0" = { + matchConfig.Name = "eth0"; + networkConfig = { + DHCP = "ipv4"; + IPv6AcceptRA = true; + }; + linkConfig.RequiredForOnline = "routable"; + }; + }; +} \ No newline at end of file diff --git a/nix-config/user-config.nix b/nix-config/user-config.nix new file mode 100644 index 0000000..ae38869 --- /dev/null +++ b/nix-config/user-config.nix @@ -0,0 +1,20 @@ +{ modulesPath, config, pkgs, ... }: + +{ + # Administrative sudo user + users.users.admin = { + isNormalUser = true; + extraGroups = [ "wheel" ]; # wheel group is sudo access + }; + + # Enable password-based SSH login for admin user + services.openssh = { + enable = true; + settings = { + AllowUsers = ["admin"]; # everyone + PasswordAuthentication = true; + PermitRootLogin = "no"; + }; + }; + +} \ No newline at end of file diff --git a/nix-config/users.nix b/nix-config/users.nix new file mode 100644 index 0000000..d832aa3 --- /dev/null +++ b/nix-config/users.nix @@ -0,0 +1,18 @@ +{ config, pkgs, ... }: +{ + users.users.nixos = { + isNormalUser = true; + extraGroups = [ "wheel" ]; + }; + + security.sudo.wheelNeedsPassword = true; + + services.openssh = { + enable = true; + settings = { + AllowUsers = ["nixos"]; + PasswordAuthentication = true; + PermitRootLogin = "no"; + }; + }; +} \ No newline at end of file diff --git a/scripts/create.sh b/scripts/create.sh new file mode 100644 index 0000000..1a2ff8b --- /dev/null +++ b/scripts/create.sh @@ -0,0 +1,2 @@ +TODO: Deploy lxc using user defined variables +TODO: Deploy vm using user defined variables \ No newline at end of file diff --git a/scripts/get-latest.sh b/scripts/get-latest.sh new file mode 100644 index 0000000..2c1c151 --- /dev/null +++ b/scripts/get-latest.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +IMAGE_TYPE="$1" +BASE_URL="https://hydra.nixos.org/job/nixos/release-24.11/nixos" +DOWNLOAD_DIR="./build" + +if [ "$IMAGE_TYPE" = "VM" ]; then + DOWNLOAD_URL="${BASE_URL}.proxmoxImage.x86_64-linux/latest/download/1" + OUTPUT_FILE="${DOWNLOAD_DIR}/nixos_proxmox_vm.vma.zst" +elif [ "$IMAGE_TYPE" = "LXC" ]; then + DOWNLOAD_URL="${BASE_URL}.proxmoxLXC.x86_64-linux/latest/download/1" + OUTPUT_FILE="${DOWNLOAD_DIR}/nixos_proxmox_lxc.tar.xz" +else + echo "Error: Invalid image type. Must be 'VM' or 'LXC'" >&2 + exit 1 +fi + +wget -q --show-progress -O "$OUTPUT_FILE" "$DOWNLOAD_URL" +EXIT_CODE=$? + +if [ $EXIT_CODE -ne 0 ]; then + echo "Error: Download failed" >&2 + rm -f "$OUTPUT_FILE" + exit $EXIT_CODE +fi \ No newline at end of file diff --git a/scripts/list-lxcs.sh b/scripts/list-lxcs.sh new file mode 100644 index 0000000..5bd0616 --- /dev/null +++ b/scripts/list-lxcs.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# ANSI color codes +BLUE='\033[0;34m' +RED='\033[0;31m' +NC='\033[0m' + +# Array to store valid CTIDs +declare -a valid_ctids + +echo -e "${BLUE}Available NixOS Containers:${NC}" +printf "%-8s %s\n" "VMID" "Name" +echo "----------------" + +# Populate the list and store valid CTIDs +for conf in /etc/pve/lxc/*.conf; do + if grep -q "^ostype: nixos" "$conf"; then + vmid=$(basename "$conf" .conf) + name=$(grep "^hostname:" "$conf" | cut -d' ' -f2) + printf "%-8s %s\n" "$vmid" "$name" + valid_ctids+=("$vmid") + fi +done + +if [ ${#valid_ctids[@]} -eq 0 ]; then + echo -e "${RED}No NixOS containers found!${NC}" >&2 + exit 1 +fi + +# Ask for user input +echo -e "\nEnter the CTID of the container you want to configure:" +read -r selected_ctid + +# Validate input +valid=0 +for ctid in "${valid_ctids[@]}"; do + if [ "$ctid" = "$selected_ctid" ]; then + valid=1 + break + fi +done + +if [ $valid -eq 0 ]; then + echo -e "${RED}Error: Invalid CTID selected!${NC}" >&2 + exit 1 +fi + +# Output the selected CTID for use in other scripts +echo "$selected_ctid" \ No newline at end of file diff --git a/scripts/mount-nixos-config.sh b/scripts/mount-nixos-config.sh new file mode 100644 index 0000000..eba429e --- /dev/null +++ b/scripts/mount-nixos-config.sh @@ -0,0 +1,39 @@ +#!/bin/bash +set -e + +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +CTID="$1" +CONFIG_FILE="/etc/pve/lxc/${CTID}.conf" +MOUNT_POINT="/root/nixos-config-${CTID}" +NIX_CONFIG_DIR="./nix-config" + +if [ ! -d "$NIX_CONFIG_DIR" ]; then + echo "Error: nix-config directory not found" + exit 1 +fi + +# Parse container config and mount +echo "Parsing container configuration..." +ROOTFS_LINE=$(grep "^rootfs:" "$CONFIG_FILE") +VOLUME_NAME=$(echo "$ROOTFS_LINE" | sed 's/rootfs: local-lvm:\([^,]*\).*/\1/') +DEVICE_PATH="/dev/pve/${VOLUME_NAME}" + +echo "Creating mount point..." +mkdir -p "$MOUNT_POINT" + +echo "Mounting container filesystem..." +mount "$DEVICE_PATH" "$MOUNT_POINT" + +echo "Copying NixOS configuration..." +mkdir -p "${MOUNT_POINT}/etc/nixos" +cp -r ${NIX_CONFIG_DIR}/* "${MOUNT_POINT}/etc/nixos/" + +echo "Unmounting container filesystem..." +umount "$MOUNT_POINT" +rmdir "$MOUNT_POINT" + +echo "Configuration files copied successfully" \ No newline at end of file diff --git a/scripts/post-deploy.sh b/scripts/post-deploy.sh new file mode 100644 index 0000000..10f313b --- /dev/null +++ b/scripts/post-deploy.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# ANSI color codes +GREEN='\033[0;32m' +NC='\033[0m' # No Color + +# Get primary IP address (excluding docker/vm interfaces) +IP_ADDRESS=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '^127\.' | head -n 1) + +echo -e "${HOSTNAME} is now deployed at ${GREEN}${IP_ADDRESS}${NC}" \ No newline at end of file diff --git a/scripts/rebuild-nixos.sh b/scripts/rebuild-nixos.sh new file mode 100644 index 0000000..18ffa9f --- /dev/null +++ b/scripts/rebuild-nixos.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +CTID="$1" + +echo "Updating channels..." +pct exec ${CTID} -- nix-channel --update + +echo "Rebuilding NixOS configuration..." +pct exec ${CTID} -- nixos-rebuild switch -I nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos -I nixos-config=/etc/nixos/configuration.nix + +echo "NixOS rebuild completed successfully" \ No newline at end of file diff --git a/scripts/setup-lxc-terminal.sh b/scripts/setup-lxc-terminal.sh new file mode 100644 index 0000000..7a0ec90 --- /dev/null +++ b/scripts/setup-lxc-terminal.sh @@ -0,0 +1,37 @@ +#!/bin/bash +set -e + +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +CTID="$1" + +# Function to add or update line in config file +update_config_line() { + local file="$1" + local search="$2" + local replace="$3" + + if [ -f "$file" ]; then + if ! grep -q "^${search}" "$file"; then + echo "${replace}" >> "$file" + else + sed -i "s|^${search}.*|${replace}|" "$file" + fi + fi +} + +# Update Proxmox LXC config +PVE_CONFIG="/etc/pve/lxc/${CTID}.conf" +update_config_line "$PVE_CONFIG" "lxc.init_cmd:" "lxc.init_cmd: /run/current-system/sw/bin/bash" +update_config_line "$PVE_CONFIG" "cmode:" "cmode: shell" + +# Update LXC system config +LXC_CONFIG="/var/lib/lxc/${CTID}/config" +update_config_line "$LXC_CONFIG" "lxc.init.cmd" "lxc.init.cmd = /run/current-system/sw/bin/bash" +update_config_line "$LXC_CONFIG" "lxc.environment = TERM" "lxc.environment = TERM=linux" +update_config_line "$LXC_CONFIG" "lxc.environment = PATH" "lxc.environment = PATH=/run/current-system/sw/bin" + +echo "LXC terminal configuration updated successfully" \ No newline at end of file diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..e5168fd --- /dev/null +++ b/setup.sh @@ -0,0 +1,65 @@ +#!/bin/bash +set -e + +# ANSI color codes +BLUE='\033[0;34m' +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' + +# Check if running as root +if [ "$(id -u)" -ne 0 ]; then + echo -e "${RED}This script must be run as root${NC}" + exit 1 +fi + +# Check and install git if needed +if ! command -v git >/dev/null 2>&1; then + echo "Installing git..." + nix-env -i git +fi + +REPO_DIR="/root/.nixos-utils" + +# Clone or update repository +if [ -d "$REPO_DIR" ]; then + echo "Updating existing repository..." + cd "$REPO_DIR" + git pull +else + echo "Cloning repository..." + git clone https://git.jeirslab.xyz/jeirmeister/NixOS-PVE-LXC.git "$REPO_DIR" + cd "$REPO_DIR" +fi + +# Make scripts executable +echo "Making scripts executable..." +find ./scripts -name "*.sh" -execdir chmod u+x {} + + +# Get CTID from list-lxcs.sh +echo -e "${BLUE}Detecting NixOS containers...${NC}" +CTID=$(./scripts/list-lxcs.sh) + +if [ -z "$CTID" ]; then + echo -e "${RED}No container ID was selected${NC}" + exit 1 +fi + +echo -e "${GREEN}Selected container: $CTID${NC}" + +# Execute configuration steps in sequence +echo -e "\nConfiguring NixOS container $CTID..." + +echo "Step 1: Setting up LXC terminal..." +./scripts/setup-lxc-terminal.sh "$CTID" + +echo "Step 2: Mounting and copying NixOS configuration..." +./scripts/mount-nixos-config.sh "$CTID" + +echo "Step 3: Rebuilding NixOS configuration..." +./scripts/rebuild-nixos.sh "$CTID" + +echo "Step 4: Running post-deployment tasks..." +./scripts/post-deploy.sh + +echo -e "${GREEN}NixOS container $CTID has been configured successfully!${NC}" \ No newline at end of file