github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/experiment/bootstrap/env.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 "fmt" 21 "hash/fnv" 22 "log" 23 "os" 24 "path/filepath" 25 "strings" 26 "time" 27 ) 28 29 // SetDefaultEnv does os.Setenv(key, value) if key does not exist (os.LookupEnv) 30 // It returns true if the key was set 31 func SetDefaultEnv(key, value string) (bool, error) { 32 _, exists := os.LookupEnv(key) 33 if !exists { 34 return true, os.Setenv(key, value) 35 } 36 return false, nil 37 } 38 39 // EnvEqual returns true if both keys have the same value or both keys do not 40 // exist. If the values are different or if one key is "" and the other 41 // is not set it will return false. 42 func EnvEqual(key1, key2 string) bool { 43 val1, exists1 := os.LookupEnv(key1) 44 val2, exists2 := os.LookupEnv(key2) 45 return val1 == val2 && exists1 == exists2 46 } 47 48 // SetupMagicEnviroment sets magic environment variables scripts currently expect. 49 func SetupMagicEnviroment(job string) (err error) { 50 home := os.Getenv(HomeEnv) 51 /* 52 TODO(fejta): jenkins sets these values. Consider migrating to using 53 a secret volume instead and passing the path to this volume 54 into bootstrap.py as a flag. 55 */ 56 _, err = SetDefaultEnv( 57 GCEPrivKeyEnv, 58 filepath.Join(home, ".ssh/google_compute_engine"), 59 ) 60 if err != nil { 61 return err 62 } 63 _, err = SetDefaultEnv( 64 GCEPubKeyEnv, 65 filepath.Join(home, ".ssh/google_compute_engine.pub"), 66 ) 67 if err != nil { 68 return err 69 } 70 _, err = SetDefaultEnv( 71 AWSPrivKeyEnv, 72 filepath.Join(home, ".ssh/kube_aws_rsa"), 73 ) 74 if err != nil { 75 return err 76 } 77 _, err = SetDefaultEnv( 78 AWSPubKeyEnv, 79 filepath.Join(home, ".ssh/kube_aws_rsa.pub"), 80 ) 81 if err != nil { 82 return err 83 } 84 85 // TODO(bentheelder): determine if we can avoid getcwd here :-/ 86 cwd, err := os.Getwd() 87 if err != nil { 88 return err 89 } 90 /* 91 TODO(fejta): jenkins sets WORKSPACE and pieces of our infra expect this 92 value. Consider doing something else in the future. 93 Furthermore, in the Jenkins and Prow environments, this is already set 94 to something reasonable, but using cwd will likely cause all sorts of 95 problems. Thus, only set this if we really need to. 96 */ 97 _, err = SetDefaultEnv(WorkspaceEnv, cwd) 98 if err != nil { 99 return err 100 } 101 /* 102 By default, Jenkins sets HOME to JENKINS_HOME, which is shared by all 103 jobs. To avoid collisions, set it to the cwd instead, but only when 104 running on Jenkins. 105 */ 106 if EnvEqual(HomeEnv, JenkinsHomeEnv) { 107 err = os.Setenv(HomeEnv, cwd) 108 if err != nil { 109 return err 110 } 111 } 112 /* 113 TODO(fejta): jenkins sets JOB_ENV and pieces of our infra expect this 114 value. Consider making everything below here agnostic to the 115 job name. 116 */ 117 jobVal, jobSet := os.LookupEnv(JobEnv) 118 if jobSet { 119 log.Printf("%s=%s (overrides %s)", JobEnv, job, jobVal) 120 } 121 err = os.Setenv(JobEnv, job) 122 if err != nil { 123 return err 124 } 125 // TODO(fejta): Magic value to tell our test code not do upload started.json 126 // TODO(fejta): delete upload-to-gcs.sh and then this value. 127 err = os.Setenv(BootstrapEnv, "yes") 128 if err != nil { 129 return err 130 } 131 // This helps prevent reuse of cloudsdk configuration. It also reduces the 132 // risk that running a job on a workstation corrupts the user's config. 133 return os.Setenv(CloudSDKEnv, filepath.Join(cwd, ".config", "gcloud")) 134 } 135 136 // utility method used in NodeName and BuildName 137 // NOTE: this will not produce the same value as hash(str) in python but 138 // it does have similar characteristics 139 func hash(s string) uint32 { 140 hasher := fnv.New32a() 141 hasher.Write([]byte(s)) 142 return hasher.Sum32() 143 } 144 145 // NodeName returns the name of the node the build is running on 146 // and sets os.Setenv(NodeNameEnv, res) if not already set 147 func NodeName() (string, error) { 148 // TODO(fejta): jenkins sets the node name and our infra expect this value. 149 // TODO(fejta): Consider doing something different here. 150 _, exists := os.LookupEnv(NodeNameEnv) 151 if !exists { 152 hostname, err := os.Hostname() 153 if err != nil { 154 return "", err 155 } 156 name := strings.Join(strings.Split(hostname, ".")[1:], "") 157 err = os.Setenv(NodeNameEnv, name) 158 if err != nil { 159 return "", err 160 } 161 } 162 return os.Getenv(NodeNameEnv), nil 163 } 164 165 // BuildName returns the name of the ID/name for the current build 166 // and sets os.Setenv(BuildNumberEnv, res) if not already set 167 func BuildName(started time.Time) (string, error) { 168 /* 169 TODO(fejta): right now jenkins sets the BUILD_NUMBER and does this 170 in an environment variable. Consider migrating this to a 171 bootstrap.py flag 172 */ 173 _, exists := os.LookupEnv(BuildNumberEnv) 174 if !exists { 175 // Automatically generate a build number if none is set 176 nodeName, err := NodeName() 177 if err != nil { 178 return "", err 179 } 180 uniq := fmt.Sprintf("%x-%d", hash(nodeName), os.Getpid()) 181 autogen := started.Format("20060102-150400-") + uniq 182 err = os.Setenv(BuildNumberEnv, autogen) 183 if err != nil { 184 return "", err 185 } 186 } 187 return os.Getenv(BuildNumberEnv), nil 188 }