diff --git a/hosts/skydick/datapool.nix b/hosts/skydick/datapool.nix index 602622e..511fb56 100644 --- a/hosts/skydick/datapool.nix +++ b/hosts/skydick/datapool.nix @@ -180,10 +180,6 @@ # # File-backed VM images live under /srv/system/vm/files. # # Block LUNs are zvol children of dick/system/vm/. # -# iSCSI zvols (block service — never the same bytes as SMB/NFS): -# zfs create -V -o volblocksize=16K dick/users//vm/ -# zfs create -V -o volblocksize=16K dick/system/vm/ -# # === Expanding the pool === # # Add another pair of Mach2 drives (driveN + driveM): @@ -208,10 +204,6 @@ # VM files: : 0750, NFS all_squash(uid), no Samba # TM: : 0750, Samba [timemachine] fruit:time machine, no NFS # -# Block services (iSCSI — separate zvols, never shared with SMB/NFS): -# dick/users//vm/ — user-owned zvols -# dick/system/vm/ — centrally managed zvols -# # Quotas: # ZFS quota on dick/users/ caps total across all child datasets. # dick/media is shared — no per-user quota; manage via service-level controls. @@ -263,73 +255,8 @@ "nfs-server.service" "samba-smbd.service" "influxdb2.service" - "iscsi-target.service" ]; - iscsiConfigGuard = pkgs.writeShellApplication { - name = "skydick-iscsi-config-guard"; - runtimeInputs = [ pkgs.coreutils pkgs.jq ]; - text = '' - set -euo pipefail - check_devices=true - if [[ "''${1:-}" == "--no-devices" ]]; then - check_devices=false - shift - fi - config="''${1:-/etc/target/saveconfig.json}" - - fail() { - echo "iSCSI configuration guard: $*" >&2 - exit 1 - } - - [[ -f "$config" ]] || fail "$config is missing or is not a regular file" - [[ -s "$config" ]] || fail "$config is empty" - [[ "$(stat -c '%u:%g' "$config")" == "0:0" ]] || fail "$config must be owned by root:root" - [[ "$(stat -c '%a' "$config")" == "600" ]] || fail "$config must have mode 0600" - - jq -e ' - type == "object" and - (.storage_objects | type == "array" and length > 0) and - all(.storage_objects[]; - .plugin == "block" and - (.dev | type == "string" and length > 0) - ) and - (.targets | type == "array" and length > 0) and - all(.targets[]; - (.tpgs | type == "array" and length > 0) and - all(.tpgs[]; - .attributes.authentication == 1 and - .attributes.generate_node_acls == 0 and - .attributes.cache_dynamic_acls == 0 and - (.portals | type == "array" and length > 0) and - all(.portals[]; - .port == 3260 and - .ip_address != "0.0.0.0" and - .ip_address != "::0" - ) and - (.luns | type == "array" and length > 0) and - (.node_acls | type == "array" and length > 0) and - all(.node_acls[]; - (.node_wwn | type == "string" and length > 0) and - (.chap_userid | type == "string" and length > 0) and - (.chap_password | type == "string" and length >= 12) and - (.mapped_luns | type == "array" and length > 0) - ) - ) - ) - ' "$config" >/dev/null || fail "$config lacks a secured block target, portal, ACL, CHAP credential, or LUN mapping" - - if $check_devices; then - device_count=0 - while IFS= read -r device; do - [[ -b "$device" ]] || fail "configured backstore $device is not a block device" - ((device_count += 1)) - done < <(jq -r '.. | objects | select(.plugin? == "block") | .dev? // empty' "$config") - ((device_count > 0)) || fail "$config has no usable block backstore" - fi - ''; - }; in { # Build sambaFull with Spotlight/tracker support. @@ -891,88 +818,11 @@ openFirewall = false; }; - # iSCSI state is intentionally imperative because targetcli can contain CHAP - # material. Keep the entire directory outside the Nix store: targetcli uses - # an atomic rename, so a directory symlink is required instead of a file - # symlink. The activation dependency migrates the current /etc/target before - # NixOS replaces the formerly generated saveconfig.json. - environment.etc."target/saveconfig.json".enable = lib.mkForce false; - environment.etc.target = { - source = "/var/lib/target"; - mode = "direct-symlink"; - }; - - system.activationScripts.iscsiTargetState = { - deps = [ "users" "groups" "specialfs" ]; - text = '' - state_dir=/var/lib/target - legacy_dir=/etc/target - - if [[ -L "$legacy_dir" ]]; then - if [[ "$(${pkgs.coreutils}/bin/readlink -f "$legacy_dir")" != "$state_dir" ]]; then - echo "Refusing to replace unexpected $legacy_dir symlink" >&2 - exit 1 - fi - elif [[ -d "$legacy_dir" ]]; then - if [[ -e "$state_dir" ]]; then - echo "Both $legacy_dir and $state_dir exist; refusing an ambiguous iSCSI state merge" >&2 - exit 1 - fi - ${iscsiConfigGuard}/bin/skydick-iscsi-config-guard --no-devices "$legacy_dir/saveconfig.json" - ${pkgs.coreutils}/bin/install -d -m 0755 /var/lib - ${pkgs.coreutils}/bin/mv "$legacy_dir" "$state_dir" - ${pkgs.coreutils}/bin/chmod 0700 "$state_dir" - elif [[ ! -d "$state_dir" ]]; then - echo "No persistent iSCSI configuration exists at $legacy_dir or $state_dir" >&2 - exit 1 - fi - - ${iscsiConfigGuard}/bin/skydick-iscsi-config-guard --no-devices "$state_dir/saveconfig.json" - - # The previous NixOS generation tracked this copied file in /etc/.clean. - # Remove only its exact bookkeeping record before setup-etc follows the - # new directory symlink and mistakes the persistent state for an obsolete - # generated file. - if [[ -f /etc/.clean ]]; then - ${pkgs.gnused}/bin/sed -i '\|^target/saveconfig.json$|d' /etc/.clean - fi - ''; - }; - system.activationScripts.etc.deps = [ "iscsiTargetState" ]; - - systemd.services.iscsi-target-config-ready = { - description = "Verify persistent LIO target configuration"; - requires = [ "dick-storage-ready.service" ]; - after = [ "dick-storage-ready.service" ]; - before = [ "iscsi-target.service" ]; - requiredBy = [ "iscsi-target.service" ]; - unitConfig.RequiresMountsFor = [ "/srv/system/vm" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - script = '' - ${iscsiConfigGuard}/bin/skydick-iscsi-config-guard /etc/target/saveconfig.json - ''; - }; - - # iSCSI — vm zvols only. A switch must never clear an active target/session; - # changed units take effect at the next controlled restart or reboot. - services.target.enable = true; - systemd.services.iscsi-target = { - requires = [ - "dick-storage-ready.service" - "dick-zfs-properties.service" - "iscsi-target-config-ready.service" - ]; - after = [ - "dick-storage-ready.service" - "dick-zfs-properties.service" - "iscsi-target-config-ready.service" - ]; - unitConfig.RequiresMountsFor = [ "/srv/system/vm" ]; - restartIfChanged = false; - stopIfChanged = false; - }; - + # iSCSI: intentionally not served. The LIO target that exported + # dick/system/vm/rh1288v3 as a block LUN was retired 2026-07-23. Its whole + # definition lived only in /etc/target/saveconfig.json — imperative runtime + # state that this host's generated /etc overwrote on every activation, so the + # export was never durable here. Do not re-enable services.target without + # first making that state persist outside the Nix store. Block volumes stay + # ZFS-local; SMB and NFS serve the filesystem. } diff --git a/hosts/skydick/default.nix b/hosts/skydick/default.nix index e783f18..9f01c82 100644 --- a/hosts/skydick/default.nix +++ b/hosts/skydick/default.nix @@ -129,7 +129,6 @@ iifname "bond40g" ip6 saddr 2a0c:b641:69c:ada0::/64 meta l4proto { tcp, udp } th dport { 111, 2049, 20001-20003 } accept comment "declared NFS global IPv6 clients" iifname "bond40g" ip saddr { 10.0.0.0/16, 10.253.0.0/16 } tcp dport 445 accept comment "SMB client networks" - iifname "bond40g" ip saddr 10.0.200.11 tcp dport 3260 accept comment "rh1288v3 iSCSI initiator" iifname "bond40g" ip saddr 10.0.75.15 tcp dport 8086 accept comment "door1 InfluxDB and Grafana" iifname "bond40g" ip saddr { 10.0.0.1, 10.0.75.15 } tcp dport 9100 accept comment "node exporter scrapers" '';