mirror of
https://github.com/containers/podman.git
synced 2025-06-22 09:58:10 +08:00
@ -136,12 +136,18 @@ type ExportValues struct {
|
||||
PodmanCommand
|
||||
Output string
|
||||
}
|
||||
|
||||
type GenerateKubeValues struct {
|
||||
PodmanCommand
|
||||
Service bool
|
||||
}
|
||||
|
||||
type GenerateSystemdValues struct {
|
||||
PodmanCommand
|
||||
Name bool
|
||||
RestartPolicy string
|
||||
StopTimeout int
|
||||
}
|
||||
|
||||
type HistoryValues struct {
|
||||
PodmanCommand
|
||||
Human bool
|
||||
|
@ -18,6 +18,7 @@ var (
|
||||
// Commands that are universally implemented
|
||||
generateCommands = []*cobra.Command{
|
||||
_containerKubeCommand,
|
||||
_containerSystemdCommand,
|
||||
}
|
||||
)
|
||||
|
||||
|
70
cmd/podman/generate_systemd.go
Normal file
70
cmd/podman/generate_systemd.go
Normal file
@ -0,0 +1,70 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||
"github.com/containers/libpod/pkg/adapter"
|
||||
"github.com/containers/libpod/pkg/systemdgen"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
containerSystemdCommand cliconfig.GenerateSystemdValues
|
||||
containerSystemdDescription = `Command generates a systemd unit file for a Podman container
|
||||
`
|
||||
_containerSystemdCommand = &cobra.Command{
|
||||
Use: "systemd [flags] CONTAINER | POD",
|
||||
Short: "Generate a systemd unit file for a Podman container",
|
||||
Long: containerSystemdDescription,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
containerSystemdCommand.InputArgs = args
|
||||
containerSystemdCommand.GlobalFlags = MainGlobalOpts
|
||||
containerSystemdCommand.Remote = remoteclient
|
||||
return generateSystemdCmd(&containerSystemdCommand)
|
||||
},
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) > 1 || len(args) < 1 {
|
||||
return errors.New("provide only one container name or ID")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Example: `podman generate kube ctrID
|
||||
`,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
containerSystemdCommand.Command = _containerSystemdCommand
|
||||
containerSystemdCommand.SetHelpTemplate(HelpTemplate())
|
||||
containerSystemdCommand.SetUsageTemplate(UsageTemplate())
|
||||
flags := containerSystemdCommand.Flags()
|
||||
flags.BoolVarP(&containerSystemdCommand.Name, "name", "n", false, "use the container name instead of ID")
|
||||
flags.IntVarP(&containerSystemdCommand.StopTimeout, "timeout", "t", -1, "stop timeout override")
|
||||
flags.StringVar(&containerSystemdCommand.RestartPolicy, "restart-policy", "on-failure", "applicable systemd restart-policy")
|
||||
}
|
||||
|
||||
func generateSystemdCmd(c *cliconfig.GenerateSystemdValues) error {
|
||||
runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
// User input stop timeout must be 0 or greater
|
||||
if c.Flag("timeout").Changed && c.StopTimeout < 0 {
|
||||
return errors.New("timeout value must be 0 or greater")
|
||||
}
|
||||
// Make sure the input restart policy is valid
|
||||
if err := systemdgen.ValidateRestartPolicy(c.RestartPolicy); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
unit, err := runtime.GenerateSystemd(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(unit)
|
||||
return nil
|
||||
}
|
@ -1218,6 +1218,8 @@ method GetLayersMapWithImageInfo() -> (layerMap: string)
|
||||
# BuildImageHierarchyMap is for the development of Podman and should not be used.
|
||||
method BuildImageHierarchyMap(name: string) -> (imageInfo: string)
|
||||
|
||||
method GenerateSystemd(name: string, restart: string, timeout: int, useName: bool) -> (unit: string)
|
||||
|
||||
# ImageNotFound means the image could not be found by the provided name or ID in local storage.
|
||||
error ImageNotFound (id: string, reason: string)
|
||||
|
||||
|
@ -25,6 +25,8 @@ Command | Descr
|
||||
[podman-exec(1)](/docs/podman-exec.1.md) | Execute a command in a running container |
|
||||
[podman-export(1)](/docs/podman-export.1.md) | Export container's filesystem contents as a tar archive |
|
||||
[podman-generate(1)](/docs/podman-generate.1.md) | Generate structured output based on Podman containers and pods |
|
||||
[podman-generate-kube(1)](/docs/podman-generate-kube.1.md) | Generate Kubernetes YAML based on a container or Pod |
|
||||
[podman-generate-systemd(1)](/docs/podman-generate-systemd.1.md) | Generate a Systemd unit file for a container |
|
||||
[podman-history(1)](/docs/podman-history.1.md) | Shows the history of an image |
|
||||
[podman-image(1)](/docs/podman-image.1.md) | Manage Images |
|
||||
[podman-image-exists(1)](/docs/podman-image-exists.1.md) | Check if an image exists in local storage |
|
||||
|
@ -919,6 +919,7 @@ _podman_generate() {
|
||||
"
|
||||
subcommands="
|
||||
kube
|
||||
systemd
|
||||
"
|
||||
__podman_subcommands "$subcommands $aliases" && return
|
||||
|
||||
@ -2460,6 +2461,32 @@ _podman_generate_kube() {
|
||||
esac
|
||||
}
|
||||
|
||||
_podman_generate_systemd() {
|
||||
local options_with_args="
|
||||
--restart-policy
|
||||
-t
|
||||
--timeout"
|
||||
|
||||
local boolean_options="
|
||||
-h
|
||||
--help
|
||||
-n
|
||||
--name
|
||||
"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=( $( compgen -W "
|
||||
$(__podman_containers --all)
|
||||
" -- "$cur" ) )
|
||||
__ltrim_colon_completions "$cur"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_podman_play_kube() {
|
||||
local options_with_args="
|
||||
--authfile
|
||||
|
69
docs/podman-generate-systemd.1.md
Normal file
69
docs/podman-generate-systemd.1.md
Normal file
@ -0,0 +1,69 @@
|
||||
% podman-generate Podman Man Pages
|
||||
% Brent Baude
|
||||
% April 2019
|
||||
# NAME
|
||||
podman-generate-systemd- Generate Systemd Unit file
|
||||
|
||||
# SYNOPSIS
|
||||
**podman generate systemd** [*-n*|*--name*] [*-t*|*--timeout*] [*--restart-policy*] *container*
|
||||
|
||||
# DESCRIPTION
|
||||
**podman generate systemd** will create a Systemd unit file that can be used to control a container. The
|
||||
command will dynamically create the unit file and output it to stdout where it can be piped by the user
|
||||
to a file. The options can be used to influence the results of the output as well.
|
||||
|
||||
|
||||
# OPTIONS:
|
||||
|
||||
**--name** **-n**
|
||||
|
||||
Use the name of the container for the start, stop, and description in the unit file
|
||||
|
||||
**--timeout** **-t**
|
||||
|
||||
Override the default stop timeout for the container with the given value.
|
||||
|
||||
**--restart-policy**
|
||||
Set the SystemD restart policy. The restart-policy must be one of: "no", "on-success", "on-failure", "on-abnormal",
|
||||
"on-watchdog", "on-abort", or "always". The default policy is *on-failure*.
|
||||
|
||||
## Examples ##
|
||||
|
||||
Create a systemd unit file for a container running nginx:
|
||||
|
||||
```
|
||||
$ sudo podman generate systemd nginx
|
||||
[Unit]
|
||||
Description=c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc Podman Container
|
||||
[Service]
|
||||
Restart=on-failure
|
||||
ExecStart=/usr/bin/podman start c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc
|
||||
ExecStop=/usr/bin/podman stop -t 10 c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc
|
||||
KillMode=none
|
||||
Type=forking
|
||||
PIDFile=/var/lib/containers/storage/overlay-containers/c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc/userdata/c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc.pid
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Create a systemd unit file for a container running nginx with an *always* restart policy and 1-second timeout.
|
||||
```
|
||||
$ sudo podman generate systemd --restart-policy=always -t 1 nginx
|
||||
[Unit]
|
||||
Description=c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc Podman Container
|
||||
[Service]
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/podman start c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc
|
||||
ExecStop=/usr/bin/podman stop -t 1 c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc
|
||||
KillMode=none
|
||||
Type=forking
|
||||
PIDFile=/var/lib/containers/storage/overlay-containers/c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc/userdata/c21da63c4783be2ac2cd3487ef8d2ec15ee2a28f63dd8f145e3b05607f31cffc.pid
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
podman(1), podman-container(1)
|
||||
|
||||
# HISTORY
|
||||
April 2019, Originally compiled by Brent Baude (bbaude at redhat dot com)
|
@ -14,6 +14,7 @@ The generate command will create structured output (like YAML) based on a contai
|
||||
| Command | Man Page | Description |
|
||||
| ------- | --------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||||
| kube | [podman-generate-kube(1)](podman-generate-kube.1.md)| Generate Kubernetes YAML based on a pod or container. |
|
||||
| systemd | [podman-generate-systemd(1)](podman-generate-systemd.1.md)| Generate a systemd unit file for a container. |
|
||||
|
||||
## SEE ALSO
|
||||
podman, podman-pod, podman-container
|
||||
|
@ -593,7 +593,7 @@ Not implemented.
|
||||
|
||||
Restart should be handled via a systemd unit files. Please add your podman
|
||||
commands to a unit file and allow systemd or your init system to handle the
|
||||
restarting of the container processes. See example below.
|
||||
restarting of the container processes. See *podman generate systemd*.
|
||||
|
||||
**--rm**=*true*|*false*
|
||||
|
||||
@ -1151,21 +1151,6 @@ the uids and gids from the host.
|
||||
$ podman run --uidmap 0:30000:7000 --gidmap 0:30000:7000 fedora echo hello
|
||||
```
|
||||
|
||||
### Running a podman container to restart inside of a systemd unit file
|
||||
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=My App
|
||||
[Service]
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/podman start -a my_app
|
||||
ExecStop=/usr/bin/podman stop -t 10 my_app
|
||||
KillMode=process
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### Configuring Storage Options from the command line
|
||||
|
||||
Podman allows for the configuration of storage by changing the values
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"github.com/containers/libpod/cmd/podman/shared"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/pkg/adapter/shortcuts"
|
||||
"github.com/containers/libpod/pkg/systemdgen"
|
||||
"github.com/containers/storage"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -940,3 +941,20 @@ func (r *LocalRuntime) Port(c *cliconfig.PortValues) ([]*Container, error) {
|
||||
}
|
||||
return portContainers, nil
|
||||
}
|
||||
|
||||
// GenerateSystemd creates a unit file for a container
|
||||
func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (string, error) {
|
||||
ctr, err := r.Runtime.LookupContainer(c.InputArgs[0])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
timeout := int(ctr.StopTimeout())
|
||||
if c.StopTimeout >= 0 {
|
||||
timeout = int(c.StopTimeout)
|
||||
}
|
||||
name := ctr.ID()
|
||||
if c.Name {
|
||||
name = ctr.Name()
|
||||
}
|
||||
return systemdgen.CreateSystemdUnitAsString(name, ctr.ID(), c.RestartPolicy, ctr.Config().StaticDir, timeout)
|
||||
}
|
||||
|
@ -956,3 +956,8 @@ func (r *LocalRuntime) Port(c *cliconfig.PortValues) ([]*Container, error) {
|
||||
}
|
||||
return containers, nil
|
||||
}
|
||||
|
||||
// GenerateSystemd creates a systemd until for a container
|
||||
func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (string, error) {
|
||||
return iopodman.GenerateSystemd().Call(r.Conn, c.InputArgs[0], c.RestartPolicy, int64(c.StopTimeout), c.Name)
|
||||
}
|
||||
|
43
pkg/systemdgen/systemdgen.go
Normal file
43
pkg/systemdgen/systemdgen.go
Normal file
@ -0,0 +1,43 @@
|
||||
package systemdgen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var template = `[Unit]
|
||||
Description=%s Podman Container
|
||||
[Service]
|
||||
Restart=%s
|
||||
ExecStart=/usr/bin/podman start %s
|
||||
ExecStop=/usr/bin/podman stop -t %d %s
|
||||
KillMode=none
|
||||
Type=forking
|
||||
PIDFile=%s
|
||||
[Install]
|
||||
WantedBy=multi-user.target`
|
||||
|
||||
var restartPolicies = []string{"no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always"}
|
||||
|
||||
// ValidateRestartPolicy checks that the user-provided policy is valid
|
||||
func ValidateRestartPolicy(restart string) error {
|
||||
for _, i := range restartPolicies {
|
||||
if i == restart {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.Errorf("%s is not a valid restart policy", restart)
|
||||
}
|
||||
|
||||
// CreateSystemdUnitAsString takes variables to create a systemd unit file used to control
|
||||
// a libpod container
|
||||
func CreateSystemdUnitAsString(name, cid, restart, pidPath string, stopTimeout int) (string, error) {
|
||||
if err := ValidateRestartPolicy(restart); err != nil {
|
||||
return "", err
|
||||
}
|
||||
pidFile := filepath.Join(pidPath, fmt.Sprintf("%s.pid", cid))
|
||||
unit := fmt.Sprintf(template, name, restart, name, stopTimeout, name, pidFile)
|
||||
return unit, nil
|
||||
}
|
@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"github.com/containers/libpod/cmd/podman/shared"
|
||||
iopodman "github.com/containers/libpod/cmd/podman/varlink"
|
||||
"github.com/containers/libpod/pkg/systemdgen"
|
||||
)
|
||||
|
||||
// GenerateKube ...
|
||||
@ -28,3 +29,24 @@ func (i *LibpodAPI) GenerateKube(call iopodman.VarlinkCall, name string, service
|
||||
Service: string(servB),
|
||||
})
|
||||
}
|
||||
|
||||
// GenerateSystemd ...
|
||||
func (i *LibpodAPI) GenerateSystemd(call iopodman.VarlinkCall, nameOrID, restart string, stopTimeout int64, useName bool) error {
|
||||
ctr, err := i.Runtime.LookupContainer(nameOrID)
|
||||
if err != nil {
|
||||
return call.ReplyErrorOccurred(err.Error())
|
||||
}
|
||||
timeout := int(ctr.StopTimeout())
|
||||
if stopTimeout >= 0 {
|
||||
timeout = int(stopTimeout)
|
||||
}
|
||||
name := ctr.ID()
|
||||
if useName {
|
||||
name = ctr.Name()
|
||||
}
|
||||
unit, err := systemdgen.CreateSystemdUnitAsString(name, ctr.ID(), restart, ctr.Config().StaticDir, timeout)
|
||||
if err != nil {
|
||||
return call.ReplyErrorOccurred(err.Error())
|
||||
}
|
||||
return call.ReplyGenerateSystemd(unit)
|
||||
}
|
||||
|
74
test/e2e/generate_systemd_test.go
Normal file
74
test/e2e/generate_systemd_test.go
Normal file
@ -0,0 +1,74 @@
|
||||
// +build !remoteclient
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
. "github.com/containers/libpod/test/utils"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"os"
|
||||
)
|
||||
|
||||
var _ = Describe("Podman generate systemd", func() {
|
||||
var (
|
||||
tempdir string
|
||||
err error
|
||||
podmanTest *PodmanTestIntegration
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
tempdir, err = CreateTempDirInTempDir()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
podmanTest = PodmanTestCreate(tempdir)
|
||||
podmanTest.Setup()
|
||||
podmanTest.RestoreAllArtifacts()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
podmanTest.Cleanup()
|
||||
f := CurrentGinkgoTestDescription()
|
||||
processTestResult(f)
|
||||
|
||||
})
|
||||
|
||||
It("podman generate systemd on bogus container", func() {
|
||||
session := podmanTest.Podman([]string{"generate", "systemd", "foobar"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||
})
|
||||
|
||||
It("podman generate systemd bad restart policy", func() {
|
||||
session := podmanTest.Podman([]string{"generate", "systemd", "--restart-policy", "never", "foobar"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||
})
|
||||
|
||||
It("podman generate systemd bad timeout value", func() {
|
||||
session := podmanTest.Podman([]string{"generate", "systemd", "--timeout", "-1", "foobar"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||
})
|
||||
|
||||
It("podman generate systemd", func() {
|
||||
n := podmanTest.Podman([]string{"run", "--name", "nginx", "-dt", nginx})
|
||||
n.WaitWithDefaultTimeout()
|
||||
Expect(n.ExitCode()).To(Equal(0))
|
||||
|
||||
session := podmanTest.Podman([]string{"generate", "systemd", "nginx"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman generate systemd with timeout", func() {
|
||||
n := podmanTest.Podman([]string{"run", "--name", "nginx", "-dt", nginx})
|
||||
n.WaitWithDefaultTimeout()
|
||||
Expect(n.ExitCode()).To(Equal(0))
|
||||
|
||||
session := podmanTest.Podman([]string{"generate", "systemd", "--timeout", "5", "nginx"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
})
|
||||
|
||||
})
|
Reference in New Issue
Block a user