forked from istio/istio
/
var.go
259 lines (209 loc) · 6.44 KB
/
var.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
// Copyright 2019 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package env makes it possible to track use of environment variables within a procress
// in order to generate documentation for these uses.
package env
import (
"os"
"sort"
"strconv"
"sync"
"time"
"istio.io/istio/pkg/log"
)
// The type of a variable's value
type VarType byte
const (
STRING VarType = iota
BOOL
INT
FLOAT
DURATION
)
// Var describes a single environment variable
type Var struct {
// The name of the environment variable.
Name string
// The optional default value of the environment variable.
DefaultValue string
// Description of the environment variable's purpose.
Description string
// Hide the existence of this variable when outputting usage information.
Hidden bool
// Mark this variable as deprecated when generating usage information.
Deprecated bool
// The type of the variable's value
Type VarType
}
// StringVar represents a single string environment variable.
type StringVar struct {
Var
}
// BoolVar represents a single boolean environment variable.
type BoolVar struct {
Var
}
// IntVar represents a single integer environment variable.
type IntVar struct {
Var
}
// FloatVar represents a single floating-point environment variable.
type FloatVar struct {
Var
}
// DurationVar represents a single duration environment variable.
type DurationVar struct {
Var
}
var allVars = make(map[string]Var)
var mutex sync.Mutex
// Returns a description of this process' environment variables, sorted by name.
func VarDescriptions() []Var {
mutex.Lock()
sorted := make([]Var, 0, len(allVars))
for _, v := range allVars {
sorted = append(sorted, v)
}
mutex.Unlock()
sort.Slice(sorted, func(i, j int) bool {
return sorted[i].Name < sorted[j].Name
})
return sorted
}
// RegisterStringVar registers a new string environment variable.
func RegisterStringVar(name string, defaultValue string, description string) StringVar {
v := Var{Name: name, DefaultValue: defaultValue, Description: description, Type: STRING}
RegisterVar(v)
return StringVar{getVar(name)}
}
// RegisterBoolVar registers a new boolean environment variable.
func RegisterBoolVar(name string, defaultValue bool, description string) BoolVar {
v := Var{Name: name, DefaultValue: strconv.FormatBool(defaultValue), Description: description, Type: BOOL}
RegisterVar(v)
return BoolVar{getVar(name)}
}
// RegisterIntVar registers a new integer environment variable.
func RegisterIntVar(name string, defaultValue int, description string) IntVar {
v := Var{Name: name, DefaultValue: strconv.FormatInt(int64(defaultValue), 10), Description: description, Type: INT}
RegisterVar(v)
return IntVar{getVar(name)}
}
// RegisterFloatVar registers a new floating-point environment variable.
func RegisterFloatVar(name string, defaultValue float64, description string) FloatVar {
v := Var{Name: name, DefaultValue: strconv.FormatFloat(defaultValue, 'G', -1, 64), Description: description, Type: FLOAT}
RegisterVar(v)
return FloatVar{v}
}
// RegisterDurationVar registers a new duration environment variable.
func RegisterDurationVar(name string, defaultValue time.Duration, description string) DurationVar {
v := Var{Name: name, DefaultValue: defaultValue.String(), Description: description, Type: DURATION}
RegisterVar(v)
return DurationVar{getVar(name)}
}
// RegisterVar registers a generic environment variable.
func RegisterVar(v Var) {
mutex.Lock()
if old, ok := allVars[v.Name]; ok {
if v.Description != "" {
allVars[v.Name] = v // last one with a description wins if the same variable name is registered multiple times
}
if old.Description != v.Description || old.DefaultValue != v.DefaultValue || old.Type != v.Type || old.Deprecated != v.Deprecated || old.Hidden != v.Hidden {
log.Warnf("The environment variable %s was registered multiple times using different metadata: %v, %v", v.Name, old, v)
}
} else {
allVars[v.Name] = v
}
mutex.Unlock()
}
func getVar(name string) Var {
mutex.Lock()
result := allVars[name]
mutex.Unlock()
return result
}
func (v StringVar) Get() string {
result, _ := v.Lookup()
return result
}
func (v StringVar) Lookup() (string, bool) {
result, ok := os.LookupEnv(v.Name)
if !ok {
result = v.DefaultValue
}
return result, ok
}
func (v BoolVar) Get() bool {
result, _ := v.Lookup()
return result
}
func (v BoolVar) Lookup() (bool, bool) {
result, ok := os.LookupEnv(v.Name)
if !ok {
result = v.DefaultValue
}
b, err := strconv.ParseBool(result)
if err != nil {
log.Warnf("Invalid environment variable value `%s`, expecting true/false, defaulting to %v", result, v.DefaultValue)
b, _ = strconv.ParseBool(v.DefaultValue)
}
return b, ok
}
func (v IntVar) Get() int {
result, _ := v.Lookup()
return result
}
func (v IntVar) Lookup() (int, bool) {
result, ok := os.LookupEnv(v.Name)
if !ok {
result = v.DefaultValue
}
i, err := strconv.Atoi(result)
if err != nil {
log.Warnf("Invalid environment variable value `%s`, expecting an integer, defaulting to %v", result, v.DefaultValue)
i, _ = strconv.Atoi(v.DefaultValue)
}
return i, ok
}
func (v FloatVar) Get() float64 {
result, _ := v.Lookup()
return result
}
func (v FloatVar) Lookup() (float64, bool) {
result, ok := os.LookupEnv(v.Name)
if !ok {
result = v.DefaultValue
}
f, err := strconv.ParseFloat(result, 64)
if err != nil {
log.Warnf("Invalid environment variable value `%s`, expecting a floating-point value, defaulting to %v", result, v.DefaultValue)
f, _ = strconv.ParseFloat(v.DefaultValue, 64)
}
return f, ok
}
func (v DurationVar) Get() time.Duration {
result, _ := v.Lookup()
return result
}
func (v DurationVar) Lookup() (time.Duration, bool) {
result, ok := os.LookupEnv(v.Name)
if !ok {
result = v.DefaultValue
}
d, err := time.ParseDuration(result)
if err != nil {
log.Warnf("Invalid environment variable value `%s`, expecting a duration, defaulting to %v", result, v.DefaultValue)
d, _ = time.ParseDuration(v.DefaultValue)
}
return d, ok
}