mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-08-26 02:07:56 +00:00
It is rare but possible that storage locations for the graphroot and the runroot are not mounted at boot time, and therefore might race when doing container operations. An example we've seen in the wild is that a slow tmpfs mount for the runroot would suddenly mount over /run, causing the container to lose all currently-running data, requiring a system refresh to get it back. This patch adds RequiresMountsFor= to the systemd.unit header to ensure the paths for both the graphroot and runroot are mounted prior to starting any generated unit files. Signed-off-by: Robb Manes <rmanes@redhat.com>
104 lines
3.1 KiB
Go
104 lines
3.1 KiB
Go
package generate
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/containers/podman/v3/pkg/systemd/define"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// minTimeoutStopSec is the minimal stop timeout for generated systemd units.
|
|
// Once exceeded, processes of the services are killed and the cgroup(s) are
|
|
// cleaned up.
|
|
const minTimeoutStopSec = 60
|
|
|
|
// validateRestartPolicy checks that the user-provided policy is valid.
|
|
func validateRestartPolicy(restart string) error {
|
|
for _, i := range define.RestartPolicies {
|
|
if i == restart {
|
|
return nil
|
|
}
|
|
}
|
|
return errors.Errorf("%s is not a valid restart policy", restart)
|
|
}
|
|
|
|
const headerTemplate = `# {{{{.ServiceName}}}}.service
|
|
{{{{- if (eq .GenerateNoHeader false) }}}}
|
|
# autogenerated by Podman {{{{.PodmanVersion}}}}
|
|
{{{{- if .TimeStamp}}}}
|
|
# {{{{.TimeStamp}}}}
|
|
{{{{- end}}}}
|
|
{{{{- end}}}}
|
|
|
|
[Unit]
|
|
Description=Podman {{{{.ServiceName}}}}.service
|
|
Documentation=man:podman-generate-systemd(1)
|
|
Wants=network.target
|
|
After=network-online.target
|
|
RequiresMountsFor={{{{.GraphRoot}}}} {{{{.RunRoot}}}}
|
|
`
|
|
|
|
// filterPodFlags removes --pod and --pod-id-file from the specified command.
|
|
func filterPodFlags(command []string) []string {
|
|
processed := []string{}
|
|
for i := 0; i < len(command); i++ {
|
|
s := command[i]
|
|
if s == "--pod" || s == "--pod-id-file" {
|
|
i++
|
|
continue
|
|
}
|
|
if strings.HasPrefix(s, "--pod=") || strings.HasPrefix(s, "--pod-id-file=") {
|
|
continue
|
|
}
|
|
processed = append(processed, s)
|
|
}
|
|
return processed
|
|
}
|
|
|
|
// escapeSystemdArguments makes sure that all arguments with at least one whitespace
|
|
// are quoted to make sure those are interpreted as one argument instead of
|
|
// multiple ones. Also make sure to escape all characters which have a special
|
|
// meaning to systemd -> $,% and \
|
|
// see: https://www.freedesktop.org/software/systemd/man/systemd.service.html#Command%20lines
|
|
func escapeSystemdArguments(command []string) []string {
|
|
for i := range command {
|
|
command[i] = strings.ReplaceAll(command[i], "$", "$$")
|
|
command[i] = strings.ReplaceAll(command[i], "%", "%%")
|
|
if strings.ContainsAny(command[i], " \t") {
|
|
command[i] = strconv.Quote(command[i])
|
|
} else if strings.Contains(command[i], `\`) {
|
|
// strconv.Quote also escapes backslashes so
|
|
// we should replace only if strconv.Quote was not used
|
|
command[i] = strings.ReplaceAll(command[i], `\`, `\\`)
|
|
}
|
|
}
|
|
return command
|
|
}
|
|
|
|
func removeDetachArg(args []string, argCount int) []string {
|
|
// "--detach=false" could also be in the container entrypoint
|
|
// split them off so we do not remove it there
|
|
realArgs := args[len(args)-argCount:]
|
|
flagArgs := removeArg("-d=false", args[:len(args)-argCount])
|
|
flagArgs = removeArg("--detach=false", flagArgs)
|
|
return append(flagArgs, realArgs...)
|
|
}
|
|
|
|
func removeReplaceArg(args []string, argCount int) []string {
|
|
// "--replace=false" could also be in the container entrypoint
|
|
// split them off so we do not remove it there
|
|
realArgs := args[len(args)-argCount:]
|
|
flagArgs := removeArg("--replace=false", args[:len(args)-argCount])
|
|
return append(flagArgs, realArgs...)
|
|
}
|
|
|
|
func removeArg(arg string, args []string) []string {
|
|
newArgs := []string{}
|
|
for _, a := range args {
|
|
if a != arg {
|
|
newArgs = append(newArgs, a)
|
|
}
|
|
}
|
|
return newArgs
|
|
}
|