mirror of
https://github.com/containers/podman.git
synced 2025-06-23 02:18:13 +08:00
Merge pull request #9035 from Luap99/fix-9034
Make generate systemd --new robust against double curly braces
This commit is contained in:
@ -30,14 +30,14 @@ func validateRestartPolicy(restart string) error {
|
||||
return errors.Errorf("%s is not a valid restart policy", restart)
|
||||
}
|
||||
|
||||
const headerTemplate = `# {{.ServiceName}}.service
|
||||
# autogenerated by Podman {{.PodmanVersion}}
|
||||
{{- if .TimeStamp}}
|
||||
# {{.TimeStamp}}
|
||||
{{- end}}
|
||||
const headerTemplate = `# {{{{.ServiceName}}}}.service
|
||||
# autogenerated by Podman {{{{.PodmanVersion}}}}
|
||||
{{{{- if .TimeStamp}}}}
|
||||
# {{{{.TimeStamp}}}}
|
||||
{{{{- end}}}}
|
||||
|
||||
[Unit]
|
||||
Description=Podman {{.ServiceName}}.service
|
||||
Description=Podman {{{{.ServiceName}}}}.service
|
||||
Documentation=man:podman-generate-systemd(1)
|
||||
Wants=network.target
|
||||
After=network-online.target
|
||||
|
@ -72,22 +72,22 @@ type containerInfo struct {
|
||||
}
|
||||
|
||||
const containerTemplate = headerTemplate + `
|
||||
{{- if .BoundToServices}}
|
||||
BindsTo={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
|
||||
After={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
|
||||
{{- end}}
|
||||
{{{{- if .BoundToServices}}}}
|
||||
BindsTo={{{{- range $index, $value := .BoundToServices -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}.service{{{{end}}}}
|
||||
After={{{{- range $index, $value := .BoundToServices -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}.service{{{{end}}}}
|
||||
{{{{- end}}}}
|
||||
|
||||
[Service]
|
||||
Environment={{.EnvVariable}}=%n
|
||||
Restart={{.RestartPolicy}}
|
||||
TimeoutStopSec={{.TimeoutStopSec}}
|
||||
{{- if .ExecStartPre}}
|
||||
ExecStartPre={{.ExecStartPre}}
|
||||
{{- end}}
|
||||
ExecStart={{.ExecStart}}
|
||||
ExecStop={{.ExecStop}}
|
||||
ExecStopPost={{.ExecStopPost}}
|
||||
PIDFile={{.PIDFile}}
|
||||
Environment={{{{.EnvVariable}}}}=%n
|
||||
Restart={{{{.RestartPolicy}}}}
|
||||
TimeoutStopSec={{{{.TimeoutStopSec}}}}
|
||||
{{{{- if .ExecStartPre}}}}
|
||||
ExecStartPre={{{{.ExecStartPre}}}}
|
||||
{{{{- end}}}}
|
||||
ExecStart={{{{.ExecStart}}}}
|
||||
ExecStop={{{{.ExecStop}}}}
|
||||
ExecStopPost={{{{.ExecStopPost}}}}
|
||||
PIDFile={{{{.PIDFile}}}}
|
||||
Type=forking
|
||||
|
||||
[Install]
|
||||
@ -173,9 +173,9 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
|
||||
}
|
||||
|
||||
info.EnvVariable = EnvVariable
|
||||
info.ExecStart = "{{.Executable}} start {{.ContainerNameOrID}}"
|
||||
info.ExecStop = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerNameOrID}}"
|
||||
info.ExecStopPost = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerNameOrID}}"
|
||||
info.ExecStart = "{{{{.Executable}}}} start {{{{.ContainerNameOrID}}}}"
|
||||
info.ExecStop = "{{{{.Executable}}}} stop {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}} {{{{.ContainerNameOrID}}}}"
|
||||
info.ExecStopPost = "{{{{.Executable}}}} stop {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}} {{{{.ContainerNameOrID}}}}"
|
||||
|
||||
// Assemble the ExecStart command when creating a new container.
|
||||
//
|
||||
@ -209,8 +209,8 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
|
||||
}
|
||||
startCommand = append(startCommand,
|
||||
"run",
|
||||
"--conmon-pidfile", "{{.PIDFile}}",
|
||||
"--cidfile", "{{.ContainerIDFile}}",
|
||||
"--conmon-pidfile", "{{{{.PIDFile}}}}",
|
||||
"--cidfile", "{{{{.ContainerIDFile}}}}",
|
||||
"--cgroups=no-conmon",
|
||||
)
|
||||
// If the container is in a pod, make sure that the
|
||||
@ -281,10 +281,10 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
|
||||
startCommand = append(startCommand, remainingCmd...)
|
||||
startCommand = quoteArguments(startCommand)
|
||||
|
||||
info.ExecStartPre = "/bin/rm -f {{.PIDFile}} {{.ContainerIDFile}}"
|
||||
info.ExecStartPre = "/bin/rm -f {{{{.PIDFile}}}} {{{{.ContainerIDFile}}}}"
|
||||
info.ExecStart = strings.Join(startCommand, " ")
|
||||
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.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
|
||||
@ -307,7 +307,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
|
||||
// generation. That's especially needed for embedding the PID and ID
|
||||
// files in other fields which will eventually get replaced in the 2nd
|
||||
// template execution.
|
||||
templ, err := template.New("container_template").Parse(containerTemplate)
|
||||
templ, err := template.New("container_template").Delims("{{{{", "}}}}").Parse(containerTemplate)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error parsing systemd service template")
|
||||
}
|
||||
@ -318,7 +318,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
|
||||
}
|
||||
|
||||
// Now parse the generated template (i.e., buf) and execute it.
|
||||
templ, err = template.New("container_template").Parse(buf.String())
|
||||
templ, err = template.New("container_template").Delims("{{{{", "}}}}").Parse(buf.String())
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error parsing systemd service template")
|
||||
}
|
||||
|
@ -329,6 +329,29 @@ Type=forking
|
||||
WantedBy=multi-user.target default.target
|
||||
`
|
||||
|
||||
goodNewWithJournaldTag := `# jadda-jadda.service
|
||||
# autogenerated by Podman CI
|
||||
|
||||
[Unit]
|
||||
Description=Podman jadda-jadda.service
|
||||
Documentation=man:podman-generate-systemd(1)
|
||||
Wants=network.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||||
Restart=always
|
||||
TimeoutStopSec=70
|
||||
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
|
||||
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --replace --name test --log-driver=journald --log-opt=tag={{.Name}} awesome-image:latest
|
||||
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
|
||||
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
|
||||
PIDFile=%t/jadda-jadda.pid
|
||||
Type=forking
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target default.target
|
||||
`
|
||||
tests := []struct {
|
||||
name string
|
||||
info containerInfo
|
||||
@ -608,6 +631,22 @@ WantedBy=multi-user.target default.target
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{"good with journald log tag (see #9034)",
|
||||
containerInfo{
|
||||
Executable: "/usr/bin/podman",
|
||||
ServiceName: "jadda-jadda",
|
||||
ContainerNameOrID: "jadda-jadda",
|
||||
RestartPolicy: "always",
|
||||
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
|
||||
StopTimeout: 10,
|
||||
PodmanVersion: "CI",
|
||||
CreateCommand: []string{"I'll get stripped", "create", "--name", "test", "--log-driver=journald", "--log-opt=tag={{.Name}}", "awesome-image:latest"},
|
||||
EnvVariable: EnvVariable,
|
||||
},
|
||||
goodNewWithJournaldTag,
|
||||
true,
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
test := tt
|
||||
|
@ -72,23 +72,23 @@ type podInfo struct {
|
||||
ExecStopPost string
|
||||
}
|
||||
|
||||
const podTemplate = headerTemplate + `Requires={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
|
||||
Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
|
||||
const podTemplate = headerTemplate + `Requires={{{{- range $index, $value := .RequiredServices -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}.service{{{{end}}}}
|
||||
Before={{{{- range $index, $value := .RequiredServices -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}.service{{{{end}}}}
|
||||
|
||||
[Service]
|
||||
Environment={{.EnvVariable}}=%n
|
||||
Restart={{.RestartPolicy}}
|
||||
TimeoutStopSec={{.TimeoutStopSec}}
|
||||
{{- if .ExecStartPre1}}
|
||||
ExecStartPre={{.ExecStartPre1}}
|
||||
{{- end}}
|
||||
{{- if .ExecStartPre2}}
|
||||
ExecStartPre={{.ExecStartPre2}}
|
||||
{{- end}}
|
||||
ExecStart={{.ExecStart}}
|
||||
ExecStop={{.ExecStop}}
|
||||
ExecStopPost={{.ExecStopPost}}
|
||||
PIDFile={{.PIDFile}}
|
||||
Environment={{{{.EnvVariable}}}}=%n
|
||||
Restart={{{{.RestartPolicy}}}}
|
||||
TimeoutStopSec={{{{.TimeoutStopSec}}}}
|
||||
{{{{- if .ExecStartPre1}}}}
|
||||
ExecStartPre={{{{.ExecStartPre1}}}}
|
||||
{{{{- end}}}}
|
||||
{{{{- if .ExecStartPre2}}}}
|
||||
ExecStartPre={{{{.ExecStartPre2}}}}
|
||||
{{{{- end}}}}
|
||||
ExecStart={{{{.ExecStart}}}}
|
||||
ExecStop={{{{.ExecStop}}}}
|
||||
ExecStopPost={{{{.ExecStopPost}}}}
|
||||
PIDFile={{{{.PIDFile}}}}
|
||||
Type=forking
|
||||
|
||||
[Install]
|
||||
@ -236,9 +236,9 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
|
||||
}
|
||||
|
||||
info.EnvVariable = EnvVariable
|
||||
info.ExecStart = "{{.Executable}} start {{.InfraNameOrID}}"
|
||||
info.ExecStop = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.InfraNameOrID}}"
|
||||
info.ExecStopPost = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.InfraNameOrID}}"
|
||||
info.ExecStart = "{{{{.Executable}}}} start {{{{.InfraNameOrID}}}}"
|
||||
info.ExecStop = "{{{{.Executable}}}} stop {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}} {{{{.InfraNameOrID}}}}"
|
||||
info.ExecStopPost = "{{{{.Executable}}}} stop {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}} {{{{.InfraNameOrID}}}}"
|
||||
|
||||
// Assemble the ExecStart command when creating a new pod.
|
||||
//
|
||||
@ -278,8 +278,8 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
|
||||
startCommand = append(startCommand, podRootArgs...)
|
||||
startCommand = append(startCommand,
|
||||
[]string{"pod", "create",
|
||||
"--infra-conmon-pidfile", "{{.PIDFile}}",
|
||||
"--pod-id-file", "{{.PodIDFile}}"}...)
|
||||
"--infra-conmon-pidfile", "{{{{.PIDFile}}}}",
|
||||
"--pod-id-file", "{{{{.PodIDFile}}}}"}...)
|
||||
|
||||
// Presence check for certain flags/options.
|
||||
fs := pflag.NewFlagSet("args", pflag.ContinueOnError)
|
||||
@ -308,11 +308,11 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
|
||||
startCommand = append(startCommand, podCreateArgs...)
|
||||
startCommand = quoteArguments(startCommand)
|
||||
|
||||
info.ExecStartPre1 = "/bin/rm -f {{.PIDFile}} {{.PodIDFile}}"
|
||||
info.ExecStartPre1 = "/bin/rm -f {{{{.PIDFile}}}} {{{{.PodIDFile}}}}"
|
||||
info.ExecStartPre2 = strings.Join(startCommand, " ")
|
||||
info.ExecStart = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}pod start --pod-id-file {{.PodIDFile}}"
|
||||
info.ExecStop = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}pod stop --ignore --pod-id-file {{.PodIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}"
|
||||
info.ExecStopPost = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}pod rm --ignore -f --pod-id-file {{.PodIDFile}}"
|
||||
info.ExecStart = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}pod start --pod-id-file {{{{.PodIDFile}}}}"
|
||||
info.ExecStop = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}pod stop --ignore --pod-id-file {{{{.PodIDFile}}}} {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}}"
|
||||
info.ExecStopPost = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}pod rm --ignore -f --pod-id-file {{{{.PodIDFile}}}}"
|
||||
}
|
||||
info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout
|
||||
|
||||
@ -334,7 +334,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
|
||||
// generation. That's especially needed for embedding the PID and ID
|
||||
// files in other fields which will eventually get replaced in the 2nd
|
||||
// template execution.
|
||||
templ, err := template.New("pod_template").Parse(podTemplate)
|
||||
templ, err := template.New("pod_template").Delims("{{{{", "}}}}").Parse(podTemplate)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error parsing systemd service template")
|
||||
}
|
||||
@ -345,7 +345,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
|
||||
}
|
||||
|
||||
// Now parse the generated template (i.e., buf) and execute it.
|
||||
templ, err = template.New("pod_template").Parse(buf.String())
|
||||
templ, err = template.New("pod_template").Delims("{{{{", "}}}}").Parse(buf.String())
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error parsing systemd service template")
|
||||
}
|
||||
|
@ -139,6 +139,33 @@ ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-123abc.pod-
|
||||
PIDFile=%t/pod-123abc.pid
|
||||
Type=forking
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target default.target
|
||||
`
|
||||
|
||||
podNewLabelWithCurlyBraces := `# pod-123abc.service
|
||||
# autogenerated by Podman CI
|
||||
|
||||
[Unit]
|
||||
Description=Podman pod-123abc.service
|
||||
Documentation=man:podman-generate-systemd(1)
|
||||
Wants=network.target
|
||||
After=network-online.target
|
||||
Requires=container-1.service container-2.service
|
||||
Before=container-1.service container-2.service
|
||||
|
||||
[Service]
|
||||
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||||
Restart=on-failure
|
||||
TimeoutStopSec=70
|
||||
ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id
|
||||
ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo --label key={{someval}} --replace
|
||||
ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id
|
||||
ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-123abc.pod-id -t 10
|
||||
ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-123abc.pod-id
|
||||
PIDFile=%t/pod-123abc.pid
|
||||
Type=forking
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target default.target
|
||||
`
|
||||
@ -230,6 +257,22 @@ WantedBy=multi-user.target default.target
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{"pod --new with double curly braces",
|
||||
podInfo{
|
||||
Executable: "/usr/bin/podman",
|
||||
ServiceName: "pod-123abc",
|
||||
InfraNameOrID: "jadda-jadda-infra",
|
||||
RestartPolicy: "on-failure",
|
||||
PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
|
||||
StopTimeout: 10,
|
||||
PodmanVersion: "CI",
|
||||
RequiredServices: []string{"container-1", "container-2"},
|
||||
CreateCommand: []string{"podman", "pod", "create", "--name", "foo", "--label", "key={{someval}}"},
|
||||
},
|
||||
podNewLabelWithCurlyBraces,
|
||||
true,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
@ -355,4 +355,25 @@ var _ = Describe("Podman generate systemd", func() {
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.IsJSONOutputValid()).To(BeTrue())
|
||||
})
|
||||
|
||||
It("podman generate systemd --new create command with double curly braces", func() {
|
||||
// Regression test for #9034
|
||||
session := podmanTest.Podman([]string{"create", "--name", "foo", "--log-driver=journald", "--log-opt=tag={{.Name}}", ALPINE})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.Podman([]string{"generate", "systemd", "--new", "foo"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring(" --log-opt=tag={{.Name}} "))
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "create", "--name", "pod", "--label", "key={{someval}}"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.Podman([]string{"generate", "systemd", "--new", "pod"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.OutputToString()).To(ContainSubstring(" --label key={{someval}}"))
|
||||
})
|
||||
})
|
||||
|
Reference in New Issue
Block a user