mirror of https://github.com/containers/podman.git
Merge pull request #17627 from umohnani8/pod-restart
Add --restart flag to pod create
This commit is contained in:
commit
09c11a8d95
|
@ -386,14 +386,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
|
||||||
)
|
)
|
||||||
_ = cmd.RegisterFlagCompletionFunc(requiresFlagName, AutocompleteContainers)
|
_ = 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(
|
createFlags.BoolVar(
|
||||||
&cf.Rm,
|
&cf.Rm,
|
||||||
"rm", false,
|
"rm", false,
|
||||||
|
@ -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
|
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"
|
shmSizeFlagName := "shm-size"
|
||||||
createFlags.String(
|
createFlags.String(
|
||||||
shmSizeFlagName, shmSize(),
|
shmSizeFlagName, shmSize(),
|
||||||
|
|
|
@ -137,6 +137,7 @@ func create(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
cliVals.InitContainerType = initctr
|
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)
|
cliVals, err := CreateInit(cmd, cliVals, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -405,6 +406,7 @@ func createPodIfNecessary(cmd *cobra.Command, s *specgen.SpecGenerator, netOpts
|
||||||
CpusetCpus: cliVals.CPUSetCPUs,
|
CpusetCpus: cliVals.CPUSetCPUs,
|
||||||
Pid: cliVals.PID,
|
Pid: cliVals.PID,
|
||||||
Userns: uns,
|
Userns: uns,
|
||||||
|
Restart: cliVals.Restart,
|
||||||
}
|
}
|
||||||
// Unset config values we passed to the pod to prevent them being used twice for the container and pod.
|
// Unset config values we passed to the pod to prevent them being used twice for the container and pod.
|
||||||
s.ContainerBasicConfig.Hostname = ""
|
s.ContainerBasicConfig.Hostname = ""
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -300,6 +301,7 @@ func createPsOut() ([]map[string]string, string) {
|
||||||
"PIDNS": "pidns",
|
"PIDNS": "pidns",
|
||||||
"Pod": "pod id",
|
"Pod": "pod id",
|
||||||
"PodName": "podname", // undo camelcase space break
|
"PodName": "podname", // undo camelcase space break
|
||||||
|
"Restarts": "restarts",
|
||||||
"RunningFor": "running for",
|
"RunningFor": "running for",
|
||||||
"UTS": "uts",
|
"UTS": "uts",
|
||||||
"User": "userns",
|
"User": "userns",
|
||||||
|
@ -377,6 +379,10 @@ func (l psReporter) Status() string {
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l psReporter) Restarts() string {
|
||||||
|
return strconv.Itoa(int(l.ListContainer.Restarts))
|
||||||
|
}
|
||||||
|
|
||||||
func (l psReporter) RunningFor() string {
|
func (l psReporter) RunningFor() string {
|
||||||
return l.CreatedHuman()
|
return l.CreatedHuman()
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,6 +259,7 @@ func create(cmd *cobra.Command, args []string) error {
|
||||||
podSpec.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false)
|
podSpec.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false)
|
||||||
podSpec.InfraContainerSpec.RawImageName = rawImageName
|
podSpec.InfraContainerSpec.RawImageName = rawImageName
|
||||||
podSpec.InfraContainerSpec.NetworkOptions = podSpec.NetworkOptions
|
podSpec.InfraContainerSpec.NetworkOptions = podSpec.NetworkOptions
|
||||||
|
podSpec.InfraContainerSpec.RestartPolicy = podSpec.RestartPolicy
|
||||||
err = specgenutil.FillOutSpecGen(podSpec.InfraContainerSpec, &infraOptions, []string{})
|
err = specgenutil.FillOutSpecGen(podSpec.InfraContainerSpec, &infraOptions, []string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -147,6 +148,7 @@ func pods(cmd *cobra.Command, _ []string) error {
|
||||||
"ContainerStatuses": "STATUS",
|
"ContainerStatuses": "STATUS",
|
||||||
"Cgroup": "CGROUP",
|
"Cgroup": "CGROUP",
|
||||||
"Namespace": "NAMESPACES",
|
"Namespace": "NAMESPACES",
|
||||||
|
"Restarts": "RESTARTS",
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := rpt.Execute(headers); err != nil {
|
if err := rpt.Execute(headers); err != nil {
|
||||||
|
@ -178,6 +180,7 @@ func podPsFormat() string {
|
||||||
if !psInput.CtrStatus && !psInput.CtrNames && !psInput.CtrIds {
|
if !psInput.CtrStatus && !psInput.CtrNames && !psInput.CtrIds {
|
||||||
row = append(row, "{{.NumberOfContainers}}")
|
row = append(row, "{{.NumberOfContainers}}")
|
||||||
}
|
}
|
||||||
|
|
||||||
return "{{range . }}" + strings.Join(row, "\t") + "\n" + "{{end -}}"
|
return "{{range . }}" + strings.Join(row, "\t") + "\n" + "{{end -}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,6 +268,15 @@ func (l ListPodReporter) ContainerStatuses() string {
|
||||||
return strings.Join(statuses, ",")
|
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 {
|
func sortPodPsOutput(sortBy string, lprs []*entities.ListPodsReport) error {
|
||||||
switch sortBy {
|
switch sortBy {
|
||||||
case "created":
|
case "created":
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
####> This option file is used in:
|
####> This option file is used in:
|
||||||
####> podman create, run
|
####> podman create, pod clone, pod create, run
|
||||||
####> If file is edited, make sure the changes
|
####> If file is edited, make sure the changes
|
||||||
####> are applicable to all of those.
|
####> are applicable to all of those.
|
||||||
#### **--restart**=*policy*
|
#### **--restart**=*policy*
|
||||||
|
@ -10,6 +10,7 @@ Restart policy will not take effect if a container is stopped via the **podman k
|
||||||
Valid _policy_ values are:
|
Valid _policy_ values are:
|
||||||
|
|
||||||
- `no` : Do not restart containers on exit
|
- `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
|
- `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
|
- `always` : Restart containers when they exit, regardless of status, retrying indefinitely
|
||||||
- `unless-stopped` : Identical to **always**
|
- `unless-stopped` : Identical to **always**
|
||||||
|
|
|
@ -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 pid.pod
|
||||||
|
|
||||||
|
@@option restart
|
||||||
|
|
||||||
|
Default restart policy for all the containers in a pod.
|
||||||
|
|
||||||
@@option security-opt
|
@@option security-opt
|
||||||
|
|
||||||
@@option shm-size
|
@@option shm-size
|
||||||
|
|
|
@ -143,6 +143,10 @@ but only by the pod itself.
|
||||||
|
|
||||||
@@option replace
|
@@option replace
|
||||||
|
|
||||||
|
@@option restart
|
||||||
|
|
||||||
|
Default restart policy for all the containers in a pod.
|
||||||
|
|
||||||
@@option security-opt
|
@@option security-opt
|
||||||
|
|
||||||
#### **--share**=*namespace*
|
#### **--share**=*namespace*
|
||||||
|
|
|
@ -50,6 +50,7 @@ Valid placeholders for the Go template are listed below:
|
||||||
| .Name | Pod name |
|
| .Name | Pod name |
|
||||||
| .Namespace | Namespace |
|
| .Namespace | Namespace |
|
||||||
| .NumContainers | Number of containers in the pod |
|
| .NumContainers | Number of containers in the pod |
|
||||||
|
| .RestartPolicy | Restart policy of the pod |
|
||||||
| .SecurityOpts | Security options |
|
| .SecurityOpts | Security options |
|
||||||
| .SharedNamespaces | Pod shared namespaces |
|
| .SharedNamespaces | Pod shared namespaces |
|
||||||
| .State | Pod state |
|
| .State | Pod state |
|
||||||
|
|
|
@ -77,20 +77,21 @@ Pretty-print containers to JSON or using a Go template
|
||||||
|
|
||||||
Valid placeholders for the Go template are listed below:
|
Valid placeholders for the Go template are listed below:
|
||||||
|
|
||||||
| **Placeholder** | **Description** |
|
| **Placeholder** | **Description** |
|
||||||
|---------------------|----------------------------------------------------|
|
|---------------------|------------------------------------------------------|
|
||||||
| .Cgroup | Cgroup path of pod |
|
| .Cgroup | Cgroup path of pod |
|
||||||
| .ContainerIds | Comma-separated list of container IDs in the pod |
|
| .ContainerIds | Comma-separated list of container IDs in the pod |
|
||||||
| .ContainerNames | Comma-separated list of container names in the pod |
|
| .ContainerNames | Comma-separated list of container names in the pod |
|
||||||
| .ContainerStatuses | Comma-separated list of container statuses |
|
| .ContainerStatuses | Comma-separated list of container statuses |
|
||||||
| .Created | Creation time of pod |
|
| .Created | Creation time of pod |
|
||||||
| .ID | Container ID |
|
| .ID | Container ID |
|
||||||
| .InfraID | Pod infra container ID |
|
| .InfraID | Pod infra container ID |
|
||||||
| .Labels | All the labels assigned to the pod |
|
| .Labels | All the labels assigned to the pod |
|
||||||
| .Name | Name of pod |
|
| .Name | Name of pod |
|
||||||
| .Networks | Show all networks connected to the infra container |
|
| .Networks | Show all networks connected to the infra container |
|
||||||
| .NumberOfContainers | Show the number of containers attached to pod |
|
| .NumberOfContainers | Show the number of containers attached to pod |
|
||||||
| .Status | Status of pod |
|
| .Restarts | Show the total number of container restarts in a pod |
|
||||||
|
| .Status | Status of pod |
|
||||||
|
|
||||||
#### **--help**, **-h**
|
#### **--help**, **-h**
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,7 @@ Valid placeholders for the Go template are listed below:
|
||||||
| .Pod | Pod the container is associated with (SHA) |
|
| .Pod | Pod the container is associated with (SHA) |
|
||||||
| .PodName | Seems to be empty no matter what |
|
| .PodName | Seems to be empty no matter what |
|
||||||
| .Ports | Exposed ports |
|
| .Ports | Exposed ports |
|
||||||
|
| .Restarts | Display the container restart count |
|
||||||
| .RunningFor | Time elapsed since container was started |
|
| .RunningFor | Time elapsed since container was started |
|
||||||
| .Size | Size of container |
|
| .Size | Size of container |
|
||||||
| .StartedAt | Time (epoch seconds) the container started |
|
| .StartedAt | Time (epoch seconds) the container started |
|
||||||
|
|
|
@ -203,7 +203,6 @@ type ContainerState struct {
|
||||||
// restart policy. This is NOT incremented by normal container restarts
|
// restart policy. This is NOT incremented by normal container restarts
|
||||||
// (only by restart policy).
|
// (only by restart policy).
|
||||||
RestartCount uint `json:"restartCount,omitempty"`
|
RestartCount uint `json:"restartCount,omitempty"`
|
||||||
|
|
||||||
// StartupHCPassed indicates that the startup healthcheck has
|
// StartupHCPassed indicates that the startup healthcheck has
|
||||||
// succeeded and the main healthcheck can begin.
|
// succeeded and the main healthcheck can begin.
|
||||||
StartupHCPassed bool `json:"startupHCPassed,omitempty"`
|
StartupHCPassed bool `json:"startupHCPassed,omitempty"`
|
||||||
|
@ -730,6 +729,18 @@ func (c *Container) State() (define.ContainerStatus, error) {
|
||||||
return c.state.State, nil
|
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
|
// Mounted returns whether the container is mounted and the path it is mounted
|
||||||
// at (if it is mounted).
|
// at (if it is mounted).
|
||||||
// If the container is not mounted, no error is returned, and the mountpoint
|
// If the container is not mounted, no error is returned, and the mountpoint
|
||||||
|
|
|
@ -83,6 +83,8 @@ type InspectPodData struct {
|
||||||
BlkioWeight uint64 `json:"blkio_weight,omitempty"`
|
BlkioWeight uint64 `json:"blkio_weight,omitempty"`
|
||||||
// BlkioWeightDevice contains the blkio weight device limits for the pod
|
// BlkioWeightDevice contains the blkio weight device limits for the pod
|
||||||
BlkioWeightDevice []InspectBlkioWeightDevice `json:"blkio_weight_device,omitempty"`
|
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
|
// InspectPodInfraConfig contains the configuration of the pod's infra
|
||||||
|
|
|
@ -97,23 +97,8 @@ func (p *Pod) GenerateForKube(ctx context.Context, getService bool) (*v1.Pod, []
|
||||||
}
|
}
|
||||||
pod.Spec.HostAliases = extraHost
|
pod.Spec.HostAliases = extraHost
|
||||||
|
|
||||||
// vendor/k8s.io/api/core/v1/types.go: v1.Container cannot save restartPolicy
|
// Set the pod's restart policy
|
||||||
// so set it at here
|
pod.Spec.RestartPolicy = getPodRestartPolicy(p.config.RestartPolicy)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.SharesPID() {
|
if p.SharesPID() {
|
||||||
// unfortunately, go doesn't have a nice way to specify a pointer to a bool
|
// unfortunately, go doesn't have a nice way to specify a pointer to a bool
|
||||||
|
@ -136,7 +121,7 @@ func (p *Pod) getInfraContainer() (*Container, error) {
|
||||||
// kind YAML.
|
// kind YAML.
|
||||||
func GenerateForKubeDeployment(ctx context.Context, pod *YAMLPod, options entities.GenerateKubeOptions) (*YAMLDeployment, error) {
|
func GenerateForKubeDeployment(ctx context.Context, pod *YAMLPod, options entities.GenerateKubeOptions) (*YAMLDeployment, error) {
|
||||||
// Restart policy for Deployments can only be set to Always
|
// 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")
|
return nil, fmt.Errorf("k8s Deployments can only have restartPolicy set to Always")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,6 +584,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getServic
|
||||||
kubeAnnotations := make(map[string]string)
|
kubeAnnotations := make(map[string]string)
|
||||||
ctrNames := make([]string, 0, len(ctrs))
|
ctrNames := make([]string, 0, len(ctrs))
|
||||||
var hostname string
|
var hostname string
|
||||||
|
var restartPolicy *string
|
||||||
for _, ctr := range ctrs {
|
for _, ctr := range ctrs {
|
||||||
ctrNames = append(ctrNames, removeUnderscores(ctr.Name()))
|
ctrNames = append(ctrNames, removeUnderscores(ctr.Name()))
|
||||||
for k, v := range ctr.config.Spec.Annotations {
|
for k, v := range ctr.config.Spec.Annotations {
|
||||||
|
@ -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 {
|
if ctr.config.Spec.Process != nil {
|
||||||
var ulimitArr []string
|
var ulimitArr []string
|
||||||
defaultUlimits := util.DefaultContainerConfig().Ulimits()
|
defaultUlimits := util.DefaultContainerConfig().Ulimits()
|
||||||
|
@ -700,7 +691,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getServic
|
||||||
podName += "-pod"
|
podName += "-pod"
|
||||||
}
|
}
|
||||||
|
|
||||||
return newPodObject(
|
pod := newPodObject(
|
||||||
podName,
|
podName,
|
||||||
kubeAnnotations,
|
kubeAnnotations,
|
||||||
kubeInitCtrs,
|
kubeInitCtrs,
|
||||||
|
@ -709,7 +700,30 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container, getServic
|
||||||
&podDNS,
|
&podDNS,
|
||||||
hostNetwork,
|
hostNetwork,
|
||||||
hostUsers,
|
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
|
// containerToV1Container converts information we know about a libpod container
|
||||||
|
|
|
@ -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.
|
// WithPodHostname sets the hostname of the pod.
|
||||||
func WithPodHostname(hostname string) PodCreateOption {
|
func WithPodHostname(hostname string) PodCreateOption {
|
||||||
return func(pod *Pod) error {
|
return func(pod *Pod) error {
|
||||||
|
|
|
@ -81,6 +81,12 @@ type PodConfig struct {
|
||||||
// The pod's exit policy.
|
// The pod's exit policy.
|
||||||
ExitPolicy config.PodExitPolicy `json:"ExitPolicy,omitempty"`
|
ExitPolicy config.PodExitPolicy `json:"ExitPolicy,omitempty"`
|
||||||
|
|
||||||
|
// The pod's restart policy
|
||||||
|
RestartPolicy string `json:"RestartPolicy,omitempty"`
|
||||||
|
|
||||||
|
// The max number of retries for a pod based on restart policy
|
||||||
|
RestartRetries *uint `json:"RestartRetries,omitempty"`
|
||||||
|
|
||||||
// ID of the pod's lock
|
// ID of the pod's lock
|
||||||
LockID uint32 `json:"lockID"`
|
LockID uint32 `json:"lockID"`
|
||||||
|
|
||||||
|
@ -522,3 +528,10 @@ func (p *Pod) Config() (*PodConfig, error) {
|
||||||
|
|
||||||
return conf, err
|
return conf, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfigNoCopy returns the configuration used by the pod.
|
||||||
|
// Note that the returned value is not a copy and must hence
|
||||||
|
// only be used in a reading fashion.
|
||||||
|
func (p *Pod) ConfigNoCopy() *PodConfig {
|
||||||
|
return p.config
|
||||||
|
}
|
||||||
|
|
|
@ -741,6 +741,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
|
||||||
CPUSetMems: p.CPUSetMems(),
|
CPUSetMems: p.CPUSetMems(),
|
||||||
BlkioDeviceWriteBps: p.BlkiThrottleWriteBps(),
|
BlkioDeviceWriteBps: p.BlkiThrottleWriteBps(),
|
||||||
CPUShares: p.CPUShares(),
|
CPUShares: p.CPUShares(),
|
||||||
|
RestartPolicy: p.config.RestartPolicy,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &inspectData, nil
|
return &inspectData, nil
|
||||||
|
|
|
@ -55,6 +55,10 @@ type ListContainer struct {
|
||||||
PodName string
|
PodName string
|
||||||
// Port mappings
|
// Port mappings
|
||||||
Ports []types.PortMapping
|
Ports []types.PortMapping
|
||||||
|
// Restarts is how many times the container was restarted by its
|
||||||
|
// restart policy. This is NOT incremented by normal container restarts
|
||||||
|
// (only by restart policy).
|
||||||
|
Restarts uint
|
||||||
// Size of the container rootfs. Requires the size boolean to be true
|
// Size of the container rootfs. Requires the size boolean to be true
|
||||||
Size *define.ContainerSize
|
Size *define.ContainerSize
|
||||||
// Time when container started
|
// Time when container started
|
||||||
|
|
|
@ -38,9 +38,10 @@ type ListPodsReport struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListPodContainer struct {
|
type ListPodContainer struct {
|
||||||
Id string //nolint:revive,stylecheck
|
Id string //nolint:revive,stylecheck
|
||||||
Names string
|
Names string
|
||||||
Status string
|
Status string
|
||||||
|
RestartCount uint
|
||||||
}
|
}
|
||||||
|
|
||||||
type PodPauseOptions struct {
|
type PodPauseOptions struct {
|
||||||
|
@ -135,6 +136,7 @@ type PodCreateOptions struct {
|
||||||
Net *NetOptions `json:"net,omitempty"`
|
Net *NetOptions `json:"net,omitempty"`
|
||||||
Share []string `json:"share,omitempty"`
|
Share []string `json:"share,omitempty"`
|
||||||
ShareParent *bool `json:"share_parent,omitempty"`
|
ShareParent *bool `json:"share_parent,omitempty"`
|
||||||
|
Restart string `json:"restart,omitempty"`
|
||||||
Pid string `json:"pid,omitempty"`
|
Pid string `json:"pid,omitempty"`
|
||||||
Cpus float64 `json:"cpus,omitempty"`
|
Cpus float64 `json:"cpus,omitempty"`
|
||||||
CpusetCpus string `json:"cpuset_cpus,omitempty"`
|
CpusetCpus string `json:"cpuset_cpus,omitempty"`
|
||||||
|
@ -375,6 +377,14 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod
|
||||||
s.ShareParent = p.ShareParent
|
s.ShareParent = p.ShareParent
|
||||||
s.PodCreateCommand = p.CreateCommand
|
s.PodCreateCommand = p.CreateCommand
|
||||||
s.VolumesFrom = p.VolumesFrom
|
s.VolumesFrom = p.VolumesFrom
|
||||||
|
if p.Restart != "" {
|
||||||
|
policy, retries, err := util.ParseRestartPolicy(p.Restart)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.RestartPolicy = policy
|
||||||
|
s.RestartRetries = &retries
|
||||||
|
}
|
||||||
|
|
||||||
// Networking config
|
// Networking config
|
||||||
|
|
||||||
|
|
|
@ -592,16 +592,16 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ctrRestartPolicy string
|
// Set the restart policy from the kube yaml at the pod level in podman
|
||||||
switch podYAML.Spec.RestartPolicy {
|
switch podYAML.Spec.RestartPolicy {
|
||||||
case v1.RestartPolicyAlways:
|
case v1.RestartPolicyAlways:
|
||||||
ctrRestartPolicy = define.RestartPolicyAlways
|
podSpec.PodSpecGen.RestartPolicy = define.RestartPolicyAlways
|
||||||
case v1.RestartPolicyOnFailure:
|
case v1.RestartPolicyOnFailure:
|
||||||
ctrRestartPolicy = define.RestartPolicyOnFailure
|
podSpec.PodSpecGen.RestartPolicy = define.RestartPolicyOnFailure
|
||||||
case v1.RestartPolicyNever:
|
case v1.RestartPolicyNever:
|
||||||
ctrRestartPolicy = define.RestartPolicyNo
|
podSpec.PodSpecGen.RestartPolicy = define.RestartPolicyNo
|
||||||
default: // Default to Always
|
default: // Default to Always
|
||||||
ctrRestartPolicy = define.RestartPolicyAlways
|
podSpec.PodSpecGen.RestartPolicy = define.RestartPolicyAlways
|
||||||
}
|
}
|
||||||
|
|
||||||
if podOpt.Infra {
|
if podOpt.Infra {
|
||||||
|
@ -775,7 +775,6 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
||||||
PodName: podName,
|
PodName: podName,
|
||||||
PodSecurityContext: podYAML.Spec.SecurityContext,
|
PodSecurityContext: podYAML.Spec.SecurityContext,
|
||||||
ReadOnly: readOnly,
|
ReadOnly: readOnly,
|
||||||
RestartPolicy: ctrRestartPolicy,
|
|
||||||
SeccompPaths: seccompPaths,
|
SeccompPaths: seccompPaths,
|
||||||
SecretsManager: secretsManager,
|
SecretsManager: secretsManager,
|
||||||
UserNSIsHost: p.Userns.IsHost(),
|
UserNSIsHost: p.Userns.IsHost(),
|
||||||
|
|
|
@ -429,10 +429,15 @@ func (ic *ContainerEngine) listPodReportFromPod(p *libpod.Pod) (*entities.ListPo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
restartCount, err := c.RestartCount()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
lpcs[i] = &entities.ListPodContainer{
|
lpcs[i] = &entities.ListPodContainer{
|
||||||
Id: c.ID(),
|
Id: c.ID(),
|
||||||
Names: c.Name(),
|
Names: c.Name(),
|
||||||
Status: state.String(),
|
Status: state.String(),
|
||||||
|
RestartCount: restartCount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
infraID, err := p.InfraContainerID()
|
infraID, err := p.InfraContainerID()
|
||||||
|
|
|
@ -145,6 +145,7 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
|
||||||
portMappings []libnetworkTypes.PortMapping
|
portMappings []libnetworkTypes.PortMapping
|
||||||
networks []string
|
networks []string
|
||||||
healthStatus string
|
healthStatus string
|
||||||
|
restartCount uint
|
||||||
)
|
)
|
||||||
|
|
||||||
batchErr := ctr.Batch(func(c *libpod.Container) error {
|
batchErr := ctr.Batch(func(c *libpod.Container) error {
|
||||||
|
@ -193,6 +194,11 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
restartCount, err = c.RestartCount()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if !opts.Size && !opts.Namespace {
|
if !opts.Size && !opts.Namespace {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -251,6 +257,7 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
|
||||||
StartedAt: startedTime.Unix(),
|
StartedAt: startedTime.Unix(),
|
||||||
State: conState.String(),
|
State: conState.String(),
|
||||||
Status: healthStatus,
|
Status: healthStatus,
|
||||||
|
Restarts: restartCount,
|
||||||
}
|
}
|
||||||
if opts.Pod && len(conConfig.Pod) > 0 {
|
if opts.Pod && len(conConfig.Pod) > 0 {
|
||||||
podName, err := rt.GetPodName(conConfig.Pod)
|
podName, err := rt.GetPodName(conConfig.Pod)
|
||||||
|
|
|
@ -555,12 +555,24 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *l
|
||||||
}
|
}
|
||||||
// Default used if not overridden on command line
|
// Default used if not overridden on command line
|
||||||
|
|
||||||
if s.RestartPolicy != "" {
|
var (
|
||||||
if s.RestartRetries != nil {
|
restartPolicy string
|
||||||
options = append(options, libpod.WithRestartRetries(*s.RestartRetries))
|
retries uint
|
||||||
|
)
|
||||||
|
// If the container is running in a pod, use the pod's restart policy for all the containers
|
||||||
|
if pod != nil {
|
||||||
|
podConfig := pod.ConfigNoCopy()
|
||||||
|
if podConfig.RestartRetries != nil {
|
||||||
|
retries = *podConfig.RestartRetries
|
||||||
}
|
}
|
||||||
options = append(options, libpod.WithRestartPolicy(s.RestartPolicy))
|
restartPolicy = podConfig.RestartPolicy
|
||||||
|
} else if s.RestartPolicy != "" {
|
||||||
|
if s.RestartRetries != nil {
|
||||||
|
retries = *s.RestartRetries
|
||||||
|
}
|
||||||
|
restartPolicy = s.RestartPolicy
|
||||||
}
|
}
|
||||||
|
options = append(options, libpod.WithRestartRetries(retries), libpod.WithRestartPolicy(restartPolicy))
|
||||||
|
|
||||||
if s.ContainerHealthCheckConfig.HealthConfig != nil {
|
if s.ContainerHealthCheckConfig.HealthConfig != nil {
|
||||||
options = append(options, libpod.WithHealthCheck(s.ContainerHealthCheckConfig.HealthConfig))
|
options = append(options, libpod.WithHealthCheck(s.ContainerHealthCheckConfig.HealthConfig))
|
||||||
|
|
|
@ -165,6 +165,10 @@ func createPodOptions(p *specgen.PodSpecGenerator) ([]libpod.PodCreateOption, er
|
||||||
}
|
}
|
||||||
|
|
||||||
options = append(options, libpod.WithPodExitPolicy(p.ExitPolicy))
|
options = append(options, libpod.WithPodExitPolicy(p.ExitPolicy))
|
||||||
|
options = append(options, libpod.WithPodRestartPolicy(p.RestartPolicy))
|
||||||
|
if p.RestartRetries != nil {
|
||||||
|
options = append(options, libpod.WithPodRestartRetries(*p.RestartRetries))
|
||||||
|
}
|
||||||
|
|
||||||
return options, nil
|
return options, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,17 @@ type PodBasicConfig struct {
|
||||||
// Conflicts with NoInfra=true.
|
// Conflicts with NoInfra=true.
|
||||||
// Optional.
|
// Optional.
|
||||||
SharedNamespaces []string `json:"shared_namespaces,omitempty"`
|
SharedNamespaces []string `json:"shared_namespaces,omitempty"`
|
||||||
|
// RestartPolicy is the pod's restart policy - an action which
|
||||||
|
// will be taken when one or all the containers in the pod exits.
|
||||||
|
// If not given, the default policy will be set to Always, which
|
||||||
|
// restarts the containers in the pod when they exit indefinitely.
|
||||||
|
// Optional.
|
||||||
|
RestartPolicy string `json:"restart_policy,omitempty"`
|
||||||
|
// RestartRetries is the number of attempts that will be made to restart
|
||||||
|
// the container.
|
||||||
|
// Only available when RestartPolicy is set to "on-failure".
|
||||||
|
// Optional.
|
||||||
|
RestartRetries *uint `json:"restart_tries,omitempty"`
|
||||||
// PodCreateCommand is the command used to create this pod.
|
// PodCreateCommand is the command used to create this pod.
|
||||||
// This will be shown in the output of Inspect() on the pod, and may
|
// This will be shown in the output of Inspect() on the pod, and may
|
||||||
// also be used by some tools that wish to recreate the pod
|
// also be used by some tools that wish to recreate the pod
|
||||||
|
|
|
@ -808,27 +808,12 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
|
||||||
s.OOMScoreAdj = c.OOMScoreAdj
|
s.OOMScoreAdj = c.OOMScoreAdj
|
||||||
}
|
}
|
||||||
if c.Restart != "" {
|
if c.Restart != "" {
|
||||||
splitRestart := strings.Split(c.Restart, ":")
|
policy, retries, err := util.ParseRestartPolicy(c.Restart)
|
||||||
switch len(splitRestart) {
|
if err != nil {
|
||||||
case 1:
|
return err
|
||||||
// No retries specified
|
|
||||||
case 2:
|
|
||||||
if strings.ToLower(splitRestart[0]) != "on-failure" {
|
|
||||||
return errors.New("restart policy retries can only be specified with on-failure restart policy")
|
|
||||||
}
|
|
||||||
retries, err := strconv.Atoi(splitRestart[1])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing restart policy retry count: %w", err)
|
|
||||||
}
|
|
||||||
if retries < 0 {
|
|
||||||
return errors.New("must specify restart policy retry count as a number greater than 0")
|
|
||||||
}
|
|
||||||
var retriesUint = uint(retries)
|
|
||||||
s.RestartRetries = &retriesUint
|
|
||||||
default:
|
|
||||||
return errors.New("invalid restart policy: may specify retries at most once")
|
|
||||||
}
|
}
|
||||||
s.RestartPolicy = splitRestart[0]
|
s.RestartPolicy = policy
|
||||||
|
s.RestartRetries = &retries
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.Secrets) == 0 || len(c.Secrets) != 0 {
|
if len(s.Secrets) == 0 || len(c.Secrets) != 0 {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
encconfig "github.com/containers/ocicrypt/config"
|
encconfig "github.com/containers/ocicrypt/config"
|
||||||
enchelpers "github.com/containers/ocicrypt/helpers"
|
enchelpers "github.com/containers/ocicrypt/helpers"
|
||||||
|
"github.com/containers/podman/v4/libpod/define"
|
||||||
"github.com/containers/podman/v4/pkg/errorhandling"
|
"github.com/containers/podman/v4/pkg/errorhandling"
|
||||||
"github.com/containers/podman/v4/pkg/namespaces"
|
"github.com/containers/podman/v4/pkg/namespaces"
|
||||||
"github.com/containers/podman/v4/pkg/rootless"
|
"github.com/containers/podman/v4/pkg/rootless"
|
||||||
|
@ -665,3 +666,37 @@ func DecryptConfig(decryptionKeys []string) (*encconfig.DecryptConfig, error) {
|
||||||
|
|
||||||
return decryptConfig, nil
|
return decryptConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseRestartPolicy parses the value given to the --restart flag and returns the policy
|
||||||
|
// and restart retries value
|
||||||
|
func ParseRestartPolicy(policy string) (string, uint, error) {
|
||||||
|
var (
|
||||||
|
retriesUint uint
|
||||||
|
policyType string
|
||||||
|
)
|
||||||
|
splitRestart := strings.Split(policy, ":")
|
||||||
|
switch len(splitRestart) {
|
||||||
|
case 1:
|
||||||
|
// No retries specified
|
||||||
|
policyType = splitRestart[0]
|
||||||
|
if strings.ToLower(splitRestart[0]) == "never" {
|
||||||
|
policyType = define.RestartPolicyNo
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if strings.ToLower(splitRestart[0]) != "on-failure" {
|
||||||
|
return "", 0, errors.New("restart policy retries can only be specified with on-failure restart policy")
|
||||||
|
}
|
||||||
|
retries, err := strconv.Atoi(splitRestart[1])
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, fmt.Errorf("parsing restart policy retry count: %w", err)
|
||||||
|
}
|
||||||
|
if retries < 0 {
|
||||||
|
return "", 0, errors.New("must specify restart policy retry count as a number greater than 0")
|
||||||
|
}
|
||||||
|
retriesUint = uint(retries)
|
||||||
|
policyType = splitRestart[0]
|
||||||
|
default:
|
||||||
|
return "", 0, errors.New("invalid restart policy: may specify retries at most once")
|
||||||
|
}
|
||||||
|
return policyType, retriesUint, nil
|
||||||
|
}
|
||||||
|
|
|
@ -528,18 +528,21 @@ var _ = Describe("Podman kube generate", func() {
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman generate kube on pod with restartPolicy", func() {
|
It("podman generate kube on pod with restartPolicy set for container in a pod", func() {
|
||||||
|
//TODO: v5.0 - change/remove test once we block --restart on container when it is in a pod
|
||||||
// podName, set, expect
|
// podName, set, expect
|
||||||
testSli := [][]string{
|
testSli := [][]string{
|
||||||
{"testPod1", "", ""}, // some pod create from cmdline, so set it to an empty string and let k8s default it to Always
|
{"testPod1", "", ""}, // some pod create from cmdline, so set it to an empty string and let k8s default it to Always
|
||||||
{"testPod2", "always", "Always"},
|
{"testPod2", "always", "Always"},
|
||||||
{"testPod3", "on-failure", "OnFailure"},
|
{"testPod3", "on-failure", "OnFailure"},
|
||||||
{"testPod4", "no", "Never"},
|
{"testPod4", "no", "Never"},
|
||||||
|
{"testPod5", "never", "Never"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range testSli {
|
for k, v := range testSli {
|
||||||
podName := v[0]
|
podName := v[0]
|
||||||
podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName})
|
// Need to set --restart during pod creation as gen kube only picks up the pod's restart policy
|
||||||
|
podSession := podmanTest.Podman([]string{"pod", "create", "--restart", v[1], "--name", podName})
|
||||||
podSession.WaitWithDefaultTimeout()
|
podSession.WaitWithDefaultTimeout()
|
||||||
Expect(podSession).Should(Exit(0))
|
Expect(podSession).Should(Exit(0))
|
||||||
|
|
||||||
|
@ -561,6 +564,67 @@ var _ = Describe("Podman kube generate", func() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman generate kube on pod with restartPolicy", func() {
|
||||||
|
// podName, set, expect
|
||||||
|
testSli := [][]string{
|
||||||
|
{"testPod1", "", ""},
|
||||||
|
{"testPod2", "always", "Always"},
|
||||||
|
{"testPod3", "on-failure", "OnFailure"},
|
||||||
|
{"testPod4", "no", "Never"},
|
||||||
|
{"testPod5", "never", "Never"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range testSli {
|
||||||
|
podName := v[0]
|
||||||
|
podSession := podmanTest.Podman([]string{"pod", "create", "--restart", v[1], podName})
|
||||||
|
podSession.WaitWithDefaultTimeout()
|
||||||
|
Expect(podSession).Should(Exit(0))
|
||||||
|
|
||||||
|
ctrName := "ctr" + strconv.Itoa(k)
|
||||||
|
ctr1Session := podmanTest.Podman([]string{"create", "--name", ctrName, "--pod", podName, ALPINE, "top"})
|
||||||
|
ctr1Session.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctr1Session).Should(Exit(0))
|
||||||
|
|
||||||
|
kube := podmanTest.Podman([]string{"generate", "kube", podName})
|
||||||
|
kube.WaitWithDefaultTimeout()
|
||||||
|
Expect(kube).Should(Exit(0))
|
||||||
|
|
||||||
|
pod := new(v1.Pod)
|
||||||
|
err := yaml.Unmarshal(kube.Out.Contents(), pod)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(string(pod.Spec.RestartPolicy)).To(Equal(v[2]))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman generate kube on ctr with restartPolicy", func() {
|
||||||
|
// podName, set, expect
|
||||||
|
testSli := [][]string{
|
||||||
|
{"", ""}, // some ctr created from cmdline, set it to "" and let k8s default it to Always
|
||||||
|
{"always", "Always"},
|
||||||
|
{"on-failure", "OnFailure"},
|
||||||
|
{"no", "Never"},
|
||||||
|
{"never", "Never"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range testSli {
|
||||||
|
ctrName := "ctr" + strconv.Itoa(k)
|
||||||
|
ctrSession := podmanTest.Podman([]string{"create", "--restart", v[0], "--name", ctrName, ALPINE, "top"})
|
||||||
|
ctrSession.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctrSession).Should(Exit(0))
|
||||||
|
|
||||||
|
kube := podmanTest.Podman([]string{"generate", "kube", ctrName})
|
||||||
|
kube.WaitWithDefaultTimeout()
|
||||||
|
Expect(kube).Should(Exit(0))
|
||||||
|
|
||||||
|
pod := new(v1.Pod)
|
||||||
|
err := yaml.Unmarshal(kube.Out.Contents(), pod)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(string(pod.Spec.RestartPolicy)).To(Equal(v[1]))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
It("podman generate kube on pod with memory limit", func() {
|
It("podman generate kube on pod with memory limit", func() {
|
||||||
SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1")
|
SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1")
|
||||||
podName := "testMemoryLimit"
|
podName := "testMemoryLimit"
|
||||||
|
@ -1465,13 +1529,12 @@ USER test1`
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman generate kube on pod with --type=deployment and --restart=no should fail", func() {
|
It("podman generate kube on pod with --type=deployment and --restart=no should fail", func() {
|
||||||
// TODO: When we add --restart for pods, fix this test to reflect that
|
|
||||||
podName := "test-pod"
|
podName := "test-pod"
|
||||||
session := podmanTest.Podman([]string{"pod", "create", podName})
|
session := podmanTest.Podman([]string{"pod", "create", "--restart", "no", podName})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(Exit(0))
|
Expect(session).Should(Exit(0))
|
||||||
|
|
||||||
session = podmanTest.Podman([]string{"create", "--pod", podName, "--restart", "no", ALPINE, "top"})
|
session = podmanTest.Podman([]string{"create", "--pod", podName, ALPINE, "top"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session).Should(Exit(0))
|
Expect(session).Should(Exit(0))
|
||||||
|
|
||||||
|
|
|
@ -2382,7 +2382,7 @@ var _ = Describe("Podman play kube", func() {
|
||||||
kube.WaitWithDefaultTimeout()
|
kube.WaitWithDefaultTimeout()
|
||||||
Expect(kube).Should(Exit(0))
|
Expect(kube).Should(Exit(0))
|
||||||
|
|
||||||
inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "{{.HostConfig.RestartPolicy.Name}}"})
|
inspect := podmanTest.Podman([]string{"inspect", pod.Name, "--format", "{{.RestartPolicy}}"})
|
||||||
inspect.WaitWithDefaultTimeout()
|
inspect.WaitWithDefaultTimeout()
|
||||||
Expect(inspect).Should(Exit(0))
|
Expect(inspect).Should(Exit(0))
|
||||||
Expect(inspect.OutputToString()).To(Equal(v[2]))
|
Expect(inspect.OutputToString()).To(Equal(v[2]))
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/apparmor"
|
"github.com/containers/common/pkg/apparmor"
|
||||||
"github.com/containers/common/pkg/seccomp"
|
"github.com/containers/common/pkg/seccomp"
|
||||||
|
@ -1211,4 +1212,115 @@ ENTRYPOINT ["sleep","99999"]
|
||||||
Expect(inspect).Should(Exit(0))
|
Expect(inspect).Should(Exit(0))
|
||||||
Expect(inspect.OutputToString()).Should(Equal(pod2Name))
|
Expect(inspect.OutputToString()).Should(Equal(pod2Name))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman pod create --restart set to default", func() {
|
||||||
|
// When the --restart flag is not set, the default value is No
|
||||||
|
// TODO: v5.0 change this so that the default value is Always
|
||||||
|
podName := "mypod"
|
||||||
|
testCtr := "ctr1"
|
||||||
|
session := podmanTest.Podman([]string{"pod", "create", podName})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
// add container to pod
|
||||||
|
ctrRun := podmanTest.Podman([]string{"run", "--name", testCtr, "-d", "--pod", podName, ALPINE, "echo", "hello"})
|
||||||
|
ctrRun.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctrRun).Should(Exit(0))
|
||||||
|
// Wait about 1 second, so we can check the number of restarts as default restart policy is set to No
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
ps := podmanTest.Podman([]string{"ps", "-a", "--filter", "name=" + testCtr, "--format", "{{.Restarts}}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps).Should(Exit(0))
|
||||||
|
restarts, err := strconv.Atoi(ps.OutputToString())
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(restarts).To(BeNumerically("==", 0))
|
||||||
|
ps = podmanTest.Podman([]string{"ps", "-a", "--filter", "name=" + testCtr, "--format", "{{.Status}}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps).Should(Exit(0))
|
||||||
|
Expect(ps.OutputToString()).To(ContainSubstring("Exited"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman pod create --restart=on-failure", func() {
|
||||||
|
// Restart policy set to on-failure with max 2 retries
|
||||||
|
podName := "mypod"
|
||||||
|
runningCtr := "ctr1"
|
||||||
|
testCtr := "ctr2"
|
||||||
|
session := podmanTest.Podman([]string{"pod", "create", "--restart", "on-failure:2", podName})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
// add container to pod
|
||||||
|
ctrRun := podmanTest.Podman([]string{"run", "--name", runningCtr, "-d", "--pod", podName, ALPINE, "sleep", "100"})
|
||||||
|
ctrRun.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctrRun).Should(Exit(0))
|
||||||
|
ctrRun = podmanTest.Podman([]string{"run", "--name", testCtr, "-d", "--pod", podName, ALPINE, "sh", "-c", "echo hello && exit 1"})
|
||||||
|
ctrRun.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctrRun).Should(Exit(0))
|
||||||
|
// Wait about 2 seconds, so we can check the number of restarts after failure
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
ps := podmanTest.Podman([]string{"ps", "-a", "--filter", "name=" + testCtr, "--format", "{{.Restarts}}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps).Should(Exit(0))
|
||||||
|
restarts, err := strconv.Atoi(ps.OutputToString())
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(restarts).To(BeNumerically("==", 2))
|
||||||
|
ps = podmanTest.Podman([]string{"ps", "-a", "--filter", "name=" + testCtr, "--format", "{{.Status}}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps).Should(Exit(0))
|
||||||
|
Expect(ps.OutputToString()).To(ContainSubstring("Exited"))
|
||||||
|
ps = podmanTest.Podman([]string{"ps", "-a", "--filter", "name=" + runningCtr, "--format", "{{.Status}}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps).Should(Exit(0))
|
||||||
|
Expect(ps.OutputToString()).To(ContainSubstring("Up"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman pod create --restart=no/never", func() {
|
||||||
|
// never and no are the same, just different words to do the same thing
|
||||||
|
policy := []string{"no", "never"}
|
||||||
|
for _, p := range policy {
|
||||||
|
podName := "mypod-" + p
|
||||||
|
runningCtr := "ctr1-" + p
|
||||||
|
testCtr := "ctr2-" + p
|
||||||
|
testCtr2 := "ctr3-" + p
|
||||||
|
session := podmanTest.Podman([]string{"pod", "create", "--restart", p, podName})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
// add container to pod
|
||||||
|
ctrRun := podmanTest.Podman([]string{"run", "--name", runningCtr, "-d", "--pod", podName, ALPINE, "sleep", "100"})
|
||||||
|
ctrRun.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctrRun).Should(Exit(0))
|
||||||
|
ctrRun = podmanTest.Podman([]string{"run", "--name", testCtr, "-d", "--pod", podName, ALPINE, "echo", "hello"})
|
||||||
|
ctrRun.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctrRun).Should(Exit(0))
|
||||||
|
ctrRun = podmanTest.Podman([]string{"run", "--name", testCtr2, "-d", "--pod", podName, ALPINE, "sh", "-c", "echo hello && exit 1"})
|
||||||
|
ctrRun.WaitWithDefaultTimeout()
|
||||||
|
Expect(ctrRun).Should(Exit(0))
|
||||||
|
// Wait 1 second, so we can check the number of restarts and make sure the container has actually ran
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
// check first test container - container exits with exit code 0
|
||||||
|
ps := podmanTest.Podman([]string{"ps", "-a", "--filter", "name=" + testCtr, "--format", "{{.Restarts}}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps).Should(Exit(0))
|
||||||
|
restarts, err := strconv.Atoi(ps.OutputToString())
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(restarts).To(BeNumerically("==", 0))
|
||||||
|
ps = podmanTest.Podman([]string{"ps", "-a", "--filter", "name=" + testCtr, "--format", "{{.Status}}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps).Should(Exit(0))
|
||||||
|
Expect(ps.OutputToString()).To(ContainSubstring("Exited"))
|
||||||
|
// Check second test container - container exits with non-zero exit code
|
||||||
|
ps = podmanTest.Podman([]string{"ps", "-a", "--filter", "name=" + testCtr2, "--format", "{{.Restarts}}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps).Should(Exit(0))
|
||||||
|
restarts, err = strconv.Atoi(ps.OutputToString())
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(restarts).To(BeNumerically("==", 0))
|
||||||
|
ps = podmanTest.Podman([]string{"ps", "-a", "--filter", "name=" + testCtr2, "--format", "{{.Status}}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps).Should(Exit(0))
|
||||||
|
Expect(ps.OutputToString()).To(ContainSubstring("Exited"))
|
||||||
|
ps = podmanTest.Podman([]string{"ps", "-a", "--filter", "name=" + runningCtr, "--format", "{{.Status}}"})
|
||||||
|
ps.WaitWithDefaultTimeout()
|
||||||
|
Expect(ps).Should(Exit(0))
|
||||||
|
Expect(ps.OutputToString()).To(ContainSubstring("Up"))
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue