feat: adicionar drbit-new-client.sh (espelho do repo Dashboard)
This commit is contained in:
commit
ea90025ff8
1 changed files with 271 additions and 0 deletions
271
drbit-new-client.sh
Executable file
271
drbit-new-client.sh
Executable file
|
|
@ -0,0 +1,271 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# drbit-new-client.sh — provisiona uma VM nova para um cliente DRBIT
|
||||||
|
#
|
||||||
|
# Roda no shell do HOST PROXMOX. Não depende de nenhuma VM/template
|
||||||
|
# pré-existente: baixa a imagem cloud oficial do Ubuntu 24.04, cria a VM
|
||||||
|
# do zero (qm create + qm importdisk) e anexa um drive de cloud-init que,
|
||||||
|
# no primeiro boot, clona o repo da intranet e roda install.sh.
|
||||||
|
#
|
||||||
|
# Ver wiki/projetos/intranet/provisionamento-novo-cliente.md para o
|
||||||
|
# contexto arquitetural completo.
|
||||||
|
#
|
||||||
|
# Uso:
|
||||||
|
# ./drbit-new-client.sh --nome ecp [--ip 192.168.1.80 --gw 192.168.1.1] [opções]
|
||||||
|
#
|
||||||
|
# Por padrão a VM sobe com DHCP (igual ao modelo community-scripts — fica a
|
||||||
|
# critério de quem provisiona definir IP fixo depois). Se --ip for informado,
|
||||||
|
# a VM já sobe com IP estático.
|
||||||
|
#
|
||||||
|
# ⚠️ Para clientes que vão virar Domínio AD (Samba 4 AD DC), o IP PRECISA
|
||||||
|
# ser fixo — defina --ip/--gw aqui, ou configure manualmente depois via
|
||||||
|
# netplan (ver wiki/infraestrutura/template-vm.md) antes do Setup Wizard
|
||||||
|
# provisionar o AD.
|
||||||
|
#
|
||||||
|
# Opções:
|
||||||
|
# --nome <slug> obrigatório — vira hostname srv-<slug> e nome da VM
|
||||||
|
# --ip <ip> opcional — IP estático da VM (ex: 192.168.1.80). Sem isso, usa DHCP
|
||||||
|
# --gw <gateway> default: 192.168.1.1 (só usado com --ip)
|
||||||
|
# --vmid <id> default: próximo livre (pvesh get /cluster/nextid)
|
||||||
|
# --cores <n> default: 2
|
||||||
|
# --ram <mb> default: 2048
|
||||||
|
# --disk <gb> default: 32
|
||||||
|
# --bridge <nome> default: vmbr0
|
||||||
|
# --storage <nome> default: local-lvm
|
||||||
|
# --ssh-key <path> default: ~/.ssh/id_drbit_lab.pub
|
||||||
|
# --repo-url <url> default: https://git.drbit.tec.br/drbit/Dashboard.git
|
||||||
|
# Repo privado — passe a URL com o token de provisionamento
|
||||||
|
# embutido (usuário drbit-provisioning, token read-only):
|
||||||
|
# https://drbit-provisioning:<token>@git.drbit.tec.br/drbit/Dashboard.git
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ── defaults ──────────────────────────────────────────────────────────────
|
||||||
|
GW="192.168.1.1"
|
||||||
|
VMID=""
|
||||||
|
CORES=2
|
||||||
|
RAM=2048
|
||||||
|
DISK=32
|
||||||
|
BRIDGE="vmbr0"
|
||||||
|
STORAGE="local-lvm"
|
||||||
|
SSH_KEY_FILE="$HOME/.ssh/id_drbit_lab.pub"
|
||||||
|
|
||||||
|
UBUNTU_RELEASE="noble"
|
||||||
|
IMG_URL="https://cloud-images.ubuntu.com/releases/${UBUNTU_RELEASE}/release/ubuntu-24.04-server-cloudimg-amd64.img"
|
||||||
|
IMG_CACHE="/var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img"
|
||||||
|
REPO_URL="https://git.drbit.tec.br/drbit/Dashboard.git"
|
||||||
|
|
||||||
|
NOME=""
|
||||||
|
IP=""
|
||||||
|
|
||||||
|
# ── helpers ───────────────────────────────────────────────────────────────
|
||||||
|
msg_info() { echo -e " \033[1;34m➜\033[0m $*"; }
|
||||||
|
msg_ok() { echo -e " \033[1;32m✓\033[0m $*"; }
|
||||||
|
msg_error() { echo -e " \033[1;31m✗\033[0m $*" >&2; }
|
||||||
|
|
||||||
|
# ── parse args ────────────────────────────────────────────────────────────
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--nome) NOME="$2"; shift 2 ;;
|
||||||
|
--ip) IP="$2"; shift 2 ;;
|
||||||
|
--gw) GW="$2"; shift 2 ;;
|
||||||
|
--vmid) VMID="$2"; shift 2 ;;
|
||||||
|
--cores) CORES="$2"; shift 2 ;;
|
||||||
|
--ram) RAM="$2"; shift 2 ;;
|
||||||
|
--disk) DISK="$2"; shift 2 ;;
|
||||||
|
--bridge) BRIDGE="$2"; shift 2 ;;
|
||||||
|
--storage) STORAGE="$2"; shift 2 ;;
|
||||||
|
--ssh-key) SSH_KEY_FILE="$2"; shift 2 ;;
|
||||||
|
--repo-url) REPO_URL="$2"; shift 2 ;;
|
||||||
|
*) msg_error "Argumento desconhecido: $1"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# ── validações ────────────────────────────────────────────────────────────
|
||||||
|
if [[ -z "$NOME" ]]; then
|
||||||
|
msg_error "Uso: $0 --nome <slug> [--ip <ip> --gw <gateway>] [opções]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v qm &>/dev/null; then
|
||||||
|
msg_error "Comando 'qm' não encontrado — este script roda no host Proxmox."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$SSH_KEY_FILE" ]]; then
|
||||||
|
msg_error "Chave pública SSH não encontrada em: $SSH_KEY_FILE (use --ssh-key)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
HOSTNAME="srv-${NOME}"
|
||||||
|
|
||||||
|
if [[ -z "$VMID" ]]; then
|
||||||
|
VMID=$(pvesh get /cluster/nextid)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$IP" ]]; then
|
||||||
|
msg_info "Provisionando VM '$HOSTNAME' (VMID $VMID, IP estático $IP)"
|
||||||
|
else
|
||||||
|
msg_info "Provisionando VM '$HOSTNAME' (VMID $VMID, IP via DHCP)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 1. cache da imagem cloud oficial ─────────────────────────────────────
|
||||||
|
if [[ -f "$IMG_CACHE" ]]; then
|
||||||
|
msg_ok "Imagem Ubuntu 24.04 cloud já em cache: $IMG_CACHE"
|
||||||
|
else
|
||||||
|
msg_info "Baixando imagem Ubuntu 24.04 cloud (cloud-images.ubuntu.com)..."
|
||||||
|
mkdir -p "$(dirname "$IMG_CACHE")"
|
||||||
|
curl -fsSL -o "$IMG_CACHE" "$IMG_URL"
|
||||||
|
msg_ok "Imagem baixada: $IMG_CACHE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 2. garantir que a storage 'local' suporta snippets ───────────────────
|
||||||
|
CONTENT=$(awk '/^dir: local$/{f=1; next} f && /^\tcontent/ {print $2; exit} /^[a-z]/{f=0}' /etc/pve/storage.cfg)
|
||||||
|
if [[ "$CONTENT" != *snippets* ]]; then
|
||||||
|
msg_info "Habilitando 'snippets' na storage local..."
|
||||||
|
pvesm set local --content "${CONTENT},snippets"
|
||||||
|
msg_ok "Storage 'local' agora aceita snippets"
|
||||||
|
else
|
||||||
|
msg_ok "Storage 'local' já aceita snippets"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 3. gerar cloud-init user-data ────────────────────────────────────────
|
||||||
|
SSH_PUBKEY=$(cat "$SSH_KEY_FILE")
|
||||||
|
SNIPPET_PATH="/var/lib/vz/snippets/drbit-${VMID}.yaml"
|
||||||
|
mkdir -p /var/lib/vz/snippets
|
||||||
|
|
||||||
|
msg_info "Gerando cloud-init user-data ($SNIPPET_PATH)..."
|
||||||
|
cat > "$SNIPPET_PATH" <<EOF
|
||||||
|
#cloud-config
|
||||||
|
hostname: ${HOSTNAME}
|
||||||
|
manage_etc_hosts: true
|
||||||
|
users:
|
||||||
|
- name: drbit
|
||||||
|
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||||
|
shell: /bin/bash
|
||||||
|
ssh_authorized_keys:
|
||||||
|
- ${SSH_PUBKEY}
|
||||||
|
chpasswd:
|
||||||
|
list: |
|
||||||
|
drbit:b1tadmin
|
||||||
|
expire: false
|
||||||
|
package_update: true
|
||||||
|
packages:
|
||||||
|
- git
|
||||||
|
runcmd:
|
||||||
|
- until getent hosts git.drbit.tec.br >/dev/null 2>&1; do sleep 5; done
|
||||||
|
- git clone ${REPO_URL} /opt/drbit-intranet
|
||||||
|
- bash /opt/drbit-intranet/install.sh
|
||||||
|
EOF
|
||||||
|
msg_ok "user-data gerado"
|
||||||
|
|
||||||
|
# ── 4. criar VM ───────────────────────────────────────────────────────────
|
||||||
|
msg_info "Criando VM $VMID..."
|
||||||
|
qm create "$VMID" \
|
||||||
|
-name "$HOSTNAME" \
|
||||||
|
-memory "$RAM" \
|
||||||
|
-cores "$CORES" \
|
||||||
|
-net0 "virtio,bridge=${BRIDGE}" \
|
||||||
|
-ostype l26 \
|
||||||
|
-scsihw virtio-scsi-pci \
|
||||||
|
-agent 1
|
||||||
|
msg_ok "VM criada"
|
||||||
|
|
||||||
|
# ── 5. importar disco ────────────────────────────────────────────────────
|
||||||
|
msg_info "Importando imagem como disco..."
|
||||||
|
qm importdisk "$VMID" "$IMG_CACHE" "$STORAGE"
|
||||||
|
|
||||||
|
# o disco importado fica como "unused0" na config da VM
|
||||||
|
DISK_REF=$(qm config "$VMID" | grep -oP '^unused0:\s*\K.*')
|
||||||
|
if [[ -z "$DISK_REF" ]]; then
|
||||||
|
msg_error "Não foi possível identificar o disco importado (unused0 não encontrado)."
|
||||||
|
qm config "$VMID"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Anexando disco ($DISK_REF)..."
|
||||||
|
qm set "$VMID" -scsi0 "$DISK_REF"
|
||||||
|
msg_ok "Disco anexado"
|
||||||
|
|
||||||
|
msg_info "Redimensionando disco para ${DISK}G..."
|
||||||
|
qm resize "$VMID" scsi0 "${DISK}G"
|
||||||
|
msg_ok "Disco redimensionado (cloud-init faz growpart/resizefs no primeiro boot)"
|
||||||
|
|
||||||
|
# ── 6. cloud-init drive + boot + rede ────────────────────────────────────
|
||||||
|
if [[ -n "$IP" ]]; then
|
||||||
|
IPCONFIG="ip=${IP}/24,gw=${GW}"
|
||||||
|
msg_info "Configurando cloud-init e rede (IP estático ${IP}/24, gw ${GW})..."
|
||||||
|
else
|
||||||
|
IPCONFIG="ip=dhcp"
|
||||||
|
msg_info "Configurando cloud-init e rede (DHCP)..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
qm set "$VMID" \
|
||||||
|
-ide2 "${STORAGE}:cloudinit" \
|
||||||
|
-boot order=scsi0 \
|
||||||
|
-serial0 socket -vga serial0 \
|
||||||
|
-ipconfig0 "$IPCONFIG" \
|
||||||
|
-nameserver "1.1.1.1 8.8.8.8" \
|
||||||
|
-cicustom "user=local:snippets/drbit-${VMID}.yaml"
|
||||||
|
msg_ok "Cloud-init configurado"
|
||||||
|
|
||||||
|
# ── 7. iniciar ────────────────────────────────────────────────────────────
|
||||||
|
msg_info "Iniciando VM..."
|
||||||
|
qm start "$VMID"
|
||||||
|
msg_ok "VM iniciada"
|
||||||
|
|
||||||
|
# ── 8. descobrir IP (DHCP) e aguardar Setup Wizard responder ─────────────
|
||||||
|
FINAL_IP="$IP"
|
||||||
|
|
||||||
|
if [[ -z "$FINAL_IP" ]]; then
|
||||||
|
msg_info "Aguardando guest agent informar o IP (DHCP, até 5min)..."
|
||||||
|
DEADLINE=$((SECONDS + 300))
|
||||||
|
while (( SECONDS < DEADLINE )); do
|
||||||
|
FINAL_IP=$(qm guest cmd "$VMID" network-get-interfaces 2>/dev/null \
|
||||||
|
| grep -oP '"ip-address"\s*:\s*"\K[0-9.]+' \
|
||||||
|
| grep -vE '^(127\.|169\.254\.)' \
|
||||||
|
| head -1 || true)
|
||||||
|
[[ -n "$FINAL_IP" ]] && break
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "$FINAL_IP" ]]; then
|
||||||
|
msg_error "Não foi possível descobrir o IP via guest agent. Verifique com: qm guest cmd $VMID network-get-interfaces"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
msg_ok "IP detectado via DHCP: $FINAL_IP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Aguardando o Setup Wizard subir em http://${FINAL_IP}/setup (até 10min)..."
|
||||||
|
DEADLINE=$((SECONDS + 600))
|
||||||
|
while (( SECONDS < DEADLINE )); do
|
||||||
|
if curl -sf -o /dev/null "http://${FINAL_IP}/setup"; then
|
||||||
|
msg_ok "Setup Wizard respondendo!"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! curl -sf -o /dev/null "http://${FINAL_IP}/setup"; then
|
||||||
|
msg_error "Timeout aguardando o Setup Wizard. Verifique a VM (qm terminal $VMID) e o cloud-init (/var/log/cloud-init-output.log)."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 9. resumo ─────────────────────────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "──────────────────────────────────────────"
|
||||||
|
echo " VM $VMID ($HOSTNAME) pronta!"
|
||||||
|
echo ""
|
||||||
|
echo " Acesse o Setup Wizard:"
|
||||||
|
echo " http://${FINAL_IP}/setup"
|
||||||
|
echo ""
|
||||||
|
echo " SSH: ssh drbit@${FINAL_IP} (chave $SSH_KEY_FILE ou senha b1tadmin)"
|
||||||
|
echo " ⚠️ Trocar a senha padrão 'b1tadmin' em produção."
|
||||||
|
if [[ -z "$IP" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo " ⚠️ IP via DHCP ($FINAL_IP). Para Domínio AD (Samba 4 AD DC), defina"
|
||||||
|
echo " IP fixo antes de provisionar o AD pelo Setup Wizard:"
|
||||||
|
echo " editar /etc/netplan/50-cloud-init.yaml (ou criar 99-static.yaml)"
|
||||||
|
echo " → sudo netplan apply"
|
||||||
|
fi
|
||||||
|
echo "──────────────────────────────────────────"
|
||||||
Loading…
Add table
Reference in a new issue