Separator is no longer prepended when prefix is empty on podman generate systemd

When podman generate systemd is invoked, it previously did not check if
container-prefix or pod-prefix are empty. When these are empty, the file name
starts with the separator, which is hyphen by default. This results in files
like '-containername.service'.

The code now checks if these prefixes are empty. If they are, the filename no
longer adds a separator. Instead, it uses name or ID of the container or pod.

Closes #13272

Signed-off-by: Nirmal Patel <npate012@gmail.com>
This commit is contained in:
Nirmal Patel 2022-02-19 17:55:23 -05:00
parent b1d37a7e21
commit 714e5a13d9
7 changed files with 180 additions and 13 deletions

View File

@ -25,18 +25,15 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
RestartSec uint `schema:"restartSec"`
StopTimeout uint `schema:"stopTimeout"`
StartTimeout uint `schema:"startTimeout"`
ContainerPrefix string `schema:"containerPrefix"`
PodPrefix string `schema:"podPrefix"`
Separator string `schema:"separator"`
ContainerPrefix *string `schema:"containerPrefix"`
PodPrefix *string `schema:"podPrefix"`
Separator *string `schema:"separator"`
Wants []string `schema:"wants"`
After []string `schema:"after"`
Requires []string `schema:"requires"`
}{
StartTimeout: 0,
StopTimeout: util.DefaultContainerConfig().Engine.StopTimeout,
ContainerPrefix: "container",
PodPrefix: "pod",
Separator: "-",
StartTimeout: 0,
StopTimeout: util.DefaultContainerConfig().Engine.StopTimeout,
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
@ -44,6 +41,21 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
return
}
var ContainerPrefix = "container"
if query.ContainerPrefix != nil {
ContainerPrefix = *query.ContainerPrefix
}
var PodPrefix = "pod"
if query.PodPrefix != nil {
PodPrefix = *query.PodPrefix
}
var Separator = "-"
if query.Separator != nil {
Separator = *query.Separator
}
containerEngine := abi.ContainerEngine{Libpod: runtime}
options := entities.GenerateSystemdOptions{
Name: query.Name,
@ -53,9 +65,9 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
RestartPolicy: query.RestartPolicy,
StartTimeout: &query.StartTimeout,
StopTimeout: &query.StopTimeout,
ContainerPrefix: query.ContainerPrefix,
PodPrefix: query.PodPrefix,
Separator: query.Separator,
ContainerPrefix: ContainerPrefix,
PodPrefix: PodPrefix,
Separator: Separator,
RestartSec: &query.RestartSec,
Wants: query.Wants,
After: query.After,

View File

@ -137,3 +137,17 @@ func removeArg(arg string, args []string) []string {
}
return newArgs
}
// This function is used to get name of systemd service from prefix, separator, and
// container/pod name. If prefix is empty, the service name does not include the
// separator. This is to avoid a situation where service name starts with the separator
// which is usually hyphen.
func getServiceName(prefix string, separator string, name string) string {
serviceName := name
if len(prefix) > 0 {
serviceName = prefix + separator + name
}
return serviceName
}

View File

@ -236,7 +236,9 @@ func containerServiceName(ctr *libpod.Container, options entities.GenerateSystem
if options.Name {
nameOrID = ctr.Name()
}
serviceName := fmt.Sprintf("%s%s%s", options.ContainerPrefix, options.Separator, nameOrID)
serviceName := getServiceName(options.ContainerPrefix, options.Separator, nameOrID)
return nameOrID, serviceName
}

View File

