Let SIGTERM cancel a running pass and bound nfs-server's clean-up at 10 s, so a hanging command cannot keep the export file past the stop timeout
This commit is contained in:
@@ -56,7 +56,14 @@ func (m *Machine) Pass(ctx context.Context, last *Status) Status {
|
||||
if _, note := m.Backup(); note != "" {
|
||||
s.Said = append(s.Said, note)
|
||||
}
|
||||
m.setWalk(ctx)
|
||||
exports, refused, said := m.Judge(c, roster, wants)
|
||||
m.setWalk(nil)
|
||||
if ctx.Err() != nil {
|
||||
// Stopping: write nothing and reload nothing, so Stopped starts at once.
|
||||
s.Problems = append(s.Problems, "the pass was ended by the process stopping; nothing was written")
|
||||
return s
|
||||
}
|
||||
s.Refused = refused
|
||||
s.Said = append(s.Said, said...)
|
||||
|
||||
@@ -80,7 +87,7 @@ func (m *Machine) Pass(ctx context.Context, last *Status) Status {
|
||||
}
|
||||
}
|
||||
if reload != "" {
|
||||
if _, err := m.AsRoot("exportfs", "-ra"); err != nil {
|
||||
if _, err := m.AsRootWithin(ctx, "exportfs", "-ra"); err != nil {
|
||||
s.ReloadError = err.Error()
|
||||
} else {
|
||||
at := m.Now().UTC()
|
||||
@@ -102,6 +109,10 @@ func (m *Machine) Pass(ctx context.Context, last *Status) Status {
|
||||
return s
|
||||
}
|
||||
|
||||
// StopTimeout bounds Stopped and the commands it runs: well under the service manager's stop timeout (90 s,
|
||||
// then SIGKILL), so the export file is gone before the process could be killed (mesh-host #62).
|
||||
var StopTimeout = 10 * time.Second
|
||||
|
||||
// RunExports is the process: a pass now and every Every until the context ends, then Stopped.
|
||||
func (m *Machine) RunExports(ctx context.Context) error {
|
||||
last := m.Pass(ctx, nil)
|
||||
@@ -184,11 +195,25 @@ func (m *Machine) Stopped() {
|
||||
if _, err := m.Read(ConfigFile); err == nil || !os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), StopTimeout)
|
||||
defer cancel()
|
||||
// The file first: removing it needs no command, so a hanging sudo or exportfs cannot keep it.
|
||||
if err := m.unexport(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "nfs-server:", err)
|
||||
loud("the module was unassigned and its export file is still there: " + err.Error() +
|
||||
"; remove " + ExportFile + " and run exportfs -ra as root")
|
||||
return
|
||||
}
|
||||
if _, err := m.AsRoot("exportfs", "-ra"); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "nfs-server: the export file is gone, and exportfs -ra failed:", err)
|
||||
fmt.Fprintln(os.Stderr, "nfs-server: unassigned: the export file "+ExportFile+" is removed")
|
||||
if _, err := m.AsRootWithin(ctx, "exportfs", "-ra"); err != nil {
|
||||
loud("the module was unassigned and its export file is removed, but the kernel may still export its " +
|
||||
"shares until exportfs -ra runs as root: " + err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, "nfs-server: unassigned: the kernel let the shares go (exportfs -ra)")
|
||||
}
|
||||
|
||||
// loud says, on the process's log where the service manager's journal keeps it, what an unassignment left
|
||||
// undone, so a person finds it rather than an export that outlived its module.
|
||||
func loud(what string) {
|
||||
fmt.Fprintln(os.Stderr, "nfs-server: UNASSIGNED, NOT CLEAN: "+what)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user