Skip to content

Commit

Permalink
Merge pull request #19371 from danishprakash/daemonset-support
Browse files Browse the repository at this point in the history
kube: add DaemonSet support
  • Loading branch information
openshift-merge-robot authored Aug 8, 2023
2 parents 331d618 + d6815da commit 195f1be
Show file tree
Hide file tree
Showing 2 changed files with 255 additions and 1 deletion.
50 changes: 49 additions & 1 deletion pkg/domain/infra/abi/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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...)
Expand Down Expand Up @@ -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

Expand Down
206 changes: 206 additions & 0 deletions test/e2e/play_kube_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1044,6 +1197,7 @@ var (
defaultCtrImage = ALPINE
defaultPodName = "testPod"
defaultVolName = "testVol"
defaultDaemonSetName = "testDaemonSet"
defaultDeploymentName = "testDeployment"
defaultConfigMapName = "testConfigMap"
defaultSecretName = "testSecret"
Expand All @@ -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":
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit 195f1be

Please sign in to comment.