diff --git a/Makefile b/Makefile index 735f359..549bbe8 100644 --- a/Makefile +++ b/Makefile @@ -1,80 +1,20 @@ -# Load .env file if it exists --include .env -export - -.PHONY: help cloud-deploy cloud-status cloud-destroy usb-build usb-flash local-vm-run local-shell clean - -DOMAIN := $(or $(WORKSHOP_DOMAIN),codecrispi.es) -USB_DEVICE := /dev/sdX +.PHONY: help vm-run clean help: - @echo "🍪 CODE CRISPIES Workshop" + @echo "🍪 Workshop VM with Containers" @echo "" - @echo "Usage: make " + @echo "Commands:" + @echo " make vm-run - Start VM with participant containers" + @echo " make clean - Clean build artifacts" @echo "" - @echo "--- Local VM Development ---" - @echo " make local-vm-run - Start the complete workshop environment in a VM" - @echo "" - @echo "--- Cloud Infrastructure ---" - @echo " make deploy-cloud - Deploy VMs to Hetzner" - @echo " make status-cloud - Check the status of cloud servers" - @echo " make destroy-cloud - Destroy all cloud infrastructure" - @echo "" - @echo "--- USB Drive Creation ---" - @echo " make build-usb - Build the NixOS ISO for the workshop" - @echo " make flash-usb - Flash the ISO to a USB drive (set USB_DEVICE)" - @echo "" - @echo "--- Host Development Shell ---" - @echo " make local-shell - Enter a dev shell with terraform, etc., on your main machine" + @echo "Inside the VM:" + @echo " ssh root@192.168.100.11 # Connect to hopper container" + @echo " ssh root@192.168.100.12 # Connect to curie container" - -# --- Local Development --- -local-vm-run: - @echo "🚀 Starting local workshop environment inside a VM..." - @echo " (A new window with a desktop will open. Close it to stop the VM.)" +vm-run: + @echo "🚀 Starting workshop VM with containers..." + @echo "VM will open with desktop. Terminal shows SSH commands." nix run --impure .#local-vm -# --- Cloud Infrastructure --- -deploy-cloud: - @echo "🚀 Deploying to Hetzner Cloud..." - cd terraform && terraform init - cd terraform && terraform apply -auto-approve \ - -var="hcloud_token=${HCLOUD_TOKEN}" \ - -var="domain=${DOMAIN}" \ - -var="ssh_public_key=$$(cat ~/.ssh/id_rsa.pub)" - @echo "🔍 Running health checks..." - ./scripts/deploy.sh - @echo "✅ Cloud deployment complete and verified!" - -status-cloud: - @echo "📊 Checking server status..." - @for name in hopper curie lovelace noether hamilton franklin johnson clarke goldberg liskov wing rosen shaw karp rich; do \ - echo -n "$$name.${DOMAIN}: "; \ - if curl -s -f https://traefik.$$name.${DOMAIN}/ping >/dev/null 2>&1; then \ - echo "✅ Ready"; \ - else \ - echo "❌ Not ready"; \ - fi; \ - done - -destroy-cloud: - cd terraform && terraform destroy -auto-approve - -# --- USB Boot Drive --- -build-usb: - @echo "🔨 Building NixOS workshop ISO..." - nix build .#live-iso - @echo "✅ ISO built: result/iso/nixos.iso" - -flash-usb: build-usb - @echo "⚠️ Flashing to ${USB_DEVICE} - THIS WILL ERASE THE DEVICE!" - @read -p "Continue? [y/N]: " confirm && [ "$$confirm" = "y" ] - sudo dd if=result/iso/nixos.iso of=${USB_DEVICE} bs=4M status=progress oflag=sync - @echo "✅ USB drive ready!" - -# --- Host Development --- -local-shell: - nix develop - clean: rm -rf result .direnv diff --git a/flake.lock b/flake.lock index 14b879e..0594294 100644 --- a/flake.lock +++ b/flake.lock @@ -1,75 +1,24 @@ { "nodes": { - "nixlib": { - "locked": { - "lastModified": 1736643958, - "narHash": "sha256-tmpqTSWVRJVhpvfSN9KXBvKEXplrwKnSZNAoNPf/S/s=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "1418bc28a52126761c02dd3d89b2d8ca0f521181", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" - } - }, - "nixos-generators": { - "inputs": { - "nixlib": "nixlib", - "nixpkgs": "nixpkgs" - }, - "locked": { - "lastModified": 1751903740, - "narHash": "sha256-PeSkNMvkpEvts+9DjFiop1iT2JuBpyknmBUs0Un0a4I=", - "owner": "nix-community", - "repo": "nixos-generators", - "rev": "032decf9db65efed428afd2fa39d80f7089085eb", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixos-generators", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1736657626, - "narHash": "sha256-FWlPMUzp0lkQBdhKlPqtQdqmp+/C+1MBiEytaYfrCTY=", + "lastModified": 1754937576, + "narHash": "sha256-3sWA5WJybUE16kIMZ3+uxcxKZY/JRR4DFBqLdSLBo7w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2f9e2f85cb14a46410a1399aa9ea7ecf433e422e", + "rev": "ddae11e58c0c345bf66efbddbf2192ed0e58f896", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1754725699, - "narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", + "ref": "nixos-25.05", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { - "nixos-generators": "nixos-generators", - "nixpkgs": "nixpkgs_2" + "nixpkgs": "nixpkgs" } } }, diff --git a/flake.nix b/flake.nix index 7305b25..022e2c1 100644 --- a/flake.nix +++ b/flake.nix @@ -1,65 +1,31 @@ { - description = "CODE CRISPIES Workshop Infrastructure"; + description = "Workshop VM with Participant Containers"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - nixos-generators.url = "github:nix-community/nixos-generators"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; }; - outputs = { self, nixpkgs, nixos-generators }: + outputs = { self, nixpkgs }: let system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; - participantRange = nixpkgs.lib.range 1 2; - fullParticipantNames = [ - "hopper" "curie" "lovelace" "noether" "hamilton" - "franklin" "johnson" "clarke" "goldberg" "liskov" - "wing" "rosen" "shaw" "karp" "rich" - ]; + participantNames = [ "hopper" "curie" ]; in { packages.${system} = { - live-iso = nixos-generators.nixosGenerate { - inherit system; - format = "iso"; - modules = [ - ({ pkgs, ... }: { - system.stateVersion = "25.05"; - networking.networkmanager.enable = true; - users.users.workshop = { - isNormalUser = true; - shell = pkgs.zsh; - extraGroups = [ "wheel" ]; - password = "workshop"; - }; - services.getty.autologinUser = "workshop"; - programs.zsh.enable = true; - environment.systemPackages = with pkgs; [ openssh curl git ]; - services.xserver = { - enable = true; - displayManager.lightdm.enable = true; - desktopManager.xfce.enable = true; - }; - services.displayManager.autoLogin.enable = true; - services.displayManager.autoLogin.user = "workshop"; - }) - ]; - }; - local-vm = self.nixosConfigurations.workshop-local.config.system.build.vm; + local-vm = self.nixosConfigurations.workshop-vm.config.system.build.vm; }; - nixosConfigurations.workshop-local = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; + nixosConfigurations.workshop-vm = nixpkgs.lib.nixosSystem { + inherit system; modules = [ ({ config, pkgs, ... }: { system.stateVersion = "25.05"; + boot.loader.grub.enable = false; boot.loader.generic-extlinux-compatible.enable = true; - - # Enable IP forwarding for NAT boot.kernel.sysctl."net.ipv4.ip_forward" = 1; - # Host VM user setup users.users.workshop = { isNormalUser = true; extraGroups = [ "wheel" ]; @@ -67,75 +33,61 @@ shell = pkgs.bash; }; - # GUI setup + security.pam.services.login.allowNullPassword = true; + security.sudo.wheelNeedsPassword = false; + + # CORRECTED GUI setup services.xserver = { enable = true; desktopManager.xfce.enable = true; - displayManager.lightdm.enable = true; - }; - services.displayManager.autoLogin.enable = true; - services.displayManager.autoLogin.user = "workshop"; - - # Auto-open root terminal - services.xserver.displayManager.sessionCommands = '' - ${pkgs.xfce.xfce4-terminal}/bin/xfce4-terminal -T "Workshop Root Shell" -e "sudo -i" & - ''; - - # Workshop user convenience - programs.bash = { - shellAliases = { - connect = "sudo nixos-container login"; - containers = "sudo nixos-container list"; - root = "sudo -i"; + displayManager = { + lightdm.enable = true; + autoLogin.enable = true; + autoLogin.user = "workshop"; + sessionCommands = '' + ${pkgs.xfce.xfce4-terminal}/bin/xfce4-terminal --title="Workshop Terminal" \ + --command="bash -c 'echo \"🍪 Workshop VM Ready!\"; echo \"\"; echo \"SSH into containers:\"; echo \" ssh root@192.168.100.11 # hopper\"; echo \" ssh root@192.168.100.12 # curie\"; echo \"\"; bash'" & + ''; }; }; - + environment.systemPackages = with pkgs; [ - gnumake nano nixos-container firefox git curl jq + firefox curl git jq nano tree nixos-container ]; - security.pam.services.login.allowNullPassword = true; - security.sudo.wheelNeedsPassword = false; - networking.hostName = "workshop-vm"; - - # FIXED: Proper NAT configuration + networking = { + hostName = "workshop-vm"; + firewall.enable = false; nat = { enable = true; internalInterfaces = ["ve-+"]; externalInterface = "eth0"; - # Ensure we have masquerading - extraCommands = '' - iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth0 -j MASQUERADE - ''; - }; - firewall = { - enable = true; - trustedInterfaces = [ "ve-+" ]; - # Allow forwarding from containers - extraCommands = '' - iptables -A FORWARD -i ve-+ -j ACCEPT - iptables -A FORWARD -o ve-+ -j ACCEPT - ''; }; }; + + programs.bash.shellAliases = { + containers = "nixos-container list"; + hopper = "ssh root@192.168.100.11"; + curie = "ssh root@192.168.100.12"; + }; - # Container configurations - containers = builtins.listToAttrs (map (i: - let participant = builtins.elemAt fullParticipantNames (i - 1); + # Container configs (same as before) + containers = builtins.listToAttrs (builtins.genList (i: + let + name = builtins.elemAt participantNames i; + ip = "192.168.100.${toString (11 + i)}"; in { - name = participant; + inherit name; value = { autoStart = true; privateNetwork = true; hostAddress = "192.168.100.1"; - localAddress = "192.168.100.${toString (10 + i)}"; + localAddress = ip; + config = { system.stateVersion = "25.05"; - users.users.root = { - password = "root"; - openssh.authorizedKeys.keys = []; - }; + users.users.root.password = "root"; users.users.workshop = { isNormalUser = true; password = "workshop"; @@ -150,124 +102,51 @@ }; }; - # FIXED: Proper network configuration networking = { - hostName = participant; - nameservers = [ "8.8.8.8" "1.1.1.1" ]; - defaultGateway = { - address = "192.168.100.1"; - interface = "eth0"; - }; + hostName = name; + nameservers = [ "8.8.8.8" ]; firewall.enable = false; - useHostResolvConf = false; - # Ensure eth0 is configured properly - interfaces.eth0.ipv4.addresses = [{ - address = "192.168.100.${toString (10 + i)}"; - prefixLength = 24; - }]; }; - console.enable = true; security.sudo.wheelNeedsPassword = false; - virtualisation.docker.enable = true; + environment.systemPackages = with pkgs; [ - docker git curl jq wget gnutar gzip util-linux + docker curl git wget jq ]; - # FIXED: Better network initialization - systemd.services.container-network-setup = { - wantedBy = [ "network.target" ]; - before = [ "network-online.target" ]; + systemd.services.workshop-setup = { + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" "docker.service" ]; + wants = [ "network-online.target" ]; script = '' - # Ensure proper routing - ${pkgs.iproute2}/bin/ip route add default via 192.168.100.1 dev eth0 || true - # Set up DNS - echo "nameserver 8.8.8.8" > /etc/resolv.conf - echo "nameserver 1.1.1.1" >> /etc/resolv.conf + echo "🍪 Setting up ${name} container..." + + for i in {1..10}; do + if curl -s --max-time 5 google.com >/dev/null 2>&1; then + echo "✅ Network ready" + break + fi + echo "⏳ Waiting for network... ($i/10)" + sleep 2 + done + + ${pkgs.docker}/bin/docker swarm init --advertise-addr ${ip} || true + + echo "✅ ${name} container ready!" + echo "SSH: ssh root@${ip} (password: root)" ''; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; }; - - systemd.services.workshop-setup = { - wantedBy = [ "multi-user.target" ]; - after = [ "network-online.target" "docker.service" "container-network-setup.service" ]; - wants = [ "network-online.target" ]; - script = '' - export HOME=/root - export PATH=/run/current-system/sw/bin:$PATH - - # Wait for network with better test - echo "Testing network connectivity..." - for attempt in {1..30}; do - if ${pkgs.curl}/bin/curl -s --max-time 10 --connect-timeout 5 https://install.abra.coopcloud.tech >/dev/null 2>&1; then - echo "Network is up!" - break - fi - echo "Attempt $attempt: Waiting for network..." - sleep 2 - done - - # Docker swarm init - ${pkgs.docker}/bin/docker swarm init --advertise-addr 192.168.100.${toString (10 + i)} || true - - # Install abra - if [ ! -f /root/.local/bin/abra ]; then - echo "Installing abra..." - ${pkgs.curl}/bin/curl -fsSL https://install.abra.coopcloud.tech | ${pkgs.bash}/bin/bash - fi - - # Make abra globally available - if [ -f /root/.local/bin/abra ]; then - ln -sf /root/.local/bin/abra /usr/local/bin/abra || true - fi - - # Add server - if command -v abra >/dev/null 2>&1; then - abra server add ${participant}.local || true - fi - ''; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - StandardOutput = "journal"; - StandardError = "journal"; - }; - }; - - environment.sessionVariables = { - PATH = [ "/root/.local/bin" "$PATH" ]; - }; }; }; } - ) participantRange); - - # DNS for .local domains - services.dnsmasq = { - enable = true; - settings = { - address = builtins.concatMap (i: - let participant = builtins.elemAt fullParticipantNames (i - 1); - in [ "/${participant}.local/192.168.100.${toString (10 + i)}" ] - ) participantRange; - server = [ "8.8.8.8" "1.1.1.1" ]; - }; - }; + ) (builtins.length participantNames)); }) ]; }; - - devShells.${system}.default = pkgs.mkShell { - buildInputs = with pkgs; [ - terraform - nixos-rebuild - docker - openssh - ]; - }; }; }