@ -87,6 +87,30 @@ ExecStopPost=/usr/bin/podman stop -t 10 foobar
PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
WantedBy=default.target
`
goodNameEmptyContainerPrefix := `# foobar.service
# autogenerated by Podman CI
[Unit]
Description=Podman foobar.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/var/run/containers/storage
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman start foobar
ExecStop=/usr/bin/podman stop -t 10 foobar
ExecStopPost=/usr/bin/podman stop -t 10 foobar
PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
WantedBy=default.target
`
@ -1206,6 +1230,24 @@ WantedBy=default.target
false,
true,
},
{"good with name and empty container-prefix",
containerInfo{
Executable: "/usr/bin/podman",
ServiceName: "foobar",
ContainerNameOrID: "foobar",
PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
StopTimeout: 10,
PodmanVersion: "CI",
EnvVariable: define.EnvVariable,
GraphRoot: "/var/lib/containers/storage",
RunRoot: "/var/run/containers/storage",
},
goodNameEmptyContainerPrefix,
false,
false,
false,
false,
},
}
for _, tt := range tests {
test := tt

View File

@ -242,7 +242,8 @@ func generatePodInfo(pod *libpod.Pod, options entities.GenerateSystemdOptions) (
nameOrID = pod.Name()
ctrNameOrID = infraCtr.Name()
}
serviceName := fmt.Sprintf("%s%s%s", options.PodPrefix, options.Separator, nameOrID)
serviceName := getServiceName(options.PodPrefix, options.Separator, nameOrID)
info := podInfo{
ServiceName: serviceName,

View File

@ -67,6 +67,32 @@ WantedBy=default.target
podGood := serviceInfo + headerInfo + podContent
podGoodNoHeaderInfo := serviceInfo + podContent
podGoodWithEmptyPrefix := `# 123abc.service
# autogenerated by Podman CI
[Unit]
Description=Podman 123abc.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/var/run/containers/storage
Requires=container-1.service container-2.service
Before=container-1.service container-2.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=102
ExecStart=/usr/bin/podman start jadda-jadda-infra
ExecStop=/usr/bin/podman stop -t 42 jadda-jadda-infra
ExecStopPost=/usr/bin/podman stop -t 42 jadda-jadda-infra
PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
WantedBy=default.target
`
podGoodCustomWants := `# pod-123abc.service
# autogenerated by Podman CI
@ -580,6 +606,24 @@ WantedBy=default.target
false,
false,
},
{"pod with empty pod-prefix",
podInfo{
Executable: "/usr/bin/podman",
ServiceName: "123abc",
InfraNameOrID: "jadda-jadda-infra",
PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
StopTimeout: 42,
PodmanVersion: "CI",
GraphRoot: "/var/lib/containers/storage",
RunRoot: "/var/run/containers/storage",
RequiredServices: []string{"container-1", "container-2"},
CreateCommand: []string{"podman", "pod", "create", "--name", "foo", "bar=arg with space"},
},
podGoodWithEmptyPrefix,
false,
false,
false,
},
}
for _, tt := range tests {

View File

@ -423,6 +423,20 @@ var _ = Describe("Podman generate systemd", func() {
})
It("podman generate systemd --container-prefix ''", func() {
n := podmanTest.Podman([]string{"create", "--name", "foo", "alpine", "top"})
n.WaitWithDefaultTimeout()
Expect(n).Should(Exit(0))
session := podmanTest.Podman([]string{"generate", "systemd", "--name", "--container-prefix", "", "foo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
// Grepping the output (in addition to unit tests)
Expect(session.OutputToString()).To(ContainSubstring("# foo.service"))
})
It("podman generate systemd --separator _", func() {
n := podmanTest.Podman([]string{"create", "--name", "foo", "alpine", "top"})
n.WaitWithDefaultTimeout()
@ -485,6 +499,44 @@ var _ = Describe("Podman generate systemd", func() {
Expect(session.OutputToString()).To(ContainSubstring("BindsTo=p_foo.service"))
})
It("podman generate systemd pod --pod-prefix '' --container-prefix '' --separator _ change all prefixes/separator", func() {
n := podmanTest.Podman([]string{"pod", "create", "--name", "foo"})
n.WaitWithDefaultTimeout()
Expect(n).Should(Exit(0))
n = podmanTest.Podman([]string{"create", "--pod", "foo", "--name", "foo-1", "alpine", "top"})
n.WaitWithDefaultTimeout()
Expect(n).Should(Exit(0))
n = podmanTest.Podman([]string{"create", "--pod", "foo", "--name", "foo-2", "alpine", "top"})
n.WaitWithDefaultTimeout()
Expect(n).Should(Exit(0))
// test systemd generate with empty pod prefix
session1 := podmanTest.Podman([]string{"generate", "systemd", "--pod-prefix", "", "--name", "foo"})
session1.WaitWithDefaultTimeout()
Expect(session1).Should(Exit(0))
// Grepping the output (in addition to unit tests)
Expect(session1.OutputToString()).To(ContainSubstring("# foo.service"))
Expect(session1.OutputToString()).To(ContainSubstring("Requires=container-foo-1.service container-foo-2.service"))
Expect(session1.OutputToString()).To(ContainSubstring("# container-foo-1.service"))
Expect(session1.OutputToString()).To(ContainSubstring("BindsTo=foo.service"))
// test systemd generate with empty container and pod prefix
session2 := podmanTest.Podman([]string{"generate", "systemd", "--container-prefix", "", "--pod-prefix", "", "--separator", "_", "--name", "foo"})
session2.WaitWithDefaultTimeout()
Expect(session2).Should(Exit(0))
// Grepping the output (in addition to unit tests)
Expect(session2.OutputToString()).To(ContainSubstring("# foo.service"))
Expect(session2.OutputToString()).To(ContainSubstring("Requires=foo-1.service foo-2.service"))
Expect(session2.OutputToString()).To(ContainSubstring("# foo-1.service"))
Expect(session2.OutputToString()).To(ContainSubstring("# foo-2.service"))
Expect(session2.OutputToString()).To(ContainSubstring("BindsTo=foo.service"))
})
It("podman generate systemd pod with containers --new", func() {
tmpDir, err := ioutil.TempDir("", "")
Expect(err).To(BeNil())