github.com/abayer/test-infra@v0.0.5/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  }