Update kube gen & play to use pod restart policy

Podman kube generate now uses the pod's restart policy
when generating the kube yaml. If generating from containers
only, use the restart policy of the first non-init container.
Podman kube play applies the pod restart policy from the yaml
file to the pod. The containers within a pod inherit this restart
policy.

Signed-off-by: Urvashi Mohnani <umohnani@redhat.com>
This commit is contained in:
Urvashi Mohnani
2023-04-13 13:45:28 -04:00
parent db4ad54f92
commit fa1ba17bc1
4 changed files with 108 additions and 32 deletions

View File

@ -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

View File

@ -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(),

View File

@ -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))

View File

@ -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]))