Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make podman generate systemd --new flag parsing more robust #8851

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions pkg/systemd/generate/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,30 @@ func quoteArguments(command []string) []string {
}
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
}
80 changes: 55 additions & 25 deletions pkg/systemd/generate/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v2/version"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
)

// containerInfo contains data required for generating a container's systemd
Expand Down Expand Up @@ -44,6 +45,9 @@ type containerInfo struct {
// Executable is the path to the podman executable. Will be auto-filled if
// left empty.
Executable string
// RootFlags contains the root flags which were used to create the container
// Only used with --new
RootFlags string
// TimeStamp at the time of creating the unit file. Will be set internally.
TimeStamp string
// CreateCommand is the full command plus arguments of the process the
Expand Down Expand Up @@ -185,22 +189,30 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
info.ContainerIDFile = "%t/" + info.ServiceName + ".ctr-id"
// The create command must at least have three arguments:
// /usr/bin/podman run $IMAGE
index := 2
if info.CreateCommand[1] == "container" {
index = 3
index := 0
for i, arg := range info.CreateCommand {
if arg == "run" || arg == "create" {
index = i + 1
break
}
}
if len(info.CreateCommand) < index+1 {
if index == 0 {
return "", errors.Errorf("container's create command is too short or invalid: %v", info.CreateCommand)
}
// We're hard-coding the first five arguments and append the
// CreateCommand with a stripped command and subcommand.
startCommand := []string{
info.Executable,
startCommand := []string{info.Executable}
if index > 2 {
// include root flags
info.RootFlags = strings.Join(quoteArguments(info.CreateCommand[1:index-1]), " ")
startCommand = append(startCommand, info.CreateCommand[1:index-1]...)
}
startCommand = append(startCommand,
"run",
"--conmon-pidfile", "{{.PIDFile}}",
"--cidfile", "{{.ContainerIDFile}}",
"--cgroups=no-conmon",
}
)
// If the container is in a pod, make sure that the
// --pod-id-file is set correctly.
if info.pod != nil {
Expand All @@ -210,23 +222,27 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
}

// Presence check for certain flags/options.
hasDetachParam := false
hasNameParam := false
hasReplaceParam := false
for _, p := range info.CreateCommand[index:] {
switch p {
case "--detach", "-d":
hasDetachParam = true
case "--name":
hasNameParam = true
case "--replace":
hasReplaceParam = true
}
if strings.HasPrefix(p, "--name=") {
hasNameParam = true
}
fs := pflag.NewFlagSet("args", pflag.ContinueOnError)
fs.ParseErrorsWhitelist.UnknownFlags = true
fs.Usage = func() {}
fs.SetInterspersed(false)
fs.BoolP("detach", "d", false, "")
fs.String("name", "", "")
fs.Bool("replace", false, "")
fs.Parse(info.CreateCommand[index:])

hasDetachParam, err := fs.GetBool("detach")
if err != nil {
return "", err
}
hasNameParam := fs.Lookup("name").Changed
hasReplaceParam, err := fs.GetBool("replace")
if err != nil {
return "", err
}

remainingCmd := info.CreateCommand[index:]

if !hasDetachParam {
// Enforce detaching
//
Expand All @@ -240,21 +256,35 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
// will wait the `podman run` command exit until failed
// with timeout error.
startCommand = append(startCommand, "-d")

if fs.Changed("detach") {
// this can only happen if --detach=false is set
// in that case we need to remove it otherwise we
// would overwrite the previous detach arg to false
remainingCmd = removeDetachArg(remainingCmd, fs.NArg())
}
}
if hasNameParam && !hasReplaceParam {
// Enforce --replace for named containers. This will
// make systemd units more robust as it allows them to
// start after system crashes (see
// github.com/containers/podman/issues/5485).
startCommand = append(startCommand, "--replace")

if fs.Changed("replace") {
// this can only happen if --replace=false is set
// in that case we need to remove it otherwise we
// would overwrite the previous replace arg to false
remainingCmd = removeReplaceArg(remainingCmd, fs.NArg())
}
}
startCommand = append(startCommand, info.CreateCommand[index:]...)
startCommand = append(startCommand, remainingCmd...)
startCommand = quoteArguments(startCommand)

info.ExecStartPre = "/bin/rm -f {{.PIDFile}} {{.ContainerIDFile}}"
info.ExecStart = strings.Join(startCommand, " ")
info.ExecStop = "{{.Executable}} stop --ignore --cidfile {{.ContainerIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}"
info.ExecStopPost = "{{.Executable}} rm --ignore -f --cidfile {{.ContainerIDFile}}"
info.ExecStop = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}stop --ignore --cidfile {{.ContainerIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}"
info.ExecStopPost = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}rm --ignore -f --cidfile {{.ContainerIDFile}}"
}

info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout
Expand Down
Loading