github.com/apprenda/kismatic@v1.12.0/integration-tests/install.go (about) 1 package integration_tests 2 3 import ( 4 "bufio" 5 "crypto/tls" 6 "fmt" 7 "html/template" 8 "net/http" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "time" 13 14 homedir "github.com/mitchellh/go-homedir" 15 . "github.com/onsi/ginkgo" 16 . "github.com/onsi/gomega" 17 ) 18 19 func leaveIt() bool { 20 return os.Getenv("LEAVE_ARTIFACTS") != "" 21 } 22 23 func GetSSHKeyFile() (string, error) { 24 dir, err := homedir.Dir() 25 if err != nil { 26 return "", err 27 } 28 return filepath.Join(dir, ".ssh", "kismatic-integration-testing.pem"), nil 29 } 30 31 type installOptions struct { 32 disablePackageInstallation bool 33 disableDockerInstallation bool 34 disconnectedInstallation bool 35 dockerRegistryServer string 36 dockerRegistryCAPath string 37 dockerRegistryUsername string 38 dockerRegistryPassword string 39 modifyHostsFiles bool 40 httpProxy string 41 httpsProxy string 42 noProxy string 43 dockerStorageDriver string 44 serviceCIDR string 45 disableCNI bool 46 cniProvider string 47 dnsProvider string 48 heapsterReplicas int 49 heapsterInfluxdbPVC string 50 cloudProvider string 51 kubeAPIServerOptions map[string]string 52 kubeControllerManagerOptions map[string]string 53 kubeSchedulerOptions map[string]string 54 kubeProxyOptions map[string]string 55 kubeletOptions map[string]string 56 } 57 58 func installKismaticMini(node NodeDeets, sshKey string) error { 59 sshUser := node.SSHUser 60 plan := PlanAWS{ 61 Etcd: []NodeDeets{node}, 62 Master: []NodeDeets{node}, 63 Worker: []NodeDeets{node}, 64 Ingress: []NodeDeets{node}, 65 Storage: []NodeDeets{node}, 66 LoadBalancer: node.PublicIP, 67 SSHKeyFile: sshKey, 68 SSHUser: sshUser, 69 } 70 return installKismaticWithPlan(plan) 71 } 72 73 func resetKismatic() error { 74 By("Resetting Cluster") 75 cmd := exec.Command("./kismatic", "reset", "-f", "kismatic-testing.yaml", "--force") 76 cmd.Stdout = os.Stdout 77 cmd.Stderr = os.Stderr 78 return cmd.Run() 79 } 80 81 func installKismatic(nodes provisionedNodes, installOpts installOptions, sshKey string) error { 82 return installKismaticWithPlan(buildPlan(nodes, installOpts, sshKey)) 83 } 84 85 func validateKismatic(nodes provisionedNodes, installOpts installOptions, sshKey string) error { 86 return validateKismaticWithPlan(buildPlan(nodes, installOpts, sshKey)) 87 } 88 89 func buildPlan(nodes provisionedNodes, installOpts installOptions, sshKey string) PlanAWS { 90 sshUser := nodes.master[0].SSHUser 91 masterDNS := nodes.master[0].PublicIP 92 disableHelm := false 93 if nodes.dnsRecord != nil && nodes.dnsRecord.Name != "" { 94 masterDNS = nodes.dnsRecord.Name 95 // disable helm if using Route53 96 disableHelm = true 97 } 98 plan := PlanAWS{ 99 DisablePackageInstallation: installOpts.disablePackageInstallation, 100 DisableDockerInstallation: installOpts.disableDockerInstallation, 101 DisconnectedInstallation: installOpts.disconnectedInstallation, 102 Etcd: nodes.etcd, 103 Master: nodes.master, 104 Worker: nodes.worker, 105 Ingress: nodes.ingress, 106 Storage: nodes.storage, 107 LoadBalancer: masterDNS, 108 SSHKeyFile: sshKey, 109 SSHUser: sshUser, 110 DockerRegistryCAPath: installOpts.dockerRegistryCAPath, 111 DockerRegistryServer: installOpts.dockerRegistryServer, 112 DockerRegistryUsername: installOpts.dockerRegistryUsername, 113 DockerRegistryPassword: installOpts.dockerRegistryPassword, 114 ModifyHostsFiles: installOpts.modifyHostsFiles, 115 HTTPProxy: installOpts.httpProxy, 116 HTTPSProxy: installOpts.httpsProxy, 117 NoProxy: installOpts.noProxy, 118 DockerStorageDriver: installOpts.dockerStorageDriver, 119 ServiceCIDR: installOpts.serviceCIDR, 120 DisableCNI: installOpts.disableCNI, 121 CNIProvider: installOpts.cniProvider, 122 DNSProvider: installOpts.dnsProvider, 123 DisableHelm: disableHelm, 124 HeapsterReplicas: installOpts.heapsterReplicas, 125 HeapsterInfluxdbPVC: installOpts.heapsterInfluxdbPVC, 126 CloudProvider: installOpts.cloudProvider, 127 KubeAPIServerOptions: installOpts.kubeAPIServerOptions, 128 KubeControllerManagerOptions: installOpts.kubeControllerManagerOptions, 129 KubeSchedulerOptions: installOpts.kubeSchedulerOptions, 130 KubeProxyOptions: installOpts.kubeProxyOptions, 131 KubeletOptions: installOpts.kubeletOptions, 132 } 133 return plan 134 } 135 136 func installKismaticWithPlan(plan PlanAWS) error { 137 writePlanFile(plan) 138 139 By("Punch it Chewie!") 140 cmd := exec.Command("./kismatic", "install", "apply", "-f", "kismatic-testing.yaml") 141 cmd.Stdout = os.Stdout 142 cmd.Stderr = os.Stderr 143 144 if err := cmd.Run(); err != nil { 145 // run diagnostics on error 146 fmt.Println("----- Running diagnose command -----") 147 diagsCmd := exec.Command("./kismatic", "diagnose", "-f", "kismatic-testing.yaml") 148 diagsCmd.Stdout = os.Stdout 149 diagsCmd.Stderr = os.Stderr 150 if errDiags := diagsCmd.Run(); errDiags != nil { 151 fmt.Printf("ERROR: error running diagnose command: %v", errDiags) 152 } 153 return err 154 } 155 return nil 156 } 157 158 func validateKismaticWithPlan(plan PlanAWS) error { 159 writePlanFile(plan) 160 161 By("Validate Plan") 162 cmd := exec.Command("./kismatic", "install", "validate", "-f", "kismatic-testing.yaml") 163 cmd.Stdout = os.Stdout 164 cmd.Stderr = os.Stderr 165 return cmd.Run() 166 } 167 168 func writePlanFile(plan PlanAWS) { 169 By("Building a template") 170 template, err := template.New("planAWSOverlay").Parse(planAWSOverlay) 171 FailIfError(err, "Couldn't parse template") 172 173 path := "kismatic-testing.yaml" 174 _, err = os.Stat(path) 175 // create file if not exists 176 if os.IsNotExist(err) { 177 f, err := os.Create(path) 178 FailIfError(err, "Error creating plan") 179 defer f.Close() 180 w := bufio.NewWriter(f) 181 err = template.Execute(w, &plan) 182 FailIfError(err, "Error filling in plan template") 183 w.Flush() 184 } 185 } 186 187 func installKismaticWithABadNode() { 188 By("Building a template") 189 template, err := template.New("planAWSOverlay").Parse(planAWSOverlay) 190 FailIfError(err, "Couldn't parse template") 191 192 By("Faking infrastructure") 193 fakeNode := NodeDeets{ 194 id: "FakeId", 195 PublicIP: "10.0.0.0", 196 Hostname: "FakeHostname", 197 } 198 199 By("Building a plan to set up an overlay network cluster on this hardware") 200 sshKey, err := GetSSHKeyFile() 201 FailIfError(err, "Error getting SSH Key file") 202 plan := PlanAWS{ 203 Etcd: []NodeDeets{fakeNode}, 204 Master: []NodeDeets{fakeNode}, 205 Worker: []NodeDeets{fakeNode}, 206 Ingress: []NodeDeets{fakeNode}, 207 LoadBalancer: "yep.nope", 208 SSHUser: "Billy Rubin", 209 SSHKeyFile: sshKey, 210 } 211 By("Writing plan file out to disk") 212 f, err := os.Create("kismatic-testing.yaml") 213 FailIfError(err, "Error waiting for nodes") 214 defer f.Close() 215 w := bufio.NewWriter(f) 216 err = template.Execute(w, &plan) 217 FailIfError(err, "Error filling in plan template") 218 w.Flush() 219 f.Close() 220 221 By("Validing our plan") 222 cmd := exec.Command("./kismatic", "install", "validate", "-f", f.Name()) 223 cmd.Stdout = os.Stdout 224 cmd.Stderr = os.Stderr 225 err = cmd.Run() 226 if err == nil { 227 Fail("Validation succeeeded even though it shouldn't have") 228 } 229 230 By("Well, try it anyway") 231 cmd = exec.Command("./kismatic", "install", "apply", "-f", f.Name()) 232 cmd.Stdout = os.Stdout 233 cmd.Stderr = os.Stderr 234 err = cmd.Run() 235 if err == nil { 236 Fail("Application succeeeded even though it shouldn't have") 237 } 238 } 239 240 func completesInTime(dothis func(), howLong time.Duration) bool { 241 c1 := make(chan string, 1) 242 go func() { 243 dothis() 244 c1 <- "completed" 245 }() 246 247 select { 248 case <-c1: 249 return true 250 case <-time.After(howLong): 251 return false 252 } 253 } 254 255 func canAccessDashboard(url string) error { 256 tr := &http.Transport{ 257 TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 258 } 259 client := http.Client{ 260 Timeout: 1000 * time.Millisecond, 261 Transport: tr, 262 } 263 req, err := http.NewRequest(http.MethodGet, url, nil) 264 if err != nil { 265 return fmt.Errorf("Could not create request for ingress via %s, %v", url, err) 266 } 267 // Access the dashboard a few times to hit all replicas 268 for i := 0; i < 3; i++ { 269 resp, err := client.Do(req) 270 if err != nil { 271 return fmt.Errorf("Could not reach ingress via %s, %v", url, err) 272 } 273 if resp.StatusCode != 200 { 274 return fmt.Errorf("Ingress status code is not 200, got %d vi %s", resp.StatusCode, url) 275 } 276 } 277 278 return nil 279 } 280 281 func FailIfError(err error, message ...interface{}) { 282 Expect(err).ToNot(HaveOccurred(), message...) 283 } 284 285 func FailIfSuccess(err error) { 286 if err == nil { 287 Fail("Expected failure") 288 } 289 } 290 291 func FileExists(path string) bool { 292 if _, err := os.Stat(path); os.IsNotExist(err) { 293 return false 294 } 295 return true 296 }