Files
elmprodvpn/selective-vpn-api/app/transport_backends_adapter_systemd_action_exec.go

91 lines
2.6 KiB
Go

package app
import (
"fmt"
"strings"
"time"
)
func transportSystemdRunActionUnits(
client TransportClient,
action string,
units []string,
aggOut *[]string,
aggErr *[]string,
) *transportBackendActionResult {
for _, unit := range units {
stdout, stderr, exitCode, err := transportRunCommand(transportBackendActionTimeout, "systemctl", action, unit)
if s := strings.TrimSpace(stdout); s != "" {
*aggOut = append(*aggOut, unit+": "+s)
}
if s := strings.TrimSpace(stderr); s != "" {
*aggErr = append(*aggErr, unit+": "+s)
}
if (action == "start" || action == "restart") &&
client.Kind == TransportClientSingBox &&
transportSystemdUnitMissingError(stdout, stderr, exitCode, err) {
appendTraceLineRateLimited(
"transport",
fmt.Sprintf("systemctl %s unit missing, trying auto-provision: client=%s unit=%s", action, client.ID, unit),
20*time.Second,
)
provision := (transportSystemdBackend{}).Provision(client)
if s := strings.TrimSpace(provision.Stdout); s != "" {
*aggOut = append(*aggOut, "provision: "+s)
}
if s := strings.TrimSpace(provision.Stderr); s != "" {
*aggErr = append(*aggErr, "provision: "+s)
}
if !provision.OK {
msg := strings.TrimSpace(provision.Message)
if msg == "" {
msg = "auto-provision failed"
}
return &transportBackendActionResult{
OK: false,
Code: provision.Code,
Message: msg,
ExitCode: provision.ExitCode,
Stdout: strings.Join(*aggOut, "\n"),
Stderr: strings.Join(*aggErr, "\n"),
Retryable: true,
}
}
stdout, stderr, exitCode, err = transportRunCommand(transportBackendActionTimeout, "systemctl", action, unit)
if s := strings.TrimSpace(stdout); s != "" {
*aggOut = append(*aggOut, unit+": "+s)
}
if s := strings.TrimSpace(stderr); s != "" {
*aggErr = append(*aggErr, unit+": "+s)
}
}
if action == "stop" && transportSystemdStopMissingUnitNoop(stdout, stderr, exitCode, err) {
appendTraceLineRateLimited(
"transport",
fmt.Sprintf("systemctl stop noop: client=%s unit=%s reason=unit-missing", client.ID, unit),
15*time.Second,
)
continue
}
if err != nil || exitCode != 0 {
msg := strings.TrimSpace(stderr)
if msg == "" {
msg = strings.TrimSpace(stdout)
}
if msg == "" {
msg = fmt.Sprintf("systemctl %s %s failed", action, unit)
}
return &transportBackendActionResult{
OK: false,
Code: "TRANSPORT_BACKEND_ACTION_FAILED",
Message: msg,
ExitCode: exitCode,
Stdout: strings.Join(*aggOut, "\n"),
Stderr: strings.Join(*aggErr, "\n"),
Retryable: action != "stop",
}
}
}
return nil
}