From 4a86be23c816fb7aff597459b54316bc937f318d Mon Sep 17 00:00:00 2001 From: oxpoe Date: Sat, 17 Oct 2026 14:08:44 +0700 Subject: [PATCH] feat: skrip auto pasang NIC macvlan + DHCP untuk instance incus --- LICENSE | 21 ++++++++ README.md | 85 +++++++++++++++++++++++++++++++ incus-macvlan.sh | 128 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100755 incus-macvlan.sh diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6da4880 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 oxpoe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..dcd3a76 --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# auto-macvlan + +Skrip untuk memasang **NIC macvlan** ke instance **Incus** dan mengaktifkan **DHCP di guest**, sehingga instance langsung mendapat IP di LAN (mis. `192.168.200.x`) — bukan IP NAT internal incus. + +Cocok untuk instance yang perlu diakses langsung dari LAN (web, SSH, service yang di-publish podman/docker di dalamnya). + +## Pemakaian + +```bash +./incus-macvlan.sh [device] [network] +``` + +Contoh: + +```bash +# pakai default: device eth1, network eth200 +./incus-macvlan.sh web1 + +# tentukan device & network +./incus-macvlan.sh web1 eth1 eth200 + +# buat network macvlan bila belum ada +./incus-macvlan.sh web1 --create --parent enp2s0 +``` + +## Opsi + +| Opsi | Default | Keterangan | +|---|---|---| +| `--parent ` | dari default route host | Interface fisik host untuk parent macvlan | +| `--network ` | `eth200` | Nama network macvlan di incus | +| `--device ` | `eth1` | Nama NIC di dalam guest | +| `--create` | mati | Buat network macvlan kalau belum ada | +| `-h, --help` | | Bantuan | + +Argumen posisional: `$1` instance, `$2` device, `$3` network. Opsi mengalahkan posisional. + +## Yang dilakukan + +1. Cek instance ada dan berjalan (start bila perlu). +2. Pastikan network macvlan ada (buat dengan `--create` bila perlu). +3. Pasang NIC `nic network= name=` ke instance (hotplug). +4. Aktifkan DHCP di guest: + - **NetworkManager** → `nmcli` + - **systemd-networkd** → `/etc/systemd/network/20-.network` + - fallback: `dhcpcd` / `dhclient` / `udhcpc` +5. Tunggu dan tampilkan IP LAN. + +Idempotent — aman dijalankan ulang. + +## Persiapan network macvlan (sekali) + +```bash +incus network create eth200 --type=macvlan parent=enp2s0 +``` + +Atau biarkan skrip membuatnya dengan `--create`. + +## Syarat + +- Host Incus punya NIC fisik yang terhubung ke LAN (parent, mis. `enp2s0`). +- **DHCP server di LAN** aktif (IP instance berasal dari router LAN, bukan incus). +- Guest punya salah satu DHCP client di atas. + +## Catatan penting + +- **Host Incus tidak bisa menghubungi instance lewat IP LAN macvlan** (batasan macvlan). Dari host, kelola lewat `incus exec`; instance tetap bisa diakses dari perangkat LAN lain. +- Bila instance punya **dua NIC** (incusbr0 + macvlan) dan default route dari incusbr0 menang, balasan ke LAN bisa keluar lewat NIC yang salah. Solusi: jadikan macvlan default dengan metrik lebih rendah, mis.: + + ```ini + # /etc/systemd/network/20-eth1.network + [Match] + Name=eth1 + [Network] + DHCP=yes + [DHCPv4] + RouteMetric=50 + ``` + + atau nonaktifkan NIC incusbr0 bila tidak diperlukan. +- IP yang didapat dinamis dari LAN. Kalau butuh statis, atur DHCP reservation di router atau konfigurasi statis di guest. + +## Lisensi + +MIT — lihat [LICENSE](LICENSE). diff --git a/incus-macvlan.sh b/incus-macvlan.sh new file mode 100755 index 0000000..f7c1905 --- /dev/null +++ b/incus-macvlan.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env bash +# +# incus-macvlan.sh — pasang NIC macvlan + aktifkan DHCP di guest incus, +# supaya instance langsung dapat IP di LAN (mis. 192.168.200.x). +# +# Pakai: +# ./incus-macvlan.sh [device] [network] +# ./incus-macvlan.sh web1 +# ./incus-macvlan.sh web1 eth1 eth200 +# +# Opsi: +# --parent interface fisik host (default: dari default route host) +# --network nama network macvlan (default: eth200) +# --device nama NIC di guest (default: eth1) +# --create buat network macvlan kalau belum ada +# -h, --help bantuan +# +# Idempotent: aman dijalankan berulang. Kalau instance sudah punya NIC +# di network macvlan (termasuk dari profile), NIC tidak ditambahkan lagi. +set -euo pipefail + +INSTANCE=""; DEVICE="eth1"; NETWORK="eth200"; PARENT=""; CREATE=0 +POS=() + +say(){ printf '%s\n' "$*"; } +die(){ printf 'error: %s\n' "$*" >&2; exit 1; } + +while [ $# -gt 0 ]; do + case "$1" in + --parent) PARENT="${2:?--parent butuh nilai}"; shift 2 ;; + --network) NETWORK="${2:?--network butuh nilai}"; shift 2 ;; + --device) DEVICE="${2:?--device butuh nilai}"; shift 2 ;; + --create) CREATE=1; shift ;; + -h|--help) sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; + -*) die "opsi tak dikenal: $1" ;; + *) POS+=("$1"); shift ;; + esac +done + +INSTANCE="${POS[0]:-}" +[ -n "${POS[1]:-}" ] && DEVICE="${POS[1]}" +[ -n "${POS[2]:-}" ] && NETWORK="${POS[2]}" +[ -n "$INSTANCE" ] || die "pakai: $(basename "$0") [device] [network]" + +[[ "$DEVICE" =~ ^[A-Za-z0-9_.-]+$ ]] || die "nama device tidak valid: $DEVICE" +[[ "$NETWORK" =~ ^[A-Za-z0-9_.-]+$ ]] || die "nama network tidak valid: $NETWORK" +command -v incus >/dev/null 2>&1 || die "perintah 'incus' tidak ditemukan" +incus info "$INSTANCE" /dev/null 2>&1 || die "instance '$INSTANCE' tidak ditemukan" + +if [ -z "$PARENT" ]; then + PARENT="$(ip route show default 2>/dev/null | awk '{print $5; exit}')" + PARENT="${PARENT:-enp2s0}" +fi + +# ---- network macvlan ---- +if incus network list -c n -f csv /dev/null | grep -qx "$NETWORK"; then + say "network '$NETWORK' sudah ada" +else + [ "$CREATE" = 1 ] || die "network '$NETWORK' belum ada (pakai --create, parent $PARENT)" + say "membuat network macvlan '$NETWORK' (parent $PARENT)" + incus network create "$NETWORK" --type=macvlan parent="$PARENT" /dev/null | grep -q "network: $NETWORK"; then + say "instance sudah punya NIC di network '$NETWORK' (dilewati)" +elif incus config device list "$INSTANCE" /dev/null; then + nmcli device connect "$dev" >/dev/null 2>&1 || true + elif systemctl is-active --quiet systemd-networkd 2>/dev/null || [ -d /etc/systemd/network ]; then + printf "[Match]\nName=%s\n[Network]\nDHCP=yes\n" "$dev" > "/etc/systemd/network/20-$dev.network" + elif command -v dhcpcd >/dev/null 2>&1; then dhcpcd "$dev" >/dev/null 2>&1 || true + elif command -v dhclient >/dev/null 2>&1; then dhclient "$dev" >/dev/null 2>&1 || true + elif command -v udhcpc >/dev/null 2>&1; then udhcpc -i "$dev" >/dev/null 2>&1 || true + fi + } + for i in /sys/class/net/*; do + dev=$(basename "$i"); [ "$dev" = lo ] && continue + ip -4 addr show "$dev" 2>/dev/null | grep -q "inet " && continue + configure_one "$dev" + done + systemctl restart systemd-networkd >/dev/null 2>&1 || true +' /dev/null \ + | tr ',' '\n' | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' \ + | grep -vE '^(10\.|127\.)' | head -1 || true)" + [ -n "$IP" ] && break + sleep 1 +done + +say "" +if [ -n "$IP" ]; then + say "instance : $INSTANCE" + say "network : $NETWORK (parent $PARENT)" + say "IP LAN : $IP" + say "SSH : ssh root@$IP" +else + say "instance : $INSTANCE" + say "IP LAN : belum terdeteksi" + say "cek : incus exec $INSTANCE -- ip -4 addr" + exit 1 +fi