Skip to content

Commit

Permalink
Add generate systemd -e/--env option
Browse files Browse the repository at this point in the history
-e/--env option sets environment variables to the systemd unit files.

Fixes: containers#15523

Signed-off-by: Toshiki Sonoda <sonoda.toshiki@fujitsu.com>
  • Loading branch information
sstosh committed Sep 1, 2022
1 parent 72f4c77 commit c85df72
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 15 deletions.
16 changes: 16 additions & 0 deletions cmd/podman/generate/systemd.go
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/pkg/domain/entities"
envLib "github.com/containers/podman/v4/pkg/env"
systemDefine "github.com/containers/podman/v4/pkg/systemd/define"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
Expand All @@ -28,9 +29,11 @@ const (
wantsFlagName = "wants"
afterFlagName = "after"
requiresFlagName = "requires"
envFlagName = "env"
)

var (
envInput []string
files bool
format string
systemdRestart string
Expand Down Expand Up @@ -109,6 +112,9 @@ func init() {
flags.StringArrayVar(&systemdOptions.Requires, requiresFlagName, nil, "Similar to wants, but declares stronger requirement dependencies")
_ = systemdCmd.RegisterFlagCompletionFunc(requiresFlagName, completion.AutocompleteNone)

flags.StringArrayVarP(&envInput, envFlagName, "e", []string{}, "Set environment variables to the systemd unit files")
_ = systemdCmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone)

flags.SetNormalizeFunc(utils.TimeoutAliasFlags)
}

