diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/compat/containers.go | 55 | ||||
-rw-r--r-- | pkg/bindings/containers/containers.go | 12 | ||||
-rw-r--r-- | pkg/bindings/containers/types.go | 2 | ||||
-rw-r--r-- | pkg/bindings/containers/types_remove_options.go | 32 | ||||
-rw-r--r-- | pkg/domain/entities/containers.go | 11 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 30 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 8 | ||||
-rw-r--r-- | pkg/specgen/generate/container.go | 8 | ||||
-rw-r--r-- | pkg/systemd/generate/common.go | 12 | ||||
-rw-r--r-- | pkg/systemd/generate/containers.go | 48 | ||||
-rw-r--r-- | pkg/systemd/generate/containers_test.go | 39 | ||||
-rw-r--r-- | pkg/systemd/generate/pods.go | 52 | ||||
-rw-r--r-- | pkg/systemd/generate/pods_test.go | 43 |
13 files changed, 243 insertions, 109 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 6e1945db1..aa12afc82 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -14,7 +14,9 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/api/handlers/utils" + "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/filters" + "github.com/containers/podman/v2/pkg/domain/infra/abi" "github.com/containers/podman/v2/pkg/ps" "github.com/containers/podman/v2/pkg/signal" "github.com/docker/docker/api/types" @@ -29,9 +31,11 @@ import ( func RemoveContainer(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - Force bool `schema:"force"` - Vols bool `schema:"v"` - Link bool `schema:"link"` + All bool `schema:"all"` + Force bool `schema:"force"` + Ignore bool `schema:"ignore"` + Link bool `schema:"link"` + Volumes bool `schema:"v"` }{ // override any golang type defaults } @@ -49,34 +53,31 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) { } runtime := r.Context().Value("runtime").(*libpod.Runtime) + // Now use the ABI implementation to prevent us from having duplicate + // code. + containerEngine := abi.ContainerEngine{Libpod: runtime} name := utils.GetName(r) - con, err := runtime.LookupContainer(name) - if err != nil && errors.Cause(err) == define.ErrNoSuchCtr { - // Failed to get container. If force is specified, get the container's ID - // and evict it - if !query.Force { + options := entities.RmOptions{ + All: query.All, + Force: query.Force, + Volumes: query.Volumes, + Ignore: query.Ignore, + } + report, err := containerEngine.ContainerRm(r.Context(), []string{name}, options) + if err != nil { + if errors.Cause(err) == define.ErrNoSuchCtr { utils.ContainerNotFound(w, name, err) return } - if _, err := runtime.EvictContainer(r.Context(), name, query.Vols); err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { - logrus.Debugf("Ignoring error (--allow-missing): %q", err) - w.WriteHeader(http.StatusNoContent) - return - } - logrus.Warn(errors.Wrapf(err, "failed to evict container: %q", name)) - utils.InternalServerError(w, err) - return - } - w.WriteHeader(http.StatusNoContent) + utils.InternalServerError(w, err) return } - - if err := runtime.RemoveContainer(r.Context(), con, query.Force, query.Vols); err != nil { - utils.InternalServerError(w, err) + if report[0].Err != nil { + utils.InternalServerError(w, report[0].Err) return } + utils.WriteResponse(w, http.StatusNoContent, nil) } @@ -326,6 +327,11 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON, state.Running = true } + // docker calls the configured state "created" + if state.Status == define.ContainerStateConfigured.String() { + state.Status = define.ContainerStateCreated.String() + } + formatCapabilities(inspect.HostConfig.CapDrop) formatCapabilities(inspect.HostConfig.CapAdd) @@ -337,6 +343,11 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON, if err := json.Unmarshal(h, &hc); err != nil { return nil, err } + + // k8s-file == json-file + if hc.LogConfig.Type == define.KubernetesLogging { + hc.LogConfig.Type = define.JSONLogging + } g, err := json.Marshal(inspect.GraphDriver) if err != nil { return nil, err diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go index 73e4d1d3d..40fcfbded 100644 --- a/pkg/bindings/containers/containers.go +++ b/pkg/bindings/containers/containers.go @@ -71,8 +71,10 @@ func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, } // Remove removes a container from local storage. The force bool designates -// that the container should be removed forcibly (example, even it is running). The volumes -// bool dictates that a container's volumes should also be removed. +// that the container should be removed forcibly (example, even it is running). +// The volumes bool dictates that a container's volumes should also be removed. +// The All option indicates that all containers should be removed +// The Ignore option indicates that if a container did not exist, ignore the error func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error { if options == nil { options = new(RemoveOptions) @@ -85,9 +87,15 @@ func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error if v := options.GetVolumes(); options.Changed("Volumes") { params.Set("v", strconv.FormatBool(v)) } + if all := options.GetAll(); options.Changed("All") { + params.Set("all", strconv.FormatBool(all)) + } if force := options.GetForce(); options.Changed("Force") { params.Set("force", strconv.FormatBool(force)) } + if ignore := options.GetIgnore(); options.Changed("Ignore") { + params.Set("ignore", strconv.FormatBool(ignore)) + } response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID) if err != nil { return err diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go index 43cb58a54..24604fa83 100644 --- a/pkg/bindings/containers/types.go +++ b/pkg/bindings/containers/types.go @@ -122,6 +122,8 @@ type PruneOptions struct { //go:generate go run ../generator/generator.go RemoveOptions // RemoveOptions are optional options for removing containers type RemoveOptions struct { + All *bool + Ignore *bool Force *bool Volumes *bool } diff --git a/pkg/bindings/containers/types_remove_options.go b/pkg/bindings/containers/types_remove_options.go index e21fb41f7..3ef32fa03 100644 --- a/pkg/bindings/containers/types_remove_options.go +++ b/pkg/bindings/containers/types_remove_options.go @@ -87,6 +87,38 @@ func (o *RemoveOptions) ToParams() (url.Values, error) { return params, nil } +// WithAll +func (o *RemoveOptions) WithAll(value bool) *RemoveOptions { + v := &value + o.All = v + return o +} + +// GetAll +func (o *RemoveOptions) GetAll() bool { + var all bool + if o.All == nil { + return all + } + return *o.All +} + +// WithIgnore +func (o *RemoveOptions) WithIgnore(value bool) *RemoveOptions { + v := &value + o.Ignore = v + return o +} + +// GetIgnore +func (o *RemoveOptions) GetIgnore() bool { + var ignore bool + if o.Ignore == nil { + return ignore + } + return *o.Ignore +} + // WithForce func (o *RemoveOptions) WithForce(value bool) *RemoveOptions { v := &value diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index d8576c101..4c1bd6a7d 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -128,12 +128,11 @@ type RestartReport struct { } type RmOptions struct { - All bool - CIDFiles []string - Force bool - Ignore bool - Latest bool - Volumes bool + All bool + Force bool + Ignore bool + Latest bool + Volumes bool } type RmReport struct { diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index a8f4d44a8..48a32817d 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -264,30 +264,30 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, reports := []*entities.RmReport{} names := namesOrIds - for _, cidFile := range options.CIDFiles { - content, err := ioutil.ReadFile(cidFile) - if err != nil { - return nil, errors.Wrap(err, "error reading CIDFile") - } - id := strings.Split(string(content), "\n")[0] - names = append(names, id) - } - // Attempt to remove named containers directly from storage, if container is defined in libpod // this will fail and code will fall through to removing the container from libpod.` tmpNames := []string{} for _, ctr := range names { report := entities.RmReport{Id: ctr} - if err := ic.Libpod.RemoveStorageContainer(ctr, options.Force); err != nil { + report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force) + switch errors.Cause(report.Err) { + case nil: // remove container names that we successfully deleted - tmpNames = append(tmpNames, ctr) - } else { reports = append(reports, &report) + case define.ErrNoSuchCtr: + // There is still a potential this is a libpod container + tmpNames = append(tmpNames, ctr) + default: + if _, err := ic.Libpod.LookupContainer(ctr); errors.Cause(err) == define.ErrNoSuchCtr { + // remove container failed, but not a libpod container + reports = append(reports, &report) + continue + } + // attempt to remove as a libpod container + tmpNames = append(tmpNames, ctr) } } - if len(tmpNames) < len(names) { - names = tmpNames - } + names = tmpNames ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod) if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) { diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 84a07f8e9..524b29553 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -173,14 +173,6 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st } func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, opts entities.RmOptions) ([]*entities.RmReport, error) { - for _, cidFile := range opts.CIDFiles { - content, err := ioutil.ReadFile(cidFile) - if err != nil { - return nil, errors.Wrap(err, "error reading CIDFile") - } - id := strings.Split(string(content), "\n")[0] - namesOrIds = append(namesOrIds, id) - } ctrs, err := getContainersByContext(ic.ClientCtx, opts.All, opts.Ignore, namesOrIds) if err != nil { return nil, err diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 2feb1d3b2..cc3f7928c 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -257,6 +257,14 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat } } + if s.LogConfiguration == nil { + s.LogConfiguration = &specgen.LogConfig{} + } + // set log-driver from common if not already set + if len(s.LogConfiguration.Driver) < 1 { + s.LogConfiguration.Driver = rtc.Containers.LogDriver + } + warnings, err := verifyContainerResources(s) if err != nil { return warnings, err diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go index 8901298db..de6751a17 100644 --- a/pkg/systemd/generate/common.go +++ b/pkg/systemd/generate/common.go @@ -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 diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go index b64b2593c..5f52b0a77 100644 --- a/pkg/systemd/generate/containers.go +++ b/pkg/systemd/generate/containers.go @@ -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") } diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go index c8e65bfe3..96d95644b 100644 --- a/pkg/systemd/generate/containers_test.go +++ b/pkg/systemd/generate/containers_test.go @@ -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 diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go index 7678a240f..c7e3aa955 100644 --- a/pkg/systemd/generate/pods.go +++ b/pkg/systemd/generate/pods.go @@ -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") } diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go index 1c6330160..2b430226b 100644 --- a/pkg/systemd/generate/pods_test.go +++ b/pkg/systemd/generate/pods_test.go @@ -143,6 +143,33 @@ Type=forking 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 +` + tests := []struct { name string info podInfo @@ -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 { |