github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/kubetest/kops.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "flag" 21 "fmt" 22 "io/ioutil" 23 "os" 24 "os/exec" 25 "os/user" 26 "path/filepath" 27 "strconv" 28 "strings" 29 "time" 30 ) 31 32 var ( 33 // kops specific flags. 34 kopsPath = flag.String("kops", "", "(kops only) Path to the kops binary. Must be set for kops.") 35 kopsCluster = flag.String("kops-cluster", "", "(kops only) Cluster name. Must be set for kops.") 36 kopsState = flag.String("kops-state", "", "(kops only) s3:// path to kops state store. Must be set.") 37 kopsSSHKey = flag.String("kops-ssh-key", "", "(kops only) Path to ssh key-pair for each node (defaults '~/.ssh/kube_aws_rsa' if unset.)") 38 kopsKubeVersion = flag.String("kops-kubernetes-version", "", "(kops only) If set, the version of Kubernetes to deploy (can be a URL to a GCS path where the release is stored) (Defaults to kops default, latest stable release.).") 39 kopsZones = flag.String("kops-zones", "us-west-2a", "(kops AWS only) AWS zones for kops deployment, comma delimited.") 40 kopsNodes = flag.Int("kops-nodes", 2, "(kops only) Number of nodes to create.") 41 kopsUpTimeout = flag.Duration("kops-up-timeout", 20*time.Minute, "(kops only) Time limit between 'kops config / kops update' and a response from the Kubernetes API.") 42 kopsAdminAccess = flag.String("kops-admin-access", "", "(kops only) If set, restrict apiserver access to this CIDR range.") 43 kopsImage = flag.String("kops-image", "", "(kops only) Image (AMI) for nodes to use. (Defaults to kops default, a Debian image with a custom kubernetes kernel.)") 44 kopsArgs = flag.String("kops-args", "", "(kops only) Additional space-separated args to pass unvalidated to 'kops create cluster', e.g. '--kops-args=\"--dns private --node-size t2.micro\"'") 45 kopsPriorityPath = flag.String("kops-priority-path", "", "Insert into PATH if set") 46 ) 47 48 type kops struct { 49 path string 50 kubeVersion string 51 sshKey string 52 zones []string 53 nodes int 54 adminAccess string 55 cluster string 56 image string 57 args string 58 kubecfg string 59 } 60 61 var _ deployer = kops{} 62 63 func migrateKopsEnv() error { 64 return migrateOptions([]migratedOption{ 65 { 66 env: "KOPS_STATE_STORE", 67 option: kopsState, 68 name: "--kops-state", 69 skipPush: true, 70 }, 71 { 72 env: "AWS_SSH_KEY", 73 option: kopsSSHKey, 74 name: "--kops-ssh-key", 75 skipPush: true, 76 }, 77 { 78 env: "PRIORITY_PATH", 79 option: kopsPriorityPath, 80 name: "--kops-priority-path", 81 skipPush: true, 82 }, 83 }) 84 } 85 86 func newKops() (*kops, error) { 87 if err := migrateKopsEnv(); err != nil { 88 return nil, err 89 } 90 if *kopsPath == "" { 91 return nil, fmt.Errorf("--kops must be set to a valid binary path for kops deployment") 92 } 93 if *kopsCluster == "" { 94 return nil, fmt.Errorf("--kops-cluster must be set to a valid cluster name for kops deployment") 95 } 96 if *kopsState == "" { 97 return nil, fmt.Errorf("--kops-state must be set to a valid S3 path for kops deployment") 98 } 99 if *kopsPriorityPath != "" { 100 if err := insertPath(*kopsPriorityPath); err != nil { 101 return nil, err 102 } 103 } 104 105 // TODO(fejta): consider explicitly passing these env items where needed. 106 sshKey := *kopsSSHKey 107 if sshKey == "" { 108 usr, err := user.Current() 109 if err != nil { 110 return nil, err 111 } 112 sshKey = filepath.Join(usr.HomeDir, ".ssh/kube_aws_rsa") 113 } 114 if err := os.Setenv("KOPS_STATE_STORE", *kopsState); err != nil { 115 return nil, err 116 } 117 f, err := ioutil.TempFile("", "kops-kubecfg") 118 if err != nil { 119 return nil, err 120 } 121 defer f.Close() 122 kubecfg := f.Name() 123 if err := f.Chmod(0600); err != nil { 124 return nil, err 125 } 126 if err := os.Setenv("KUBECONFIG", kubecfg); err != nil { 127 return nil, err 128 } 129 // Set KUBERNETES_CONFORMANCE_TEST so the auth info is picked up 130 // from kubectl instead of bash inference. 131 if err := os.Setenv("KUBERNETES_CONFORMANCE_TEST", "yes"); err != nil { 132 return nil, err 133 } 134 // Set KUBERNETES_CONFORMANCE_PROVIDER to override the 135 // cloudprovider for KUBERNETES_CONFORMANCE_TEST. 136 if err := os.Setenv("KUBERNETES_CONFORMANCE_PROVIDER", "aws"); err != nil { 137 return nil, err 138 } 139 // AWS_SSH_KEY is required by the AWS e2e tests. 140 if err := os.Setenv("AWS_SSH_KEY", sshKey); err != nil { 141 return nil, err 142 } 143 // ZONE is required by the AWS e2e tests. 144 zones := strings.Split(*kopsZones, ",") 145 if err := os.Setenv("ZONE", zones[0]); err != nil { 146 return nil, err 147 } 148 return &kops{ 149 path: *kopsPath, 150 kubeVersion: *kopsKubeVersion, 151 sshKey: sshKey + ".pub", // kops only needs the public key, e2es need the private key. 152 zones: zones, 153 nodes: *kopsNodes, 154 adminAccess: *kopsAdminAccess, 155 cluster: *kopsCluster, 156 image: *kopsImage, 157 args: *kopsArgs, 158 kubecfg: kubecfg, 159 }, nil 160 } 161 162 func (k kops) Up() error { 163 createArgs := []string{ 164 "create", "cluster", 165 "--name", k.cluster, 166 "--ssh-public-key", k.sshKey, 167 "--node-count", strconv.Itoa(k.nodes), 168 "--zones", strings.Join(k.zones, ","), 169 } 170 if k.kubeVersion != "" { 171 createArgs = append(createArgs, "--kubernetes-version", k.kubeVersion) 172 } 173 if k.adminAccess != "" { 174 createArgs = append(createArgs, "--admin-access", k.adminAccess) 175 } 176 if k.image != "" { 177 createArgs = append(createArgs, "--image", k.image) 178 } 179 if k.args != "" { 180 createArgs = append(createArgs, strings.Split(k.args, " ")...) 181 } 182 if err := finishRunning(exec.Command(k.path, createArgs...)); err != nil { 183 return fmt.Errorf("kops configuration failed: %v", err) 184 } 185 if err := finishRunning(exec.Command(k.path, "update", "cluster", k.cluster, "--yes")); err != nil { 186 return fmt.Errorf("kops bringup failed: %v", err) 187 } 188 // TODO(zmerlynn): More cluster validation. This should perhaps be 189 // added to kops and not here, but this is a fine place to loop 190 // for now. 191 return waitForNodes(k, k.nodes+1, *kopsUpTimeout) 192 } 193 194 func (k kops) IsUp() error { 195 return isUp(k) 196 } 197 198 func (k kops) DumpClusterLogs(localPath, gcsPath string) error { 199 return defaultDumpClusterLogs(localPath, gcsPath) 200 } 201 202 func (k kops) TestSetup() error { 203 info, err := os.Stat(k.kubecfg) 204 if err != nil { 205 return err 206 } 207 if info.Size() > 0 { 208 // Assume that if we already have it, it's good. 209 return nil 210 } 211 if err := finishRunning(exec.Command(k.path, "export", "kubecfg", k.cluster)); err != nil { 212 return fmt.Errorf("Failure exporting kops kubecfg: %v", err) 213 } 214 return nil 215 } 216 217 func (k kops) Down() error { 218 // We do a "kops get" first so the exit status of "kops delete" is 219 // more sensical in the case of a non-existent cluster. ("kops 220 // delete" will exit with status 1 on a non-existent cluster) 221 err := finishRunning(exec.Command(k.path, "get", "clusters", k.cluster)) 222 if err != nil { 223 // This is expected if the cluster doesn't exist. 224 return nil 225 } 226 return finishRunning(exec.Command(k.path, "delete", "cluster", k.cluster, "--yes")) 227 }