1package env 2 3import ( 4 "errors" 5 "fmt" 6 "os" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/go-acme/lego/v4/log" 12) 13 14// Get environment variables. 15func Get(names ...string) (map[string]string, error) { 16 values := map[string]string{} 17 18 var missingEnvVars []string 19 for _, envVar := range names { 20 value := GetOrFile(envVar) 21 if value == "" { 22 missingEnvVars = append(missingEnvVars, envVar) 23 } 24 values[envVar] = value 25 } 26 27 if len(missingEnvVars) > 0 { 28 return nil, fmt.Errorf("some credentials information are missing: %s", strings.Join(missingEnvVars, ",")) 29 } 30 31 return values, nil 32} 33 34// GetWithFallback Get environment variable values. 35// The first name in each group is use as key in the result map. 36// 37// case 1: 38// 39// // LEGO_ONE="ONE" 40// // LEGO_TWO="TWO" 41// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"}) 42// // => "LEGO_ONE" = "ONE" 43// 44// case 2: 45// 46// // LEGO_ONE="" 47// // LEGO_TWO="TWO" 48// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"}) 49// // => "LEGO_ONE" = "TWO" 50// 51// case 3: 52// 53// // LEGO_ONE="" 54// // LEGO_TWO="" 55// env.GetWithFallback([]string{"LEGO_ONE", "LEGO_TWO"}) 56// // => error 57// 58func GetWithFallback(groups ...[]string) (map[string]string, error) { 59 values := map[string]string{} 60 61 var missingEnvVars []string 62 for _, names := range groups { 63 if len(names) == 0 { 64 return nil, errors.New("undefined environment variable names") 65 } 66 67 value, envVar := getOneWithFallback(names[0], names[1:]...) 68 if value == "" { 69 missingEnvVars = append(missingEnvVars, envVar) 70 continue 71 } 72 values[envVar] = value 73 } 74 75 if len(missingEnvVars) > 0 { 76 return nil, fmt.Errorf("some credentials information are missing: %s", strings.Join(missingEnvVars, ",")) 77 } 78 79 return values, nil 80} 81 82func getOneWithFallback(main string, names ...string) (string, string) { 83 value := GetOrFile(main) 84 if len(value) > 0 { 85 return value, main 86 } 87 88 for _, name := range names { 89 value := GetOrFile(name) 90 if len(value) > 0 { 91 return value, main 92 } 93 } 94 95 return "", main 96} 97 98// GetOrDefaultInt returns the given environment variable value as an integer. 99// Returns the default if the envvar cannot be coopered to an int, or is not found. 100func GetOrDefaultInt(envVar string, defaultValue int) int { 101 v, err := strconv.Atoi(GetOrFile(envVar)) 102 if err != nil { 103 return defaultValue 104 } 105 106 return v 107} 108 109// GetOrDefaultSecond returns the given environment variable value as an time.Duration (second). 110// Returns the default if the envvar cannot be coopered to an int, or is not found. 111func GetOrDefaultSecond(envVar string, defaultValue time.Duration) time.Duration { 112 v := GetOrDefaultInt(envVar, -1) 113 if v < 0 { 114 return defaultValue 115 } 116 117 return time.Duration(v) * time.Second 118} 119 120// GetOrDefaultString returns the given environment variable value as a string. 121// Returns the default if the envvar cannot be find. 122func GetOrDefaultString(envVar, defaultValue string) string { 123 v := GetOrFile(envVar) 124 if v == "" { 125 return defaultValue 126 } 127 128 return v 129} 130 131// GetOrDefaultBool returns the given environment variable value as a boolean. 132// Returns the default if the envvar cannot be coopered to a boolean, or is not found. 133func GetOrDefaultBool(envVar string, defaultValue bool) bool { 134 v, err := strconv.ParseBool(GetOrFile(envVar)) 135 if err != nil { 136 return defaultValue 137 } 138 139 return v 140} 141 142// GetOrFile Attempts to resolve 'key' as an environment variable. 143// Failing that, it will check to see if '<key>_FILE' exists. 144// If so, it will attempt to read from the referenced file to populate a value. 145func GetOrFile(envVar string) string { 146 envVarValue := os.Getenv(envVar) 147 if envVarValue != "" { 148 return envVarValue 149 } 150 151 fileVar := envVar + "_FILE" 152 fileVarValue := os.Getenv(fileVar) 153 if fileVarValue == "" { 154 return envVarValue 155 } 156 157 fileContents, err := os.ReadFile(fileVarValue) 158 if err != nil { 159 log.Printf("Failed to read the file %s (defined by env var %s): %s", fileVarValue, fileVar, err) 160 return "" 161 } 162 163 return strings.TrimSuffix(string(fileContents), "\n") 164} 165