github.com/apprenda/kismatic@v1.12.0/integration-tests/install_test.go (about) 1 package integration_tests 2 3 import ( 4 "io/ioutil" 5 "os" 6 "time" 7 8 yaml "gopkg.in/yaml.v2" 9 10 "os/exec" 11 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 ) 15 16 var _ = Describe("kismatic", func() { 17 BeforeEach(func() { 18 dir := setupTestWorkingDir() 19 os.Chdir(dir) 20 }) 21 22 Describe("calling kismatic with no verb", func() { 23 It("should output help text", func() { 24 c := exec.Command("./kismatic") 25 helpbytes, helperr := c.Output() 26 Expect(helperr).To(BeNil()) 27 helpText := string(helpbytes) 28 Expect(helpText).To(ContainSubstring("Usage")) 29 }) 30 }) 31 32 Describe("Calling 'install plan'", func() { 33 Context("and just hitting enter", func() { 34 It("should result in the output of a well formed default plan file", func() { 35 By("Outputing a file") 36 c := exec.Command("./kismatic", "install", "plan") 37 helpbytes, helperr := c.Output() 38 Expect(helperr).To(BeNil()) 39 helpText := string(helpbytes) 40 Expect(helpText).To(ContainSubstring("Generating installation plan file template")) 41 Expect(helpText).To(ContainSubstring("3 etcd nodes")) 42 Expect(helpText).To(ContainSubstring("2 master nodes")) 43 Expect(helpText).To(ContainSubstring("3 worker nodes")) 44 Expect(helpText).To(ContainSubstring("2 ingress nodes")) 45 Expect(helpText).To(ContainSubstring("0 storage nodes")) 46 47 Expect(FileExists("kismatic-cluster.yaml")).To(Equal(true)) 48 49 By("Reading generated plan file") 50 yamlBytes, err := ioutil.ReadFile("kismatic-cluster.yaml") 51 if err != nil { 52 Fail("Could not read cluster file") 53 } 54 yamlBlob := string(yamlBytes) 55 planFromYaml := ClusterPlan{} 56 unmarshallErr := yaml.Unmarshal([]byte(yamlBlob), &planFromYaml) 57 if unmarshallErr != nil { 58 Fail("Could not unmarshall cluster yaml: %v") 59 } 60 61 By("Verifying generated plan file") 62 Expect(planFromYaml.Etcd.ExpectedCount).To(Equal(3)) 63 Expect(planFromYaml.Master.ExpectedCount).To(Equal(2)) 64 Expect(planFromYaml.Worker.ExpectedCount).To(Equal(3)) 65 Expect(planFromYaml.Ingress.ExpectedCount).To(Equal(2)) 66 Expect(planFromYaml.Storage.ExpectedCount).To(Equal(0)) 67 }) 68 }) 69 }) 70 71 Describe("calling install apply", func() { 72 Context("when targeting non-existent infrastructure", func() { 73 It("should fail in a reasonable amount of time", func() { 74 if !completesInTime(installKismaticWithABadNode, 600*time.Second) { 75 Fail("It shouldn't take 600 seconds for Kismatic to fail with bad nodes.") 76 } 77 }) 78 }) 79 80 Context("when deploying a cluster with all node roles", func() { 81 installOpts := installOptions{} 82 ItOnAWS("should install successfully [slow]", func(aws infrastructureProvisioner) { 83 WithInfrastructure(NodeCount{1, 1, 1, 1, 1}, Ubuntu1604LTS, aws, func(nodes provisionedNodes, sshKey string) { 84 err := installKismatic(nodes, installOpts, sshKey) 85 Expect(err).ToNot(HaveOccurred()) 86 }) 87 }) 88 }) 89 90 Context("when deploying a cluster with all node roles and docker already installed", func() { 91 installOpts := installOptions{disableDockerInstallation: true} 92 ItOnAWS("should install successfully [slow]", func(aws infrastructureProvisioner) { 93 WithInfrastructure(NodeCount{1, 1, 1, 1, 1}, Ubuntu1604LTS, aws, func(nodes provisionedNodes, sshKey string) { 94 err := validateKismatic(nodes, installOpts, sshKey) 95 if err == nil { 96 Fail("Validation should fail when docker.disable = true and docker is not yet installed.") 97 } 98 InstallDockerPackage(nodes, Ubuntu1604LTS, sshKey) 99 err = installKismatic(nodes, installOpts, sshKey) 100 Expect(err).ToNot(HaveOccurred()) 101 }) 102 }) 103 }) 104 105 Context("when deploying a cluster with all node roles and cloud-provider on CentOS", func() { 106 ItOnAWS("should install successfully [slow]", func(aws infrastructureProvisioner) { 107 WithInfrastructure(NodeCount{1, 1, 2, 1, 1}, CentOS7, aws, func(nodes provisionedNodes, sshKey string) { 108 testCloudProvider(nodes, sshKey) 109 }) 110 }) 111 }) 112 113 Context("when deploying a cluster with all node roles and cloud-provider on RHEL", func() { 114 ItOnAWS("should install successfully [slow]", func(aws infrastructureProvisioner) { 115 WithInfrastructure(NodeCount{1, 1, 2, 1, 1}, RedHat7, aws, func(nodes provisionedNodes, sshKey string) { 116 testCloudProvider(nodes, sshKey) 117 }) 118 }) 119 }) 120 121 Context("when deploying a cluster with all node roles and cloud-provider on Ubuntu", func() { 122 ItOnAWS("should install successfully [slow]", func(aws infrastructureProvisioner) { 123 WithInfrastructure(NodeCount{1, 1, 2, 1, 1}, Ubuntu1604LTS, aws, func(nodes provisionedNodes, sshKey string) { 124 testCloudProvider(nodes, sshKey) 125 }) 126 }) 127 }) 128 129 Context("when deploying a cluster with all node roles and disabled CNI", func() { 130 installOpts := installOptions{ 131 disableCNI: true, 132 } 133 ItOnAWS("should install successfully [slow]", func(aws infrastructureProvisioner) { 134 WithInfrastructure(NodeCount{1, 1, 1, 1, 1}, Ubuntu1604LTS, aws, func(nodes provisionedNodes, sshKey string) { 135 err := installKismatic(nodes, installOpts, sshKey) 136 Expect(err).ToNot(HaveOccurred()) 137 }) 138 }) 139 }) 140 141 Context("when targeting CentOS", func() { 142 ItOnAWS("should install successfully", func(aws infrastructureProvisioner) { 143 WithMiniInfrastructure(CentOS7, aws, func(node NodeDeets, sshKey string) { 144 err := installKismaticMini(node, sshKey) 145 Expect(err).ToNot(HaveOccurred()) 146 // Ensure preflight checks are idempotent on CentOS7 147 err = runValidate("kismatic-testing.yaml") 148 Expect(err).ToNot(HaveOccurred()) 149 err = resetKismatic() 150 Expect(err).ToNot(HaveOccurred()) 151 }) 152 }) 153 }) 154 155 Context("when targeting RHEL", func() { 156 ItOnAWS("should install successfully", func(aws infrastructureProvisioner) { 157 WithMiniInfrastructure(RedHat7, aws, func(node NodeDeets, sshKey string) { 158 err := installKismaticMini(node, sshKey) 159 Expect(err).ToNot(HaveOccurred()) 160 // Ensure preflight checks are idempotent on RedHat7 161 err = runValidate("kismatic-testing.yaml") 162 Expect(err).ToNot(HaveOccurred()) 163 err = resetKismatic() 164 Expect(err).ToNot(HaveOccurred()) 165 }) 166 }) 167 }) 168 169 Context("when targeting Ubuntu", func() { 170 ItOnAWS("should install successfully", func(aws infrastructureProvisioner) { 171 WithMiniInfrastructure(Ubuntu1604LTS, aws, func(node NodeDeets, sshKey string) { 172 err := installKismaticMini(node, sshKey) 173 Expect(err).ToNot(HaveOccurred()) 174 // Ensure preflight checks are idempotent on Ubuntu 1604 175 err = runValidate("kismatic-testing.yaml") 176 Expect(err).ToNot(HaveOccurred()) 177 err = resetKismatic() 178 Expect(err).ToNot(HaveOccurred()) 179 }) 180 }) 181 }) 182 183 Context("when using direct-lvm docker storage", func() { 184 installOpts := installOptions{ 185 dockerStorageDriver: "devicemapper", 186 } 187 Context("when targeting CentOS", func() { 188 ItOnAWS("should install successfully", func(aws infrastructureProvisioner) { 189 WithMiniInfrastructureAndBlockDevice(CentOS7, aws, func(node NodeDeets, sshKey string) { 190 theNode := []NodeDeets{node} 191 nodes := provisionedNodes{ 192 etcd: theNode, 193 master: theNode, 194 worker: theNode, 195 ingress: theNode, 196 } 197 err := installKismatic(nodes, installOpts, sshKey) 198 Expect(err).ToNot(HaveOccurred()) 199 err = resetKismatic() 200 Expect(err).ToNot(HaveOccurred()) 201 }) 202 }) 203 }) 204 205 Context("when targeting RHEL", func() { 206 ItOnAWS("should install successfully", func(aws infrastructureProvisioner) { 207 WithMiniInfrastructureAndBlockDevice(RedHat7, aws, func(node NodeDeets, sshKey string) { 208 theNode := []NodeDeets{node} 209 nodes := provisionedNodes{ 210 etcd: theNode, 211 master: theNode, 212 worker: theNode, 213 ingress: theNode, 214 } 215 err := installKismatic(nodes, installOpts, sshKey) 216 Expect(err).ToNot(HaveOccurred()) 217 err = resetKismatic() 218 Expect(err).ToNot(HaveOccurred()) 219 }) 220 }) 221 }) 222 }) 223 224 Context("when using overlay2 docker storage", func() { 225 installOpts := installOptions{ 226 dockerStorageDriver: "overlay2", 227 } 228 Context("when targeting Ubuntu", func() { 229 ItOnAWS("should install successfully", func(aws infrastructureProvisioner) { 230 WithMiniInfrastructureAndBlockDevice(Ubuntu1604LTS, aws, func(node NodeDeets, sshKey string) { 231 theNode := []NodeDeets{node} 232 nodes := provisionedNodes{ 233 etcd: theNode, 234 master: theNode, 235 worker: theNode, 236 ingress: theNode, 237 } 238 err := installKismatic(nodes, installOpts, sshKey) 239 Expect(err).ToNot(HaveOccurred()) 240 }) 241 }) 242 }) 243 }) 244 245 // TODO add back when --endpoint-reconciler-type=lease 246 // Context("when deploying an HA cluster", func() { 247 // ItOnAWS("should still be a highly available cluster after removing a master node [slow]", func(aws infrastructureProvisioner) { 248 // WithInfrastructureAndDNS(NodeCount{1, 2, 1, 1, 0}, Ubuntu1604LTS, aws, func(nodes provisionedNodes, sshKey string) { 249 // // install cluster 250 // installOpts := installOptions{} 251 // err := installKismatic(nodes, installOpts, sshKey) 252 // Expect(err).ToNot(HaveOccurred()) 253 254 // By("Removing a Kubernetes master node") 255 // if err = aws.TerminateNode(nodes.master[0]); err != nil { 256 // FailIfError(err, "could not remove node") 257 // } 258 // By("Re-running Kuberang") 259 // if err = runViaSSH([]string{"sudo kuberang --kubeconfig /root/.kube/config"}, []NodeDeets{nodes.master[1]}, sshKey, 5*time.Minute); err != nil { 260 // FailIfError(err, "kuberang error") 261 // } 262 // }) 263 // }) 264 // }) 265 266 // This spec will be used for testing non-destructive kismatic features on 267 // a new cluster. 268 // This spec is open to modification when new assertions have to be made 269 Context("when deploying a skunkworks cluster", func() { 270 Context("with Calico as the CNI provider", func() { 271 ItOnAWS("should install successfully [slow]", func(aws infrastructureProvisioner) { 272 WithInfrastructure(NodeCount{3, 2, 5, 2, 2}, Ubuntu1604LTS, aws, func(nodes provisionedNodes, sshKey string) { 273 // reserve 3 of the workers for the add-node test 274 allWorkers := nodes.worker 275 nodes.worker = allWorkers[0 : len(nodes.worker)-3] 276 277 // install cluster 278 installOpts := installOptions{ 279 heapsterReplicas: 3, 280 heapsterInfluxdbPVC: "influxdb", 281 kubeAPIServerOptions: map[string]string{"v": "3"}, 282 kubeControllerManagerOptions: map[string]string{"v": "3"}, 283 kubeSchedulerOptions: map[string]string{"v": "3"}, 284 kubeProxyOptions: map[string]string{"v": "3"}, 285 kubeletOptions: map[string]string{"v": "3"}, 286 } 287 err := installKismatic(nodes, installOpts, sshKey) 288 Expect(err).ToNot(HaveOccurred()) 289 290 sub := SubDescribe("Using a running cluster") 291 defer sub.Check() 292 293 sub.It("should allow adding a worker node", func() error { 294 newNode := allWorkers[len(allWorkers)-1] 295 return addNodeToCluster(newNode, sshKey, []string{"com.integrationtest/worker=true"}, []string{}) 296 }) 297 298 sub.It("should allow adding a ingress node", func() error { 299 newNode := allWorkers[len(allWorkers)-2] 300 return addNodeToCluster(newNode, sshKey, []string{"com.integrationtest/worker=true"}, []string{"ingress"}) 301 }) 302 303 sub.It("should allow adding a storage node", func() error { 304 newNode := allWorkers[len(allWorkers)-3] 305 return addNodeToCluster(newNode, sshKey, []string{"com.integrationtest/worker=true"}, []string{"storage"}) 306 }) 307 308 sub.It("should be able to deploy a workload with ingress", func() error { 309 return verifyIngressNodes(nodes.master[0], nodes.ingress, sshKey) 310 }) 311 312 // Use master[0] public IP 313 // sub.It("should have an accessible dashboard", func() error { 314 // return canAccessDashboard(fmt.Sprintf("https://admin:abbazabba@%s:6443/ui", nodes.master[0].PublicIP)) 315 // }) 316 317 sub.It("should respect network policies", func() error { 318 return verifyNetworkPolicy(nodes.master[0], sshKey) 319 }) 320 321 sub.It("should support heapster with persistent storage", func() error { 322 return verifyHeapster(nodes.master[0], sshKey) 323 }) 324 325 sub.It("should have tiller running", func() error { 326 return verifyTiller(nodes.master[0], sshKey) 327 }) 328 329 sub.It("nodes should contain expected labels", func() error { 330 return containsLabels(nodes, sshKey) 331 }) 332 333 sub.It("nodes should contain expected component overrides", func() error { 334 return ContainsOverrides(nodes, sshKey) 335 }) 336 337 sub.It("should allow for running preflight checks idempotently", func() error { 338 return runValidate("kismatic-testing.yaml") 339 }) 340 }) 341 }) 342 }) 343 }) 344 345 Context("when deploying a skunkworks cluster", func() { 346 Context("with Weave as the CNI provider", func() { 347 ItOnAWS("should install successfully [slow]", func(aws infrastructureProvisioner) { 348 WithInfrastructure(NodeCount{3, 2, 5, 2, 2}, Ubuntu1604LTS, aws, func(nodes provisionedNodes, sshKey string) { 349 // reserve 3 of the workers for the add-node test 350 allWorkers := nodes.worker 351 nodes.worker = allWorkers[0 : len(nodes.worker)-3] 352 353 // install cluster 354 installOpts := installOptions{ 355 heapsterReplicas: 3, 356 heapsterInfluxdbPVC: "influxdb", 357 cniProvider: "weave", 358 } 359 err := installKismatic(nodes, installOpts, sshKey) 360 Expect(err).ToNot(HaveOccurred()) 361 362 sub := SubDescribe("Using a running cluster") 363 defer sub.Check() 364 365 sub.It("should allow adding a worker node", func() error { 366 newNode := allWorkers[len(allWorkers)-1] 367 return addNodeToCluster(newNode, sshKey, []string{"com.integrationtest/worker=true"}, []string{}) 368 }) 369 370 sub.It("should allow adding a ingress node", func() error { 371 newNode := allWorkers[len(allWorkers)-2] 372 return addNodeToCluster(newNode, sshKey, []string{"com.integrationtest/worker=true"}, []string{"ingress"}) 373 }) 374 375 sub.It("should allow adding a storage node", func() error { 376 newNode := allWorkers[len(allWorkers)-3] 377 return addNodeToCluster(newNode, sshKey, []string{"com.integrationtest/worker=true"}, []string{"storage"}) 378 }) 379 380 sub.It("should be able to deploy a workload with ingress", func() error { 381 return verifyIngressNodes(nodes.master[0], nodes.ingress, sshKey) 382 }) 383 384 // Use master[0] public IP 385 // sub.It("should have an accessible dashboard", func() error { 386 // return canAccessDashboard(fmt.Sprintf("https://admin:abbazabba@%s:6443/ui", nodes.master[0].PublicIP)) 387 // }) 388 389 sub.It("should respect network policies", func() error { 390 return verifyNetworkPolicy(nodes.master[0], sshKey) 391 }) 392 393 sub.It("should support heapster with persistent storage", func() error { 394 return verifyHeapster(nodes.master[0], sshKey) 395 }) 396 397 sub.It("should have tiller running", func() error { 398 return verifyTiller(nodes.master[0], sshKey) 399 }) 400 401 sub.It("nodes should contain expected labels", func() error { 402 return containsLabels(nodes, sshKey) 403 }) 404 405 sub.It("should allow for running preflight checks idempotently", func() error { 406 return runValidate("kismatic-testing.yaml") 407 }) 408 }) 409 }) 410 }) 411 }) 412 413 // Context("when deploying a skunkworks cluster", func() { 414 // Context("with Contiv as the CNI provider", func() { 415 // ItOnAWS("should install successfully [slow]", func(aws infrastructureProvisioner) { 416 // WithInfrastructure(NodeCount{3, 2, 3, 2, 2}, Ubuntu1604LTS, aws, func(nodes provisionedNodes, sshKey string) { 417 // // reserve 3 of the workers for the add-node test 418 // allWorkers := nodes.worker 419 // nodes.worker = allWorkers[0 : len(nodes.worker)-1] 420 421 // // install cluster 422 // installOpts := installOptions{ 423 // heapsterReplicas: 3, 424 // heapsterInfluxdbPVC: "influxdb", 425 // cniProvider: "contiv", 426 // } 427 // err := installKismatic(nodes, installOpts, sshKey) 428 // Expect(err).ToNot(HaveOccurred()) 429 430 // sub := SubDescribe("Using a running cluster") 431 // defer sub.Check() 432 433 // sub.It("should allow adding a worker node", func() error { 434 // newNode := allWorkers[len(allWorkers)-1] 435 // return addNodeToCluster(newNode, sshKey, []string{}) 436 // }) 437 438 // // This test is flaky with contiv 439 // // sub.It("should be able to deploy a workload with ingress", func() error { 440 // // return verifyIngressNodes(nodes.master[0], nodes.ingress, sshKey) 441 // // }) 442 443 // // Use master[0] public IP 444 // // There is an issue with contiv that prevents this test from passing consistently 445 // // sub.It("should have an accessible dashboard", func() error { 446 // // return canAccessDashboard(fmt.Sprintf("https://admin:abbazabba@%s:6443/ui", nodes.master[0].PublicIP)) 447 // // }) 448 449 // // Contiv does not support the Kubernetes network policy API 450 // // sub.It("should respect network policies", func() error { 451 // // return verifyNetworkPolicy(nodes.master[0], sshKey) 452 // // }) 453 454 // sub.It("should support heapster with persistent storage", func() error { 455 // return verifyHeapster(nodes.master[0], sshKey) 456 // }) 457 458 // sub.It("should have tiller running", func() error { 459 // return verifyTiller(nodes.master[0], sshKey) 460 // }) 461 // }) 462 // }) 463 // }) 464 // }) 465 466 Context("when deploying a skunkworks cluster", func() { 467 Context("with CoreDNS as the DNS provider", func() { 468 ItOnAWS("should install successfully [slow]", func(aws infrastructureProvisioner) { 469 WithInfrastructure(NodeCount{3, 2, 5, 2, 2}, Ubuntu1604LTS, aws, func(nodes provisionedNodes, sshKey string) { 470 // reserve 3 of the workers for the add-node test 471 allWorkers := nodes.worker 472 nodes.worker = allWorkers[0 : len(nodes.worker)-3] 473 474 // install cluster 475 installOpts := installOptions{ 476 heapsterReplicas: 3, 477 heapsterInfluxdbPVC: "influxdb", 478 dnsProvider: "coredns", 479 } 480 err := installKismatic(nodes, installOpts, sshKey) 481 Expect(err).ToNot(HaveOccurred()) 482 483 sub := SubDescribe("Using a running cluster") 484 defer sub.Check() 485 486 sub.It("should allow adding a worker node", func() error { 487 newNode := allWorkers[len(allWorkers)-1] 488 return addNodeToCluster(newNode, sshKey, []string{"com.integrationtest/worker=true"}, []string{}) 489 }) 490 491 sub.It("should allow adding a ingress node", func() error { 492 newNode := allWorkers[len(allWorkers)-2] 493 return addNodeToCluster(newNode, sshKey, []string{"com.integrationtest/worker=true"}, []string{"ingress"}) 494 }) 495 496 sub.It("should allow adding a storage node", func() error { 497 newNode := allWorkers[len(allWorkers)-3] 498 return addNodeToCluster(newNode, sshKey, []string{"com.integrationtest/worker=true"}, []string{"storage"}) 499 }) 500 501 sub.It("should be able to deploy a workload with ingress", func() error { 502 return verifyIngressNodes(nodes.master[0], nodes.ingress, sshKey) 503 }) 504 505 sub.It("should respect network policies", func() error { 506 return verifyNetworkPolicy(nodes.master[0], sshKey) 507 }) 508 509 sub.It("should support heapster with persistent storage", func() error { 510 return verifyHeapster(nodes.master[0], sshKey) 511 }) 512 513 sub.It("should have tiller running", func() error { 514 return verifyTiller(nodes.master[0], sshKey) 515 }) 516 }) 517 }) 518 }) 519 }) 520 521 ItOnPacket("should install successfully [slow]", func(packet infrastructureProvisioner) { 522 WithMiniInfrastructure(Ubuntu1604LTS, packet, func(node NodeDeets, sshKey string) { 523 err := installKismaticMini(node, sshKey) 524 Expect(err).ToNot(HaveOccurred()) 525 }) 526 }) 527 }) 528 }) 529 530 func testCloudProvider(nodes provisionedNodes, sshKey string) { 531 installOpts := installOptions{cloudProvider: "aws"} 532 533 By("installing the cluster") 534 err := installKismatic(nodes, installOpts, sshKey) 535 Expect(err).ToNot(HaveOccurred()) 536 537 By("test the cloud provider integration") 538 err = testAWSCloudProvider(nodes.master[0], sshKey) 539 Expect(err).ToNot(HaveOccurred()) 540 }