mirror of
				https://github.com/docker/compose.git
				synced 2025-10-31 19:24:21 +01:00 
			
		
		
		
	This reverts commit 6b61902a23763fd51d6a5e864cc568b33058b06e. Signed-off-by: Guillaume Tardif <guillaume.tardif@gmail.com>
		
			
				
	
	
		
			1034 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			1034 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // +build kube
 | |
| 
 | |
| /*
 | |
|    Copyright 2020 Docker Compose CLI authors
 | |
| 
 | |
|    Licensed under the Apache License, Version 2.0 (the "License");
 | |
|    you may not use this file except in compliance with the License.
 | |
|    You may obtain a copy of the License at
 | |
| 
 | |
|        http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
|    Unless required by applicable law or agreed to in writing, software
 | |
|    distributed under the License is distributed on an "AS IS" BASIS,
 | |
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|    See the License for the specific language governing permissions and
 | |
|    limitations under the License.
 | |
| */
 | |
| 
 | |
| package resources
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"runtime"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/compose-spec/compose-go/loader"
 | |
| 	"github.com/compose-spec/compose-go/types"
 | |
| 	"github.com/stretchr/testify/assert"
 | |
| 	apiv1 "k8s.io/api/core/v1"
 | |
| 	"k8s.io/apimachinery/pkg/api/resource"
 | |
| )
 | |
| 
 | |
| func loadYAML(yaml string) (*types.Project, error) {
 | |
| 	dict, err := loader.ParseYAML([]byte(yaml))
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	workingDir, err := os.Getwd()
 | |
| 	if err != nil {
 | |
| 		panic(err)
 | |
| 	}
 | |
| 	configs := []types.ConfigFile{
 | |
| 		{
 | |
| 			Filename: "test-compose.yaml",
 | |
| 			Config:   dict,
 | |
| 		},
 | |
| 	}
 | |
| 	config := types.ConfigDetails{
 | |
| 		WorkingDir:  workingDir,
 | |
| 		ConfigFiles: configs,
 | |
| 		Environment: nil,
 | |
| 	}
 | |
| 	return loader.Load(config)
 | |
| }
 | |
| 
 | |
| 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) {
 | |
| 	model, err := loadYAML(yaml)
 | |
| 	if err != nil {
 | |
| 		return apiv1.PodTemplateSpec{}, err
 | |
| 	}
 | |
| 
 | |
| 	return toPodTemplate(model, model.Services[0], nil)
 | |
| }
 | |
| 
 | |
| 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)
 | |
| }
 | |
| 
 | |
| /* FIXME
 | |
| func TestToPodWithGlobalVolume(t *testing.T) {
 | |
| 	podTemplate := podTemplate(t, `
 | |
| version: "3"
 | |
| services:
 | |
|   db:
 | |
|     image: "postgres:9.4"
 | |
|     volumes:
 | |
| 	  - dbdata:/var/lib/postgresql/data
 | |
| volumes:
 | |
|   dbdata:
 | |
| `)
 | |
| 
 | |
| 	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)
 | |
| }
 | |
| 
 | |
| /* FIXME
 | |
| func TestToPodWithRelativeVolumes(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)
 | |
| }
 | |
| 
 | |
| /* FIXME
 | |
| 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])
 | |
| }
 | |
| */
 | |
| 
 | |
| /* FIXME
 | |
| 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])
 | |
| }
 | |
| */
 | |
| 
 | |
| /* FIXME
 | |
| func TestToPodWithFileBasedSecret(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])
 | |
| }
 | |
| */
 | |
| 
 | |
| /* FIXME
 | |
| func TestToPodWithTwoFileBasedSecrets(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])
 | |
| }
 | |
| 
 | |
| /* FIXME
 | |
| func TestToPodWithFileBasedConfig(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])
 | |
| }
 | |
| */
 | |
| 
 | |
| /* FIXME
 | |
| func TestToPodWithTargetlessFileBasedConfig(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])
 | |
| }
 | |
| 
 | |
| /* FIXME
 | |
| func TestToPodWithTwoConfigsSameMountPoint(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)
 | |
| }
 | |
| 
 | |
| /* FIXME
 | |
| func TestToPodWithPullSecret(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)
 | |
| }
 | |
| */
 | |
| 
 | |
| /* FIXME
 | |
| func TestToPodWithPullPolicy(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)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| */
 |