Files
ubuntu-bare-metal/scripts/configure-static-dual-nic.sh
tomasz-syn-grzegorza 359afb3a59 Initial import: bare-metal stacks, Server UI, GPU fan, tutorials.
Infrastructure configs for GMKtec K11 (Docker, vLLM, LocalAI, ComfyUI,
control-plane, gpu-fan agent, Server UI with CLI/file explorer/GPU fan curve).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 12:02:04 +00:00

422 lines
11 KiB
Bash
Executable File

#!/usr/bin/env bash
# Statyczne IP na dwóch kartach Ethernet — GMKtec K11 (gmktec-k11)
#
# Skanuje link na eno1 / enp3s0, pokazuje menu CLI i generuje Netplan.
# Rollback: scripts/restore-dhcp-network.sh
set -euo pipefail
NETPLAN_FILE="/etc/netplan/00-installer-config.yaml"
NIC_A="eno1"
NIC_B="enp3s0"
IP80="192.168.100.80/24"
IP90="192.168.100.90/24"
GATEWAY="192.168.100.1"
DNS="192.168.100.1"
DRY_RUN=false
NON_INTERACTIVE=false
PROFILE=""
# Po wyborze profilu (ustawiane przez apply_profile)
GW_NIC=""
ENO1_IPS=""
ENP3S0_IPS=""
PROFILE_NAME=""
usage() {
cat <<'EOF'
Użycie: sudo ./configure-static-dual-nic.sh [opcje]
Opcje:
--dry-run Skan + menu (lub profil) + YAML, bez zapisu i apply
--non-interactive Pomiń menu (wymaga --profile)
--profile <nazwa> Profil konfiguracji (patrz niżej)
-h, --help Ta pomoc
Profile (--non-interactive):
dual-eno1 eno1=.80+brama, enp3s0=.90
dual-enp3s0 enp3s0=.80+brama, eno1=.90
single-eno1-80 tylko eno1: .80+brama
single-eno1-both tylko eno1: .80+.90+brama
single-enp3s0-90 tylko enp3s0: .90+brama
single-enp3s0-80 tylko enp3s0: .80+brama
single-enp3s0-both tylko enp3s0: .80+.90+brama
Interaktywnie skrypt skanuje kable i pokazuje tylko pasujące opcje.
Rollback: sudo ./restore-dhcp-network.sh
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run) DRY_RUN=true; shift ;;
--non-interactive) NON_INTERACTIVE=true; shift ;;
--profile)
if [[ $# -lt 2 ]]; then
echo "BŁĄD: --profile wymaga nazwy." >&2
exit 1
fi
PROFILE="$2"
shift 2
;;
-h|--help) usage; exit 0 ;;
*) echo "Nieznana opcja: $1" >&2; usage >&2; exit 1 ;;
esac
done
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
echo "BŁĄD: Uruchom skrypt jako root (sudo)." >&2
exit 1
fi
if ! command -v netplan >/dev/null 2>&1; then
echo "BŁĄD: netplan nie jest zainstalowany." >&2
exit 1
fi
for nic in "$NIC_A" "$NIC_B"; do
if ! ip link show "$nic" &>/dev/null; then
echo "BŁĄD: Interfejs $nic nie istnieje." >&2
ip -br link || true
exit 1
fi
done
has_link() {
local nic="$1"
if command -v ethtool >/dev/null 2>&1; then
ethtool "$nic" 2>/dev/null | grep -q "Link detected: yes"
return $?
fi
ip link show "$nic" | grep -q "LOWER_UP"
}
current_ipv4() {
local nic="$1"
ip -4 -br addr show "$nic" 2>/dev/null | awk '{print $3}' | head -1
}
# Zwraca: LINK_ENO1 LINK_ENP3S0 (yes/no)
scan_nics() {
LINK_ENO1="no"
LINK_ENP3S0="no"
has_link "$NIC_A" && LINK_ENO1="yes"
has_link "$NIC_B" && LINK_ENP3S0="yes"
echo "=== Skan interfejsów ==="
printf " %-8s %-6s %-8s %s\n" "Interfejs" "Stan" "Link" "IPv4"
for nic in "$NIC_A" "$NIC_B"; do
local state link_flag ipv4
state=$(ip -br link show "$nic" | awk '{print $2}')
if has_link "$nic"; then link_flag="TAK"; else link_flag="NIE"; fi
ipv4=$(current_ipv4 "$nic")
ipv4="${ipv4:-}"
printf " %-8s %-6s %-8s %s\n" "$nic" "$state" "$link_flag" "$ipv4"
done
echo ""
}
ips_has() {
local list="$1"
local which="$2"
[[ " $list " == *" $which "* ]]
}
apply_profile() {
local key="$1"
PROFILE_NAME="$key"
case "$key" in
dual-eno1)
GW_NIC="$NIC_A"; ENO1_IPS="80"; ENP3S0_IPS="90" ;;
dual-enp3s0)
GW_NIC="$NIC_B"; ENO1_IPS="90"; ENP3S0_IPS="80" ;;
single-eno1-80)
GW_NIC="$NIC_A"; ENO1_IPS="80"; ENP3S0_IPS="" ;;
single-eno1-both)
GW_NIC="$NIC_A"; ENO1_IPS="80 90"; ENP3S0_IPS="" ;;
single-enp3s0-90)
GW_NIC="$NIC_B"; ENO1_IPS=""; ENP3S0_IPS="90" ;;
single-enp3s0-80)
GW_NIC="$NIC_B"; ENO1_IPS=""; ENP3S0_IPS="80" ;;
single-enp3s0-both)
GW_NIC="$NIC_B"; ENO1_IPS=""; ENP3S0_IPS="80 90" ;;
*)
echo "BŁĄD: Nieznany profil: $key" >&2
return 1
;;
esac
}
profile_description() {
local key="$1"
case "$key" in
dual-eno1) echo "eno1=.80+brama, enp3s0=.90" ;;
dual-enp3s0) echo "enp3s0=.80+brama, eno1=.90" ;;
single-eno1-80) echo "eno1=.80+brama (enp3s0 bez adresu)" ;;
single-eno1-both) echo "eno1=.80+.90+brama (oba IP na eno1)" ;;
single-enp3s0-90) echo "enp3s0=.90+brama (usługi LAN)" ;;
single-enp3s0-80) echo "enp3s0=.80+brama" ;;
single-enp3s0-both) echo "enp3s0=.80+.90+brama (oba IP na enp3s0)" ;;
*) echo "$key" ;;
esac
}
# MENU_KEYS[], MENU_LABELS[] — numeracja od 1
declare -a MENU_KEYS=()
declare -a MENU_LABELS=()
build_menu() {
MENU_KEYS=()
MENU_LABELS=()
if [[ "$LINK_ENO1" == "yes" && "$LINK_ENP3S0" == "yes" ]]; then
MENU_KEYS+=(dual-eno1 dual-enp3s0)
MENU_LABELS+=(
"Dual: eno1=.80+brama, enp3s0=.90 (zalecane)"
"Dual odwrócony: enp3s0=.80+brama, eno1=.90"
)
elif [[ "$LINK_ENO1" == "yes" ]]; then
MENU_KEYS+=(single-eno1-80 single-eno1-both)
MENU_LABELS+=(
"Pojedynczy eno1: .80+brama"
"Pojedynczy eno1: .80+.90+brama (awaryjnie, oba IP na jednej karcie)"
)
elif [[ "$LINK_ENP3S0" == "yes" ]]; then
MENU_KEYS+=(single-enp3s0-90 single-enp3s0-80 single-enp3s0-both)
MENU_LABELS+=(
"Pojedynczy enp3s0: .90+brama (zalecane — usługi Docker)"
"Pojedynczy enp3s0: .80+brama"
"Pojedynczy enp3s0: .80+.90+brama (oba IP na jednej karcie)"
)
else
echo "BŁĄD: Żaden interfejs nie ma aktywnego linku (kabel sieciowy)." >&2
echo " Podłącz kabel do eno1 lub enp3s0 i uruchom skrypt ponownie." >&2
exit 1
fi
}
show_menu() {
echo "=== Wybierz konfigurację ==="
local i
for i in "${!MENU_KEYS[@]}"; do
printf " %d) %s\n" "$((i + 1))" "${MENU_LABELS[$i]}"
done
printf " 0) Anuluj\n"
echo ""
}
pick_profile_interactive() {
build_menu
show_menu
local choice
while true; do
read -r -p "Wybór [1-${#MENU_KEYS[@]}, domyślnie 1]: " choice
choice="${choice:-1}"
if [[ "$choice" == "0" ]]; then
echo "Anulowano."
exit 0
fi
if [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#MENU_KEYS[@]} )); then
apply_profile "${MENU_KEYS[$((choice - 1))]}"
return 0
fi
echo "Nieprawidłowy wybór."
done
}
pick_profile() {
if [[ -n "$PROFILE" ]]; then
apply_profile "$PROFILE"
elif [[ "$NON_INTERACTIVE" == true ]]; then
echo "BŁĄD: --non-interactive wymaga --profile <nazwa>." >&2
exit 1
else
pick_profile_interactive
fi
}
build_nic_block() {
local nic="$1"
local ips="$2"
local is_gw="$3"
local has_cable="$4"
local optional="true"
[[ "$is_gw" == "yes" ]] && optional="false"
echo " ${nic}:"
echo " dhcp4: false"
echo " dhcp6: false"
echo " optional: ${optional}"
if [[ -n "$ips" ]]; then
echo " ignore-carrier: true"
echo " addresses:"
ips_has "$ips" "80" && echo " - ${IP80}"
ips_has "$ips" "90" && echo " - ${IP90}"
fi
if [[ "$is_gw" == "yes" ]]; then
echo " routes:"
echo " - to: default"
echo " via: ${GATEWAY}"
echo " metric: 100"
echo " nameservers:"
echo " addresses:"
echo " - ${DNS}"
fi
}
write_netplan_file() {
local content="$1"
local tmp
tmp=$(mktemp) || { echo "BŁĄD: mktemp nie powiódł się." >&2; return 1; }
chmod 600 "$tmp"
printf '%s\n' "$content" > "$tmp"
mv -f "$tmp" "$NETPLAN_FILE"
chmod 600 "$NETPLAN_FILE"
}
render_netplan() {
local eno1_gw="no" enp3_gw="no"
[[ "$GW_NIC" == "$NIC_A" ]] && eno1_gw="yes"
[[ "$GW_NIC" == "$NIC_B" ]] && enp3_gw="yes"
{
echo "network:"
echo " version: 2"
echo " renderer: networkd"
echo " ethernets:"
build_nic_block "$NIC_A" "$ENO1_IPS" "$eno1_gw" "$LINK_ENO1"
build_nic_block "$NIC_B" "$ENP3S0_IPS" "$enp3_gw" "$LINK_ENP3S0"
}
}
expected_ips_for_nic() {
local nic="$1"
local ips=""
if [[ "$nic" == "$NIC_A" ]]; then ips="$ENO1_IPS"; else ips="$ENP3S0_IPS"; fi
if ips_has "$ips" "80"; then echo "192.168.100.80"; fi
if ips_has "$ips" "90"; then echo "192.168.100.90"; fi
}
verify_config() {
local ok=true
echo "=== Weryfikacja ==="
for nic in "$NIC_A" "$NIC_B"; do
local ip
while read -r ip; do
[[ -z "$ip" ]] && continue
if ip -4 addr show dev "$nic" | grep -q "inet ${ip}/"; then
echo " ${nic}: ${ip} OK"
else
echo " ${nic}: ${ip} BRAK — próbuję networkctl reconfigure ..."
networkctl reconfigure "$nic" 2>/dev/null || true
sleep 2
if ip -4 addr show dev "$nic" | grep -q "inet ${ip}/"; then
echo " ${nic}: ${ip} OK (po reconfigure)"
else
echo " ${nic}: ${ip} NADAL BRAK"
ok=false
fi
fi
done < <(expected_ips_for_nic "$nic")
done
ip -br addr show "$NIC_A" "$NIC_B" 2>/dev/null || ip -br addr show "$NIC_A" "$NIC_B"
echo "--- trasy ---"
ip route show default || echo " (brak trasy domyślnej)"
if ping -c 1 -W 3 -I "$GW_NIC" "$GATEWAY" &>/dev/null; then
echo " ping -I ${GW_NIC} ${GATEWAY}: OK"
else
echo " ping -I ${GW_NIC} ${GATEWAY}: NIEUDANY"
ok=false
fi
if [[ "$ok" != true ]]; then
echo ""
echo "WERYFIKACJA NIEUDANA — sprawdź kable, rezerwację IP na routerze."
echo "Rollback: sudo $(dirname "$0")/restore-dhcp-network.sh"
return 1
fi
return 0
}
wait_for_ips() {
local attempt
for attempt in $(seq 1 15); do
local missing=false
for nic in "$NIC_A" "$NIC_B"; do
local ip
while read -r ip; do
[[ -z "$ip" ]] && continue
ip -4 addr show dev "$nic" | grep -q "inet ${ip}/" || missing=true
done < <(expected_ips_for_nic "$nic")
done
[[ "$missing" == false ]] && return 0
networkctl reconfigure "$NIC_A" 2>/dev/null || true
networkctl reconfigure "$NIC_B" 2>/dev/null || true
sleep 1
done
return 1
}
# --- main ---
scan_nics
pick_profile
STATIC_YAML=$(render_netplan)
echo "=== Wybrany profil: ${PROFILE_NAME} ==="
echo " $(profile_description "$PROFILE_NAME")"
echo " Brama domyślna: ${GW_NIC}"
echo ""
if [[ "$DRY_RUN" == true ]]; then
echo "=== DRY-RUN: docelowy Netplan ($NETPLAN_FILE) ==="
echo "$STATIC_YAML"
echo ""
echo "Dry-run: backup, zapis i netplan apply zostały pominięte."
exit 0
fi
echo "=== Backup Netplan ==="
if [[ -f "$NETPLAN_FILE" ]]; then
backup="${NETPLAN_FILE}.bak.$(date +%Y%m%d%H%M%S)"
cp -a "$NETPLAN_FILE" "$backup"
echo " Zapisano: $backup"
else
echo " Brak istniejącego $NETPLAN_FILE — backup pominięty."
fi
echo "=== Zapis statycznej konfiguracji ==="
write_netplan_file "$STATIC_YAML"
echo " Zapisano: $NETPLAN_FILE"
echo "=== netplan generate ==="
if ! netplan generate 2>&1; then
echo ""
echo "BŁĄD: netplan generate nie powiódł się. Przywróć backup lub uruchom restore-dhcp-network.sh"
exit 1
fi
echo "=== netplan apply ==="
netplan apply
wait_for_ips || true
verify_config || exit 1
echo ""
echo "=== GOTOWE ==="
echo " Profil: ${PROFILE_NAME}$(profile_description "$PROFILE_NAME")"
echo " Brama: ${GW_NIC} -> ${GATEWAY}"
[[ -n "$ENO1_IPS" ]] && echo " eno1: ${ENO1_IPS} -> 192.168.100.{${ENO1_IPS// /,}}"
[[ -n "$ENP3S0_IPS" ]] && echo " enp3s0: ${ENP3S0_IPS} -> 192.168.100.{${ENP3S0_IPS// /,}}"
echo ""
echo "SSH: sprawdź ip -br addr (adresy .80 / .90 na aktywnych kartach)"
echo "Rollback: sudo $(dirname "$0")/restore-dhcp-network.sh"