v0.84.0: ReassertNetworkMounts — NAS automount survives guest reboots (RCA fix 1)
Storage §8 decision table (stop + enable --now on idle triggers; active mounts untouched), daemon leg at startup with per-running-guest visibility verify, guest-hook post-start leg (root, direct systemctl, non-fatal). Red-proofs: always-rearm table FAIL; unwired hook FAIL. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -450,12 +450,43 @@ func (h *SudoHostOps) RemoveNetworkMount(ctx context.Context, name string) error
|
||||
// timeout — it NEVER stat()s the (possibly EIO/D-state) mountpoint, so a black-holed NAS cannot wedge
|
||||
// this call. Best-effort: an unreadable unit dir yields an empty list.
|
||||
func (h *SudoHostOps) ListNetworkMounts(ctx context.Context) ([]NetworkMountStatus, error) {
|
||||
entries, err := h.networkUnitEntries()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mounts := h.mountedFSTypes()
|
||||
var out []NetworkMountStatus
|
||||
for _, e := range entries {
|
||||
st := NetworkMountStatus{
|
||||
Name: e.name,
|
||||
Protocol: e.proto,
|
||||
Server: e.server,
|
||||
Export: e.export,
|
||||
Where: e.where,
|
||||
Configured: true,
|
||||
Mounted: isNetworkMounted(mounts[e.where]),
|
||||
Reachable: endpointReachable(netEndpoint(e.proto, e.server)),
|
||||
}
|
||||
st.Health = networkHealth(st.Reachable, st.Mounted)
|
||||
out = append(out, st)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// networkUnitEntry is one installed network-storage unit pair, parsed from its .mount file.
|
||||
type networkUnitEntry struct {
|
||||
name, proto, server, export, where string
|
||||
}
|
||||
|
||||
// networkUnitEntries enumerates the installed network-storage unit pairs from the (world-readable)
|
||||
// unit dir — the shared core of ListNetworkMounts and ReassertNetworkAutomounts. No probing, no
|
||||
// mountpoint access. Best-effort per file; an unreadable unit dir is the only error.
|
||||
func (h *SudoHostOps) networkUnitEntries() ([]networkUnitEntry, error) {
|
||||
entries, err := os.ReadDir(h.unitDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("netmount: reading unit dir: %w", err)
|
||||
}
|
||||
mounts := h.mountedFSTypes()
|
||||
var out []NetworkMountStatus
|
||||
var out []networkUnitEntry
|
||||
for _, e := range entries {
|
||||
if !strings.HasSuffix(e.Name(), ".mount") {
|
||||
continue // the .mount unit carries the What/Type; the .automount mirrors Where only
|
||||
@@ -468,18 +499,13 @@ func (h *SudoHostOps) ListNetworkMounts(ctx context.Context) ([]NetworkMountStat
|
||||
if !ok {
|
||||
continue // not one of ours (or a drive by-uuid mount)
|
||||
}
|
||||
st := NetworkMountStatus{
|
||||
Name: strings.TrimPrefix(where, NetworkMountRoot+"/"),
|
||||
Protocol: proto,
|
||||
Server: server,
|
||||
Export: export,
|
||||
Where: where,
|
||||
Configured: true,
|
||||
Mounted: isNetworkMounted(mounts[where]),
|
||||
Reachable: endpointReachable(netEndpoint(proto, server)),
|
||||
}
|
||||
st.Health = networkHealth(st.Reachable, st.Mounted)
|
||||
out = append(out, st)
|
||||
out = append(out, networkUnitEntry{
|
||||
name: strings.TrimPrefix(where, NetworkMountRoot+"/"),
|
||||
proto: proto,
|
||||
server: server,
|
||||
export: export,
|
||||
where: where,
|
||||
})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user