Archived
Merge branch 'main' of https://gitea.lan.ddnsgeek.com/beatzaplenty/nixos
This commit is contained in:
@@ -44,14 +44,8 @@ in
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Pool exists on a device but not yet imported — let the standard
|
# Locate the data disk first — used for both the fallback import
|
||||||
# zfs-import-${poolName}.service handle it normally.
|
# attempt and, only if the disk is genuinely blank, pool creation.
|
||||||
if zpool import -d /dev/disk/by-id -N "${poolName}" 2>/dev/null; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# No pool found at all. Create it on the Proxmox data disk (scsi1),
|
|
||||||
# which appears as /dev/disk/by-id/scsi-*drive-scsi1 inside the VM.
|
|
||||||
DATA_DISK=""
|
DATA_DISK=""
|
||||||
for candidate in /dev/disk/by-id/scsi-*drive-scsi1; do
|
for candidate in /dev/disk/by-id/scsi-*drive-scsi1; do
|
||||||
[[ "$candidate" == *-part* ]] && continue
|
[[ "$candidate" == *-part* ]] && continue
|
||||||
@@ -63,8 +57,31 @@ in
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Try importing via the by-id symlink directory first (normal path),
|
||||||
|
# then fall back to scanning the disk directly. The two-step exists
|
||||||
|
# because of a udev race: systemd-udev-settle.service can clear before
|
||||||
|
# /dev/disk/by-id/ entries are fully populated, causing the first
|
||||||
|
# import to fail even when the pool is intact on the disk.
|
||||||
|
if zpool import -d /dev/disk/by-id -N "${poolName}" 2>/dev/null; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if zpool import -d "$DATA_DISK" -N "${poolName}" 2>/dev/null; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Both import attempts failed. Before creating a new pool, verify the
|
||||||
|
# disk is genuinely blank — if ZFS label metadata is present the import
|
||||||
|
# failed for some other reason and we must not clobber existing data.
|
||||||
|
if zdb -l "$DATA_DISK" 2>/dev/null | grep -q "name: '${poolName}'"; then
|
||||||
|
echo "zfs-init-${poolName}: $DATA_DISK has ZFS pool '${poolName}' metadata but import failed — refusing to overwrite existing data. Run 'zpool import -d $DATA_DISK ${poolName}' manually to investigate." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Disk is genuinely blank: create the pool. -f is intentionally
|
||||||
|
# omitted so that if we somehow reach this point with an existing pool
|
||||||
|
# on the disk, zpool refuses rather than silently destroying data.
|
||||||
echo "zfs-init-${poolName}: creating pool on $DATA_DISK"
|
echo "zfs-init-${poolName}: creating pool on $DATA_DISK"
|
||||||
zpool create -f "${poolName}" "$DATA_DISK"
|
zpool create "${poolName}" "$DATA_DISK"
|
||||||
${lib.concatMapStrings (ds: ''
|
${lib.concatMapStrings (ds: ''
|
||||||
zfs create "${poolName}/${ds}"
|
zfs create "${poolName}/${ds}"
|
||||||
'') poolDatasets}
|
'') poolDatasets}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
../tailscale/subnet-router.nix
|
../tailscale/subnet-router.nix
|
||||||
|
../tailscale/ts-dns-forwarder.nix
|
||||||
../beszel/enable-agent.nix
|
../beszel/enable-agent.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
{ vars, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Run dnsmasq on the LAN interface as a forwarding-only resolver for
|
||||||
|
# *.ts.net (Tailscale MagicDNS names). FreeIPA's bind-dyndb-ldap
|
||||||
|
# cannot reach 100.100.100.100 (Tailscale's internal resolver) directly
|
||||||
|
# because the DC is not a Tailscale node. This host IS a Tailscale node
|
||||||
|
# and can reach 100.100.100.100 via its tailscale0 interface, so it
|
||||||
|
# acts as an intermediary: FreeIPA has a conditional forward zone for
|
||||||
|
# ts.net pointing here (vars.tailscaleRouterIp), and this dnsmasq
|
||||||
|
# instance forwards those queries onward to Tailscale's resolver.
|
||||||
|
#
|
||||||
|
# Configure FreeIPA once after deploying this host:
|
||||||
|
# kinit admin
|
||||||
|
# ipa dnsforwardzone-add ${vars.tailnetDomain} \
|
||||||
|
# --forwarder=${vars.tailscaleRouterIp} \
|
||||||
|
# --forward-policy=only
|
||||||
|
# Note: IPA refuses to shadow ts.net (a real public TLD); use the
|
||||||
|
# tailnet-specific subdomain (vars.tailnetDomain) instead.
|
||||||
|
services.dnsmasq = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
# Listen only on the LAN interface — not tailscale0 or loopback.
|
||||||
|
# bind-interfaces prevents dnsmasq from binding to 0.0.0.0 and
|
||||||
|
# then filtering by interface later; combined with `interface` this
|
||||||
|
# ensures it genuinely listens only on eth0.
|
||||||
|
bind-interfaces = true;
|
||||||
|
interface = [ vars.lxcLanInterface ];
|
||||||
|
|
||||||
|
# Forward-only: no local /etc/hosts or /etc/resolv.conf reading,
|
||||||
|
# no negative caching of NXDOMAIN for names this instance doesn't
|
||||||
|
# serve. All ts.net queries come from FreeIPA's conditional forwarder
|
||||||
|
# and must be answered by Tailscale's resolver.
|
||||||
|
no-hosts = true;
|
||||||
|
no-resolv = true;
|
||||||
|
|
||||||
|
# Tailscale's internal "Quad100" resolver — reachable from any
|
||||||
|
# Tailscale node via the tailscale0 interface. Scoped to the
|
||||||
|
# specific tailnet subdomain (vars.tailnetDomain) rather than
|
||||||
|
# all of ts.net: FreeIPA refuses to shadow ts.net (a real public
|
||||||
|
# TLD with DNSimple nameservers) so the conditional forward zone
|
||||||
|
# in FreeIPA must use the tailnet-specific subdomain instead:
|
||||||
|
# ipa dnsforwardzone-add ${vars.tailnetDomain} \
|
||||||
|
# --forwarder=${vars.tailscaleRouterIp} \
|
||||||
|
# --forward-policy=only
|
||||||
|
server = [ "/${vars.tailnetDomain}/100.100.100.100" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedUDPPorts = [ 53 ];
|
||||||
|
networking.firewall.allowedTCPPorts = [ 53 ];
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user