From f0ccac199bd500729dabc8948bbd4ddd0124231e Mon Sep 17 00:00:00 2001
From: zhangguanzhang <zhangguanzhang@qq.com>
Date: Thu, 17 Sep 2020 22:18:43 +0800
Subject: [PATCH] handle the play kube and generate kube for with restartPolicy

Signed-off-by: zhangguanzhang <zhangguanzhang@qq.com>
---
 libpod/kube.go                 | 18 +++++++++
 pkg/domain/infra/abi/play.go   | 13 +++++++
 test/e2e/generate_kube_test.go | 34 +++++++++++++++++
 test/e2e/play_kube_test.go     | 68 +++++++++++++++++++++++++++-------
 4 files changed, 119 insertions(+), 14 deletions(-)

diff --git a/libpod/kube.go b/libpod/kube.go
index 9d5cbe68b2..f83e99d82e 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -77,6 +77,24 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) {
 	}
 	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 RestartPolicyAlways:
+				pod.Spec.RestartPolicy = v1.RestartPolicyAlways
+			case RestartPolicyOnFailure:
+				pod.Spec.RestartPolicy = v1.RestartPolicyOnFailure
+			case RestartPolicyNo:
+				pod.Spec.RestartPolicy = v1.RestartPolicyNever
+			default: // some pod create from cmdline, such as "", so set it to Never
+				pod.Spec.RestartPolicy = v1.RestartPolicyNever
+			}
+			break
+		}
+	}
+
 	if p.SharesPID() {
 		// unfortunately, go doesn't have a nice way to specify a pointer to a bool
 		b := true
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 659cc799c7..aa6aeede28 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -299,6 +299,18 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
 		return nil, err
 	}
 
