diff --git a/docs/conversion.md b/docs/conversion.md index e962b867..3b478061 100644 --- a/docs/conversion.md +++ b/docs/conversion.md @@ -32,7 +32,7 @@ This document outlines all possible conversion details regarding `docker-compose | logging | N | | | | network_mode | N | | | | networks | N | | | -| pid | N | | | +| pid | Y | Pod.Spec.HostPID | | | ports | Y | Service.Spec.Ports | | | security_opt | N | | | | stop_grace_period | Y | Pod.Spec.TerminationGracePeriodSeconds | | diff --git a/pkg/kobject/kobject.go b/pkg/kobject/kobject.go index 3572423d..51fdda93 100644 --- a/pkg/kobject/kobject.go +++ b/pkg/kobject/kobject.go @@ -76,6 +76,7 @@ type ServiceConfig struct { CapAdd []string `compose:"cap_add" bundle:""` CapDrop []string `compose:"cap_drop" bundle:""` Expose []string `compose:"expose" bundle:""` + Pid string `compose:"pid" bundle:""` Privileged bool `compose:"privileged" bundle:""` Restart string `compose:"restart" bundle:""` User string `compose:"user" bundle:"User"` diff --git a/pkg/loader/compose/compose.go b/pkg/loader/compose/compose.go index fd0524be..9c5646b9 100644 --- a/pkg/loader/compose/compose.go +++ b/pkg/loader/compose/compose.go @@ -68,7 +68,6 @@ func checkUnsupportedKey(composeProject *project.Project) []string { "MacAddress": false, "MemSwapLimit": false, "NetworkMode": false, - "Pid": false, "SecurityOpt": false, "ShmSize": false, "StopSignal": false, @@ -368,6 +367,7 @@ func (c *Compose) LoadFile(files []string) (kobject.KomposeObject, error) { serviceConfig.CPUQuota = int64(composeServiceConfig.CPUQuota) serviceConfig.CapAdd = composeServiceConfig.CapAdd serviceConfig.CapDrop = composeServiceConfig.CapDrop + serviceConfig.Pid = composeServiceConfig.Pid serviceConfig.Expose = composeServiceConfig.Expose serviceConfig.Privileged = composeServiceConfig.Privileged serviceConfig.Restart = composeServiceConfig.Restart diff --git a/pkg/transformer/kubernetes/k8sutils.go b/pkg/transformer/kubernetes/k8sutils.go index f40100a3..76f4aafe 100644 --- a/pkg/transformer/kubernetes/k8sutils.go +++ b/pkg/transformer/kubernetes/k8sutils.go @@ -399,6 +399,16 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic template.Spec.Containers[0].Resources.Limits = memoryResourceList } + podSecurityContext := &api.PodSecurityContext{} + //set pid namespace mode + if service.Pid != "" { + if service.Pid == "host" { + podSecurityContext.HostPID = true + } else { + log.Warningf("Ignoring PID key for service \"%v\". Invalid value \"%v\".", name, service.Pid) + } + } + // Setup security context securityContext := &api.SecurityContext{} if service.Privileged == true { @@ -423,7 +433,9 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic if *securityContext != (api.SecurityContext{}) { template.Spec.Containers[0].SecurityContext = securityContext } - + if !reflect.DeepEqual(*podSecurityContext, api.PodSecurityContext{}) { + template.Spec.SecurityContext = podSecurityContext + } template.Spec.Containers[0].Ports = ports template.ObjectMeta.Labels = transformer.ConfigLabels(name) diff --git a/pkg/transformer/kubernetes/k8sutils_test.go b/pkg/transformer/kubernetes/k8sutils_test.go index 7c2ed342..94f7f042 100644 --- a/pkg/transformer/kubernetes/k8sutils_test.go +++ b/pkg/transformer/kubernetes/k8sutils_test.go @@ -174,6 +174,80 @@ func TestCreateServiceWithServiceUser(t *testing.T) { } +func TestTransformWithPid(t *testing.T) { + // An example service + service := kobject.ServiceConfig{ + ContainerName: "name", + Image: "image", + Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, + Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: api.ProtocolTCP}}, + Command: []string{"cmd"}, + WorkingDir: "dir", + Args: []string{"arg1", "arg2"}, + Volumes: []string{"/tmp/volume"}, + Network: []string{"network1", "network2"}, + Restart: "always", + Pid: "host", + } + + // An example object generated via k8s runtime.Objects() + komposeObject := kobject.KomposeObject{ + ServiceConfigs: map[string]kobject.ServiceConfig{"app": service}, + } + k := Kubernetes{} + objects, err := k.Transform(komposeObject, kobject.ConvertOptions{CreateD: true, Replicas: 3}) + if err != nil { + t.Error(errors.Wrap(err, "k.Transform failed")) + } + + for _, obj := range objects { + if deploy, ok := obj.(*extensions.Deployment); ok { + hostPid := deploy.Spec.Template.Spec.SecurityContext.HostPID + if hostPid != true { + t.Errorf("Pid in ServiceConfig is not matching HostPID in PodSpec") + } + } + } +} + +func TestTransformWithInvaildPid(t *testing.T) { + // An example service + service := kobject.ServiceConfig{ + ContainerName: "name", + Image: "image", + Environment: []kobject.EnvVar{kobject.EnvVar{Name: "env", Value: "value"}}, + Port: []kobject.Ports{kobject.Ports{HostPort: 123, ContainerPort: 456, Protocol: api.ProtocolTCP}}, + Command: []string{"cmd"}, + WorkingDir: "dir", + Args: []string{"arg1", "arg2"}, + Volumes: []string{"/tmp/volume"}, + Network: []string{"network1", "network2"}, + Restart: "always", + Pid: "badvalue", + } + + // An example object generated via k8s runtime.Objects() + komposeObject := kobject.KomposeObject{ + ServiceConfigs: map[string]kobject.ServiceConfig{"app": service}, + } + k := Kubernetes{} + objects, err := k.Transform(komposeObject, kobject.ConvertOptions{CreateD: true, Replicas: 3}) + if err != nil { + t.Error(errors.Wrap(err, "k.Transform failed")) + } + + for _, obj := range objects { + if deploy, ok := obj.(*extensions.Deployment); ok { + if deploy.Spec.Template.Spec.SecurityContext != nil { + hostPid := deploy.Spec.Template.Spec.SecurityContext.HostPID + if hostPid != false { + t.Errorf("Pid in ServiceConfig is not matching HostPID in PodSpec") + } + } + } + } +} + func TestIsDir(t *testing.T) { tempPath := "/tmp/kompose_unit" tempDir := filepath.Join(tempPath, "i_am_dir")