diff --git a/debian-13-fr-vm-v2.sh b/debian-13-fr-vm-v2.sh index e69de29..f8ae4ba 100644 --- a/debian-13-fr-vm-v2.sh +++ b/debian-13-fr-vm-v2.sh @@ -0,0 +1,364 @@ +#!/usr/bin/env bash +# Debian 13 (Trixie) VM - AZYLIS preset +# - Bridge par défaut: dhcp +# - Cloud-init: activé par défaut +# - IPv4: DHCP (ipconfig0) +# - Locale/Clavier: FR robuste (kbd + console-setup + loadkeys) +# - Agent Proxmox: qemu-guest-agent +# - Resize disque: qm resize + growpart/resize_rootfs +# - Pas d'auto-start: onboot=0 + ne démarre pas la VM à la fin +# - Console noVNC plus confortable: VGA virtio + GRUB_GFXMODE 1920x1080 + +set -euo pipefail + +# ----------------------------- +# Defaults (tu peux changer ici) +# ----------------------------- +HN_DEFAULT="debian13" +BRG_DEFAULT="dhcp" +CORE_DEFAULT="2" +RAM_DEFAULT="2048" # MiB +DISK_DEFAULT="20G" # ex: 8G, 20G, 50G +START_VM_DEFAULT="no" # yes/no +ONBOOT_DEFAULT="0" # 0/1 + +# Root access via Proxmox cloud-init fields +CI_USER_DEFAULT="root" +CI_PASS_DEFAULT="root" # ATTENTION: à adapter en prod + +# Debian 13 cloud image +DEBIAN13_URL="https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2" + +# Notes/logo (Proxmox description) +AZYLIS_SITE="https://www.azylis.net" +AZYLIS_LOGO="https://www.azylis.net/favicon.ico" # si tu as une URL PNG/SVG directe du logo, remplace ici + +# ----------------------------- +# Helpers +# ----------------------------- +YW=$'\033[33m' +GN=$'\033[1;92m' +RD=$'\033[01;31m' +BL=$'\033[36m' +CL=$'\033[m' +TAB=" " + +msg_info(){ echo -e "${TAB}${YW}▶${CL} $*"; } +msg_ok(){ echo -e "${TAB}${GN}✔${CL} $*"; } +msg_err(){ echo -e "${TAB}${RD}✖${CL} $*" >&2; } + +need_cmd() { command -v "$1" >/dev/null 2>&1 || { msg_err "Commande manquante: $1"; exit 1; }; } + +get_valid_nextid() { + local try_id + try_id=$(pvesh get /cluster/nextid) + while true; do + if [ -f "/etc/pve/qemu-server/${try_id}.conf" ] || [ -f "/etc/pve/lxc/${try_id}.conf" ]; then + try_id=$((try_id + 1)); continue + fi + if lvs --noheadings -o lv_name 2>/dev/null | grep -qE "(^|[-_])${try_id}($|[-_])"; then + try_id=$((try_id + 1)); continue + fi + break + done + echo "$try_id" +} + +# ----------------------------- +# Pre-flight +# ----------------------------- +if [[ "$(id -u)" -ne 0 ]]; then + msg_err "Lance ce script en root sur le noeud Proxmox." + exit 1 +fi + +need_cmd pvesh +need_cmd pvesm +need_cmd qm +need_cmd curl +need_cmd awk +need_cmd sed + +if ! command -v whiptail >/dev/null 2>&1; then + msg_err "whiptail n'est pas installé. Installe-le: apt update && apt install -y whiptail" + exit 1 +fi + +# ----------------------------- +# UI +# ----------------------------- +VMID="$(get_valid_nextid)" +HN="$HN_DEFAULT" +BRG="$BRG_DEFAULT" +CORE_COUNT="$CORE_DEFAULT" +RAM_SIZE="$RAM_DEFAULT" +DISK_SIZE="$DISK_DEFAULT" +START_VM="$START_VM_DEFAULT" + +if ! whiptail --backtitle "AZYLIS - Proxmox" --title "Debian 13 VM" --yesno \ + "Ce script va créer une VM Debian 13 (cloud image) avec presets AZYLIS.\n\nContinuer ?" 12 70; then + msg_err "Annulé." + exit 0 +fi + +HN="$(whiptail --backtitle "AZYLIS - Proxmox" --title "Hostname" --inputbox "Hostname VM:" 8 60 "$HN" 3>&1 1>&2 2>&3 || true)" +HN="${HN:-$HN_DEFAULT}" + +BRG="$(whiptail --backtitle "AZYLIS - Proxmox" --title "Bridge" --inputbox "Bridge Proxmox (nom Linux):" 8 60 "$BRG" 3>&1 1>&2 2>&3 || true)" +BRG="${BRG:-$BRG_DEFAULT}" + +CORE_COUNT="$(whiptail --backtitle "AZYLIS - Proxmox" --title "CPU" --inputbox "vCPU:" 8 60 "$CORE_COUNT" 3>&1 1>&2 2>&3 || true)" +CORE_COUNT="${CORE_COUNT:-$CORE_DEFAULT}" + +RAM_SIZE="$(whiptail --backtitle "AZYLIS - Proxmox" --title "RAM" --inputbox "RAM (MiB):" 8 60 "$RAM_SIZE" 3>&1 1>&2 2>&3 || true)" +RAM_SIZE="${RAM_SIZE:-$RAM_DEFAULT}" + +DISK_SIZE="$(whiptail --backtitle "AZYLIS - Proxmox" --title "Disque" --inputbox "Taille disque (ex: 20G):" 8 60 "$DISK_SIZE" 3>&1 1>&2 2>&3 || true)" +DISK_SIZE="${DISK_SIZE:-$DISK_DEFAULT}" + +if whiptail --backtitle "AZYLIS - Proxmox" --title "Démarrage" --defaultno --yesno \ + "Démarrer la VM automatiquement à la fin ?" 10 70; then + START_VM="yes" +else + START_VM="no" +fi + +# ----------------------------- +# Storage selection (images) +# ----------------------------- +msg_info "Détection des stockages compatibles (content: images)" +STORAGE_MENU=() +MSG_MAX_LEN=0 + +while read -r line; do + TAG="$(awk '{print $1}' <<<"$line")" + TYPE="$(awk '{print $2}' <<<"$line")" + FREE="$(awk '{print $6}' <<<"$(pvesm status -storage "$TAG" | awk 'NR==2{print}')" 2>/dev/null || true)" + ITEM="Type: ${TYPE} Free: ${FREE:-?}" + (( ${#ITEM} > MSG_MAX_LEN )) && MSG_MAX_LEN=${#ITEM} + STORAGE_MENU+=("$TAG" "$ITEM" "OFF") +done < <(pvesm status -content images | awk 'NR>1') + +if [[ ${#STORAGE_MENU[@]} -lt 3 ]]; then + msg_err "Aucun stockage valide détecté (content images)." + exit 1 +fi + +if [[ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]]; then + STORAGE="${STORAGE_MENU[0]}" +else + STORAGE="$(whiptail --backtitle "AZYLIS - Proxmox" --title "Storage" --radiolist \ + "Choisis le stockage pour la VM:" 16 $((MSG_MAX_LEN + 30)) 6 \ + "${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3)" +fi + +msg_ok "Storage: ${BL}${STORAGE}${CL}" +msg_ok "VMID: ${BL}${VMID}${CL} | Hostname: ${BL}${HN}${CL} | Bridge: ${BL}${BRG}${CL}" + +# ----------------------------- +# Download image +# ----------------------------- +TMPDIR="$(mktemp -d)" +cleanup() { rm -rf "$TMPDIR" >/dev/null 2>&1 || true; } +trap cleanup EXIT + +cd "$TMPDIR" +FILE="$(basename "$DEBIAN13_URL")" +msg_info "Téléchargement Debian 13 cloud image: $FILE" +curl -fL -o "$FILE" "$DEBIAN13_URL" +msg_ok "Image téléchargée" + +# ----------------------------- +# Create VM +# ----------------------------- +msg_info "Création VM (sans autostart)" +qm create "$VMID" \ + -name "$HN" \ + -cores "$CORE_COUNT" \ + -memory "$RAM_SIZE" \ + -ostype l26 \ + -scsihw virtio-scsi-pci \ + -net0 "virtio,bridge=${BRG}" \ + -agent 1 \ + -onboot "$ONBOOT_DEFAULT" \ + -tablet 0 \ + -localtime 1 >/dev/null + +# Better console for noVNC +qm set "$VMID" --vga virtio >/dev/null + +# UEFI (optional, but common) +qm set "$VMID" --bios ovmf >/dev/null + +msg_ok "VM créée" + +# ----------------------------- +# Import disk +# ----------------------------- +msg_info "Import disque dans ${STORAGE}" +IMPORT_LOG="$(qm importdisk "$VMID" "$FILE" "$STORAGE" 2>&1 || true)" +IMPORT_DISK="$(awk -F"'" '/Successfully imported disk as/ {print $2}' <<<"$IMPORT_LOG" | tail -n1)" +if [[ -z "${IMPORT_DISK:-}" ]]; then + # Fallback (souvent vrai sur ZFS/LVM) + IMPORT_DISK="${STORAGE}:vm-${VMID}-disk-0" +fi + +# Attach + cloudinit drive +qm set "$VMID" \ + --scsi0 "${IMPORT_DISK},discard=on,ssd=1" \ + --scsi1 "${STORAGE}:cloudinit" \ + --boot order=scsi0 \ + --serial0 socket >/dev/null + +# Resize disk side (Proxmox) +msg_info "Resize disque virtuel à ${DISK_SIZE}" +qm resize "$VMID" scsi0 "$DISK_SIZE" >/dev/null +msg_ok "Resize Proxmox OK" + +# Cloud-init network: DHCP IPv4 +qm set "$VMID" --ipconfig0 ip=dhcp >/dev/null + +# Cloud-init root user/password (via Proxmox fields) +qm set "$VMID" --ciuser "$CI_USER_DEFAULT" --cipassword "$CI_PASS_DEFAULT" >/dev/null + +# ----------------------------- +# Cloud-init user-data (FR + guest agent + grow root + 1080p gfx) +# ----------------------------- +SNIPPET_DIR="/var/lib/vz/snippets" +mkdir -p "$SNIPPET_DIR" +USERDATA_FILE="${SNIPPET_DIR}/${VMID}-user-data.yaml" + +msg_info "Génération cloud-init user-data: ${USERDATA_FILE}" + +cat > "$USERDATA_FILE" <<'EOF' +#cloud-config +package_update: true + +# Auto-grow partition + filesystem +growpart: + mode: auto + devices: ["/"] + ignore_growroot_disabled: false +resize_rootfs: true + +packages: + - qemu-guest-agent + - cloud-guest-utils + - locales + - kbd + - console-setup + - keyboard-configuration + +locale: fr_FR.UTF-8 + +write_files: + # Console keymap FR + police petite + - path: /etc/default/console-setup + content: | + ACTIVE_CONSOLES="/dev/tty[1-6]" + CHARMAP="UTF-8" + CODESET="Lat15" + FONTFACE="Fixed" + FONTSIZE="8x16" + KEYMAP="fr" + + - path: /etc/default/keyboard + content: | + XKBLAYOUT="fr" + XKBVARIANT="" + XKBMODEL="pc105" + XKBOPTIONS="" + + # Force GRUB gfxmode 1080p (utile pour noVNC/VGA) + - path: /etc/default/grub.d/99-pve-video.cfg + content: | + GRUB_GFXMODE=1920x1080 + GRUB_GFXPAYLOAD_LINUX=keep + +runcmd: + # Locale + - sed -i 's/^# *fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/' /etc/locale.gen || true + - locale-gen fr_FR.UTF-8 || true + - update-locale LANG=fr_FR.UTF-8 || true + + # Console keymap immédiat + - loadkeys fr || true + - setupcon -k || true + + # GRUB update (pour prendre le 1080p) + - update-grub || true + + # Agent Proxmox + - systemctl enable qemu-guest-agent || true + - systemctl start qemu-guest-agent || true +EOF + +# Attach snippet to VM (requires 'local' storage with Snippets enabled) +qm set "$VMID" --cicustom "user=local:snippets/${VMID}-user-data.yaml" >/dev/null + +msg_ok "Cloud-init user-data appliqué" + +# ----------------------------- +# Proxmox Notes (Description) +# ----------------------------- +CREATED_AT="$(date -Is)" +DESCRIPTION=$( + cat < + + AZYLIS + +

AZYLIS — Debian 13 VM

+ + +Infos VM + + +Accès + + +Provisioning + + +
+Créé le ${CREATED_AT} +EOF +) +qm set "$VMID" -description "$DESCRIPTION" >/dev/null +msg_ok "Notes VM (AZYLIS) ajoutées" + +# ----------------------------- +# Finish +# ----------------------------- +msg_ok "VM Debian 13 prête: ${BL}${VMID}${CL}" + +if [[ "$START_VM" == "yes" ]]; then + msg_info "Démarrage VM..." + qm start "$VMID" >/dev/null + msg_ok "VM démarrée." +else + msg_ok "VM laissée arrêtée (comme demandé)." +fi + +echo +echo "Commandes utiles :" +echo " qm config ${VMID} | egrep 'name:|net0|ipconfig0|ciuser|cipassword|vga|scsi0|scsi1'" +echo " qm cloudinit dump ${VMID} user" +echo " qm cloudinit dump ${VMID} network" \ No newline at end of file