v0.4.65: swap kernel-mount NFS for userspace SMB (smbclient)
v0.4.64's NFS path didn't work on Unraid even with --privileged
because Unraid's base kernel ships without the nfs/nfsv4 client
modules — and no container-side configuration can load a host kernel
module. SMB has the same kernel-mount problem (`mount -t cifs` needs
the cifs module) but it also has a usable *userspace* client: Samba's
`smbclient` CLI, which speaks the SMB protocol over a plain TCP socket
with no kernel involvement. This is the same approach Bootimus uses,
and works in every container regardless of host kernel modules or
container capabilities.
What's gone:
* `crates/iso-store/src/nfs.rs` (in entirety)
* `NfsManager`, `NfsMount`, `NfsAddRequest`, `NfsVersion` types
* `IsoSource::Nfs` variant
* `IsoStore::nfs_root` / `IsoStore::set_nfs_root`
* `/api/nfs`, `/api/nfs/:id`, `/api/nfs/:id/scan` routes
* `nfs` terminal command
* Storage tab's NFS shares card and the v0.4.64 fstab-options
diagnostics work (the whole error path is moot now)
What's new:
* `crates/iso-store/src/smb_share.rs` — `SmbShareManager` that drives
`smbclient` as a subprocess. Indexes shares via `smbclient -c "ls
*.iso"` and streams files via `smbclient -c "get file -"` piped
straight into HTTP response bodies. No local cache, no double disk
usage.
* `IsoSource::Smb { share_id, relative_path }` variant.
* `IsoStore::iso_path_for` returns None for SMB sources — the HTTP
ISO download handler dispatches on the source kind and streams via
the SmbShareManager when it's SMB.
* `/api/smb-shares` + `/api/smb-shares/:id` + `/api/smb-shares/:id/scan`
routes.
* `share` terminal command (`list | add //srv/share [auth] | remove |
scan`). Auth spec is `guest` or `user:password`.
* Storage tab: SMB shares card replaces the NFS one. Two-column form
for server + share name, three-column form for guest checkbox /
username / password. Username and password fields auto-disable when
Guest is checked.
* Credentials live under <work_dir>/smb_creds/<id>.cred at 0600
permissions so they don't leak through `ps`. Persisted state at
<work_dir>/smb_shares.json (sans password — re-entered on add /
re-scan).
Why subprocess and not a Rust crate:
* The Debian runtime image already ships the `samba` package
(Dockerfile line 84) — `smbclient` is right there.
* Library options (pavao, etc.) wrap libsmbclient so they still pull
in the same C library at runtime.
* Subprocess gives operators a verifiable mental model — anything
OpenPXE can do over SMB, they can reproduce by running `smbclient`
manually at a shell.
Range-request limitation, called out in the smb_share.rs module docs
and the UI explainer: `smbclient -c 'get file -'` is a sequential
whole-file stream. HTTP range requests on SMB-sourced ISOs return
416. PXE workloads (iPXE chain, casper sanboot, wimboot) do
whole-file sequential reads, so this works in practice. A follow-up
release can add libsmbclient-based seek if a real workload needs it.
Stderr-to-hint translation patterns mirror v0.4.64's NFS work:
NT_STATUS_LOGON_FAILURE → "check credentials", BAD_NETWORK_NAME →
"check share name", connection refused / timeout → "verify
reachability + firewall", etc. UI renders the raw smbclient error
plus the hint as two lines.
Tests (149 total, was 142 in v0.4.64):
* smb_share parser tests covering ISO + skipped directory, filenames
with spaces, non-ISO filtering.
* hint_for() translation tests for the dominant NT_STATUS codes.
* Server normalization (smb://, cifs://, \\, // prefixes all stripped).
* HTTP integration: shares list starts empty, invalid server / missing
username / path in share name all rejected with actionable hints.
`cargo clippy --workspace --all-targets -- -D warnings` clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
de23a2be33
commit
062b1497d4
@@ -4,7 +4,7 @@ use openpxe_core::{
|
||||
AdminStore, BootLog, BrandingStore, ClientRegistry, DeploymentQueue, HostBindings, LogBus,
|
||||
Metrics, SettingsStore, SsoStore,
|
||||
};
|
||||
use openpxe_iso_store::{IsoStore, NfsManager, SmbManager};
|
||||
use openpxe_iso_store::{IsoStore, SmbManager, SmbShareManager};
|
||||
use std::sync::Arc;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
@@ -44,11 +44,14 @@ pub struct AppState {
|
||||
/// `smb_dir` at startup; `None` in pure-Linux-only deployments where
|
||||
/// Windows support is not wired in. Settings toggle drives start/stop.
|
||||
pub smb: Option<Arc<SmbManager>>,
|
||||
/// NFS share manager. Always present (mounting is opt-in by the
|
||||
/// operator from the Storage tab); `add()` requires `mount.nfs` to be
|
||||
/// available in the runtime image. Surfaces errors per-mount rather
|
||||
/// than failing the global state.
|
||||
pub nfs: NfsManager,
|
||||
/// v0.4.65: SMB share manager — userspace consumer of remote SMB
|
||||
/// shares via Samba's `smbclient` CLI. Replaces the kernel-mount
|
||||
/// NFS path that v0.4.64 shipped; that path didn't work on hosts
|
||||
/// (Unraid, etc.) whose kernel ships without the nfs/cifs client
|
||||
/// modules, and no container-side configuration could fix it.
|
||||
/// `smbclient` does the SMB protocol over a plain TCP socket in
|
||||
/// userspace — works in any container, no special caps required.
|
||||
pub smb_shares: SmbShareManager,
|
||||
/// Browser chunked upload state. Multipart uploads still go straight
|
||||
/// through `IsoStore`, but the UI uses sessions so large ISO transfers
|
||||
/// can show deterministic progress and leave visible partial files.
|
||||
|
||||
Reference in New Issue
Block a user