force run container detached if container CreateCommand missing the detach param

the podman generated systemd service file has `Type=forking` service,
so the command after `ExecStart=` should not run in front.
if someone created a container and has the detach(`-d`) param missing
like this
```
podman create --name ngxdemo -P nginxdemos/hello
```
and generate the file with `--new` param:
```
podman generate systemd --name --new ngxdemo
```
because `podman run xxx` has no `-d` param,
so the container is not run in background and nerver exit.
and systemd will fail to start the service:
```
sudo systemctl start container-ngxdemo.service
Job for container-ngxdemo.service failed because a timeout was exceeded.
See "systemctl status container-ngxdemo.service" and "journalctl -xe" for details.
```

Signed-off-by: 荒野無燈 <ttys3@outlook.com>
This commit is contained in:
荒野無燈
2020-03-10 12:28:03 +08:00
parent f378e82e2d
commit 194723f314
4 changed files with 139 additions and 1 deletions

View File

@ -25,6 +25,7 @@ Use the name of the container for the start, stop, and description in the unit f
**--new** **--new**
Create a new container via podman-run instead of starting an existing one. This option relies on container configuration files, which may not map directly to podman CLI flags; please review the generated output carefully before placing in production. Create a new container via podman-run instead of starting an existing one. This option relies on container configuration files, which may not map directly to podman CLI flags; please review the generated output carefully before placing in production.
Since we use systemd `Type=forking` service, using this option will force the container run with the detached param `-d`
**--timeout**, **-t**=*value* **--timeout**, **-t**=*value*

View File

@ -164,6 +164,26 @@ func CreateContainerSystemdUnit(info *ContainerInfo, opts Options) (string, erro
"--cidfile", "%t/%n-cid", "--cidfile", "%t/%n-cid",
"--cgroups=no-conmon", "--cgroups=no-conmon",
} }
// Enforce detaching
//
// since we use systemd `Type=forking` service
// @see https://www.freedesktop.org/software/systemd/man/systemd.service.html#Type=
// when we generated systemd service file with the --new param,
// `ExecStart` will have `/usr/bin/podman run ...`
// if `info.CreateCommand` has no `-d` or `--detach` param,
// podman will run the container in default attached mode,
// as a result, `systemd start` will wait the `podman run` command exit until failed with timeout error.
hasDetachParam := false
for _, p := range info.CreateCommand[index:] {
if p == "--detach" || p == "-d" {
hasDetachParam = true
}
}
if !hasDetachParam {
command = append(command, "-d")
}
command = append(command, info.CreateCommand[index:]...) command = append(command, info.CreateCommand[index:]...)
info.RunCommand = strings.Join(command, " ") info.RunCommand = strings.Join(command, " ")
info.New = true info.New = true

View File

@ -132,13 +132,57 @@ After=network-online.target
[Service] [Service]
Restart=always Restart=always
ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid
ExecStart=/usr/bin/podman run --conmon-pidfile %t/%n-pid --cidfile %t/%n-cid --cgroups=no-conmon --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN ExecStart=/usr/bin/podman run --conmon-pidfile %t/%n-pid --cidfile %t/%n-cid --cgroups=no-conmon -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 42 ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 42
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid
PIDFile=%t/%n-pid PIDFile=%t/%n-pid
KillMode=none KillMode=none
Type=forking Type=forking
[Install]
WantedBy=multi-user.target`
goodNameNewDetach := `# 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]
Restart=always
ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid
ExecStart=/usr/bin/podman run --conmon-pidfile %t/%n-pid --cidfile %t/%n-cid --cgroups=no-conmon --detach --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 42
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid
PIDFile=%t/%n-pid
KillMode=none
Type=forking
[Install]
WantedBy=multi-user.target`
goodIdNew := `# container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
# autogenerated by Podman CI
[Unit]
Description=Podman container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
Documentation=man:podman-generate-systemd(1)
Wants=network.target
After=network-online.target
[Service]
Restart=always
ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid
ExecStart=/usr/bin/podman run --conmon-pidfile %t/%n-pid --cidfile %t/%n-cid --cgroups=no-conmon -d awesome-image:latest
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid
PIDFile=%t/%n-pid
KillMode=none
Type=forking
[Install] [Install]
WantedBy=multi-user.target` WantedBy=multi-user.target`
@ -230,6 +274,51 @@ WantedBy=multi-user.target`
goodNameNew, goodNameNew,
false, false,
}, },
{"good with explicit short detach param",
ContainerInfo{
Executable: "/usr/bin/podman",
ServiceName: "jadda-jadda",
ContainerName: "jadda-jadda",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
StopTimeout: 42,
PodmanVersion: "CI",
New: true,
CreateCommand: []string{"I'll get stripped", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
},
goodNameNew,
false,
},
{"good with explicit full detach param",
ContainerInfo{
Executable: "/usr/bin/podman",
ServiceName: "jadda-jadda",
ContainerName: "jadda-jadda",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
StopTimeout: 42,
PodmanVersion: "CI",
New: true,
CreateCommand: []string{"I'll get stripped", "container", "run", "--detach", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
},
goodNameNewDetach,
false,
},
{"good with id and no param",
ContainerInfo{
Executable: "/usr/bin/podman",
ServiceName: "container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
ContainerName: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
StopTimeout: 10,
PodmanVersion: "CI",
New: true,
CreateCommand: []string{"I'll get stripped", "container", "run", "awesome-image:latest"},
},
goodIdNew,
false,
},
} }
for _, tt := range tests { for _, tt := range tests {
test := tt test := tt

View File

@ -195,6 +195,34 @@ var _ = Describe("Podman generate systemd", func() {
Expect(found).To(BeTrue()) Expect(found).To(BeTrue())
}) })
It("podman generate systemd --new without explicit detaching param", func() {
n := podmanTest.Podman([]string{"create", "--name", "foo", "alpine", "top"})
n.WaitWithDefaultTimeout()
Expect(n.ExitCode()).To(Equal(0))
session := podmanTest.Podman([]string{"generate", "systemd", "--timeout", "42", "--name", "--new", "foo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
// Grepping the output (in addition to unit tests)
found, _ := session.GrepString("--cgroups=no-conmon -d")
Expect(found).To(BeTrue())
})
It("podman generate systemd --new with explicit detaching param in middle", func() {
n := podmanTest.Podman([]string{"create", "--name", "foo", "-d", "alpine", "top"})
n.WaitWithDefaultTimeout()
Expect(n.ExitCode()).To(Equal(0))
session := podmanTest.Podman([]string{"generate", "systemd", "--timeout", "42", "--name", "--new", "foo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
// Grepping the output (in addition to unit tests)
found, _ := session.GrepString("--name foo -d alpine top")
Expect(found).To(BeTrue())
})
It("podman generate systemd --new pod", func() { It("podman generate systemd --new pod", func() {
n := podmanTest.Podman([]string{"pod", "create", "--name", "foo"}) n := podmanTest.Podman([]string{"pod", "create", "--name", "foo"})
n.WaitWithDefaultTimeout() n.WaitWithDefaultTimeout()