mirror of https://github.com/containers/podman.git
				
				
				
			Merge pull request #19371 from danishprakash/daemonset-support
kube: add DaemonSet support
This commit is contained in:
		
						commit
						195f1be89a
					
				|  | @ -246,6 +246,22 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options | |||
| 			} | ||||
| 			notifyProxies = append(notifyProxies, proxies...) | ||||
| 
 | ||||
| 			report.Pods = append(report.Pods, r.Pods...) | ||||
| 			validKinds++ | ||||
| 			ranContainers = true | ||||
| 		case "DaemonSet": | ||||
| 			var daemonSetYAML v1apps.DaemonSet | ||||
| 
 | ||||
| 			if err := yaml.Unmarshal(document, &daemonSetYAML); err != nil { | ||||
| 				return nil, fmt.Errorf("unable to read YAML as Kube DaemonSet: %w", err) | ||||
| 			} | ||||
| 
 | ||||
| 			r, proxies, err := ic.playKubeDaemonSet(ctx, &daemonSetYAML, options, &ipIndex, configMaps, serviceContainer) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			notifyProxies = append(notifyProxies, proxies...) | ||||
| 
 | ||||
| 			report.Pods = append(report.Pods, r.Pods...) | ||||
| 			validKinds++ | ||||
| 			ranContainers = true | ||||
|  | @ -366,6 +382,29 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options | |||
| 	return report, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) playKubeDaemonSet(ctx context.Context, daemonSetYAML *v1apps.DaemonSet, options entities.PlayKubeOptions, ipIndex *int, configMaps []v1.ConfigMap, serviceContainer *libpod.Container) (*entities.PlayKubeReport, []*notifyproxy.NotifyProxy, error) { | ||||
| 	var ( | ||||
| 		daemonSetName string | ||||
| 		podSpec       v1.PodTemplateSpec | ||||
| 		report        entities.PlayKubeReport | ||||
| 	) | ||||
| 
 | ||||
| 	daemonSetName = daemonSetYAML.ObjectMeta.Name | ||||
| 	if daemonSetName == "" { | ||||
| 		return nil, nil, errors.New("daemonSet does not have a name") | ||||
| 	} | ||||
| 	podSpec = daemonSetYAML.Spec.Template | ||||
| 
 | ||||
| 	podName := fmt.Sprintf("%s-pod", daemonSetName) | ||||
| 	podReport, proxies, err := ic.playKubePod(ctx, podName, &podSpec, options, ipIndex, daemonSetYAML.Annotations, configMaps, serviceContainer) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, fmt.Errorf("encountered while bringing up pod %s: %w", podName, err) | ||||
| 	} | ||||
| 	report.Pods = podReport.Pods | ||||
| 
 | ||||
| 	return &report, proxies, nil | ||||
| } | ||||
| 
 | ||||