Expand Down Expand Up @@ -141,6 +147,16 @@ func systemd(cmd *cobra.Command, args []string) error {
if cmd.Flags().Changed(stopTimeoutCompatFlagName) {
setStopTimeout++
}
if cmd.Flags().Changed(envFlagName) {
systemdOptions.Envs = make(map[string]string)

cliEnv, err := envLib.ParseSlice(envInput)
if err != nil {
return fmt.Errorf("error parsing environment variables: %w", err)
}

systemdOptions.Envs = envLib.Join(systemdOptions.Envs, cliEnv)
}
switch setStopTimeout {
case 1:
systemdOptions.StopTimeout = &stopTimeout
Expand Down
8 changes: 8 additions & 0 deletions docs/source/markdown/podman-generate-systemd.1.md
Expand Up @@ -44,6 +44,14 @@ User-defined dependencies will be appended to the generated unit file, but any e

Set the systemd unit name prefix for containers. The default is *container*.

#### **--env**, **-e**=*env*

Set environment variables to the systemd unit files.

This option allows arbitrary environment variables that are available for the process to be launched inside of the container. If an environment variable is specified without a value, Podman will check the host environment for a value and set the variable only if it is set on the host. As a special case, if an environment variable ending in __*__ is specified without a value, Podman will search the host environment for variables starting with the prefix and will add those variables to the container.

See [**Environment**](#environment) note below for precedence and examples.

#### **--files**, **-f**

Generate files instead of printing to stdout. The generated files are named {container,pod}-{ID,name}.service and will be placed in the current working directory.
Expand Down
30 changes: 16 additions & 14 deletions pkg/api/handlers/libpod/generate.go
Expand Up @@ -17,20 +17,21 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
query := struct {
Name bool `schema:"useName"`
New bool `schema:"new"`
NoHeader bool `schema:"noHeader"`
TemplateUnitFile bool `schema:"templateUnitFile"`
RestartPolicy *string `schema:"restartPolicy"`
RestartSec uint `schema:"restartSec"`
StopTimeout uint `schema:"stopTimeout"`
StartTimeout uint `schema:"startTimeout"`
ContainerPrefix *string `schema:"containerPrefix"`
PodPrefix *string `schema:"podPrefix"`
Separator *string `schema:"separator"`
Wants []string `schema:"wants"`
After []string `schema:"after"`
Requires []string `schema:"requires"`
Name bool `schema:"useName"`
New bool `schema:"new"`
NoHeader bool `schema:"noHeader"`
TemplateUnitFile bool `schema:"templateUnitFile"`
RestartPolicy *string `schema:"restartPolicy"`
RestartSec uint `schema:"restartSec"`
StopTimeout uint `schema:"stopTimeout"`
StartTimeout uint `schema:"startTimeout"`
ContainerPrefix *string `schema:"containerPrefix"`
PodPrefix *string `schema:"podPrefix"`
Separator *string `schema:"separator"`
Wants []string `schema:"wants"`
After []string `schema:"after"`
Requires []string `schema:"requires"`
Envs map[string]string `schema:"envs"`
}{
StartTimeout: 0,
StopTimeout: util.DefaultContainerConfig().Engine.StopTimeout,
Expand Down Expand Up @@ -72,6 +73,7 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
Wants: query.Wants,
After: query.After,
Requires: query.Requires,
Envs: query.Envs,
}

report, err := containerEngine.GenerateSystemd(r.Context(), utils.GetName(r), options)
Expand Down
2 changes: 2 additions & 0 deletions pkg/bindings/generate/types.go
Expand Up @@ -38,4 +38,6 @@ type SystemdOptions struct {
After *[]string
// Requires - systemd requires list for the container or pods
Requires *[]string
// Envs - environment variables setted by -e/--env
Envs map[string]string
}
15 changes: 15 additions & 0 deletions pkg/bindings/generate/types_systemd_options.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pkg/domain/entities/generate.go
Expand Up @@ -32,6 +32,8 @@ type GenerateSystemdOptions struct {
After []string
// Requires - systemd requires list for the container or pods
Requires []string
// Envs - environment variables setted by -e/--env
Envs map[string]string
}

// GenerateSystemdReport
Expand Down
3 changes: 2 additions & 1 deletion pkg/domain/infra/tunnel/generate.go
Expand Up @@ -19,7 +19,8 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string,
WithSeparator(opts.Separator).
WithWants(opts.Wants).
WithAfter(opts.After).
WithRequires(opts.Requires)
WithRequires(opts.Requires).
WithEnvs(opts.Envs)

if opts.StartTimeout != nil {
options.WithStartTimeout(*opts.StartTimeout)
Expand Down
8 changes: 8 additions & 0 deletions pkg/systemd/generate/containers.go
Expand Up @@ -69,6 +69,9 @@ type containerInfo struct {
ExtraEnvs []string
// EnvVariable is generate.EnvVariable and must not be set.
EnvVariable string
// OptEnvs contains the container environment variables setted by
// -e/--env options.
OptEnvs map[string]string
// ExecStartPre of the unit.
ExecStartPre string
// ExecStart of the unit.
Expand Down Expand Up @@ -127,6 +130,10 @@ Environment={{{{.EnvVariable}}}}=%n{{{{- if (eq .IdentifySpecifier true) }}}}-%i
{{{{- if .ExtraEnvs}}}}
Environment={{{{- range $index, $value := .ExtraEnvs -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}{{{{end}}}}
{{{{- end}}}}
{{{{- if .OptEnvs}}}}
{{{{- range $index, $value := .OptEnvs -}}}}{{{{if $index}}}}{{{{end}}}}
Environment={{{{ $index }}}}={{{{ $value }}}}{{{{end}}}}
{{{{- end}}}}
Restart={{{{.RestartPolicy}}}}
{{{{- if .StartLimitBurst}}}}
StartLimitBurst={{{{.StartLimitBurst}}}}
Expand Down Expand Up @@ -321,6 +328,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst

info.Type = "forking"
info.EnvVariable = define.EnvVariable
info.OptEnvs = options.Envs
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}}}}"
Expand Down
28 changes: 28 additions & 0 deletions test/e2e/generate_systemd_test.go
Expand Up @@ -600,4 +600,32 @@ var _ = Describe("Podman generate systemd", func() {
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring(" --label key={{someval}}"))
})

It("podman generate systemd --env", func() {
session := podmanTest.RunTopContainer("test")
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))

session = podmanTest.Podman([]string{"generate", "systemd", "--env", "foo=bar", "-e", "hoge=fuga", "test"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring("Environment=foo=bar"))
Expect(session.OutputToString()).To(ContainSubstring("Environment=hoge=fuga"))

session = podmanTest.Podman([]string{"generate", "systemd", "--env", "=bar", "-e", "hoge=fuga", "test"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(125))
Expect(session.ErrorToString()).To(ContainSubstring("invalid environment variable"))

session = podmanTest.Podman([]string{"generate", "systemd", "--env", "foo=bar", "-e", "hoge=fuga", "--new", "test"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring("Environment=foo=bar"))
Expect(session.OutputToString()).To(ContainSubstring("Environment=hoge=fuga"))

session = podmanTest.Podman([]string{"generate", "systemd", "--env", "foo=bar", "-e", "=fuga", "--new", "test"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(125))
Expect(session.ErrorToString()).To(ContainSubstring("invalid environment variable"))
})
})

0 comments on commit c85df72

Please sign in to comment.