Skip to content

Commit

Permalink
Merge pull request #17627 from umohnani8/pod-restart
Browse files Browse the repository at this point in the history
Add --restart flag to pod create
  • Loading branch information
openshift-merge-robot authored May 2, 2023
2 parents 6577e3f + fa1ba17 commit 09c11a8
Show file tree
Hide file tree
Showing 30 changed files with 440 additions and 85 deletions.
16 changes: 8 additions & 8 deletions cmd/podman/common/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,14 +386,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(requiresFlagName, AutocompleteContainers)

restartFlagName := "restart"
createFlags.StringVar(
&cf.Restart,
restartFlagName, "",
`Restart policy to apply when a container exits ("always"|"no"|"on-failure"|"unless-stopped")`,
)
_ = cmd.RegisterFlagCompletionFunc(restartFlagName, AutocompleteRestartOption)

createFlags.BoolVar(
&cf.Rm,
"rm", false,
Expand Down Expand Up @@ -635,6 +627,14 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
}
if mode == entities.InfraMode || (mode == entities.CreateMode) { // infra container flags, create should also pick these up
restartFlagName := "restart"
createFlags.StringVar(
&cf.Restart,
restartFlagName, "",
`Restart policy to apply when a container exits ("always"|"no"|"never"|"on-failure"|"unless-stopped")`,
)
_ = cmd.RegisterFlagCompletionFunc(restartFlagName, AutocompleteRestartOption)

shmSizeFlagName := "shm-size"
createFlags.String(
shmSizeFlagName, shmSize(),
Expand Down
2 changes: 2 additions & 0 deletions cmd/podman/containers/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ func create(cmd *cobra.Command, args []string) error {
}
cliVals.InitContainerType = initctr
}
// TODO: v5.0 block users from setting restart policy for a container if the container is in a pod

cliVals, err := CreateInit(cmd, cliVals, false)
if err != nil {
Expand Down Expand Up @@ -405,6 +406,7 @@ func createPodIfNecessary(cmd *cobra.Command, s *specgen.SpecGenerator, netOpts
CpusetCpus: cliVals.CPUSetCPUs,
Pid: cliVals.PID,
Userns: uns,
Restart: cliVals.Restart,
}
// Unset config values we passed to the pod to prevent them being used twice for the container and pod.
s.ContainerBasicConfig.Hostname = ""
Expand Down
6 changes: 6 additions & 0 deletions cmd/podman/containers/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"os"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -300,6 +301,7 @@ func createPsOut() ([]map[string]string, string) {
"PIDNS": "pidns",
"Pod": "pod id",
"PodName": "podname", // undo camelcase space break
"Restarts": "restarts",
"RunningFor": "running for",
"UTS": "uts",
"User": "userns",
Expand Down Expand Up @@ -377,6 +379,10 @@ func (l psReporter) Status() string {
return state
}

func (l psReporter) Restarts() string {
return strconv.Itoa(int(l.ListContainer.Restarts))
}

func (l psReporter) RunningFor() string {
return l.CreatedHuman()
}
Expand Down
1 change: 1 addition & 0 deletions cmd/podman/pods/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ func create(cmd *cobra.Command, args []string) error {
podSpec.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false)
podSpec.InfraContainerSpec.RawImageName = rawImageName
podSpec.InfraContainerSpec.NetworkOptions = podSpec.NetworkOptions
podSpec.InfraContainerSpec.RestartPolicy = podSpec.RestartPolicy
err = specgenutil.FillOutSpecGen(podSpec.InfraContainerSpec, &infraOptions, []string{})
if err != nil {
return err
Expand Down
12 changes: 12 additions & 0 deletions cmd/podman/pods/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"sort"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -147,6 +148,7 @@ func pods(cmd *cobra.Command, _ []string) error {
"ContainerStatuses": "STATUS",
"Cgroup": "CGROUP",
"Namespace": "NAMESPACES",
"Restarts": "RESTARTS",
})

if err := rpt.Execute(headers); err != nil {
Expand Down Expand Up @@ -178,6 +180,7 @@ func podPsFormat() string {
if !psInput.CtrStatus && !psInput.CtrNames && !psInput.CtrIds {
row = append(row, "{{.NumberOfContainers}}")
}

return "{{range . }}" + strings.Join(row, "\t") + "\n" + "{{end -}}"
}

Expand Down Expand Up @@ -265,6 +268,15 @@ func (l ListPodReporter) ContainerStatuses() string {
return strings.Join(statuses, ",")
}

// Restarts returns the total number of restarts for all the containers in the pod
func (l ListPodReporter) Restarts() string {
restarts := 0
for _, c := range l.Containers {
restarts += int(c.RestartCount)
}
return strconv.Itoa(restarts)
}

func sortPodPsOutput(sortBy string, lprs []*entities.ListPodsReport) error {
switch sortBy {
case "created":
Expand Down
3 changes: 2 additions & 1 deletion docs/source/markdown/options/restart.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, pod clone, pod create, run
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--restart**=*policy*
Expand All @@ -10,6 +10,7 @@ Restart policy will not take effect if a container is stopped via the **podman k
Valid _policy_ values are:

- `no` : Do not restart containers on exit
- `never` : Synonym for **no**; do not restart containers on exit
- `on-failure[:max_retries]` : Restart containers when they exit with a non-zero exit code, retrying indefinitely or until the optional *max_retries* count is hit
- `always` : Restart containers when they exit, regardless of status, retrying indefinitely
- `unless-stopped` : Identical to **always**
Expand Down
4 changes: 4 additions & 0 deletions docs/source/markdown/podman-pod-clone.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ Set a custom name for the cloned pod. The default if not specified is of the syn

@@option pid.pod

@@option restart

Default restart policy for all the containers in a pod.

@@option security-opt

@@option shm-size
Expand Down
4 changes: 4 additions & 0 deletions docs/source/markdown/podman-pod-create.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ but only by the pod itself.

@@option replace

@@option restart

Default restart policy for all the containers in a pod.

@@option security-opt

#### **--share**=*namespace*
Expand Down
1 change: 1 addition & 0 deletions docs/source/markdown/podman-pod-inspect.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Valid placeholders for the Go template are listed below:
| .Name | Pod name |
| .Namespace | Namespace |
| .NumContainers | Number of containers in the pod |
| .RestartPolicy | Restart policy of the pod |
| .SecurityOpts | Security options |
| .SharedNamespaces | Pod shared namespaces |
| .State | Pod state |
Expand Down
29 changes: 15 additions & 14 deletions docs/source/markdown/podman-pod-ps.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,21 @@ Pretty-print containers to JSON or using a Go template

Valid placeholders for the Go template are listed below:

| **Placeholder** | **Description** |
|---------------------|----------------------------------------------------|
| .Cgroup | Cgroup path of pod |
| .ContainerIds | Comma-separated list of container IDs in the pod |
| .ContainerNames | Comma-separated list of container names in the pod |
| .ContainerStatuses | Comma-separated list of container statuses |
| .Created | Creation time of pod |
| .ID | Container ID |
| .InfraID | Pod infra container ID |
| .Labels | All the labels assigned to the pod |
| .Name | Name of pod |
| .Networks | Show all networks connected to the infra container |
| .NumberOfContainers | Show the number of containers attached to pod |
| .Status | Status of pod |
| **Placeholder** | **Description** |
|---------------------|------------------------------------------------------|
| .Cgroup | Cgroup path of pod |
| .ContainerIds | Comma-separated list of container IDs in the pod |
| .ContainerNames | Comma-separated list of container names in the pod |
| .ContainerStatuses | Comma-separated list of container statuses |
| .Created | Creation time of pod |
| .ID | Container ID |
| .InfraID | Pod infra container ID |
| .Labels | All the labels assigned to the pod |
| .Name | Name of pod |
| .Networks | Show all networks connected to the infra container |
| .NumberOfContainers | Show the number of containers attached to pod |
| .Restarts | Show the total number of container restarts in a pod |
| .Status | Status of pod |

#### **--help**, **-h**

Expand Down
1 change: 1 addition & 0 deletions docs/source/markdown/podman-ps.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Valid placeholders for the Go template are listed below:
| .Pod | Pod the container is associated with (SHA) |
| .PodName | Seems to be empty no matter what |
| .Ports | Exposed ports |
| .Restarts | Display the container restart count |
| .RunningFor | Time elapsed since container was started |
| .Size | Size of container |
| .StartedAt | Time (epoch seconds) the container started |
Expand Down
13 changes: 12 additions & 1 deletion libpod/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ type ContainerState struct {
// restart policy. This is NOT incremented by normal container restarts
// (only by restart policy).
RestartCount uint `json:"restartCount,omitempty"`

// StartupHCPassed indicates that the startup healthcheck has
// succeeded and the main healthcheck can begin.
StartupHCPassed bool `json:"startupHCPassed,omitempty"`
Expand Down Expand Up @@ -730,6 +729,18 @@ func (c *Container) State() (define.ContainerStatus, error) {
return c.state.State, nil
}

func (c *Container) RestartCount() (uint, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()

if err := c.syncContainer(); err != nil {
return 0, err
}
}
return c.state.RestartCount, nil
}

// Mounted returns whether the container is mounted and the path it is mounted
// at (if it is mounted).
// If the container is not mounted, no error is returned, and the mountpoint
Expand Down
2 changes: 2 additions & 0 deletions libpod/define/pod_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ type InspectPodData struct {
BlkioWeight uint64 `json:"blkio_weight,omitempty"`
// BlkioWeightDevice contains the blkio weight device limits for the pod
BlkioWeightDevice []InspectBlkioWeightDevice `json:"blkio_weight_device,omitempty"`
// RestartPolicy of the pod.
RestartPolicy string `json:"RestartPolicy,omitempty"`
}

// InspectPodInfraConfig contains the configuration of the pod's infra
Expand Down
54 changes: 34 additions & 20 deletions libpod/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,8 @@ func (p *Pod) GenerateForKube(ctx context.Context, getService bool) (*v1.Pod, []
}
pod.Spec.HostAliases = extraHost

// vendor/k8s.io/api/core/v1/types.go: v1.Container cannot save restartPolicy
// so set it at here
for _, ctr := range allContainers {
if !ctr.IsInfra() {
switch ctr.config.RestartPolicy {
case define.RestartPolicyAlways:
pod.Spec.RestartPolicy = v1.RestartPolicyAlways
case define.RestartPolicyOnFailure:
pod.Spec.RestartPolicy = v1.RestartPolicyOnFailure
case define.RestartPolicyNo:
pod.Spec.RestartPolicy = v1.RestartPolicyNever
default: // some pod create from cmdline, such as "", so set it to "" as k8s automatically defaults to always
pod.Spec.RestartPolicy = ""
}
break
}
}
// Set the pod's restart policy
pod.Spec.RestartPolicy = getPodRestartPolicy(p.config.RestartPolicy)

if p.SharesPID() {
// unfortunately, go doesn't have a nice way to specify a pointer to a bool
Expand All @@ -136,7 +121,7 @@ func (p *Pod) getInfraContainer() (*Container, error) {
// kind YAML.
func GenerateForKubeDeployment(ctx context.Context, pod *YAMLPod, options entities.GenerateKubeOptions) (*YAMLDeployment, error) {
// Restart policy for Deployments can only be set to Always
if options.Type == define.K8sKindDeployment && !(pod.Spec.RestartPolicy == "" || pod.Spec.RestartPolicy == define.RestartPolicyAlways) {
if options.Type == define.K8sKindDeployment && !(pod.Spec.RestartPolicy == "" || pod.Spec.RestartPolicy == v1.RestartPolicyAlways) {
return nil, fmt.Errorf("k8s Deployments can only have restartPolicy set to Always")
}

Expand Down Expand Up @@ -599,6 +584,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getServic
kubeAnnotations := make(map[string]string)
ctrNames := make([]string, 0, len(ctrs))
var hostname string
var restartPolicy *string
for _, ctr := range ctrs {
ctrNames = append(ctrNames, removeUnderscores(ctr.Name()))
for k, v := range ctr.config.Spec.Annotations {
Expand All @@ -623,6 +609,11 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getServic
}
}

// Use the restart policy of the first non-init container
if !isInit && restartPolicy == nil {
restartPolicy = &ctr.config.RestartPolicy
}

if ctr.config.Spec.Process != nil {
var ulimitArr []string
defaultUlimits := util.DefaultContainerConfig().Ulimits()
Expand Down Expand Up @@ -700,7 +691,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getServic
podName += "-pod"
}

return newPodObject(
pod := newPodObject(
podName,
kubeAnnotations,
kubeInitCtrs,
Expand All @@ -709,7 +700,30 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getServic
&podDNS,
hostNetwork,
hostUsers,
hostname), nil
hostname)

// Set the pod's restart policy
policy := ""
if restartPolicy != nil {
policy = *restartPolicy
}
pod.Spec.RestartPolicy = getPodRestartPolicy(policy)

return pod, nil
}

// getPodRestartPolicy returns the pod restart policy to be set in the generated kube yaml
func getPodRestartPolicy(policy string) v1.RestartPolicy {
switch policy {
case define.RestartPolicyNo:
return v1.RestartPolicyNever
case define.RestartPolicyAlways:
return v1.RestartPolicyAlways
case define.RestartPolicyOnFailure:
return v1.RestartPolicyOnFailure
default: // some pod/ctr create from cmdline, such as "" - set it to "" and let k8s handle the defaults
return ""
}
}

// containerToV1Container converts information we know about a libpod container
Expand Down
34 changes: 34 additions & 0 deletions libpod/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -2020,6 +2020,40 @@ func WithPodExitPolicy(policy string) PodCreateOption {
}
}

// WithPodRestartPolicy sets the restart policy of the pod.
func WithPodRestartPolicy(policy string) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}

switch policy {
//TODO: v5.0 if no restart policy is set, follow k8s convention and default to Always
case define.RestartPolicyNone, define.RestartPolicyNo, define.RestartPolicyOnFailure, define.RestartPolicyAlways, define.RestartPolicyUnlessStopped:
pod.config.RestartPolicy = policy
default:
return fmt.Errorf("%q is not a valid restart policy: %w", policy, define.ErrInvalidArg)
}

return nil
}
}

// WithPodRestartRetries sets the number of retries to use when restarting a
// container with the "on-failure" restart policy.
// 0 is an allowed value, and indicates infinite retries.
func WithPodRestartRetries(tries uint) PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}

pod.config.RestartRetries = &tries

return nil
}
}

// WithPodHostname sets the hostname of the pod.
func WithPodHostname(hostname string) PodCreateOption {
return func(pod *Pod) error {
Expand Down
Loading

0 comments on commit 09c11a8

Please sign in to comment.