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 }