+	var ctrRestartPolicy string
+	switch podYAML.Spec.RestartPolicy {
+	case v1.RestartPolicyAlways:
+		ctrRestartPolicy = libpod.RestartPolicyAlways
+	case v1.RestartPolicyOnFailure:
+		ctrRestartPolicy = libpod.RestartPolicyOnFailure
+	case v1.RestartPolicyNever:
+		ctrRestartPolicy = libpod.RestartPolicyNo
+	default: // Default to Always
+		ctrRestartPolicy = libpod.RestartPolicyAlways
+	}
+
 	containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers))
 	for _, container := range podYAML.Spec.Containers {
 		pullPolicy := util.PullImageMissing
@@ -326,6 +338,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
 		if err != nil {
 			return nil, err
 		}
+		conf.RestartPolicy = ctrRestartPolicy
 		ctr, err := createconfig.CreateContainerFromCreateConfig(ctx, ic.Libpod, conf, pod)
 		if err != nil {
 			return nil, err
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index e886c6000f..a3a841dc68 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -3,6 +3,7 @@ package integration
 import (
 	"os"
 	"path/filepath"
+	"strconv"
 
 	. "github.com/containers/podman/v2/test/utils"
 	"github.com/ghodss/yaml"
@@ -201,6 +202,39 @@ var _ = Describe("Podman generate kube", func() {
 		// Expect(err).To(BeNil())
 	})
 
+	It("podman generate kube on pod with restartPolicy", func() {
+		// podName,  set,  expect
+		testSli := [][]string{
+			{"testPod1", "", "Never"}, // some pod create from cmdline, so set it to Never
+			{"testPod2", "always", "Always"},
+			{"testPod3", "on-failure", "OnFailure"},
+			{"testPod4", "no", "Never"},
+		}
+
+		for k, v := range testSli {
+			podName := v[0]
+			podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName})
+			podSession.WaitWithDefaultTimeout()
+			Expect(podSession.ExitCode()).To(Equal(0))
+
+			ctrName := "ctr" + strconv.Itoa(k)
+			ctr1Session := podmanTest.Podman([]string{"create", "--name", ctrName, "--pod", podName,
+				"--restart", v[1], ALPINE, "top"})
+			ctr1Session.WaitWithDefaultTimeout()
+			Expect(ctr1Session.ExitCode()).To(Equal(0))
+
+			kube := podmanTest.Podman([]string{"generate", "kube", podName})
+			kube.WaitWithDefaultTimeout()
+			Expect(kube.ExitCode()).To(Equal(0))
+
+			pod := new(v1.Pod)
+			err := yaml.Unmarshal(kube.Out.Contents(), pod)
+			Expect(err).To(BeNil())
+
+			Expect(string(pod.Spec.RestartPolicy)).To(Equal(v[2]))
+		}
+	})
+
 	It("podman generate kube on pod with ports", func() {
 		podName := "test"
 		podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName, "-p", "4000:4000", "-p", "5000:5000"})
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index f58862ab20..7a5aebcc21 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -46,6 +46,7 @@ metadata:
 {{ end }}
 
 spec:
+  restartPolicy: {{ .RestartPolicy }}
   hostname: {{ .Hostname }}
   hostAliases:
 {{ range .HostAliases }}
@@ -165,6 +166,7 @@ spec:
       {{- end }}
       {{- end }}
     spec:
+      restartPolicy: {{ .RestartPolicy }}
       hostname: {{ .Hostname }}
       containers:
     {{ with .Ctrs }}
@@ -274,13 +276,14 @@ func generateDeploymentKubeYaml(deployment *Deployment, fileName string) error {
 
 // Pod describes the options a kube yaml can be configured at pod level
 type Pod struct {
-	Name        string
-	Hostname    string
-	HostAliases []HostAlias
-	Ctrs        []*Ctr
-	Volumes     []*Volume
-	Labels      map[string]string
-	Annotations map[string]string
+	Name          string
+	RestartPolicy string
+	Hostname      string
+	HostAliases   []HostAlias
+	Ctrs          []*Ctr
+	Volumes       []*Volume
+	Labels        map[string]string
+	Annotations   map[string]string
 }
 
 type HostAlias struct {
@@ -293,13 +296,14 @@ type HostAlias struct {
 // if no containers are added, it will add the default container
 func getPod(options ...podOption) *Pod {
 	p := Pod{
-		Name:        defaultPodName,
-		Hostname:    "",
-		HostAliases: nil,
-		Ctrs:        make([]*Ctr, 0),
-		Volumes:     make([]*Volume, 0),
-		Labels:      make(map[string]string),
-		Annotations: make(map[string]string),
+		Name:          defaultPodName,
+		RestartPolicy: "Never",
+		Hostname:      "",
+		HostAliases:   nil,
+		Ctrs:          make([]*Ctr, 0),
+		Volumes:       make([]*Volume, 0),
+		Labels:        make(map[string]string),
+		Annotations:   make(map[string]string),
 	}
 	for _, option := range options {
 		option(&p)
@@ -312,6 +316,12 @@ func getPod(options ...podOption) *Pod {
 
 type podOption func(*Pod)
 
+func withPodName(name string) podOption {
+	return func(pod *Pod) {
+		pod.Name = name
+	}
+}
+
 func withHostname(h string) podOption {
 	return func(pod *Pod) {
 		pod.Hostname = h
@@ -333,6 +343,12 @@ func withCtr(c *Ctr) podOption {
 	}
 }
 
+func withRestartPolicy(policy string) podOption {
+	return func(pod *Pod) {
+		pod.RestartPolicy = policy
+	}
+}
+
 func withLabel(k, v string) podOption {
 	return func(pod *Pod) {
 		pod.Labels[k] = v
@@ -649,6 +665,30 @@ var _ = Describe("Podman generate kube", func() {
 		Expect(inspect.OutputToString()).To(ContainSubstring(`[echo hello world]`))
 	})
 
+	It("podman play kube test restartPolicy", func() {
+		// podName,  set,  expect
+		testSli := [][]string{
+			{"testPod1", "", "always"}, // Default eqaul to always
+			{"testPod2", "Always", "always"},
+			{"testPod3", "OnFailure", "on-failure"},
+			{"testPod4", "Never", "no"},
+		}
+		for _, v := range testSli {
+			pod := getPod(withPodName(v[0]), withRestartPolicy(v[1]))
+			err := generatePodKubeYaml(pod, kubeYaml)
+			Expect(err).To(BeNil())
+
+			kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+			kube.WaitWithDefaultTimeout()
+			Expect(kube.ExitCode()).To(Equal(0))
+
+			inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "{{.HostConfig.RestartPolicy.Name}}"})
+			inspect.WaitWithDefaultTimeout()
+			Expect(inspect.ExitCode()).To(Equal(0))
+			Expect(inspect.OutputToString()).To(Equal(v[2]))
+		}
+	})
+
 	It("podman play kube test hostname", func() {
 		pod := getPod()
 		err := generatePodKubeYaml(pod, kubeYaml)