package app import ( "fmt" "strings" "time" ) func transportSystemdRunPreActionHooks( client TransportClient, action string, units []string, netnsEnabled bool, aggOut *[]string, aggErr *[]string, ) *transportBackendActionResult { if action == "start" || action == "restart" { migOut, migErr := transportSystemdMaybeMigrateLegacySingBoxUnits(client, units) *aggOut = append(*aggOut, migOut...) *aggErr = append(*aggErr, migErr...) } if netnsEnabled && (action == "start" || action == "restart") { if msg, err := transportEnsureNetnsForClient(client); strings.TrimSpace(msg) != "" || err != nil { if s := strings.TrimSpace(msg); s != "" { *aggOut = append(*aggOut, "netns: "+s) appendTraceLine("transport", fmt.Sprintf("netns setup: client=%s action=%s %s", client.ID, action, s)) } if err != nil { *aggErr = append(*aggErr, "netns: "+err.Error()) appendTraceLineRateLimited("transport", fmt.Sprintf("netns setup failed: client=%s action=%s err=%v", client.ID, action, err), 30*time.Second) if transportNetnsStrict(client) { return &transportBackendActionResult{ OK: false, Code: "TRANSPORT_BACKEND_NETNS_SETUP_FAILED", Message: err.Error(), ExitCode: -1, Stdout: strings.Join(*aggOut, "\n"), Stderr: strings.Join(*aggErr, "\n"), Retryable: true, } } } } } if !netnsEnabled { if msg, err := transportMaybeSyncBootstrapBypass(client, action); strings.TrimSpace(msg) != "" || err != nil { if s := strings.TrimSpace(msg); s != "" { *aggOut = append(*aggOut, "bootstrap: "+s) appendTraceLine("transport", fmt.Sprintf("bootstrap bypass: client=%s action=%s %s", client.ID, action, s)) } if err != nil { *aggErr = append(*aggErr, "bootstrap: "+err.Error()) appendTraceLineRateLimited("transport", fmt.Sprintf("bootstrap bypass failed: client=%s action=%s err=%v", client.ID, action, err), 30*time.Second) if (action == "start" || action == "restart") && transportBootstrapBypassStrict(client) { return &transportBackendActionResult{ OK: false, Code: "TRANSPORT_BACKEND_BOOTSTRAP_BYPASS_FAILED", Message: err.Error(), ExitCode: -1, Stdout: strings.Join(*aggOut, "\n"), Stderr: strings.Join(*aggErr, "\n"), Retryable: true, } } } } } if action == "start" || action == "restart" { transportSystemdResetFailedUnits(units) } return nil } func transportSystemdResetFailedUnits(units []string) { for _, unit := range units { stdout, stderr, code, err := transportRunCommand(transportBackendActionTimeout, "systemctl", "reset-failed", unit) // reset-failed is best-effort: do not block lifecycle on this step. if err != nil || code != 0 { appendTraceLineRateLimited("transport", fmt.Sprintf("systemctl reset-failed stdout: unit=%s out=%q", unit, strings.TrimSpace(stdout)), 20*time.Second) appendTraceLineRateLimited("transport", fmt.Sprintf("systemctl reset-failed stderr: unit=%s err=%q", unit, strings.TrimSpace(stderr)), 20*time.Second) appendTraceLineRateLimited("transport", fmt.Sprintf("systemctl reset-failed warning: unit=%s code=%d err=%v", unit, code, err), 20*time.Second) } } } func transportSystemdRunPostStopCleanup( client TransportClient, action string, aggOut *[]string, aggErr *[]string, ) { if msg, err := transportCleanupNetnsForClient(client); strings.TrimSpace(msg) != "" || err != nil { if s := strings.TrimSpace(msg); s != "" { *aggOut = append(*aggOut, "netns: "+s) appendTraceLine("transport", fmt.Sprintf("netns cleanup: client=%s action=%s %s", client.ID, action, s)) } if err != nil { *aggErr = append(*aggErr, "netns: "+err.Error()) appendTraceLineRateLimited("transport", fmt.Sprintf("netns cleanup warning: client=%s action=%s err=%v", client.ID, action, err), 30*time.Second) } } }