mirror of
https://github.com/docker/compose.git
synced 2025-07-25 14:44:29 +02:00
podTemplate conversion test cases
adapted from compose-on-kubernetes some test need to be fixed, marked as /*FIXME Test*/ Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
f7c86a7d30
commit
f1976eca07
@ -30,14 +30,22 @@ func toPodTemplate(serviceConfig types.ServiceConfig, labels map[string]string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return apiv1.PodTemplateSpec{}, err
|
return apiv1.PodTemplateSpec{}, err
|
||||||
}
|
}
|
||||||
limits, err := toResource(serviceConfig.Deploy)
|
|
||||||
|
var limits apiv1.ResourceList = nil
|
||||||
|
if serviceConfig.Deploy != nil && serviceConfig.Deploy.Resources.Limits != nil {
|
||||||
|
limits, err = toResource(serviceConfig.Deploy.Resources.Limits)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiv1.PodTemplateSpec{}, err
|
return apiv1.PodTemplateSpec{}, err
|
||||||
}
|
}
|
||||||
requests, err := toResource(serviceConfig.Deploy)
|
}
|
||||||
|
var requests apiv1.ResourceList = nil
|
||||||
|
if serviceConfig.Deploy != nil && serviceConfig.Deploy.Resources.Reservations != nil {
|
||||||
|
requests, err = toResource(serviceConfig.Deploy.Resources.Reservations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiv1.PodTemplateSpec{}, err
|
return apiv1.PodTemplateSpec{}, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
volumes, err := toVolumes(serviceConfig, model)
|
volumes, err := toVolumes(serviceConfig, model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiv1.PodTemplateSpec{}, err
|
return apiv1.PodTemplateSpec{}, err
|
||||||
@ -252,12 +260,7 @@ func toRestartPolicy(s types.ServiceConfig) (apiv1.RestartPolicy, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toResource(deploy *types.DeployConfig) (apiv1.ResourceList, error) {
|
func toResource(res *types.Resource) (apiv1.ResourceList, error) {
|
||||||
if deploy == nil || deploy.Resources.Limits == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
res := deploy.Resources.Limits
|
|
||||||
list := make(apiv1.ResourceList)
|
list := make(apiv1.ResourceList)
|
||||||
if res.NanoCPUs != "" {
|
if res.NanoCPUs != "" {
|
||||||
cpus, err := resource.ParseQuantity(res.NanoCPUs)
|
cpus, err := resource.ParseQuantity(res.NanoCPUs)
|
||||||
|
984
convert/pod_test.go
Normal file
984
convert/pod_test.go
Normal file
@ -0,0 +1,984 @@
|
|||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/compose-spec/compose-go/loader"
|
||||||
|
"github.com/compose-spec/compose-go/types"
|
||||||
|
"github.com/docker/helm-prototype/pkg/compose"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
apiv1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadYAML(yaml string) (*compose.Project, error) {
|
||||||
|
dict, err := loader.ParseYAML([]byte(yaml))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
workingDir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return compose.NewProject(types.ConfigDetails{
|
||||||
|
WorkingDir: workingDir,
|
||||||
|
ConfigFiles: []types.ConfigFile{
|
||||||
|
{Filename: "compose.yaml", Config: dict},
|
||||||
|
},
|
||||||
|
}, "test")
|
||||||
|
}
|
||||||
|
|
||||||
|
func podTemplate(t *testing.T, yaml string) apiv1.PodTemplateSpec {
|
||||||
|
res, err := podTemplateWithError(yaml)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func podTemplateWithError(yaml string) (apiv1.PodTemplateSpec, error) {
|
||||||
|
project, err := loadYAML(yaml)
|
||||||
|
if err != nil {
|
||||||
|
return apiv1.PodTemplateSpec{}, err
|
||||||
|
}
|
||||||
|
return toPodTemplate(project.Services[0], nil, project)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithDockerSocket(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
t.Skip("on windows, source path validation is broken (and actually, source validation for windows workload is broken too). Skip it for now, as we don't support it yet")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
volumes:
|
||||||
|
- "/var/run/docker.sock:/var/run/docker.sock"
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedVolume := apiv1.Volume{
|
||||||
|
Name: "mount-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
HostPath: &apiv1.HostPathVolumeSource{
|
||||||
|
Path: "/var/run",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMount := apiv1.VolumeMount{
|
||||||
|
Name: "mount-0",
|
||||||
|
MountPath: "/var/run/docker.sock",
|
||||||
|
SubPath: "docker.sock",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 1)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 1)
|
||||||
|
assert.Equal(t, expectedVolume, podTemplate.Spec.Volumes[0])
|
||||||
|
assert.Equal(t, expectedMount, podTemplate.Spec.Containers[0].VolumeMounts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithFunkyCommand(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: basi/node-exporter
|
||||||
|
command: ["-collector.procfs", "/host/proc", "-collector.sysfs", "/host/sys"]
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedArgs := []string{
|
||||||
|
`-collector.procfs`,
|
||||||
|
`/host/proc`, // ?
|
||||||
|
`-collector.sysfs`,
|
||||||
|
`/host/sys`, // ?
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectedArgs, podTemplate.Spec.Containers[0].Args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithGlobalVolume(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: "postgres:9.4"
|
||||||
|
volumes:
|
||||||
|
- dbdata:/var/lib/postgresql/data
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedMount := apiv1.VolumeMount{
|
||||||
|
Name: "dbdata",
|
||||||
|
MountPath: "/var/lib/postgresql/data",
|
||||||
|
}
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 0)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 1)
|
||||||
|
assert.Equal(t, expectedMount, podTemplate.Spec.Containers[0].VolumeMounts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithResources(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: "postgres:9.4"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: "0.001"
|
||||||
|
memory: 50Mb
|
||||||
|
reservations:
|
||||||
|
cpus: "0.0001"
|
||||||
|
memory: 20Mb
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedResourceRequirements := apiv1.ResourceRequirements{
|
||||||
|
Limits: map[apiv1.ResourceName]resource.Quantity{
|
||||||
|
apiv1.ResourceCPU: resource.MustParse("0.001"),
|
||||||
|
apiv1.ResourceMemory: resource.MustParse(fmt.Sprintf("%d", 50*1024*1024)),
|
||||||
|
},
|
||||||
|
Requests: map[apiv1.ResourceName]resource.Quantity{
|
||||||
|
apiv1.ResourceCPU: resource.MustParse("0.0001"),
|
||||||
|
apiv1.ResourceMemory: resource.MustParse(fmt.Sprintf("%d", 20*1024*1024)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectedResourceRequirements, podTemplate.Spec.Containers[0].Resources)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithCapabilities(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
cap_add:
|
||||||
|
- ALL
|
||||||
|
cap_drop:
|
||||||
|
- NET_ADMIN
|
||||||
|
- SYS_ADMIN
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedSecurityContext := &apiv1.SecurityContext{
|
||||||
|
Capabilities: &apiv1.Capabilities{
|
||||||
|
Add: []apiv1.Capability{"ALL"},
|
||||||
|
Drop: []apiv1.Capability{"NET_ADMIN", "SYS_ADMIN"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expectedSecurityContext, podTemplate.Spec.Containers[0].SecurityContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithReadOnly(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
read_only: true
|
||||||
|
`)
|
||||||
|
|
||||||
|
yes := true
|
||||||
|
expectedSecurityContext := &apiv1.SecurityContext{
|
||||||
|
ReadOnlyRootFilesystem: &yes,
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectedSecurityContext, podTemplate.Spec.Containers[0].SecurityContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithPrivileged(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
privileged: true
|
||||||
|
`)
|
||||||
|
|
||||||
|
yes := true
|
||||||
|
expectedSecurityContext := &apiv1.SecurityContext{
|
||||||
|
Privileged: &yes,
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectedSecurityContext, podTemplate.Spec.Containers[0].SecurityContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithEnvNilShouldErrorOut(t *testing.T) {
|
||||||
|
_, err := podTemplateWithError(`
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
environment:
|
||||||
|
- SESSION_SECRET
|
||||||
|
`)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithEnv(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
environment:
|
||||||
|
- RACK_ENV=development
|
||||||
|
- SHOW=true
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedEnv := []apiv1.EnvVar{
|
||||||
|
{
|
||||||
|
Name: "RACK_ENV",
|
||||||
|
Value: "development",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "SHOW",
|
||||||
|
Value: "true",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expectedEnv, podTemplate.Spec.Containers[0].Env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithVolume(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
t.Skip("on windows, source path validation is broken (and actually, source validation for windows workload is broken too). Skip it for now, as we don't support it yet")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
volumes:
|
||||||
|
- /ignore:/ignore
|
||||||
|
- /opt/data:/var/lib/mysql:ro
|
||||||
|
`)
|
||||||
|
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 2)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func /*FIXME Test*/ToPodWithRelativeVolumes(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
t.Skip("on windows, source path validation is broken (and actually, source validation for windows workload is broken too). Skip it for now, as we don't support it yet")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err := podTemplateWithError(`
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
volumes:
|
||||||
|
- ./fail:/ignore
|
||||||
|
`)
|
||||||
|
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithHealthCheck(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost"]
|
||||||
|
interval: 90s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedLivenessProbe := &apiv1.Probe{
|
||||||
|
TimeoutSeconds: 10,
|
||||||
|
PeriodSeconds: 90,
|
||||||
|
FailureThreshold: 3,
|
||||||
|
Handler: apiv1.Handler{
|
||||||
|
Exec: &apiv1.ExecAction{
|
||||||
|
Command: []string{"curl", "-f", "http://localhost"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expectedLivenessProbe, podTemplate.Spec.Containers[0].LivenessProbe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithShellHealthCheck(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -f http://localhost"]
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedLivenessProbe := &apiv1.Probe{
|
||||||
|
TimeoutSeconds: 1,
|
||||||
|
PeriodSeconds: 1,
|
||||||
|
FailureThreshold: 3,
|
||||||
|
Handler: apiv1.Handler{
|
||||||
|
Exec: &apiv1.ExecAction{
|
||||||
|
Command: []string{"sh", "-c", "curl -f http://localhost"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expectedLivenessProbe, podTemplate.Spec.Containers[0].LivenessProbe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithTargetlessExternalSecret(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
secrets:
|
||||||
|
- my_secret
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedVolume := apiv1.Volume{
|
||||||
|
Name: "secret-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
Secret: &apiv1.SecretVolumeSource{
|
||||||
|
SecretName: "my_secret",
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "file", // TODO: This is the key we assume external secrets use
|
||||||
|
Path: "secret-0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMount := apiv1.VolumeMount{
|
||||||
|
Name: "secret-0",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/run/secrets/my_secret",
|
||||||
|
SubPath: "secret-0",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 1)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 1)
|
||||||
|
assert.Equal(t, expectedVolume, podTemplate.Spec.Volumes[0])
|
||||||
|
assert.Equal(t, expectedMount, podTemplate.Spec.Containers[0].VolumeMounts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithExternalSecret(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
secrets:
|
||||||
|
- source: my_secret
|
||||||
|
target: nginx_secret
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedVolume := apiv1.Volume{
|
||||||
|
Name: "secret-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
Secret: &apiv1.SecretVolumeSource{
|
||||||
|
SecretName: "my_secret",
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "file", // TODO: This is the key we assume external secrets use
|
||||||
|
Path: "secret-0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMount := apiv1.VolumeMount{
|
||||||
|
Name: "secret-0",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/run/secrets/nginx_secret",
|
||||||
|
SubPath: "secret-0",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 1)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 1)
|
||||||
|
assert.Equal(t, expectedVolume, podTemplate.Spec.Volumes[0])
|
||||||
|
assert.Equal(t, expectedMount, podTemplate.Spec.Containers[0].VolumeMounts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func /*FIXME Test*/ToPodWithFileBasedSecret(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
secrets:
|
||||||
|
- source: my_secret
|
||||||
|
secrets:
|
||||||
|
my_secret:
|
||||||
|
file: ./secret.txt
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedVolume := apiv1.Volume{
|
||||||
|
Name: "secret-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
Secret: &apiv1.SecretVolumeSource{
|
||||||
|
SecretName: "my_secret",
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "secret.txt",
|
||||||
|
Path: "secret-0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMount := apiv1.VolumeMount{
|
||||||
|
Name: "secret-0",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/run/secrets/my_secret",
|
||||||
|
SubPath: "secret-0",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 1)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 1)
|
||||||
|
assert.Equal(t, expectedVolume, podTemplate.Spec.Volumes[0])
|
||||||
|
assert.Equal(t, expectedMount, podTemplate.Spec.Containers[0].VolumeMounts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func /*FIXME Test*/ToPodWithTwoFileBasedSecrets(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
secrets:
|
||||||
|
- source: my_secret1
|
||||||
|
- source: my_secret2
|
||||||
|
target: secret2
|
||||||
|
secrets:
|
||||||
|
my_secret1:
|
||||||
|
file: ./secret1.txt
|
||||||
|
my_secret2:
|
||||||
|
file: ./secret2.txt
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedVolumes := []apiv1.Volume{
|
||||||
|
{
|
||||||
|
Name: "secret-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
Secret: &apiv1.SecretVolumeSource{
|
||||||
|
SecretName: "my_secret1",
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "secret1.txt",
|
||||||
|
Path: "secret-0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "secret-1",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
Secret: &apiv1.SecretVolumeSource{
|
||||||
|
SecretName: "my_secret2",
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "secret2.txt",
|
||||||
|
Path: "secret-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMounts := []apiv1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "secret-0",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/run/secrets/my_secret1",
|
||||||
|
SubPath: "secret-0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "secret-1",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/run/secrets/secret2",
|
||||||
|
SubPath: "secret-1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expectedVolumes, podTemplate.Spec.Volumes)
|
||||||
|
assert.Equal(t, expectedMounts, podTemplate.Spec.Containers[0].VolumeMounts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithTerminationGracePeriod(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
stop_grace_period: 100s
|
||||||
|
`)
|
||||||
|
|
||||||
|
expected := int64(100)
|
||||||
|
assert.Equal(t, &expected, podTemplate.Spec.TerminationGracePeriodSeconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithTmpfs(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
tmpfs:
|
||||||
|
- /tmp
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedVolume := apiv1.Volume{
|
||||||
|
Name: "tmp-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
EmptyDir: &apiv1.EmptyDirVolumeSource{
|
||||||
|
Medium: "Memory",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMount := apiv1.VolumeMount{
|
||||||
|
Name: "tmp-0",
|
||||||
|
MountPath: "/tmp",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 1)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 1)
|
||||||
|
assert.Equal(t, expectedVolume, podTemplate.Spec.Volumes[0])
|
||||||
|
assert.Equal(t, expectedMount, podTemplate.Spec.Containers[0].VolumeMounts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithNumericalUser(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
user: "1000"
|
||||||
|
`)
|
||||||
|
|
||||||
|
userID := int64(1000)
|
||||||
|
|
||||||
|
expectedSecurityContext := &apiv1.SecurityContext{
|
||||||
|
RunAsUser: &userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expectedSecurityContext, podTemplate.Spec.Containers[0].SecurityContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithGitVolume(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
volumes:
|
||||||
|
- source: "git@github.com:moby/moby.git"
|
||||||
|
target: /sources
|
||||||
|
type: git
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedVolume := apiv1.Volume{
|
||||||
|
Name: "mount-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
GitRepo: &apiv1.GitRepoVolumeSource{
|
||||||
|
Repository: "git@github.com:moby/moby.git",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMount := apiv1.VolumeMount{
|
||||||
|
Name: "mount-0",
|
||||||
|
ReadOnly: false,
|
||||||
|
MountPath: "/sources",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 1)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 1)
|
||||||
|
assert.Equal(t, expectedVolume, podTemplate.Spec.Volumes[0])
|
||||||
|
assert.Equal(t, expectedMount, podTemplate.Spec.Containers[0].VolumeMounts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func /*FIXME Test*/ToPodWithFileBasedConfig(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
configs:
|
||||||
|
- source: my_config
|
||||||
|
target: /usr/share/nginx/html/index.html
|
||||||
|
uid: "103"
|
||||||
|
gid: "103"
|
||||||
|
mode: 0440
|
||||||
|
configs:
|
||||||
|
my_config:
|
||||||
|
file: ./file.html
|
||||||
|
`)
|
||||||
|
|
||||||
|
mode := int32(0440)
|
||||||
|
|
||||||
|
expectedVolume := apiv1.Volume{
|
||||||
|
Name: "config-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
ConfigMap: &apiv1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: apiv1.LocalObjectReference{
|
||||||
|
Name: "my_config",
|
||||||
|
},
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "file.html",
|
||||||
|
Path: "config-0",
|
||||||
|
Mode: &mode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMount := apiv1.VolumeMount{
|
||||||
|
Name: "config-0",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/usr/share/nginx/html/index.html",
|
||||||
|
SubPath: "config-0",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 1)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 1)
|
||||||
|
assert.Equal(t, expectedVolume, podTemplate.Spec.Volumes[0])
|
||||||
|
assert.Equal(t, expectedMount, podTemplate.Spec.Containers[0].VolumeMounts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func /*FIXME Test*/ToPodWithTargetlessFileBasedConfig(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
configs:
|
||||||
|
- my_config
|
||||||
|
configs:
|
||||||
|
my_config:
|
||||||
|
file: ./file.html
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedVolume := apiv1.Volume{
|
||||||
|
Name: "config-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
ConfigMap: &apiv1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: apiv1.LocalObjectReference{
|
||||||
|
Name: "myconfig",
|
||||||
|
},
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "file.html",
|
||||||
|
Path: "config-0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMount := apiv1.VolumeMount{
|
||||||
|
Name: "config-0",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/myconfig",
|
||||||
|
SubPath: "config-0",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 1)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 1)
|
||||||
|
assert.Equal(t, expectedVolume, podTemplate.Spec.Volumes[0])
|
||||||
|
assert.Equal(t, expectedMount, podTemplate.Spec.Containers[0].VolumeMounts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithExternalConfig(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
configs:
|
||||||
|
- source: my_config
|
||||||
|
target: /usr/share/nginx/html/index.html
|
||||||
|
uid: "103"
|
||||||
|
gid: "103"
|
||||||
|
mode: 0440
|
||||||
|
configs:
|
||||||
|
my_config:
|
||||||
|
external: true
|
||||||
|
`)
|
||||||
|
|
||||||
|
mode := int32(0440)
|
||||||
|
|
||||||
|
expectedVolume := apiv1.Volume{
|
||||||
|
Name: "config-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
ConfigMap: &apiv1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: apiv1.LocalObjectReference{
|
||||||
|
Name: "my_config",
|
||||||
|
},
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "file", // TODO: This is the key we assume external config use
|
||||||
|
Path: "config-0",
|
||||||
|
Mode: &mode,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMount := apiv1.VolumeMount{
|
||||||
|
Name: "config-0",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/usr/share/nginx/html/index.html",
|
||||||
|
SubPath: "config-0",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, podTemplate.Spec.Volumes, 1)
|
||||||
|
assert.Len(t, podTemplate.Spec.Containers[0].VolumeMounts, 1)
|
||||||
|
assert.Equal(t, expectedVolume, podTemplate.Spec.Volumes[0])
|
||||||
|
assert.Equal(t, expectedMount, podTemplate.Spec.Containers[0].VolumeMounts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func /*FIXME Test*/ToPodWithTwoConfigsSameMountPoint(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
configs:
|
||||||
|
- source: first
|
||||||
|
target: /data/first.json
|
||||||
|
mode: "0440"
|
||||||
|
- source: second
|
||||||
|
target: /data/second.json
|
||||||
|
mode: "0550"
|
||||||
|
configs:
|
||||||
|
first:
|
||||||
|
file: ./file1
|
||||||
|
secondv:
|
||||||
|
file: ./file2
|
||||||
|
`)
|
||||||
|
|
||||||
|
mode0440 := int32(0440)
|
||||||
|
mode0550 := int32(0550)
|
||||||
|
|
||||||
|
expectedVolumes := []apiv1.Volume{
|
||||||
|
{
|
||||||
|
Name: "config-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
ConfigMap: &apiv1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: apiv1.LocalObjectReference{
|
||||||
|
Name: "first",
|
||||||
|
},
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "file1",
|
||||||
|
Path: "config-0",
|
||||||
|
Mode: &mode0440,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "config-1",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
ConfigMap: &apiv1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: apiv1.LocalObjectReference{
|
||||||
|
Name: "second",
|
||||||
|
},
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "file2",
|
||||||
|
Path: "config-1",
|
||||||
|
Mode: &mode0550,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMounts := []apiv1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "config-0",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/data/first.json",
|
||||||
|
SubPath: "config-0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "config-1",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/data/second.json",
|
||||||
|
SubPath: "config-1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expectedVolumes, podTemplate.Spec.Volumes)
|
||||||
|
assert.Equal(t, expectedMounts, podTemplate.Spec.Containers[0].VolumeMounts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPodWithTwoExternalConfigsSameMountPoint(t *testing.T) {
|
||||||
|
podTemplate := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
configs:
|
||||||
|
- source: first
|
||||||
|
target: /data/first.json
|
||||||
|
- source: second
|
||||||
|
target: /data/second.json
|
||||||
|
configs:
|
||||||
|
first:
|
||||||
|
file: ./file1
|
||||||
|
second:
|
||||||
|
file: ./file2
|
||||||
|
`)
|
||||||
|
|
||||||
|
expectedVolumes := []apiv1.Volume{
|
||||||
|
{
|
||||||
|
Name: "config-0",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
ConfigMap: &apiv1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: apiv1.LocalObjectReference{
|
||||||
|
Name: "first",
|
||||||
|
},
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "file",
|
||||||
|
Path: "config-0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "config-1",
|
||||||
|
VolumeSource: apiv1.VolumeSource{
|
||||||
|
ConfigMap: &apiv1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: apiv1.LocalObjectReference{
|
||||||
|
Name: "second",
|
||||||
|
},
|
||||||
|
Items: []apiv1.KeyToPath{
|
||||||
|
{
|
||||||
|
Key: "file",
|
||||||
|
Path: "config-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMounts := []apiv1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "config-0",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/data/first.json",
|
||||||
|
SubPath: "config-0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "config-1",
|
||||||
|
ReadOnly: true,
|
||||||
|
MountPath: "/data/second.json",
|
||||||
|
SubPath: "config-1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, expectedVolumes, podTemplate.Spec.Volumes)
|
||||||
|
assert.Equal(t, expectedMounts, podTemplate.Spec.Containers[0].VolumeMounts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func /*FIXME Test*/ToPodWithPullSecret(t *testing.T) {
|
||||||
|
podTemplateWithSecret := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
x-kubernetes.pull-secret: test-pull-secret
|
||||||
|
`)
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(podTemplateWithSecret.Spec.ImagePullSecrets))
|
||||||
|
assert.Equal(t, "test-pull-secret", podTemplateWithSecret.Spec.ImagePullSecrets[0].Name)
|
||||||
|
|
||||||
|
podTemplateNoSecret := podTemplate(t, `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
`)
|
||||||
|
|
||||||
|
assert.Nil(t, podTemplateNoSecret.Spec.ImagePullSecrets)
|
||||||
|
}
|
||||||
|
|
||||||
|
func /*FIXME Test*/ToPodWithPullPolicy(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
stack string
|
||||||
|
expectedPolicy apiv1.PullPolicy
|
||||||
|
expectedError string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "specific tag",
|
||||||
|
stack: `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx:specific
|
||||||
|
`,
|
||||||
|
expectedPolicy: apiv1.PullIfNotPresent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "latest tag",
|
||||||
|
stack: `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx:latest
|
||||||
|
`,
|
||||||
|
expectedPolicy: apiv1.PullAlways,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "explicit policy",
|
||||||
|
stack: `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx:specific
|
||||||
|
x-kubernetes.pull-policy: Never
|
||||||
|
`,
|
||||||
|
expectedPolicy: apiv1.PullNever,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid policy",
|
||||||
|
stack: `
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
nginx:
|
||||||
|
image: nginx:specific
|
||||||
|
x-kubernetes.pull-policy: Invalid
|
||||||
|
`,
|
||||||
|
expectedError: `invalid pull policy "Invalid", must be "Always", "IfNotPresent" or "Never"`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
pod, err := podTemplateWithError(c.stack)
|
||||||
|
if c.expectedError != "" {
|
||||||
|
assert.EqualError(t, err, c.expectedError)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, pod.Spec.Containers[0].ImagePullPolicy, c.expectedPolicy)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -170,13 +170,13 @@ func defaultMode(mode *uint32) *int32 {
|
|||||||
return defaultMode
|
return defaultMode
|
||||||
}
|
}
|
||||||
|
|
||||||
func secretVolume(config types.ServiceSecretConfig, topLevelSecret types.SecretConfig, subPath string) *apiv1.VolumeSource {
|
func secretVolume(config types.ServiceSecretConfig, topLevelConfig types.SecretConfig, subPath string) *apiv1.VolumeSource {
|
||||||
return &apiv1.VolumeSource{
|
return &apiv1.VolumeSource{
|
||||||
Secret: &apiv1.SecretVolumeSource{
|
Secret: &apiv1.SecretVolumeSource{
|
||||||
SecretName: config.Source,
|
SecretName: config.Source,
|
||||||
Items: []apiv1.KeyToPath{
|
Items: []apiv1.KeyToPath{
|
||||||
{
|
{
|
||||||
Key: toKey(topLevelSecret.File),
|
Key: toKey(topLevelConfig.File),
|
||||||
Path: subPath,
|
Path: subPath,
|
||||||
Mode: defaultMode(config.Mode),
|
Mode: defaultMode(config.Mode),
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user