github.com/docker/compose-on-kubernetes@v0.5.0/internal/convert/deployment_test.go (about)

     1  package convert
     2  
     3  import (
     4  	"runtime"
     5  	"testing"
     6  
     7  	"github.com/docker/compose-on-kubernetes/internal/stackresources"
     8  	. "github.com/docker/compose-on-kubernetes/internal/test/builders"
     9  	"github.com/stretchr/testify/assert"
    10  	appsv1 "k8s.io/api/apps/v1"
    11  	apiv1 "k8s.io/api/core/v1"
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  )
    14  
    15  func TestToDeployment(t *testing.T) {
    16  	s := Stack("demo",
    17  		WithService("nginx",
    18  			Image("nginx:latest"),
    19  		),
    20  	)
    21  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
    22  	assert.NoError(t, err)
    23  	deployment := stack.Deployments["nginx"]
    24  
    25  	replicas := int32(1)
    26  	revisionHistoryLimit := int32(3)
    27  
    28  	expectedLabels := map[string]string{
    29  		"com.docker.stack.namespace": "demo",
    30  		"com.docker.service.name":    "nginx",
    31  		"com.docker.service.id":      "demo-nginx",
    32  	}
    33  
    34  	expectedDeployment := appsv1.Deployment{
    35  		ObjectMeta: metav1.ObjectMeta{
    36  			Name:        "nginx",
    37  			Labels:      expectedLabels,
    38  			Annotations: expectedAnnotationsOnCreate,
    39  		},
    40  		Spec: appsv1.DeploymentSpec{
    41  			Selector: &metav1.LabelSelector{
    42  				MatchLabels: expectedLabels,
    43  			},
    44  			Replicas:             &replicas,
    45  			RevisionHistoryLimit: &revisionHistoryLimit,
    46  			Template: apiv1.PodTemplateSpec{
    47  				ObjectMeta: metav1.ObjectMeta{
    48  					Labels: expectedLabels,
    49  				},
    50  				Spec: apiv1.PodSpec{
    51  					Containers: []apiv1.Container{
    52  						{
    53  							Name:            "nginx",
    54  							Image:           "nginx:latest",
    55  							ImagePullPolicy: apiv1.PullAlways,
    56  						},
    57  					},
    58  					Affinity: makeExpectedAffinity(
    59  						kv(kubernetesOs, "linux"),
    60  						kv(kubernetesArch, "amd64"),
    61  					),
    62  				},
    63  			},
    64  		},
    65  	}
    66  
    67  	assert.Equal(t, expectedDeployment, deployment)
    68  }
    69  
    70  func TestToDeploymentWithPorts(t *testing.T) {
    71  	s := Stack("demo",
    72  		WithService("redis",
    73  			Image("redis:alpine"),
    74  			Entrypoint("sh", "-c"),
    75  			Command("echo", "hello"),
    76  			WorkingDir("/code"),
    77  			WithPort(443),
    78  			WithPort(8080, Published(80)),
    79  			Tty, StdinOpen,
    80  		),
    81  	)
    82  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
    83  	assert.NoError(t, err)
    84  	deployment := stack.Deployments["redis"]
    85  
    86  	expectedContainers := []apiv1.Container{
    87  		{
    88  			Name:            "redis",
    89  			Image:           "redis:alpine",
    90  			ImagePullPolicy: apiv1.PullIfNotPresent,
    91  			Command:         []string{"sh", "-c"},
    92  			Args:            []string{"echo", "hello"},
    93  			WorkingDir:      "/code",
    94  			TTY:             true,
    95  			Stdin:           true,
    96  			Ports: []apiv1.ContainerPort{
    97  				{
    98  					ContainerPort: 443,
    99  					Protocol:      apiv1.ProtocolTCP,
   100  				},
   101  				{
   102  					ContainerPort: 8080,
   103  					Protocol:      apiv1.ProtocolTCP,
   104  				},
   105  			},
   106  		},
   107  	}
   108  
   109  	assert.Equal(t, expectedContainers, deployment.Spec.Template.Spec.Containers)
   110  }
   111  
   112  func TestToDeploymentWithLongPort(t *testing.T) {
   113  	s := Stack("demo",
   114  		WithService("redis",
   115  			Image("redis:alpine"),
   116  			WithPort(443, Published(4443), ProtocolUDP),
   117  		),
   118  	)
   119  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   120  	assert.NoError(t, err)
   121  	deployment := stack.Deployments["redis"]
   122  
   123  	expectedPorts := []apiv1.ContainerPort{
   124  		{
   125  			ContainerPort: 443,
   126  			Protocol:      apiv1.ProtocolUDP,
   127  		},
   128  	}
   129  	assert.Equal(t, expectedPorts, deployment.Spec.Template.Spec.Containers[0].Ports)
   130  }
   131  
   132  func TestToDeploymentWithRestartPolicy(t *testing.T) {
   133  	s := Stack("demo",
   134  		WithService("redis",
   135  			Image("redis:alpine"),
   136  			Deploy(RestartPolicy(OnFailure)),
   137  		),
   138  	)
   139  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   140  	assert.NoError(t, err)
   141  	deployment := stack.Deployments["redis"]
   142  	// For a deployment, the restart policy is ignored
   143  	assert.Equal(t, apiv1.RestartPolicyAlways, deployment.Spec.Template.Spec.RestartPolicy)
   144  }
   145  
   146  func TestToDeploymentWithReplicas(t *testing.T) {
   147  	s := Stack("demo",
   148  		WithService("redis",
   149  			Image("redis:alpine"),
   150  			Deploy(Replicas(6)),
   151  		),
   152  	)
   153  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   154  	assert.NoError(t, err)
   155  	deployment := stack.Deployments["redis"]
   156  
   157  	replicas := int32(6)
   158  	revisionHistoryLimit := int32(3)
   159  
   160  	expectedLabels := map[string]string{
   161  		"com.docker.stack.namespace": "demo",
   162  		"com.docker.service.name":    "redis",
   163  		"com.docker.service.id":      "demo-redis",
   164  	}
   165  
   166  	expectedDeploymentSpec := appsv1.DeploymentSpec{
   167  		Selector: &metav1.LabelSelector{
   168  			MatchLabels: expectedLabels,
   169  		},
   170  		Replicas:             &replicas,
   171  		RevisionHistoryLimit: &revisionHistoryLimit,
   172  		Template: apiv1.PodTemplateSpec{
   173  			ObjectMeta: metav1.ObjectMeta{
   174  				Labels: expectedLabels,
   175  			},
   176  			Spec: apiv1.PodSpec{
   177  				Containers: []apiv1.Container{
   178  					{
   179  						Name:            "redis",
   180  						Image:           "redis:alpine",
   181  						ImagePullPolicy: apiv1.PullIfNotPresent,
   182  					},
   183  				},
   184  				Affinity: makeExpectedAffinity(
   185  					kv(kubernetesOs, "linux"),
   186  					kv(kubernetesArch, "amd64"),
   187  				),
   188  			},
   189  		},
   190  	}
   191  
   192  	assert.Equal(t, expectedDeploymentSpec, deployment.Spec)
   193  }
   194  
   195  func TestToDeploymentWithLabels(t *testing.T) {
   196  	s := Stack("demo",
   197  		WithService("nginx",
   198  			Image("nginx:latest"),
   199  			Deploy(
   200  				WithDeployLabel("prod", "true"),
   201  				WithDeployLabel("mode", "quick"),
   202  			),
   203  			WithLabel("com.example.description", "Database volume"),
   204  			WithLabel("com.example.department", "IT/Ops"),
   205  			WithLabel("com.example.label-with-empty-value", ""),
   206  		),
   207  	)
   208  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   209  	assert.NoError(t, err)
   210  	deployment := stack.Deployments["nginx"]
   211  
   212  	expectedDeploymentLabels := map[string]string{
   213  		"com.docker.stack.namespace": "demo",
   214  		"com.docker.service.name":    "nginx",
   215  		"com.docker.service.id":      "demo-nginx",
   216  		"prod":                       "true",
   217  		"mode":                       "quick",
   218  	}
   219  
   220  	expectedPodLabels := map[string]string{
   221  		"com.docker.stack.namespace": "demo",
   222  		"com.docker.service.name":    "nginx",
   223  		"com.docker.service.id":      "demo-nginx",
   224  		"prod":                       "true",
   225  		"mode":                       "quick",
   226  	}
   227  
   228  	expectedPodAnnotations := map[string]string{
   229  		"com.example.description":            "Database volume",
   230  		"com.example.department":             "IT/Ops",
   231  		"com.example.label-with-empty-value": "",
   232  	}
   233  
   234  	assert.Equal(t, expectedDeploymentLabels, deployment.ObjectMeta.Labels)
   235  	assert.Equal(t, expectedPodLabels, deployment.Spec.Template.ObjectMeta.Labels)
   236  	assert.Equal(t, expectedPodAnnotations, deployment.Spec.Template.ObjectMeta.Annotations)
   237  }
   238  
   239  func TestToDeploymentWithHostIPC(t *testing.T) {
   240  	s := Stack("demo",
   241  		WithService("redis",
   242  			Image("redis:alpine"),
   243  			IPC("host"),
   244  		),
   245  	)
   246  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   247  	assert.NoError(t, err)
   248  	deployment := stack.Deployments["redis"]
   249  
   250  	assert.True(t, deployment.Spec.Template.Spec.HostIPC)
   251  }
   252  
   253  func TestToDeploymentWithHostPID(t *testing.T) {
   254  	s := Stack("demo",
   255  		WithService("redis",
   256  			Image("redis:alpine"),
   257  			PID("host"),
   258  		),
   259  	)
   260  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   261  	assert.NoError(t, err)
   262  	deployment := stack.Deployments["redis"]
   263  
   264  	assert.True(t, deployment.Spec.Template.Spec.HostPID)
   265  }
   266  
   267  func TestToDeploymentWithHostname(t *testing.T) {
   268  	s := Stack("demo",
   269  		WithService("redis",
   270  			Image("redis:alpine"),
   271  			Hostname("foo"),
   272  		),
   273  	)
   274  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   275  	assert.NoError(t, err)
   276  	deployment := stack.Deployments["redis"]
   277  
   278  	assert.Equal(t, "foo", deployment.Spec.Template.Spec.Hostname)
   279  }
   280  
   281  func TestToDeploymentWithExtraHosts(t *testing.T) {
   282  	s := Stack("demo",
   283  		WithService("redis",
   284  			Image("redis:alpine"),
   285  			WithExtraHost("somehost:162.242.195.82"),
   286  			WithExtraHost("somehost2:162.242.195.82"),
   287  			WithExtraHost("otherhost:50.31.209.229"),
   288  		),
   289  	)
   290  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   291  	assert.NoError(t, err)
   292  	deployment := stack.Deployments["redis"]
   293  
   294  	expectedHostAliases := []apiv1.HostAlias{
   295  		{
   296  			IP:        "162.242.195.82",
   297  			Hostnames: []string{"somehost", "somehost2"},
   298  		},
   299  		{
   300  			IP:        "50.31.209.229",
   301  			Hostnames: []string{"otherhost"},
   302  		},
   303  	}
   304  
   305  	assert.Equal(t, expectedHostAliases, deployment.Spec.Template.Spec.HostAliases)
   306  }
   307  
   308  func TestToDeploymentWithUpdateConfig(t *testing.T) {
   309  	s := Stack("demo",
   310  		WithService("nginx",
   311  			Image("nginx"),
   312  			Deploy(Update(Parallelism(2))),
   313  		),
   314  	)
   315  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   316  	assert.NoError(t, err)
   317  	deployment := stack.Deployments["nginx"]
   318  
   319  	assert.Equal(t, "RollingUpdate", string(deployment.Spec.Strategy.Type))
   320  	assert.Equal(t, int32(2), deployment.Spec.Strategy.RollingUpdate.MaxUnavailable.IntVal)
   321  }
   322  
   323  func TestToDeploymentWithBind(t *testing.T) {
   324  	if runtime.GOOS == "windows" {
   325  		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")
   326  		return
   327  	}
   328  	s := Stack("demo",
   329  		WithService("nginx",
   330  			Image("nginx"),
   331  			WithVolume(
   332  				Source("/var/run/postgres/postgres.sock"),
   333  				Target("/var/run/postgres/postgres.sock"),
   334  				Mount,
   335  			),
   336  		),
   337  	)
   338  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   339  	assert.NoError(t, err)
   340  	assert.Contains(t, stack.Deployments, "nginx")
   341  }
   342  
   343  func TestToDeploymentWithVolume(t *testing.T) {
   344  	s := Stack("demo",
   345  		WithService("nginx",
   346  			Image("nginx"),
   347  			WithVolume(
   348  				Source("dbdata"),
   349  				Target("/var/lib/postgresql/data"),
   350  				Volume,
   351  			),
   352  		),
   353  	)
   354  	stack, err := StackToStack(*s, loadBalancerServiceStrategy{}, stackresources.EmptyStackState)
   355  	assert.NoError(t, err)
   356  	assert.NotContains(t, stack.Deployments, "nginx")
   357  }