| func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAML *v1apps.Deployment, options entities.PlayKubeOptions, ipIndex *int, configMaps []v1.ConfigMap, serviceContainer *libpod.Container) (*entities.PlayKubeReport, []*notifyproxy.NotifyProxy, error) { | ||||
| 	var ( | ||||
| 		deploymentName string | ||||
|  | @ -1249,7 +1288,7 @@ func sortKubeKinds(documentList [][]byte) ([][]byte, error) { | |||
| 		} | ||||
| 
 | ||||
| 		switch kind { | ||||
| 		case "Pod", "Deployment": | ||||
| 		case "Pod", "Deployment", "DaemonSet": | ||||
| 			sortedDocumentList = append(sortedDocumentList, document) | ||||
| 		default: | ||||
| 			sortedDocumentList = append([][]byte{document}, sortedDocumentList...) | ||||
|  | @ -1354,6 +1393,15 @@ func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, opt | |||
| 					volumeNames = append(volumeNames, vs.Secret.SecretName) | ||||
| 				} | ||||
| 			} | ||||
| 		case "DaemonSet": | ||||
| 			var daemonSetYAML v1apps.DaemonSet | ||||
| 
 | ||||
| 			if err := yaml.Unmarshal(document, &daemonSetYAML); err != nil { | ||||
| 				return nil, fmt.Errorf("unable to read YAML as Kube DaemonSet: %w", err) | ||||
| 			} | ||||
| 
 | ||||
| 			podName := fmt.Sprintf("%s-pod", daemonSetYAML.Name) | ||||
| 			podNames = append(podNames, podName) | ||||
| 		case "Deployment": | ||||
| 			var deploymentYAML v1apps.Deployment | ||||
| 
 | ||||
|  |  | |||
|  | @ -723,6 +723,159 @@ spec: | |||
| status: {} | ||||
| ` | ||||
| 
 | ||||
| var daemonSetYamlTemplate = ` | ||||
| apiVersion: v1 | ||||
| kind: DaemonSet | ||||
| metadata: | ||||
|   creationTimestamp: "2019-07-17T14:44:08Z" | ||||
|   name: {{ .Name }} | ||||
|   labels: | ||||
|     app: {{ .Name }} | ||||
| {{ with .Labels }} | ||||
|   {{ range $key, $value := . }} | ||||
|     {{ $key }}: {{ $value }} | ||||
|   {{ end }} | ||||
| {{ end }} | ||||
| {{ with .Annotations }} | ||||
|   annotations: | ||||
|   {{ range $key, $value := . }} | ||||
|     {{ $key }}: {{ $value }} | ||||
|   {{ end }} | ||||
| {{ end }} | ||||
| 
 | ||||
| spec: | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       app: {{ .Name }} | ||||
|   template: | ||||
|   {{ with .PodTemplate }} | ||||
|     metadata: | ||||
|       labels: | ||||
|         app: {{ .Name }} | ||||
|         {{- with .Labels }}{{ range $key, $value := . }} | ||||
|         {{ $key }}: {{ $value }} | ||||
|         {{- end }}{{ end }} | ||||
|       {{- with .Annotations }} | ||||
|       annotations: | ||||
|       {{- range $key, $value := . }} | ||||
|         {{ $key }}: {{ $value }} | ||||
|       {{- end }} | ||||
|       {{- end }} | ||||
|     spec: | ||||
|       restartPolicy: {{ .RestartPolicy }} | ||||
|       hostname: {{ .Hostname }} | ||||
|       hostNetwork: {{ .HostNetwork }} | ||||
|       containers: | ||||
|     {{ with .Ctrs }} | ||||
|       {{ range . }} | ||||
|       - command: | ||||
|         {{ range .Cmd }} | ||||
|         - {{.}} | ||||
|         {{ end }} | ||||
|         args: | ||||
|         {{ range .Arg }} | ||||
|         - {{.}} | ||||
|         {{ end }} | ||||
|         env: | ||||
|         - name: HOSTNAME | ||||
|         {{ range .Env }} | ||||
|         - name: {{ .Name }} | ||||
|         {{ if (eq .ValueFrom "configmap") }} | ||||
|           valueFrom: | ||||
|             configMapKeyRef: | ||||
|               name: {{ .RefName }} | ||||
|               key: {{ .RefKey }} | ||||
|               optional: {{ .Optional }} | ||||
|         {{ end }} | ||||
|         {{ if (eq .ValueFrom "secret") }} | ||||
|           valueFrom: | ||||
|             secretKeyRef: | ||||
|               name: {{ .RefName }} | ||||
|               key: {{ .RefKey }} | ||||
|               optional: {{ .Optional }} | ||||
|         {{ end }} | ||||
|         {{ if (eq .ValueFrom "") }} | ||||
|           value: {{ .Value }} | ||||
|         {{ end }} | ||||
|         {{ end }} | ||||
|         {{ with .EnvFrom}} | ||||
|         envFrom: | ||||
|         {{ range . }} | ||||
|         {{ if (eq .From "configmap") }} | ||||
|         - configMapRef: | ||||
|             name: {{ .Name }} | ||||
|             optional: {{ .Optional }} | ||||
|         {{ end }} | ||||
|         {{ if (eq .From "secret") }} | ||||
|         - secretRef: | ||||
|             name: {{ .Name }} | ||||
|             optional: {{ .Optional }} | ||||
|         {{ end }} | ||||
|         {{ end }} | ||||
|         {{ end }} | ||||
|         image: {{ .Image }} | ||||
|         name: {{ .Name }} | ||||
|         imagePullPolicy: {{ .PullPolicy }} | ||||
|         {{- if or .CPURequest .CPULimit .MemoryRequest .MemoryLimit }} | ||||
|         resources: | ||||
|           {{- if or .CPURequest .MemoryRequest }} | ||||
|           requests: | ||||
|             {{if .CPURequest }}cpu: {{ .CPURequest }}{{ end }} | ||||
|             {{if .MemoryRequest }}memory: {{ .MemoryRequest }}{{ end }} | ||||
|           {{- end }} | ||||
|           {{- if or .CPULimit .MemoryLimit }} | ||||
|           limits: | ||||
|             {{if .CPULimit }}cpu: {{ .CPULimit }}{{ end }} | ||||
|             {{if .MemoryLimit }}memory: {{ .MemoryLimit }}{{ end }} | ||||
|           {{- end }} | ||||
|         {{- end }} | ||||
|         {{ if .SecurityContext }} | ||||
|         securityContext: | ||||
|           allowPrivilegeEscalation: true | ||||
|           {{ if .Caps }} | ||||
|           capabilities: | ||||
|             {{ with .CapAdd }} | ||||
|             add: | ||||
|               {{ range . }} | ||||
|               - {{.}} | ||||
|               {{ end }} | ||||
|             {{ end }} | ||||
|             {{ with .CapDrop }} | ||||
|             drop: | ||||
|               {{ range . }} | ||||
|               - {{.}} | ||||
|               {{ end }} | ||||
|             {{ end }} | ||||
|           {{ end }} | ||||
|           privileged: false | ||||
|           readOnlyRootFilesystem: false | ||||
|         workingDir: / | ||||
|         volumeMounts: | ||||
|         {{ if .VolumeMount }} | ||||
|         - name: {{.VolumeName}} | ||||
|           mountPath: {{ .VolumeMountPath }} | ||||
|           readonly: {{.VolumeReadOnly}} | ||||
|         {{ end }} | ||||
|         {{ end }} | ||||
|       {{ end }} | ||||
|     {{ end }} | ||||
|     {{ with .Volumes }} | ||||
|       volumes: | ||||
|       {{ range . }} | ||||
|       - name: {{ .Name }} | ||||
|         {{- if (eq .VolumeType "HostPath") }} | ||||
|         hostPath: | ||||
|           path: {{ .HostPath.Path }} | ||||
|           type: {{ .HostPath.Type }} | ||||
|         {{- end }} | ||||
|         {{- if (eq .VolumeType "PersistentVolumeClaim") }} | ||||
|         persistentVolumeClaim: | ||||
|           claimName: {{ .PersistentVolumeClaim.ClaimName }} | ||||
|         {{- end }} | ||||
|       {{ end }} | ||||
|     {{ end }} | ||||
| {{ end }} | ||||
| ` | ||||
| var deploymentYamlTemplate = ` | ||||
| apiVersion: v1 | ||||
| kind: Deployment | ||||
|  | @ -1044,6 +1197,7 @@ var ( | |||
| 	defaultCtrImage       = ALPINE | ||||
| 	defaultPodName        = "testPod" | ||||
| 	defaultVolName        = "testVol" | ||||
| 	defaultDaemonSetName  = "testDaemonSet" | ||||
| 	defaultDeploymentName = "testDeployment" | ||||
| 	defaultConfigMapName  = "testConfigMap" | ||||
| 	defaultSecretName     = "testSecret" | ||||
|  | @ -1065,6 +1219,8 @@ func getKubeYaml(kind string, object interface{}) (string, error) { | |||
| 		yamlTemplate = configMapYamlTemplate | ||||
| 	case "pod": | ||||
| 		yamlTemplate = podYamlTemplate | ||||
| 	case "daemonset": | ||||
| 		yamlTemplate = daemonSetYamlTemplate | ||||
| 	case "deployment": | ||||
| 		yamlTemplate = deploymentYamlTemplate | ||||
| 	case "persistentVolumeClaim": | ||||
|  | @ -1356,6 +1512,29 @@ func withHostUsers(val bool) podOption { | |||
| } | ||||
| 
 | ||||
| // Deployment describes the options a kube yaml can be configured at deployment level
 | ||||
| type DaemonSet struct { | ||||
| 	Name        string | ||||
| 	Labels      map[string]string | ||||
| 	Annotations map[string]string | ||||
| 	PodTemplate *Pod | ||||
| } | ||||
| 
 | ||||
| func getDaemonSet(options ...daemonSetOption) *DaemonSet { | ||||
| 	d := DaemonSet{ | ||||
| 		Name:        defaultDaemonSetName, | ||||
| 		Labels:      make(map[string]string), | ||||
| 		Annotations: make(map[string]string), | ||||
| 		PodTemplate: getPod(), | ||||
| 	} | ||||
| 	for _, option := range options { | ||||
| 		option(&d) | ||||
| 	} | ||||
| 
 | ||||
| 	return &d | ||||
| } | ||||
| 
 | ||||
| type daemonSetOption func(*DaemonSet) | ||||
| 
 | ||||
| type Deployment struct { | ||||
| 	Name        string | ||||
| 	Replicas    int32 | ||||
|  | @ -1399,6 +1578,16 @@ func withReplicas(replicas int32) deploymentOption { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // getPodNameInDeployment returns the Pod object
 | ||||
| // with just its name set, so that it can be passed around
 | ||||
| // and into getCtrNameInPod for ease of testing
 | ||||
| func getPodNameInDaemonSet(d *DaemonSet) Pod { | ||||
| 	p := Pod{} | ||||
| 	p.Name = fmt.Sprintf("%s-pod", d.Name) | ||||
| 
 | ||||
| 	return p | ||||
| } | ||||
| 
 | ||||
| // getPodNameInDeployment returns the Pod object
 | ||||
| // with just its name set, so that it can be passed around
 | ||||
| // and into getCtrNameInPod for ease of testing
 | ||||
|  | @ -2951,6 +3140,23 @@ spec: | |||
| 		Expect(ctr[0].Config).To(HaveField("StopSignal", uint(51))) | ||||
| 	}) | ||||
| 
 | ||||
| 	It("podman play kube daemonset sanity", func() { | ||||
| 		daemonset := getDaemonSet() | ||||
| 		err := generateKubeYaml("daemonset", daemonset, kubeYaml) | ||||
| 		Expect(err).ToNot(HaveOccurred()) | ||||
| 
 | ||||
| 		kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) | ||||
| 		kube.WaitWithDefaultTimeout() | ||||
| 		Expect(kube).Should(Exit(0)) | ||||
| 
 | ||||
| 		podName := getPodNameInDaemonSet(daemonset) | ||||
| 		inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(&podName), "--format", "'{{ .Config.Entrypoint }}'"}) | ||||
| 		inspect.WaitWithDefaultTimeout() | ||||
| 		Expect(inspect).Should(Exit(0)) | ||||
| 		// yaml's command should override the image's Entrypoint
 | ||||
| 		Expect(inspect.OutputToString()).To(ContainSubstring(strings.Join(defaultCtrCmd, " "))) | ||||
| 	}) | ||||
| 
 | ||||
| 	// Deployment related tests
 | ||||
| 	It("podman play kube deployment 1 replica test correct command", func() { | ||||
| 		deployment := getDeployment() | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue